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