Source code for scitex_git._init

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# File: /home/ywatanabe/proj/scitex-code/src/scitex/git/init.py

"""
Git initialization utilities.

Provides functions to initialize, find, and manage git repositories
with different strategies (child, parent, origin).
"""

from logging import getLogger
from pathlib import Path
from typing import Optional

from git import InvalidGitRepositoryError, Repo

logger = getLogger(__name__)


[docs] def find_parent_git(project_dir: Path) -> Optional[Path]: """ Find parent git repository by walking up directory tree. Args: project_dir: Starting directory to search from Returns: Path to parent git root, or None if not found """ try: repo_parent = Repo(project_dir.parent, search_parent_directories=True) return Path(repo_parent.git_dir).parent except InvalidGitRepositoryError: return None
[docs] def remove_child_git(project_dir: Path) -> bool: """ Remove project's local .git folder. When parent git is found, the project's own .git/ is redundant and should be removed to avoid nested git repository issues. Args: project_dir: Project directory containing .git to remove Returns: True if removed successfully or doesn't exist, False on error """ child_git = project_dir / ".git" if not child_git.exists(): logger.info(f"No child .git found at {project_dir}") return True try: import shutil logger.info("Removing child .git to use parent repository...") shutil.rmtree(child_git) logger.info(f"Removed child .git from {project_dir}") return True except PermissionError as e: logger.error(f"Permission denied removing .git from {project_dir}: {e}") return False except Exception as e: logger.error(f"Failed to remove child .git from {project_dir}: {e}") return False
[docs] def create_child_git(project_dir: Path) -> Optional[Path]: """ Create isolated git repository in project directory. Uses GitPython to initialize and make initial commit. Args: project_dir: Directory to initialize as git repo Returns: Path to git root (project_dir), or None on failure """ try: try: repo = Repo(project_dir) logger.info(f"Project is already a git repository at {project_dir}") # Optional structure validation: only runs if scitex-writer is # installed AND the project happens to follow the writer-tree # convention. If either is false, fall through quietly — the # repo itself is still valid. try: from scitex_writer._utils._verify_tree_structure import ( verify_tree_structure, ) verify_tree_structure(project_dir) except Exception as _verify_err: # ImportError: scitex-writer not installed. # ProjectValidationError / ValueError / OSError: project # doesn't follow the writer tree (config/, src/, ... etc). # All are non-fatal here — the repo itself is still valid; # tree validation is a writer-side concern. logger.debug(f"Optional verify_tree_structure skipped: {_verify_err}") return project_dir except InvalidGitRepositoryError: logger.info(f"Initializing new git repository at {project_dir}") repo = Repo.init(project_dir) repo.index.add(["."]) repo.index.commit("Initial commit from scitex template") logger.info(f"Git repository initialized at {project_dir}") return project_dir except PermissionError as e: logger.error(f"Permission denied creating git repository at {project_dir}: {e}") return None except OSError as e: logger.error(f"IO error creating git repository at {project_dir}: {e}") return None except Exception as e: logger.error(f"Failed to create child git repository at {project_dir}: {e}") return None
[docs] def init_git_repo( project_dir: Path, git_strategy: Optional[str] = "child" ) -> Optional[Path]: """ Initialize or detect git repository based on git_strategy. Args: project_dir: Project directory git_strategy: Git initialization strategy - None: Git disabled, returns None - 'child': Creates isolated git repo in project directory - 'parent': Tries to use parent git, degrades to 'child' if not found - 'origin': Preserves template's original git history (handled by clone) Returns: Path to git repository root, or None if disabled """ if git_strategy is None: logger.info("Git initialization disabled (git_strategy=None)") return None if git_strategy == "parent": logger.info("Using 'parent' git strategy, searching for parent repository...") parent_git = find_parent_git(project_dir) if parent_git: logger.info(f"Found parent git repository: {parent_git}") remove_child_git(project_dir) return parent_git logger.warning( f"No parent git repository found for {project_dir}. " f"Degrading to 'child' strategy (isolated git repo)." ) return create_child_git(project_dir) if git_strategy == "child": logger.info("Using 'child' git strategy, creating isolated repository...") return create_child_git(project_dir) if git_strategy == "origin": logger.info("Using 'origin' git strategy, template git history preserved...") try: repo = Repo(project_dir) logger.info(f"Found git repository at {project_dir}") return project_dir except InvalidGitRepositoryError: logger.warning( f"No git repository found at {project_dir}. " f"Degrading to 'child' strategy." ) return create_child_git(project_dir) raise ValueError( f"Unknown git_strategy: {git_strategy}. " f"Expected 'parent', 'child', 'origin', or None" )
__all__ = [ "find_parent_git", "remove_child_git", "create_child_git", "init_git_repo", ] # EOF