summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/git/db.py27
m---------lib/git/ext/gitdb0
-rw-r--r--lib/git/repo/base.py3
-rw-r--r--lib/git/repo/fun.py23
-rw-r--r--test/git/test_repo.py73
5 files changed, 79 insertions, 47 deletions
diff --git a/lib/git/db.py b/lib/git/db.py
index c36446d0..945031bb 100644
--- a/lib/git/db.py
+++ b/lib/git/db.py
@@ -1,11 +1,15 @@
-"""Module with our own gitdb implementation - it uses the git command"""
+"""Module with our own gitdb implementation - it uses the git command"""
+from exc import GitCommandError
+
from gitdb.base import (
OInfo,
OStream
)
-from gitdb.util import bin_to_hex
-
+from gitdb.util import (
+ bin_to_hex,
+ hex_to_bin
+ )
from gitdb.db import GitDB
from gitdb.db import LooseObjectDB
@@ -35,3 +39,20 @@ class GitCmdObjectDB(LooseObjectDB):
t = self._git.stream_object_data(bin_to_hex(sha))
return OStream(*t)
+
+ # { Interface
+
+ def partial_to_complete_sha_hex(partial_hexsha):
+ """:return: Full binary 20 byte sha from the given partial hexsha
+ :raise AmbiguousObjectName:
+ :raise BadObject:
+ :note: currently we only raise BadObject as git does not communicate
+ AmbiguousObjects separately"""
+ try:
+ hexsha, typename, size = self._git.get_object_header(partial_hexsha)
+ return hex_to_bin(hexsha)
+ except GitCommandError:
+ raise BadObject(partial_hexsha)
+ # END handle exceptions
+
+ #} END interface
diff --git a/lib/git/ext/gitdb b/lib/git/ext/gitdb
-Subproject 46bf4710e0f7184ac4875e8037de30b5081bfda
+Subproject ac7d4757ab4041f5f0f5806934130024b098bb8
diff --git a/lib/git/repo/base.py b/lib/git/repo/base.py
index 976a68bf..e659225e 100644
--- a/lib/git/repo/base.py
+++ b/lib/git/repo/base.py
@@ -58,8 +58,7 @@ class Repo(object):
# precompiled regex
re_whitespace = re.compile(r'\s+')
re_hexsha_only = re.compile('^[0-9A-Fa-f]{40}$')
- re_hexsha_shortened = re.compile('^[0-9A-Fa-f]{7,40}$')
- re_hexsha_domain = re.compile('^[0-9A-Fa-f]{1,40}$')
+ re_hexsha_shortened = re.compile('^[0-9A-Fa-f]{4,40}$')
re_author_committer_start = re.compile(r'^(author|committer)')
re_tab_full_line = re.compile(r'^\t(.*)$')
diff --git a/lib/git/repo/fun.py b/lib/git/repo/fun.py
index ab2eb8be..a0f66fe5 100644
--- a/lib/git/repo/fun.py
+++ b/lib/git/repo/fun.py
@@ -7,9 +7,9 @@ from gitdb.util import (
join,
isdir,
isfile,
- hex_to_bin
+ hex_to_bin,
+ bin_to_hex
)
-
from string import digits
__all__ = ('rev_parse', 'is_git_dir', 'touch')
@@ -30,6 +30,18 @@ def is_git_dir(d):
os.readlink(headref).startswith('refs'))
return False
+
+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.
+ :param hexsha: hexsha with less than 40 byte"""
+ try:
+ return bin_to_hex(odb.partial_to_complete_sha_hex(hexsha))
+ except BadObject:
+ return None
+ # END exception handling
+
+
def name_to_object(repo, name):
""":return: object specified by the given name, hexshas ( short and long )
as well as references are supported"""
@@ -39,7 +51,7 @@ def name_to_object(repo, name):
if repo.re_hexsha_shortened.match(name):
if len(name) != 40:
# find long sha for short sha
- raise NotImplementedError("short sha parsing")
+ hexsha = short_to_long(repo.odb, name)
else:
hexsha = name
# END handle short shas
@@ -55,11 +67,6 @@ def name_to_object(repo, name):
# tried everything ? fail
if hexsha is None:
- # it could also be a very short ( less than 7 ) hexsha, which
- # wasnt tested in the first run
- if len(name) < 7 and repo.re_hexsha_domain.match(name):
- raise NotImplementedError()
- # END try short name
raise BadObject(name)
# END assert hexsha was found
diff --git a/test/git/test_repo.py b/test/git/test_repo.py
index b2891378..5f663d6f 100644
--- a/test/git/test_repo.py
+++ b/test/git/test_repo.py
@@ -3,43 +3,45 @@
#
# This module is part of GitPython and is released under
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
-
-import os, sys
from test.testlib import *
from git import *
from git.util import join_path_native
+from git.exc import BadObject
+from gitdb.util import hex_to_bin
+
+import os, sys
import tempfile
import shutil
from cStringIO import StringIO
-from git.exc import BadObject
+
class TestRepo(TestBase):
@raises(InvalidGitRepositoryError)
- def _test_new_should_raise_on_invalid_repo_location(self):
+ def test_new_should_raise_on_invalid_repo_location(self):
Repo(tempfile.gettempdir())
@raises(NoSuchPathError)
- def _test_new_should_raise_on_non_existant_path(self):
+ def test_new_should_raise_on_non_existant_path(self):
Repo("repos/foobar")
- def _test_repo_creation_from_different_paths(self):
+ def test_repo_creation_from_different_paths(self):
r_from_gitdir = Repo(self.rorepo.git_dir)
assert r_from_gitdir.git_dir == self.rorepo.git_dir
assert r_from_gitdir.git_dir.endswith('.git')
assert not self.rorepo.git.working_dir.endswith('.git')
assert r_from_gitdir.git.working_dir == self.rorepo.git.working_dir
- def _test_description(self):
+ def test_description(self):
txt = "Test repository"
self.rorepo.description = txt
assert_equal(self.rorepo.description, txt)
- def _test_heads_should_return_array_of_head_objects(self):
+ def test_heads_should_return_array_of_head_objects(self):
for head in self.rorepo.heads:
assert_equal(Head, head.__class__)
- def _test_heads_should_populate_head_data(self):
+ def test_heads_should_populate_head_data(self):
for head in self.rorepo.heads:
assert head.name
assert isinstance(head.commit,Commit)
@@ -48,7 +50,7 @@ class TestRepo(TestBase):
assert isinstance(self.rorepo.heads.master, Head)
assert isinstance(self.rorepo.heads['master'], Head)
- def _test_tree_from_revision(self):
+ def test_tree_from_revision(self):
tree = self.rorepo.tree('0.1.6')
assert len(tree.hexsha) == 40
assert tree.type == "tree"
@@ -57,7 +59,7 @@ class TestRepo(TestBase):
# try from invalid revision that does not exist
self.failUnlessRaises(ValueError, self.rorepo.tree, 'hello world')
- def _test_commits(self):
+ def test_commits(self):
mc = 10
commits = list(self.rorepo.iter_commits('0.1.6', max_count=mc))
assert len(commits) == mc
@@ -79,7 +81,7 @@ class TestRepo(TestBase):
c = commits[1]
assert isinstance(c.parents, tuple)
- def _test_trees(self):
+ def test_trees(self):
mc = 30
num_trees = 0
for tree in self.rorepo.iter_trees('0.1.5', max_count=mc):
@@ -89,7 +91,7 @@ class TestRepo(TestBase):
assert num_trees == mc
- def _test_empty_repo(self, repo):
+ def _assert_empty_repo(self, repo):
# test all kinds of things with an empty, freshly initialized repo.
# It should throw good errors
@@ -117,7 +119,7 @@ class TestRepo(TestBase):
# END test repos with working tree
- def _test_init(self):
+ def test_init(self):
prev_cwd = os.getcwd()
os.chdir(tempfile.gettempdir())
git_dir_rela = "repos/foo/bar.git"
@@ -131,12 +133,12 @@ class TestRepo(TestBase):
assert r.bare == True
assert os.path.isdir(r.git_dir)
- self._test_empty_repo(r)
+ self._assert_empty_repo(r)
# test clone
clone_path = path + "_clone"
rc = r.clone(clone_path)
- self._test_empty_repo(rc)
+ self._assert_empty_repo(rc)
shutil.rmtree(git_dir_abs)
try:
@@ -153,7 +155,7 @@ class TestRepo(TestBase):
r = Repo.init(bare=False)
r.bare == False
- self._test_empty_repo(r)
+ self._assert_empty_repo(r)
finally:
try:
shutil.rmtree(del_dir_abs)
@@ -162,17 +164,17 @@ class TestRepo(TestBase):
os.chdir(prev_cwd)
# END restore previous state
- def _test_bare_property(self):
+ def test_bare_property(self):
self.rorepo.bare
- def _test_daemon_export(self):
+ def test_daemon_export(self):
orig_val = self.rorepo.daemon_export
self.rorepo.daemon_export = not orig_val
assert self.rorepo.daemon_export == ( not orig_val )
self.rorepo.daemon_export = orig_val
assert self.rorepo.daemon_export == orig_val
- def _test_alternates(self):
+ def test_alternates(self):
cur_alternates = self.rorepo.alternates
# empty alternates
self.rorepo.alternates = []
@@ -182,15 +184,15 @@ class TestRepo(TestBase):
assert alts == self.rorepo.alternates
self.rorepo.alternates = cur_alternates
- def _test_repr(self):
+ def test_repr(self):
path = os.path.join(os.path.abspath(GIT_REPO), '.git')
assert_equal('<git.Repo "%s">' % path, repr(self.rorepo))
- def _test_is_dirty_with_bare_repository(self):
+ def test_is_dirty_with_bare_repository(self):
self.rorepo._bare = True
assert_false(self.rorepo.is_dirty())
- def _test_is_dirty(self):
+ def test_is_dirty(self):
self.rorepo._bare = False
for index in (0,1):
for working_tree in (0,1):
@@ -202,23 +204,23 @@ class TestRepo(TestBase):
self.rorepo._bare = True
assert self.rorepo.is_dirty() == False
- def _test_head(self):
+ def test_head(self):
assert self.rorepo.head.reference.object == self.rorepo.active_branch.object
- def _test_index(self):
+ def test_index(self):
index = self.rorepo.index
assert isinstance(index, IndexFile)
- def _test_tag(self):
+ def test_tag(self):
assert self.rorepo.tag('refs/tags/0.1.5').commit
- def _test_archive(self):
+ def test_archive(self):
tmpfile = os.tmpfile()
self.rorepo.archive(tmpfile, '0.1.5')
assert tmpfile.tell()
@patch_object(Git, '_call_process')
- def _test_should_display_blame_information(self, git):
+ def test_should_display_blame_information(self, git):
git.return_value = fixture('blame')
b = self.rorepo.blame( 'master', 'lib/git.py')
assert_equal(13, len(b))
@@ -244,7 +246,7 @@ class TestRepo(TestBase):
assert_true( isinstance( tlist[0], basestring ) )
assert_true( len( tlist ) < sum( len(t) for t in tlist ) ) # test for single-char bug
- def _test_untracked_files(self):
+ def test_untracked_files(self):
base = self.rorepo.working_tree_dir
files = ( join_path_native(base, "__test_myfile"),
join_path_native(base, "__test_other_file") )
@@ -270,13 +272,13 @@ class TestRepo(TestBase):
assert len(self.rorepo.untracked_files) == (num_recently_untracked - len(files))
- def _test_config_reader(self):
+ def test_config_reader(self):
reader = self.rorepo.config_reader() # all config files
assert reader.read_only
reader = self.rorepo.config_reader("repository") # single config file
assert reader.read_only
- def _test_config_writer(self):
+ def test_config_writer(self):
for config_level in self.rorepo.config_level:
try:
writer = self.rorepo.config_writer(config_level)
@@ -287,7 +289,7 @@ class TestRepo(TestBase):
pass
# END for each config level
- def _test_creation_deletion(self):
+ def test_creation_deletion(self):
# just a very quick test to assure it generally works. There are
# specialized cases in the test_refs module
head = self.rorepo.create_head("new_head", "HEAD~1")
@@ -299,12 +301,12 @@ class TestRepo(TestBase):
remote = self.rorepo.create_remote("new_remote", "git@server:repo.git")
self.rorepo.delete_remote(remote)
- def _test_comparison_and_hash(self):
+ def test_comparison_and_hash(self):
# this is only a preliminary test, more testing done in test_index
assert self.rorepo == self.rorepo and not (self.rorepo != self.rorepo)
assert len(set((self.rorepo, self.rorepo))) == 1
- def _test_git_cmd(self):
+ def test_git_cmd(self):
# test CatFileContentStream, just to be very sure we have no fencepost errors
# last \n is the terminating newline that it expects
l1 = "0123456789\n"
@@ -442,6 +444,9 @@ class TestRepo(TestBase):
def test_rev_parse(self):
rev_parse = self.rorepo.rev_parse
+ # try special case: This one failed beforehand
+ assert self.rorepo.odb.partial_to_complete_sha_hex("33ebe") == hex_to_bin("33ebe7acec14b25c5f84f35a664803fcab2f7781")
+
# start from reference
num_resolved = 0
for ref in Reference.iter_items(self.rorepo):