/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/transform.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-01-14 00:01:32 UTC
  • mfrom: (4957.1.1 jam-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20100114000132-3p3rabnonjw3gzqb
(jam) Merge bzr.stable, bringing in bug fixes #175839, #504390

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-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
17
17
import os
18
18
import errno
19
19
from stat import S_ISREG, S_IEXEC
 
20
import time
20
21
 
21
22
from bzrlib.lazy_import import lazy_import
22
23
lazy_import(globals(), """
161
162
 
162
163
    def adjust_path(self, name, parent, trans_id):
163
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")
164
167
        if trans_id == self._new_root:
165
168
            raise CantMoveRoot
166
169
        self._new_name[trans_id] = name
167
170
        self._new_parent[trans_id] = parent
168
 
        if parent == ROOT_PARENT:
169
 
            if self._new_root is not None:
170
 
                raise ValueError("Cannot have multiple roots.")
171
 
            self._new_root = trans_id
172
171
 
173
172
    def adjust_root_path(self, name, parent):
174
173
        """Emulate moving the root by moving all children, instead.
202
201
        self.version_file(old_root_file_id, old_root)
203
202
        self.unversion_file(self._new_root)
204
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
 
205
265
    def trans_id_tree_file_id(self, inventory_id):
206
266
        """Determine the transaction id of a working tree file.
207
267
 
253
313
 
254
314
    def delete_contents(self, trans_id):
255
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
256
318
        self.tree_kind(trans_id)
257
319
        self._removed_contents.add(trans_id)
258
320
 
1023
1085
        self._limbo_children_names = {}
1024
1086
        # List of transform ids that need to be renamed from limbo into place
1025
1087
        self._needs_rename = set()
 
1088
        self._creation_mtime = None
1026
1089
 
1027
1090
    def finalize(self):
1028
1091
        """Release the working tree lock, if held, clean up limbo dir.
1075
1138
        if (trans_id in self._limbo_files and
1076
1139
            trans_id not in self._needs_rename):
1077
1140
            self._rename_in_limbo([trans_id])
1078
 
            self._limbo_children[previous_parent].remove(trans_id)
1079
 
            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]
1080
1145
 
1081
1146
    def _rename_in_limbo(self, trans_ids):
1082
1147
        """Fix limbo names so that the right final path is produced.
1095
1160
                continue
1096
1161
            new_path = self._limbo_name(trans_id)
1097
1162
            os.rename(old_path, new_path)
 
1163
            for descendant in self._limbo_descendants(trans_id):
 
1164
                desc_path = self._limbo_files[descendant]
 
1165
                desc_path = new_path + desc_path[len(old_path):]
 
1166
                self._limbo_files[descendant] = desc_path
 
1167
 
 
1168
    def _limbo_descendants(self, trans_id):
 
1169
        """Return the set of trans_ids whose limbo paths descend from this."""
 
1170
        descendants = set(self._limbo_children.get(trans_id, []))
 
1171
        for descendant in list(descendants):
 
1172
            descendants.update(self._limbo_descendants(descendant))
 
1173
        return descendants
1098
1174
 
1099
1175
    def create_file(self, contents, trans_id, mode_id=None):
1100
1176
        """Schedule creation of a new file.
1122
1198
            f.writelines(contents)
1123
1199
        finally:
1124
1200
            f.close()
 
1201
        self._set_mtime(name)
1125
1202
        self._set_mode(trans_id, mode_id, S_ISREG)
1126
1203
 
1127
1204
    def _read_file_chunks(self, trans_id):
1134
1211
    def _read_symlink_target(self, trans_id):
1135
1212
        return os.readlink(self._limbo_name(trans_id))
1136
1213
 
 
1214
    def _set_mtime(self, path):
 
1215
        """All files that are created get the same mtime.
 
1216
 
 
1217
        This time is set by the first object to be created.
 
1218
        """
 
1219
        if self._creation_mtime is None:
 
1220
            self._creation_mtime = time.time()
 
1221
        os.utime(path, (self._creation_mtime, self._creation_mtime))
 
1222
 
1137
1223
    def create_hardlink(self, path, trans_id):
1138
1224
        """Schedule creation of a hard link"""
1139
1225
        name = self._limbo_name(trans_id)
1542
1628
                child_pb.update('removing file', num, len(tree_paths))
1543
1629
                full_path = self._tree.abspath(path)
1544
1630
                if trans_id in self._removed_contents:
1545
 
                    mover.pre_delete(full_path, os.path.join(self._deletiondir,
1546
 
                                     trans_id))
1547
 
                elif trans_id in self._new_name or trans_id in \
1548
 
                    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):
1549
1635
                    try:
1550
1636
                        mover.rename(full_path, self._limbo_name(trans_id))
1551
1637
                    except OSError, e:
1902
1988
    def get_file_mtime(self, file_id, path=None):
1903
1989
        """See Tree.get_file_mtime"""
1904
1990
        if not self._content_change(file_id):
1905
 
            return self._transform._tree.get_file_mtime(file_id, path)
 
1991
            return self._transform._tree.get_file_mtime(file_id)
1906
1992
        return self._stat_limbo_file(file_id).st_mtime
1907
1993
 
1908
1994
    def _file_size(self, entry, stat_value):
1962
2048
                statval = os.lstat(limbo_name)
1963
2049
                size = statval.st_size
1964
2050
                if not supports_executable():
1965
 
                    executable = None
 
2051
                    executable = False
1966
2052
                else:
1967
2053
                    executable = statval.st_mode & S_IEXEC
1968
2054
            else:
1970
2056
                executable = None
1971
2057
            if kind == 'symlink':
1972
2058
                link_or_sha1 = os.readlink(limbo_name).decode(osutils._fs_enc)
1973
 
        if supports_executable():
1974
 
            executable = tt._new_executability.get(trans_id, executable)
 
2059
        executable = tt._new_executability.get(trans_id, executable)
1975
2060
        return kind, size, executable, link_or_sha1
1976
2061
 
1977
2062
    def iter_changes(self, from_tree, include_unchanged=False,
2290
2375
        new_desired_files = desired_files
2291
2376
    else:
2292
2377
        iter = accelerator_tree.iter_changes(tree, include_unchanged=True)
2293
 
        unchanged = dict((f, p[1]) for (f, p, c, v, d, n, k, e)
2294
 
                         in iter if not (c or e[0] != e[1]))
 
2378
        unchanged = [(f, p[1]) for (f, p, c, v, d, n, k, e)
 
2379
                     in iter if not (c or e[0] != e[1])]
 
2380
        if accelerator_tree.supports_content_filtering():
 
2381
            unchanged = [(f, p) for (f, p) in unchanged
 
2382
                         if not accelerator_tree.iter_search_rules([p]).next()]
 
2383
        unchanged = dict(unchanged)
2295
2384
        new_desired_files = []
2296
2385
        count = 0
2297
2386
        for file_id, (trans_id, tree_path) in desired_files:
2636
2725
                    parent_trans = ROOT_PARENT
2637
2726
                else:
2638
2727
                    parent_trans = tt.trans_id_file_id(parent[1])
2639
 
                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)
2640
2732
            if executable[0] != executable[1] and kind[1] == "file":
2641
2733
                tt.set_executability(executable[1], trans_id)
2642
2734
        if working_tree.supports_content_filtering():
2655
2747
            for (trans_id, mode_id), bytes in target_tree.iter_files_bytes(
2656
2748
                deferred_files):
2657
2749
                tt.create_file(bytes, trans_id, mode_id)
 
2750
        tt.fixup_new_roots()
2658
2751
    finally:
2659
2752
        if basis_tree is not None:
2660
2753
            basis_tree.unlock()