Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(987)

Unified Diff: scripts/slave/patch_path_filter.py

Issue 27575002: Patch path filtering script. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Simplified after discovering upload.py stuff, and more tests! Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: scripts/slave/patch_path_filter.py
diff --git a/scripts/slave/patch_path_filter.py b/scripts/slave/patch_path_filter.py
new file mode 100755
index 0000000000000000000000000000000000000000..67daed08f70151cc6cbc30f241656d8294f516b2
--- /dev/null
+++ b/scripts/slave/patch_path_filter.py
@@ -0,0 +1,107 @@
+#!/usr/bin/python
+# Copyright 2013 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.
+
+"""Script that can be used to filter out files from a patch/diff.
+
+Usage: pipe the patch contents to stdin and the filtered output will be written
+to stdout.
+The output will be compatible with the patch program, both for Subversion and
+Git patches.
+NOTICE: the script can only manage patches created by depot tools (i.e. it
+is supposed to be used for tryjob generated patches. This is because it relies
+no the Index: line being present, which is normally not the case for Git patches
+(it is added by depot_tools/third_party/upload.py during the creation of the
+try job).
+"""
+
+import optparse
+import os
+import re
+import sys
+
+from depot_tools import patch
+
+
+def parse_patch_set(patch_contents):
+ patch_chunks = []
+ current_chunk = []
+ for line in patch_contents.splitlines(True):
+ # See https://code.google.com/p/chromium/codesearch#
+ # chromium/tools/depot_tools/third_party/upload.py
+ # for details on how patches uploaded with depot_tools will have each
+ # file chunk start with either of these strings (for both Git and SVN).
+ if ((line.startswith('Index:') or line.startswith('Property changes on:'))
iannucci 2013/12/10 21:32:23 FYI, you can do line.startswith(('Index:', 'Prop
kjellander_chromium 2013/12/11 13:31:31 Thanks, fixed.
+ and current_chunk):
+ patch_chunks.insert(0, current_chunk)
+ current_chunk = []
+ current_chunk.append(line)
+
+ if current_chunk:
+ patch_chunks.insert(0, current_chunk)
+
+ # Parse filename for each patch chunk and create FilePatchDiff objects
+ filename_regex = re.compile(r'^.*: ([^\t]+).*\n$')
iannucci 2013/12/10 21:32:23 I would put this up in the global scope as FILENAM
kjellander_chromium 2013/12/11 13:31:31 Done.
+ patches = []
+ for chunk in patch_chunks:
+ match = filename_regex.match(chunk[0])
+ if not match:
+ raise Exception('Did not find any filename in line "%s". Notice that '
+ 'only patches uploaded using depot tools are supported '
+ 'since normal Git patches don\'t include the "Index:" '
+ 'line.' % chunk[0])
+ filename = match.group(1).replace('\\', '/')
+ patches.append(patch.FilePatchDiff(filename=filename, diff=''.join(chunk),
+ svn_properties=[]))
+ return patch.PatchSet(patches)
+
+
+def convert_to_patch_compatible_diff(filename, patch_data):
kjellander_chromium 2013/12/10 20:46:03 When doing testing on actual checkouts with the ap
+ """Convert patch data to be compatible with the standard patch program.
+
+ This will remove the "a/" and "b/" prefixes added by Git, so the patch becomes
+ compatible with the standard patch program.
iannucci 2013/12/10 21:32:23 you could also just pass -p1 to patch.
kjellander_chromium 2013/12/11 13:31:31 I could if I knew when invoking the patch program
+ """
+ diff = ''
+ for line in patch_data.splitlines(True):
+ if line.startswith('---'):
+ line = line.replace('a/' + filename, filename)
+ if line.startswith('+++'):
iannucci 2013/12/10 21:32:23 elif? though obviously both won't hit, but it may
kjellander_chromium 2013/12/11 13:31:31 Done.
+ line = line.replace('b/' + filename, filename)
+ diff += line
+ return diff
+
+
+def main():
+ usage = '%s -f <path-filter> [-r <root-dir>]' % os.path.basename(sys.argv[0])
+ parser = optparse.OptionParser(usage=usage)
+ parser.add_option('-f', '--path-filter',
+ help=('The path filter (UNIX paths) that all file paths '
+ 'are required to have to pass this filter (no '
+ 'regexp).'))
+ parser.add_option('-r', '--root-dir',
+ help=('The patch root dir in which to apply the patch. If '
+ 'specified, it will be prepended to the filename '
+ 'for each patch entry before the filter is applied.'))
+
+ options, args = parser.parse_args()
+ if args:
+ parser.error('Unused args: %s' % args)
+ if not options.path_filter:
+ parser.error('A path filter must be be specified.')
+
+ patch_contents = sys.stdin.read()
+
+ # Only print the patch entries that passes our path filter.
+ for patch_entry in parse_patch_set(patch_contents):
+ filename = patch_entry.filename
+ if options.root_dir:
+ filename = os.path.join(options.root_dir, filename)
+
+ if filename.startswith(options.path_filter):
+ print convert_to_patch_compatible_diff(patch_entry.filename,
+ patch_entry.get(for_git=False)),
+
+if __name__ == '__main__':
+ sys.exit(main())

Powered by Google App Engine
This is Rietveld 408576698