pre-commit.py 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  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', '--ignore-submodules=dirty',
  23. 'HEAD')
  24. for line in diff.splitlines():
  25. path = line.split()[-1]
  26. if path == 'DEPS':
  27. has_deps_diff = True
  28. continue
  29. if line.startswith(':160000 160000'):
  30. staged_gitlinks.append(path)
  31. if not staged_gitlinks or has_deps_diff:
  32. exit(0)
  33. # There are staged gitlinks and DEPS wasn't changed. Get git_dependencies
  34. # migration state in DEPS.
  35. state = None
  36. try:
  37. with open('DEPS', 'r') as f:
  38. for l in f.readlines():
  39. if l.startswith('git_dependencies'):
  40. state = l.split()[-1].strip(' "\'')
  41. break
  42. except OSError:
  43. # Don't abort the commit if DEPS wasn't found.
  44. exit(0)
  45. if state != SYNC:
  46. # DEPS only has to be in sync with gitlinks when state is SYNC.
  47. exit(0)
  48. prompt = (
  49. f'Found no change to DEPS, but found staged gitlink(s) in diff:\n{diff}\n'
  50. 'Press Enter/Return if you intended to include them or "n" to unstage '
  51. '(exclude from commit) the gitlink(s): ')
  52. print(prompt)
  53. if os.getenv(TESTING_ANSWER) is not None:
  54. answer = os.getenv(TESTING_ANSWER)
  55. else:
  56. try:
  57. sys.stdin = open("/dev/tty", "r")
  58. except (FileNotFoundError, OSError):
  59. try:
  60. sys.stdin = open('CON')
  61. except:
  62. print(
  63. 'Unable to acquire input handle, proceeding without modifications'
  64. )
  65. exit(0)
  66. answer = input()
  67. disable_msg = f'To disable this hook, set {SKIP_VAR}=1'
  68. if answer.lower() == 'n':
  69. print(
  70. f'\nUnstaging {len(staged_gitlinks)} staged gitlink(s) found in diff'
  71. )
  72. git_common.run('restore', '--staged', '--', *staged_gitlinks)
  73. if len(staged_gitlinks) == len(diff.splitlines()):
  74. print(
  75. '\nFound no changes after unstaging gitlinks, aborting commit.')
  76. print(disable_msg)
  77. exit(1)
  78. print(disable_msg)
  79. if __name__ == "__main__":
  80. main()