Skip to content

Commit 5bd7d44

Browse files
committed
repo.rev_parse: Added support for simple log parsing - dates are not yet supported, mainly because I don't need it
1 parent 9ccd777 commit 5bd7d44

File tree

3 files changed

+73
-13
lines changed

3 files changed

+73
-13
lines changed

doc/source/changes.rst

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Changelog
55
0.3.2 Beta 2
66
============
77
* Added reflog support ( reading and writing )
8+
* Repo.rev_parse now supports the [ref]@{n} syntax, where n is the number of steps to look into the reference's past
89

910
0.3.2 Beta 1
1011
============

repo/fun.py

+52-10
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,13 @@ def short_to_long(odb, hexsha):
4242
# END exception handling
4343

4444

45-
def name_to_object(repo, name):
46-
""":return: object specified by the given name, hexshas ( short and long )
47-
as well as references are supported"""
45+
def name_to_object(repo, name, return_ref=False):
46+
"""
47+
:return: object specified by the given name, hexshas ( short and long )
48+
as well as references are supported
49+
:param return_ref: if name specifies a reference, we will return the reference
50+
instead of the object. Otherwise it will raise BadObject
51+
"""
4852
hexsha = None
4953

5054
# is it a hexsha ? Try the most common ones, which is 7 to 40
@@ -59,12 +63,20 @@ def name_to_object(repo, name):
5963
for base in ('%s', 'refs/%s', 'refs/tags/%s', 'refs/heads/%s', 'refs/remotes/%s', 'refs/remotes/%s/HEAD'):
6064
try:
6165
hexsha = SymbolicReference.dereference_recursive(repo, base % name)
66+
if return_ref:
67+
return SymbolicReference(repo, base % name)
68+
#END handle symbolic ref
6269
break
6370
except ValueError:
6471
pass
6572
# END for each base
6673
# END handle hexsha
67-
74+
75+
# didn't find any ref, this is an error
76+
if return_ref:
77+
raise BadObject("Couldn't find reference named %r" % name)
78+
#END handle return ref
79+
6880
# tried everything ? fail
6981
if hexsha is None:
7082
raise BadObject(name)
@@ -101,9 +113,6 @@ def rev_parse(repo, rev):
101113
:note: Currently there is no access to the rev-log, rev-specs may only contain
102114
topological tokens such ~ and ^.
103115
:raise BadObject: if the given revision could not be found"""
104-
if '@' in rev:
105-
raise ValueError("There is no rev-log support yet")
106-
107116

108117
# colon search mode ?
109118
if rev.startswith(':/'):
@@ -112,22 +121,37 @@ def rev_parse(repo, rev):
112121
# END handle search
113122

114123
obj = None
124+
ref = None
115125
output_type = "commit"
116126
start = 0
117127
parsed_to = 0
118128
lr = len(rev)
119129
while start < lr:
120-
if rev[start] not in "^~:":
130+
if rev[start] not in "^~:@":
121131
start += 1
122132
continue
123133
# END handle start
124134

135+
token = rev[start]
136+
125137
if obj is None:
126138
# token is a rev name
127-
obj = name_to_object(repo, rev[:start])
139+
if start == 0:
140+
ref = repo.head.ref
141+
else:
142+
if token == '@':
143+
ref = name_to_object(repo, rev[:start], return_ref=True)
144+
else:
145+
obj = name_to_object(repo, rev[:start])
146+
#END handle token
147+
#END handle refname
148+
149+
if ref is not None:
150+
obj = ref.commit
151+
#END handle ref
128152
# END initialize obj on first token
129153

130-
token = rev[start]
154+
131155
start += 1
132156

133157
# try to parse {type}
@@ -153,6 +177,24 @@ def rev_parse(repo, rev):
153177
# cannot do anything for non-tags
154178
pass
155179
# END handle tag
180+
elif token == '@':
181+
# try single int
182+
assert ref is not None, "Requre Reference to access reflog"
183+
revlog_index = None
184+
try:
185+
# transform reversed index into the format of our revlog
186+
revlog_index = -(int(output_type)+1)
187+
except ValueError:
188+
# TODO: Try to parse the other date options, using parse_date
189+
# maybe
190+
raise NotImplementedError("Support for additional @{...} modes not implemented")
191+
#END handle revlog index
192+
193+
entry = ref.log()[revlog_index]
194+
obj = Object.new_from_sha(repo, hex_to_bin(entry.newhexsha))
195+
196+
# make it pass the following checks
197+
output_type = None
156198
else:
157199
raise ValueError("Invalid output type: %s ( in %s )" % (output_type, rev))
158200
# END handle output type

test/test_repo.py

+20-3
Original file line numberDiff line numberDiff line change
@@ -467,11 +467,12 @@ def _assert_rev_parse(self, name):
467467
def test_rev_parse(self):
468468
rev_parse = self.rorepo.rev_parse
469469

470-
# try special case: This one failed beforehand
470+
# try special case: This one failed at some point, make sure its fixed
471471
assert rev_parse("33ebe").hexsha == "33ebe7acec14b25c5f84f35a664803fcab2f7781"
472472

473473
# start from reference
474474
num_resolved = 0
475+
475476
for ref in Reference.iter_items(self.rorepo):
476477
path_tokens = ref.path.split("/")
477478
for pt in range(len(path_tokens)):
@@ -546,9 +547,25 @@ def test_rev_parse(self):
546547
# missing starting brace
547548
self.failUnlessRaises(ValueError, rev_parse, '0.1.4^tree}')
548549

550+
# REVLOG
551+
#######
552+
head = self.rorepo.head
553+
554+
# need to specify a ref when using the @ syntax
555+
self.failUnlessRaises(BadObject, rev_parse, "%s@{0}" % head.commit.hexsha)
556+
557+
# uses HEAD.ref by default
558+
assert rev_parse('@{0}') == head.commit
559+
if not head.is_detached:
560+
assert rev_parse('%s@{0}' % head.ref.name) == head.ref.commit
561+
#END operate on non-detached head
562+
563+
# the last position
564+
assert rev_parse('@{1}') != head.commit
565+
566+
# currently, nothing more is supported
567+
self.failUnlessRaises(NotImplementedError, rev_parse, "@{1 week ago}")
549568

550-
# cannot handle rev-log for now
551-
self.failUnlessRaises(ValueError, rev_parse, "hi@there")
552569

553570
def test_repo_odbtype(self):
554571
target_type = GitDB

0 commit comments

Comments
 (0)