Blame view
tools/patman/series.py
9.14 KB
0d24de9d5 Add 'patman' patc... |
1 2 |
# Copyright (c) 2011 The Chromium OS Authors. # |
1a4596601 Add GPL-2.0+ SPDX... |
3 |
# SPDX-License-Identifier: GPL-2.0+ |
0d24de9d5 Add 'patman' patc... |
4 |
# |
311872551 patman: Add all C... |
5 |
import itertools |
0d24de9d5 Add 'patman' patc... |
6 |
import os |
21a19d70e patman: Add a cal... |
7 |
import get_maintainer |
0d24de9d5 Add 'patman' patc... |
8 9 10 11 |
import gitutil import terminal # Series-xxx tags that we understand |
fe2f8d9e2 patman: Add Cover... |
12 |
valid_series = ['to', 'cc', 'version', 'changes', 'prefix', 'notes', 'name', |
645b271a6 patman: Add Serie... |
13 |
'cover-cc', 'process_log'] |
0d24de9d5 Add 'patman' patc... |
14 15 16 17 18 19 20 21 22 23 24 |
class Series(dict): """Holds information about a patch series, including all tags. Vars: cc: List of aliases/emails to Cc all patches to commits: List of Commit objects, one for each patch cover: List of lines in the cover letter notes: List of lines in the notes changes: (dict) List of changes for each version, The key is the integer version number |
f0b739f15 buildman: Allow c... |
25 |
allow_overwrite: Allow tags to overwrite an existing tag |
0d24de9d5 Add 'patman' patc... |
26 27 28 29 |
""" def __init__(self): self.cc = [] self.to = [] |
fe2f8d9e2 patman: Add Cover... |
30 |
self.cover_cc = [] |
0d24de9d5 Add 'patman' patc... |
31 32 33 34 |
self.commits = [] self.cover = None self.notes = [] self.changes = {} |
f0b739f15 buildman: Allow c... |
35 |
self.allow_overwrite = False |
0d24de9d5 Add 'patman' patc... |
36 |
|
d94566a11 patman: Cache the... |
37 38 39 40 |
# Written in MakeCcFile() # key: name of patch file # value: list of email addresses self._generated_cc = {} |
0d24de9d5 Add 'patman' patc... |
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# These make us more like a dictionary def __setattr__(self, name, value): self[name] = value def __getattr__(self, name): return self[name] def AddTag(self, commit, line, name, value): """Add a new Series-xxx tag along with its value. Args: line: Source line containing tag (useful for debug/error messages) name: Tag name (part after 'Series-') value: Tag value (part after 'Series-xxx: ') """ # If we already have it, then add to our list |
fe2f8d9e2 patman: Add Cover... |
57 |
name = name.replace('-', '_') |
f0b739f15 buildman: Allow c... |
58 |
if name in self and not self.allow_overwrite: |
0d24de9d5 Add 'patman' patc... |
59 60 61 62 63 64 65 66 67 68 69 70 71 |
values = value.split(',') values = [str.strip() for str in values] if type(self[name]) != type([]): raise ValueError("In %s: line '%s': Cannot add another value " "'%s' to series '%s'" % (commit.hash, line, values, self[name])) self[name] += values # Otherwise just set the value elif name in valid_series: self[name] = value else: raise ValueError("In %s: line '%s': Unknown 'Series-%s': valid " |
ef0e9de82 patman: Support S... |
72 |
"options are %s" % (commit.hash, line, name, |
0d24de9d5 Add 'patman' patc... |
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
', '.join(valid_series))) def AddCommit(self, commit): """Add a commit into our list of commits We create a list of tags in the commit subject also. Args: commit: Commit object to add """ commit.CheckTags() self.commits.append(commit) def ShowActions(self, args, cmd, process_tags): """Show what actions we will/would perform Args: args: List of patch files we created cmd: The git command we would have run process_tags: Process tags as if they were aliases """ col = terminal.Color() print 'Dry run, so not doing much. But I would do this:' print print 'Send a total of %d patch%s with %scover letter.' % ( len(args), '' if len(args) == 1 else 'es', self.get('cover') and 'a ' or 'no ') # TODO: Colour the patches according to whether they passed checks for upto in range(len(args)): commit = self.commits[upto] print col.Color(col.GREEN, ' %s' % args[upto]) |
d94566a11 patman: Cache the... |
105 |
cc_list = list(self._generated_cc[commit.patch]) |
0d24de9d5 Add 'patman' patc... |
106 |
|
43de0244c patman: Do not Cc... |
107 108 109 110 111 112 |
# Skip items in To list if 'to' in self: try: map(cc_list.remove, gitutil.BuildEmailList(self.to)) except ValueError: pass |
0d24de9d5 Add 'patman' patc... |
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
for email in cc_list: if email == None: email = col.Color(col.YELLOW, "<alias '%s' not found>" % tag) if email: print ' Cc: ',email print for item in gitutil.BuildEmailList(self.get('to', '<none>')): print 'To:\t ', item for item in gitutil.BuildEmailList(self.cc): print 'Cc:\t ', item print 'Version: ', self.get('version') print 'Prefix:\t ', self.get('prefix') if self.cover: print 'Cover: %d lines' % len(self.cover) |
fe2f8d9e2 patman: Add Cover... |
128 129 |
cover_cc = gitutil.BuildEmailList(self.get('cover_cc', '')) all_ccs = itertools.chain(cover_cc, *self._generated_cc.values()) |
311872551 patman: Add all C... |
130 131 |
for email in set(all_ccs): print ' Cc: ',email |
0d24de9d5 Add 'patman' patc... |
132 133 134 135 136 137 138 139 |
if cmd: print 'Git command: %s' % cmd def MakeChangeLog(self, commit): """Create a list of changes for each version. Return: The change log as a list of strings, one per line |
27e976004 patman: Issue emp... |
140 |
Changes in v4: |
244e6f970 patman: Use rever... |
141 |
- Jog the dial back closer to the widget |
27e976004 patman: Issue emp... |
142 143 |
Changes in v3: None Changes in v2: |
0d24de9d5 Add 'patman' patc... |
144 145 |
- Fix the widget - Jog the dial |
0d24de9d5 Add 'patman' patc... |
146 147 148 |
etc. """ final = [] |
645b271a6 patman: Add Serie... |
149 150 |
process_it = self.get('process_log', '').split(',') process_it = [item.strip() for item in process_it] |
0d24de9d5 Add 'patman' patc... |
151 |
need_blank = False |
244e6f970 patman: Use rever... |
152 |
for change in sorted(self.changes, reverse=True): |
0d24de9d5 Add 'patman' patc... |
153 154 155 156 |
out = [] for this_commit, text in self.changes[change]: if commit and this_commit != commit: continue |
645b271a6 patman: Add Serie... |
157 158 |
if 'uniq' not in process_it or text not in out: out.append(text) |
27e976004 patman: Issue emp... |
159 160 |
line = 'Changes in v%d:' % change have_changes = len(out) > 0 |
645b271a6 patman: Add Serie... |
161 162 |
if 'sort' in process_it: out = sorted(out) |
27e976004 patman: Issue emp... |
163 164 165 166 167 168 169 170 |
if have_changes: out.insert(0, line) else: out = [line + ' None'] if need_blank: out.insert(0, '') final += out need_blank = have_changes |
0d24de9d5 Add 'patman' patc... |
171 172 173 174 175 176 177 178 179 180 181 182 |
if self.changes: final.append('') return final def DoChecks(self): """Check that each version has a change log Print an error if something is wrong. """ col = terminal.Color() if self.get('version'): changes_copy = dict(self.changes) |
d5f81d8ac patman: Allow for... |
183 |
for version in range(1, int(self.version) + 1): |
0d24de9d5 Add 'patman' patc... |
184 185 186 |
if self.changes.get(version): del changes_copy[version] else: |
d5f81d8ac patman: Allow for... |
187 188 189 |
if version > 1: str = 'Change log missing for v%d' % version print col.Color(col.RED, str) |
0d24de9d5 Add 'patman' patc... |
190 191 192 193 194 195 |
for version in changes_copy: str = 'Change log for unknown version v%d' % version print col.Color(col.RED, str) elif self.changes: str = 'Change log exists, but no version is set' print col.Color(col.RED, str) |
a1318f7cd patman: Provide o... |
196 |
def MakeCcFile(self, process_tags, cover_fname, raise_on_error): |
0d24de9d5 Add 'patman' patc... |
197 |
"""Make a cc file for us to use for per-commit Cc automation |
d94566a11 patman: Cache the... |
198 |
Also stores in self._generated_cc to make ShowActions() faster. |
0d24de9d5 Add 'patman' patc... |
199 200 |
Args: process_tags: Process tags as if they were aliases |
311872551 patman: Add all C... |
201 |
cover_fname: If non-None the name of the cover letter. |
a1318f7cd patman: Provide o... |
202 203 |
raise_on_error: True to raise an error when an alias fails to match, False to just print a message. |
0d24de9d5 Add 'patman' patc... |
204 205 206 207 208 209 |
Return: Filename of temp file created """ # Look for commit tags (of the form 'xxx:' at the start of the subject) fname = '/tmp/patman.%d' % os.getpid() fd = open(fname, 'w') |
311872551 patman: Add all C... |
210 |
all_ccs = [] |
0d24de9d5 Add 'patman' patc... |
211 212 213 |
for commit in self.commits: list = [] if process_tags: |
a1318f7cd patman: Provide o... |
214 215 216 217 |
list += gitutil.BuildEmailList(commit.tags, raise_on_error=raise_on_error) list += gitutil.BuildEmailList(commit.cc_list, raise_on_error=raise_on_error) |
21a19d70e patman: Add a cal... |
218 |
list += get_maintainer.GetMaintainer(commit.patch) |
311872551 patman: Add all C... |
219 |
all_ccs += list |
0d24de9d5 Add 'patman' patc... |
220 |
print >>fd, commit.patch, ', '.join(list) |
d94566a11 patman: Cache the... |
221 |
self._generated_cc[commit.patch] = list |
0d24de9d5 Add 'patman' patc... |
222 |
|
311872551 patman: Add all C... |
223 |
if cover_fname: |
fe2f8d9e2 patman: Add Cover... |
224 225 |
cover_cc = gitutil.BuildEmailList(self.get('cover_cc', '')) print >>fd, cover_fname, ', '.join(set(cover_cc + all_ccs)) |
311872551 patman: Add all C... |
226 |
|
0d24de9d5 Add 'patman' patc... |
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 |
fd.close() return fname def AddChange(self, version, commit, info): """Add a new change line to a version. This will later appear in the change log. Args: version: version number to add change list to info: change line for this version """ if not self.changes.get(version): self.changes[version] = [] self.changes[version].append([commit, info]) def GetPatchPrefix(self): """Get the patch version string Return: Patch string, like 'RFC PATCH v5' or just 'PATCH' """ version = '' if self.get('version'): version = ' v%s' % self['version'] # Get patch name prefix prefix = '' if self.get('prefix'): prefix = '%s ' % self['prefix'] return '%sPATCH%s' % (prefix, version) |