bzr branch
http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
| 
1534.7.106
by Aaron Bentley
 Cleaned up imports, added copyright statements  | 
1  | 
# Copyright (C) 2006 Canonical Ltd
 | 
2  | 
||
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.
 | 
|
7  | 
||
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.
 | 
|
12  | 
||
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  | 
|
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
21  | 
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,  | 
| 
1534.7.162
by Aaron Bentley
 Handle failures creating/deleting the Limbo directory  | 
22  | 
ReusingTransform, NotVersionedError, CantMoveRoot,  | 
23  | 
ExistingLimbo, ImmortalLimbo)  | 
|
| 
1534.7.106
by Aaron Bentley
 Cleaned up imports, added copyright statements  | 
24  | 
from bzrlib.inventory import InventoryEntry  | 
| 
1534.8.3
by Aaron Bentley
 Added Diff3 merging for tree transforms  | 
25  | 
from bzrlib.osutils import file_kind, supports_executable, pathjoin  | 
| 
1534.9.1
by Aaron Bentley
 Added progress bars to merge  | 
26  | 
from bzrlib.progress import DummyProgress  | 
| 
1534.7.173
by Aaron Bentley
 Added conflict warnings to revert  | 
27  | 
from bzrlib.trace import mutter, warning  | 
| 
1534.7.31
by Aaron Bentley
 Changed tree root parent to ROOT_PARENT  | 
28  | 
|
| 
1534.7.167
by Aaron Bentley
 PEP8 and comment cleanups  | 
29  | 
|
| 
1534.7.31
by Aaron Bentley
 Changed tree root parent to ROOT_PARENT  | 
30  | 
ROOT_PARENT = "root-parent"  | 
31  | 
||
| 
1534.7.167
by Aaron Bentley
 PEP8 and comment cleanups  | 
32  | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
33  | 
def unique_add(map, key, value):  | 
34  | 
if key in map:  | 
|
| 
1534.7.5
by Aaron Bentley
 Got unique_add under test  | 
35  | 
raise DuplicateKey(key=key)  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
36  | 
map[key] = value  | 
37  | 
||
| 
1534.7.167
by Aaron Bentley
 PEP8 and comment cleanups  | 
38  | 
|
| 
1534.7.191
by Aaron Bentley
 Got transform.apply to list modified paths  | 
39  | 
class _TransformResults(object):  | 
40  | 
def __init__(self, modified_paths):  | 
|
41  | 
object.__init__(self)  | 
|
42  | 
self.modified_paths = modified_paths  | 
|
43  | 
||
44  | 
||
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
45  | 
class TreeTransform(object):  | 
| 
1534.7.179
by Aaron Bentley
 Added Transform docs  | 
46  | 
"""Represent a tree transformation.  | 
47  | 
    
 | 
|
48  | 
    This object is designed to support incremental generation of the transform,
 | 
|
49  | 
    in any order.  
 | 
|
50  | 
    
 | 
|
51  | 
    It is easy to produce malformed transforms, but they are generally
 | 
|
52  | 
    harmless.  Attempting to apply a malformed transform will cause an
 | 
|
53  | 
    exception to be raised before any modifications are made to the tree.  
 | 
|
54  | 
||
55  | 
    Many kinds of malformed transforms can be corrected with the 
 | 
|
56  | 
    resolve_conflicts function.  The remaining ones indicate programming error,
 | 
|
57  | 
    such as trying to create a file with no path.
 | 
|
58  | 
||
59  | 
    Two sets of file creation methods are supplied.  Convenience methods are:
 | 
|
60  | 
     * new_file
 | 
|
61  | 
     * new_directory
 | 
|
62  | 
     * new_symlink
 | 
|
63  | 
||
64  | 
    These are composed of the low-level methods:
 | 
|
65  | 
     * create_path
 | 
|
66  | 
     * create_file or create_directory or create_symlink
 | 
|
67  | 
     * version_file
 | 
|
68  | 
     * set_executability
 | 
|
69  | 
    """
 | 
|
| 
1534.9.1
by Aaron Bentley
 Added progress bars to merge  | 
70  | 
def __init__(self, tree, pb=DummyProgress()):  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
71  | 
"""Note: a write lock is taken on the tree.  | 
72  | 
        
 | 
|
73  | 
        Use TreeTransform.finalize() to release the lock
 | 
|
74  | 
        """
 | 
|
75  | 
object.__init__(self)  | 
|
76  | 
self._tree = tree  | 
|
77  | 
self._tree.lock_write()  | 
|
| 
1534.7.162
by Aaron Bentley
 Handle failures creating/deleting the Limbo directory  | 
78  | 
try:  | 
79  | 
control_files = self._tree._control_files  | 
|
80  | 
self._limbodir = control_files.controlfilename('limbo')  | 
|
81  | 
try:  | 
|
82  | 
os.mkdir(self._limbodir)  | 
|
83  | 
except OSError, e:  | 
|
84  | 
if e.errno == errno.EEXIST:  | 
|
85  | 
raise ExistingLimbo(self._limbodir)  | 
|
86  | 
except:  | 
|
87  | 
self._tree.unlock()  | 
|
88  | 
            raise
 | 
|
89  | 
||
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
90  | 
self._id_number = 0  | 
91  | 
self._new_name = {}  | 
|
92  | 
self._new_parent = {}  | 
|
| 
1534.7.4
by Aaron Bentley
 Unified all file types as 'contents'  | 
93  | 
self._new_contents = {}  | 
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
94  | 
self._removed_contents = set()  | 
| 
1534.7.25
by Aaron Bentley
 Added set_executability  | 
95  | 
self._new_executability = {}  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
96  | 
self._new_id = {}  | 
| 
1534.7.143
by Aaron Bentley
 Prevented get_trans_id from automatically versioning file ids  | 
97  | 
self._non_present_ids = {}  | 
| 
1534.7.75
by Aaron Bentley
 Added reverse-lookup for versioned files and get_trans_id  | 
98  | 
self._r_new_id = {}  | 
| 
1534.7.39
by Aaron Bentley
 Ensured that files can be unversioned (de-versioned?)  | 
99  | 
self._removed_id = set()  | 
| 
1534.7.7
by Aaron Bentley
 Added support for all-file path ids  | 
100  | 
self._tree_path_ids = {}  | 
| 
1534.7.8
by Aaron Bentley
 Added TreeTransform.final_kind  | 
101  | 
self._tree_id_paths = {}  | 
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
102  | 
self._new_root = self.trans_id_tree_file_id(tree.get_root_id())  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
103  | 
self.__done = False  | 
| 
1534.9.1
by Aaron Bentley
 Added progress bars to merge  | 
104  | 
self._pb = pb  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
105  | 
|
| 
1534.7.132
by Aaron Bentley
 Got cooked conflicts working  | 
106  | 
def __get_root(self):  | 
107  | 
return self._new_root  | 
|
108  | 
||
109  | 
root = property(__get_root)  | 
|
110  | 
||
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
111  | 
def finalize(self):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
112  | 
"""Release the working tree lock, if held, clean up limbo dir."""  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
113  | 
if self._tree is None:  | 
114  | 
            return
 | 
|
| 
1534.7.162
by Aaron Bentley
 Handle failures creating/deleting the Limbo directory  | 
115  | 
try:  | 
116  | 
for trans_id, kind in self._new_contents.iteritems():  | 
|
117  | 
path = self._limbo_name(trans_id)  | 
|
118  | 
if kind == "directory":  | 
|
119  | 
os.rmdir(path)  | 
|
120  | 
else:  | 
|
121  | 
os.unlink(path)  | 
|
122  | 
try:  | 
|
123  | 
os.rmdir(self._limbodir)  | 
|
124  | 
except OSError:  | 
|
125  | 
                # We don't especially care *why* the dir is immortal.
 | 
|
126  | 
raise ImmortalLimbo(self._limbodir)  | 
|
127  | 
finally:  | 
|
128  | 
self._tree.unlock()  | 
|
129  | 
self._tree = None  | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
130  | 
|
131  | 
def _assign_id(self):  | 
|
132  | 
"""Produce a new tranform id"""  | 
|
133  | 
new_id = "new-%s" % self._id_number  | 
|
134  | 
self._id_number +=1  | 
|
135  | 
return new_id  | 
|
136  | 
||
137  | 
def create_path(self, name, parent):  | 
|
138  | 
"""Assign a transaction id to a new path"""  | 
|
139  | 
trans_id = self._assign_id()  | 
|
140  | 
unique_add(self._new_name, trans_id, name)  | 
|
141  | 
unique_add(self._new_parent, trans_id, parent)  | 
|
142  | 
return trans_id  | 
|
143  | 
||
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
144  | 
def adjust_path(self, name, parent, trans_id):  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
145  | 
"""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  | 
146  | 
if trans_id == self._new_root:  | 
147  | 
raise CantMoveRoot  | 
|
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
148  | 
self._new_name[trans_id] = name  | 
149  | 
self._new_parent[trans_id] = parent  | 
|
150  | 
||
| 
1534.7.68
by Aaron Bentley
 Got semi-reasonable root directory renaming working  | 
151  | 
def adjust_root_path(self, name, parent):  | 
152  | 
"""Emulate moving the root by moving all children, instead.  | 
|
153  | 
        
 | 
|
154  | 
        We do this by undoing the association of root's transaction id with the
 | 
|
155  | 
        current tree.  This allows us to create a new directory with that
 | 
|
| 
1534.7.69
by Aaron Bentley
 Got real root moves working  | 
156  | 
        transaction id.  We unversion the root directory and version the 
 | 
157  | 
        physically new directory, and hope someone versions the tree root
 | 
|
158  | 
        later.
 | 
|
| 
1534.7.68
by Aaron Bentley
 Got semi-reasonable root directory renaming working  | 
159  | 
        """
 | 
160  | 
old_root = self._new_root  | 
|
161  | 
old_root_file_id = self.final_file_id(old_root)  | 
|
162  | 
        # force moving all children of root
 | 
|
163  | 
for child_id in self.iter_tree_children(old_root):  | 
|
164  | 
if child_id != parent:  | 
|
165  | 
self.adjust_path(self.final_name(child_id),  | 
|
166  | 
self.final_parent(child_id), child_id)  | 
|
| 
1534.7.69
by Aaron Bentley
 Got real root moves working  | 
167  | 
file_id = self.final_file_id(child_id)  | 
168  | 
if file_id is not None:  | 
|
169  | 
self.unversion_file(child_id)  | 
|
170  | 
self.version_file(file_id, child_id)  | 
|
| 
1534.7.68
by Aaron Bentley
 Got semi-reasonable root directory renaming working  | 
171  | 
|
172  | 
        # the physical root needs a new transaction id
 | 
|
173  | 
self._tree_path_ids.pop("")  | 
|
174  | 
self._tree_id_paths.pop(old_root)  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
175  | 
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  | 
176  | 
if parent == old_root:  | 
177  | 
parent = self._new_root  | 
|
178  | 
self.adjust_path(name, parent, old_root)  | 
|
179  | 
self.create_directory(old_root)  | 
|
| 
1534.7.69
by Aaron Bentley
 Got real root moves working  | 
180  | 
self.version_file(old_root_file_id, old_root)  | 
181  | 
self.unversion_file(self._new_root)  | 
|
| 
1534.7.68
by Aaron Bentley
 Got semi-reasonable root directory renaming working  | 
182  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
183  | 
def trans_id_tree_file_id(self, inventory_id):  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
184  | 
"""Determine the transaction id of a working tree file.  | 
185  | 
        
 | 
|
186  | 
        This reflects only files that already exist, not ones that will be
 | 
|
187  | 
        added by transactions.
 | 
|
188  | 
        """
 | 
|
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
189  | 
path = self._tree.inventory.id2path(inventory_id)  | 
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
190  | 
return self.trans_id_tree_path(path)  | 
| 
1534.7.7
by Aaron Bentley
 Added support for all-file path ids  | 
191  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
192  | 
def trans_id_file_id(self, file_id):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
193  | 
"""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  | 
194  | 
        A new id is only created for file_ids that were never present.  If
 | 
195  | 
        a transaction has been unversioned, it is deliberately still returned.
 | 
|
196  | 
        (this will likely lead to an unversioned parent conflict.)
 | 
|
197  | 
        """
 | 
|
198  | 
if file_id in self._r_new_id and self._r_new_id[file_id] is not None:  | 
|
199  | 
return self._r_new_id[file_id]  | 
|
200  | 
elif file_id in self._tree.inventory:  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
201  | 
return self.trans_id_tree_file_id(file_id)  | 
| 
1534.7.143
by Aaron Bentley
 Prevented get_trans_id from automatically versioning file ids  | 
202  | 
elif file_id in self._non_present_ids:  | 
203  | 
return self._non_present_ids[file_id]  | 
|
| 
1534.7.75
by Aaron Bentley
 Added reverse-lookup for versioned files and get_trans_id  | 
204  | 
else:  | 
205  | 
trans_id = self._assign_id()  | 
|
| 
1534.7.143
by Aaron Bentley
 Prevented get_trans_id from automatically versioning file ids  | 
206  | 
self._non_present_ids[file_id] = trans_id  | 
| 
1534.7.75
by Aaron Bentley
 Added reverse-lookup for versioned files and get_trans_id  | 
207  | 
return trans_id  | 
208  | 
||
| 
1534.7.12
by Aaron Bentley
 Added canonical_path function  | 
209  | 
def canonical_path(self, path):  | 
210  | 
"""Get the canonical tree-relative path"""  | 
|
211  | 
        # don't follow final symlinks
 | 
|
212  | 
dirname, basename = os.path.split(self._tree.abspath(path))  | 
|
213  | 
dirname = os.path.realpath(dirname)  | 
|
| 
1534.7.166
by Aaron Bentley
 Swapped os.path.join for pathjoin everywhere  | 
214  | 
return self._tree.relpath(pathjoin(dirname, basename))  | 
| 
1534.7.12
by Aaron Bentley
 Added canonical_path function  | 
215  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
216  | 
def trans_id_tree_path(self, path):  | 
| 
1534.7.7
by Aaron Bentley
 Added support for all-file path ids  | 
217  | 
"""Determine (and maybe set) the transaction ID for a tree path."""  | 
| 
1534.7.12
by Aaron Bentley
 Added canonical_path function  | 
218  | 
path = self.canonical_path(path)  | 
| 
1534.7.7
by Aaron Bentley
 Added support for all-file path ids  | 
219  | 
if path not in self._tree_path_ids:  | 
220  | 
self._tree_path_ids[path] = self._assign_id()  | 
|
| 
1534.7.8
by Aaron Bentley
 Added TreeTransform.final_kind  | 
221  | 
self._tree_id_paths[self._tree_path_ids[path]] = path  | 
| 
1534.7.7
by Aaron Bentley
 Added support for all-file path ids  | 
222  | 
return self._tree_path_ids[path]  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
223  | 
|
| 
1534.7.16
by Aaron Bentley
 Added get_tree_parent  | 
224  | 
def get_tree_parent(self, trans_id):  | 
| 
1534.7.31
by Aaron Bentley
 Changed tree root parent to ROOT_PARENT  | 
225  | 
"""Determine id of the parent in the tree."""  | 
| 
1534.7.16
by Aaron Bentley
 Added get_tree_parent  | 
226  | 
path = self._tree_id_paths[trans_id]  | 
227  | 
if path == "":  | 
|
| 
1534.7.31
by Aaron Bentley
 Changed tree root parent to ROOT_PARENT  | 
228  | 
return ROOT_PARENT  | 
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
229  | 
return self.trans_id_tree_path(os.path.dirname(path))  | 
| 
1534.7.16
by Aaron Bentley
 Added get_tree_parent  | 
230  | 
|
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
231  | 
def create_file(self, contents, trans_id, mode_id=None):  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
232  | 
"""Schedule creation of a new file.  | 
233  | 
||
234  | 
        See also new_file.
 | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
235  | 
        
 | 
236  | 
        Contents is an iterator of strings, all of which will be written
 | 
|
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
237  | 
        to the target destination.
 | 
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
238  | 
|
239  | 
        New file takes the permissions of any existing file with that id,
 | 
|
240  | 
        unless mode_id is specified.
 | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
241  | 
        """
 | 
| 
1534.7.73
by Aaron Bentley
 Changed model again. Now iterator is used immediately.  | 
242  | 
f = file(self._limbo_name(trans_id), 'wb')  | 
| 
1534.8.1
by Aaron Bentley
 Reference files in limbo before their creation is finished, for finalize.  | 
243  | 
unique_add(self._new_contents, trans_id, 'file')  | 
| 
1534.7.73
by Aaron Bentley
 Changed model again. Now iterator is used immediately.  | 
244  | 
for segment in contents:  | 
245  | 
f.write(segment)  | 
|
246  | 
f.close()  | 
|
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
247  | 
self._set_mode(trans_id, mode_id, S_ISREG)  | 
248  | 
||
249  | 
def _set_mode(self, trans_id, mode_id, typefunc):  | 
|
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
250  | 
"""Set the mode of new file contents.  | 
251  | 
        The mode_id is the existing file to get the mode from (often the same
 | 
|
252  | 
        as trans_id).  The operation is only performed if there's a mode match
 | 
|
253  | 
        according to typefunc.
 | 
|
254  | 
        """
 | 
|
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
255  | 
if mode_id is None:  | 
256  | 
mode_id = trans_id  | 
|
257  | 
try:  | 
|
258  | 
old_path = self._tree_id_paths[mode_id]  | 
|
259  | 
except KeyError:  | 
|
260  | 
            return
 | 
|
261  | 
try:  | 
|
262  | 
mode = os.stat(old_path).st_mode  | 
|
263  | 
except OSError, e:  | 
|
264  | 
if e.errno == errno.ENOENT:  | 
|
265  | 
                return
 | 
|
266  | 
else:  | 
|
267  | 
                raise
 | 
|
268  | 
if typefunc(mode):  | 
|
269  | 
os.chmod(self._limbo_name(trans_id), mode)  | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
270  | 
|
| 
1534.7.20
by Aaron Bentley
 Added directory handling  | 
271  | 
def create_directory(self, trans_id):  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
272  | 
"""Schedule creation of a new directory.  | 
273  | 
        
 | 
|
274  | 
        See also new_directory.
 | 
|
275  | 
        """
 | 
|
| 
1534.7.73
by Aaron Bentley
 Changed model again. Now iterator is used immediately.  | 
276  | 
os.mkdir(self._limbo_name(trans_id))  | 
277  | 
unique_add(self._new_contents, trans_id, 'directory')  | 
|
| 
1534.7.20
by Aaron Bentley
 Added directory handling  | 
278  | 
|
| 
1534.7.22
by Aaron Bentley
 Added symlink support  | 
279  | 
def create_symlink(self, target, trans_id):  | 
280  | 
"""Schedule creation of a new symbolic link.  | 
|
281  | 
||
282  | 
        target is a bytestring.
 | 
|
283  | 
        See also new_symlink.
 | 
|
284  | 
        """
 | 
|
| 
1534.7.73
by Aaron Bentley
 Changed model again. Now iterator is used immediately.  | 
285  | 
os.symlink(target, self._limbo_name(trans_id))  | 
286  | 
unique_add(self._new_contents, trans_id, 'symlink')  | 
|
| 
1534.7.22
by Aaron Bentley
 Added symlink support  | 
287  | 
|
| 
1534.7.129
by Aaron Bentley
 Converted test cases to Tree Transform  | 
288  | 
    @staticmethod
 | 
289  | 
def delete_any(full_path):  | 
|
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
290  | 
"""Delete a file or directory."""  | 
| 
1534.7.129
by Aaron Bentley
 Converted test cases to Tree Transform  | 
291  | 
try:  | 
292  | 
os.unlink(full_path)  | 
|
293  | 
except OSError, e:  | 
|
294  | 
        # We may be renaming a dangling inventory id
 | 
|
| 
1185.50.85
by John Arbash Meinel
 Mac OSX raises EPERM when you try to unlink a directory  | 
295  | 
if e.errno not in (errno.EISDIR, errno.EACCES, errno.EPERM):  | 
| 
1534.7.129
by Aaron Bentley
 Converted test cases to Tree Transform  | 
296  | 
                raise
 | 
297  | 
os.rmdir(full_path)  | 
|
298  | 
||
299  | 
def cancel_creation(self, trans_id):  | 
|
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
300  | 
"""Cancel the creation of new file contents."""  | 
| 
1534.7.129
by Aaron Bentley
 Converted test cases to Tree Transform  | 
301  | 
del self._new_contents[trans_id]  | 
302  | 
self.delete_any(self._limbo_name(trans_id))  | 
|
303  | 
||
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
304  | 
def delete_contents(self, trans_id):  | 
305  | 
"""Schedule the contents of a path entry for deletion"""  | 
|
| 
1534.7.130
by Aaron Bentley
 More conflict handling, test porting  | 
306  | 
self.tree_kind(trans_id)  | 
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
307  | 
self._removed_contents.add(trans_id)  | 
308  | 
||
| 
1534.7.61
by Aaron Bentley
 Handled parent loops, missing parents, unversioned parents  | 
309  | 
def cancel_deletion(self, trans_id):  | 
310  | 
"""Cancel a scheduled deletion"""  | 
|
311  | 
self._removed_contents.remove(trans_id)  | 
|
312  | 
||
| 
1534.7.39
by Aaron Bentley
 Ensured that files can be unversioned (de-versioned?)  | 
313  | 
def unversion_file(self, trans_id):  | 
314  | 
"""Schedule a path entry to become unversioned"""  | 
|
315  | 
self._removed_id.add(trans_id)  | 
|
316  | 
||
317  | 
def delete_versioned(self, trans_id):  | 
|
318  | 
"""Delete and unversion a versioned file"""  | 
|
319  | 
self.delete_contents(trans_id)  | 
|
320  | 
self.unversion_file(trans_id)  | 
|
321  | 
||
| 
1534.7.25
by Aaron Bentley
 Added set_executability  | 
322  | 
def set_executability(self, executability, trans_id):  | 
| 
1534.7.167
by Aaron Bentley
 PEP8 and comment cleanups  | 
323  | 
"""Schedule setting of the 'execute' bit  | 
324  | 
        To unschedule, set to None
 | 
|
325  | 
        """
 | 
|
| 
1534.7.26
by Aaron Bentley
 Added conflicts for setting executability on unversioned/non-file entries  | 
326  | 
if executability is None:  | 
327  | 
del self._new_executability[trans_id]  | 
|
328  | 
else:  | 
|
329  | 
unique_add(self._new_executability, trans_id, executability)  | 
|
| 
1534.7.25
by Aaron Bentley
 Added set_executability  | 
330  | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
331  | 
def version_file(self, file_id, trans_id):  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
332  | 
"""Schedule a file to become versioned."""  | 
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
333  | 
assert file_id is not None  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
334  | 
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  | 
335  | 
unique_add(self._r_new_id, file_id, trans_id)  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
336  | 
|
| 
1534.7.105
by Aaron Bentley
 Got merge with rename working  | 
337  | 
def cancel_versioning(self, trans_id):  | 
338  | 
"""Undo a previous versioning of a file"""  | 
|
339  | 
file_id = self._new_id[trans_id]  | 
|
340  | 
del self._new_id[trans_id]  | 
|
341  | 
del self._r_new_id[file_id]  | 
|
342  | 
||
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
343  | 
def new_paths(self):  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
344  | 
"""Determine the paths of all new and changed files"""  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
345  | 
new_ids = set()  | 
| 
1534.7.132
by Aaron Bentley
 Got cooked conflicts working  | 
346  | 
fp = FinalPaths(self)  | 
| 
1534.7.4
by Aaron Bentley
 Unified all file types as 'contents'  | 
347  | 
for id_set in (self._new_name, self._new_parent, self._new_contents,  | 
| 
1534.7.25
by Aaron Bentley
 Added set_executability  | 
348  | 
self._new_id, self._new_executability):  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
349  | 
new_ids.update(id_set)  | 
350  | 
new_paths = [(fp.get_path(t), t) for t in new_ids]  | 
|
351  | 
new_paths.sort()  | 
|
352  | 
return new_paths  | 
|
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
353  | 
|
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
354  | 
def tree_kind(self, trans_id):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
355  | 
"""Determine the file kind in the working tree.  | 
356  | 
||
357  | 
        Raises NoSuchFile if the file does not exist
 | 
|
358  | 
        """
 | 
|
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
359  | 
path = self._tree_id_paths.get(trans_id)  | 
360  | 
if path is None:  | 
|
361  | 
raise NoSuchFile(None)  | 
|
362  | 
try:  | 
|
363  | 
return file_kind(self._tree.abspath(path))  | 
|
364  | 
except OSError, e:  | 
|
365  | 
if e.errno != errno.ENOENT:  | 
|
366  | 
                raise
 | 
|
367  | 
else:  | 
|
368  | 
raise NoSuchFile(path)  | 
|
369  | 
||
| 
1534.7.8
by Aaron Bentley
 Added TreeTransform.final_kind  | 
370  | 
def final_kind(self, trans_id):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
371  | 
"""Determine the final file kind, after any changes applied.  | 
| 
1534.7.8
by Aaron Bentley
 Added TreeTransform.final_kind  | 
372  | 
        
 | 
373  | 
        Raises NoSuchFile if the file does not exist/has no contents.
 | 
|
374  | 
        (It is conceivable that a path would be created without the
 | 
|
375  | 
        corresponding contents insertion command)
 | 
|
376  | 
        """
 | 
|
377  | 
if trans_id in self._new_contents:  | 
|
| 
1534.7.73
by Aaron Bentley
 Changed model again. Now iterator is used immediately.  | 
378  | 
return self._new_contents[trans_id]  | 
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
379  | 
elif trans_id in self._removed_contents:  | 
380  | 
raise NoSuchFile(None)  | 
|
| 
1534.7.8
by Aaron Bentley
 Added TreeTransform.final_kind  | 
381  | 
else:  | 
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
382  | 
return self.tree_kind(trans_id)  | 
| 
1534.7.8
by Aaron Bentley
 Added TreeTransform.final_kind  | 
383  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
384  | 
def tree_file_id(self, trans_id):  | 
| 
1534.7.41
by Aaron Bentley
 Got inventory ID movement working  | 
385  | 
"""Determine the file id associated with the trans_id in the tree"""  | 
386  | 
try:  | 
|
387  | 
path = self._tree_id_paths[trans_id]  | 
|
388  | 
except KeyError:  | 
|
389  | 
            # the file is a new, unversioned file, or invalid trans_id
 | 
|
390  | 
return None  | 
|
391  | 
        # the file is old; the old id is still valid
 | 
|
| 
1534.7.68
by Aaron Bentley
 Got semi-reasonable root directory renaming working  | 
392  | 
if self._new_root == trans_id:  | 
393  | 
return self._tree.inventory.root.file_id  | 
|
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
394  | 
return self._tree.inventory.path2id(path)  | 
| 
1534.7.41
by Aaron Bentley
 Got inventory ID movement working  | 
395  | 
|
| 
1534.7.13
by Aaron Bentley
 Implemented final_file_id  | 
396  | 
def final_file_id(self, trans_id):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
397  | 
"""Determine the file id after any changes are applied, or None.  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
398  | 
        
 | 
399  | 
        None indicates that the file will not be versioned after changes are
 | 
|
400  | 
        applied.
 | 
|
401  | 
        """
 | 
|
| 
1534.7.13
by Aaron Bentley
 Implemented final_file_id  | 
402  | 
try:  | 
403  | 
            # there is a new id for this file
 | 
|
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
404  | 
assert self._new_id[trans_id] is not None  | 
| 
1534.7.13
by Aaron Bentley
 Implemented final_file_id  | 
405  | 
return self._new_id[trans_id]  | 
406  | 
except KeyError:  | 
|
| 
1534.7.39
by Aaron Bentley
 Ensured that files can be unversioned (de-versioned?)  | 
407  | 
if trans_id in self._removed_id:  | 
408  | 
return None  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
409  | 
return self.tree_file_id(trans_id)  | 
| 
1534.7.13
by Aaron Bentley
 Implemented final_file_id  | 
410  | 
|
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
411  | 
def inactive_file_id(self, trans_id):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
412  | 
"""Return the inactive file_id associated with a transaction id.  | 
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
413  | 
        That is, the one in the tree or in non_present_ids.
 | 
414  | 
        The file_id may actually be active, too.
 | 
|
415  | 
        """
 | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
416  | 
file_id = self.tree_file_id(trans_id)  | 
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
417  | 
if file_id is not None:  | 
418  | 
return file_id  | 
|
419  | 
for key, value in self._non_present_ids.iteritems():  | 
|
420  | 
if value == trans_id:  | 
|
421  | 
return key  | 
|
422  | 
||
| 
1534.7.17
by Aaron Bentley
 Added final_parent function  | 
423  | 
def final_parent(self, trans_id):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
424  | 
"""Determine the parent file_id, after any changes are applied.  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
425  | 
|
| 
1534.7.31
by Aaron Bentley
 Changed tree root parent to ROOT_PARENT  | 
426  | 
        ROOT_PARENT is returned for the tree root.
 | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
427  | 
        """
 | 
| 
1534.7.17
by Aaron Bentley
 Added final_parent function  | 
428  | 
try:  | 
429  | 
return self._new_parent[trans_id]  | 
|
430  | 
except KeyError:  | 
|
431  | 
return self.get_tree_parent(trans_id)  | 
|
432  | 
||
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
433  | 
def final_name(self, trans_id):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
434  | 
"""Determine the final filename, after all changes are applied."""  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
435  | 
try:  | 
436  | 
return self._new_name[trans_id]  | 
|
437  | 
except KeyError:  | 
|
438  | 
return os.path.basename(self._tree_id_paths[trans_id])  | 
|
439  | 
||
440  | 
def _by_parent(self):  | 
|
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
441  | 
"""Return a map of parent: children for known parents.  | 
442  | 
        
 | 
|
443  | 
        Only new paths and parents of tree files with assigned ids are used.
 | 
|
444  | 
        """
 | 
|
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
445  | 
by_parent = {}  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
446  | 
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.  | 
447  | 
items.extend((t, self.final_parent(t)) for t in  | 
448  | 
self._tree_id_paths.keys())  | 
|
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
449  | 
for trans_id, parent_id in items:  | 
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
450  | 
if parent_id not in by_parent:  | 
451  | 
by_parent[parent_id] = set()  | 
|
452  | 
by_parent[parent_id].add(trans_id)  | 
|
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
453  | 
return by_parent  | 
| 
1534.7.11
by Aaron Bentley
 Refactored conflict handling  | 
454  | 
|
| 
1534.7.57
by Aaron Bentley
 Enhanced conflict resolution.  | 
455  | 
def path_changed(self, trans_id):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
456  | 
"""Return True if a trans_id's path has changed."""  | 
| 
1534.7.57
by Aaron Bentley
 Enhanced conflict resolution.  | 
457  | 
return trans_id in self._new_name or trans_id in self._new_parent  | 
458  | 
||
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
459  | 
def find_conflicts(self):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
460  | 
"""Find any violations of inventory or filesystem invariants"""  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
461  | 
if self.__done is True:  | 
462  | 
raise ReusingTransform()  | 
|
463  | 
conflicts = []  | 
|
464  | 
        # ensure all children of all existent parents are known
 | 
|
465  | 
        # all children of non-existent parents are known, by definition.
 | 
|
466  | 
self._add_tree_children()  | 
|
467  | 
by_parent = self._by_parent()  | 
|
| 
1534.7.15
by Aaron Bentley
 Add conflict types related to versioning  | 
468  | 
conflicts.extend(self._unversioned_parents(by_parent))  | 
| 
1534.7.19
by Aaron Bentley
 Added tests for parent loops  | 
469  | 
conflicts.extend(self._parent_loops())  | 
| 
1534.7.11
by Aaron Bentley
 Refactored conflict handling  | 
470  | 
conflicts.extend(self._duplicate_entries(by_parent))  | 
| 
1534.7.50
by Aaron Bentley
 Detect duplicate inventory ids  | 
471  | 
conflicts.extend(self._duplicate_ids())  | 
| 
1534.7.11
by Aaron Bentley
 Refactored conflict handling  | 
472  | 
conflicts.extend(self._parent_type_conflicts(by_parent))  | 
| 
1534.7.15
by Aaron Bentley
 Add conflict types related to versioning  | 
473  | 
conflicts.extend(self._improper_versioning())  | 
| 
1534.7.26
by Aaron Bentley
 Added conflicts for setting executability on unversioned/non-file entries  | 
474  | 
conflicts.extend(self._executability_conflicts())  | 
| 
1534.7.152
by Aaron Bentley
 Fixed overwrites  | 
475  | 
conflicts.extend(self._overwrite_conflicts())  | 
| 
1534.7.15
by Aaron Bentley
 Add conflict types related to versioning  | 
476  | 
return conflicts  | 
477  | 
||
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
478  | 
def _add_tree_children(self):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
479  | 
"""Add all the children of all active parents to the known paths.  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
480  | 
|
481  | 
        Active parents are those which gain children, and those which are
 | 
|
482  | 
        removed.  This is a necessary first step in detecting conflicts.
 | 
|
483  | 
        """
 | 
|
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
484  | 
parents = self._by_parent().keys()  | 
485  | 
parents.extend([t for t in self._removed_contents if  | 
|
486  | 
self.tree_kind(t) == 'directory'])  | 
|
| 
1534.7.50
by Aaron Bentley
 Detect duplicate inventory ids  | 
487  | 
for trans_id in self._removed_id:  | 
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
488  | 
file_id = self.tree_file_id(trans_id)  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
489  | 
if self._tree.inventory[file_id].kind in ('directory',  | 
490  | 
'root_directory'):  | 
|
| 
1534.7.50
by Aaron Bentley
 Detect duplicate inventory ids  | 
491  | 
parents.append(trans_id)  | 
492  | 
||
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
493  | 
for parent_id in parents:  | 
| 
1534.7.67
by Aaron Bentley
 Refactored _add_tree_children  | 
494  | 
            # ensure that all children are registered with the transaction
 | 
495  | 
list(self.iter_tree_children(parent_id))  | 
|
496  | 
||
497  | 
def iter_tree_children(self, parent_id):  | 
|
498  | 
"""Iterate through the entry's tree children, if any"""  | 
|
499  | 
try:  | 
|
500  | 
path = self._tree_id_paths[parent_id]  | 
|
501  | 
except KeyError:  | 
|
502  | 
            return
 | 
|
503  | 
try:  | 
|
504  | 
children = os.listdir(self._tree.abspath(path))  | 
|
505  | 
except OSError, e:  | 
|
| 
1534.7.71
by abentley
 All tests pass under Windows  | 
506  | 
if e.errno != errno.ENOENT and e.errno != errno.ESRCH:  | 
| 
1534.7.67
by Aaron Bentley
 Refactored _add_tree_children  | 
507  | 
                raise
 | 
508  | 
            return
 | 
|
509  | 
||
510  | 
for child in children:  | 
|
511  | 
childpath = joinpath(path, child)  | 
|
| 
1534.7.180
by Aaron Bentley
 Merge from mainline  | 
512  | 
if self._tree.is_control_filename(childpath):  | 
| 
1534.7.67
by Aaron Bentley
 Refactored _add_tree_children  | 
513  | 
                continue
 | 
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
514  | 
yield self.trans_id_tree_path(childpath)  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
515  | 
|
| 
1534.7.19
by Aaron Bentley
 Added tests for parent loops  | 
516  | 
def _parent_loops(self):  | 
517  | 
"""No entry should be its own ancestor"""  | 
|
518  | 
conflicts = []  | 
|
519  | 
for trans_id in self._new_parent:  | 
|
520  | 
seen = set()  | 
|
521  | 
parent_id = trans_id  | 
|
| 
1534.7.31
by Aaron Bentley
 Changed tree root parent to ROOT_PARENT  | 
522  | 
while parent_id is not ROOT_PARENT:  | 
| 
1534.7.19
by Aaron Bentley
 Added tests for parent loops  | 
523  | 
seen.add(parent_id)  | 
524  | 
parent_id = self.final_parent(parent_id)  | 
|
525  | 
if parent_id == trans_id:  | 
|
526  | 
conflicts.append(('parent loop', trans_id))  | 
|
527  | 
if parent_id in seen:  | 
|
528  | 
                    break
 | 
|
529  | 
return conflicts  | 
|
530  | 
||
| 
1534.7.15
by Aaron Bentley
 Add conflict types related to versioning  | 
531  | 
def _unversioned_parents(self, by_parent):  | 
532  | 
"""If parent directories are versioned, children must be versioned."""  | 
|
533  | 
conflicts = []  | 
|
534  | 
for parent_id, children in by_parent.iteritems():  | 
|
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
535  | 
if parent_id is ROOT_PARENT:  | 
536  | 
                continue
 | 
|
| 
1534.7.15
by Aaron Bentley
 Add conflict types related to versioning  | 
537  | 
if self.final_file_id(parent_id) is not None:  | 
538  | 
                continue
 | 
|
539  | 
for child_id in children:  | 
|
540  | 
if self.final_file_id(child_id) is not None:  | 
|
541  | 
conflicts.append(('unversioned parent', parent_id))  | 
|
542  | 
break;  | 
|
543  | 
return conflicts  | 
|
544  | 
||
545  | 
def _improper_versioning(self):  | 
|
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
546  | 
"""Cannot version a file with no contents, or a bad type.  | 
| 
1534.7.15
by Aaron Bentley
 Add conflict types related to versioning  | 
547  | 
        
 | 
548  | 
        However, existing entries with no contents are okay.
 | 
|
549  | 
        """
 | 
|
550  | 
conflicts = []  | 
|
551  | 
for trans_id in self._new_id.iterkeys():  | 
|
552  | 
try:  | 
|
553  | 
kind = self.final_kind(trans_id)  | 
|
554  | 
except NoSuchFile:  | 
|
555  | 
conflicts.append(('versioning no contents', trans_id))  | 
|
556  | 
                continue
 | 
|
557  | 
if not InventoryEntry.versionable_kind(kind):  | 
|
| 
1534.7.20
by Aaron Bentley
 Added directory handling  | 
558  | 
conflicts.append(('versioning bad kind', trans_id, kind))  | 
| 
1534.7.11
by Aaron Bentley
 Refactored conflict handling  | 
559  | 
return conflicts  | 
560  | 
||
| 
1534.7.26
by Aaron Bentley
 Added conflicts for setting executability on unversioned/non-file entries  | 
561  | 
def _executability_conflicts(self):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
562  | 
"""Check for bad executability changes.  | 
563  | 
        
 | 
|
564  | 
        Only versioned files may have their executability set, because
 | 
|
565  | 
        1. only versioned entries can have executability under windows
 | 
|
566  | 
        2. only files can be executable.  (The execute bit on a directory
 | 
|
567  | 
           does not indicate searchability)
 | 
|
568  | 
        """
 | 
|
| 
1534.7.26
by Aaron Bentley
 Added conflicts for setting executability on unversioned/non-file entries  | 
569  | 
conflicts = []  | 
570  | 
for trans_id in self._new_executability:  | 
|
571  | 
if self.final_file_id(trans_id) is None:  | 
|
572  | 
conflicts.append(('unversioned executability', trans_id))  | 
|
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
573  | 
else:  | 
574  | 
try:  | 
|
575  | 
non_file = self.final_kind(trans_id) != "file"  | 
|
576  | 
except NoSuchFile:  | 
|
577  | 
non_file = True  | 
|
578  | 
if non_file is True:  | 
|
579  | 
conflicts.append(('non-file executability', trans_id))  | 
|
| 
1534.7.26
by Aaron Bentley
 Added conflicts for setting executability on unversioned/non-file entries  | 
580  | 
return conflicts  | 
581  | 
||
| 
1534.7.152
by Aaron Bentley
 Fixed overwrites  | 
582  | 
def _overwrite_conflicts(self):  | 
583  | 
"""Check for overwrites (not permitted on Win32)"""  | 
|
584  | 
conflicts = []  | 
|
585  | 
for trans_id in self._new_contents:  | 
|
586  | 
try:  | 
|
587  | 
self.tree_kind(trans_id)  | 
|
588  | 
except NoSuchFile:  | 
|
589  | 
                continue
 | 
|
590  | 
if trans_id not in self._removed_contents:  | 
|
591  | 
conflicts.append(('overwrite', trans_id,  | 
|
592  | 
self.final_name(trans_id)))  | 
|
593  | 
return conflicts  | 
|
594  | 
||
| 
1534.7.11
by Aaron Bentley
 Refactored conflict handling  | 
595  | 
def _duplicate_entries(self, by_parent):  | 
596  | 
"""No directory may have two entries with the same name."""  | 
|
597  | 
conflicts = []  | 
|
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
598  | 
for children in by_parent.itervalues():  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
599  | 
name_ids = [(self.final_name(t), t) for t in children]  | 
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
600  | 
name_ids.sort()  | 
601  | 
last_name = None  | 
|
602  | 
last_trans_id = None  | 
|
603  | 
for name, trans_id in name_ids:  | 
|
604  | 
if name == last_name:  | 
|
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
605  | 
conflicts.append(('duplicate', last_trans_id, trans_id,  | 
606  | 
name))  | 
|
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
607  | 
last_name = name  | 
608  | 
last_trans_id = trans_id  | 
|
| 
1534.7.11
by Aaron Bentley
 Refactored conflict handling  | 
609  | 
return conflicts  | 
610  | 
||
| 
1534.7.50
by Aaron Bentley
 Detect duplicate inventory ids  | 
611  | 
def _duplicate_ids(self):  | 
612  | 
"""Each inventory id may only be used once"""  | 
|
613  | 
conflicts = []  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
614  | 
removed_tree_ids = set((self.tree_file_id(trans_id) for trans_id in  | 
| 
1534.7.50
by Aaron Bentley
 Detect duplicate inventory ids  | 
615  | 
self._removed_id))  | 
616  | 
active_tree_ids = set((f for f in self._tree.inventory if  | 
|
617  | 
f not in removed_tree_ids))  | 
|
618  | 
for trans_id, file_id in self._new_id.iteritems():  | 
|
619  | 
if file_id in active_tree_ids:  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
620  | 
old_trans_id = self.trans_id_tree_file_id(file_id)  | 
| 
1534.7.50
by Aaron Bentley
 Detect duplicate inventory ids  | 
621  | 
conflicts.append(('duplicate id', old_trans_id, trans_id))  | 
622  | 
return conflicts  | 
|
623  | 
||
| 
1534.7.11
by Aaron Bentley
 Refactored conflict handling  | 
624  | 
def _parent_type_conflicts(self, by_parent):  | 
625  | 
"""parents must have directory 'contents'."""  | 
|
626  | 
conflicts = []  | 
|
| 
1534.7.37
by Aaron Bentley
 Allowed removed dirs to have content-free children.  | 
627  | 
for parent_id, children in by_parent.iteritems():  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
628  | 
if parent_id is ROOT_PARENT:  | 
629  | 
                continue
 | 
|
| 
1534.7.37
by Aaron Bentley
 Allowed removed dirs to have content-free children.  | 
630  | 
if not self._any_contents(children):  | 
631  | 
                continue
 | 
|
632  | 
for child in children:  | 
|
633  | 
try:  | 
|
634  | 
self.final_kind(child)  | 
|
635  | 
except NoSuchFile:  | 
|
636  | 
                    continue
 | 
|
| 
1534.7.10
by Aaron Bentley
 Implemented missing parent and non-directory parent conflicts  | 
637  | 
try:  | 
638  | 
kind = self.final_kind(parent_id)  | 
|
639  | 
except NoSuchFile:  | 
|
640  | 
kind = None  | 
|
641  | 
if kind is None:  | 
|
642  | 
conflicts.append(('missing parent', parent_id))  | 
|
643  | 
elif kind != "directory":  | 
|
644  | 
conflicts.append(('non-directory parent', parent_id))  | 
|
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
645  | 
return conflicts  | 
| 
1534.7.37
by Aaron Bentley
 Allowed removed dirs to have content-free children.  | 
646  | 
|
647  | 
def _any_contents(self, trans_ids):  | 
|
648  | 
"""Return true if any of the trans_ids, will have contents."""  | 
|
649  | 
for trans_id in trans_ids:  | 
|
650  | 
try:  | 
|
651  | 
kind = self.final_kind(trans_id)  | 
|
652  | 
except NoSuchFile:  | 
|
653  | 
                continue
 | 
|
654  | 
return True  | 
|
655  | 
return False  | 
|
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
656  | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
657  | 
def apply(self):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
658  | 
"""Apply all changes to the inventory and filesystem.  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
659  | 
        
 | 
660  | 
        If filesystem or inventory conflicts are present, MalformedTransform
 | 
|
661  | 
        will be thrown.
 | 
|
662  | 
        """
 | 
|
| 
1534.7.49
by Aaron Bentley
 Printed conflicts in MalformedTransform  | 
663  | 
conflicts = self.find_conflicts()  | 
664  | 
if len(conflicts) != 0:  | 
|
665  | 
raise MalformedTransform(conflicts=conflicts)  | 
|
| 
1534.7.41
by Aaron Bentley
 Got inventory ID movement working  | 
666  | 
limbo_inv = {}  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
667  | 
inv = self._tree.inventory  | 
| 
1534.7.41
by Aaron Bentley
 Got inventory ID movement working  | 
668  | 
self._apply_removals(inv, limbo_inv)  | 
| 
1534.7.191
by Aaron Bentley
 Got transform.apply to list modified paths  | 
669  | 
modified_paths = self._apply_insertions(inv, limbo_inv)  | 
| 
1534.7.35
by Aaron Bentley
 Got file renaming working  | 
670  | 
self._tree._write_inventory(inv)  | 
671  | 
self.__done = True  | 
|
| 
1534.7.59
by Aaron Bentley
 Simplified tests  | 
672  | 
self.finalize()  | 
| 
1534.7.191
by Aaron Bentley
 Got transform.apply to list modified paths  | 
673  | 
return _TransformResults(modified_paths)  | 
| 
1534.7.35
by Aaron Bentley
 Got file renaming working  | 
674  | 
|
| 
1534.7.72
by Aaron Bentley
 Moved new content generation to pre-renames  | 
675  | 
def _limbo_name(self, trans_id):  | 
676  | 
"""Generate the limbo name of a file"""  | 
|
| 
1534.7.166
by Aaron Bentley
 Swapped os.path.join for pathjoin everywhere  | 
677  | 
return pathjoin(self._limbodir, trans_id)  | 
| 
1534.7.72
by Aaron Bentley
 Moved new content generation to pre-renames  | 
678  | 
|
| 
1534.7.41
by Aaron Bentley
 Got inventory ID movement working  | 
679  | 
def _apply_removals(self, inv, limbo_inv):  | 
| 
1534.7.36
by Aaron Bentley
 Added rename tests  | 
680  | 
"""Perform tree operations that remove directory/inventory names.  | 
681  | 
        
 | 
|
682  | 
        That is, delete files that are to be deleted, and put any files that
 | 
|
683  | 
        need renaming into limbo.  This must be done in strict child-to-parent
 | 
|
684  | 
        order.
 | 
|
685  | 
        """
 | 
|
| 
1534.7.35
by Aaron Bentley
 Got file renaming working  | 
686  | 
tree_paths = list(self._tree_path_ids.iteritems())  | 
687  | 
tree_paths.sort(reverse=True)  | 
|
| 
1534.9.1
by Aaron Bentley
 Added progress bars to merge  | 
688  | 
for num, data in enumerate(tree_paths):  | 
689  | 
path, trans_id = data  | 
|
690  | 
self._pb.update('removing file', num+1, len(tree_paths))  | 
|
| 
1534.7.43
by abentley
 Fixed some Windows bugs, introduced a conflicts bug  | 
691  | 
full_path = self._tree.abspath(path)  | 
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
692  | 
if trans_id in self._removed_contents:  | 
| 
1534.7.129
by Aaron Bentley
 Converted test cases to Tree Transform  | 
693  | 
self.delete_any(full_path)  | 
| 
1534.7.35
by Aaron Bentley
 Got file renaming working  | 
694  | 
elif trans_id in self._new_name or trans_id in self._new_parent:  | 
| 
1534.7.48
by Aaron Bentley
 Ensured we can move/rename dangling inventory entries  | 
695  | 
try:  | 
| 
1534.7.118
by Aaron Bentley
 Dirty merge of the mainline  | 
696  | 
os.rename(full_path, self._limbo_name(trans_id))  | 
| 
1534.7.48
by Aaron Bentley
 Ensured we can move/rename dangling inventory entries  | 
697  | 
except OSError, e:  | 
698  | 
if e.errno != errno.ENOENT:  | 
|
699  | 
                        raise
 | 
|
| 
1534.7.39
by Aaron Bentley
 Ensured that files can be unversioned (de-versioned?)  | 
700  | 
if trans_id in self._removed_id:  | 
| 
1534.7.69
by Aaron Bentley
 Got real root moves working  | 
701  | 
if trans_id == self._new_root:  | 
702  | 
file_id = self._tree.inventory.root.file_id  | 
|
703  | 
else:  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
704  | 
file_id = self.tree_file_id(trans_id)  | 
| 
1534.7.69
by Aaron Bentley
 Got real root moves working  | 
705  | 
del inv[file_id]  | 
| 
1534.7.41
by Aaron Bentley
 Got inventory ID movement working  | 
706  | 
elif trans_id in self._new_name or trans_id in self._new_parent:  | 
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
707  | 
file_id = self.tree_file_id(trans_id)  | 
| 
1534.7.57
by Aaron Bentley
 Enhanced conflict resolution.  | 
708  | 
if file_id is not None:  | 
709  | 
limbo_inv[trans_id] = inv[file_id]  | 
|
710  | 
del inv[file_id]  | 
|
| 
1534.9.1
by Aaron Bentley
 Added progress bars to merge  | 
711  | 
self._pb.clear()  | 
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
712  | 
|
| 
1534.7.41
by Aaron Bentley
 Got inventory ID movement working  | 
713  | 
def _apply_insertions(self, inv, limbo_inv):  | 
| 
1534.7.36
by Aaron Bentley
 Added rename tests  | 
714  | 
"""Perform tree operations that insert directory/inventory names.  | 
715  | 
        
 | 
|
716  | 
        That is, create any files that need to be created, and restore from
 | 
|
717  | 
        limbo any files that needed renaming.  This must be done in strict
 | 
|
718  | 
        parent-to-child order.
 | 
|
719  | 
        """
 | 
|
| 
1534.9.1
by Aaron Bentley
 Added progress bars to merge  | 
720  | 
new_paths = self.new_paths()  | 
| 
1534.7.191
by Aaron Bentley
 Got transform.apply to list modified paths  | 
721  | 
modified_paths = []  | 
| 
1534.9.1
by Aaron Bentley
 Added progress bars to merge  | 
722  | 
for num, (path, trans_id) in enumerate(new_paths):  | 
723  | 
self._pb.update('adding file', num+1, len(new_paths))  | 
|
| 
1534.7.4
by Aaron Bentley
 Unified all file types as 'contents'  | 
724  | 
try:  | 
| 
1534.7.73
by Aaron Bentley
 Changed model again. Now iterator is used immediately.  | 
725  | 
kind = self._new_contents[trans_id]  | 
| 
1534.7.4
by Aaron Bentley
 Unified all file types as 'contents'  | 
726  | 
except KeyError:  | 
727  | 
kind = contents = None  | 
|
| 
1534.7.72
by Aaron Bentley
 Moved new content generation to pre-renames  | 
728  | 
if trans_id in self._new_contents or self.path_changed(trans_id):  | 
| 
1534.7.48
by Aaron Bentley
 Ensured we can move/rename dangling inventory entries  | 
729  | 
full_path = self._tree.abspath(path)  | 
730  | 
try:  | 
|
| 
1534.7.72
by Aaron Bentley
 Moved new content generation to pre-renames  | 
731  | 
os.rename(self._limbo_name(trans_id), full_path)  | 
| 
1534.7.48
by Aaron Bentley
 Ensured we can move/rename dangling inventory entries  | 
732  | 
except OSError, e:  | 
733  | 
                    # We may be renaming a dangling inventory id
 | 
|
734  | 
if e.errno != errno.ENOENT:  | 
|
735  | 
                        raise
 | 
|
| 
1534.7.73
by Aaron Bentley
 Changed model again. Now iterator is used immediately.  | 
736  | 
if trans_id in self._new_contents:  | 
| 
1534.7.191
by Aaron Bentley
 Got transform.apply to list modified paths  | 
737  | 
modified_paths.append(full_path)  | 
| 
1534.7.73
by Aaron Bentley
 Changed model again. Now iterator is used immediately.  | 
738  | 
del self._new_contents[trans_id]  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
739  | 
|
740  | 
if trans_id in self._new_id:  | 
|
741  | 
if kind is None:  | 
|
| 
1534.7.14
by Aaron Bentley
 Fixed file_kind call  | 
742  | 
kind = file_kind(self._tree.abspath(path))  | 
| 
1534.7.149
by Aaron Bentley
 Removed bare except  | 
743  | 
inv.add_path(path, kind, self._new_id[trans_id])  | 
| 
1534.7.41
by Aaron Bentley
 Got inventory ID movement working  | 
744  | 
elif trans_id in self._new_name or trans_id in self._new_parent:  | 
| 
1534.7.56
by Aaron Bentley
 Implemented the backup file detritus  | 
745  | 
entry = limbo_inv.get(trans_id)  | 
746  | 
if entry is not None:  | 
|
747  | 
entry.name = self.final_name(trans_id)  | 
|
| 
1534.7.150
by Aaron Bentley
 Handled simultaneous renames of parent and child better  | 
748  | 
parent_path = os.path.dirname(path)  | 
749  | 
entry.parent_id = self._tree.inventory.path2id(parent_path)  | 
|
| 
1534.7.56
by Aaron Bentley
 Implemented the backup file detritus  | 
750  | 
inv.add(entry)  | 
| 
1534.7.41
by Aaron Bentley
 Got inventory ID movement working  | 
751  | 
|
| 
1534.7.25
by Aaron Bentley
 Added set_executability  | 
752  | 
            # requires files and inventory entries to be in place
 | 
753  | 
if trans_id in self._new_executability:  | 
|
754  | 
self._set_executability(path, inv, trans_id)  | 
|
| 
1534.9.1
by Aaron Bentley
 Added progress bars to merge  | 
755  | 
self._pb.clear()  | 
| 
1534.7.191
by Aaron Bentley
 Got transform.apply to list modified paths  | 
756  | 
return modified_paths  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
757  | 
|
| 
1534.7.25
by Aaron Bentley
 Added set_executability  | 
758  | 
def _set_executability(self, path, inv, trans_id):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
759  | 
"""Set the executability of versioned files """  | 
| 
1534.7.25
by Aaron Bentley
 Added set_executability  | 
760  | 
file_id = inv.path2id(path)  | 
761  | 
new_executability = self._new_executability[trans_id]  | 
|
762  | 
inv[file_id].executable = new_executability  | 
|
763  | 
if supports_executable():  | 
|
764  | 
abspath = self._tree.abspath(path)  | 
|
765  | 
current_mode = os.stat(abspath).st_mode  | 
|
766  | 
if new_executability:  | 
|
767  | 
umask = os.umask(0)  | 
|
768  | 
os.umask(umask)  | 
|
769  | 
to_mode = current_mode | (0100 & ~umask)  | 
|
770  | 
                # Enable x-bit for others only if they can read it.
 | 
|
771  | 
if current_mode & 0004:  | 
|
772  | 
to_mode |= 0001 & ~umask  | 
|
773  | 
if current_mode & 0040:  | 
|
774  | 
to_mode |= 0010 & ~umask  | 
|
775  | 
else:  | 
|
776  | 
to_mode = current_mode & ~0111  | 
|
777  | 
os.chmod(abspath, to_mode)  | 
|
778  | 
||
| 
1534.7.23
by Aaron Bentley
 Transform.new_entry -> Transform._new_entry  | 
779  | 
def _new_entry(self, name, parent_id, file_id):  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
780  | 
"""Helper function to create a new filesystem entry."""  | 
| 
1534.7.2
by Aaron Bentley
 Added convenience function  | 
781  | 
trans_id = self.create_path(name, parent_id)  | 
782  | 
if file_id is not None:  | 
|
783  | 
self.version_file(file_id, trans_id)  | 
|
784  | 
return trans_id  | 
|
785  | 
||
| 
1534.7.27
by Aaron Bentley
 Added execute bit to new_file method  | 
786  | 
def new_file(self, name, parent_id, contents, file_id=None,  | 
787  | 
executable=None):  | 
|
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
788  | 
"""Convenience method to create files.  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
789  | 
        
 | 
790  | 
        name is the name of the file to create.
 | 
|
791  | 
        parent_id is the transaction id of the parent directory of the file.
 | 
|
792  | 
        contents is an iterator of bytestrings, which will be used to produce
 | 
|
793  | 
        the file.
 | 
|
794  | 
        file_id is the inventory ID of the file, if it is to be versioned.
 | 
|
795  | 
        """
 | 
|
| 
1534.7.23
by Aaron Bentley
 Transform.new_entry -> Transform._new_entry  | 
796  | 
trans_id = self._new_entry(name, parent_id, file_id)  | 
| 
1534.7.20
by Aaron Bentley
 Added directory handling  | 
797  | 
self.create_file(contents, trans_id)  | 
| 
1534.7.27
by Aaron Bentley
 Added execute bit to new_file method  | 
798  | 
if executable is not None:  | 
799  | 
self.set_executability(executable, trans_id)  | 
|
| 
1534.7.20
by Aaron Bentley
 Added directory handling  | 
800  | 
return trans_id  | 
801  | 
||
802  | 
def new_directory(self, name, parent_id, file_id=None):  | 
|
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
803  | 
"""Convenience method to create directories.  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
804  | 
|
805  | 
        name is the name of the directory to create.
 | 
|
806  | 
        parent_id is the transaction id of the parent directory of the
 | 
|
807  | 
        directory.
 | 
|
808  | 
        file_id is the inventory ID of the directory, if it is to be versioned.
 | 
|
809  | 
        """
 | 
|
| 
1534.7.23
by Aaron Bentley
 Transform.new_entry -> Transform._new_entry  | 
810  | 
trans_id = self._new_entry(name, parent_id, file_id)  | 
| 
1534.7.20
by Aaron Bentley
 Added directory handling  | 
811  | 
self.create_directory(trans_id)  | 
812  | 
return trans_id  | 
|
813  | 
||
| 
1534.7.22
by Aaron Bentley
 Added symlink support  | 
814  | 
def new_symlink(self, name, parent_id, target, file_id=None):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
815  | 
"""Convenience method to create symbolic link.  | 
| 
1534.7.22
by Aaron Bentley
 Added symlink support  | 
816  | 
        
 | 
817  | 
        name is the name of the symlink to create.
 | 
|
818  | 
        parent_id is the transaction id of the parent directory of the symlink.
 | 
|
819  | 
        target is a bytestring of the target of the symlink.
 | 
|
820  | 
        file_id is the inventory ID of the file, if it is to be versioned.
 | 
|
821  | 
        """
 | 
|
| 
1534.7.23
by Aaron Bentley
 Transform.new_entry -> Transform._new_entry  | 
822  | 
trans_id = self._new_entry(name, parent_id, file_id)  | 
| 
1534.7.22
by Aaron Bentley
 Added symlink support  | 
823  | 
self.create_symlink(target, trans_id)  | 
824  | 
return trans_id  | 
|
825  | 
||
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
826  | 
def joinpath(parent, child):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
827  | 
"""Join tree-relative paths, handling the tree root specially"""  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
828  | 
if parent is None or parent == "":  | 
829  | 
return child  | 
|
830  | 
else:  | 
|
| 
1534.7.166
by Aaron Bentley
 Swapped os.path.join for pathjoin everywhere  | 
831  | 
return pathjoin(parent, child)  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
832  | 
|
| 
1534.7.167
by Aaron Bentley
 PEP8 and comment cleanups  | 
833  | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
834  | 
class FinalPaths(object):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
835  | 
"""Make path calculation cheap by memoizing paths.  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
836  | 
|
837  | 
    The underlying tree must not be manipulated between calls, or else
 | 
|
838  | 
    the results will likely be incorrect.
 | 
|
839  | 
    """
 | 
|
| 
1534.7.132
by Aaron Bentley
 Got cooked conflicts working  | 
840  | 
def __init__(self, transform):  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
841  | 
object.__init__(self)  | 
842  | 
self._known_paths = {}  | 
|
| 
1534.7.33
by Aaron Bentley
 Fixed naming  | 
843  | 
self.transform = transform  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
844  | 
|
845  | 
def _determine_path(self, trans_id):  | 
|
| 
1534.7.132
by Aaron Bentley
 Got cooked conflicts working  | 
846  | 
if trans_id == self.transform.root:  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
847  | 
return ""  | 
| 
1534.7.33
by Aaron Bentley
 Fixed naming  | 
848  | 
name = self.transform.final_name(trans_id)  | 
849  | 
parent_id = self.transform.final_parent(trans_id)  | 
|
| 
1534.7.132
by Aaron Bentley
 Got cooked conflicts working  | 
850  | 
if parent_id == self.transform.root:  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
851  | 
return name  | 
852  | 
else:  | 
|
| 
1534.7.166
by Aaron Bentley
 Swapped os.path.join for pathjoin everywhere  | 
853  | 
return pathjoin(self.get_path(parent_id), name)  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
854  | 
|
855  | 
def get_path(self, trans_id):  | 
|
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
856  | 
"""Find the final path associated with a trans_id"""  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
857  | 
if trans_id not in self._known_paths:  | 
858  | 
self._known_paths[trans_id] = self._determine_path(trans_id)  | 
|
859  | 
return self._known_paths[trans_id]  | 
|
| 
1534.7.28
by Aaron Bentley
 Nearly-working build_tree replacement  | 
860  | 
|
| 
1534.7.30
by Aaron Bentley
 Factored out topological id sorting  | 
861  | 
def topology_sorted_ids(tree):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
862  | 
"""Determine the topological order of the ids in a tree"""  | 
| 
1534.7.30
by Aaron Bentley
 Factored out topological id sorting  | 
863  | 
file_ids = list(tree)  | 
864  | 
file_ids.sort(key=tree.id2path)  | 
|
865  | 
return file_ids  | 
|
| 
1534.7.28
by Aaron Bentley
 Nearly-working build_tree replacement  | 
866  | 
|
| 
1534.7.165
by Aaron Bentley
 Switched to build_tree instead of revert  | 
867  | 
def build_tree(tree, wt):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
868  | 
"""Create working tree for a branch, using a Transaction."""  | 
| 
1534.7.28
by Aaron Bentley
 Nearly-working build_tree replacement  | 
869  | 
file_trans_id = {}  | 
870  | 
tt = TreeTransform(wt)  | 
|
871  | 
try:  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
872  | 
file_trans_id[wt.get_root_id()] = tt.trans_id_tree_file_id(wt.get_root_id())  | 
| 
1534.7.30
by Aaron Bentley
 Factored out topological id sorting  | 
873  | 
file_ids = topology_sorted_ids(tree)  | 
| 
1534.7.29
by Aaron Bentley
 Got build passing all tests  | 
874  | 
for file_id in file_ids:  | 
| 
1534.7.28
by Aaron Bentley
 Nearly-working build_tree replacement  | 
875  | 
entry = tree.inventory[file_id]  | 
876  | 
if entry.parent_id is None:  | 
|
877  | 
                continue
 | 
|
878  | 
if entry.parent_id not in file_trans_id:  | 
|
879  | 
raise repr(entry.parent_id)  | 
|
880  | 
parent_id = file_trans_id[entry.parent_id]  | 
|
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
881  | 
file_trans_id[file_id] = new_by_entry(tt, entry, parent_id, tree)  | 
882  | 
tt.apply()  | 
|
883  | 
finally:  | 
|
884  | 
tt.finalize()  | 
|
885  | 
||
886  | 
def new_by_entry(tt, entry, parent_id, tree):  | 
|
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
887  | 
"""Create a new file according to its inventory entry"""  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
888  | 
name = entry.name  | 
889  | 
kind = entry.kind  | 
|
890  | 
if kind == 'file':  | 
|
| 
1534.7.79
by Aaron Bentley
 Stopped calling get_file_lines on WorkingTree  | 
891  | 
contents = tree.get_file(entry.file_id).readlines()  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
892  | 
executable = tree.is_executable(entry.file_id)  | 
893  | 
return tt.new_file(name, parent_id, contents, entry.file_id,  | 
|
894  | 
executable)  | 
|
895  | 
elif kind == 'directory':  | 
|
| 
1534.7.54
by Aaron Bentley
 Fixed thinko  | 
896  | 
return tt.new_directory(name, parent_id, entry.file_id)  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
897  | 
elif kind == 'symlink':  | 
| 
1534.7.183
by Aaron Bentley
 Fixed build_tree with symlinks  | 
898  | 
target = tree.get_symlink_target(entry.file_id)  | 
899  | 
return tt.new_symlink(name, parent_id, target, entry.file_id)  | 
|
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
900  | 
|
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
901  | 
def create_by_entry(tt, entry, tree, trans_id, lines=None, mode_id=None):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
902  | 
"""Create new file contents according to an inventory entry."""  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
903  | 
if entry.kind == "file":  | 
| 
1534.7.97
by Aaron Bentley
 Ensured foo.BASE is a directory if there's a conflict  | 
904  | 
if lines == None:  | 
905  | 
lines = tree.get_file(entry.file_id).readlines()  | 
|
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
906  | 
tt.create_file(lines, trans_id, mode_id=mode_id)  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
907  | 
elif entry.kind == "symlink":  | 
| 
1534.7.101
by Aaron Bentley
 Got conflicts on symlinks working properly  | 
908  | 
tt.create_symlink(tree.get_symlink_target(entry.file_id), trans_id)  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
909  | 
elif entry.kind == "directory":  | 
| 
1534.7.51
by Aaron Bentley
 New approach to revert  | 
910  | 
tt.create_directory(trans_id)  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
911  | 
|
| 
1534.7.89
by Aaron Bentley
 Handle all content types in three-way  | 
912  | 
def create_entry_executability(tt, entry, trans_id):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
913  | 
"""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  | 
914  | 
if entry.kind == "file":  | 
915  | 
tt.set_executability(entry.executable, trans_id)  | 
|
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
916  | 
|
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
917  | 
|
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
918  | 
def find_interesting(working_tree, target_tree, filenames):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
919  | 
"""Find the ids corresponding to specified filenames."""  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
920  | 
if not filenames:  | 
921  | 
interesting_ids = None  | 
|
922  | 
else:  | 
|
923  | 
interesting_ids = set()  | 
|
| 
1534.7.118
by Aaron Bentley
 Dirty merge of the mainline  | 
924  | 
for tree_path in filenames:  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
925  | 
for tree in (working_tree, target_tree):  | 
926  | 
not_found = True  | 
|
927  | 
file_id = tree.inventory.path2id(tree_path)  | 
|
928  | 
if file_id is not None:  | 
|
929  | 
interesting_ids.add(file_id)  | 
|
930  | 
not_found = False  | 
|
931  | 
if not_found:  | 
|
| 
1534.7.123
by Aaron Bentley
 Fixed handling of unversioned files  | 
932  | 
raise NotVersionedError(path=tree_path)  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
933  | 
return interesting_ids  | 
934  | 
||
935  | 
||
| 
1534.7.56
by Aaron Bentley
 Implemented the backup file detritus  | 
936  | 
def change_entry(tt, file_id, working_tree, target_tree,  | 
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
937  | 
trans_id_file_id, backups, trans_id):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
938  | 
"""Replace a file_id's contents with those from a target tree."""  | 
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
939  | 
e_trans_id = trans_id_file_id(file_id)  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
940  | 
entry = target_tree.inventory[file_id]  | 
941  | 
has_contents, contents_mod, meta_mod, = _entry_changes(file_id, entry,  | 
|
942  | 
working_tree)  | 
|
943  | 
if contents_mod:  | 
|
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
944  | 
mode_id = e_trans_id  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
945  | 
if has_contents:  | 
| 
1534.7.56
by Aaron Bentley
 Implemented the backup file detritus  | 
946  | 
if not backups:  | 
947  | 
tt.delete_contents(e_trans_id)  | 
|
948  | 
else:  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
949  | 
parent_trans_id = trans_id_file_id(entry.parent_id)  | 
| 
1534.7.56
by Aaron Bentley
 Implemented the backup file detritus  | 
950  | 
tt.adjust_path(entry.name+"~", parent_trans_id, e_trans_id)  | 
951  | 
tt.unversion_file(e_trans_id)  | 
|
952  | 
e_trans_id = tt.create_path(entry.name, parent_trans_id)  | 
|
953  | 
tt.version_file(file_id, e_trans_id)  | 
|
954  | 
trans_id[file_id] = e_trans_id  | 
|
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
955  | 
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  | 
956  | 
create_entry_executability(tt, entry, e_trans_id)  | 
957  | 
||
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
958  | 
elif meta_mod:  | 
| 
1534.7.58
by abentley
 Fixed executability bug  | 
959  | 
tt.set_executability(entry.executable, e_trans_id)  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
960  | 
if tt.final_name(e_trans_id) != entry.name:  | 
961  | 
adjust_path = True  | 
|
962  | 
else:  | 
|
963  | 
parent_id = tt.final_parent(e_trans_id)  | 
|
964  | 
parent_file_id = tt.final_file_id(parent_id)  | 
|
965  | 
if parent_file_id != entry.parent_id:  | 
|
966  | 
adjust_path = True  | 
|
967  | 
else:  | 
|
968  | 
adjust_path = False  | 
|
969  | 
if adjust_path:  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
970  | 
parent_trans_id = trans_id_file_id(entry.parent_id)  | 
| 
1534.7.56
by Aaron Bentley
 Implemented the backup file detritus  | 
971  | 
tt.adjust_path(entry.name, parent_trans_id, e_trans_id)  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
972  | 
|
973  | 
||
974  | 
def _entry_changes(file_id, entry, working_tree):  | 
|
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
975  | 
"""Determine in which ways the inventory entry has changed.  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
976  | 
|
977  | 
    Returns booleans: has_contents, content_mod, meta_mod
 | 
|
978  | 
    has_contents means there are currently contents, but they differ
 | 
|
979  | 
    contents_mod means contents need to be modified
 | 
|
980  | 
    meta_mod means the metadata needs to be modified
 | 
|
981  | 
    """
 | 
|
982  | 
cur_entry = working_tree.inventory[file_id]  | 
|
983  | 
try:  | 
|
984  | 
working_kind = working_tree.kind(file_id)  | 
|
985  | 
has_contents = True  | 
|
986  | 
except OSError, e:  | 
|
987  | 
if e.errno != errno.ENOENT:  | 
|
988  | 
            raise
 | 
|
989  | 
has_contents = False  | 
|
990  | 
contents_mod = True  | 
|
991  | 
meta_mod = False  | 
|
992  | 
if has_contents is True:  | 
|
993  | 
real_e_kind = entry.kind  | 
|
994  | 
if real_e_kind == 'root_directory':  | 
|
995  | 
real_e_kind = 'directory'  | 
|
996  | 
if real_e_kind != working_kind:  | 
|
997  | 
contents_mod, meta_mod = True, False  | 
|
998  | 
else:  | 
|
999  | 
cur_entry._read_tree_state(working_tree.id2path(file_id),  | 
|
1000  | 
working_tree)  | 
|
1001  | 
contents_mod, meta_mod = entry.detect_changes(cur_entry)  | 
|
| 
1534.7.175
by Aaron Bentley
 Ensured revert writes a normal inventory  | 
1002  | 
cur_entry._forget_tree_state()  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1003  | 
return has_contents, contents_mod, meta_mod  | 
1004  | 
||
| 
1534.7.56
by Aaron Bentley
 Implemented the backup file detritus  | 
1005  | 
|
| 
1534.9.4
by Aaron Bentley
 Added progress bars to revert.  | 
1006  | 
def revert(working_tree, target_tree, filenames, backups=False,  | 
1007  | 
pb=DummyProgress()):  | 
|
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
1008  | 
"""Revert a working tree's contents to those of a target tree."""  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1009  | 
interesting_ids = find_interesting(working_tree, target_tree, filenames)  | 
1010  | 
def interesting(file_id):  | 
|
1011  | 
return interesting_ids is None or file_id in interesting_ids  | 
|
1012  | 
||
| 
1534.9.7
by Aaron Bentley
 Show progress bars in revert  | 
1013  | 
tt = TreeTransform(working_tree, pb)  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1014  | 
try:  | 
| 
1558.3.3
by Aaron Bentley
 Fix error handling for merge_modified  | 
1015  | 
merge_modified = working_tree.merge_modified()  | 
| 
1534.7.51
by Aaron Bentley
 New approach to revert  | 
1016  | 
trans_id = {}  | 
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
1017  | 
def trans_id_file_id(file_id):  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1018  | 
try:  | 
| 
1534.7.51
by Aaron Bentley
 New approach to revert  | 
1019  | 
return trans_id[file_id]  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1020  | 
except KeyError:  | 
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
1021  | 
return tt.trans_id_tree_file_id(file_id)  | 
| 
1534.7.51
by Aaron Bentley
 New approach to revert  | 
1022  | 
|
| 
1534.9.4
by Aaron Bentley
 Added progress bars to revert.  | 
1023  | 
sorted_interesting = [i for i in topology_sorted_ids(target_tree) if  | 
1024  | 
interesting(i)]  | 
|
1025  | 
for id_num, file_id in enumerate(sorted_interesting):  | 
|
1026  | 
pb.update("Reverting file", id_num+1, len(sorted_interesting))  | 
|
| 
1534.7.52
by Aaron Bentley
 Revert fixes with disappearing roots  | 
1027  | 
if file_id not in working_tree.inventory:  | 
| 
1534.7.51
by Aaron Bentley
 New approach to revert  | 
1028  | 
entry = target_tree.inventory[file_id]  | 
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
1029  | 
parent_id = trans_id_file_id(entry.parent_id)  | 
| 
1534.7.51
by Aaron Bentley
 New approach to revert  | 
1030  | 
e_trans_id = new_by_entry(tt, entry, parent_id, target_tree)  | 
1031  | 
trans_id[file_id] = e_trans_id  | 
|
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1032  | 
else:  | 
| 
1534.7.193
by Aaron Bentley
 Stopped revert from preserving file contents produced by merges  | 
1033  | 
backup_this = backups  | 
1034  | 
if file_id in merge_modified:  | 
|
1035  | 
backup_this = False  | 
|
1036  | 
del merge_modified[file_id]  | 
|
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1037  | 
change_entry(tt, file_id, working_tree, target_tree,  | 
| 
1534.7.193
by Aaron Bentley
 Stopped revert from preserving file contents produced by merges  | 
1038  | 
trans_id_file_id, backup_this, trans_id)  | 
| 
1534.9.5
by Aaron Bentley
 Merged dangling inventory fix  | 
1039  | 
wt_interesting = [i for i in working_tree.inventory if interesting(i)]  | 
| 
1534.9.4
by Aaron Bentley
 Added progress bars to revert.  | 
1040  | 
for id_num, file_id in enumerate(wt_interesting):  | 
1041  | 
pb.update("New file check", id_num+1, len(sorted_interesting))  | 
|
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1042  | 
if file_id not in target_tree:  | 
| 
1534.7.193
by Aaron Bentley
 Stopped revert from preserving file contents produced by merges  | 
1043  | 
trans_id = tt.trans_id_tree_file_id(file_id)  | 
1044  | 
tt.unversion_file(trans_id)  | 
|
1045  | 
if file_id in merge_modified:  | 
|
1046  | 
tt.delete_contents(trans_id)  | 
|
1047  | 
del merge_modified[file_id]  | 
|
| 
1534.9.7
by Aaron Bentley
 Show progress bars in revert  | 
1048  | 
raw_conflicts = resolve_conflicts(tt, pb)  | 
| 
1534.7.173
by Aaron Bentley
 Added conflict warnings to revert  | 
1049  | 
for line in conflicts_strings(cook_conflicts(raw_conflicts, tt)):  | 
1050  | 
warning(line)  | 
|
| 
1534.7.28
by Aaron Bentley
 Nearly-working build_tree replacement  | 
1051  | 
tt.apply()  | 
| 
1534.7.193
by Aaron Bentley
 Stopped revert from preserving file contents produced by merges  | 
1052  | 
working_tree.set_merge_modified({})  | 
| 
1534.7.28
by Aaron Bentley
 Nearly-working build_tree replacement  | 
1053  | 
finally:  | 
1054  | 
tt.finalize()  | 
|
| 
1534.9.4
by Aaron Bentley
 Added progress bars to revert.  | 
1055  | 
pb.clear()  | 
| 
1534.7.51
by Aaron Bentley
 New approach to revert  | 
1056  | 
|
| 
1534.7.57
by Aaron Bentley
 Enhanced conflict resolution.  | 
1057  | 
|
| 
1534.9.1
by Aaron Bentley
 Added progress bars to merge  | 
1058  | 
def resolve_conflicts(tt, pb=DummyProgress()):  | 
| 
1534.7.57
by Aaron Bentley
 Enhanced conflict resolution.  | 
1059  | 
"""Make many conflict-resolution attempts, but die if they fail"""  | 
| 
1534.7.169
by Aaron Bentley
 Add filesystem/inventory conflicts to conflict output  | 
1060  | 
new_conflicts = set()  | 
| 
1534.9.1
by Aaron Bentley
 Added progress bars to merge  | 
1061  | 
try:  | 
1062  | 
for n in range(10):  | 
|
1063  | 
pb.update('Resolution pass', n+1, 10)  | 
|
1064  | 
conflicts = tt.find_conflicts()  | 
|
1065  | 
if len(conflicts) == 0:  | 
|
1066  | 
return new_conflicts  | 
|
1067  | 
new_conflicts.update(conflict_pass(tt, conflicts))  | 
|
1068  | 
raise MalformedTransform(conflicts=conflicts)  | 
|
1069  | 
finally:  | 
|
1070  | 
pb.clear()  | 
|
| 
1534.7.57
by Aaron Bentley
 Enhanced conflict resolution.  | 
1071  | 
|
1072  | 
||
1073  | 
def conflict_pass(tt, conflicts):  | 
|
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
1074  | 
"""Resolve some classes of conflicts."""  | 
| 
1534.7.169
by Aaron Bentley
 Add filesystem/inventory conflicts to conflict output  | 
1075  | 
new_conflicts = set()  | 
| 
1534.7.61
by Aaron Bentley
 Handled parent loops, missing parents, unversioned parents  | 
1076  | 
for c_type, conflict in ((c[0], c) for c in conflicts):  | 
1077  | 
if c_type == 'duplicate id':  | 
|
| 
1534.7.51
by Aaron Bentley
 New approach to revert  | 
1078  | 
tt.unversion_file(conflict[1])  | 
| 
1534.7.170
by Aaron Bentley
 Cleaned up filesystem conflict handling  | 
1079  | 
new_conflicts.add((c_type, 'Unversioned existing file',  | 
1080  | 
conflict[1], conflict[2], ))  | 
|
| 
1534.7.61
by Aaron Bentley
 Handled parent loops, missing parents, unversioned parents  | 
1081  | 
elif c_type == 'duplicate':  | 
| 
1534.7.57
by Aaron Bentley
 Enhanced conflict resolution.  | 
1082  | 
            # files that were renamed take precedence
 | 
1083  | 
new_name = tt.final_name(conflict[1])+'.moved'  | 
|
1084  | 
final_parent = tt.final_parent(conflict[1])  | 
|
1085  | 
if tt.path_changed(conflict[1]):  | 
|
1086  | 
tt.adjust_path(new_name, final_parent, conflict[2])  | 
|
| 
1534.7.171
by Aaron Bentley
 Implemented stringifying filesystem conflicts  | 
1087  | 
new_conflicts.add((c_type, 'Moved existing file to',  | 
1088  | 
conflict[2], conflict[1]))  | 
|
| 
1534.7.57
by Aaron Bentley
 Enhanced conflict resolution.  | 
1089  | 
else:  | 
1090  | 
tt.adjust_path(new_name, final_parent, conflict[1])  | 
|
| 
1534.7.171
by Aaron Bentley
 Implemented stringifying filesystem conflicts  | 
1091  | 
new_conflicts.add((c_type, 'Moved existing file to',  | 
1092  | 
conflict[1], conflict[2]))  | 
|
| 
1534.7.61
by Aaron Bentley
 Handled parent loops, missing parents, unversioned parents  | 
1093  | 
elif c_type == 'parent loop':  | 
1094  | 
            # break the loop by undoing one of the ops that caused the loop
 | 
|
1095  | 
cur = conflict[1]  | 
|
1096  | 
while not tt.path_changed(cur):  | 
|
1097  | 
cur = tt.final_parent(cur)  | 
|
| 
1534.7.170
by Aaron Bentley
 Cleaned up filesystem conflict handling  | 
1098  | 
new_conflicts.add((c_type, 'Cancelled move', cur,  | 
1099  | 
tt.final_parent(cur),))  | 
|
| 
1534.7.61
by Aaron Bentley
 Handled parent loops, missing parents, unversioned parents  | 
1100  | 
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  | 
1101  | 
|
| 
1534.7.61
by Aaron Bentley
 Handled parent loops, missing parents, unversioned parents  | 
1102  | 
elif c_type == 'missing parent':  | 
| 
1534.7.128
by Aaron Bentley
 Got missing contents test working  | 
1103  | 
trans_id = conflict[1]  | 
1104  | 
try:  | 
|
1105  | 
tt.cancel_deletion(trans_id)  | 
|
| 
1534.7.169
by Aaron Bentley
 Add filesystem/inventory conflicts to conflict output  | 
1106  | 
new_conflicts.add((c_type, 'Not deleting', trans_id))  | 
| 
1534.7.128
by Aaron Bentley
 Got missing contents test working  | 
1107  | 
except KeyError:  | 
1108  | 
tt.create_directory(trans_id)  | 
|
| 
1534.7.169
by Aaron Bentley
 Add filesystem/inventory conflicts to conflict output  | 
1109  | 
new_conflicts.add((c_type, 'Created directory.', trans_id))  | 
| 
1534.7.61
by Aaron Bentley
 Handled parent loops, missing parents, unversioned parents  | 
1110  | 
elif c_type == 'unversioned parent':  | 
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
1111  | 
tt.version_file(tt.inactive_file_id(conflict[1]), conflict[1])  | 
| 
1534.7.171
by Aaron Bentley
 Implemented stringifying filesystem conflicts  | 
1112  | 
new_conflicts.add((c_type, 'Versioned directory', conflict[1]))  | 
| 
1534.7.169
by Aaron Bentley
 Add filesystem/inventory conflicts to conflict output  | 
1113  | 
return new_conflicts  | 
1114  | 
||
1115  | 
def cook_conflicts(raw_conflicts, tt):  | 
|
| 
1534.7.170
by Aaron Bentley
 Cleaned up filesystem conflict handling  | 
1116  | 
"""Generate a list of cooked conflicts, sorted by file path"""  | 
1117  | 
def key(conflict):  | 
|
1118  | 
if conflict[2] is not None:  | 
|
1119  | 
return conflict[2], conflict[0]  | 
|
1120  | 
elif len(conflict) == 6:  | 
|
1121  | 
return conflict[4], conflict[0]  | 
|
1122  | 
else:  | 
|
1123  | 
return None, conflict[0]  | 
|
1124  | 
||
1125  | 
return sorted(list(iter_cook_conflicts(raw_conflicts, tt)), key=key)  | 
|
| 
1534.7.169
by Aaron Bentley
 Add filesystem/inventory conflicts to conflict output  | 
1126  | 
|
1127  | 
def iter_cook_conflicts(raw_conflicts, tt):  | 
|
1128  | 
cooked_conflicts = []  | 
|
| 
1534.7.170
by Aaron Bentley
 Cleaned up filesystem conflict handling  | 
1129  | 
fp = FinalPaths(tt)  | 
| 
1534.7.169
by Aaron Bentley
 Add filesystem/inventory conflicts to conflict output  | 
1130  | 
for conflict in raw_conflicts:  | 
1131  | 
c_type = conflict[0]  | 
|
| 
1534.7.170
by Aaron Bentley
 Cleaned up filesystem conflict handling  | 
1132  | 
action = conflict[1]  | 
1133  | 
modified_path = fp.get_path(conflict[2])  | 
|
1134  | 
modified_id = tt.final_file_id(conflict[2])  | 
|
1135  | 
if len(conflict) == 3:  | 
|
1136  | 
yield c_type, action, modified_path, modified_id  | 
|
1137  | 
else:  | 
|
1138  | 
conflicting_path = fp.get_path(conflict[3])  | 
|
1139  | 
conflicting_id = tt.final_file_id(conflict[3])  | 
|
1140  | 
yield (c_type, action, modified_path, modified_id,  | 
|
1141  | 
conflicting_path, conflicting_id)  | 
|
| 
1534.7.171
by Aaron Bentley
 Implemented stringifying filesystem conflicts  | 
1142  | 
|
1143  | 
||
1144  | 
def conflicts_strings(conflicts):  | 
|
1145  | 
"""Generate strings for the provided conflicts"""  | 
|
1146  | 
for conflict in conflicts:  | 
|
1147  | 
conflict_type = conflict[0]  | 
|
1148  | 
if conflict_type == 'text conflict':  | 
|
1149  | 
yield 'Text conflict in %s' % conflict[2]  | 
|
1150  | 
elif conflict_type == 'contents conflict':  | 
|
1151  | 
yield 'Contents conflict in %s' % conflict[2]  | 
|
1152  | 
elif conflict_type == 'path conflict':  | 
|
1153  | 
yield 'Path conflict: %s / %s' % conflict[2:]  | 
|
1154  | 
elif conflict_type == 'duplicate id':  | 
|
1155  | 
vals = (conflict[4], conflict[1], conflict[2])  | 
|
1156  | 
yield 'Conflict adding id to %s. %s %s.' % vals  | 
|
1157  | 
elif conflict_type == 'duplicate':  | 
|
1158  | 
vals = (conflict[4], conflict[1], conflict[2])  | 
|
1159  | 
yield 'Conflict adding file %s. %s %s.' % vals  | 
|
1160  | 
elif conflict_type == 'parent loop':  | 
|
1161  | 
vals = (conflict[4], conflict[2], conflict[1])  | 
|
1162  | 
yield 'Conflict moving %s into %s. %s.' % vals  | 
|
1163  | 
elif conflict_type == 'unversioned parent':  | 
|
1164  | 
vals = (conflict[2], conflict[1])  | 
|
1165  | 
yield 'Conflict adding versioned files to %s. %s.' % vals  | 
|
1166  | 
elif conflict_type == 'missing parent':  | 
|
1167  | 
vals = (conflict[2], conflict[1])  | 
|
1168  | 
yield 'Conflict adding files to %s. %s.' % vals  |