xref: /openbmc/u-boot/tools/patman/patman.py (revision 902a9715)
10d24de9dSSimon Glass#!/usr/bin/python
20d24de9dSSimon Glass#
30d24de9dSSimon Glass# Copyright (c) 2011 The Chromium OS Authors.
40d24de9dSSimon Glass#
50d24de9dSSimon Glass# See file CREDITS for list of people who contributed to this
60d24de9dSSimon Glass# project.
70d24de9dSSimon Glass#
80d24de9dSSimon Glass# This program is free software; you can redistribute it and/or
90d24de9dSSimon Glass# modify it under the terms of the GNU General Public License as
100d24de9dSSimon Glass# published by the Free Software Foundation; either version 2 of
110d24de9dSSimon Glass# the License, or (at your option) any later version.
120d24de9dSSimon Glass#
130d24de9dSSimon Glass# This program is distributed in the hope that it will be useful,
140d24de9dSSimon Glass# but WITHOUT ANY WARRANTY; without even the implied warranty of
150d24de9dSSimon Glass# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
160d24de9dSSimon Glass# GNU General Public License for more details.
170d24de9dSSimon Glass#
180d24de9dSSimon Glass# You should have received a copy of the GNU General Public License
190d24de9dSSimon Glass# along with this program; if not, write to the Free Software
200d24de9dSSimon Glass# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
210d24de9dSSimon Glass# MA 02111-1307 USA
220d24de9dSSimon Glass#
230d24de9dSSimon Glass
240d24de9dSSimon Glass"""See README for more information"""
250d24de9dSSimon Glass
260d24de9dSSimon Glassfrom optparse import OptionParser
270d24de9dSSimon Glassimport os
280d24de9dSSimon Glassimport re
290d24de9dSSimon Glassimport sys
300d24de9dSSimon Glassimport unittest
310d24de9dSSimon Glass
320d24de9dSSimon Glass# Our modules
330d24de9dSSimon Glassimport checkpatch
340d24de9dSSimon Glassimport command
350d24de9dSSimon Glassimport gitutil
360d24de9dSSimon Glassimport patchstream
37a1dcee84SDoug Andersonimport project
388568baedSDoug Andersonimport settings
390d24de9dSSimon Glassimport terminal
400d24de9dSSimon Glassimport test
410d24de9dSSimon Glass
420d24de9dSSimon Glass
430d24de9dSSimon Glassparser = OptionParser()
44*902a9715SSimon Glassparser.add_option('-a', '--no-apply', action='store_false',
45*902a9715SSimon Glass                  dest='apply_patches', default=True,
46*902a9715SSimon Glass                  help="Don't test-apply patches with git am")
470d24de9dSSimon Glassparser.add_option('-H', '--full-help', action='store_true', dest='full_help',
480d24de9dSSimon Glass       default=False, help='Display the README file')
490d24de9dSSimon Glassparser.add_option('-c', '--count', dest='count', type='int',
500d24de9dSSimon Glass       default=-1, help='Automatically create patches from top n commits')
510d24de9dSSimon Glassparser.add_option('-i', '--ignore-errors', action='store_true',
520d24de9dSSimon Glass       dest='ignore_errors', default=False,
530d24de9dSSimon Glass       help='Send patches email even if patch errors are found')
540d24de9dSSimon Glassparser.add_option('-n', '--dry-run', action='store_true', dest='dry_run',
55ca706e76SSimon Glass       default=False, help="Do a dry run (create but don't email patches)")
5699adf6edSVadim Bendeburyparser.add_option('-p', '--project', default=project.DetectProject(),
5799adf6edSVadim Bendebury                  help="Project name; affects default option values and "
5899adf6edSVadim Bendebury                  "aliases [default: %default]")
596d819925SDoug Andersonparser.add_option('-r', '--in-reply-to', type='string', action='store',
606d819925SDoug Anderson                  help="Message ID that this series is in reply to")
610d24de9dSSimon Glassparser.add_option('-s', '--start', dest='start', type='int',
620d24de9dSSimon Glass       default=0, help='Commit to start creating patches from (0 = HEAD)')
63a1318f7cSSimon Glassparser.add_option('-t', '--ignore-bad-tags', action='store_true',
64a1318f7cSSimon Glass                  default=False, help='Ignore bad tags / aliases')
65a1318f7cSSimon Glassparser.add_option('--test', action='store_true', dest='test',
660d24de9dSSimon Glass                  default=False, help='run tests')
670d24de9dSSimon Glassparser.add_option('-v', '--verbose', action='store_true', dest='verbose',
680d24de9dSSimon Glass       default=False, help='Verbose output of errors and warnings')
690d24de9dSSimon Glassparser.add_option('--cc-cmd', dest='cc_cmd', type='string', action='store',
700d24de9dSSimon Glass       default=None, help='Output cc list for patch file (used by git)')
7199adf6edSVadim Bendeburyparser.add_option('--no-check', action='store_false', dest='check_patch',
7299adf6edSVadim Bendebury                  default=True,
7399adf6edSVadim Bendebury                  help="Don't check for patch compliance")
740d24de9dSSimon Glassparser.add_option('--no-tags', action='store_false', dest='process_tags',
750d24de9dSSimon Glass                  default=True, help="Don't process subject tags as aliaes")
760d24de9dSSimon Glass
770d24de9dSSimon Glassparser.usage = """patman [options]
780d24de9dSSimon Glass
790d24de9dSSimon GlassCreate patches from commits in a branch, check them and email them as
80ca706e76SSimon Glassspecified by tags you place in the commits. Use -n to do a dry run first."""
810d24de9dSSimon Glass
828568baedSDoug Anderson
83a1dcee84SDoug Anderson# Parse options twice: first to get the project and second to handle
84a1dcee84SDoug Anderson# defaults properly (which depends on project).
85a1dcee84SDoug Anderson(options, args) = parser.parse_args()
86a1dcee84SDoug Andersonsettings.Setup(parser, options.project, '')
870d24de9dSSimon Glass(options, args) = parser.parse_args()
880d24de9dSSimon Glass
890d24de9dSSimon Glass# Run our meagre tests
900d24de9dSSimon Glassif options.test:
910d24de9dSSimon Glass    import doctest
920d24de9dSSimon Glass
930d24de9dSSimon Glass    sys.argv = [sys.argv[0]]
940d24de9dSSimon Glass    suite = unittest.TestLoader().loadTestsFromTestCase(test.TestPatch)
950d24de9dSSimon Glass    result = unittest.TestResult()
960d24de9dSSimon Glass    suite.run(result)
970d24de9dSSimon Glass
98656cffebSDoug Anderson    for module in ['gitutil', 'settings']:
99656cffebSDoug Anderson        suite = doctest.DocTestSuite(module)
1000d24de9dSSimon Glass        suite.run(result)
1010d24de9dSSimon Glass
1020d24de9dSSimon Glass    # TODO: Surely we can just 'print' result?
1030d24de9dSSimon Glass    print result
1040d24de9dSSimon Glass    for test, err in result.errors:
1050d24de9dSSimon Glass        print err
1060d24de9dSSimon Glass    for test, err in result.failures:
1070d24de9dSSimon Glass        print err
1080d24de9dSSimon Glass
1090d24de9dSSimon Glass# Called from git with a patch filename as argument
1100d24de9dSSimon Glass# Printout a list of additional CC recipients for this patch
1110d24de9dSSimon Glasselif options.cc_cmd:
1120d24de9dSSimon Glass    fd = open(options.cc_cmd, 'r')
1130d24de9dSSimon Glass    re_line = re.compile('(\S*) (.*)')
1140d24de9dSSimon Glass    for line in fd.readlines():
1150d24de9dSSimon Glass        match = re_line.match(line)
1160d24de9dSSimon Glass        if match and match.group(1) == args[0]:
1170d24de9dSSimon Glass            for cc in match.group(2).split(', '):
1180d24de9dSSimon Glass                cc = cc.strip()
1190d24de9dSSimon Glass                if cc:
1200d24de9dSSimon Glass                    print cc
1210d24de9dSSimon Glass    fd.close()
1220d24de9dSSimon Glass
1230d24de9dSSimon Glasselif options.full_help:
1240d24de9dSSimon Glass    pager = os.getenv('PAGER')
1250d24de9dSSimon Glass    if not pager:
1260d24de9dSSimon Glass        pager = 'more'
1270d24de9dSSimon Glass    fname = os.path.join(os.path.dirname(sys.argv[0]), 'README')
1280d24de9dSSimon Glass    command.Run(pager, fname)
1290d24de9dSSimon Glass
1300d24de9dSSimon Glass# Process commits, produce patches files, check them, email them
1310d24de9dSSimon Glasselse:
1320d24de9dSSimon Glass    gitutil.Setup()
1330d24de9dSSimon Glass
1340d24de9dSSimon Glass    if options.count == -1:
1350d24de9dSSimon Glass        # Work out how many patches to send if we can
1360d24de9dSSimon Glass        options.count = gitutil.CountCommitsToBranch() - options.start
1370d24de9dSSimon Glass
1380d24de9dSSimon Glass    col = terminal.Color()
1390d24de9dSSimon Glass    if not options.count:
1400d24de9dSSimon Glass        str = 'No commits found to process - please use -c flag'
1410d24de9dSSimon Glass        print col.Color(col.RED, str)
1420d24de9dSSimon Glass        sys.exit(1)
1430d24de9dSSimon Glass
1440d24de9dSSimon Glass    # Read the metadata from the commits
1450d24de9dSSimon Glass    if options.count:
1460d24de9dSSimon Glass        series = patchstream.GetMetaData(options.start, options.count)
1470d24de9dSSimon Glass        cover_fname, args = gitutil.CreatePatches(options.start, options.count,
1480d24de9dSSimon Glass                series)
1490d24de9dSSimon Glass
1500d24de9dSSimon Glass    # Fix up the patch files to our liking, and insert the cover letter
1510d24de9dSSimon Glass    series = patchstream.FixPatches(series, args)
1520d24de9dSSimon Glass    if series and cover_fname and series.get('cover'):
1530d24de9dSSimon Glass        patchstream.InsertCoverLetter(cover_fname, series, options.count)
1540d24de9dSSimon Glass
1550d24de9dSSimon Glass    # Do a few checks on the series
1560d24de9dSSimon Glass    series.DoChecks()
1570d24de9dSSimon Glass
1580d24de9dSSimon Glass    # Check the patches, and run them through 'git am' just to be sure
15999adf6edSVadim Bendebury    if options.check_patch:
1600d24de9dSSimon Glass        ok = checkpatch.CheckPatches(options.verbose, args)
16199adf6edSVadim Bendebury    else:
16299adf6edSVadim Bendebury        ok = True
163*902a9715SSimon Glass    if options.apply_patches:
1640d24de9dSSimon Glass        if not gitutil.ApplyPatches(options.verbose, args,
1650d24de9dSSimon Glass                                    options.count + options.start):
1660d24de9dSSimon Glass            ok = False
1670d24de9dSSimon Glass
168a1318f7cSSimon Glass    cc_file = series.MakeCcFile(options.process_tags, cover_fname,
169a1318f7cSSimon Glass                                not options.ignore_bad_tags)
170d94566a1SDoug Anderson
1710d24de9dSSimon Glass    # Email the patches out (giving the user time to check / cancel)
1720d24de9dSSimon Glass    cmd = ''
1730d24de9dSSimon Glass    if ok or options.ignore_errors:
1740d24de9dSSimon Glass        cmd = gitutil.EmailPatches(series, cover_fname, args,
175a1318f7cSSimon Glass                options.dry_run, not options.ignore_bad_tags, cc_file,
176a1318f7cSSimon Glass                in_reply_to=options.in_reply_to)
1770d24de9dSSimon Glass
1780d24de9dSSimon Glass    # For a dry run, just show our actions as a sanity check
1790d24de9dSSimon Glass    if options.dry_run:
1800d24de9dSSimon Glass        series.ShowActions(args, cmd, options.process_tags)
181d94566a1SDoug Anderson
182d94566a1SDoug Anderson    os.remove(cc_file)
183