| Index: tools/git/for-all-touched-files.py
|
| diff --git a/tools/git/for-all-touched-files.py b/tools/git/for-all-touched-files.py
|
| new file mode 100755
|
| index 0000000000000000000000000000000000000000..633fd078cdad4bcf5e8ac7e2b8ec8921b39383a1
|
| --- /dev/null
|
| +++ b/tools/git/for-all-touched-files.py
|
| @@ -0,0 +1,126 @@
|
| +#!/usr/bin/env 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|-g] [-t TOKEN] QUOTED_COMMAND
|
| +
|
| +Examples:
|
| + %prog -x gyp,gypi "tools/format_xml.py [[FILENAME]]"
|
| + %prog -c "tools/sort-headers.py [[FILENAME]]"
|
| + %prog -g "tools/sort_sources.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',)
|
| +# List of build file extensions.
|
| +_BUILD_EXTENSIONS = ('gyp', 'gypi', 'gn',)
|
| +
|
| +
|
| +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.')
|
| + # -g stands for GYP and GN.
|
| + parser.add_option('-g', '--build', default=False, action='store_true',
|
| + dest='build_only',
|
| + help='Runs your command only on build 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)
|
| +
|
| + if opts.cpp_only and opts.build_only:
|
| + parser.error("--cpp and --build are mutually exclusive")
|
| +
|
| + extensions = opts.extensions
|
| + if opts.cpp_only:
|
| + extensions = _CPP_EXTENSIONS
|
| + if opts.build_only:
|
| + extensions = _BUILD_EXTENSIONS
|
| +
|
| + ForAllTouchedFiles(opts.branch, extensions, opts.token, args[0])
|
| +
|
| +
|
| +if __name__ == '__main__':
|
| + main()
|
|
|