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