xref: /rk3399_rockchip-uboot/tools/patman/patman.py (revision 983a2749e2fdc459b2f44e82241a5c314ddbcdf6)
1e8570757SMichal Simek#!/usr/bin/env python
20d24de9dSSimon Glass#
30d24de9dSSimon Glass# Copyright (c) 2011 The Chromium OS Authors.
40d24de9dSSimon Glass#
51a459660SWolfgang Denk# SPDX-License-Identifier:	GPL-2.0+
60d24de9dSSimon Glass#
70d24de9dSSimon Glass
80d24de9dSSimon Glass"""See README for more information"""
90d24de9dSSimon Glass
100d24de9dSSimon Glassfrom optparse import OptionParser
110d24de9dSSimon Glassimport os
120d24de9dSSimon Glassimport re
130d24de9dSSimon Glassimport sys
140d24de9dSSimon Glassimport unittest
150d24de9dSSimon Glass
160d24de9dSSimon Glass# Our modules
170d24de9dSSimon Glassimport checkpatch
180d24de9dSSimon Glassimport command
190d24de9dSSimon Glassimport gitutil
200d24de9dSSimon Glassimport patchstream
21a1dcee84SDoug Andersonimport project
228568baedSDoug Andersonimport settings
230d24de9dSSimon Glassimport terminal
240d24de9dSSimon Glassimport test
250d24de9dSSimon Glass
260d24de9dSSimon Glass
270d24de9dSSimon Glassparser = OptionParser()
280d24de9dSSimon Glassparser.add_option('-H', '--full-help', action='store_true', dest='full_help',
290d24de9dSSimon Glass       default=False, help='Display the README file')
300d24de9dSSimon Glassparser.add_option('-c', '--count', dest='count', type='int',
310d24de9dSSimon Glass       default=-1, help='Automatically create patches from top n commits')
320d24de9dSSimon Glassparser.add_option('-i', '--ignore-errors', action='store_true',
330d24de9dSSimon Glass       dest='ignore_errors', default=False,
340d24de9dSSimon Glass       help='Send patches email even if patch errors are found')
35*983a2749SSimon Glassparser.add_option('-m', '--no-maintainers', action='store_false',
36*983a2749SSimon Glass       dest='add_maintainers', default=True,
37*983a2749SSimon Glass       help="Don't cc the file maintainers automatically")
380d24de9dSSimon Glassparser.add_option('-n', '--dry-run', action='store_true', dest='dry_run',
39ca706e76SSimon Glass       default=False, help="Do a dry run (create but don't email patches)")
4099adf6edSVadim Bendeburyparser.add_option('-p', '--project', default=project.DetectProject(),
4199adf6edSVadim Bendebury                  help="Project name; affects default option values and "
4299adf6edSVadim Bendebury                  "aliases [default: %default]")
436d819925SDoug Andersonparser.add_option('-r', '--in-reply-to', type='string', action='store',
446d819925SDoug Anderson                  help="Message ID that this series is in reply to")
450d24de9dSSimon Glassparser.add_option('-s', '--start', dest='start', type='int',
460d24de9dSSimon Glass       default=0, help='Commit to start creating patches from (0 = HEAD)')
47a1318f7cSSimon Glassparser.add_option('-t', '--ignore-bad-tags', action='store_true',
48a1318f7cSSimon Glass                  default=False, help='Ignore bad tags / aliases')
49a1318f7cSSimon Glassparser.add_option('--test', action='store_true', dest='test',
500d24de9dSSimon Glass                  default=False, help='run tests')
510d24de9dSSimon Glassparser.add_option('-v', '--verbose', action='store_true', dest='verbose',
520d24de9dSSimon Glass       default=False, help='Verbose output of errors and warnings')
530d24de9dSSimon Glassparser.add_option('--cc-cmd', dest='cc_cmd', type='string', action='store',
540d24de9dSSimon Glass       default=None, help='Output cc list for patch file (used by git)')
5599adf6edSVadim Bendeburyparser.add_option('--no-check', action='store_false', dest='check_patch',
5699adf6edSVadim Bendebury                  default=True,
5799adf6edSVadim Bendebury                  help="Don't check for patch compliance")
580d24de9dSSimon Glassparser.add_option('--no-tags', action='store_false', dest='process_tags',
590d24de9dSSimon Glass                  default=True, help="Don't process subject tags as aliaes")
600d24de9dSSimon Glass
61e0a4d06aSMasahiro Yamadaparser.usage += """
620d24de9dSSimon Glass
630d24de9dSSimon GlassCreate patches from commits in a branch, check them and email them as
64ca706e76SSimon Glassspecified by tags you place in the commits. Use -n to do a dry run first."""
650d24de9dSSimon Glass
668568baedSDoug Anderson
67a1dcee84SDoug Anderson# Parse options twice: first to get the project and second to handle
68a1dcee84SDoug Anderson# defaults properly (which depends on project).
69a1dcee84SDoug Anderson(options, args) = parser.parse_args()
70a1dcee84SDoug Andersonsettings.Setup(parser, options.project, '')
710d24de9dSSimon Glass(options, args) = parser.parse_args()
720d24de9dSSimon Glass
730d24de9dSSimon Glass# Run our meagre tests
740d24de9dSSimon Glassif options.test:
750d24de9dSSimon Glass    import doctest
760d24de9dSSimon Glass
770d24de9dSSimon Glass    sys.argv = [sys.argv[0]]
780d24de9dSSimon Glass    suite = unittest.TestLoader().loadTestsFromTestCase(test.TestPatch)
790d24de9dSSimon Glass    result = unittest.TestResult()
800d24de9dSSimon Glass    suite.run(result)
810d24de9dSSimon Glass
82656cffebSDoug Anderson    for module in ['gitutil', 'settings']:
83656cffebSDoug Anderson        suite = doctest.DocTestSuite(module)
840d24de9dSSimon Glass        suite.run(result)
850d24de9dSSimon Glass
860d24de9dSSimon Glass    # TODO: Surely we can just 'print' result?
870d24de9dSSimon Glass    print result
880d24de9dSSimon Glass    for test, err in result.errors:
890d24de9dSSimon Glass        print err
900d24de9dSSimon Glass    for test, err in result.failures:
910d24de9dSSimon Glass        print err
920d24de9dSSimon Glass
930d24de9dSSimon Glass# Called from git with a patch filename as argument
940d24de9dSSimon Glass# Printout a list of additional CC recipients for this patch
950d24de9dSSimon Glasselif options.cc_cmd:
960d24de9dSSimon Glass    fd = open(options.cc_cmd, 'r')
970d24de9dSSimon Glass    re_line = re.compile('(\S*) (.*)')
980d24de9dSSimon Glass    for line in fd.readlines():
990d24de9dSSimon Glass        match = re_line.match(line)
1000d24de9dSSimon Glass        if match and match.group(1) == args[0]:
1010d24de9dSSimon Glass            for cc in match.group(2).split(', '):
1020d24de9dSSimon Glass                cc = cc.strip()
1030d24de9dSSimon Glass                if cc:
1040d24de9dSSimon Glass                    print cc
1050d24de9dSSimon Glass    fd.close()
1060d24de9dSSimon Glass
1070d24de9dSSimon Glasselif options.full_help:
1080d24de9dSSimon Glass    pager = os.getenv('PAGER')
1090d24de9dSSimon Glass    if not pager:
1100d24de9dSSimon Glass        pager = 'more'
1110d24de9dSSimon Glass    fname = os.path.join(os.path.dirname(sys.argv[0]), 'README')
1120d24de9dSSimon Glass    command.Run(pager, fname)
1130d24de9dSSimon Glass
1140d24de9dSSimon Glass# Process commits, produce patches files, check them, email them
1150d24de9dSSimon Glasselse:
1160d24de9dSSimon Glass    gitutil.Setup()
1170d24de9dSSimon Glass
1180d24de9dSSimon Glass    if options.count == -1:
1190d24de9dSSimon Glass        # Work out how many patches to send if we can
1200d24de9dSSimon Glass        options.count = gitutil.CountCommitsToBranch() - options.start
1210d24de9dSSimon Glass
1220d24de9dSSimon Glass    col = terminal.Color()
1230d24de9dSSimon Glass    if not options.count:
1240d24de9dSSimon Glass        str = 'No commits found to process - please use -c flag'
12531e2141dSMasahiro Yamada        sys.exit(col.Color(col.RED, str))
1260d24de9dSSimon Glass
1270d24de9dSSimon Glass    # Read the metadata from the commits
1280d24de9dSSimon Glass    if options.count:
1290d24de9dSSimon Glass        series = patchstream.GetMetaData(options.start, options.count)
1300d24de9dSSimon Glass        cover_fname, args = gitutil.CreatePatches(options.start, options.count,
1310d24de9dSSimon Glass                series)
1320d24de9dSSimon Glass
1330d24de9dSSimon Glass    # Fix up the patch files to our liking, and insert the cover letter
1340d24de9dSSimon Glass    series = patchstream.FixPatches(series, args)
1350d24de9dSSimon Glass    if series and cover_fname and series.get('cover'):
1360d24de9dSSimon Glass        patchstream.InsertCoverLetter(cover_fname, series, options.count)
1370d24de9dSSimon Glass
1380d24de9dSSimon Glass    # Do a few checks on the series
1390d24de9dSSimon Glass    series.DoChecks()
1400d24de9dSSimon Glass
1410d24de9dSSimon Glass    # Check the patches, and run them through 'git am' just to be sure
14299adf6edSVadim Bendebury    if options.check_patch:
1430d24de9dSSimon Glass        ok = checkpatch.CheckPatches(options.verbose, args)
14499adf6edSVadim Bendebury    else:
14599adf6edSVadim Bendebury        ok = True
1460d24de9dSSimon Glass
147a1318f7cSSimon Glass    cc_file = series.MakeCcFile(options.process_tags, cover_fname,
148*983a2749SSimon Glass                                not options.ignore_bad_tags,
149*983a2749SSimon Glass                                options.add_maintainers)
150d94566a1SDoug Anderson
1510d24de9dSSimon Glass    # Email the patches out (giving the user time to check / cancel)
1520d24de9dSSimon Glass    cmd = ''
1531f727885SVadim Bendebury    its_a_go = ok or options.ignore_errors
1541f727885SVadim Bendebury    if its_a_go:
1550d24de9dSSimon Glass        cmd = gitutil.EmailPatches(series, cover_fname, args,
156a1318f7cSSimon Glass                options.dry_run, not options.ignore_bad_tags, cc_file,
157a1318f7cSSimon Glass                in_reply_to=options.in_reply_to)
1581f727885SVadim Bendebury    else:
1591f727885SVadim Bendebury        print col.Color(col.RED, "Not sending emails due to errors/warnings")
1600d24de9dSSimon Glass
1610d24de9dSSimon Glass    # For a dry run, just show our actions as a sanity check
1620d24de9dSSimon Glass    if options.dry_run:
1630d24de9dSSimon Glass        series.ShowActions(args, cmd, options.process_tags)
1641f727885SVadim Bendebury        if not its_a_go:
1651f727885SVadim Bendebury            print col.Color(col.RED, "Email would not be sent")
166d94566a1SDoug Anderson
167d94566a1SDoug Anderson    os.remove(cc_file)
168