bzr branch
http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
| 
2255.2.152
by Martin Pool
 (broken) merge aaron's workingtree format changes  | 
1  | 
# Copyright (C) 2006, 2007 Canonical Ltd
 | 
| 
1887.1.1
by Adeodato Simó
 Do not separate paragraphs in the copyright statement with blank lines,  | 
2  | 
#
 | 
| 
1534.7.106
by Aaron Bentley
 Cleaned up imports, added copyright statements  | 
3  | 
# This program is free software; you can redistribute it and/or modify
 | 
4  | 
# it under the terms of the GNU General Public License as published by
 | 
|
5  | 
# the Free Software Foundation; either version 2 of the License, or
 | 
|
6  | 
# (at your option) any later version.
 | 
|
| 
1887.1.1
by Adeodato Simó
 Do not separate paragraphs in the copyright statement with blank lines,  | 
7  | 
#
 | 
| 
1534.7.106
by Aaron Bentley
 Cleaned up imports, added copyright statements  | 
8  | 
# This program is distributed in the hope that it will be useful,
 | 
9  | 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|
10  | 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|
11  | 
# GNU General Public License for more details.
 | 
|
| 
1887.1.1
by Adeodato Simó
 Do not separate paragraphs in the copyright statement with blank lines,  | 
12  | 
#
 | 
| 
1534.7.106
by Aaron Bentley
 Cleaned up imports, added copyright statements  | 
13  | 
# You should have received a copy of the GNU General Public License
 | 
14  | 
# along with this program; if not, write to the Free Software
 | 
|
15  | 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
|
16  | 
||
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
17  | 
import os  | 
| 
1534.7.106
by Aaron Bentley
 Cleaned up imports, added copyright statements  | 
18  | 
import errno  | 
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
19  | 
from stat import S_ISREG  | 
| 
1534.7.106
by Aaron Bentley
 Cleaned up imports, added copyright statements  | 
20  | 
|
| 
1551.11.12
by Aaron Bentley
 Changes from review  | 
21  | 
from bzrlib.lazy_import import lazy_import  | 
22  | 
lazy_import(globals(), """  | 
|
| 
2100.3.21
by Aaron Bentley
 Work on checking out by-reference trees  | 
23  | 
from bzrlib import (
 | 
24  | 
    bzrdir,
 | 
|
| 
2100.3.31
by Aaron Bentley
 Merged bzr.dev (17 tests failing)  | 
25  | 
    delta,
 | 
| 
2100.3.21
by Aaron Bentley
 Work on checking out by-reference trees  | 
26  | 
    errors,
 | 
27  | 
    inventory
 | 
|
28  | 
    )
 | 
|
| 
1551.11.12
by Aaron Bentley
 Changes from review  | 
29  | 
""")  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
30  | 
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,  | 
| 
1534.7.162
by Aaron Bentley
 Handle failures creating/deleting the Limbo directory  | 
31  | 
ReusingTransform, NotVersionedError, CantMoveRoot,  | 
| 
3006.2.1
by Alexander Belchenko
 workaround for bug #81689: give a proper error message instead of traceback when symlink cannot be created (e.g. on Windows)  | 
32  | 
ExistingLimbo, ImmortalLimbo, NoFinalPath,  | 
33  | 
UnableCreateSymlink)  | 
|
| 
1534.7.106
by Aaron Bentley
 Cleaned up imports, added copyright statements  | 
34  | 
from bzrlib.inventory import InventoryEntry  | 
| 
1558.12.9
by Aaron Bentley
 Handle resolving conflicts with directories properly  | 
35  | 
from bzrlib.osutils import (file_kind, supports_executable, pathjoin, lexists,  | 
| 
3006.2.1
by Alexander Belchenko
 workaround for bug #81689: give a proper error message instead of traceback when symlink cannot be created (e.g. on Windows)  | 
36  | 
delete_any, has_symlinks)  | 
| 
1551.2.34
by Aaron Bentley
 Refactored the revert phases  | 
37  | 
from bzrlib.progress import DummyProgress, ProgressPhase  | 
| 
2687.2.1
by Martin Pool
 Rename upcoming release from 0.19 to 0.90  | 
38  | 
from bzrlib.symbol_versioning import (  | 
39  | 
deprecated_function,  | 
|
40  | 
zero_fifteen,  | 
|
41  | 
zero_ninety,  | 
|
42  | 
        )
 | 
|
| 
1534.7.173
by Aaron Bentley
 Added conflict warnings to revert  | 
43  | 
from bzrlib.trace import mutter, warning  | 
| 
1551.7.14
by Aaron Bentley
 Use specified_file_ids instead of is_inside_any in compare_trees  | 
44  | 
from bzrlib import tree  | 
| 
2255.2.152
by Martin Pool
 (broken) merge aaron's workingtree format changes  | 
45  | 
import bzrlib.ui  | 
| 
1685.1.45
by John Arbash Meinel
 Moved url functions into bzrlib.urlutils  | 
46  | 
import bzrlib.urlutils as urlutils  | 
| 
1534.7.31
by Aaron Bentley
 Changed tree root parent to ROOT_PARENT  | 
47  | 
|
| 
1534.7.167
by Aaron Bentley
 PEP8 and comment cleanups  | 
48  | 
|
| 
1534.7.31
by Aaron Bentley
 Changed tree root parent to ROOT_PARENT  | 
49  | 
ROOT_PARENT = "root-parent"  | 
50  | 
||
| 
1534.7.167
by Aaron Bentley
 PEP8 and comment cleanups  | 
51  | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
52  | 
def unique_add(map, key, value):  | 
53  | 
if key in map:  | 
|
| 
1534.7.5
by Aaron Bentley
 Got unique_add under test  | 
54  | 
raise DuplicateKey(key=key)  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
55  | 
map[key] = value  | 
56  | 
||
| 
1534.7.167
by Aaron Bentley
 PEP8 and comment cleanups  | 
57  | 
|
| 
1534.7.191
by Aaron Bentley
 Got transform.apply to list modified paths  | 
58  | 
class _TransformResults(object):  | 
| 
2502.1.5
by Aaron Bentley
 Cleanup  | 
59  | 
def __init__(self, modified_paths, rename_count):  | 
| 
1534.7.191
by Aaron Bentley
 Got transform.apply to list modified paths  | 
60  | 
object.__init__(self)  | 
61  | 
self.modified_paths = modified_paths  | 
|
| 
2502.1.5
by Aaron Bentley
 Cleanup  | 
62  | 
self.rename_count = rename_count  | 
| 
1534.7.191
by Aaron Bentley
 Got transform.apply to list modified paths  | 
63  | 
|
64  | 
||
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
65  | 
class TreeTransform(object):  | 
| 
1534.7.179
by Aaron Bentley
 Added Transform docs  | 
66  | 
"""Represent a tree transformation.  | 
67  | 
    
 | 
|
68  | 
    This object is designed to support incremental generation of the transform,
 | 
|
| 
2502.1.5
by Aaron Bentley
 Cleanup  | 
69  | 
    in any order.
 | 
70  | 
||
71  | 
    However, it gives optimum performance when parent directories are created
 | 
|
72  | 
    before their contents.  The transform is then able to put child files
 | 
|
73  | 
    directly in their parent directory, avoiding later renames.
 | 
|
| 
1534.7.179
by Aaron Bentley
 Added Transform docs  | 
74  | 
    
 | 
75  | 
    It is easy to produce malformed transforms, but they are generally
 | 
|
76  | 
    harmless.  Attempting to apply a malformed transform will cause an
 | 
|
77  | 
    exception to be raised before any modifications are made to the tree.  
 | 
|
78  | 
||
79  | 
    Many kinds of malformed transforms can be corrected with the 
 | 
|
80  | 
    resolve_conflicts function.  The remaining ones indicate programming error,
 | 
|
81  | 
    such as trying to create a file with no path.
 | 
|
82  | 
||
83  | 
    Two sets of file creation methods are supplied.  Convenience methods are:
 | 
|
84  | 
     * new_file
 | 
|
85  | 
     * new_directory
 | 
|
86  | 
     * new_symlink
 | 
|
87  | 
||
88  | 
    These are composed of the low-level methods:
 | 
|
89  | 
     * create_path
 | 
|
90  | 
     * create_file or create_directory or create_symlink
 | 
|
91  | 
     * version_file
 | 
|
92  | 
     * set_executability
 | 
|
| 
1551.19.1
by Aaron Bentley
 Documentation update for TreeTransform, suggested by Michael Hudson  | 
93  | 
|
94  | 
    Transform/Transaction ids
 | 
|
95  | 
    -------------------------
 | 
|
96  | 
    trans_ids are temporary ids assigned to all files involved in a transform.
 | 
|
97  | 
    It's possible, even common, that not all files in the Tree have trans_ids.
 | 
|
98  | 
||
99  | 
    trans_ids are used because filenames and file_ids are not good enough
 | 
|
100  | 
    identifiers; filenames change, and not all files have file_ids.  File-ids
 | 
|
101  | 
    are also associated with trans-ids, so that moving a file moves its
 | 
|
102  | 
    file-id.
 | 
|
103  | 
||
104  | 
    trans_ids are only valid for the TreeTransform that generated them.
 | 
|
105  | 
||
106  | 
    Limbo
 | 
|
107  | 
    -----
 | 
|
108  | 
    Limbo is a temporary directory use to hold new versions of files.
 | 
|
| 
2720.2.2
by Aaron Bentley
 Documentation tweaks for TreeTransform  | 
109  | 
    Files are added to limbo by create_file, create_directory, create_symlink,
 | 
110  | 
    and their convenience variants (new_*).  Files may be removed from limbo
 | 
|
111  | 
    using cancel_creation.  Files are renamed from limbo into their final
 | 
|
112  | 
    location as part of TreeTransform.apply
 | 
|
| 
1551.19.1
by Aaron Bentley
 Documentation update for TreeTransform, suggested by Michael Hudson  | 
113  | 
|
114  | 
    Limbo must be cleaned up, by either calling TreeTransform.apply or
 | 
|
115  | 
    calling TreeTransform.finalize.
 | 
|
116  | 
||
117  | 
    Files are placed into limbo inside their parent directories, where
 | 
|
118  | 
    possible.  This reduces subsequent renames, and makes operations involving
 | 
|
| 
2720.2.2
by Aaron Bentley
 Documentation tweaks for TreeTransform  | 
119  | 
    lots of files faster.  This optimization is only possible if the parent
 | 
120  | 
    directory is created *before* creating any of its children, so avoid
 | 
|
121  | 
    creating children before parents, where possible.
 | 
|
| 
1551.19.1
by Aaron Bentley
 Documentation update for TreeTransform, suggested by Michael Hudson  | 
122  | 
|
123  | 
    Pending-deletion
 | 
|
124  | 
    ----------------
 | 
|
125  | 
    This temporary directory is used by _FileMover for storing files that are
 | 
|
| 
2720.2.2
by Aaron Bentley
 Documentation tweaks for TreeTransform  | 
126  | 
    about to be deleted.  In case of rollback, the files will be restored.
 | 
127  | 
    FileMover does not delete files until it is sure that a rollback will not
 | 
|
128  | 
    happen.  
 | 
|
| 
1534.7.179
by Aaron Bentley
 Added Transform docs  | 
129  | 
    """
 | 
| 
1534.9.1
by Aaron Bentley
 Added progress bars to merge  | 
130  | 
def __init__(self, tree, pb=DummyProgress()):  | 
| 
1997.1.3
by Robert Collins
 All WorkingTree methods which write to the tree, but not to the branch  | 
131  | 
"""Note: a tree_write lock is taken on the tree.  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
132  | 
        
 | 
| 
2502.1.6
by Aaron Bentley
 Update from review comments  | 
133  | 
        Use TreeTransform.finalize() to release the lock (can be omitted if
 | 
134  | 
        TreeTransform.apply() called).
 | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
135  | 
        """
 | 
136  | 
object.__init__(self)  | 
|
137  | 
self._tree = tree  | 
|
| 
1997.1.3
by Robert Collins
 All WorkingTree methods which write to the tree, but not to the branch  | 
138  | 
self._tree.lock_tree_write()  | 
| 
1534.7.162
by Aaron Bentley
 Handle failures creating/deleting the Limbo directory  | 
139  | 
try:  | 
140  | 
control_files = self._tree._control_files  | 
|
| 
1685.1.45
by John Arbash Meinel
 Moved url functions into bzrlib.urlutils  | 
141  | 
self._limbodir = urlutils.local_path_from_url(  | 
| 
1685.1.9
by John Arbash Meinel
 Updated LocalTransport so that it's base is now a URL rather than a local path. This helps consistency with all other functions. To do so, I added local_abspath() which returns the local path, and local_path_to/from_url  | 
142  | 
control_files.controlfilename('limbo'))  | 
| 
1534.7.162
by Aaron Bentley
 Handle failures creating/deleting the Limbo directory  | 
143  | 
try:  | 
144  | 
os.mkdir(self._limbodir)  | 
|
145  | 
except OSError, e:  | 
|
146  | 
if e.errno == errno.EEXIST:  | 
|
147  | 
raise ExistingLimbo(self._limbodir)  | 
|
| 
2733.2.6
by Aaron Bentley
 Make TreeTransform commits rollbackable  | 
148  | 
self._deletiondir = urlutils.local_path_from_url(  | 
149  | 
control_files.controlfilename('pending-deletion'))  | 
|
| 
2733.2.11
by Aaron Bentley
 Detect irregularities with the pending-deletion directory  | 
150  | 
try:  | 
151  | 
os.mkdir(self._deletiondir)  | 
|
152  | 
except OSError, e:  | 
|
153  | 
if e.errno == errno.EEXIST:  | 
|
154  | 
raise errors.ExistingPendingDeletion(self._deletiondir)  | 
|
155  | 
||
| 
1534.7.162
by Aaron Bentley
 Handle failures creating/deleting the Limbo directory  | 
156  | 
except:  | 
157  | 
self._tree.unlock()  | 
|
158  | 
            raise
 | 
|
159  | 
||
| 
1551.19.1
by Aaron Bentley
 Documentation update for TreeTransform, suggested by Michael Hudson  | 
160  | 
        # counter used to generate trans-ids (which are locally unique)
 | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
161  | 
self._id_number = 0  | 
| 
1551.19.1
by Aaron Bentley
 Documentation update for TreeTransform, suggested by Michael Hudson  | 
162  | 
        # mapping of trans_id -> new basename
 | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
163  | 
self._new_name = {}  | 
| 
1551.19.1
by Aaron Bentley
 Documentation update for TreeTransform, suggested by Michael Hudson  | 
164  | 
        # mapping of trans_id -> new parent trans_id
 | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
165  | 
self._new_parent = {}  | 
| 
1551.19.1
by Aaron Bentley
 Documentation update for TreeTransform, suggested by Michael Hudson  | 
166  | 
        # mapping of trans_id with new contents -> new file_kind
 | 
| 
1534.7.4
by Aaron Bentley
 Unified all file types as 'contents'  | 
167  | 
self._new_contents = {}  | 
| 
2502.1.5
by Aaron Bentley
 Cleanup  | 
168  | 
        # A mapping of transform ids to their limbo filename
 | 
| 
2502.1.1
by Aaron Bentley
 Ensure renames only root children are renamed when building trees  | 
169  | 
self._limbo_files = {}  | 
| 
2502.1.5
by Aaron Bentley
 Cleanup  | 
170  | 
        # A mapping of transform ids to a set of the transform ids of children
 | 
| 
2502.1.6
by Aaron Bentley
 Update from review comments  | 
171  | 
        # that their limbo directory has
 | 
| 
2502.1.2
by Aaron Bentley
 Make the limited-renames functionality safer in the general case  | 
172  | 
self._limbo_children = {}  | 
| 
2502.1.5
by Aaron Bentley
 Cleanup  | 
173  | 
        # Map transform ids to maps of child filename to child transform id
 | 
| 
2502.1.4
by Aaron Bentley
 Ensure we only reuse limbo names appropriately  | 
174  | 
self._limbo_children_names = {}  | 
| 
2502.1.5
by Aaron Bentley
 Cleanup  | 
175  | 
        # List of transform ids that need to be renamed from limbo into place
 | 
| 
2502.1.1
by Aaron Bentley
 Ensure renames only root children are renamed when building trees  | 
176  | 
self._needs_rename = set()  | 
| 
1551.19.1
by Aaron Bentley
 Documentation update for TreeTransform, suggested by Michael Hudson  | 
177  | 
        # Set of trans_ids whose contents will be removed
 | 
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
178  | 
self._removed_contents = set()  | 
| 
1551.19.1
by Aaron Bentley
 Documentation update for TreeTransform, suggested by Michael Hudson  | 
179  | 
        # Mapping of trans_id -> new execute-bit value
 | 
| 
1534.7.25
by Aaron Bentley
 Added set_executability  | 
180  | 
self._new_executability = {}  | 
| 
1551.19.1
by Aaron Bentley
 Documentation update for TreeTransform, suggested by Michael Hudson  | 
181  | 
        # Mapping of trans_id -> new tree-reference value
 | 
| 
2100.3.21
by Aaron Bentley
 Work on checking out by-reference trees  | 
182  | 
self._new_reference_revision = {}  | 
| 
1551.19.1
by Aaron Bentley
 Documentation update for TreeTransform, suggested by Michael Hudson  | 
183  | 
        # Mapping of trans_id -> new file_id
 | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
184  | 
self._new_id = {}  | 
| 
1551.19.1
by Aaron Bentley
 Documentation update for TreeTransform, suggested by Michael Hudson  | 
185  | 
        # Mapping of old file-id -> trans_id
 | 
| 
1534.7.143
by Aaron Bentley
 Prevented get_trans_id from automatically versioning file ids  | 
186  | 
self._non_present_ids = {}  | 
| 
1551.19.1
by Aaron Bentley
 Documentation update for TreeTransform, suggested by Michael Hudson  | 
187  | 
        # Mapping of new file_id -> trans_id
 | 
| 
1534.7.75
by Aaron Bentley
 Added reverse-lookup for versioned files and get_trans_id  | 
188  | 
self._r_new_id = {}  | 
| 
1551.19.1
by Aaron Bentley
 Documentation update for TreeTransform, suggested by Michael Hudson  | 
189  | 
        # Set of file_ids that will be removed
 | 
| 
1534.7.39
by Aaron Bentley
 Ensured that files can be unversioned (de-versioned?)  | 
190  | 
self._removed_id = set()  | 
| 
1551.19.1
by Aaron Bentley
 Documentation update for TreeTransform, suggested by Michael Hudson  | 
191  | 
        # Mapping of path in old tree -> trans_id
 | 
| 
1534.7.7
by Aaron Bentley
 Added support for all-file path ids  | 
192  | 
self._tree_path_ids = {}  | 
| 
1551.19.1
by Aaron Bentley
 Documentation update for TreeTransform, suggested by Michael Hudson  | 
193  | 
        # Mapping trans_id -> path in old tree
 | 
| 
1534.7.8
by Aaron Bentley
 Added TreeTransform.final_kind  | 
194  | 
self._tree_id_paths = {}  | 
| 
2502.1.5
by Aaron Bentley
 Cleanup  | 
195  | 
        # Cache of realpath results, to speed up canonical_path
 | 
| 
1534.10.31
by Aaron Bentley
 Add caching to speed canonical_path  | 
196  | 
self._realpaths = {}  | 
| 
2502.1.5
by Aaron Bentley
 Cleanup  | 
197  | 
        # Cache of relpath results, to speed up canonical_path
 | 
| 
1534.10.31
by Aaron Bentley
 Add caching to speed canonical_path  | 
198  | 
self._relpaths = {}  | 
| 
1551.19.1
by Aaron Bentley
 Documentation update for TreeTransform, suggested by Michael Hudson  | 
199  | 
        # The trans_id that will be used as the tree root
 | 
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
200  | 
self._new_root = self.trans_id_tree_file_id(tree.get_root_id())  | 
| 
1551.19.1
by Aaron Bentley
 Documentation update for TreeTransform, suggested by Michael Hudson  | 
201  | 
        # Indictor of whether the transform has been applied
 | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
202  | 
self.__done = False  | 
| 
1551.19.1
by Aaron Bentley
 Documentation update for TreeTransform, suggested by Michael Hudson  | 
203  | 
        # A progress bar
 | 
| 
1534.9.1
by Aaron Bentley
 Added progress bars to merge  | 
204  | 
self._pb = pb  | 
| 
1551.19.1
by Aaron Bentley
 Documentation update for TreeTransform, suggested by Michael Hudson  | 
205  | 
        # A counter of how many files have been renamed
 | 
| 
2502.1.1
by Aaron Bentley
 Ensure renames only root children are renamed when building trees  | 
206  | 
self.rename_count = 0  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
207  | 
|
| 
1534.7.132
by Aaron Bentley
 Got cooked conflicts working  | 
208  | 
def __get_root(self):  | 
209  | 
return self._new_root  | 
|
210  | 
||
211  | 
root = property(__get_root)  | 
|
212  | 
||
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
213  | 
def finalize(self):  | 
| 
2502.1.6
by Aaron Bentley
 Update from review comments  | 
214  | 
"""Release the working tree lock, if held, clean up limbo dir.  | 
215  | 
||
216  | 
        This is required if apply has not been invoked, but can be invoked
 | 
|
217  | 
        even after apply.
 | 
|
218  | 
        """
 | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
219  | 
if self._tree is None:  | 
220  | 
            return
 | 
|
| 
1534.7.162
by Aaron Bentley
 Handle failures creating/deleting the Limbo directory  | 
221  | 
try:  | 
| 
2502.1.7
by Aaron Bentley
 Fix finalize deletion ordering  | 
222  | 
entries = [(self._limbo_name(t), t, k) for t, k in  | 
223  | 
self._new_contents.iteritems()]  | 
|
| 
2502.1.8
by Aaron Bentley
 Updates from review comments  | 
224  | 
entries.sort(reverse=True)  | 
225  | 
for path, trans_id, kind in entries:  | 
|
| 
1534.7.162
by Aaron Bentley
 Handle failures creating/deleting the Limbo directory  | 
226  | 
if kind == "directory":  | 
227  | 
os.rmdir(path)  | 
|
228  | 
else:  | 
|
229  | 
os.unlink(path)  | 
|
230  | 
try:  | 
|
231  | 
os.rmdir(self._limbodir)  | 
|
232  | 
except OSError:  | 
|
233  | 
                # We don't especially care *why* the dir is immortal.
 | 
|
234  | 
raise ImmortalLimbo(self._limbodir)  | 
|
| 
2733.2.11
by Aaron Bentley
 Detect irregularities with the pending-deletion directory  | 
235  | 
try:  | 
236  | 
os.rmdir(self._deletiondir)  | 
|
237  | 
except OSError:  | 
|
238  | 
raise errors.ImmortalPendingDeletion(self._deletiondir)  | 
|
| 
1534.7.162
by Aaron Bentley
 Handle failures creating/deleting the Limbo directory  | 
239  | 
finally:  | 
240  | 
self._tree.unlock()  | 
|
241  | 
self._tree = None  | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
242  | 
|
243  | 
def _assign_id(self):  | 
|
244  | 
"""Produce a new tranform id"""  | 
|
245  | 
new_id = "new-%s" % self._id_number  | 
|
246  | 
self._id_number +=1  | 
|
247  | 
return new_id  | 
|
248  | 
||
249  | 
def create_path(self, name, parent):  | 
|
250  | 
"""Assign a transaction id to a new path"""  | 
|
251  | 
trans_id = self._assign_id()  | 
|
252  | 
unique_add(self._new_name, trans_id, name)  | 
|
253  | 
unique_add(self._new_parent, trans_id, parent)  | 
|
254  | 
return trans_id  | 
|
255  | 
||
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
256  | 
def adjust_path(self, name, parent, trans_id):  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
257  | 
"""Change the path that is assigned to a transaction id."""  | 
| 
1534.7.66
by Aaron Bentley
 Ensured we don't accidentally move the root directory  | 
258  | 
if trans_id == self._new_root:  | 
259  | 
raise CantMoveRoot  | 
|
| 
2502.1.2
by Aaron Bentley
 Make the limited-renames functionality safer in the general case  | 
260  | 
previous_parent = self._new_parent.get(trans_id)  | 
| 
2502.1.4
by Aaron Bentley
 Ensure we only reuse limbo names appropriately  | 
261  | 
previous_name = self._new_name.get(trans_id)  | 
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
262  | 
self._new_name[trans_id] = name  | 
263  | 
self._new_parent[trans_id] = parent  | 
|
| 
2502.1.2
by Aaron Bentley
 Make the limited-renames functionality safer in the general case  | 
264  | 
if (trans_id in self._limbo_files and  | 
265  | 
trans_id not in self._needs_rename):  | 
|
266  | 
self._rename_in_limbo([trans_id])  | 
|
267  | 
self._limbo_children[previous_parent].remove(trans_id)  | 
|
| 
2502.1.4
by Aaron Bentley
 Ensure we only reuse limbo names appropriately  | 
268  | 
del self._limbo_children_names[previous_parent][previous_name]  | 
| 
2502.1.2
by Aaron Bentley
 Make the limited-renames functionality safer in the general case  | 
269  | 
|
270  | 
def _rename_in_limbo(self, trans_ids):  | 
|
| 
2502.1.6
by Aaron Bentley
 Update from review comments  | 
271  | 
"""Fix limbo names so that the right final path is produced.  | 
| 
2502.1.2
by Aaron Bentley
 Make the limited-renames functionality safer in the general case  | 
272  | 
|
273  | 
        This means we outsmarted ourselves-- we tried to avoid renaming
 | 
|
| 
2502.1.6
by Aaron Bentley
 Update from review comments  | 
274  | 
        these files later by creating them with their final names in their
 | 
275  | 
        final parents.  But now the previous name or parent is no longer
 | 
|
| 
2502.1.2
by Aaron Bentley
 Make the limited-renames functionality safer in the general case  | 
276  | 
        suitable, so we have to rename them.
 | 
| 
2502.1.14
by Aaron Bentley
 Style update suggested by Robert  | 
277  | 
|
278  | 
        Even for trans_ids that have no new contents, we must remove their
 | 
|
279  | 
        entries from _limbo_files, because they are now stale.
 | 
|
| 
2502.1.2
by Aaron Bentley
 Make the limited-renames functionality safer in the general case  | 
280  | 
        """
 | 
281  | 
for trans_id in trans_ids:  | 
|
| 
2502.1.14
by Aaron Bentley
 Style update suggested by Robert  | 
282  | 
old_path = self._limbo_files.pop(trans_id)  | 
| 
2502.1.13
by Aaron Bentley
 Updates from review  | 
283  | 
if trans_id not in self._new_contents:  | 
284  | 
                continue
 | 
|
| 
2502.1.14
by Aaron Bentley
 Style update suggested by Robert  | 
285  | 
new_path = self._limbo_name(trans_id)  | 
| 
2502.1.13
by Aaron Bentley
 Updates from review  | 
286  | 
os.rename(old_path, new_path)  | 
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
287  | 
|
| 
1534.7.68
by Aaron Bentley
 Got semi-reasonable root directory renaming working  | 
288  | 
def adjust_root_path(self, name, parent):  | 
289  | 
"""Emulate moving the root by moving all children, instead.  | 
|
290  | 
        
 | 
|
291  | 
        We do this by undoing the association of root's transaction id with the
 | 
|
292  | 
        current tree.  This allows us to create a new directory with that
 | 
|
| 
1534.7.69
by Aaron Bentley
 Got real root moves working  | 
293  | 
        transaction id.  We unversion the root directory and version the 
 | 
294  | 
        physically new directory, and hope someone versions the tree root
 | 
|
295  | 
        later.
 | 
|
| 
1534.7.68
by Aaron Bentley
 Got semi-reasonable root directory renaming working  | 
296  | 
        """
 | 
297  | 
old_root = self._new_root  | 
|
298  | 
old_root_file_id = self.final_file_id(old_root)  | 
|
299  | 
        # force moving all children of root
 | 
|
300  | 
for child_id in self.iter_tree_children(old_root):  | 
|
301  | 
if child_id != parent:  | 
|
302  | 
self.adjust_path(self.final_name(child_id),  | 
|
303  | 
self.final_parent(child_id), child_id)  | 
|
| 
1534.7.69
by Aaron Bentley
 Got real root moves working  | 
304  | 
file_id = self.final_file_id(child_id)  | 
305  | 
if file_id is not None:  | 
|
306  | 
self.unversion_file(child_id)  | 
|
307  | 
self.version_file(file_id, child_id)  | 
|
| 
1534.7.68
by Aaron Bentley
 Got semi-reasonable root directory renaming working  | 
308  | 
|
309  | 
        # the physical root needs a new transaction id
 | 
|
310  | 
self._tree_path_ids.pop("")  | 
|
311  | 
self._tree_id_paths.pop(old_root)  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
312  | 
self._new_root = self.trans_id_tree_file_id(self._tree.get_root_id())  | 
| 
1534.7.68
by Aaron Bentley
 Got semi-reasonable root directory renaming working  | 
313  | 
if parent == old_root:  | 
314  | 
parent = self._new_root  | 
|
315  | 
self.adjust_path(name, parent, old_root)  | 
|
316  | 
self.create_directory(old_root)  | 
|
| 
1534.7.69
by Aaron Bentley
 Got real root moves working  | 
317  | 
self.version_file(old_root_file_id, old_root)  | 
318  | 
self.unversion_file(self._new_root)  | 
|
| 
1534.7.68
by Aaron Bentley
 Got semi-reasonable root directory renaming working  | 
319  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
320  | 
def trans_id_tree_file_id(self, inventory_id):  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
321  | 
"""Determine the transaction id of a working tree file.  | 
322  | 
        
 | 
|
323  | 
        This reflects only files that already exist, not ones that will be
 | 
|
324  | 
        added by transactions.
 | 
|
325  | 
        """
 | 
|
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
326  | 
path = self._tree.inventory.id2path(inventory_id)  | 
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
327  | 
return self.trans_id_tree_path(path)  | 
| 
1534.7.7
by Aaron Bentley
 Added support for all-file path ids  | 
328  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
329  | 
def trans_id_file_id(self, file_id):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
330  | 
"""Determine or set the transaction id associated with a file ID.  | 
| 
1534.7.75
by Aaron Bentley
 Added reverse-lookup for versioned files and get_trans_id  | 
331  | 
        A new id is only created for file_ids that were never present.  If
 | 
332  | 
        a transaction has been unversioned, it is deliberately still returned.
 | 
|
333  | 
        (this will likely lead to an unversioned parent conflict.)
 | 
|
334  | 
        """
 | 
|
335  | 
if file_id in self._r_new_id and self._r_new_id[file_id] is not None:  | 
|
336  | 
return self._r_new_id[file_id]  | 
|
337  | 
elif file_id in self._tree.inventory:  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
338  | 
return self.trans_id_tree_file_id(file_id)  | 
| 
1534.7.143
by Aaron Bentley
 Prevented get_trans_id from automatically versioning file ids  | 
339  | 
elif file_id in self._non_present_ids:  | 
340  | 
return self._non_present_ids[file_id]  | 
|
| 
1534.7.75
by Aaron Bentley
 Added reverse-lookup for versioned files and get_trans_id  | 
341  | 
else:  | 
342  | 
trans_id = self._assign_id()  | 
|
| 
1534.7.143
by Aaron Bentley
 Prevented get_trans_id from automatically versioning file ids  | 
343  | 
self._non_present_ids[file_id] = trans_id  | 
| 
1534.7.75
by Aaron Bentley
 Added reverse-lookup for versioned files and get_trans_id  | 
344  | 
return trans_id  | 
345  | 
||
| 
1534.7.12
by Aaron Bentley
 Added canonical_path function  | 
346  | 
def canonical_path(self, path):  | 
347  | 
"""Get the canonical tree-relative path"""  | 
|
348  | 
        # don't follow final symlinks
 | 
|
| 
1534.10.31
by Aaron Bentley
 Add caching to speed canonical_path  | 
349  | 
abs = self._tree.abspath(path)  | 
350  | 
if abs in self._relpaths:  | 
|
351  | 
return self._relpaths[abs]  | 
|
352  | 
dirname, basename = os.path.split(abs)  | 
|
353  | 
if dirname not in self._realpaths:  | 
|
354  | 
self._realpaths[dirname] = os.path.realpath(dirname)  | 
|
355  | 
dirname = self._realpaths[dirname]  | 
|
356  | 
abs = pathjoin(dirname, basename)  | 
|
357  | 
if dirname in self._relpaths:  | 
|
358  | 
relpath = pathjoin(self._relpaths[dirname], basename)  | 
|
| 
1534.10.32
by Aaron Bentley
 Test and fix case where name has trailing slash  | 
359  | 
relpath = relpath.rstrip('/\\')  | 
| 
1534.10.31
by Aaron Bentley
 Add caching to speed canonical_path  | 
360  | 
else:  | 
361  | 
relpath = self._tree.relpath(abs)  | 
|
362  | 
self._relpaths[abs] = relpath  | 
|
363  | 
return relpath  | 
|
| 
1534.7.12
by Aaron Bentley
 Added canonical_path function  | 
364  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
365  | 
def trans_id_tree_path(self, path):  | 
| 
1534.7.7
by Aaron Bentley
 Added support for all-file path ids  | 
366  | 
"""Determine (and maybe set) the transaction ID for a tree path."""  | 
| 
1534.7.12
by Aaron Bentley
 Added canonical_path function  | 
367  | 
path = self.canonical_path(path)  | 
| 
1534.7.7
by Aaron Bentley
 Added support for all-file path ids  | 
368  | 
if path not in self._tree_path_ids:  | 
369  | 
self._tree_path_ids[path] = self._assign_id()  | 
|
| 
1534.7.8
by Aaron Bentley
 Added TreeTransform.final_kind  | 
370  | 
self._tree_id_paths[self._tree_path_ids[path]] = path  | 
| 
1534.7.7
by Aaron Bentley
 Added support for all-file path ids  | 
371  | 
return self._tree_path_ids[path]  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
372  | 
|
| 
1534.7.16
by Aaron Bentley
 Added get_tree_parent  | 
373  | 
def get_tree_parent(self, trans_id):  | 
| 
1534.7.31
by Aaron Bentley
 Changed tree root parent to ROOT_PARENT  | 
374  | 
"""Determine id of the parent in the tree."""  | 
| 
1534.7.16
by Aaron Bentley
 Added get_tree_parent  | 
375  | 
path = self._tree_id_paths[trans_id]  | 
376  | 
if path == "":  | 
|
| 
1534.7.31
by Aaron Bentley
 Changed tree root parent to ROOT_PARENT  | 
377  | 
return ROOT_PARENT  | 
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
378  | 
return self.trans_id_tree_path(os.path.dirname(path))  | 
| 
1534.7.16
by Aaron Bentley
 Added get_tree_parent  | 
379  | 
|
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
380  | 
def create_file(self, contents, trans_id, mode_id=None):  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
381  | 
"""Schedule creation of a new file.  | 
382  | 
||
383  | 
        See also new_file.
 | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
384  | 
        
 | 
385  | 
        Contents is an iterator of strings, all of which will be written
 | 
|
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
386  | 
        to the target destination.
 | 
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
387  | 
|
388  | 
        New file takes the permissions of any existing file with that id,
 | 
|
389  | 
        unless mode_id is specified.
 | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
390  | 
        """
 | 
| 
1711.7.22
by John Arbash Meinel
 transform: cleanup the temporary file even if unique_add fails.  | 
391  | 
name = self._limbo_name(trans_id)  | 
392  | 
f = open(name, 'wb')  | 
|
| 
1711.7.8
by John Arbash Meinel
 Use try/finally inside create_file for TreeTransform to ensure the file handle gets closed  | 
393  | 
try:  | 
| 
1711.7.22
by John Arbash Meinel
 transform: cleanup the temporary file even if unique_add fails.  | 
394  | 
try:  | 
395  | 
unique_add(self._new_contents, trans_id, 'file')  | 
|
396  | 
except:  | 
|
397  | 
                # Clean up the file, it never got registered so
 | 
|
398  | 
                # TreeTransform.finalize() won't clean it up.
 | 
|
399  | 
f.close()  | 
|
400  | 
os.unlink(name)  | 
|
401  | 
                raise
 | 
|
402  | 
||
| 
2247.1.2
by John Arbash Meinel
 Switch from for line in foo: f.write(line) to f.writelines(foo)  | 
403  | 
f.writelines(contents)  | 
| 
1711.7.8
by John Arbash Meinel
 Use try/finally inside create_file for TreeTransform to ensure the file handle gets closed  | 
404  | 
finally:  | 
405  | 
f.close()  | 
|
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
406  | 
self._set_mode(trans_id, mode_id, S_ISREG)  | 
407  | 
||
408  | 
def _set_mode(self, trans_id, mode_id, typefunc):  | 
|
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
409  | 
"""Set the mode of new file contents.  | 
410  | 
        The mode_id is the existing file to get the mode from (often the same
 | 
|
411  | 
        as trans_id).  The operation is only performed if there's a mode match
 | 
|
412  | 
        according to typefunc.
 | 
|
413  | 
        """
 | 
|
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
414  | 
if mode_id is None:  | 
415  | 
mode_id = trans_id  | 
|
416  | 
try:  | 
|
417  | 
old_path = self._tree_id_paths[mode_id]  | 
|
418  | 
except KeyError:  | 
|
419  | 
            return
 | 
|
420  | 
try:  | 
|
| 
2027.1.1
by John Arbash Meinel
 Fix bug #56549, and write a direct test that the right path is being statted  | 
421  | 
mode = os.stat(self._tree.abspath(old_path)).st_mode  | 
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
422  | 
except OSError, e:  | 
423  | 
if e.errno == errno.ENOENT:  | 
|
424  | 
                return
 | 
|
425  | 
else:  | 
|
426  | 
                raise
 | 
|
427  | 
if typefunc(mode):  | 
|
428  | 
os.chmod(self._limbo_name(trans_id), mode)  | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
429  | 
|
| 
1534.7.20
by Aaron Bentley
 Added directory handling  | 
430  | 
def create_directory(self, trans_id):  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
431  | 
"""Schedule creation of a new directory.  | 
432  | 
        
 | 
|
433  | 
        See also new_directory.
 | 
|
434  | 
        """
 | 
|
| 
1534.7.73
by Aaron Bentley
 Changed model again. Now iterator is used immediately.  | 
435  | 
os.mkdir(self._limbo_name(trans_id))  | 
436  | 
unique_add(self._new_contents, trans_id, 'directory')  | 
|
| 
1534.7.20
by Aaron Bentley
 Added directory handling  | 
437  | 
|
| 
1534.7.22
by Aaron Bentley
 Added symlink support  | 
438  | 
def create_symlink(self, target, trans_id):  | 
439  | 
"""Schedule creation of a new symbolic link.  | 
|
440  | 
||
441  | 
        target is a bytestring.
 | 
|
442  | 
        See also new_symlink.
 | 
|
443  | 
        """
 | 
|
| 
3006.2.1
by Alexander Belchenko
 workaround for bug #81689: give a proper error message instead of traceback when symlink cannot be created (e.g. on Windows)  | 
444  | 
if has_symlinks():  | 
445  | 
os.symlink(target, self._limbo_name(trans_id))  | 
|
446  | 
unique_add(self._new_contents, trans_id, 'symlink')  | 
|
447  | 
else:  | 
|
| 
3006.2.2
by Alexander Belchenko
 tests added.  | 
448  | 
try:  | 
449  | 
path = FinalPaths(self).get_path(trans_id)  | 
|
450  | 
except KeyError:  | 
|
451  | 
path = None  | 
|
452  | 
raise UnableCreateSymlink(path=path)  | 
|
| 
1534.7.22
by Aaron Bentley
 Added symlink support  | 
453  | 
|
| 
1534.7.129
by Aaron Bentley
 Converted test cases to Tree Transform  | 
454  | 
def cancel_creation(self, trans_id):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
455  | 
"""Cancel the creation of new file contents."""  | 
| 
1534.7.129
by Aaron Bentley
 Converted test cases to Tree Transform  | 
456  | 
del self._new_contents[trans_id]  | 
| 
2502.1.2
by Aaron Bentley
 Make the limited-renames functionality safer in the general case  | 
457  | 
children = self._limbo_children.get(trans_id)  | 
458  | 
        # if this is a limbo directory with children, move them before removing
 | 
|
459  | 
        # the directory
 | 
|
460  | 
if children is not None:  | 
|
461  | 
self._rename_in_limbo(children)  | 
|
462  | 
del self._limbo_children[trans_id]  | 
|
| 
2502.1.4
by Aaron Bentley
 Ensure we only reuse limbo names appropriately  | 
463  | 
del self._limbo_children_names[trans_id]  | 
| 
1558.12.9
by Aaron Bentley
 Handle resolving conflicts with directories properly  | 
464  | 
delete_any(self._limbo_name(trans_id))  | 
| 
1534.7.129
by Aaron Bentley
 Converted test cases to Tree Transform  | 
465  | 
|
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
466  | 
def delete_contents(self, trans_id):  | 
467  | 
"""Schedule the contents of a path entry for deletion"""  | 
|
| 
1534.7.130
by Aaron Bentley
 More conflict handling, test porting  | 
468  | 
self.tree_kind(trans_id)  | 
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
469  | 
self._removed_contents.add(trans_id)  | 
470  | 
||
| 
1534.7.61
by Aaron Bentley
 Handled parent loops, missing parents, unversioned parents  | 
471  | 
def cancel_deletion(self, trans_id):  | 
472  | 
"""Cancel a scheduled deletion"""  | 
|
473  | 
self._removed_contents.remove(trans_id)  | 
|
474  | 
||
| 
1534.7.39
by Aaron Bentley
 Ensured that files can be unversioned (de-versioned?)  | 
475  | 
def unversion_file(self, trans_id):  | 
476  | 
"""Schedule a path entry to become unversioned"""  | 
|
477  | 
self._removed_id.add(trans_id)  | 
|
478  | 
||
479  | 
def delete_versioned(self, trans_id):  | 
|
480  | 
"""Delete and unversion a versioned file"""  | 
|
481  | 
self.delete_contents(trans_id)  | 
|
482  | 
self.unversion_file(trans_id)  | 
|
483  | 
||
| 
1534.7.25
by Aaron Bentley
 Added set_executability  | 
484  | 
def set_executability(self, executability, trans_id):  | 
| 
1534.7.167
by Aaron Bentley
 PEP8 and comment cleanups  | 
485  | 
"""Schedule setting of the 'execute' bit  | 
486  | 
        To unschedule, set to None
 | 
|
487  | 
        """
 | 
|
| 
1534.7.26
by Aaron Bentley
 Added conflicts for setting executability on unversioned/non-file entries  | 
488  | 
if executability is None:  | 
489  | 
del self._new_executability[trans_id]  | 
|
490  | 
else:  | 
|
491  | 
unique_add(self._new_executability, trans_id, executability)  | 
|
| 
1534.7.25
by Aaron Bentley
 Added set_executability  | 
492  | 
|
| 
2100.3.21
by Aaron Bentley
 Work on checking out by-reference trees  | 
493  | 
def set_tree_reference(self, revision_id, trans_id):  | 
494  | 
"""Set the reference associated with a directory"""  | 
|
495  | 
unique_add(self._new_reference_revision, trans_id, revision_id)  | 
|
496  | 
||
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
497  | 
def version_file(self, file_id, trans_id):  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
498  | 
"""Schedule a file to become versioned."""  | 
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
499  | 
assert file_id is not None  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
500  | 
unique_add(self._new_id, trans_id, file_id)  | 
| 
1534.7.75
by Aaron Bentley
 Added reverse-lookup for versioned files and get_trans_id  | 
501  | 
unique_add(self._r_new_id, file_id, trans_id)  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
502  | 
|
| 
1534.7.105
by Aaron Bentley
 Got merge with rename working  | 
503  | 
def cancel_versioning(self, trans_id):  | 
504  | 
"""Undo a previous versioning of a file"""  | 
|
505  | 
file_id = self._new_id[trans_id]  | 
|
506  | 
del self._new_id[trans_id]  | 
|
507  | 
del self._r_new_id[file_id]  | 
|
508  | 
||
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
509  | 
def new_paths(self):  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
510  | 
"""Determine the paths of all new and changed files"""  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
511  | 
new_ids = set()  | 
| 
1534.7.132
by Aaron Bentley
 Got cooked conflicts working  | 
512  | 
fp = FinalPaths(self)  | 
| 
1534.7.4
by Aaron Bentley
 Unified all file types as 'contents'  | 
513  | 
for id_set in (self._new_name, self._new_parent, self._new_contents,  | 
| 
1534.7.25
by Aaron Bentley
 Added set_executability  | 
514  | 
self._new_id, self._new_executability):  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
515  | 
new_ids.update(id_set)  | 
516  | 
new_paths = [(fp.get_path(t), t) for t in new_ids]  | 
|
517  | 
new_paths.sort()  | 
|
518  | 
return new_paths  | 
|
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
519  | 
|
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
520  | 
def tree_kind(self, trans_id):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
521  | 
"""Determine the file kind in the working tree.  | 
522  | 
||
523  | 
        Raises NoSuchFile if the file does not exist
 | 
|
524  | 
        """
 | 
|
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
525  | 
path = self._tree_id_paths.get(trans_id)  | 
526  | 
if path is None:  | 
|
527  | 
raise NoSuchFile(None)  | 
|
528  | 
try:  | 
|
529  | 
return file_kind(self._tree.abspath(path))  | 
|
530  | 
except OSError, e:  | 
|
531  | 
if e.errno != errno.ENOENT:  | 
|
532  | 
                raise
 | 
|
533  | 
else:  | 
|
534  | 
raise NoSuchFile(path)  | 
|
535  | 
||
| 
1534.7.8
by Aaron Bentley
 Added TreeTransform.final_kind  | 
536  | 
def final_kind(self, trans_id):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
537  | 
"""Determine the final file kind, after any changes applied.  | 
| 
1534.7.8
by Aaron Bentley
 Added TreeTransform.final_kind  | 
538  | 
        
 | 
539  | 
        Raises NoSuchFile if the file does not exist/has no contents.
 | 
|
540  | 
        (It is conceivable that a path would be created without the
 | 
|
541  | 
        corresponding contents insertion command)
 | 
|
542  | 
        """
 | 
|
543  | 
if trans_id in self._new_contents:  | 
|
| 
1534.7.73
by Aaron Bentley
 Changed model again. Now iterator is used immediately.  | 
544  | 
return self._new_contents[trans_id]  | 
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
545  | 
elif trans_id in self._removed_contents:  | 
546  | 
raise NoSuchFile(None)  | 
|
| 
1534.7.8
by Aaron Bentley
 Added TreeTransform.final_kind  | 
547  | 
else:  | 
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
548  | 
return self.tree_kind(trans_id)  | 
| 
1534.7.8
by Aaron Bentley
 Added TreeTransform.final_kind  | 
549  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
550  | 
def tree_file_id(self, trans_id):  | 
| 
1534.7.41
by Aaron Bentley
 Got inventory ID movement working  | 
551  | 
"""Determine the file id associated with the trans_id in the tree"""  | 
552  | 
try:  | 
|
553  | 
path = self._tree_id_paths[trans_id]  | 
|
554  | 
except KeyError:  | 
|
555  | 
            # the file is a new, unversioned file, or invalid trans_id
 | 
|
556  | 
return None  | 
|
557  | 
        # the file is old; the old id is still valid
 | 
|
| 
1534.7.68
by Aaron Bentley
 Got semi-reasonable root directory renaming working  | 
558  | 
if self._new_root == trans_id:  | 
| 
2946.3.3
by John Arbash Meinel
 Prefer tree.get_root_id() as more explicit than tree.path2id('')  | 
559  | 
return self._tree.get_root_id()  | 
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
560  | 
return self._tree.inventory.path2id(path)  | 
| 
1534.7.41
by Aaron Bentley
 Got inventory ID movement working  | 
561  | 
|
| 
1534.7.13
by Aaron Bentley
 Implemented final_file_id  | 
562  | 
def final_file_id(self, trans_id):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
563  | 
"""Determine the file id after any changes are applied, or None.  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
564  | 
        
 | 
565  | 
        None indicates that the file will not be versioned after changes are
 | 
|
566  | 
        applied.
 | 
|
567  | 
        """
 | 
|
| 
1534.7.13
by Aaron Bentley
 Implemented final_file_id  | 
568  | 
try:  | 
569  | 
            # there is a new id for this file
 | 
|
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
570  | 
assert self._new_id[trans_id] is not None  | 
| 
1534.7.13
by Aaron Bentley
 Implemented final_file_id  | 
571  | 
return self._new_id[trans_id]  | 
572  | 
except KeyError:  | 
|
| 
1534.7.39
by Aaron Bentley
 Ensured that files can be unversioned (de-versioned?)  | 
573  | 
if trans_id in self._removed_id:  | 
574  | 
return None  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
575  | 
return self.tree_file_id(trans_id)  | 
| 
1534.7.13
by Aaron Bentley
 Implemented final_file_id  | 
576  | 
|
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
577  | 
def inactive_file_id(self, trans_id):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
578  | 
"""Return the inactive file_id associated with a transaction id.  | 
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
579  | 
        That is, the one in the tree or in non_present_ids.
 | 
580  | 
        The file_id may actually be active, too.
 | 
|
581  | 
        """
 | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
582  | 
file_id = self.tree_file_id(trans_id)  | 
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
583  | 
if file_id is not None:  | 
584  | 
return file_id  | 
|
585  | 
for key, value in self._non_present_ids.iteritems():  | 
|
586  | 
if value == trans_id:  | 
|
587  | 
return key  | 
|
588  | 
||
| 
1534.7.17
by Aaron Bentley
 Added final_parent function  | 
589  | 
def final_parent(self, trans_id):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
590  | 
"""Determine the parent file_id, after any changes are applied.  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
591  | 
|
| 
1534.7.31
by Aaron Bentley
 Changed tree root parent to ROOT_PARENT  | 
592  | 
        ROOT_PARENT is returned for the tree root.
 | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
593  | 
        """
 | 
| 
1534.7.17
by Aaron Bentley
 Added final_parent function  | 
594  | 
try:  | 
595  | 
return self._new_parent[trans_id]  | 
|
596  | 
except KeyError:  | 
|
597  | 
return self.get_tree_parent(trans_id)  | 
|
598  | 
||
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
599  | 
def final_name(self, trans_id):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
600  | 
"""Determine the final filename, after all changes are applied."""  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
601  | 
try:  | 
602  | 
return self._new_name[trans_id]  | 
|
603  | 
except KeyError:  | 
|
| 
1731.1.33
by Aaron Bentley
 Revert no-special-root changes  | 
604  | 
try:  | 
605  | 
return os.path.basename(self._tree_id_paths[trans_id])  | 
|
606  | 
except KeyError:  | 
|
607  | 
raise NoFinalPath(trans_id, self)  | 
|
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
608  | 
|
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
609  | 
def by_parent(self):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
610  | 
"""Return a map of parent: children for known parents.  | 
611  | 
        
 | 
|
612  | 
        Only new paths and parents of tree files with assigned ids are used.
 | 
|
613  | 
        """
 | 
|
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
614  | 
by_parent = {}  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
615  | 
items = list(self._new_parent.iteritems())  | 
| 
1534.7.76
by Aaron Bentley
 Fixed final_parent, for the case where finding a parent adds tree id paths.  | 
616  | 
items.extend((t, self.final_parent(t)) for t in  | 
617  | 
self._tree_id_paths.keys())  | 
|
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
618  | 
for trans_id, parent_id in items:  | 
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
619  | 
if parent_id not in by_parent:  | 
620  | 
by_parent[parent_id] = set()  | 
|
621  | 
by_parent[parent_id].add(trans_id)  | 
|
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
622  | 
return by_parent  | 
| 
1534.7.11
by Aaron Bentley
 Refactored conflict handling  | 
623  | 
|
| 
1534.7.57
by Aaron Bentley
 Enhanced conflict resolution.  | 
624  | 
def path_changed(self, trans_id):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
625  | 
"""Return True if a trans_id's path has changed."""  | 
| 
1711.9.11
by John Arbash Meinel
 change return foo in bar to return (foo in bar)  | 
626  | 
return (trans_id in self._new_name) or (trans_id in self._new_parent)  | 
| 
1534.7.57
by Aaron Bentley
 Enhanced conflict resolution.  | 
627  | 
|
| 
1966.1.2
by Aaron Bentley
 Divert files instead of failing to create them, update from review  | 
628  | 
def new_contents(self, trans_id):  | 
629  | 
return (trans_id in self._new_contents)  | 
|
630  | 
||
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
631  | 
def find_conflicts(self):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
632  | 
"""Find any violations of inventory or filesystem invariants"""  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
633  | 
if self.__done is True:  | 
634  | 
raise ReusingTransform()  | 
|
635  | 
conflicts = []  | 
|
636  | 
        # ensure all children of all existent parents are known
 | 
|
637  | 
        # all children of non-existent parents are known, by definition.
 | 
|
638  | 
self._add_tree_children()  | 
|
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
639  | 
by_parent = self.by_parent()  | 
| 
1534.7.15
by Aaron Bentley
 Add conflict types related to versioning  | 
640  | 
conflicts.extend(self._unversioned_parents(by_parent))  | 
| 
1534.7.19
by Aaron Bentley
 Added tests for parent loops  | 
641  | 
conflicts.extend(self._parent_loops())  | 
| 
1534.7.11
by Aaron Bentley
 Refactored conflict handling  | 
642  | 
conflicts.extend(self._duplicate_entries(by_parent))  | 
| 
1534.7.50
by Aaron Bentley
 Detect duplicate inventory ids  | 
643  | 
conflicts.extend(self._duplicate_ids())  | 
| 
1534.7.11
by Aaron Bentley
 Refactored conflict handling  | 
644  | 
conflicts.extend(self._parent_type_conflicts(by_parent))  | 
| 
1534.7.15
by Aaron Bentley
 Add conflict types related to versioning  | 
645  | 
conflicts.extend(self._improper_versioning())  | 
| 
1534.7.26
by Aaron Bentley
 Added conflicts for setting executability on unversioned/non-file entries  | 
646  | 
conflicts.extend(self._executability_conflicts())  | 
| 
1534.7.152
by Aaron Bentley
 Fixed overwrites  | 
647  | 
conflicts.extend(self._overwrite_conflicts())  | 
| 
1534.7.15
by Aaron Bentley
 Add conflict types related to versioning  | 
648  | 
return conflicts  | 
649  | 
||
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
650  | 
def _add_tree_children(self):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
651  | 
"""Add all the children of all active parents to the known paths.  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
652  | 
|
653  | 
        Active parents are those which gain children, and those which are
 | 
|
654  | 
        removed.  This is a necessary first step in detecting conflicts.
 | 
|
655  | 
        """
 | 
|
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
656  | 
parents = self.by_parent().keys()  | 
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
657  | 
parents.extend([t for t in self._removed_contents if  | 
658  | 
self.tree_kind(t) == 'directory'])  | 
|
| 
1534.7.50
by Aaron Bentley
 Detect duplicate inventory ids  | 
659  | 
for trans_id in self._removed_id:  | 
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
660  | 
file_id = self.tree_file_id(trans_id)  | 
| 
1731.1.2
by Aaron Bentley
 Removed all remaining uses of root_directory  | 
661  | 
if self._tree.inventory[file_id].kind == 'directory':  | 
| 
1534.7.50
by Aaron Bentley
 Detect duplicate inventory ids  | 
662  | 
parents.append(trans_id)  | 
663  | 
||
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
664  | 
for parent_id in parents:  | 
| 
1534.7.67
by Aaron Bentley
 Refactored _add_tree_children  | 
665  | 
            # ensure that all children are registered with the transaction
 | 
666  | 
list(self.iter_tree_children(parent_id))  | 
|
667  | 
||
668  | 
def iter_tree_children(self, parent_id):  | 
|
669  | 
"""Iterate through the entry's tree children, if any"""  | 
|
670  | 
try:  | 
|
671  | 
path = self._tree_id_paths[parent_id]  | 
|
672  | 
except KeyError:  | 
|
673  | 
            return
 | 
|
674  | 
try:  | 
|
675  | 
children = os.listdir(self._tree.abspath(path))  | 
|
676  | 
except OSError, e:  | 
|
| 
1534.7.71
by abentley
 All tests pass under Windows  | 
677  | 
if e.errno != errno.ENOENT and e.errno != errno.ESRCH:  | 
| 
1534.7.67
by Aaron Bentley
 Refactored _add_tree_children  | 
678  | 
                raise
 | 
679  | 
            return
 | 
|
680  | 
||
681  | 
for child in children:  | 
|
682  | 
childpath = joinpath(path, child)  | 
|
| 
1534.7.180
by Aaron Bentley
 Merge from mainline  | 
683  | 
if self._tree.is_control_filename(childpath):  | 
| 
1534.7.67
by Aaron Bentley
 Refactored _add_tree_children  | 
684  | 
                continue
 | 
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
685  | 
yield self.trans_id_tree_path(childpath)  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
686  | 
|
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
687  | 
def has_named_child(self, by_parent, parent_id, name):  | 
688  | 
try:  | 
|
689  | 
children = by_parent[parent_id]  | 
|
690  | 
except KeyError:  | 
|
691  | 
children = []  | 
|
692  | 
for child in children:  | 
|
693  | 
if self.final_name(child) == name:  | 
|
694  | 
return True  | 
|
695  | 
try:  | 
|
696  | 
path = self._tree_id_paths[parent_id]  | 
|
697  | 
except KeyError:  | 
|
698  | 
return False  | 
|
699  | 
childpath = joinpath(path, name)  | 
|
700  | 
child_id = self._tree_path_ids.get(childpath)  | 
|
701  | 
if child_id is None:  | 
|
702  | 
return lexists(self._tree.abspath(childpath))  | 
|
703  | 
else:  | 
|
| 
1773.4.1
by Martin Pool
 Add pyflakes makefile target; fix many warnings  | 
704  | 
if self.final_parent(child_id) != parent_id:  | 
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
705  | 
return False  | 
| 
1773.4.1
by Martin Pool
 Add pyflakes makefile target; fix many warnings  | 
706  | 
if child_id in self._removed_contents:  | 
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
707  | 
                # XXX What about dangling file-ids?
 | 
708  | 
return False  | 
|
709  | 
else:  | 
|
710  | 
return True  | 
|
711  | 
||
| 
1534.7.19
by Aaron Bentley
 Added tests for parent loops  | 
712  | 
def _parent_loops(self):  | 
713  | 
"""No entry should be its own ancestor"""  | 
|
714  | 
conflicts = []  | 
|
715  | 
for trans_id in self._new_parent:  | 
|
716  | 
seen = set()  | 
|
717  | 
parent_id = trans_id  | 
|
| 
1534.7.31
by Aaron Bentley
 Changed tree root parent to ROOT_PARENT  | 
718  | 
while parent_id is not ROOT_PARENT:  | 
| 
1534.7.19
by Aaron Bentley
 Added tests for parent loops  | 
719  | 
seen.add(parent_id)  | 
| 
1731.1.33
by Aaron Bentley
 Revert no-special-root changes  | 
720  | 
try:  | 
721  | 
parent_id = self.final_parent(parent_id)  | 
|
722  | 
except KeyError:  | 
|
723  | 
                    break
 | 
|
| 
1534.7.19
by Aaron Bentley
 Added tests for parent loops  | 
724  | 
if parent_id == trans_id:  | 
725  | 
conflicts.append(('parent loop', trans_id))  | 
|
726  | 
if parent_id in seen:  | 
|
727  | 
                    break
 | 
|
728  | 
return conflicts  | 
|
729  | 
||
| 
1534.7.15
by Aaron Bentley
 Add conflict types related to versioning  | 
730  | 
def _unversioned_parents(self, by_parent):  | 
731  | 
"""If parent directories are versioned, children must be versioned."""  | 
|
732  | 
conflicts = []  | 
|
733  | 
for parent_id, children in by_parent.iteritems():  | 
|
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
734  | 
if parent_id is ROOT_PARENT:  | 
735  | 
                continue
 | 
|
| 
1534.7.15
by Aaron Bentley
 Add conflict types related to versioning  | 
736  | 
if self.final_file_id(parent_id) is not None:  | 
737  | 
                continue
 | 
|
738  | 
for child_id in children:  | 
|
739  | 
if self.final_file_id(child_id) is not None:  | 
|
740  | 
conflicts.append(('unversioned parent', parent_id))  | 
|
741  | 
break;  | 
|
742  | 
return conflicts  | 
|
743  | 
||
744  | 
def _improper_versioning(self):  | 
|
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
745  | 
"""Cannot version a file with no contents, or a bad type.  | 
| 
1534.7.15
by Aaron Bentley
 Add conflict types related to versioning  | 
746  | 
        
 | 
747  | 
        However, existing entries with no contents are okay.
 | 
|
748  | 
        """
 | 
|
749  | 
conflicts = []  | 
|
750  | 
for trans_id in self._new_id.iterkeys():  | 
|
751  | 
try:  | 
|
752  | 
kind = self.final_kind(trans_id)  | 
|
753  | 
except NoSuchFile:  | 
|
754  | 
conflicts.append(('versioning no contents', trans_id))  | 
|
755  | 
                continue
 | 
|
756  | 
if not InventoryEntry.versionable_kind(kind):  | 
|
| 
1534.7.20
by Aaron Bentley
 Added directory handling  | 
757  | 
conflicts.append(('versioning bad kind', trans_id, kind))  | 
| 
1534.7.11
by Aaron Bentley
 Refactored conflict handling  | 
758  | 
return conflicts  | 
759  | 
||
| 
1534.7.26
by Aaron Bentley
 Added conflicts for setting executability on unversioned/non-file entries  | 
760  | 
def _executability_conflicts(self):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
761  | 
"""Check for bad executability changes.  | 
762  | 
        
 | 
|
763  | 
        Only versioned files may have their executability set, because
 | 
|
764  | 
        1. only versioned entries can have executability under windows
 | 
|
765  | 
        2. only files can be executable.  (The execute bit on a directory
 | 
|
766  | 
           does not indicate searchability)
 | 
|
767  | 
        """
 | 
|
| 
1534.7.26
by Aaron Bentley
 Added conflicts for setting executability on unversioned/non-file entries  | 
768  | 
conflicts = []  | 
769  | 
for trans_id in self._new_executability:  | 
|
770  | 
if self.final_file_id(trans_id) is None:  | 
|
771  | 
conflicts.append(('unversioned executability', trans_id))  | 
|
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
772  | 
else:  | 
773  | 
try:  | 
|
774  | 
non_file = self.final_kind(trans_id) != "file"  | 
|
775  | 
except NoSuchFile:  | 
|
776  | 
non_file = True  | 
|
777  | 
if non_file is True:  | 
|
778  | 
conflicts.append(('non-file executability', trans_id))  | 
|
| 
1534.7.26
by Aaron Bentley
 Added conflicts for setting executability on unversioned/non-file entries  | 
779  | 
return conflicts  | 
780  | 
||
| 
1534.7.152
by Aaron Bentley
 Fixed overwrites  | 
781  | 
def _overwrite_conflicts(self):  | 
782  | 
"""Check for overwrites (not permitted on Win32)"""  | 
|
783  | 
conflicts = []  | 
|
784  | 
for trans_id in self._new_contents:  | 
|
785  | 
try:  | 
|
786  | 
self.tree_kind(trans_id)  | 
|
787  | 
except NoSuchFile:  | 
|
788  | 
                continue
 | 
|
789  | 
if trans_id not in self._removed_contents:  | 
|
790  | 
conflicts.append(('overwrite', trans_id,  | 
|
791  | 
self.final_name(trans_id)))  | 
|
792  | 
return conflicts  | 
|
793  | 
||
| 
1534.7.11
by Aaron Bentley
 Refactored conflict handling  | 
794  | 
def _duplicate_entries(self, by_parent):  | 
795  | 
"""No directory may have two entries with the same name."""  | 
|
796  | 
conflicts = []  | 
|
| 
2590.2.16
by Aaron Bentley
 Shortcut duplicate_entries conflict check if no new names introduced  | 
797  | 
if (self._new_name, self._new_parent) == ({}, {}):  | 
798  | 
return conflicts  | 
|
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
799  | 
for children in by_parent.itervalues():  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
800  | 
name_ids = [(self.final_name(t), t) for t in children]  | 
| 
3034.4.1
by Aaron Bentley
 Start handling case-insensitivity  | 
801  | 
if not self._tree.case_sensitive:  | 
802  | 
name_ids = [(n.lower(), t) for n, t in name_ids]  | 
|
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
803  | 
name_ids.sort()  | 
804  | 
last_name = None  | 
|
805  | 
last_trans_id = None  | 
|
806  | 
for name, trans_id in name_ids:  | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
807  | 
try:  | 
808  | 
kind = self.final_kind(trans_id)  | 
|
809  | 
except NoSuchFile:  | 
|
810  | 
kind = None  | 
|
811  | 
file_id = self.final_file_id(trans_id)  | 
|
812  | 
if kind is None and file_id is None:  | 
|
813  | 
                    continue
 | 
|
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
814  | 
if name == last_name:  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
815  | 
conflicts.append(('duplicate', last_trans_id, trans_id,  | 
816  | 
name))  | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
817  | 
last_name = name  | 
818  | 
last_trans_id = trans_id  | 
|
| 
1534.7.11
by Aaron Bentley
 Refactored conflict handling  | 
819  | 
return conflicts  | 
820  | 
||
| 
1534.7.50
by Aaron Bentley
 Detect duplicate inventory ids  | 
821  | 
def _duplicate_ids(self):  | 
822  | 
"""Each inventory id may only be used once"""  | 
|
823  | 
conflicts = []  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
824  | 
removed_tree_ids = set((self.tree_file_id(trans_id) for trans_id in  | 
| 
1534.7.50
by Aaron Bentley
 Detect duplicate inventory ids  | 
825  | 
self._removed_id))  | 
826  | 
active_tree_ids = set((f for f in self._tree.inventory if  | 
|
827  | 
f not in removed_tree_ids))  | 
|
828  | 
for trans_id, file_id in self._new_id.iteritems():  | 
|
829  | 
if file_id in active_tree_ids:  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
830  | 
old_trans_id = self.trans_id_tree_file_id(file_id)  | 
| 
1534.7.50
by Aaron Bentley
 Detect duplicate inventory ids  | 
831  | 
conflicts.append(('duplicate id', old_trans_id, trans_id))  | 
832  | 
return conflicts  | 
|
833  | 
||
| 
1534.7.11
by Aaron Bentley
 Refactored conflict handling  | 
834  | 
def _parent_type_conflicts(self, by_parent):  | 
835  | 
"""parents must have directory 'contents'."""  | 
|
836  | 
conflicts = []  | 
|
| 
1534.7.37
by Aaron Bentley
 Allowed removed dirs to have content-free children.  | 
837  | 
for parent_id, children in by_parent.iteritems():  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
838  | 
if parent_id is ROOT_PARENT:  | 
839  | 
                continue
 | 
|
| 
1534.7.37
by Aaron Bentley
 Allowed removed dirs to have content-free children.  | 
840  | 
if not self._any_contents(children):  | 
841  | 
                continue
 | 
|
842  | 
for child in children:  | 
|
843  | 
try:  | 
|
844  | 
self.final_kind(child)  | 
|
845  | 
except NoSuchFile:  | 
|
846  | 
                    continue
 | 
|
| 
1534.7.10
by Aaron Bentley
 Implemented missing parent and non-directory parent conflicts  | 
847  | 
try:  | 
848  | 
kind = self.final_kind(parent_id)  | 
|
849  | 
except NoSuchFile:  | 
|
850  | 
kind = None  | 
|
851  | 
if kind is None:  | 
|
852  | 
conflicts.append(('missing parent', parent_id))  | 
|
853  | 
elif kind != "directory":  | 
|
854  | 
conflicts.append(('non-directory parent', parent_id))  | 
|
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
855  | 
return conflicts  | 
| 
1534.7.37
by Aaron Bentley
 Allowed removed dirs to have content-free children.  | 
856  | 
|
857  | 
def _any_contents(self, trans_ids):  | 
|
858  | 
"""Return true if any of the trans_ids, will have contents."""  | 
|
859  | 
for trans_id in trans_ids:  | 
|
860  | 
try:  | 
|
861  | 
kind = self.final_kind(trans_id)  | 
|
862  | 
except NoSuchFile:  | 
|
863  | 
                continue
 | 
|
864  | 
return True  | 
|
865  | 
return False  | 
|
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
866  | 
|
| 
2733.2.3
by Aaron Bentley
 Test tranform rollback  | 
867  | 
def apply(self, no_conflicts=False, _mover=None):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
868  | 
"""Apply all changes to the inventory and filesystem.  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
869  | 
        
 | 
870  | 
        If filesystem or inventory conflicts are present, MalformedTransform
 | 
|
871  | 
        will be thrown.
 | 
|
| 
2502.1.6
by Aaron Bentley
 Update from review comments  | 
872  | 
|
873  | 
        If apply succeeds, finalize is not necessary.
 | 
|
| 
2590.2.17
by Aaron Bentley
 Avoid redundant conflict check  | 
874  | 
|
875  | 
        :param no_conflicts: if True, the caller guarantees there are no
 | 
|
876  | 
            conflicts, so no check is made.
 | 
|
| 
2733.2.9
by Aaron Bentley
 Update docstrings  | 
877  | 
        :param _mover: Supply an alternate FileMover, for testing
 | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
878  | 
        """
 | 
| 
2590.2.17
by Aaron Bentley
 Avoid redundant conflict check  | 
879  | 
if not no_conflicts:  | 
880  | 
conflicts = self.find_conflicts()  | 
|
881  | 
if len(conflicts) != 0:  | 
|
882  | 
raise MalformedTransform(conflicts=conflicts)  | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
883  | 
inv = self._tree.inventory  | 
| 
2376.2.5
by Aaron Bentley
 Clean up apply methods  | 
884  | 
inventory_delta = []  | 
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
885  | 
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()  | 
886  | 
try:  | 
|
| 
2733.2.3
by Aaron Bentley
 Test tranform rollback  | 
887  | 
if _mover is None:  | 
888  | 
mover = _FileMover()  | 
|
889  | 
else:  | 
|
890  | 
mover = _mover  | 
|
| 
2733.2.2
by Aaron Bentley
 Use FileMover to perform renames in TT  | 
891  | 
try:  | 
892  | 
child_pb.update('Apply phase', 0, 2)  | 
|
893  | 
self._apply_removals(inv, inventory_delta, mover)  | 
|
894  | 
child_pb.update('Apply phase', 1, 2)  | 
|
895  | 
modified_paths = self._apply_insertions(inv, inventory_delta,  | 
|
896  | 
mover)  | 
|
897  | 
except:  | 
|
898  | 
mover.rollback()  | 
|
899  | 
                raise
 | 
|
| 
2733.2.6
by Aaron Bentley
 Make TreeTransform commits rollbackable  | 
900  | 
else:  | 
901  | 
mover.apply_deletions()  | 
|
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
902  | 
finally:  | 
903  | 
child_pb.finished()  | 
|
| 
2376.2.5
by Aaron Bentley
 Clean up apply methods  | 
904  | 
self._tree.apply_inventory_delta(inventory_delta)  | 
| 
1534.7.35
by Aaron Bentley
 Got file renaming working  | 
905  | 
self.__done = True  | 
| 
1534.7.59
by Aaron Bentley
 Simplified tests  | 
906  | 
self.finalize()  | 
| 
2502.1.5
by Aaron Bentley
 Cleanup  | 
907  | 
return _TransformResults(modified_paths, self.rename_count)  | 
| 
1534.7.35
by Aaron Bentley
 Got file renaming working  | 
908  | 
|
| 
2502.1.14
by Aaron Bentley
 Style update suggested by Robert  | 
909  | 
def _limbo_name(self, trans_id):  | 
| 
1534.7.72
by Aaron Bentley
 Moved new content generation to pre-renames  | 
910  | 
"""Generate the limbo name of a file"""  | 
| 
2502.1.14
by Aaron Bentley
 Style update suggested by Robert  | 
911  | 
limbo_name = self._limbo_files.get(trans_id)  | 
912  | 
if limbo_name is not None:  | 
|
913  | 
return limbo_name  | 
|
| 
2502.1.3
by Aaron Bentley
 Don't cause errors when creating contents for trans_ids with no parent/name  | 
914  | 
parent = self._new_parent.get(trans_id)  | 
| 
2502.1.2
by Aaron Bentley
 Make the limited-renames functionality safer in the general case  | 
915  | 
        # if the parent directory is already in limbo (e.g. when building a
 | 
916  | 
        # tree), choose a limbo name inside the parent, to reduce further
 | 
|
917  | 
        # renames.
 | 
|
| 
2502.1.4
by Aaron Bentley
 Ensure we only reuse limbo names appropriately  | 
918  | 
use_direct_path = False  | 
919  | 
if self._new_contents.get(parent) == 'directory':  | 
|
920  | 
filename = self._new_name.get(trans_id)  | 
|
921  | 
if filename is not None:  | 
|
922  | 
if parent not in self._limbo_children:  | 
|
923  | 
self._limbo_children[parent] = set()  | 
|
924  | 
self._limbo_children_names[parent] = {}  | 
|
925  | 
use_direct_path = True  | 
|
| 
2502.1.6
by Aaron Bentley
 Update from review comments  | 
926  | 
                # the direct path can only be used if no other file has
 | 
927  | 
                # already taken this pathname, i.e. if the name is unused, or
 | 
|
928  | 
                # if it is already associated with this trans_id.
 | 
|
| 
3034.4.1
by Aaron Bentley
 Start handling case-insensitivity  | 
929  | 
elif self._tree.case_sensitive:  | 
930  | 
if (self._limbo_children_names[parent].get(filename)  | 
|
931  | 
in (trans_id, None)):  | 
|
932  | 
use_direct_path = True  | 
|
933  | 
else:  | 
|
934  | 
for l_filename, l_trans_id in\  | 
|
935  | 
self._limbo_children_names[parent].iteritems():  | 
|
936  | 
if l_trans_id == trans_id:  | 
|
937  | 
                            continue
 | 
|
938  | 
if l_filename.lower() == filename.lower():  | 
|
939  | 
                            break
 | 
|
940  | 
else:  | 
|
941  | 
use_direct_path = True  | 
|
942  | 
||
| 
2502.1.4
by Aaron Bentley
 Ensure we only reuse limbo names appropriately  | 
943  | 
if use_direct_path:  | 
944  | 
limbo_name = pathjoin(self._limbo_files[parent], filename)  | 
|
| 
2502.1.2
by Aaron Bentley
 Make the limited-renames functionality safer in the general case  | 
945  | 
self._limbo_children[parent].add(trans_id)  | 
| 
2502.1.4
by Aaron Bentley
 Ensure we only reuse limbo names appropriately  | 
946  | 
self._limbo_children_names[parent][filename] = trans_id  | 
| 
2502.1.1
by Aaron Bentley
 Ensure renames only root children are renamed when building trees  | 
947  | 
else:  | 
948  | 
limbo_name = pathjoin(self._limbodir, trans_id)  | 
|
949  | 
self._needs_rename.add(trans_id)  | 
|
950  | 
self._limbo_files[trans_id] = limbo_name  | 
|
951  | 
return limbo_name  | 
|
| 
1534.7.72
by Aaron Bentley
 Moved new content generation to pre-renames  | 
952  | 
|
| 
2733.2.2
by Aaron Bentley
 Use FileMover to perform renames in TT  | 
953  | 
def _apply_removals(self, inv, inventory_delta, mover):  | 
| 
1534.7.36
by Aaron Bentley
 Added rename tests  | 
954  | 
"""Perform tree operations that remove directory/inventory names.  | 
955  | 
        
 | 
|
956  | 
        That is, delete files that are to be deleted, and put any files that
 | 
|
957  | 
        need renaming into limbo.  This must be done in strict child-to-parent
 | 
|
958  | 
        order.
 | 
|
959  | 
        """
 | 
|
| 
1534.7.35
by Aaron Bentley
 Got file renaming working  | 
960  | 
tree_paths = list(self._tree_path_ids.iteritems())  | 
961  | 
tree_paths.sort(reverse=True)  | 
|
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
962  | 
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()  | 
963  | 
try:  | 
|
964  | 
for num, data in enumerate(tree_paths):  | 
|
965  | 
path, trans_id = data  | 
|
966  | 
child_pb.update('removing file', num, len(tree_paths))  | 
|
967  | 
full_path = self._tree.abspath(path)  | 
|
968  | 
if trans_id in self._removed_contents:  | 
|
| 
2733.2.6
by Aaron Bentley
 Make TreeTransform commits rollbackable  | 
969  | 
mover.pre_delete(full_path, os.path.join(self._deletiondir,  | 
970  | 
trans_id))  | 
|
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
971  | 
elif trans_id in self._new_name or trans_id in \  | 
972  | 
self._new_parent:  | 
|
973  | 
try:  | 
|
| 
2733.2.2
by Aaron Bentley
 Use FileMover to perform renames in TT  | 
974  | 
mover.rename(full_path, self._limbo_name(trans_id))  | 
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
975  | 
except OSError, e:  | 
976  | 
if e.errno != errno.ENOENT:  | 
|
977  | 
                            raise
 | 
|
| 
2502.1.1
by Aaron Bentley
 Ensure renames only root children are renamed when building trees  | 
978  | 
else:  | 
979  | 
self.rename_count += 1  | 
|
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
980  | 
if trans_id in self._removed_id:  | 
981  | 
if trans_id == self._new_root:  | 
|
| 
2946.3.3
by John Arbash Meinel
 Prefer tree.get_root_id() as more explicit than tree.path2id('')  | 
982  | 
file_id = self._tree.get_root_id()  | 
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
983  | 
else:  | 
984  | 
file_id = self.tree_file_id(trans_id)  | 
|
| 
2376.2.4
by Aaron Bentley
 Switch TreeTransform to use WT.apply_inventory_delta  | 
985  | 
assert file_id is not None  | 
| 
2376.2.5
by Aaron Bentley
 Clean up apply methods  | 
986  | 
inventory_delta.append((path, None, file_id, None))  | 
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
987  | 
finally:  | 
988  | 
child_pb.finished()  | 
|
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
989  | 
|
| 
2733.2.2
by Aaron Bentley
 Use FileMover to perform renames in TT  | 
990  | 
def _apply_insertions(self, inv, inventory_delta, mover):  | 
| 
1534.7.36
by Aaron Bentley
 Added rename tests  | 
991  | 
"""Perform tree operations that insert directory/inventory names.  | 
992  | 
        
 | 
|
993  | 
        That is, create any files that need to be created, and restore from
 | 
|
994  | 
        limbo any files that needed renaming.  This must be done in strict
 | 
|
995  | 
        parent-to-child order.
 | 
|
996  | 
        """
 | 
|
| 
1534.9.1
by Aaron Bentley
 Added progress bars to merge  | 
997  | 
new_paths = self.new_paths()  | 
| 
1534.7.191
by Aaron Bentley
 Got transform.apply to list modified paths  | 
998  | 
modified_paths = []  | 
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
999  | 
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()  | 
| 
3100.1.1
by Aaron Bentley
 Fix ImmortalLimbo errors when transforms fail  | 
1000  | 
completed_new = []  | 
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
1001  | 
try:  | 
1002  | 
for num, (path, trans_id) in enumerate(new_paths):  | 
|
| 
2376.2.4
by Aaron Bentley
 Switch TreeTransform to use WT.apply_inventory_delta  | 
1003  | 
new_entry = None  | 
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
1004  | 
child_pb.update('adding file', num, len(new_paths))  | 
| 
1534.7.48
by Aaron Bentley
 Ensured we can move/rename dangling inventory entries  | 
1005  | 
try:  | 
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
1006  | 
kind = self._new_contents[trans_id]  | 
1007  | 
except KeyError:  | 
|
1008  | 
kind = contents = None  | 
|
1009  | 
if trans_id in self._new_contents or \  | 
|
1010  | 
self.path_changed(trans_id):  | 
|
1011  | 
full_path = self._tree.abspath(path)  | 
|
| 
2502.1.1
by Aaron Bentley
 Ensure renames only root children are renamed when building trees  | 
1012  | 
if trans_id in self._needs_rename:  | 
1013  | 
try:  | 
|
| 
2733.2.2
by Aaron Bentley
 Use FileMover to perform renames in TT  | 
1014  | 
mover.rename(self._limbo_name(trans_id), full_path)  | 
| 
2502.1.1
by Aaron Bentley
 Ensure renames only root children are renamed when building trees  | 
1015  | 
except OSError, e:  | 
1016  | 
                            # We may be renaming a dangling inventory id
 | 
|
1017  | 
if e.errno != errno.ENOENT:  | 
|
1018  | 
                                raise
 | 
|
1019  | 
else:  | 
|
1020  | 
self.rename_count += 1  | 
|
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
1021  | 
if trans_id in self._new_contents:  | 
1022  | 
modified_paths.append(full_path)  | 
|
| 
3100.1.1
by Aaron Bentley
 Fix ImmortalLimbo errors when transforms fail  | 
1023  | 
completed_new.append(trans_id)  | 
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
1024  | 
|
1025  | 
if trans_id in self._new_id:  | 
|
1026  | 
if kind is None:  | 
|
1027  | 
kind = file_kind(self._tree.abspath(path))  | 
|
| 
2100.3.21
by Aaron Bentley
 Work on checking out by-reference trees  | 
1028  | 
if trans_id in self._new_reference_revision:  | 
| 
2376.2.4
by Aaron Bentley
 Switch TreeTransform to use WT.apply_inventory_delta  | 
1029  | 
new_entry = inventory.TreeReference(  | 
1030  | 
self._new_id[trans_id],  | 
|
| 
2100.3.21
by Aaron Bentley
 Work on checking out by-reference trees  | 
1031  | 
self._new_name[trans_id],  | 
1032  | 
self.final_file_id(self._new_parent[trans_id]),  | 
|
1033  | 
None, self._new_reference_revision[trans_id])  | 
|
1034  | 
else:  | 
|
| 
2376.2.4
by Aaron Bentley
 Switch TreeTransform to use WT.apply_inventory_delta  | 
1035  | 
new_entry = inventory.make_entry(kind,  | 
1036  | 
self.final_name(trans_id),  | 
|
1037  | 
self.final_file_id(self.final_parent(trans_id)),  | 
|
1038  | 
self._new_id[trans_id])  | 
|
1039  | 
else:  | 
|
1040  | 
if trans_id in self._new_name or trans_id in\  | 
|
1041  | 
self._new_parent or\  | 
|
1042  | 
trans_id in self._new_executability:  | 
|
1043  | 
file_id = self.final_file_id(trans_id)  | 
|
1044  | 
if file_id is not None:  | 
|
1045  | 
entry = inv[file_id]  | 
|
1046  | 
new_entry = entry.copy()  | 
|
1047  | 
||
1048  | 
if trans_id in self._new_name or trans_id in\  | 
|
1049  | 
self._new_parent:  | 
|
1050  | 
if new_entry is not None:  | 
|
1051  | 
new_entry.name = self.final_name(trans_id)  | 
|
1052  | 
parent = self.final_parent(trans_id)  | 
|
1053  | 
parent_id = self.final_file_id(parent)  | 
|
1054  | 
new_entry.parent_id = parent_id  | 
|
1055  | 
||
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
1056  | 
if trans_id in self._new_executability:  | 
| 
2376.2.4
by Aaron Bentley
 Switch TreeTransform to use WT.apply_inventory_delta  | 
1057  | 
self._set_executability(path, new_entry, trans_id)  | 
1058  | 
if new_entry is not None:  | 
|
1059  | 
if new_entry.file_id in inv:  | 
|
1060  | 
old_path = inv.id2path(new_entry.file_id)  | 
|
1061  | 
else:  | 
|
1062  | 
old_path = None  | 
|
| 
2376.2.5
by Aaron Bentley
 Clean up apply methods  | 
1063  | 
inventory_delta.append((old_path, path,  | 
1064  | 
new_entry.file_id,  | 
|
1065  | 
new_entry))  | 
|
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
1066  | 
finally:  | 
1067  | 
child_pb.finished()  | 
|
| 
3100.1.1
by Aaron Bentley
 Fix ImmortalLimbo errors when transforms fail  | 
1068  | 
for trans_id in completed_new:  | 
1069  | 
del self._new_contents[trans_id]  | 
|
| 
1534.7.191
by Aaron Bentley
 Got transform.apply to list modified paths  | 
1070  | 
return modified_paths  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
1071  | 
|
| 
2376.2.4
by Aaron Bentley
 Switch TreeTransform to use WT.apply_inventory_delta  | 
1072  | 
def _set_executability(self, path, entry, trans_id):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
1073  | 
"""Set the executability of versioned files """  | 
| 
1534.7.25
by Aaron Bentley
 Added set_executability  | 
1074  | 
new_executability = self._new_executability[trans_id]  | 
| 
2376.2.4
by Aaron Bentley
 Switch TreeTransform to use WT.apply_inventory_delta  | 
1075  | 
entry.executable = new_executability  | 
| 
1534.7.25
by Aaron Bentley
 Added set_executability  | 
1076  | 
if supports_executable():  | 
1077  | 
abspath = self._tree.abspath(path)  | 
|
1078  | 
current_mode = os.stat(abspath).st_mode  | 
|
1079  | 
if new_executability:  | 
|
1080  | 
umask = os.umask(0)  | 
|
1081  | 
os.umask(umask)  | 
|
1082  | 
to_mode = current_mode | (0100 & ~umask)  | 
|
1083  | 
                # Enable x-bit for others only if they can read it.
 | 
|
1084  | 
if current_mode & 0004:  | 
|
1085  | 
to_mode |= 0001 & ~umask  | 
|
1086  | 
if current_mode & 0040:  | 
|
1087  | 
to_mode |= 0010 & ~umask  | 
|
1088  | 
else:  | 
|
1089  | 
to_mode = current_mode & ~0111  | 
|
1090  | 
os.chmod(abspath, to_mode)  | 
|
1091  | 
||
| 
1534.7.23
by Aaron Bentley
 Transform.new_entry -> Transform._new_entry  | 
1092  | 
def _new_entry(self, name, parent_id, file_id):  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
1093  | 
"""Helper function to create a new filesystem entry."""  | 
| 
1534.7.2
by Aaron Bentley
 Added convenience function  | 
1094  | 
trans_id = self.create_path(name, parent_id)  | 
1095  | 
if file_id is not None:  | 
|
1096  | 
self.version_file(file_id, trans_id)  | 
|
1097  | 
return trans_id  | 
|
1098  | 
||
| 
1534.7.27
by Aaron Bentley
 Added execute bit to new_file method  | 
1099  | 
def new_file(self, name, parent_id, contents, file_id=None,  | 
1100  | 
executable=None):  | 
|
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
1101  | 
"""Convenience method to create files.  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
1102  | 
        
 | 
1103  | 
        name is the name of the file to create.
 | 
|
1104  | 
        parent_id is the transaction id of the parent directory of the file.
 | 
|
1105  | 
        contents is an iterator of bytestrings, which will be used to produce
 | 
|
1106  | 
        the file.
 | 
|
| 
1740.2.4
by Aaron Bentley
 Update transform tests and docs  | 
1107  | 
        :param file_id: The inventory ID of the file, if it is to be versioned.
 | 
1108  | 
        :param executable: Only valid when a file_id has been supplied.
 | 
|
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
1109  | 
        """
 | 
| 
1534.7.23
by Aaron Bentley
 Transform.new_entry -> Transform._new_entry  | 
1110  | 
trans_id = self._new_entry(name, parent_id, file_id)  | 
| 
1740.2.4
by Aaron Bentley
 Update transform tests and docs  | 
1111  | 
        # TODO: rather than scheduling a set_executable call,
 | 
1112  | 
        # have create_file create the file with the right mode.
 | 
|
| 
1534.7.20
by Aaron Bentley
 Added directory handling  | 
1113  | 
self.create_file(contents, trans_id)  | 
| 
1534.7.27
by Aaron Bentley
 Added execute bit to new_file method  | 
1114  | 
if executable is not None:  | 
1115  | 
self.set_executability(executable, trans_id)  | 
|
| 
1534.7.20
by Aaron Bentley
 Added directory handling  | 
1116  | 
return trans_id  | 
1117  | 
||
1118  | 
def new_directory(self, name, parent_id, file_id=None):  | 
|
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
1119  | 
"""Convenience method to create directories.  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
1120  | 
|
1121  | 
        name is the name of the directory to create.
 | 
|
1122  | 
        parent_id is the transaction id of the parent directory of the
 | 
|
1123  | 
        directory.
 | 
|
1124  | 
        file_id is the inventory ID of the directory, if it is to be versioned.
 | 
|
1125  | 
        """
 | 
|
| 
1534.7.23
by Aaron Bentley
 Transform.new_entry -> Transform._new_entry  | 
1126  | 
trans_id = self._new_entry(name, parent_id, file_id)  | 
| 
1534.7.20
by Aaron Bentley
 Added directory handling  | 
1127  | 
self.create_directory(trans_id)  | 
1128  | 
return trans_id  | 
|
1129  | 
||
| 
1534.7.22
by Aaron Bentley
 Added symlink support  | 
1130  | 
def new_symlink(self, name, parent_id, target, file_id=None):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
1131  | 
"""Convenience method to create symbolic link.  | 
| 
1534.7.22
by Aaron Bentley
 Added symlink support  | 
1132  | 
        
 | 
1133  | 
        name is the name of the symlink to create.
 | 
|
1134  | 
        parent_id is the transaction id of the parent directory of the symlink.
 | 
|
1135  | 
        target is a bytestring of the target of the symlink.
 | 
|
1136  | 
        file_id is the inventory ID of the file, if it is to be versioned.
 | 
|
1137  | 
        """
 | 
|
| 
1534.7.23
by Aaron Bentley
 Transform.new_entry -> Transform._new_entry  | 
1138  | 
trans_id = self._new_entry(name, parent_id, file_id)  | 
| 
1534.7.22
by Aaron Bentley
 Added symlink support  | 
1139  | 
self.create_symlink(target, trans_id)  | 
1140  | 
return trans_id  | 
|
1141  | 
||
| 
1551.11.12
by Aaron Bentley
 Changes from review  | 
1142  | 
def _affected_ids(self):  | 
1143  | 
"""Return the set of transform ids affected by the transform"""  | 
|
| 
1551.11.1
by Aaron Bentley
 Initial work on converting TreeTransform to iter_changes format  | 
1144  | 
trans_ids = set(self._removed_id)  | 
1145  | 
trans_ids.update(self._new_id.keys())  | 
|
| 
1551.11.2
by Aaron Bentley
 Get kind change detection working for iter_changes  | 
1146  | 
trans_ids.update(self._removed_contents)  | 
1147  | 
trans_ids.update(self._new_contents.keys())  | 
|
1148  | 
trans_ids.update(self._new_executability.keys())  | 
|
1149  | 
trans_ids.update(self._new_name.keys())  | 
|
1150  | 
trans_ids.update(self._new_parent.keys())  | 
|
| 
1551.11.12
by Aaron Bentley
 Changes from review  | 
1151  | 
return trans_ids  | 
1152  | 
||
1153  | 
def _get_file_id_maps(self):  | 
|
1154  | 
"""Return mapping of file_ids to trans_ids in the to and from states"""  | 
|
1155  | 
trans_ids = self._affected_ids()  | 
|
| 
1551.11.1
by Aaron Bentley
 Initial work on converting TreeTransform to iter_changes format  | 
1156  | 
from_trans_ids = {}  | 
1157  | 
to_trans_ids = {}  | 
|
1158  | 
        # Build up two dicts: trans_ids associated with file ids in the
 | 
|
1159  | 
        # FROM state, vs the TO state.
 | 
|
1160  | 
for trans_id in trans_ids:  | 
|
1161  | 
from_file_id = self.tree_file_id(trans_id)  | 
|
1162  | 
if from_file_id is not None:  | 
|
1163  | 
from_trans_ids[from_file_id] = trans_id  | 
|
1164  | 
to_file_id = self.final_file_id(trans_id)  | 
|
1165  | 
if to_file_id is not None:  | 
|
1166  | 
to_trans_ids[to_file_id] = trans_id  | 
|
| 
1551.11.12
by Aaron Bentley
 Changes from review  | 
1167  | 
return from_trans_ids, to_trans_ids  | 
1168  | 
||
1169  | 
def _from_file_data(self, from_trans_id, from_versioned, file_id):  | 
|
1170  | 
"""Get data about a file in the from (tree) state  | 
|
1171  | 
||
1172  | 
        Return a (name, parent, kind, executable) tuple
 | 
|
1173  | 
        """
 | 
|
1174  | 
from_path = self._tree_id_paths.get(from_trans_id)  | 
|
1175  | 
if from_versioned:  | 
|
1176  | 
            # get data from working tree if versioned
 | 
|
1177  | 
from_entry = self._tree.inventory[file_id]  | 
|
1178  | 
from_name = from_entry.name  | 
|
1179  | 
from_parent = from_entry.parent_id  | 
|
1180  | 
else:  | 
|
1181  | 
from_entry = None  | 
|
1182  | 
if from_path is None:  | 
|
1183  | 
                # File does not exist in FROM state
 | 
|
1184  | 
from_name = None  | 
|
1185  | 
from_parent = None  | 
|
1186  | 
else:  | 
|
1187  | 
                # File exists, but is not versioned.  Have to use path-
 | 
|
1188  | 
                # splitting stuff
 | 
|
1189  | 
from_name = os.path.basename(from_path)  | 
|
1190  | 
tree_parent = self.get_tree_parent(from_trans_id)  | 
|
1191  | 
from_parent = self.tree_file_id(tree_parent)  | 
|
1192  | 
if from_path is not None:  | 
|
1193  | 
from_kind, from_executable, from_stats = \  | 
|
1194  | 
self._tree._comparison_data(from_entry, from_path)  | 
|
1195  | 
else:  | 
|
1196  | 
from_kind = None  | 
|
1197  | 
from_executable = False  | 
|
1198  | 
return from_name, from_parent, from_kind, from_executable  | 
|
1199  | 
||
1200  | 
def _to_file_data(self, to_trans_id, from_trans_id, from_executable):  | 
|
1201  | 
"""Get data about a file in the to (target) state  | 
|
1202  | 
||
1203  | 
        Return a (name, parent, kind, executable) tuple
 | 
|
1204  | 
        """
 | 
|
1205  | 
to_name = self.final_name(to_trans_id)  | 
|
1206  | 
try:  | 
|
1207  | 
to_kind = self.final_kind(to_trans_id)  | 
|
1208  | 
except NoSuchFile:  | 
|
1209  | 
to_kind = None  | 
|
1210  | 
to_parent = self.final_file_id(self.final_parent(to_trans_id))  | 
|
1211  | 
if to_trans_id in self._new_executability:  | 
|
1212  | 
to_executable = self._new_executability[to_trans_id]  | 
|
1213  | 
elif to_trans_id == from_trans_id:  | 
|
1214  | 
to_executable = from_executable  | 
|
1215  | 
else:  | 
|
1216  | 
to_executable = False  | 
|
1217  | 
return to_name, to_parent, to_kind, to_executable  | 
|
1218  | 
||
1219  | 
def _iter_changes(self):  | 
|
1220  | 
"""Produce output in the same format as Tree._iter_changes.  | 
|
1221  | 
||
1222  | 
        Will produce nonsensical results if invoked while inventory/filesystem
 | 
|
1223  | 
        conflicts (as reported by TreeTransform.find_conflicts()) are present.
 | 
|
1224  | 
||
1225  | 
        This reads the Transform, but only reproduces changes involving a
 | 
|
1226  | 
        file_id.  Files that are not versioned in either of the FROM or TO
 | 
|
1227  | 
        states are not reflected.
 | 
|
1228  | 
        """
 | 
|
1229  | 
final_paths = FinalPaths(self)  | 
|
1230  | 
from_trans_ids, to_trans_ids = self._get_file_id_maps()  | 
|
| 
1551.11.4
by Aaron Bentley
 Sort output of Transform.iter_changes by path  | 
1231  | 
results = []  | 
| 
1551.11.1
by Aaron Bentley
 Initial work on converting TreeTransform to iter_changes format  | 
1232  | 
        # Now iterate through all active file_ids
 | 
1233  | 
for file_id in set(from_trans_ids.keys() + to_trans_ids.keys()):  | 
|
| 
1551.11.7
by Aaron Bentley
 Stop modified flag bleeding into later changes  | 
1234  | 
modified = False  | 
| 
1551.11.1
by Aaron Bentley
 Initial work on converting TreeTransform to iter_changes format  | 
1235  | 
from_trans_id = from_trans_ids.get(file_id)  | 
1236  | 
            # find file ids, and determine versioning state
 | 
|
1237  | 
if from_trans_id is None:  | 
|
1238  | 
from_versioned = False  | 
|
1239  | 
from_trans_id = to_trans_ids[file_id]  | 
|
1240  | 
else:  | 
|
1241  | 
from_versioned = True  | 
|
1242  | 
to_trans_id = to_trans_ids.get(file_id)  | 
|
1243  | 
if to_trans_id is None:  | 
|
1244  | 
to_versioned = False  | 
|
1245  | 
to_trans_id = from_trans_id  | 
|
1246  | 
else:  | 
|
1247  | 
to_versioned = True  | 
|
| 
1551.11.12
by Aaron Bentley
 Changes from review  | 
1248  | 
|
1249  | 
from_name, from_parent, from_kind, from_executable = \  | 
|
1250  | 
self._from_file_data(from_trans_id, from_versioned, file_id)  | 
|
1251  | 
||
1252  | 
to_name, to_parent, to_kind, to_executable = \  | 
|
1253  | 
self._to_file_data(to_trans_id, from_trans_id, from_executable)  | 
|
1254  | 
||
| 
2255.7.96
by Robert Collins
 Change _iter_changes interface to yield both old and new paths.  | 
1255  | 
if not from_versioned:  | 
1256  | 
from_path = None  | 
|
1257  | 
else:  | 
|
1258  | 
from_path = self._tree_id_paths.get(from_trans_id)  | 
|
1259  | 
if not to_versioned:  | 
|
1260  | 
to_path = None  | 
|
1261  | 
else:  | 
|
1262  | 
to_path = final_paths.get_path(to_trans_id)  | 
|
| 
1551.11.1
by Aaron Bentley
 Initial work on converting TreeTransform to iter_changes format  | 
1263  | 
if from_kind != to_kind:  | 
1264  | 
modified = True  | 
|
| 
1551.10.37
by Aaron Bentley
 recommit of TreeTransform._iter_changes fix with missing files  | 
1265  | 
elif to_kind in ('file', 'symlink') and (  | 
| 
1551.11.2
by Aaron Bentley
 Get kind change detection working for iter_changes  | 
1266  | 
to_trans_id != from_trans_id or  | 
1267  | 
to_trans_id in self._new_contents):  | 
|
1268  | 
modified = True  | 
|
1269  | 
if (not modified and from_versioned == to_versioned and  | 
|
1270  | 
from_parent==to_parent and from_name == to_name and  | 
|
1271  | 
from_executable == to_executable):  | 
|
1272  | 
                continue
 | 
|
| 
2255.7.96
by Robert Collins
 Change _iter_changes interface to yield both old and new paths.  | 
1273  | 
results.append((file_id, (from_path, to_path), modified,  | 
| 
1551.11.1
by Aaron Bentley
 Initial work on converting TreeTransform to iter_changes format  | 
1274  | 
(from_versioned, to_versioned),  | 
| 
1551.11.2
by Aaron Bentley
 Get kind change detection working for iter_changes  | 
1275  | 
(from_parent, to_parent),  | 
| 
1551.11.1
by Aaron Bentley
 Initial work on converting TreeTransform to iter_changes format  | 
1276  | 
(from_name, to_name),  | 
1277  | 
(from_kind, to_kind),  | 
|
| 
1551.11.4
by Aaron Bentley
 Sort output of Transform.iter_changes by path  | 
1278  | 
(from_executable, to_executable)))  | 
1279  | 
return iter(sorted(results, key=lambda x:x[1]))  | 
|
| 
1551.11.1
by Aaron Bentley
 Initial work on converting TreeTransform to iter_changes format  | 
1280  | 
|
1281  | 
||
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
1282  | 
def joinpath(parent, child):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
1283  | 
"""Join tree-relative paths, handling the tree root specially"""  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
1284  | 
if parent is None or parent == "":  | 
1285  | 
return child  | 
|
1286  | 
else:  | 
|
| 
1534.7.166
by Aaron Bentley
 Swapped os.path.join for pathjoin everywhere  | 
1287  | 
return pathjoin(parent, child)  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
1288  | 
|
| 
1534.7.167
by Aaron Bentley
 PEP8 and comment cleanups  | 
1289  | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
1290  | 
class FinalPaths(object):  | 
| 
1759.2.2
by Jelmer Vernooij
 Revert some of my spelling fixes and fix some typos after review by Aaron.  | 
1291  | 
"""Make path calculation cheap by memoizing paths.  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
1292  | 
|
1293  | 
    The underlying tree must not be manipulated between calls, or else
 | 
|
1294  | 
    the results will likely be incorrect.
 | 
|
1295  | 
    """
 | 
|
| 
1534.7.132
by Aaron Bentley
 Got cooked conflicts working  | 
1296  | 
def __init__(self, transform):  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
1297  | 
object.__init__(self)  | 
1298  | 
self._known_paths = {}  | 
|
| 
1534.7.33
by Aaron Bentley
 Fixed naming  | 
1299  | 
self.transform = transform  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
1300  | 
|
1301  | 
def _determine_path(self, trans_id):  | 
|
| 
1534.7.132
by Aaron Bentley
 Got cooked conflicts working  | 
1302  | 
if trans_id == self.transform.root:  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
1303  | 
return ""  | 
| 
1534.7.33
by Aaron Bentley
 Fixed naming  | 
1304  | 
name = self.transform.final_name(trans_id)  | 
1305  | 
parent_id = self.transform.final_parent(trans_id)  | 
|
| 
1534.7.132
by Aaron Bentley
 Got cooked conflicts working  | 
1306  | 
if parent_id == self.transform.root:  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
1307  | 
return name  | 
1308  | 
else:  | 
|
| 
1534.7.166
by Aaron Bentley
 Swapped os.path.join for pathjoin everywhere  | 
1309  | 
return pathjoin(self.get_path(parent_id), name)  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
1310  | 
|
1311  | 
def get_path(self, trans_id):  | 
|
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
1312  | 
"""Find the final path associated with a trans_id"""  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
1313  | 
if trans_id not in self._known_paths:  | 
1314  | 
self._known_paths[trans_id] = self._determine_path(trans_id)  | 
|
1315  | 
return self._known_paths[trans_id]  | 
|
| 
1534.7.28
by Aaron Bentley
 Nearly-working build_tree replacement  | 
1316  | 
|
| 
3006.2.2
by Alexander Belchenko
 tests added.  | 
1317  | 
|
| 
1534.7.30
by Aaron Bentley
 Factored out topological id sorting  | 
1318  | 
def topology_sorted_ids(tree):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
1319  | 
"""Determine the topological order of the ids in a tree"""  | 
| 
1534.7.30
by Aaron Bentley
 Factored out topological id sorting  | 
1320  | 
file_ids = list(tree)  | 
1321  | 
file_ids.sort(key=tree.id2path)  | 
|
1322  | 
return file_ids  | 
|
| 
1534.7.28
by Aaron Bentley
 Nearly-working build_tree replacement  | 
1323  | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1324  | 
|
| 
1534.7.165
by Aaron Bentley
 Switched to build_tree instead of revert  | 
1325  | 
def build_tree(tree, wt):  | 
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1326  | 
"""Create working tree for a branch, using a TreeTransform.  | 
1327  | 
    
 | 
|
| 
1966.1.2
by Aaron Bentley
 Divert files instead of failing to create them, update from review  | 
1328  | 
    This function should be used on empty trees, having a tree root at most.
 | 
1329  | 
    (see merge and revert functionality for working with existing trees)
 | 
|
1330  | 
||
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1331  | 
    Existing files are handled like so:
 | 
1332  | 
    
 | 
|
| 
1966.1.2
by Aaron Bentley
 Divert files instead of failing to create them, update from review  | 
1333  | 
    - Existing bzrdirs take precedence over creating new items.  They are
 | 
1334  | 
      created as '%s.diverted' % name.
 | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1335  | 
    - Otherwise, if the content on disk matches the content we are building,
 | 
1336  | 
      it is silently replaced.
 | 
|
1337  | 
    - Otherwise, conflict resolution will move the old file to 'oldname.moved'.
 | 
|
1338  | 
    """
 | 
|
| 
2255.7.51
by Robert Collins
 Lock build_tree trees in write-first order, to support older formats that dont do lock_tree_write nicely.  | 
1339  | 
wt.lock_tree_write()  | 
| 
2255.7.49
by Robert Collins
 Lock trees passed in to build_tree.  | 
1340  | 
try:  | 
| 
2255.7.51
by Robert Collins
 Lock build_tree trees in write-first order, to support older formats that dont do lock_tree_write nicely.  | 
1341  | 
tree.lock_read()  | 
| 
2255.7.49
by Robert Collins
 Lock trees passed in to build_tree.  | 
1342  | 
try:  | 
1343  | 
return _build_tree(tree, wt)  | 
|
1344  | 
finally:  | 
|
| 
2255.7.51
by Robert Collins
 Lock build_tree trees in write-first order, to support older formats that dont do lock_tree_write nicely.  | 
1345  | 
tree.unlock()  | 
| 
2255.7.49
by Robert Collins
 Lock trees passed in to build_tree.  | 
1346  | 
finally:  | 
| 
2255.7.51
by Robert Collins
 Lock build_tree trees in write-first order, to support older formats that dont do lock_tree_write nicely.  | 
1347  | 
wt.unlock()  | 
| 
2255.7.49
by Robert Collins
 Lock trees passed in to build_tree.  | 
1348  | 
|
| 
3006.2.2
by Alexander Belchenko
 tests added.  | 
1349  | 
|
| 
2255.7.49
by Robert Collins
 Lock trees passed in to build_tree.  | 
1350  | 
def _build_tree(tree, wt):  | 
1351  | 
"""See build_tree."""  | 
|
| 
2090.2.1
by Martin Pool
 Fix some code which relies on assertions and breaks under python -O  | 
1352  | 
if len(wt.inventory) > 1: # more than just a root  | 
1353  | 
raise errors.WorkingTreeAlreadyPopulated(base=wt.basedir)  | 
|
| 
1534.7.28
by Aaron Bentley
 Nearly-working build_tree replacement  | 
1354  | 
file_trans_id = {}  | 
| 
1558.11.1
by Aaron Bentley
 Progress indicator for tree builts  | 
1355  | 
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()  | 
1356  | 
pp = ProgressPhase("Build phase", 2, top_pb)  | 
|
| 
2255.2.183
by Martin Pool
 add missing _must_be_locked and a better message  | 
1357  | 
if tree.inventory.root is not None:  | 
| 
2502.1.6
by Aaron Bentley
 Update from review comments  | 
1358  | 
        # This is kind of a hack: we should be altering the root
 | 
1359  | 
        # as part of the regular tree shape diff logic.
 | 
|
1360  | 
        # The conditional test here is to avoid doing an
 | 
|
| 
2255.2.194
by Robert Collins
 [BROKEN] Many updates to stop using experimental formats in tests.  | 
1361  | 
        # expensive operation (flush) every time the root id
 | 
1362  | 
        # is set within the tree, nor setting the root and thus
 | 
|
1363  | 
        # marking the tree as dirty, because we use two different
 | 
|
1364  | 
        # idioms here: tree interfaces and inventory interfaces.
 | 
|
| 
2946.3.3
by John Arbash Meinel
 Prefer tree.get_root_id() as more explicit than tree.path2id('')  | 
1365  | 
if wt.get_root_id() != tree.get_root_id():  | 
1366  | 
wt.set_root_id(tree.get_root_id())  | 
|
| 
2255.2.194
by Robert Collins
 [BROKEN] Many updates to stop using experimental formats in tests.  | 
1367  | 
wt.flush()  | 
| 
1534.7.28
by Aaron Bentley
 Nearly-working build_tree replacement  | 
1368  | 
tt = TreeTransform(wt)  | 
| 
1966.1.2
by Aaron Bentley
 Divert files instead of failing to create them, update from review  | 
1369  | 
divert = set()  | 
| 
1534.7.28
by Aaron Bentley
 Nearly-working build_tree replacement  | 
1370  | 
try:  | 
| 
1558.11.1
by Aaron Bentley
 Progress indicator for tree builts  | 
1371  | 
pp.next_phase()  | 
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1372  | 
file_trans_id[wt.get_root_id()] = \  | 
1373  | 
tt.trans_id_tree_file_id(wt.get_root_id())  | 
|
| 
1558.11.1
by Aaron Bentley
 Progress indicator for tree builts  | 
1374  | 
pb = bzrlib.ui.ui_factory.nested_progress_bar()  | 
1375  | 
try:  | 
|
| 
2708.1.2
by Aaron Bentley
 Use extract_files_bytes for build_tree  | 
1376  | 
deferred_contents = []  | 
| 
1966.1.2
by Aaron Bentley
 Divert files instead of failing to create them, update from review  | 
1377  | 
for num, (tree_path, entry) in \  | 
1378  | 
enumerate(tree.inventory.iter_entries_by_dir()):  | 
|
| 
2708.1.8
by Aaron Bentley
 rename extract_files_bytest to iter_files_bytes, fix build_tree / progress  | 
1379  | 
pb.update("Building tree", num - len(deferred_contents),  | 
1380  | 
len(tree.inventory))  | 
|
| 
1558.11.1
by Aaron Bentley
 Progress indicator for tree builts  | 
1381  | 
if entry.parent_id is None:  | 
1382  | 
                    continue
 | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1383  | 
reparent = False  | 
| 
1966.1.2
by Aaron Bentley
 Divert files instead of failing to create them, update from review  | 
1384  | 
file_id = entry.file_id  | 
1385  | 
target_path = wt.abspath(tree_path)  | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1386  | 
try:  | 
1387  | 
kind = file_kind(target_path)  | 
|
1388  | 
except NoSuchFile:  | 
|
1389  | 
                    pass
 | 
|
1390  | 
else:  | 
|
1391  | 
if kind == "directory":  | 
|
1392  | 
try:  | 
|
1393  | 
bzrdir.BzrDir.open(target_path)  | 
|
1394  | 
except errors.NotBranchError:  | 
|
1395  | 
                            pass
 | 
|
1396  | 
else:  | 
|
| 
1966.1.2
by Aaron Bentley
 Divert files instead of failing to create them, update from review  | 
1397  | 
divert.add(file_id)  | 
1398  | 
if (file_id not in divert and  | 
|
1399  | 
_content_match(tree, entry, file_id, kind,  | 
|
1400  | 
target_path)):  | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1401  | 
tt.delete_contents(tt.trans_id_tree_path(tree_path))  | 
1402  | 
if kind == 'directory':  | 
|
1403  | 
reparent = True  | 
|
| 
1558.11.1
by Aaron Bentley
 Progress indicator for tree builts  | 
1404  | 
if entry.parent_id not in file_trans_id:  | 
| 
2255.2.183
by Martin Pool
 add missing _must_be_locked and a better message  | 
1405  | 
raise AssertionError(  | 
1406  | 
'entry %s parent id %r is not in file_trans_id %r'  | 
|
1407  | 
% (entry, entry.parent_id, file_trans_id))  | 
|
| 
1558.11.1
by Aaron Bentley
 Progress indicator for tree builts  | 
1408  | 
parent_id = file_trans_id[entry.parent_id]  | 
| 
2708.1.8
by Aaron Bentley
 rename extract_files_bytest to iter_files_bytes, fix build_tree / progress  | 
1409  | 
if entry.kind == 'file':  | 
| 
2708.1.2
by Aaron Bentley
 Use extract_files_bytes for build_tree  | 
1410  | 
                    # We *almost* replicate new_by_entry, so that we can defer
 | 
1411  | 
                    # getting the file text, and get them all at once.
 | 
|
1412  | 
trans_id = tt.create_path(entry.name, parent_id)  | 
|
| 
2708.1.8
by Aaron Bentley
 rename extract_files_bytest to iter_files_bytes, fix build_tree / progress  | 
1413  | 
file_trans_id[file_id] = trans_id  | 
1414  | 
tt.version_file(entry.file_id, trans_id)  | 
|
| 
2708.1.2
by Aaron Bentley
 Use extract_files_bytes for build_tree  | 
1415  | 
executable = tree.is_executable(entry.file_id, tree_path)  | 
1416  | 
if executable is not None:  | 
|
| 
2708.1.8
by Aaron Bentley
 rename extract_files_bytest to iter_files_bytes, fix build_tree / progress  | 
1417  | 
tt.set_executability(executable, trans_id)  | 
| 
2708.1.2
by Aaron Bentley
 Use extract_files_bytes for build_tree  | 
1418  | 
deferred_contents.append((entry.file_id, trans_id))  | 
1419  | 
else:  | 
|
1420  | 
file_trans_id[file_id] = new_by_entry(tt, entry, parent_id,  | 
|
1421  | 
tree)  | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1422  | 
if reparent:  | 
1423  | 
new_trans_id = file_trans_id[file_id]  | 
|
1424  | 
old_parent = tt.trans_id_tree_path(tree_path)  | 
|
1425  | 
_reparent_children(tt, old_parent, new_trans_id)  | 
|
| 
2708.1.8
by Aaron Bentley
 rename extract_files_bytest to iter_files_bytes, fix build_tree / progress  | 
1426  | 
for num, (trans_id, bytes) in enumerate(  | 
1427  | 
tree.iter_files_bytes(deferred_contents)):  | 
|
| 
2708.1.6
by Aaron Bentley
 Turn extract_files_bytes into an iterator  | 
1428  | 
tt.create_file(bytes, trans_id)  | 
| 
2708.1.8
by Aaron Bentley
 rename extract_files_bytest to iter_files_bytes, fix build_tree / progress  | 
1429  | 
pb.update('Adding file contents',  | 
1430  | 
(num + len(tree.inventory) - len(deferred_contents)),  | 
|
1431  | 
len(tree.inventory))  | 
|
| 
1558.11.1
by Aaron Bentley
 Progress indicator for tree builts  | 
1432  | 
finally:  | 
1433  | 
pb.finished()  | 
|
1434  | 
pp.next_phase()  | 
|
| 
1966.1.2
by Aaron Bentley
 Divert files instead of failing to create them, update from review  | 
1435  | 
divert_trans = set(file_trans_id[f] for f in divert)  | 
1436  | 
resolver = lambda t, c: resolve_checkout(t, c, divert_trans)  | 
|
1437  | 
raw_conflicts = resolve_conflicts(tt, pass_func=resolver)  | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1438  | 
conflicts = cook_conflicts(raw_conflicts, tt)  | 
1439  | 
for conflict in conflicts:  | 
|
1440  | 
warning(conflict)  | 
|
1441  | 
try:  | 
|
1442  | 
wt.add_conflicts(conflicts)  | 
|
1443  | 
except errors.UnsupportedOperation:  | 
|
1444  | 
            pass
 | 
|
| 
2502.1.5
by Aaron Bentley
 Cleanup  | 
1445  | 
result = tt.apply()  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1446  | 
finally:  | 
1447  | 
tt.finalize()  | 
|
| 
1558.11.1
by Aaron Bentley
 Progress indicator for tree builts  | 
1448  | 
top_pb.finished()  | 
| 
2502.1.5
by Aaron Bentley
 Cleanup  | 
1449  | 
return result  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1450  | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1451  | 
|
1452  | 
def _reparent_children(tt, old_parent, new_parent):  | 
|
1453  | 
for child in tt.iter_tree_children(old_parent):  | 
|
1454  | 
tt.adjust_path(tt.final_name(child), new_parent, child)  | 
|
1455  | 
||
1456  | 
||
1457  | 
def _content_match(tree, entry, file_id, kind, target_path):  | 
|
1458  | 
if entry.kind != kind:  | 
|
1459  | 
return False  | 
|
1460  | 
if entry.kind == "directory":  | 
|
1461  | 
return True  | 
|
1462  | 
if entry.kind == "file":  | 
|
1463  | 
if tree.get_file(file_id).read() == file(target_path, 'rb').read():  | 
|
1464  | 
return True  | 
|
1465  | 
elif entry.kind == "symlink":  | 
|
1466  | 
if tree.get_symlink_target(file_id) == os.readlink(target_path):  | 
|
1467  | 
return True  | 
|
1468  | 
return False  | 
|
1469  | 
||
1470  | 
||
| 
1966.1.2
by Aaron Bentley
 Divert files instead of failing to create them, update from review  | 
1471  | 
def resolve_checkout(tt, conflicts, divert):  | 
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1472  | 
new_conflicts = set()  | 
1473  | 
for c_type, conflict in ((c[0], c) for c in conflicts):  | 
|
1474  | 
        # Anything but a 'duplicate' would indicate programmer error
 | 
|
1475  | 
assert c_type == 'duplicate', c_type  | 
|
1476  | 
        # Now figure out which is new and which is old
 | 
|
| 
1966.1.2
by Aaron Bentley
 Divert files instead of failing to create them, update from review  | 
1477  | 
if tt.new_contents(conflict[1]):  | 
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1478  | 
new_file = conflict[1]  | 
1479  | 
old_file = conflict[2]  | 
|
1480  | 
else:  | 
|
1481  | 
new_file = conflict[2]  | 
|
1482  | 
old_file = conflict[1]  | 
|
1483  | 
||
1484  | 
        # We should only get here if the conflict wasn't completely
 | 
|
1485  | 
        # resolved
 | 
|
1486  | 
final_parent = tt.final_parent(old_file)  | 
|
| 
1966.1.2
by Aaron Bentley
 Divert files instead of failing to create them, update from review  | 
1487  | 
if new_file in divert:  | 
1488  | 
new_name = tt.final_name(old_file)+'.diverted'  | 
|
1489  | 
tt.adjust_path(new_name, final_parent, new_file)  | 
|
1490  | 
new_conflicts.add((c_type, 'Diverted to',  | 
|
1491  | 
new_file, old_file))  | 
|
1492  | 
else:  | 
|
1493  | 
new_name = tt.final_name(old_file)+'.moved'  | 
|
1494  | 
tt.adjust_path(new_name, final_parent, old_file)  | 
|
1495  | 
new_conflicts.add((c_type, 'Moved existing file to',  | 
|
1496  | 
old_file, new_file))  | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1497  | 
return new_conflicts  | 
1498  | 
||
1499  | 
||
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1500  | 
def new_by_entry(tt, entry, parent_id, tree):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
1501  | 
"""Create a new file according to its inventory entry"""  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1502  | 
name = entry.name  | 
1503  | 
kind = entry.kind  | 
|
1504  | 
if kind == 'file':  | 
|
| 
1534.7.79
by Aaron Bentley
 Stopped calling get_file_lines on WorkingTree  | 
1505  | 
contents = tree.get_file(entry.file_id).readlines()  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1506  | 
executable = tree.is_executable(entry.file_id)  | 
1507  | 
return tt.new_file(name, parent_id, contents, entry.file_id,  | 
|
1508  | 
executable)  | 
|
| 
2100.3.21
by Aaron Bentley
 Work on checking out by-reference trees  | 
1509  | 
elif kind in ('directory', 'tree-reference'):  | 
1510  | 
trans_id = tt.new_directory(name, parent_id, entry.file_id)  | 
|
1511  | 
if kind == 'tree-reference':  | 
|
1512  | 
tt.set_tree_reference(entry.reference_revision, trans_id)  | 
|
1513  | 
return trans_id  | 
|
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1514  | 
elif kind == 'symlink':  | 
| 
1534.7.183
by Aaron Bentley
 Fixed build_tree with symlinks  | 
1515  | 
target = tree.get_symlink_target(entry.file_id)  | 
1516  | 
return tt.new_symlink(name, parent_id, target, entry.file_id)  | 
|
| 
2100.3.21
by Aaron Bentley
 Work on checking out by-reference trees  | 
1517  | 
else:  | 
1518  | 
raise errors.BadFileKindError(name, kind)  | 
|
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1519  | 
|
| 
3006.2.2
by Alexander Belchenko
 tests added.  | 
1520  | 
|
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
1521  | 
def create_by_entry(tt, entry, tree, trans_id, lines=None, mode_id=None):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
1522  | 
"""Create new file contents according to an inventory entry."""  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1523  | 
if entry.kind == "file":  | 
| 
1963.2.6
by Robey Pointer
 pychecker is on crack; go back to using 'is None'.  | 
1524  | 
if lines is None:  | 
| 
1534.7.97
by Aaron Bentley
 Ensured foo.BASE is a directory if there's a conflict  | 
1525  | 
lines = tree.get_file(entry.file_id).readlines()  | 
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
1526  | 
tt.create_file(lines, trans_id, mode_id=mode_id)  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1527  | 
elif entry.kind == "symlink":  | 
| 
1534.7.101
by Aaron Bentley
 Got conflicts on symlinks working properly  | 
1528  | 
tt.create_symlink(tree.get_symlink_target(entry.file_id), trans_id)  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1529  | 
elif entry.kind == "directory":  | 
| 
1534.7.51
by Aaron Bentley
 New approach to revert  | 
1530  | 
tt.create_directory(trans_id)  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1531  | 
|
| 
3006.2.2
by Alexander Belchenko
 tests added.  | 
1532  | 
|
| 
1534.7.89
by Aaron Bentley
 Handle all content types in three-way  | 
1533  | 
def create_entry_executability(tt, entry, trans_id):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
1534  | 
"""Set the executability of a trans_id according to an inventory entry"""  | 
| 
1534.7.89
by Aaron Bentley
 Handle all content types in three-way  | 
1535  | 
if entry.kind == "file":  | 
1536  | 
tt.set_executability(entry.executable, trans_id)  | 
|
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1537  | 
|
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
1538  | 
|
| 
2255.7.48
by Robert Collins
 Deprecated and make work with DirState trees 'transform.find_interesting'.  | 
1539  | 
@deprecated_function(zero_fifteen)  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1540  | 
def find_interesting(working_tree, target_tree, filenames):  | 
| 
2255.7.48
by Robert Collins
 Deprecated and make work with DirState trees 'transform.find_interesting'.  | 
1541  | 
"""Find the ids corresponding to specified filenames.  | 
1542  | 
    
 | 
|
1543  | 
    Deprecated: Please use tree1.paths2ids(filenames, [tree2]).
 | 
|
1544  | 
    """
 | 
|
1545  | 
working_tree.lock_read()  | 
|
1546  | 
try:  | 
|
1547  | 
target_tree.lock_read()  | 
|
1548  | 
try:  | 
|
1549  | 
return working_tree.paths2ids(filenames, [target_tree])  | 
|
1550  | 
finally:  | 
|
1551  | 
target_tree.unlock()  | 
|
1552  | 
finally:  | 
|
1553  | 
working_tree.unlock()  | 
|
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1554  | 
|
1555  | 
||
| 
2687.2.1
by Martin Pool
 Rename upcoming release from 0.19 to 0.90  | 
1556  | 
@deprecated_function(zero_ninety)  | 
| 
1534.7.56
by Aaron Bentley
 Implemented the backup file detritus  | 
1557  | 
def change_entry(tt, file_id, working_tree, target_tree,  | 
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
1558  | 
trans_id_file_id, backups, trans_id, by_parent):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
1559  | 
"""Replace a file_id's contents with those from a target tree."""  | 
| 
2625.4.3
by Ian Clatworthy
 Add a test to ensure the deprecation worked.  | 
1560  | 
if file_id is None and target_tree is None:  | 
1561  | 
        # skip the logic altogether in the deprecation test
 | 
|
1562  | 
        return
 | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
1563  | 
e_trans_id = trans_id_file_id(file_id)  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1564  | 
entry = target_tree.inventory[file_id]  | 
1565  | 
has_contents, contents_mod, meta_mod, = _entry_changes(file_id, entry,  | 
|
1566  | 
working_tree)  | 
|
1567  | 
if contents_mod:  | 
|
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
1568  | 
mode_id = e_trans_id  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1569  | 
if has_contents:  | 
| 
1534.7.56
by Aaron Bentley
 Implemented the backup file detritus  | 
1570  | 
if not backups:  | 
1571  | 
tt.delete_contents(e_trans_id)  | 
|
1572  | 
else:  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
1573  | 
parent_trans_id = trans_id_file_id(entry.parent_id)  | 
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
1574  | 
backup_name = get_backup_name(entry, by_parent,  | 
1575  | 
parent_trans_id, tt)  | 
|
1576  | 
tt.adjust_path(backup_name, parent_trans_id, e_trans_id)  | 
|
| 
1534.7.56
by Aaron Bentley
 Implemented the backup file detritus  | 
1577  | 
tt.unversion_file(e_trans_id)  | 
1578  | 
e_trans_id = tt.create_path(entry.name, parent_trans_id)  | 
|
1579  | 
tt.version_file(file_id, e_trans_id)  | 
|
1580  | 
trans_id[file_id] = e_trans_id  | 
|
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
1581  | 
create_by_entry(tt, entry, target_tree, e_trans_id, mode_id=mode_id)  | 
| 
1534.7.89
by Aaron Bentley
 Handle all content types in three-way  | 
1582  | 
create_entry_executability(tt, entry, e_trans_id)  | 
1583  | 
||
| 
1711.4.26
by John Arbash Meinel
 Fix #45010 correctly. Don't forget the execute bit.  | 
1584  | 
elif meta_mod:  | 
1585  | 
tt.set_executability(entry.executable, e_trans_id)  | 
|
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1586  | 
if tt.final_name(e_trans_id) != entry.name:  | 
1587  | 
adjust_path = True  | 
|
1588  | 
else:  | 
|
1589  | 
parent_id = tt.final_parent(e_trans_id)  | 
|
1590  | 
parent_file_id = tt.final_file_id(parent_id)  | 
|
1591  | 
if parent_file_id != entry.parent_id:  | 
|
1592  | 
adjust_path = True  | 
|
1593  | 
else:  | 
|
1594  | 
adjust_path = False  | 
|
1595  | 
if adjust_path:  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
1596  | 
parent_trans_id = trans_id_file_id(entry.parent_id)  | 
| 
1534.7.56
by Aaron Bentley
 Implemented the backup file detritus  | 
1597  | 
tt.adjust_path(entry.name, parent_trans_id, e_trans_id)  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1598  | 
|
1599  | 
||
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
1600  | 
def get_backup_name(entry, by_parent, parent_trans_id, tt):  | 
| 
2012.1.12
by Aaron Bentley
 Use iter_changes for revert  | 
1601  | 
return _get_backup_name(entry.name, by_parent, parent_trans_id, tt)  | 
1602  | 
||
1603  | 
||
1604  | 
def _get_backup_name(name, by_parent, parent_trans_id, tt):  | 
|
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
1605  | 
"""Produce a backup-style name that appears to be available"""  | 
1606  | 
def name_gen():  | 
|
1607  | 
counter = 1  | 
|
1608  | 
while True:  | 
|
| 
2012.1.12
by Aaron Bentley
 Use iter_changes for revert  | 
1609  | 
yield "%s.~%d~" % (name, counter)  | 
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
1610  | 
counter += 1  | 
| 
2012.1.12
by Aaron Bentley
 Use iter_changes for revert  | 
1611  | 
for new_name in name_gen():  | 
1612  | 
if not tt.has_named_child(by_parent, parent_trans_id, new_name):  | 
|
1613  | 
return new_name  | 
|
1614  | 
||
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
1615  | 
|
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1616  | 
def _entry_changes(file_id, entry, working_tree):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
1617  | 
"""Determine in which ways the inventory entry has changed.  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1618  | 
|
1619  | 
    Returns booleans: has_contents, content_mod, meta_mod
 | 
|
1620  | 
    has_contents means there are currently contents, but they differ
 | 
|
1621  | 
    contents_mod means contents need to be modified
 | 
|
1622  | 
    meta_mod means the metadata needs to be modified
 | 
|
1623  | 
    """
 | 
|
1624  | 
cur_entry = working_tree.inventory[file_id]  | 
|
1625  | 
try:  | 
|
1626  | 
working_kind = working_tree.kind(file_id)  | 
|
1627  | 
has_contents = True  | 
|
| 
1757.2.4
by Robert Collins
 Teach file_kind about NoSuchFile, reducing duplicate code, and add user files before entering the main loop in smart_add.  | 
1628  | 
except NoSuchFile:  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1629  | 
has_contents = False  | 
1630  | 
contents_mod = True  | 
|
1631  | 
meta_mod = False  | 
|
1632  | 
if has_contents is True:  | 
|
| 
1731.1.1
by Aaron Bentley
 Make root entry an InventoryDirectory, make EmptyTree really empty  | 
1633  | 
if entry.kind != working_kind:  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1634  | 
contents_mod, meta_mod = True, False  | 
1635  | 
else:  | 
|
1636  | 
cur_entry._read_tree_state(working_tree.id2path(file_id),  | 
|
1637  | 
working_tree)  | 
|
1638  | 
contents_mod, meta_mod = entry.detect_changes(cur_entry)  | 
|
| 
1534.7.175
by Aaron Bentley
 Ensured revert writes a normal inventory  | 
1639  | 
cur_entry._forget_tree_state()  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1640  | 
return has_contents, contents_mod, meta_mod  | 
1641  | 
||
| 
1534.7.56
by Aaron Bentley
 Implemented the backup file detritus  | 
1642  | 
|
| 
2255.2.53
by Robert Collins
 Teach TreeTransform to lock basis_trees if it acquires them, fixing revert on a dirstate working tree.  | 
1643  | 
def revert(working_tree, target_tree, filenames, backups=False,  | 
| 
2225.1.1
by Aaron Bentley
 Added revert change display, with tests  | 
1644  | 
pb=DummyProgress(), change_reporter=None):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
1645  | 
"""Revert a working tree's contents to those of a target tree."""  | 
| 
2255.2.53
by Robert Collins
 Teach TreeTransform to lock basis_trees if it acquires them, fixing revert on a dirstate working tree.  | 
1646  | 
target_tree.lock_read()  | 
| 
1534.9.7
by Aaron Bentley
 Show progress bars in revert  | 
1647  | 
tt = TreeTransform(working_tree, pb)  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1648  | 
try:  | 
| 
2012.1.12
by Aaron Bentley
 Use iter_changes for revert  | 
1649  | 
pp = ProgressPhase("Revert phase", 3, pb)  | 
1650  | 
pp.next_phase()  | 
|
1651  | 
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()  | 
|
1652  | 
try:  | 
|
| 
2499.1.1
by Aaron Bentley
 Revert does not try to preserve file contents produced by revert  | 
1653  | 
merge_modified = _alter_files(working_tree, target_tree, tt,  | 
1654  | 
child_pb, filenames, backups)  | 
|
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
1655  | 
finally:  | 
1656  | 
child_pb.finished()  | 
|
| 
1551.2.34
by Aaron Bentley
 Refactored the revert phases  | 
1657  | 
pp.next_phase()  | 
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
1658  | 
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()  | 
1659  | 
try:  | 
|
| 
1551.19.5
by Aaron Bentley
 Fix revert when parent dir is missing  | 
1660  | 
raw_conflicts = resolve_conflicts(tt, child_pb,  | 
1661  | 
lambda t, c: conflict_pass(t, c, target_tree))  | 
|
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
1662  | 
finally:  | 
1663  | 
child_pb.finished()  | 
|
| 
1558.7.13
by Aaron Bentley
 WorkingTree.revert returns conflicts  | 
1664  | 
conflicts = cook_conflicts(raw_conflicts, tt)  | 
| 
1551.11.5
by Aaron Bentley
 cleanup  | 
1665  | 
if change_reporter:  | 
| 
1551.10.25
by Aaron Bentley
 Make ChangeReporter private  | 
1666  | 
change_reporter = delta._ChangeReporter(  | 
| 
2255.7.98
by Robert Collins
 Merge bzr.dev.  | 
1667  | 
unversioned_filter=working_tree.is_ignored)  | 
| 
1551.11.5
by Aaron Bentley
 cleanup  | 
1668  | 
delta.report_changes(tt._iter_changes(), change_reporter)  | 
| 
1551.11.6
by Aaron Bentley
 Emit change listings before conflict warnings  | 
1669  | 
for conflict in conflicts:  | 
1670  | 
warning(conflict)  | 
|
1671  | 
pp.next_phase()  | 
|
| 
1534.7.28
by Aaron Bentley
 Nearly-working build_tree replacement  | 
1672  | 
tt.apply()  | 
| 
2499.1.1
by Aaron Bentley
 Revert does not try to preserve file contents produced by revert  | 
1673  | 
working_tree.set_merge_modified(merge_modified)  | 
| 
1534.7.28
by Aaron Bentley
 Nearly-working build_tree replacement  | 
1674  | 
finally:  | 
| 
2255.2.53
by Robert Collins
 Teach TreeTransform to lock basis_trees if it acquires them, fixing revert on a dirstate working tree.  | 
1675  | 
target_tree.unlock()  | 
| 
1534.7.28
by Aaron Bentley
 Nearly-working build_tree replacement  | 
1676  | 
tt.finalize()  | 
| 
1534.9.4
by Aaron Bentley
 Added progress bars to revert.  | 
1677  | 
pb.clear()  | 
| 
1558.7.13
by Aaron Bentley
 WorkingTree.revert returns conflicts  | 
1678  | 
return conflicts  | 
| 
1534.7.51
by Aaron Bentley
 New approach to revert  | 
1679  | 
|
| 
1534.7.57
by Aaron Bentley
 Enhanced conflict resolution.  | 
1680  | 
|
| 
2255.2.149
by Robert Collins
 Crufty but existing _iter_changes implementation for WorkingTreeFormat4.  | 
1681  | 
def _alter_files(working_tree, target_tree, tt, pb, specific_files,  | 
| 
1551.11.3
by Aaron Bentley
 Use tree transform to emit upcoming change list  | 
1682  | 
backups):  | 
| 
2012.1.12
by Aaron Bentley
 Use iter_changes for revert  | 
1683  | 
merge_modified = working_tree.merge_modified()  | 
| 
1551.11.3
by Aaron Bentley
 Use tree transform to emit upcoming change list  | 
1684  | 
change_list = target_tree._iter_changes(working_tree,  | 
| 
2255.2.149
by Robert Collins
 Crufty but existing _iter_changes implementation for WorkingTreeFormat4.  | 
1685  | 
specific_files=specific_files, pb=pb)  | 
| 
2012.1.12
by Aaron Bentley
 Use iter_changes for revert  | 
1686  | 
if target_tree.inventory.root is None:  | 
1687  | 
skip_root = True  | 
|
1688  | 
else:  | 
|
1689  | 
skip_root = False  | 
|
1690  | 
basis_tree = None  | 
|
| 
2255.2.53
by Robert Collins
 Teach TreeTransform to lock basis_trees if it acquires them, fixing revert on a dirstate working tree.  | 
1691  | 
try:  | 
| 
2708.1.5
by Aaron Bentley
 Use Tree.extract_files_bytes in revert  | 
1692  | 
deferred_files = []  | 
| 
2255.2.53
by Robert Collins
 Teach TreeTransform to lock basis_trees if it acquires them, fixing revert on a dirstate working tree.  | 
1693  | 
for id_num, (file_id, path, changed_content, versioned, parent, name,  | 
1694  | 
kind, executable) in enumerate(change_list):  | 
|
1695  | 
if skip_root and file_id[0] is not None and parent[0] is None:  | 
|
1696  | 
                continue
 | 
|
1697  | 
trans_id = tt.trans_id_file_id(file_id)  | 
|
1698  | 
mode_id = None  | 
|
1699  | 
if changed_content:  | 
|
1700  | 
keep_content = False  | 
|
1701  | 
if kind[0] == 'file' and (backups or kind[1] is None):  | 
|
1702  | 
wt_sha1 = working_tree.get_file_sha1(file_id)  | 
|
1703  | 
if merge_modified.get(file_id) != wt_sha1:  | 
|
| 
2502.1.6
by Aaron Bentley
 Update from review comments  | 
1704  | 
                        # acquire the basis tree lazily to prevent the
 | 
1705  | 
                        # expense of accessing it when it's not needed ?
 | 
|
1706  | 
                        # (Guessing, RBC, 200702)
 | 
|
| 
2255.2.53
by Robert Collins
 Teach TreeTransform to lock basis_trees if it acquires them, fixing revert on a dirstate working tree.  | 
1707  | 
if basis_tree is None:  | 
1708  | 
basis_tree = working_tree.basis_tree()  | 
|
1709  | 
basis_tree.lock_read()  | 
|
1710  | 
if file_id in basis_tree:  | 
|
1711  | 
if wt_sha1 != basis_tree.get_file_sha1(file_id):  | 
|
1712  | 
keep_content = True  | 
|
1713  | 
elif kind[1] is None and not versioned[1]:  | 
|
| 
2012.1.12
by Aaron Bentley
 Use iter_changes for revert  | 
1714  | 
keep_content = True  | 
| 
2255.2.53
by Robert Collins
 Teach TreeTransform to lock basis_trees if it acquires them, fixing revert on a dirstate working tree.  | 
1715  | 
if kind[0] is not None:  | 
1716  | 
if not keep_content:  | 
|
1717  | 
tt.delete_contents(trans_id)  | 
|
1718  | 
elif kind[1] is not None:  | 
|
1719  | 
parent_trans_id = tt.trans_id_file_id(parent[0])  | 
|
1720  | 
by_parent = tt.by_parent()  | 
|
1721  | 
backup_name = _get_backup_name(name[0], by_parent,  | 
|
1722  | 
parent_trans_id, tt)  | 
|
1723  | 
tt.adjust_path(backup_name, parent_trans_id, trans_id)  | 
|
1724  | 
new_trans_id = tt.create_path(name[0], parent_trans_id)  | 
|
1725  | 
if versioned == (True, True):  | 
|
1726  | 
tt.unversion_file(trans_id)  | 
|
1727  | 
tt.version_file(file_id, new_trans_id)  | 
|
1728  | 
                        # New contents should have the same unix perms as old
 | 
|
1729  | 
                        # contents
 | 
|
1730  | 
mode_id = trans_id  | 
|
1731  | 
trans_id = new_trans_id  | 
|
1732  | 
if kind[1] == 'directory':  | 
|
1733  | 
tt.create_directory(trans_id)  | 
|
1734  | 
elif kind[1] == 'symlink':  | 
|
1735  | 
tt.create_symlink(target_tree.get_symlink_target(file_id),  | 
|
1736  | 
trans_id)  | 
|
1737  | 
elif kind[1] == 'file':  | 
|
| 
2708.1.6
by Aaron Bentley
 Turn extract_files_bytes into an iterator  | 
1738  | 
deferred_files.append((file_id, (trans_id, mode_id)))  | 
| 
2499.1.1
by Aaron Bentley
 Revert does not try to preserve file contents produced by revert  | 
1739  | 
if basis_tree is None:  | 
1740  | 
basis_tree = working_tree.basis_tree()  | 
|
1741  | 
basis_tree.lock_read()  | 
|
1742  | 
new_sha1 = target_tree.get_file_sha1(file_id)  | 
|
1743  | 
if (file_id in basis_tree and new_sha1 ==  | 
|
1744  | 
basis_tree.get_file_sha1(file_id)):  | 
|
1745  | 
if file_id in merge_modified:  | 
|
1746  | 
del merge_modified[file_id]  | 
|
1747  | 
else:  | 
|
1748  | 
merge_modified[file_id] = new_sha1  | 
|
1749  | 
||
| 
2255.2.53
by Robert Collins
 Teach TreeTransform to lock basis_trees if it acquires them, fixing revert on a dirstate working tree.  | 
1750  | 
                    # preserve the execute bit when backing up
 | 
1751  | 
if keep_content and executable[0] == executable[1]:  | 
|
1752  | 
tt.set_executability(executable[1], trans_id)  | 
|
1753  | 
else:  | 
|
1754  | 
assert kind[1] is None  | 
|
1755  | 
if versioned == (False, True):  | 
|
1756  | 
tt.version_file(file_id, trans_id)  | 
|
1757  | 
if versioned == (True, False):  | 
|
1758  | 
tt.unversion_file(trans_id)  | 
|
1759  | 
if (name[1] is not None and  | 
|
1760  | 
(name[0] != name[1] or parent[0] != parent[1])):  | 
|
1761  | 
tt.adjust_path(  | 
|
1762  | 
name[1], tt.trans_id_file_id(parent[1]), trans_id)  | 
|
1763  | 
if executable[0] != executable[1] and kind[1] == "file":  | 
|
1764  | 
tt.set_executability(executable[1], trans_id)  | 
|
| 
2708.1.8
by Aaron Bentley
 rename extract_files_bytest to iter_files_bytes, fix build_tree / progress  | 
1765  | 
for (trans_id, mode_id), bytes in target_tree.iter_files_bytes(  | 
| 
2708.1.6
by Aaron Bentley
 Turn extract_files_bytes into an iterator  | 
1766  | 
deferred_files):  | 
1767  | 
tt.create_file(bytes, trans_id, mode_id)  | 
|
| 
2255.2.53
by Robert Collins
 Teach TreeTransform to lock basis_trees if it acquires them, fixing revert on a dirstate working tree.  | 
1768  | 
finally:  | 
1769  | 
if basis_tree is not None:  | 
|
1770  | 
basis_tree.unlock()  | 
|
| 
2499.1.1
by Aaron Bentley
 Revert does not try to preserve file contents produced by revert  | 
1771  | 
return merge_modified  | 
| 
2012.1.12
by Aaron Bentley
 Use iter_changes for revert  | 
1772  | 
|
1773  | 
||
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1774  | 
def resolve_conflicts(tt, pb=DummyProgress(), pass_func=None):  | 
| 
1534.7.57
by Aaron Bentley
 Enhanced conflict resolution.  | 
1775  | 
"""Make many conflict-resolution attempts, but die if they fail"""  | 
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1776  | 
if pass_func is None:  | 
1777  | 
pass_func = conflict_pass  | 
|
| 
1534.7.169
by Aaron Bentley
 Add filesystem/inventory conflicts to conflict output  | 
1778  | 
new_conflicts = set()  | 
| 
1534.9.1
by Aaron Bentley
 Added progress bars to merge  | 
1779  | 
try:  | 
1780  | 
for n in range(10):  | 
|
1781  | 
pb.update('Resolution pass', n+1, 10)  | 
|
1782  | 
conflicts = tt.find_conflicts()  | 
|
1783  | 
if len(conflicts) == 0:  | 
|
1784  | 
return new_conflicts  | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1785  | 
new_conflicts.update(pass_func(tt, conflicts))  | 
| 
1534.9.1
by Aaron Bentley
 Added progress bars to merge  | 
1786  | 
raise MalformedTransform(conflicts=conflicts)  | 
1787  | 
finally:  | 
|
1788  | 
pb.clear()  | 
|
| 
1534.7.57
by Aaron Bentley
 Enhanced conflict resolution.  | 
1789  | 
|
1790  | 
||
| 
2590.2.8
by Aaron Bentley
 Restore conflict handling changes  | 
1791  | 
def conflict_pass(tt, conflicts, path_tree=None):  | 
1792  | 
"""Resolve some classes of conflicts.  | 
|
1793  | 
||
1794  | 
    :param tt: The transform to resolve conflicts in
 | 
|
1795  | 
    :param conflicts: The conflicts to resolve
 | 
|
1796  | 
    :param path_tree: A Tree to get supplemental paths from
 | 
|
1797  | 
    """
 | 
|
| 
1534.7.169
by Aaron Bentley
 Add filesystem/inventory conflicts to conflict output  | 
1798  | 
new_conflicts = set()  | 
| 
1534.7.61
by Aaron Bentley
 Handled parent loops, missing parents, unversioned parents  | 
1799  | 
for c_type, conflict in ((c[0], c) for c in conflicts):  | 
1800  | 
if c_type == 'duplicate id':  | 
|
| 
1534.7.51
by Aaron Bentley
 New approach to revert  | 
1801  | 
tt.unversion_file(conflict[1])  | 
| 
1534.7.170
by Aaron Bentley
 Cleaned up filesystem conflict handling  | 
1802  | 
new_conflicts.add((c_type, 'Unversioned existing file',  | 
1803  | 
conflict[1], conflict[2], ))  | 
|
| 
1534.7.61
by Aaron Bentley
 Handled parent loops, missing parents, unversioned parents  | 
1804  | 
elif c_type == 'duplicate':  | 
| 
1534.7.57
by Aaron Bentley
 Enhanced conflict resolution.  | 
1805  | 
            # files that were renamed take precedence
 | 
1806  | 
final_parent = tt.final_parent(conflict[1])  | 
|
1807  | 
if tt.path_changed(conflict[1]):  | 
|
| 
3034.4.1
by Aaron Bentley
 Start handling case-insensitivity  | 
1808  | 
existing_file, new_file = conflict[2], conflict[1]  | 
| 
1534.7.57
by Aaron Bentley
 Enhanced conflict resolution.  | 
1809  | 
else:  | 
| 
3034.4.1
by Aaron Bentley
 Start handling case-insensitivity  | 
1810  | 
existing_file, new_file = conflict[1], conflict[2]  | 
1811  | 
new_name = tt.final_name(existing_file)+'.moved'  | 
|
1812  | 
tt.adjust_path(new_name, final_parent, existing_file)  | 
|
1813  | 
new_conflicts.add((c_type, 'Moved existing file to',  | 
|
1814  | 
existing_file, new_file))  | 
|
| 
1534.7.61
by Aaron Bentley
 Handled parent loops, missing parents, unversioned parents  | 
1815  | 
elif c_type == 'parent loop':  | 
1816  | 
            # break the loop by undoing one of the ops that caused the loop
 | 
|
1817  | 
cur = conflict[1]  | 
|
1818  | 
while not tt.path_changed(cur):  | 
|
1819  | 
cur = tt.final_parent(cur)  | 
|
| 
1534.7.170
by Aaron Bentley
 Cleaned up filesystem conflict handling  | 
1820  | 
new_conflicts.add((c_type, 'Cancelled move', cur,  | 
1821  | 
tt.final_parent(cur),))  | 
|
| 
1534.7.61
by Aaron Bentley
 Handled parent loops, missing parents, unversioned parents  | 
1822  | 
tt.adjust_path(tt.final_name(cur), tt.get_tree_parent(cur), cur)  | 
| 
1534.7.169
by Aaron Bentley
 Add filesystem/inventory conflicts to conflict output  | 
1823  | 
|
| 
1534.7.61
by Aaron Bentley
 Handled parent loops, missing parents, unversioned parents  | 
1824  | 
elif c_type == 'missing parent':  | 
| 
1534.7.128
by Aaron Bentley
 Got missing contents test working  | 
1825  | 
trans_id = conflict[1]  | 
1826  | 
try:  | 
|
1827  | 
tt.cancel_deletion(trans_id)  | 
|
| 
1551.8.22
by Aaron Bentley
 Improve message when OTHER deletes an in-use tree  | 
1828  | 
new_conflicts.add(('deleting parent', 'Not deleting',  | 
1829  | 
trans_id))  | 
|
| 
1534.7.128
by Aaron Bentley
 Got missing contents test working  | 
1830  | 
except KeyError:  | 
1831  | 
tt.create_directory(trans_id)  | 
|
| 
1551.8.22
by Aaron Bentley
 Improve message when OTHER deletes an in-use tree  | 
1832  | 
new_conflicts.add((c_type, 'Created directory', trans_id))  | 
| 
2590.2.8
by Aaron Bentley
 Restore conflict handling changes  | 
1833  | 
try:  | 
1834  | 
tt.final_name(trans_id)  | 
|
1835  | 
except NoFinalPath:  | 
|
| 
1551.19.6
by Aaron Bentley
 Revert doesn't crash restoring a file from a deleted directory  | 
1836  | 
if path_tree is not None:  | 
1837  | 
file_id = tt.final_file_id(trans_id)  | 
|
1838  | 
entry = path_tree.inventory[file_id]  | 
|
1839  | 
parent_trans_id = tt.trans_id_file_id(entry.parent_id)  | 
|
1840  | 
tt.adjust_path(entry.name, parent_trans_id, trans_id)  | 
|
| 
1534.7.61
by Aaron Bentley
 Handled parent loops, missing parents, unversioned parents  | 
1841  | 
elif c_type == 'unversioned parent':  | 
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
1842  | 
tt.version_file(tt.inactive_file_id(conflict[1]), conflict[1])  | 
| 
1534.7.171
by Aaron Bentley
 Implemented stringifying filesystem conflicts  | 
1843  | 
new_conflicts.add((c_type, 'Versioned directory', conflict[1]))  | 
| 
1534.7.169
by Aaron Bentley
 Add filesystem/inventory conflicts to conflict output  | 
1844  | 
return new_conflicts  | 
1845  | 
||
| 
1666.1.4
by Robert Collins
 * 'Metadir' is now the default disk format. This improves behaviour in  | 
1846  | 
|
| 
1534.7.169
by Aaron Bentley
 Add filesystem/inventory conflicts to conflict output  | 
1847  | 
def cook_conflicts(raw_conflicts, tt):  | 
| 
1534.7.170
by Aaron Bentley
 Cleaned up filesystem conflict handling  | 
1848  | 
"""Generate a list of cooked conflicts, sorted by file path"""  | 
| 
1666.1.4
by Robert Collins
 * 'Metadir' is now the default disk format. This improves behaviour in  | 
1849  | 
from bzrlib.conflicts import Conflict  | 
1850  | 
conflict_iter = iter_cook_conflicts(raw_conflicts, tt)  | 
|
1851  | 
return sorted(conflict_iter, key=Conflict.sort_key)  | 
|
| 
1534.7.170
by Aaron Bentley
 Cleaned up filesystem conflict handling  | 
1852  | 
|
| 
1534.7.169
by Aaron Bentley
 Add filesystem/inventory conflicts to conflict output  | 
1853  | 
|
1854  | 
def iter_cook_conflicts(raw_conflicts, tt):  | 
|
| 
1534.10.19
by Aaron Bentley
 Stanza conversion, cooking  | 
1855  | 
from bzrlib.conflicts import Conflict  | 
| 
1534.7.170
by Aaron Bentley
 Cleaned up filesystem conflict handling  | 
1856  | 
fp = FinalPaths(tt)  | 
| 
1534.7.169
by Aaron Bentley
 Add filesystem/inventory conflicts to conflict output  | 
1857  | 
for conflict in raw_conflicts:  | 
1858  | 
c_type = conflict[0]  | 
|
| 
1534.7.170
by Aaron Bentley
 Cleaned up filesystem conflict handling  | 
1859  | 
action = conflict[1]  | 
1860  | 
modified_path = fp.get_path(conflict[2])  | 
|
1861  | 
modified_id = tt.final_file_id(conflict[2])  | 
|
1862  | 
if len(conflict) == 3:  | 
|
| 
1534.10.19
by Aaron Bentley
 Stanza conversion, cooking  | 
1863  | 
yield Conflict.factory(c_type, action=action, path=modified_path,  | 
1864  | 
file_id=modified_id)  | 
|
1865  | 
||
| 
1534.7.170
by Aaron Bentley
 Cleaned up filesystem conflict handling  | 
1866  | 
else:  | 
1867  | 
conflicting_path = fp.get_path(conflict[3])  | 
|
1868  | 
conflicting_id = tt.final_file_id(conflict[3])  | 
|
| 
1534.10.19
by Aaron Bentley
 Stanza conversion, cooking  | 
1869  | 
yield Conflict.factory(c_type, action=action, path=modified_path,  | 
1870  | 
file_id=modified_id,  | 
|
1871  | 
conflict_path=conflicting_path,  | 
|
1872  | 
conflict_file_id=conflicting_id)  | 
|
| 
2733.2.1
by Aaron Bentley
 Implement FileMover, to support TreeTransform rollback  | 
1873  | 
|
1874  | 
||
1875  | 
class _FileMover(object):  | 
|
| 
2733.2.9
by Aaron Bentley
 Update docstrings  | 
1876  | 
"""Moves and deletes files for TreeTransform, tracking operations"""  | 
| 
2733.2.1
by Aaron Bentley
 Implement FileMover, to support TreeTransform rollback  | 
1877  | 
|
1878  | 
def __init__(self):  | 
|
1879  | 
self.past_renames = []  | 
|
| 
2733.2.5
by Aaron Bentley
 Implement FileMover.pre_delete and FileMover.apply_deletions  | 
1880  | 
self.pending_deletions = []  | 
| 
2733.2.1
by Aaron Bentley
 Implement FileMover, to support TreeTransform rollback  | 
1881  | 
|
1882  | 
def rename(self, from_, to):  | 
|
| 
2733.2.9
by Aaron Bentley
 Update docstrings  | 
1883  | 
"""Rename a file from one path to another. Functions like os.rename"""  | 
| 
3063.1.1
by Alexander Belchenko
 Catch OSError 17 (file exists) in final phase of tree transform and show filename to user (#111758).  | 
1884  | 
try:  | 
1885  | 
os.rename(from_, to)  | 
|
1886  | 
except OSError, e:  | 
|
| 
3063.1.3
by Aaron Bentley
 Update for Linux  | 
1887  | 
if e.errno in (errno.EEXIST, errno.ENOTEMPTY):  | 
| 
3063.1.1
by Alexander Belchenko
 Catch OSError 17 (file exists) in final phase of tree transform and show filename to user (#111758).  | 
1888  | 
raise errors.FileExists(to, str(e))  | 
1889  | 
            raise
 | 
|
| 
2733.2.1
by Aaron Bentley
 Implement FileMover, to support TreeTransform rollback  | 
1890  | 
self.past_renames.append((from_, to))  | 
1891  | 
||
| 
2733.2.5
by Aaron Bentley
 Implement FileMover.pre_delete and FileMover.apply_deletions  | 
1892  | 
def pre_delete(self, from_, to):  | 
| 
2733.2.9
by Aaron Bentley
 Update docstrings  | 
1893  | 
"""Rename a file out of the way and mark it for deletion.  | 
1894  | 
||
1895  | 
        Unlike os.unlink, this works equally well for files and directories.
 | 
|
1896  | 
        :param from_: The current file path
 | 
|
1897  | 
        :param to: A temporary path for the file
 | 
|
1898  | 
        """
 | 
|
| 
2733.2.5
by Aaron Bentley
 Implement FileMover.pre_delete and FileMover.apply_deletions  | 
1899  | 
self.rename(from_, to)  | 
1900  | 
self.pending_deletions.append(to)  | 
|
1901  | 
||
| 
2733.2.1
by Aaron Bentley
 Implement FileMover, to support TreeTransform rollback  | 
1902  | 
def rollback(self):  | 
| 
2733.2.9
by Aaron Bentley
 Update docstrings  | 
1903  | 
"""Reverse all renames that have been performed"""  | 
| 
2733.2.1
by Aaron Bentley
 Implement FileMover, to support TreeTransform rollback  | 
1904  | 
for from_, to in reversed(self.past_renames):  | 
1905  | 
os.rename(to, from_)  | 
|
| 
2733.2.12
by Aaron Bentley
 Updates from review  | 
1906  | 
        # after rollback, don't reuse _FileMover
 | 
1907  | 
past_renames = None  | 
|
1908  | 
pending_deletions = None  | 
|
| 
2733.2.5
by Aaron Bentley
 Implement FileMover.pre_delete and FileMover.apply_deletions  | 
1909  | 
|
1910  | 
def apply_deletions(self):  | 
|
| 
2733.2.9
by Aaron Bentley
 Update docstrings  | 
1911  | 
"""Apply all marked deletions"""  | 
| 
2733.2.5
by Aaron Bentley
 Implement FileMover.pre_delete and FileMover.apply_deletions  | 
1912  | 
for path in self.pending_deletions:  | 
1913  | 
delete_any(path)  | 
|
| 
2733.2.12
by Aaron Bentley
 Updates from review  | 
1914  | 
        # after apply_deletions, don't reuse _FileMover
 | 
1915  | 
past_renames = None  | 
|
1916  | 
pending_deletions = None  |