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

Merge fix for use of alternates in DiskObjectStore.__contains__ and DiskObjectStore.__iter__.

Changeset 11e4b3d18288

Parents c4f0c51e7583

Parents 75f7f6668c89

by Jelmer Vernooij

Changes to 3 files · Browse files at 11e4b3d18288 Showing diff from parent c4f0c51e7583 75f7f6668c89 Diff from another changeset...

Change 1 of 1 Show Entire File NEWS Stacked
 
1
 
 
 
 
 
2
3
4
 
1
2
3
4
5
6
7
8
9
@@ -1,4 +1,9 @@
 0.9.0 UNRELEASED + + BUG FIXES + + * Fix use of alternates in ``DiskObjectStore``.{__contains__,__iter__}. + (Dmitriy)    0.8.6 2012-11-09  
 
231
232
233
234
 
 
 
 
235
236
 
 
 
 
 
 
 
 
 
 
 
 
237
238
239
 
257
258
259
 
 
 
 
 
 
260
261
262
 
283
284
285
286
 
287
288
289
290
 
 
 
 
291
292
293
 
231
232
233
 
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
 
272
273
274
275
276
277
278
279
280
281
282
283
 
304
305
306
 
307
308
309
310
 
311
312
313
314
315
316
317
@@ -231,9 +231,24 @@
  return []     def contains_packed(self, sha): - """Check if a particular object is present by SHA1 and is packed.""" + """Check if a particular object is present by SHA1 and is packed. + + This does not check alternates. + """   for pack in self.packs:   if sha in pack: + return True + return False + + def __contains__(self, sha): + """Check if a particular object is present by SHA1. + + This method makes no distinction between loose and packed objects. + """ + if self.contains_packed(sha) or self.contains_loose(sha): + return True + for alternate in self.alternates: + if sha in alternate:   return True   return False   @@ -257,6 +272,12 @@
  if self._pack_cache is None or self._pack_cache_stale():   self._pack_cache = self._load_packs()   return self._pack_cache + + def _iter_alternate_objects(self): + """Iterate over the SHAs of all the objects in alternate stores.""" + for alternate in self.alternates: + for alternate_object in alternate: + yield alternate_object     def _iter_loose_objects(self):   """Iterate over the SHAs of all loose objects.""" @@ -283,11 +304,14 @@
    def __iter__(self):   """Iterate over the SHAs that are present in this store.""" - iterables = self.packs + [self._iter_loose_objects()] + iterables = self.packs + [self._iter_loose_objects()] + [self._iter_alternate_objects()]   return itertools.chain(*iterables)     def contains_loose(self, sha): - """Check if a particular object is present by SHA1 and is loose.""" + """Check if a particular object is present by SHA1 and is loose. + + This does not check alternates. + """   return self._get_loose_object(sha) is not None     def get_raw(self, name):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
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
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
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
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
 # test_object_store.py -- tests for object_store.py  # Copyright (C) 2008 Jelmer Vernooij <jelmer@samba.org>  #  # This program is free software; you can redistribute it and/or  # modify it under the terms of the GNU General Public License  # as published by the Free Software Foundation; version 2  # or (at your option) any later version of the License.  #  # This program is distributed in the hope that it will be useful,  # but WITHOUT ANY WARRANTY; without even the implied warranty of  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the  # GNU General Public License for more details.  #  # You should have received a copy of the GNU General Public License  # along with this program; if not, write to the Free Software  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,  # MA 02110-1301, USA.    """Tests for the object store interface."""      from cStringIO import StringIO  import os  import shutil  import tempfile    from dulwich.index import (   commit_tree,   )  from dulwich.errors import (   NotTreeError,   )  from dulwich.objects import (   sha_to_hex,   object_class,   Blob,   Tag,   Tree,   TreeEntry,   )  from dulwich.object_store import (   DiskObjectStore,   MemoryObjectStore,   ObjectStoreGraphWalker,   tree_lookup_path,   )  from dulwich.pack import (   REF_DELTA,   write_pack_objects,   )  from dulwich.tests import (   TestCase,   )  from dulwich.tests.utils import (   make_object,   build_pack,   )      testobject = make_object(Blob, data="yummy data")      class ObjectStoreTests(object):     def test_determine_wants_all(self):   self.assertEqual(["1" * 40],   self.store.determine_wants_all({"refs/heads/foo": "1" * 40}))     def test_determine_wants_all_zero(self):   self.assertEqual([],   self.store.determine_wants_all({"refs/heads/foo": "0" * 40}))     def test_iter(self):   self.assertEqual([], list(self.store))     def test_get_nonexistant(self):   self.assertRaises(KeyError, lambda: self.store["a" * 40])     def test_contains_nonexistant(self):   self.assertFalse(("a" * 40) in self.store)     def test_add_objects_empty(self):   self.store.add_objects([])     def test_add_commit(self):   # TODO: Argh, no way to construct Git commit objects without   # access to a serialized form.   self.store.add_objects([])     def test_add_object(self):   self.store.add_object(testobject)   self.assertEqual(set([testobject.id]), set(self.store))   self.assertTrue(testobject.id in self.store)   r = self.store[testobject.id]   self.assertEqual(r, testobject)     def test_add_objects(self):   data = [(testobject, "mypath")]   self.store.add_objects(data)   self.assertEqual(set([testobject.id]), set(self.store))   self.assertTrue(testobject.id in self.store)   r = self.store[testobject.id]   self.assertEqual(r, testobject)     def test_tree_changes(self):   blob_a1 = make_object(Blob, data='a1')   blob_a2 = make_object(Blob, data='a2')   blob_b = make_object(Blob, data='b')   for blob in [blob_a1, blob_a2, blob_b]:   self.store.add_object(blob)     blobs_1 = [('a', blob_a1.id, 0100644), ('b', blob_b.id, 0100644)]   tree1_id = commit_tree(self.store, blobs_1)   blobs_2 = [('a', blob_a2.id, 0100644), ('b', blob_b.id, 0100644)]   tree2_id = commit_tree(self.store, blobs_2)   change_a = (('a', 'a'), (0100644, 0100644), (blob_a1.id, blob_a2.id))   self.assertEqual([change_a],   list(self.store.tree_changes(tree1_id, tree2_id)))   self.assertEqual(   [change_a, (('b', 'b'), (0100644, 0100644), (blob_b.id, blob_b.id))],   list(self.store.tree_changes(tree1_id, tree2_id,   want_unchanged=True)))     def test_iter_tree_contents(self):   blob_a = make_object(Blob, data='a')   blob_b = make_object(Blob, data='b')   blob_c = make_object(Blob, data='c')   for blob in [blob_a, blob_b, blob_c]:   self.store.add_object(blob)     blobs = [   ('a', blob_a.id, 0100644),   ('ad/b', blob_b.id, 0100644),   ('ad/bd/c', blob_c.id, 0100755),   ('ad/c', blob_c.id, 0100644),   ('c', blob_c.id, 0100644),   ]   tree_id = commit_tree(self.store, blobs)   self.assertEqual([TreeEntry(p, m, h) for (p, h, m) in blobs],   list(self.store.iter_tree_contents(tree_id)))     def test_iter_tree_contents_include_trees(self):   blob_a = make_object(Blob, data='a')   blob_b = make_object(Blob, data='b')   blob_c = make_object(Blob, data='c')   for blob in [blob_a, blob_b, blob_c]:   self.store.add_object(blob)     blobs = [   ('a', blob_a.id, 0100644),   ('ad/b', blob_b.id, 0100644),   ('ad/bd/c', blob_c.id, 0100755),   ]   tree_id = commit_tree(self.store, blobs)   tree = self.store[tree_id]   tree_ad = self.store[tree['ad'][1]]   tree_bd = self.store[tree_ad['bd'][1]]     expected = [   TreeEntry('', 0040000, tree_id),   TreeEntry('a', 0100644, blob_a.id),   TreeEntry('ad', 0040000, tree_ad.id),   TreeEntry('ad/b', 0100644, blob_b.id),   TreeEntry('ad/bd', 0040000, tree_bd.id),   TreeEntry('ad/bd/c', 0100755, blob_c.id),   ]   actual = self.store.iter_tree_contents(tree_id, include_trees=True)   self.assertEqual(expected, list(actual))     def make_tag(self, name, obj):   tag = make_object(Tag, name=name, message='',   tag_time=12345, tag_timezone=0,   tagger='Test Tagger <test@example.com>',   object=(object_class(obj.type_name), obj.id))   self.store.add_object(tag)   return tag     def test_peel_sha(self):   self.store.add_object(testobject)   tag1 = self.make_tag('1', testobject)   tag2 = self.make_tag('2', testobject)   tag3 = self.make_tag('3', testobject)   for obj in [testobject, tag1, tag2, tag3]:   self.assertEqual(testobject, self.store.peel_sha(obj.id))     def test_get_raw(self):   self.store.add_object(testobject)   self.assertEqual((Blob.type_num, 'yummy data'),   self.store.get_raw(testobject.id))      class MemoryObjectStoreTests(ObjectStoreTests, TestCase):     def setUp(self):   TestCase.setUp(self)   self.store = MemoryObjectStore()      class PackBasedObjectStoreTests(ObjectStoreTests):     def tearDown(self):   for pack in self.store.packs:   pack.close()     def test_empty_packs(self):   self.assertEqual([], self.store.packs)     def test_pack_loose_objects(self):   b1 = make_object(Blob, data="yummy data")   self.store.add_object(b1)   b2 = make_object(Blob, data="more yummy data")   self.store.add_object(b2)   self.assertEqual([], self.store.packs)   self.assertEqual(2, self.store.pack_loose_objects())   self.assertNotEquals([], self.store.packs)   self.assertEqual(0, self.store.pack_loose_objects())      class DiskObjectStoreTests(PackBasedObjectStoreTests, TestCase):     def setUp(self):   TestCase.setUp(self)   self.store_dir = tempfile.mkdtemp()   self.addCleanup(shutil.rmtree, self.store_dir)   self.store = DiskObjectStore.init(self.store_dir)     def tearDown(self):   TestCase.tearDown(self)   PackBasedObjectStoreTests.tearDown(self)     def test_alternates(self):   alternate_dir = tempfile.mkdtemp()   self.addCleanup(shutil.rmtree, alternate_dir)   alternate_store = DiskObjectStore(alternate_dir)   b2 = make_object(Blob, data="yummy data")   alternate_store.add_object(b2)   store = DiskObjectStore(self.store_dir)   self.assertRaises(KeyError, store.__getitem__, b2.id)   store.add_alternate_path(alternate_dir) + self.assertIn(b2.id, store)   self.assertEqual(b2, store[b2.id])     def test_add_alternate_path(self):   store = DiskObjectStore(self.store_dir)   self.assertEqual([], store._read_alternate_paths())   store.add_alternate_path("/foo/path")   self.assertEqual(["/foo/path"], store._read_alternate_paths())   store.add_alternate_path("/bar/path")   self.assertEqual(   ["/foo/path", "/bar/path"],   store._read_alternate_paths())     def test_pack_dir(self):   o = DiskObjectStore(self.store_dir)   self.assertEqual(os.path.join(self.store_dir, "pack"), o.pack_dir)     def test_add_pack(self):   o = DiskObjectStore(self.store_dir)   f, commit = o.add_pack()   b = make_object(Blob, data="more yummy data")   write_pack_objects(f, [(b, None)])   commit()     def test_add_thin_pack(self):   o = DiskObjectStore(self.store_dir)   blob = make_object(Blob, data='yummy data')   o.add_object(blob)     f = StringIO()   entries = build_pack(f, [   (REF_DELTA, (blob.id, 'more yummy data')),   ], store=o)   pack = o.add_thin_pack(f.read, None)   try:   packed_blob_sha = sha_to_hex(entries[0][3])   pack.check_length_and_checksum()   self.assertEqual(sorted([blob.id, packed_blob_sha]), list(pack))   self.assertTrue(o.contains_packed(packed_blob_sha))   self.assertTrue(o.contains_packed(blob.id))   self.assertEqual((Blob.type_num, 'more yummy data'),   o.get_raw(packed_blob_sha))   finally:   # FIXME: DiskObjectStore should have close() which do the following:   for p in o._pack_cache or []:   p.close()     pack.close()    class TreeLookupPathTests(TestCase):     def setUp(self):   TestCase.setUp(self)   self.store = MemoryObjectStore()   blob_a = make_object(Blob, data='a')   blob_b = make_object(Blob, data='b')   blob_c = make_object(Blob, data='c')   for blob in [blob_a, blob_b, blob_c]:   self.store.add_object(blob)     blobs = [   ('a', blob_a.id, 0100644),   ('ad/b', blob_b.id, 0100644),   ('ad/bd/c', blob_c.id, 0100755),   ('ad/c', blob_c.id, 0100644),   ('c', blob_c.id, 0100644),   ]   self.tree_id = commit_tree(self.store, blobs)     def get_object(self, sha):   return self.store[sha]     def test_lookup_blob(self):   o_id = tree_lookup_path(self.get_object, self.tree_id, 'a')[1]   self.assertTrue(isinstance(self.store[o_id], Blob))     def test_lookup_tree(self):   o_id = tree_lookup_path(self.get_object, self.tree_id, 'ad')[1]   self.assertTrue(isinstance(self.store[o_id], Tree))   o_id = tree_lookup_path(self.get_object, self.tree_id, 'ad/bd')[1]   self.assertTrue(isinstance(self.store[o_id], Tree))   o_id = tree_lookup_path(self.get_object, self.tree_id, 'ad/bd/')[1]   self.assertTrue(isinstance(self.store[o_id], Tree))     def test_lookup_nonexistent(self):   self.assertRaises(KeyError, tree_lookup_path, self.get_object, self.tree_id, 'j')     def test_lookup_not_tree(self):   self.assertRaises(NotTreeError, tree_lookup_path, self.get_object, self.tree_id, 'ad/b/j')    # TODO: MissingObjectFinderTests    class ObjectStoreGraphWalkerTests(TestCase):     def get_walker(self, heads, parent_map):   return ObjectStoreGraphWalker(heads,   parent_map.__getitem__)     def test_empty(self):   gw = self.get_walker([], {})   self.assertIs(None, gw.next())   gw.ack("aa" * 20)   self.assertIs(None, gw.next())     def test_descends(self):   gw = self.get_walker(["a"], {"a": ["b"], "b": []})   self.assertEqual("a", gw.next())   self.assertEqual("b", gw.next())     def test_present(self):   gw = self.get_walker(["a"], {"a": ["b"], "b": []})   gw.ack("a")   self.assertIs(None, gw.next())     def test_parent_present(self):   gw = self.get_walker(["a"], {"a": ["b"], "b": []})   self.assertEqual("a", gw.next())   gw.ack("a")   self.assertIs(None, gw.next())     def test_child_ack_later(self):   gw = self.get_walker(["a"], {"a": ["b"], "b": ["c"], "c": []})   self.assertEqual("a", gw.next())   self.assertEqual("b", gw.next())   gw.ack("a")   self.assertIs(None, gw.next())     def test_only_once(self):   # a b   # | |   # c d   # \ /   # e   gw = self.get_walker(["a", "b"], {   "a": ["c"],   "b": ["d"],   "c": ["e"],   "d": ["e"],   "e": [],   })   self.assertEqual("a", gw.next())   self.assertEqual("c", gw.next())   gw.ack("a")   self.assertEqual("b", gw.next())   self.assertEqual("d", gw.next())   self.assertIs(None, gw.next())