~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/inventory.py

merge from aaron - fixes bare excepts, adds ancestor namespace

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
 
28
28
from bzrlib.osutils import uuid, quotefn, splitpath, joinpath, appendpath
29
29
from bzrlib.trace import mutter
 
30
from bzrlib.errors import NotVersionedError
 
31
        
30
32
 
31
33
class InventoryEntry(object):
32
34
    """Description of a versioned file.
53
55
    >>> i.path2id('')
54
56
    'TREE_ROOT'
55
57
    >>> i.add(InventoryEntry('123', 'src', 'directory', ROOT_ID))
 
58
    InventoryEntry('123', 'src', kind='directory', parent_id='TREE_ROOT')
56
59
    >>> i.add(InventoryEntry('2323', 'hello.c', 'file', parent_id='123'))
 
60
    InventoryEntry('2323', 'hello.c', kind='file', parent_id='123')
57
61
    >>> for j in i.iter_entries():
58
62
    ...   print j
59
63
    ... 
64
68
    ...
65
69
    BzrError: inventory already contains entry with id {2323}
66
70
    >>> i.add(InventoryEntry('2324', 'bye.c', 'file', '123'))
 
71
    InventoryEntry('2324', 'bye.c', kind='file', parent_id='123')
67
72
    >>> i.add(InventoryEntry('2325', 'wibble', 'directory', '123'))
 
73
    InventoryEntry('2325', 'wibble', kind='directory', parent_id='123')
68
74
    >>> i.path2id('src/wibble')
69
75
    '2325'
70
76
    >>> '2325' in i
71
77
    True
72
78
    >>> i.add(InventoryEntry('2326', 'wibble.c', 'file', '2325'))
 
79
    InventoryEntry('2326', 'wibble.c', kind='file', parent_id='2325')
73
80
    >>> i['2326']
74
81
    InventoryEntry('2326', 'wibble.c', kind='file', parent_id='2325')
75
82
    >>> for j in i.iter_entries():
92
99
    # TODO: split InventoryEntry into subclasses for files,
93
100
    # directories, etc etc.
94
101
 
95
 
    text_sha1 = None
96
 
    text_size = None
97
 
    
 
102
    __slots__ = ['text_sha1', 'text_size', 'file_id', 'name', 'kind',
 
103
                 'text_id', 'parent_id', 'children',
 
104
                 'text_version', 'entry_version', ]
 
105
 
 
106
 
98
107
    def __init__(self, file_id, name, kind, parent_id, text_id=None):
99
108
        """Create an InventoryEntry
100
109
        
110
119
        Traceback (most recent call last):
111
120
        BzrCheckError: InventoryEntry name 'src/hello.c' is invalid
112
121
        """
 
122
        assert isinstance(name, basestring), name
113
123
        if '/' in name or '\\' in name:
114
124
            raise BzrCheckError('InventoryEntry name %r is invalid' % name)
115
125
        
 
126
        self.text_version = None
 
127
        self.entry_version = None
 
128
        self.text_sha1 = None
 
129
        self.text_size = None
116
130
        self.file_id = file_id
117
131
        self.name = name
118
132
        self.kind = kind
152
166
                   self.parent_id))
153
167
 
154
168
    
155
 
    def to_element(self):
156
 
        """Convert to XML element"""
157
 
        from bzrlib.xml import Element
158
 
        
159
 
        e = Element('entry')
160
 
 
161
 
        e.set('name', self.name)
162
 
        e.set('file_id', self.file_id)
163
 
        e.set('kind', self.kind)
164
 
 
165
 
        if self.text_size != None:
166
 
            e.set('text_size', '%d' % self.text_size)
167
 
            
168
 
        for f in ['text_id', 'text_sha1']:
169
 
            v = getattr(self, f)
170
 
            if v != None:
171
 
                e.set(f, v)
172
 
 
173
 
        # to be conservative, we don't externalize the root pointers
174
 
        # for now, leaving them as null in the xml form.  in a future
175
 
        # version it will be implied by nested elements.
176
 
        if self.parent_id != ROOT_ID:
177
 
            assert isinstance(self.parent_id, basestring)
178
 
            e.set('parent_id', self.parent_id)
179
 
 
180
 
        e.tail = '\n'
181
 
            
182
 
        return e
183
 
 
184
 
 
185
 
    def from_element(cls, elt):
186
 
        assert elt.tag == 'entry'
187
 
 
188
 
        ## original format inventories don't have a parent_id for
189
 
        ## nodes in the root directory, but it's cleaner to use one
190
 
        ## internally.
191
 
        parent_id = elt.get('parent_id')
192
 
        if parent_id == None:
193
 
            parent_id = ROOT_ID
194
 
 
195
 
        self = cls(elt.get('file_id'), elt.get('name'), elt.get('kind'), parent_id)
196
 
        self.text_id = elt.get('text_id')
197
 
        self.text_sha1 = elt.get('text_sha1')
198
 
        
199
 
        ## mutter("read inventoryentry: %r" % (elt.attrib))
200
 
 
201
 
        v = elt.get('text_size')
202
 
        self.text_size = v and int(v)
203
 
 
204
 
        return self
205
 
            
206
 
 
207
 
    from_element = classmethod(from_element)
208
 
 
209
169
    def __eq__(self, other):
210
170
        if not isinstance(other, InventoryEntry):
211
171
            return NotImplemented
216
176
               and (self.text_size == other.text_size) \
217
177
               and (self.text_id == other.text_id) \
218
178
               and (self.parent_id == other.parent_id) \
219
 
               and (self.kind == other.kind)
 
179
               and (self.kind == other.kind) \
 
180
               and (self.text_version == other.text_version) \
 
181
               and (self.entry_version == other.entry_version)
220
182
 
221
183
 
222
184
    def __ne__(self, other):
263
225
 
264
226
    >>> inv = Inventory()
265
227
    >>> inv.add(InventoryEntry('123-123', 'hello.c', 'file', ROOT_ID))
 
228
    InventoryEntry('123-123', 'hello.c', kind='file', parent_id='TREE_ROOT')
266
229
    >>> inv['123-123'].name
267
230
    'hello.c'
268
231
 
279
242
    ['hello.c']
280
243
    >>> inv = Inventory('TREE_ROOT-12345678-12345678')
281
244
    >>> inv.add(InventoryEntry('123-123', 'hello.c', 'file', ROOT_ID))
 
245
    InventoryEntry('123-123', 'hello.c', kind='file', parent_id='TREE_ROOT-12345678-12345678')
282
246
    """
283
247
    def __init__(self, root_id=ROOT_ID):
284
248
        """Create or read an inventory.
366
330
 
367
331
        >>> inv = Inventory()
368
332
        >>> inv.add(InventoryEntry('123', 'foo.c', 'file', ROOT_ID))
 
333
        InventoryEntry('123', 'foo.c', kind='file', parent_id='TREE_ROOT')
369
334
        >>> '123' in inv
370
335
        True
371
336
        >>> '456' in inv
379
344
 
380
345
        >>> inv = Inventory()
381
346
        >>> inv.add(InventoryEntry('123123', 'hello.c', 'file', ROOT_ID))
 
347
        InventoryEntry('123123', 'hello.c', kind='file', parent_id='TREE_ROOT')
382
348
        >>> inv['123123'].name
383
349
        'hello.c'
384
350
        """
402
368
        """Add entry to inventory.
403
369
 
404
370
        To add  a file to a branch ready to be committed, use Branch.add,
405
 
        which calls this."""
 
371
        which calls this.
 
372
 
 
373
        Returns the new entry object.
 
374
        """
406
375
        if entry.file_id in self._byid:
407
376
            raise BzrError("inventory already contains entry with id {%s}" % entry.file_id)
408
377
 
420
389
 
421
390
        self._byid[entry.file_id] = entry
422
391
        parent.children[entry.name] = entry
 
392
        return entry
423
393
 
424
394
 
425
395
    def add_path(self, relpath, kind, file_id=None):
426
396
        """Add entry from a path.
427
397
 
428
 
        The immediate parent must already be versioned"""
429
 
        from bzrlib.errors import NotVersionedError
 
398
        The immediate parent must already be versioned.
 
399
 
 
400
        Returns the new entry object."""
 
401
        from bzrlib.branch import gen_file_id
430
402
        
431
403
        parts = bzrlib.osutils.splitpath(relpath)
432
404
        if len(parts) == 0:
433
405
            raise BzrError("cannot re-add root of inventory")
434
406
 
435
407
        if file_id == None:
436
 
            from bzrlib.branch import gen_file_id
437
408
            file_id = gen_file_id(relpath)
438
409
 
439
410
        parent_path = parts[:-1]
451
422
 
452
423
        >>> inv = Inventory()
453
424
        >>> inv.add(InventoryEntry('123', 'foo.c', 'file', ROOT_ID))
 
425
        InventoryEntry('123', 'foo.c', kind='file', parent_id='TREE_ROOT')
454
426
        >>> '123' in inv
455
427
        True
456
428
        >>> del inv['123']
472
444
        del self[ie.parent_id].children[ie.name]
473
445
 
474
446
 
475
 
    def to_element(self):
476
 
        """Convert to XML Element"""
477
 
        from bzrlib.xml import Element
478
 
        
479
 
        e = Element('inventory')
480
 
        e.text = '\n'
481
 
        if self.root.file_id not in (None, ROOT_ID):
482
 
            e.set('file_id', self.root.file_id)
483
 
        for path, ie in self.iter_entries():
484
 
            e.append(ie.to_element())
485
 
        return e
486
 
    
487
 
 
488
 
    def from_element(cls, elt):
489
 
        """Construct from XML Element
490
 
        
491
 
        >>> inv = Inventory()
492
 
        >>> inv.add(InventoryEntry('foo.c-123981239', 'foo.c', 'file', ROOT_ID))
493
 
        >>> elt = inv.to_element()
494
 
        >>> inv2 = Inventory.from_element(elt)
495
 
        >>> inv2 == inv
496
 
        True
497
 
        """
498
 
        # XXXX: doctest doesn't run this properly under python2.3
499
 
        assert elt.tag == 'inventory'
500
 
        root_id = elt.get('file_id') or ROOT_ID
501
 
        o = cls(root_id)
502
 
        for e in elt:
503
 
            ie = InventoryEntry.from_element(e)
504
 
            if ie.parent_id == ROOT_ID:
505
 
                ie.parent_id = root_id
506
 
            o.add(ie)
507
 
        return o
508
 
        
509
 
    from_element = classmethod(from_element)
510
 
 
511
 
 
512
447
    def __eq__(self, other):
513
448
        """Compare two sets by comparing their contents.
514
449
 
517
452
        >>> i1 == i2
518
453
        True
519
454
        >>> i1.add(InventoryEntry('123', 'foo', 'file', ROOT_ID))
 
455
        InventoryEntry('123', 'foo', kind='file', parent_id='TREE_ROOT')
520
456
        >>> i1 == i2
521
457
        False
522
458
        >>> i2.add(InventoryEntry('123', 'foo', 'file', ROOT_ID))
 
459
        InventoryEntry('123', 'foo', kind='file', parent_id='TREE_ROOT')
523
460
        >>> i1 == i2
524
461
        True
525
462
        """
541
478
        raise ValueError('not hashable')
542
479
 
543
480
 
544
 
 
545
481
    def get_idpath(self, file_id):
546
482
        """Return a list of file_ids for the path to an entry.
547
483
 
640
576
 
641
577
 
642
578
 
643
 
_NAME_RE = re.compile(r'^[^/\\]+$')
 
579
_NAME_RE = None
644
580
 
645
581
def is_valid_name(name):
 
582
    global _NAME_RE
 
583
    if _NAME_RE == None:
 
584
        _NAME_RE = re.compile(r'^[^/\\]+$')
 
585
        
646
586
    return bool(_NAME_RE.match(name))