diff options
Diffstat (limited to 'git/db/py')
-rw-r--r-- | git/db/py/base.py | 74 | ||||
-rw-r--r-- | git/db/py/complex.py | 18 | ||||
-rw-r--r-- | git/db/py/resolve.py | 44 | ||||
-rw-r--r-- | git/db/py/transport.py | 61 |
4 files changed, 142 insertions, 55 deletions
diff --git a/git/db/py/base.py b/git/db/py/base.py index f45711d5..cc326c27 100644 --- a/git/db/py/base.py +++ b/git/db/py/base.py @@ -35,7 +35,7 @@ import os __all__ = ( 'PureObjectDBR', 'PureObjectDBW', 'PureRootPathDB', 'PureCompoundDB', - 'PureConfigurationMixin', 'PureRepositoryPathsMixin') + 'PureConfigurationMixin', 'PureRepositoryPathsMixin', 'PureAlternatesFileMixin') class PureObjectDBR(ObjectDBR): @@ -385,3 +385,75 @@ class PureConfigurationMixin(ConfigurationMixin): #} END interface + +class PureAlternatesFileMixin(object): + """Utility able to read and write an alternates file through the alternates property + It needs to be part of a type with the git_dir or db_path property. + + The file by default is assumed to be located at the default location as imposed + by the standard git repository layout""" + + #{ Configuration + alternates_filepath = os.path.join('info', 'alternates') # relative path to alternates file + + #} END configuration + + def __init__(self, *args, **kwargs): + super(PureAlternatesFileMixin, self).__init__(*args, **kwargs) + self._alternates_path() # throws on incompatible type + + #{ Interface + + def _alternates_path(self): + if hasattr(self, 'git_dir'): + return join(self.git_dir, 'objects', self.alternates_filepath) + elif hasattr(self, 'db_path'): + return self.db_path(self.alternates_filepath) + else: + raise AssertionError("This mixin requires a parent type with either the git_dir property or db_path method") + #END handle path + + def _get_alternates(self): + """The list of alternates for this repo from which objects can be retrieved + + :return: list of strings being pathnames of alternates""" + alternates_path = self._alternates_path() + + if os.path.exists(alternates_path): + try: + f = open(alternates_path) + alts = f.read() + finally: + f.close() + return alts.strip().splitlines() + else: + return list() + # END handle path exists + + def _set_alternates(self, alts): + """Sets the alternates + + :parm alts: + is the array of string paths representing the alternates at which + git should look for objects, i.e. /home/user/repo/.git/objects + + :raise NoSuchPathError: + :note: + The method does not check for the existance of the paths in alts + as the caller is responsible.""" + alternates_path = self._alternates_path() + if not alts: + if isfile(alternates_path): + os.remove(alternates_path) + else: + try: + f = open(alternates_path, 'w') + f.write("\n".join(alts)) + finally: + f.close() + # END file handling + # END alts handling + + alternates = property(_get_alternates, _set_alternates, doc="Retrieve a list of alternates paths or set a list paths to be used as alternates") + + #} END interface diff --git a/git/db/py/complex.py b/git/db/py/complex.py index de68d4fd..6504b3ed 100644 --- a/git/db/py/complex.py +++ b/git/db/py/complex.py @@ -8,6 +8,7 @@ from base import ( PureRootPathDB, PureRepositoryPathsMixin, PureConfigurationMixin, + PureAlternatesFileMixin, ) from resolve import PureReferencesMixin @@ -17,6 +18,8 @@ from pack import PurePackedODB from ref import PureReferenceDB from submodule import PureSubmoduleDB +from git.db.compat import RepoCompatInterface + from git.util import ( LazyMixin, normpath, @@ -30,10 +33,11 @@ from git.exc import ( ) import os -__all__ = ('PureGitODB', 'PureGitDB') +__all__ = ('PureGitODB', 'PureGitDB', 'PureCompatibilityGitDB') -class PureGitODB(PureRootPathDB, PureObjectDBW, PureCompoundDB, PureSubmoduleDB): +class PureGitODB(PureRootPathDB, PureObjectDBW, PureCompoundDB, + PureSubmoduleDB, PureAlternatesFileMixin): """A git-style object-only database, which contains all objects in the 'objects' subdirectory. :note: The type needs to be initialized on the ./objects directory to function, @@ -47,7 +51,7 @@ class PureGitODB(PureRootPathDB, PureObjectDBW, PureCompoundDB, PureSubmoduleDB) # Directories packs_dir = 'pack' loose_dir = '' - alternates_dir = os.path.join('info', 'alternates') + def __init__(self, root_path): """Initialize ourselves on a git ./objects directory""" @@ -59,7 +63,7 @@ class PureGitODB(PureRootPathDB, PureObjectDBW, PureCompoundDB, PureSubmoduleDB) loose_db = None for subpath, dbcls in ((self.packs_dir, self.PackDBCls), (self.loose_dir, self.LooseDBCls), - (self.alternates_dir, self.PureReferenceDBCls)): + (self.alternates_filepath, self.PureReferenceDBCls)): path = self.db_path(subpath) if os.path.exists(path): self._dbs.append(dbcls(path)) @@ -75,7 +79,7 @@ class PureGitODB(PureRootPathDB, PureObjectDBW, PureCompoundDB, PureSubmoduleDB) # END handle error # we the first one should have the store method - assert loose_db is not None and hasattr(loose_db, 'store'), "First database needs store functionality" + assert loose_db is not None and hasattr(loose_db, 'store'), "One database needs store functionality" # finally set the value self._loose_db = loose_db @@ -97,6 +101,7 @@ class PureGitODB(PureRootPathDB, PureObjectDBW, PureCompoundDB, PureSubmoduleDB) #} END objectdbw interface + class PureGitDB(PureGitODB, PureRepositoryPathsMixin, PureConfigurationMixin, PureReferencesMixin): """Git like database with support for object lookup as well as reference resolution. Our rootpath is set to the actual .git directory (bare on unbare). @@ -112,3 +117,6 @@ class PureGitDB(PureGitODB, PureRepositoryPathsMixin, PureConfigurationMixin, Pu +class PureCompatibilityGitDB(PureGitDB, RepoCompatInterface): + """Pure git database with a compatability layer required by 0.3x code""" + diff --git a/git/db/py/resolve.py b/git/db/py/resolve.py index 9cce8efe..94992d11 100644 --- a/git/db/py/resolve.py +++ b/git/db/py/resolve.py @@ -5,6 +5,9 @@ from git.db.interface import ReferencesMixin from git.exc import BadObject from git.refs import SymbolicReference from git.objects.base import Object +from git.refs.head import HEAD +from git.refs.headref import Head +from git.refs.tag import TagReference from git.util import ( join, isdir, @@ -281,17 +284,52 @@ class PureReferencesMixin(ReferencesMixin): re_hexsha_only = re.compile('^[0-9A-Fa-f]{40}$') re_hexsha_shortened = re.compile('^[0-9A-Fa-f]{4,40}$') + #{ Configuration + # Types to use when instatiating references + TagReferenceCls = TagReference + HeadCls = Head + ReferenceCls = Reference + HEADCls = HEAD + #} END configuration + def resolve(self, name): + return self.resolve_object(name).binsha + + def resolve_object(self, name): return rev_parse(self, name) @property def references(self): - raise NotImplementedError() + return self.ReferenceCls.list_items(self) @property def heads(self): - raise NotImplementedError() + return self.HeadCls.list_items(self) @property def tags(self): - raise NotImplementedError() + return self.TagReferenceCls.list_items(self) + + def tag(self, name): + return self.tags[name] + + @property + def head(self): + return self.HEADCls(self,'HEAD') + + def create_head(self, path, commit='HEAD', force=False, logmsg=None ): + return self.HeadCls.create(self, path, commit, force, logmsg) + + def delete_head(self, *heads, **kwargs): + return self.HeadCls.delete(self, *heads, **kwargs) + + def create_tag(self, path, ref='HEAD', message=None, force=False, **kwargs): + return self.TagReferenceCls.create(self, path, ref, message, force, **kwargs) + + def delete_tag(self, *tags): + return self.TagReferenceCls.delete(self, *tags) + + + # compat + branches = heads + refs = references diff --git a/git/db/py/transport.py b/git/db/py/transport.py index f8edfb23..00d222b0 100644 --- a/git/db/py/transport.py +++ b/git/db/py/transport.py @@ -9,6 +9,10 @@ from git.db.interface import ( TransportDB, FetchInfo, RefSpec ) +from git.refs.remote import RemoteReference +from git.remote import Remote + + __all__ = ["PureTransportDB"] class PurePushInfo(PushInfo): @@ -23,67 +27,32 @@ class PureFetchInfo(FetchInfo): class PureTransportDB(TransportDB): - """A database which allows to transport objects from and to different locations - which are specified by urls (location) and refspecs (what to transport, - see http://www.kernel.org/pub/software/scm/git/docs/git-fetch.html). - - At the beginning of a transport operation, it will be determined which objects - have to be sent (either by this or by the other side). - - Afterwards a pack with the required objects is sent (or received). If there is - nothing to send, the pack will be empty. - - The communication itself if implemented using a protocol instance which deals - with the actual formatting of the lines sent. - - As refspecs involve symbolic names for references to be handled, we require - RefParse functionality. How this is done is up to the actual implementation.""" # The following variables need to be set by the derived class #{Configuration protocol = None + RemoteCls = Remote #}end configuraiton #{ Interface def fetch(self, url, refspecs, progress=None, **kwargs): - """Fetch the objects defined by the given refspec from the given url. - :param url: url identifying the source of the objects. It may also be - a symbol from which the respective url can be resolved, like the - name of the remote. The implementation should allow objects as input - as well, these are assumed to resovle to a meaningful string though. - :param refspecs: iterable of reference specifiers or RefSpec instance, - identifying the references to be fetch from the remote. - :param progress: callable which receives progress messages for user consumption - :param kwargs: may be used for additional parameters that the actual implementation could - find useful. - :return: List of PureFetchInfo compatible instances which provide information about what - was previously fetched, in the order of the input refspecs. - :note: even if the operation fails, one of the returned PureFetchInfo instances - may still contain errors or failures in only part of the refspecs. - :raise: if any issue occours during the transport or if the url is not - supported by the protocol. - """ raise NotImplementedError() def push(self, url, refspecs, progress=None, **kwargs): - """Transport the objects identified by the given refspec to the remote - at the given url. - :param url: Decribes the location which is to receive the objects - see fetch() for more details - :param refspecs: iterable of refspecs strings or RefSpec instances - to identify the objects to push - :param progress: see fetch() - :param kwargs: additional arguments which may be provided by the caller - as they may be useful to the actual implementation - :todo: what to return ? - :raise: if any issue arises during transport or if the url cannot be handled""" raise NotImplementedError() @property def remotes(self): - """:return: An IterableList of Remote objects allowing to access and manipulate remotes - :note: Remote objects can also be used for the actual push or fetch operation""" - raise NotImplementedError() + return self.RemoteCls.list_items(self) + + def remote(self, name='origin'): + return self.remotes[name] + def create_remote(self, name, url, **kwargs): + return self.RemoteCls.create(self, name, url, **kwargs) + + def delete_remote(self, remote): + return self.RemoteCls.remove(self, remote) + #}end interface |