Skip to content

Commit 1f93479

Browse files
committed
Add support for custom scripts found on PATH
1 parent 3400246 commit 1f93479

File tree

4 files changed

+61
-3
lines changed

4 files changed

+61
-3
lines changed

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10-
## [0.0.3] - 2025-05-09
10+
## [0.0.4] - 2025-04-10
11+
12+
### Added
13+
14+
- Support for custom scripts found on PATH
15+
16+
## [0.0.3] - 2025-04-09
1117

1218
### Added
1319

pyproject.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
55
[project]
66
requires-python = ">=3.9"
77
name = "minimal-pba-cli"
8-
version = "0.0.3"
8+
version = "0.0.4"
99
description = "A minimal command-line interface using plugin-based architecture"
1010
authors = [
1111
{ name = "Dane Hillard", email = "[email protected]" }
@@ -21,8 +21,9 @@ classifiers = [
2121
"Programming Language :: Python :: 3.13",
2222
"Programming Language :: Python :: 3",
2323
"Programming Language :: Python :: 3 :: Only",
24-
"License :: OSI Approved :: MIT License",
2524
]
25+
license = "MIT"
26+
dynamic = ["readme"]
2627
dependencies = [
2728
"packaging>=24.2",
2829
"requests>=2.32.3",

src/minimal_pba_cli/cli.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
from minimal_pba_cli.upgrade import upgrade
1111
from minimal_pba_cli.plugin import plugin, find_plugins
12+
from minimal_pba_cli.customization import list_available_commands, create_command_wrapper
1213

1314

1415
app = typer.Typer()
@@ -31,6 +32,8 @@ def main():
3132
_register_plugins(app)
3233
app.add_typer(plugin, name="plugin", help="Manage plugins.")
3334
app.command()(upgrade)
35+
for command, full_path in list_available_commands():
36+
create_command_wrapper(app, command, full_path)
3437
app()
3538

3639

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import contextlib
2+
import errno
3+
import os
4+
import sys
5+
from pathlib import Path
6+
7+
import typer
8+
9+
10+
def list_available_commands(prefix: str = "minimal-pba-cli-") -> list[tuple[str, str]]:
11+
"""List all commands available on the PATH that match an optional prefix."""
12+
commands = []
13+
14+
for path_str in os.getenv("PATH", "").split(os.pathsep):
15+
path = Path(path_str)
16+
17+
with contextlib.suppress(PermissionError):
18+
if path.is_dir():
19+
for file in path.iterdir():
20+
if file.is_dir():
21+
continue
22+
23+
if os.access(file, os.X_OK) and file.name.startswith(prefix):
24+
commands.append((file.name, str(file)))
25+
return sorted(set(commands))
26+
27+
28+
def create_command_wrapper(cli: typer.Typer, command: str, full_path: str):
29+
cli_command_name = command.replace("minimal-pba-cli-", "")
30+
31+
def typer_wrapper_command():
32+
commands = [command, *sys.argv[2:]]
33+
command_string = " ".join(commands)
34+
display = typer.style(command_string, fg=typer.colors.CYAN, bold=True)
35+
typer.echo(f"Running {display}", err=True)
36+
37+
try:
38+
os.execlp(command, *commands)
39+
except OSError as e:
40+
if e.errno == errno.ENOEXEC:
41+
typer.secho(f"Command {command} found, but does not specify a handler. Try adding a shebang line to the file.", fg=typer.colors.RED, err=True)
42+
43+
typer_wrapper_command.__doc__ = f"({full_path}): Custom command with unknown options. Try `pba-cli {cli_command_name} -- --help` for more information."
44+
45+
cli.command(
46+
name=cli_command_name,
47+
context_settings={"ignore_unknown_options": True, "allow_extra_args": True},
48+
)(typer_wrapper_command)

0 commit comments

Comments
 (0)