~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/inventory.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-02-23 17:00:36 UTC
  • mfrom: (4032.1.4 jam-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20090223170036-3q1v68ewdt8i0to5
(Marius Kruger) Remove all trailing whitespace and add tests to
        enforce this.

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
 
# FIXME: This refactoring of the workingtree code doesn't seem to keep 
 
17
# FIXME: This refactoring of the workingtree code doesn't seem to keep
18
18
# the WorkingTree's copy of the inventory in sync with the branch.  The
19
19
# branch modifies its working inventory when it does a commit to make
20
20
# missing files permanently removed.
69
69
        file_id of the parent directory, or ROOT_ID
70
70
 
71
71
    revision
72
 
        the revision_id in which this variation of this file was 
 
72
        the revision_id in which this variation of this file was
73
73
        introduced.
74
74
 
75
75
    executable
78
78
 
79
79
    text_sha1
80
80
        sha-1 of the text of the file
81
 
        
 
81
 
82
82
    text_size
83
83
        size in bytes of the text of the file
84
 
        
 
84
 
85
85
    (reading a version 4 tree created a text_id field.)
86
86
 
87
87
    >>> i = Inventory()
94
94
    >>> shouldbe = {0: '', 1: 'src', 2: 'src/hello.c'}
95
95
    >>> for ix, j in enumerate(i.iter_entries()):
96
96
    ...   print (j[0] == shouldbe[ix], j[1])
97
 
    ... 
 
97
    ...
98
98
    (True, InventoryDirectory('TREE_ROOT', u'', parent_id=None, revision=None))
99
99
    (True, InventoryDirectory('123', 'src', parent_id='TREE_ROOT', revision=None))
100
100
    (True, InventoryFile('2323', 'hello.c', parent_id='123', sha1=None, len=None))
112
112
    InventoryFile('2326', 'wibble.c', parent_id='2325', sha1=None, len=None)
113
113
    >>> for path, entry in i.iter_entries():
114
114
    ...     print path
115
 
    ... 
 
115
    ...
116
116
    <BLANKLINE>
117
117
    src
118
118
    src/bye.c
125
125
 
126
126
    # Constants returned by describe_change()
127
127
    #
128
 
    # TODO: These should probably move to some kind of FileChangeDescription 
129
 
    # class; that's like what's inside a TreeDelta but we want to be able to 
 
128
    # TODO: These should probably move to some kind of FileChangeDescription
 
129
    # class; that's like what's inside a TreeDelta but we want to be able to
130
130
    # generate them just for one file at a time.
131
131
    RENAMED = 'renamed'
132
132
    MODIFIED_AND_RENAMED = 'modified and renamed'
133
 
    
 
133
 
134
134
    __slots__ = []
135
135
 
136
136
    def detect_changes(self, old_entry):
137
137
        """Return a (text_modified, meta_modified) from this to old_entry.
138
 
        
139
 
        _read_tree_state must have been called on self and old_entry prior to 
 
138
 
 
139
        _read_tree_state must have been called on self and old_entry prior to
140
140
        calling detect_changes.
141
141
        """
142
142
        return False, False
144
144
    def _diff(self, text_diff, from_label, tree, to_label, to_entry, to_tree,
145
145
             output_to, reverse=False):
146
146
        """Perform a diff between two entries of the same kind."""
147
 
    
 
147
 
148
148
    def parent_candidates(self, previous_inventories):
149
149
        """Find possible per-file graph parents.
150
150
 
163
163
                if ie.revision in candidates:
164
164
                    # same revision value in two different inventories:
165
165
                    # correct possible inconsistencies:
166
 
                    #     * there was a bug in revision updates with 'x' bit 
 
166
                    #     * there was a bug in revision updates with 'x' bit
167
167
                    #       support.
168
168
                    try:
169
169
                        if candidates[ie.revision].executable != ie.executable:
199
199
 
200
200
    def __init__(self, file_id, name, parent_id, text_id=None):
201
201
        """Create an InventoryEntry
202
 
        
 
202
 
203
203
        The filename must be a single component, relative to the
204
204
        parent directory; it cannot be a whole path or relative name.
205
205
 
242
242
    @deprecated_method(deprecated_in((1, 6, 0)))
243
243
    def put_on_disk(self, dest, dp, tree):
244
244
        """Create a representation of self on disk in the prefix dest.
245
 
        
 
245
 
246
246
        This is a template method - implement _put_on_disk in subclasses.
247
247
        """
248
248
        fullpath = osutils.pathjoin(dest, dp)
267
267
        This is a template method, override _check for kind specific
268
268
        tests.
269
269
 
270
 
        :param checker: Check object providing context for the checks; 
 
270
        :param checker: Check object providing context for the checks;
271
271
             can be used to find out what parts of the repository have already
272
272
             been checked.
273
273
        :param rev_id: Revision id from which this InventoryEntry was loaded.
283
283
 
284
284
    def _check(self, checker, rev_id, tree):
285
285
        """Check this inventory entry for kind specific errors."""
286
 
        raise BzrCheckError('unknown entry kind %r in revision {%s}' % 
 
286
        raise BzrCheckError('unknown entry kind %r in revision {%s}' %
287
287
                            (self.kind, rev_id))
288
288
 
289
289
    def copy(self):
293
293
    @staticmethod
294
294
    def describe_change(old_entry, new_entry):
295
295
        """Describe the change between old_entry and this.
296
 
        
 
296
 
297
297
        This smells of being an InterInventoryEntry situation, but as its
298
298
        the first one, we're making it a static method for now.
299
299
 
300
 
        An entry with a different parent, or different name is considered 
 
300
        An entry with a different parent, or different name is considered
301
301
        to be renamed. Reparenting is an internal detail.
302
302
        Note that renaming the parent does not trigger a rename for the
303
303
        child entry itself.
384
384
 
385
385
    def _read_tree_state(self, path, work_tree):
386
386
        """Populate fields in the inventory entry from the given tree.
387
 
        
 
387
 
388
388
        Note that this should be modified to be a noop on virtual trees
389
389
        as all entries created there are prepopulated.
390
390
        """
391
 
        # TODO: Rather than running this manually, we should check the 
 
391
        # TODO: Rather than running this manually, we should check the
392
392
        # working sha1 and other expensive properties when they're
393
393
        # first requested, or preload them if they're already known
394
394
        pass            # nothing to do by default
420
420
    def __eq__(self, other):
421
421
        if not isinstance(other, RootEntry):
422
422
            return NotImplemented
423
 
        
 
423
 
424
424
        return (self.file_id == other.file_id) \
425
425
               and (self.children == other.children)
426
426
 
682
682
 
683
683
 
684
684
class TreeReference(InventoryEntry):
685
 
    
 
685
 
686
686
    kind = 'tree-reference'
687
 
    
 
687
 
688
688
    def __init__(self, file_id, name, parent_id, revision=None,
689
689
                 reference_revision=None):
690
690
        InventoryEntry.__init__(self, file_id, name, parent_id)
702
702
            self.file_id, path)
703
703
 
704
704
    def _forget_tree_state(self):
705
 
        self.reference_revision = None 
 
705
        self.reference_revision = None
706
706
 
707
707
    def _unchanged(self, previous_ie):
708
708
        """See InventoryEntry._unchanged."""
736
736
    'hello.c'
737
737
 
738
738
    May be treated as an iterator or set to look up file ids:
739
 
    
 
739
 
740
740
    >>> bool(inv.path2id('hello.c'))
741
741
    True
742
742
    >>> '123-123' in inv
785
785
 
786
786
            Each change is a tuple, of the form (old_path, new_path, file_id,
787
787
            new_entry).
788
 
            
 
788
 
789
789
            When new_path is None, the change indicates the removal of an entry
790
790
            from the inventory and new_entry will be ignored (using None is
791
791
            appropriate). If new_path is not None, then new_entry must be an
792
792
            InventoryEntry instance, which will be incorporated into the
793
793
            inventory (and replace any existing entry with the same file id).
794
 
            
 
794
 
795
795
            When old_path is None, the change indicates the addition of
796
796
            a new entry to the inventory.
797
 
            
 
797
 
798
798
            When neither new_path nor old_path are None, the change is a
799
799
            modification to an entry, such as a rename, reparent, kind change
800
 
            etc. 
 
800
            etc.
801
801
 
802
802
            The children attribute of new_entry is ignored. This is because
803
803
            this method preserves children automatically across alterations to
876
876
            yield '', self.root
877
877
        elif isinstance(from_dir, basestring):
878
878
            from_dir = self._byid[from_dir]
879
 
            
 
879
 
880
880
        # unrolling the recursive called changed the time from
881
881
        # 440ms/663ms (inline/total) to 116ms/116ms
882
882
        children = from_dir.children.items()
938
938
                file_id = list(specific_file_ids)[0]
939
939
                if file_id in self:
940
940
                    yield self.id2path(file_id), self[file_id]
941
 
                return 
 
941
                return
942
942
            from_dir = self.root
943
943
            if (specific_file_ids is None or yield_parents or
944
944
                self.root.file_id in specific_file_ids):
964
964
                add_ancestors(file_id)
965
965
        else:
966
966
            parents = None
967
 
            
 
967
 
968
968
        stack = [(u'', from_dir)]
969
969
        while stack:
970
970
            cur_relpath, cur_dir = stack.pop()
974
974
 
975
975
                child_relpath = cur_relpath + child_name
976
976
 
977
 
                if (specific_file_ids is None or 
 
977
                if (specific_file_ids is None or
978
978
                    child_ie.file_id in specific_file_ids or
979
979
                    (yield_parents and child_ie.file_id in parents)):
980
980
                    yield child_relpath, child_ie
1012
1012
        accum = []
1013
1013
        def descend(parent_ie, parent_path):
1014
1014
            accum.append((parent_path, parent_ie))
1015
 
            
 
1015
 
1016
1016
            kids = [(ie.name, ie) for ie in parent_ie.children.itervalues() if ie.kind == 'directory']
1017
1017
            kids.sort()
1018
1018
 
1021
1021
                descend(child_ie, child_path)
1022
1022
        descend(self.root, u'')
1023
1023
        return accum
1024
 
        
 
1024
 
1025
1025
    def __contains__(self, file_id):
1026
1026
        """True if this entry contains a file with given id.
1027
1027
 
1100
1100
        The immediate parent must already be versioned.
1101
1101
 
1102
1102
        Returns the new entry object."""
1103
 
        
 
1103
 
1104
1104
        parts = osutils.splitpath(relpath)
1105
1105
 
1106
1106
        if len(parts) == 0:
1186
1186
 
1187
1187
    def id2path(self, file_id):
1188
1188
        """Return as a string the path to file_id.
1189
 
        
 
1189
 
1190
1190
        >>> i = Inventory()
1191
1191
        >>> e = i.add(InventoryDirectory('src-id', 'src', ROOT_ID))
1192
1192
        >>> e = i.add(InventoryFile('foo-id', 'foo.c', parent_id='src-id'))
1195
1195
        """
1196
1196
        # get all names, skipping root
1197
1197
        return '/'.join(reversed(
1198
 
            [parent.name for parent in 
 
1198
            [parent.name for parent in
1199
1199
             self._iter_file_id_parents(file_id)][:-1]))
1200
 
            
 
1200
 
1201
1201
    def path2id(self, name):
1202
1202
        """Walk down through directories to return entry of last component.
1203
1203
 
1314
1314
 
1315
1315
        del old_parent.children[file_ie.name]
1316
1316
        new_parent.children[new_name] = file_ie
1317
 
        
 
1317
 
1318
1318
        file_ie.name = new_name
1319
1319
        file_ie.parent_id = new_parent_id
1320
1320
 
1375
1375
    global _NAME_RE
1376
1376
    if _NAME_RE is None:
1377
1377
        _NAME_RE = re.compile(r'^[^/\\]+$')
1378
 
        
 
1378
 
1379
1379
    return bool(_NAME_RE.match(name))