dcheng | ff84560 | 2016-09-23 18:56:19 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 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 | |
| 7 | This is a custom merge driver for git that helps automatically resolves |
| 8 | conflicts caused by clang-format changes. The conflict resolution |
| 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 |
| 11 | the remaining work to git merge-file. |
| 12 | |
| 13 | See https://git-scm.com/docs/gitattributes ("Defining a custom merge |
| 14 | driver") for more details. |
| 15 | """ |
| 16 | |
| 17 | import subprocess |
| 18 | import sys |
| 19 | |
| 20 | import clang_format |
| 21 | |
| 22 | |
| 23 | def main(): |
| 24 | if len(sys.argv) < 5: |
| 25 | print('usage: %s <base> <current> <others> <path in the tree>' % |
| 26 | sys.argv[0]) |
| 27 | sys.exit(1) |
| 28 | |
| 29 | base, current, others, file_name_in_tree = sys.argv[1:5] |
thakis | 9bd40a6 | 2016-10-01 01:39:15 | [diff] [blame] | 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 | |
dcheng | ff84560 | 2016-09-23 18:56:19 | [diff] [blame] | 39 | print 'Running clang-format 3-way merge driver on ' + file_name_in_tree |
| 40 | |
| 41 | try: |
| 42 | tool = clang_format.FindClangFormatToolInChromiumTree() |
| 43 | for fpath in base, current, others: |
| 44 | # Typically, clang-format is used with the -i option to rewrite files |
| 45 | # in-place. However, merge files live in the repo root, so --style=file |
| 46 | # will always pick up the root .clang-format. |
| 47 | # |
| 48 | # Instead, this tool uses --assume-filename so clang-format will pick up |
| 49 | # the appropriate .clang-format. Unfortunately, --assume-filename only |
| 50 | # works when the input is from stdin, so the file I/O portions are lifted |
| 51 | # up into the script as well. |
| 52 | with open(fpath, 'rb') as input_file: |
| 53 | output = subprocess.check_output( |
| 54 | [tool, '--assume-filename=%s' % file_name_in_tree, '--style=file'], |
| 55 | stdin=input_file) |
| 56 | with open(fpath, 'wb') as output_file: |
| 57 | output_file.write(output) |
| 58 | except clang_format.NotFoundError, e: |
| 59 | print e |
| 60 | print 'Failed to find clang-format. Falling-back on standard 3-way merge' |
| 61 | |
| 62 | return subprocess.call(['git', 'merge-file', '-Lcurrent', '-Lbase', '-Lother', |
| 63 | current, base, others]) |
| 64 | |
| 65 | |
| 66 | if __name__ == '__main__': |
| 67 | sys.exit(main()) |