-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcli.py
More file actions
156 lines (133 loc) · 4.54 KB
/
Copy pathcli.py
File metadata and controls
156 lines (133 loc) · 4.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
"""Command-line interface for apdev."""
from __future__ import annotations
import argparse
import importlib.resources
import os
import subprocess
import sys
from pathlib import Path
import apdev
from apdev.check_chars import check_paths
from apdev.check_imports import check_circular_imports
from apdev.config import load_config
def _get_release_script() -> Path:
"""Locate the bundled release.sh script."""
ref = importlib.resources.files("apdev").joinpath("release.sh")
return Path(str(ref))
def _build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
prog="apdev",
description="Shared development tools for Python projects",
)
parser.add_argument(
"--version",
action="version",
version=f"apdev {apdev.__version__}",
)
subparsers = parser.add_subparsers(dest="command")
# check-chars
chars_parser = subparsers.add_parser(
"check-chars",
help="Validate files contain only allowed characters",
)
chars_parser.add_argument(
"files",
nargs="*",
type=Path,
help="Files to check",
)
chars_parser.add_argument(
"--charset",
action="append",
default=[],
help="Extra charset preset to enable (repeatable, e.g. --charset chinese)",
)
chars_parser.add_argument(
"--charset-file",
action="append",
default=[],
dest="charset_files",
help="Path to custom charset JSON file (repeatable)",
)
# check-imports
imports_parser = subparsers.add_parser(
"check-imports",
help="Detect circular imports in a Python package",
)
imports_parser.add_argument(
"--package",
dest="base_package",
help="Base package name (e.g. apflow). Reads from [tool.apdev] if omitted.",
)
imports_parser.add_argument(
"--src-dir",
dest="src_dir",
help="Source directory containing the package (default: src)",
)
# release
release_parser = subparsers.add_parser(
"release",
help="Interactive release automation (build, tag, GitHub release, PyPI upload)",
)
release_parser.add_argument(
"--yes",
"-y",
action="store_true",
help="Auto-accept all defaults (silent mode)",
)
release_parser.add_argument(
"version",
nargs="?",
help="Version to release (auto-detected from pyproject.toml if omitted)",
)
return parser
def main(argv: list[str] | None = None) -> int:
"""Entry point for the apdev CLI."""
parser = _build_parser()
args = parser.parse_args(argv)
if args.command is None:
parser.print_help()
return 0
if args.command == "check-chars":
from apdev.check_chars import resolve_charsets
charset_names = list(args.charset)
charset_files = list(args.charset_files)
# Fall back to APDEV_EXTRA_CHARS env var if no CLI args
if not charset_names and not charset_files:
env_val = os.environ.get("APDEV_EXTRA_CHARS", "")
if env_val:
for item in env_val.split(","):
item = item.strip()
if not item:
continue
if os.sep in item or item.endswith(".json"):
charset_files.append(item)
else:
charset_names.append(item)
extra_ranges, dangerous = resolve_charsets(charset_names, charset_files)
return check_paths(args.files, extra_ranges=extra_ranges, dangerous=dangerous)
if args.command == "check-imports":
config = load_config()
base_package = args.base_package or config.get("base_package")
src_dir_str = args.src_dir or config.get("src_dir", "src")
src_dir = Path(src_dir_str)
if not base_package:
print(
"Error: --package is required (or set base_package in [tool.apdev])",
file=sys.stderr,
)
return 1
return check_circular_imports(src_dir, base_package=base_package)
if args.command == "release":
script = _get_release_script()
if not script.is_file():
print("Error: release.sh not found in package", file=sys.stderr)
return 1
cmd = ["bash", str(script)]
if args.yes:
cmd.append("--yes")
if args.version:
cmd.append(args.version)
result = subprocess.run(cmd, env={**os.environ})
return result.returncode
return 0