diff options
Diffstat (limited to 'tools/patman')
-rw-r--r-- | tools/patman/README | 13 | ||||
-rw-r--r-- | tools/patman/gitutil.py | 93 | ||||
-rw-r--r-- | tools/patman/patchstream.py | 4 | ||||
-rw-r--r-- | tools/patman/series.py | 21 |
4 files changed, 98 insertions, 33 deletions
diff --git a/tools/patman/README b/tools/patman/README index e466886ed2..7d039e82bc 100644 --- a/tools/patman/README +++ b/tools/patman/README @@ -52,12 +52,15 @@ will get a consistent result each time. How to configure it =================== -For most cases of using patman for U-Boot development, patman will -locate and use the file 'doc/git-mailrc' in your U-Boot directory. -This contains most of the aliases you will need. +For most cases of using patman for U-Boot development, patman can use the +file 'doc/git-mailrc' in your U-Boot directory to supply the email aliases +you need. To make this work, tell git where to find the file by typing +this once: -For Linux the 'scripts/get_maintainer.pl' handles figuring out where -to send patches pretty well. + git config sendemail.aliasesfile doc/git-mailrc + +For both Linux and U-Boot the 'scripts/get_maintainer.pl' handles figuring +out where to send patches pretty well. During the first run patman creates a config file for you by taking the default user name and email address from the global .gitconfig file. diff --git a/tools/patman/gitutil.py b/tools/patman/gitutil.py index b68df5d72e..c593070d67 100644 --- a/tools/patman/gitutil.py +++ b/tools/patman/gitutil.py @@ -61,6 +61,52 @@ def CountCommitsToBranch(): patch_count = int(stdout) return patch_count +def NameRevision(commit_hash): + """Gets the revision name for a commit + + Args: + commit_hash: Commit hash to look up + + Return: + Name of revision, if any, else None + """ + pipe = ['git', 'name-rev', commit_hash] + stdout = command.RunPipe([pipe], capture=True, oneline=True).stdout + + # We expect a commit, a space, then a revision name + name = stdout.split(' ')[1].strip() + return name + +def GuessUpstream(git_dir, branch): + """Tries to guess the upstream for a branch + + This lists out top commits on a branch and tries to find a suitable + upstream. It does this by looking for the first commit where + 'git name-rev' returns a plain branch name, with no ! or ^ modifiers. + + Args: + git_dir: Git directory containing repo + branch: Name of branch + + Returns: + Tuple: + Name of upstream branch (e.g. 'upstream/master') or None if none + Warning/error message, or None if none + """ + pipe = [LogCmd(branch, git_dir=git_dir, oneline=True, count=100)] + result = command.RunPipe(pipe, capture=True, capture_stderr=True, + raise_on_error=False) + if result.return_code: + return None, "Branch '%s' not found" % branch + for line in result.stdout.splitlines()[1:]: + commit_hash = line.split(' ')[0] + name = NameRevision(commit_hash) + if '~' not in name and '^' not in name: + if name.startswith('remotes/'): + name = name[8:] + return name, "Guessing upstream as '%s'" % name + return None, "Cannot find a suitable upstream for branch '%s'" % branch + def GetUpstream(git_dir, branch): """Returns the name of the upstream for a branch @@ -69,7 +115,9 @@ def GetUpstream(git_dir, branch): branch: Name of branch Returns: - Name of upstream branch (e.g. 'upstream/master') or None if none + Tuple: + Name of upstream branch (e.g. 'upstream/master') or None if none + Warning/error message, or None if none """ try: remote = command.OutputOneLine('git', '--git-dir', git_dir, 'config', @@ -77,13 +125,14 @@ def GetUpstream(git_dir, branch): merge = command.OutputOneLine('git', '--git-dir', git_dir, 'config', 'branch.%s.merge' % branch) except: - return None + upstream, msg = GuessUpstream(git_dir, branch) + return upstream, msg if remote == '.': return merge elif remote and merge: leaf = merge.split('/')[-1] - return '%s/%s' % (remote, leaf) + return '%s/%s' % (remote, leaf), None else: raise ValueError, ("Cannot determine upstream branch for branch " "'%s' remote='%s', merge='%s'" % (branch, remote, merge)) @@ -99,10 +148,29 @@ def GetRangeInBranch(git_dir, branch, include_upstream=False): Expression in the form 'upstream..branch' which can be used to access the commits. If the branch does not exist, returns None. """ - upstream = GetUpstream(git_dir, branch) + upstream, msg = GetUpstream(git_dir, branch) if not upstream: - return None - return '%s%s..%s' % (upstream, '~' if include_upstream else '', branch) + return None, msg + rstr = '%s%s..%s' % (upstream, '~' if include_upstream else '', branch) + return rstr, msg + +def CountCommitsInRange(git_dir, range_expr): + """Returns the number of commits in the given range. + + Args: + git_dir: Directory containing git repo + range_expr: Range to check + Return: + Number of patches that exist in the supplied rangem or None if none + were found + """ + pipe = [LogCmd(range_expr, git_dir=git_dir, oneline=True)] + result = command.RunPipe(pipe, capture=True, capture_stderr=True, + raise_on_error=False) + if result.return_code: + return None, "Range '%s' not found or is invalid" % range_expr + patch_count = len(result.stdout.splitlines()) + return patch_count, None def CountCommitsInBranch(git_dir, branch, include_upstream=False): """Returns the number of commits in the given branch. @@ -114,14 +182,10 @@ def CountCommitsInBranch(git_dir, branch, include_upstream=False): Number of patches that exist on top of the branch, or None if the branch does not exist. """ - range_expr = GetRangeInBranch(git_dir, branch, include_upstream) + range_expr, msg = GetRangeInBranch(git_dir, branch, include_upstream) if not range_expr: - return None - pipe = [LogCmd(range_expr, git_dir=git_dir, oneline=True), - ['wc', '-l']] - result = command.RunPipe(pipe, capture=True, oneline=True) - patch_count = int(result.stdout) - return patch_count + return None, msg + return CountCommitsInRange(git_dir, range_expr) def CountCommits(commit_range): """Returns the number of commits in the given range. @@ -328,7 +392,8 @@ def EmailPatches(series, cover_fname, args, dry_run, raise_on_error, cc_fname, "Or do something like this\n" "git config sendemail.to u-boot@lists.denx.de") return - cc = BuildEmailList(series.get('cc'), '--cc', alias, raise_on_error) + cc = BuildEmailList(list(set(series.get('cc')) - set(series.get('to'))), + '--cc', alias, raise_on_error) if self_only: to = BuildEmailList([os.getenv('USER')], '--to', alias, raise_on_error) cc = [] diff --git a/tools/patman/patchstream.py b/tools/patman/patchstream.py index da0488337b..8c3a0ec9ee 100644 --- a/tools/patman/patchstream.py +++ b/tools/patman/patchstream.py @@ -139,6 +139,9 @@ class PatchStream: # Initially we have no output. Prepare the input line string out = [] line = line.rstrip('\n') + + commit_match = re_commit.match(line) if self.is_log else None + if self.is_log: if line[:4] == ' ': line = line[4:] @@ -146,7 +149,6 @@ class PatchStream: # Handle state transition and skipping blank lines series_tag_match = re_series_tag.match(line) commit_tag_match = re_commit_tag.match(line) - commit_match = re_commit.match(line) if self.is_log else None cover_cc_match = re_cover_cc.match(line) signoff_match = re_signoff.match(line) tag_match = None diff --git a/tools/patman/series.py b/tools/patman/series.py index b67f870b7e..60ebc766f7 100644 --- a/tools/patman/series.py +++ b/tools/patman/series.py @@ -94,6 +94,9 @@ class Series(dict): cmd: The git command we would have run process_tags: Process tags as if they were aliases """ + to_set = set(gitutil.BuildEmailList(self.to)); + cc_set = set(gitutil.BuildEmailList(self.cc)); + col = terminal.Color() print 'Dry run, so not doing much. But I would do this:' print @@ -106,24 +109,16 @@ class Series(dict): commit = self.commits[upto] print col.Color(col.GREEN, ' %s' % args[upto]) cc_list = list(self._generated_cc[commit.patch]) - - # Skip items in To list - if 'to' in self: - try: - map(cc_list.remove, gitutil.BuildEmailList(self.to)) - except ValueError: - pass - - for email in cc_list: + for email in set(cc_list) - to_set - cc_set: 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>')): + for item in to_set: print 'To:\t ', item - for item in gitutil.BuildEmailList(self.cc): + for item in cc_set - to_set: print 'Cc:\t ', item print 'Version: ', self.get('version') print 'Prefix:\t ', self.get('prefix') @@ -131,7 +126,7 @@ class Series(dict): print 'Cover: %d lines' % len(self.cover) cover_cc = gitutil.BuildEmailList(self.get('cover_cc', '')) all_ccs = itertools.chain(cover_cc, *self._generated_cc.values()) - for email in set(all_ccs): + for email in set(all_ccs) - to_set - cc_set: print ' Cc: ',email if cmd: print 'Git command: %s' % cmd @@ -230,7 +225,7 @@ class Series(dict): if add_maintainers: list += get_maintainer.GetMaintainer(commit.patch) all_ccs += list - print >>fd, commit.patch, ', '.join(list) + print >>fd, commit.patch, ', '.join(set(list)) self._generated_cc[commit.patch] = list if cover_fname: |