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
 | 
| 
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  | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
21  | 
from bzrlib import bzrdir, errors  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
22  | 
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,  | 
| 
1534.7.162
by Aaron Bentley
 Handle failures creating/deleting the Limbo directory  | 
23  | 
ReusingTransform, NotVersionedError, CantMoveRoot,  | 
| 
1731.1.33
by Aaron Bentley
 Revert no-special-root changes  | 
24  | 
ExistingLimbo, ImmortalLimbo, NoFinalPath)  | 
| 
1534.7.106
by Aaron Bentley
 Cleaned up imports, added copyright statements  | 
25  | 
from bzrlib.inventory import InventoryEntry  | 
| 
1558.12.9
by Aaron Bentley
 Handle resolving conflicts with directories properly  | 
26  | 
from bzrlib.osutils import (file_kind, supports_executable, pathjoin, lexists,  | 
| 
1685.1.45
by John Arbash Meinel
 Moved url functions into bzrlib.urlutils  | 
27  | 
delete_any)  | 
| 
1551.2.34
by Aaron Bentley
 Refactored the revert phases  | 
28  | 
from bzrlib.progress import DummyProgress, ProgressPhase  | 
| 
1534.7.173
by Aaron Bentley
 Added conflict warnings to revert  | 
29  | 
from bzrlib.trace import mutter, warning  | 
| 
1551.7.14
by Aaron Bentley
 Use specified_file_ids instead of is_inside_any in compare_trees  | 
30  | 
from bzrlib import tree  | 
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
31  | 
import bzrlib.ui  | 
| 
1685.1.45
by John Arbash Meinel
 Moved url functions into bzrlib.urlutils  | 
32  | 
import bzrlib.urlutils as urlutils  | 
| 
1534.7.31
by Aaron Bentley
 Changed tree root parent to ROOT_PARENT  | 
33  | 
|
| 
1534.7.167
by Aaron Bentley
 PEP8 and comment cleanups  | 
34  | 
|
| 
1534.7.31
by Aaron Bentley
 Changed tree root parent to ROOT_PARENT  | 
35  | 
ROOT_PARENT = "root-parent"  | 
36  | 
||
| 
1534.7.167
by Aaron Bentley
 PEP8 and comment cleanups  | 
37  | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
38  | 
def unique_add(map, key, value):  | 
39  | 
if key in map:  | 
|
| 
1534.7.5
by Aaron Bentley
 Got unique_add under test  | 
40  | 
raise DuplicateKey(key=key)  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
41  | 
map[key] = value  | 
42  | 
||
| 
1534.7.167
by Aaron Bentley
 PEP8 and comment cleanups  | 
43  | 
|
| 
1534.7.191
by Aaron Bentley
 Got transform.apply to list modified paths  | 
44  | 
class _TransformResults(object):  | 
45  | 
def __init__(self, modified_paths):  | 
|
46  | 
object.__init__(self)  | 
|
47  | 
self.modified_paths = modified_paths  | 
|
48  | 
||
49  | 
||
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
50  | 
class TreeTransform(object):  | 
| 
1534.7.179
by Aaron Bentley
 Added Transform docs  | 
51  | 
"""Represent a tree transformation.  | 
52  | 
    
 | 
|
53  | 
    This object is designed to support incremental generation of the transform,
 | 
|
54  | 
    in any order.  
 | 
|
55  | 
    
 | 
|
56  | 
    It is easy to produce malformed transforms, but they are generally
 | 
|
57  | 
    harmless.  Attempting to apply a malformed transform will cause an
 | 
|
58  | 
    exception to be raised before any modifications are made to the tree.  
 | 
|
59  | 
||
60  | 
    Many kinds of malformed transforms can be corrected with the 
 | 
|
61  | 
    resolve_conflicts function.  The remaining ones indicate programming error,
 | 
|
62  | 
    such as trying to create a file with no path.
 | 
|
63  | 
||
64  | 
    Two sets of file creation methods are supplied.  Convenience methods are:
 | 
|
65  | 
     * new_file
 | 
|
66  | 
     * new_directory
 | 
|
67  | 
     * new_symlink
 | 
|
68  | 
||
69  | 
    These are composed of the low-level methods:
 | 
|
70  | 
     * create_path
 | 
|
71  | 
     * create_file or create_directory or create_symlink
 | 
|
72  | 
     * version_file
 | 
|
73  | 
     * set_executability
 | 
|
74  | 
    """
 | 
|
| 
1534.9.1
by Aaron Bentley
 Added progress bars to merge  | 
75  | 
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  | 
76  | 
"""Note: a tree_write lock is taken on the tree.  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
77  | 
        
 | 
78  | 
        Use TreeTransform.finalize() to release the lock
 | 
|
79  | 
        """
 | 
|
80  | 
object.__init__(self)  | 
|
81  | 
self._tree = tree  | 
|
| 
1997.1.3
by Robert Collins
 All WorkingTree methods which write to the tree, but not to the branch  | 
82  | 
self._tree.lock_tree_write()  | 
| 
1534.7.162
by Aaron Bentley
 Handle failures creating/deleting the Limbo directory  | 
83  | 
try:  | 
84  | 
control_files = self._tree._control_files  | 
|
| 
1685.1.45
by John Arbash Meinel
 Moved url functions into bzrlib.urlutils  | 
85  | 
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  | 
86  | 
control_files.controlfilename('limbo'))  | 
| 
1534.7.162
by Aaron Bentley
 Handle failures creating/deleting the Limbo directory  | 
87  | 
try:  | 
88  | 
os.mkdir(self._limbodir)  | 
|
89  | 
except OSError, e:  | 
|
90  | 
if e.errno == errno.EEXIST:  | 
|
91  | 
raise ExistingLimbo(self._limbodir)  | 
|
92  | 
except:  | 
|
93  | 
self._tree.unlock()  | 
|
94  | 
            raise
 | 
|
95  | 
||
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
96  | 
self._id_number = 0  | 
97  | 
self._new_name = {}  | 
|
98  | 
self._new_parent = {}  | 
|
| 
1534.7.4
by Aaron Bentley
 Unified all file types as 'contents'  | 
99  | 
self._new_contents = {}  | 
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
100  | 
self._removed_contents = set()  | 
| 
1534.7.25
by Aaron Bentley
 Added set_executability  | 
101  | 
self._new_executability = {}  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
102  | 
self._new_id = {}  | 
| 
1534.7.143
by Aaron Bentley
 Prevented get_trans_id from automatically versioning file ids  | 
103  | 
self._non_present_ids = {}  | 
| 
1534.7.75
by Aaron Bentley
 Added reverse-lookup for versioned files and get_trans_id  | 
104  | 
self._r_new_id = {}  | 
| 
1534.7.39
by Aaron Bentley
 Ensured that files can be unversioned (de-versioned?)  | 
105  | 
self._removed_id = set()  | 
| 
1534.7.7
by Aaron Bentley
 Added support for all-file path ids  | 
106  | 
self._tree_path_ids = {}  | 
| 
1534.7.8
by Aaron Bentley
 Added TreeTransform.final_kind  | 
107  | 
self._tree_id_paths = {}  | 
| 
1534.10.31
by Aaron Bentley
 Add caching to speed canonical_path  | 
108  | 
self._realpaths = {}  | 
109  | 
        # Cache of realpath results, to speed up canonical_path
 | 
|
110  | 
self._relpaths = {}  | 
|
111  | 
        # Cache of relpath results, to speed up canonical_path
 | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
112  | 
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  | 
113  | 
self.__done = False  | 
| 
1534.9.1
by Aaron Bentley
 Added progress bars to merge  | 
114  | 
self._pb = pb  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
115  | 
|
| 
1534.7.132
by Aaron Bentley
 Got cooked conflicts working  | 
116  | 
def __get_root(self):  | 
117  | 
return self._new_root  | 
|
118  | 
||
119  | 
root = property(__get_root)  | 
|
120  | 
||
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
121  | 
def finalize(self):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
122  | 
"""Release the working tree lock, if held, clean up limbo dir."""  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
123  | 
if self._tree is None:  | 
124  | 
            return
 | 
|
| 
1534.7.162
by Aaron Bentley
 Handle failures creating/deleting the Limbo directory  | 
125  | 
try:  | 
126  | 
for trans_id, kind in self._new_contents.iteritems():  | 
|
127  | 
path = self._limbo_name(trans_id)  | 
|
128  | 
if kind == "directory":  | 
|
129  | 
os.rmdir(path)  | 
|
130  | 
else:  | 
|
131  | 
os.unlink(path)  | 
|
132  | 
try:  | 
|
133  | 
os.rmdir(self._limbodir)  | 
|
134  | 
except OSError:  | 
|
135  | 
                # We don't especially care *why* the dir is immortal.
 | 
|
136  | 
raise ImmortalLimbo(self._limbodir)  | 
|
137  | 
finally:  | 
|
138  | 
self._tree.unlock()  | 
|
139  | 
self._tree = None  | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
140  | 
|
141  | 
def _assign_id(self):  | 
|
142  | 
"""Produce a new tranform id"""  | 
|
143  | 
new_id = "new-%s" % self._id_number  | 
|
144  | 
self._id_number +=1  | 
|
145  | 
return new_id  | 
|
146  | 
||
147  | 
def create_path(self, name, parent):  | 
|
148  | 
"""Assign a transaction id to a new path"""  | 
|
149  | 
trans_id = self._assign_id()  | 
|
150  | 
unique_add(self._new_name, trans_id, name)  | 
|
151  | 
unique_add(self._new_parent, trans_id, parent)  | 
|
152  | 
return trans_id  | 
|
153  | 
||
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
154  | 
def adjust_path(self, name, parent, trans_id):  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
155  | 
"""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  | 
156  | 
if trans_id == self._new_root:  | 
157  | 
raise CantMoveRoot  | 
|
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
158  | 
self._new_name[trans_id] = name  | 
159  | 
self._new_parent[trans_id] = parent  | 
|
160  | 
||
| 
1534.7.68
by Aaron Bentley
 Got semi-reasonable root directory renaming working  | 
161  | 
def adjust_root_path(self, name, parent):  | 
162  | 
"""Emulate moving the root by moving all children, instead.  | 
|
163  | 
        
 | 
|
164  | 
        We do this by undoing the association of root's transaction id with the
 | 
|
165  | 
        current tree.  This allows us to create a new directory with that
 | 
|
| 
1534.7.69
by Aaron Bentley
 Got real root moves working  | 
166  | 
        transaction id.  We unversion the root directory and version the 
 | 
167  | 
        physically new directory, and hope someone versions the tree root
 | 
|
168  | 
        later.
 | 
|
| 
1534.7.68
by Aaron Bentley
 Got semi-reasonable root directory renaming working  | 
169  | 
        """
 | 
170  | 
old_root = self._new_root  | 
|
171  | 
old_root_file_id = self.final_file_id(old_root)  | 
|
172  | 
        # force moving all children of root
 | 
|
173  | 
for child_id in self.iter_tree_children(old_root):  | 
|
174  | 
if child_id != parent:  | 
|
175  | 
self.adjust_path(self.final_name(child_id),  | 
|
176  | 
self.final_parent(child_id), child_id)  | 
|
| 
1534.7.69
by Aaron Bentley
 Got real root moves working  | 
177  | 
file_id = self.final_file_id(child_id)  | 
178  | 
if file_id is not None:  | 
|
179  | 
self.unversion_file(child_id)  | 
|
180  | 
self.version_file(file_id, child_id)  | 
|
| 
1534.7.68
by Aaron Bentley
 Got semi-reasonable root directory renaming working  | 
181  | 
|
182  | 
        # the physical root needs a new transaction id
 | 
|
183  | 
self._tree_path_ids.pop("")  | 
|
184  | 
self._tree_id_paths.pop(old_root)  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
185  | 
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  | 
186  | 
if parent == old_root:  | 
187  | 
parent = self._new_root  | 
|
188  | 
self.adjust_path(name, parent, old_root)  | 
|
189  | 
self.create_directory(old_root)  | 
|
| 
1534.7.69
by Aaron Bentley
 Got real root moves working  | 
190  | 
self.version_file(old_root_file_id, old_root)  | 
191  | 
self.unversion_file(self._new_root)  | 
|
| 
1534.7.68
by Aaron Bentley
 Got semi-reasonable root directory renaming working  | 
192  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
193  | 
def trans_id_tree_file_id(self, inventory_id):  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
194  | 
"""Determine the transaction id of a working tree file.  | 
195  | 
        
 | 
|
196  | 
        This reflects only files that already exist, not ones that will be
 | 
|
197  | 
        added by transactions.
 | 
|
198  | 
        """
 | 
|
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
199  | 
path = self._tree.inventory.id2path(inventory_id)  | 
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
200  | 
return self.trans_id_tree_path(path)  | 
| 
1534.7.7
by Aaron Bentley
 Added support for all-file path ids  | 
201  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
202  | 
def trans_id_file_id(self, file_id):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
203  | 
"""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  | 
204  | 
        A new id is only created for file_ids that were never present.  If
 | 
205  | 
        a transaction has been unversioned, it is deliberately still returned.
 | 
|
206  | 
        (this will likely lead to an unversioned parent conflict.)
 | 
|
207  | 
        """
 | 
|
208  | 
if file_id in self._r_new_id and self._r_new_id[file_id] is not None:  | 
|
209  | 
return self._r_new_id[file_id]  | 
|
210  | 
elif file_id in self._tree.inventory:  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
211  | 
return self.trans_id_tree_file_id(file_id)  | 
| 
1534.7.143
by Aaron Bentley
 Prevented get_trans_id from automatically versioning file ids  | 
212  | 
elif file_id in self._non_present_ids:  | 
213  | 
return self._non_present_ids[file_id]  | 
|
| 
1534.7.75
by Aaron Bentley
 Added reverse-lookup for versioned files and get_trans_id  | 
214  | 
else:  | 
215  | 
trans_id = self._assign_id()  | 
|
| 
1534.7.143
by Aaron Bentley
 Prevented get_trans_id from automatically versioning file ids  | 
216  | 
self._non_present_ids[file_id] = trans_id  | 
| 
1534.7.75
by Aaron Bentley
 Added reverse-lookup for versioned files and get_trans_id  | 
217  | 
return trans_id  | 
218  | 
||
| 
1534.7.12
by Aaron Bentley
 Added canonical_path function  | 
219  | 
def canonical_path(self, path):  | 
220  | 
"""Get the canonical tree-relative path"""  | 
|
221  | 
        # don't follow final symlinks
 | 
|
| 
1534.10.31
by Aaron Bentley
 Add caching to speed canonical_path  | 
222  | 
abs = self._tree.abspath(path)  | 
223  | 
if abs in self._relpaths:  | 
|
224  | 
return self._relpaths[abs]  | 
|
225  | 
dirname, basename = os.path.split(abs)  | 
|
226  | 
if dirname not in self._realpaths:  | 
|
227  | 
self._realpaths[dirname] = os.path.realpath(dirname)  | 
|
228  | 
dirname = self._realpaths[dirname]  | 
|
229  | 
abs = pathjoin(dirname, basename)  | 
|
230  | 
if dirname in self._relpaths:  | 
|
231  | 
relpath = pathjoin(self._relpaths[dirname], basename)  | 
|
| 
1534.10.32
by Aaron Bentley
 Test and fix case where name has trailing slash  | 
232  | 
relpath = relpath.rstrip('/\\')  | 
| 
1534.10.31
by Aaron Bentley
 Add caching to speed canonical_path  | 
233  | 
else:  | 
234  | 
relpath = self._tree.relpath(abs)  | 
|
235  | 
self._relpaths[abs] = relpath  | 
|
236  | 
return relpath  | 
|
| 
1534.7.12
by Aaron Bentley
 Added canonical_path function  | 
237  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
238  | 
def trans_id_tree_path(self, path):  | 
| 
1534.7.7
by Aaron Bentley
 Added support for all-file path ids  | 
239  | 
"""Determine (and maybe set) the transaction ID for a tree path."""  | 
| 
1534.7.12
by Aaron Bentley
 Added canonical_path function  | 
240  | 
path = self.canonical_path(path)  | 
| 
1534.7.7
by Aaron Bentley
 Added support for all-file path ids  | 
241  | 
if path not in self._tree_path_ids:  | 
242  | 
self._tree_path_ids[path] = self._assign_id()  | 
|
| 
1534.7.8
by Aaron Bentley
 Added TreeTransform.final_kind  | 
243  | 
self._tree_id_paths[self._tree_path_ids[path]] = path  | 
| 
1534.7.7
by Aaron Bentley
 Added support for all-file path ids  | 
244  | 
return self._tree_path_ids[path]  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
245  | 
|
| 
1534.7.16
by Aaron Bentley
 Added get_tree_parent  | 
246  | 
def get_tree_parent(self, trans_id):  | 
| 
1534.7.31
by Aaron Bentley
 Changed tree root parent to ROOT_PARENT  | 
247  | 
"""Determine id of the parent in the tree."""  | 
| 
1534.7.16
by Aaron Bentley
 Added get_tree_parent  | 
248  | 
path = self._tree_id_paths[trans_id]  | 
249  | 
if path == "":  | 
|
| 
1534.7.31
by Aaron Bentley
 Changed tree root parent to ROOT_PARENT  | 
250  | 
return ROOT_PARENT  | 
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
251  | 
return self.trans_id_tree_path(os.path.dirname(path))  | 
| 
1534.7.16
by Aaron Bentley
 Added get_tree_parent  | 
252  | 
|
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
253  | 
def create_file(self, contents, trans_id, mode_id=None):  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
254  | 
"""Schedule creation of a new file.  | 
255  | 
||
256  | 
        See also new_file.
 | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
257  | 
        
 | 
258  | 
        Contents is an iterator of strings, all of which will be written
 | 
|
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
259  | 
        to the target destination.
 | 
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
260  | 
|
261  | 
        New file takes the permissions of any existing file with that id,
 | 
|
262  | 
        unless mode_id is specified.
 | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
263  | 
        """
 | 
| 
1711.7.22
by John Arbash Meinel
 transform: cleanup the temporary file even if unique_add fails.  | 
264  | 
name = self._limbo_name(trans_id)  | 
265  | 
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  | 
266  | 
try:  | 
| 
1711.7.22
by John Arbash Meinel
 transform: cleanup the temporary file even if unique_add fails.  | 
267  | 
try:  | 
268  | 
unique_add(self._new_contents, trans_id, 'file')  | 
|
269  | 
except:  | 
|
270  | 
                # Clean up the file, it never got registered so
 | 
|
271  | 
                # TreeTransform.finalize() won't clean it up.
 | 
|
272  | 
f.close()  | 
|
273  | 
os.unlink(name)  | 
|
274  | 
                raise
 | 
|
275  | 
||
| 
1711.7.8
by John Arbash Meinel
 Use try/finally inside create_file for TreeTransform to ensure the file handle gets closed  | 
276  | 
for segment in contents:  | 
277  | 
f.write(segment)  | 
|
278  | 
finally:  | 
|
279  | 
f.close()  | 
|
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
280  | 
self._set_mode(trans_id, mode_id, S_ISREG)  | 
281  | 
||
282  | 
def _set_mode(self, trans_id, mode_id, typefunc):  | 
|
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
283  | 
"""Set the mode of new file contents.  | 
284  | 
        The mode_id is the existing file to get the mode from (often the same
 | 
|
285  | 
        as trans_id).  The operation is only performed if there's a mode match
 | 
|
286  | 
        according to typefunc.
 | 
|
287  | 
        """
 | 
|
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
288  | 
if mode_id is None:  | 
289  | 
mode_id = trans_id  | 
|
290  | 
try:  | 
|
291  | 
old_path = self._tree_id_paths[mode_id]  | 
|
292  | 
except KeyError:  | 
|
293  | 
            return
 | 
|
294  | 
try:  | 
|
| 
2027.1.1
by John Arbash Meinel
 Fix bug #56549, and write a direct test that the right path is being statted  | 
295  | 
mode = os.stat(self._tree.abspath(old_path)).st_mode  | 
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
296  | 
except OSError, e:  | 
297  | 
if e.errno == errno.ENOENT:  | 
|
298  | 
                return
 | 
|
299  | 
else:  | 
|
300  | 
                raise
 | 
|
301  | 
if typefunc(mode):  | 
|
302  | 
os.chmod(self._limbo_name(trans_id), mode)  | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
303  | 
|
| 
1534.7.20
by Aaron Bentley
 Added directory handling  | 
304  | 
def create_directory(self, trans_id):  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
305  | 
"""Schedule creation of a new directory.  | 
306  | 
        
 | 
|
307  | 
        See also new_directory.
 | 
|
308  | 
        """
 | 
|
| 
1534.7.73
by Aaron Bentley
 Changed model again. Now iterator is used immediately.  | 
309  | 
os.mkdir(self._limbo_name(trans_id))  | 
310  | 
unique_add(self._new_contents, trans_id, 'directory')  | 
|
| 
1534.7.20
by Aaron Bentley
 Added directory handling  | 
311  | 
|
| 
1534.7.22
by Aaron Bentley
 Added symlink support  | 
312  | 
def create_symlink(self, target, trans_id):  | 
313  | 
"""Schedule creation of a new symbolic link.  | 
|
314  | 
||
315  | 
        target is a bytestring.
 | 
|
316  | 
        See also new_symlink.
 | 
|
317  | 
        """
 | 
|
| 
1534.7.73
by Aaron Bentley
 Changed model again. Now iterator is used immediately.  | 
318  | 
os.symlink(target, self._limbo_name(trans_id))  | 
319  | 
unique_add(self._new_contents, trans_id, 'symlink')  | 
|
| 
1534.7.22
by Aaron Bentley
 Added symlink support  | 
320  | 
|
| 
1534.7.129
by Aaron Bentley
 Converted test cases to Tree Transform  | 
321  | 
def cancel_creation(self, trans_id):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
322  | 
"""Cancel the creation of new file contents."""  | 
| 
1534.7.129
by Aaron Bentley
 Converted test cases to Tree Transform  | 
323  | 
del self._new_contents[trans_id]  | 
| 
1558.12.9
by Aaron Bentley
 Handle resolving conflicts with directories properly  | 
324  | 
delete_any(self._limbo_name(trans_id))  | 
| 
1534.7.129
by Aaron Bentley
 Converted test cases to Tree Transform  | 
325  | 
|
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
326  | 
def delete_contents(self, trans_id):  | 
327  | 
"""Schedule the contents of a path entry for deletion"""  | 
|
| 
1534.7.130
by Aaron Bentley
 More conflict handling, test porting  | 
328  | 
self.tree_kind(trans_id)  | 
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
329  | 
self._removed_contents.add(trans_id)  | 
330  | 
||
| 
1534.7.61
by Aaron Bentley
 Handled parent loops, missing parents, unversioned parents  | 
331  | 
def cancel_deletion(self, trans_id):  | 
332  | 
"""Cancel a scheduled deletion"""  | 
|
333  | 
self._removed_contents.remove(trans_id)  | 
|
334  | 
||
| 
1534.7.39
by Aaron Bentley
 Ensured that files can be unversioned (de-versioned?)  | 
335  | 
def unversion_file(self, trans_id):  | 
336  | 
"""Schedule a path entry to become unversioned"""  | 
|
337  | 
self._removed_id.add(trans_id)  | 
|
338  | 
||
339  | 
def delete_versioned(self, trans_id):  | 
|
340  | 
"""Delete and unversion a versioned file"""  | 
|
341  | 
self.delete_contents(trans_id)  | 
|
342  | 
self.unversion_file(trans_id)  | 
|
343  | 
||
| 
1534.7.25
by Aaron Bentley
 Added set_executability  | 
344  | 
def set_executability(self, executability, trans_id):  | 
| 
1534.7.167
by Aaron Bentley
 PEP8 and comment cleanups  | 
345  | 
"""Schedule setting of the 'execute' bit  | 
346  | 
        To unschedule, set to None
 | 
|
347  | 
        """
 | 
|
| 
1534.7.26
by Aaron Bentley
 Added conflicts for setting executability on unversioned/non-file entries  | 
348  | 
if executability is None:  | 
349  | 
del self._new_executability[trans_id]  | 
|
350  | 
else:  | 
|
351  | 
unique_add(self._new_executability, trans_id, executability)  | 
|
| 
1534.7.25
by Aaron Bentley
 Added set_executability  | 
352  | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
353  | 
def version_file(self, file_id, trans_id):  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
354  | 
"""Schedule a file to become versioned."""  | 
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
355  | 
assert file_id is not None  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
356  | 
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  | 
357  | 
unique_add(self._r_new_id, file_id, trans_id)  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
358  | 
|
| 
1534.7.105
by Aaron Bentley
 Got merge with rename working  | 
359  | 
def cancel_versioning(self, trans_id):  | 
360  | 
"""Undo a previous versioning of a file"""  | 
|
361  | 
file_id = self._new_id[trans_id]  | 
|
362  | 
del self._new_id[trans_id]  | 
|
363  | 
del self._r_new_id[file_id]  | 
|
364  | 
||
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
365  | 
def new_paths(self):  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
366  | 
"""Determine the paths of all new and changed files"""  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
367  | 
new_ids = set()  | 
| 
1534.7.132
by Aaron Bentley
 Got cooked conflicts working  | 
368  | 
fp = FinalPaths(self)  | 
| 
1534.7.4
by Aaron Bentley
 Unified all file types as 'contents'  | 
369  | 
for id_set in (self._new_name, self._new_parent, self._new_contents,  | 
| 
1534.7.25
by Aaron Bentley
 Added set_executability  | 
370  | 
self._new_id, self._new_executability):  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
371  | 
new_ids.update(id_set)  | 
372  | 
new_paths = [(fp.get_path(t), t) for t in new_ids]  | 
|
373  | 
new_paths.sort()  | 
|
374  | 
return new_paths  | 
|
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
375  | 
|
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
376  | 
def tree_kind(self, trans_id):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
377  | 
"""Determine the file kind in the working tree.  | 
378  | 
||
379  | 
        Raises NoSuchFile if the file does not exist
 | 
|
380  | 
        """
 | 
|
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
381  | 
path = self._tree_id_paths.get(trans_id)  | 
382  | 
if path is None:  | 
|
383  | 
raise NoSuchFile(None)  | 
|
384  | 
try:  | 
|
385  | 
return file_kind(self._tree.abspath(path))  | 
|
386  | 
except OSError, e:  | 
|
387  | 
if e.errno != errno.ENOENT:  | 
|
388  | 
                raise
 | 
|
389  | 
else:  | 
|
390  | 
raise NoSuchFile(path)  | 
|
391  | 
||
| 
1534.7.8
by Aaron Bentley
 Added TreeTransform.final_kind  | 
392  | 
def final_kind(self, trans_id):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
393  | 
"""Determine the final file kind, after any changes applied.  | 
| 
1534.7.8
by Aaron Bentley
 Added TreeTransform.final_kind  | 
394  | 
        
 | 
395  | 
        Raises NoSuchFile if the file does not exist/has no contents.
 | 
|
396  | 
        (It is conceivable that a path would be created without the
 | 
|
397  | 
        corresponding contents insertion command)
 | 
|
398  | 
        """
 | 
|
399  | 
if trans_id in self._new_contents:  | 
|
| 
1534.7.73
by Aaron Bentley
 Changed model again. Now iterator is used immediately.  | 
400  | 
return self._new_contents[trans_id]  | 
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
401  | 
elif trans_id in self._removed_contents:  | 
402  | 
raise NoSuchFile(None)  | 
|
| 
1534.7.8
by Aaron Bentley
 Added TreeTransform.final_kind  | 
403  | 
else:  | 
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
404  | 
return self.tree_kind(trans_id)  | 
| 
1534.7.8
by Aaron Bentley
 Added TreeTransform.final_kind  | 
405  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
406  | 
def tree_file_id(self, trans_id):  | 
| 
1534.7.41
by Aaron Bentley
 Got inventory ID movement working  | 
407  | 
"""Determine the file id associated with the trans_id in the tree"""  | 
408  | 
try:  | 
|
409  | 
path = self._tree_id_paths[trans_id]  | 
|
410  | 
except KeyError:  | 
|
411  | 
            # the file is a new, unversioned file, or invalid trans_id
 | 
|
412  | 
return None  | 
|
413  | 
        # the file is old; the old id is still valid
 | 
|
| 
1534.7.68
by Aaron Bentley
 Got semi-reasonable root directory renaming working  | 
414  | 
if self._new_root == trans_id:  | 
415  | 
return self._tree.inventory.root.file_id  | 
|
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
416  | 
return self._tree.inventory.path2id(path)  | 
| 
1534.7.41
by Aaron Bentley
 Got inventory ID movement working  | 
417  | 
|
| 
1534.7.13
by Aaron Bentley
 Implemented final_file_id  | 
418  | 
def final_file_id(self, trans_id):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
419  | 
"""Determine the file id after any changes are applied, or None.  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
420  | 
        
 | 
421  | 
        None indicates that the file will not be versioned after changes are
 | 
|
422  | 
        applied.
 | 
|
423  | 
        """
 | 
|
| 
1534.7.13
by Aaron Bentley
 Implemented final_file_id  | 
424  | 
try:  | 
425  | 
            # there is a new id for this file
 | 
|
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
426  | 
assert self._new_id[trans_id] is not None  | 
| 
1534.7.13
by Aaron Bentley
 Implemented final_file_id  | 
427  | 
return self._new_id[trans_id]  | 
428  | 
except KeyError:  | 
|
| 
1534.7.39
by Aaron Bentley
 Ensured that files can be unversioned (de-versioned?)  | 
429  | 
if trans_id in self._removed_id:  | 
430  | 
return None  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
431  | 
return self.tree_file_id(trans_id)  | 
| 
1534.7.13
by Aaron Bentley
 Implemented final_file_id  | 
432  | 
|
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
433  | 
def inactive_file_id(self, trans_id):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
434  | 
"""Return the inactive file_id associated with a transaction id.  | 
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
435  | 
        That is, the one in the tree or in non_present_ids.
 | 
436  | 
        The file_id may actually be active, too.
 | 
|
437  | 
        """
 | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
438  | 
file_id = self.tree_file_id(trans_id)  | 
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
439  | 
if file_id is not None:  | 
440  | 
return file_id  | 
|
441  | 
for key, value in self._non_present_ids.iteritems():  | 
|
442  | 
if value == trans_id:  | 
|
443  | 
return key  | 
|
444  | 
||
| 
1534.7.17
by Aaron Bentley
 Added final_parent function  | 
445  | 
def final_parent(self, trans_id):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
446  | 
"""Determine the parent file_id, after any changes are applied.  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
447  | 
|
| 
1534.7.31
by Aaron Bentley
 Changed tree root parent to ROOT_PARENT  | 
448  | 
        ROOT_PARENT is returned for the tree root.
 | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
449  | 
        """
 | 
| 
1534.7.17
by Aaron Bentley
 Added final_parent function  | 
450  | 
try:  | 
451  | 
return self._new_parent[trans_id]  | 
|
452  | 
except KeyError:  | 
|
453  | 
return self.get_tree_parent(trans_id)  | 
|
454  | 
||
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
455  | 
def final_name(self, trans_id):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
456  | 
"""Determine the final filename, after all changes are applied."""  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
457  | 
try:  | 
458  | 
return self._new_name[trans_id]  | 
|
459  | 
except KeyError:  | 
|
| 
1731.1.33
by Aaron Bentley
 Revert no-special-root changes  | 
460  | 
try:  | 
461  | 
return os.path.basename(self._tree_id_paths[trans_id])  | 
|
462  | 
except KeyError:  | 
|
463  | 
raise NoFinalPath(trans_id, self)  | 
|
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
464  | 
|
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
465  | 
def by_parent(self):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
466  | 
"""Return a map of parent: children for known parents.  | 
467  | 
        
 | 
|
468  | 
        Only new paths and parents of tree files with assigned ids are used.
 | 
|
469  | 
        """
 | 
|
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
470  | 
by_parent = {}  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
471  | 
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.  | 
472  | 
items.extend((t, self.final_parent(t)) for t in  | 
473  | 
self._tree_id_paths.keys())  | 
|
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
474  | 
for trans_id, parent_id in items:  | 
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
475  | 
if parent_id not in by_parent:  | 
476  | 
by_parent[parent_id] = set()  | 
|
477  | 
by_parent[parent_id].add(trans_id)  | 
|
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
478  | 
return by_parent  | 
| 
1534.7.11
by Aaron Bentley
 Refactored conflict handling  | 
479  | 
|
| 
1534.7.57
by Aaron Bentley
 Enhanced conflict resolution.  | 
480  | 
def path_changed(self, trans_id):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
481  | 
"""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)  | 
482  | 
return (trans_id in self._new_name) or (trans_id in self._new_parent)  | 
| 
1534.7.57
by Aaron Bentley
 Enhanced conflict resolution.  | 
483  | 
|
| 
1966.1.2
by Aaron Bentley
 Divert files instead of failing to create them, update from review  | 
484  | 
def new_contents(self, trans_id):  | 
485  | 
return (trans_id in self._new_contents)  | 
|
486  | 
||
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
487  | 
def find_conflicts(self):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
488  | 
"""Find any violations of inventory or filesystem invariants"""  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
489  | 
if self.__done is True:  | 
490  | 
raise ReusingTransform()  | 
|
491  | 
conflicts = []  | 
|
492  | 
        # ensure all children of all existent parents are known
 | 
|
493  | 
        # all children of non-existent parents are known, by definition.
 | 
|
494  | 
self._add_tree_children()  | 
|
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
495  | 
by_parent = self.by_parent()  | 
| 
1534.7.15
by Aaron Bentley
 Add conflict types related to versioning  | 
496  | 
conflicts.extend(self._unversioned_parents(by_parent))  | 
| 
1534.7.19
by Aaron Bentley
 Added tests for parent loops  | 
497  | 
conflicts.extend(self._parent_loops())  | 
| 
1534.7.11
by Aaron Bentley
 Refactored conflict handling  | 
498  | 
conflicts.extend(self._duplicate_entries(by_parent))  | 
| 
1534.7.50
by Aaron Bentley
 Detect duplicate inventory ids  | 
499  | 
conflicts.extend(self._duplicate_ids())  | 
| 
1534.7.11
by Aaron Bentley
 Refactored conflict handling  | 
500  | 
conflicts.extend(self._parent_type_conflicts(by_parent))  | 
| 
1534.7.15
by Aaron Bentley
 Add conflict types related to versioning  | 
501  | 
conflicts.extend(self._improper_versioning())  | 
| 
1534.7.26
by Aaron Bentley
 Added conflicts for setting executability on unversioned/non-file entries  | 
502  | 
conflicts.extend(self._executability_conflicts())  | 
| 
1534.7.152
by Aaron Bentley
 Fixed overwrites  | 
503  | 
conflicts.extend(self._overwrite_conflicts())  | 
| 
1534.7.15
by Aaron Bentley
 Add conflict types related to versioning  | 
504  | 
return conflicts  | 
505  | 
||
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
506  | 
def _add_tree_children(self):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
507  | 
"""Add all the children of all active parents to the known paths.  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
508  | 
|
509  | 
        Active parents are those which gain children, and those which are
 | 
|
510  | 
        removed.  This is a necessary first step in detecting conflicts.
 | 
|
511  | 
        """
 | 
|
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
512  | 
parents = self.by_parent().keys()  | 
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
513  | 
parents.extend([t for t in self._removed_contents if  | 
514  | 
self.tree_kind(t) == 'directory'])  | 
|
| 
1534.7.50
by Aaron Bentley
 Detect duplicate inventory ids  | 
515  | 
for trans_id in self._removed_id:  | 
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
516  | 
file_id = self.tree_file_id(trans_id)  | 
| 
1731.1.2
by Aaron Bentley
 Removed all remaining uses of root_directory  | 
517  | 
if self._tree.inventory[file_id].kind == 'directory':  | 
| 
1534.7.50
by Aaron Bentley
 Detect duplicate inventory ids  | 
518  | 
parents.append(trans_id)  | 
519  | 
||
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
520  | 
for parent_id in parents:  | 
| 
1534.7.67
by Aaron Bentley
 Refactored _add_tree_children  | 
521  | 
            # ensure that all children are registered with the transaction
 | 
522  | 
list(self.iter_tree_children(parent_id))  | 
|
523  | 
||
524  | 
def iter_tree_children(self, parent_id):  | 
|
525  | 
"""Iterate through the entry's tree children, if any"""  | 
|
526  | 
try:  | 
|
527  | 
path = self._tree_id_paths[parent_id]  | 
|
528  | 
except KeyError:  | 
|
529  | 
            return
 | 
|
530  | 
try:  | 
|
531  | 
children = os.listdir(self._tree.abspath(path))  | 
|
532  | 
except OSError, e:  | 
|
| 
1534.7.71
by abentley
 All tests pass under Windows  | 
533  | 
if e.errno != errno.ENOENT and e.errno != errno.ESRCH:  | 
| 
1534.7.67
by Aaron Bentley
 Refactored _add_tree_children  | 
534  | 
                raise
 | 
535  | 
            return
 | 
|
536  | 
||
537  | 
for child in children:  | 
|
538  | 
childpath = joinpath(path, child)  | 
|
| 
1534.7.180
by Aaron Bentley
 Merge from mainline  | 
539  | 
if self._tree.is_control_filename(childpath):  | 
| 
1534.7.67
by Aaron Bentley
 Refactored _add_tree_children  | 
540  | 
                continue
 | 
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
541  | 
yield self.trans_id_tree_path(childpath)  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
542  | 
|
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
543  | 
def has_named_child(self, by_parent, parent_id, name):  | 
544  | 
try:  | 
|
545  | 
children = by_parent[parent_id]  | 
|
546  | 
except KeyError:  | 
|
547  | 
children = []  | 
|
548  | 
for child in children:  | 
|
549  | 
if self.final_name(child) == name:  | 
|
550  | 
return True  | 
|
551  | 
try:  | 
|
552  | 
path = self._tree_id_paths[parent_id]  | 
|
553  | 
except KeyError:  | 
|
554  | 
return False  | 
|
555  | 
childpath = joinpath(path, name)  | 
|
556  | 
child_id = self._tree_path_ids.get(childpath)  | 
|
557  | 
if child_id is None:  | 
|
558  | 
return lexists(self._tree.abspath(childpath))  | 
|
559  | 
else:  | 
|
| 
1773.4.1
by Martin Pool
 Add pyflakes makefile target; fix many warnings  | 
560  | 
if self.final_parent(child_id) != parent_id:  | 
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
561  | 
return False  | 
| 
1773.4.1
by Martin Pool
 Add pyflakes makefile target; fix many warnings  | 
562  | 
if child_id in self._removed_contents:  | 
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
563  | 
                # XXX What about dangling file-ids?
 | 
564  | 
return False  | 
|
565  | 
else:  | 
|
566  | 
return True  | 
|
567  | 
||
| 
1534.7.19
by Aaron Bentley
 Added tests for parent loops  | 
568  | 
def _parent_loops(self):  | 
569  | 
"""No entry should be its own ancestor"""  | 
|
570  | 
conflicts = []  | 
|
571  | 
for trans_id in self._new_parent:  | 
|
572  | 
seen = set()  | 
|
573  | 
parent_id = trans_id  | 
|
| 
1534.7.31
by Aaron Bentley
 Changed tree root parent to ROOT_PARENT  | 
574  | 
while parent_id is not ROOT_PARENT:  | 
| 
1534.7.19
by Aaron Bentley
 Added tests for parent loops  | 
575  | 
seen.add(parent_id)  | 
| 
1731.1.33
by Aaron Bentley
 Revert no-special-root changes  | 
576  | 
try:  | 
577  | 
parent_id = self.final_parent(parent_id)  | 
|
578  | 
except KeyError:  | 
|
579  | 
                    break
 | 
|
| 
1534.7.19
by Aaron Bentley
 Added tests for parent loops  | 
580  | 
if parent_id == trans_id:  | 
581  | 
conflicts.append(('parent loop', trans_id))  | 
|
582  | 
if parent_id in seen:  | 
|
583  | 
                    break
 | 
|
584  | 
return conflicts  | 
|
585  | 
||
| 
1534.7.15
by Aaron Bentley
 Add conflict types related to versioning  | 
586  | 
def _unversioned_parents(self, by_parent):  | 
587  | 
"""If parent directories are versioned, children must be versioned."""  | 
|
588  | 
conflicts = []  | 
|
589  | 
for parent_id, children in by_parent.iteritems():  | 
|
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
590  | 
if parent_id is ROOT_PARENT:  | 
591  | 
                continue
 | 
|
| 
1534.7.15
by Aaron Bentley
 Add conflict types related to versioning  | 
592  | 
if self.final_file_id(parent_id) is not None:  | 
593  | 
                continue
 | 
|
594  | 
for child_id in children:  | 
|
595  | 
if self.final_file_id(child_id) is not None:  | 
|
596  | 
conflicts.append(('unversioned parent', parent_id))  | 
|
597  | 
break;  | 
|
598  | 
return conflicts  | 
|
599  | 
||
600  | 
def _improper_versioning(self):  | 
|
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
601  | 
"""Cannot version a file with no contents, or a bad type.  | 
| 
1534.7.15
by Aaron Bentley
 Add conflict types related to versioning  | 
602  | 
        
 | 
603  | 
        However, existing entries with no contents are okay.
 | 
|
604  | 
        """
 | 
|
605  | 
conflicts = []  | 
|
606  | 
for trans_id in self._new_id.iterkeys():  | 
|
607  | 
try:  | 
|
608  | 
kind = self.final_kind(trans_id)  | 
|
609  | 
except NoSuchFile:  | 
|
610  | 
conflicts.append(('versioning no contents', trans_id))  | 
|
611  | 
                continue
 | 
|
612  | 
if not InventoryEntry.versionable_kind(kind):  | 
|
| 
1534.7.20
by Aaron Bentley
 Added directory handling  | 
613  | 
conflicts.append(('versioning bad kind', trans_id, kind))  | 
| 
1534.7.11
by Aaron Bentley
 Refactored conflict handling  | 
614  | 
return conflicts  | 
615  | 
||
| 
1534.7.26
by Aaron Bentley
 Added conflicts for setting executability on unversioned/non-file entries  | 
616  | 
def _executability_conflicts(self):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
617  | 
"""Check for bad executability changes.  | 
618  | 
        
 | 
|
619  | 
        Only versioned files may have their executability set, because
 | 
|
620  | 
        1. only versioned entries can have executability under windows
 | 
|
621  | 
        2. only files can be executable.  (The execute bit on a directory
 | 
|
622  | 
           does not indicate searchability)
 | 
|
623  | 
        """
 | 
|
| 
1534.7.26
by Aaron Bentley
 Added conflicts for setting executability on unversioned/non-file entries  | 
624  | 
conflicts = []  | 
625  | 
for trans_id in self._new_executability:  | 
|
626  | 
if self.final_file_id(trans_id) is None:  | 
|
627  | 
conflicts.append(('unversioned executability', trans_id))  | 
|
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
628  | 
else:  | 
629  | 
try:  | 
|
630  | 
non_file = self.final_kind(trans_id) != "file"  | 
|
631  | 
except NoSuchFile:  | 
|
632  | 
non_file = True  | 
|
633  | 
if non_file is True:  | 
|
634  | 
conflicts.append(('non-file executability', trans_id))  | 
|
| 
1534.7.26
by Aaron Bentley
 Added conflicts for setting executability on unversioned/non-file entries  | 
635  | 
return conflicts  | 
636  | 
||
| 
1534.7.152
by Aaron Bentley
 Fixed overwrites  | 
637  | 
def _overwrite_conflicts(self):  | 
638  | 
"""Check for overwrites (not permitted on Win32)"""  | 
|
639  | 
conflicts = []  | 
|
640  | 
for trans_id in self._new_contents:  | 
|
641  | 
try:  | 
|
642  | 
self.tree_kind(trans_id)  | 
|
643  | 
except NoSuchFile:  | 
|
644  | 
                continue
 | 
|
645  | 
if trans_id not in self._removed_contents:  | 
|
646  | 
conflicts.append(('overwrite', trans_id,  | 
|
647  | 
self.final_name(trans_id)))  | 
|
648  | 
return conflicts  | 
|
649  | 
||
| 
1534.7.11
by Aaron Bentley
 Refactored conflict handling  | 
650  | 
def _duplicate_entries(self, by_parent):  | 
651  | 
"""No directory may have two entries with the same name."""  | 
|
652  | 
conflicts = []  | 
|
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
653  | 
for children in by_parent.itervalues():  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
654  | 
name_ids = [(self.final_name(t), t) for t in children]  | 
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
655  | 
name_ids.sort()  | 
656  | 
last_name = None  | 
|
657  | 
last_trans_id = None  | 
|
658  | 
for name, trans_id in name_ids:  | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
659  | 
try:  | 
660  | 
kind = self.final_kind(trans_id)  | 
|
661  | 
except NoSuchFile:  | 
|
662  | 
kind = None  | 
|
663  | 
file_id = self.final_file_id(trans_id)  | 
|
664  | 
if kind is None and file_id is None:  | 
|
665  | 
                    continue
 | 
|
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
666  | 
if name == last_name:  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
667  | 
conflicts.append(('duplicate', last_trans_id, trans_id,  | 
668  | 
name))  | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
669  | 
last_name = name  | 
670  | 
last_trans_id = trans_id  | 
|
| 
1534.7.11
by Aaron Bentley
 Refactored conflict handling  | 
671  | 
return conflicts  | 
672  | 
||
| 
1534.7.50
by Aaron Bentley
 Detect duplicate inventory ids  | 
673  | 
def _duplicate_ids(self):  | 
674  | 
"""Each inventory id may only be used once"""  | 
|
675  | 
conflicts = []  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
676  | 
removed_tree_ids = set((self.tree_file_id(trans_id) for trans_id in  | 
| 
1534.7.50
by Aaron Bentley
 Detect duplicate inventory ids  | 
677  | 
self._removed_id))  | 
678  | 
active_tree_ids = set((f for f in self._tree.inventory if  | 
|
679  | 
f not in removed_tree_ids))  | 
|
680  | 
for trans_id, file_id in self._new_id.iteritems():  | 
|
681  | 
if file_id in active_tree_ids:  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
682  | 
old_trans_id = self.trans_id_tree_file_id(file_id)  | 
| 
1534.7.50
by Aaron Bentley
 Detect duplicate inventory ids  | 
683  | 
conflicts.append(('duplicate id', old_trans_id, trans_id))  | 
684  | 
return conflicts  | 
|
685  | 
||
| 
1534.7.11
by Aaron Bentley
 Refactored conflict handling  | 
686  | 
def _parent_type_conflicts(self, by_parent):  | 
687  | 
"""parents must have directory 'contents'."""  | 
|
688  | 
conflicts = []  | 
|
| 
1534.7.37
by Aaron Bentley
 Allowed removed dirs to have content-free children.  | 
689  | 
for parent_id, children in by_parent.iteritems():  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
690  | 
if parent_id is ROOT_PARENT:  | 
691  | 
                continue
 | 
|
| 
1534.7.37
by Aaron Bentley
 Allowed removed dirs to have content-free children.  | 
692  | 
if not self._any_contents(children):  | 
693  | 
                continue
 | 
|
694  | 
for child in children:  | 
|
695  | 
try:  | 
|
696  | 
self.final_kind(child)  | 
|
697  | 
except NoSuchFile:  | 
|
698  | 
                    continue
 | 
|
| 
1534.7.10
by Aaron Bentley
 Implemented missing parent and non-directory parent conflicts  | 
699  | 
try:  | 
700  | 
kind = self.final_kind(parent_id)  | 
|
701  | 
except NoSuchFile:  | 
|
702  | 
kind = None  | 
|
703  | 
if kind is None:  | 
|
704  | 
conflicts.append(('missing parent', parent_id))  | 
|
705  | 
elif kind != "directory":  | 
|
706  | 
conflicts.append(('non-directory parent', parent_id))  | 
|
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
707  | 
return conflicts  | 
| 
1534.7.37
by Aaron Bentley
 Allowed removed dirs to have content-free children.  | 
708  | 
|
709  | 
def _any_contents(self, trans_ids):  | 
|
710  | 
"""Return true if any of the trans_ids, will have contents."""  | 
|
711  | 
for trans_id in trans_ids:  | 
|
712  | 
try:  | 
|
713  | 
kind = self.final_kind(trans_id)  | 
|
714  | 
except NoSuchFile:  | 
|
715  | 
                continue
 | 
|
716  | 
return True  | 
|
717  | 
return False  | 
|
| 
1534.7.6
by Aaron Bentley
 Added conflict handling  | 
718  | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
719  | 
def apply(self):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
720  | 
"""Apply all changes to the inventory and filesystem.  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
721  | 
        
 | 
722  | 
        If filesystem or inventory conflicts are present, MalformedTransform
 | 
|
723  | 
        will be thrown.
 | 
|
724  | 
        """
 | 
|
| 
1534.7.49
by Aaron Bentley
 Printed conflicts in MalformedTransform  | 
725  | 
conflicts = self.find_conflicts()  | 
726  | 
if len(conflicts) != 0:  | 
|
727  | 
raise MalformedTransform(conflicts=conflicts)  | 
|
| 
1534.7.41
by Aaron Bentley
 Got inventory ID movement working  | 
728  | 
limbo_inv = {}  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
729  | 
inv = self._tree.inventory  | 
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
730  | 
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()  | 
731  | 
try:  | 
|
732  | 
child_pb.update('Apply phase', 0, 2)  | 
|
733  | 
self._apply_removals(inv, limbo_inv)  | 
|
734  | 
child_pb.update('Apply phase', 1, 2)  | 
|
735  | 
modified_paths = self._apply_insertions(inv, limbo_inv)  | 
|
736  | 
finally:  | 
|
737  | 
child_pb.finished()  | 
|
| 
1534.7.35
by Aaron Bentley
 Got file renaming working  | 
738  | 
self._tree._write_inventory(inv)  | 
739  | 
self.__done = True  | 
|
| 
1534.7.59
by Aaron Bentley
 Simplified tests  | 
740  | 
self.finalize()  | 
| 
1534.7.191
by Aaron Bentley
 Got transform.apply to list modified paths  | 
741  | 
return _TransformResults(modified_paths)  | 
| 
1534.7.35
by Aaron Bentley
 Got file renaming working  | 
742  | 
|
| 
1534.7.72
by Aaron Bentley
 Moved new content generation to pre-renames  | 
743  | 
def _limbo_name(self, trans_id):  | 
744  | 
"""Generate the limbo name of a file"""  | 
|
| 
1534.7.166
by Aaron Bentley
 Swapped os.path.join for pathjoin everywhere  | 
745  | 
return pathjoin(self._limbodir, trans_id)  | 
| 
1534.7.72
by Aaron Bentley
 Moved new content generation to pre-renames  | 
746  | 
|
| 
1534.7.41
by Aaron Bentley
 Got inventory ID movement working  | 
747  | 
def _apply_removals(self, inv, limbo_inv):  | 
| 
1534.7.36
by Aaron Bentley
 Added rename tests  | 
748  | 
"""Perform tree operations that remove directory/inventory names.  | 
749  | 
        
 | 
|
750  | 
        That is, delete files that are to be deleted, and put any files that
 | 
|
751  | 
        need renaming into limbo.  This must be done in strict child-to-parent
 | 
|
752  | 
        order.
 | 
|
753  | 
        """
 | 
|
| 
1534.7.35
by Aaron Bentley
 Got file renaming working  | 
754  | 
tree_paths = list(self._tree_path_ids.iteritems())  | 
755  | 
tree_paths.sort(reverse=True)  | 
|
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
756  | 
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()  | 
757  | 
try:  | 
|
758  | 
for num, data in enumerate(tree_paths):  | 
|
759  | 
path, trans_id = data  | 
|
760  | 
child_pb.update('removing file', num, len(tree_paths))  | 
|
761  | 
full_path = self._tree.abspath(path)  | 
|
762  | 
if trans_id in self._removed_contents:  | 
|
| 
1558.12.9
by Aaron Bentley
 Handle resolving conflicts with directories properly  | 
763  | 
delete_any(full_path)  | 
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
764  | 
elif trans_id in self._new_name or trans_id in \  | 
765  | 
self._new_parent:  | 
|
766  | 
try:  | 
|
767  | 
os.rename(full_path, self._limbo_name(trans_id))  | 
|
768  | 
except OSError, e:  | 
|
769  | 
if e.errno != errno.ENOENT:  | 
|
770  | 
                            raise
 | 
|
771  | 
if trans_id in self._removed_id:  | 
|
772  | 
if trans_id == self._new_root:  | 
|
773  | 
file_id = self._tree.inventory.root.file_id  | 
|
774  | 
else:  | 
|
775  | 
file_id = self.tree_file_id(trans_id)  | 
|
776  | 
del inv[file_id]  | 
|
777  | 
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  | 
778  | 
file_id = self.tree_file_id(trans_id)  | 
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
779  | 
if file_id is not None:  | 
780  | 
limbo_inv[trans_id] = inv[file_id]  | 
|
781  | 
del inv[file_id]  | 
|
782  | 
finally:  | 
|
783  | 
child_pb.finished()  | 
|
| 
1534.7.34
by Aaron Bentley
 Proper conflicts for removals  | 
784  | 
|
| 
1534.7.41
by Aaron Bentley
 Got inventory ID movement working  | 
785  | 
def _apply_insertions(self, inv, limbo_inv):  | 
| 
1534.7.36
by Aaron Bentley
 Added rename tests  | 
786  | 
"""Perform tree operations that insert directory/inventory names.  | 
787  | 
        
 | 
|
788  | 
        That is, create any files that need to be created, and restore from
 | 
|
789  | 
        limbo any files that needed renaming.  This must be done in strict
 | 
|
790  | 
        parent-to-child order.
 | 
|
791  | 
        """
 | 
|
| 
1534.9.1
by Aaron Bentley
 Added progress bars to merge  | 
792  | 
new_paths = self.new_paths()  | 
| 
1534.7.191
by Aaron Bentley
 Got transform.apply to list modified paths  | 
793  | 
modified_paths = []  | 
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
794  | 
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()  | 
795  | 
try:  | 
|
796  | 
for num, (path, trans_id) in enumerate(new_paths):  | 
|
797  | 
child_pb.update('adding file', num, len(new_paths))  | 
|
| 
1534.7.48
by Aaron Bentley
 Ensured we can move/rename dangling inventory entries  | 
798  | 
try:  | 
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
799  | 
kind = self._new_contents[trans_id]  | 
800  | 
except KeyError:  | 
|
801  | 
kind = contents = None  | 
|
802  | 
if trans_id in self._new_contents or \  | 
|
803  | 
self.path_changed(trans_id):  | 
|
804  | 
full_path = self._tree.abspath(path)  | 
|
805  | 
try:  | 
|
806  | 
os.rename(self._limbo_name(trans_id), full_path)  | 
|
807  | 
except OSError, e:  | 
|
808  | 
                        # We may be renaming a dangling inventory id
 | 
|
809  | 
if e.errno != errno.ENOENT:  | 
|
810  | 
                            raise
 | 
|
811  | 
if trans_id in self._new_contents:  | 
|
812  | 
modified_paths.append(full_path)  | 
|
813  | 
del self._new_contents[trans_id]  | 
|
814  | 
||
815  | 
if trans_id in self._new_id:  | 
|
816  | 
if kind is None:  | 
|
817  | 
kind = file_kind(self._tree.abspath(path))  | 
|
818  | 
inv.add_path(path, kind, self._new_id[trans_id])  | 
|
819  | 
elif trans_id in self._new_name or trans_id in\  | 
|
820  | 
self._new_parent:  | 
|
821  | 
entry = limbo_inv.get(trans_id)  | 
|
822  | 
if entry is not None:  | 
|
823  | 
entry.name = self.final_name(trans_id)  | 
|
824  | 
parent_path = os.path.dirname(path)  | 
|
825  | 
entry.parent_id = \  | 
|
826  | 
self._tree.inventory.path2id(parent_path)  | 
|
827  | 
inv.add(entry)  | 
|
828  | 
||
829  | 
                # requires files and inventory entries to be in place
 | 
|
830  | 
if trans_id in self._new_executability:  | 
|
831  | 
self._set_executability(path, inv, trans_id)  | 
|
832  | 
finally:  | 
|
833  | 
child_pb.finished()  | 
|
| 
1534.7.191
by Aaron Bentley
 Got transform.apply to list modified paths  | 
834  | 
return modified_paths  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
835  | 
|
| 
1534.7.25
by Aaron Bentley
 Added set_executability  | 
836  | 
def _set_executability(self, path, inv, trans_id):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
837  | 
"""Set the executability of versioned files """  | 
| 
1534.7.25
by Aaron Bentley
 Added set_executability  | 
838  | 
file_id = inv.path2id(path)  | 
839  | 
new_executability = self._new_executability[trans_id]  | 
|
840  | 
inv[file_id].executable = new_executability  | 
|
841  | 
if supports_executable():  | 
|
842  | 
abspath = self._tree.abspath(path)  | 
|
843  | 
current_mode = os.stat(abspath).st_mode  | 
|
844  | 
if new_executability:  | 
|
845  | 
umask = os.umask(0)  | 
|
846  | 
os.umask(umask)  | 
|
847  | 
to_mode = current_mode | (0100 & ~umask)  | 
|
848  | 
                # Enable x-bit for others only if they can read it.
 | 
|
849  | 
if current_mode & 0004:  | 
|
850  | 
to_mode |= 0001 & ~umask  | 
|
851  | 
if current_mode & 0040:  | 
|
852  | 
to_mode |= 0010 & ~umask  | 
|
853  | 
else:  | 
|
854  | 
to_mode = current_mode & ~0111  | 
|
855  | 
os.chmod(abspath, to_mode)  | 
|
856  | 
||
| 
1534.7.23
by Aaron Bentley
 Transform.new_entry -> Transform._new_entry  | 
857  | 
def _new_entry(self, name, parent_id, file_id):  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
858  | 
"""Helper function to create a new filesystem entry."""  | 
| 
1534.7.2
by Aaron Bentley
 Added convenience function  | 
859  | 
trans_id = self.create_path(name, parent_id)  | 
860  | 
if file_id is not None:  | 
|
861  | 
self.version_file(file_id, trans_id)  | 
|
862  | 
return trans_id  | 
|
863  | 
||
| 
1534.7.27
by Aaron Bentley
 Added execute bit to new_file method  | 
864  | 
def new_file(self, name, parent_id, contents, file_id=None,  | 
865  | 
executable=None):  | 
|
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
866  | 
"""Convenience method to create files.  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
867  | 
        
 | 
868  | 
        name is the name of the file to create.
 | 
|
869  | 
        parent_id is the transaction id of the parent directory of the file.
 | 
|
870  | 
        contents is an iterator of bytestrings, which will be used to produce
 | 
|
871  | 
        the file.
 | 
|
| 
1740.2.4
by Aaron Bentley
 Update transform tests and docs  | 
872  | 
        :param file_id: The inventory ID of the file, if it is to be versioned.
 | 
873  | 
        :param executable: Only valid when a file_id has been supplied.
 | 
|
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
874  | 
        """
 | 
| 
1534.7.23
by Aaron Bentley
 Transform.new_entry -> Transform._new_entry  | 
875  | 
trans_id = self._new_entry(name, parent_id, file_id)  | 
| 
1740.2.4
by Aaron Bentley
 Update transform tests and docs  | 
876  | 
        # TODO: rather than scheduling a set_executable call,
 | 
877  | 
        # have create_file create the file with the right mode.
 | 
|
| 
1534.7.20
by Aaron Bentley
 Added directory handling  | 
878  | 
self.create_file(contents, trans_id)  | 
| 
1534.7.27
by Aaron Bentley
 Added execute bit to new_file method  | 
879  | 
if executable is not None:  | 
880  | 
self.set_executability(executable, trans_id)  | 
|
| 
1534.7.20
by Aaron Bentley
 Added directory handling  | 
881  | 
return trans_id  | 
882  | 
||
883  | 
def new_directory(self, name, parent_id, file_id=None):  | 
|
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
884  | 
"""Convenience method to create directories.  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
885  | 
|
886  | 
        name is the name of the directory to create.
 | 
|
887  | 
        parent_id is the transaction id of the parent directory of the
 | 
|
888  | 
        directory.
 | 
|
889  | 
        file_id is the inventory ID of the directory, if it is to be versioned.
 | 
|
890  | 
        """
 | 
|
| 
1534.7.23
by Aaron Bentley
 Transform.new_entry -> Transform._new_entry  | 
891  | 
trans_id = self._new_entry(name, parent_id, file_id)  | 
| 
1534.7.20
by Aaron Bentley
 Added directory handling  | 
892  | 
self.create_directory(trans_id)  | 
893  | 
return trans_id  | 
|
894  | 
||
| 
1534.7.22
by Aaron Bentley
 Added symlink support  | 
895  | 
def new_symlink(self, name, parent_id, target, file_id=None):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
896  | 
"""Convenience method to create symbolic link.  | 
| 
1534.7.22
by Aaron Bentley
 Added symlink support  | 
897  | 
        
 | 
898  | 
        name is the name of the symlink to create.
 | 
|
899  | 
        parent_id is the transaction id of the parent directory of the symlink.
 | 
|
900  | 
        target is a bytestring of the target of the symlink.
 | 
|
901  | 
        file_id is the inventory ID of the file, if it is to be versioned.
 | 
|
902  | 
        """
 | 
|
| 
1534.7.23
by Aaron Bentley
 Transform.new_entry -> Transform._new_entry  | 
903  | 
trans_id = self._new_entry(name, parent_id, file_id)  | 
| 
1534.7.22
by Aaron Bentley
 Added symlink support  | 
904  | 
self.create_symlink(target, trans_id)  | 
905  | 
return trans_id  | 
|
906  | 
||
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
907  | 
def joinpath(parent, child):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
908  | 
"""Join tree-relative paths, handling the tree root specially"""  | 
| 
1534.7.32
by Aaron Bentley
 Got conflict handling working when conflicts involve existing files  | 
909  | 
if parent is None or parent == "":  | 
910  | 
return child  | 
|
911  | 
else:  | 
|
| 
1534.7.166
by Aaron Bentley
 Swapped os.path.join for pathjoin everywhere  | 
912  | 
return pathjoin(parent, child)  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
913  | 
|
| 
1534.7.167
by Aaron Bentley
 PEP8 and comment cleanups  | 
914  | 
|
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
915  | 
class FinalPaths(object):  | 
| 
1759.2.2
by Jelmer Vernooij
 Revert some of my spelling fixes and fix some typos after review by Aaron.  | 
916  | 
"""Make path calculation cheap by memoizing paths.  | 
| 
1534.7.21
by Aaron Bentley
 Updated docstrings  | 
917  | 
|
918  | 
    The underlying tree must not be manipulated between calls, or else
 | 
|
919  | 
    the results will likely be incorrect.
 | 
|
920  | 
    """
 | 
|
| 
1534.7.132
by Aaron Bentley
 Got cooked conflicts working  | 
921  | 
def __init__(self, transform):  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
922  | 
object.__init__(self)  | 
923  | 
self._known_paths = {}  | 
|
| 
1534.7.33
by Aaron Bentley
 Fixed naming  | 
924  | 
self.transform = transform  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
925  | 
|
926  | 
def _determine_path(self, trans_id):  | 
|
| 
1534.7.132
by Aaron Bentley
 Got cooked conflicts working  | 
927  | 
if trans_id == self.transform.root:  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
928  | 
return ""  | 
| 
1534.7.33
by Aaron Bentley
 Fixed naming  | 
929  | 
name = self.transform.final_name(trans_id)  | 
930  | 
parent_id = self.transform.final_parent(trans_id)  | 
|
| 
1534.7.132
by Aaron Bentley
 Got cooked conflicts working  | 
931  | 
if parent_id == self.transform.root:  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
932  | 
return name  | 
933  | 
else:  | 
|
| 
1534.7.166
by Aaron Bentley
 Swapped os.path.join for pathjoin everywhere  | 
934  | 
return pathjoin(self.get_path(parent_id), name)  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
935  | 
|
936  | 
def get_path(self, trans_id):  | 
|
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
937  | 
"""Find the final path associated with a trans_id"""  | 
| 
1534.7.1
by Aaron Bentley
 Got creation of a versioned file working  | 
938  | 
if trans_id not in self._known_paths:  | 
939  | 
self._known_paths[trans_id] = self._determine_path(trans_id)  | 
|
940  | 
return self._known_paths[trans_id]  | 
|
| 
1534.7.28
by Aaron Bentley
 Nearly-working build_tree replacement  | 
941  | 
|
| 
1534.7.30
by Aaron Bentley
 Factored out topological id sorting  | 
942  | 
def topology_sorted_ids(tree):  | 
| 
1534.7.40
by Aaron Bentley
 Updated docs  | 
943  | 
"""Determine the topological order of the ids in a tree"""  | 
| 
1534.7.30
by Aaron Bentley
 Factored out topological id sorting  | 
944  | 
file_ids = list(tree)  | 
945  | 
file_ids.sort(key=tree.id2path)  | 
|
946  | 
return file_ids  | 
|
| 
1534.7.28
by Aaron Bentley
 Nearly-working build_tree replacement  | 
947  | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
948  | 
|
| 
1534.7.165
by Aaron Bentley
 Switched to build_tree instead of revert  | 
949  | 
def build_tree(tree, wt):  | 
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
950  | 
"""Create working tree for a branch, using a TreeTransform.  | 
951  | 
    
 | 
|
| 
1966.1.2
by Aaron Bentley
 Divert files instead of failing to create them, update from review  | 
952  | 
    This function should be used on empty trees, having a tree root at most.
 | 
953  | 
    (see merge and revert functionality for working with existing trees)
 | 
|
954  | 
||
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
955  | 
    Existing files are handled like so:
 | 
956  | 
    
 | 
|
| 
1966.1.2
by Aaron Bentley
 Divert files instead of failing to create them, update from review  | 
957  | 
    - Existing bzrdirs take precedence over creating new items.  They are
 | 
958  | 
      created as '%s.diverted' % name.
 | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
959  | 
    - Otherwise, if the content on disk matches the content we are building,
 | 
960  | 
      it is silently replaced.
 | 
|
961  | 
    - Otherwise, conflict resolution will move the old file to 'oldname.moved'.
 | 
|
962  | 
    """
 | 
|
| 
2090.2.1
by Martin Pool
 Fix some code which relies on assertions and breaks under python -O  | 
963  | 
if len(wt.inventory) > 1: # more than just a root  | 
964  | 
raise errors.WorkingTreeAlreadyPopulated(base=wt.basedir)  | 
|
| 
1534.7.28
by Aaron Bentley
 Nearly-working build_tree replacement  | 
965  | 
file_trans_id = {}  | 
| 
1558.11.1
by Aaron Bentley
 Progress indicator for tree builts  | 
966  | 
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()  | 
967  | 
pp = ProgressPhase("Build phase", 2, top_pb)  | 
|
| 
1731.1.33
by Aaron Bentley
 Revert no-special-root changes  | 
968  | 
if tree.inventory.root is not None:  | 
969  | 
wt.set_root_id(tree.inventory.root.file_id)  | 
|
| 
1534.7.28
by Aaron Bentley
 Nearly-working build_tree replacement  | 
970  | 
tt = TreeTransform(wt)  | 
| 
1966.1.2
by Aaron Bentley
 Divert files instead of failing to create them, update from review  | 
971  | 
divert = set()  | 
| 
1534.7.28
by Aaron Bentley
 Nearly-working build_tree replacement  | 
972  | 
try:  | 
| 
1558.11.1
by Aaron Bentley
 Progress indicator for tree builts  | 
973  | 
pp.next_phase()  | 
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
974  | 
file_trans_id[wt.get_root_id()] = \  | 
975  | 
tt.trans_id_tree_file_id(wt.get_root_id())  | 
|
| 
1558.11.1
by Aaron Bentley
 Progress indicator for tree builts  | 
976  | 
pb = bzrlib.ui.ui_factory.nested_progress_bar()  | 
977  | 
try:  | 
|
| 
1966.1.2
by Aaron Bentley
 Divert files instead of failing to create them, update from review  | 
978  | 
for num, (tree_path, entry) in \  | 
979  | 
enumerate(tree.inventory.iter_entries_by_dir()):  | 
|
980  | 
pb.update("Building tree", num, len(tree.inventory))  | 
|
| 
1558.11.1
by Aaron Bentley
 Progress indicator for tree builts  | 
981  | 
if entry.parent_id is None:  | 
982  | 
                    continue
 | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
983  | 
reparent = False  | 
| 
1966.1.2
by Aaron Bentley
 Divert files instead of failing to create them, update from review  | 
984  | 
file_id = entry.file_id  | 
985  | 
target_path = wt.abspath(tree_path)  | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
986  | 
try:  | 
987  | 
kind = file_kind(target_path)  | 
|
988  | 
except NoSuchFile:  | 
|
989  | 
                    pass
 | 
|
990  | 
else:  | 
|
991  | 
if kind == "directory":  | 
|
992  | 
try:  | 
|
993  | 
bzrdir.BzrDir.open(target_path)  | 
|
994  | 
except errors.NotBranchError:  | 
|
995  | 
                            pass
 | 
|
996  | 
else:  | 
|
| 
1966.1.2
by Aaron Bentley
 Divert files instead of failing to create them, update from review  | 
997  | 
divert.add(file_id)  | 
998  | 
if (file_id not in divert and  | 
|
999  | 
_content_match(tree, entry, file_id, kind,  | 
|
1000  | 
target_path)):  | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1001  | 
tt.delete_contents(tt.trans_id_tree_path(tree_path))  | 
1002  | 
if kind == 'directory':  | 
|
1003  | 
reparent = True  | 
|
| 
1558.11.1
by Aaron Bentley
 Progress indicator for tree builts  | 
1004  | 
if entry.parent_id not in file_trans_id:  | 
1005  | 
raise repr(entry.parent_id)  | 
|
1006  | 
parent_id = file_trans_id[entry.parent_id]  | 
|
| 
1966.1.2
by Aaron Bentley
 Divert files instead of failing to create them, update from review  | 
1007  | 
file_trans_id[file_id] = new_by_entry(tt, entry, parent_id,  | 
| 
1558.11.1
by Aaron Bentley
 Progress indicator for tree builts  | 
1008  | 
tree)  | 
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1009  | 
if reparent:  | 
1010  | 
new_trans_id = file_trans_id[file_id]  | 
|
1011  | 
old_parent = tt.trans_id_tree_path(tree_path)  | 
|
1012  | 
_reparent_children(tt, old_parent, new_trans_id)  | 
|
| 
1558.11.1
by Aaron Bentley
 Progress indicator for tree builts  | 
1013  | 
finally:  | 
1014  | 
pb.finished()  | 
|
1015  | 
pp.next_phase()  | 
|
| 
1966.1.2
by Aaron Bentley
 Divert files instead of failing to create them, update from review  | 
1016  | 
divert_trans = set(file_trans_id[f] for f in divert)  | 
1017  | 
resolver = lambda t, c: resolve_checkout(t, c, divert_trans)  | 
|
1018  | 
raw_conflicts = resolve_conflicts(tt, pass_func=resolver)  | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1019  | 
conflicts = cook_conflicts(raw_conflicts, tt)  | 
1020  | 
for conflict in conflicts:  | 
|
1021  | 
warning(conflict)  | 
|
1022  | 
try:  | 
|
1023  | 
wt.add_conflicts(conflicts)  | 
|
1024  | 
except errors.UnsupportedOperation:  | 
|
1025  | 
            pass
 | 
|
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1026  | 
tt.apply()  | 
1027  | 
finally:  | 
|
1028  | 
tt.finalize()  | 
|
| 
1558.11.1
by Aaron Bentley
 Progress indicator for tree builts  | 
1029  | 
top_pb.finished()  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1030  | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1031  | 
|
1032  | 
def _reparent_children(tt, old_parent, new_parent):  | 
|
1033  | 
for child in tt.iter_tree_children(old_parent):  | 
|
1034  | 
tt.adjust_path(tt.final_name(child), new_parent, child)  | 
|
1035  | 
||
1036  | 
||
1037  | 
def _content_match(tree, entry, file_id, kind, target_path):  | 
|
1038  | 
if entry.kind != kind:  | 
|
1039  | 
return False  | 
|
1040  | 
if entry.kind == "directory":  | 
|
1041  | 
return True  | 
|
1042  | 
if entry.kind == "file":  | 
|
1043  | 
if tree.get_file(file_id).read() == file(target_path, 'rb').read():  | 
|
1044  | 
return True  | 
|
1045  | 
elif entry.kind == "symlink":  | 
|
1046  | 
if tree.get_symlink_target(file_id) == os.readlink(target_path):  | 
|
1047  | 
return True  | 
|
1048  | 
return False  | 
|
1049  | 
||
1050  | 
||
| 
1966.1.2
by Aaron Bentley
 Divert files instead of failing to create them, update from review  | 
1051  | 
def resolve_checkout(tt, conflicts, divert):  | 
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1052  | 
new_conflicts = set()  | 
1053  | 
for c_type, conflict in ((c[0], c) for c in conflicts):  | 
|
1054  | 
        # Anything but a 'duplicate' would indicate programmer error
 | 
|
1055  | 
assert c_type == 'duplicate', c_type  | 
|
1056  | 
        # 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  | 
1057  | 
if tt.new_contents(conflict[1]):  | 
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1058  | 
new_file = conflict[1]  | 
1059  | 
old_file = conflict[2]  | 
|
1060  | 
else:  | 
|
1061  | 
new_file = conflict[2]  | 
|
1062  | 
old_file = conflict[1]  | 
|
1063  | 
||
1064  | 
        # We should only get here if the conflict wasn't completely
 | 
|
1065  | 
        # resolved
 | 
|
1066  | 
final_parent = tt.final_parent(old_file)  | 
|
| 
1966.1.2
by Aaron Bentley
 Divert files instead of failing to create them, update from review  | 
1067  | 
if new_file in divert:  | 
1068  | 
new_name = tt.final_name(old_file)+'.diverted'  | 
|
1069  | 
tt.adjust_path(new_name, final_parent, new_file)  | 
|
1070  | 
new_conflicts.add((c_type, 'Diverted to',  | 
|
1071  | 
new_file, old_file))  | 
|
1072  | 
else:  | 
|
1073  | 
new_name = tt.final_name(old_file)+'.moved'  | 
|
1074  | 
tt.adjust_path(new_name, final_parent, old_file)  | 
|
1075  | 
new_conflicts.add((c_type, 'Moved existing file to',  | 
|
1076  | 
old_file, new_file))  | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1077  | 
return new_conflicts  | 
1078  | 
||
1079  | 
||
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1080  | 
def new_by_entry(tt, entry, parent_id, tree):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
1081  | 
"""Create a new file according to its inventory entry"""  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1082  | 
name = entry.name  | 
1083  | 
kind = entry.kind  | 
|
1084  | 
if kind == 'file':  | 
|
| 
1534.7.79
by Aaron Bentley
 Stopped calling get_file_lines on WorkingTree  | 
1085  | 
contents = tree.get_file(entry.file_id).readlines()  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1086  | 
executable = tree.is_executable(entry.file_id)  | 
1087  | 
return tt.new_file(name, parent_id, contents, entry.file_id,  | 
|
1088  | 
executable)  | 
|
1089  | 
elif kind == 'directory':  | 
|
| 
1534.7.54
by Aaron Bentley
 Fixed thinko  | 
1090  | 
return tt.new_directory(name, parent_id, entry.file_id)  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1091  | 
elif kind == 'symlink':  | 
| 
1534.7.183
by Aaron Bentley
 Fixed build_tree with symlinks  | 
1092  | 
target = tree.get_symlink_target(entry.file_id)  | 
1093  | 
return tt.new_symlink(name, parent_id, target, entry.file_id)  | 
|
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1094  | 
|
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
1095  | 
def create_by_entry(tt, entry, tree, trans_id, lines=None, mode_id=None):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
1096  | 
"""Create new file contents according to an inventory entry."""  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1097  | 
if entry.kind == "file":  | 
| 
1963.2.6
by Robey Pointer
 pychecker is on crack; go back to using 'is None'.  | 
1098  | 
if lines is None:  | 
| 
1534.7.97
by Aaron Bentley
 Ensured foo.BASE is a directory if there's a conflict  | 
1099  | 
lines = tree.get_file(entry.file_id).readlines()  | 
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
1100  | 
tt.create_file(lines, trans_id, mode_id=mode_id)  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1101  | 
elif entry.kind == "symlink":  | 
| 
1534.7.101
by Aaron Bentley
 Got conflicts on symlinks working properly  | 
1102  | 
tt.create_symlink(tree.get_symlink_target(entry.file_id), trans_id)  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1103  | 
elif entry.kind == "directory":  | 
| 
1534.7.51
by Aaron Bentley
 New approach to revert  | 
1104  | 
tt.create_directory(trans_id)  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1105  | 
|
| 
1534.7.89
by Aaron Bentley
 Handle all content types in three-way  | 
1106  | 
def create_entry_executability(tt, entry, trans_id):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
1107  | 
"""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  | 
1108  | 
if entry.kind == "file":  | 
1109  | 
tt.set_executability(entry.executable, trans_id)  | 
|
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1110  | 
|
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
1111  | 
|
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1112  | 
def find_interesting(working_tree, target_tree, filenames):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
1113  | 
"""Find the ids corresponding to specified filenames."""  | 
| 
1551.7.7
by Aaron Bentley
 Handle revert DIRECTORY  | 
1114  | 
trees = (working_tree, target_tree)  | 
| 
1551.7.22
by Aaron Bentley
 Changes from review  | 
1115  | 
return tree.find_ids_across_trees(filenames, trees)  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1116  | 
|
1117  | 
||
| 
1534.7.56
by Aaron Bentley
 Implemented the backup file detritus  | 
1118  | 
def change_entry(tt, file_id, working_tree, target_tree,  | 
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
1119  | 
trans_id_file_id, backups, trans_id, by_parent):  | 
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
1120  | 
"""Replace a file_id's contents with those from a target tree."""  | 
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
1121  | 
e_trans_id = trans_id_file_id(file_id)  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1122  | 
entry = target_tree.inventory[file_id]  | 
1123  | 
has_contents, contents_mod, meta_mod, = _entry_changes(file_id, entry,  | 
|
1124  | 
working_tree)  | 
|
1125  | 
if contents_mod:  | 
|
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
1126  | 
mode_id = e_trans_id  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1127  | 
if has_contents:  | 
| 
1534.7.56
by Aaron Bentley
 Implemented the backup file detritus  | 
1128  | 
if not backups:  | 
1129  | 
tt.delete_contents(e_trans_id)  | 
|
1130  | 
else:  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
1131  | 
parent_trans_id = trans_id_file_id(entry.parent_id)  | 
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
1132  | 
backup_name = get_backup_name(entry, by_parent,  | 
1133  | 
parent_trans_id, tt)  | 
|
1134  | 
tt.adjust_path(backup_name, parent_trans_id, e_trans_id)  | 
|
| 
1534.7.56
by Aaron Bentley
 Implemented the backup file detritus  | 
1135  | 
tt.unversion_file(e_trans_id)  | 
1136  | 
e_trans_id = tt.create_path(entry.name, parent_trans_id)  | 
|
1137  | 
tt.version_file(file_id, e_trans_id)  | 
|
1138  | 
trans_id[file_id] = e_trans_id  | 
|
| 
1534.7.117
by Aaron Bentley
 Simplified permission handling of existing files in transform.  | 
1139  | 
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  | 
1140  | 
create_entry_executability(tt, entry, e_trans_id)  | 
1141  | 
||
| 
1711.4.26
by John Arbash Meinel
 Fix #45010 correctly. Don't forget the execute bit.  | 
1142  | 
elif meta_mod:  | 
1143  | 
tt.set_executability(entry.executable, e_trans_id)  | 
|
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1144  | 
if tt.final_name(e_trans_id) != entry.name:  | 
1145  | 
adjust_path = True  | 
|
1146  | 
else:  | 
|
1147  | 
parent_id = tt.final_parent(e_trans_id)  | 
|
1148  | 
parent_file_id = tt.final_file_id(parent_id)  | 
|
1149  | 
if parent_file_id != entry.parent_id:  | 
|
1150  | 
adjust_path = True  | 
|
1151  | 
else:  | 
|
1152  | 
adjust_path = False  | 
|
1153  | 
if adjust_path:  | 
|
| 
1534.7.181
by Aaron Bentley
 Renamed a bunch of functions  | 
1154  | 
parent_trans_id = trans_id_file_id(entry.parent_id)  | 
| 
1534.7.56
by Aaron Bentley
 Implemented the backup file detritus  | 
1155  | 
tt.adjust_path(entry.name, parent_trans_id, e_trans_id)  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1156  | 
|
1157  | 
||
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
1158  | 
def get_backup_name(entry, by_parent, parent_trans_id, tt):  | 
| 
2012.1.12
by Aaron Bentley
 Use iter_changes for revert  | 
1159  | 
return _get_backup_name(entry.name, by_parent, parent_trans_id, tt)  | 
1160  | 
||
1161  | 
||
1162  | 
def _get_backup_name(name, by_parent, parent_trans_id, tt):  | 
|
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
1163  | 
"""Produce a backup-style name that appears to be available"""  | 
1164  | 
def name_gen():  | 
|
1165  | 
counter = 1  | 
|
1166  | 
while True:  | 
|
| 
2012.1.12
by Aaron Bentley
 Use iter_changes for revert  | 
1167  | 
yield "%s.~%d~" % (name, counter)  | 
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
1168  | 
counter += 1  | 
| 
2012.1.12
by Aaron Bentley
 Use iter_changes for revert  | 
1169  | 
for new_name in name_gen():  | 
1170  | 
if not tt.has_named_child(by_parent, parent_trans_id, new_name):  | 
|
1171  | 
return new_name  | 
|
1172  | 
||
| 
1534.10.28
by Aaron Bentley
 Use numbered backup files  | 
1173  | 
|
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1174  | 
def _entry_changes(file_id, entry, working_tree):  | 
| 
1534.7.156
by Aaron Bentley
 PEP8 fixes  | 
1175  | 
"""Determine in which ways the inventory entry has changed.  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1176  | 
|
1177  | 
    Returns booleans: has_contents, content_mod, meta_mod
 | 
|
1178  | 
    has_contents means there are currently contents, but they differ
 | 
|
1179  | 
    contents_mod means contents need to be modified
 | 
|
1180  | 
    meta_mod means the metadata needs to be modified
 | 
|
1181  | 
    """
 | 
|
1182  | 
cur_entry = working_tree.inventory[file_id]  | 
|
1183  | 
try:  | 
|
1184  | 
working_kind = working_tree.kind(file_id)  | 
|
1185  | 
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.  | 
1186  | 
except NoSuchFile:  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1187  | 
has_contents = False  | 
1188  | 
contents_mod = True  | 
|
1189  | 
meta_mod = False  | 
|
1190  | 
if has_contents is True:  | 
|
| 
1731.1.1
by Aaron Bentley
 Make root entry an InventoryDirectory, make EmptyTree really empty  | 
1191  | 
if entry.kind != working_kind:  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1192  | 
contents_mod, meta_mod = True, False  | 
1193  | 
else:  | 
|
1194  | 
cur_entry._read_tree_state(working_tree.id2path(file_id),  | 
|
1195  | 
working_tree)  | 
|
1196  | 
contents_mod, meta_mod = entry.detect_changes(cur_entry)  | 
|
| 
1534.7.175
by Aaron Bentley
 Ensured revert writes a normal inventory  | 
1197  | 
cur_entry._forget_tree_state()  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1198  | 
return has_contents, contents_mod, meta_mod  | 
1199  | 
||
| 
1534.7.56
by Aaron Bentley
 Implemented the backup file detritus  | 
1200  | 
|
| 
1534.9.4
by Aaron Bentley
 Added progress bars to revert.  | 
1201  | 
def revert(working_tree, target_tree, filenames, backups=False,  | 
1202  | 
pb=DummyProgress()):  | 
|
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
1203  | 
"""Revert a working tree's contents to those of a target tree."""  | 
| 
1534.7.55
by Aaron Bentley
 Fixed up the change detection  | 
1204  | 
interesting_ids = find_interesting(working_tree, target_tree, filenames)  | 
| 
1534.9.7
by Aaron Bentley
 Show progress bars in revert  | 
1205  | 
tt = TreeTransform(working_tree, pb)  | 
| 
1534.7.47
by Aaron Bentley
 Started work on 'revert'  | 
1206  | 
try:  | 
| 
2012.1.12
by Aaron Bentley
 Use iter_changes for revert  | 
1207  | 
pp = ProgressPhase("Revert phase", 3, pb)  | 
1208  | 
pp.next_phase()  | 
|
1209  | 
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()  | 
|
1210  | 
try:  | 
|
1211  | 
_alter_files(working_tree, target_tree, tt, child_pb,  | 
|
1212  | 
interesting_ids, backups)  | 
|
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
1213  | 
finally:  | 
1214  | 
child_pb.finished()  | 
|
| 
1551.2.34
by Aaron Bentley
 Refactored the revert phases  | 
1215  | 
pp.next_phase()  | 
| 
1551.2.31
by Aaron Bentley
 Got merge and revert using nested pbs  | 
1216  | 
child_pb = bzrlib.ui.ui_factory.nested_progress_bar()  | 
1217  | 
try:  | 
|
1218  | 
raw_conflicts = resolve_conflicts(tt, child_pb)  | 
|
1219  | 
finally:  | 
|
1220  | 
child_pb.finished()  | 
|
| 
1558.7.13
by Aaron Bentley
 WorkingTree.revert returns conflicts  | 
1221  | 
conflicts = cook_conflicts(raw_conflicts, tt)  | 
| 
1534.10.27
by Aaron Bentley
 Merge from mainline  | 
1222  | 
for conflict in conflicts:  | 
| 
1534.10.24
by Aaron Bentley
 Eliminated conflicts_to_strings, made remove_files a ConflictList member  | 
1223  | 
warning(conflict)  | 
| 
1551.2.34
by Aaron Bentley
 Refactored the revert phases  | 
1224  | 
pp.next_phase()  | 
| 
1534.7.28
by Aaron Bentley
 Nearly-working build_tree replacement  | 
1225  | 
tt.apply()  | 
| 
1534.7.193
by Aaron Bentley
 Stopped revert from preserving file contents produced by merges  | 
1226  | 
working_tree.set_merge_modified({})  | 
| 
1534.7.28
by Aaron Bentley
 Nearly-working build_tree replacement  | 
1227  | 
finally:  | 
1228  | 
tt.finalize()  | 
|
| 
1534.9.4
by Aaron Bentley
 Added progress bars to revert.  | 
1229  | 
pb.clear()  | 
| 
1558.7.13
by Aaron Bentley
 WorkingTree.revert returns conflicts  | 
1230  | 
return conflicts  | 
| 
1534.7.51
by Aaron Bentley
 New approach to revert  | 
1231  | 
|
| 
1534.7.57
by Aaron Bentley
 Enhanced conflict resolution.  | 
1232  | 
|
| 
2012.1.12
by Aaron Bentley
 Use iter_changes for revert  | 
1233  | 
def _alter_files(working_tree, target_tree, tt, pb, interesting_ids, backups):  | 
1234  | 
merge_modified = working_tree.merge_modified()  | 
|
1235  | 
iterator = target_tree._iter_changes(working_tree,  | 
|
| 
2012.1.16
by Aaron Bentley
 Support progress bars in iter_changes  | 
1236  | 
specific_file_ids=interesting_ids,  | 
1237  | 
pb=pb)  | 
|
| 
2012.1.12
by Aaron Bentley
 Use iter_changes for revert  | 
1238  | 
if target_tree.inventory.root is None:  | 
1239  | 
skip_root = True  | 
|
1240  | 
else:  | 
|
1241  | 
skip_root = False  | 
|
1242  | 
basis_tree = None  | 
|
1243  | 
for id_num, (file_id, path, changed_content, versioned, parent, name, kind,  | 
|
1244  | 
executable) in enumerate(iterator):  | 
|
1245  | 
if skip_root and file_id[0] is not None and parent[0] is None:  | 
|
1246  | 
            continue
 | 
|
1247  | 
trans_id = tt.trans_id_file_id(file_id)  | 
|
| 
2012.1.15
by Aaron Bentley
 Minor tweaks  | 
1248  | 
mode_id = None  | 
| 
2012.1.12
by Aaron Bentley
 Use iter_changes for revert  | 
1249  | 
if changed_content:  | 
1250  | 
keep_content = False  | 
|
1251  | 
if kind[0] == 'file' and (backups or kind[1] is None):  | 
|
1252  | 
wt_sha1 = working_tree.get_file_sha1(file_id)  | 
|
1253  | 
if merge_modified.get(file_id) != wt_sha1:  | 
|
1254  | 
if basis_tree is None:  | 
|
1255  | 
basis_tree = working_tree.basis_tree()  | 
|
1256  | 
if file_id in basis_tree:  | 
|
1257  | 
if wt_sha1 != basis_tree.get_file_sha1(file_id):  | 
|
1258  | 
keep_content = True  | 
|
1259  | 
elif kind[1] is None and not versioned[1]:  | 
|
1260  | 
keep_content = True  | 
|
1261  | 
if kind[0] is not None:  | 
|
1262  | 
if not keep_content:  | 
|
1263  | 
tt.delete_contents(trans_id)  | 
|
1264  | 
elif kind[1] is not None:  | 
|
1265  | 
parent_trans_id = tt.trans_id_file_id(parent[0])  | 
|
| 
2012.1.13
by Aaron Bentley
 Optimize revert  | 
1266  | 
by_parent = tt.by_parent()  | 
| 
2012.1.12
by Aaron Bentley
 Use iter_changes for revert  | 
1267  | 
backup_name = _get_backup_name(name[0], by_parent,  | 
1268  | 
parent_trans_id, tt)  | 
|
1269  | 
tt.adjust_path(backup_name, parent_trans_id, trans_id)  | 
|
1270  | 
new_trans_id = tt.create_path(name[0], parent_trans_id)  | 
|
1271  | 
if versioned == (True, True):  | 
|
1272  | 
tt.unversion_file(trans_id)  | 
|
1273  | 
tt.version_file(file_id, new_trans_id)  | 
|
| 
2012.1.15
by Aaron Bentley
 Minor tweaks  | 
1274  | 
mode_id = trans_id  | 
| 
2012.1.12
by Aaron Bentley
 Use iter_changes for revert  | 
1275  | 
trans_id = new_trans_id  | 
1276  | 
if kind[1] == 'directory':  | 
|
1277  | 
tt.create_directory(trans_id)  | 
|
1278  | 
elif kind[1] == 'symlink':  | 
|
1279  | 
tt.create_symlink(target_tree.get_symlink_target(file_id),  | 
|
1280  | 
trans_id)  | 
|
1281  | 
elif kind[1] == 'file':  | 
|
| 
2012.1.13
by Aaron Bentley
 Optimize revert  | 
1282  | 
tt.create_file(target_tree.get_file_lines(file_id),  | 
| 
2012.1.12
by Aaron Bentley
 Use iter_changes for revert  | 
1283  | 
trans_id)  | 
| 
2012.1.15
by Aaron Bentley
 Minor tweaks  | 
1284  | 
if executable[0] != executable[1]:  | 
1285  | 
tt.set_executability(executable[1], trans_id)  | 
|
| 
2012.1.12
by Aaron Bentley
 Use iter_changes for revert  | 
1286  | 
else:  | 
1287  | 
assert kind[1] is None  | 
|
1288  | 
if versioned == (False, True):  | 
|
1289  | 
tt.version_file(file_id, trans_id)  | 
|
1290  | 
if versioned == (True, False):  | 
|
1291  | 
tt.unversion_file(trans_id)  | 
|
1292  | 
if (name[1] is not None and  | 
|
1293  | 
(name[0] != name[1] or parent[0] != parent[1])):  | 
|
1294  | 
tt.adjust_path(name[1], tt.trans_id_file_id(parent[1]), trans_id)  | 
|
1295  | 
||
1296  | 
||
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1297  | 
def resolve_conflicts(tt, pb=DummyProgress(), pass_func=None):  | 
| 
1534.7.57
by Aaron Bentley
 Enhanced conflict resolution.  | 
1298  | 
"""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  | 
1299  | 
if pass_func is None:  | 
1300  | 
pass_func = conflict_pass  | 
|
| 
1534.7.169
by Aaron Bentley
 Add filesystem/inventory conflicts to conflict output  | 
1301  | 
new_conflicts = set()  | 
| 
1534.9.1
by Aaron Bentley
 Added progress bars to merge  | 
1302  | 
try:  | 
1303  | 
for n in range(10):  | 
|
1304  | 
pb.update('Resolution pass', n+1, 10)  | 
|
1305  | 
conflicts = tt.find_conflicts()  | 
|
1306  | 
if len(conflicts) == 0:  | 
|
1307  | 
return new_conflicts  | 
|
| 
1966.1.1
by Aaron Bentley
 Implement disk-content merge and conflict resolution for build_tree  | 
1308  | 
new_conflicts.update(pass_func(tt, conflicts))  | 
| 
1534.9.1
by Aaron Bentley
 Added progress bars to merge  | 
1309  | 
raise MalformedTransform(conflicts=conflicts)  | 
1310  | 
finally:  | 
|
1311  | 
pb.clear()  | 
|
| 
1534.7.57
by Aaron Bentley
 Enhanced conflict resolution.  | 
1312  | 
|
1313  | 
||
1314  | 
def conflict_pass(tt, conflicts):  | 
|
| 
1534.7.157
by Aaron Bentley
 Added more docs  | 
1315  | 
"""Resolve some classes of conflicts."""  | 
| 
1534.7.169
by Aaron Bentley
 Add filesystem/inventory conflicts to conflict output  | 
1316  | 
new_conflicts = set()  | 
| 
1534.7.61
by Aaron Bentley
 Handled parent loops, missing parents, unversioned parents  | 
1317  | 
for c_type, conflict in ((c[0], c) for c in conflicts):  | 
1318  | 
if c_type == 'duplicate id':  | 
|
| 
1534.7.51
by Aaron Bentley
 New approach to revert  | 
1319  | 
tt.unversion_file(conflict[1])  | 
| 
1534.7.170
by Aaron Bentley
 Cleaned up filesystem conflict handling  | 
1320  | 
new_conflicts.add((c_type, 'Unversioned existing file',  | 
1321  | 
conflict[1], conflict[2], ))  | 
|
| 
1534.7.61
by Aaron Bentley
 Handled parent loops, missing parents, unversioned parents  | 
1322  | 
elif c_type == 'duplicate':  | 
| 
1534.7.57
by Aaron Bentley
 Enhanced conflict resolution.  | 
1323  | 
            # files that were renamed take precedence
 | 
1324  | 
new_name = tt.final_name(conflict[1])+'.moved'  | 
|
1325  | 
final_parent = tt.final_parent(conflict[1])  | 
|
1326  | 
if tt.path_changed(conflict[1]):  | 
|
1327  | 
tt.adjust_path(new_name, final_parent, conflict[2])  | 
|
| 
1534.7.171
by Aaron Bentley
 Implemented stringifying filesystem conflicts  | 
1328  | 
new_conflicts.add((c_type, 'Moved existing file to',  | 
1329  | 
conflict[2], conflict[1]))  | 
|
| 
1534.7.57
by Aaron Bentley
 Enhanced conflict resolution.  | 
1330  | 
else:  | 
1331  | 
tt.adjust_path(new_name, final_parent, conflict[1])  | 
|
| 
1534.7.171
by Aaron Bentley
 Implemented stringifying filesystem conflicts  | 
1332  | 
new_conflicts.add((c_type, 'Moved existing file to',  | 
1333  | 
conflict[1], conflict[2]))  | 
|
| 
1534.7.61
by Aaron Bentley
 Handled parent loops, missing parents, unversioned parents  | 
1334  | 
elif c_type == 'parent loop':  | 
1335  | 
            # break the loop by undoing one of the ops that caused the loop
 | 
|
1336  | 
cur = conflict[1]  | 
|
1337  | 
while not tt.path_changed(cur):  | 
|
1338  | 
cur = tt.final_parent(cur)  | 
|
| 
1534.7.170
by Aaron Bentley
 Cleaned up filesystem conflict handling  | 
1339  | 
new_conflicts.add((c_type, 'Cancelled move', cur,  | 
1340  | 
tt.final_parent(cur),))  | 
|
| 
1534.7.61
by Aaron Bentley
 Handled parent loops, missing parents, unversioned parents  | 
1341  | 
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  | 
1342  | 
|
| 
1534.7.61
by Aaron Bentley
 Handled parent loops, missing parents, unversioned parents  | 
1343  | 
elif c_type == 'missing parent':  | 
| 
1534.7.128
by Aaron Bentley
 Got missing contents test working  | 
1344  | 
trans_id = conflict[1]  | 
1345  | 
try:  | 
|
1346  | 
tt.cancel_deletion(trans_id)  | 
|
| 
1551.8.22
by Aaron Bentley
 Improve message when OTHER deletes an in-use tree  | 
1347  | 
new_conflicts.add(('deleting parent', 'Not deleting',  | 
1348  | 
trans_id))  | 
|
| 
1534.7.128
by Aaron Bentley
 Got missing contents test working  | 
1349  | 
except KeyError:  | 
1350  | 
tt.create_directory(trans_id)  | 
|
| 
1551.8.22
by Aaron Bentley
 Improve message when OTHER deletes an in-use tree  | 
1351  | 
new_conflicts.add((c_type, 'Created directory', trans_id))  | 
| 
1534.7.61
by Aaron Bentley
 Handled parent loops, missing parents, unversioned parents  | 
1352  | 
elif c_type == 'unversioned parent':  | 
| 
1534.7.148
by Aaron Bentley
 Handled the remaining file versioning case  | 
1353  | 
tt.version_file(tt.inactive_file_id(conflict[1]), conflict[1])  | 
| 
1534.7.171
by Aaron Bentley
 Implemented stringifying filesystem conflicts  | 
1354  | 
new_conflicts.add((c_type, 'Versioned directory', conflict[1]))  | 
| 
1534.7.169
by Aaron Bentley
 Add filesystem/inventory conflicts to conflict output  | 
1355  | 
return new_conflicts  | 
1356  | 
||
| 
1666.1.4
by Robert Collins
 * 'Metadir' is now the default disk format. This improves behaviour in  | 
1357  | 
|
| 
1534.7.169
by Aaron Bentley
 Add filesystem/inventory conflicts to conflict output  | 
1358  | 
def cook_conflicts(raw_conflicts, tt):  | 
| 
1534.7.170
by Aaron Bentley
 Cleaned up filesystem conflict handling  | 
1359  | 
"""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  | 
1360  | 
from bzrlib.conflicts import Conflict  | 
1361  | 
conflict_iter = iter_cook_conflicts(raw_conflicts, tt)  | 
|
1362  | 
return sorted(conflict_iter, key=Conflict.sort_key)  | 
|
| 
1534.7.170
by Aaron Bentley
 Cleaned up filesystem conflict handling  | 
1363  | 
|
| 
1534.7.169
by Aaron Bentley
 Add filesystem/inventory conflicts to conflict output  | 
1364  | 
|
1365  | 
def iter_cook_conflicts(raw_conflicts, tt):  | 
|
| 
1534.10.19
by Aaron Bentley
 Stanza conversion, cooking  | 
1366  | 
from bzrlib.conflicts import Conflict  | 
| 
1534.7.170
by Aaron Bentley
 Cleaned up filesystem conflict handling  | 
1367  | 
fp = FinalPaths(tt)  | 
| 
1534.7.169
by Aaron Bentley
 Add filesystem/inventory conflicts to conflict output  | 
1368  | 
for conflict in raw_conflicts:  | 
1369  | 
c_type = conflict[0]  | 
|
| 
1534.7.170
by Aaron Bentley
 Cleaned up filesystem conflict handling  | 
1370  | 
action = conflict[1]  | 
1371  | 
modified_path = fp.get_path(conflict[2])  | 
|
1372  | 
modified_id = tt.final_file_id(conflict[2])  | 
|
1373  | 
if len(conflict) == 3:  | 
|
| 
1534.10.19
by Aaron Bentley
 Stanza conversion, cooking  | 
1374  | 
yield Conflict.factory(c_type, action=action, path=modified_path,  | 
1375  | 
file_id=modified_id)  | 
|
1376  | 
||
| 
1534.7.170
by Aaron Bentley
 Cleaned up filesystem conflict handling  | 
1377  | 
else:  | 
1378  | 
conflicting_path = fp.get_path(conflict[3])  | 
|
1379  | 
conflicting_id = tt.final_file_id(conflict[3])  | 
|
| 
1534.10.19
by Aaron Bentley
 Stanza conversion, cooking  | 
1380  | 
yield Conflict.factory(c_type, action=action, path=modified_path,  | 
1381  | 
file_id=modified_id,  | 
|
1382  | 
conflict_path=conflicting_path,  | 
|
1383  | 
conflict_file_id=conflicting_id)  |