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