diff options
Diffstat (limited to 'tools/patman/gitutil.py')
| -rw-r--r-- | tools/patman/gitutil.py | 136 | 
1 files changed, 132 insertions, 4 deletions
| diff --git a/tools/patman/gitutil.py b/tools/patman/gitutil.py index ca3ba4a03..4e21d4c2a 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,6 +327,8 @@ 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 @@ -262,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)] @@ -359,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 @@ -389,6 +509,14 @@ def Setup():      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 |