Skip to content

Commit ccd4ff9

Browse files
committed
Fixed reference tests - symbolic refs now need to be created with a git_dir() providing repository. Currently there is no separate interface for this, which might have to be added at some point just for the sake of completeness
1 parent 00c5301 commit ccd4ff9

File tree

8 files changed

+92
-32
lines changed

8 files changed

+92
-32
lines changed

doc/source/changes.rst

+7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
Changelog
33
#########
44

5+
****
6+
NEXT
7+
****
8+
* Added interface to allow transporting git data: **TransportDBMixin**
9+
* Added interface to allow reference resolution: **RefParseMixin**
10+
* Added implementation of git datbase with support for transportation and reference resolution: **RefGitDB**
11+
512
*****
613
0.5.2
714
*****

gitdb/db/base.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,10 @@ class TransportDBMixin(object):
411411
nothing to send, the pack will be empty.
412412
413413
The communication itself if implemented using a protocol instance which deals
414-
with the actual formatting of the lines sent."""
414+
with the actual formatting of the lines sent.
415+
416+
As refspecs involve symbolic names for references to be handled, we require
417+
RefParse functionality. How this is done is up to the actual implementation."""
415418
# The following variables need to be set by the derived class
416419
#{Configuration
417420
protocol = None
@@ -456,3 +459,13 @@ def push(self, url, refspecs, progress=None, **kwargs):
456459
#}end interface
457460

458461

462+
class RefParseMixin(object):
463+
"""Interface allowing to resolve symbolic names or partial hexadecimal shas into
464+
actual binary shas. The actual feature set depends on the implementation though,
465+
but should follow git-rev-parse."""
466+
467+
def resolve(self, name):
468+
"""Resolve the given name into a binary sha. Valid names are as defined
469+
in the rev-parse documentation http://www.kernel.org/pub/software/scm/git/docs/git-rev-parse.html"""
470+
raise NotImplementedError()
471+

gitdb/db/git.py

+42-4
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,28 @@
1212
from pack import PackedDB
1313
from ref import ReferenceDB
1414

15-
from gitdb.util import LazyMixin
15+
from gitdb.util import (
16+
LazyMixin,
17+
normpath,
18+
join,
19+
dirname
20+
)
1621
from gitdb.exc import (
1722
InvalidDBRoot,
1823
BadObject,
1924
AmbiguousObjectName
2025
)
2126
import os
2227

23-
__all__ = ('GitDB', )
28+
__all__ = ('GitDB', 'RefGitDB')
2429

2530

2631
class GitDB(FileDBBase, ObjectDBW, CompoundDB):
2732
"""A git-style object database, which contains all objects in the 'objects'
28-
subdirectory"""
33+
subdirectory.
34+
:note: The type needs to be initialized on the ./objects directory to function,
35+
as it deals solely with object lookup. Use a RefGitDB type if you need
36+
reference and push support."""
2937
# Configuration
3038
PackDBCls = PackedDB
3139
LooseDBCls = LooseObjectDB
@@ -37,7 +45,7 @@ class GitDB(FileDBBase, ObjectDBW, CompoundDB):
3745
alternates_dir = os.path.join('info', 'alternates')
3846

3947
def __init__(self, root_path):
40-
"""Initialize ourselves on a git objects directory"""
48+
"""Initialize ourselves on a git ./objects directory"""
4149
super(GitDB, self).__init__(root_path)
4250

4351
def _set_cache_(self, attr):
@@ -83,3 +91,33 @@ def set_ostream(self, ostream):
8391

8492
#} END objectdbw interface
8593

94+
95+
class RefGitDB(GitDB):
96+
"""Git like database with support for object lookup as well as reference resolution.
97+
Our rootpath is set to the actual .git directory (bare on unbare).
98+
99+
The root_path will be the git objects directory. Use git_dir() to obtain the actual top-level
100+
git directory."""
101+
#directories
102+
objs_dir = 'objects'
103+
__slots__ = "_git_dir" # slots has no effect here, its just to keep track of used attrs
104+
105+
def __init__(self, root_path):
106+
"""Initialize ourselves on the .git directory, or the .git/objects directory."""
107+
root_path = normpath(root_path) # truncate trailing /
108+
self._git_dir = root_path
109+
if root_path.endswith(self.objs_dir):
110+
self._git_dir = dirname(root_path)
111+
else:
112+
root_path = join(root_path, self.objs_dir)
113+
#END handle directory
114+
assert self._git_dir.endswith('.git'), "require initialization on a git directory, got %s" % self._git_dir
115+
super(RefGitDB, self).__init__(root_path)
116+
117+
118+
#{ Interface
119+
def git_dir(self):
120+
""":return: main git directory containing objects and references"""
121+
return self._git_dir
122+
123+
#} END interface

gitdb/ref/log.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ def path(cls, ref):
151151
instance would be found. The path is not guaranteed to point to a valid
152152
file though.
153153
:param ref: SymbolicReference instance"""
154-
return join(ref.odb.root_path(), "logs", to_native_path(ref.path))
154+
return join(ref.odb.git_dir(), "logs", to_native_path(ref.path))
155155

156156
@classmethod
157157
def iter_entries(cls, stream):

gitdb/ref/symbolic.py

+16-15
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class SymbolicReference(object):
4242
#{ Configuration
4343
# Object class to be used when instantiating objects
4444
ObjectCls = Object
45+
CommitCls = Commit
4546

4647
# all of the following are set by the package initializer
4748
HEADCls = None
@@ -80,11 +81,11 @@ def name(self):
8081

8182
@property
8283
def abspath(self):
83-
return join_path_native(self.odb.root_path(), self.path)
84+
return join_path_native(self.odb.git_dir(), self.path)
8485

8586
@classmethod
8687
def _get_packed_refs_path(cls, odb):
87-
return join(odb.root_path(), 'packed-refs')
88+
return join(odb.git_dir(), 'packed-refs')
8889

8990
@classmethod
9091
def _iter_packed_refs(cls, odb):
@@ -137,7 +138,7 @@ def _get_ref_info(cls, odb, ref_path):
137138
point to, or None"""
138139
tokens = None
139140
try:
140-
fp = open(join(odb.root_path(), ref_path), 'r')
141+
fp = open(join(odb.git_dir(), ref_path), 'r')
141142
value = fp.read().rstrip()
142143
fp.close()
143144
tokens = value.split(" ")
@@ -216,7 +217,7 @@ def _get_commit(self):
216217
obj = obj.object
217218
#END dereference tag
218219

219-
if obj.type != Commit.type:
220+
if obj.type != self.CommitCls.type:
220221
raise TypeError("Symbolic Reference pointed to object %r, commit was required" % obj)
221222
#END handle type
222223
return obj
@@ -229,13 +230,13 @@ def set_commit(self, commit, logmsg = None):
229230
:return: self"""
230231
# check the type - assume the best if it is a base-string
231232
is_invalid_type = False
232-
if isinstance(commit, Object):
233-
is_invalid_type = commit.type != Commit.type
233+
if isinstance(commit, self.ObjectCls):
234+
is_invalid_type = commit.type != self.CommitCls.type
234235
elif isinstance(commit, SymbolicReference):
235-
is_invalid_type = commit.object.type != Commit.type
236+
is_invalid_type = commit.object.type != self.CommitCls.type
236237
else:
237238
try:
238-
is_invalid_type = self.odb.rev_parse(commit).type != Commit.type
239+
is_invalid_type = self.odb.rev_parse(commit).type != self.CommitCls.type
239240
except BadObject:
240241
raise ValueError("Invalid object: %s" % commit)
241242
#END handle exception
@@ -286,7 +287,7 @@ def set_reference(self, ref, logmsg = None):
286287
obj = None
287288
if isinstance(ref, SymbolicReference):
288289
write_value = "ref: %s" % ref.path
289-
elif isinstance(ref, Object):
290+
elif isinstance(ref, self.ObjectCls):
290291
obj = ref
291292
write_value = ref.hexsha
292293
elif isinstance(ref, basestring):
@@ -414,7 +415,7 @@ def delete(cls, odb, path):
414415
or just "myreference", hence 'refs/' is implied.
415416
Alternatively the symbolic reference to be deleted"""
416417
full_ref_path = cls.to_full_path(path)
417-
abs_path = join(odb.root_path(), full_ref_path)
418+
abs_path = join(odb.git_dir(), full_ref_path)
418419
if exists(abs_path):
419420
os.remove(abs_path)
420421
else:
@@ -467,7 +468,7 @@ def _create(cls, odb, path, resolve, reference, force, logmsg=None):
467468
corresponding object and a detached symbolic reference will be created
468469
instead"""
469470
full_ref_path = cls.to_full_path(path)
470-
abs_ref_path = join(odb.root_path(), full_ref_path)
471+
abs_ref_path = join(odb.git_dir(), full_ref_path)
471472

472473
# figure out target data
473474
target = reference
@@ -539,8 +540,8 @@ def rename(self, new_path, force=False):
539540
if self.path == new_path:
540541
return self
541542

542-
new_abs_path = join(self.odb.root_path(), new_path)
543-
cur_abs_path = join(self.odb.root_path(), self.path)
543+
new_abs_path = join(self.odb.git_dir(), new_path)
544+
cur_abs_path = join(self.odb.git_dir(), self.path)
544545
if isfile(new_abs_path):
545546
if not force:
546547
# if they point to the same file, its not an error
@@ -570,7 +571,7 @@ def _iter_items(cls, odb, common_path = None):
570571

571572
# walk loose refs
572573
# Currently we do not follow links
573-
for root, dirs, files in os.walk(join_path_native(odb.root_path(), common_path)):
574+
for root, dirs, files in os.walk(join_path_native(odb.git_dir(), common_path)):
574575
if 'refs/' not in root: # skip non-refs subfolders
575576
refs_id = [ i for i,d in enumerate(dirs) if d == 'refs' ]
576577
if refs_id:
@@ -579,7 +580,7 @@ def _iter_items(cls, odb, common_path = None):
579580

580581
for f in files:
581582
abs_path = to_native_path_linux(join_path(root, f))
582-
rela_paths.add(abs_path.replace(to_native_path_linux(odb.root_path()) + '/', ""))
583+
rela_paths.add(abs_path.replace(to_native_path_linux(odb.git_dir()) + '/', ""))
583584
# END for each file in root directory
584585
# END for each directory to walk
585586

gitdb/test/lib.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"""Utilities used in ODB testing"""
66
from gitdb import (
77
OStream,
8-
GitDB
8+
RefGitDB
99
)
1010
from gitdb.stream import (
1111
Sha1Writer,
@@ -72,7 +72,7 @@ def wrapper(self, path):
7272
shutil.copytree(src_dir, path)
7373
target_gitdir = os.path.join(path, '.git')
7474
assert os.path.isdir(target_gitdir)
75-
return func(self, GitDB(target_gitdir))
75+
return func(self, RefGitDB(target_gitdir))
7676
#END wrapper
7777
wrapper.__name__ = func.__name__
7878
return with_rw_directory(wrapper)
@@ -195,7 +195,7 @@ def _assert(self):
195195

196196
class TestBase(unittest.TestCase):
197197
"""Base class for all tests"""
198-
rorepo = GitDB(repo_dir())
198+
rorepo = RefGitDB(repo_dir())
199199

200200
#} END bases
201201

gitdb/test/test_refs.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class TestRefs(TestBase):
1919

2020
def test_from_path(self):
2121
# should be able to create any reference directly
22-
for ref_type in ( Reference, Head, TagReference, RemoteReference ):
22+
for ref_type in (Reference, Head, TagReference, RemoteReference):
2323
for name in ('rela_name', 'path/rela_name'):
2424
full_path = ref_type.to_full_path(name)
2525
instance = ref_type.from_path(self.rorepo, full_path)
@@ -32,25 +32,25 @@ def test_tag_base(self):
3232
for tag in TagReference.list_items(self.rorepo):
3333
assert "refs/tags" in tag.path
3434
assert tag.name
35-
assert isinstance( tag.commit, Commit )
35+
assert isinstance(tag.commit, tag.CommitCls)
3636
if tag.tag is not None:
37-
tag_object_refs.append( tag )
37+
tag_object_refs.append(tag)
3838
tagobj = tag.tag
3939
# have no dict
4040
self.failUnlessRaises(AttributeError, setattr, tagobj, 'someattr', 1)
41-
assert isinstance( tagobj, TagObject )
41+
assert isinstance(tagobj, TagObject)
4242
assert tagobj.tag == tag.name
43-
assert isinstance( tagobj.tagger, Actor )
44-
assert isinstance( tagobj.tagged_date, int )
45-
assert isinstance( tagobj.tagger_tz_offset, int )
43+
assert isinstance(tagobj.tagger, Actor)
44+
assert isinstance(tagobj.tagged_date, int)
45+
assert isinstance(tagobj.tagger_tz_offset, int)
4646
assert tagobj.message
4747
assert tag.object == tagobj
4848
# can't assign the object
4949
self.failUnlessRaises(AttributeError, setattr, tag, 'object', tagobj)
5050
# END if we have a tag object
5151
# END for tag in repo-tags
5252
assert tag_object_refs
53-
assert isinstance(self.rorepo.tags['0.1.5'], TagReference)
53+
assert isinstance(TagReference.list_items(self.rorepo)['0.5.0'], TagReference)
5454

5555
def test_tags(self):
5656
# tag refs can point to tag objects or to commits

gitdb/util.py

+1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ def unpack_from(fmt, data, offset=0):
7373
remove = os.remove
7474
dirname = os.path.dirname
7575
basename = os.path.basename
76+
normpath = os.path.normpath
7677
join = os.path.join
7778
read = os.read
7879
write = os.write

0 commit comments

Comments
 (0)