~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/inventory.py

  • Committer: Aaron Bentley
  • Date: 2005-08-10 21:43:27 UTC
  • mto: (1092.1.41) (1185.3.4) (974.1.47)
  • mto: This revision was merged to the branch mainline in revision 1110.
  • Revision ID: abentley@panoramicfeedback.com-20050810214327-4e8c22e4cba24527
Eliminated ThreeWayInventory

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