Skip to content

Commit 023dc12

Browse files
committed
Merge branch 'dulwich'
2 parents 2baf8a4 + f4f330f commit 023dc12

18 files changed

+327
-75
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66
/dist
77
/doc/_build
88
nbproject
9+
.nosebazinga

git/db/compat.py

+19-5
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,10 @@
44
# the New BSD License: http://www.opensource.org/licenses/bsd-license.php
55
"""Module providing adaptors to maintain backwards compatability"""
66

7-
class RepoCompatibilityInterface(object):
7+
class RepoCompatibilityInterfaceNoBare(object):
88
"""Interface to install backwards compatability of the new complex repository
99
types with the previous, all in one, repository."""
1010

11-
@property
12-
def bare(self):
13-
return self.is_bare
14-
1511
def rev_parse(self, *args, **kwargs):
1612
return self.resolve_object(*args, **kwargs)
1713

@@ -28,4 +24,22 @@ def active_branch(self):
2824
return self.head.reference
2925

3026
def __repr__(self):
27+
"""Return the representation of the repository, the way it used to be"""
3128
return '<git.Repo "%s">' % self.git_dir
29+
30+
@property
31+
def branches(self):
32+
return self.heads
33+
34+
35+
class RepoCompatibilityInterface(RepoCompatibilityInterfaceNoBare):
36+
"""Interface to install backwards compatability of the new complex repository
37+
types with the previous, all in one, repository."""
38+
39+
@property
40+
def bare(self):
41+
return self.is_bare
42+
43+
@property
44+
def refs(self):
45+
return self.references

git/db/dulwich/__init__.py

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
"""Dulwich module initialization"""
2+
3+
def init_dulwich():
4+
""":raise ImportError: if dulwich is not present"""
5+
try:
6+
import dulwich
7+
except ImportError:
8+
raise ImportError("Could not find 'dulwich' in the PYTHONPATH - dulwich functionality is not available")
9+
#END handle dulwich import
10+
11+
12+
13+
init_dulwich()

git/db/dulwich/complex.py

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
2+
__all__ = ['DulwichGitODB', 'DulwichGitDB', 'DulwichCompatibilityGitDB']
3+
4+
from git.db.py.complex import PureGitODB
5+
from git.db.py.base import (
6+
PureRepositoryPathsMixin,
7+
PureConfigurationMixin,
8+
PureIndexDB,
9+
)
10+
from git.db.py.resolve import PureReferencesMixin
11+
from git.db.py.transport import PureTransportDB
12+
from git.db.py.submodule import PureSubmoduleDB
13+
14+
from git.db.cmd.complex import CmdHighLevelRepository, GitCommandMixin
15+
from git.db.compat import RepoCompatibilityInterfaceNoBare
16+
17+
#from git.db.interface import ObjectDBW, ObjectDBR
18+
from dulwich.repo import Repo as DulwichRepo
19+
from dulwich.objects import ShaFile
20+
21+
from git.base import OInfo, OStream
22+
from git.fun import type_id_to_type_map, type_to_type_id_map
23+
24+
from cStringIO import StringIO
25+
import os
26+
27+
28+
class DulwichGitODB(PureGitODB):
29+
"""A full fledged database to read and write object files from all kinds of sources."""
30+
31+
def __init__(self, objects_root):
32+
"""Initalize this instance"""
33+
PureGitODB.__init__(self, objects_root)
34+
if hasattr(self, 'working_dir'):
35+
wd = self.working_dir
36+
else:
37+
wd = os.path.dirname(os.path.dirname(objects_root))
38+
#END try to figure out good entry for dulwich, which doesn't do an extensive search
39+
self._dw_repo = DulwichRepo(wd)
40+
41+
def __getattr__(self, attr):
42+
try:
43+
# supply LazyMixin with this call first
44+
return super(DulwichGitODB, self).__getattr__(attr)
45+
except AttributeError:
46+
# now assume its on the dulwich repository ... for now
47+
return getattr(self._dw_repo, attr)
48+
#END handle attr
49+
50+
#{ Object DBR
51+
52+
def info(self, binsha):
53+
type_id, uncomp_data = self._dw_repo.object_store.get_raw(binsha)
54+
return OInfo(binsha, type_id_to_type_map[type_id], len(uncomp_data))
55+
56+
def stream(self, binsha):
57+
type_id, uncomp_data = self._dw_repo.object_store.get_raw(binsha)
58+
return OStream(binsha, type_id_to_type_map[type_id], len(uncomp_data), StringIO(uncomp_data))
59+
60+
#}END object dbr
61+
62+
#{ Object DBW
63+
64+
def store(self, istream):
65+
obj = ShaFile.from_raw_string(type_to_type_id_map[istream.type], istream.read())
66+
self._dw_repo.object_store.add_object(obj)
67+
istream.binsha = obj.sha().digest()
68+
return istream
69+
70+
#}END object dbw
71+
72+
class DulwichGitDB( PureRepositoryPathsMixin, PureConfigurationMixin,
73+
PureReferencesMixin, PureSubmoduleDB,
74+
PureIndexDB,
75+
PureTransportDB, # not fully implemented
76+
GitCommandMixin,
77+
CmdHighLevelRepository,
78+
DulwichGitODB): # must come last, as it doesn't pass on __init__ with super
79+
80+
81+
def __init__(self, root_path):
82+
"""Initialize ourselves on the .git directory, or the .git/objects directory."""
83+
PureRepositoryPathsMixin._initialize(self, root_path)
84+
super(DulwichGitDB, self).__init__(self.objects_dir)
85+
86+
87+
class DulwichCompatibilityGitDB(RepoCompatibilityInterfaceNoBare, DulwichGitDB):
88+
"""Basic dulwich compatibility database"""
89+
pass
90+

git/db/interface.py

+2-10
Original file line numberDiff line numberDiff line change
@@ -561,16 +561,8 @@ def delete_tag(self, *tags):
561561
raise NotImplementedError()
562562

563563
#}END edit methods
564-
565-
#{ Backward Compatability
566-
# These aliases need to be provided by the implementing interface as well
567-
refs = references
568-
branches = heads
569-
#} END backward compatability
570-
571-
572-
573-
564+
565+
574566
class RepositoryPathsMixin(object):
575567
"""Represents basic functionality of a full git repository. This involves an
576568
optional working tree, a git directory with references and an object directory.

git/db/py/base.py

+31-34
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,6 @@ def __init__(self, root_path):
104104
super(PureRootPathDB, self).__init__(root_path)
105105

106106

107-
108107
#{ Interface
109108
def root_path(self):
110109
return self._root_path
@@ -132,44 +131,33 @@ class PureCompoundDB(CompoundDB, PureObjectDBR, LazyMixin, CachingDB):
132131
def _set_cache_(self, attr):
133132
if attr == '_dbs':
134133
self._dbs = list()
135-
elif attr == '_obj_cache':
136-
self._obj_cache = dict()
137134
else:
138135
super(PureCompoundDB, self)._set_cache_(attr)
139136

140-
def _db_query(self, sha):
141-
""":return: database containing the given 20 byte sha
142-
:raise BadObject:"""
143-
# most databases use binary representations, prevent converting
144-
# it everytime a database is being queried
145-
try:
146-
return self._obj_cache[sha]
147-
except KeyError:
148-
pass
149-
# END first level cache
150-
151-
for db in self._dbs:
152-
if db.has_object(sha):
153-
self._obj_cache[sha] = db
154-
return db
155-
# END for each database
156-
raise BadObject(sha)
157-
158137
#{ PureObjectDBR interface
159138

160139
def has_object(self, sha):
161-
try:
162-
self._db_query(sha)
163-
return True
164-
except BadObject:
165-
return False
166-
# END handle exceptions
140+
for db in self._dbs:
141+
if db.has_object(sha):
142+
return True
143+
#END for each db
144+
return False
167145

168146
def info(self, sha):
169-
return self._db_query(sha).info(sha)
147+
for db in self._dbs:
148+
try:
149+
return db.info(sha)
150+
except BadObject:
151+
pass
152+
#END for each db
170153

171154
def stream(self, sha):
172-
return self._db_query(sha).stream(sha)
155+
for db in self._dbs:
156+
try:
157+
return db.stream(sha)
158+
except BadObject:
159+
pass
160+
#END for each db
173161

174162
def size(self):
175163
return reduce(lambda x,y: x+y, (db.size() for db in self._dbs), 0)
@@ -186,7 +174,6 @@ def databases(self):
186174

187175
def update_cache(self, force=False):
188176
# something might have changed, clear everything
189-
self._obj_cache.clear()
190177
stat = False
191178
for db in self._dbs:
192179
if isinstance(db, CachingDB):
@@ -233,7 +220,7 @@ def partial_to_complete_sha(self, partial_binsha, hex_len):
233220

234221
class PureRepositoryPathsMixin(RepositoryPathsMixin):
235222
# slots has no effect here, its just to keep track of used attrs
236-
__slots__ = ("_git_path", '_bare')
223+
__slots__ = ("_git_path", '_bare', '_working_tree_dir')
237224

238225
#{ Configuration
239226
repo_dir = '.git'
@@ -272,14 +259,16 @@ def _initialize(self, path):
272259
raise InvalidGitRepositoryError(epath)
273260
# END path not found
274261

275-
self._bare = self._git_path.endswith(self.repo_dir)
262+
self._bare = self._working_tree_dir is None
276263
if hasattr(self, 'config_reader'):
277264
try:
278265
self._bare = self.config_reader("repository").getboolean('core','bare')
279266
except Exception:
280267
# lets not assume the option exists, although it should
281268
pass
269+
#END handle exception
282270
#END check bare flag
271+
self._working_tree_dir = self._bare and None or self._working_tree_dir
283272

284273
#} end subclass interface
285274

@@ -313,7 +302,7 @@ def git_dir(self):
313302

314303
@property
315304
def working_tree_dir(self):
316-
if self.is_bare:
305+
if self._working_tree_dir is None:
317306
raise AssertionError("Repository at %s is bare and does not have a working tree directory" % self.git_dir)
318307
#END assertion
319308
return dirname(self.git_dir)
@@ -354,6 +343,10 @@ class PureConfigurationMixin(ConfigurationMixin):
354343
repo_config_file_name = "config"
355344
#} END
356345

346+
def __new__(cls, *args, **kwargs):
347+
"""This is just a stupid workaround for the evil py2.6 change which makes mixins quite impossible"""
348+
return super(PureConfigurationMixin, cls).__new__(cls, *args, **kwargs)
349+
357350
def __init__(self, *args, **kwargs):
358351
"""Verify prereqs"""
359352
try:
@@ -421,7 +414,11 @@ class PureAlternatesFileMixin(object):
421414
#} END configuration
422415

423416
def __init__(self, *args, **kwargs):
424-
super(PureAlternatesFileMixin, self).__init__(*args, **kwargs)
417+
try:
418+
super(PureAlternatesFileMixin, self).__init__(*args, **kwargs)
419+
except TypeError:
420+
pass
421+
#END handle py2.6 code breaking changes
425422
self._alternates_path() # throws on incompatible type
426423

427424
#{ Interface

git/db/py/complex.py

+3-13
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,7 @@
2222

2323
from git.db.compat import RepoCompatibilityInterface
2424

25-
from git.util import (
26-
LazyMixin,
27-
normpath,
28-
join,
29-
dirname
30-
)
31-
from git.exc import (
32-
InvalidDBRoot,
33-
BadObject,
34-
AmbiguousObjectName
35-
)
25+
from git.exc import InvalidDBRoot
3626
import os
3727

3828
__all__ = ('PureGitODB', 'PurePartialGitDB', 'PureCompatibilityGitDB')
@@ -106,7 +96,8 @@ def set_ostream(self, ostream):
10696
class PurePartialGitDB(PureGitODB,
10797
PureRepositoryPathsMixin, PureConfigurationMixin,
10898
PureReferencesMixin, PureSubmoduleDB,
109-
PureIndexDB, PureTransportDB
99+
PureIndexDB,
100+
PureTransportDB # not fully implemented
110101
# HighLevelRepository Currently not implemented !
111102
):
112103
"""Git like database with support for object lookup as well as reference resolution.
@@ -122,7 +113,6 @@ def __init__(self, root_path):
122113
super(PurePartialGitDB, self).__init__(self.objects_dir)
123114

124115

125-
126116
class PureCompatibilityGitDB(PurePartialGitDB, RepoCompatibilityInterface):
127117
"""Pure git database with a compatability layer required by 0.3x code"""
128118

git/db/py/resolve.py

-4
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,3 @@ def create_tag(self, path, ref='HEAD', message=None, force=False, **kwargs):
361361
def delete_tag(self, *tags):
362362
return self.TagReferenceCls.delete(self, *tags)
363363

364-
365-
# compat
366-
branches = heads
367-
refs = references

git/test/db/base.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -601,20 +601,26 @@ def test_rev_parse(self):
601601
self.failUnlessRaises(NotImplementedError, rev_parse, "@{1 week ago}")
602602

603603
def test_submodules(self):
604-
assert len(self.rorepo.submodules) == 1 # non-recursive
604+
assert len(self.rorepo.submodules) == 2 # non-recursive
605605
# in previous configurations, we had recursive repositories so this would compare to 2
606-
# now there is only one left, as gitdb was merged
607-
assert len(list(self.rorepo.iter_submodules())) == 1
606+
# now there is only one left, as gitdb was merged, but we have smmap instead
607+
assert len(list(self.rorepo.iter_submodules())) == 2
608608

609-
assert isinstance(self.rorepo.submodule("git/ext/async"), Submodule)
609+
assert isinstance(self.rorepo.submodule("async"), Submodule)
610610
self.failUnlessRaises(ValueError, self.rorepo.submodule, "doesn't exist")
611611

612612
@with_rw_repo('HEAD', bare=False)
613613
def test_submodule_update(self, rwrepo):
614614
# fails in bare mode
615615
rwrepo._bare = True
616+
# special handling: there are repo implementations which have a bare attribute. IN that case, set it directly
617+
if not rwrepo.bare:
618+
rwrepo.bare = True
616619
self.failUnlessRaises(InvalidGitRepositoryError, rwrepo.submodule_update)
617620
rwrepo._bare = False
621+
if rwrepo.bare:
622+
rwrepo.bare = False
623+
#END special repo handling
618624

619625
# test create submodule
620626
sm = rwrepo.submodules[0]

git/test/db/dulwich/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright (C) 2010, 2011 Sebastian Thiel ([email protected]) and contributors
2+
#
3+
# This module is part of GitDB and is released under
4+
# the New BSD License: http://www.opensource.org/licenses/bsd-license.php

0 commit comments

Comments
 (0)