clang_format_merge_driver.py 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. #!/usr/bin/env python3
  2. # Copyright 2016 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. """clang-format 3-way merge driver.
  6. This is a custom merge driver for git that helps automatically resolves
  7. conflicts caused by clang-format changes. The conflict resolution
  8. strategy is extremely simple: it simply clang-formats the current,
  9. ancestor branch's, and other branch's version of the file and delegates
  10. the remaining work to git merge-file.
  11. See https://git-scm.com/docs/gitattributes ("Defining a custom merge
  12. driver") for more details.
  13. """
  14. from __future__ import print_function
  15. import subprocess
  16. import sys
  17. import clang_format
  18. def main():
  19. if len(sys.argv) < 5:
  20. print('usage: %s <base> <current> <others> <path in the tree>' %
  21. sys.argv[0])
  22. sys.exit(1)
  23. # pylint: disable=unbalanced-tuple-unpacking
  24. base, current, others, file_name_in_tree = sys.argv[1:5]
  25. # pylint: enable=unbalanced-tuple-unpacking
  26. if file_name_in_tree == '%P':
  27. print(file=sys.stderr)
  28. print('ERROR: clang-format merge driver needs git 2.5+', file=sys.stderr)
  29. if sys.platform == 'darwin':
  30. print('Upgrade to Xcode 7.2+', file=sys.stderr)
  31. print(file=sys.stderr)
  32. return 1
  33. print('Running clang-format 3-way merge driver on ' + file_name_in_tree)
  34. try:
  35. tool = clang_format.FindClangFormatToolInChromiumTree()
  36. for fpath in base, current, others:
  37. # Typically, clang-format is used with the -i option to rewrite files
  38. # in-place. However, merge files live in the repo root, so --style=file
  39. # will always pick up the root .clang-format.
  40. #
  41. # Instead, this tool uses --assume-filename so clang-format will pick up
  42. # the appropriate .clang-format. Unfortunately, --assume-filename only
  43. # works when the input is from stdin, so the file I/O portions are lifted
  44. # up into the script as well.
  45. with open(fpath, 'rb') as input_file:
  46. output = subprocess.check_output(
  47. [tool, '--assume-filename=%s' % file_name_in_tree, '--style=file'],
  48. stdin=input_file)
  49. with open(fpath, 'wb') as output_file:
  50. output_file.write(output)
  51. except clang_format.NotFoundError as e:
  52. print(e)
  53. print('Failed to find clang-format. Falling-back on standard 3-way merge')
  54. return subprocess.call(['git', 'merge-file', '-Lcurrent', '-Lbase', '-Lother',
  55. current, base, others])
  56. if __name__ == '__main__':
  57. sys.exit(main())