~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

  • Committer: Vincent Ladeuil
  • Date: 2010-03-02 10:21:39 UTC
  • mfrom: (4797.2.24 2.1)
  • mto: This revision was merged to the branch mainline in revision 5069.
  • Revision ID: v.ladeuil+lp@free.fr-20100302102139-b5cba7h6xu13mekg
Merge 2.1 into trunk including fixes for #331095, #507557, #185103, #524184 and #369501

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""WorkingTree object and friends.
18
18
 
19
19
A WorkingTree represents the editable working copy of a branch.
20
 
Operations which represent the WorkingTree are also done here, 
21
 
such as renaming or adding files.  The WorkingTree has an inventory 
22
 
which is updated by these operations.  A commit produces a 
 
20
Operations which represent the WorkingTree are also done here,
 
21
such as renaming or adding files.  The WorkingTree has an inventory
 
22
which is updated by these operations.  A commit produces a
23
23
new revision based on the workingtree and its inventory.
24
24
 
25
25
At the moment every WorkingTree has its own branch.  Remote
48
48
import itertools
49
49
import operator
50
50
import stat
51
 
from time import time
52
 
import warnings
53
51
import re
54
52
 
55
53
import bzrlib
57
55
    branch,
58
56
    bzrdir,
59
57
    conflicts as _mod_conflicts,
60
 
    dirstate,
61
58
    errors,
62
59
    generate_ids,
63
60
    globbing,
 
61
    graph as _mod_graph,
64
62
    hashcache,
65
63
    ignores,
 
64
    inventory,
66
65
    merge,
67
66
    revision as _mod_revision,
68
67
    revisiontree,
69
 
    repository,
70
 
    textui,
71
68
    trace,
72
69
    transform,
73
70
    ui,
74
 
    urlutils,
 
71
    views,
75
72
    xml5,
76
 
    xml6,
77
73
    xml7,
78
74
    )
79
75
import bzrlib.branch
80
76
from bzrlib.transport import get_transport
81
 
import bzrlib.ui
82
 
from bzrlib.workingtree_4 import WorkingTreeFormat4
 
77
from bzrlib.workingtree_4 import (
 
78
    WorkingTreeFormat4,
 
79
    WorkingTreeFormat5,
 
80
    WorkingTreeFormat6,
 
81
    )
83
82
""")
84
83
 
85
84
from bzrlib import symbol_versioning
86
85
from bzrlib.decorators import needs_read_lock, needs_write_lock
87
 
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, TreeReference
88
 
from bzrlib.lockable_files import LockableFiles, TransportLock
 
86
from bzrlib.lockable_files import LockableFiles
89
87
from bzrlib.lockdir import LockDir
90
88
import bzrlib.mutabletree
91
89
from bzrlib.mutabletree import needs_tree_write_lock
92
90
from bzrlib import osutils
93
91
from bzrlib.osutils import (
94
 
    compact_date,
95
92
    file_kind,
96
93
    isdir,
97
94
    normpath,
98
95
    pathjoin,
99
 
    rand_chars,
100
96
    realpath,
101
97
    safe_unicode,
102
98
    splitpath,
103
99
    supports_executable,
104
100
    )
 
101
from bzrlib.filters import filtered_input_file
105
102
from bzrlib.trace import mutter, note
106
103
from bzrlib.transport.local import LocalTransport
107
 
from bzrlib.progress import DummyProgress, ProgressPhase
108
 
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
 
104
from bzrlib.progress import ProgressPhase
 
105
from bzrlib.revision import CURRENT_REVISION
109
106
from bzrlib.rio import RioReader, rio_file, Stanza
110
 
from bzrlib.symbol_versioning import (deprecated_passed,
111
 
        deprecated_method,
112
 
        deprecated_function,
113
 
        DEPRECATED_PARAMETER,
114
 
        zero_eight,
115
 
        zero_eleven,
116
 
        zero_thirteen,
117
 
        )
 
107
from bzrlib.symbol_versioning import (
 
108
    deprecated_passed,
 
109
    DEPRECATED_PARAMETER,
 
110
    )
118
111
 
119
112
 
120
113
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
 
114
# TODO: Modifying the conflict objects or their type is currently nearly
 
115
# impossible as there is no clear relationship between the working tree format
 
116
# and the conflict list file format.
121
117
CONFLICT_HEADER_1 = "BZR conflict list format 1"
122
118
 
123
119
ERROR_PATH_NOT_FOUND = 3    # WindowsError errno code, equivalent to ENOENT
124
120
 
125
121
 
126
 
@deprecated_function(zero_thirteen)
127
 
def gen_file_id(name):
128
 
    """Return new file id for the basename 'name'.
129
 
 
130
 
    Use bzrlib.generate_ids.gen_file_id() instead
131
 
    """
132
 
    return generate_ids.gen_file_id(name)
133
 
 
134
 
 
135
 
@deprecated_function(zero_thirteen)
136
 
def gen_root_id():
137
 
    """Return a new tree-root file id.
138
 
 
139
 
    This has been deprecated in favor of bzrlib.generate_ids.gen_root_id()
140
 
    """
141
 
    return generate_ids.gen_root_id()
142
 
 
143
 
 
144
122
class TreeEntry(object):
145
123
    """An entry that implements the minimum interface used by commands.
146
124
 
147
 
    This needs further inspection, it may be better to have 
 
125
    This needs further inspection, it may be better to have
148
126
    InventoryEntries without ids - though that seems wrong. For now,
149
127
    this is a parallel hierarchy to InventoryEntry, and needs to become
150
128
    one of several things: decorates to that hierarchy, children of, or
153
131
    no InventoryEntry available - i.e. for unversioned objects.
154
132
    Perhaps they should be UnversionedEntry et al. ? - RBC 20051003
155
133
    """
156
 
 
 
134
 
157
135
    def __eq__(self, other):
158
136
        # yes, this us ugly, TODO: best practice __eq__ style.
159
137
        return (isinstance(other, TreeEntry)
160
138
                and other.__class__ == self.__class__)
161
 
 
 
139
 
162
140
    def kind_character(self):
163
141
        return "???"
164
142
 
206
184
    not listed in the Inventory and vice versa.
207
185
    """
208
186
 
 
187
    # override this to set the strategy for storing views
 
188
    def _make_views(self):
 
189
        return views.DisabledViews(self)
 
190
 
209
191
    def __init__(self, basedir='.',
210
192
                 branch=DEPRECATED_PARAMETER,
211
193
                 _inventory=None,
222
204
        if not _internal:
223
205
            raise errors.BzrError("Please use bzrdir.open_workingtree or "
224
206
                "WorkingTree.open() to obtain a WorkingTree.")
225
 
        assert isinstance(basedir, basestring), \
226
 
            "base directory %r is not a string" % basedir
227
207
        basedir = safe_unicode(basedir)
228
208
        mutter("opening working tree %r", basedir)
229
209
        if deprecated_passed(branch):
237
217
            self._control_files = self.branch.control_files
238
218
        else:
239
219
            # assume all other formats have their own control files.
240
 
            assert isinstance(_control_files, LockableFiles), \
241
 
                    "_control_files must be a LockableFiles, not %r" \
242
 
                    % _control_files
243
220
            self._control_files = _control_files
 
221
        self._transport = self._control_files._transport
244
222
        # update the whole cache up front and write to disk if anything changed;
245
223
        # in the future we might want to do this more selectively
246
224
        # two possible ways offer themselves : in self._unlock, write the cache
250
228
        wt_trans = self.bzrdir.get_workingtree_transport(None)
251
229
        cache_filename = wt_trans.local_abspath('stat-cache')
252
230
        self._hashcache = hashcache.HashCache(basedir, cache_filename,
253
 
                                              self._control_files._file_mode)
 
231
            self.bzrdir._get_file_mode(),
 
232
            self._content_filter_stack_provider())
254
233
        hc = self._hashcache
255
234
        hc.read()
256
235
        # is this scan needed ? it makes things kinda slow.
270
249
            # the Format factory and creation methods that are
271
250
            # permitted to do this.
272
251
            self._set_inventory(_inventory, dirty=False)
 
252
        self._detect_case_handling()
 
253
        self._rules_searcher = None
 
254
        self.views = self._make_views()
 
255
 
 
256
    def _detect_case_handling(self):
 
257
        wt_trans = self.bzrdir.get_workingtree_transport(None)
 
258
        try:
 
259
            wt_trans.stat("FoRMaT")
 
260
        except errors.NoSuchFile:
 
261
            self.case_sensitive = True
 
262
        else:
 
263
            self.case_sensitive = False
 
264
 
 
265
        self._setup_directory_is_tree_reference()
273
266
 
274
267
    branch = property(
275
268
        fget=lambda self: self._branch,
290
283
        self._control_files.break_lock()
291
284
        self.branch.break_lock()
292
285
 
 
286
    def _get_check_refs(self):
 
287
        """Return the references needed to perform a check of this tree.
 
288
        
 
289
        The default implementation returns no refs, and is only suitable for
 
290
        trees that have no local caching and can commit on ghosts at any time.
 
291
 
 
292
        :seealso: bzrlib.check for details about check_refs.
 
293
        """
 
294
        return []
 
295
 
293
296
    def requires_rich_root(self):
294
297
        return self._format.requires_rich_root
295
298
 
296
299
    def supports_tree_reference(self):
297
300
        return False
298
301
 
 
302
    def supports_content_filtering(self):
 
303
        return self._format.supports_content_filtering()
 
304
 
 
305
    def supports_views(self):
 
306
        return self.views.supports_views()
 
307
 
299
308
    def _set_inventory(self, inv, dirty):
300
309
        """Set the internal cached inventory.
301
310
 
306
315
            False then the inventory is the same as that on disk and any
307
316
            serialisation would be unneeded overhead.
308
317
        """
309
 
        assert inv.root is not None
310
318
        self._inventory = inv
311
319
        self._inventory_is_modified = dirty
312
320
 
316
324
 
317
325
        """
318
326
        if path is None:
319
 
            path = os.path.getcwdu()
 
327
            path = osutils.getcwd()
320
328
        control = bzrdir.BzrDir.open(path, _unsupported)
321
329
        return control.open_workingtree(_unsupported)
322
 
        
 
330
 
323
331
    @staticmethod
324
332
    def open_containing(path=None):
325
333
        """Open an existing working tree which has its root about path.
326
 
        
 
334
 
327
335
        This probes for a working tree at path and searches upwards from there.
328
336
 
329
337
        Basically we keep looking up until we find the control directory or
347
355
        """
348
356
        return WorkingTree.open(path, _unsupported=True)
349
357
 
 
358
    @staticmethod
 
359
    def find_trees(location):
 
360
        def list_current(transport):
 
361
            return [d for d in transport.list_dir('') if d != '.bzr']
 
362
        def evaluate(bzrdir):
 
363
            try:
 
364
                tree = bzrdir.open_workingtree()
 
365
            except errors.NoWorkingTree:
 
366
                return True, None
 
367
            else:
 
368
                return True, tree
 
369
        transport = get_transport(location)
 
370
        iterator = bzrdir.BzrDir.find_bzrdirs(transport, evaluate=evaluate,
 
371
                                              list_current=list_current)
 
372
        return [t for t in iterator if t is not None]
 
373
 
350
374
    # should be deprecated - this is slow and in any case treating them as a
351
375
    # container is (we now know) bad style -- mbp 20070302
352
376
    ## @deprecated_method(zero_fifteen)
361
385
            if osutils.lexists(self.abspath(path)):
362
386
                yield ie.file_id
363
387
 
 
388
    def all_file_ids(self):
 
389
        """See Tree.iter_all_file_ids"""
 
390
        return set(self.inventory)
 
391
 
364
392
    def __repr__(self):
365
393
        return "<%s of %s>" % (self.__class__.__name__,
366
394
                               getattr(self, 'basedir', None))
370
398
 
371
399
    def basis_tree(self):
372
400
        """Return RevisionTree for the current last revision.
373
 
        
 
401
 
374
402
        If the left most parent is a ghost then the returned tree will be an
375
 
        empty tree - one obtained by calling repository.revision_tree(None).
 
403
        empty tree - one obtained by calling
 
404
        repository.revision_tree(NULL_REVISION).
376
405
        """
377
406
        try:
378
407
            revision_id = self.get_parent_ids()[0]
380
409
            # no parents, return an empty revision tree.
381
410
            # in the future this should return the tree for
382
411
            # 'empty:' - the implicit root empty tree.
383
 
            return self.branch.repository.revision_tree(None)
 
412
            return self.branch.repository.revision_tree(
 
413
                       _mod_revision.NULL_REVISION)
384
414
        try:
385
415
            return self.revision_tree(revision_id)
386
416
        except errors.NoSuchRevision:
390
420
        # at this point ?
391
421
        try:
392
422
            return self.branch.repository.revision_tree(revision_id)
393
 
        except errors.RevisionNotPresent:
 
423
        except (errors.RevisionNotPresent, errors.NoSuchRevision):
394
424
            # the basis tree *may* be a ghost or a low level error may have
395
 
            # occured. If the revision is present, its a problem, if its not
 
425
            # occurred. If the revision is present, its a problem, if its not
396
426
            # its a ghost.
397
427
            if self.branch.repository.has_revision(revision_id):
398
428
                raise
399
429
            # the basis tree is a ghost so return an empty tree.
400
 
            return self.branch.repository.revision_tree(None)
 
430
            return self.branch.repository.revision_tree(
 
431
                       _mod_revision.NULL_REVISION)
401
432
 
402
433
    def _cleanup(self):
403
434
        self._flush_ignore_list_cache()
404
435
 
405
 
    @staticmethod
406
 
    @deprecated_method(zero_eight)
407
 
    def create(branch, directory):
408
 
        """Create a workingtree for branch at directory.
409
 
 
410
 
        If existing_directory already exists it must have a .bzr directory.
411
 
        If it does not exist, it will be created.
412
 
 
413
 
        This returns a new WorkingTree object for the new checkout.
414
 
 
415
 
        TODO FIXME RBC 20060124 when we have checkout formats in place this
416
 
        should accept an optional revisionid to checkout [and reject this if
417
 
        checking out into the same dir as a pre-checkout-aware branch format.]
418
 
 
419
 
        XXX: When BzrDir is present, these should be created through that 
420
 
        interface instead.
421
 
        """
422
 
        warnings.warn('delete WorkingTree.create', stacklevel=3)
423
 
        transport = get_transport(directory)
424
 
        if branch.bzrdir.root_transport.base == transport.base:
425
 
            # same dir 
426
 
            return branch.bzrdir.create_workingtree()
427
 
        # different directory, 
428
 
        # create a branch reference
429
 
        # and now a working tree.
430
 
        raise NotImplementedError
431
 
 
432
 
    @staticmethod
433
 
    @deprecated_method(zero_eight)
434
 
    def create_standalone(directory):
435
 
        """Create a checkout and a branch and a repo at directory.
436
 
 
437
 
        Directory must exist and be empty.
438
 
 
439
 
        please use BzrDir.create_standalone_workingtree
440
 
        """
441
 
        return bzrdir.BzrDir.create_standalone_workingtree(directory)
442
 
 
443
436
    def relpath(self, path):
444
437
        """Return the local path portion from a given path.
445
 
        
446
 
        The path may be absolute or relative. If its a relative path it is 
 
438
 
 
439
        The path may be absolute or relative. If its a relative path it is
447
440
        interpreted relative to the python current working directory.
448
441
        """
449
442
        return osutils.relpath(self.basedir, path)
451
444
    def has_filename(self, filename):
452
445
        return osutils.lexists(self.abspath(filename))
453
446
 
454
 
    def get_file(self, file_id, path=None):
 
447
    def get_file(self, file_id, path=None, filtered=True):
 
448
        return self.get_file_with_stat(file_id, path, filtered=filtered)[0]
 
449
 
 
450
    def get_file_with_stat(self, file_id, path=None, filtered=True,
 
451
        _fstat=os.fstat):
 
452
        """See Tree.get_file_with_stat."""
455
453
        if path is None:
456
454
            path = self.id2path(file_id)
457
 
        return self.get_file_byname(path)
458
 
 
459
 
    def get_file_text(self, file_id):
460
 
        return self.get_file(file_id).read()
461
 
 
462
 
    def get_file_byname(self, filename):
463
 
        return file(self.abspath(filename), 'rb')
 
455
        file_obj = self.get_file_byname(path, filtered=False)
 
456
        stat_value = _fstat(file_obj.fileno())
 
457
        if filtered and self.supports_content_filtering():
 
458
            filters = self._content_filter_stack(path)
 
459
            file_obj = filtered_input_file(file_obj, filters)
 
460
        return (file_obj, stat_value)
 
461
 
 
462
    def get_file_text(self, file_id, path=None, filtered=True):
 
463
        return self.get_file(file_id, path=path, filtered=filtered).read()
 
464
 
 
465
    def get_file_byname(self, filename, filtered=True):
 
466
        path = self.abspath(filename)
 
467
        f = file(path, 'rb')
 
468
        if filtered and self.supports_content_filtering():
 
469
            filters = self._content_filter_stack(filename)
 
470
            return filtered_input_file(f, filters)
 
471
        else:
 
472
            return f
 
473
 
 
474
    def get_file_lines(self, file_id, path=None, filtered=True):
 
475
        """See Tree.get_file_lines()"""
 
476
        file = self.get_file(file_id, path, filtered=filtered)
 
477
        try:
 
478
            return file.readlines()
 
479
        finally:
 
480
            file.close()
464
481
 
465
482
    @needs_read_lock
466
483
    def annotate_iter(self, file_id, default_revision=CURRENT_REVISION):
473
490
        incorrectly attributed to CURRENT_REVISION (but after committing, the
474
491
        attribution will be correct).
475
492
        """
476
 
        basis = self.basis_tree()
477
 
        basis.lock_read()
478
 
        try:
479
 
            changes = self._iter_changes(basis, True, [self.id2path(file_id)],
480
 
                require_versioned=True).next()
481
 
            changed_content, kind = changes[2], changes[6]
482
 
            if not changed_content:
483
 
                return basis.annotate_iter(file_id)
484
 
            if kind[1] is None:
485
 
                return None
486
 
            import annotate
487
 
            if kind[0] != 'file':
488
 
                old_lines = []
489
 
            else:
490
 
                old_lines = list(basis.annotate_iter(file_id))
491
 
            old = [old_lines]
492
 
            for tree in self.branch.repository.revision_trees(
493
 
                self.get_parent_ids()[1:]):
494
 
                if file_id not in tree:
495
 
                    continue
496
 
                old.append(list(tree.annotate_iter(file_id)))
497
 
            return annotate.reannotate(old, self.get_file(file_id).readlines(),
498
 
                                       default_revision)
499
 
        finally:
500
 
            basis.unlock()
 
493
        maybe_file_parent_keys = []
 
494
        for parent_id in self.get_parent_ids():
 
495
            try:
 
496
                parent_tree = self.revision_tree(parent_id)
 
497
            except errors.NoSuchRevisionInTree:
 
498
                parent_tree = self.branch.repository.revision_tree(parent_id)
 
499
            parent_tree.lock_read()
 
500
            try:
 
501
                if file_id not in parent_tree:
 
502
                    continue
 
503
                ie = parent_tree.inventory[file_id]
 
504
                if ie.kind != 'file':
 
505
                    # Note: this is slightly unnecessary, because symlinks and
 
506
                    # directories have a "text" which is the empty text, and we
 
507
                    # know that won't mess up annotations. But it seems cleaner
 
508
                    continue
 
509
                parent_text_key = (file_id, ie.revision)
 
510
                if parent_text_key not in maybe_file_parent_keys:
 
511
                    maybe_file_parent_keys.append(parent_text_key)
 
512
            finally:
 
513
                parent_tree.unlock()
 
514
        graph = _mod_graph.Graph(self.branch.repository.texts)
 
515
        heads = graph.heads(maybe_file_parent_keys)
 
516
        file_parent_keys = []
 
517
        for key in maybe_file_parent_keys:
 
518
            if key in heads:
 
519
                file_parent_keys.append(key)
 
520
 
 
521
        # Now we have the parents of this content
 
522
        annotator = self.branch.repository.texts.get_annotator()
 
523
        text = self.get_file(file_id).read()
 
524
        this_key =(file_id, default_revision)
 
525
        annotator.add_special_text(this_key, file_parent_keys, text)
 
526
        annotations = [(key[-1], line)
 
527
                       for key, line in annotator.annotate_flat(this_key)]
 
528
        return annotations
501
529
 
502
530
    def _get_ancestors(self, default_revision):
503
531
        ancestors = set([default_revision])
508
536
 
509
537
    def get_parent_ids(self):
510
538
        """See Tree.get_parent_ids.
511
 
        
 
539
 
512
540
        This implementation reads the pending merges list and last_revision
513
541
        value and uses that to decide what the parents list should be.
514
542
        """
518
546
        else:
519
547
            parents = [last_rev]
520
548
        try:
521
 
            merges_file = self._control_files.get('pending-merges')
 
549
            merges_bytes = self._transport.get_bytes('pending-merges')
522
550
        except errors.NoSuchFile:
523
551
            pass
524
552
        else:
525
 
            for l in merges_file.readlines():
 
553
            for l in osutils.split_lines(merges_bytes):
526
554
                revision_id = l.rstrip('\n')
527
555
                parents.append(revision_id)
528
556
        return parents
531
559
    def get_root_id(self):
532
560
        """Return the id of this trees root"""
533
561
        return self._inventory.root.file_id
534
 
        
 
562
 
535
563
    def _get_store_filename(self, file_id):
536
564
        ## XXX: badly named; this is not in the store at all
537
565
        return self.abspath(self.id2path(file_id))
539
567
    @needs_read_lock
540
568
    def clone(self, to_bzrdir, revision_id=None):
541
569
        """Duplicate this working tree into to_bzr, including all state.
542
 
        
 
570
 
543
571
        Specifically modified files are kept as modified, but
544
572
        ignored and unknown files are discarded.
545
573
 
546
574
        If you want to make a new line of development, see bzrdir.sprout()
547
575
 
548
576
        revision
549
 
            If not None, the cloned tree will have its last revision set to 
550
 
            revision, and and difference between the source trees last revision
 
577
            If not None, the cloned tree will have its last revision set to
 
578
            revision, and difference between the source trees last revision
551
579
            and this one merged in.
552
580
        """
553
581
        # assumes the target bzr dir format is compatible.
554
 
        result = self._format.initialize(to_bzrdir)
 
582
        result = to_bzrdir.create_workingtree()
555
583
        self.copy_content_into(result, revision_id)
556
584
        return result
557
585
 
586
614
    __contains__ = has_id
587
615
 
588
616
    def get_file_size(self, file_id):
589
 
        return os.path.getsize(self.id2abspath(file_id))
 
617
        """See Tree.get_file_size"""
 
618
        # XXX: this returns the on-disk size; it should probably return the
 
619
        # canonical size
 
620
        try:
 
621
            return os.path.getsize(self.id2abspath(file_id))
 
622
        except OSError, e:
 
623
            if e.errno != errno.ENOENT:
 
624
                raise
 
625
            else:
 
626
                return None
590
627
 
591
628
    @needs_read_lock
592
629
    def get_file_sha1(self, file_id, path=None, stat_value=None):
601
638
 
602
639
    def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
603
640
        file_id = self.path2id(path)
 
641
        if file_id is None:
 
642
            # For unversioned files on win32, we just assume they are not
 
643
            # executable
 
644
            return False
604
645
        return self._inventory[file_id].executable
605
646
 
606
647
    def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
628
669
        """See MutableTree._add."""
629
670
        # TODO: Re-adding a file that is removed in the working copy
630
671
        # should probably put it back with the previous ID.
631
 
        # the read and write working inventory should not occur in this 
 
672
        # the read and write working inventory should not occur in this
632
673
        # function - they should be part of lock_write and unlock.
633
674
        inv = self.inventory
634
675
        for f, file_id, kind in zip(files, ids, kinds):
635
 
            assert kind is not None
636
676
            if file_id is None:
637
677
                inv.add_path(f, kind=kind)
638
678
            else:
717
757
            raise
718
758
        kind = _mapper(stat_result.st_mode)
719
759
        if kind == 'file':
720
 
            size = stat_result.st_size
721
 
            # try for a stat cache lookup
722
 
            executable = self._is_executable_from_path_and_stat(path, stat_result)
723
 
            return (kind, size, executable, self._sha_from_stat(
724
 
                path, stat_result))
 
760
            return self._file_content_summary(path, stat_result)
725
761
        elif kind == 'directory':
726
762
            # perhaps it looks like a plain directory, but it's really a
727
763
            # reference.
729
765
                kind = 'tree-reference'
730
766
            return kind, None, None, None
731
767
        elif kind == 'symlink':
732
 
            return ('symlink', None, None, os.readlink(abspath))
 
768
            target = osutils.readlink(abspath)
 
769
            return ('symlink', None, None, target)
733
770
        else:
734
771
            return (kind, None, None, None)
735
772
 
736
 
    @deprecated_method(zero_eleven)
737
 
    @needs_read_lock
738
 
    def pending_merges(self):
739
 
        """Return a list of pending merges.
740
 
 
741
 
        These are revisions that have been merged into the working
742
 
        directory but not yet committed.
743
 
 
744
 
        As of 0.11 this is deprecated. Please see WorkingTree.get_parent_ids()
745
 
        instead - which is available on all tree objects.
746
 
        """
747
 
        return self.get_parent_ids()[1:]
 
773
    def _file_content_summary(self, path, stat_result):
 
774
        size = stat_result.st_size
 
775
        executable = self._is_executable_from_path_and_stat(path, stat_result)
 
776
        # try for a stat cache lookup
 
777
        return ('file', size, executable, self._sha_from_stat(
 
778
            path, stat_result))
748
779
 
749
780
    def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
750
781
        """Common ghost checking functionality from set_parent_*.
760
791
 
761
792
    def _set_merges_from_parent_ids(self, parent_ids):
762
793
        merges = parent_ids[1:]
763
 
        self._control_files.put_bytes('pending-merges', '\n'.join(merges))
 
794
        self._transport.put_bytes('pending-merges', '\n'.join(merges),
 
795
            mode=self.bzrdir._get_file_mode())
 
796
 
 
797
    def _filter_parent_ids_by_ancestry(self, revision_ids):
 
798
        """Check that all merged revisions are proper 'heads'.
 
799
 
 
800
        This will always return the first revision_id, and any merged revisions
 
801
        which are
 
802
        """
 
803
        if len(revision_ids) == 0:
 
804
            return revision_ids
 
805
        graph = self.branch.repository.get_graph()
 
806
        heads = graph.heads(revision_ids)
 
807
        new_revision_ids = revision_ids[:1]
 
808
        for revision_id in revision_ids[1:]:
 
809
            if revision_id in heads and revision_id not in new_revision_ids:
 
810
                new_revision_ids.append(revision_id)
 
811
        if new_revision_ids != revision_ids:
 
812
            trace.mutter('requested to set revision_ids = %s,'
 
813
                         ' but filtered to %s', revision_ids, new_revision_ids)
 
814
        return new_revision_ids
764
815
 
765
816
    @needs_tree_write_lock
766
817
    def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
767
818
        """Set the parent ids to revision_ids.
768
 
        
 
819
 
769
820
        See also set_parent_trees. This api will try to retrieve the tree data
770
821
        for each element of revision_ids from the trees repository. If you have
771
822
        tree data already available, it is more efficient to use
780
831
        for revision_id in revision_ids:
781
832
            _mod_revision.check_not_reserved_id(revision_id)
782
833
 
 
834
        revision_ids = self._filter_parent_ids_by_ancestry(revision_ids)
 
835
 
783
836
        if len(revision_ids) > 0:
784
837
            self.set_last_revision(revision_ids[0])
785
838
        else:
797
850
        self._check_parents_for_ghosts(parent_ids,
798
851
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
799
852
 
 
853
        parent_ids = self._filter_parent_ids_by_ancestry(parent_ids)
 
854
 
800
855
        if len(parent_ids) == 0:
801
856
            leftmost_parent_id = _mod_revision.NULL_REVISION
802
857
            leftmost_parent_tree = None
842
897
    def _put_rio(self, filename, stanzas, header):
843
898
        self._must_be_locked()
844
899
        my_file = rio_file(stanzas, header)
845
 
        self._control_files.put(filename, my_file)
 
900
        self._transport.put_file(filename, my_file,
 
901
            mode=self.bzrdir._get_file_mode())
846
902
 
847
903
    @needs_write_lock # because merge pulls data into the branch.
848
904
    def merge_from_branch(self, branch, to_revision=None, from_revision=None,
849
 
        merge_type=None):
 
905
                          merge_type=None, force=False):
850
906
        """Merge from a branch into this working tree.
851
907
 
852
908
        :param branch: The branch to merge from.
856
912
            branch.last_revision().
857
913
        """
858
914
        from bzrlib.merge import Merger, Merge3Merger
859
 
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
860
 
        try:
861
 
            merger = Merger(self.branch, this_tree=self, pb=pb)
862
 
            merger.pp = ProgressPhase("Merge phase", 5, pb)
863
 
            merger.pp.next_phase()
864
 
            # check that there are no
865
 
            # local alterations
866
 
            merger.check_basis(check_clean=True, require_commits=False)
867
 
            if to_revision is None:
868
 
                to_revision = _mod_revision.ensure_null(branch.last_revision())
869
 
            merger.other_rev_id = to_revision
870
 
            if _mod_revision.is_null(merger.other_rev_id):
871
 
                raise errors.NoCommits(branch)
872
 
            self.branch.fetch(branch, last_revision=merger.other_rev_id)
873
 
            merger.other_basis = merger.other_rev_id
874
 
            merger.other_tree = self.branch.repository.revision_tree(
875
 
                merger.other_rev_id)
876
 
            merger.other_branch = branch
877
 
            merger.pp.next_phase()
878
 
            if from_revision is None:
879
 
                merger.find_base()
880
 
            else:
881
 
                merger.set_base_revision(from_revision, branch)
882
 
            if merger.base_rev_id == merger.other_rev_id:
883
 
                raise errors.PointlessMerge
884
 
            merger.backup_files = False
885
 
            if merge_type is None:
886
 
                merger.merge_type = Merge3Merger
887
 
            else:
888
 
                merger.merge_type = merge_type
889
 
            merger.set_interesting_files(None)
890
 
            merger.show_base = False
891
 
            merger.reprocess = False
892
 
            conflicts = merger.do_merge()
893
 
            merger.set_pending()
894
 
        finally:
895
 
            pb.finished()
 
915
        merger = Merger(self.branch, this_tree=self)
 
916
        # check that there are no local alterations
 
917
        if not force and self.has_changes():
 
918
            raise errors.UncommittedChanges(self)
 
919
        if to_revision is None:
 
920
            to_revision = _mod_revision.ensure_null(branch.last_revision())
 
921
        merger.other_rev_id = to_revision
 
922
        if _mod_revision.is_null(merger.other_rev_id):
 
923
            raise errors.NoCommits(branch)
 
924
        self.branch.fetch(branch, last_revision=merger.other_rev_id)
 
925
        merger.other_basis = merger.other_rev_id
 
926
        merger.other_tree = self.branch.repository.revision_tree(
 
927
            merger.other_rev_id)
 
928
        merger.other_branch = branch
 
929
        if from_revision is None:
 
930
            merger.find_base()
 
931
        else:
 
932
            merger.set_base_revision(from_revision, branch)
 
933
        if merger.base_rev_id == merger.other_rev_id:
 
934
            raise errors.PointlessMerge
 
935
        merger.backup_files = False
 
936
        if merge_type is None:
 
937
            merger.merge_type = Merge3Merger
 
938
        else:
 
939
            merger.merge_type = merge_type
 
940
        merger.set_interesting_files(None)
 
941
        merger.show_base = False
 
942
        merger.reprocess = False
 
943
        conflicts = merger.do_merge()
 
944
        merger.set_pending()
896
945
        return conflicts
897
946
 
898
947
    @needs_read_lock
899
948
    def merge_modified(self):
900
949
        """Return a dictionary of files modified by a merge.
901
950
 
902
 
        The list is initialized by WorkingTree.set_merge_modified, which is 
 
951
        The list is initialized by WorkingTree.set_merge_modified, which is
903
952
        typically called after we make some automatic updates to the tree
904
953
        because of a merge.
905
954
 
907
956
        still in the working inventory and have that text hash.
908
957
        """
909
958
        try:
910
 
            hashfile = self._control_files.get('merge-hashes')
 
959
            hashfile = self._transport.get('merge-hashes')
911
960
        except errors.NoSuchFile:
912
961
            return {}
913
 
        merge_hashes = {}
914
962
        try:
915
 
            if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
 
963
            merge_hashes = {}
 
964
            try:
 
965
                if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
 
966
                    raise errors.MergeModifiedFormatError()
 
967
            except StopIteration:
916
968
                raise errors.MergeModifiedFormatError()
917
 
        except StopIteration:
918
 
            raise errors.MergeModifiedFormatError()
919
 
        for s in RioReader(hashfile):
920
 
            # RioReader reads in Unicode, so convert file_ids back to utf8
921
 
            file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
922
 
            if file_id not in self.inventory:
923
 
                continue
924
 
            text_hash = s.get("hash")
925
 
            if text_hash == self.get_file_sha1(file_id):
926
 
                merge_hashes[file_id] = text_hash
927
 
        return merge_hashes
 
969
            for s in RioReader(hashfile):
 
970
                # RioReader reads in Unicode, so convert file_ids back to utf8
 
971
                file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
 
972
                if file_id not in self.inventory:
 
973
                    continue
 
974
                text_hash = s.get("hash")
 
975
                if text_hash == self.get_file_sha1(file_id):
 
976
                    merge_hashes[file_id] = text_hash
 
977
            return merge_hashes
 
978
        finally:
 
979
            hashfile.close()
928
980
 
929
981
    @needs_write_lock
930
982
    def mkdir(self, path, file_id=None):
936
988
        return file_id
937
989
 
938
990
    def get_symlink_target(self, file_id):
939
 
        return os.readlink(self.id2abspath(file_id))
 
991
        abspath = self.id2abspath(file_id)
 
992
        target = osutils.readlink(abspath)
 
993
        return target
940
994
 
941
995
    @needs_write_lock
942
996
    def subsume(self, other_tree):
980
1034
            other_tree.unlock()
981
1035
        other_tree.bzrdir.retire_bzrdir()
982
1036
 
983
 
    def _directory_is_tree_reference(self, relpath):
984
 
        # as a special case, if a directory contains control files then 
 
1037
    def _setup_directory_is_tree_reference(self):
 
1038
        if self._branch.repository._format.supports_tree_reference:
 
1039
            self._directory_is_tree_reference = \
 
1040
                self._directory_may_be_tree_reference
 
1041
        else:
 
1042
            self._directory_is_tree_reference = \
 
1043
                self._directory_is_never_tree_reference
 
1044
 
 
1045
    def _directory_is_never_tree_reference(self, relpath):
 
1046
        return False
 
1047
 
 
1048
    def _directory_may_be_tree_reference(self, relpath):
 
1049
        # as a special case, if a directory contains control files then
985
1050
        # it's a tree reference, except that the root of the tree is not
986
1051
        return relpath and osutils.isdir(self.abspath(relpath) + u"/.bzr")
987
1052
        # TODO: We could ask all the control formats whether they
998
1063
    @needs_tree_write_lock
999
1064
    def extract(self, file_id, format=None):
1000
1065
        """Extract a subtree from this tree.
1001
 
        
 
1066
 
1002
1067
        A new branch will be created, relative to the path for this tree.
1003
1068
        """
1004
1069
        self.flush()
1009
1074
                transport = transport.clone(name)
1010
1075
                transport.ensure_base()
1011
1076
            return transport
1012
 
            
 
1077
 
1013
1078
        sub_path = self.id2path(file_id)
1014
1079
        branch_transport = mkdirs(sub_path)
1015
1080
        if format is None:
1016
 
            format = bzrdir.format_registry.make_bzrdir('dirstate-with-subtree')
 
1081
            format = self.bzrdir.cloning_metadir()
1017
1082
        branch_transport.ensure_base()
1018
1083
        branch_bzrdir = format.initialize_on_transport(branch_transport)
1019
1084
        try:
1020
1085
            repo = branch_bzrdir.find_repository()
1021
1086
        except errors.NoRepositoryPresent:
1022
1087
            repo = branch_bzrdir.create_repository()
1023
 
            assert repo.supports_rich_root()
1024
 
        else:
1025
 
            if not repo.supports_rich_root():
1026
 
                raise errors.RootNotRich()
 
1088
        if not repo.supports_rich_root():
 
1089
            raise errors.RootNotRich()
1027
1090
        new_branch = branch_bzrdir.create_branch()
1028
1091
        new_branch.pull(self.branch)
1029
1092
        for parent_id in self.get_parent_ids():
1034
1097
            branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
1035
1098
        else:
1036
1099
            tree_bzrdir = branch_bzrdir
1037
 
        wt = tree_bzrdir.create_workingtree(NULL_REVISION)
 
1100
        wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
1038
1101
        wt.set_parent_ids(self.get_parent_ids())
1039
1102
        my_inv = self.inventory
1040
 
        child_inv = Inventory(root_id=None)
 
1103
        child_inv = inventory.Inventory(root_id=None)
1041
1104
        new_root = my_inv[file_id]
1042
1105
        my_inv.remove_recursive_id(file_id)
1043
1106
        new_root.parent_id = None
1061
1124
        sio = StringIO()
1062
1125
        self._serialize(self._inventory, sio)
1063
1126
        sio.seek(0)
1064
 
        self._control_files.put('inventory', sio)
 
1127
        self._transport.put_file('inventory', sio,
 
1128
            mode=self.bzrdir._get_file_mode())
1065
1129
        self._inventory_is_modified = False
1066
1130
 
1067
1131
    def _kind(self, relpath):
1068
1132
        return osutils.file_kind(self.abspath(relpath))
1069
1133
 
1070
 
    def list_files(self, include_root=False):
1071
 
        """Recursively list all files as (path, class, kind, id, entry).
 
1134
    def list_files(self, include_root=False, from_dir=None, recursive=True):
 
1135
        """List all files as (path, class, kind, id, entry).
1072
1136
 
1073
1137
        Lists, but does not descend into unversioned directories.
1074
 
 
1075
1138
        This does not include files that have been deleted in this
1076
 
        tree.
 
1139
        tree. Skips the control directory.
1077
1140
 
1078
 
        Skips the control directory.
 
1141
        :param include_root: if True, do not return an entry for the root
 
1142
        :param from_dir: start from this directory or None for the root
 
1143
        :param recursive: whether to recurse into subdirectories or not
1079
1144
        """
1080
1145
        # list_files is an iterator, so @needs_read_lock doesn't work properly
1081
1146
        # with it. So callers should be careful to always read_lock the tree.
1083
1148
            raise errors.ObjectNotLocked(self)
1084
1149
 
1085
1150
        inv = self.inventory
1086
 
        if include_root is True:
 
1151
        if from_dir is None and include_root is True:
1087
1152
            yield ('', 'V', 'directory', inv.root.file_id, inv.root)
1088
1153
        # Convert these into local objects to save lookup times
1089
1154
        pathjoin = osutils.pathjoin
1096
1161
        fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
1097
1162
 
1098
1163
        # directory file_id, relative path, absolute path, reverse sorted children
1099
 
        children = os.listdir(self.basedir)
 
1164
        if from_dir is not None:
 
1165
            from_dir_id = inv.path2id(from_dir)
 
1166
            if from_dir_id is None:
 
1167
                # Directory not versioned
 
1168
                return
 
1169
            from_dir_abspath = pathjoin(self.basedir, from_dir)
 
1170
        else:
 
1171
            from_dir_id = inv.root.file_id
 
1172
            from_dir_abspath = self.basedir
 
1173
        children = os.listdir(from_dir_abspath)
1100
1174
        children.sort()
1101
 
        # jam 20060527 The kernel sized tree seems equivalent whether we 
 
1175
        # jam 20060527 The kernel sized tree seems equivalent whether we
1102
1176
        # use a deque and popleft to keep them sorted, or if we use a plain
1103
1177
        # list and just reverse() them.
1104
1178
        children = collections.deque(children)
1105
 
        stack = [(inv.root.file_id, u'', self.basedir, children)]
 
1179
        stack = [(from_dir_id, u'', from_dir_abspath, children)]
1106
1180
        while stack:
1107
1181
            from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
1108
1182
 
1124
1198
 
1125
1199
                # absolute path
1126
1200
                fap = from_dir_abspath + '/' + f
1127
 
                
 
1201
 
1128
1202
                f_ie = inv.get_child(from_dir_id, f)
1129
1203
                if f_ie:
1130
1204
                    c = 'V'
1162
1236
                    except KeyError:
1163
1237
                        yield fp[1:], c, fk, None, TreeEntry()
1164
1238
                    continue
1165
 
                
 
1239
 
1166
1240
                if fk != 'directory':
1167
1241
                    continue
1168
1242
 
1169
 
                # But do this child first
1170
 
                new_children = os.listdir(fap)
1171
 
                new_children.sort()
1172
 
                new_children = collections.deque(new_children)
1173
 
                stack.append((f_ie.file_id, fp, fap, new_children))
1174
 
                # Break out of inner loop,
1175
 
                # so that we start outer loop with child
1176
 
                break
 
1243
                # But do this child first if recursing down
 
1244
                if recursive:
 
1245
                    new_children = os.listdir(fap)
 
1246
                    new_children.sort()
 
1247
                    new_children = collections.deque(new_children)
 
1248
                    stack.append((f_ie.file_id, fp, fap, new_children))
 
1249
                    # Break out of inner loop,
 
1250
                    # so that we start outer loop with child
 
1251
                    break
1177
1252
            else:
1178
1253
                # if we finished all children, pop it off the stack
1179
1254
                stack.pop()
1185
1260
        to_dir must exist in the inventory.
1186
1261
 
1187
1262
        If to_dir exists and is a directory, the files are moved into
1188
 
        it, keeping their old names.  
 
1263
        it, keeping their old names.
1189
1264
 
1190
1265
        Note that to_dir is only the last component of the new name;
1191
1266
        this doesn't change the directory.
1228
1303
                                       DeprecationWarning)
1229
1304
 
1230
1305
        # check destination directory
1231
 
        assert not isinstance(from_paths, basestring)
 
1306
        if isinstance(from_paths, basestring):
 
1307
            raise ValueError()
1232
1308
        inv = self.inventory
1233
1309
        to_abs = self.abspath(to_dir)
1234
1310
        if not isdir(to_abs):
1318
1394
                only_change_inv = True
1319
1395
            elif self.has_filename(from_rel) and not self.has_filename(to_rel):
1320
1396
                only_change_inv = False
 
1397
            elif (not self.case_sensitive
 
1398
                  and from_rel.lower() == to_rel.lower()
 
1399
                  and self.has_filename(from_rel)):
 
1400
                only_change_inv = False
1321
1401
            else:
1322
1402
                # something is wrong, so lets determine what exactly
1323
1403
                if not self.has_filename(from_rel) and \
1326
1406
                        errors.PathsDoNotExist(paths=(str(from_rel),
1327
1407
                        str(to_rel))))
1328
1408
                else:
1329
 
                    raise errors.RenameFailedFilesExist(from_rel, to_rel,
1330
 
                        extra="(Use --after to update the Bazaar id)")
 
1409
                    raise errors.RenameFailedFilesExist(from_rel, to_rel)
1331
1410
            rename_entry.only_change_inv = only_change_inv
1332
1411
        return rename_entries
1333
1412
 
1353
1432
        inv = self.inventory
1354
1433
        for entry in moved:
1355
1434
            try:
1356
 
                self._move_entry(_RenameEntry(entry.to_rel, entry.from_id,
 
1435
                self._move_entry(WorkingTree._RenameEntry(
 
1436
                    entry.to_rel, entry.from_id,
1357
1437
                    entry.to_tail, entry.to_parent_id, entry.from_rel,
1358
1438
                    entry.from_tail, entry.from_parent_id,
1359
1439
                    entry.only_change_inv))
1410
1490
        from_tail = splitpath(from_rel)[-1]
1411
1491
        from_id = inv.path2id(from_rel)
1412
1492
        if from_id is None:
1413
 
            raise errors.BzrRenameFailedError(from_rel,to_rel,
1414
 
                errors.NotVersionedError(path=str(from_rel)))
1415
 
        from_entry = inv[from_id]
 
1493
            # if file is missing in the inventory maybe it's in the basis_tree
 
1494
            basis_tree = self.branch.basis_tree()
 
1495
            from_id = basis_tree.path2id(from_rel)
 
1496
            if from_id is None:
 
1497
                raise errors.BzrRenameFailedError(from_rel,to_rel,
 
1498
                    errors.NotVersionedError(path=str(from_rel)))
 
1499
            # put entry back in the inventory so we can rename it
 
1500
            from_entry = basis_tree.inventory[from_id].copy()
 
1501
            inv.add(from_entry)
 
1502
        else:
 
1503
            from_entry = inv[from_id]
1416
1504
        from_parent_id = from_entry.parent_id
1417
1505
        to_dir, to_tail = os.path.split(to_rel)
1418
1506
        to_dir_id = inv.path2id(to_dir)
1464
1552
        These are files in the working directory that are not versioned or
1465
1553
        control files or ignored.
1466
1554
        """
1467
 
        # force the extras method to be fully executed before returning, to 
 
1555
        # force the extras method to be fully executed before returning, to
1468
1556
        # prevent race conditions with the lock
1469
1557
        return iter(
1470
1558
            [subp for subp in self.extras() if not self.is_ignored(subp)])
1480
1568
        :raises: NoSuchId if any fileid is not currently versioned.
1481
1569
        """
1482
1570
        for file_id in file_ids:
 
1571
            if file_id not in self._inventory:
 
1572
                raise errors.NoSuchId(self, file_id)
 
1573
        for file_id in file_ids:
1483
1574
            if self._inventory.has_id(file_id):
1484
1575
                self._inventory.remove_recursive_id(file_id)
1485
 
            else:
1486
 
                raise errors.NoSuchId(self, file_id)
1487
1576
        if len(file_ids):
1488
 
            # in the future this should just set a dirty bit to wait for the 
 
1577
            # in the future this should just set a dirty bit to wait for the
1489
1578
            # final unlock. However, until all methods of workingtree start
1490
 
            # with the current in -memory inventory rather than triggering 
 
1579
            # with the current in -memory inventory rather than triggering
1491
1580
            # a read, it is more complex - we need to teach read_inventory
1492
1581
            # to know when to read, and when to not read first... and possibly
1493
1582
            # to save first when the in memory one may be corrupted.
1494
1583
            # so for now, we just only write it if it is indeed dirty.
1495
1584
            # - RBC 20060907
1496
1585
            self._write_inventory(self._inventory)
1497
 
    
1498
 
    @deprecated_method(zero_eight)
1499
 
    def iter_conflicts(self):
1500
 
        """List all files in the tree that have text or content conflicts.
1501
 
        DEPRECATED.  Use conflicts instead."""
1502
 
        return self._iter_conflicts()
1503
1586
 
1504
1587
    def _iter_conflicts(self):
1505
1588
        conflicted = set()
1514
1597
 
1515
1598
    @needs_write_lock
1516
1599
    def pull(self, source, overwrite=False, stop_revision=None,
1517
 
             change_reporter=None, possible_transports=None):
1518
 
        top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
1600
             change_reporter=None, possible_transports=None, local=False):
1519
1601
        source.lock_read()
1520
1602
        try:
1521
 
            pp = ProgressPhase("Pull phase", 2, top_pb)
1522
 
            pp.next_phase()
1523
1603
            old_revision_info = self.branch.last_revision_info()
1524
1604
            basis_tree = self.basis_tree()
1525
1605
            count = self.branch.pull(source, overwrite, stop_revision,
1526
 
                                     possible_transports=possible_transports)
 
1606
                                     possible_transports=possible_transports,
 
1607
                                     local=local)
1527
1608
            new_revision_info = self.branch.last_revision_info()
1528
1609
            if new_revision_info != old_revision_info:
1529
 
                pp.next_phase()
1530
1610
                repository = self.branch.repository
1531
 
                pb = bzrlib.ui.ui_factory.nested_progress_bar()
1532
1611
                basis_tree.lock_read()
1533
1612
                try:
1534
1613
                    new_basis_tree = self.branch.basis_tree()
1537
1616
                                new_basis_tree,
1538
1617
                                basis_tree,
1539
1618
                                this_tree=self,
1540
 
                                pb=pb,
 
1619
                                pb=None,
1541
1620
                                change_reporter=change_reporter)
1542
 
                    if (basis_tree.inventory.root is None and
1543
 
                        new_basis_tree.inventory.root is not None):
1544
 
                        self.set_root_id(new_basis_tree.inventory.root.file_id)
 
1621
                    basis_root_id = basis_tree.get_root_id()
 
1622
                    new_root_id = new_basis_tree.get_root_id()
 
1623
                    if basis_root_id != new_root_id:
 
1624
                        self.set_root_id(new_root_id)
1545
1625
                finally:
1546
 
                    pb.finished()
1547
1626
                    basis_tree.unlock()
1548
1627
                # TODO - dedup parents list with things merged by pull ?
1549
1628
                # reuse the revisiontree we merged against to set the new
1550
1629
                # tree data.
1551
1630
                parent_trees = [(self.branch.last_revision(), new_basis_tree)]
1552
 
                # we have to pull the merge trees out again, because 
1553
 
                # merge_inner has set the ids. - this corner is not yet 
 
1631
                # we have to pull the merge trees out again, because
 
1632
                # merge_inner has set the ids. - this corner is not yet
1554
1633
                # layered well enough to prevent double handling.
1555
1634
                # XXX TODO: Fix the double handling: telling the tree about
1556
1635
                # the already known parent data is wasteful.
1562
1641
            return count
1563
1642
        finally:
1564
1643
            source.unlock()
1565
 
            top_pb.finished()
1566
1644
 
1567
1645
    @needs_write_lock
1568
1646
    def put_file_bytes_non_atomic(self, file_id, bytes):
1594
1672
 
1595
1673
            fl = []
1596
1674
            for subf in os.listdir(dirabs):
1597
 
                if subf == '.bzr':
 
1675
                if self.bzrdir.is_control_filename(subf):
1598
1676
                    continue
1599
1677
                if subf not in dir_entry.children:
1600
 
                    subf_norm, can_access = osutils.normalized_filename(subf)
 
1678
                    try:
 
1679
                        (subf_norm,
 
1680
                         can_access) = osutils.normalized_filename(subf)
 
1681
                    except UnicodeDecodeError:
 
1682
                        path_os_enc = path.encode(osutils._fs_enc)
 
1683
                        relpath = path_os_enc + '/' + subf
 
1684
                        raise errors.BadFilenameEncoding(relpath,
 
1685
                                                         osutils._fs_enc)
1601
1686
                    if subf_norm != subf and can_access:
1602
1687
                        if subf_norm not in dir_entry.children:
1603
1688
                            fl.append(subf_norm)
1604
1689
                    else:
1605
1690
                        fl.append(subf)
1606
 
            
 
1691
 
1607
1692
            fl.sort()
1608
1693
            for subf in fl:
1609
1694
                subp = pathjoin(path, subf)
1646
1731
        r"""Check whether the filename matches an ignore pattern.
1647
1732
 
1648
1733
        Patterns containing '/' or '\' need to match the whole path;
1649
 
        others match against only the last component.
 
1734
        others match against only the last component.  Patterns starting
 
1735
        with '!' are ignore exceptions.  Exceptions take precedence
 
1736
        over regular patterns and cause the filename to not be ignored.
1650
1737
 
1651
1738
        If the file is ignored, returns the pattern which caused it to
1652
1739
        be ignored, otherwise None.  So this can simply be used as a
1653
1740
        boolean if desired."""
1654
1741
        if getattr(self, '_ignoreglobster', None) is None:
1655
 
            self._ignoreglobster = globbing.Globster(self.get_ignore_list())
 
1742
            self._ignoreglobster = globbing.ExceptionGlobster(self.get_ignore_list())
1656
1743
        return self._ignoreglobster.match(filename)
1657
1744
 
1658
1745
    def kind(self, file_id):
1659
1746
        return file_kind(self.id2abspath(file_id))
1660
1747
 
 
1748
    def stored_kind(self, file_id):
 
1749
        """See Tree.stored_kind"""
 
1750
        return self.inventory[file_id].kind
 
1751
 
1661
1752
    def _comparison_data(self, entry, path):
1662
1753
        abspath = self.abspath(path)
1663
1754
        try:
1745
1836
    def _reset_data(self):
1746
1837
        """Reset transient data that cannot be revalidated."""
1747
1838
        self._inventory_is_modified = False
1748
 
        result = self._deserialize(self._control_files.get('inventory'))
 
1839
        f = self._transport.get('inventory')
 
1840
        try:
 
1841
            result = self._deserialize(f)
 
1842
        finally:
 
1843
            f.close()
1749
1844
        self._set_inventory(result, dirty=False)
1750
1845
 
1751
1846
    @needs_tree_write_lock
1756
1851
 
1757
1852
    def _change_last_revision(self, new_revision):
1758
1853
        """Template method part of set_last_revision to perform the change.
1759
 
        
 
1854
 
1760
1855
        This is used to allow WorkingTree3 instances to not affect branch
1761
1856
        when their last revision is set.
1762
1857
        """
1772
1867
 
1773
1868
    def _write_basis_inventory(self, xml):
1774
1869
        """Write the basis inventory XML to the basis-inventory file"""
1775
 
        assert isinstance(xml, str), 'serialised xml must be bytestring.'
1776
1870
        path = self._basis_inventory_name()
1777
1871
        sio = StringIO(xml)
1778
 
        self._control_files.put(path, sio)
 
1872
        self._transport.put_file(path, sio,
 
1873
            mode=self.bzrdir._get_file_mode())
1779
1874
 
1780
1875
    def _create_basis_xml_from_inventory(self, revision_id, inventory):
1781
1876
        """Create the text that will be saved in basis-inventory"""
1788
1883
        # as commit already has that ready-to-use [while the format is the
1789
1884
        # same, that is].
1790
1885
        try:
1791
 
            # this double handles the inventory - unpack and repack - 
 
1886
            # this double handles the inventory - unpack and repack -
1792
1887
            # but is easier to understand. We can/should put a conditional
1793
1888
            # in here based on whether the inventory is in the latest format
1794
1889
            # - perhaps we should repack all inventories on a repository
1795
1890
            # upgrade ?
1796
1891
            # the fast path is to copy the raw xml from the repository. If the
1797
 
            # xml contains 'revision_id="', then we assume the right 
 
1892
            # xml contains 'revision_id="', then we assume the right
1798
1893
            # revision_id is set. We must check for this full string, because a
1799
1894
            # root node id can legitimately look like 'revision_id' but cannot
1800
1895
            # contain a '"'.
1801
 
            xml = self.branch.repository.get_inventory_xml(new_revision)
 
1896
            xml = self.branch.repository._get_inventory_xml(new_revision)
1802
1897
            firstline = xml.split('\n', 1)[0]
1803
 
            if (not 'revision_id="' in firstline or 
 
1898
            if (not 'revision_id="' in firstline or
1804
1899
                'format="7"' not in firstline):
1805
 
                inv = self.branch.repository.deserialise_inventory(
1806
 
                    new_revision, xml)
 
1900
                inv = self.branch.repository._serializer.read_inventory_from_string(
 
1901
                    xml, new_revision)
1807
1902
                xml = self._create_basis_xml_from_inventory(new_revision, inv)
1808
1903
            self._write_basis_inventory(xml)
1809
1904
        except (errors.NoSuchRevision, errors.RevisionNotPresent):
1812
1907
    def read_basis_inventory(self):
1813
1908
        """Read the cached basis inventory."""
1814
1909
        path = self._basis_inventory_name()
1815
 
        return self._control_files.get(path).read()
1816
 
        
 
1910
        return self._transport.get_bytes(path)
 
1911
 
1817
1912
    @needs_read_lock
1818
1913
    def read_working_inventory(self):
1819
1914
        """Read the working inventory.
1820
 
        
 
1915
 
1821
1916
        :raises errors.InventoryModified: read_working_inventory will fail
1822
1917
            when the current in memory inventory has been modified.
1823
1918
        """
1824
 
        # conceptually this should be an implementation detail of the tree. 
 
1919
        # conceptually this should be an implementation detail of the tree.
1825
1920
        # XXX: Deprecate this.
1826
1921
        # ElementTree does its own conversion from UTF-8, so open in
1827
1922
        # binary.
1828
1923
        if self._inventory_is_modified:
1829
1924
            raise errors.InventoryModified(self)
1830
 
        result = self._deserialize(self._control_files.get('inventory'))
 
1925
        f = self._transport.get('inventory')
 
1926
        try:
 
1927
            result = self._deserialize(f)
 
1928
        finally:
 
1929
            f.close()
1831
1930
        self._set_inventory(result, dirty=False)
1832
1931
        return result
1833
1932
 
1848
1947
 
1849
1948
        new_files=set()
1850
1949
        unknown_nested_files=set()
 
1950
        if to_file is None:
 
1951
            to_file = sys.stdout
1851
1952
 
1852
1953
        def recurse_directory_to_add_files(directory):
1853
1954
            # Recurse directory and add all files
1854
1955
            # so we can check if they have changed.
1855
1956
            for parent_info, file_infos in\
1856
 
                osutils.walkdirs(self.abspath(directory),
1857
 
                    directory):
1858
 
                for relpath, basename, kind, lstat, abspath in file_infos:
 
1957
                self.walkdirs(directory):
 
1958
                for relpath, basename, kind, lstat, fileid, kind in file_infos:
1859
1959
                    # Is it versioned or ignored?
1860
1960
                    if self.path2id(relpath) or self.is_ignored(relpath):
1861
1961
                        # Add nested content for deletion.
1871
1971
            filename = self.relpath(abspath)
1872
1972
            if len(filename) > 0:
1873
1973
                new_files.add(filename)
1874
 
                if osutils.isdir(abspath):
1875
 
                    recurse_directory_to_add_files(filename)
 
1974
                recurse_directory_to_add_files(filename)
1876
1975
 
1877
1976
        files = list(new_files)
1878
1977
 
1887
1986
            has_changed_files = len(unknown_nested_files) > 0
1888
1987
            if not has_changed_files:
1889
1988
                for (file_id, path, content_change, versioned, parent_id, name,
1890
 
                     kind, executable) in self._iter_changes(self.basis_tree(),
 
1989
                     kind, executable) in self.iter_changes(self.basis_tree(),
1891
1990
                         include_unchanged=True, require_versioned=False,
1892
1991
                         want_unversioned=True, specific_files=files):
1893
 
                    # Check if it's an unknown (but not ignored) OR
1894
 
                    # changed (but not deleted) :
1895
 
                    if not self.is_ignored(path[1]) and (
1896
 
                        versioned == (False, False) or
1897
 
                        content_change and kind[1] != None):
 
1992
                    if versioned == (False, False):
 
1993
                        # The record is unknown ...
 
1994
                        if not self.is_ignored(path[1]):
 
1995
                            # ... but not ignored
 
1996
                            has_changed_files = True
 
1997
                            break
 
1998
                    elif content_change and (kind[1] is not None):
 
1999
                        # Versioned and changed, but not deleted
1898
2000
                        has_changed_files = True
1899
2001
                        break
1900
2002
 
1908
2010
                        tree_delta.unversioned.extend((unknown_file,))
1909
2011
                raise errors.BzrRemoveChangedFilesError(tree_delta)
1910
2012
 
1911
 
        # Build inv_delta and delete files where applicaple,
 
2013
        # Build inv_delta and delete files where applicable,
1912
2014
        # do this before any modifications to inventory.
1913
2015
        for f in files:
1914
2016
            fid = self.path2id(f)
1922
2024
                        new_status = 'I'
1923
2025
                    else:
1924
2026
                        new_status = '?'
1925
 
                    textui.show_status(new_status, self.kind(fid), f,
1926
 
                                       to_file=to_file)
 
2027
                    # XXX: Really should be a more abstract reporter interface
 
2028
                    kind_ch = osutils.kind_marker(self.kind(fid))
 
2029
                    to_file.write(new_status + '       ' + f + kind_ch + '\n')
1927
2030
                # Unversion file
1928
2031
                inv_delta.append((f, None, fid, None))
1929
2032
                message = "removed %s" % (f,)
1952
2055
 
1953
2056
    @needs_tree_write_lock
1954
2057
    def revert(self, filenames=None, old_tree=None, backups=True,
1955
 
               pb=DummyProgress(), report_changes=False):
 
2058
               pb=None, report_changes=False):
1956
2059
        from bzrlib.conflicts import resolve
1957
2060
        if filenames == []:
1958
2061
            filenames = None
1971
2074
            if filenames is None and len(self.get_parent_ids()) > 1:
1972
2075
                parent_trees = []
1973
2076
                last_revision = self.last_revision()
1974
 
                if last_revision != NULL_REVISION:
 
2077
                if last_revision != _mod_revision.NULL_REVISION:
1975
2078
                    if basis_tree is None:
1976
2079
                        basis_tree = self.basis_tree()
1977
2080
                        basis_tree.lock_read()
1979
2082
                self.set_parent_trees(parent_trees)
1980
2083
                resolve(self)
1981
2084
            else:
1982
 
                resolve(self, filenames, ignore_misses=True)
 
2085
                resolve(self, filenames, ignore_misses=True, recursive=True)
1983
2086
        finally:
1984
2087
            if basis_tree is not None:
1985
2088
                basis_tree.unlock()
2015
2118
    def set_inventory(self, new_inventory_list):
2016
2119
        from bzrlib.inventory import (Inventory,
2017
2120
                                      InventoryDirectory,
2018
 
                                      InventoryEntry,
2019
2121
                                      InventoryFile,
2020
2122
                                      InventoryLink)
2021
2123
        inv = Inventory(self.get_root_id())
2023
2125
            name = os.path.basename(path)
2024
2126
            if name == "":
2025
2127
                continue
2026
 
            # fixme, there should be a factory function inv,add_?? 
 
2128
            # fixme, there should be a factory function inv,add_??
2027
2129
            if kind == 'directory':
2028
2130
                inv.add(InventoryDirectory(file_id, name, parent))
2029
2131
            elif kind == 'file':
2037
2139
    @needs_tree_write_lock
2038
2140
    def set_root_id(self, file_id):
2039
2141
        """Set the root id for this tree."""
2040
 
        # for compatability 
 
2142
        # for compatability
2041
2143
        if file_id is None:
2042
 
            symbol_versioning.warn(symbol_versioning.zero_twelve
2043
 
                % 'WorkingTree.set_root_id with fileid=None',
2044
 
                DeprecationWarning,
2045
 
                stacklevel=3)
2046
 
            file_id = ROOT_ID
2047
 
        else:
2048
 
            file_id = osutils.safe_file_id(file_id)
 
2144
            raise ValueError(
 
2145
                'WorkingTree.set_root_id with fileid=None')
 
2146
        file_id = osutils.safe_file_id(file_id)
2049
2147
        self._set_root_id(file_id)
2050
2148
 
2051
2149
    def _set_root_id(self, file_id):
2052
2150
        """Set the root id for this tree, in a format specific manner.
2053
2151
 
2054
 
        :param file_id: The file id to assign to the root. It must not be 
 
2152
        :param file_id: The file id to assign to the root. It must not be
2055
2153
            present in the current inventory or an error will occur. It must
2056
2154
            not be None, but rather a valid file id.
2057
2155
        """
2076
2174
 
2077
2175
    def unlock(self):
2078
2176
        """See Branch.unlock.
2079
 
        
 
2177
 
2080
2178
        WorkingTree locking just uses the Branch locking facilities.
2081
2179
        This is current because all working trees have an embedded branch
2082
2180
        within them. IF in the future, we were to make branch data shareable
2083
 
        between multiple working trees, i.e. via shared storage, then we 
 
2181
        between multiple working trees, i.e. via shared storage, then we
2084
2182
        would probably want to lock both the local tree, and the branch.
2085
2183
        """
2086
2184
        raise NotImplementedError(self.unlock)
2087
2185
 
2088
 
    def update(self, change_reporter=None, possible_transports=None):
 
2186
    _marker = object()
 
2187
 
 
2188
    def update(self, change_reporter=None, possible_transports=None,
 
2189
               revision=None, old_tip=_marker):
2089
2190
        """Update a working tree along its branch.
2090
2191
 
2091
2192
        This will update the branch if its bound too, which means we have
2109
2210
        - Merge current state -> basis tree of the master w.r.t. the old tree
2110
2211
          basis.
2111
2212
        - Do a 'normal' merge of the old branch basis if it is relevant.
 
2213
 
 
2214
        :param revision: The target revision to update to. Must be in the
 
2215
            revision history.
 
2216
        :param old_tip: If branch.update() has already been run, the value it
 
2217
            returned (old tip of the branch or None). _marker is used
 
2218
            otherwise.
2112
2219
        """
2113
 
        if self.branch.get_master_branch(possible_transports) is not None:
 
2220
        if self.branch.get_bound_location() is not None:
2114
2221
            self.lock_write()
2115
 
            update_branch = True
 
2222
            update_branch = (old_tip is self._marker)
2116
2223
        else:
2117
2224
            self.lock_tree_write()
2118
2225
            update_branch = False
2120
2227
            if update_branch:
2121
2228
                old_tip = self.branch.update(possible_transports)
2122
2229
            else:
2123
 
                old_tip = None
2124
 
            return self._update_tree(old_tip, change_reporter)
 
2230
                if old_tip is self._marker:
 
2231
                    old_tip = None
 
2232
            return self._update_tree(old_tip, change_reporter, revision)
2125
2233
        finally:
2126
2234
            self.unlock()
2127
2235
 
2128
2236
    @needs_tree_write_lock
2129
 
    def _update_tree(self, old_tip=None, change_reporter=None):
 
2237
    def _update_tree(self, old_tip=None, change_reporter=None, revision=None):
2130
2238
        """Update a tree to the master branch.
2131
2239
 
2132
2240
        :param old_tip: if supplied, the previous tip revision the branch,
2138
2246
        # cant set that until we update the working trees last revision to be
2139
2247
        # one from the new branch, because it will just get absorbed by the
2140
2248
        # parent de-duplication logic.
2141
 
        # 
 
2249
        #
2142
2250
        # We MUST save it even if an error occurs, because otherwise the users
2143
2251
        # local work is unreferenced and will appear to have been lost.
2144
 
        # 
2145
 
        result = 0
 
2252
        #
 
2253
        nb_conflicts = 0
2146
2254
        try:
2147
2255
            last_rev = self.get_parent_ids()[0]
2148
2256
        except IndexError:
2149
2257
            last_rev = _mod_revision.NULL_REVISION
2150
 
        if last_rev != _mod_revision.ensure_null(self.branch.last_revision()):
2151
 
            # merge tree state up to new branch tip.
 
2258
        if revision is None:
 
2259
            revision = self.branch.last_revision()
 
2260
        else:
 
2261
            if revision not in self.branch.revision_history():
 
2262
                raise errors.NoSuchRevision(self.branch, revision)
 
2263
 
 
2264
        old_tip = old_tip or _mod_revision.NULL_REVISION
 
2265
 
 
2266
        if not _mod_revision.is_null(old_tip) and old_tip != last_rev:
 
2267
            # the branch we are bound to was updated
 
2268
            # merge those changes in first
 
2269
            base_tree  = self.basis_tree()
 
2270
            other_tree = self.branch.repository.revision_tree(old_tip)
 
2271
            nb_conflicts = merge.merge_inner(self.branch, other_tree,
 
2272
                                             base_tree, this_tree=self,
 
2273
                                             change_reporter=change_reporter)
 
2274
            if nb_conflicts:
 
2275
                self.add_parent_tree((old_tip, other_tree))
 
2276
                trace.note('Rerun update after fixing the conflicts.')
 
2277
                return nb_conflicts
 
2278
 
 
2279
        if last_rev != _mod_revision.ensure_null(revision):
 
2280
            # the working tree is up to date with the branch
 
2281
            # we can merge the specified revision from master
 
2282
            to_tree = self.branch.repository.revision_tree(revision)
 
2283
            to_root_id = to_tree.get_root_id()
 
2284
 
2152
2285
            basis = self.basis_tree()
2153
2286
            basis.lock_read()
2154
2287
            try:
2155
 
                to_tree = self.branch.basis_tree()
2156
 
                if basis.inventory.root is None:
2157
 
                    self.set_root_id(to_tree.inventory.root.file_id)
 
2288
                if (basis.inventory.root is None
 
2289
                    or basis.inventory.root.file_id != to_root_id):
 
2290
                    self.set_root_id(to_root_id)
2158
2291
                    self.flush()
2159
 
                result += merge.merge_inner(
2160
 
                                      self.branch,
2161
 
                                      to_tree,
2162
 
                                      basis,
2163
 
                                      this_tree=self,
2164
 
                                      change_reporter=change_reporter)
2165
2292
            finally:
2166
2293
                basis.unlock()
 
2294
 
 
2295
            # determine the branch point
 
2296
            graph = self.branch.repository.get_graph()
 
2297
            base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
 
2298
                                                last_rev)
 
2299
            base_tree = self.branch.repository.revision_tree(base_rev_id)
 
2300
 
 
2301
            nb_conflicts = merge.merge_inner(self.branch, to_tree, base_tree,
 
2302
                                             this_tree=self,
 
2303
                                             change_reporter=change_reporter)
 
2304
            self.set_last_revision(revision)
2167
2305
            # TODO - dedup parents list with things merged by pull ?
2168
2306
            # reuse the tree we've updated to to set the basis:
2169
 
            parent_trees = [(self.branch.last_revision(), to_tree)]
 
2307
            parent_trees = [(revision, to_tree)]
2170
2308
            merges = self.get_parent_ids()[1:]
2171
2309
            # Ideally we ask the tree for the trees here, that way the working
2172
 
            # tree can decide whether to give us teh entire tree or give us a
 
2310
            # tree can decide whether to give us the entire tree or give us a
2173
2311
            # lazy initialised tree. dirstate for instance will have the trees
2174
2312
            # in ram already, whereas a last-revision + basis-inventory tree
2175
2313
            # will not, but also does not need them when setting parents.
2176
2314
            for parent in merges:
2177
2315
                parent_trees.append(
2178
2316
                    (parent, self.branch.repository.revision_tree(parent)))
2179
 
            if (old_tip is not None and not _mod_revision.is_null(old_tip)):
 
2317
            if not _mod_revision.is_null(old_tip):
2180
2318
                parent_trees.append(
2181
2319
                    (old_tip, self.branch.repository.revision_tree(old_tip)))
2182
2320
            self.set_parent_trees(parent_trees)
2183
2321
            last_rev = parent_trees[0][0]
2184
 
        else:
2185
 
            # the working tree had the same last-revision as the master
2186
 
            # branch did. We may still have pivot local work from the local
2187
 
            # branch into old_tip:
2188
 
            if (old_tip is not None and not _mod_revision.is_null(old_tip)):
2189
 
                self.add_parent_tree_id(old_tip)
2190
 
        if (old_tip is not None and not _mod_revision.is_null(old_tip)
2191
 
            and old_tip != last_rev):
2192
 
            # our last revision was not the prior branch last revision
2193
 
            # and we have converted that last revision to a pending merge.
2194
 
            # base is somewhere between the branch tip now
2195
 
            # and the now pending merge
2196
 
 
2197
 
            # Since we just modified the working tree and inventory, flush out
2198
 
            # the current state, before we modify it again.
2199
 
            # TODO: jam 20070214 WorkingTree3 doesn't require this, dirstate
2200
 
            #       requires it only because TreeTransform directly munges the
2201
 
            #       inventory and calls tree._write_inventory(). Ultimately we
2202
 
            #       should be able to remove this extra flush.
2203
 
            self.flush()
2204
 
            graph = self.branch.repository.get_graph()
2205
 
            base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
2206
 
                                                old_tip)
2207
 
            base_tree = self.branch.repository.revision_tree(base_rev_id)
2208
 
            other_tree = self.branch.repository.revision_tree(old_tip)
2209
 
            result += merge.merge_inner(
2210
 
                                  self.branch,
2211
 
                                  other_tree,
2212
 
                                  base_tree,
2213
 
                                  this_tree=self,
2214
 
                                  change_reporter=change_reporter)
2215
 
        return result
 
2322
        return nb_conflicts
2216
2323
 
2217
2324
    def _write_hashcache_if_dirty(self):
2218
2325
        """Write out the hashcache if it is dirty."""
2302
2409
            current_inv = None
2303
2410
            inv_finished = True
2304
2411
        while not inv_finished or not disk_finished:
 
2412
            if current_disk:
 
2413
                ((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
 
2414
                    cur_disk_dir_content) = current_disk
 
2415
            else:
 
2416
                ((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
 
2417
                    cur_disk_dir_content) = ((None, None), None)
2305
2418
            if not disk_finished:
2306
2419
                # strip out .bzr dirs
2307
 
                if current_disk[0][1][top_strip_len:] == '':
2308
 
                    # osutils.walkdirs can be made nicer - 
 
2420
                if (cur_disk_dir_path_from_top[top_strip_len:] == '' and
 
2421
                    len(cur_disk_dir_content) > 0):
 
2422
                    # osutils.walkdirs can be made nicer -
2309
2423
                    # yield the path-from-prefix rather than the pathjoined
2310
2424
                    # value.
2311
 
                    bzrdir_loc = bisect_left(current_disk[1], ('.bzr', '.bzr'))
2312
 
                    if current_disk[1][bzrdir_loc][0] == '.bzr':
 
2425
                    bzrdir_loc = bisect_left(cur_disk_dir_content,
 
2426
                        ('.bzr', '.bzr'))
 
2427
                    if (bzrdir_loc < len(cur_disk_dir_content)
 
2428
                        and self.bzrdir.is_control_filename(
 
2429
                            cur_disk_dir_content[bzrdir_loc][0])):
2313
2430
                        # we dont yield the contents of, or, .bzr itself.
2314
 
                        del current_disk[1][bzrdir_loc]
 
2431
                        del cur_disk_dir_content[bzrdir_loc]
2315
2432
            if inv_finished:
2316
2433
                # everything is unknown
2317
2434
                direction = 1
2319
2436
                # everything is missing
2320
2437
                direction = -1
2321
2438
            else:
2322
 
                direction = cmp(current_inv[0][0], current_disk[0][0])
 
2439
                direction = cmp(current_inv[0][0], cur_disk_dir_relpath)
2323
2440
            if direction > 0:
2324
2441
                # disk is before inventory - unknown
2325
2442
                dirblock = [(relpath, basename, kind, stat, None, None) for
2326
 
                    relpath, basename, kind, stat, top_path in current_disk[1]]
2327
 
                yield (current_disk[0][0], None), dirblock
 
2443
                    relpath, basename, kind, stat, top_path in
 
2444
                    cur_disk_dir_content]
 
2445
                yield (cur_disk_dir_relpath, None), dirblock
2328
2446
                try:
2329
2447
                    current_disk = disk_iterator.next()
2330
2448
                except StopIteration:
2332
2450
            elif direction < 0:
2333
2451
                # inventory is before disk - missing.
2334
2452
                dirblock = [(relpath, basename, 'unknown', None, fileid, kind)
2335
 
                    for relpath, basename, dkind, stat, fileid, kind in 
 
2453
                    for relpath, basename, dkind, stat, fileid, kind in
2336
2454
                    current_inv[1]]
2337
2455
                yield (current_inv[0][0], current_inv[0][1]), dirblock
2338
2456
                try:
2344
2462
                # merge the inventory and disk data together
2345
2463
                dirblock = []
2346
2464
                for relpath, subiterator in itertools.groupby(sorted(
2347
 
                    current_inv[1] + current_disk[1], key=operator.itemgetter(0)), operator.itemgetter(1)):
 
2465
                    current_inv[1] + cur_disk_dir_content,
 
2466
                    key=operator.itemgetter(0)), operator.itemgetter(1)):
2348
2467
                    path_elements = list(subiterator)
2349
2468
                    if len(path_elements) == 2:
2350
2469
                        inv_row, disk_row = path_elements
2403
2522
                relroot = ""
2404
2523
            # FIXME: stash the node in pending
2405
2524
            entry = inv[top_id]
2406
 
            for name, child in entry.sorted_children():
2407
 
                dirblock.append((relroot + name, name, child.kind, None,
2408
 
                    child.file_id, child.kind
2409
 
                    ))
 
2525
            if entry.kind == 'directory':
 
2526
                for name, child in entry.sorted_children():
 
2527
                    dirblock.append((relroot + name, name, child.kind, None,
 
2528
                        child.file_id, child.kind
 
2529
                        ))
2410
2530
            yield (currentdir[0], entry.file_id), dirblock
2411
2531
            # push the user specified dirs from dirblock
2412
2532
            for dir in reversed(dirblock):
2445
2565
        self.set_conflicts(un_resolved)
2446
2566
        return un_resolved, resolved
2447
2567
 
 
2568
    @needs_read_lock
 
2569
    def _check(self, references):
 
2570
        """Check the tree for consistency.
 
2571
 
 
2572
        :param references: A dict with keys matching the items returned by
 
2573
            self._get_check_refs(), and values from looking those keys up in
 
2574
            the repository.
 
2575
        """
 
2576
        tree_basis = self.basis_tree()
 
2577
        tree_basis.lock_read()
 
2578
        try:
 
2579
            repo_basis = references[('trees', self.last_revision())]
 
2580
            if len(list(repo_basis.iter_changes(tree_basis))) > 0:
 
2581
                raise errors.BzrCheckError(
 
2582
                    "Mismatched basis inventory content.")
 
2583
            self._validate()
 
2584
        finally:
 
2585
            tree_basis.unlock()
 
2586
 
2448
2587
    def _validate(self):
2449
2588
        """Validate internal structures.
2450
2589
 
2456
2595
        """
2457
2596
        return
2458
2597
 
 
2598
    def _get_rules_searcher(self, default_searcher):
 
2599
        """See Tree._get_rules_searcher."""
 
2600
        if self._rules_searcher is None:
 
2601
            self._rules_searcher = super(WorkingTree,
 
2602
                self)._get_rules_searcher(default_searcher)
 
2603
        return self._rules_searcher
 
2604
 
 
2605
    def get_shelf_manager(self):
 
2606
        """Return the ShelfManager for this WorkingTree."""
 
2607
        from bzrlib.shelf import ShelfManager
 
2608
        return ShelfManager(self, self._transport)
 
2609
 
2459
2610
 
2460
2611
class WorkingTree2(WorkingTree):
2461
2612
    """This is the Format 2 working tree.
2462
2613
 
2463
 
    This was the first weave based working tree. 
 
2614
    This was the first weave based working tree.
2464
2615
     - uses os locks for locking.
2465
2616
     - uses the branch last-revision.
2466
2617
    """
2476
2627
        if self._inventory is None:
2477
2628
            self.read_working_inventory()
2478
2629
 
 
2630
    def _get_check_refs(self):
 
2631
        """Return the references needed to perform a check of this tree."""
 
2632
        return [('trees', self.last_revision())]
 
2633
 
2479
2634
    def lock_tree_write(self):
2480
2635
        """See WorkingTree.lock_tree_write().
2481
2636
 
2499
2654
            if self._inventory_is_modified:
2500
2655
                self.flush()
2501
2656
            self._write_hashcache_if_dirty()
2502
 
                    
 
2657
 
2503
2658
        # reverse order of locking.
2504
2659
        try:
2505
2660
            return self._control_files.unlock()
2521
2676
    def _last_revision(self):
2522
2677
        """See Mutable.last_revision."""
2523
2678
        try:
2524
 
            return self._control_files.get('last-revision').read()
 
2679
            return self._transport.get_bytes('last-revision')
2525
2680
        except errors.NoSuchFile:
2526
2681
            return _mod_revision.NULL_REVISION
2527
2682
 
2528
2683
    def _change_last_revision(self, revision_id):
2529
2684
        """See WorkingTree._change_last_revision."""
2530
 
        if revision_id is None or revision_id == NULL_REVISION:
 
2685
        if revision_id is None or revision_id == _mod_revision.NULL_REVISION:
2531
2686
            try:
2532
 
                self._control_files._transport.delete('last-revision')
 
2687
                self._transport.delete('last-revision')
2533
2688
            except errors.NoSuchFile:
2534
2689
                pass
2535
2690
            return False
2536
2691
        else:
2537
 
            self._control_files.put_bytes('last-revision', revision_id)
 
2692
            self._transport.put_bytes('last-revision', revision_id,
 
2693
                mode=self.bzrdir._get_file_mode())
2538
2694
            return True
2539
2695
 
 
2696
    def _get_check_refs(self):
 
2697
        """Return the references needed to perform a check of this tree."""
 
2698
        return [('trees', self.last_revision())]
 
2699
 
2540
2700
    @needs_tree_write_lock
2541
2701
    def set_conflicts(self, conflicts):
2542
 
        self._put_rio('conflicts', conflicts.to_stanzas(), 
 
2702
        self._put_rio('conflicts', conflicts.to_stanzas(),
2543
2703
                      CONFLICT_HEADER_1)
2544
2704
 
2545
2705
    @needs_tree_write_lock
2552
2712
    @needs_read_lock
2553
2713
    def conflicts(self):
2554
2714
        try:
2555
 
            confile = self._control_files.get('conflicts')
 
2715
            confile = self._transport.get('conflicts')
2556
2716
        except errors.NoSuchFile:
2557
2717
            return _mod_conflicts.ConflictList()
2558
2718
        try:
2559
 
            if confile.next() != CONFLICT_HEADER_1 + '\n':
 
2719
            try:
 
2720
                if confile.next() != CONFLICT_HEADER_1 + '\n':
 
2721
                    raise errors.ConflictFormatError()
 
2722
            except StopIteration:
2560
2723
                raise errors.ConflictFormatError()
2561
 
        except StopIteration:
2562
 
            raise errors.ConflictFormatError()
2563
 
        return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
 
2724
            return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
 
2725
        finally:
 
2726
            confile.close()
2564
2727
 
2565
2728
    def unlock(self):
2566
2729
        # do non-implementation specific cleanup
2583
2746
            return path[:-len(suffix)]
2584
2747
 
2585
2748
 
2586
 
@deprecated_function(zero_eight)
2587
 
def is_control_file(filename):
2588
 
    """See WorkingTree.is_control_filename(filename)."""
2589
 
    ## FIXME: better check
2590
 
    filename = normpath(filename)
2591
 
    while filename != '':
2592
 
        head, tail = os.path.split(filename)
2593
 
        ## mutter('check %r for control file' % ((head, tail),))
2594
 
        if tail == '.bzr':
2595
 
            return True
2596
 
        if filename == head:
2597
 
            break
2598
 
        filename = head
2599
 
    return False
2600
 
 
2601
 
 
2602
2749
class WorkingTreeFormat(object):
2603
2750
    """An encapsulation of the initialization and open routines for a format.
2604
2751
 
2607
2754
     * a format string,
2608
2755
     * an open routine.
2609
2756
 
2610
 
    Formats are placed in an dict by their format string for reference 
 
2757
    Formats are placed in an dict by their format string for reference
2611
2758
    during workingtree opening. Its not required that these be instances, they
2612
 
    can be classes themselves with class methods - it simply depends on 
 
2759
    can be classes themselves with class methods - it simply depends on
2613
2760
    whether state is needed for a given format or not.
2614
2761
 
2615
2762
    Once a format is deprecated, just deprecate the initialize and open
2616
 
    methods on the format class. Do not deprecate the object, as the 
 
2763
    methods on the format class. Do not deprecate the object, as the
2617
2764
    object will be created every time regardless.
2618
2765
    """
2619
2766
 
2632
2779
        """Return the format for the working tree object in a_bzrdir."""
2633
2780
        try:
2634
2781
            transport = a_bzrdir.get_workingtree_transport(None)
2635
 
            format_string = transport.get("format").read()
 
2782
            format_string = transport.get_bytes("format")
2636
2783
            return klass._formats[format_string]
2637
2784
        except errors.NoSuchFile:
2638
2785
            raise errors.NoWorkingTree(base=transport.base)
2639
2786
        except KeyError:
2640
 
            raise errors.UnknownFormatError(format=format_string)
 
2787
            raise errors.UnknownFormatError(format=format_string,
 
2788
                                            kind="working tree")
2641
2789
 
2642
2790
    def __eq__(self, other):
2643
2791
        return self.__class__ is other.__class__
2662
2810
        """Is this format supported?
2663
2811
 
2664
2812
        Supported formats can be initialized and opened.
2665
 
        Unsupported formats may not support initialization or committing or 
 
2813
        Unsupported formats may not support initialization or committing or
2666
2814
        some other features depending on the reason for not being supported.
2667
2815
        """
2668
2816
        return True
2669
2817
 
 
2818
    def supports_content_filtering(self):
 
2819
        """True if this format supports content filtering."""
 
2820
        return False
 
2821
 
 
2822
    def supports_views(self):
 
2823
        """True if this format supports stored views."""
 
2824
        return False
 
2825
 
2670
2826
    @classmethod
2671
2827
    def register_format(klass, format):
2672
2828
        klass._formats[format.get_format_string()] = format
2677
2833
 
2678
2834
    @classmethod
2679
2835
    def unregister_format(klass, format):
2680
 
        assert klass._formats[format.get_format_string()] is format
2681
2836
        del klass._formats[format.get_format_string()]
2682
2837
 
2683
2838
 
2684
2839
class WorkingTreeFormat2(WorkingTreeFormat):
2685
 
    """The second working tree format. 
 
2840
    """The second working tree format.
2686
2841
 
2687
2842
    This format modified the hash cache from the format 1 hash cache.
2688
2843
    """
2693
2848
        """See WorkingTreeFormat.get_format_description()."""
2694
2849
        return "Working tree format 2"
2695
2850
 
2696
 
    def stub_initialize_remote(self, control_files):
2697
 
        """As a special workaround create critical control files for a remote working tree
2698
 
        
 
2851
    def _stub_initialize_on_transport(self, transport, file_mode):
 
2852
        """Workaround: create control files for a remote working tree.
 
2853
 
2699
2854
        This ensures that it can later be updated and dealt with locally,
2700
 
        since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with 
 
2855
        since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2701
2856
        no working tree.  (See bug #43064).
2702
2857
        """
2703
2858
        sio = StringIO()
2704
 
        inv = Inventory()
 
2859
        inv = inventory.Inventory()
2705
2860
        xml5.serializer_v5.write_inventory(inv, sio, working=True)
2706
2861
        sio.seek(0)
2707
 
        control_files.put('inventory', sio)
2708
 
 
2709
 
        control_files.put_bytes('pending-merges', '')
2710
 
        
2711
 
 
2712
 
    def initialize(self, a_bzrdir, revision_id=None):
 
2862
        transport.put_file('inventory', sio, file_mode)
 
2863
        transport.put_bytes('pending-merges', '', file_mode)
 
2864
 
 
2865
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
 
2866
                   accelerator_tree=None, hardlink=False):
2713
2867
        """See WorkingTreeFormat.initialize()."""
2714
2868
        if not isinstance(a_bzrdir.transport, LocalTransport):
2715
2869
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
2716
 
        branch = a_bzrdir.open_branch()
 
2870
        if from_branch is not None:
 
2871
            branch = from_branch
 
2872
        else:
 
2873
            branch = a_bzrdir.open_branch()
2717
2874
        if revision_id is None:
2718
2875
            revision_id = _mod_revision.ensure_null(branch.last_revision())
2719
2876
        branch.lock_write()
2721
2878
            branch.generate_revision_history(revision_id)
2722
2879
        finally:
2723
2880
            branch.unlock()
2724
 
        inv = Inventory()
 
2881
        inv = inventory.Inventory()
2725
2882
        wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
2726
2883
                         branch,
2727
2884
                         inv,
2730
2887
                         _bzrdir=a_bzrdir)
2731
2888
        basis_tree = branch.repository.revision_tree(revision_id)
2732
2889
        if basis_tree.inventory.root is not None:
2733
 
            wt.set_root_id(basis_tree.inventory.root.file_id)
 
2890
            wt.set_root_id(basis_tree.get_root_id())
2734
2891
        # set the parent list and cache the basis tree.
2735
2892
        if _mod_revision.is_null(revision_id):
2736
2893
            parent_trees = []
2772
2929
        - is new in bzr 0.8
2773
2930
        - uses a LockDir to guard access for writes.
2774
2931
    """
2775
 
    
 
2932
 
2776
2933
    upgrade_recommended = True
2777
2934
 
2778
2935
    def get_format_string(self):
2795
2952
 
2796
2953
    def _open_control_files(self, a_bzrdir):
2797
2954
        transport = a_bzrdir.get_workingtree_transport(None)
2798
 
        return LockableFiles(transport, self._lock_file_name, 
 
2955
        return LockableFiles(transport, self._lock_file_name,
2799
2956
                             self._lock_class)
2800
2957
 
2801
 
    def initialize(self, a_bzrdir, revision_id=None):
 
2958
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
 
2959
                   accelerator_tree=None, hardlink=False):
2802
2960
        """See WorkingTreeFormat.initialize().
2803
 
        
2804
 
        revision_id allows creating a working tree at a different
2805
 
        revision than the branch is at.
 
2961
 
 
2962
        :param revision_id: if supplied, create a working tree at a different
 
2963
            revision than the branch is at.
 
2964
        :param accelerator_tree: A tree which can be used for retrieving file
 
2965
            contents more quickly than the revision tree, i.e. a workingtree.
 
2966
            The revision tree will be used for cases where accelerator_tree's
 
2967
            content is different.
 
2968
        :param hardlink: If true, hard-link files from accelerator_tree,
 
2969
            where possible.
2806
2970
        """
2807
2971
        if not isinstance(a_bzrdir.transport, LocalTransport):
2808
2972
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
2810
2974
        control_files = self._open_control_files(a_bzrdir)
2811
2975
        control_files.create_lock()
2812
2976
        control_files.lock_write()
2813
 
        control_files.put_utf8('format', self.get_format_string())
2814
 
        branch = a_bzrdir.open_branch()
 
2977
        transport.put_bytes('format', self.get_format_string(),
 
2978
            mode=a_bzrdir._get_file_mode())
 
2979
        if from_branch is not None:
 
2980
            branch = from_branch
 
2981
        else:
 
2982
            branch = a_bzrdir.open_branch()
2815
2983
        if revision_id is None:
2816
2984
            revision_id = _mod_revision.ensure_null(branch.last_revision())
2817
2985
        # WorkingTree3 can handle an inventory which has a unique root id.
2832
3000
            basis_tree = branch.repository.revision_tree(revision_id)
2833
3001
            # only set an explicit root id if there is one to set.
2834
3002
            if basis_tree.inventory.root is not None:
2835
 
                wt.set_root_id(basis_tree.inventory.root.file_id)
2836
 
            if revision_id == NULL_REVISION:
 
3003
                wt.set_root_id(basis_tree.get_root_id())
 
3004
            if revision_id == _mod_revision.NULL_REVISION:
2837
3005
                wt.set_parent_trees([])
2838
3006
            else:
2839
3007
                wt.set_parent_trees([(revision_id, basis_tree)])
2846
3014
        return wt
2847
3015
 
2848
3016
    def _initial_inventory(self):
2849
 
        return Inventory()
 
3017
        return inventory.Inventory()
2850
3018
 
2851
3019
    def __init__(self):
2852
3020
        super(WorkingTreeFormat3, self).__init__()
2867
3035
 
2868
3036
    def _open(self, a_bzrdir, control_files):
2869
3037
        """Open the tree itself.
2870
 
        
 
3038
 
2871
3039
        :param a_bzrdir: the dir for the tree.
2872
3040
        :param control_files: the control files for the tree.
2873
3041
        """
2881
3049
        return self.get_format_string()
2882
3050
 
2883
3051
 
2884
 
__default_format = WorkingTreeFormat4()
 
3052
__default_format = WorkingTreeFormat6()
2885
3053
WorkingTreeFormat.register_format(__default_format)
 
3054
WorkingTreeFormat.register_format(WorkingTreeFormat5())
 
3055
WorkingTreeFormat.register_format(WorkingTreeFormat4())
2886
3056
WorkingTreeFormat.register_format(WorkingTreeFormat3())
2887
3057
WorkingTreeFormat.set_default_format(__default_format)
2888
3058
# formats which have no format string are not discoverable