X-Git-Url: https://git.kernelconcepts.de/?a=blobdiff_plain;f=tools%2Fpatman%2Fgitutil.py;h=4e21d4c2a778acaa642479859691b8287b269196;hb=f140b5863b258120f5412ea86733f70c87837ee9;hp=72d37a0b04e5bd752b107a95c15c700f33ff4164;hpb=c68436fa427a69ea308d74c410067507d6c7103b;p=karo-tx-uboot.git diff --git a/tools/patman/gitutil.py b/tools/patman/gitutil.py index 72d37a0b04..4e21d4c2a7 100644 --- a/tools/patman/gitutil.py +++ b/tools/patman/gitutil.py @@ -23,11 +23,12 @@ import command import re import os import series -import settings import subprocess import sys import terminal +import settings + def CountCommitsToBranch(): """Returns number of commits between HEAD and the tracking branch. @@ -40,10 +41,123 @@ def CountCommitsToBranch(): """ pipe = [['git', 'log', '--no-color', '--oneline', '@{upstream}..'], ['wc', '-l']] - stdout = command.RunPipe(pipe, capture=True, oneline=True) + stdout = command.RunPipe(pipe, capture=True, oneline=True).stdout + patch_count = int(stdout) + return patch_count + +def GetUpstream(git_dir, branch): + """Returns the name of the upstream for a branch + + Args: + git_dir: Git directory containing repo + branch: Name of branch + + Returns: + Name of upstream branch (e.g. 'upstream/master') or None if none + """ + remote = command.OutputOneLine('git', '--git-dir', git_dir, 'config', + 'branch.%s.remote' % branch) + merge = command.OutputOneLine('git', '--git-dir', git_dir, 'config', + 'branch.%s.merge' % branch) + if remote == '.': + return merge + elif remote and merge: + leaf = merge.split('/')[-1] + return '%s/%s' % (remote, leaf) + else: + raise ValueError, ("Cannot determine upstream branch for branch " + "'%s' remote='%s', merge='%s'" % (branch, remote, merge)) + + +def GetRangeInBranch(git_dir, branch, include_upstream=False): + """Returns an expression for the commits in the given branch. + + Args: + git_dir: Directory containing git repo + branch: Name of branch + Return: + Expression in the form 'upstream..branch' which can be used to + access the commits. + """ + upstream = GetUpstream(git_dir, branch) + return '%s%s..%s' % (upstream, '~' if include_upstream else '', branch) + +def CountCommitsInBranch(git_dir, branch, include_upstream=False): + """Returns the number of commits in the given branch. + + Args: + git_dir: Directory containing git repo + branch: Name of branch + Return: + Number of patches that exist on top of the branch + """ + range_expr = GetRangeInBranch(git_dir, branch, include_upstream) + pipe = [['git', '--git-dir', git_dir, 'log', '--oneline', range_expr], + ['wc', '-l']] + result = command.RunPipe(pipe, capture=True, oneline=True) + patch_count = int(result.stdout) + return patch_count + +def CountCommits(commit_range): + """Returns the number of commits in the given range. + + Args: + commit_range: Range of commits to count (e.g. 'HEAD..base') + Return: + Number of patches that exist on top of the branch + """ + pipe = [['git', 'log', '--oneline', commit_range], + ['wc', '-l']] + stdout = command.RunPipe(pipe, capture=True, oneline=True).stdout patch_count = int(stdout) return patch_count +def Checkout(commit_hash, git_dir=None, work_tree=None, force=False): + """Checkout the selected commit for this build + + Args: + commit_hash: Commit hash to check out + """ + pipe = ['git'] + if git_dir: + pipe.extend(['--git-dir', git_dir]) + if work_tree: + pipe.extend(['--work-tree', work_tree]) + pipe.append('checkout') + if force: + pipe.append('-f') + pipe.append(commit_hash) + result = command.RunPipe([pipe], capture=True, raise_on_error=False) + if result.return_code != 0: + raise OSError, 'git checkout (%s): %s' % (pipe, result.stderr) + +def Clone(git_dir, output_dir): + """Checkout the selected commit for this build + + Args: + commit_hash: Commit hash to check out + """ + pipe = ['git', 'clone', git_dir, '.'] + result = command.RunPipe([pipe], capture=True, cwd=output_dir) + if result.return_code != 0: + raise OSError, 'git clone: %s' % result.stderr + +def Fetch(git_dir=None, work_tree=None): + """Fetch from the origin repo + + Args: + commit_hash: Commit hash to check out + """ + pipe = ['git'] + if git_dir: + pipe.extend(['--git-dir', git_dir]) + if work_tree: + pipe.extend(['--work-tree', work_tree]) + pipe.append('fetch') + result = command.RunPipe([pipe], capture=True) + if result.return_code != 0: + raise OSError, 'git fetch: %s' % result.stderr + def CreatePatches(start, count, series): """Create a series of patches from the top of the current branch. @@ -203,7 +317,7 @@ def BuildEmailList(in_list, tag=None, alias=None): return result def EmailPatches(series, cover_fname, args, dry_run, cc_fname, - self_only=False, alias=None): + self_only=False, alias=None, in_reply_to=None): """Email a patch series. Args: @@ -213,10 +327,16 @@ def EmailPatches(series, cover_fname, args, dry_run, cc_fname, dry_run: Just return the command that would be run cc_fname: Filename of Cc file for per-commit Cc self_only: True to just email to yourself as a test + in_reply_to: If set we'll pass this to git as --in-reply-to. + Should be a message ID that this is in reply to. Returns: Git command that was/would be run + # For the duration of this doctest pretend that we ran patman with ./patman + >>> _old_argv0 = sys.argv[0] + >>> sys.argv[0] = './patman' + >>> alias = {} >>> alias['fred'] = ['f.bloggs@napier.co.nz'] >>> alias['john'] = ['j.bloggs@napier.co.nz'] @@ -244,6 +364,9 @@ def EmailPatches(series, cover_fname, args, dry_run, cc_fname, 'git send-email --annotate --to "f.bloggs@napier.co.nz" --cc \ "f.bloggs@napier.co.nz" --cc "j.bloggs@napier.co.nz" --cc \ "m.poppins@cloud.net" --cc-cmd "./patman --cc-cmd cc-fname" cover p1 p2' + + # Restore argv[0] since we clobbered it. + >>> sys.argv[0] = _old_argv0 """ to = BuildEmailList(series.get('to'), '--to', alias) if not to: @@ -255,6 +378,9 @@ def EmailPatches(series, cover_fname, args, dry_run, cc_fname, to = BuildEmailList([os.getenv('USER')], '--to', alias) cc = [] cmd = ['git', 'send-email', '--annotate'] + if in_reply_to: + cmd.append('--in-reply-to="%s"' % in_reply_to) + cmd += to cmd += cc cmd += ['--cc-cmd', '"%s --cc-cmd %s"' % (sys.argv[0], cc_fname)] @@ -340,8 +466,8 @@ def GetTopLevel(): This test makes sure that we are running tests in the right subdir - >>> os.path.realpath(os.getcwd()) == \ - os.path.join(GetTopLevel(), 'tools', 'scripts', 'patman') + >>> os.path.realpath(os.path.dirname(__file__)) == \ + os.path.join(GetTopLevel(), 'tools', 'patman') True """ return command.OutputOneLine('git', 'rev-parse', '--show-toplevel') @@ -352,7 +478,8 @@ def GetAliasFile(): Returns: Filename of git alias file, or None if none """ - fname = command.OutputOneLine('git', 'config', 'sendemail.aliasesfile') + fname = command.OutputOneLine('git', 'config', 'sendemail.aliasesfile', + raise_on_error=False) if fname: fname = os.path.join(GetTopLevel(), fname.strip()) return fname @@ -377,13 +504,19 @@ def GetDefaultUserEmail(): def Setup(): """Set up git utils, by reading the alias files.""" - settings.Setup('') - # Check for a git alias file also alias_fname = GetAliasFile() if alias_fname: settings.ReadGitAliases(alias_fname) +def GetHead(): + """Get the hash of the current HEAD + + Returns: + Hash of HEAD + """ + return command.OutputOneLine('git', 'show', '-s', '--pretty=format:%H') + if __name__ == "__main__": import doctest