| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -191,8 +191,11 @@ def to_file(self, filepath): | |||
| 191 | 191 | #END handle change | |
| 192 | 192 | ||
| 193 | 193 | @classmethod | |
| 194 | - def append_entry(cls, filepath, oldbinsha, newbinsha, message): | ||
| 195 | - """Append a new log entry to the revlog at filepath. | ||
| 194 | + def append_entry(cls, config_reader, filepath, oldbinsha, newbinsha, message): | ||
| 195 | + """Append a new log entry to the revlog at filepath. | ||
| 196 | + :param config_reader: configuration reader of the repository - used to obtain | ||
| 197 | + user information. May be None | ||
| 198 | + :param filepath: full path to the log file | ||
| 196 | 199 | :param oldbinsha: binary sha of the previous commit | |
| 197 | 200 | :param newbinsha: binary sha of the current commit | |
| 198 | 201 | :param message: message describing the change to the reference | |
@@ -205,7 +208,7 @@ def append_entry(cls, filepath, oldbinsha, newbinsha, message): | |||
| 205 | 208 | raise ValueError("Shas need to be given in binary format") | |
| 206 | 209 | #END handle sha type | |
| 207 | 210 | assure_directory_exists(filepath, is_file=True) | |
| 208 | - entry = RefLogEntry((bin_to_hex(oldbinsha), bin_to_hex(newbinsha), Actor.committer(), (int(time.time()), time.altzone), message)) | ||
| 211 | + entry = RefLogEntry((bin_to_hex(oldbinsha), bin_to_hex(newbinsha), Actor.committer(config_reader), (int(time.time()), time.altzone), message)) | ||
| 209 | 212 | ||
| 210 | 213 | lf = LockFile(filepath) | |
| 211 | 214 | lf._obtain_lock_or_raise() | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -18,6 +18,7 @@ class Reference(SymbolicReference, LazyMixin, Iterable): | |||
| 18 | 18 | """Represents a named reference to any object. Subclasses may apply restrictions though, | |
| 19 | 19 | i.e. Heads can only point to commits.""" | |
| 20 | 20 | __slots__ = tuple() | |
| 21 | + _points_to_commits_only = False | ||
| 21 | 22 | _resolve_ref_on_create = True | |
| 22 | 23 | _common_path_default = "refs" | |
| 23 | 24 | ||
@@ -36,42 +37,6 @@ def __init__(self, repo, path): | |||
| 36 | 37 | def __str__(self): | |
| 37 | 38 | return self.name | |
| 38 | 39 | ||
| 39 | - def _get_object(self): | ||
| 40 | - """ | ||
| 41 | - :return: | ||
| 42 | - The object our ref currently refers to. Refs can be cached, they will | ||
| 43 | - always point to the actual object as it gets re-created on each query""" | ||
| 44 | - # have to be dynamic here as we may be a tag which can point to anything | ||
| 45 | - # Our path will be resolved to the hexsha which will be used accordingly | ||
| 46 | - return Object.new_from_sha(self.repo, hex_to_bin(self.dereference_recursive(self.repo, self.path))) | ||
| 47 | - | ||
| 48 | - def _set_object(self, ref): | ||
| 49 | - """ | ||
| 50 | - Set our reference to point to the given ref. It will be converted | ||
| 51 | - to a specific hexsha. | ||
| 52 | - If the reference does not exist, it will be created. | ||
| 53 | - | ||
| 54 | - :note: | ||
| 55 | - TypeChecking is done by the git command""" | ||
| 56 | - abs_path = self.abspath | ||
| 57 | - existed = True | ||
| 58 | - if not isfile(abs_path): | ||
| 59 | - existed = False | ||
| 60 | - open(abs_path, 'wb').write(Object.NULL_HEX_SHA) | ||
| 61 | - # END quick create | ||
| 62 | - | ||
| 63 | - # do it safely by specifying the old value | ||
| 64 | - try: | ||
| 65 | - self.repo.git.update_ref(self.path, ref, (existed and self._get_object().hexsha) or None) | ||
| 66 | - except: | ||
| 67 | - if not existed: | ||
| 68 | - os.remove(abs_path) | ||
| 69 | - # END remove file on error if it didn't exist before | ||
| 70 | - raise | ||
| 71 | - # END exception handling | ||
| 72 | - | ||
| 73 | - object = property(_get_object, _set_object, doc="Return the object our ref currently refers to") | ||
| 74 | - | ||
| 75 | 40 | @property | |
| 76 | 41 | def name(self): | |
| 77 | 42 | """:return: (shortest) Name of this reference - it may contain path components""" | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,5 +1,5 @@ | |||
| 1 | 1 | import os | |
| 2 | - from git.objects import Commit | ||
| 2 | + from git.objects import Object, Commit | ||
| 3 | 3 | from git.util import ( | |
| 4 | 4 | join_path, | |
| 5 | 5 | join_path_native, | |
@@ -30,6 +30,7 @@ class SymbolicReference(object): | |||
| 30 | 30 | A typical example for a symbolic reference is HEAD.""" | |
| 31 | 31 | __slots__ = ("repo", "path") | |
| 32 | 32 | _resolve_ref_on_create = False | |
| 33 | + _points_to_commits_only = True | ||
| 33 | 34 | _common_path_default = "" | |
| 34 | 35 | _id_attribute_ = "name" | |
| 35 | 36 | ||
@@ -107,66 +108,89 @@ def dereference_recursive(cls, repo, ref_path): | |||
| 107 | 108 | intermediate references as required | |
| 108 | 109 | :param repo: the repository containing the reference at ref_path""" | |
| 109 | 110 | while True: | |
| 110 | - ref = cls(repo, ref_path) | ||
| 111 | - hexsha, ref_path = ref._get_ref_info() | ||
| 111 | + hexsha, ref_path = cls._get_ref_info(repo, ref_path) | ||
| 112 | 112 | if hexsha is not None: | |
| 113 | 113 | return hexsha | |
| 114 | 114 | # END recursive dereferencing | |
| 115 | 115 | ||
| 116 | - def _get_ref_info(self): | ||
| 116 | + @classmethod | ||
| 117 | + def _get_ref_info(cls, repo, path): | ||
| 117 | 118 | """Return: (sha, target_ref_path) if available, the sha the file at | |
| 118 | 119 | rela_path points to, or None. target_ref_path is the reference we | |
| 119 | 120 | point to, or None""" | |
| 120 | 121 | tokens = None | |
| 121 | 122 | try: | |
| 122 | - fp = open(self.abspath, 'r') | ||
| 123 | + fp = open(join(repo.git_dir, path), 'r') | ||
| 123 | 124 | value = fp.read().rstrip() | |
| 124 | 125 | fp.close() | |
| 125 | 126 | tokens = value.split(" ") | |
| 126 | 127 | except (OSError,IOError): | |
| 127 | 128 | # Probably we are just packed, find our entry in the packed refs file | |
| 128 | 129 | # NOTE: We are not a symbolic ref if we are in a packed file, as these | |
| 129 | 130 | # are excluded explictly | |
| 130 | - for sha, path in self._iter_packed_refs(self.repo): | ||
| 131 | - if path != self.path: continue | ||
| 131 | + for sha, path in cls._iter_packed_refs(repo): | ||
| 132 | + if path != path: continue | ||
| 132 | 133 | tokens = (sha, path) | |
| 133 | 134 | break | |
| 134 | 135 | # END for each packed ref | |
| 135 | 136 | # END handle packed refs | |
| 136 | 137 | ||
| 137 | 138 | if tokens is None: | |
| 138 | - raise ValueError("Reference at %r does not exist" % self.path) | ||
| 139 | + raise ValueError("Reference at %r does not exist" % path) | ||
| 139 | 140 | ||
| 140 | 141 | # is it a reference ? | |
| 141 | 142 | if tokens[0] == 'ref:': | |
| 142 | 143 | return (None, tokens[1]) | |
| 143 | 144 | ||
| 144 | 145 | # its a commit | |
| 145 | - if self.repo.re_hexsha_only.match(tokens[0]): | ||
| 146 | + if repo.re_hexsha_only.match(tokens[0]): | ||
| 146 | 147 | return (tokens[0], None) | |
| 147 | 148 | ||
| 148 | - raise ValueError("Failed to parse reference information from %r" % self.path) | ||
| 149 | - | ||
| 149 | + raise ValueError("Failed to parse reference information from %r" % path) | ||
| 150 | + | ||
| 151 | + def _get_object(self): | ||
| 152 | + """ | ||
| 153 | + :return: | ||
| 154 | + The object our ref currently refers to. Refs can be cached, they will | ||
| 155 | + always point to the actual object as it gets re-created on each query""" | ||
| 156 | + # have to be dynamic here as we may be a tag which can point to anything | ||
| 157 | + # Our path will be resolved to the hexsha which will be used accordingly | ||
| 158 | + return Object.new_from_sha(self.repo, hex_to_bin(self.dereference_recursive(self.repo, self.path))) | ||
| 159 | + | ||
| 150 | 160 | def _get_commit(self): | |
| 151 | 161 | """ | |
| 152 | 162 | :return: | |
| 153 | 163 | Commit object we point to, works for detached and non-detached | |
| 154 | - SymbolicReferences""" | ||
| 155 | - # we partially reimplement it to prevent unnecessary file access | ||
| 156 | - hexsha, target_ref_path = self._get_ref_info() | ||
| 157 | - | ||
| 158 | - # it is a detached reference | ||
| 159 | - if hexsha: | ||
| 160 | - return Commit(self.repo, hex_to_bin(hexsha)) | ||
| 161 | - | ||
| 162 | - return self.from_path(self.repo, target_ref_path).commit | ||
| 164 | + SymbolicReferences. The symbolic reference will be dereferenced recursively.""" | ||
| 165 | + obj = self._get_object() | ||
| 166 | + if obj.type != Commit.type: | ||
| 167 | + raise TypeError("Symbolic Reference pointed to object %r, commit was required" % obj) | ||
| 168 | + #END handle type | ||
| 169 | + return obj | ||
| 163 | 170 | ||
| 164 | 171 | def set_commit(self, commit, msg = None): | |
| 165 | - """Set our commit, possibly dereference our symbolic reference first. | ||
| 172 | + """As set_object, but restricts the type of object to be a Commit | ||
| 173 | + :note: To save cycles, we do not yet check whether the given Object | ||
| 174 | + is actually referring to a commit - for now it may be any of our | ||
| 175 | + Object or Reference types, as well as a refspec""" | ||
| 176 | + # may have to check the type ... this is costly as we would have to use | ||
| 177 | + # revparse | ||
| 178 | + self.set_object(commit, msg) | ||
| 179 | + | ||
| 180 | + | ||
| 181 | + def set_object(self, object, msg = None): | ||
| 182 | + """Set the object we point to, possibly dereference our symbolic reference first. | ||
| 166 | 183 | If the reference does not exist, it will be created | |
| 167 | 184 | ||
| 185 | + :param object: a refspec, a SymbolicReference or an Object instance. SymbolicReferences | ||
| 186 | + will be dereferenced beforehand to obtain the object they point to | ||
| 168 | 187 | :param msg: If not None, the message will be used in the reflog entry to be | |
| 169 | - written. Otherwise the reflog is not altered""" | ||
| 188 | + written. Otherwise the reflog is not altered | ||
| 189 | + :note: plain SymbolicReferences may not actually point to objects by convention""" | ||
| 190 | + if isinstance(object, SymbolicReference): | ||
| 191 | + object = object.object | ||
| 192 | + #END resolve references | ||
| 193 | + | ||
| 170 | 194 | is_detached = True | |
| 171 | 195 | try: | |
| 172 | 196 | is_detached = self.is_detached | |
@@ -175,56 +199,66 @@ def set_commit(self, commit, msg = None): | |||
| 175 | 199 | # END handle non-existing ones | |
| 176 | 200 | ||
| 177 | 201 | if is_detached: | |
| 178 | - return self.set_reference(commit, msg) | ||
| 202 | + return self.set_reference(object, msg) | ||
| 179 | 203 | ||
| 180 | 204 | # set the commit on our reference | |
| 181 | - self._get_reference().set_commit(commit, msg) | ||
| 205 | + self._get_reference().set_object(object, msg) | ||
| 182 | 206 | ||
| 183 | 207 | commit = property(_get_commit, set_commit, doc="Query or set commits directly") | |
| 208 | + object = property(_get_object, set_object, doc="Return the object our ref currently refers to") | ||
| 184 | 209 | ||
| 185 | 210 | def _get_reference(self): | |
| 186 | 211 | """:return: Reference Object we point to | |
| 187 | 212 | :raise TypeError: If this symbolic reference is detached, hence it doesn't point | |
| 188 | 213 | to a reference, but to a commit""" | |
| 189 | - sha, target_ref_path = self._get_ref_info() | ||
| 214 | + sha, target_ref_path = self._get_ref_info(self.repo, self.path) | ||
| 190 | 215 | if target_ref_path is None: | |
| 191 | 216 | raise TypeError("%s is a detached symbolic reference as it points to %r" % (self, sha)) | |
| 192 | 217 | return self.from_path(self.repo, target_ref_path) | |
| 193 | 218 | ||
| 194 | 219 | def set_reference(self, ref, msg = None): | |
| 195 | 220 | """Set ourselves to the given ref. It will stay a symbol if the ref is a Reference. | |
| 196 | - Otherwise a commmit, given as Commit object or refspec, is assumed and if valid, | ||
| 221 | + Otherwise an Object, given as Object instance or refspec, is assumed and if valid, | ||
| 197 | 222 | will be set which effectively detaches the refererence if it was a purely | |
| 198 | 223 | symbolic one. | |
| 199 | 224 | ||
| 200 | - :param ref: SymbolicReference instance, Commit instance or refspec string | ||
| 225 | + :param ref: SymbolicReference instance, Object instance or refspec string | ||
| 226 | + Only if the ref is a SymbolicRef instance, we will point to it. Everthiny | ||
| 227 | + else is dereferenced to obtain the actual object. | ||
| 201 | 228 | :param msg: If set to a string, the message will be used in the reflog. | |
| 202 | 229 | Otherwise, a reflog entry is not written for the changed reference. | |
| 203 | 230 | The previous commit of the entry will be the commit we point to now. | |
| 204 | 231 | ||
| 205 | - See also: log_append()""" | ||
| 232 | + See also: log_append() | ||
| 233 | + :note: This symbolic reference will not be dereferenced. For that, see | ||
| 234 | + ``set_object(...)``""" | ||
| 206 | 235 | write_value = None | |
| 236 | + obj = None | ||
| 207 | 237 | if isinstance(ref, SymbolicReference): | |
| 208 | 238 | write_value = "ref: %s" % ref.path | |
| 209 | - elif isinstance(ref, Commit): | ||
| 239 | + elif isinstance(ref, Object): | ||
| 240 | + obj = ref | ||
| 210 | 241 | write_value = ref.hexsha | |
| 211 | - else: | ||
| 242 | + elif isinstance(ref, basestring): | ||
| 212 | 243 | try: | |
| 213 | - write_value = ref.commit.hexsha | ||
| 214 | - except AttributeError: | ||
| 215 | - try: | ||
| 216 | - obj = self.repo.rev_parse(ref+"^{}") # optionally deref tags | ||
| 217 | - if obj.type != "commit": | ||
| 218 | - raise TypeError("Invalid object type behind sha: %s" % sha) | ||
| 219 | - write_value = obj.hexsha | ||
| 220 | - except Exception: | ||
| 221 | - raise ValueError("Could not extract object from %s" % ref) | ||
| 222 | - # END end try string | ||
| 244 | + obj = self.repo.rev_parse(ref+"^{}") # optionally deref tags | ||
| 245 | + write_value = obj.hexsha | ||
| 246 | + except Exception: | ||
| 247 | + raise ValueError("Could not extract object from %s" % ref) | ||
| 248 | + # END end try string | ||
| 249 | + else: | ||
| 250 | + raise ValueError("Unrecognized Value: %r" % ref) | ||
| 223 | 251 | # END try commit attribute | |
| 252 | + | ||
| 253 | + # typecheck | ||
| 254 | + if obj is not None and self._points_to_commits_only and obj.type != Commit.type: | ||
| 255 | + raise TypeError("Require commit, got %r" % obj) | ||
| 256 | + #END verify type | ||
| 257 | + | ||
| 224 | 258 | oldbinsha = None | |
| 225 | 259 | if msg is not None: | |
| 226 | 260 | try: | |
| 227 | - oldhexsha = self.commit.binsha | ||
| 261 | + oldbinsha = self.commit.binsha | ||
| 228 | 262 | except ValueError: | |
| 229 | 263 | oldbinsha = Commit.NULL_BIN_SHA | |
| 230 | 264 | #END handle non-existing | |
@@ -247,14 +281,14 @@ def set_reference(self, ref, msg = None): | |||
| 247 | 281 | # aliased reference | |
| 248 | 282 | reference = property(_get_reference, set_reference, doc="Returns the Reference we point to") | |
| 249 | 283 | ref = reference | |
| 250 | - | ||
| 284 | + | ||
| 251 | 285 | def is_valid(self): | |
| 252 | 286 | """ | |
| 253 | 287 | :return: | |
| 254 | 288 | True if the reference is valid, hence it can be read and points to | |
| 255 | 289 | a valid object or reference.""" | |
| 256 | 290 | try: | |
| 257 | - self.commit | ||
| 291 | + self.object | ||
| 258 | 292 | except (OSError, ValueError): | |
| 259 | 293 | return False | |
| 260 | 294 | else: | |
@@ -288,7 +322,7 @@ def log_append(self, oldbinsha, message, newbinsha=None): | |||
| 288 | 322 | :param newbinsha: The sha the ref points to now. If None, our current commit sha | |
| 289 | 323 | will be used | |
| 290 | 324 | :return: added RefLogEntry instance""" | |
| 291 | - return RefLog.append_entry(RefLog.path(self), oldbinsha, | ||
| 325 | + return RefLog.append_entry(self.repo.config_reader(), RefLog.path(self), oldbinsha, | ||
| 292 | 326 | (newbinsha is None and self.commit.binsha) or newbinsha, | |
| 293 | 327 | message) | |
| 294 | 328 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -60,6 +60,7 @@ def test_base(self): | |||
| 60 | 60 | # test serialize and deserialize - results must match exactly | |
| 61 | 61 | binsha = chr(255)*20 | |
| 62 | 62 | msg = "my reflog message" | |
| 63 | + cr = repo.config_reader() | ||
| 63 | 64 | for rlp in (rlp_head, rlp_master): | |
| 64 | 65 | reflog = RefLog.from_file(rlp) | |
| 65 | 66 | tfile = os.path.join(tdir, os.path.basename(rlp)) | |
@@ -73,7 +74,7 @@ def test_base(self): | |||
| 73 | 74 | assert open(tfile).read() == open(rlp).read() | |
| 74 | 75 | ||
| 75 | 76 | # append an entry | |
| 76 | - entry = RefLog.append_entry(tfile, IndexObject.NULL_BIN_SHA, binsha, msg) | ||
| 77 | + entry = RefLog.append_entry(cr, tfile, IndexObject.NULL_BIN_SHA, binsha, msg) | ||
| 77 | 78 | assert entry.oldhexsha == IndexObject.NULL_HEX_SHA | |
| 78 | 79 | assert entry.newhexsha == 'f'*40 | |
| 79 | 80 | assert entry.message == msg | |
| Back | FazBrowse Home | New Git URL |
0 commit comments