~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/inventory.py

  • Committer: mbp at sourcefrog
  • Date: 2005-04-08 05:39:46 UTC
  • Revision ID: mbp@sourcefrog.net-20050408053946-1cb3415e1f8f58493034a5cf
- import lovely urlgrabber library

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
 
17
"""Inventories map files to their name in a revision."""
 
18
 
 
19
# TODO: Maybe store inventory_id in the file?  Not really needed.
 
20
 
 
21
__author__ = "Martin Pool <mbp@canonical.com>"
 
22
 
17
23
 
18
24
# This should really be an id randomly assigned when the tree is
19
25
# created, but it's not for now.
29
35
    from elementtree.ElementTree import Element, ElementTree, SubElement
30
36
 
31
37
from xml import XMLMixin
32
 
from errors import bailout, BzrError, BzrCheckError
 
38
from errors import bailout, BzrError
33
39
 
34
40
import bzrlib
35
41
from bzrlib.osutils import uuid, quotefn, splitpath, joinpath, appendpath
91
97
    >>> i.id2path('2326')
92
98
    'src/wibble/wibble.c'
93
99
 
94
 
    TODO: Maybe also keep the full path of the entry, and the children?
 
100
    :todo: Maybe also keep the full path of the entry, and the children?
95
101
           But those depend on its position within a particular inventory, and
96
102
           it would be nice not to need to hold the backpointer here.
97
103
    """
98
104
 
99
105
    # TODO: split InventoryEntry into subclasses for files,
100
106
    # directories, etc etc.
101
 
 
102
 
    text_sha1 = None
103
 
    text_size = None
104
107
    
105
108
    def __init__(self, file_id, name, kind, parent_id, text_id=None):
106
109
        """Create an InventoryEntry
115
118
        '123'
116
119
        >>> e = InventoryEntry('123', 'src/hello.c', 'file', ROOT_ID)
117
120
        Traceback (most recent call last):
118
 
        BzrCheckError: InventoryEntry name 'src/hello.c' is invalid
 
121
        BzrError: ("InventoryEntry name is not a simple filename: 'src/hello.c'", [])
119
122
        """
120
 
        if '/' in name or '\\' in name:
121
 
            raise BzrCheckError('InventoryEntry name %r is invalid' % name)
 
123
        
 
124
        if len(splitpath(name)) != 1:
 
125
            bailout('InventoryEntry name is not a simple filename: %r'
 
126
                    % name)
122
127
        
123
128
        self.file_id = file_id
124
129
        self.name = name
 
130
        assert kind in ['file', 'directory']
125
131
        self.kind = kind
126
132
        self.text_id = text_id
127
133
        self.parent_id = parent_id
 
134
        self.text_sha1 = None
 
135
        self.text_size = None
128
136
        if kind == 'directory':
129
137
            self.children = {}
130
 
        elif kind == 'file':
131
 
            pass
132
138
        else:
133
 
            raise BzrError("unhandled entry kind %r" % kind)
134
 
 
 
139
            assert kind == 'file'
135
140
 
136
141
 
137
142
    def sorted_children(self):
246
251
class Inventory(XMLMixin):
247
252
    """Inventory of versioned files in a tree.
248
253
 
249
 
    This describes which file_id is present at each point in the tree,
250
 
    and possibly the SHA-1 or other information about the file.
251
 
    Entries can be looked up either by path or by file_id.
 
254
    An Inventory acts like a set of InventoryEntry items.  You can
 
255
    also look files up by their file_id or name.
 
256
    
 
257
    May be read from and written to a metadata file in a tree.  To
 
258
    manipulate the inventory (for example to add a file), it is read
 
259
    in, modified, and then written back out.
252
260
 
253
261
    The inventory represents a typical unix file tree, with
254
262
    directories containing files and subdirectories.  We never store
286
294
    </inventory>
287
295
 
288
296
    """
 
297
 
 
298
    ## TODO: Make sure only canonical filenames are stored.
 
299
 
 
300
    ## TODO: Do something sensible about the possible collisions on
 
301
    ## case-losing filesystems.  Perhaps we should just always forbid
 
302
    ## such collisions.
 
303
 
 
304
    ## TODO: No special cases for root, rather just give it a file id
 
305
    ## like everything else.
 
306
 
 
307
    ## TODO: Probably change XML serialization to use nesting
 
308
 
289
309
    def __init__(self):
290
310
        """Create or read an inventory.
291
311
 
323
343
            yield name, ie
324
344
            if ie.kind == 'directory':
325
345
                for cn, cie in self.iter_entries(from_dir=ie.file_id):
326
 
                    yield os.path.join(name, cn), cie
 
346
                    yield '/'.join((name, cn)), cie
327
347
                    
328
348
 
329
349
 
371
391
        >>> inv['123123'].name
372
392
        'hello.c'
373
393
        """
 
394
        if file_id == None:
 
395
            raise BzrError("can't look up file_id None")
 
396
            
374
397
        try:
375
398
            return self._byid[file_id]
376
399
        except KeyError:
377
 
            if file_id == None:
378
 
                raise BzrError("can't look up file_id None")
379
 
            else:
380
 
                raise BzrError("file_id {%s} not in inventory" % file_id)
381
 
 
382
 
 
383
 
    def get_file_kind(self, file_id):
384
 
        return self._byid[file_id].kind
 
400
            raise BzrError("file_id {%s} not in inventory" % file_id)
 
401
 
385
402
 
386
403
    def get_child(self, parent_id, filename):
387
404
        return self[parent_id].children.get(filename)
538
555
 
539
556
        # get all names, skipping root
540
557
        p = [self[fid].name for fid in self.get_idpath(file_id)[1:]]
541
 
        return os.sep.join(p)
 
558
        return '/'.join(p)
542
559
            
543
560
 
544
561