Skip to content

Instantly share code, notes, and snippets.

@yeiichi
Last active April 17, 2025 00:38
Show Gist options
  • Save yeiichi/18d9cb1adb634d5f24b469241acd3b01 to your computer and use it in GitHub Desktop.
Save yeiichi/18d9cb1adb634d5f24b469241acd3b01 to your computer and use it in GitHub Desktop.
Quickstart script for generic project directories with Sphinx documentation.
#!/usr/bin/env python3
"""
Quickstart script for Generic project.
This Python script, `pj_quickstart.py`, automates the creation of a generic
project directory structure. It also integrates Sphinx documentation and
performs additional configuration tasks.
"""
import argparse
import shutil
import subprocess
from pathlib import Path
# Constants
PROJECT_ROOT = Path(__file__).resolve().parent
TEMPLATE_DIR = PROJECT_ROOT / 'templates'
PJ_REPO_TEMPLATE = TEMPLATE_DIR / 'pj_repo_tmpl'
CWD = Path.cwd()
COLOR_YELLOW = '\033[93m'
COLOR_END = '\033[0m'
AUTHOR = 'Your Name'
# Directory names
SUB_DIR_01 = 'specifications'
SUB_DIR_02 = 'contracts'
SUB_DIR_03 = 'schedule'
SUB_DIR_04 = 'meetings'
SUB_DIR_05 = 'deliverables'
SUB_DIR_06 = 'references'
SUB_DIR_07 = 'miscellaneous'
SUB_DIR_DOCS_SOURCE = 'docs/source'
def create_project_directory(dst_dir: Path) -> None:
"""
Create a new project directory by copying a template directory.
Copies the contents of a predefined repository template directory to the specified
destination directory. Ensures the destination directory is newly created and does
not already exist. Outputs a message to indicate the location of the newly created
project.
Arguments:
dst_dir (Path): The destination path where the new project directory will be
created.
Returns:
None
"""
shutil.copytree(PJ_REPO_TEMPLATE, dst_dir, dirs_exist_ok=False)
print(f'{COLOR_YELLOW}Project created at {dst_dir}{COLOR_END}')
def create_symlink(src_dir: Path, alias_dir: Path) -> None:
alias_dir.symlink_to(src_dir, target_is_directory=True)
print(f'Symlink created at {alias_dir}.')
def get_directory_aliases(project_dir: Path) -> dict[Path, Path]:
"""
Returns a mapping of source directories to their corresponding alias directories.
"""
aliases = {
project_dir / SUB_DIR_01: project_dir / SUB_DIR_DOCS_SOURCE / SUB_DIR_01,
project_dir / SUB_DIR_02: project_dir / SUB_DIR_DOCS_SOURCE / SUB_DIR_02,
project_dir / SUB_DIR_03: project_dir / SUB_DIR_DOCS_SOURCE / SUB_DIR_03,
project_dir / SUB_DIR_04: project_dir / SUB_DIR_DOCS_SOURCE / SUB_DIR_04,
project_dir / SUB_DIR_05: project_dir / SUB_DIR_DOCS_SOURCE / SUB_DIR_05,
project_dir / SUB_DIR_06: project_dir / SUB_DIR_DOCS_SOURCE / SUB_DIR_06,
project_dir / SUB_DIR_07: project_dir / SUB_DIR_DOCS_SOURCE / SUB_DIR_07,
}
return {source.resolve(): alias.resolve() for source, alias in aliases.items()}
def setup_sphinx_directories(parent_dir: Path, project_name: str):
print(f'{COLOR_YELLOW}\nCreating Sphinx directories.{COLOR_END}')
subprocess.run(
['sphinx-quickstart', 'docs', '-q', '--sep', '-p', project_name, '-a', AUTHOR],
cwd=parent_dir
)
def insert_line(file_path, target_line_number, text_to_insert):
lines = file_path.read_text().splitlines()
lines.insert(target_line_number, text_to_insert)
file_path.write_text("\n".join(lines) + "\n")
def main():
# Parse command-line arguments.
parser = argparse.ArgumentParser(
prog='pj_quickstart',
description='Quickstart Generic project')
parser.add_argument('project_name', help='Name of the project')
args = parser.parse_args()
# Set up project directory
project_name = args.project_name
project_dir = CWD / project_name
create_project_directory(project_dir)
# Create symlinks using alias mapping.
alias_map = get_directory_aliases(project_dir)
for source, alias in alias_map.items():
create_symlink(source, alias)
# Setup Sphinx directories.
setup_sphinx_directories(project_dir, project_name)
# Modify Sphinx toctree in the top level index.rst.
insert_line(
project_dir / SUB_DIR_DOCS_SOURCE / 'index.rst',
12,
f'''\
{SUB_DIR_01}/index
{SUB_DIR_02}/index
{SUB_DIR_03}/index
{SUB_DIR_04}/index
{SUB_DIR_05}/index
{SUB_DIR_06}/index
{SUB_DIR_07}/index''')
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment