git.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import logging
  2. import subprocess
  3. import sys
  4. from pathlib import Path
  5. from typing import NoReturn
  6. logger = logging.getLogger(__name__)
  7. GIT_PATH = None
  8. try:
  9. GIT_PATH = subprocess.check_output(["/usr/bin/which", "git"], text=True).strip()
  10. except subprocess.CalledProcessError:
  11. # no git found in the system.
  12. # stop everything and exit. print a user-facing
  13. # message asking to install git.
  14. logger.error(
  15. "search_file_content error => git is not installed",
  16. )
  17. sys.exit(1)
  18. def is_git_repo(repo: str) -> bool:
  19. """Spawn a shell and use git binary to test if current path is under git."""
  20. def check_if_valid_repo(repo: str) -> bool:
  21. is_repo = subprocess.check_output(
  22. [GIT_PATH, "rev-parse", "--is-inside-work-tree"], text=True, cwd=repo
  23. )
  24. is_repo = is_repo.strip()
  25. if is_repo == "true":
  26. return True
  27. elif is_repo == "false":
  28. return False
  29. else:
  30. logger.error(f"is-git-repo error => {is_repo} not a valid path")
  31. return False
  32. repo = Path(repo)
  33. if repo.exists():
  34. if repo.is_dir():
  35. return check_if_valid_repo(repo)
  36. else:
  37. logger.error(f"is-git-repo error => {repo} is not a directory")
  38. repo = repo.parent
  39. return check_if_valid_repo(repo)
  40. else:
  41. logger.error(f"is-git-repo error => {repo} is an invalid path")
  42. return False
  43. def git_ls_files(
  44. repo: str, pattern_matching: list[str], fullpath: bool = True
  45. ) -> list[Path]:
  46. """Return list of git-tracked filepaths from given repository path."""
  47. filepaths = subprocess.check_output(
  48. [GIT_PATH, "ls-files", "--", *pattern_matching], text=True, cwd=repo
  49. )
  50. filepaths = filepaths.strip().splitlines()
  51. if fullpath:
  52. filepaths = [Path(repo / filepath) for filepath in filepaths]
  53. return filepaths
  54. def git_is_file_tracked(repo: str, filepath: str) -> bool:
  55. """Check if given filepath is found by git ls-files -- <filepath> command."""
  56. matched = subprocess.check_output(
  57. [GIT_PATH, "ls-files", "--", filepath], text=True, cwd=repo
  58. )
  59. is_tracked = True if matched.strip() == filepath else False
  60. return is_tracked
  61. def git_add_commit(repo: str, filepath: str, msg: str) -> NoReturn:
  62. """Spawn a shell and use git binary to perform `git add` and `git commit`
  63. on given <filepath>, and with specificed commit <msg>.
  64. """
  65. logger.info(f"git-add-commit... {repo, filepath, msg}")
  66. r = subprocess.run(
  67. f"{GIT_PATH} add '{filepath}' && {GIT_PATH} commit '{filepath}' -m '{msg}'",
  68. shell=True,
  69. cwd=repo,
  70. )
  71. logger.info(f"git-add-commit result => {r.returncode, r.stdout, r.stderr}")
  72. def git_log_last_commit(repo: str):
  73. """Spawn a shell and run git binary to get the last commit from the
  74. git log of the given <repo>.
  75. """
  76. filepaths = subprocess.check_output(
  77. [GIT_PATH, "log", "-1", "--pretty=format:%cd"], text=True, cwd=repo
  78. )
  79. filepaths = filepaths.strip().splitlines()
  80. filepaths = [Path(repo / filepath) for filepath in filepaths]
  81. return filepaths
  82. def git_get_list_of_changed_filepaths_in_last_commit(
  83. repo: str, oldrev: str, newrev: str, pattern: list[str]
  84. ) -> tuple[str, str]:
  85. """Return list of git modified filepaths, filtered by image type.
  86. git diff --name-only <oldrev>..<newrev>
  87. """
  88. filepaths = subprocess.check_output(
  89. [
  90. GIT_PATH,
  91. "diff",
  92. "--name-only",
  93. oldrev,
  94. newrev,
  95. ],
  96. text=True,
  97. cwd=repo,
  98. )
  99. filepaths = filepaths.strip().splitlines()
  100. filepaths = [filepath for filepath in filepaths if Path(filepath).suffix in pattern]
  101. return filepaths