diff options
author | tc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-08 18:08:24 +0000 |
---|---|---|
committer | tc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-08 18:08:24 +0000 |
commit | 84ca6b797d24c6f82b012e48d6d9793670a84181 (patch) | |
tree | 727b7e40206c065613889cd5807fa36704f32d40 | |
parent | 6c1abbc64be2d15f179e7941ba979aa2e6d23045 (diff) | |
download | chromium_src-84ca6b797d24c6f82b012e48d6d9793670a84181.zip chromium_src-84ca6b797d24c6f82b012e48d6d9793670a84181.tar.gz chromium_src-84ca6b797d24c6f82b012e48d6d9793670a84181.tar.bz2 |
Get rid of WEBKIT_MERGE_REVISION, it's already behind the real
revision from the DEPS file.
Review URL: http://codereview.chromium.org/113153
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15652 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | WEBKIT_MERGE_REVISION | 1 | ||||
-rw-r--r-- | webkit/tools/merge/diff3-wrapper.bat | 10 | ||||
-rwxr-xr-x | webkit/tools/merge/diff3-wrapper.py | 127 | ||||
-rwxr-xr-x | webkit/tools/merge/gen-merge-diff.sh | 98 | ||||
-rw-r--r-- | webkit/tools/merge/merge.bat | 1 | ||||
-rwxr-xr-x | webkit/tools/merge/merge.py | 205 | ||||
-rwxr-xr-x | webkit/tools/merge/merge.sh | 19 | ||||
-rwxr-xr-x | webkit/tools/merge/update-branch-webkit.py | 750 |
8 files changed, 0 insertions, 1211 deletions
diff --git a/WEBKIT_MERGE_REVISION b/WEBKIT_MERGE_REVISION deleted file mode 100644 index 215e846..0000000 --- a/WEBKIT_MERGE_REVISION +++ /dev/null @@ -1 +0,0 @@ -http://svn.webkit.org/repository/webkit/trunk@43371
\ No newline at end of file diff --git a/webkit/tools/merge/diff3-wrapper.bat b/webkit/tools/merge/diff3-wrapper.bat deleted file mode 100644 index a818f4e..0000000 --- a/webkit/tools/merge/diff3-wrapper.bat +++ /dev/null @@ -1,10 +0,0 @@ -@ECHO off - -:: 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 diff3-wrapper.py so it can be called from svn. - -%~dp0\..\..\..\third_party\python_24\python %~dp0diff3-wrapper.py %* -exit /B %ERRORLEVEL% diff --git a/webkit/tools/merge/diff3-wrapper.py b/webkit/tools/merge/diff3-wrapper.py deleted file mode 100755 index 2d0f0e2..0000000 --- a/webkit/tools/merge/diff3-wrapper.py +++ /dev/null @@ -1,127 +0,0 @@ -#!/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 or kdiff3 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 -import traceback - -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("c:/Progra~1/Beyond~1/BComp.exe") - if not os.path.exists(exe): - exe = GetPathToBinary("c:/Progra~2/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("c:/Progra~1/KDiff3/kdiff3.exe") - if not os.path.exists(exe): - exe = GetPathToBinary("c:/Progra~2/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." - - try: - # Work around http://bugs.python.org/issue3905 - # by passing stderr and stdin as well since beyondcompare is a GUI app - return_code = subprocess.call(cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - stdin=subprocess.PIPE, - shell=True) - except Exception,e: - print "Error running " + (" ".join(cmd)) - traceback.print_exc(file=sys.stdout) - - # 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[:-1] - print merged_file_contents - return return_code - -if '__main__' == __name__: - try: - return_code = main(sys.argv) - except Exception,e: - traceback.print_exc(file=sys.stdout) - # diff3 uses '1' to mean "conflict" and 2 to mean "I barfed". - sys.exit(2) # return "I barfed" - sys.exit(return_code) diff --git a/webkit/tools/merge/gen-merge-diff.sh b/webkit/tools/merge/gen-merge-diff.sh deleted file mode 100755 index 10aa0fb..0000000 --- a/webkit/tools/merge/gen-merge-diff.sh +++ /dev/null @@ -1,98 +0,0 @@ -#!/bin/sh -# -# Copyright 2007 Google Inc. -# All rights reserved. -# -# This script expects to live in chrome/tools/branch/. If it's ever moved, -# the value of |root| will need to be changed below. -# -# Generate a helper script that does a 3-way diff on each forked WebKit file -# you give it. The diff will be among: -# base: original third_party file from a Chrome trunk checkout -# diff1: updated third_party file from the merge branch -# diff2: forked file in webkit/pending or wherever. -# -# Run this script from the merge branch. Give it the path to the root of your -# trunk checkout (the directory containing src and data directories) as the -# first argument, and a list of forked files (e.g. from either copy of -# webkit/pending/) as the second argument. -# -# Example usage: -# ./gen-merge-diff.sh /cygdrive/c/src/chrome/trunk webkit/pending/*.* -# -# Once the helper script is generated, you can run it to do the 3-way diff. - -wkfilelist=/tmp/webkit-branch-merge/third_party_list.txt - -execdir=`dirname $0` -root=$execdir/../.. - -origtrunk=$1 -origroot=$origtrunk -shift - -if [[ $# -lt 1 || ! -d "$origroot/third_party" ]]; then - echo "Usage: $0 <path-to-the-base-dir-of-chrome-trunk> [list-of-forked-files]" - echo "Example: $0 /cygdrive/c/src/chrome/trunk webkit/pending/*.*" - exit 1 -fi - -if which p4merge.exe >& /dev/null; then - merge_exe=p4merge.exe -else - merge_exe="/cygdrive/c/Program Files/Perforce/p4merge.exe" - if [ ! -e "$merge_exe" ]; then - echo "WARNING: It looks like you don't have p4merge installed." - echo "You must edit merge-diff.sh and change the diff3way function to" - echo "point at a valid merge tool." - fi -fi - -if [ -e $wkfilelist ]; then - echo "Using cached file listing of third_party." - echo "WARNING: If the cached file is not up to date, you should execute:" - echo " rm $wkfilelist" - echo "and run this script again." -else - echo "Creating file listing of third_party..." - (cd $root && find third_party -type f | grep -v '/\.svn' | grep -v 'ForwardingHeaders' | grep -v 'DerivedSources' > $wkfilelist) -fi - -# Prepare the helper script. - -cat > merge-diff.sh <<EOF -#!/bin/sh - -function diff3way { - a=\`cygpath -wa \$1\` - b=\`cygpath -wa \$2\` - c=\`cygpath -wa \$3\` - "$merge_exe" "\$a" "\$b" "\$c" "\$c" -} - -EOF - -chmod +x merge-diff.sh - -# Now add all the diff commands to the helper script. - -for each in "$@"; do - filename=`echo $each | sed -e "s,.*/,,g"` - tpfile=`grep "/\<$filename\>" $wkfilelist` - if [ "$tpfile" != "" ]; then - # Only run the 3-way diff if the upstream file has changed - ignored=`diff "$origroot/$tpfile" "$root/$tpfile"` - if [ $? != 0 ]; then - echo "diff3way \"$origroot/$tpfile\" \"$root/$tpfile\" \"$each\"" >> merge-diff.sh - fi - fi -done - -cat << EOF - -====================== -Created: merge-diff.sh - -Please edit this file to make sure it is correct. Then run it with -'./merge-diff.sh'. -EOF diff --git a/webkit/tools/merge/merge.bat b/webkit/tools/merge/merge.bat deleted file mode 100644 index 4168144..0000000 --- a/webkit/tools/merge/merge.bat +++ /dev/null @@ -1 +0,0 @@ -@..\..\..\third_party\python_24\python.exe merge.py %*
diff --git a/webkit/tools/merge/merge.py b/webkit/tools/merge/merge.py deleted file mode 100755 index 2736253..0000000 --- a/webkit/tools/merge/merge.py +++ /dev/null @@ -1,205 +0,0 @@ -#!/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. - -"""Does a webkit merge to tip of tree WebKit or a revision -specified on the command line. Looks at trunk/src/WEBKIT_MERGE_REVISION -to find the repository and revision to merge from. - -Example usage: - merge.py - merge.py --new_revision 12345 - merge.py --diff3-tool kdiff3 - -""" - -import optparse -import os -import re -import subprocess -import sys -import xml.dom.minidom - -import google.path_utils - -class Merger(object): - """ Does svn merges. """ - - DIFF3_WRAPPER_PATH = os.path.join('..', '..', 'webkit', 'tools', 'merge', - 'diff3-wrapper.bat') - - def __init__(self, repository, webkit_root, old_revision, - new_revision, is_dry_run, svn_path='svn', diff3_tool=None): - """ - Args: - repository: the repository that we are merging to/from. - webkit_root: path to third_party/WebKit directory in which to run svn - commands. - old_revision: the revision we are currently merged to. - new_revision: the revision we are merging to. - is_dry_run: whether to actually make changes or just print intended - changes. - svn_path: the path to the svn executable (or find it in the user's path) - 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_tool = diff3_tool - self._svn = svn_path - - def MergeDirectory(self, directory): - """ Merges the given directory in the repository into the same directory - in the working copy. - """ - command = [self._svn, "merge", "--accept", "edit", "-r", - "%s:%s" % (self._old_revision, self._new_revision), - "%s/%s" % (self._repository, directory), directory] - if self._diff3_tool is not None: - command.append("--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: - returncode = subprocess.call(command, cwd=self._webkit_root, shell=True) - if returncode != 0: - raise "Are you sure you're running SVN 1.5? svn --version to check" - - # On Windows, find modified files and force them to LF. We trust dos2unix - # not to change binary files. - if sys.platform == 'win32': - command = [self._svn, "status", "--xml", directory] - print ' '.join(command) - info = subprocess.Popen(command, cwd=self._webkit_root, shell=True, - stdout=subprocess.PIPE).communicate()[0] - dom = xml.dom.minidom.parseString(info) - for entry in dom.getElementsByTagName("entry"): - file_path = entry.getAttribute("path") - type = os.path.splitext(file_path)[-1] - status = (entry.getElementsByTagName('wc-status')[0] - .getAttribute('item')) - # TODO(pamg): Is this the same in non-English svn? - if status == "modified": - command = ["dos2unix.exe", file_path] - if self._is_dry_run: - print ' '.join(command) - else: - subprocess.call(command, cwd=self._webkit_root, shell=True) - - -def GetCurrentRepositoryAndRevision(webkit_merge_revision_path): - """ Gets the repository and revision we're currently merged to according to - the WEBKIT_MERGE_REVISION file checked in. - - Args: - webkit_merge_revision_path: path to WEBKIT_MERGE_REVISION file. - """ - contents = open(webkit_merge_revision_path).read().strip() - split_contents = contents.split("@") - return {'repository': split_contents[0], 'old_revision': split_contents[1]} - -def GetTipOfTreeRevision(svn, repository): - """ Gets the tip-of-tree revision for the repository. - """ - info = subprocess.Popen([svn, "info", "--xml", repository], - shell=True, - stdout=subprocess.PIPE).communicate()[0] - dom = xml.dom.minidom.parseString(info) - return dom.getElementsByTagName('entry')[0].getAttribute('revision') - -def UpdateWebKitMergeRevision(webkit_merge_revision_path, repository, - new_revision, is_dry_run): - """ Updates the checked in WEBKIT_MERGE_REVISION file with the repository - and revision we just merged to. - - Args: - webkit_merge_revision_path: path to WEBKIT_MERGE_REVISION file. - repository: repository we've merged to. - new_revision: revision we've merged to. - is_dry_run: whether to update the file or just print out the update that - would be done. - """ - new_merge_revision = "%s@%s" % (repository, new_revision) - if is_dry_run: - print "%s=%s" % (webkit_merge_revision_path, new_merge_revision) - else: - print "Updating %s" % webkit_merge_revision_path - #TODO(ojan): Check that the write suceeded. - open(webkit_merge_revision_path, "w").write(new_merge_revision) - -def UpdateDeps(deps_path, new_revision, is_dry_run): - contents = open(deps_path).read() - path = '"webkit_revision": "' - pattern = re.compile(path + "\d+") - contents = pattern.sub(path + str(new_revision), contents) - if is_dry_run: - print "%s=%s" % (deps_path, contents) - else: - print "Updating %s" % deps_path - open(deps_path, "w").write(contents) - -def Sync(is_dry_run): - sync_command = ["gclient", "sync"] - if is_dry_run: - print ' '.join(sync_command) - else: - returncode = subprocess.call(sync_command, shell=True) - if returncode != 0: - raise "gclient sync failed, go beat darin with a squishy bat." - -def main(options, args): - """ Does the merge and updates WEBKIT_MERGE_REVISION. - - Args: - options: a dictionary of commandline arguments. - args: currently unused. - """ - Sync(options.dry_run) - - webkit_merge_revision_path = google.path_utils.FindUpward( - google.path_utils.ScriptDir(), 'WEBKIT_MERGE_REVISION') - - repository_and_revision = GetCurrentRepositoryAndRevision( - webkit_merge_revision_path) - repository = repository_and_revision['repository'] - old_revision = repository_and_revision['old_revision'] - - if options.new_revision: - new_revision = options.new_revision - else: - new_revision = GetTipOfTreeRevision(options.svn, repository) - - webkit_root = google.path_utils.FindUpward(google.path_utils.ScriptDir(), - 'third_party', 'WebKit') - - merger = Merger(repository, webkit_root, old_revision, new_revision, - options.dry_run, options.svn, options.diff3_tool) - merger.MergeDirectory("WebCore") - merger.MergeDirectory("JavaScriptCore") - - UpdateWebKitMergeRevision(webkit_merge_revision_path, repository, - new_revision, options.dry_run) - deps_path = google.path_utils.FindUpward( - google.path_utils.ScriptDir(), 'src', 'DEPS') - UpdateDeps(deps_path, new_revision, options.dry_run) - Sync(options.dry_run) - -if '__main__' == __name__: - option_parser = optparse.OptionParser() - 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.") - option_parser.add_option("", "--dry-run", action="store_true", default=False, - help="Print out actions the merge would take, but " - "don't actually do them.") - option_parser.add_option("", "--svn", default="svn", - help="Path to svn executable, if it's not in your " - "PATH.") - options, args = option_parser.parse_args() - main(options, args) diff --git a/webkit/tools/merge/merge.sh b/webkit/tools/merge/merge.sh deleted file mode 100755 index c0e6a30..0000000 --- a/webkit/tools/merge/merge.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -exec_dir=$(dirname $0) - -if [ "$OSTYPE" = "cygwin" ]; then - system_root=`cygpath "$SYSTEMROOT"` - PATH="/usr/bin:$system_root/system32:$system_root:$system_root/system32/WBEM:$PATH" - export PATH - PYTHON_PROG="$exec_dir/../../../third_party/python_24/python.exe" -else - PYTHON_PROG=python - # When not using the included python, we don't get automatic site.py paths. - # Specifically, run_webkit_tests needs the paths in: - # third_party/python_24/Lib/site-packages/google.pth - PYTHONPATH="$(readlink -f ${exec_dir}/../../../tools/python):$PYTHONPATH" - export PYTHONPATH -fi - -"$PYTHON_PROG" "$exec_dir/merge.py" "$@" diff --git a/webkit/tools/merge/update-branch-webkit.py b/webkit/tools/merge/update-branch-webkit.py deleted file mode 100755 index 09fbd63..0000000 --- a/webkit/tools/merge/update-branch-webkit.py +++ /dev/null @@ -1,750 +0,0 @@ -#!/usr/bin/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. - -""" -Update a copy of WebKit to a given version, issuing the necessary gvn commands. - - -This script is intended for internal use only, by knowledgeable users, and -therefore does not taint-check user-supplied values. - -Cygwin is required to run this script, for 'cygpath'. - -Only tested on Windows, running in Cygwin. Most of this script should -be compatible with Linux as well. The paths may not be correct for -running in a Windows cmd shell. - -TODO(pamg): Test in Windows cmd shell and fix problems. - -Usage notes: - In normal usage, it's expected that the user will first run svn manually - to update a local copy of the WebKit trunk to a known (or head) revision. - The svn checkout is prone to odd failures (network timeouts, etc.), so - it's safer to run it by hand so you can more easily notice and recover - from any problems. Note that if you're running svn more than once, to - update more than one directory, you'll want to specify a --revision (-r) - on any calls after the first, just in case someone's landed something - while you were checking out the first directory. - For example: - - cd /tmp/webkit-branch-merge/WebKit - svn co http://svn.webkit.org/repository/webkit/trunk/WebCore WebCore - [...Checked out revision 19776.] - svn co -r 19776 \ - http://svn.webkit.org/repository/webkit/trunk/JavaScriptCore \ - JavaScriptCore - cd /path/to/webkit/tools/merge - python ./update-branch-webkit.py --diff --real \ - --old /path/to/mergebranch/ 19776 - - Here the --old parameter points to the root of your merge branch checkout, - containing the src/ and data/ directories. You can also append - --new [directory name] to point to the directory where you've checked out - the latest webkit files (if you checked them out to somewhere other than - /tmp/webkit-branch-merge/WebKit as depicted above). The --new parameter - should be a "WebKit" directory that corresponds to the webkit svn trunk. - - If you want to see what the script will do before doing it, remove the - --real option. When you're satisfied that it's doing the right thing, you - can restore --real and run it one more time. In that case, you can also - leave off --diff on each run after the first, allowing the script to use a - cached file of diffs rather than re-generating it each time. Other options - are available as well; see 'update-branch-webkit --help' for a full list. - - Directories may be specified with Windows-style paths, but the slashes - must be forward-slashes, not backslashes, or the Cygwin shell will remove - them. -""" - -import errno -import logging -import optparse -import os -import re -import shutil -import subprocess -import sys -import traceback - -# Whether to produce additional debugging information. -DEBUGGING = False - -# The filename holding the new WebKit Subversion revision number. -BASE_REV_FILE = 'BASE_REVISION' - -# The URL from which to checkout the new revision if needed. -SVN_URL = 'http://svn.webkit.org/repository/webkit/trunk' - -# The files in which to save lists of added, deleted, and edited files. -SAVE_ADDED_FILES = 'merge-add-files.txt' -SAVE_DELETED_FILES = 'merge-delete-files.txt' -SAVE_EDITED_FILES = 'merge-edit-files.txt' -SAVE_OBSOLETE_FILES = 'merge-obsolete-files.txt' - -# Executable names, found in the system PATH. -SVN = 'svn.exe' -DIFF = 'diff.exe' -CYGPATH = 'cygpath.exe' - -# Directories to be entirely ignored when updating the merge branch. -IGNORE_DIRS = ['.svn', 'DerivedSources'] - -# Global cygpath process. -_cygpath_proc = None - -######################################## -# Error classes - -class LocalError(Exception): - """Base class for local errors.""" - stack_trace = True - code = 1 - -class ArgumentError(LocalError): - """Exception raised for errors in parsed script arguments.""" - stack_trace = False - code = 2 - -class CannotFindError(LocalError): - """Exception raised for an expected file or directory that does not exist.""" - def __init__(self, description, path): - LocalError.__init__(self, "Can't find %s '%s'" % (description, path)) - stack_trace = False - code = 3 - -class CannotWriteError(LocalError): - """Exception raised when writing to a necessary file fails.""" - def __init__(self, path): - LocalError.__init__(self, "Can't write to '%s'" % path) - stack_trace = False - code = 4 - -class CommandError(LocalError): - """Exception raised when an external command fails.""" - def __init__(self, prefix, value): - """ - Build a descriptive error message using available information. - - Args: - prefix: Descriptive text prepended to the error message. - value: Error value as provided in the exception, if any. May be None. - """ - if value is not None: - (errnum, message) = value - LocalError.__init__(self, "%s: %s (%s)" % (prefix, message, errnum)) - else: - LocalError.__init__(self, prefix) - stack_trace = False - code = 5 - - -######################################## -# Utility functions - -def GetAbsolutePath(path): - """Convert an unknown-style path to an absolute, mixed-style Windows path. - - We use an external cygpath binary to do the conversion. For performance - reasons, we use a single cygpath process. - """ - global _cygpath_proc - if not _cygpath_proc: - _cygpath_proc = subprocess.Popen([CYGPATH, '-a', '-m', '-f', '-'], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE) - _cygpath_proc.stdin.write(path + '\n') - return _cygpath_proc.stdout.readline().rstrip() - -def PathFromChromeRoot(subdir): - """Return the path of the given WebKit path relative to the Chrome merge dir. - - We could get fancy and search for these, but it's so much simpler to just - set them, it's arguably even easier to maintain that way. - - Args: - subdir: The relative path to be converted. It may be a directory or a - filename, and it should be specified relative to the WebKit checkout - (e.g., 'WebCore'). - - Returns: - The path to the given subdirectory dir in the Chrome webkit tree, starting - from the src directory. - """ - return os.path.join('third_party', subdir) - -def NewDir(subdir=''): - """Return an absolute path to the subdirectory within the WebKit checkout. - - The subdir is specified relative to the WebKit checkout (e.g., 'WebCore'). - """ - return GetAbsolutePath(os.path.join(options.new, subdir)) - -def OldDir(subdir=''): - """Return an absolute path to the given subdirectory within the merge branch. - - The subdir is specified relative to the WebKit checkout (e.g., 'WebCore'). - """ - reldir = PathFromChromeRoot(subdir) - return GetAbsolutePath(os.path.join(options.old, reldir)) - -def TempDir(relative_path=''): - """Return an absolute path to the given location in the temp directory.""" - return GetAbsolutePath(os.path.join(options.temp_dir, relative_path)) - -def CollectFileList(search_dir, old): - """Recursively collect a set of files within the given directory. - - FIXME(pamg): This function assumes that there are no instances of the string - given by the search_dir argument in either of the source paths (old and - new). That is, if dir is 'WebCore', the --old and --new options must not - contain the string 'WebCore'. - - Args: - search_dir: The directory within which to search. It should be specified - relative to the WebKit checkout (e.g., 'WebCore'). - old: Boolean value indicating whether to look for files in the old - directory (i.e., the Chrome merge branch) or the new one (the WebKit - checkout). - - Returns: - A set of file paths relative to (and including) the given dir, with no - leading slash. - """ - # FIXME(pamg): This replacement is why --old and --new can't contain - # search_dir. - if old: - path = OldDir(search_dir) - basedir = path.replace(search_dir, '') - else: - path = NewDir(search_dir) - basedir = path.replace(search_dir, '') - - result = set() - for root, dirs, files in os.walk(path): - # We want the directory from search_dir onward, and we need '/' separators - # to match what diff returns. - relative_dir = root.replace(basedir, '', 1).replace('\\', '/') - for filename in files: - if not IgnoreFile(root): - result.add('/'.join([relative_dir, filename])) - return result - -def MakeDirectory(path): - """Create a path and its parents, returning a set of the paths created.""" - - logging.debug('Making directory %s' % path) - add = set() - (basepath, subdir) = os.path.split(path) - if not os.path.exists(basepath): - add = add.union(MakeDirectory(basepath)) - if options.real: - os.mkdir(path) - add.add(path) - return add - -def IsAvailable(executable): - """Return True if the given executable can be found. - - An executable is deemed available if it exists (for an absolute or relative - path) or is in the system path (for a simple filename). This is a naive - implementation that assumes that if a file with the given name exists, it is - accessible and executable. - """ - - if os.path.dirname(executable) != '': - # This is a pathname, either relative or absolute. - return os.path.exists(executable) - - paths = os.environ['PATH'].split(os.pathsep) - for path_dir in paths: - if os.path.exists(os.path.join(path_dir, executable)): - return True - return False - -def IgnoreFile(path): - """Return True if the path is in the list of directories to be ignored.""" - for ignore_dir in IGNORE_DIRS: - path = path.replace('\\', '/') - path = '/' + path + '/' - if '/' + ignore_dir + '/' in path: - return True - return False - -def WriteFile(path, data): - """Write the given data to the path. - - Args: - path: The absolute filename to be written. - data: The string data to be written to the file. - - Raises: - CannotWriteError if the write fails. - """ - logging.debug('Writing file to %s' % path) - try: - f = open(path, 'w') - f.write(data) - f.close() - except IOError, e: - raise CannotWriteError(path) - -def WriteAbsoluteFileList(filename, file_list): - """Write a file containing a sorted list of absolute paths in the branch. - - Args: - filename: The file to write. - file_list: An unsorted list of file paths, given relative to the WebKit - checkout (e.g., 'WebCore/ChangeLog'). - """ - logging.info('Saving %s' % filename) - file_paths = [OldDir(x) for x in file_list] - # Sort after converting to absolute paths, in case some of the incoming paths - # were already absolute. - file_paths.sort() - WriteFile(filename, '\n'.join(file_paths)) - -def RunShellCommand(command, description, run=True): - """Run a command in the shell, waiting for completion. - - Args: - command: The shell command to be run, as a string. - description: A brief description of the command, to be used in an error - message if needed. - run: If false, the command will be logged, but it won't actually be - executed. - - Raises: - CommandError if the command runs but exits with a nonzero status. - """ - logging.debug(command) - if run: - result = subprocess.call(command, shell=True) - if result: - raise CommandError(description, None) - - -######################################## -# Task functions. - -def ValidateArguments(): - """Validate incoming options. - - Canonicalize paths and make sure that they exist, make sure a diff file - exists if one is being used, and check for all required executables. - """ - if options.revision is None: - raise ArgumentError('Please specify a --revision.') - try: - # We need the revision as a string, but we want to make sure it's numeric. - options.revision = str(int(options.revision)) - except ValueError: - raise ArgumentError('Revision must be a number.') - if options.revision < 1: - raise ArgumentError('Revision must be at least 1.') - - options.dir_list = options.directories.split(',') - if not len(options.dir_list): - raise ArgumentError('Please list at least one directory.') - - options.old = GetAbsolutePath(options.old) - options.new = GetAbsolutePath(options.new) - options.temp_dir = GetAbsolutePath(options.temp_dir) - - if not os.path.exists(options.old): - raise CannotFindError('old dir', options.old) - if not os.path.exists(options.new): - raise CannotFindError('new dir', options.new) - for dir_name in options.dir_list: - if not os.path.exists(os.path.join(options.old, 'third_party', dir_name)): - raise CannotFindError('old %s' % dir_name, '') - if not os.path.exists(os.path.join(options.new, dir_name)): - raise CannotFindError('new %s' % dir_name, '') - if not os.path.exists(options.temp_dir): - logging.info('Creating temp directory %s' % options.temp_dir) - os.makedirs(options.temp_dir) - - saved_diff_path = TempDir(SAVE_EDITED_FILES) - if not options.diff and not os.path.exists(saved_diff_path): - logging.warning("No saved diff file at '%s'. Running diff again." % - saved_diff_path) - options.diff = True - - if options.svn_checkout: - if not IsAvailable(SVN): - raise CannotFindError('executable', SVN) - else: - checkout_dir = NewDir() - if not IsAvailable(checkout_dir): - raise CannotFindError('new WebKit checkout', checkout_dir) - if options.diff: - if not IsAvailable(DIFF): - raise CannotFindError('executable', DIFF) - if not IsAvailable('gvn.bat'): - raise CannotFindError('batch file', 'gvn.bat') - -def RunSvnCheckout(revision): - """Use svn to checkout a new WebKit from SVN_URL into the temp dir.""" - logging.info('Checking out revision %s', revision) - for checkout_dir in options.dir_list: - new_dir = NewDir(checkout_dir) - url = SVN_URL + '/' + checkout_dir - command = '%s checkout -r %s %s %s' % (SVN, revision, url, new_dir) - RunShellCommand(command, 'Running svn') - -def UpdateBaseRevision(revision): - """Update the merge branch BASE_REVISION file.""" - new_baserev_file = NewDir(BASE_REV_FILE) - try: - existing_revision = open(new_baserev_file, 'r').read().rstrip() - except IOError, e: - if e.errno == errno.ENOENT: - existing_revision = -1 - else: - raise - if revision != existing_revision: - logging.info('Updating %s to %s' % (new_baserev_file, revision)) - WriteFile(new_baserev_file, revision) - -def RunDiff(saved_file): - """Collect a set of files that differ between the WebKit and Chrome trees. - - Run a recursive diff for each of the relevant directories, collecting a set - of files that differ between them. Save the resulting list in a file, and - also return the set. - - Args: - saved_file: The file in which to save the list of differing files. - - Returns: - A set of paths to files that differ between the two trees. Paths are - given relative to the WebKit checkout (e.g., 'WebCore/ChangeLog'). - - Raises: - CommandError if the diff command returns an error or produces unrecognized - output. - """ - # Regular expressions for parsing the output of the diff. - add_delete_re = re.compile("^Only in [^ ]+") - edit_re = re.compile("^Files ([^ ]+) and [^ ]+ differ") - - # Generate a set of the possible leading directory strings, to be removed - # from the file paths reported by diff. - dir_replacements = set() - for checkout_dir in options.dir_list: - # FIXME(pamg): This assumes that the name of the dir being processed is - # not a substring of options.new. See the FIXME for CollectFileList. - base_dir = NewDir(checkout_dir).replace(checkout_dir, '') - dir_replacements.add(base_dir) - - # Collect the set of edited files. - edited = set() - for diff_dir in options.dir_list: - logging.info('Generating diffs for %s' % diff_dir) - command = [DIFF, '--recursive', '--ignore-space-change', '--brief', - NewDir(diff_dir), OldDir(diff_dir)] - logging.debug(command) - try: - p = subprocess.Popen(command, stdout=subprocess.PIPE) - diff_text = p.stdout.read().replace('\r', '') - rc = p.wait() - except OSError, e: - raise CommandError('Running diff ' + command, e) - # Diff exit status is 0 if the directories compared are the same, 1 if - # they differ, or 2 if an error was encountered. - if rc < 0 or rc > 1: - raise CommandError('Error running diff command', None) - - # Examine this directory's diff result and build a list of changed files. - # Although we're not interested in added or deleted files, we parse the - # "Only in..." lines to catch any errors. - # Files C:/new/directory/file.h and C:/old/directory/file.h differ - # (ignored) Only in C:/new/directory: new_filename.h - # (ignored) Only in C:/old/directory: old_filename.h - logging.info('Analyzing %s diff results' % diff_dir) - for diff_line in diff_text.split('\n'): - if IgnoreFile(diff_line): - continue - if edit_re.search(diff_line) is not None: - filename = re.sub(edit_re, r'\1', diff_line) - for replace in dir_replacements: - filename = filename.replace(replace, '', 1) - edited.add(filename) - elif add_delete_re.search(diff_line) is not None: - # Do nothing, but don't complain about an error. - pass - elif diff_line != '': - raise CommandError("Unknown diff result '%s'" % diff_line, None) - - WriteFile(saved_file, '\n'.join(sorted(edited))) - return edited - -def CopyFiles(files): - """Copy files from WebKit to the merge branch, collecting added directories. - - If options.real is False, collect the directories that would be added, but - don't actually make the directories or perform the copies. - - Args: - files: The set of files to be copied, with paths given relative to the - WebKit checkout (e.g., 'WebCore/ChangeLog'). - - Returns: - A set of absolute directory paths that were created in the merge branch - in order to copy the files. - - Raises: - CommandError if the file copy fails. - """ - logging.info('Copying files from %s to %s' % (options.new, options.old)) - added = set() - for file in files: - # Create the directory if it doesn't exist. - # TODO(pamg): This has a lot of redundancy and could probably be made - # faster. - dirname = os.path.dirname(file) - old_dir = OldDir(dirname) - if not os.path.exists(old_dir): - # We need to handle each new directory level individually, for gvn add. - added = added.union(MakeDirectory(old_dir)) - new_path = NewDir(file) - old_path = OldDir(file) - if options.real: - try: - shutil.copyfile(new_path, old_path) - except IOError, e: - raise CommandError('Copying file', e) - return added - -def CopyObsoleteFiles(files): - """Copy new versions of obsolete header files into .obsolete names. - - If options.real is False, log the copy but do not actually perform it. - - Args: - files: The set of header files to be copied, with paths given relative to - the WebKit checkout and not including '.obsolete' (e.g., - 'WebCore/html/HTMLElement.h'). Their directories should already exist. - - Raises: - CommandError if the file copy fails. - """ - for file in files: - # The directory should already exist. - new_path = NewDir(file) - old_path = OldDir(file + '.obsolete') - logging.debug('Copying %s to %s' % (new_path, old_path)) - if options.real: - try: - shutil.copyfile(new_path, old_path) - except IOError, e: - raise CommandError('Copying obsolete file', e) - -def CopyBaseRevisionFile(): - """Copy the BASE_REV_FILE from the WebKit checkout to the merge branch. - - If options.real is False, log the copy but do not actually perform it. - - Raises: - CommandError if the file copy fails. - """ - logging.info('Copying %s to %s' % (BASE_REV_FILE, OldDir())) - if options.real: - try: - shutil.copyfile(NewDir(BASE_REV_FILE), OldDir(BASE_REV_FILE)) - except IOError, e: - raise CommandError('Copying %s' % BASE_REV_FILE, e) - - -def main(options, args): - """Perform the merge.""" - - ValidateArguments() - - # Report configuration. - logging.info('Updating to revision %s' % options.revision) - logging.info('Updating into old directory %s' % options.old) - logging.info('Using WebKit from new directory %s' % options.new) - logging.info('Using temp directory %s' % options.temp_dir) - - if not options.real: - logging.warning('DEBUGGING: Not issuing mkdir, cp, or gvn commands') - - if options.svn_checkout: - RunSvnCheckout(options.revision) - - UpdateBaseRevision(options.revision) - - # Make sure desired directories are in the checkout. - for checkout_dir in options.dir_list: - if not os.path.exists(NewDir(checkout_dir)): - raise CannotFindError('webkit checkout dir', NewDir(checkout_dir)) - - # Generate or load diffs between relevant directories in the two trees. - saved_diff_path = TempDir(SAVE_EDITED_FILES) - if options.diff: - edit_files = RunDiff(saved_diff_path) - else: - logging.info('Reading diffs from %s' % saved_diff_path) - diff_text = open(saved_diff_path, 'r').read() - edit_files = set(diff_text.split('\n')) - - # Collect filenames in each directory. - old_files = set() - new_files = set() - logging.info('Collecting lists of old and new files') - for collect_dir in options.dir_list: - logging.debug('Collecting old files in %s' % collect_dir) - old_files = old_files.union(CollectFileList(collect_dir, old=True)) - logging.debug('Collecting new files in %s' % collect_dir) - new_files = new_files.union(CollectFileList(collect_dir, old=False)) - - add_files = new_files - old_files - delete_files = old_files - new_files - - if DEBUGGING: - WriteFile(TempDir('old.txt'), '\n'.join(sorted(old_files))) - WriteFile(TempDir('new.txt'), '\n'.join(sorted(new_files))) - - # Find any obsolete files ostensibly to be deleted, and rename (rather than - # re-adding) their corresponding new .h files. We trust that no filename - # that ends with '.obsolete' will also contain another '.obsolete' in its - # name. - obsolete_files = set() - # Iterate through a copy of the deleted set since we'll be changing it. - delete_files_copy = delete_files.copy() - for deleted in delete_files_copy: - if deleted.endswith('.obsolete'): - try: - # Only the add_files.remove() should be able to raise a KeyError. - # If we have no original file to rename, don't delete the .obsolete - # one either. - delete_files.remove(deleted) - deleted = deleted.replace('.obsolete', '') - add_files.remove(deleted) - obsolete_files.add(deleted) - except KeyError, e: - logging.warning('No new file found for old %s.obsolete.' % deleted) - - # Save the list of obsolete files for future reference. - WriteFile(TempDir(SAVE_OBSOLETE_FILES), '\n'.join(sorted(obsolete_files))) - - # Save the list of deleted files, converted to absolute paths, for use by - # gvn. - WriteAbsoluteFileList(TempDir(SAVE_DELETED_FILES), delete_files) - - # Issue gvn deletes. We do this before copying over the added files so that - # an apparently new file that only differs from an old one in the case of - # its filename will be copied with the right name even though Windows - # filenames are case-insensitive. (Otherwise, if the file cppparser.h - # already existed in the Chrome branch but was renamed to CPPParser.h in the - # WebKit checkout, the "added" file CPPParser.h would be copied into - # cppparser.h rather than using its new name.) - if len(delete_files): - logging.info('Issuing gvn delete') - command = 'gvn --targets %s delete' % TempDir(SAVE_DELETED_FILES) - RunShellCommand(command, 'Running gvn delete', options.real) - - # Copy added and edited files from the svn checkout, collecting added - # directories in the process. - if not options.deletes_only: - add_dirs = CopyFiles(add_files | edit_files) - for dir_name in add_dirs: - # We want relative paths, so truncate the path. - add_files.add(dir_name[len(OldDir()) + 1:]) - CopyObsoleteFiles(obsolete_files) - CopyBaseRevisionFile() - - # Save the sorted list of added files, converted to absolute paths, for use - # by gvn. Sorting ensures that new directories are added before their - # contents are. - WriteAbsoluteFileList(TempDir(SAVE_ADDED_FILES), add_files) - - # Issue gvn adds. - os.chdir(OldDir()) - if len(add_files) and not options.deletes_only: - logging.info('Issuing gvn add') - command = 'gvn --targets %s add' % TempDir(SAVE_ADDED_FILES) - RunShellCommand(command, 'Running gvn add', options.real) - - # Print statistics. - logging.info('Edited: %s' % len(edit_files)) - logging.info('Added: %s' % len(add_files)) - logging.info('Deleted: %s' % len(delete_files)) - logging.info('Renamed (obsoletes): %s' % len(obsolete_files)) - - return 0 - -if '__main__' == __name__: - # Set up logging. - if DEBUGGING: - loglevel = logging.DEBUG - else: - loglevel = logging.INFO - logging.basicConfig(level=loglevel, - format='%(asctime)s %(levelname)-7s: %(message)s', - datefmt='%H:%M:%S') - - # We need cygpath to convert our default paths. - try: - if not IsAvailable(CYGPATH): - raise CannotFindError('cygpath', CYGPATH) - except LocalError, e: - if e.stack_trace or DEBUGGING: - traceback.print_exc() - logging.error(e) - sys.exit(e.code) - - # Set up option parsing. - opt = optparse.OptionParser() - - opt.add_option('-r', '--revision', default=None, - help='(REQUIRED): New WebKit revision (already checked out, or to be)') - - opt.add_option('', '--directories', - default='JavaScriptCore,WebCore', - help='Comma-separated list of directories to update') - - opt.add_option('', '--old', - default=GetAbsolutePath('/cygdrive/c/src/merge/'), - help='Path to top of branch checkout, holding src/ and data/') - - opt.add_option('', '--new', - default=GetAbsolutePath('/tmp/webkit-branch-merge/WebKit'), - help='Directory containing new WebKit checkout') - - opt.add_option('', '--temp-dir', - default=GetAbsolutePath('/tmp/webkit-branch-merge'), - help='Temp directory available for use (will be created)') - - opt.add_option('', '--svn-checkout', action='store_true', - default=False, - help='Run a new svn checkout into the new dir') - - opt.add_option('', '--diff', action='store_true', - default=False, - help='Run a fresh diff rather than using a saved diff file') - - opt.add_option('', '--deletes-only', action='store_true', - default=False, - help='Only issue gvn commands for deletes (this is useful' - 'when the case of a filename has changed)') - - opt.add_option('', '--real', action='store_true', - default=False, - help="I'm ready: do the mkdir, cp, and gvn commands for real") - - (options, args) = opt.parse_args() - - # Run. - try: - exit_value = main(options, args) - except LocalError, e: - if e.stack_trace or DEBUGGING: - traceback.print_exc() - logging.error(e) - exit_value = e.code - - sys.exit(exit_value) - |