From c949118827afb549daa94fe3171b5e415bb32ea9 Mon Sep 17 00:00:00 2001 From: "ojan@google.com" Date: Tue, 2 Dec 2008 00:53:57 +0000 Subject: Add a wrapper around beyondcompare/kdiff3 so that it can be plugged into svn merge's diff3-cmd. Eventually, others can use this for other diff3 tools as well, they'll just need to add the right tweaks to support other tools. Review URL: http://codereview.chromium.org/11520 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@6192 0039d316-1c4b-4281-b951-d872f2087c98 --- webkit/tools/merge/diff3-wrapper.py | 104 ++++++++++++++++++++++++++++++++++++ webkit/tools/merge/merge.py | 32 +++++++---- 2 files changed, 127 insertions(+), 9 deletions(-) create mode 100755 webkit/tools/merge/diff3-wrapper.py diff --git a/webkit/tools/merge/diff3-wrapper.py b/webkit/tools/merge/diff3-wrapper.py new file mode 100755 index 0000000..50dc310 --- /dev/null +++ b/webkit/tools/merge/diff3-wrapper.py @@ -0,0 +1,104 @@ +#!/bin/env python +# Copyright (c) 2006-2008 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. + +"""Wrapper around BeyondCompare so it can be used as svn's diff3-cmd tool. + +The basic idea here is based heavily off of diffwrap.py at: +http://svnbook.red-bean.com/en/1.5/svn.advanced.externaldifftools.html#svn.advanced.externaldifftools.diff3.ex-1 +""" + +import optparse +import os +import subprocess +import sys + +CYGDRIVE = '/cygdrive/' +CYGLEN = len(CYGDRIVE) + +# TODO(ojan): Eventually make this a cross-platform script that makes it easy +# to use different diffing tools (an enum of tools maybe?). +# The difficulty is that each tool has its own supported arguments. +def EnsureWindowsPath(path): + """ Returns a Windows-style path given a Windows path or a cygwin path. + """ + if path.startswith(CYGDRIVE): + path = path[CYGLEN:CYGLEN + 1] + ':' + path[CYGLEN + 1:] + path = path.replace('/', '\\') + return path + +def GetPathToBinary(exe): + """ Try to find a copy of the binary that exists. Search for the full path + and then the basename. + """ + if not os.path.exists(exe): + exe = os.path.basename(exe) + return exe + +def main(args): + """ Provides a wrapper around 3rd-party diffing tools so they can be used as + the diff3-cmd in svn merge. + + args: The arguments passed by svn merge to its diff3 tool. + """ + # Grab the arguments from the end of the list since svn will add any other + # arguments provided before these. + + # The titles of the files being diffed. + title_mine = EnsureWindowsPath(args[-8]) + title_older = EnsureWindowsPath(args[-6]) + title_yours = EnsureWindowsPath(args[-4]) + + # The paths to the files being diffed. These will be temp files. + mine = EnsureWindowsPath(args[-3]) + older = EnsureWindowsPath(args[-2]) + yours = EnsureWindowsPath(args[-1]) + + # The command for which diff3 tool to use. + diff_tool = args[1] + + if diff_tool == "--use-beyondcompare": + exe = GetPathToBinary("/cygdrive/c/Progra~1/Beyond~1/BComp.exe") + cmd = [exe, + mine, + yours, + older, + mine, + '/reviewconflicts', + '/automerge', + '/leftreadonly', + '/rightreadonly', + '/ignoreunimportant', + '/lefttitle', title_mine, + '/righttitle', title_yours, + '/centertitle', title_older, + '/outputtitle', 'merged'] + elif diff_tool == "--use-kdiff3": + exe = GetPathToBinary("/cygdrive/c/Progra~1/KDiff3/kdiff3.exe") + cmd = [exe, + older, + mine, + yours, + "--merge", + "--auto", + "--output", mine] + else: + # TODO(ojan): Maybe fall back to diff3? + raise Exception, "Must specify a diff tool to use." + + value = subprocess.call(cmd, stdout=subprocess.PIPE) + + # After performing the merge, this script needs to print the contents + # of the merged file to stdout. + # Return an errorcode of 0 on successful merge, 1 if unresolved conflicts + # remain in the result. Any other errorcode will be treated as fatal. + merged_file_contents = open(mine).read() + # For reasons I don't understand, an extra line break gets added at the end + # of the file. Strip it. + merged_file_contents = merged_file_contents[:len(merged_file_contents)-1] + print merged_file_contents + sys.exit(value) + +if '__main__' == __name__: + main(sys.argv) \ No newline at end of file diff --git a/webkit/tools/merge/merge.py b/webkit/tools/merge/merge.py index e6cfd6b..afcd8bd 100755 --- a/webkit/tools/merge/merge.py +++ b/webkit/tools/merge/merge.py @@ -10,11 +10,12 @@ to find the repository and revision to merge from. Example usage: merge.py merge.py --new_revision 12345 - merge.py --diff3_cmd myfancydiffcommand.exe + merge.py --diff3-tool kdiff3 """ import optparse +import os import subprocess import xml.dom.minidom @@ -23,8 +24,11 @@ import google.path_utils class Merger(object): """ Does svn merges. """ + DIFF3_WRAPPER_PATH = os.path.join('..', '..', 'webkit', 'tools', 'merge', + 'diff3-wrapper.py') + def __init__(self, repository, webkit_root, old_revision, - new_revision, is_dry_run, diff3_cmd=None): + new_revision, is_dry_run, diff3_tool=None): """ Args: repository: the repository that we are merging to/from. @@ -34,14 +38,14 @@ class Merger(object): new_revision: the revision we are merging to. is_dry_run: whether to actually make changes or just print intended changes. - diff3_cmd: the tool for doing 3-way diffs. + diff3_tool: the tool for doing 3-way diffs. """ self._repository = repository self._webkit_root = webkit_root self._old_revision = old_revision self._new_revision = new_revision self._is_dry_run = is_dry_run - self._diff3_cmd = diff3_cmd + self._diff3_tool = diff3_tool def MergeDirectory(self, directory): """ Merges the given directory in the repository into the same directory @@ -50,9 +54,11 @@ class Merger(object): command = ["svn", "merge", "--accept", "edit", "-r", "%s:%s" % (self._old_revision, self._new_revision), "%s/%s" % (self._repository, directory), directory] - if self._diff3_cmd is not None: + if self._diff3_tool is not None: command.append("--diff3-cmd") - command.append(self._diff3_cmd) + command.append(self.DIFF3_WRAPPER_PATH) + command.append("-x") + command.append("--use-%s" % self._diff3_tool) print ' '.join(command) if not self._is_dry_run: #TODO(ojan): Check return code here. @@ -98,6 +104,10 @@ def UpdateWebKitMergeRevision(webkit_merge_revision_path, repository, #TODO(ojan): Check that the write suceeded. file.write(new_merge_revision) +def UpdateDeps(deps_path, new_revision, is_dry_run): + #TODO(ojan): Get this to update the revision of the appropriate bits in DEPS. + pass + def main(options, args): """ Does the merge and updates WEBKIT_MERGE_REVISION. @@ -114,6 +124,9 @@ def main(options, args): webkit_merge_revision_path = google.path_utils.FindUpward( google.path_utils.ScriptDir(), 'WEBKIT_MERGE_REVISION') + + deps_path = google.path_utils.FindUpward( + google.path_utils.ScriptDir(), 'DEPS') repository_and_revision = GetCurrentRepositoryAndRevision( webkit_merge_revision_path) @@ -129,17 +142,18 @@ def main(options, args): 'third_party', 'WebKit') merger = Merger(repository, webkit_root, old_revision, new_revision, - options.dry_run, options.diff3_cmd) + options.dry_run, options.diff3_tool) merger.MergeDirectory("JavaScriptCore") merger.MergeDirectory("WebCore") UpdateWebKitMergeRevision(webkit_merge_revision_path, repository, new_revision, options.dry_run) + UpdateDeps(deps_path, new_revision, options.dry_run) if '__main__' == __name__: option_parser = optparse.OptionParser() - option_parser.add_option("", "--diff3-cmd", default=None, - help="Optional. Path to 3-way diff tool.") + option_parser.add_option("", "--diff3-tool", default=None, + help="Optional. diff3 tool to use. Can be 'kdiff3' or 'beyondcompare'") option_parser.add_option("", "--new-revision", default=None, help="Optional. Revision to merge to. Tip of tree " "revision will be used if omitted.") -- cgit v1.1