|
| 1 | +import argparse |
| 2 | +import shutil |
| 3 | +import sys |
| 4 | +from importlib import resources |
| 5 | +from pathlib import Path |
| 6 | + |
| 7 | + |
| 8 | +def scaffold(project_name: str, package_name: str, target: Path) -> None: |
| 9 | + with resources.as_file( |
| 10 | + resources.files("pyplatez").joinpath("templates") |
| 11 | + ) as tmpl_dir: |
| 12 | + shutil.copytree(tmpl_dir, target, dirs_exist_ok=True) |
| 13 | + |
| 14 | + old_pkg = target / "src" / "pyplatez" |
| 15 | + new_pkg = target / "src" / package_name |
| 16 | + if old_pkg.exists(): |
| 17 | + old_pkg.rename(new_pkg) |
| 18 | + |
| 19 | + pyproject = target / "pyproject.toml" |
| 20 | + if pyproject.exists(): |
| 21 | + text = pyproject.read_text() |
| 22 | + text = text.replace('name = "pyplatez"', f'name = "{project_name}"') |
| 23 | + text = text.replace( |
| 24 | + 'description = "minimalist python template for professional/hobbyist works"', |
| 25 | + 'description = "Add your description here"', |
| 26 | + ) |
| 27 | + pyproject.write_text(text) |
| 28 | + |
| 29 | + print(f" '{project_name}' ready at ./{target.name}") |
| 30 | + print(f" cd {target.name} && uv sync") |
| 31 | + |
| 32 | + |
| 33 | +def main() -> None: |
| 34 | + parser = argparse.ArgumentParser( |
| 35 | + prog="pyplatez", |
| 36 | + description="A batteries-included Python-starter project-template", |
| 37 | + ) |
| 38 | + sub = parser.add_subparsers(dest="command") |
| 39 | + |
| 40 | + init = sub.add_parser("init", help="Create a new project") |
| 41 | + init.add_argument("name", help="Project name") |
| 42 | + init.add_argument( |
| 43 | + "--path", default=None, help="Where to create it (default: ./<name>)" |
| 44 | + ) |
| 45 | + |
| 46 | + args = parser.parse_args() |
| 47 | + |
| 48 | + if args.command == "init": |
| 49 | + package_name = args.name.replace("-", "_") |
| 50 | + if not package_name.isidentifier(): |
| 51 | + print( |
| 52 | + f" Error: '{args.name}' cannot be normalized to a valid Python package name.", |
| 53 | + file=sys.stderr, |
| 54 | + ) |
| 55 | + sys.exit(1) |
| 56 | + |
| 57 | + target = Path(args.path) if args.path else Path.cwd() / args.name |
| 58 | + |
| 59 | + if target.exists(): |
| 60 | + if not target.is_dir(): |
| 61 | + print( |
| 62 | + f" Error: '{target}' already exists and is a file, not a directory.", |
| 63 | + file=sys.stderr, |
| 64 | + ) |
| 65 | + sys.exit(1) |
| 66 | + if any(target.iterdir()): |
| 67 | + print( |
| 68 | + f" Error: '{target}' already exists and is not empty.", |
| 69 | + file=sys.stderr, |
| 70 | + ) |
| 71 | + sys.exit(1) |
| 72 | + |
| 73 | + target.mkdir(parents=True, exist_ok=True) |
| 74 | + scaffold(args.name, package_name, target) |
| 75 | + else: |
| 76 | + parser.print_help() |
0 commit comments