"Das U-Boot" Source Tree
at master 246 lines 10 kB view raw
1# 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 u_boot_pylib import terminal 18 19 20def setup(): 21 """Do required setup before doing anything""" 22 gitutil.setup() 23 24 25def prepare_patches(col, branch, count, start, end, ignore_binary, signoff, 26 keep_change_id=False): 27 """Figure out what patches to generate, then generate them 28 29 The patch files are written to the current directory, e.g. 0001_xxx.patch 30 0002_yyy.patch 31 32 Args: 33 col (terminal.Color): Colour output object 34 branch (str): Branch to create patches from (None = current) 35 count (int): Number of patches to produce, or -1 to produce patches for 36 the current branch back to the upstream commit 37 start (int): Start partch to use (0=first / top of branch) 38 end (int): End patch to use (0=last one in series, 1=one before that, 39 etc.) 40 ignore_binary (bool): Don't generate patches for binary files 41 keep_change_id (bool): Preserve the Change-Id tag. 42 43 Returns: 44 Tuple: 45 Series object for this series (set of patches) 46 Filename of the cover letter as a string (None if none) 47 patch_files: List of patch filenames, each a string, e.g. 48 ['0001_xxx.patch', '0002_yyy.patch'] 49 """ 50 if count == -1: 51 # Work out how many patches to send if we can 52 count = (gitutil.count_commits_to_branch(branch) - start) 53 54 if not count: 55 str = 'No commits found to process - please use -c flag, or run:\n' \ 56 ' git branch --set-upstream-to remote/branch' 57 sys.exit(col.build(col.RED, str)) 58 59 # Read the metadata from the commits 60 to_do = count - end 61 series = patchstream.get_metadata(branch, start, to_do) 62 cover_fname, patch_files = gitutil.create_patches( 63 branch, start, to_do, ignore_binary, series, signoff) 64 65 # Fix up the patch files to our liking, and insert the cover letter 66 patchstream.fix_patches(series, patch_files, keep_change_id) 67 if cover_fname and series.get('cover'): 68 patchstream.insert_cover_letter(cover_fname, series, to_do) 69 return series, cover_fname, patch_files 70 71 72def check_patches(series, patch_files, run_checkpatch, verbose, use_tree): 73 """Run some checks on a set of patches 74 75 This santiy-checks the patman tags like Series-version and runs the patches 76 through checkpatch 77 78 Args: 79 series (Series): Series object for this series (set of patches) 80 patch_files (list): List of patch filenames, each a string, e.g. 81 ['0001_xxx.patch', '0002_yyy.patch'] 82 run_checkpatch (bool): True to run checkpatch.pl 83 verbose (bool): True to print out every line of the checkpatch output as 84 it is parsed 85 use_tree (bool): If False we'll pass '--no-tree' to checkpatch. 86 87 Returns: 88 bool: True if the patches had no errors, False if they did 89 """ 90 # Do a few checks on the series 91 series.DoChecks() 92 93 # Check the patches 94 if run_checkpatch: 95 ok = checkpatch.check_patches(verbose, patch_files, use_tree) 96 else: 97 ok = True 98 return ok 99 100 101def email_patches(col, series, cover_fname, patch_files, process_tags, its_a_go, 102 ignore_bad_tags, add_maintainers, get_maintainer_script, limit, 103 dry_run, in_reply_to, thread, smtp_server): 104 """Email patches to the recipients 105 106 This emails out the patches and cover letter using 'git send-email'. Each 107 patch is copied to recipients identified by the patch tag and output from 108 the get_maintainer.pl script. The cover letter is copied to all recipients 109 of any patch. 110 111 To make this work a CC file is created holding the recipients for each patch 112 and the cover letter. See the main program 'cc_cmd' for this logic. 113 114 Args: 115 col (terminal.Color): Colour output object 116 series (Series): Series object for this series (set of patches) 117 cover_fname (str): Filename of the cover letter as a string (None if 118 none) 119 patch_files (list): List of patch filenames, each a string, e.g. 120 ['0001_xxx.patch', '0002_yyy.patch'] 121 process_tags (bool): True to process subject tags in each patch, e.g. 122 for 'dm: spi: Add SPI support' this would be 'dm' and 'spi'. The 123 tags are looked up in the configured sendemail.aliasesfile and also 124 in ~/.patman (see README) 125 its_a_go (bool): True if we are going to actually send the patches, 126 False if the patches have errors and will not be sent unless 127 @ignore_errors 128 ignore_bad_tags (bool): True to just print a warning for unknown tags, 129 False to halt with an error 130 add_maintainers (bool): Run the get_maintainer.pl script for each patch 131 get_maintainer_script (str): The script used to retrieve which 132 maintainers to cc 133 limit (int): Limit on the number of people that can be cc'd on a single 134 patch or the cover letter (None if no limit) 135 dry_run (bool): Don't actually email the patches, just print out what 136 would be sent 137 in_reply_to (str): If not None we'll pass this to git as --in-reply-to. 138 Should be a message ID that this is in reply to. 139 thread (bool): True to add --thread to git send-email (make all patches 140 reply to cover-letter or first patch in series) 141 smtp_server (str): SMTP server to use to send patches (None for default) 142 """ 143 cc_file = series.MakeCcFile(process_tags, cover_fname, not ignore_bad_tags, 144 add_maintainers, limit, get_maintainer_script) 145 146 # Email the patches out (giving the user time to check / cancel) 147 cmd = '' 148 if its_a_go: 149 cmd = gitutil.email_patches( 150 series, cover_fname, patch_files, dry_run, not ignore_bad_tags, 151 cc_file, in_reply_to=in_reply_to, thread=thread, 152 smtp_server=smtp_server) 153 else: 154 print(col.build(col.RED, "Not sending emails due to errors/warnings")) 155 156 # For a dry run, just show our actions as a sanity check 157 if dry_run: 158 series.ShowActions(patch_files, cmd, process_tags) 159 if not its_a_go: 160 print(col.build(col.RED, "Email would not be sent")) 161 162 os.remove(cc_file) 163 164def send(args): 165 """Create, check and send patches by email 166 167 Args: 168 args (argparse.Namespace): Arguments to patman 169 """ 170 setup() 171 col = terminal.Color() 172 series, cover_fname, patch_files = prepare_patches( 173 col, args.branch, args.count, args.start, args.end, 174 args.ignore_binary, args.add_signoff, 175 keep_change_id=args.keep_change_id) 176 ok = check_patches(series, patch_files, args.check_patch, 177 args.verbose, args.check_patch_use_tree) 178 179 ok = ok and gitutil.check_suppress_cc_config() 180 181 its_a_go = ok or args.ignore_errors 182 email_patches( 183 col, series, cover_fname, patch_files, args.process_tags, 184 its_a_go, args.ignore_bad_tags, args.add_maintainers, 185 args.get_maintainer_script, args.limit, args.dry_run, 186 args.in_reply_to, args.thread, args.smtp_server) 187 188def patchwork_status(branch, count, start, end, dest_branch, force, 189 show_comments, url): 190 """Check the status of patches in patchwork 191 192 This finds the series in patchwork using the Series-link tag, checks for new 193 comments and review tags, displays then and creates a new branch with the 194 review tags. 195 196 Args: 197 branch (str): Branch to create patches from (None = current) 198 count (int): Number of patches to produce, or -1 to produce patches for 199 the current branch back to the upstream commit 200 start (int): Start partch to use (0=first / top of branch) 201 end (int): End patch to use (0=last one in series, 1=one before that, 202 etc.) 203 dest_branch (str): Name of new branch to create with the updated tags 204 (None to not create a branch) 205 force (bool): With dest_branch, force overwriting an existing branch 206 show_comments (bool): True to display snippets from the comments 207 provided by reviewers 208 url (str): URL of patchwork server, e.g. 'https://patchwork.ozlabs.org'. 209 This is ignored if the series provides a Series-patchwork-url tag. 210 211 Raises: 212 ValueError: if the branch has no Series-link value 213 """ 214 if count == -1: 215 # Work out how many patches to send if we can 216 count = (gitutil.count_commits_to_branch(branch) - start) 217 218 series = patchstream.get_metadata(branch, start, count - end) 219 warnings = 0 220 for cmt in series.commits: 221 if cmt.warn: 222 print('%d warnings for %s:' % (len(cmt.warn), cmt.hash)) 223 for warn in cmt.warn: 224 print('\t', warn) 225 warnings += 1 226 print 227 if warnings: 228 raise ValueError('Please fix warnings before running status') 229 links = series.get('links') 230 if not links: 231 raise ValueError("Branch has no Series-links value") 232 233 # Find the link without a version number (we don't support versions yet) 234 found = [link for link in links.split() if not ':' in link] 235 if not found: 236 raise ValueError('Series-links has no current version (without :)') 237 238 # Allow the series to override the URL 239 if 'patchwork_url' in series: 240 url = series.patchwork_url 241 242 # Import this here to avoid failing on other commands if the dependencies 243 # are not present 244 from patman import status 245 status.check_patchwork_status(series, found[0], branch, dest_branch, force, 246 show_comments, url)