Source code for foundry_dev_tools.utils.repo

"""This file provides helper function for git repos."""

from __future__ import annotations

import logging
import subprocess
import warnings
from pathlib import Path

from foundry_dev_tools.errors.meta import FoundryDevToolsError

LOGGER = logging.getLogger(__name__)


[docs] def get_repo(repo_dir: Path | None = None) -> tuple[str, str, str, Path]: """Get the repository RID of the current working directory. Args: repo_dir: the path to a (sub)directory of a git repo, otherwise current working directory Returns: tuple[str,str,str]: repo_rid,git_ref,git_revision_hash """ if git_dir := git_toplevel_dir(repo_dir, use_git=True): gradle_props = git_dir.joinpath("gradle.properties") if gradle_props.is_file(): try: with gradle_props.open("r") as gpf: for line in gpf.readlines(): if line.startswith("transformsRepoRid"): return ( line.split("=")[1].strip(), get_git_ref(git_dir), get_git_revision_hash(git_dir), git_dir, ) except Exception as e: msg = "Can't get repository RID from the gradle.properties file. Malformed file?" raise FoundryDevToolsError(msg) from e msg = "Can't get repository RID from the gradle.properties file. Is this really a foundry repository?" raise FoundryDevToolsError( msg, ) msg = "There is no gradle.properties file at the top of the git repository, can't get repository RID." raise FoundryDevToolsError( msg, ) msg = ( "If you don't provide a repository RID you need to be in a repository directory to detect what you want to" " build." ) raise FoundryDevToolsError( msg, )
[docs] def get_git_ref(git_dir: Path | None = None) -> str: """Get the branch ref in the supplied git directory. Args: git_dir: the path to a (sub)directory of a git repo, otherwise current working directory """ return ( subprocess.check_output( [ "git", "symbolic-ref", "HEAD", ], cwd=git_dir, ) .decode("ascii") .strip() )
[docs] def get_git_revision_hash(git_dir: Path | None = None) -> str: """Get the git revision hash. Args: git_dir: the path to a (sub)directory of a git repo, otherwise current working directory """ return ( subprocess.check_output( [ "git", "rev-parse", "HEAD", ], cwd=git_dir, ) .decode("ascii") .strip() )
[docs] def git_toplevel_dir(git_dir: Path | None = None, use_git: bool = False) -> Path | None: """Get git top level directory. Args: git_dir: the path to a (sub)directory of a git repo, otherwise current working directory use_git: if true call git executable with subprocess, otherwise use minimal python only implementation Returns: Path | None: the path to the toplevel git directory or None if nothing was found. """ if use_git: try: return Path( subprocess.check_output(["git", "rev-parse", "--show-toplevel"], cwd=git_dir).decode("utf-8").strip(), ) except subprocess.CalledProcessError: pass if git_dir is None: git_dir = Path.cwd() if git_dir.joinpath(".git").exists(): return git_dir for p in git_dir.resolve().parents: if p.joinpath(".git").exists(): return p return None
[docs] def get_branch(caller_filename: Path) -> str: """Get name of current checked out git branch as defined in the git HEAD file. Args: caller_filename (Path): Path of file that calls the function Returns: str: Name of checked out branch """ git_dir = git_toplevel_dir(caller_filename) if not git_dir: # fallback for VS Interactive Console # or Jupyter lab on Windows git_dir = Path.cwd() if git_dir.joinpath(".git").is_file(): # Infer branch from git submodule with git_dir.joinpath(".git").open() as gf: rel_submodule_git_dir = gf.read().strip().replace("gitdir: ", "") head_file = git_dir.joinpath(rel_submodule_git_dir, "HEAD").resolve() else: head_file = git_dir.joinpath(".git", "HEAD") if head_file.is_file(): with head_file.open() as hf: ref = hf.read().strip() if ref.startswith("ref: refs/heads/"): return ref[16:] return "HEAD" # immitate behaviour of `git rev-parse --abbrev-ref HEAD` warnings.warn("Could not detect git branch of project, falling back to 'master'.") return "master"