~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/inventory.py

  • Committer: mbp at sourcefrog
  • Date: 2005-03-28 02:49:46 UTC
  • Revision ID: mbp@sourcefrog.net-20050328024945-d80f4adc5dfaa9a1
More help for check command

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# (C) 2005 Canonical Ltd
 
1
#! /usr/bin/env python
 
2
# -*- coding: UTF-8 -*-
2
3
 
3
4
# This program is free software; you can redistribute it and/or modify
4
5
# it under the terms of the GNU General Public License as published by
16
17
 
17
18
"""Inventories map files to their name in a revision."""
18
19
 
19
 
# TODO: Maybe store inventory_id in the file?  Not really needed.
20
20
 
21
21
__copyright__ = "Copyright (C) 2005 Canonical Ltd."
22
22
__author__ = "Martin Pool <mbp@canonical.com>"
124
124
        self.parent_id = parent_id
125
125
        self.text_sha1 = None
126
126
        self.text_size = None
127
 
        if kind == 'directory':
128
 
            self.children = {}
129
127
 
130
128
 
131
129
    def copy(self):
226
224
    >>> inv.add(InventoryEntry('123-123', 'hello.c'))
227
225
    >>> inv['123-123'].name
228
226
    'hello.c'
 
227
    >>> for file_id in inv: print file_id
 
228
    ...
 
229
    123-123
229
230
 
230
231
    May be treated as an iterator or set to look up file ids:
231
232
    
246
247
 
247
248
    """
248
249
 
 
250
    ## TODO: Clear up handling of files in subdirectories; we probably
 
251
    ## do want to be able to just look them up by name but this
 
252
    ## probably means gradually walking down the path, looking up as we go.
 
253
 
249
254
    ## TODO: Make sure only canonical filenames are stored.
250
255
 
251
256
    ## TODO: Do something sensible about the possible collisions on
252
257
    ## case-losing filesystems.  Perhaps we should just always forbid
253
258
    ## such collisions.
254
259
 
255
 
    ## TODO: No special cases for root, rather just give it a file id
256
 
    ## like everything else.
257
 
 
258
 
    ## TODO: Probably change XML serialization to use nesting
 
260
    ## _tree should probably just be stored as
 
261
    ## InventoryEntry._children on each directory.
259
262
 
260
263
    def __init__(self):
261
264
        """Create or read an inventory.
264
267
        from there.  If the file is specified, read from that. If not,
265
268
        the inventory is created empty.
266
269
        """
267
 
        self._root = InventoryEntry(None, '', kind='directory')
268
 
        self._byid = {None: self._root}
 
270
        self._byid = dict()
 
271
 
 
272
        # _tree is indexed by parent_id; at each level a map from name
 
273
        # to ie.  The None entry is the root.
 
274
        self._tree = {None: {}}
269
275
 
270
276
 
271
277
    def __iter__(self):
279
285
 
280
286
    def iter_entries(self, parent_id=None):
281
287
        """Return (path, entry) pairs, in order by name."""
282
 
        kids = self[parent_id].children.items()
 
288
        kids = self._tree[parent_id].items()
283
289
        kids.sort()
284
290
        for name, ie in kids:
285
291
            yield name, ie
299
305
        
300
306
 
301
307
 
 
308
    def children(self, parent_id):
 
309
        """Return entries that are direct children of parent_id."""
 
310
        return self._tree[parent_id]
 
311
                    
 
312
 
 
313
 
 
314
    # TODO: return all paths and entries
 
315
 
 
316
 
302
317
    def __contains__(self, file_id):
303
318
        """True if this entry contains a file with given id.
304
319
 
323
338
        return self._byid[file_id]
324
339
 
325
340
 
326
 
    def get_child(self, parent_id, filename):
327
 
        if parent_id == None:
328
 
            return self._root.children.get(filename)
329
 
        else:
330
 
            return self[parent_id].children.get(filename)
331
 
 
332
 
 
333
341
    def add(self, entry):
334
342
        """Add entry to inventory.
335
343
 
336
344
        To add  a file to a branch ready to be committed, use Branch.add,
337
345
        which calls this."""
338
 
        if entry.file_id in self._byid:
 
346
        if entry.file_id in self:
339
347
            bailout("inventory already contains entry with id {%s}" % entry.file_id)
340
348
 
341
 
        parent = self._byid[entry.parent_id]
342
 
        if parent.kind != 'directory':
343
 
            bailout("attempt to add under non-directory {%s}" % parent.file_id)
344
 
 
345
 
        if parent.children.has_key(entry.name):
346
 
            bailout("%s is already versioned" %
347
 
                    appendpath(self.id2path(parent.file_id), entry.name))
 
349
        if entry.parent_id != None:
 
350
            if entry.parent_id not in self:
 
351
                bailout("parent_id %s of new entry not found in inventory"
 
352
                        % entry.parent_id)
 
353
            
 
354
        if self._tree[entry.parent_id].has_key(entry.name):
 
355
            bailout("%s is already versioned"
 
356
                    % appendpath(self.id2path(entry.parent_id), entry.name))
348
357
 
349
358
        self._byid[entry.file_id] = entry
350
 
        parent.children[entry.name] = entry
 
359
        self._tree[entry.parent_id][entry.name] = entry
 
360
 
 
361
        if entry.kind == 'directory':
 
362
            self._tree[entry.file_id] = {}
351
363
 
352
364
 
353
365
    def add_path(self, relpath, kind, file_id=None):
380
392
        """
381
393
        ie = self[file_id]
382
394
 
383
 
        assert self[ie.parent_id].children[ie.name] == ie
 
395
        assert self._tree[ie.parent_id][ie.name] == ie
384
396
        
385
397
        # TODO: Test deleting all children; maybe hoist to a separate
386
398
        # deltree method?
387
399
        if ie.kind == 'directory':
388
 
            for cie in ie.children.values():
 
400
            for cie in self._tree[file_id].values():
389
401
                del self[cie.file_id]
390
 
            del ie.children
 
402
            del self._tree[file_id]
391
403
 
392
404
        del self._byid[file_id]
393
 
        del self[ie.parent_id].children[ie.name]
 
405
        del self._tree[ie.parent_id][ie.name]
394
406
 
395
407
 
396
408
    def id_set(self):
478
490
        if isinstance(name, types.StringTypes):
479
491
            name = splitpath(name)
480
492
 
481
 
        parent = self[None]
 
493
        parent_id = None
482
494
        for f in name:
483
495
            try:
484
 
                cie = parent.children[f]
 
496
                cie = self._tree[parent_id][f]
485
497
                assert cie.name == f
486
 
                parent = cie
 
498
                parent_id = cie.file_id
487
499
            except KeyError:
488
500
                # or raise an error?
489
501
                return None
490
502
 
491
 
        return parent.file_id
 
503
        return parent_id
 
504
 
 
505
 
 
506
    def get_child(self, parent_id, child_name):
 
507
        return self._tree[parent_id].get(child_name)
492
508
 
493
509
 
494
510
    def has_filename(self, names):