blob: 0974c840598b89a71f652f0815448ca3675ac87c [file] [log] [blame]
Simon Glassefeac062019-10-31 07:42:52 -06001#!/usr/bin/env python3
Tom Rini10e47792018-05-06 17:58:06 -04002# SPDX-License-Identifier: GPL-2.0+
Simon Glass26132882012-01-14 15:12:45 +00003#
4# Copyright (c) 2011 The Chromium OS Authors.
5#
Simon Glass26132882012-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 Glassbdaad402020-04-17 18:08:52 -060015if __name__ == "__main__":
Simon Glass42143162020-04-17 18:09:05 -060016 # Allow 'from patman import xxx to work'
Simon Glassbdaad402020-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 Glass26132882012-01-14 15:12:45 +000020# Our modules
Simon Glassa997ea52020-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 Glass26132882012-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 Meng5b0a5112020-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 Glass46b84d82014-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 Glass26132882012-01-14 15:12:45 +000044parser.add_option('-n', '--dry-run', action='store_true', dest='dry_run',
Simon Glass33bdd9e2013-03-26 13:09:45 +000045 default=False, help="Do a dry run (create but don't email patches)")
Vadim Bendeburyc549f082013-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 Anderson06f27ac2013-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 Glass26132882012-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 Glass12ea5f42013-03-26 13:09:42 +000053parser.add_option('-t', '--ignore-bad-tags', action='store_true',
54 default=False, help='Ignore bad tags / aliases')
Simon Glass26132882012-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 Meng5b0a5112020-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 Glass26132882012-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 Menga04f1212020-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 Bendeburyc549f082013-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 Glass26132882012-01-14 15:12:45 +000067parser.add_option('--no-tags', action='store_false', dest='process_tags',
Sean Anderson48f46d62020-05-04 16:28:34 -040068 default=True, help="Don't process subject tags as aliases")
Simon Glass8137e302018-06-19 09:56:07 -060069parser.add_option('--smtp-server', type='str',
70 help="Specify the SMTP server to 'git send-email'")
Bin Meng5b0a5112020-05-04 00:52:43 -070071parser.add_option('--test', action='store_true', dest='test',
72 default=False, help='run tests')
Simon Glass26132882012-01-14 15:12:45 +000073
Masahiro Yamadaa97f35f2014-08-21 14:28:03 +090074parser.usage += """
Simon Glass26132882012-01-14 15:12:45 +000075
76Create patches from commits in a branch, check them and email them as
Simon Glass33bdd9e2013-03-26 13:09:45 +000077specified by tags you place in the commits. Use -n to do a dry run first."""
Simon Glass26132882012-01-14 15:12:45 +000078
Doug Anderson3d3077c2012-12-03 14:43:17 +000079
Doug Anderson31ffd7f2012-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 Glass26132882012-01-14 15:12:45 +000084(options, args) = parser.parse_args()
85
Simon Glass2b68b362015-07-30 13:47:41 -060086if __name__ != "__main__":
87 pass
88
Simon Glass26132882012-01-14 15:12:45 +000089# Run our meagre tests
Simon Glass2b68b362015-07-30 13:47:41 -060090elif options.test:
Simon Glass26132882012-01-14 15:12:45 +000091 import doctest
Simon Glassa997ea52020-04-17 18:09:04 -060092 from patman import func_test
Simon Glass26132882012-01-14 15:12:45 +000093
94 sys.argv = [sys.argv[0]]
Simon Glass26132882012-01-14 15:12:45 +000095 result = unittest.TestResult()
Simon Glassdf1bc5c2017-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 Glass26132882012-01-14 15:12:45 +000099
Simon Glass5f9325d2020-04-09 15:08:40 -0600100 for module in ['gitutil', 'settings', 'terminal']:
Doug Anderson06a95152012-12-03 14:43:19 +0000101 suite = doctest.DocTestSuite(module)
102 suite.run(result)
Simon Glass26132882012-01-14 15:12:45 +0000103
104 # TODO: Surely we can just 'print' result?
Paul Burtonc3931342016-09-27 16:03:50 +0100105 print(result)
Simon Glass26132882012-01-14 15:12:45 +0000106 for test, err in result.errors:
Paul Burtonc3931342016-09-27 16:03:50 +0100107 print(err)
Simon Glass26132882012-01-14 15:12:45 +0000108 for test, err in result.failures:
Paul Burtonc3931342016-09-27 16:03:50 +0100109 print(err)
Simon Glass26132882012-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 Torokhovef7f67d2019-10-21 20:09:56 -0700119 for cc in match.group(2).split('\0'):
Simon Glass26132882012-01-14 15:12:45 +0000120 cc = cc.strip()
121 if cc:
Paul Burtonc3931342016-09-27 16:03:50 +0100122 print(cc)
Simon Glass26132882012-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 Glassc29101f2016-03-06 19:45:34 -0700129 fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
130 'README')
Simon Glass26132882012-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 Yamada880828d2014-08-16 00:59:26 +0900144 sys.exit(col.Color(col.RED, str))
Simon Glass26132882012-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 Menga04f1212020-05-04 00:52:44 -0700150 options.ignore_binary, series)
Simon Glass26132882012-01-14 15:12:45 +0000151
152 # Fix up the patch files to our liking, and insert the cover letter
Simon Glassfdf70022017-05-29 15:31:27 -0600153 patchstream.FixPatches(series, args)
154 if cover_fname and series.get('cover'):
Simon Glass26132882012-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 Bendeburyc549f082013-01-09 16:00:10 +0000161 if options.check_patch:
162 ok = checkpatch.CheckPatches(options.verbose, args)
163 else:
164 ok = True
Simon Glass26132882012-01-14 15:12:45 +0000165
Simon Glass12ea5f42013-03-26 13:09:42 +0000166 cc_file = series.MakeCcFile(options.process_tags, cover_fname,
Simon Glass46b84d82014-09-14 20:23:17 -0600167 not options.ignore_bad_tags,
Chris Packhamb84fb482018-06-07 20:45:06 +1200168 options.add_maintainers, options.limit)
Doug Anderson507e8e82012-12-03 14:40:42 +0000169
Simon Glass26132882012-01-14 15:12:45 +0000170 # Email the patches out (giving the user time to check / cancel)
171 cmd = ''
Vadim Bendeburyfbf8ee02014-09-04 10:45:13 -0700172 its_a_go = ok or options.ignore_errors
173 if its_a_go:
Simon Glass26132882012-01-14 15:12:45 +0000174 cmd = gitutil.EmailPatches(series, cover_fname, args,
Simon Glass12ea5f42013-03-26 13:09:42 +0000175 options.dry_run, not options.ignore_bad_tags, cc_file,
Simon Glass8137e302018-06-19 09:56:07 -0600176 in_reply_to=options.in_reply_to, thread=options.thread,
177 smtp_server=options.smtp_server)
Vadim Bendeburyfbf8ee02014-09-04 10:45:13 -0700178 else:
Paul Burtonc3931342016-09-27 16:03:50 +0100179 print(col.Color(col.RED, "Not sending emails due to errors/warnings"))
Simon Glass26132882012-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 Bendeburyfbf8ee02014-09-04 10:45:13 -0700184 if not its_a_go:
Paul Burtonc3931342016-09-27 16:03:50 +0100185 print(col.Color(col.RED, "Email would not be sent"))
Doug Anderson507e8e82012-12-03 14:40:42 +0000186
187 os.remove(cc_file)