/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
5557.1.7 by John Arbash Meinel
Merge in the bzr.dev 5582
1
# Copyright (C) 2006-2011 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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1534.7.106 by Aaron Bentley
Cleaned up imports, added copyright statements
16
7479.2.1 by Jelmer Vernooij
Drop python2 support.
17
import contextlib
1534.7.1 by Aaron Bentley
Got creation of a versioned file working
18
import os
1534.7.106 by Aaron Bentley
Cleaned up imports, added copyright statements
19
import errno
3363.2.27 by Aaron Bentley
Make path_content_summary a core API
20
from stat import S_ISREG, S_IEXEC
4934.1.1 by John Arbash Meinel
Basic implementation for windows and bug #488724.
21
import time
1534.7.106 by Aaron Bentley
Cleaned up imports, added copyright statements
22
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
23
from . import (
6449.6.5 by Jelmer Vernooij
Merge bzr.transform.orphan_policy move to config stacks.
24
    config as _mod_config,
7490.83.1 by Jelmer Vernooij
Add abstract methods.
25
    controldir,
5409.1.7 by Vincent Ladeuil
First orphaning implementation (some tests lacking).
26
    errors,
27
    lazy_import,
7490.85.2 by Jelmer Vernooij
Split PreviewTree.
28
    lock,
7490.83.1 by Jelmer Vernooij
Add abstract methods.
29
    osutils,
5409.1.14 by Vincent Ladeuil
Prepare for more ways to handle orphans.
30
    registry,
5753.2.3 by Jelmer Vernooij
Fix transform tests.
31
    trace,
5409.1.7 by Vincent Ladeuil
First orphaning implementation (some tests lacking).
32
    )
33
lazy_import.lazy_import(globals(), """
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
34
from breezy import (
5988.2.1 by Vincent Ladeuil
Do not generate path conflicts if a corresponding content conflict exists
35
    conflicts,
0.13.8 by Aaron Bentley
Integrate serialization into TreeTransforms
36
    multiparent,
3363.2.4 by Aaron Bentley
Get significant portions of PreviewTree implemented and passing tests
37
    revision as _mod_revision,
4961.2.9 by Martin Pool
Rip out most remaining uses of DummyProgressBar
38
    ui,
5582.10.4 by Jelmer Vernooij
Fix a bunch of tests.
39
    urlutils,
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
40
    )
7490.83.1 by Jelmer Vernooij
Add abstract methods.
41
from breezy.i18n import gettext
7490.83.5 by Jelmer Vernooij
Fix import tariff test.
42
""")
7490.83.1 by Jelmer Vernooij
Add abstract methods.
43
7490.69.1 by Jelmer Vernooij
Move some more tests to breezy.bzr.
44
from .errors import (DuplicateKey,
45
                     BzrError, InternalBzrError)
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
46
from .filters import filtered_output_bytes, ContentFilterContext
47
from .mutabletree import MutableTree
48
from .osutils import (
3363.2.19 by Aaron Bentley
Make PreviewTree.path2id correct
49
    delete_any,
50
    file_kind,
51
    pathjoin,
3363.15.4 by Aaron Bentley
Implement PreviewTree.get_file_sha1 properly
52
    sha_file,
3363.2.19 by Aaron Bentley
Make PreviewTree.path2id correct
53
    splitpath,
7122.6.3 by Jelmer Vernooij
Merge trunk.
54
    supports_symlinks,
5579.3.1 by Jelmer Vernooij
Remove unused imports.
55
    )
6624 by Jelmer Vernooij
Merge Python3 porting work ('py3 pokes')
56
from .progress import ProgressPhase
6883.5.3 by Jelmer Vernooij
Add find_previous_path.
57
from .tree import (
7357.1.8 by Jelmer Vernooij
Remove the InterTree object.
58
    InterTree,
7322.1.6 by Jelmer Vernooij
Use the new attributes on TreeChange.
59
    TreeChange,
7490.83.7 by Jelmer Vernooij
Key by path rather than by file id.
60
    find_previous_path,
6883.5.3 by Jelmer Vernooij
Add find_previous_path.
61
    )
1534.7.31 by Aaron Bentley
Changed tree root parent to ROOT_PARENT
62
1534.7.167 by Aaron Bentley
PEP8 and comment cleanups
63
1534.7.31 by Aaron Bentley
Changed tree root parent to ROOT_PARENT
64
ROOT_PARENT = "root-parent"
65
7143.15.2 by Jelmer Vernooij
Run autopep8.
66
7490.69.1 by Jelmer Vernooij
Move some more tests to breezy.bzr.
67
class NoFinalPath(BzrError):
68
69
    _fmt = ("No final name for trans_id %(trans_id)r\n"
70
            "file-id: %(file_id)r\n"
71
            "root trans-id: %(root_trans_id)r\n")
72
73
    def __init__(self, trans_id, transform):
74
        self.trans_id = trans_id
75
        self.file_id = transform.final_file_id(trans_id)
76
        self.root_trans_id = transform.root
77
78
79
class ReusingTransform(BzrError):
80
81
    _fmt = "Attempt to reuse a transform that has already been applied."
82
83
84
class MalformedTransform(InternalBzrError):
85
86
    _fmt = "Tree transform is malformed %(conflicts)r"
87
88
7490.77.4 by Jelmer Vernooij
Move some errors around.
89
class CantMoveRoot(BzrError):
90
91
    _fmt = "Moving the root directory is not supported at this time"
92
93
7490.69.1 by Jelmer Vernooij
Move some more tests to breezy.bzr.
94
class ImmortalLimbo(BzrError):
95
96
    _fmt = """Unable to delete transform temporary directory %(limbo_dir)s.
97
    Please examine %(limbo_dir)s to see if it contains any files you wish to
98
    keep, and delete it when you are done."""
99
100
    def __init__(self, limbo_dir):
101
        BzrError.__init__(self)
102
        self.limbo_dir = limbo_dir
103
104
7490.77.4 by Jelmer Vernooij
Move some errors around.
105
class TransformRenameFailed(BzrError):
106
107
    _fmt = "Failed to rename %(from_path)s to %(to_path)s: %(why)s"
108
109
    def __init__(self, from_path, to_path, why, errno):
110
        self.from_path = from_path
111
        self.to_path = to_path
112
        self.why = why
113
        self.errno = errno
114
115
1534.7.1 by Aaron Bentley
Got creation of a versioned file working
116
def unique_add(map, key, value):
117
    if key in map:
1534.7.5 by Aaron Bentley
Got unique_add under test
118
        raise DuplicateKey(key=key)
1534.7.1 by Aaron Bentley
Got creation of a versioned file working
119
    map[key] = value
120
1534.7.167 by Aaron Bentley
PEP8 and comment cleanups
121
1534.7.191 by Aaron Bentley
Got transform.apply to list modified paths
122
class _TransformResults(object):
7490.77.14 by Jelmer Vernooij
Split transform.
123
2502.1.5 by Aaron Bentley
Cleanup
124
    def __init__(self, modified_paths, rename_count):
1534.7.191 by Aaron Bentley
Got transform.apply to list modified paths
125
        object.__init__(self)
126
        self.modified_paths = modified_paths
2502.1.5 by Aaron Bentley
Cleanup
127
        self.rename_count = rename_count
1534.7.191 by Aaron Bentley
Got transform.apply to list modified paths
128
129
7490.77.17 by Jelmer Vernooij
Rationalize TreeTransform class hierarchy.
130
class TreeTransform(object):
131
    """Represent a tree transformation.
132
133
    This object is designed to support incremental generation of the transform,
134
    in any order.
135
136
    However, it gives optimum performance when parent directories are created
137
    before their contents.  The transform is then able to put child files
138
    directly in their parent directory, avoiding later renames.
139
140
    It is easy to produce malformed transforms, but they are generally
141
    harmless.  Attempting to apply a malformed transform will cause an
142
    exception to be raised before any modifications are made to the tree.
143
144
    Many kinds of malformed transforms can be corrected with the
145
    resolve_conflicts function.  The remaining ones indicate programming error,
146
    such as trying to create a file with no path.
147
148
    Two sets of file creation methods are supplied.  Convenience methods are:
149
     * new_file
150
     * new_directory
151
     * new_symlink
152
153
    These are composed of the low-level methods:
154
     * create_path
155
     * create_file or create_directory or create_symlink
156
     * version_file
157
     * set_executability
158
159
    Transform/Transaction ids
160
    -------------------------
161
    trans_ids are temporary ids assigned to all files involved in a transform.
162
    It's possible, even common, that not all files in the Tree have trans_ids.
163
164
    trans_ids are only valid for the TreeTransform that generated them.
165
    """
7490.77.14 by Jelmer Vernooij
Split transform.
166
167
    def __init__(self, tree, pb=None):
168
        self._tree = tree
7490.77.15 by Jelmer Vernooij
Factor out non-version things.
169
        # A progress bar
170
        self._pb = pb
7490.77.14 by Jelmer Vernooij
Split transform.
171
        self._id_number = 0
172
        # Mapping of path in old tree -> trans_id
173
        self._tree_path_ids = {}
174
        # Mapping trans_id -> path in old tree
175
        self._tree_id_paths = {}
7490.77.15 by Jelmer Vernooij
Factor out non-version things.
176
        # mapping of trans_id -> new basename
177
        self._new_name = {}
178
        # mapping of trans_id -> new parent trans_id
179
        self._new_parent = {}
180
        # mapping of trans_id with new contents -> new file_kind
181
        self._new_contents = {}
182
        # Set of trans_ids whose contents will be removed
183
        self._removed_contents = set()
184
        # Mapping of trans_id -> new execute-bit value
185
        self._new_executability = {}
186
        # Mapping of trans_id -> new tree-reference value
187
        self._new_reference_revision = {}
188
        # Set of trans_ids that will be removed
189
        self._removed_id = set()
190
        # Indicator of whether the transform has been applied
191
        self._done = False
7490.77.14 by Jelmer Vernooij
Split transform.
192
193
    def __enter__(self):
194
        """Support Context Manager API."""
7490.77.15 by Jelmer Vernooij
Factor out non-version things.
195
        return self
7490.77.14 by Jelmer Vernooij
Split transform.
196
197
    def __exit__(self, exc_type, exc_val, exc_tb):
198
        """Support Context Manager API."""
7490.77.15 by Jelmer Vernooij
Factor out non-version things.
199
        self.finalize()
7490.77.14 by Jelmer Vernooij
Split transform.
200
201
    def iter_tree_children(self, trans_id):
202
        """Iterate through the entry's tree children, if any.
203
204
        :param trans_id: trans id to iterate
205
        :returns: Iterator over paths
206
        """
207
        raise NotImplementedError(self.iter_tree_children)
208
209
    def canonical_path(self, path):
210
        return path
211
212
    def tree_kind(self, trans_id):
213
        raise NotImplementedError(self.tree_kind)
214
7490.77.16 by Jelmer Vernooij
Move more generic code.
215
    def by_parent(self):
216
        """Return a map of parent: children for known parents.
217
218
        Only new paths and parents of tree files with assigned ids are used.
219
        """
220
        by_parent = {}
7518.1.2 by Jelmer Vernooij
Fix imports of sixish.
221
        items = list(self._new_parent.items())
7490.77.16 by Jelmer Vernooij
Move more generic code.
222
        items.extend((t, self.final_parent(t))
223
                     for t in list(self._tree_id_paths))
224
        for trans_id, parent_id in items:
225
            if parent_id not in by_parent:
226
                by_parent[parent_id] = set()
227
            by_parent[parent_id].add(trans_id)
228
        return by_parent
229
7490.77.14 by Jelmer Vernooij
Split transform.
230
    def finalize(self):
231
        """Release the working tree lock, if held.
232
233
        This is required if apply has not been invoked, but can be invoked
234
        even after apply.
235
        """
236
        raise NotImplementedError(self.finalize)
237
238
    def create_path(self, name, parent):
239
        """Assign a transaction id to a new path"""
7490.77.16 by Jelmer Vernooij
Move more generic code.
240
        trans_id = self._assign_id()
241
        unique_add(self._new_name, trans_id, name)
242
        unique_add(self._new_parent, trans_id, parent)
243
        return trans_id
7490.77.14 by Jelmer Vernooij
Split transform.
244
245
    def adjust_path(self, name, parent, trans_id):
246
        """Change the path that is assigned to a transaction id."""
7490.77.15 by Jelmer Vernooij
Factor out non-version things.
247
        if parent is None:
248
            raise ValueError("Parent trans-id may not be None")
249
        if trans_id == self._new_root:
250
            raise CantMoveRoot
251
        self._new_name[trans_id] = name
252
        self._new_parent[trans_id] = parent
7490.77.14 by Jelmer Vernooij
Split transform.
253
254
    def adjust_root_path(self, name, parent):
255
        """Emulate moving the root by moving all children, instead.
256
257
        We do this by undoing the association of root's transaction id with the
258
        current tree.  This allows us to create a new directory with that
259
        transaction id.  We unversion the root directory and version the
260
        physically new directory, and hope someone versions the tree root
261
        later.
262
        """
263
        raise NotImplementedError(self.adjust_root_path)
264
265
    def fixup_new_roots(self):
266
        """Reinterpret requests to change the root directory
267
268
        Instead of creating a root directory, or moving an existing directory,
269
        all the attributes and children of the new root are applied to the
270
        existing root directory.
271
272
        This means that the old root trans-id becomes obsolete, so it is
273
        recommended only to invoke this after the root trans-id has become
274
        irrelevant.
275
        """
276
        raise NotImplementedError(self.fixup_new_roots)
277
278
    def _assign_id(self):
279
        """Produce a new tranform id"""
280
        new_id = "new-%s" % self._id_number
281
        self._id_number += 1
282
        return new_id
283
284
    def trans_id_tree_path(self, path):
285
        """Determine (and maybe set) the transaction ID for a tree path."""
286
        path = self.canonical_path(path)
287
        if path not in self._tree_path_ids:
288
            self._tree_path_ids[path] = self._assign_id()
289
            self._tree_id_paths[self._tree_path_ids[path]] = path
290
        return self._tree_path_ids[path]
291
292
    def get_tree_parent(self, trans_id):
293
        """Determine id of the parent in the tree."""
294
        path = self._tree_id_paths[trans_id]
295
        if path == "":
296
            return ROOT_PARENT
297
        return self.trans_id_tree_path(os.path.dirname(path))
298
299
    def delete_contents(self, trans_id):
300
        """Schedule the contents of a path entry for deletion"""
7490.77.15 by Jelmer Vernooij
Factor out non-version things.
301
        kind = self.tree_kind(trans_id)
302
        if kind is not None:
303
            self._removed_contents.add(trans_id)
7490.77.14 by Jelmer Vernooij
Split transform.
304
305
    def cancel_deletion(self, trans_id):
306
        """Cancel a scheduled deletion"""
7490.77.15 by Jelmer Vernooij
Factor out non-version things.
307
        self._removed_contents.remove(trans_id)
7490.77.14 by Jelmer Vernooij
Split transform.
308
309
    def delete_versioned(self, trans_id):
310
        """Delete and unversion a versioned file"""
7490.77.15 by Jelmer Vernooij
Factor out non-version things.
311
        self.delete_contents(trans_id)
312
        self.unversion_file(trans_id)
7490.77.14 by Jelmer Vernooij
Split transform.
313
314
    def set_executability(self, executability, trans_id):
315
        """Schedule setting of the 'execute' bit
316
        To unschedule, set to None
317
        """
7490.77.15 by Jelmer Vernooij
Factor out non-version things.
318
        if executability is None:
319
            del self._new_executability[trans_id]
320
        else:
321
            unique_add(self._new_executability, trans_id, executability)
7490.77.14 by Jelmer Vernooij
Split transform.
322
323
    def set_tree_reference(self, revision_id, trans_id):
324
        """Set the reference associated with a directory"""
7490.77.15 by Jelmer Vernooij
Factor out non-version things.
325
        unique_add(self._new_reference_revision, trans_id, revision_id)
7490.77.14 by Jelmer Vernooij
Split transform.
326
327
    def version_file(self, trans_id, file_id=None):
328
        """Schedule a file to become versioned."""
329
        raise NotImplementedError(self.version_file)
330
331
    def cancel_versioning(self, trans_id):
332
        """Undo a previous versioning of a file"""
333
        raise NotImplementedError(self.cancel_versioning)
334
7490.77.15 by Jelmer Vernooij
Factor out non-version things.
335
    def unversion_file(self, trans_id):
336
        """Schedule a path entry to become unversioned"""
337
        self._removed_id.add(trans_id)
338
7490.77.14 by Jelmer Vernooij
Split transform.
339
    def new_paths(self, filesystem_only=False):
340
        """Determine the paths of all new and changed files.
341
342
        :param filesystem_only: if True, only calculate values for files
343
            that require renames or execute bit changes.
344
        """
345
        raise NotImplementedError(self.new_paths)
346
347
    def final_kind(self, trans_id):
348
        """Determine the final file kind, after any changes applied.
349
350
        :return: None if the file does not exist/has no contents.  (It is
351
            conceivable that a path would be created without the corresponding
352
            contents insertion command)
353
        """
7490.77.15 by Jelmer Vernooij
Factor out non-version things.
354
        if trans_id in self._new_contents:
355
            return self._new_contents[trans_id]
356
        elif trans_id in self._removed_contents:
357
            return None
358
        else:
359
            return self.tree_kind(trans_id)
7490.77.14 by Jelmer Vernooij
Split transform.
360
361
    def tree_path(self, trans_id):
362
        """Determine the tree path associated with the trans_id."""
7490.77.15 by Jelmer Vernooij
Factor out non-version things.
363
        return self._tree_id_paths.get(trans_id)
7490.77.14 by Jelmer Vernooij
Split transform.
364
365
    def final_is_versioned(self, trans_id):
366
        raise NotImplementedError(self.final_is_versioned)
367
368
    def final_parent(self, trans_id):
369
        """Determine the parent file_id, after any changes are applied.
370
371
        ROOT_PARENT is returned for the tree root.
372
        """
7490.77.15 by Jelmer Vernooij
Factor out non-version things.
373
        try:
374
            return self._new_parent[trans_id]
375
        except KeyError:
376
            return self.get_tree_parent(trans_id)
7490.77.14 by Jelmer Vernooij
Split transform.
377
378
    def final_name(self, trans_id):
379
        """Determine the final filename, after all changes are applied."""
7490.77.15 by Jelmer Vernooij
Factor out non-version things.
380
        try:
381
            return self._new_name[trans_id]
382
        except KeyError:
383
            try:
384
                return os.path.basename(self._tree_id_paths[trans_id])
385
            except KeyError:
386
                raise NoFinalPath(trans_id, self)
7490.77.14 by Jelmer Vernooij
Split transform.
387
388
    def path_changed(self, trans_id):
389
        """Return True if a trans_id's path has changed."""
7490.77.15 by Jelmer Vernooij
Factor out non-version things.
390
        return (trans_id in self._new_name) or (trans_id in self._new_parent)
7490.77.14 by Jelmer Vernooij
Split transform.
391
392
    def new_contents(self, trans_id):
7490.77.15 by Jelmer Vernooij
Factor out non-version things.
393
        return (trans_id in self._new_contents)
7490.77.14 by Jelmer Vernooij
Split transform.
394
395
    def find_conflicts(self):
396
        """Find any violations of inventory or filesystem invariants"""
397
        raise NotImplementedError(self.find_conflicts)
398
399
    def new_file(self, name, parent_id, contents, file_id=None,
400
                 executable=None, sha1=None):
401
        """Convenience method to create files.
402
403
        name is the name of the file to create.
404
        parent_id is the transaction id of the parent directory of the file.
405
        contents is an iterator of bytestrings, which will be used to produce
406
        the file.
407
        :param file_id: The inventory ID of the file, if it is to be versioned.
408
        :param executable: Only valid when a file_id has been supplied.
409
        """
410
        raise NotImplementedError(self.new_file)
411
412
    def new_directory(self, name, parent_id, file_id=None):
413
        """Convenience method to create directories.
414
415
        name is the name of the directory to create.
416
        parent_id is the transaction id of the parent directory of the
417
        directory.
418
        file_id is the inventory ID of the directory, if it is to be versioned.
419
        """
420
        raise NotImplementedError(self.new_directory)
421
422
    def new_symlink(self, name, parent_id, target, file_id=None):
423
        """Convenience method to create symbolic link.
424
425
        name is the name of the symlink to create.
426
        parent_id is the transaction id of the parent directory of the symlink.
427
        target is a bytestring of the target of the symlink.
428
        file_id is the inventory ID of the file, if it is to be versioned.
429
        """
430
        raise NotImplementedError(self.new_symlink)
431
432
    def new_orphan(self, trans_id, parent_id):
433
        """Schedule an item to be orphaned.
434
435
        When a directory is about to be removed, its children, if they are not
436
        versioned are moved out of the way: they don't have a parent anymore.
437
438
        :param trans_id: The trans_id of the existing item.
439
        :param parent_id: The parent trans_id of the item.
440
        """
441
        raise NotImplementedError(self.new_orphan)
442
443
    def iter_changes(self):
444
        """Produce output in the same format as Tree.iter_changes.
445
446
        Will produce nonsensical results if invoked while inventory/filesystem
447
        conflicts (as reported by TreeTransform.find_conflicts()) are present.
448
449
        This reads the Transform, but only reproduces changes involving a
450
        file_id.  Files that are not versioned in either of the FROM or TO
451
        states are not reflected.
452
        """
453
        raise NotImplementedError(self.iter_changes)
454
455
    def get_preview_tree(self):
456
        """Return a tree representing the result of the transform.
457
458
        The tree is a snapshot, and altering the TreeTransform will invalidate
459
        it.
460
        """
461
        raise NotImplementedError(self.get_preview_tree)
462
463
    def commit(self, branch, message, merge_parents=None, strict=False,
464
               timestamp=None, timezone=None, committer=None, authors=None,
465
               revprops=None, revision_id=None):
466
        """Commit the result of this TreeTransform to a branch.
467
468
        :param branch: The branch to commit to.
469
        :param message: The message to attach to the commit.
470
        :param merge_parents: Additional parent revision-ids specified by
471
            pending merges.
472
        :param strict: If True, abort the commit if there are unversioned
473
            files.
474
        :param timestamp: if not None, seconds-since-epoch for the time and
475
            date.  (May be a float.)
476
        :param timezone: Optional timezone for timestamp, as an offset in
477
            seconds.
478
        :param committer: Optional committer in email-id format.
479
            (e.g. "J Random Hacker <jrandom@example.com>")
480
        :param authors: Optional list of authors in email-id format.
481
        :param revprops: Optional dictionary of revision properties.
482
        :param revision_id: Optional revision id.  (Specifying a revision-id
483
            may reduce performance for some non-native formats.)
484
        :return: The revision_id of the revision committed.
485
        """
486
        raise NotImplementedError(self.commit)
487
488
    def create_file(self, contents, trans_id, mode_id=None, sha1=None):
489
        """Schedule creation of a new file.
490
491
        :seealso: new_file.
492
493
        :param contents: an iterator of strings, all of which will be written
494
            to the target destination.
495
        :param trans_id: TreeTransform handle
496
        :param mode_id: If not None, force the mode of the target file to match
497
            the mode of the object referenced by mode_id.
498
            Otherwise, we will try to preserve mode bits of an existing file.
499
        :param sha1: If the sha1 of this content is already known, pass it in.
500
            We can use it to prevent future sha1 computations.
501
        """
502
        raise NotImplementedError(self.create_file)
503
504
    def create_directory(self, trans_id):
505
        """Schedule creation of a new directory.
506
507
        See also new_directory.
508
        """
509
        raise NotImplementedError(self.create_directory)
510
511
    def create_symlink(self, target, trans_id):
512
        """Schedule creation of a new symbolic link.
513
514
        target is a bytestring.
515
        See also new_symlink.
516
        """
517
        raise NotImplementedError(self.create_symlink)
518
519
    def create_hardlink(self, path, trans_id):
520
        """Schedule creation of a hard link"""
521
        raise NotImplementedError(self.create_hardlink)
522
523
    def cancel_creation(self, trans_id):
524
        """Cancel the creation of new file contents."""
525
        raise NotImplementedError(self.cancel_creation)
526
527
5409.1.16 by Vincent Ladeuil
Add ``bzrlib.transform.orphan_policy`` and allows ``never`` to restore the previous behaviour.
528
class OrphaningError(errors.BzrError):
529
530
    # Only bugs could lead to such exception being seen by the user
531
    internal_error = True
532
    _fmt = "Error while orphaning %s in %s directory"
533
534
    def __init__(self, orphan, parent):
535
        errors.BzrError.__init__(self)
536
        self.orphan = orphan
537
        self.parent = parent
538
539
540
class OrphaningForbidden(OrphaningError):
541
542
    _fmt = "Policy: %s doesn't allow creating orphans."
543
544
    def __init__(self, policy):
545
        errors.BzrError.__init__(self)
546
        self.policy = policy
5409.1.14 by Vincent Ladeuil
Prepare for more ways to handle orphans.
547
548
549
def move_orphan(tt, orphan_id, parent_id):
550
    """See TreeTransformBase.new_orphan.
551
6681.2.4 by Jelmer Vernooij
More renames.
552
    This creates a new orphan in the `brz-orphans` dir at the root of the
5409.1.14 by Vincent Ladeuil
Prepare for more ways to handle orphans.
553
    `TreeTransform`.
554
555
    :param tt: The TreeTransform orphaning `trans_id`.
556
557
    :param orphan_id: The trans id that should be orphaned.
558
559
    :param parent_id: The orphan parent trans id.
560
    """
561
    # Add the orphan dir if it doesn't exist
6681.2.4 by Jelmer Vernooij
More renames.
562
    orphan_dir_basename = 'brz-orphans'
5409.1.16 by Vincent Ladeuil
Add ``bzrlib.transform.orphan_policy`` and allows ``never`` to restore the previous behaviour.
563
    od_id = tt.trans_id_tree_path(orphan_dir_basename)
5409.1.14 by Vincent Ladeuil
Prepare for more ways to handle orphans.
564
    if tt.final_kind(od_id) is None:
565
        tt.create_directory(od_id)
566
    parent_path = tt._tree_id_paths[parent_id]
567
    # Find a name that doesn't exist yet in the orphan dir
568
    actual_name = tt.final_name(orphan_id)
569
    new_name = tt._available_backup_name(actual_name, od_id)
570
    tt.adjust_path(new_name, od_id, orphan_id)
5753.2.3 by Jelmer Vernooij
Fix transform tests.
571
    trace.warning('%s has been orphaned in %s'
5409.1.16 by Vincent Ladeuil
Add ``bzrlib.transform.orphan_policy`` and allows ``never`` to restore the previous behaviour.
572
                  % (joinpath(parent_path, actual_name), orphan_dir_basename))
573
574
575
def refuse_orphan(tt, orphan_id, parent_id):
576
    """See TreeTransformBase.new_orphan.
577
5409.1.23 by Vincent Ladeuil
Add more doc and fix rst typos
578
    This refuses to create orphan, letting the caller handle the conflict.
5409.1.16 by Vincent Ladeuil
Add ``bzrlib.transform.orphan_policy`` and allows ``never`` to restore the previous behaviour.
579
    """
580
    raise OrphaningForbidden('never')
5409.1.14 by Vincent Ladeuil
Prepare for more ways to handle orphans.
581
582
583
orphaning_registry = registry.Registry()
5409.1.25 by Vincent Ladeuil
Better docs.
584
orphaning_registry.register(
6973.11.9 by Jelmer Vernooij
Fix tests.
585
    u'conflict', refuse_orphan,
5409.1.25 by Vincent Ladeuil
Better docs.
586
    'Leave orphans in place and create a conflict on the directory.')
587
orphaning_registry.register(
6973.11.9 by Jelmer Vernooij
Fix tests.
588
    u'move', move_orphan,
6681.2.4 by Jelmer Vernooij
More renames.
589
    'Move orphans into the brz-orphans directory.')
6973.11.9 by Jelmer Vernooij
Fix tests.
590
orphaning_registry._set_default_key(u'conflict')
5409.1.7 by Vincent Ladeuil
First orphaning implementation (some tests lacking).
591
4354.5.1 by Aaron Bentley
Split out a DiskTreeTransform class that manages Limbo.
592
6449.6.5 by Jelmer Vernooij
Merge bzr.transform.orphan_policy move to config stacks.
593
opt_transform_orphan = _mod_config.RegistryOption(
6883.13.1 by Jelmer Vernooij
Rename bzr.transform.orphan_policy -> transform.orphan_policy.
594
    'transform.orphan_policy', orphaning_registry,
6449.6.5 by Jelmer Vernooij
Merge bzr.transform.orphan_policy move to config stacks.
595
    help='Policy for orphaned files during transform operations.',
596
    invalid='warning')
597
598
1534.7.32 by Aaron Bentley
Got conflict handling working when conflicts involve existing files
599
def joinpath(parent, child):
1534.7.40 by Aaron Bentley
Updated docs
600
    """Join tree-relative paths, handling the tree root specially"""
1534.7.32 by Aaron Bentley
Got conflict handling working when conflicts involve existing files
601
    if parent is None or parent == "":
602
        return child
603
    else:
1534.7.166 by Aaron Bentley
Swapped os.path.join for pathjoin everywhere
604
        return pathjoin(parent, child)
1534.7.1 by Aaron Bentley
Got creation of a versioned file working
605
1534.7.167 by Aaron Bentley
PEP8 and comment cleanups
606
1534.7.1 by Aaron Bentley
Got creation of a versioned file working
607
class FinalPaths(object):
1759.2.2 by Jelmer Vernooij
Revert some of my spelling fixes and fix some typos after review by Aaron.
608
    """Make path calculation cheap by memoizing paths.
1534.7.21 by Aaron Bentley
Updated docstrings
609
610
    The underlying tree must not be manipulated between calls, or else
611
    the results will likely be incorrect.
612
    """
7143.15.2 by Jelmer Vernooij
Run autopep8.
613
1534.7.132 by Aaron Bentley
Got cooked conflicts working
614
    def __init__(self, transform):
1534.7.1 by Aaron Bentley
Got creation of a versioned file working
615
        object.__init__(self)
616
        self._known_paths = {}
1534.7.33 by Aaron Bentley
Fixed naming
617
        self.transform = transform
1534.7.1 by Aaron Bentley
Got creation of a versioned file working
618
619
    def _determine_path(self, trans_id):
4526.9.23 by Robert Collins
Change the tree transform test_first_commit test to set a root id in the new tree, and workaround an apparent bug in TreeTransform._determine_path.
620
        if (trans_id == self.transform.root or trans_id == ROOT_PARENT):
6996 by Jelmer Vernooij
Merge lp:~jelmer/brz/python3-e
621
            return u""
1534.7.33 by Aaron Bentley
Fixed naming
622
        name = self.transform.final_name(trans_id)
623
        parent_id = self.transform.final_parent(trans_id)
1534.7.132 by Aaron Bentley
Got cooked conflicts working
624
        if parent_id == self.transform.root:
1534.7.1 by Aaron Bentley
Got creation of a versioned file working
625
            return name
626
        else:
1534.7.166 by Aaron Bentley
Swapped os.path.join for pathjoin everywhere
627
            return pathjoin(self.get_path(parent_id), name)
1534.7.1 by Aaron Bentley
Got creation of a versioned file working
628
629
    def get_path(self, trans_id):
1534.7.157 by Aaron Bentley
Added more docs
630
        """Find the final path associated with a trans_id"""
1534.7.1 by Aaron Bentley
Got creation of a versioned file working
631
        if trans_id not in self._known_paths:
632
            self._known_paths[trans_id] = self._determine_path(trans_id)
633
        return self._known_paths[trans_id]
1534.7.28 by Aaron Bentley
Nearly-working build_tree replacement
634
3453.2.3 by Aaron Bentley
Enable using a precomputed inventory delta for build_tree.
635
    def get_paths(self, trans_ids):
636
        return [(self.get_path(t), t) for t in trans_ids]
637
638
639
def build_tree(tree, wt, accelerator_tree=None, hardlink=False,
3453.2.6 by Aaron Bentley
Rename mutate_tree to delta_from_tree, add comment
640
               delta_from_tree=False):
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
641
    """Create working tree for a branch, using a TreeTransform.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
642
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
643
    This function should be used on empty trees, having a tree root at most.
644
    (see merge and revert functionality for working with existing trees)
645
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
646
    Existing files are handled like so:
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
647
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
648
    - Existing bzrdirs take precedence over creating new items.  They are
649
      created as '%s.diverted' % name.
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
650
    - Otherwise, if the content on disk matches the content we are building,
651
      it is silently replaced.
652
    - Otherwise, conflict resolution will move the old file to 'oldname.moved'.
3123.5.17 by Aaron Bentley
Update docs
653
654
    :param tree: The tree to convert wt into a copy of
655
    :param wt: The working tree that files will be placed into
656
    :param accelerator_tree: A tree which can be used for retrieving file
657
        contents more quickly than tree itself, i.e. a workingtree.  tree
658
        will be used for cases where accelerator_tree's content is different.
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
659
    :param hardlink: If true, hard-link files to accelerator_tree, where
3136.1.4 by Aaron Bentley
Avoid id2abspath calls
660
        possible.  accelerator_tree must implement abspath, i.e. be a
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
661
        working tree.
3453.2.6 by Aaron Bentley
Rename mutate_tree to delta_from_tree, add comment
662
    :param delta_from_tree: If true, build_tree may use the input Tree to
663
        generate the inventory delta.
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
664
    """
7479.2.1 by Jelmer Vernooij
Drop python2 support.
665
    with contextlib.ExitStack() as exit_stack:
7356.1.2 by Jelmer Vernooij
Use ExitStack in more places.
666
        exit_stack.enter_context(wt.lock_tree_write())
667
        exit_stack.enter_context(tree.lock_read())
6754.8.4 by Jelmer Vernooij
Use new context stuff.
668
        if accelerator_tree is not None:
7356.1.2 by Jelmer Vernooij
Use ExitStack in more places.
669
            exit_stack.enter_context(accelerator_tree.lock_read())
670
        return _build_tree(tree, wt, accelerator_tree, hardlink,
671
                           delta_from_tree)
2255.7.49 by Robert Collins
Lock trees passed in to build_tree.
672
3006.2.2 by Alexander Belchenko
tests added.
673
3453.2.6 by Aaron Bentley
Rename mutate_tree to delta_from_tree, add comment
674
def _build_tree(tree, wt, accelerator_tree, hardlink, delta_from_tree):
2255.7.49 by Robert Collins
Lock trees passed in to build_tree.
675
    """See build_tree."""
6825.5.1 by Jelmer Vernooij
Implement Tree.all_versioned_paths.
676
    for num, _unused in enumerate(wt.all_versioned_paths()):
3146.8.16 by Aaron Bentley
Updates from review
677
        if num > 0:  # more than just a root
678
            raise errors.WorkingTreeAlreadyPopulated(base=wt.basedir)
1534.7.28 by Aaron Bentley
Nearly-working build_tree replacement
679
    file_trans_id = {}
5582.10.4 by Jelmer Vernooij
Fix a bunch of tests.
680
    top_pb = ui.ui_factory.nested_progress_bar()
1558.11.1 by Aaron Bentley
Progress indicator for tree builts
681
    pp = ProgressPhase("Build phase", 2, top_pb)
7358.14.1 by Jelmer Vernooij
Remove Tree.get_root_id() in favour of Tree.path2id('').
682
    if tree.path2id('') is not None:
2502.1.6 by Aaron Bentley
Update from review comments
683
        # This is kind of a hack: we should be altering the root
684
        # as part of the regular tree shape diff logic.
685
        # The conditional test here is to avoid doing an
2255.2.194 by Robert Collins
[BROKEN] Many updates to stop using experimental formats in tests.
686
        # expensive operation (flush) every time the root id
687
        # is set within the tree, nor setting the root and thus
688
        # marking the tree as dirty, because we use two different
689
        # idioms here: tree interfaces and inventory interfaces.
7358.14.1 by Jelmer Vernooij
Remove Tree.get_root_id() in favour of Tree.path2id('').
690
        if wt.path2id('') != tree.path2id(''):
691
            wt.set_root_id(tree.path2id(''))
2255.2.194 by Robert Collins
[BROKEN] Many updates to stop using experimental formats in tests.
692
            wt.flush()
7490.77.2 by Jelmer Vernooij
Split out git and bzr-specific transforms.
693
    tt = wt.transform()
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
694
    divert = set()
1534.7.28 by Aaron Bentley
Nearly-working build_tree replacement
695
    try:
1558.11.1 by Aaron Bentley
Progress indicator for tree builts
696
        pp.next_phase()
7490.83.7 by Jelmer Vernooij
Key by path rather than by file id.
697
        file_trans_id[find_previous_path(wt, tree, '')] = tt.trans_id_tree_path('')
6861.4.1 by Jelmer Vernooij
Make progress bars context managers.
698
        with ui.ui_factory.nested_progress_bar() as pb:
2708.1.2 by Aaron Bentley
Use extract_files_bytes for build_tree
699
            deferred_contents = []
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
700
            num = 0
6825.5.1 by Jelmer Vernooij
Implement Tree.all_versioned_paths.
701
            total = len(tree.all_versioned_paths())
3453.2.6 by Aaron Bentley
Rename mutate_tree to delta_from_tree, add comment
702
            if delta_from_tree:
3453.2.3 by Aaron Bentley
Enable using a precomputed inventory delta for build_tree.
703
                precomputed_delta = []
704
            else:
705
                precomputed_delta = None
5268.2.7 by Parth Malwankar
fixed comment
706
            # Check if tree inventory has content. If so, we populate
5268.2.3 by Parth Malwankar
keep the tree_entries list lazy to ensure progress bar works
707
            # existing_files with the directory content. If there are no
708
            # entries we skip populating existing_files as its not used.
709
            # This improves performance and unncessary work on large
710
            # directory trees. (#501307)
5268.2.5 by Parth Malwankar
simplified conditional file list creating using existing count.
711
            if total > 0:
5268.2.1 by Parth Malwankar
init no longer iterates files in dir.
712
                existing_files = set()
713
                for dir, files in wt.walkdirs():
714
                    existing_files.update(f[0] for f in files)
5268.2.5 by Parth Malwankar
simplified conditional file list creating using existing count.
715
            for num, (tree_path, entry) in \
7143.15.2 by Jelmer Vernooij
Run autopep8.
716
                    enumerate(tree.iter_entries_by_dir()):
717
                pb.update(gettext("Building tree"), num
718
                          - len(deferred_contents), total)
1558.11.1 by Aaron Bentley
Progress indicator for tree builts
719
                if entry.parent_id is None:
720
                    continue
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
721
                reparent = False
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
722
                file_id = entry.file_id
3453.2.6 by Aaron Bentley
Rename mutate_tree to delta_from_tree, add comment
723
                if delta_from_tree:
3453.2.3 by Aaron Bentley
Enable using a precomputed inventory delta for build_tree.
724
                    precomputed_delta.append((None, tree_path, file_id, entry))
3453.2.5 by Aaron Bentley
Avoid statting tons of non-existant files when building from scratch
725
                if tree_path in existing_files:
726
                    target_path = wt.abspath(tree_path)
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
727
                    kind = file_kind(target_path)
728
                    if kind == "directory":
729
                        try:
6207.3.3 by jelmer at samba
Fix tests and the like.
730
                            controldir.ControlDir.open(target_path)
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
731
                        except errors.NotBranchError:
732
                            pass
733
                        else:
7490.83.7 by Jelmer Vernooij
Key by path rather than by file id.
734
                            divert.add(tree_path)
735
                    if (tree_path not in divert
7143.16.10 by Jelmer Vernooij
Fix E128.
736
                        and _content_match(
7350.6.6 by Jelmer Vernooij
Drop unused file_id argument.
737
                            tree, entry, tree_path, kind, target_path)):
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
738
                        tt.delete_contents(tt.trans_id_tree_path(tree_path))
739
                        if kind == 'directory':
740
                            reparent = True
7490.83.7 by Jelmer Vernooij
Key by path rather than by file id.
741
                parent_id = file_trans_id[osutils.dirname(tree_path)]
2708.1.8 by Aaron Bentley
rename extract_files_bytest to iter_files_bytes, fix build_tree / progress
742
                if entry.kind == 'file':
2708.1.2 by Aaron Bentley
Use extract_files_bytes for build_tree
743
                    # We *almost* replicate new_by_entry, so that we can defer
744
                    # getting the file text, and get them all at once.
745
                    trans_id = tt.create_path(entry.name, parent_id)
7490.83.7 by Jelmer Vernooij
Key by path rather than by file id.
746
                    file_trans_id[tree_path] = trans_id
7490.77.8 by Jelmer Vernooij
Change argument order for Transform.version_file.
747
                    tt.version_file(trans_id, file_id=file_id)
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
748
                    executable = tree.is_executable(tree_path)
3453.2.3 by Aaron Bentley
Enable using a precomputed inventory delta for build_tree.
749
                    if executable:
2708.1.8 by Aaron Bentley
rename extract_files_bytest to iter_files_bytes, fix build_tree / progress
750
                        tt.set_executability(executable, trans_id)
7490.77.1 by Jelmer Vernooij
Remove use of file_id when we don't need it.
751
                    trans_data = (trans_id, tree_path, entry.text_sha1)
6874.2.1 by Jelmer Vernooij
Make Tree.iter_files_bytes() take paths rather than file_ids.
752
                    deferred_contents.append((tree_path, trans_data))
2708.1.2 by Aaron Bentley
Use extract_files_bytes for build_tree
753
                else:
7490.83.7 by Jelmer Vernooij
Key by path rather than by file id.
754
                    file_trans_id[tree_path] = new_by_entry(
7143.15.2 by Jelmer Vernooij
Run autopep8.
755
                        tree_path, tt, entry, parent_id, tree)
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
756
                if reparent:
7490.83.7 by Jelmer Vernooij
Key by path rather than by file id.
757
                    new_trans_id = file_trans_id[tree_path]
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
758
                    old_parent = tt.trans_id_tree_path(tree_path)
759
                    _reparent_children(tt, old_parent, new_trans_id)
3136.1.11 by Aaron Bentley
Updates from review
760
            offset = num + 1 - len(deferred_contents)
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
761
            _create_files(tt, tree, deferred_contents, pb, offset,
762
                          accelerator_tree, hardlink)
1558.11.1 by Aaron Bentley
Progress indicator for tree builts
763
        pp.next_phase()
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
764
        divert_trans = set(file_trans_id[f] for f in divert)
7143.15.2 by Jelmer Vernooij
Run autopep8.
765
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
766
        def resolver(t, c):
767
            return resolve_checkout(t, c, divert_trans)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
768
        raw_conflicts = resolve_conflicts(tt, pass_func=resolver)
3453.2.4 by Aaron Bentley
Disable fast-path when conflicts are encountered
769
        if len(raw_conflicts) > 0:
770
            precomputed_delta = None
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
771
        conflicts = cook_conflicts(raw_conflicts, tt)
772
        for conflict in conflicts:
7479.2.1 by Jelmer Vernooij
Drop python2 support.
773
            trace.warning(str(conflict))
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
774
        try:
775
            wt.add_conflicts(conflicts)
776
        except errors.UnsupportedOperation:
777
            pass
3453.2.3 by Aaron Bentley
Enable using a precomputed inventory delta for build_tree.
778
        result = tt.apply(no_conflicts=True,
779
                          precomputed_delta=precomputed_delta)
1534.7.47 by Aaron Bentley
Started work on 'revert'
780
    finally:
781
        tt.finalize()
1558.11.1 by Aaron Bentley
Progress indicator for tree builts
782
        top_pb.finished()
2502.1.5 by Aaron Bentley
Cleanup
783
    return result
1534.7.47 by Aaron Bentley
Started work on 'revert'
784
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
785
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
786
def _create_files(tt, tree, desired_files, pb, offset, accelerator_tree,
787
                  hardlink):
788
    total = len(desired_files) + offset
4208.4.1 by Ian Clatworthy
eol conversion support
789
    wt = tt._tree
3123.5.5 by Aaron Bentley
Split out _iter_files_bytes_accelerated
790
    if accelerator_tree is None:
791
        new_desired_files = desired_files
792
    else:
3254.1.1 by Aaron Bentley
Make Tree.iter_changes a public method
793
        iter = accelerator_tree.iter_changes(tree, include_unchanged=True)
7322.1.6 by Jelmer Vernooij
Use the new attributes on TreeChange.
794
        unchanged = [
795
            change.path for change in iter
796
            if not (change.changed_content or change.executable[0] != change.executable[1])]
4826.1.1 by Andrew Bennetts
Quick change to allow hardlinking from a tree that supports content filtering for files that are unaffected by filters.
797
        if accelerator_tree.supports_content_filtering():
6874.2.1 by Jelmer Vernooij
Make Tree.iter_files_bytes() take paths rather than file_ids.
798
            unchanged = [(tp, ap) for (tp, ap) in unchanged
799
                         if not next(accelerator_tree.iter_search_rules([ap]))]
4826.1.1 by Andrew Bennetts
Quick change to allow hardlinking from a tree that supports content filtering for files that are unaffected by filters.
800
        unchanged = dict(unchanged)
3123.5.5 by Aaron Bentley
Split out _iter_files_bytes_accelerated
801
        new_desired_files = []
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
802
        count = 0
7490.77.1 by Jelmer Vernooij
Remove use of file_id when we don't need it.
803
        for unused_tree_path, (trans_id, tree_path, text_sha1) in desired_files:
6874.2.1 by Jelmer Vernooij
Make Tree.iter_files_bytes() take paths rather than file_ids.
804
            accelerator_path = unchanged.get(tree_path)
3123.5.12 by Aaron Bentley
Try to optimize iter_changes_accelerated
805
            if accelerator_path is None:
6874.2.1 by Jelmer Vernooij
Make Tree.iter_files_bytes() take paths rather than file_ids.
806
                new_desired_files.append((tree_path,
7490.77.1 by Jelmer Vernooij
Remove use of file_id when we don't need it.
807
                                          (trans_id, tree_path, text_sha1)))
3123.5.12 by Aaron Bentley
Try to optimize iter_changes_accelerated
808
                continue
6138.4.1 by Jonathan Riddell
add gettext to progress bar strings
809
            pb.update(gettext('Adding file contents'), count + offset, total)
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
810
            if hardlink:
3136.1.4 by Aaron Bentley
Avoid id2abspath calls
811
                tt.create_hardlink(accelerator_tree.abspath(accelerator_path),
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
812
                                   trans_id)
813
            else:
7192.5.2 by Jelmer Vernooij
Fixes.
814
                with accelerator_tree.get_file(accelerator_path) as f:
6977.2.1 by Jelmer Vernooij
Require that get_file implementations are contect managers, simplify file handling in transform.
815
                    chunks = osutils.file_iterator(f)
816
                    if wt.supports_content_filtering():
817
                        filters = wt._content_filter_stack(tree_path)
818
                        chunks = filtered_output_bytes(chunks, filters,
7143.15.2 by Jelmer Vernooij
Run autopep8.
819
                                                       ContentFilterContext(tree_path, tree))
6977.2.1 by Jelmer Vernooij
Require that get_file implementations are contect managers, simplify file handling in transform.
820
                    tt.create_file(chunks, trans_id, sha1=text_sha1)
3136.1.2 by Aaron Bentley
Implement hard-linking for build_tree
821
            count += 1
822
        offset += count
7490.77.1 by Jelmer Vernooij
Remove use of file_id when we don't need it.
823
    for count, ((trans_id, tree_path, text_sha1), contents) in enumerate(
3368.2.20 by Ian Clatworthy
move filtering up the layers in TreeTransform
824
            tree.iter_files_bytes(new_desired_files)):
4208.4.1 by Ian Clatworthy
eol conversion support
825
        if wt.supports_content_filtering():
826
            filters = wt._content_filter_stack(tree_path)
3368.2.45 by Ian Clatworthy
add and use supports_content_filtering API
827
            contents = filtered_output_bytes(contents, filters,
7143.15.2 by Jelmer Vernooij
Run autopep8.
828
                                             ContentFilterContext(tree_path, tree))
5752.5.1 by John Arbash Meinel
Merge up transform-create-file
829
        tt.create_file(contents, trans_id, sha1=text_sha1)
6138.4.1 by Jonathan Riddell
add gettext to progress bar strings
830
        pb.update(gettext('Adding file contents'), count + offset, total)
3123.5.5 by Aaron Bentley
Split out _iter_files_bytes_accelerated
831
832
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
833
def _reparent_children(tt, old_parent, new_parent):
834
    for child in tt.iter_tree_children(old_parent):
835
        tt.adjust_path(tt.final_name(child), new_parent, child)
836
5409.1.7 by Vincent Ladeuil
First orphaning implementation (some tests lacking).
837
3144.4.2 by Aaron Bentley
Handle non-directory parent conflicts (abentley, #177390)
838
def _reparent_transform_children(tt, old_parent, new_parent):
839
    by_parent = tt.by_parent()
840
    for child in by_parent[old_parent]:
841
        tt.adjust_path(tt.final_name(child), new_parent, child)
1551.19.32 by Aaron Bentley
Don't traceback when adding files to a deleted root (abentley, #210092)
842
    return by_parent[old_parent]
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
843
5409.1.7 by Vincent Ladeuil
First orphaning implementation (some tests lacking).
844
7350.6.6 by Jelmer Vernooij
Drop unused file_id argument.
845
def _content_match(tree, entry, tree_path, kind, target_path):
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
846
    if entry.kind != kind:
847
        return False
848
    if entry.kind == "directory":
849
        return True
850
    if entry.kind == "file":
6977.2.1 by Jelmer Vernooij
Require that get_file implementations are contect managers, simplify file handling in transform.
851
        with open(target_path, 'rb') as f1, \
7143.16.21 by Jelmer Vernooij
Fix regressions.
852
                tree.get_file(tree_path) as f2:
6977.2.1 by Jelmer Vernooij
Require that get_file implementations are contect managers, simplify file handling in transform.
853
            if osutils.compare_files(f1, f2):
4708.2.2 by Martin
Workingtree changes sitting around since November, more explict closing of files in bzrlib
854
                return True
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
855
    elif entry.kind == "symlink":
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
856
        if tree.get_symlink_target(tree_path) == os.readlink(target_path):
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
857
            return True
858
    return False
859
860
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
861
def resolve_checkout(tt, conflicts, divert):
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
862
    new_conflicts = set()
863
    for c_type, conflict in ((c[0], c) for c in conflicts):
864
        # Anything but a 'duplicate' would indicate programmer error
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
865
        if c_type != 'duplicate':
866
            raise AssertionError(c_type)
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
867
        # 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
868
        if tt.new_contents(conflict[1]):
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
869
            new_file = conflict[1]
870
            old_file = conflict[2]
871
        else:
872
            new_file = conflict[2]
873
            old_file = conflict[1]
874
875
        # We should only get here if the conflict wasn't completely
876
        # resolved
877
        final_parent = tt.final_parent(old_file)
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
878
        if new_file in divert:
7143.15.2 by Jelmer Vernooij
Run autopep8.
879
            new_name = tt.final_name(old_file) + '.diverted'
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
880
            tt.adjust_path(new_name, final_parent, new_file)
881
            new_conflicts.add((c_type, 'Diverted to',
882
                               new_file, old_file))
883
        else:
7143.15.2 by Jelmer Vernooij
Run autopep8.
884
            new_name = tt.final_name(old_file) + '.moved'
1966.1.2 by Aaron Bentley
Divert files instead of failing to create them, update from review
885
            tt.adjust_path(new_name, final_parent, old_file)
886
            new_conflicts.add((c_type, 'Moved existing file to',
887
                               old_file, new_file))
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
888
    return new_conflicts
889
890
6809.4.4 by Jelmer Vernooij
Swap arguments for Tree.is_executable.
891
def new_by_entry(path, tt, entry, parent_id, tree):
1534.7.157 by Aaron Bentley
Added more docs
892
    """Create a new file according to its inventory entry"""
1534.7.47 by Aaron Bentley
Started work on 'revert'
893
    name = entry.name
894
    kind = entry.kind
895
    if kind == 'file':
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
896
        with tree.get_file(path) as f:
897
            executable = tree.is_executable(path)
6977.2.1 by Jelmer Vernooij
Require that get_file implementations are contect managers, simplify file handling in transform.
898
            return tt.new_file(
7143.15.2 by Jelmer Vernooij
Run autopep8.
899
                name, parent_id, osutils.file_iterator(f), entry.file_id,
900
                executable)
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
901
    elif kind in ('directory', 'tree-reference'):
902
        trans_id = tt.new_directory(name, parent_id, entry.file_id)
903
        if kind == 'tree-reference':
904
            tt.set_tree_reference(entry.reference_revision, trans_id)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
905
        return trans_id
1534.7.47 by Aaron Bentley
Started work on 'revert'
906
    elif kind == 'symlink':
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
907
        target = tree.get_symlink_target(path)
1534.7.183 by Aaron Bentley
Fixed build_tree with symlinks
908
        return tt.new_symlink(name, parent_id, target, entry.file_id)
2100.3.21 by Aaron Bentley
Work on checking out by-reference trees
909
    else:
910
        raise errors.BadFileKindError(name, kind)
1534.7.47 by Aaron Bentley
Started work on 'revert'
911
3006.2.2 by Alexander Belchenko
tests added.
912
7350.5.1 by Jelmer Vernooij
Remove file_id from transform's create_from_tree, get filter tree paths by path.
913
def create_from_tree(tt, trans_id, tree, path, chunks=None,
7143.15.2 by Jelmer Vernooij
Run autopep8.
914
                     filter_tree_path=None):
4443.2.1 by Ian Clatworthy
apply content filters when merging new files
915
    """Create new file contents according to tree contents.
6809.4.7 by Jelmer Vernooij
Swap arguments for get_symlink_target and kind/stored_kind.
916
4443.2.1 by Ian Clatworthy
apply content filters when merging new files
917
    :param filter_tree_path: the tree path to use to lookup
918
      content filters to apply to the bytes output in the working tree.
919
      This only applies if the working tree supports content filtering.
920
    """
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
921
    kind = tree.kind(path)
3363.17.24 by Aaron Bentley
Implement create_by_tree
922
    if kind == 'directory':
923
        tt.create_directory(trans_id)
924
    elif kind == "file":
6977.2.1 by Jelmer Vernooij
Require that get_file implementations are contect managers, simplify file handling in transform.
925
        if chunks is None:
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
926
            f = tree.get_file(path)
6977.2.1 by Jelmer Vernooij
Require that get_file implementations are contect managers, simplify file handling in transform.
927
            chunks = osutils.file_iterator(f)
928
        else:
929
            f = None
930
        try:
931
            wt = tt._tree
932
            if wt.supports_content_filtering() and filter_tree_path is not None:
933
                filters = wt._content_filter_stack(filter_tree_path)
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
934
                chunks = filtered_output_bytes(
935
                    chunks, filters,
936
                    ContentFilterContext(filter_tree_path, tree))
6977.2.1 by Jelmer Vernooij
Require that get_file implementations are contect managers, simplify file handling in transform.
937
            tt.create_file(chunks, trans_id)
938
        finally:
939
            if f is not None:
940
                f.close()
3363.17.24 by Aaron Bentley
Implement create_by_tree
941
    elif kind == "symlink":
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
942
        tt.create_symlink(tree.get_symlink_target(path), trans_id)
3363.17.27 by Aaron Bentley
Add default case for create_from_tree
943
    else:
944
        raise AssertionError('Unknown kind %r' % kind)
3363.17.24 by Aaron Bentley
Implement create_by_tree
945
946
1534.7.89 by Aaron Bentley
Handle all content types in three-way
947
def create_entry_executability(tt, entry, trans_id):
1534.7.157 by Aaron Bentley
Added more docs
948
    """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
949
    if entry.kind == "file":
950
        tt.set_executability(entry.executable, trans_id)
1534.7.47 by Aaron Bentley
Started work on 'revert'
951
1534.7.157 by Aaron Bentley
Added more docs
952
2255.2.53 by Robert Collins
Teach TreeTransform to lock basis_trees if it acquires them, fixing revert on a dirstate working tree.
953
def revert(working_tree, target_tree, filenames, backups=False,
4961.2.9 by Martin Pool
Rip out most remaining uses of DummyProgressBar
954
           pb=None, change_reporter=None):
1534.7.157 by Aaron Bentley
Added more docs
955
    """Revert a working tree's contents to those of a target tree."""
4961.2.9 by Martin Pool
Rip out most remaining uses of DummyProgressBar
956
    pb = ui.ui_factory.nested_progress_bar()
1534.7.47 by Aaron Bentley
Started work on 'revert'
957
    try:
7490.77.2 by Jelmer Vernooij
Split out git and bzr-specific transforms.
958
        with target_tree.lock_read(), working_tree.transform(pb) as tt:
6969.3.2 by Jelmer Vernooij
Use context managers for locking.
959
            pp = ProgressPhase("Revert phase", 3, pb)
960
            conflicts, merge_modified = _prepare_revert_transform(
961
                working_tree, target_tree, tt, filenames, backups, pp)
962
            if change_reporter:
7490.83.1 by Jelmer Vernooij
Add abstract methods.
963
                from . import delta
6969.3.2 by Jelmer Vernooij
Use context managers for locking.
964
                change_reporter = delta._ChangeReporter(
965
                    unversioned_filter=working_tree.is_ignored)
966
                delta.report_changes(tt.iter_changes(), change_reporter)
967
            for conflict in conflicts:
7479.2.1 by Jelmer Vernooij
Drop python2 support.
968
                trace.warning(str(conflict))
6969.3.2 by Jelmer Vernooij
Use context managers for locking.
969
            pp.next_phase()
970
            tt.apply()
971
            if working_tree.supports_merge_modified():
972
                working_tree.set_merge_modified(merge_modified)
1534.7.28 by Aaron Bentley
Nearly-working build_tree replacement
973
    finally:
1534.9.4 by Aaron Bentley
Added progress bars to revert.
974
        pb.clear()
1558.7.13 by Aaron Bentley
WorkingTree.revert returns conflicts
975
    return conflicts
1534.7.51 by Aaron Bentley
New approach to revert
976
1534.7.57 by Aaron Bentley
Enhanced conflict resolution.
977
3363.2.10 by Aaron Bentley
Refactor _prepare_revert_transform out of revert
978
def _prepare_revert_transform(working_tree, target_tree, tt, filenames,
3363.2.17 by Aaron Bentley
Start implementing post-change PreviewTree functionality
979
                              backups, pp, basis_tree=None,
980
                              merge_modified=None):
6861.4.1 by Jelmer Vernooij
Make progress bars context managers.
981
    with ui.ui_factory.nested_progress_bar() as child_pb:
3363.2.17 by Aaron Bentley
Start implementing post-change PreviewTree functionality
982
        if merge_modified is None:
983
            merge_modified = working_tree.merge_modified()
3363.2.10 by Aaron Bentley
Refactor _prepare_revert_transform out of revert
984
        merge_modified = _alter_files(working_tree, target_tree, tt,
3363.2.17 by Aaron Bentley
Start implementing post-change PreviewTree functionality
985
                                      child_pb, filenames, backups,
986
                                      merge_modified, basis_tree)
6861.4.1 by Jelmer Vernooij
Make progress bars context managers.
987
    with ui.ui_factory.nested_progress_bar() as child_pb:
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
988
        raw_conflicts = resolve_conflicts(
989
            tt, child_pb, lambda t, c: conflict_pass(t, c, target_tree))
3363.2.10 by Aaron Bentley
Refactor _prepare_revert_transform out of revert
990
    conflicts = cook_conflicts(raw_conflicts, tt)
991
    return conflicts, merge_modified
992
993
2255.2.149 by Robert Collins
Crufty but existing _iter_changes implementation for WorkingTreeFormat4.
994
def _alter_files(working_tree, target_tree, tt, pb, specific_files,
3363.2.17 by Aaron Bentley
Start implementing post-change PreviewTree functionality
995
                 backups, merge_modified, basis_tree=None):
3363.10.25 by Aaron Bentley
_alter_files locks supplied basis_tree
996
    if basis_tree is not None:
997
        basis_tree.lock_read()
5783.3.1 by John Arbash Meinel
Do an 'obvious' transformation for clarity.
998
    # We ask the working_tree for its changes relative to the target, rather
999
    # than the target changes relative to the working tree. Because WT4 has an
1000
    # optimizer to compare itself to a target, but no optimizer for the
1001
    # reverse.
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
1002
    change_list = working_tree.iter_changes(
1003
        target_tree, specific_files=specific_files, pb=pb)
6973.3.1 by Jelmer Vernooij
Avoid using file ids where possible.
1004
    if not target_tree.is_versioned(u''):
2012.1.12 by Aaron Bentley
Use iter_changes for revert
1005
        skip_root = True
1006
    else:
1007
        skip_root = False
2255.2.53 by Robert Collins
Teach TreeTransform to lock basis_trees if it acquires them, fixing revert on a dirstate working tree.
1008
    try:
2708.1.5 by Aaron Bentley
Use Tree.extract_files_bytes in revert
1009
        deferred_files = []
7322.1.7 by Jelmer Vernooij
Fix remaining tests.
1010
        for id_num, change in enumerate(change_list):
1011
            file_id = change.file_id
1012
            target_path, wt_path = change.path
1013
            target_versioned, wt_versioned = change.versioned
1014
            target_parent, wt_parent = change.parent_id
1015
            target_name, wt_name = change.name
1016
            target_kind, wt_kind = change.kind
1017
            target_executable, wt_executable = change.executable
5783.3.1 by John Arbash Meinel
Do an 'obvious' transformation for clarity.
1018
            if skip_root and wt_parent is None:
2255.2.53 by Robert Collins
Teach TreeTransform to lock basis_trees if it acquires them, fixing revert on a dirstate working tree.
1019
                continue
1020
            trans_id = tt.trans_id_file_id(file_id)
1021
            mode_id = None
7322.1.7 by Jelmer Vernooij
Fix remaining tests.
1022
            if change.changed_content:
2255.2.53 by Robert Collins
Teach TreeTransform to lock basis_trees if it acquires them, fixing revert on a dirstate working tree.
1023
                keep_content = False
5783.3.1 by John Arbash Meinel
Do an 'obvious' transformation for clarity.
1024
                if wt_kind == 'file' and (backups or target_kind is None):
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
1025
                    wt_sha1 = working_tree.get_file_sha1(wt_path)
7350.4.1 by Jelmer Vernooij
Use paths as keys in merge modified dictionaries.
1026
                    if merge_modified.get(wt_path) != wt_sha1:
2502.1.6 by Aaron Bentley
Update from review comments
1027
                        # acquire the basis tree lazily to prevent the
1028
                        # expense of accessing it when it's not needed ?
1029
                        # (Guessing, RBC, 200702)
2255.2.53 by Robert Collins
Teach TreeTransform to lock basis_trees if it acquires them, fixing revert on a dirstate working tree.
1030
                        if basis_tree is None:
1031
                            basis_tree = working_tree.basis_tree()
1032
                            basis_tree.lock_read()
7357.1.8 by Jelmer Vernooij
Remove the InterTree object.
1033
                        basis_inter = InterTree.get(basis_tree, working_tree)
1034
                        basis_path = basis_inter.find_source_path(wt_path)
6883.5.3 by Jelmer Vernooij
Add find_previous_path.
1035
                        if basis_path is None:
6809.4.13 by Jelmer Vernooij
Fix tests.
1036
                            if target_kind is None and not target_versioned:
1037
                                keep_content = True
1038
                        else:
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
1039
                            if wt_sha1 != basis_tree.get_file_sha1(basis_path):
6809.4.13 by Jelmer Vernooij
Fix tests.
1040
                                keep_content = True
5783.3.1 by John Arbash Meinel
Do an 'obvious' transformation for clarity.
1041
                if wt_kind is not None:
2255.2.53 by Robert Collins
Teach TreeTransform to lock basis_trees if it acquires them, fixing revert on a dirstate working tree.
1042
                    if not keep_content:
1043
                        tt.delete_contents(trans_id)
5783.3.1 by John Arbash Meinel
Do an 'obvious' transformation for clarity.
1044
                    elif target_kind is not None:
1045
                        parent_trans_id = tt.trans_id_file_id(wt_parent)
5409.8.4 by Vincent Ladeuil
Fix indentations.
1046
                        backup_name = tt._available_backup_name(
5783.3.1 by John Arbash Meinel
Do an 'obvious' transformation for clarity.
1047
                            wt_name, parent_trans_id)
2255.2.53 by Robert Collins
Teach TreeTransform to lock basis_trees if it acquires them, fixing revert on a dirstate working tree.
1048
                        tt.adjust_path(backup_name, parent_trans_id, trans_id)
5783.3.1 by John Arbash Meinel
Do an 'obvious' transformation for clarity.
1049
                        new_trans_id = tt.create_path(wt_name, parent_trans_id)
5783.3.2 by John Arbash Meinel
catch a couple more cases
1050
                        if wt_versioned and target_versioned:
2255.2.53 by Robert Collins
Teach TreeTransform to lock basis_trees if it acquires them, fixing revert on a dirstate working tree.
1051
                            tt.unversion_file(trans_id)
7490.77.8 by Jelmer Vernooij
Change argument order for Transform.version_file.
1052
                            tt.version_file(new_trans_id, file_id=file_id)
2255.2.53 by Robert Collins
Teach TreeTransform to lock basis_trees if it acquires them, fixing revert on a dirstate working tree.
1053
                        # New contents should have the same unix perms as old
1054
                        # contents
1055
                        mode_id = trans_id
1056
                        trans_id = new_trans_id
5783.3.1 by John Arbash Meinel
Do an 'obvious' transformation for clarity.
1057
                if target_kind in ('directory', 'tree-reference'):
2255.2.53 by Robert Collins
Teach TreeTransform to lock basis_trees if it acquires them, fixing revert on a dirstate working tree.
1058
                    tt.create_directory(trans_id)
5783.3.1 by John Arbash Meinel
Do an 'obvious' transformation for clarity.
1059
                    if target_kind == 'tree-reference':
6809.4.1 by Jelmer Vernooij
Swap file_id and path arguments for get_reference_revision and get_nested_tree.
1060
                        revision = target_tree.get_reference_revision(
7143.15.15 by Jelmer Vernooij
Merge trunk.
1061
                            target_path)
3363.11.3 by Aaron Bentley
Handle adding tree references in revert
1062
                        tt.set_tree_reference(revision, trans_id)
5783.3.1 by John Arbash Meinel
Do an 'obvious' transformation for clarity.
1063
                elif target_kind == 'symlink':
6809.4.13 by Jelmer Vernooij
Fix tests.
1064
                    tt.create_symlink(target_tree.get_symlink_target(
7143.15.15 by Jelmer Vernooij
Merge trunk.
1065
                        target_path), trans_id)
5783.3.1 by John Arbash Meinel
Do an 'obvious' transformation for clarity.
1066
                elif target_kind == 'file':
7143.15.2 by Jelmer Vernooij
Run autopep8.
1067
                    deferred_files.append(
1068
                        (target_path, (trans_id, mode_id, file_id)))
2499.1.1 by Aaron Bentley
Revert does not try to preserve file contents produced by revert
1069
                    if basis_tree is None:
1070
                        basis_tree = working_tree.basis_tree()
1071
                        basis_tree.lock_read()
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
1072
                    new_sha1 = target_tree.get_file_sha1(target_path)
7357.1.8 by Jelmer Vernooij
Remove the InterTree object.
1073
                    basis_inter = InterTree.get(basis_tree, target_tree)
1074
                    basis_path = basis_inter.find_source_path(target_path)
6809.4.5 by Jelmer Vernooij
Swap arguments for get_file_*.
1075
                    if (basis_path is not None and
7143.15.15 by Jelmer Vernooij
Merge trunk.
1076
                            new_sha1 == basis_tree.get_file_sha1(basis_path)):
7350.4.3 by Jelmer Vernooij
Fix tests.
1077
                        # If the new contents of the file match what is in basis,
1078
                        # then there is no need to store in merge_modified.
1079
                        if basis_path in merge_modified:
1080
                            del merge_modified[basis_path]
2499.1.1 by Aaron Bentley
Revert does not try to preserve file contents produced by revert
1081
                    else:
7350.4.3 by Jelmer Vernooij
Fix tests.
1082
                        merge_modified[target_path] = new_sha1
2499.1.1 by Aaron Bentley
Revert does not try to preserve file contents produced by revert
1083
2255.2.53 by Robert Collins
Teach TreeTransform to lock basis_trees if it acquires them, fixing revert on a dirstate working tree.
1084
                    # preserve the execute bit when backing up
5783.3.1 by John Arbash Meinel
Do an 'obvious' transformation for clarity.
1085
                    if keep_content and wt_executable == target_executable:
1086
                        tt.set_executability(target_executable, trans_id)
1087
                elif target_kind is not None:
1088
                    raise AssertionError(target_kind)
5783.3.2 by John Arbash Meinel
catch a couple more cases
1089
            if not wt_versioned and target_versioned:
7490.77.8 by Jelmer Vernooij
Change argument order for Transform.version_file.
1090
                tt.version_file(trans_id, file_id=file_id)
5783.3.2 by John Arbash Meinel
catch a couple more cases
1091
            if wt_versioned and not target_versioned:
2255.2.53 by Robert Collins
Teach TreeTransform to lock basis_trees if it acquires them, fixing revert on a dirstate working tree.
1092
                tt.unversion_file(trans_id)
7143.15.2 by Jelmer Vernooij
Run autopep8.
1093
            if (target_name is not None
1094
                    and (wt_name != target_name or wt_parent != target_parent)):
5783.3.1 by John Arbash Meinel
Do an 'obvious' transformation for clarity.
1095
                if target_name == '' and target_parent is None:
3363.2.16 by Aaron Bentley
Fix root directory creation
1096
                    parent_trans = ROOT_PARENT
1097
                else:
5783.3.1 by John Arbash Meinel
Do an 'obvious' transformation for clarity.
1098
                    parent_trans = tt.trans_id_file_id(target_parent)
1099
                if wt_parent is None and wt_versioned:
1100
                    tt.adjust_root_path(target_name, parent_trans)
4634.122.2 by Aaron Bentley, John Arbash Meinel
Bring the fixup_new_roots code from the nested-trees code.
1101
                else:
5783.3.1 by John Arbash Meinel
Do an 'obvious' transformation for clarity.
1102
                    tt.adjust_path(target_name, parent_trans, trans_id)
1103
            if wt_executable != target_executable and target_kind == "file":
1104
                tt.set_executability(target_executable, trans_id)
4443.2.7 by Ian Clatworthy
test and fix for revert with content filtering
1105
        if working_tree.supports_content_filtering():
6874.2.1 by Jelmer Vernooij
Make Tree.iter_files_bytes() take paths rather than file_ids.
1106
            for (trans_id, mode_id, file_id), bytes in (
7143.15.2 by Jelmer Vernooij
Run autopep8.
1107
                    target_tree.iter_files_bytes(deferred_files)):
4634.102.4 by Ian Clatworthy
Explain why we're using the target tree to look up the path when reverting
1108
                # We're reverting a tree to the target tree so using the
1109
                # target tree to find the file path seems the best choice
1110
                # here IMO - Ian C 27/Oct/2009
4443.2.7 by Ian Clatworthy
test and fix for revert with content filtering
1111
                filter_tree_path = target_tree.id2path(file_id)
1112
                filters = working_tree._content_filter_stack(filter_tree_path)
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
1113
                bytes = filtered_output_bytes(
1114
                    bytes, filters,
1115
                    ContentFilterContext(filter_tree_path, working_tree))
4443.2.7 by Ian Clatworthy
test and fix for revert with content filtering
1116
                tt.create_file(bytes, trans_id, mode_id)
1117
        else:
6874.2.1 by Jelmer Vernooij
Make Tree.iter_files_bytes() take paths rather than file_ids.
1118
            for (trans_id, mode_id, file_id), bytes in target_tree.iter_files_bytes(
7143.15.2 by Jelmer Vernooij
Run autopep8.
1119
                    deferred_files):
4443.2.7 by Ian Clatworthy
test and fix for revert with content filtering
1120
                tt.create_file(bytes, trans_id, mode_id)
4634.122.2 by Aaron Bentley, John Arbash Meinel
Bring the fixup_new_roots code from the nested-trees code.
1121
        tt.fixup_new_roots()
2255.2.53 by Robert Collins
Teach TreeTransform to lock basis_trees if it acquires them, fixing revert on a dirstate working tree.
1122
    finally:
1123
        if basis_tree is not None:
1124
            basis_tree.unlock()
2499.1.1 by Aaron Bentley
Revert does not try to preserve file contents produced by revert
1125
    return merge_modified
2012.1.12 by Aaron Bentley
Use iter_changes for revert
1126
1127
4961.2.9 by Martin Pool
Rip out most remaining uses of DummyProgressBar
1128
def resolve_conflicts(tt, pb=None, pass_func=None):
1534.7.57 by Aaron Bentley
Enhanced conflict resolution.
1129
    """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
1130
    if pass_func is None:
1131
        pass_func = conflict_pass
1534.7.169 by Aaron Bentley
Add filesystem/inventory conflicts to conflict output
1132
    new_conflicts = set()
6861.4.1 by Jelmer Vernooij
Make progress bars context managers.
1133
    with ui.ui_factory.nested_progress_bar() as pb:
1534.9.1 by Aaron Bentley
Added progress bars to merge
1134
        for n in range(10):
7143.15.2 by Jelmer Vernooij
Run autopep8.
1135
            pb.update(gettext('Resolution pass'), n + 1, 10)
1534.9.1 by Aaron Bentley
Added progress bars to merge
1136
            conflicts = tt.find_conflicts()
1137
            if len(conflicts) == 0:
1138
                return new_conflicts
1966.1.1 by Aaron Bentley
Implement disk-content merge and conflict resolution for build_tree
1139
            new_conflicts.update(pass_func(tt, conflicts))
1534.9.1 by Aaron Bentley
Added progress bars to merge
1140
        raise MalformedTransform(conflicts=conflicts)
1534.7.57 by Aaron Bentley
Enhanced conflict resolution.
1141
1142
2590.2.8 by Aaron Bentley
Restore conflict handling changes
1143
def conflict_pass(tt, conflicts, path_tree=None):
1144
    """Resolve some classes of conflicts.
1145
1146
    :param tt: The transform to resolve conflicts in
1147
    :param conflicts: The conflicts to resolve
1148
    :param path_tree: A Tree to get supplemental paths from
1149
    """
1534.7.169 by Aaron Bentley
Add filesystem/inventory conflicts to conflict output
1150
    new_conflicts = set()
1534.7.61 by Aaron Bentley
Handled parent loops, missing parents, unversioned parents
1151
    for c_type, conflict in ((c[0], c) for c in conflicts):
1152
        if c_type == 'duplicate id':
1534.7.51 by Aaron Bentley
New approach to revert
1153
            tt.unversion_file(conflict[1])
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
1154
            new_conflicts.add((c_type, 'Unversioned existing file',
1155
                               conflict[1], conflict[2], ))
1534.7.61 by Aaron Bentley
Handled parent loops, missing parents, unversioned parents
1156
        elif c_type == 'duplicate':
1534.7.57 by Aaron Bentley
Enhanced conflict resolution.
1157
            # files that were renamed take precedence
1158
            final_parent = tt.final_parent(conflict[1])
1159
            if tt.path_changed(conflict[1]):
3034.4.1 by Aaron Bentley
Start handling case-insensitivity
1160
                existing_file, new_file = conflict[2], conflict[1]
1534.7.57 by Aaron Bentley
Enhanced conflict resolution.
1161
            else:
3034.4.1 by Aaron Bentley
Start handling case-insensitivity
1162
                existing_file, new_file = conflict[1], conflict[2]
6015.47.2 by Vincent Ladeuil
Cosmetic change.
1163
            new_name = tt.final_name(existing_file) + '.moved'
3034.4.1 by Aaron Bentley
Start handling case-insensitivity
1164
            tt.adjust_path(new_name, final_parent, existing_file)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1165
            new_conflicts.add((c_type, 'Moved existing file to',
3034.4.1 by Aaron Bentley
Start handling case-insensitivity
1166
                               existing_file, new_file))
1534.7.61 by Aaron Bentley
Handled parent loops, missing parents, unversioned parents
1167
        elif c_type == 'parent loop':
1168
            # break the loop by undoing one of the ops that caused the loop
1169
            cur = conflict[1]
1170
            while not tt.path_changed(cur):
1171
                cur = tt.final_parent(cur)
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
1172
            new_conflicts.add((c_type, 'Cancelled move', cur,
1173
                               tt.final_parent(cur),))
1534.7.61 by Aaron Bentley
Handled parent loops, missing parents, unversioned parents
1174
            tt.adjust_path(tt.final_name(cur), tt.get_tree_parent(cur), cur)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1175
1534.7.61 by Aaron Bentley
Handled parent loops, missing parents, unversioned parents
1176
        elif c_type == 'missing parent':
1534.7.128 by Aaron Bentley
Got missing contents test working
1177
            trans_id = conflict[1]
5409.1.3 by Vincent Ladeuil
Clarify b.transform.conflict_pass.
1178
            if trans_id in tt._removed_contents:
5409.1.16 by Vincent Ladeuil
Add ``bzrlib.transform.orphan_policy`` and allows ``never`` to restore the previous behaviour.
1179
                cancel_deletion = True
5409.1.14 by Vincent Ladeuil
Prepare for more ways to handle orphans.
1180
                orphans = tt._get_potential_orphans(trans_id)
1181
                if orphans:
5409.1.16 by Vincent Ladeuil
Add ``bzrlib.transform.orphan_policy`` and allows ``never`` to restore the previous behaviour.
1182
                    cancel_deletion = False
5409.1.7 by Vincent Ladeuil
First orphaning implementation (some tests lacking).
1183
                    # All children are orphans
1184
                    for o in orphans:
5409.1.14 by Vincent Ladeuil
Prepare for more ways to handle orphans.
1185
                        try:
1186
                            tt.new_orphan(o, trans_id)
5409.1.16 by Vincent Ladeuil
Add ``bzrlib.transform.orphan_policy`` and allows ``never`` to restore the previous behaviour.
1187
                        except OrphaningError:
1188
                            # Something bad happened so we cancel the directory
1189
                            # deletion which will leave it in place with a
1190
                            # conflict. The user can deal with it from there.
1191
                            # Note that this also catch the case where we don't
1192
                            # want to create orphans and leave the directory in
1193
                            # place.
1194
                            cancel_deletion = True
5409.1.14 by Vincent Ladeuil
Prepare for more ways to handle orphans.
1195
                            break
5409.1.16 by Vincent Ladeuil
Add ``bzrlib.transform.orphan_policy`` and allows ``never`` to restore the previous behaviour.
1196
                if cancel_deletion:
5409.1.7 by Vincent Ladeuil
First orphaning implementation (some tests lacking).
1197
                    # Cancel the directory deletion
1198
                    tt.cancel_deletion(trans_id)
1199
                    new_conflicts.add(('deleting parent', 'Not deleting',
1200
                                       trans_id))
5409.1.3 by Vincent Ladeuil
Clarify b.transform.conflict_pass.
1201
            else:
1551.19.32 by Aaron Bentley
Don't traceback when adding files to a deleted root (abentley, #210092)
1202
                create = True
2590.2.8 by Aaron Bentley
Restore conflict handling changes
1203
                try:
1204
                    tt.final_name(trans_id)
1205
                except NoFinalPath:
1551.19.6 by Aaron Bentley
Revert doesn't crash restoring a file from a deleted directory
1206
                    if path_tree is not None:
1207
                        file_id = tt.final_file_id(trans_id)
1551.19.32 by Aaron Bentley
Don't traceback when adding files to a deleted root (abentley, #210092)
1208
                        if file_id is None:
1209
                            file_id = tt.inactive_file_id(trans_id)
6634.2.1 by Martin
Apply 2to3 next fixer and make compatible
1210
                        _, entry = next(path_tree.iter_entries_by_dir(
6885.5.7 by Jelmer Vernooij
Use specific_files rather than specific_file_ids in transform.
1211
                            specific_files=[path_tree.id2path(file_id)]))
1551.19.32 by Aaron Bentley
Don't traceback when adding files to a deleted root (abentley, #210092)
1212
                        # special-case the other tree root (move its
1213
                        # children to current root)
1214
                        if entry.parent_id is None:
5128.1.1 by Vincent Ladeuil
Uncontroversial cleanups, mostly comments
1215
                            create = False
1551.19.32 by Aaron Bentley
Don't traceback when adding files to a deleted root (abentley, #210092)
1216
                            moved = _reparent_transform_children(
1217
                                tt, trans_id, tt.root)
1218
                            for child in moved:
1219
                                new_conflicts.add((c_type, 'Moved to root',
1220
                                                   child))
1221
                        else:
1222
                            parent_trans_id = tt.trans_id_file_id(
1223
                                entry.parent_id)
1224
                            tt.adjust_path(entry.name, parent_trans_id,
1225
                                           trans_id)
1226
                if create:
1227
                    tt.create_directory(trans_id)
1228
                    new_conflicts.add((c_type, 'Created directory', trans_id))
1534.7.61 by Aaron Bentley
Handled parent loops, missing parents, unversioned parents
1229
        elif c_type == 'unversioned parent':
1551.19.32 by Aaron Bentley
Don't traceback when adding files to a deleted root (abentley, #210092)
1230
            file_id = tt.inactive_file_id(conflict[1])
1231
            # special-case the other tree root (move its children instead)
6883.7.10 by Jelmer Vernooij
Avoid has_id.
1232
            if path_tree and path_tree.path2id('') == file_id:
7260.1.2 by Jelmer Vernooij
Fix flake8 issues.
1233
                # This is the root entry, skip it
7143.15.2 by Jelmer Vernooij
Run autopep8.
1234
                continue
7490.77.8 by Jelmer Vernooij
Change argument order for Transform.version_file.
1235
            tt.version_file(conflict[1], file_id=file_id)
1534.7.171 by Aaron Bentley
Implemented stringifying filesystem conflicts
1236
            new_conflicts.add((c_type, 'Versioned directory', conflict[1]))
3144.4.2 by Aaron Bentley
Handle non-directory parent conflicts (abentley, #177390)
1237
        elif c_type == 'non-directory parent':
1238
            parent_id = conflict[1]
1239
            parent_parent = tt.final_parent(parent_id)
1240
            parent_name = tt.final_name(parent_id)
1241
            parent_file_id = tt.final_file_id(parent_id)
1242
            new_parent_id = tt.new_directory(parent_name + '.new',
7143.15.2 by Jelmer Vernooij
Run autopep8.
1243
                                             parent_parent, parent_file_id)
3144.4.2 by Aaron Bentley
Handle non-directory parent conflicts (abentley, #177390)
1244
            _reparent_transform_children(tt, parent_id, new_parent_id)
3146.8.19 by Aaron Bentley
Merge with bzr.dev
1245
            if parent_file_id is not None:
1246
                tt.unversion_file(parent_id)
3144.4.2 by Aaron Bentley
Handle non-directory parent conflicts (abentley, #177390)
1247
            new_conflicts.add((c_type, 'Created directory', new_parent_id))
3363.10.29 by Aaron Bentley
Treat versioned files with no contents as a conflict
1248
        elif c_type == 'versioning no contents':
1249
            tt.cancel_versioning(conflict[1])
1534.7.169 by Aaron Bentley
Add filesystem/inventory conflicts to conflict output
1250
    return new_conflicts
1251
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
1252
1534.7.169 by Aaron Bentley
Add filesystem/inventory conflicts to conflict output
1253
def cook_conflicts(raw_conflicts, tt):
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
1254
    """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
1255
    conflict_iter = iter_cook_conflicts(raw_conflicts, tt)
5988.2.1 by Vincent Ladeuil
Do not generate path conflicts if a corresponding content conflict exists
1256
    return sorted(conflict_iter, key=conflicts.Conflict.sort_key)
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
1257
1534.7.169 by Aaron Bentley
Add filesystem/inventory conflicts to conflict output
1258
1259
def iter_cook_conflicts(raw_conflicts, tt):
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
1260
    fp = FinalPaths(tt)
1534.7.169 by Aaron Bentley
Add filesystem/inventory conflicts to conflict output
1261
    for conflict in raw_conflicts:
1262
        c_type = conflict[0]
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
1263
        action = conflict[1]
1264
        modified_path = fp.get_path(conflict[2])
1265
        modified_id = tt.final_file_id(conflict[2])
1266
        if len(conflict) == 3:
5988.2.1 by Vincent Ladeuil
Do not generate path conflicts if a corresponding content conflict exists
1267
            yield conflicts.Conflict.factory(
1268
                c_type, action=action, path=modified_path, file_id=modified_id)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1269
1534.7.170 by Aaron Bentley
Cleaned up filesystem conflict handling
1270
        else:
1271
            conflicting_path = fp.get_path(conflict[3])
1272
            conflicting_id = tt.final_file_id(conflict[3])
5988.2.1 by Vincent Ladeuil
Do not generate path conflicts if a corresponding content conflict exists
1273
            yield conflicts.Conflict.factory(
1274
                c_type, action=action, path=modified_path,
1275
                file_id=modified_id,
1276
                conflict_path=conflicting_path,
1277
                conflict_file_id=conflicting_id)
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
1278
1279
1280
class _FileMover(object):
2733.2.9 by Aaron Bentley
Update docstrings
1281
    """Moves and deletes files for TreeTransform, tracking operations"""
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
1282
1283
    def __init__(self):
1284
        self.past_renames = []
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
1285
        self.pending_deletions = []
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
1286
1287
    def rename(self, from_, to):
5186.2.2 by Martin Pool
wrap os.rename to insert the source and destination filenames in any exception that may be raised
1288
        """Rename a file from one path to another."""
3063.1.1 by Alexander Belchenko
Catch OSError 17 (file exists) in final phase of tree transform and show filename to user (#111758).
1289
        try:
5050.15.1 by Martin
Revert change of rename function in transform from r5192 to fix failures on Windows
1290
            os.rename(from_, to)
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
1291
        except OSError as e:
3063.1.3 by Aaron Bentley
Update for Linux
1292
            if e.errno in (errno.EEXIST, errno.ENOTEMPTY):
3063.1.1 by Alexander Belchenko
Catch OSError 17 (file exists) in final phase of tree transform and show filename to user (#111758).
1293
                raise errors.FileExists(to, str(e))
5186.2.5 by Martin Pool
Raise a specific clearer error when a rename fails inside transform
1294
            # normal OSError doesn't include filenames so it's hard to see where
1295
            # the problem is, see https://bugs.launchpad.net/bzr/+bug/491763
7490.77.4 by Jelmer Vernooij
Move some errors around.
1296
            raise TransformRenameFailed(from_, to, str(e), e.errno)
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
1297
        self.past_renames.append((from_, to))
1298
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
1299
    def pre_delete(self, from_, to):
2733.2.9 by Aaron Bentley
Update docstrings
1300
        """Rename a file out of the way and mark it for deletion.
1301
1302
        Unlike os.unlink, this works equally well for files and directories.
1303
        :param from_: The current file path
1304
        :param to: A temporary path for the file
1305
        """
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
1306
        self.rename(from_, to)
1307
        self.pending_deletions.append(to)
1308
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
1309
    def rollback(self):
2733.2.9 by Aaron Bentley
Update docstrings
1310
        """Reverse all renames that have been performed"""
2733.2.1 by Aaron Bentley
Implement FileMover, to support TreeTransform rollback
1311
        for from_, to in reversed(self.past_renames):
5186.2.7 by Martin Pool
Update other cases where transform detects failure to rename
1312
            try:
5050.15.1 by Martin
Revert change of rename function in transform from r5192 to fix failures on Windows
1313
                os.rename(to, from_)
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
1314
            except OSError as e:
7490.77.4 by Jelmer Vernooij
Move some errors around.
1315
                raise TransformRenameFailed(to, from_, str(e), e.errno)
2733.2.12 by Aaron Bentley
Updates from review
1316
        # after rollback, don't reuse _FileMover
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
1317
        self.past_renames = None
1318
        self.pending_deletions = None
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
1319
1320
    def apply_deletions(self):
2733.2.9 by Aaron Bentley
Update docstrings
1321
        """Apply all marked deletions"""
2733.2.5 by Aaron Bentley
Implement FileMover.pre_delete and FileMover.apply_deletions
1322
        for path in self.pending_deletions:
1323
            delete_any(path)
2733.2.12 by Aaron Bentley
Updates from review
1324
        # after apply_deletions, don't reuse _FileMover
7143.15.5 by Jelmer Vernooij
More PEP8 fixes.
1325
        self.past_renames = None
1326
        self.pending_deletions = None
6652.1.1 by Jelmer Vernooij
Bundle the link-tree command.
1327
1328
1329
def link_tree(target_tree, source_tree):
1330
    """Where possible, hard-link files in a tree to those in another tree.
1331
1332
    :param target_tree: Tree to change
1333
    :param source_tree: Tree to hard-link from
1334
    """
7490.77.2 by Jelmer Vernooij
Split out git and bzr-specific transforms.
1335
    with target_tree.transform() as tt:
7322.1.6 by Jelmer Vernooij
Use the new attributes on TreeChange.
1336
        for change in target_tree.iter_changes(source_tree, include_unchanged=True):
1337
            if change.changed_content:
1338
                continue
1339
            if change.kind != ('file', 'file'):
1340
                continue
1341
            if change.executable[0] != change.executable[1]:
1342
                continue
1343
            trans_id = tt.trans_id_tree_path(change.path[1])
6652.1.1 by Jelmer Vernooij
Bundle the link-tree command.
1344
            tt.delete_contents(trans_id)
7322.1.6 by Jelmer Vernooij
Use the new attributes on TreeChange.
1345
            tt.create_hardlink(source_tree.abspath(change.path[0]), trans_id)
6652.1.1 by Jelmer Vernooij
Bundle the link-tree command.
1346
        tt.apply()
7490.85.1 by Jelmer Vernooij
Factor out PreviewTree.
1347
1348
1349
class PreviewTree(object):
1350
    """Preview tree."""
1351
1352
    def __init__(self, transform):
1353
        self._transform = transform
7490.85.2 by Jelmer Vernooij
Split PreviewTree.
1354
        self._parent_ids = []
1355
        self.__by_parent = None
1356
        self._path2trans_id_cache = {}
1357
        self._all_children_cache = {}
1358
        self._final_name_cache = {}
1359
1360
    @property
1361
    def _by_parent(self):
1362
        if self.__by_parent is None:
1363
            self.__by_parent = self._transform.by_parent()
1364
        return self.__by_parent
1365
1366
    def get_parent_ids(self):
1367
        return self._parent_ids
1368
1369
    def set_parent_ids(self, parent_ids):
1370
        self._parent_ids = parent_ids
1371
1372
    def get_revision_tree(self, revision_id):
1373
        return self._transform._tree.get_revision_tree(revision_id)
1374
1375
    def is_locked(self):
1376
        return False
1377
1378
    def lock_read(self):
1379
        # Perhaps in theory, this should lock the TreeTransform?
1380
        return lock.LogicalLockResult(self.unlock)
1381
1382
    def unlock(self):
1383
        pass
1384
1385
    def _path2trans_id(self, path):
1386
        # We must not use None here, because that is a valid value to store.
1387
        trans_id = self._path2trans_id_cache.get(path, object)
1388
        if trans_id is not object:
1389
            return trans_id
1390
        segments = osutils.splitpath(path)
1391
        cur_parent = self._transform.root
1392
        for cur_segment in segments:
1393
            for child in self._all_children(cur_parent):
1394
                final_name = self._final_name_cache.get(child)
1395
                if final_name is None:
1396
                    final_name = self._transform.final_name(child)
1397
                    self._final_name_cache[child] = final_name
1398
                if final_name == cur_segment:
1399
                    cur_parent = child
1400
                    break
1401
            else:
1402
                self._path2trans_id_cache[path] = None
1403
                return None
1404
        self._path2trans_id_cache[path] = cur_parent
1405
        return cur_parent
1406
1407
    def _all_children(self, trans_id):
1408
        children = self._all_children_cache.get(trans_id)
1409
        if children is not None:
1410
            return children
1411
        children = set(self._transform.iter_tree_children(trans_id))
1412
        # children in the _new_parent set are provided by _by_parent.
1413
        children.difference_update(self._transform._new_parent)
1414
        children.update(self._by_parent.get(trans_id, []))
1415
        self._all_children_cache[trans_id] = children
1416
        return children
1417
1418
    def get_file_with_stat(self, path):
1419
        return self.get_file(path), None
1420
1421
    def is_executable(self, path):
1422
        trans_id = self._path2trans_id(path)
1423
        if trans_id is None:
1424
            return False
1425
        try:
1426
            return self._transform._new_executability[trans_id]
1427
        except KeyError:
1428
            try:
1429
                return self._transform._tree.is_executable(path)
1430
            except OSError as e:
1431
                if e.errno == errno.ENOENT:
1432
                    return False
1433
                raise
1434
            except errors.NoSuchFile:
1435
                return False
1436
1437
    def has_filename(self, path):
1438
        trans_id = self._path2trans_id(path)
1439
        if trans_id in self._transform._new_contents:
1440
            return True
1441
        elif trans_id in self._transform._removed_contents:
1442
            return False
1443
        else:
1444
            return self._transform._tree.has_filename(path)
1445
1446
    def get_file_sha1(self, path, stat_value=None):
1447
        trans_id = self._path2trans_id(path)
1448
        if trans_id is None:
1449
            raise errors.NoSuchFile(path)
1450
        kind = self._transform._new_contents.get(trans_id)
1451
        if kind is None:
1452
            return self._transform._tree.get_file_sha1(path)
1453
        if kind == 'file':
1454
            with self.get_file(path) as fileobj:
1455
                return osutils.sha_file(fileobj)
1456
1457
    def get_file_verifier(self, path, stat_value=None):
1458
        trans_id = self._path2trans_id(path)
1459
        if trans_id is None:
1460
            raise errors.NoSuchFile(path)
1461
        kind = self._transform._new_contents.get(trans_id)
1462
        if kind is None:
1463
            return self._transform._tree.get_file_verifier(path)
1464
        if kind == 'file':
1465
            with self.get_file(path) as fileobj:
1466
                return ("SHA1", osutils.sha_file(fileobj))
1467
1468
    def kind(self, path):
1469
        trans_id = self._path2trans_id(path)
1470
        if trans_id is None:
1471
            raise errors.NoSuchFile(path)
1472
        return self._transform.final_kind(trans_id)
1473
1474
    def stored_kind(self, path):
1475
        trans_id = self._path2trans_id(path)
1476
        if trans_id is None:
1477
            raise errors.NoSuchFile(path)
1478
        try:
1479
            return self._transform._new_contents[trans_id]
1480
        except KeyError:
1481
            return self._transform._tree.stored_kind(path)
1482
1483
    def _get_repository(self):
1484
        repo = getattr(self._transform._tree, '_repository', None)
1485
        if repo is None:
1486
            repo = self._transform._tree.branch.repository
1487
        return repo
1488
1489
    def _iter_parent_trees(self):
1490
        for revision_id in self.get_parent_ids():
1491
            try:
1492
                yield self.revision_tree(revision_id)
1493
            except errors.NoSuchRevisionInTree:
1494
                yield self._get_repository().revision_tree(revision_id)
1495
1496
    def get_file_size(self, path):
1497
        """See Tree.get_file_size"""
1498
        trans_id = self._path2trans_id(path)
1499
        if trans_id is None:
1500
            raise errors.NoSuchFile(path)
1501
        kind = self._transform.final_kind(trans_id)
1502
        if kind != 'file':
1503
            return None
1504
        if trans_id in self._transform._new_contents:
1505
            return self._stat_limbo_file(trans_id).st_size
1506
        if self.kind(path) == 'file':
1507
            return self._transform._tree.get_file_size(path)
1508
        else:
1509
            return None
1510
1511
    def get_reference_revision(self, path):
1512
        trans_id = self._path2trans_id(path)
1513
        if trans_id is None:
1514
            raise errors.NoSuchFile(path)
1515
        reference_revision = self._transform._new_reference_revision.get(trans_id)
1516
        if reference_revision is None:
1517
            return self._transform._tree.get_reference_revision(path)
1518
        return reference_revision
1519
1520
    def tree_kind(self, trans_id):
1521
        path = self._tree_id_paths.get(trans_id)
1522
        if path is None:
1523
            return None
1524
        kind = self._tree.path_content_summary(path)[0]
1525
        if kind == 'missing':
1526
            kind = None
1527
        return kind