summaryrefslogtreecommitdiff
path: root/git/db/py
diff options
context:
space:
mode:
Diffstat (limited to 'git/db/py')
-rw-r--r--git/db/py/base.py278
-rw-r--r--git/db/py/complex.py78
-rw-r--r--git/db/py/loose.py128
-rw-r--r--git/db/py/mem.py65
-rw-r--r--git/db/py/pack.py88
-rw-r--r--git/db/py/ref.py20
-rw-r--r--git/db/py/resolve.py162
-rw-r--r--git/db/py/submodule.py13
-rw-r--r--git/db/py/transport.py35
9 files changed, 436 insertions, 431 deletions
diff --git a/git/db/py/base.py b/git/db/py/base.py
index 6710a0cc..127d828a 100644
--- a/git/db/py/base.py
+++ b/git/db/py/base.py
@@ -6,29 +6,29 @@
from git.db.interface import *
from git.util import (
- pool,
- join,
- isfile,
- normpath,
- abspath,
- dirname,
- LazyMixin,
- hex_to_bin,
- bin_to_hex,
- expandvars,
- expanduser,
- exists,
- is_git_dir,
- )
+ pool,
+ join,
+ isfile,
+ normpath,
+ abspath,
+ dirname,
+ LazyMixin,
+ hex_to_bin,
+ bin_to_hex,
+ expandvars,
+ expanduser,
+ exists,
+ is_git_dir,
+)
from git.index import IndexFile
from git.config import GitConfigParser
-from git.exc import (
- BadObject,
- AmbiguousObjectName,
- InvalidGitRepositoryError,
- NoSuchPathError
- )
+from git.exc import (
+ BadObject,
+ AmbiguousObjectName,
+ InvalidGitRepositoryError,
+ NoSuchPathError
+)
from async import ChannelThreadTask
@@ -37,28 +37,28 @@ import sys
import os
-__all__ = ( 'PureObjectDBR', 'PureObjectDBW', 'PureRootPathDB', 'PureCompoundDB',
- 'PureConfigurationMixin', 'PureRepositoryPathsMixin', 'PureAlternatesFileMixin',
- 'PureIndexDB')
-
+__all__ = ('PureObjectDBR', 'PureObjectDBW', 'PureRootPathDB', 'PureCompoundDB',
+ 'PureConfigurationMixin', 'PureRepositoryPathsMixin', 'PureAlternatesFileMixin',
+ 'PureIndexDB')
+
class PureObjectDBR(ObjectDBR):
-
- #{ Query Interface
-
+
+ #{ Query Interface
+
def has_object_async(self, reader):
task = ChannelThreadTask(reader, str(self.has_object_async), lambda sha: (sha, self.has_object(sha)))
- return pool.add_task(task)
-
+ return pool.add_task(task)
+
def info_async(self, reader):
task = ChannelThreadTask(reader, str(self.info_async), self.info)
return pool.add_task(task)
-
+
def stream_async(self, reader):
# base implementation just uses the stream method repeatedly
task = ChannelThreadTask(reader, str(self.stream_async), self.stream)
return pool.add_task(task)
-
+
def partial_to_complete_sha_hex(self, partial_hexsha):
len_partial_hexsha = len(partial_hexsha)
if len_partial_hexsha % 2 != 0:
@@ -67,53 +67,52 @@ class PureObjectDBR(ObjectDBR):
partial_binsha = hex_to_bin(partial_hexsha)
# END assure successful binary conversion
return self.partial_to_complete_sha(partial_binsha, len(partial_hexsha))
-
+
#} END query interface
-
-
+
+
class PureObjectDBW(ObjectDBW):
-
+
def __init__(self, *args, **kwargs):
try:
super(PureObjectDBW, self).__init__(*args, **kwargs)
except TypeError:
pass
- #END handle py 2.6
+ # END handle py 2.6
self._ostream = None
-
+
#{ Edit Interface
def set_ostream(self, stream):
cstream = self._ostream
self._ostream = stream
return cstream
-
+
def ostream(self):
return self._ostream
-
+
def store_async(self, reader):
- task = ChannelThreadTask(reader, str(self.store_async), self.store)
+ task = ChannelThreadTask(reader, str(self.store_async), self.store)
return pool.add_task(task)
-
+
#} END edit interface
-
+
class PureRootPathDB(RootPathDB):
-
+
def __init__(self, root_path):
self._root_path = root_path
super(PureRootPathDB, self).__init__(root_path)
-
-
- #{ Interface
+
+ #{ Interface
def root_path(self):
return self._root_path
-
+
def db_path(self, rela_path=None):
if not rela_path:
return self._root_path
return join(self._root_path, rela_path)
#} END interface
-
+
def _databases_recursive(database, output):
"""Fill output list with database from db, in order. Deals with Loose, Packed
@@ -127,50 +126,51 @@ def _databases_recursive(database, output):
else:
output.append(database)
# END handle database type
-
+
class PureCompoundDB(CompoundDB, PureObjectDBR, LazyMixin, CachingDB):
+
def _set_cache_(self, attr):
if attr == '_dbs':
self._dbs = list()
else:
super(PureCompoundDB, self)._set_cache_(attr)
-
- #{ PureObjectDBR interface
-
+
+ #{ PureObjectDBR interface
+
def has_object(self, sha):
for db in self._dbs:
if db.has_object(sha):
return True
- #END for each db
+ # END for each db
return False
-
+
def info(self, sha):
for db in self._dbs:
try:
return db.info(sha)
except BadObject:
pass
- #END for each db
-
+ # END for each db
+
def stream(self, sha):
for db in self._dbs:
try:
return db.stream(sha)
except BadObject:
pass
- #END for each db
+ # END for each db
def size(self):
- return reduce(lambda x,y: x+y, (db.size() for db in self._dbs), 0)
-
+ return reduce(lambda x, y: x + y, (db.size() for db in self._dbs), 0)
+
def sha_iter(self):
return chain(*(db.sha_iter() for db in self._dbs))
-
+
#} END object DBR Interface
-
+
#{ Interface
-
+
def databases(self):
return tuple(self._dbs)
@@ -183,15 +183,15 @@ class PureCompoundDB(CompoundDB, PureObjectDBR, LazyMixin, CachingDB):
# END if is caching db
# END for each database to update
return stat
-
+
def partial_to_complete_sha_hex(self, partial_hexsha):
len_partial_hexsha = len(partial_hexsha)
if len_partial_hexsha % 2 != 0:
partial_binsha = hex_to_bin(partial_hexsha + "0")
else:
partial_binsha = hex_to_bin(partial_hexsha)
- # END assure successful binary conversion
-
+ # END assure successful binary conversion
+
candidate = None
for db in self._dbs:
full_bin_sha = None
@@ -213,34 +213,34 @@ class PureCompoundDB(CompoundDB, PureObjectDBR, LazyMixin, CachingDB):
if not candidate:
raise BadObject(partial_binsha)
return candidate
-
+
def partial_to_complete_sha(self, partial_binsha, hex_len):
"""Simple adaptor to feed into our implementation"""
return self.partial_to_complete_sha_hex(bin_to_hex(partial_binsha)[:hex_len])
#} END interface
-
-
+
+
class PureRepositoryPathsMixin(RepositoryPathsMixin):
# slots has no effect here, its just to keep track of used attrs
- __slots__ = ("_git_path", '_bare', '_working_tree_dir')
-
- #{ Configuration
+ __slots__ = ("_git_path", '_bare', '_working_tree_dir')
+
+ #{ Configuration
repo_dir = '.git'
objs_dir = 'objects'
#} END configuration
-
+
#{ Subclass Interface
def _initialize(self, path):
epath = abspath(expandvars(expanduser(path or os.getcwd())))
if not exists(epath):
raise NoSuchPathError(epath)
- #END check file
+ # END check file
self._working_tree_dir = None
self._git_path = None
curpath = epath
-
+
# walk up the path to find the .git dir
while curpath:
if is_git_dir(curpath):
@@ -256,7 +256,7 @@ class PureRepositoryPathsMixin(RepositoryPathsMixin):
if not dummy:
break
# END while curpath
-
+
if self._git_path is None:
raise InvalidGitRepositoryError(epath)
# END path not found
@@ -264,167 +264,167 @@ class PureRepositoryPathsMixin(RepositoryPathsMixin):
self._bare = self._working_tree_dir is None
if hasattr(self, 'config_reader'):
try:
- self._bare = self.config_reader("repository").getboolean('core','bare')
+ self._bare = self.config_reader("repository").getboolean('core', 'bare')
except Exception:
# lets not assume the option exists, although it should
pass
- #END handle exception
- #END check bare flag
+ # END handle exception
+ # END check bare flag
self._working_tree_dir = self._bare and None or self._working_tree_dir
-
+
#} end subclass interface
-
+
#{ Object Interface
-
+
def __eq__(self, rhs):
if hasattr(rhs, 'git_dir'):
return self.git_dir == rhs.git_dir
return False
-
+
def __ne__(self, rhs):
return not self.__eq__(rhs)
-
+
def __hash__(self):
return hash(self.git_dir)
def __repr__(self):
return "%s(%r)" % (type(self).__name__, self.git_dir)
-
+
#} END object interface
-
+
#{ Interface
-
+
@property
def is_bare(self):
return self._bare
-
+
@property
def git_dir(self):
return self._git_path
-
+
@property
def working_tree_dir(self):
if self._working_tree_dir is None:
raise AssertionError("Repository at %s is bare and does not have a working tree directory" % self.git_dir)
- #END assertion
+ # END assertion
return dirname(self.git_dir)
-
+
@property
def objects_dir(self):
return join(self.git_dir, self.objs_dir)
-
+
@property
def working_dir(self):
if self.is_bare:
return self.git_dir
else:
return self.working_tree_dir
- #END handle bare state
-
+ # END handle bare state
+
def _mk_description():
def _get_description(self):
filename = join(self.git_dir, 'description')
return file(filename).read().rstrip()
-
+
def _set_description(self, descr):
filename = join(self.git_dir, 'description')
- file(filename, 'w').write(descr+'\n')
-
+ file(filename, 'w').write(descr + '\n')
+
return property(_get_description, _set_description, "Descriptive text for the content of the repository")
description = _mk_description()
del(_mk_description)
-
+
#} END interface
-
-
+
+
class PureConfigurationMixin(ConfigurationMixin):
-
+
#{ Configuration
system_config_file_name = "gitconfig"
repo_config_file_name = "config"
#} END
-
+
def __new__(cls, *args, **kwargs):
"""This is just a stupid workaround for the evil py2.6 change which makes mixins quite impossible"""
return super(PureConfigurationMixin, cls).__new__(cls, *args, **kwargs)
-
+
def __init__(self, *args, **kwargs):
"""Verify prereqs"""
try:
super(PureConfigurationMixin, self).__init__(*args, **kwargs)
except TypeError:
pass
- #END handle code-breaking change in python 2.6
+ # END handle code-breaking change in python 2.6
assert hasattr(self, 'git_dir')
-
- def _path_at_level(self, level ):
- # we do not support an absolute path of the gitconfig on windows ,
+
+ def _path_at_level(self, level):
+ # we do not support an absolute path of the gitconfig on windows ,
# use the global config instead
if sys.platform == "win32" and level == "system":
level = "global"
- #END handle windows
-
+ # END handle windows
+
if level == "system":
return "/etc/%s" % self.system_config_file_name
elif level == "global":
return normpath(expanduser("~/.%s" % self.system_config_file_name))
elif level == "repository":
return join(self.git_dir, self.repo_config_file_name)
- #END handle level
-
+ # END handle level
+
raise ValueError("Invalid configuration level: %r" % level)
-
+
#{ Interface
-
+
def config_reader(self, config_level=None):
files = None
if config_level is None:
- files = [ self._path_at_level(f) for f in self.config_level ]
+ files = [self._path_at_level(f) for f in self.config_level]
else:
- files = [ self._path_at_level(config_level) ]
- #END handle level
+ files = [self._path_at_level(config_level)]
+ # END handle level
return GitConfigParser(files, read_only=True)
-
+
def config_writer(self, config_level="repository"):
return GitConfigParser(self._path_at_level(config_level), read_only=False)
-
-
+
#} END interface
-
-
+
+
class PureIndexDB(IndexDB):
#{ Configuration
IndexCls = IndexFile
#} END configuration
-
+
@property
def index(self):
return self.IndexCls(self)
-
-
+
+
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):
try:
super(PureAlternatesFileMixin, self).__init__(*args, **kwargs)
except TypeError:
pass
- #END handle py2.6 code breaking changes
- self._alternates_path() # throws on incompatible type
-
- #{ Interface
-
+ # END handle py2.6 code breaking changes
+ 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)
@@ -432,8 +432,8 @@ class PureAlternatesFileMixin(object):
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
-
+ # END handle path
+
def _get_alternates(self):
"""The list of alternates for this repo from which objects can be retrieved
@@ -462,7 +462,7 @@ class PureAlternatesFileMixin(object):
:note:
The method does not check for the existance of the paths in alts
as the caller is responsible."""
- alternates_path = self._alternates_path()
+ alternates_path = self._alternates_path()
if not alts:
if isfile(alternates_path):
os.remove(alternates_path)
@@ -472,10 +472,10 @@ class PureAlternatesFileMixin(object):
f.write("\n".join(alts))
finally:
f.close()
- # END file handling
+ # 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")
-
+ 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 9d06f74a..1ef40ac2 100644
--- a/git/db/py/complex.py
+++ b/git/db/py/complex.py
@@ -4,14 +4,14 @@
# the New BSD License: http://www.opensource.org/licenses/bsd-license.php
from git.db.interface import HighLevelRepository
from base import (
- PureCompoundDB,
- PureObjectDBW,
- PureRootPathDB,
- PureRepositoryPathsMixin,
- PureConfigurationMixin,
- PureAlternatesFileMixin,
- PureIndexDB,
- )
+ PureCompoundDB,
+ PureObjectDBW,
+ PureRootPathDB,
+ PureRepositoryPathsMixin,
+ PureConfigurationMixin,
+ PureAlternatesFileMixin,
+ PureIndexDB,
+)
from transport import PureTransportDB
from resolve import PureReferencesMixin
@@ -29,6 +29,7 @@ __all__ = ('PureGitODB', 'PurePartialGitDB', 'PureCompatibilityGitDB')
class PureGitODB(PureRootPathDB, PureObjectDBW, PureCompoundDB, 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,
@@ -38,23 +39,22 @@ class PureGitODB(PureRootPathDB, PureObjectDBW, PureCompoundDB, PureAlternatesFi
PackDBCls = PurePackedODB
LooseDBCls = PureLooseObjectODB
PureReferenceDBCls = PureReferenceDB
-
+
# Directories
packs_dir = 'pack'
loose_dir = ''
-
-
+
def __init__(self, root_path):
"""Initialize ourselves on a git ./objects directory"""
super(PureGitODB, self).__init__(root_path)
-
+
def _set_cache_(self, attr):
if attr == '_dbs' or attr == '_loose_db':
self._dbs = list()
loose_db = None
- for subpath, dbcls in ((self.packs_dir, self.PackDBCls),
- (self.loose_dir, self.LooseDBCls),
- (self.alternates_filepath, self.PureReferenceDBCls)):
+ for subpath, dbcls in ((self.packs_dir, self.PackDBCls),
+ (self.loose_dir, self.LooseDBCls),
+ (self.alternates_filepath, self.PureReferenceDBCls)):
path = self.db_path(subpath)
if os.path.exists(path):
self._dbs.append(dbcls(path))
@@ -63,56 +63,56 @@ class PureGitODB(PureRootPathDB, PureObjectDBW, PureCompoundDB, PureAlternatesFi
# END remember loose db
# END check path exists
# END for each db type
-
+
# should have at least one subdb
if not self._dbs:
raise InvalidDBRoot(self.root_path())
# END handle error
-
+
# we the first one should have the store method
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
else:
super(PureGitODB, self)._set_cache_(attr)
# END handle attrs
-
+
#{ PureObjectDBW interface
-
+
def store(self, istream):
return self._loose_db.store(istream)
-
+
def ostream(self):
return self._loose_db.ostream()
-
+
def set_ostream(self, ostream):
return self._loose_db.set_ostream(ostream)
-
+
#} END objectdbw interface
-
-
-
-class PurePartialGitDB(PureGitODB,
- PureRepositoryPathsMixin, PureConfigurationMixin,
- PureReferencesMixin, PureSubmoduleDB,
- PureIndexDB,
- PureTransportDB # not fully implemented
- # HighLevelRepository Currently not implemented !
- ):
+
+
+class PurePartialGitDB(PureGitODB,
+ PureRepositoryPathsMixin, PureConfigurationMixin,
+ PureReferencesMixin, PureSubmoduleDB,
+ PureIndexDB,
+ PureTransportDB # not fully implemented
+ # HighLevelRepository Currently not implemented !
+ ):
+
"""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).
-
+
The root_path will be the git objects directory. Use git_path() to obtain the actual top-level
git directory."""
- #directories
-
+ # directories
+
def __init__(self, root_path):
"""Initialize ourselves on the .git directory, or the .git/objects directory."""
PureRepositoryPathsMixin._initialize(self, root_path)
super(PurePartialGitDB, self).__init__(self.objects_dir)
-
-
+
+
class PureCompatibilityGitDB(PurePartialGitDB, RepoCompatibilityInterface):
+
"""Pure git database with a compatability layer required by 0.3x code"""
-
diff --git a/git/db/py/loose.py b/git/db/py/loose.py
index 8267be98..40639e4e 100644
--- a/git/db/py/loose.py
+++ b/git/db/py/loose.py
@@ -3,53 +3,53 @@
# This module is part of GitDB and is released under
# the New BSD License: http://www.opensource.org/licenses/bsd-license.php
from base import (
- PureRootPathDB,
- PureObjectDBR,
- PureObjectDBW
- )
+ PureRootPathDB,
+ PureObjectDBR,
+ PureObjectDBW
+)
from git.exc import (
- InvalidDBRoot,
+ InvalidDBRoot,
BadObject,
AmbiguousObjectName
- )
+)
from git.stream import (
- DecompressMemMapReader,
- FDCompressedSha1Writer,
- FDStream,
- Sha1Writer
- )
+ DecompressMemMapReader,
+ FDCompressedSha1Writer,
+ FDStream,
+ Sha1Writer
+)
from git.base import (
- OStream,
- OInfo
- )
+ OStream,
+ OInfo
+)
from git.util import (
- file_contents_ro_filepath,
- ENOENT,
- hex_to_bin,
- bin_to_hex,
- exists,
- chmod,
- isdir,
- isfile,
- remove,
- mkdir,
- rename,
- dirname,
- basename,
- join
- )
-
-from git.fun import (
+ file_contents_ro_filepath,
+ ENOENT,
+ hex_to_bin,
+ bin_to_hex,
+ exists,
+ chmod,
+ isdir,
+ isfile,
+ remove,
+ mkdir,
+ rename,
+ dirname,
+ basename,
+ join
+)
+
+from git.fun import (
chunk_size,
- loose_object_header_info,
+ loose_object_header_info,
write_object,
stream_copy
- )
+)
import tempfile
import mmap
@@ -57,23 +57,23 @@ import sys
import os
-__all__ = ( 'PureLooseObjectODB', )
+__all__ = ('PureLooseObjectODB', )
class PureLooseObjectODB(PureRootPathDB, PureObjectDBR, PureObjectDBW):
+
"""A database which operates on loose object files"""
-
+
# CONFIGURATION
# chunks in which data will be copied between streams
stream_chunk_size = chunk_size
-
+
# On windows we need to keep it writable, otherwise it cannot be removed
# either
new_objects_mode = 0444
if os.name == 'nt':
new_objects_mode = 0644
-
-
+
def __init__(self, root_path):
super(PureLooseObjectODB, self).__init__(root_path)
self._hexsha_to_file = dict()
@@ -81,14 +81,14 @@ class PureLooseObjectODB(PureRootPathDB, PureObjectDBR, PureObjectDBW):
# Depending on the root, this might work for some mounts, for others not, which
# is why it is per instance
self._fd_open_flags = getattr(os, 'O_NOATIME', 0)
-
- #{ Interface
+
+ #{ Interface
def object_path(self, hexsha):
"""
:return: path at which the object with the given hexsha would be stored,
relative to the database root"""
return join(hexsha[:2], hexsha[2:])
-
+
def readable_db_object_path(self, hexsha):
"""
:return: readable object path to the object identified by hexsha
@@ -97,8 +97,8 @@ class PureLooseObjectODB(PureRootPathDB, PureObjectDBR, PureObjectDBW):
return self._hexsha_to_file[hexsha]
except KeyError:
pass
- # END ignore cache misses
-
+ # END ignore cache misses
+
# try filesystem
path = self.db_path(self.object_path(hexsha))
if exists(path):
@@ -106,10 +106,9 @@ class PureLooseObjectODB(PureRootPathDB, PureObjectDBR, PureObjectDBW):
return path
# END handle cache
raise BadObject(hexsha)
-
-
+
#} END interface
-
+
def _map_loose_object(self, sha):
"""
:return: memory map of that file to allow random read access
@@ -117,7 +116,7 @@ class PureLooseObjectODB(PureRootPathDB, PureObjectDBR, PureObjectDBW):
db_path = self.db_path(self.object_path(bin_to_hex(sha)))
try:
return file_contents_ro_filepath(db_path, flags=self._fd_open_flags)
- except OSError,e:
+ except OSError, e:
if e.errno != ENOENT:
# try again without noatime
try:
@@ -135,13 +134,13 @@ class PureLooseObjectODB(PureRootPathDB, PureObjectDBR, PureObjectDBW):
finally:
os.close(fd)
# END assure file is closed
-
+
def set_ostream(self, stream):
""":raise TypeError: if the stream does not support the Sha1Writer interface"""
if stream is not None and not isinstance(stream, Sha1Writer):
raise TypeError("Output stream musst support the %s interface" % Sha1Writer.__name__)
return super(PureLooseObjectODB, self).set_ostream(stream)
-
+
def info(self, sha):
m = self._map_loose_object(sha)
try:
@@ -150,12 +149,12 @@ class PureLooseObjectODB(PureRootPathDB, PureObjectDBR, PureObjectDBW):
finally:
m.close()
# END assure release of system resources
-
+
def stream(self, sha):
m = self._map_loose_object(sha)
- type, size, stream = DecompressMemMapReader.new(m, close_on_deletion = True)
+ type, size, stream = DecompressMemMapReader.new(m, close_on_deletion=True)
return OStream(sha, type, size, stream)
-
+
def has_object(self, sha):
try:
self.readable_db_object_path(bin_to_hex(sha))
@@ -163,7 +162,7 @@ class PureLooseObjectODB(PureRootPathDB, PureObjectDBR, PureObjectDBW):
except BadObject:
return False
# END check existance
-
+
def partial_to_complete_sha_hex(self, partial_hexsha):
""":return: 20 byte binary sha1 string which matches the given name uniquely
:param name: hexadecimal partial name
@@ -180,7 +179,7 @@ class PureLooseObjectODB(PureRootPathDB, PureObjectDBR, PureObjectDBW):
if candidate is None:
raise BadObject(partial_hexsha)
return candidate
-
+
def store(self, istream):
"""note: The sha we produce will be hex by nature"""
tmp_path = None
@@ -188,14 +187,14 @@ class PureLooseObjectODB(PureRootPathDB, PureObjectDBR, PureObjectDBW):
if writer is None:
# open a tmp file to write the data to
fd, tmp_path = tempfile.mkstemp(prefix='obj', dir=self._root_path)
-
+
if istream.binsha is None:
writer = FDCompressedSha1Writer(fd)
else:
writer = FDStream(fd)
# END handle direct stream copies
# END handle custom writer
-
+
try:
try:
if istream.binsha is not None:
@@ -205,7 +204,7 @@ class PureLooseObjectODB(PureRootPathDB, PureObjectDBR, PureObjectDBW):
else:
# write object with header, we have to make a new one
write_object(istream.type, istream.size, istream.read, writer.write,
- chunk_size=self.stream_chunk_size)
+ chunk_size=self.stream_chunk_size)
# END handle direct stream copies
finally:
if tmp_path:
@@ -216,14 +215,14 @@ class PureLooseObjectODB(PureRootPathDB, PureObjectDBR, PureObjectDBW):
os.remove(tmp_path)
raise
# END assure tmpfile removal on error
-
+
hexsha = None
if istream.binsha:
hexsha = istream.hexsha
else:
hexsha = writer.sha(as_hex=True)
# END handle sha
-
+
if tmp_path:
obj_path = self.db_path(self.object_path(hexsha))
obj_dir = dirname(obj_path)
@@ -235,29 +234,28 @@ class PureLooseObjectODB(PureRootPathDB, PureObjectDBR, PureObjectDBW):
remove(obj_path)
# END handle win322
rename(tmp_path, obj_path)
-
+
# make sure its readable for all ! It started out as rw-- tmp file
# but needs to be rwrr
chmod(obj_path, self.new_objects_mode)
# END handle dry_run
-
+
istream.binsha = hex_to_bin(hexsha)
return istream
-
+
def sha_iter(self):
# find all files which look like an object, extract sha from there
for root, dirs, files in os.walk(self.root_path()):
root_base = basename(root)
if len(root_base) != 2:
continue
-
+
for f in files:
if len(f) != 38:
continue
yield hex_to_bin(root_base + f)
# END for each file
# END for each walk iteration
-
+
def size(self):
return len(tuple(self.sha_iter()))
-
diff --git a/git/db/py/mem.py b/git/db/py/mem.py
index 63ceb756..65a457fe 100644
--- a/git/db/py/mem.py
+++ b/git/db/py/mem.py
@@ -4,72 +4,74 @@
# the New BSD License: http://www.opensource.org/licenses/bsd-license.php
"""Contains the MemoryDatabase implementation"""
from base import (
- PureObjectDBR,
- PureObjectDBW
- )
+ PureObjectDBR,
+ PureObjectDBW
+)
from loose import PureLooseObjectODB
from git.base import (
- OStream,
- IStream,
- )
+ OStream,
+ IStream,
+)
from git.exc import (
- BadObject,
- UnsupportedOperation
- )
+ BadObject,
+ UnsupportedOperation
+)
from git.stream import (
- ZippedStoreShaWriter,
- DecompressMemMapReader,
- )
+ ZippedStoreShaWriter,
+ DecompressMemMapReader,
+)
from cStringIO import StringIO
__all__ = ("PureMemoryDB", )
+
class PureMemoryDB(PureObjectDBR, PureObjectDBW):
+
"""A memory database stores everything to memory, providing fast IO and object
retrieval. It should be used to buffer results and obtain SHAs before writing
it to the actual physical storage, as it allows to query whether object already
exists in the target storage before introducing actual IO
-
+
:note: memory is currently not threadsafe, hence the async methods cannot be used
for storing"""
-
+
def __init__(self):
super(PureMemoryDB, self).__init__()
self._db = PureLooseObjectODB("path/doesnt/matter")
-
+
# maps 20 byte shas to their OStream objects
self._cache = dict()
-
+
def set_ostream(self, stream):
raise UnsupportedOperation("PureMemoryDB's always stream into memory")
-
+
def store(self, istream):
zstream = ZippedStoreShaWriter()
self._db.set_ostream(zstream)
-
+
istream = self._db.store(istream)
zstream.close() # close to flush
zstream.seek(0)
-
- # don't provide a size, the stream is written in object format, hence the
+
+ # don't provide a size, the stream is written in object format, hence the
# header needs decompression
- decomp_stream = DecompressMemMapReader(zstream.getvalue(), close_on_deletion=False)
+ decomp_stream = DecompressMemMapReader(zstream.getvalue(), close_on_deletion=False)
self._cache[istream.binsha] = OStream(istream.binsha, istream.type, istream.size, decomp_stream)
-
+
return istream
-
+
def store_async(self, reader):
raise UnsupportedOperation("PureMemoryDBs cannot currently be used for async write access")
-
+
def has_object(self, sha):
return sha in self._cache
def info(self, sha):
# we always return streams, which are infos as well
return self.stream(sha)
-
+
def stream(self, sha):
try:
ostream = self._cache[sha]
@@ -79,15 +81,14 @@ class PureMemoryDB(PureObjectDBR, PureObjectDBW):
except KeyError:
raise BadObject(sha)
# END exception handling
-
+
def size(self):
return len(self._cache)
-
+
def sha_iter(self):
return self._cache.iterkeys()
-
-
- #{ Interface
+
+ #{ Interface
def stream_copy(self, sha_iter, odb):
"""Copy the streams as identified by sha's yielded by sha_iter into the given odb
The streams will be copied directly
@@ -99,12 +100,12 @@ class PureMemoryDB(PureObjectDBR, PureObjectDBW):
if odb.has_object(sha):
continue
# END check object existance
-
+
ostream = self.stream(sha)
# compressed data including header
sio = StringIO(ostream.stream.data())
istream = IStream(ostream.type, ostream.size, sio, sha)
-
+
odb.store(istream)
count += 1
# END for each sha
diff --git a/git/db/py/pack.py b/git/db/py/pack.py
index 0d4c533a..e107aba2 100644
--- a/git/db/py/pack.py
+++ b/git/db/py/pack.py
@@ -5,17 +5,17 @@
"""Module containing a database to deal with packs"""
from git.db import CachingDB
from base import (
- PureRootPathDB,
- PureObjectDBR
- )
+ PureRootPathDB,
+ PureObjectDBR
+)
from git.util import LazyMixin
from git.exc import (
- BadObject,
- UnsupportedOperation,
- AmbiguousObjectName
- )
+ BadObject,
+ UnsupportedOperation,
+ AmbiguousObjectName
+)
from git.pack import PackEntity
@@ -28,16 +28,17 @@ __all__ = ('PurePackedODB', )
class PurePackedODB(PureRootPathDB, PureObjectDBR, CachingDB, LazyMixin):
+
"""A database operating on a set of object packs"""
-
+
# the type to use when instantiating a pack entity
PackEntityCls = PackEntity
-
+
# sort the priority list every N queries
- # Higher values are better, performance tests don't show this has
+ # Higher values are better, performance tests don't show this has
# any effect, but it should have one
_sort_interval = 500
-
+
def __init__(self, root_path):
super(PurePackedODB, self).__init__(root_path)
# list of lists with three items:
@@ -47,16 +48,16 @@ class PurePackedODB(PureRootPathDB, PureObjectDBR, CachingDB, LazyMixin):
# self._entities = list() # lazy loaded list
self._hit_count = 0 # amount of hits
self._st_mtime = 0 # last modification data of our root path
-
+
def _set_cache_(self, attr):
if attr == '_entities':
self._entities = list()
self.update_cache(force=True)
# END handle entities initialization
-
+
def _sort_entities(self):
self._entities.sort(key=lambda l: l[0], reverse=True)
-
+
def _pack_info(self, sha):
""":return: tuple(entity, index) for an item at the given sha
:param sha: 20 or 40 byte sha
@@ -69,7 +70,7 @@ class PurePackedODB(PureRootPathDB, PureObjectDBR, CachingDB, LazyMixin):
if self._hit_count % self._sort_interval == 0:
self._sort_entities()
# END update sorting
-
+
for item in self._entities:
index = item[2](sha)
if index is not None:
@@ -78,14 +79,14 @@ class PurePackedODB(PureRootPathDB, PureObjectDBR, CachingDB, LazyMixin):
return (item[1], index)
# END index found in pack
# END for each item
-
+
# no hit, see whether we have to update packs
# NOTE: considering packs don't change very often, we safe this call
# and leave it to the super-caller to trigger that
raise BadObject(sha)
-
- #{ Object DB Read
-
+
+ #{ Object DB Read
+
def has_object(self, sha):
try:
self._pack_info(sha)
@@ -93,15 +94,15 @@ class PurePackedODB(PureRootPathDB, PureObjectDBR, CachingDB, LazyMixin):
except BadObject:
return False
# END exception handling
-
+
def info(self, sha):
entity, index = self._pack_info(sha)
return entity.info_at_index(index)
-
+
def stream(self, sha):
entity, index = self._pack_info(sha)
return entity.stream_at_index(index)
-
+
def sha_iter(self):
sha_list = list()
for entity in self.entities():
@@ -111,35 +112,34 @@ class PurePackedODB(PureRootPathDB, PureObjectDBR, CachingDB, LazyMixin):
yield sha_by_index(index)
# END for each index
# END for each entity
-
+
def size(self):
sizes = [item[1].index().size() for item in self._entities]
- return reduce(lambda x,y: x+y, sizes, 0)
-
+ return reduce(lambda x, y: x + y, sizes, 0)
+
#} END object db read
-
+
#{ object db write
-
+
def store(self, istream):
"""Storing individual objects is not feasible as a pack is designed to
hold multiple objects. Writing or rewriting packs for single objects is
inefficient"""
raise UnsupportedOperation()
-
+
def store_async(self, reader):
# TODO: add PureObjectDBRW before implementing this
raise NotImplementedError()
-
+
#} END object db write
-
-
- #{ Interface
-
+
+ #{ Interface
+
def update_cache(self, force=False):
"""
Update our cache with the acutally existing packs on disk. Add new ones,
and remove deleted ones. We keep the unchanged ones
-
+
:param force: If True, the cache will be updated even though the directory
does not appear to have changed according to its modification timestamp.
:return: True if the packs have been updated so there is new information,
@@ -149,12 +149,12 @@ class PurePackedODB(PureRootPathDB, PureObjectDBR, CachingDB, LazyMixin):
return False
# END abort early on no change
self._st_mtime = stat.st_mtime
-
+
# packs are supposed to be prefixed with pack- by git-convention
# get all pack files, figure out what changed
pack_files = set(glob.glob(os.path.join(self.root_path(), "pack-*.pack")))
our_pack_files = set(item[1].pack().path() for item in self._entities)
-
+
# new packs
for pack_file in (pack_files - our_pack_files):
# init the hit-counter/priority with the size, a good measure for hit-
@@ -162,7 +162,7 @@ class PurePackedODB(PureRootPathDB, PureObjectDBR, CachingDB, LazyMixin):
entity = self.PackEntityCls(pack_file)
self._entities.append([entity.pack().size(), entity, entity.index().sha_to_index])
# END for each new packfile
-
+
# removed packs
for pack_file in (our_pack_files - pack_files):
del_index = -1
@@ -175,15 +175,15 @@ class PurePackedODB(PureRootPathDB, PureObjectDBR, CachingDB, LazyMixin):
assert del_index != -1
del(self._entities[del_index])
# END for each removed pack
-
+
# reinitialize prioritiess
self._sort_entities()
return True
-
+
def entities(self):
""":return: list of pack entities operated upon by this database"""
- return [ item[1] for item in self._entities ]
-
+ return [item[1] for item in self._entities]
+
def partial_to_complete_sha(self, partial_binsha, canonical_length):
""":return: 20 byte sha as inferred by the given partial binary sha
:param partial_binsha: binary sha with less than 20 bytes
@@ -202,11 +202,11 @@ class PurePackedODB(PureRootPathDB, PureObjectDBR, CachingDB, LazyMixin):
candidate = sha
# END handle full sha could be found
# END for each entity
-
+
if candidate:
return candidate
-
+
# still not found ?
raise BadObject(partial_binsha)
-
+
#} END interface
diff --git a/git/db/py/ref.py b/git/db/py/ref.py
index 75bc4fd1..3552f2a3 100644
--- a/git/db/py/ref.py
+++ b/git/db/py/ref.py
@@ -7,18 +7,20 @@ from base import PureCompoundDB
import os
__all__ = ('PureReferenceDB', )
+
class PureReferenceDB(PureCompoundDB):
+
"""A database consisting of database referred to in a file"""
-
+
# Configuration
# Specifies the object database to use for the paths found in the alternates
# file. If None, it defaults to the PureGitODB
ObjectDBCls = None
-
+
def __init__(self, ref_file):
super(PureReferenceDB, self).__init__()
self._ref_file = ref_file
-
+
def _set_cache_(self, attr):
if attr == '_dbs':
self._dbs = list()
@@ -26,7 +28,7 @@ class PureReferenceDB(PureCompoundDB):
else:
super(PureReferenceDB, self)._set_cache_(attr)
# END handle attrs
-
+
def _update_dbs_from_ref_file(self):
dbcls = self.ObjectDBCls
if dbcls is None:
@@ -34,7 +36,7 @@ class PureReferenceDB(PureCompoundDB):
import complex
dbcls = complex.PureGitODB
# END get db type
-
+
# try to get as many as possible, don't fail if some are unavailable
ref_paths = list()
try:
@@ -42,10 +44,10 @@ class PureReferenceDB(PureCompoundDB):
except (OSError, IOError):
pass
# END handle alternates
-
+
ref_paths_set = set(ref_paths)
cur_ref_paths_set = set(db.root_path() for db in self._dbs)
-
+
# remove existing
for path in (cur_ref_paths_set - ref_paths_set):
for i, db in enumerate(self._dbs[:]):
@@ -54,7 +56,7 @@ class PureReferenceDB(PureCompoundDB):
continue
# END del matching db
# END for each path to remove
-
+
# add new
# sort them to maintain order
added_paths = sorted(ref_paths_set - cur_ref_paths_set, key=lambda p: ref_paths.index(p))
@@ -70,7 +72,7 @@ class PureReferenceDB(PureCompoundDB):
# ignore invalid paths or issues
pass
# END for each path to add
-
+
def update_cache(self, force=False):
# re-read alternates and update databases
self._update_dbs_from_ref_file()
diff --git a/git/db/py/resolve.py b/git/db/py/resolve.py
index 8a64d76b..4301c2ad 100644
--- a/git/db/py/resolve.py
+++ b/git/db/py/resolve.py
@@ -4,12 +4,12 @@ version assuming compatible interface for reference and object types"""
from git.db.interface import ReferencesMixin
from git.exc import BadObject
from git.refs import (
- SymbolicReference,
- Reference,
- HEAD,
- Head,
- TagReference
- )
+ SymbolicReference,
+ Reference,
+ HEAD,
+ Head,
+ TagReference
+)
from git.refs.head import HEAD
from git.refs.headref import Head
from git.refs.tag import TagReference
@@ -17,13 +17,13 @@ from git.refs.tag import TagReference
from git.objects.base import Object
from git.objects.commit import Commit
from git.util import (
- join,
- isdir,
- isfile,
- hex_to_bin,
- bin_to_hex,
- is_git_dir
- )
+ join,
+ isdir,
+ isfile,
+ hex_to_bin,
+ bin_to_hex,
+ is_git_dir
+)
from string import digits
import os
import re
@@ -32,6 +32,7 @@ __all__ = ["PureReferencesMixin"]
#{ Utilities
+
def short_to_long(odb, hexsha):
""":return: long hexadecimal sha1 from the given less-than-40 byte hexsha
or None if no candidate could be found.
@@ -41,8 +42,8 @@ def short_to_long(odb, hexsha):
except BadObject:
return None
# END exception handling
-
-
+
+
def name_to_object(repo, name, return_ref=False):
"""
:return: object specified by the given name, hexshas ( short and long )
@@ -51,7 +52,7 @@ def name_to_object(repo, name, return_ref=False):
instead of the object. Otherwise it will raise BadObject
"""
hexsha = None
-
+
# is it a hexsha ? Try the most common ones, which is 7 to 40
if repo.re_hexsha_shortened.match(name):
if len(name) != 40:
@@ -60,9 +61,9 @@ def name_to_object(repo, name, return_ref=False):
else:
hexsha = name
# END handle short shas
- #END find sha if it matches
-
- # if we couldn't find an object for what seemed to be a short hexsha
+ # END find sha if it matches
+
+ # if we couldn't find an object for what seemed to be a short hexsha
# try to find it as reference anyway, it could be named 'aaa' for instance
if hexsha is None:
for base in ('%s', 'refs/%s', 'refs/tags/%s', 'refs/heads/%s', 'refs/remotes/%s', 'refs/remotes/%s/HEAD'):
@@ -70,7 +71,7 @@ def name_to_object(repo, name, return_ref=False):
hexsha = SymbolicReference.dereference_recursive(repo, base % name)
if return_ref:
return SymbolicReference(repo, base % name)
- #END handle symbolic ref
+ # END handle symbolic ref
break
except ValueError:
pass
@@ -80,15 +81,16 @@ def name_to_object(repo, name, return_ref=False):
# didn't find any ref, this is an error
if return_ref:
raise BadObject("Couldn't find reference named %r" % name)
- #END handle return ref
+ # END handle return ref
# tried everything ? fail
if hexsha is None:
raise BadObject(name)
# END assert hexsha was found
-
+
return Object.new_from_sha(repo, hex_to_bin(hexsha))
+
def deref_tag(tag):
"""Recursively dereference a tag and return the resulting object"""
while True:
@@ -99,16 +101,18 @@ def deref_tag(tag):
# END dereference tag
return tag
+
def to_commit(obj):
"""Convert the given object to a commit if possible and return it"""
if obj.type == 'tag':
obj = deref_tag(obj)
-
+
if obj.type != "commit":
raise ValueError("Cannot convert object %r to type commit" % obj)
# END verify type
return obj
+
def rev_parse(repo, rev):
"""
:return: Object at the given revision, either Commit, Tag, Tree or Blob
@@ -120,13 +124,13 @@ def rev_parse(repo, rev):
:raise BadObject: if the given revision could not be found
:raise ValueError: If rev couldn't be parsed
:raise IndexError: If invalid reflog index is specified"""
-
+
# colon search mode ?
if rev.startswith(':/'):
# colon search mode
raise NotImplementedError("commit by message search ( regex )")
# END handle search
-
+
obj = None
ref = None
output_type = "commit"
@@ -138,9 +142,9 @@ def rev_parse(repo, rev):
start += 1
continue
# END handle start
-
+
token = rev[start]
-
+
if obj is None:
# token is a rev name
if start == 0:
@@ -150,27 +154,26 @@ def rev_parse(repo, rev):
ref = name_to_object(repo, rev[:start], return_ref=True)
else:
obj = name_to_object(repo, rev[:start])
- #END handle token
- #END handle refname
-
+ # END handle token
+ # END handle refname
+
if ref is not None:
obj = ref.commit
- #END handle ref
+ # END handle ref
# END initialize obj on first token
-
-
+
start += 1
-
+
# try to parse {type}
if start < lr and rev[start] == '{':
end = rev.find('}', start)
if end == -1:
raise ValueError("Missing closing brace to define type in %s" % rev)
- output_type = rev[start+1:end] # exclude brace
-
- # handle type
+ output_type = rev[start + 1:end] # exclude brace
+
+ # handle type
if output_type == 'commit':
- pass # default
+ pass # default
elif output_type == 'tree':
try:
obj = to_commit(obj).tree
@@ -190,37 +193,37 @@ def rev_parse(repo, rev):
revlog_index = None
try:
# transform reversed index into the format of our revlog
- revlog_index = -(int(output_type)+1)
+ revlog_index = -(int(output_type) + 1)
except ValueError:
# TODO: Try to parse the other date options, using parse_date
# maybe
raise NotImplementedError("Support for additional @{...} modes not implemented")
- #END handle revlog index
-
+ # END handle revlog index
+
try:
entry = ref.log_entry(revlog_index)
except IndexError:
raise IndexError("Invalid revlog index: %i" % revlog_index)
- #END handle index out of bound
-
+ # END handle index out of bound
+
obj = Object.new_from_sha(repo, hex_to_bin(entry.newhexsha))
-
+
# make it pass the following checks
output_type = None
else:
- raise ValueError("Invalid output type: %s ( in %s )" % (output_type, rev))
+ raise ValueError("Invalid output type: %s ( in %s )" % (output_type, rev))
# END handle output type
-
+
# empty output types don't require any specific type, its just about dereferencing tags
if output_type and obj.type != output_type:
raise ValueError("Could not accomodate requested object type %r, got %s" % (output_type, obj.type))
# END verify ouput type
-
- start = end+1 # skip brace
+
+ start = end + 1 # skip brace
parsed_to = start
continue
# END parse type
-
+
# try to parse a number
num = 0
if token != ":":
@@ -234,15 +237,14 @@ def rev_parse(repo, rev):
break
# END handle number
# END number parse loop
-
+
# no explicit number given, 1 is the default
- # It could be 0 though
+ # It could be 0 though
if not found_digit:
num = 1
# END set default num
# END number parsing only if non-blob mode
-
-
+
parsed_to = start
# handle hiererarchy walk
try:
@@ -255,7 +257,7 @@ def rev_parse(repo, rev):
obj = to_commit(obj)
# must be n'th parent
if num:
- obj = obj.parents[num-1]
+ obj = obj.parents[num - 1]
elif token == ":":
if obj.type != "tree":
obj = obj.tree
@@ -269,29 +271,31 @@ def rev_parse(repo, rev):
raise BadObject("Invalid Revision in %s" % rev)
# END exception handling
# END parse loop
-
+
# still no obj ? Its probably a simple name
if obj is None:
obj = name_to_object(repo, rev)
parsed_to = lr
# END handle simple name
-
+
if obj is None:
raise ValueError("Revision specifier could not be parsed: %s" % rev)
if parsed_to != lr:
raise ValueError("Didn't consume complete rev spec %s, consumed part: %s" % (rev, rev[:parsed_to]))
-
+
return obj
#} END utilities
+
class PureReferencesMixin(ReferencesMixin):
+
"""Pure-Python refparse implementation"""
-
+
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
@@ -300,64 +304,62 @@ class PureReferencesMixin(ReferencesMixin):
HEADCls = HEAD
CommitCls = Commit
#} 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):
return self.ReferenceCls.list_items(self)
-
+
@property
def heads(self):
return self.HeadCls.list_items(self)
-
+
@property
def tags(self):
return self.TagReferenceCls.list_items(self)
-
+
def tag(self, name):
return self.TagReferenceCls(self, self.TagReferenceCls.to_full_path(name))
-
+
def commit(self, rev=None):
if rev is None:
return self.head.commit
else:
- return self.resolve_object(str(rev)+"^0")
- #END handle revision
-
+ return self.resolve_object(str(rev) + "^0")
+ # END handle revision
+
def iter_trees(self, *args, **kwargs):
- return ( c.tree for c in self.iter_commits(*args, **kwargs) )
+ return (c.tree for c in self.iter_commits(*args, **kwargs))
def tree(self, rev=None):
if rev is None:
return self.head.commit.tree
else:
- return self.resolve_object(str(rev)+"^{tree}")
+ return self.resolve_object(str(rev) + "^{tree}")
def iter_commits(self, rev=None, paths='', **kwargs):
if rev is None:
rev = self.head.commit
-
+
return self.CommitCls.iter_items(self, rev, paths, **kwargs)
-
@property
def head(self):
- return self.HEADCls(self,'HEAD')
-
- def create_head(self, path, commit='HEAD', force=False, logmsg=None ):
+ 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)
-
diff --git a/git/db/py/submodule.py b/git/db/py/submodule.py
index 0f2120c5..39b20961 100644
--- a/git/db/py/submodule.py
+++ b/git/db/py/submodule.py
@@ -8,26 +8,27 @@ from git.db.interface import SubmoduleDB
__all__ = ["PureSubmoduleDB"]
+
class PureSubmoduleDB(SubmoduleDB):
+
"""Pure python implementation of submodule functionality"""
-
+
@property
def submodules(self):
return Submodule.list_items(self)
-
+
def submodule(self, name):
try:
return self.submodules[name]
except IndexError:
raise ValueError("Didn't find submodule named %r" % name)
# END exception handling
-
+
def create_submodule(self, *args, **kwargs):
return Submodule.add(self, *args, **kwargs)
-
+
def iter_submodules(self, *args, **kwargs):
return RootModule(self).traverse(*args, **kwargs)
-
+
def submodule_update(self, *args, **kwargs):
return RootModule(self).update(*args, **kwargs)
-
diff --git a/git/db/py/transport.py b/git/db/py/transport.py
index 7bcaab95..809d1977 100644
--- a/git/db/py/transport.py
+++ b/git/db/py/transport.py
@@ -4,10 +4,10 @@
# the New BSD License: http://www.opensource.org/licenses/bsd-license.php
"""Implement a transport compatible database which sends objects using the git protocol"""
-from git.db.interface import ( TransportDB,
- PushInfo,
- FetchInfo,
- RefSpec )
+from git.db.interface import (TransportDB,
+ PushInfo,
+ FetchInfo,
+ RefSpec)
from git.refs.remote import RemoteReference
from git.remote import Remote
@@ -15,16 +15,18 @@ from git.remote import Remote
__all__ = ["PureTransportDB"]
+
class PurePushInfo(PushInfo):
+
"""TODO: Implementation"""
__slots__ = tuple()
-
-
-
+
+
class PureFetchInfo(FetchInfo):
+
"""TODO"""
__slots__ = tuple()
-
+
class PureTransportDB(TransportDB):
# The following variables need to be set by the derived class
@@ -32,27 +34,26 @@ class PureTransportDB(TransportDB):
protocol = None
RemoteCls = Remote
#}end configuraiton
-
+
#{ Interface
-
+
def fetch(self, url, refspecs, progress=None, **kwargs):
raise NotImplementedError()
-
+
def push(self, url, refspecs, progress=None, **kwargs):
raise NotImplementedError()
-
+
@property
def remotes(self):
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
+ #}end interface