aboutsummaryrefslogtreecommitdiff
path: root/git/refs/symbolic.py
diff options
context:
space:
mode:
authorSebastian Thiel <byronimo@gmail.com>2011-06-07 21:36:42 +0200
committerSebastian Thiel <byronimo@gmail.com>2011-06-07 21:36:42 +0200
commit58a930a632c867b65b9a3802e2f4190cf32e33ee (patch)
tree95b1311a3a4bfcdf4c2dba66f360e6985184013e /git/refs/symbolic.py
parenta98e0af511b728030c12bf8633b077866bb74e47 (diff)
parentf6897c78be5a5530129df50742cb6cabfb8609c9 (diff)
downloadGitPython-58a930a632c867b65b9a3802e2f4190cf32e33ee.tar.gz
GitPython-58a930a632c867b65b9a3802e2f4190cf32e33ee.zip
Merge branch 'gitdbmerger'
Diffstat (limited to 'git/refs/symbolic.py')
-rw-r--r--git/refs/symbolic.py158
1 files changed, 96 insertions, 62 deletions
diff --git a/git/refs/symbolic.py b/git/refs/symbolic.py
index aec68750..ddee3809 100644
--- a/git/refs/symbolic.py
+++ b/git/refs/symbolic.py
@@ -1,24 +1,26 @@
import os
-from git.objects import Object, Commit
+import re
+
+from git.objects import (
+ Object,
+ Commit
+ )
from git.util import (
join_path,
join_path_native,
to_native_path_linux,
- assure_directory_exists
+ assure_directory_exists,
+ join,
+ dirname,
+ isdir,
+ exists,
+ isfile,
+ rename,
+ hex_to_bin,
+ LockedFD
)
-from gitdb.exc import BadObject
-from gitdb.util import (
- join,
- dirname,
- isdir,
- exists,
- isfile,
- rename,
- hex_to_bin,
- LockedFD
- )
-
+from git.exc import BadObject
from log import RefLog
__all__ = ["SymbolicReference"]
@@ -30,11 +32,27 @@ class SymbolicReference(object):
A typical example for a symbolic reference is HEAD."""
__slots__ = ("repo", "path")
+
_resolve_ref_on_create = False
_points_to_commits_only = True
_common_path_default = ""
_id_attribute_ = "name"
+ re_hexsha_only = re.compile('^[0-9A-Fa-f]{40}$')
+
+ #{ Configuration
+ # Object class to be used when instantiating objects
+ ObjectCls = Object
+ CommitCls = Commit
+
+ # all of the following are set by the package initializer
+ HEADCls = None
+ HeadCls = None
+ RemoteReferenceCls = None
+ TagReferenceCls = None
+ ReferenceCls = None
+ #}END configuration
+
def __init__(self, repo, path):
self.repo = repo
self.path = path
@@ -143,20 +161,53 @@ class SymbolicReference(object):
return (None, tokens[1])
# its a commit
- if repo.re_hexsha_only.match(tokens[0]):
+ if cls.re_hexsha_only.match(tokens[0]):
return (tokens[0], None)
raise ValueError("Failed to parse reference information from %r" % ref_path)
- def _get_object(self):
+ def _get_object_sha(self):
"""
:return:
- The object our ref currently refers to. Refs can be cached, they will
+ The binary sha to the object our ref currently refers to. Refs can be cached, they will
always point to the actual object as it gets re-created on each query"""
+ return hex_to_bin(self.dereference_recursive(self.repo, self.path))
+
+ def _get_object(self):
+ """
+ :return:
+ The object our ref currently refers to."""
# have to be dynamic here as we may be a tag which can point to anything
# Our path will be resolved to the hexsha which will be used accordingly
- return Object.new_from_sha(self.repo, hex_to_bin(self.dereference_recursive(self.repo, self.path)))
+ return self.ObjectCls.new_from_sha(self.repo, self._get_object_sha())
+ def set_object(self, object_id, logmsg = None):
+ """Set the object we point to, possibly dereference our symbolic reference first.
+ If the reference does not exist, it will be created
+
+ :param object: a reference specifier string, a SymbolicReference or an object hex sha.
+ SymbolicReferences will be dereferenced beforehand to obtain the object they point to
+ :param logmsg: If not None, the message will be used in the reflog entry to be
+ written. Otherwise the reflog is not altered
+ :note: plain SymbolicReferences may not actually point to objects by convention
+ :return: self"""
+ if isinstance(object_id, SymbolicReference):
+ object = object.object
+ #END resolve references
+
+ is_detached = True
+ try:
+ is_detached = self.is_detached
+ except ValueError:
+ pass
+ # END handle non-existing ones
+
+ if is_detached:
+ return self.set_reference(object_id, logmsg)
+
+ # set the commit on our reference
+ return self._get_reference().set_object(object_id, logmsg)
+
def _get_commit(self):
"""
:return:
@@ -167,7 +218,7 @@ class SymbolicReference(object):
obj = obj.object
#END dereference tag
- if obj.type != Commit.type:
+ if obj.type != self.CommitCls.type:
raise TypeError("Symbolic Reference pointed to object %r, commit was required" % obj)
#END handle type
return obj
@@ -179,20 +230,20 @@ class SymbolicReference(object):
a commit
:return: self"""
# check the type - assume the best if it is a base-string
- invalid_type = False
- if isinstance(commit, Object):
- invalid_type = commit.type != Commit.type
+ is_invalid_type = False
+ if isinstance(commit, self.ObjectCls):
+ is_invalid_type = commit.type != self.CommitCls.type
elif isinstance(commit, SymbolicReference):
- invalid_type = commit.object.type != Commit.type
+ is_invalid_type = commit.object.type != self.CommitCls.type
else:
try:
- invalid_type = self.repo.rev_parse(commit).type != Commit.type
+ is_invalid_type = self.repo.resolve_object(commit).type != self.CommitCls.type
except BadObject:
raise ValueError("Invalid object: %s" % commit)
#END handle exception
# END verify type
- if invalid_type:
+ if is_invalid_type:
raise ValueError("Need commit, got %r" % commit)
#END handle raise
@@ -202,35 +253,9 @@ class SymbolicReference(object):
return self
- def set_object(self, object, logmsg = None):
- """Set the object we point to, possibly dereference our symbolic reference first.
- If the reference does not exist, it will be created
-
- :param object: a refspec, a SymbolicReference or an Object instance. SymbolicReferences
- will be dereferenced beforehand to obtain the object they point to
- :param logmsg: If not None, the message will be used in the reflog entry to be
- written. Otherwise the reflog is not altered
- :note: plain SymbolicReferences may not actually point to objects by convention
- :return: self"""
- if isinstance(object, SymbolicReference):
- object = object.object
- #END resolve references
-
- is_detached = True
- try:
- is_detached = self.is_detached
- except ValueError:
- pass
- # END handle non-existing ones
-
- if is_detached:
- return self.set_reference(object, logmsg)
-
- # set the commit on our reference
- return self._get_reference().set_object(object, logmsg)
-
commit = property(_get_commit, set_commit, doc="Query or set commits directly")
object = property(_get_object, set_object, doc="Return the object our ref currently refers to")
+ object_binsha = property(_get_object_sha, set_object, doc="Return the object our ref currently refers to")
def _get_reference(self):
""":return: Reference Object we point to
@@ -247,7 +272,7 @@ class SymbolicReference(object):
will be set which effectively detaches the refererence if it was a purely
symbolic one.
- :param ref: SymbolicReference instance, Object instance or refspec string
+ :param ref: SymbolicReference instance, hexadecimal sha string or refspec string
Only if the ref is a SymbolicRef instance, we will point to it. Everthiny
else is dereferenced to obtain the actual object.
:param logmsg: If set to a string, the message will be used in the reflog.
@@ -263,12 +288,12 @@ class SymbolicReference(object):
obj = None
if isinstance(ref, SymbolicReference):
write_value = "ref: %s" % ref.path
- elif isinstance(ref, Object):
+ elif isinstance(ref, self.ObjectCls):
obj = ref
write_value = ref.hexsha
elif isinstance(ref, basestring):
try:
- obj = self.repo.rev_parse(ref+"^{}") # optionally deref tags
+ obj = self.repo.resolve_object(ref+"^{}") # optionally deref tags
write_value = obj.hexsha
except BadObject:
raise ValueError("Could not extract object from %s" % ref)
@@ -318,7 +343,7 @@ class SymbolicReference(object):
a valid object or reference."""
try:
self.object
- except (OSError, ValueError):
+ except (OSError, ValueError, BadObject):
return False
else:
return True
@@ -449,7 +474,16 @@ class SymbolicReference(object):
# figure out target data
target = reference
if resolve:
- target = repo.rev_parse(str(reference))
+ # could just use the resolve method, but it could be expensive
+ # so we handle most common cases ourselves
+ if isinstance(reference, cls.ObjectCls):
+ target = reference.hexsha
+ elif isinstance(reference, SymbolicReference):
+ target = reference.object.hexsha
+ else:
+ target = repo.resolve_object(str(reference))
+ #END handle resoltion
+ #END need resolution
if not force and isfile(abs_ref_path):
target_data = str(target)
@@ -579,7 +613,7 @@ class SymbolicReference(object):
def iter_items(cls, repo, common_path = None):
"""Find all refs in the repository
- :param repo: is the Repo
+ :param repo: is the repo
:param common_path:
Optional keyword argument to the path which is to be shared by all
@@ -588,12 +622,12 @@ class SymbolicReference(object):
refs suitable for the actual class are returned.
:return:
- git.SymbolicReference[], each of them is guaranteed to be a symbolic
- ref which is not detached.
+ git.SymbolicReference[], each of them is guaranteed to be a *only* a symbolic
+ ref, or a derived class which is not detached
List is lexigraphically sorted
The returned objects represent actual subclasses, such as Head or TagReference"""
- return ( r for r in cls._iter_items(repo, common_path) if r.__class__ == SymbolicReference or not r.is_detached )
+ return ( r for r in cls._iter_items(repo, common_path) if r.__class__ == cls or not r.is_detached )
@classmethod
def from_path(cls, repo, path):
@@ -606,7 +640,7 @@ class SymbolicReference(object):
if not path:
raise ValueError("Cannot create Reference from %r" % path)
- for ref_type in (HEAD, Head, RemoteReference, TagReference, Reference, SymbolicReference):
+ for ref_type in (cls.HEADCls, cls.HeadCls, cls.RemoteReferenceCls, cls.TagReferenceCls, cls.ReferenceCls, cls):
try:
instance = ref_type(repo, path)
if instance.__class__ == SymbolicReference and instance.is_detached: