Kiln » Dependencies » Dulwich Read More
Clone URL:  
Pushed to one repository · View In Graph Contained in master

Add include-tag capability to server.

For this, we need to pass an include_tag flag as well as a dict of
shas that we kno have tags pointing to them all the way down to
MissingObjectFinder.

Added unit test to server.py, but still missing MissingObjectFinder
tests.

Change-Id: Ifd5e623c712842d0eb5133fb5fb78ab2c8c6970f

Changeset b32d76dc0dc1

Parent 9f16fe75dfb8

committed by Dave Borowitz

authored by Dave Borowitz

Changes to 5 files · Browse files at b32d76dc0dc1 Showing diff from parent 9f16fe75dfb8 Diff from another changeset...

 
195
196
197
198
 
 
199
200
201
202
203
204
 
 
205
206
207
 
 
208
209
210
 
637
638
639
 
 
 
640
641
642
 
 
643
644
645
 
647
648
649
 
650
651
652
 
673
674
675
 
 
676
677
678
 
195
196
197
 
198
199
200
201
202
203
204
205
206
207
208
209
 
210
211
212
213
214
 
641
642
643
644
645
646
647
648
 
649
650
651
652
653
 
655
656
657
658
659
660
661
 
682
683
684
685
686
687
688
689
@@ -195,16 +195,20 @@
  else:   yield path, mode, hexsha   - def find_missing_objects(self, haves, wants, progress=None): + def find_missing_objects(self, haves, wants, progress=None, + get_tagged=None):   """Find the missing objects required for a set of revisions.     :param haves: Iterable over SHAs already in common.   :param wants: Iterable over SHAs of objects to fetch.   :param progress: Simple progress function that will be called with   updated progress strings. + :param get_tagged: Function that returns a dict of pointed-to sha -> tag + sha for including tags.   :return: Iterator over (sha, path) pairs.   """ - return iter(MissingObjectFinder(self, haves, wants, progress).next, None) + finder = MissingObjectFinder(self, haves, wants, progress, get_tagged) + return iter(finder.next, None)     def find_common_revisions(self, graphwalker):   """Find which revisions this store has in common using graphwalker. @@ -637,9 +641,13 @@
  :param haves: SHA1s of commits not to send (already present in target)   :param wants: SHA1s of commits to send   :param progress: Optional function to report progress to. + :param get_tagged: Function that returns a dict of pointed-to sha -> tag + sha for including tags. + :param tagged: dict of pointed-to sha -> tag sha for including tags   """   - def __init__(self, object_store, haves, wants, progress=None): + def __init__(self, object_store, haves, wants, progress=None, + get_tagged=None):   self.sha_done = set(haves)   self.objects_to_send = set([(w, None, False) for w in wants if w not in haves])   self.object_store = object_store @@ -647,6 +655,7 @@
  self.progress = lambda x: None   else:   self.progress = progress + self._tagged = get_tagged and get_tagged() or {}     def add_todo(self, entries):   self.objects_to_send.update([e for e in entries if not e[0] in self.sha_done]) @@ -673,6 +682,8 @@
  self.parse_tree(o)   elif isinstance(o, Tag):   self.parse_tag(o) + if sha in self._tagged: + self.add_todo([(self._tagged[sha], None, True)])   self.sha_done.add(sha)   self.progress("counting objects: %d\r" % len(self.sha_done))   return (sha, name)
Change 1 of 2 Show Entire File dulwich/​repo.py Stacked
 
648
649
650
651
 
 
652
653
654
 
658
659
660
 
 
661
662
663
664
665
666
 
 
667
668
669
 
648
649
650
 
651
652
653
654
655
 
659
660
661
662
663
664
665
666
667
668
 
669
670
671
672
673
@@ -648,7 +648,8 @@
  progress))   return self.get_refs()   - def fetch_objects(self, determine_wants, graph_walker, progress): + def fetch_objects(self, determine_wants, graph_walker, progress, + get_tagged=None):   """Fetch the missing objects required for a set of revisions.     :param determine_wants: Function that takes a dictionary with heads @@ -658,12 +659,15 @@
  that a revision is present.   :param progress: Simple progress function that will be called with   updated progress strings. + :param get_tagged: Function that returns a dict of pointed-to sha -> tag + sha for including tags.   :return: iterator over objects, with __len__ implemented   """   wants = determine_wants(self.get_refs())   haves = self.object_store.find_common_revisions(graph_walker)   return self.object_store.iter_shas( - self.object_store.find_missing_objects(haves, wants, progress)) + self.object_store.find_missing_objects(haves, wants, progress, + get_tagged))     def get_graph_walker(self, heads=None):   if heads is None:
Change 1 of 4 Show Entire File dulwich/​server.py Stacked
 
76
77
78
79
 
 
80
81
82
83
 
 
84
85
86
 
91
92
93
 
94
95
96
 
204
205
206
207
 
208
209
210
 
214
215
216
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
217
218
219
220
221
222
 
 
223
224
225
 
76
77
78
 
79
80
81
82
83
84
85
86
87
88
89
 
94
95
96
97
98
99
100
 
208
209
210
 
211
212
213
214
 
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
 
255
256
257
258
259
@@ -76,11 +76,14 @@
  """   raise NotImplementedError   - def fetch_objects(self, determine_wants, graph_walker, progress): + def fetch_objects(self, determine_wants, graph_walker, progress, + get_tagged=None):   """   Yield the objects required for a list of commits.     :param progress: is a callback to send progress messages to the client + :param get_tagged: Function that returns a dict of pointed-to sha -> tag + sha for including tags.   """   raise NotImplementedError   @@ -91,6 +94,7 @@
  if repo is None:   repo = Repo(tmpfile.mkdtemp())   self.repo = repo + self.refs = self.repo.refs   self.object_store = self.repo.object_store   self.fetch_objects = self.repo.fetch_objects   self.get_refs = self.repo.get_refs @@ -204,7 +208,7 @@
    def capabilities(self):   return ("multi_ack_detailed", "multi_ack", "side-band-64k", "thin-pack", - "ofs-delta", "no-progress") + "ofs-delta", "no-progress", "include-tag")     def required_capabilities(self):   return ("side-band-64k", "thin-pack", "ofs-delta") @@ -214,12 +218,42 @@
  return   self.proto.write_sideband(2, message)   + def get_tagged(self, refs=None, repo=None): + """Get a dict of peeled values of tags to their original tag shas. + + :param refs: dict of refname -> sha of possible tags; defaults to all of + the backend's refs. + :param repo: optional Repo instance for getting peeled refs; defaults to + the backend's repo, if available + :return: dict of peeled_sha -> tag_sha, where tag_sha is the sha of a + tag whose peeled value is peeled_sha. + """ + if not self.has_capability("include-tag"): + return {} + if refs is None: + refs = self.backend.get_refs() + if repo is None: + repo = getattr(self.backend, "repo", None) + if repo is None: + # Bail if we don't have a Repo available; this is ok since + # clients must be able to handle if the server doesn't include + # all relevant tags. + # TODO: either guarantee a Repo, or fix behavior when missing + return {} + tagged = {} + for name, sha in refs.iteritems(): + peeled_sha = repo.get_peeled(name) + if peeled_sha != sha: + tagged[peeled_sha] = sha + return tagged +   def handle(self):   write = lambda x: self.proto.write_sideband(1, x)     graph_walker = ProtocolGraphWalker(self)   objects_iter = self.backend.fetch_objects( - graph_walker.determine_wants, graph_walker, self.progress) + graph_walker.determine_wants, graph_walker, self.progress, + get_tagged=self.get_tagged)     # Do they want any objects?   if len(objects_iter) == 0:
 
99
100
101
 
 
 
 
99
100
101
102
103
104
@@ -99,3 +99,6 @@
  shutil.rmtree("foo")   os.makedirs(os.path.join("foo", "pack"))   self.store = DiskObjectStore("foo") + + +# TODO: MissingObjectFinderTests
 
142
143
144
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
146
147
 
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
@@ -142,6 +142,31 @@
  self._handler.progress('second message')   self.assertEqual(None, self._handler.proto.get_received_line(2))   + def test_get_tagged(self): + refs = { + 'refs/tags/tag1': ONE, + 'refs/tags/tag2': TWO, + 'refs/heads/master': FOUR, # not a tag, no peeled value + } + peeled = { + 'refs/tags/tag1': '1234', + 'refs/tags/tag2': '5678', + } + + class TestRepo(object): + def get_peeled(self, ref): + return peeled.get(ref, refs[ref]) + + caps = list(self._handler.required_capabilities()) + ['include-tag'] + self._handler.set_client_capabilities(caps) + self.assertEquals({'1234': ONE, '5678': TWO}, + self._handler.get_tagged(refs, repo=TestRepo())) + + # non-include-tag case + caps = self._handler.required_capabilities() + self._handler.set_client_capabilities(caps) + self.assertEquals({}, self._handler.get_tagged(refs, repo=TestRepo())) +    class TestCommit(object):   def __init__(self, sha, parents, commit_time):