diff --git a/clang_format_merge_driver b/clang_format_merge_driver new file mode 100755 index 000000000..8b7904946 --- /dev/null +++ b/clang_format_merge_driver @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +base_dir=$(dirname "$0") + +PYTHONDONTWRITEBYTECODE=1 exec python "$base_dir/clang_format_merge_driver.py" "$@" diff --git a/clang_format_merge_driver.bat b/clang_format_merge_driver.bat new file mode 100755 index 000000000..848724959 --- /dev/null +++ b/clang_format_merge_driver.bat @@ -0,0 +1,11 @@ +@echo off +:: Copyright 2016 The Chromium Authors. All rights reserved. +:: Use of this source code is governed by a BSD-style license that can be +:: found in the LICENSE file. +setlocal + +:: This is required with cygwin only. +PATH=%~dp0;%PATH% + +:: Defer control. +%~dp0python "%~dp0\clang_format_merge_driver.py" %* diff --git a/clang_format_merge_driver.py b/clang_format_merge_driver.py new file mode 100755 index 000000000..5f0449a28 --- /dev/null +++ b/clang_format_merge_driver.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +"""clang-format 3-way merge driver. + +This is a custom merge driver for git that helps automatically resolves +conflicts caused by clang-format changes. The conflict resolution +strategy is extremely simple: it simply clang-formats the current, +ancestor branch's, and other branch's version of the file and delegates +the remaining work to git merge-file. + +See https://git-scm.com/docs/gitattributes ("Defining a custom merge +driver") for more details. +""" + +import subprocess +import sys + +import clang_format + + +def main(): + if len(sys.argv) < 5: + print('usage: %s ' % + sys.argv[0]) + sys.exit(1) + + base, current, others, file_name_in_tree = sys.argv[1:5] + print 'Running clang-format 3-way merge driver on ' + file_name_in_tree + + try: + tool = clang_format.FindClangFormatToolInChromiumTree() + for fpath in base, current, others: + # Typically, clang-format is used with the -i option to rewrite files + # in-place. However, merge files live in the repo root, so --style=file + # will always pick up the root .clang-format. + # + # Instead, this tool uses --assume-filename so clang-format will pick up + # the appropriate .clang-format. Unfortunately, --assume-filename only + # works when the input is from stdin, so the file I/O portions are lifted + # up into the script as well. + with open(fpath, 'rb') as input_file: + output = subprocess.check_output( + [tool, '--assume-filename=%s' % file_name_in_tree, '--style=file'], + stdin=input_file) + with open(fpath, 'wb') as output_file: + output_file.write(output) + except clang_format.NotFoundError, e: + print e + print 'Failed to find clang-format. Falling-back on standard 3-way merge' + + return subprocess.call(['git', 'merge-file', '-Lcurrent', '-Lbase', '-Lother', + current, base, others]) + + +if __name__ == '__main__': + sys.exit(main())