~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transform.py

  • Committer: Vincent Ladeuil
  • Date: 2011-06-27 15:42:09 UTC
  • mfrom: (5993 +trunk)
  • mto: (5993.1.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 5994.
  • Revision ID: v.ladeuil+lp@free.fr-20110627154209-azubuhbuxsz109hq
Merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
137
137
        # A counter of how many files have been renamed
138
138
        self.rename_count = 0
139
139
 
 
140
    def __enter__(self):
 
141
        """Support Context Manager API."""
 
142
        return self
 
143
 
 
144
    def __exit__(self, exc_type, exc_val, exc_tb):
 
145
        """Support Context Manager API."""
 
146
        self.finalize()
 
147
 
140
148
    def finalize(self):
141
149
        """Release the working tree lock, if held.
142
150
 
244
252
        if (self.tree_file_id(self._new_root) is not None and
245
253
            self._new_root not in self._removed_id):
246
254
            self.unversion_file(self._new_root)
247
 
        self.version_file(file_id, self._new_root)
 
255
        if file_id is not None:
 
256
            self.version_file(file_id, self._new_root)
248
257
 
249
258
        # Now move children of new root into old root directory.
250
259
        # Ensure all children are registered with the transaction, but don't
384
393
        return sorted(FinalPaths(self).get_paths(new_ids))
385
394
 
386
395
    def _inventory_altered(self):
387
 
        """Get the trans_ids and paths of files needing new inv entries."""
388
 
        new_ids = set()
389
 
        for id_set in [self._new_name, self._new_parent, self._new_id,
 
396
        """Determine which trans_ids need new Inventory entries.
 
397
 
 
398
        An new entry is needed when anything that would be reflected by an
 
399
        inventory entry changes, including file name, file_id, parent file_id,
 
400
        file kind, and the execute bit.
 
401
 
 
402
        Some care is taken to return entries with real changes, not cases
 
403
        where the value is deleted and then restored to its original value,
 
404
        but some actually unchanged values may be returned.
 
405
 
 
406
        :returns: A list of (path, trans_id) for all items requiring an
 
407
            inventory change. Ordered by path.
 
408
        """
 
409
        changed_ids = set()
 
410
        # Find entries whose file_ids are new (or changed).
 
411
        new_file_id = set(t for t in self._new_id
 
412
                          if self._new_id[t] != self.tree_file_id(t))
 
413
        for id_set in [self._new_name, self._new_parent, new_file_id,
390
414
                       self._new_executability]:
391
 
            new_ids.update(id_set)
 
415
            changed_ids.update(id_set)
 
416
        # removing implies a kind change
392
417
        changed_kind = set(self._removed_contents)
 
418
        # so does adding
393
419
        changed_kind.intersection_update(self._new_contents)
394
 
        changed_kind.difference_update(new_ids)
 
420
        # Ignore entries that are already known to have changed.
 
421
        changed_kind.difference_update(changed_ids)
 
422
        #  to keep only the truly changed ones
395
423
        changed_kind = (t for t in changed_kind
396
424
                        if self.tree_kind(t) != self.final_kind(t))
397
 
        new_ids.update(changed_kind)
398
 
        return sorted(FinalPaths(self).get_paths(new_ids))
 
425
        # all kind changes will alter the inventory
 
426
        changed_ids.update(changed_kind)
 
427
        # To find entries with changed parent_ids, find parents which existed,
 
428
        # but changed file_id.
 
429
        changed_file_id = set(t for t in new_file_id if t in self._removed_id)
 
430
        # Now add all their children to the set.
 
431
        for parent_trans_id in new_file_id:
 
432
            changed_ids.update(self.iter_tree_children(parent_trans_id))
 
433
        return sorted(FinalPaths(self).get_paths(changed_ids))
399
434
 
400
435
    def final_kind(self, trans_id):
401
436
        """Determine the final file kind, after any changes applied.
1154
1189
        self._deletiondir = None
1155
1190
        # A mapping of transform ids to their limbo filename
1156
1191
        self._limbo_files = {}
 
1192
        self._possibly_stale_limbo_files = set()
1157
1193
        # A mapping of transform ids to a set of the transform ids of children
1158
1194
        # that their limbo directory has
1159
1195
        self._limbo_children = {}
1172
1208
        if self._tree is None:
1173
1209
            return
1174
1210
        try:
1175
 
            entries = [(self._limbo_name(t), t, k) for t, k in
1176
 
                       self._new_contents.iteritems()]
1177
 
            entries.sort(reverse=True)
1178
 
            for path, trans_id, kind in entries:
1179
 
                delete_any(path)
 
1211
            limbo_paths = self._limbo_files.values() + list(
 
1212
                self._possibly_stale_limbo_files)
 
1213
            limbo_paths = sorted(limbo_paths, reverse=True)
 
1214
            for path in limbo_paths:
 
1215
                try:
 
1216
                    delete_any(path)
 
1217
                except OSError, e:
 
1218
                    if e.errno != errno.ENOENT:
 
1219
                        raise
 
1220
                    # XXX: warn? perhaps we just got interrupted at an
 
1221
                    # inconvenient moment, but perhaps files are disappearing
 
1222
                    # from under us?
1180
1223
            try:
1181
1224
                delete_any(self._limbodir)
1182
1225
            except OSError:
1231
1274
        entries from _limbo_files, because they are now stale.
1232
1275
        """
1233
1276
        for trans_id in trans_ids:
1234
 
            old_path = self._limbo_files.pop(trans_id)
 
1277
            old_path = self._limbo_files[trans_id]
 
1278
            self._possibly_stale_limbo_files.add(old_path)
 
1279
            del self._limbo_files[trans_id]
1235
1280
            if trans_id not in self._new_contents:
1236
1281
                continue
1237
1282
            new_path = self._limbo_name(trans_id)
1238
1283
            os.rename(old_path, new_path)
 
1284
            self._possibly_stale_limbo_files.remove(old_path)
1239
1285
            for descendant in self._limbo_descendants(trans_id):
1240
1286
                desc_path = self._limbo_files[descendant]
1241
1287
                desc_path = new_path + desc_path[len(old_path):]
1265
1311
        name = self._limbo_name(trans_id)
1266
1312
        f = open(name, 'wb')
1267
1313
        try:
1268
 
            try:
1269
 
                unique_add(self._new_contents, trans_id, 'file')
1270
 
            except:
1271
 
                # Clean up the file, it never got registered so
1272
 
                # TreeTransform.finalize() won't clean it up.
1273
 
                f.close()
1274
 
                os.unlink(name)
1275
 
                raise
 
1314
            unique_add(self._new_contents, trans_id, 'file')
1276
1315
            f.writelines(contents)
1277
1316
        finally:
1278
1317
            f.close()
1788
1827
        tree_paths.sort(reverse=True)
1789
1828
        child_pb = ui.ui_factory.nested_progress_bar()
1790
1829
        try:
1791
 
            for num, data in enumerate(tree_paths):
1792
 
                path, trans_id = data
 
1830
            for num, (path, trans_id) in enumerate(tree_paths):
 
1831
                # do not attempt to move root into a subdirectory of itself.
 
1832
                if path == '':
 
1833
                    continue
1793
1834
                child_pb.update('removing file', num, len(tree_paths))
1794
1835
                full_path = self._tree.abspath(path)
1795
1836
                if trans_id in self._removed_contents:
1851
1892
                    self._observed_sha1s[trans_id] = (o_sha1, st)
1852
1893
        finally:
1853
1894
            child_pb.finished()
 
1895
        for path, trans_id in new_paths:
 
1896
            # new_paths includes stuff like workingtree conflicts. Only the
 
1897
            # stuff in new_contents actually comes from limbo.
 
1898
            if trans_id in self._limbo_files:
 
1899
                del self._limbo_files[trans_id]
1854
1900
        self._new_contents.clear()
1855
1901
        return modified_paths
1856
1902