~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: 2006-03-20 10:33:11 UTC
  • mfrom: (1615.1.2 bzr.mbp.integration)
  • Revision ID: pqm@pqm.ubuntu.com-20060320103311-a87ccd7ffe9ce14f
(mbp) pycurl bugfixes, robert's knit performance stuff

Show diffs side-by-side

added added

removed removed

Lines of Context:
119
119
                 'revision']
120
120
 
121
121
    def _add_text_to_weave(self, new_lines, parents, weave_store, transaction):
122
 
        versionedfile = weave_store.get_weave(self.file_id, transaction)
 
122
        versionedfile = weave_store.get_weave_or_empty(self.file_id,
 
123
                                                       transaction)
123
124
        versionedfile.add_lines(self.revision, parents, new_lines)
124
125
 
125
126
    def detect_changes(self, old_entry):
151
152
             output_to, reverse=False):
152
153
        """Perform a diff between two entries of the same kind."""
153
154
 
154
 
    def find_previous_heads(self, previous_inventories, entry_weave):
 
155
    def find_previous_heads(self, previous_inventories,
 
156
                            versioned_file_store,
 
157
                            transaction,
 
158
                            entry_vf=None):
155
159
        """Return the revisions and entries that directly preceed this.
156
160
 
157
161
        Returned as a map from revision to inventory entry.
159
163
        This is a map containing the file revisions in all parents
160
164
        for which the file exists, and its revision is not a parent of
161
165
        any other. If the file is new, the set will be empty.
 
166
 
 
167
        :param versioned_file_store: A store where ancestry data on this
 
168
                                     file id can be queried.
 
169
        :param transaction: The transaction that queries to the versioned 
 
170
                            file store should be completed under.
 
171
        :param entry_vf: The entry versioned file, if its already available.
162
172
        """
163
173
        def get_ancestors(weave, entry):
164
174
            return set(weave.get_ancestry(entry.revision))
 
175
        # revision:ie mapping for each ie found in previous_inventories.
 
176
        candidates = {}
 
177
        # revision:ie mapping with one revision for each head.
165
178
        heads = {}
 
179
        # revision: ancestor list for each head
166
180
        head_ancestors = {}
 
181
        # identify candidate head revision ids.
167
182
        for inv in previous_inventories:
168
183
            if self.file_id in inv:
169
184
                ie = inv[self.file_id]
170
185
                assert ie.file_id == self.file_id
171
 
                if ie.revision in heads:
172
 
                    # fixup logic, there was a bug in revision updates.
173
 
                    # with x bit support.
 
186
                if ie.revision in candidates:
 
187
                    # same revision value in two different inventories:
 
188
                    # correct possible inconsistencies:
 
189
                    #     * there was a bug in revision updates with 'x' bit 
 
190
                    #       support.
174
191
                    try:
175
 
                        if heads[ie.revision].executable != ie.executable:
176
 
                            heads[ie.revision].executable = False
 
192
                        if candidates[ie.revision].executable != ie.executable:
 
193
                            candidates[ie.revision].executable = False
177
194
                            ie.executable = False
178
195
                    except AttributeError:
179
196
                        pass
180
 
                    assert heads[ie.revision] == ie
 
197
                    # must now be the same.
 
198
                    assert candidates[ie.revision] == ie
181
199
                else:
182
 
                    # may want to add it.
183
 
                    # may already be covered:
184
 
                    already_present = 0 != len(
185
 
                        [head for head in heads 
186
 
                         if ie.revision in head_ancestors[head]])
187
 
                    if already_present:
188
 
                        # an ancestor of a known head.
189
 
                        continue
190
 
                    # definately a head:
191
 
                    ancestors = get_ancestors(entry_weave, ie)
192
 
                    # may knock something else out:
193
 
                    check_heads = list(heads.keys())
194
 
                    for head in check_heads:
195
 
                        if head in ancestors:
196
 
                            # this head is not really a head
197
 
                            heads.pop(head)
198
 
                    head_ancestors[ie.revision] = ancestors
199
 
                    heads[ie.revision] = ie
 
200
                    # add this revision as a candidate.
 
201
                    candidates[ie.revision] = ie
 
202
 
 
203
        # common case optimisation
 
204
        if len(candidates) == 1:
 
205
            # if there is only one candidate revision found
 
206
            # then we can opening the versioned file to access ancestry:
 
207
            # there cannot be any ancestors to eliminate when there is 
 
208
            # only one revision available.
 
209
            heads[ie.revision] = ie
 
210
            return heads
 
211
 
 
212
        # eliminate ancestors amongst the available candidates:
 
213
        # heads are those that are not an ancestor of any other candidate
 
214
        # - this provides convergence at a per-file level.
 
215
        for ie in candidates.values():
 
216
            # may be an ancestor of a known head:
 
217
            already_present = 0 != len(
 
218
                [head for head in heads 
 
219
                 if ie.revision in head_ancestors[head]])
 
220
            if already_present:
 
221
                # an ancestor of an analyzed candidate.
 
222
                continue
 
223
            # not an ancestor of a known head:
 
224
            # load the versioned file for this file id if needed
 
225
            if entry_vf is None:
 
226
                entry_vf = versioned_file_store.get_weave_or_empty(
 
227
                    self.file_id, transaction)
 
228
            ancestors = get_ancestors(entry_vf, ie)
 
229
            # may knock something else out:
 
230
            check_heads = list(heads.keys())
 
231
            for head in check_heads:
 
232
                if head in ancestors:
 
233
                    # this previously discovered 'head' is not
 
234
                    # really a head - its an ancestor of the newly 
 
235
                    # found head,
 
236
                    heads.pop(head)
 
237
            head_ancestors[ie.revision] = ancestors
 
238
            heads[ie.revision] = ie
200
239
        return heads
201
240
 
202
241
    def get_tar_item(self, root, dp, now, tree):
980
1019
    def __hash__(self):
981
1020
        raise ValueError('not hashable')
982
1021
 
 
1022
    def _iter_file_id_parents(self, file_id):
 
1023
        """Yield the parents of file_id up to the root."""
 
1024
        while file_id != None:
 
1025
            try:
 
1026
                ie = self._byid[file_id]
 
1027
            except KeyError:
 
1028
                raise BzrError("file_id {%s} not found in inventory" % file_id)
 
1029
            yield ie
 
1030
            file_id = ie.parent_id
983
1031
 
984
1032
    def get_idpath(self, file_id):
985
1033
        """Return a list of file_ids for the path to an entry.
990
1038
        root directory as depth 1.
991
1039
        """
992
1040
        p = []
993
 
        while file_id != None:
994
 
            try:
995
 
                ie = self._byid[file_id]
996
 
            except KeyError:
997
 
                raise BzrError("file_id {%s} not found in inventory" % file_id)
998
 
            p.insert(0, ie.file_id)
999
 
            file_id = ie.parent_id
 
1041
        for parent in self._iter_file_id_parents(file_id):
 
1042
            p.insert(0, parent.file_id)
1000
1043
        return p
1001
1044
 
1002
 
 
1003
1045
    def id2path(self, file_id):
1004
 
        """Return as a list the path to file_id.
 
1046
        """Return as a string the path to file_id.
1005
1047
        
1006
1048
        >>> i = Inventory()
1007
1049
        >>> e = i.add(InventoryDirectory('src-id', 'src', ROOT_ID))
1010
1052
        src/foo.c
1011
1053
        """
1012
1054
        # get all names, skipping root
1013
 
        p = [self._byid[fid].name for fid in self.get_idpath(file_id)[1:]]
1014
 
        if p:
1015
 
            return pathjoin(*p)
1016
 
        else:
1017
 
            return ''
 
1055
        return '/'.join(reversed(
 
1056
            [parent.name for parent in 
 
1057
             self._iter_file_id_parents(file_id)][:-1]))
1018
1058
            
1019
 
 
1020
 
 
1021
1059
    def path2id(self, name):
1022
1060
        """Walk down through directories to return entry of last component.
1023
1061