pre-commit.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. #!/usr/bin/env python3
  2. # Copyright (c) 2023 The Chromium Authors. All rights reserved.
  3. # Use of this source code is governed by a BSD-style license that can be
  4. # found in the LICENSE file.
  5. """A git pre-commit hook to drop staged gitlink changes.
  6. To bypass this hook, set SKIP_GITLINK_PRECOMMIT=1.
  7. """
  8. import os
  9. import sys
  10. ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  11. sys.path.insert(0, ROOT_DIR)
  12. import git_common
  13. from gclient_eval import SYNC
  14. SKIP_VAR = 'SKIP_GITLINK_PRECOMMIT'
  15. TESTING_ANSWER = 'TESTING_ANSWER'
  16. def main():
  17. if os.getenv(SKIP_VAR) == '1':
  18. print(f'{SKIP_VAR} is set. Committing gitlinks, if any.')
  19. exit(0)
  20. has_deps_diff = False
  21. staged_gitlinks = []
  22. diff = git_common.run('diff-index', '--cached', 'HEAD')
  23. for line in diff.splitlines():
  24. path = line.split()[-1]
  25. if path == 'DEPS':
  26. has_deps_diff = True
  27. continue
  28. if line.startswith(':160000 160000'):
  29. staged_gitlinks.append(path)
  30. if not staged_gitlinks or has_deps_diff:
  31. exit(0)
  32. # There are staged gitlinks and DEPS wasn't changed. Get git_dependencies
  33. # migration state in DEPS.
  34. state = None
  35. try:
  36. with open('DEPS', 'r') as f:
  37. for l in f.readlines():
  38. if l.startswith('git_dependencies'):
  39. state = l.split()[-1].strip(' "\'')
  40. break
  41. except OSError:
  42. # Don't abort the commit if DEPS wasn't found.
  43. exit(0)
  44. if state != SYNC:
  45. # DEPS only has to be in sync with gitlinks when state is SYNC.
  46. exit(0)
  47. prompt = (
  48. f'Found no change to DEPS, but found staged gitlink(s) in diff:\n{diff}\n'
  49. 'Press Enter/Return if you intended to include them or "n" to unstage '
  50. '(exclude from commit) the gitlink(s): ')
  51. print(prompt)
  52. if os.getenv(TESTING_ANSWER) is not None:
  53. answer = os.getenv(TESTING_ANSWER)
  54. else:
  55. try:
  56. sys.stdin = open("/dev/tty", "r")
  57. except (FileNotFoundError, OSError):
  58. try:
  59. sys.stdin = open('CON')
  60. except:
  61. print(
  62. 'Unable to acquire input handle, proceeding without modifications'
  63. )
  64. exit(0)
  65. answer = input()
  66. disable_msg = f'To disable this hook, set {SKIP_VAR}=1'
  67. if answer.lower() == 'n':
  68. print(
  69. f'\nUnstaging {len(staged_gitlinks)} staged gitlink(s) found in diff'
  70. )
  71. git_common.run('restore', '--staged', '--', *staged_gitlinks)
  72. if len(staged_gitlinks) == len(diff.splitlines()):
  73. print(
  74. '\nFound no changes after unstaging gitlinks, aborting commit.')
  75. print(disable_msg)
  76. exit(1)
  77. print(disable_msg)
  78. if __name__ == "__main__":
  79. main()