Source code for scaffold_kit.init

"""Project initialization module.

This module provides functionality to initialize new projects by copying
example configuration and scaffold files from the scaffold_kit package.
It supports copying individual example files or all example files at once
to help users quickly set up their project structure.

Usage:
    To run this script, navigate to your project's root directory or parent
    directory and execute it as a module:

    # Copy all example files:
    $ uv run python -m scaffold_kit.init

    # Copy a specific example file:
    $ uv run python -m scaffold_kit.scaffold config-file
"""

from __future__ import annotations

import sys
import shutil
import argparse
import importlib.resources

from pathlib import Path
from typing import Optional


[docs] def init_project(example_name: Optional[str] = None) -> int: """Initialize a new project by copying example files. This function initializes a new project by copying example files from the scaffold_kit package. It can copy either a specific example file or all example files to the current working directory. Args: example_name: The name of the example file to copy. If None, all example files will be copied. Valid options include 'ignore-file', 'config-file', and 'scaffold-file'. Returns: Exit code: 0 for success, 1 if any errors occurred. Examples: Copy a specific example file: >>> init_project('config-file') Successfully copied '.scaffoldkitrc.yaml' to the current directory. 0 Copy all example files: >>> init_project() No example specified. Copying all example files... Successfully copied '.scaffoldignore' to the current directory. Successfully copied '.scaffoldkitrc.yaml' to the current directory. Successfully copied 'scaffold.yaml' to the current directory. 0 """ try: # Access the examples directory bundled with the package examples_path = importlib.resources.files("scaffold_kit").joinpath( "examples" ) # Define mapping of user-friendly names to actual file paths file_map = { "ignore-file": examples_path.joinpath(".scaffoldignore"), "config-file": examples_path.joinpath( # pylint: disable=too-many-function-args "configs", ".scaffoldkitrc.yaml" ), "scaffold-file": examples_path.joinpath( # pylint: disable=too-many-function-args "scaffold", "scaffold.yaml" ), } exit_code = 0 if example_name: # Copy specific file if example_name not in file_map: print( f"Error: Example file '{example_name}' not found.", file=sys.stderr, ) print("Available options:") for key in file_map: print(f" - {key}") return 1 source_path = file_map[example_name] destination_name = Path(source_path).name exit_code = _copy_file(source_path, destination_name) else: # Copy all files print("No example specified. Copying all example files...") for _, source_path in file_map.items(): destination_name = Path(source_path).name result = _copy_file(source_path, destination_name) if result != 0: exit_code = 1 return exit_code except Exception as e: # pylint: disable=broad-except print(f"Unexpected error accessing example files: {e}", file=sys.stderr) return 1
def _copy_file(source_path: Path, destination_name: str) -> int: """Copy a single file and handle errors gracefully. Args: source_path: Path to the source file destination_name: Name for the destination file Returns: Exit code: 0 for success, 1 for failure """ destination_path = Path.cwd() / destination_name try: # Check if destination already exists if destination_path.exists(): print( f"Warning: '{destination_name}' already exists, skipping.", file=sys.stderr, ) return 1 # Copy the file with importlib.resources.as_file(source_path) as source_file: shutil.copy2(source_file, destination_path) print( f"Successfully copied '{destination_name}' to the current " "directory." ) return 0 except PermissionError: print( f"Warning: Permission denied when copying '{destination_name}'.", file=sys.stderr, ) return 1 except OSError as e: print( f"Warning: Failed to copy '{destination_name}': {e}", file=sys.stderr, ) return 1 except Exception as e: # pylint: disable=broad-except print( f"Warning: Unexpected error copying '{destination_name}': {e}", file=sys.stderr, ) return 1
[docs] def main(): """Main entry point to run the init process. Parses command-line arguments and runs the init_project process. """ # 1. Create the argument parser. parser = argparse.ArgumentParser( description="Initialize a new project by copying example files." ) # 2. Add the optional target argument. parser.add_argument( "target", type=str, nargs="?", choices=["ignore-file", "config-file", "scaffold-file"], help="Target file to copy (optional). " "If not provided, all files will be copied.", ) args = parser.parse_args() # 3. Call the main scaffolding function with parsed arguments. exit_code = init_project(args.target) sys.exit(exit_code)
if __name__ == "__main__": main()