Blame view
tools/patman/patman.py
6.4 KB
d41ce506b Initial Release, ... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
#!/usr/bin/env python2 # # Copyright (c) 2011 The Chromium OS Authors. # # SPDX-License-Identifier: GPL-2.0+ # """See README for more information""" from optparse import OptionParser import os import re import sys import unittest # Our modules try: from patman import checkpatch, command, gitutil, patchstream, \ project, settings, terminal, test except ImportError: import checkpatch import command import gitutil import patchstream import project import settings import terminal import test parser = OptionParser() parser.add_option('-H', '--full-help', action='store_true', dest='full_help', default=False, help='Display the README file') parser.add_option('-c', '--count', dest='count', type='int', default=-1, help='Automatically create patches from top n commits') parser.add_option('-i', '--ignore-errors', action='store_true', dest='ignore_errors', default=False, help='Send patches email even if patch errors are found') parser.add_option('-m', '--no-maintainers', action='store_false', dest='add_maintainers', default=True, help="Don't cc the file maintainers automatically") parser.add_option('-n', '--dry-run', action='store_true', dest='dry_run', default=False, help="Do a dry run (create but don't email patches)") parser.add_option('-p', '--project', default=project.DetectProject(), help="Project name; affects default option values and " "aliases [default: %default]") parser.add_option('-r', '--in-reply-to', type='string', action='store', help="Message ID that this series is in reply to") parser.add_option('-s', '--start', dest='start', type='int', default=0, help='Commit to start creating patches from (0 = HEAD)') parser.add_option('-t', '--ignore-bad-tags', action='store_true', default=False, help='Ignore bad tags / aliases') parser.add_option('--test', action='store_true', dest='test', default=False, help='run tests') parser.add_option('-v', '--verbose', action='store_true', dest='verbose', default=False, help='Verbose output of errors and warnings') parser.add_option('--cc-cmd', dest='cc_cmd', type='string', action='store', default=None, help='Output cc list for patch file (used by git)') parser.add_option('--no-check', action='store_false', dest='check_patch', default=True, help="Don't check for patch compliance") parser.add_option('--no-tags', action='store_false', dest='process_tags', default=True, help="Don't process subject tags as aliaes") parser.add_option('-T', '--thread', action='store_true', dest='thread', default=False, help='Create patches as a single thread') parser.usage += """ Create patches from commits in a branch, check them and email them as specified by tags you place in the commits. Use -n to do a dry run first.""" # Parse options twice: first to get the project and second to handle # defaults properly (which depends on project). (options, args) = parser.parse_args() settings.Setup(parser, options.project, '') (options, args) = parser.parse_args() if __name__ != "__main__": pass # Run our meagre tests elif options.test: import doctest import func_test sys.argv = [sys.argv[0]] result = unittest.TestResult() for module in (test.TestPatch, func_test.TestFunctional): suite = unittest.TestLoader().loadTestsFromTestCase(module) suite.run(result) for module in ['gitutil', 'settings']: suite = doctest.DocTestSuite(module) suite.run(result) # TODO: Surely we can just 'print' result? print(result) for test, err in result.errors: print(err) for test, err in result.failures: print(err) # Called from git with a patch filename as argument # Printout a list of additional CC recipients for this patch elif options.cc_cmd: fd = open(options.cc_cmd, 'r') re_line = re.compile('(\S*) (.*)') for line in fd.readlines(): match = re_line.match(line) if match and match.group(1) == args[0]: for cc in match.group(2).split(', '): cc = cc.strip() if cc: print(cc) fd.close() elif options.full_help: pager = os.getenv('PAGER') if not pager: pager = 'more' fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), 'README') command.Run(pager, fname) # Process commits, produce patches files, check them, email them else: gitutil.Setup() if options.count == -1: # Work out how many patches to send if we can options.count = gitutil.CountCommitsToBranch() - options.start col = terminal.Color() if not options.count: str = 'No commits found to process - please use -c flag' sys.exit(col.Color(col.RED, str)) # Read the metadata from the commits if options.count: series = patchstream.GetMetaData(options.start, options.count) cover_fname, args = gitutil.CreatePatches(options.start, options.count, series) # Fix up the patch files to our liking, and insert the cover letter patchstream.FixPatches(series, args) if cover_fname and series.get('cover'): patchstream.InsertCoverLetter(cover_fname, series, options.count) # Do a few checks on the series series.DoChecks() # Check the patches, and run them through 'git am' just to be sure if options.check_patch: ok = checkpatch.CheckPatches(options.verbose, args) else: ok = True cc_file = series.MakeCcFile(options.process_tags, cover_fname, not options.ignore_bad_tags, options.add_maintainers) # Email the patches out (giving the user time to check / cancel) cmd = '' its_a_go = ok or options.ignore_errors if its_a_go: cmd = gitutil.EmailPatches(series, cover_fname, args, options.dry_run, not options.ignore_bad_tags, cc_file, in_reply_to=options.in_reply_to, thread=options.thread) else: print(col.Color(col.RED, "Not sending emails due to errors/warnings")) # For a dry run, just show our actions as a sanity check if options.dry_run: series.ShowActions(args, cmd, options.process_tags) if not its_a_go: print(col.Color(col.RED, "Email would not be sent")) os.remove(cc_file) |