~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/inventory.py

  • Committer: Aaron Bentley
  • Date: 2005-08-25 13:10:25 UTC
  • mfrom: (974.1.38)
  • mto: (1092.1.42) (1185.3.4)
  • mto: This revision was merged to the branch mainline in revision 1178.
  • Revision ID: abentley@panoramicfeedback.com-20050825131025-2aa94bcbbd646a00
Fixed return value when not an ImmutableStore

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
 
23
23
import sys, os.path, types, re
24
24
 
25
 
try:
26
 
    from cElementTree import Element, ElementTree, SubElement
27
 
except ImportError:
28
 
    from elementtree.ElementTree import Element, ElementTree, SubElement
29
 
 
30
 
from xml import XMLMixin
31
 
from errors import bailout, BzrError, BzrCheckError
32
 
 
33
25
import bzrlib
 
26
from bzrlib.errors import BzrError, BzrCheckError
 
27
 
34
28
from bzrlib.osutils import uuid, quotefn, splitpath, joinpath, appendpath
35
29
from bzrlib.trace import mutter
 
30
from bzrlib.errors import NotVersionedError
 
31
        
36
32
 
37
 
class InventoryEntry(XMLMixin):
 
33
class InventoryEntry(object):
38
34
    """Description of a versioned file.
39
35
 
40
36
    An InventoryEntry has the following fields, which are also
68
64
    >>> i.add(InventoryEntry('2323', 'bye.c', 'file', '123'))
69
65
    Traceback (most recent call last):
70
66
    ...
71
 
    BzrError: ('inventory already contains entry with id {2323}', [])
 
67
    BzrError: inventory already contains entry with id {2323}
72
68
    >>> i.add(InventoryEntry('2324', 'bye.c', 'file', '123'))
73
69
    >>> i.add(InventoryEntry('2325', 'wibble', 'directory', '123'))
74
70
    >>> i.path2id('src/wibble')
98
94
    # TODO: split InventoryEntry into subclasses for files,
99
95
    # directories, etc etc.
100
96
 
101
 
    text_sha1 = None
102
 
    text_size = None
103
 
    
 
97
    __slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
 
98
                 'text_id', 'parent_id', 'children', ]
 
99
 
104
100
    def __init__(self, file_id, name, kind, parent_id, text_id=None):
105
101
        """Create an InventoryEntry
106
102
        
119
115
        if '/' in name or '\\' in name:
120
116
            raise BzrCheckError('InventoryEntry name %r is invalid' % name)
121
117
        
 
118
        self.text_sha1 = None
 
119
        self.text_size = None
 
120
    
122
121
        self.file_id = file_id
123
122
        self.name = name
124
123
        self.kind = kind
160
159
    
161
160
    def to_element(self):
162
161
        """Convert to XML element"""
 
162
        from bzrlib.xml import Element
 
163
        
163
164
        e = Element('entry')
164
165
 
165
166
        e.set('name', self.name)
248
249
 
249
250
 
250
251
 
251
 
class Inventory(XMLMixin):
 
252
class Inventory(object):
252
253
    """Inventory of versioned files in a tree.
253
254
 
254
255
    This describes which file_id is present at each point in the tree,
266
267
    inserted, other than through the Inventory API.
267
268
 
268
269
    >>> inv = Inventory()
269
 
    >>> inv.write_xml(sys.stdout)
270
 
    <inventory>
271
 
    </inventory>
272
270
    >>> inv.add(InventoryEntry('123-123', 'hello.c', 'file', ROOT_ID))
273
271
    >>> inv['123-123'].name
274
272
    'hello.c'
284
282
 
285
283
    >>> [x[0] for x in inv.iter_entries()]
286
284
    ['hello.c']
287
 
    
288
 
    >>> inv.write_xml(sys.stdout)
289
 
    <inventory>
290
 
    <entry file_id="123-123" kind="file" name="hello.c" />
291
 
    </inventory>
292
 
 
 
285
    >>> inv = Inventory('TREE_ROOT-12345678-12345678')
 
286
    >>> inv.add(InventoryEntry('123-123', 'hello.c', 'file', ROOT_ID))
293
287
    """
294
 
    def __init__(self):
 
288
    def __init__(self, root_id=ROOT_ID):
295
289
        """Create or read an inventory.
296
290
 
297
291
        If a working directory is specified, the inventory is read
301
295
        The inventory is created with a default root directory, with
302
296
        an id of None.
303
297
        """
304
 
        self.root = RootEntry(ROOT_ID)
 
298
        # We are letting Branch(init=True) create a unique inventory
 
299
        # root id. Rather than generating a random one here.
 
300
        #if root_id is None:
 
301
        #    root_id = bzrlib.branch.gen_file_id('TREE_ROOT')
 
302
        self.root = RootEntry(root_id)
305
303
        self._byid = {self.root.file_id: self.root}
306
304
 
307
305
 
411
409
        To add  a file to a branch ready to be committed, use Branch.add,
412
410
        which calls this."""
413
411
        if entry.file_id in self._byid:
414
 
            bailout("inventory already contains entry with id {%s}" % entry.file_id)
 
412
            raise BzrError("inventory already contains entry with id {%s}" % entry.file_id)
 
413
 
 
414
        if entry.parent_id == ROOT_ID or entry.parent_id is None:
 
415
            entry.parent_id = self.root.file_id
415
416
 
416
417
        try:
417
418
            parent = self._byid[entry.parent_id]
418
419
        except KeyError:
419
 
            bailout("parent_id {%s} not in inventory" % entry.parent_id)
 
420
            raise BzrError("parent_id {%s} not in inventory" % entry.parent_id)
420
421
 
421
422
        if parent.children.has_key(entry.name):
422
 
            bailout("%s is already versioned" %
 
423
            raise BzrError("%s is already versioned" %
423
424
                    appendpath(self.id2path(parent.file_id), entry.name))
424
425
 
425
426
        self._byid[entry.file_id] = entry
430
431
        """Add entry from a path.
431
432
 
432
433
        The immediate parent must already be versioned"""
 
434
        from bzrlib.branch import gen_file_id
 
435
        
433
436
        parts = bzrlib.osutils.splitpath(relpath)
434
437
        if len(parts) == 0:
435
 
            bailout("cannot re-add root of inventory")
 
438
            raise BzrError("cannot re-add root of inventory")
436
439
 
437
440
        if file_id == None:
438
 
            file_id = bzrlib.branch.gen_file_id(relpath)
439
 
 
440
 
        parent_id = self.path2id(parts[:-1])
441
 
        assert parent_id != None
 
441
            file_id = gen_file_id(relpath)
 
442
 
 
443
        parent_path = parts[:-1]
 
444
        parent_id = self.path2id(parent_path)
 
445
        if parent_id == None:
 
446
            raise NotVersionedError(parent_path)
 
447
 
442
448
        ie = InventoryEntry(file_id, parts[-1],
443
449
                            kind=kind, parent_id=parent_id)
444
450
        return self.add(ie)
472
478
 
473
479
    def to_element(self):
474
480
        """Convert to XML Element"""
 
481
        from bzrlib.xml import Element
 
482
        
475
483
        e = Element('inventory')
476
484
        e.text = '\n'
 
485
        if self.root.file_id not in (None, ROOT_ID):
 
486
            e.set('file_id', self.root.file_id)
477
487
        for path, ie in self.iter_entries():
478
488
            e.append(ie.to_element())
479
489
        return e
481
491
 
482
492
    def from_element(cls, elt):
483
493
        """Construct from XML Element
484
 
 
 
494
        
485
495
        >>> inv = Inventory()
486
496
        >>> inv.add(InventoryEntry('foo.c-123981239', 'foo.c', 'file', ROOT_ID))
487
497
        >>> elt = inv.to_element()
489
499
        >>> inv2 == inv
490
500
        True
491
501
        """
 
502
        # XXXX: doctest doesn't run this properly under python2.3
492
503
        assert elt.tag == 'inventory'
493
 
        o = cls()
 
504
        root_id = elt.get('file_id') or ROOT_ID
 
505
        o = cls(root_id)
494
506
        for e in elt:
495
 
            o.add(InventoryEntry.from_element(e))
 
507
            ie = InventoryEntry.from_element(e)
 
508
            if ie.parent_id == ROOT_ID:
 
509
                ie.parent_id = root_id
 
510
            o.add(ie)
496
511
        return o
497
512
        
498
513
    from_element = classmethod(from_element)
544
559
            try:
545
560
                ie = self._byid[file_id]
546
561
            except KeyError:
547
 
                bailout("file_id {%s} not found in inventory" % file_id)
 
562
                raise BzrError("file_id {%s} not found in inventory" % file_id)
548
563
            p.insert(0, ie.file_id)
549
564
            file_id = ie.parent_id
550
565
        return p
554
569
        """Return as a list the path to file_id."""
555
570
 
556
571
        # get all names, skipping root
557
 
        p = [self[fid].name for fid in self.get_idpath(file_id)[1:]]
 
572
        p = [self._byid[fid].name for fid in self.get_idpath(file_id)[1:]]
558
573
        return os.sep.join(p)
559
574
            
560
575
 
604
619
 
605
620
        This does not move the working file."""
606
621
        if not is_valid_name(new_name):
607
 
            bailout("not an acceptable filename: %r" % new_name)
 
622
            raise BzrError("not an acceptable filename: %r" % new_name)
608
623
 
609
624
        new_parent = self._byid[new_parent_id]
610
625
        if new_name in new_parent.children:
611
 
            bailout("%r already exists in %r" % (new_name, self.id2path(new_parent_id)))
 
626
            raise BzrError("%r already exists in %r" % (new_name, self.id2path(new_parent_id)))
612
627
 
613
628
        new_parent_idpath = self.get_idpath(new_parent_id)
614
629
        if file_id in new_parent_idpath:
615
 
            bailout("cannot move directory %r into a subdirectory of itself, %r"
 
630
            raise BzrError("cannot move directory %r into a subdirectory of itself, %r"
616
631
                    % (self.id2path(file_id), self.id2path(new_parent_id)))
617
632
 
618
633
        file_ie = self._byid[file_id]