blob: 0974c840598b89a71f652f0815448ca3675ac87c [file] [log] [blame]
Simon Glasse3986d92019-10-31 07:42:52 -06001#!/usr/bin/env python3
Tom Rini83d290c2018-05-06 17:58:06 -04002# SPDX-License-Identifier: GPL-2.0+
Simon Glass0d24de92012-01-14 15:12:45 +00003#
4# Copyright (c) 2011 The Chromium OS Authors.
5#
Simon Glass0d24de92012-01-14 15:12:45 +00006
7"""See README for more information"""
8
9from optparse import OptionParser
10import os
11import re
12import sys
13import unittest
14
Simon Glass0d7a8c42020-04-17 18:08:52 -060015if __name__ == "__main__":
Simon Glassb4fa9492020-04-17 18:09:05 -060016 # Allow 'from patman import xxx to work'
Simon Glass0d7a8c42020-04-17 18:08:52 -060017 our_path = os.path.dirname(os.path.realpath(__file__))
18 sys.path.append(os.path.join(our_path, '..'))
19
Simon Glass0d24de92012-01-14 15:12:45 +000020# Our modules
Simon Glassbf776672020-04-17 18:09:04 -060021from patman import checkpatch
22from patman import command
23from patman import gitutil
24from patman import patchstream
25from patman import project
26from patman import settings
27from patman import terminal
28from patman import test
Simon Glass0d24de92012-01-14 15:12:45 +000029
30
31parser = OptionParser()
32parser.add_option('-H', '--full-help', action='store_true', dest='full_help',
33 default=False, help='Display the README file')
34parser.add_option('-c', '--count', dest='count', type='int',
35 default=-1, help='Automatically create patches from top n commits')
36parser.add_option('-i', '--ignore-errors', action='store_true',
37 dest='ignore_errors', default=False,
38 help='Send patches email even if patch errors are found')
Bin Meng0fc01bf2020-05-04 00:52:43 -070039parser.add_option('-l', '--limit-cc', dest='limit', type='int',
40 default=None, help='Limit the cc list to LIMIT entries [default: %default]')
Simon Glass983a2742014-09-14 20:23:17 -060041parser.add_option('-m', '--no-maintainers', action='store_false',
42 dest='add_maintainers', default=True,
43 help="Don't cc the file maintainers automatically")
Simon Glass0d24de92012-01-14 15:12:45 +000044parser.add_option('-n', '--dry-run', action='store_true', dest='dry_run',
Simon Glassca706e72013-03-26 13:09:45 +000045 default=False, help="Do a dry run (create but don't email patches)")
Vadim Bendebury99adf6e2013-01-09 16:00:10 +000046parser.add_option('-p', '--project', default=project.DetectProject(),
47 help="Project name; affects default option values and "
48 "aliases [default: %default]")
Doug Anderson6d819922013-03-17 10:31:04 +000049parser.add_option('-r', '--in-reply-to', type='string', action='store',
50 help="Message ID that this series is in reply to")
Simon Glass0d24de92012-01-14 15:12:45 +000051parser.add_option('-s', '--start', dest='start', type='int',
52 default=0, help='Commit to start creating patches from (0 = HEAD)')
Simon Glassa1318f72013-03-26 13:09:42 +000053parser.add_option('-t', '--ignore-bad-tags', action='store_true',
54 default=False, help='Ignore bad tags / aliases')
Simon Glass0d24de92012-01-14 15:12:45 +000055parser.add_option('-v', '--verbose', action='store_true', dest='verbose',
56 default=False, help='Verbose output of errors and warnings')
Bin Meng0fc01bf2020-05-04 00:52:43 -070057parser.add_option('-T', '--thread', action='store_true', dest='thread',
58 default=False, help='Create patches as a single thread')
Simon Glass0d24de92012-01-14 15:12:45 +000059parser.add_option('--cc-cmd', dest='cc_cmd', type='string', action='store',
60 default=None, help='Output cc list for patch file (used by git)')
Bin Meng14aa35a2020-05-04 00:52:44 -070061parser.add_option('--no-binary', action='store_true', dest='ignore_binary',
62 default=False,
63 help="Do not output contents of changes in binary files")
Vadim Bendebury99adf6e2013-01-09 16:00:10 +000064parser.add_option('--no-check', action='store_false', dest='check_patch',
65 default=True,
66 help="Don't check for patch compliance")
Simon Glass0d24de92012-01-14 15:12:45 +000067parser.add_option('--no-tags', action='store_false', dest='process_tags',
Sean Anderson6949f702020-05-04 16:28:34 -040068 default=True, help="Don't process subject tags as aliases")
Simon Glassa60aedf2018-06-19 09:56:07 -060069parser.add_option('--smtp-server', type='str',
70 help="Specify the SMTP server to 'git send-email'")
Bin Meng0fc01bf2020-05-04 00:52:43 -070071parser.add_option('--test', action='store_true', dest='test',
72 default=False, help='run tests')
Simon Glass0d24de92012-01-14 15:12:45 +000073
Masahiro Yamadae0a4d062014-08-21 14:28:03 +090074parser.usage += """
Simon Glass0d24de92012-01-14 15:12:45 +000075
76Create patches from commits in a branch, check them and email them as
Simon Glassca706e72013-03-26 13:09:45 +000077specified by tags you place in the commits. Use -n to do a dry run first."""
Simon Glass0d24de92012-01-14 15:12:45 +000078
Doug Anderson8568bae2012-12-03 14:43:17 +000079
Doug Andersona1dcee82012-12-03 14:43:18 +000080# Parse options twice: first to get the project and second to handle
81# defaults properly (which depends on project).
82(options, args) = parser.parse_args()
83settings.Setup(parser, options.project, '')
Simon Glass0d24de92012-01-14 15:12:45 +000084(options, args) = parser.parse_args()
85
Simon Glass9649e152015-07-30 13:47:41 -060086if __name__ != "__main__":
87 pass
88
Simon Glass0d24de92012-01-14 15:12:45 +000089# Run our meagre tests
Simon Glass9649e152015-07-30 13:47:41 -060090elif options.test:
Simon Glass0d24de92012-01-14 15:12:45 +000091 import doctest
Simon Glassbf776672020-04-17 18:09:04 -060092 from patman import func_test
Simon Glass0d24de92012-01-14 15:12:45 +000093
94 sys.argv = [sys.argv[0]]
Simon Glass0d24de92012-01-14 15:12:45 +000095 result = unittest.TestResult()
Simon Glass6e87ae12017-05-29 15:31:31 -060096 for module in (test.TestPatch, func_test.TestFunctional):
97 suite = unittest.TestLoader().loadTestsFromTestCase(module)
98 suite.run(result)
Simon Glass0d24de92012-01-14 15:12:45 +000099
Simon Glass37b224f2020-04-09 15:08:40 -0600100 for module in ['gitutil', 'settings', 'terminal']:
Doug Anderson656cffe2012-12-03 14:43:19 +0000101 suite = doctest.DocTestSuite(module)
102 suite.run(result)
Simon Glass0d24de92012-01-14 15:12:45 +0000103
104 # TODO: Surely we can just 'print' result?
Paul Burtona920a172016-09-27 16:03:50 +0100105 print(result)
Simon Glass0d24de92012-01-14 15:12:45 +0000106 for test, err in result.errors:
Paul Burtona920a172016-09-27 16:03:50 +0100107 print(err)
Simon Glass0d24de92012-01-14 15:12:45 +0000108 for test, err in result.failures:
Paul Burtona920a172016-09-27 16:03:50 +0100109 print(err)
Simon Glass0d24de92012-01-14 15:12:45 +0000110
111# Called from git with a patch filename as argument
112# Printout a list of additional CC recipients for this patch
113elif options.cc_cmd:
114 fd = open(options.cc_cmd, 'r')
115 re_line = re.compile('(\S*) (.*)')
116 for line in fd.readlines():
117 match = re_line.match(line)
118 if match and match.group(1) == args[0]:
Dmitry Torokhov8ab452d2019-10-21 20:09:56 -0700119 for cc in match.group(2).split('\0'):
Simon Glass0d24de92012-01-14 15:12:45 +0000120 cc = cc.strip()
121 if cc:
Paul Burtona920a172016-09-27 16:03:50 +0100122 print(cc)
Simon Glass0d24de92012-01-14 15:12:45 +0000123 fd.close()
124
125elif options.full_help:
126 pager = os.getenv('PAGER')
127 if not pager:
128 pager = 'more'
Simon Glass2bdeade2016-03-06 19:45:34 -0700129 fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
130 'README')
Simon Glass0d24de92012-01-14 15:12:45 +0000131 command.Run(pager, fname)
132
133# Process commits, produce patches files, check them, email them
134else:
135 gitutil.Setup()
136
137 if options.count == -1:
138 # Work out how many patches to send if we can
139 options.count = gitutil.CountCommitsToBranch() - options.start
140
141 col = terminal.Color()
142 if not options.count:
143 str = 'No commits found to process - please use -c flag'
Masahiro Yamada31e21412014-08-16 00:59:26 +0900144 sys.exit(col.Color(col.RED, str))
Simon Glass0d24de92012-01-14 15:12:45 +0000145
146 # Read the metadata from the commits
147 if options.count:
148 series = patchstream.GetMetaData(options.start, options.count)
149 cover_fname, args = gitutil.CreatePatches(options.start, options.count,
Bin Meng14aa35a2020-05-04 00:52:44 -0700150 options.ignore_binary, series)
Simon Glass0d24de92012-01-14 15:12:45 +0000151
152 # Fix up the patch files to our liking, and insert the cover letter
Simon Glassdb116cc2017-05-29 15:31:27 -0600153 patchstream.FixPatches(series, args)
154 if cover_fname and series.get('cover'):
Simon Glass0d24de92012-01-14 15:12:45 +0000155 patchstream.InsertCoverLetter(cover_fname, series, options.count)
156
157 # Do a few checks on the series
158 series.DoChecks()
159
160 # Check the patches, and run them through 'git am' just to be sure
Vadim Bendebury99adf6e2013-01-09 16:00:10 +0000161 if options.check_patch:
162 ok = checkpatch.CheckPatches(options.verbose, args)
163 else:
164 ok = True
Simon Glass0d24de92012-01-14 15:12:45 +0000165
Simon Glassa1318f72013-03-26 13:09:42 +0000166 cc_file = series.MakeCcFile(options.process_tags, cover_fname,
Simon Glass983a2742014-09-14 20:23:17 -0600167 not options.ignore_bad_tags,
Chris Packham4fb35022018-06-07 20:45:06 +1200168 options.add_maintainers, options.limit)
Doug Andersond94566a2012-12-03 14:40:42 +0000169
Simon Glass0d24de92012-01-14 15:12:45 +0000170 # Email the patches out (giving the user time to check / cancel)
171 cmd = ''
Vadim Bendebury1f727882014-09-04 10:45:13 -0700172 its_a_go = ok or options.ignore_errors
173 if its_a_go:
Simon Glass0d24de92012-01-14 15:12:45 +0000174 cmd = gitutil.EmailPatches(series, cover_fname, args,
Simon Glassa1318f72013-03-26 13:09:42 +0000175 options.dry_run, not options.ignore_bad_tags, cc_file,
Simon Glassa60aedf2018-06-19 09:56:07 -0600176 in_reply_to=options.in_reply_to, thread=options.thread,
177 smtp_server=options.smtp_server)
Vadim Bendebury1f727882014-09-04 10:45:13 -0700178 else:
Paul Burtona920a172016-09-27 16:03:50 +0100179 print(col.Color(col.RED, "Not sending emails due to errors/warnings"))
Simon Glass0d24de92012-01-14 15:12:45 +0000180
181 # For a dry run, just show our actions as a sanity check
182 if options.dry_run:
183 series.ShowActions(args, cmd, options.process_tags)
Vadim Bendebury1f727882014-09-04 10:45:13 -0700184 if not its_a_go:
Paul Burtona920a172016-09-27 16:03:50 +0100185 print(col.Color(col.RED, "Email would not be sent"))
Doug Andersond94566a2012-12-03 14:40:42 +0000186
187 os.remove(cc_file)