import logging import subprocess import sys from pathlib import Path from typing import NoReturn logger = logging.getLogger(__name__) GIT_PATH = None try: GIT_PATH = subprocess.check_output(["/usr/bin/which", "git"], text=True).strip() except subprocess.CalledProcessError: # no git found in the system. # stop everything and exit. print a user-facing # message asking to install git. logger.error( "search_file_content error => git is not installed", ) sys.exit(1) def is_git_repo(repo: str) -> bool: """Spawn a shell and use git binary to test if current path is under git.""" def check_if_valid_repo(repo: str) -> bool: is_repo = subprocess.check_output( [GIT_PATH, "rev-parse", "--is-inside-work-tree"], text=True, cwd=repo ) is_repo = is_repo.strip() if is_repo == "true": return True elif is_repo == "false": return False else: logger.error(f"is-git-repo error => {is_repo} not a valid path") return False repo = Path(repo) if repo.exists(): if repo.is_dir(): return check_if_valid_repo(repo) else: logger.error(f"is-git-repo error => {repo} is not a directory") repo = repo.parent return check_if_valid_repo(repo) else: logger.error(f"is-git-repo error => {repo} is an invalid path") return False def git_ls_files( repo: str, pattern_matching: list[str], fullpath: bool = True ) -> list[Path]: """Return list of git-tracked filepaths from given repository path.""" filepaths = subprocess.check_output( [GIT_PATH, "ls-files", "--", *pattern_matching], text=True, cwd=repo ) filepaths = filepaths.strip().splitlines() if fullpath: filepaths = [Path(repo / filepath) for filepath in filepaths] return filepaths def git_is_file_tracked(repo: str, filepath: str) -> bool: """Check if given filepath is found by git ls-files -- command.""" matched = subprocess.check_output( [GIT_PATH, "ls-files", "--", filepath], text=True, cwd=repo ) is_tracked = True if matched.strip() == filepath else False return is_tracked def git_add_commit(repo: str, filepath: str, msg: str) -> NoReturn: """Spawn a shell and use git binary to perform `git add` and `git commit` on given , and with specificed commit . """ logger.info(f"git-add-commit... {repo, filepath, msg}") r = subprocess.run( f"{GIT_PATH} add '{filepath}' && {GIT_PATH} commit '{filepath}' -m '{msg}'", shell=True, cwd=repo, ) logger.info(f"git-add-commit result => {r.returncode, r.stdout, r.stderr}") def git_log_last_commit(repo: str): """Spawn a shell and run git binary to get the last commit from the git log of the given . """ filepaths = subprocess.check_output( [GIT_PATH, "log", "-1", "--pretty=format:%cd"], text=True, cwd=repo ) filepaths = filepaths.strip().splitlines() filepaths = [Path(repo / filepath) for filepath in filepaths] return filepaths def git_get_list_of_changed_filepaths_in_last_commit( repo: str, oldrev: str, newrev: str, pattern: list[str] ) -> tuple[str, str]: """Return list of git modified filepaths, filtered by image type. git diff --name-only .. """ filepaths = subprocess.check_output( [ GIT_PATH, "diff", "--name-only", oldrev, newrev, ], text=True, cwd=repo, ) filepaths = filepaths.strip().splitlines() filepaths = [filepath for filepath in filepaths if Path(filepath).suffix in pattern] return filepaths