blob: 72c67b8bbd45d9ea10e468759bd603793a090f8a [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)')
Vadim Bendeburyc549f082013-01-09 16:00:10 +000061parser.add_option('--no-check', action='store_false', dest='check_patch',
62 default=True,
63 help="Don't check for patch compliance")
Simon Glass26132882012-01-14 15:12:45 +000064parser.add_option('--no-tags', action='store_false', dest='process_tags',
65 default=True, help="Don't process subject tags as aliaes")
Simon Glass8137e302018-06-19 09:56:07 -060066parser.add_option('--smtp-server', type='str',
67 help="Specify the SMTP server to 'git send-email'")
Bin Meng5b0a5112020-05-04 00:52:43 -070068parser.add_option('--test', action='store_true', dest='test',
69 default=False, help='run tests')
Simon Glass26132882012-01-14 15:12:45 +000070
Masahiro Yamadaa97f35f2014-08-21 14:28:03 +090071parser.usage += """
Simon Glass26132882012-01-14 15:12:45 +000072
73Create patches from commits in a branch, check them and email them as
Simon Glass33bdd9e2013-03-26 13:09:45 +000074specified by tags you place in the commits. Use -n to do a dry run first."""
Simon Glass26132882012-01-14 15:12:45 +000075
Doug Anderson3d3077c2012-12-03 14:43:17 +000076
Doug Anderson31ffd7f2012-12-03 14:43:18 +000077# Parse options twice: first to get the project and second to handle
78# defaults properly (which depends on project).
79(options, args) = parser.parse_args()
80settings.Setup(parser, options.project, '')
Simon Glass26132882012-01-14 15:12:45 +000081(options, args) = parser.parse_args()
82
Simon Glass2b68b362015-07-30 13:47:41 -060083if __name__ != "__main__":
84 pass
85
Simon Glass26132882012-01-14 15:12:45 +000086# Run our meagre tests
Simon Glass2b68b362015-07-30 13:47:41 -060087elif options.test:
Simon Glass26132882012-01-14 15:12:45 +000088 import doctest
Simon Glassa997ea52020-04-17 18:09:04 -060089 from patman import func_test
Simon Glass26132882012-01-14 15:12:45 +000090
91 sys.argv = [sys.argv[0]]
Simon Glass26132882012-01-14 15:12:45 +000092 result = unittest.TestResult()
Simon Glassdf1bc5c2017-05-29 15:31:31 -060093 for module in (test.TestPatch, func_test.TestFunctional):
94 suite = unittest.TestLoader().loadTestsFromTestCase(module)
95 suite.run(result)
Simon Glass26132882012-01-14 15:12:45 +000096
Simon Glass5f9325d2020-04-09 15:08:40 -060097 for module in ['gitutil', 'settings', 'terminal']:
Doug Anderson06a95152012-12-03 14:43:19 +000098 suite = doctest.DocTestSuite(module)
99 suite.run(result)
Simon Glass26132882012-01-14 15:12:45 +0000100
101 # TODO: Surely we can just 'print' result?
Paul Burtonc3931342016-09-27 16:03:50 +0100102 print(result)
Simon Glass26132882012-01-14 15:12:45 +0000103 for test, err in result.errors:
Paul Burtonc3931342016-09-27 16:03:50 +0100104 print(err)
Simon Glass26132882012-01-14 15:12:45 +0000105 for test, err in result.failures:
Paul Burtonc3931342016-09-27 16:03:50 +0100106 print(err)
Simon Glass26132882012-01-14 15:12:45 +0000107
108# Called from git with a patch filename as argument
109# Printout a list of additional CC recipients for this patch
110elif options.cc_cmd:
111 fd = open(options.cc_cmd, 'r')
112 re_line = re.compile('(\S*) (.*)')
113 for line in fd.readlines():
114 match = re_line.match(line)
115 if match and match.group(1) == args[0]:
Dmitry Torokhovef7f67d2019-10-21 20:09:56 -0700116 for cc in match.group(2).split('\0'):
Simon Glass26132882012-01-14 15:12:45 +0000117 cc = cc.strip()
118 if cc:
Paul Burtonc3931342016-09-27 16:03:50 +0100119 print(cc)
Simon Glass26132882012-01-14 15:12:45 +0000120 fd.close()
121
122elif options.full_help:
123 pager = os.getenv('PAGER')
124 if not pager:
125 pager = 'more'
Simon Glassc29101f2016-03-06 19:45:34 -0700126 fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
127 'README')
Simon Glass26132882012-01-14 15:12:45 +0000128 command.Run(pager, fname)
129
130# Process commits, produce patches files, check them, email them
131else:
132 gitutil.Setup()
133
134 if options.count == -1:
135 # Work out how many patches to send if we can
136 options.count = gitutil.CountCommitsToBranch() - options.start
137
138 col = terminal.Color()
139 if not options.count:
140 str = 'No commits found to process - please use -c flag'
Masahiro Yamada880828d2014-08-16 00:59:26 +0900141 sys.exit(col.Color(col.RED, str))
Simon Glass26132882012-01-14 15:12:45 +0000142
143 # Read the metadata from the commits
144 if options.count:
145 series = patchstream.GetMetaData(options.start, options.count)
146 cover_fname, args = gitutil.CreatePatches(options.start, options.count,
147 series)
148
149 # Fix up the patch files to our liking, and insert the cover letter
Simon Glassfdf70022017-05-29 15:31:27 -0600150 patchstream.FixPatches(series, args)
151 if cover_fname and series.get('cover'):
Simon Glass26132882012-01-14 15:12:45 +0000152 patchstream.InsertCoverLetter(cover_fname, series, options.count)
153
154 # Do a few checks on the series
155 series.DoChecks()
156
157 # Check the patches, and run them through 'git am' just to be sure
Vadim Bendeburyc549f082013-01-09 16:00:10 +0000158 if options.check_patch:
159 ok = checkpatch.CheckPatches(options.verbose, args)
160 else:
161 ok = True
Simon Glass26132882012-01-14 15:12:45 +0000162
Simon Glass12ea5f42013-03-26 13:09:42 +0000163 cc_file = series.MakeCcFile(options.process_tags, cover_fname,
Simon Glass46b84d82014-09-14 20:23:17 -0600164 not options.ignore_bad_tags,
Chris Packhamb84fb482018-06-07 20:45:06 +1200165 options.add_maintainers, options.limit)
Doug Anderson507e8e82012-12-03 14:40:42 +0000166
Simon Glass26132882012-01-14 15:12:45 +0000167 # Email the patches out (giving the user time to check / cancel)
168 cmd = ''
Vadim Bendeburyfbf8ee02014-09-04 10:45:13 -0700169 its_a_go = ok or options.ignore_errors
170 if its_a_go:
Simon Glass26132882012-01-14 15:12:45 +0000171 cmd = gitutil.EmailPatches(series, cover_fname, args,
Simon Glass12ea5f42013-03-26 13:09:42 +0000172 options.dry_run, not options.ignore_bad_tags, cc_file,
Simon Glass8137e302018-06-19 09:56:07 -0600173 in_reply_to=options.in_reply_to, thread=options.thread,
174 smtp_server=options.smtp_server)
Vadim Bendeburyfbf8ee02014-09-04 10:45:13 -0700175 else:
Paul Burtonc3931342016-09-27 16:03:50 +0100176 print(col.Color(col.RED, "Not sending emails due to errors/warnings"))
Simon Glass26132882012-01-14 15:12:45 +0000177
178 # For a dry run, just show our actions as a sanity check
179 if options.dry_run:
180 series.ShowActions(args, cmd, options.process_tags)
Vadim Bendeburyfbf8ee02014-09-04 10:45:13 -0700181 if not its_a_go:
Paul Burtonc3931342016-09-27 16:03:50 +0100182 print(col.Color(col.RED, "Email would not be sent"))
Doug Anderson507e8e82012-12-03 14:40:42 +0000183
184 os.remove(cc_file)