@@ -21,6 +21,84 @@ def sha_to_hex(sha):
2121 return hexsha
2222
2323
24+ class TreeModifier (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+ for i , t in enumerate (self ._cache ):
37+ if t [2 ] == name :
38+ return i
39+ # END found item
40+ # END for each item in cache
41+ return - 1
42+
43+ #{ Interface
44+ def set_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 = lambda t : t [2 ]) # sort by name
50+ return self
51+ #} END interface
52+
53+ #{ Mutators
54+ def add (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 '/' in name :
65+ raise ValueError ("Name must not contain '/' characters" )
66+ if len (hexsha ) != 40 :
67+ raise ValueError ("Hexsha required, got %r" % hexsha )
68+ if (mode >> 12 ) not in Tree ._map_id_to_type :
69+ raise ValueError ("Invalid object type according to mode %o" % mode )
70+
71+ index = self ._index_by_name (name )
72+ item = (hexsha , mode , name )
73+ if index == - 1 :
74+ self ._cache .append (item )
75+ else :
76+ if force :
77+ self ._cache [index ] = item
78+ else :
79+ ex_item = self ._cache [index ]
80+ if ex_item [0 ] != hexsha or ex_item [1 ] != mode :
81+ raise ValueError ("Item %r existed with different properties" % name )
82+ # END handle mismatch
83+ # END handle force
84+ # END handle name exists
85+ return self
86+
87+ def add_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+ if index > - 1 :
97+ del (self ._cache [index ])
98+
99+ #} END mutators
100+
101+
24102class Tree (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 [ i for i in self if i .type == "blob" ]
200277
278+ @property
279+ def cache (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+ return TreeModifier (self ._cache )
201285
202286 def traverse ( self , predicate = lambda i ,d : True ,
203287 prune = lambda i ,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
0 commit comments