| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5,6 +5,7 @@ Changelog | |||
| 5 | 5 | 0.3.2 Beta 2 | |
| 6 | 6 | ============ | |
| 7 | 7 | * Added reflog support ( reading and writing ) | |
| 8 | + * Repo.rev_parse now supports the [ref]@{n} syntax, where n is the number of steps to look into the reference's past | ||
| 8 | 9 | ||
| 9 | 10 | 0.3.2 Beta 1 | |
| 10 | 11 | ============ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -42,9 +42,13 @@ def short_to_long(odb, hexsha): | |||
| 42 | 42 | # END exception handling | |
| 43 | 43 | ||
| 44 | 44 | ||
| 45 | - def name_to_object(repo, name): | ||
| 46 | - """:return: object specified by the given name, hexshas ( short and long ) | ||
| 47 | - as well as references are supported""" | ||
| 45 | + def name_to_object(repo, name, return_ref=False): | ||
| 46 | + """ | ||
| 47 | + :return: object specified by the given name, hexshas ( short and long ) | ||
| 48 | + as well as references are supported | ||
| 49 | + :param return_ref: if name specifies a reference, we will return the reference | ||
| 50 | + instead of the object. Otherwise it will raise BadObject | ||
| 51 | + """ | ||
| 48 | 52 | hexsha = None | |
| 49 | 53 | ||
| 50 | 54 | # is it a hexsha ? Try the most common ones, which is 7 to 40 | |
@@ -59,12 +63,20 @@ def name_to_object(repo, name): | |||
| 59 | 63 | for base in ('%s', 'refs/%s', 'refs/tags/%s', 'refs/heads/%s', 'refs/remotes/%s', 'refs/remotes/%s/HEAD'): | |
| 60 | 64 | try: | |
| 61 | 65 | hexsha = SymbolicReference.dereference_recursive(repo, base % name) | |
| 66 | + if return_ref: | ||
| 67 | + return SymbolicReference(repo, base % name) | ||
| 68 | + #END handle symbolic ref | ||
| 62 | 69 | break | |
| 63 | 70 | except ValueError: | |
| 64 | 71 | pass | |
| 65 | 72 | # END for each base | |
| 66 | 73 | # END handle hexsha | |
| 67 | - | ||
| 74 | + | ||
| 75 | + # didn't find any ref, this is an error | ||
| 76 | + if return_ref: | ||
| 77 | + raise BadObject("Couldn't find reference named %r" % name) | ||
| 78 | + #END handle return ref | ||
| 79 | + | ||
| 68 | 80 | # tried everything ? fail | |
| 69 | 81 | if hexsha is None: | |
| 70 | 82 | raise BadObject(name) | |
@@ -101,9 +113,6 @@ def rev_parse(repo, rev): | |||
| 101 | 113 | :note: Currently there is no access to the rev-log, rev-specs may only contain | |
| 102 | 114 | topological tokens such ~ and ^. | |
| 103 | 115 | :raise BadObject: if the given revision could not be found""" | |
| 104 | - if '@' in rev: | ||
| 105 | - raise ValueError("There is no rev-log support yet") | ||
| 106 | - | ||
| 107 | 116 | ||
| 108 | 117 | # colon search mode ? | |
| 109 | 118 | if rev.startswith(':/'): | |
@@ -112,22 +121,37 @@ def rev_parse(repo, rev): | |||
| 112 | 121 | # END handle search | |
| 113 | 122 | ||
| 114 | 123 | obj = None | |
| 124 | + ref = None | ||
| 115 | 125 | output_type = "commit" | |
| 116 | 126 | start = 0 | |
| 117 | 127 | parsed_to = 0 | |
| 118 | 128 | lr = len(rev) | |
| 119 | 129 | while start < lr: | |
| 120 | - if rev[start] not in "^~:": | ||
| 130 | + if rev[start] not in "^~:@": | ||
| 121 | 131 | start += 1 | |
| 122 | 132 | continue | |
| 123 | 133 | # END handle start | |
| 124 | 134 | ||
| 135 | + token = rev[start] | ||
| 136 | + | ||
| 125 | 137 | if obj is None: | |
| 126 | 138 | # token is a rev name | |
| 127 | - obj = name_to_object(repo, rev[:start]) | ||
| 139 | + if start == 0: | ||
| 140 | + ref = repo.head.ref | ||
| 141 | + else: | ||
| 142 | + if token == '@': | ||
| 143 | + ref = name_to_object(repo, rev[:start], return_ref=True) | ||
| 144 | + else: | ||
| 145 | + obj = name_to_object(repo, rev[:start]) | ||
| 146 | + #END handle token | ||
| 147 | + #END handle refname | ||
| 148 | + | ||
| 149 | + if ref is not None: | ||
| 150 | + obj = ref.commit | ||
| 151 | + #END handle ref | ||
| 128 | 152 | # END initialize obj on first token | |
| 129 | 153 | ||
| 130 | - token = rev[start] | ||
| 154 | + | ||
| 131 | 155 | start += 1 | |
| 132 | 156 | ||
| 133 | 157 | # try to parse {type} | |
@@ -153,6 +177,24 @@ def rev_parse(repo, rev): | |||
| 153 | 177 | # cannot do anything for non-tags | |
| 154 | 178 | pass | |
| 155 | 179 | # END handle tag | |
| 180 | + elif token == '@': | ||
| 181 | + # try single int | ||
| 182 | + assert ref is not None, "Requre Reference to access reflog" | ||
| 183 | + revlog_index = None | ||
| 184 | + try: | ||
| 185 | + # transform reversed index into the format of our revlog | ||
| 186 | + revlog_index = -(int(output_type)+1) | ||
| 187 | + except ValueError: | ||
| 188 | + # TODO: Try to parse the other date options, using parse_date | ||
| 189 | + # maybe | ||
| 190 | + raise NotImplementedError("Support for additional @{...} modes not implemented") | ||
| 191 | + #END handle revlog index | ||
| 192 | + | ||
| 193 | + entry = ref.log()[revlog_index] | ||
| 194 | + obj = Object.new_from_sha(repo, hex_to_bin(entry.newhexsha)) | ||
| 195 | + | ||
| 196 | + # make it pass the following checks | ||
| 197 | + output_type = None | ||
| 156 | 198 | else: | |
| 157 | 199 | raise ValueError("Invalid output type: %s ( in %s )" % (output_type, rev)) | |
| 158 | 200 | # END handle output type | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -467,11 +467,12 @@ def _assert_rev_parse(self, name): | |||
| 467 | 467 | def test_rev_parse(self): | |
| 468 | 468 | rev_parse = self.rorepo.rev_parse | |
| 469 | 469 | ||
| 470 | - # try special case: This one failed beforehand | ||
| 470 | + # try special case: This one failed at some point, make sure its fixed | ||
| 471 | 471 | assert rev_parse("33ebe").hexsha == "33ebe7acec14b25c5f84f35a664803fcab2f7781" | |
| 472 | 472 | ||
| 473 | 473 | # start from reference | |
| 474 | 474 | num_resolved = 0 | |
| 475 | + | ||
| 475 | 476 | for ref in Reference.iter_items(self.rorepo): | |
| 476 | 477 | path_tokens = ref.path.split("/") | |
| 477 | 478 | for pt in range(len(path_tokens)): | |
@@ -546,9 +547,25 @@ def test_rev_parse(self): | |||
| 546 | 547 | # missing starting brace | |
| 547 | 548 | self.failUnlessRaises(ValueError, rev_parse, '0.1.4^tree}') | |
| 548 | 549 | ||
| 550 | + # REVLOG | ||
| 551 | + ####### | ||
| 552 | + head = self.rorepo.head | ||
| 553 | + | ||
| 554 | + # need to specify a ref when using the @ syntax | ||
| 555 | + self.failUnlessRaises(BadObject, rev_parse, "%s@{0}" % head.commit.hexsha) | ||
| 556 | + | ||
| 557 | + # uses HEAD.ref by default | ||
| 558 | + assert rev_parse('@{0}') == head.commit | ||
| 559 | + if not head.is_detached: | ||
| 560 | + assert rev_parse('%s@{0}' % head.ref.name) == head.ref.commit | ||
| 561 | + #END operate on non-detached head | ||
| 562 | + | ||
| 563 | + # the last position | ||
| 564 | + assert rev_parse('@{1}') != head.commit | ||
| 565 | + | ||
| 566 | + # currently, nothing more is supported | ||
| 567 | + self.failUnlessRaises(NotImplementedError, rev_parse, "@{1 week ago}") | ||
| 549 | 568 | ||
| 550 | - # cannot handle rev-log for now | ||
| 551 | - self.failUnlessRaises(ValueError, rev_parse, "hi@there") | ||
| 552 | 569 | ||
| 553 | 570 | def test_repo_odbtype(self): | |
| 554 | 571 | target_type = GitDB | |
| Back | FazBrowse Home | New Git URL |
0 commit comments