summaryrefslogtreecommitdiffstats
path: root/tools/git
diff options
context:
space:
mode:
authorjoi@chromium.org <joi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-01 11:46:52 +0000
committerjoi@chromium.org <joi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-01 11:46:52 +0000
commit10ab0ed503293ec16bba8b6397e5169c0a3a896b (patch)
tree92dca0869af16bd34d787b930cf081b8bff4a702 /tools/git
parentf2a4351bb986766e774341b411516306d3e96b2b (diff)
downloadchromium_src-10ab0ed503293ec16bba8b6397e5169c0a3a896b.zip
chromium_src-10ab0ed503293ec16bba8b6397e5169c0a3a896b.tar.gz
chromium_src-10ab0ed503293ec16bba8b6397e5169c0a3a896b.tar.bz2
Adds a tool that lets you run a command for each modified file on your git branch or in your workspace.
Also, add a flag to sort-headers.py to make it more useful when used in conjunction with that tool, that suppresses the y/N prompt after each diff (as vetting a bulk change may be easier once it's in your working directory, using your favorite diff tool). Refactor the script slightly while I'm in there. BUG=none TEST=none Review URL: http://codereview.chromium.org/8390055 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@108097 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools/git')
-rwxr-xr-xtools/git/for-all-touched-files.py114
1 files changed, 114 insertions, 0 deletions
diff --git a/tools/git/for-all-touched-files.py b/tools/git/for-all-touched-files.py
new file mode 100755
index 0000000..d776743
--- /dev/null
+++ b/tools/git/for-all-touched-files.py
@@ -0,0 +1,114 @@
+#!/usr/bin/python
+# Copyright (c) 2011 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.
+
+"""
+ Invokes the specified (quoted) command for all files modified
+ between the current git branch and the specified branch or commit.
+
+ The special token [[FILENAME]] (or whatever you choose using the -t
+ flag) is replaced with each of the filenames of new or modified files.
+
+ Deleted files are not included. Neither are untracked files.
+
+Synopsis:
+ %prog [-b BRANCH] [-d] [-x EXTENSIONS|-c] [-t TOKEN] QUOTED_COMMAND
+
+Examples:
+ %prog -x gyp,gypi "tools/format_xml.py [[FILENAME]]"
+ %prog -c "tools/sort-headers.py [[FILENAME]]"
+ %prog -t "~~BINGO~~" "echo I modified ~~BINGO~~"
+"""
+
+import optparse
+import os
+import subprocess
+import sys
+
+
+# List of C++-like source file extensions.
+_CPP_EXTENSIONS = ('h', 'hh', 'hpp', 'c', 'cc', 'cpp', 'cxx', 'mm',)
+
+
+def GitShell(args, ignore_return=False):
+ """A shell invocation suitable for communicating with git. Returns
+ output as list of lines, raises exception on error.
+ """
+ job = subprocess.Popen(args,
+ shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ (out, err) = job.communicate()
+ if job.returncode != 0 and not ignore_return:
+ print out
+ raise Exception("Error %d running command %s" % (
+ job.returncode, args))
+ return out.split('\n')
+
+
+def FilenamesFromGit(branch_name, extensions):
+ """Provides a list of all new and modified files listed by [git diff
+ branch_name] where branch_name can be blank to get a diff of the
+ workspace.
+
+ Excludes deleted files.
+
+ If extensions is not an empty list, include only files with one of
+ the extensions on the list.
+ """
+ lines = GitShell('git diff --stat=600,500 %s' % branch_name)
+ filenames = []
+ for line in lines:
+ line = line.lstrip()
+ # Avoid summary line, and files that have been deleted (no plus).
+ if line.find('|') != -1 and line.find('+') != -1:
+ filename = line.split()[0]
+ if filename:
+ filename = filename.rstrip()
+ ext = filename.rsplit('.')[-1]
+ if not extensions or ext in extensions:
+ filenames.append(filename)
+ return filenames
+
+
+def ForAllTouchedFiles(branch_name, extensions, token, command):
+ """For each new or modified file output by [git diff branch_name],
+ run command with token replaced with the filename. If extensions is
+ not empty, do this only for files with one of the extensions in that
+ list.
+ """
+ filenames = FilenamesFromGit(branch_name, extensions)
+ for filename in filenames:
+ os.system(command.replace(token, filename))
+
+
+def main():
+ parser = optparse.OptionParser(usage=__doc__)
+ parser.add_option('-x', '--extensions', default='', dest='extensions',
+ help='Limits to files with given extensions '
+ '(comma-separated).')
+ parser.add_option('-c', '--cpp', default=False, action='store_true',
+ dest='cpp_only',
+ help='Runs your command only on C++-like source files.')
+ parser.add_option('-t', '--token', default='[[FILENAME]]', dest='token',
+ help='Sets the token to be replaced for each file '
+ 'in your command (default [[FILENAME]]).')
+ parser.add_option('-b', '--branch', default='origin/master', dest='branch',
+ help='Sets what to diff to (default origin/master). Set '
+ 'to empty to diff workspace against HEAD.')
+ opts, args = parser.parse_args()
+
+ if not args:
+ parser.print_help()
+ sys.exit(1)
+
+ extensions = opts.extensions
+ if opts.cpp_only:
+ extensions = _CPP_EXTENSIONS
+
+ ForAllTouchedFiles(opts.branch, extensions, opts.token, args[0])
+
+
+if __name__ == '__main__':
+ main()