~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transform.py

  • Committer: John Arbash Meinel
  • Date: 2010-01-12 21:08:30 UTC
  • mfrom: (4634.119.4 2.0)
  • mto: This revision was merged to the branch mainline in revision 4954.
  • Revision ID: john@arbash-meinel.com-20100112210830-met16yivsvxb5i0u
Merge bzr.stable, including the bugfix for #494269

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007, 2008, 2009 Canonical Ltd
 
1
# Copyright (C) 2006, 2007, 2008, 2009, 2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
162
162
 
163
163
    def adjust_path(self, name, parent, trans_id):
164
164
        """Change the path that is assigned to a transaction id."""
 
165
        if parent is None:
 
166
            raise ValueError("Parent trans-id may not be None")
165
167
        if trans_id == self._new_root:
166
168
            raise CantMoveRoot
167
169
        self._new_name[trans_id] = name
168
170
        self._new_parent[trans_id] = parent
169
 
        if parent == ROOT_PARENT:
170
 
            if self._new_root is not None:
171
 
                raise ValueError("Cannot have multiple roots.")
172
 
            self._new_root = trans_id
173
171
 
174
172
    def adjust_root_path(self, name, parent):
175
173
        """Emulate moving the root by moving all children, instead.
203
201
        self.version_file(old_root_file_id, old_root)
204
202
        self.unversion_file(self._new_root)
205
203
 
 
204
    def fixup_new_roots(self):
 
205
        """Reinterpret requests to change the root directory
 
206
 
 
207
        Instead of creating a root directory, or moving an existing directory,
 
208
        all the attributes and children of the new root are applied to the
 
209
        existing root directory.
 
210
 
 
211
        This means that the old root trans-id becomes obsolete, so it is
 
212
        recommended only to invoke this after the root trans-id has become
 
213
        irrelevant.
 
214
        """
 
215
        new_roots = [k for k, v in self._new_parent.iteritems() if v is
 
216
                     ROOT_PARENT]
 
217
        if len(new_roots) < 1:
 
218
            return
 
219
        if len(new_roots) != 1:
 
220
            raise ValueError('A tree cannot have two roots!')
 
221
        if self._new_root is None:
 
222
            self._new_root = new_roots[0]
 
223
            return
 
224
        old_new_root = new_roots[0]
 
225
        # TODO: What to do if a old_new_root is present, but self._new_root is
 
226
        #       not listed as being removed? This code explicitly unversions
 
227
        #       the old root and versions it with the new file_id. Though that
 
228
        #       seems like an incomplete delta
 
229
 
 
230
        # unversion the new root's directory.
 
231
        file_id = self.final_file_id(old_new_root)
 
232
        if old_new_root in self._new_id:
 
233
            self.cancel_versioning(old_new_root)
 
234
        else:
 
235
            self.unversion_file(old_new_root)
 
236
        # if, at this stage, root still has an old file_id, zap it so we can
 
237
        # stick a new one in.
 
238
        if (self.tree_file_id(self._new_root) is not None and
 
239
            self._new_root not in self._removed_id):
 
240
            self.unversion_file(self._new_root)
 
241
        self.version_file(file_id, self._new_root)
 
242
 
 
243
        # Now move children of new root into old root directory.
 
244
        # Ensure all children are registered with the transaction, but don't
 
245
        # use directly-- some tree children have new parents
 
246
        list(self.iter_tree_children(old_new_root))
 
247
        # Move all children of new root into old root directory.
 
248
        for child in self.by_parent().get(old_new_root, []):
 
249
            self.adjust_path(self.final_name(child), self._new_root, child)
 
250
 
 
251
        # Ensure old_new_root has no directory.
 
252
        if old_new_root in self._new_contents:
 
253
            self.cancel_creation(old_new_root)
 
254
        else:
 
255
            self.delete_contents(old_new_root)
 
256
 
 
257
        # prevent deletion of root directory.
 
258
        if self._new_root in self._removed_contents:
 
259
            self.cancel_deletion(self._new_root)
 
260
 
 
261
        # destroy path info for old_new_root.
 
262
        del self._new_parent[old_new_root]
 
263
        del self._new_name[old_new_root]
 
264
 
206
265
    def trans_id_tree_file_id(self, inventory_id):
207
266
        """Determine the transaction id of a working tree file.
208
267
 
254
313
 
255
314
    def delete_contents(self, trans_id):
256
315
        """Schedule the contents of a path entry for deletion"""
 
316
        # Ensure that the object exists in the WorkingTree, this will raise an
 
317
        # exception if there is a problem
257
318
        self.tree_kind(trans_id)
258
319
        self._removed_contents.add(trans_id)
259
320
 
1077
1138
        if (trans_id in self._limbo_files and
1078
1139
            trans_id not in self._needs_rename):
1079
1140
            self._rename_in_limbo([trans_id])
1080
 
            self._limbo_children[previous_parent].remove(trans_id)
1081
 
            del self._limbo_children_names[previous_parent][previous_name]
 
1141
            if previous_parent != parent:
 
1142
                self._limbo_children[previous_parent].remove(trans_id)
 
1143
            if previous_parent != parent or previous_name != name:
 
1144
                del self._limbo_children_names[previous_parent][previous_name]
1082
1145
 
1083
1146
    def _rename_in_limbo(self, trans_ids):
1084
1147
        """Fix limbo names so that the right final path is produced.
1565
1628
                child_pb.update('removing file', num, len(tree_paths))
1566
1629
                full_path = self._tree.abspath(path)
1567
1630
                if trans_id in self._removed_contents:
1568
 
                    mover.pre_delete(full_path, os.path.join(self._deletiondir,
1569
 
                                     trans_id))
1570
 
                elif trans_id in self._new_name or trans_id in \
1571
 
                    self._new_parent:
 
1631
                    delete_path = os.path.join(self._deletiondir, trans_id)
 
1632
                    mover.pre_delete(full_path, delete_path)
 
1633
                elif (trans_id in self._new_name
 
1634
                      or trans_id in self._new_parent):
1572
1635
                    try:
1573
1636
                        mover.rename(full_path, self._limbo_name(trans_id))
1574
1637
                    except OSError, e:
2662
2725
                    parent_trans = ROOT_PARENT
2663
2726
                else:
2664
2727
                    parent_trans = tt.trans_id_file_id(parent[1])
2665
 
                tt.adjust_path(name[1], parent_trans, trans_id)
 
2728
                if parent[0] is None and versioned[0]:
 
2729
                    tt.adjust_root_path(name[1], parent_trans)
 
2730
                else:
 
2731
                    tt.adjust_path(name[1], parent_trans, trans_id)
2666
2732
            if executable[0] != executable[1] and kind[1] == "file":
2667
2733
                tt.set_executability(executable[1], trans_id)
2668
2734
        if working_tree.supports_content_filtering():
2681
2747
            for (trans_id, mode_id), bytes in target_tree.iter_files_bytes(
2682
2748
                deferred_files):
2683
2749
                tt.create_file(bytes, trans_id, mode_id)
 
2750
        tt.fixup_new_roots()
2684
2751
    finally:
2685
2752
        if basis_tree is not None:
2686
2753
            basis_tree.unlock()