Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd924091

Browse files
committed
tree: added TreeModifier, allowing to adjust existing trees safely and or fast, while staying compatible with serialization which requires it to be sorted
1 parentfe5289e commitd924091

File tree

5 files changed

+152
-16
lines changed

5 files changed

+152
-16
lines changed

‎lib/git/objects/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
fromblobimport*
88
fromtreeimport*
99
fromcommitimport*
10+
fromsubmoduleimport*
1011

1112
__all__= [nameforname,objinlocals().items()
1213
ifnot (name.startswith('_')orinspect.ismodule(obj)) ]

‎lib/git/objects/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ def _mode_str_to_int(cls, modestr):
197197
for example.
198198
"""
199199
mode=0
200-
foriteration,charinenumerate(reversed(modestr[-6:])):
200+
foriteration,charinenumerate(reversed(modestr[-6:])):
201201
mode+=int(char)<<iteration*3
202202
# END for each char
203203
returnmode

‎lib/git/objects/commit.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ def _deserialize(self, stream):
402402
""":param from_rev_list: if true, the stream format is coming from the rev-list command
403403
Otherwise it is assumed to be a plain data stream from our object"""
404404
readline=stream.readline
405-
self.tree=Tree(self.repo,readline().split()[1],0,'')
405+
self.tree=Tree(self.repo,readline().split()[1],Tree.tree_id<<12,'')
406406

407407
self.parents=list()
408408
next_line=None

‎lib/git/objects/tree.py

Lines changed: 91 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,84 @@ def sha_to_hex(sha):
2121
returnhexsha
2222

2323

24+
classTreeModifier(object):
25+
"""A utility class providing methods to alter the underlying cache in a list-like
26+
fashion.
27+
Once all adjustments are complete, the _cache, which really is a refernce to
28+
the cache of a tree, will be sorted. Assuring it will be in a serializable state"""
29+
__slots__='_cache'
30+
31+
def__init__(self,cache):
32+
self._cache=cache
33+
34+
def_index_by_name(self,name):
35+
""":return: index of an item with name, or -1 if not found"""
36+
fori,tinenumerate(self._cache):
37+
ift[2]==name:
38+
returni
39+
# END found item
40+
# END for each item in cache
41+
return-1
42+
43+
#{ Interface
44+
defset_done(self):
45+
"""Call this method once you are done modifying the tree information.
46+
It may be called several times, but be aware that each call will cause
47+
a sort operation
48+
:return self:"""
49+
self._cache.sort(key=lambdat:t[2])# sort by name
50+
returnself
51+
#} END interface
52+
53+
#{ Mutators
54+
defadd(self,hexsha,mode,name,force=False):
55+
"""Add the given item to the tree. If an item with the given name already
56+
exists, nothing will be done, but a ValueError will be raised if the
57+
sha and mode of the existing item do not match the one you add, unless
58+
force is True
59+
:param hexsha: The 40 byte sha of the item to add
60+
:param mode: int representing the stat compatible mode of the item
61+
:param force: If True, an item with your name and information will overwrite
62+
any existing item with the same name, no matter which information it has
63+
:return: self"""
64+
if'/'inname:
65+
raiseValueError("Name must not contain '/' characters")
66+
iflen(hexsha)!=40:
67+
raiseValueError("Hexsha required, got %r"%hexsha)
68+
if (mode>>12)notinTree._map_id_to_type:
69+
raiseValueError("Invalid object type according to mode %o"%mode)
70+
71+
index=self._index_by_name(name)
72+
item= (hexsha,mode,name)
73+
ifindex==-1:
74+
self._cache.append(item)
75+
else:
76+
ifforce:
77+
self._cache[index]=item
78+
else:
79+
ex_item=self._cache[index]
80+
ifex_item[0]!=hexshaorex_item[1]!=mode:
81+
raiseValueError("Item %r existed with different properties"%name)
82+
# END handle mismatch
83+
# END handle force
84+
# END handle name exists
85+
returnself
86+
87+
defadd_unchecked(self,hexsha,mode,name):
88+
"""Add the given item to the tree, its correctness is assumed, which
89+
puts the caller into responsibility to assure the input is correct.
90+
For more information on the parameters, see ``add``"""
91+
self._cache.append((hexsha,mode,name))
92+
93+
def__delitem__(self,name):
94+
"""Deletes an item with the given name if it exists"""
95+
index=self._index_by_name(name)
96+
ifindex>-1:
97+
del(self._cache[index])
98+
99+
#} END mutators
100+
101+
24102
classTree(base.IndexObject,diff.Diffable,utils.Traversable,utils.Serializable):
25103
"""
26104
Tress represent a ordered list of Blobs and other Trees. Hence it can be
@@ -42,8 +120,8 @@ class Tree(base.IndexObject, diff.Diffable, utils.Traversable, utils.Serializabl
42120
type="tree"
43121
__slots__="_cache"
44122

45-
#using ascii codes for comparison
46-
commit_id=016
123+
#actual integer ids for comparison
124+
commit_id=016
47125
blob_id=010
48126
symlink_id=012
49127
tree_id=004
@@ -56,7 +134,7 @@ class Tree(base.IndexObject, diff.Diffable, utils.Traversable, utils.Serializabl
56134
}
57135

58136

59-
def__init__(self,repo,sha,mode=0,path=None):
137+
def__init__(self,repo,sha,mode=tree_id<<12,path=None):
60138
super(Tree,self).__init__(repo,sha,mode,path)
61139

62140
@classmethod
@@ -133,7 +211,6 @@ def _iter_from_data(self, data):
133211
yield (sha_to_hex(sha),mode,name)
134212
# END for each byte in data stream
135213

136-
137214
def__div__(self,file):
138215
"""
139216
Find the named object in this tree's contents
@@ -198,6 +275,13 @@ def blobs(self):
198275
"""
199276
return [iforiinselfifi.type=="blob" ]
200277

278+
@property
279+
defcache(self):
280+
""":return: An object allowing to modify the internal cache. This can be used
281+
to change the tree's contents. When done, make sure you call ``set_done``
282+
on the tree modifier, or serialization behaviour will be incorrect.
283+
See the ``TreeModifier`` for more information on how to alter the cache"""
284+
returnTreeModifier(self._cache)
201285

202286
deftraverse(self,predicate=lambdai,d:True,
203287
prune=lambdai,d:False,depth=-1,branch_first=True,
@@ -253,11 +337,9 @@ def __reversed__(self):
253337

254338
def_serialize(self,stream,presort=False):
255339
"""Serialize this tree into the stream. Please note that we will assume
256-
our tree data to be in a sorted state. If this is not the case, set the
257-
presort flag True
258-
:param presort: if True, default False, sort our tree information before
259-
writing it to the stream. This should be done if the cache changed
260-
in the meanwhile"""
340+
our tree data to be in a sorted state. If this is not the case, serialization
341+
will not generate a correct tree representation as these are assumed to be sorted
342+
by algorithms"""
261343
ord_zero=ord('0')
262344
bit_mask=7# 3 bits set
263345
hex_to_bin=binascii.a2b_hex

‎test/git/test_tree.py

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,73 @@ def test_serializable(self):
1818
ifitem.type!=Tree.type:
1919
continue
2020
# END skip non-trees
21-
orig_data=item.data
22-
orig_cache=item._cache
21+
tree=item
22+
orig_data=tree.data
23+
orig_cache=tree._cache
2324

2425
stream=StringIO()
25-
item._serialize(stream)
26+
tree._serialize(stream)
2627
assertstream.getvalue()==orig_data
2728

2829
stream.seek(0)
2930
testtree=Tree(self.rorepo,Tree.NULL_HEX_SHA,0,'')
3031
testtree._deserialize(stream)
3132
asserttesttree._cache==orig_cache
3233

33-
# add an item, serialize with presort
34-
self.fail("presort")
34+
35+
# TEST CACHE MUTATOR
36+
mod=testtree.cache
37+
self.failUnlessRaises(ValueError,mod.add,"invalid sha",0,"name")
38+
self.failUnlessRaises(ValueError,mod.add,Tree.NULL_HEX_SHA,0,"invalid mode")
39+
self.failUnlessRaises(ValueError,mod.add,Tree.NULL_HEX_SHA,tree.mode,"invalid/name")
40+
41+
# add new item
42+
name="fake_dir"
43+
mod.add(testtree.NULL_HEX_SHA,tree.mode,name)
44+
assertnameintesttree
45+
46+
# its available in the tree immediately
47+
assertisinstance(testtree[name],Tree)
48+
49+
# adding it again will not cause multiple of them to be presents
50+
cur_count=len(testtree)
51+
mod.add(testtree.NULL_HEX_SHA,tree.mode,name)
52+
assertlen(testtree)==cur_count
53+
54+
# fails with a different sha - name exists
55+
hexsha="1"*40
56+
self.failUnlessRaises(ValueError,mod.add,hexsha,tree.mode,name)
57+
58+
# force it - replace existing one
59+
mod.add(hexsha,tree.mode,name,force=True)
60+
asserttesttree[name].sha==hexsha
61+
assertlen(testtree)==cur_count
62+
63+
# unchecked addition always works, even with invalid items
64+
invalid_name="hi/there"
65+
mod.add_unchecked(hexsha,0,invalid_name)
66+
assertlen(testtree)==cur_count+1
67+
68+
del(mod[invalid_name])
69+
assertlen(testtree)==cur_count
70+
# del again, its fine
71+
del(mod[invalid_name])
72+
73+
# have added one item, we are done
74+
mod.set_done()
75+
mod.set_done()# multiple times are okay
76+
77+
# serialize, its different now
78+
stream=StringIO()
79+
testtree._serialize(stream)
80+
stream.seek(0)
81+
assertstream.getvalue()!=orig_data
82+
83+
# replaces cache, but we make sure of it
84+
del(testtree._cache)
85+
testtree._deserialize(stream)
86+
assertnameintesttree
87+
assertinvalid_namenotintesttree
3588
# END for each item in tree
3689

3790
deftest_traverse(self):

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp