blob: b48eac41fd7dae5e56222403fbed6cf615ba5d2f [file] [log] [blame]
Simon Glass85a03de2020-07-05 21:41:49 -06001# SPDX-License-Identifier: GPL-2.0+
2#
3# Copyright 2020 Google LLC
4#
5"""Handles the main control logic of patman
6
7This module provides various functions called by the main program to implement
8the features of patman.
9"""
10
11import os
12import sys
13
14from patman import checkpatch
15from patman import gitutil
16from patman import patchstream
17from patman import terminal
18
19def setup():
20 """Do required setup before doing anything"""
21 gitutil.Setup()
22
Simon Glassb4aa8aa2020-07-05 21:41:51 -060023def prepare_patches(col, branch, count, start, ignore_binary):
Simon Glass85a03de2020-07-05 21:41:49 -060024 """Figure out what patches to generate, then generate them
25
26 The patch files are written to the current directory, e.g. 0001_xxx.patch
27 0002_yyy.patch
28
29 Args:
30 col (terminal.Color): Colour output object
Simon Glassb4aa8aa2020-07-05 21:41:51 -060031 branch (str): Branch to create patches from (None = current)
Simon Glass85a03de2020-07-05 21:41:49 -060032 count (int): Number of patches to produce, or -1 to produce patches for
33 the current branch back to the upstream commit
34 start (int): Start partch to use (0=first / top of branch)
35 ignore_binary (bool): Don't generate patches for binary files
36
37 Returns:
38 Tuple:
39 Series object for this series (set of patches)
40 Filename of the cover letter as a string (None if none)
41 patch_files: List of patch filenames, each a string, e.g.
42 ['0001_xxx.patch', '0002_yyy.patch']
43 """
44 if count == -1:
45 # Work out how many patches to send if we can
Simon Glassb4aa8aa2020-07-05 21:41:51 -060046 count = (gitutil.CountCommitsToBranch(branch) - start)
Simon Glass85a03de2020-07-05 21:41:49 -060047
48 if not count:
49 sys.exit(col.Color(col.RED,
50 'No commits found to process - please use -c flag'))
51
52 # Read the metadata from the commits
53 to_do = count
Simon Glassb4aa8aa2020-07-05 21:41:51 -060054 series = patchstream.GetMetaData(branch, start, to_do)
Simon Glass85a03de2020-07-05 21:41:49 -060055 cover_fname, patch_files = gitutil.CreatePatches(
Simon Glassb4aa8aa2020-07-05 21:41:51 -060056 branch, start, to_do, ignore_binary, series)
Simon Glass85a03de2020-07-05 21:41:49 -060057
58 # Fix up the patch files to our liking, and insert the cover letter
59 patchstream.FixPatches(series, patch_files)
60 if cover_fname and series.get('cover'):
61 patchstream.InsertCoverLetter(cover_fname, series, to_do)
62 return series, cover_fname, patch_files
63
64def check_patches(series, patch_files, run_checkpatch, verbose):
65 """Run some checks on a set of patches
66
67 This santiy-checks the patman tags like Series-version and runs the patches
68 through checkpatch
69
70 Args:
71 series (Series): Series object for this series (set of patches)
72 patch_files (list): List of patch filenames, each a string, e.g.
73 ['0001_xxx.patch', '0002_yyy.patch']
74 run_checkpatch (bool): True to run checkpatch.pl
75 verbose (bool): True to print out every line of the checkpatch output as
76 it is parsed
77
78 Returns:
79 bool: True if the patches had no errors, False if they did
80 """
81 # Do a few checks on the series
82 series.DoChecks()
83
84 # Check the patches, and run them through 'git am' just to be sure
85 if run_checkpatch:
86 ok = checkpatch.CheckPatches(verbose, patch_files)
87 else:
88 ok = True
89 return ok
90
91
92def email_patches(col, series, cover_fname, patch_files, process_tags, its_a_go,
93 ignore_bad_tags, add_maintainers, limit, dry_run, in_reply_to,
94 thread, smtp_server):
95 """Email patches to the recipients
96
97 This emails out the patches and cover letter using 'git send-email'. Each
98 patch is copied to recipients identified by the patch tag and output from
99 the get_maintainer.pl script. The cover letter is copied to all recipients
100 of any patch.
101
102 To make this work a CC file is created holding the recipients for each patch
103 and the cover letter. See the main program 'cc_cmd' for this logic.
104
105 Args:
106 col (terminal.Color): Colour output object
107 series (Series): Series object for this series (set of patches)
108 cover_fname (str): Filename of the cover letter as a string (None if
109 none)
110 patch_files (list): List of patch filenames, each a string, e.g.
111 ['0001_xxx.patch', '0002_yyy.patch']
112 process_tags (bool): True to process subject tags in each patch, e.g.
113 for 'dm: spi: Add SPI support' this would be 'dm' and 'spi'. The
114 tags are looked up in the configured sendemail.aliasesfile and also
115 in ~/.patman (see README)
116 its_a_go (bool): True if we are going to actually send the patches,
117 False if the patches have errors and will not be sent unless
118 @ignore_errors
119 ignore_bad_tags (bool): True to just print a warning for unknown tags,
120 False to halt with an error
121 add_maintainers (bool): Run the get_maintainer.pl script for each patch
122 limit (int): Limit on the number of people that can be cc'd on a single
123 patch or the cover letter (None if no limit)
124 dry_run (bool): Don't actually email the patches, just print out what
125 would be sent
126 in_reply_to (str): If not None we'll pass this to git as --in-reply-to.
127 Should be a message ID that this is in reply to.
128 thread (bool): True to add --thread to git send-email (make all patches
129 reply to cover-letter or first patch in series)
130 smtp_server (str): SMTP server to use to send patches (None for default)
131 """
132 cc_file = series.MakeCcFile(process_tags, cover_fname, not ignore_bad_tags,
133 add_maintainers, limit)
134
135 # Email the patches out (giving the user time to check / cancel)
136 cmd = ''
137 if its_a_go:
138 cmd = gitutil.EmailPatches(
139 series, cover_fname, patch_files, dry_run, not ignore_bad_tags,
140 cc_file, in_reply_to=in_reply_to, thread=thread,
141 smtp_server=smtp_server)
142 else:
143 print(col.Color(col.RED, "Not sending emails due to errors/warnings"))
144
145 # For a dry run, just show our actions as a sanity check
146 if dry_run:
147 series.ShowActions(patch_files, cmd, process_tags)
148 if not its_a_go:
149 print(col.Color(col.RED, "Email would not be sent"))
150
151 os.remove(cc_file)
152
153def send(options):
154 """Create, check and send patches by email
155
156 Args:
157 options (optparse.Values): Arguments to patman
158 """
159 setup()
160 col = terminal.Color()
161 series, cover_fname, patch_files = prepare_patches(
Simon Glassb4aa8aa2020-07-05 21:41:51 -0600162 col, options.branch, options.count, options.start,
163 options.ignore_binary)
Simon Glass85a03de2020-07-05 21:41:49 -0600164 ok = check_patches(series, patch_files, options.check_patch,
165 options.verbose)
Simon Glassb4aa8aa2020-07-05 21:41:51 -0600166
Simon Glass85a03de2020-07-05 21:41:49 -0600167 its_a_go = ok or options.ignore_errors
168 if its_a_go:
169 email_patches(
170 col, series, cover_fname, patch_files, options.process_tags,
171 its_a_go, options.ignore_bad_tags, options.add_maintainers,
172 options.limit, options.dry_run, options.in_reply_to, options.thread,
173 options.smtp_server)