1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
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
105
106
107
|
import pygit2
import re
import subprocess
from git_deps.errors import InvalidCommitish
from git_deps.utils import abort
class GitUtils(object):
@classmethod
def abbreviate_sha1(cls, sha1):
"""Uniquely abbreviates the given SHA1."""
# For now we invoke git-rev-parse(1), but hopefully eventually
# we will be able to do this via pygit2.
cmd = ['git', 'rev-parse', '--short', sha1]
# cls.logger.debug(" ".join(cmd))
out = subprocess.check_output(cmd, universal_newlines=True).strip()
# cls.logger.debug(out)
return out
@classmethod
def describe(cls, sha1):
"""Returns a human-readable representation of the given SHA1."""
# For now we invoke git-describe(1), but eventually we will be
# able to do this via pygit2, since libgit2 already provides
# an API for this:
# https://github.com/libgit2/pygit2/pull/459#issuecomment-68866929
# https://github.com/libgit2/libgit2/pull/2592
cmd = [
'git', 'describe',
'--all', # look for tags and branches
'--long', # remotes/github/master-0-g2b6d591
# '--contains',
# '--abbrev',
sha1
]
# cls.logger.debug(" ".join(cmd))
out = None
try:
out = subprocess.check_output(
cmd, stderr=subprocess.STDOUT, universal_newlines=True)
except subprocess.CalledProcessError as e:
if e.output.find('No tags can describe') != -1:
return ''
raise
out = out.strip()
out = re.sub(r'^(heads|tags|remotes)/', '', out)
# We already have the abbreviated SHA1 from abbreviate_sha1()
out = re.sub(r'-g[0-9a-f]{7,}$', '', out)
# cls.logger.debug(out)
return out
@classmethod
def oneline(cls, commit):
try:
ret = commit.message.split('\n', 1)[0]
except UnicodeDecodeError:
ret = "Invalid utf-8 commit message"
return ret
@classmethod
def commit_summary(cls, commit):
return "%s %s" % (commit.hex[:8], cls.oneline(commit))
@classmethod
def refs_to(cls, sha1, repo):
"""Returns all refs pointing to the given SHA1."""
matching = []
for refname in repo.listall_references():
symref = repo.lookup_reference(refname)
dref = symref.resolve()
oid = dref.target
commit = repo.get(oid)
if commit.hex == sha1:
matching.append(symref.shorthand)
return matching
@classmethod
def rev_list(cls, rev_range):
cmd = ['git', 'rev-list', rev_range]
return subprocess.check_output(cmd, universal_newlines=True) \
.strip().split('\n')
@classmethod
def ref_commit(cls, repo, rev):
try:
commit = repo.revparse_single(rev)
except (KeyError, ValueError):
raise InvalidCommitish(rev)
if isinstance(commit, pygit2.Tag):
commit = commit.get_object()
return commit
@classmethod
def get_repo(cls, path='.'):
try:
repo_path = pygit2.discover_repository(path)
except KeyError:
abort("Couldn't find a repository in the current directory.")
return pygit2.Repository(repo_path)
|