~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

  • Committer: John Arbash Meinel
  • Date: 2006-08-14 16:16:53 UTC
  • mto: (1946.2.6 reduce-knit-churn)
  • mto: This revision was merged to the branch mainline in revision 1919.
  • Revision ID: john@arbash-meinel.com-20060814161653-54cdcdadcd4e9003
Remove bogus entry from BRANCH.TODO

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
WorkingTree.open(dir).
30
30
"""
31
31
 
 
32
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
 
33
CONFLICT_HEADER_1 = "BZR conflict list format 1"
 
34
 
32
35
# TODO: Give the workingtree sole responsibility for the working inventory;
33
36
# remove the variable and references to it from the branch.  This may require
34
37
# updating the commit code so as to update the inventory within the working
36
39
# At the moment they may alias the inventory and have old copies of it in
37
40
# memory.  (Now done? -- mbp 20060309)
38
41
 
39
 
from cStringIO import StringIO
40
 
import os
41
 
import re
42
 
 
43
 
from bzrlib.lazy_import import lazy_import
44
 
lazy_import(globals(), """
 
42
from binascii import hexlify
45
43
import collections
46
44
from copy import deepcopy
 
45
from cStringIO import StringIO
47
46
import errno
48
47
import fnmatch
 
48
import os
 
49
import re
49
50
import stat
50
51
from time import time
51
52
import warnings
52
53
 
53
54
import bzrlib
54
 
from bzrlib import (
55
 
    bzrdir,
56
 
    conflicts as _mod_conflicts,
57
 
    errors,
58
 
    ignores,
59
 
    merge,
60
 
    osutils,
61
 
    textui,
62
 
    transform,
63
 
    urlutils,
64
 
    xml5,
65
 
    xml6,
66
 
    )
 
55
from bzrlib import bzrdir, errors, ignores, osutils, urlutils
 
56
from bzrlib.atomicfile import AtomicFile
67
57
import bzrlib.branch
68
 
from bzrlib.transport import get_transport
69
 
import bzrlib.ui
70
 
""")
71
 
 
72
 
from bzrlib import symbol_versioning
 
58
from bzrlib.conflicts import Conflict, ConflictList, CONFLICT_SUFFIXES
73
59
from bzrlib.decorators import needs_read_lock, needs_write_lock
74
60
from bzrlib.errors import (BzrCheckError,
75
61
                           BzrError,
81
67
                           MergeModifiedFormatError,
82
68
                           UnsupportedOperation,
83
69
                           )
84
 
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID
 
70
from bzrlib.inventory import InventoryEntry, Inventory
85
71
from bzrlib.lockable_files import LockableFiles, TransportLock
86
72
from bzrlib.lockdir import LockDir
87
 
import bzrlib.mutabletree
88
 
from bzrlib.mutabletree import needs_tree_write_lock
 
73
from bzrlib.merge import merge_inner, transform_tree
89
74
from bzrlib.osutils import (
90
 
    compact_date,
91
 
    file_kind,
92
 
    isdir,
93
 
    pathjoin,
94
 
    safe_unicode,
95
 
    splitpath,
96
 
    rand_chars,
97
 
    normpath,
98
 
    realpath,
99
 
    supports_executable,
100
 
    )
101
 
from bzrlib.trace import mutter, note
102
 
from bzrlib.transport.local import LocalTransport
103
 
import bzrlib.tree
 
75
                            abspath,
 
76
                            compact_date,
 
77
                            file_kind,
 
78
                            isdir,
 
79
                            getcwd,
 
80
                            pathjoin,
 
81
                            pumpfile,
 
82
                            safe_unicode,
 
83
                            splitpath,
 
84
                            rand_chars,
 
85
                            normpath,
 
86
                            realpath,
 
87
                            relpath,
 
88
                            rename,
 
89
                            supports_executable,
 
90
                            )
104
91
from bzrlib.progress import DummyProgress, ProgressPhase
105
92
from bzrlib.revision import NULL_REVISION
106
 
import bzrlib.revisiontree
107
93
from bzrlib.rio import RioReader, rio_file, Stanza
108
94
from bzrlib.symbol_versioning import (deprecated_passed,
109
95
        deprecated_method,
110
96
        deprecated_function,
111
97
        DEPRECATED_PARAMETER,
112
98
        zero_eight,
113
 
        zero_eleven,
114
99
        )
115
 
 
116
 
 
117
 
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
118
 
CONFLICT_HEADER_1 = "BZR conflict list format 1"
 
100
from bzrlib.trace import mutter, note
 
101
from bzrlib.transform import build_tree
 
102
from bzrlib.transport import get_transport
 
103
from bzrlib.transport.local import LocalTransport
 
104
from bzrlib.textui import show_status
 
105
import bzrlib.tree
 
106
import bzrlib.ui
 
107
import bzrlib.xml5
 
108
 
119
109
 
120
110
# the regex removes any weird characters; we don't escape them 
121
111
# but rather just pull them out
165
155
 
166
156
def gen_root_id():
167
157
    """Return a new tree-root file id."""
168
 
    return gen_file_id('tree_root')
 
158
    return gen_file_id('TREE_ROOT')
169
159
 
170
160
 
171
161
class TreeEntry(object):
223
213
        return ''
224
214
 
225
215
 
226
 
class WorkingTree(bzrlib.mutabletree.MutableTree):
 
216
class WorkingTree(bzrlib.tree.Tree):
227
217
    """Working copy tree.
228
218
 
229
219
    The inventory is held in the `Branch` working-inventory, and the
260
250
            self.basedir = wt.basedir
261
251
            self._control_files = wt._control_files
262
252
            self._hashcache = wt._hashcache
263
 
            self._set_inventory(wt._inventory, dirty=False)
 
253
            self._set_inventory(wt._inventory)
264
254
            self._format = wt._format
265
255
            self.bzrdir = wt.bzrdir
266
256
        from bzrlib.hashcache import HashCache
308
298
            hc.write()
309
299
 
310
300
        if _inventory is None:
311
 
            self._inventory_is_modified = False
312
 
            self.read_working_inventory()
 
301
            self._set_inventory(self.read_working_inventory())
313
302
        else:
314
 
            # the caller of __init__ has provided an inventory,
315
 
            # we assume they know what they are doing - as its only
316
 
            # the Format factory and creation methods that are
317
 
            # permitted to do this.
318
 
            self._set_inventory(_inventory, dirty=False)
 
303
            self._set_inventory(_inventory)
319
304
 
320
305
    branch = property(
321
306
        fget=lambda self: self._branch,
336
321
        self._control_files.break_lock()
337
322
        self.branch.break_lock()
338
323
 
339
 
    def _set_inventory(self, inv, dirty):
340
 
        """Set the internal cached inventory.
341
 
 
342
 
        :param inv: The inventory to set.
343
 
        :param dirty: A boolean indicating whether the inventory is the same
344
 
            logical inventory as whats on disk. If True the inventory is not
345
 
            the same and should be written to disk or data will be lost, if
346
 
            False then the inventory is the same as that on disk and any
347
 
            serialisation would be unneeded overhead.
348
 
        """
349
 
        assert inv.root is not None
 
324
    def _set_inventory(self, inv):
350
325
        self._inventory = inv
351
 
        self._inventory_is_modified = dirty
 
326
        self.path2id = self._inventory.path2id
 
327
 
 
328
    def is_control_filename(self, filename):
 
329
        """True if filename is the name of a control file in this tree.
 
330
        
 
331
        :param filename: A filename within the tree. This is a relative path
 
332
        from the root of this tree.
 
333
 
 
334
        This is true IF and ONLY IF the filename is part of the meta data
 
335
        that bzr controls in this tree. I.E. a random .bzr directory placed
 
336
        on disk will not be a control file for this tree.
 
337
        """
 
338
        return self.bzrdir.is_control_filename(filename)
352
339
 
353
340
    @staticmethod
354
341
    def open(path=None, _unsupported=False):
406
393
        return pathjoin(self.basedir, filename)
407
394
    
408
395
    def basis_tree(self):
409
 
        """Return RevisionTree for the current last revision.
410
 
        
411
 
        If the left most parent is a ghost then the returned tree will be an
412
 
        empty tree - one obtained by calling repository.revision_tree(None).
413
 
        """
414
 
        try:
415
 
            revision_id = self.get_parent_ids()[0]
416
 
        except IndexError:
417
 
            # no parents, return an empty revision tree.
418
 
            # in the future this should return the tree for
419
 
            # 'empty:' - the implicit root empty tree.
420
 
            return self.branch.repository.revision_tree(None)
421
 
        else:
 
396
        """Return RevisionTree for the current last revision."""
 
397
        revision_id = self.last_revision()
 
398
        if revision_id is not None:
422
399
            try:
423
400
                xml = self.read_basis_inventory()
424
 
                inv = xml6.serializer_v6.read_inventory_from_string(xml)
425
 
                if inv is not None and inv.revision_id == revision_id:
426
 
                    return bzrlib.revisiontree.RevisionTree(
427
 
                        self.branch.repository, inv, revision_id)
428
 
            except (NoSuchFile, errors.BadInventoryFormat):
429
 
                pass
430
 
        # No cached copy available, retrieve from the repository.
431
 
        # FIXME? RBC 20060403 should we cache the inventory locally
432
 
        # at this point ?
433
 
        try:
434
 
            return self.branch.repository.revision_tree(revision_id)
435
 
        except errors.RevisionNotPresent:
436
 
            # the basis tree *may* be a ghost or a low level error may have
437
 
            # occured. If the revision is present, its a problem, if its not
438
 
            # its a ghost.
439
 
            if self.branch.repository.has_revision(revision_id):
440
 
                raise
441
 
            # the basis tree is a ghost so return an empty tree.
442
 
            return self.branch.repository.revision_tree(None)
 
401
                inv = bzrlib.xml5.serializer_v5.read_inventory_from_string(xml)
 
402
            except NoSuchFile:
 
403
                inv = None
 
404
            if inv is not None and inv.revision_id == revision_id:
 
405
                return bzrlib.tree.RevisionTree(self.branch.repository, inv,
 
406
                                                revision_id)
 
407
        # FIXME? RBC 20060403 should we cache the inventory here ?
 
408
        return self.branch.repository.revision_tree(revision_id)
443
409
 
444
410
    @staticmethod
445
411
    @deprecated_method(zero_eight)
485
451
        The path may be absolute or relative. If its a relative path it is 
486
452
        interpreted relative to the python current working directory.
487
453
        """
488
 
        return osutils.relpath(self.basedir, path)
 
454
        return relpath(self.basedir, path)
489
455
 
490
456
    def has_filename(self, filename):
491
457
        return osutils.lexists(self.abspath(filename))
505
471
        This implementation reads the pending merges list and last_revision
506
472
        value and uses that to decide what the parents list should be.
507
473
        """
508
 
        last_rev = self._last_revision()
 
474
        last_rev = self.last_revision()
509
475
        if last_rev is None:
510
476
            parents = []
511
477
        else:
512
478
            parents = [last_rev]
513
 
        try:
514
 
            merges_file = self._control_files.get_utf8('pending-merges')
515
 
        except NoSuchFile:
516
 
            pass
517
 
        else:
518
 
            for l in merges_file.readlines():
519
 
                parents.append(l.rstrip('\n'))
520
 
        return parents
 
479
        other_parents = self.pending_merges()
 
480
        return parents + other_parents
521
481
 
522
 
    @needs_read_lock
523
482
    def get_root_id(self):
524
483
        """Return the id of this trees root"""
525
 
        return self._inventory.root.file_id
 
484
        inv = self.read_working_inventory()
 
485
        return inv.root.file_id
526
486
        
527
487
    def _get_store_filename(self, file_id):
528
488
        ## XXX: badly named; this is not in the store at all
554
514
    @needs_read_lock
555
515
    def copy_content_into(self, tree, revision_id=None):
556
516
        """Copy the current content and user files of this tree into tree."""
557
 
        tree.set_root_id(self.get_root_id())
558
517
        if revision_id is None:
559
 
            merge.transform_tree(tree, self)
 
518
            transform_tree(tree, self)
560
519
        else:
561
 
            # TODO now merge from tree.last_revision to revision (to preserve
562
 
            # user local changes)
563
 
            merge.transform_tree(tree, self)
564
 
            tree.set_parent_ids([revision_id])
 
520
            # TODO now merge from tree.last_revision to revision
 
521
            transform_tree(tree, self)
 
522
            tree.set_last_revision(revision_id)
 
523
 
 
524
    @needs_write_lock
 
525
    def commit(self, message=None, revprops=None, *args, **kwargs):
 
526
        # avoid circular imports
 
527
        from bzrlib.commit import Commit
 
528
        if revprops is None:
 
529
            revprops = {}
 
530
        if not 'branch-nick' in revprops:
 
531
            revprops['branch-nick'] = self.branch.nick
 
532
        # args for wt.commit start at message from the Commit.commit method,
 
533
        # but with branch a kwarg now, passing in args as is results in the
 
534
        #message being used for the branch
 
535
        args = (DEPRECATED_PARAMETER, message, ) + args
 
536
        committed_id = Commit().commit( working_tree=self, revprops=revprops,
 
537
            *args, **kwargs)
 
538
        self._set_inventory(self.read_working_inventory())
 
539
        return committed_id
565
540
 
566
541
    def id2abspath(self, file_id):
567
542
        return self.abspath(self.id2path(file_id))
606
581
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
607
582
 
608
583
    @needs_write_lock
609
 
    def _add(self, files, ids, kinds):
610
 
        """See MutableTree._add."""
 
584
    def add(self, files, ids=None):
 
585
        """Make files versioned.
 
586
 
 
587
        Note that the command line normally calls smart_add instead,
 
588
        which can automatically recurse.
 
589
 
 
590
        This adds the files to the inventory, so that they will be
 
591
        recorded by the next commit.
 
592
 
 
593
        files
 
594
            List of paths to add, relative to the base of the tree.
 
595
 
 
596
        ids
 
597
            If set, use these instead of automatically generated ids.
 
598
            Must be the same length as the list of files, but may
 
599
            contain None for ids that are to be autogenerated.
 
600
 
 
601
        TODO: Perhaps have an option to add the ids even if the files do
 
602
              not (yet) exist.
 
603
 
 
604
        TODO: Perhaps callback with the ids and paths as they're added.
 
605
        """
611
606
        # TODO: Re-adding a file that is removed in the working copy
612
607
        # should probably put it back with the previous ID.
613
 
        # the read and write working inventory should not occur in this 
614
 
        # function - they should be part of lock_write and unlock.
 
608
        if isinstance(files, basestring):
 
609
            assert(ids is None or isinstance(ids, basestring))
 
610
            files = [files]
 
611
            if ids is not None:
 
612
                ids = [ids]
 
613
 
 
614
        if ids is None:
 
615
            ids = [None] * len(files)
 
616
        else:
 
617
            assert(len(ids) == len(files))
 
618
 
615
619
        inv = self.read_working_inventory()
616
 
        for f, file_id, kind in zip(files, ids, kinds):
617
 
            assert kind is not None
 
620
        for f,file_id in zip(files, ids):
 
621
            if self.is_control_filename(f):
 
622
                raise errors.ForbiddenControlFileError(filename=f)
 
623
 
 
624
            fp = splitpath(f)
 
625
 
 
626
            if len(fp) == 0:
 
627
                raise BzrError("cannot add top-level %r" % f)
 
628
 
 
629
            fullpath = normpath(self.abspath(f))
 
630
            try:
 
631
                kind = file_kind(fullpath)
 
632
            except OSError, e:
 
633
                if e.errno == errno.ENOENT:
 
634
                    raise NoSuchFile(fullpath)
 
635
            if not InventoryEntry.versionable_kind(kind):
 
636
                raise errors.BadFileKindError(filename=f, kind=kind)
618
637
            if file_id is None:
619
638
                inv.add_path(f, kind=kind)
620
639
            else:
621
640
                inv.add_path(f, kind=kind, file_id=file_id)
 
641
 
622
642
        self._write_inventory(inv)
623
643
 
624
 
    @needs_tree_write_lock
625
 
    def _gather_kinds(self, files, kinds):
626
 
        """See MutableTree._gather_kinds."""
627
 
        for pos, f in enumerate(files):
628
 
            if kinds[pos] is None:
629
 
                fullpath = normpath(self.abspath(f))
630
 
                try:
631
 
                    kinds[pos] = file_kind(fullpath)
632
 
                except OSError, e:
633
 
                    if e.errno == errno.ENOENT:
634
 
                        raise NoSuchFile(fullpath)
635
 
 
636
644
    @needs_write_lock
637
 
    def add_parent_tree_id(self, revision_id, allow_leftmost_as_ghost=False):
638
 
        """Add revision_id as a parent.
639
 
 
640
 
        This is equivalent to retrieving the current list of parent ids
641
 
        and setting the list to its value plus revision_id.
642
 
 
643
 
        :param revision_id: The revision id to add to the parent list. It may
644
 
        be a ghost revision as long as its not the first parent to be added,
645
 
        or the allow_leftmost_as_ghost parameter is set True.
646
 
        :param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
647
 
        """
648
 
        parents = self.get_parent_ids() + [revision_id]
649
 
        self.set_parent_ids(parents,
650
 
            allow_leftmost_as_ghost=len(parents) > 1 or allow_leftmost_as_ghost)
651
 
 
652
 
    @needs_tree_write_lock
653
 
    def add_parent_tree(self, parent_tuple, allow_leftmost_as_ghost=False):
654
 
        """Add revision_id, tree tuple as a parent.
655
 
 
656
 
        This is equivalent to retrieving the current list of parent trees
657
 
        and setting the list to its value plus parent_tuple. See also
658
 
        add_parent_tree_id - if you only have a parent id available it will be
659
 
        simpler to use that api. If you have the parent already available, using
660
 
        this api is preferred.
661
 
 
662
 
        :param parent_tuple: The (revision id, tree) to add to the parent list.
663
 
            If the revision_id is a ghost, pass None for the tree.
664
 
        :param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
665
 
        """
666
 
        parent_ids = self.get_parent_ids() + [parent_tuple[0]]
667
 
        if len(parent_ids) > 1:
668
 
            # the leftmost may have already been a ghost, preserve that if it
669
 
            # was.
670
 
            allow_leftmost_as_ghost = True
671
 
        self.set_parent_ids(parent_ids,
672
 
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
673
 
 
674
 
    @needs_tree_write_lock
675
645
    def add_pending_merge(self, *revision_ids):
676
646
        # TODO: Perhaps should check at this point that the
677
647
        # history of the revision is actually present?
678
 
        parents = self.get_parent_ids()
 
648
        p = self.pending_merges()
679
649
        updated = False
680
650
        for rev_id in revision_ids:
681
 
            if rev_id in parents:
 
651
            if rev_id in p:
682
652
                continue
683
 
            parents.append(rev_id)
 
653
            p.append(rev_id)
684
654
            updated = True
685
655
        if updated:
686
 
            self.set_parent_ids(parents, allow_leftmost_as_ghost=True)
 
656
            self.set_pending_merges(p)
687
657
 
688
 
    @deprecated_method(zero_eleven)
689
658
    @needs_read_lock
690
659
    def pending_merges(self):
691
660
        """Return a list of pending merges.
692
661
 
693
662
        These are revisions that have been merged into the working
694
663
        directory but not yet committed.
695
 
 
696
 
        As of 0.11 this is deprecated. Please see WorkingTree.get_parent_ids()
697
 
        instead - which is available on all tree objects.
698
 
        """
699
 
        return self.get_parent_ids()[1:]
700
 
 
701
 
    def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
702
 
        """Common ghost checking functionality from set_parent_*.
703
 
 
704
 
        This checks that the left hand-parent exists if there are any
705
 
        revisions present.
706
 
        """
707
 
        if len(revision_ids) > 0:
708
 
            leftmost_id = revision_ids[0]
709
 
            if (not allow_leftmost_as_ghost and not
710
 
                self.branch.repository.has_revision(leftmost_id)):
711
 
                raise errors.GhostRevisionUnusableHere(leftmost_id)
712
 
 
713
 
    def _set_merges_from_parent_ids(self, parent_ids):
714
 
        merges = parent_ids[1:]
715
 
        self._control_files.put_utf8('pending-merges', '\n'.join(merges))
716
 
 
717
 
    @needs_tree_write_lock
718
 
    def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
719
 
        """Set the parent ids to revision_ids.
720
 
        
721
 
        See also set_parent_trees. This api will try to retrieve the tree data
722
 
        for each element of revision_ids from the trees repository. If you have
723
 
        tree data already available, it is more efficient to use
724
 
        set_parent_trees rather than set_parent_ids. set_parent_ids is however
725
 
        an easier API to use.
726
 
 
727
 
        :param revision_ids: The revision_ids to set as the parent ids of this
728
 
            working tree. Any of these may be ghosts.
729
 
        """
730
 
        self._check_parents_for_ghosts(revision_ids,
731
 
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
732
 
 
733
 
        if len(revision_ids) > 0:
734
 
            self.set_last_revision(revision_ids[0])
735
 
        else:
736
 
            self.set_last_revision(None)
737
 
 
738
 
        self._set_merges_from_parent_ids(revision_ids)
739
 
 
740
 
    @needs_tree_write_lock
741
 
    def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
742
 
        """See MutableTree.set_parent_trees."""
743
 
        parent_ids = [rev for (rev, tree) in parents_list]
744
 
 
745
 
        self._check_parents_for_ghosts(parent_ids,
746
 
            allow_leftmost_as_ghost=allow_leftmost_as_ghost)
747
 
 
748
 
        if len(parent_ids) == 0:
749
 
            leftmost_parent_id = None
750
 
            leftmost_parent_tree = None
751
 
        else:
752
 
            leftmost_parent_id, leftmost_parent_tree = parents_list[0]
753
 
 
754
 
        if self._change_last_revision(leftmost_parent_id):
755
 
            if leftmost_parent_tree is None:
756
 
                # If we don't have a tree, fall back to reading the
757
 
                # parent tree from the repository.
758
 
                self._cache_basis_inventory(leftmost_parent_id)
759
 
            else:
760
 
                inv = leftmost_parent_tree.inventory
761
 
                xml = self._create_basis_xml_from_inventory(
762
 
                                        leftmost_parent_id, inv)
763
 
                self._write_basis_inventory(xml)
764
 
        self._set_merges_from_parent_ids(parent_ids)
765
 
 
766
 
    @needs_tree_write_lock
 
664
        """
 
665
        try:
 
666
            merges_file = self._control_files.get_utf8('pending-merges')
 
667
        except NoSuchFile:
 
668
            return []
 
669
        p = []
 
670
        for l in merges_file.readlines():
 
671
            p.append(l.rstrip('\n'))
 
672
        return p
 
673
 
 
674
    @needs_write_lock
767
675
    def set_pending_merges(self, rev_list):
768
 
        parents = self.get_parent_ids()
769
 
        leftmost = parents[:1]
770
 
        new_parents = leftmost + rev_list
771
 
        self.set_parent_ids(new_parents)
 
676
        self._control_files.put_utf8('pending-merges', '\n'.join(rev_list))
772
677
 
773
 
    @needs_tree_write_lock
 
678
    @needs_write_lock
774
679
    def set_merge_modified(self, modified_hashes):
775
680
        def iter_stanzas():
776
681
            for file_id, hash in modified_hashes.iteritems():
777
682
                yield Stanza(file_id=file_id, hash=hash)
778
683
        self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
779
684
 
780
 
    @needs_tree_write_lock
 
685
    @needs_write_lock
781
686
    def _put_rio(self, filename, stanzas, header):
782
687
        my_file = rio_file(stanzas, header)
783
688
        self._control_files.put(filename, my_file)
784
689
 
785
 
    @needs_write_lock # because merge pulls data into the branch.
786
 
    def merge_from_branch(self, branch, to_revision=None):
787
 
        """Merge from a branch into this working tree.
788
 
 
789
 
        :param branch: The branch to merge from.
790
 
        :param to_revision: If non-None, the merge will merge to to_revision, but 
791
 
            not beyond it. to_revision does not need to be in the history of
792
 
            the branch when it is supplied. If None, to_revision defaults to
793
 
            branch.last_revision().
794
 
        """
795
 
        from bzrlib.merge import Merger, Merge3Merger
796
 
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
797
 
        try:
798
 
            merger = Merger(self.branch, this_tree=self, pb=pb)
799
 
            merger.pp = ProgressPhase("Merge phase", 5, pb)
800
 
            merger.pp.next_phase()
801
 
            # check that there are no
802
 
            # local alterations
803
 
            merger.check_basis(check_clean=True, require_commits=False)
804
 
            if to_revision is None:
805
 
                to_revision = branch.last_revision()
806
 
            merger.other_rev_id = to_revision
807
 
            if merger.other_rev_id is None:
808
 
                raise error.NoCommits(branch)
809
 
            self.branch.fetch(branch, last_revision=merger.other_rev_id)
810
 
            merger.other_basis = merger.other_rev_id
811
 
            merger.other_tree = self.branch.repository.revision_tree(
812
 
                merger.other_rev_id)
813
 
            merger.pp.next_phase()
814
 
            merger.find_base()
815
 
            if merger.base_rev_id == merger.other_rev_id:
816
 
                raise errors.PointlessMerge
817
 
            merger.backup_files = False
818
 
            merger.merge_type = Merge3Merger
819
 
            merger.set_interesting_files(None)
820
 
            merger.show_base = False
821
 
            merger.reprocess = False
822
 
            conflicts = merger.do_merge()
823
 
            merger.set_pending()
824
 
        finally:
825
 
            pb.finished()
826
 
        return conflicts
827
 
 
828
690
    @needs_read_lock
829
691
    def merge_modified(self):
830
692
        try:
846
708
                merge_hashes[file_id] = hash
847
709
        return merge_hashes
848
710
 
849
 
    @needs_write_lock
850
 
    def mkdir(self, path, file_id=None):
851
 
        """See MutableTree.mkdir()."""
852
 
        if file_id is None:
853
 
            file_id = gen_file_id(os.path.basename(path))
854
 
        os.mkdir(self.abspath(path))
855
 
        self.add(path, file_id, 'directory')
856
 
        return file_id
857
 
 
858
711
    def get_symlink_target(self, file_id):
859
712
        return os.readlink(self.id2abspath(file_id))
860
713
 
866
719
        else:
867
720
            return '?'
868
721
 
869
 
    def flush(self):
870
 
        """Write the in memory inventory to disk."""
871
 
        # TODO: Maybe this should only write on dirty ?
872
 
        if self._control_files._lock_mode != 'w':
873
 
            raise errors.NotWriteLocked(self)
874
 
        sio = StringIO()
875
 
        xml5.serializer_v5.write_inventory(self._inventory, sio)
876
 
        sio.seek(0)
877
 
        self._control_files.put('inventory', sio)
878
 
        self._inventory_is_modified = False
879
 
 
880
 
    def list_files(self, include_root=False):
 
722
    def list_files(self):
881
723
        """Recursively list all files as (path, class, kind, id, entry).
882
724
 
883
725
        Lists, but does not descend into unversioned directories.
888
730
        Skips the control directory.
889
731
        """
890
732
        inv = self._inventory
891
 
        if include_root is True:
892
 
            yield ('', 'V', 'directory', inv.root.file_id, inv.root)
893
733
        # Convert these into local objects to save lookup times
894
734
        pathjoin = osutils.pathjoin
895
735
        file_kind = osutils.file_kind
988
828
                # if we finished all children, pop it off the stack
989
829
                stack.pop()
990
830
 
991
 
    @needs_tree_write_lock
 
831
 
 
832
    @needs_write_lock
992
833
    def move(self, from_paths, to_name):
993
834
        """Rename files.
994
835
 
1013
854
        if not self.has_filename(to_name):
1014
855
            raise BzrError("destination %r not in working directory" % to_abs)
1015
856
        to_dir_id = inv.path2id(to_name)
1016
 
        if to_dir_id is None and to_name != '':
 
857
        if to_dir_id == None and to_name != '':
1017
858
            raise BzrError("destination %r is not a versioned directory" % to_name)
1018
859
        to_dir_ie = inv[to_dir_id]
1019
860
        if to_dir_ie.kind != 'directory':
1025
866
            if not self.has_filename(f):
1026
867
                raise BzrError("%r does not exist in working tree" % f)
1027
868
            f_id = inv.path2id(f)
1028
 
            if f_id is None:
 
869
            if f_id == None:
1029
870
                raise BzrError("%r is not versioned" % f)
1030
871
            name_tail = splitpath(f)[-1]
1031
872
            dest_path = pathjoin(to_name, name_tail)
1038
879
        # create a file in this interval and then the rename might be
1039
880
        # left half-done.  But we should have caught most problems.
1040
881
        orig_inv = deepcopy(self.inventory)
1041
 
        original_modified = self._inventory_is_modified
1042
882
        try:
1043
 
            if len(from_paths):
1044
 
                self._inventory_is_modified = True
1045
883
            for f in from_paths:
1046
884
                name_tail = splitpath(f)[-1]
1047
885
                dest_path = pathjoin(to_name, name_tail)
1048
886
                result.append((f, dest_path))
1049
887
                inv.rename(inv.path2id(f), to_dir_id, name_tail)
1050
888
                try:
1051
 
                    osutils.rename(self.abspath(f), self.abspath(dest_path))
 
889
                    rename(self.abspath(f), self.abspath(dest_path))
1052
890
                except OSError, e:
1053
891
                    raise BzrError("failed to rename %r to %r: %s" %
1054
892
                                   (f, dest_path, e[1]),
1055
893
                            ["rename rolled back"])
1056
894
        except:
1057
895
            # restore the inventory on error
1058
 
            self._set_inventory(orig_inv, dirty=original_modified)
 
896
            self._set_inventory(orig_inv)
1059
897
            raise
1060
898
        self._write_inventory(inv)
1061
899
        return result
1062
900
 
1063
 
    @needs_tree_write_lock
 
901
    @needs_write_lock
1064
902
    def rename_one(self, from_rel, to_rel):
1065
903
        """Rename one file.
1066
904
 
1073
911
            raise BzrError("can't rename: new working file %r already exists" % to_rel)
1074
912
 
1075
913
        file_id = inv.path2id(from_rel)
1076
 
        if file_id is None:
 
914
        if file_id == None:
1077
915
            raise BzrError("can't rename: old name %r is not versioned" % from_rel)
1078
916
 
1079
917
        entry = inv[file_id]
1085
923
 
1086
924
        to_dir, to_tail = os.path.split(to_rel)
1087
925
        to_dir_id = inv.path2id(to_dir)
1088
 
        if to_dir_id is None and to_dir != '':
 
926
        if to_dir_id == None and to_dir != '':
1089
927
            raise BzrError("can't determine destination directory id for %r" % to_dir)
1090
928
 
1091
929
        mutter("rename_one:")
1100
938
        from_abs = self.abspath(from_rel)
1101
939
        to_abs = self.abspath(to_rel)
1102
940
        try:
1103
 
            osutils.rename(from_abs, to_abs)
 
941
            rename(from_abs, to_abs)
1104
942
        except OSError, e:
1105
943
            inv.rename(file_id, from_parent, from_name)
1106
944
            raise BzrError("failed to rename %r to %r: %s"
1118
956
        for subp in self.extras():
1119
957
            if not self.is_ignored(subp):
1120
958
                yield subp
1121
 
    
1122
 
    @needs_tree_write_lock
1123
 
    def unversion(self, file_ids):
1124
 
        """Remove the file ids in file_ids from the current versioned set.
1125
 
 
1126
 
        When a file_id is unversioned, all of its children are automatically
1127
 
        unversioned.
1128
 
 
1129
 
        :param file_ids: The file ids to stop versioning.
1130
 
        :raises: NoSuchId if any fileid is not currently versioned.
1131
 
        """
1132
 
        for file_id in file_ids:
1133
 
            if self._inventory.has_id(file_id):
1134
 
                self._inventory.remove_recursive_id(file_id)
1135
 
            else:
1136
 
                raise errors.NoSuchId(self, file_id)
1137
 
        if len(file_ids):
1138
 
            # in the future this should just set a dirty bit to wait for the 
1139
 
            # final unlock. However, until all methods of workingtree start
1140
 
            # with the current in -memory inventory rather than triggering 
1141
 
            # a read, it is more complex - we need to teach read_inventory
1142
 
            # to know when to read, and when to not read first... and possibly
1143
 
            # to save first when the in memory one may be corrupted.
1144
 
            # so for now, we just only write it if it is indeed dirty.
1145
 
            # - RBC 20060907
1146
 
            self._write_inventory(self._inventory)
1147
 
    
 
959
 
1148
960
    @deprecated_method(zero_eight)
1149
961
    def iter_conflicts(self):
1150
962
        """List all files in the tree that have text or content conflicts.
1182
994
                repository = self.branch.repository
1183
995
                pb = bzrlib.ui.ui_factory.nested_progress_bar()
1184
996
                try:
1185
 
                    new_basis_tree = self.branch.basis_tree()
1186
 
                    merge.merge_inner(
1187
 
                                self.branch,
1188
 
                                new_basis_tree,
1189
 
                                basis_tree,
1190
 
                                this_tree=self,
 
997
                    merge_inner(self.branch,
 
998
                                self.branch.basis_tree(),
 
999
                                basis_tree, 
 
1000
                                this_tree=self, 
1191
1001
                                pb=pb)
1192
 
                    if (basis_tree.inventory.root is None and
1193
 
                        new_basis_tree.inventory.root is not None):
1194
 
                        self.set_root_id(new_basis_tree.inventory.root.file_id)
1195
1002
                finally:
1196
1003
                    pb.finished()
1197
 
                # TODO - dedup parents list with things merged by pull ?
1198
 
                # reuse the revisiontree we merged against to set the new
1199
 
                # tree data.
1200
 
                parent_trees = [(self.branch.last_revision(), new_basis_tree)]
1201
 
                # we have to pull the merge trees out again, because 
1202
 
                # merge_inner has set the ids. - this corner is not yet 
1203
 
                # layered well enough to prevent double handling.
1204
 
                merges = self.get_parent_ids()[1:]
1205
 
                parent_trees.extend([
1206
 
                    (parent, repository.revision_tree(parent)) for
1207
 
                     parent in merges])
1208
 
                self.set_parent_trees(parent_trees)
 
1004
                self.set_last_revision(self.branch.last_revision())
1209
1005
            return count
1210
1006
        finally:
1211
1007
            source.unlock()
1212
1008
            top_pb.finished()
1213
1009
 
1214
 
    @needs_write_lock
1215
 
    def put_file_bytes_non_atomic(self, file_id, bytes):
1216
 
        """See MutableTree.put_file_bytes_non_atomic."""
1217
 
        stream = file(self.id2abspath(file_id), 'wb')
1218
 
        try:
1219
 
            stream.write(bytes)
1220
 
        finally:
1221
 
            stream.close()
1222
 
        # TODO: update the hashcache here ?
1223
 
 
1224
1010
    def extras(self):
1225
1011
        """Yield all unknown files in this WorkingTree.
1226
1012
 
1314
1100
        """Yield list of PATH, IGNORE_PATTERN"""
1315
1101
        for subp in self.extras():
1316
1102
            pat = self.is_ignored(subp)
1317
 
            if pat is not None:
 
1103
            if pat != None:
1318
1104
                yield subp, pat
1319
1105
 
1320
1106
    def get_ignore_list(self):
1375
1161
        for regex, mapping in rules:
1376
1162
            match = regex.match(filename)
1377
1163
            if match is not None:
1378
 
                # one or more of the groups in mapping will have a non-None
1379
 
                # group match.
 
1164
                # one or more of the groups in mapping will have a non-None group 
 
1165
                # match.
1380
1166
                groups = match.groups()
1381
1167
                rules = [mapping[group] for group in 
1382
1168
                    mapping if groups[group] is not None]
1386
1172
    def kind(self, file_id):
1387
1173
        return file_kind(self.id2abspath(file_id))
1388
1174
 
 
1175
    @needs_read_lock
1389
1176
    def last_revision(self):
1390
 
        """Return the last revision of the branch for this tree.
1391
 
 
1392
 
        This format tree does not support a separate marker for last-revision
1393
 
        compared to the branch.
1394
 
 
1395
 
        See MutableTree.last_revision
 
1177
        """Return the last revision id of this working tree.
 
1178
 
 
1179
        In early branch formats this was == the branch last_revision,
 
1180
        but that cannot be relied upon - for working tree operations,
 
1181
        always use tree.last_revision().
1396
1182
        """
1397
 
        return self._last_revision()
1398
 
 
1399
 
    @needs_read_lock
1400
 
    def _last_revision(self):
1401
 
        """helper for get_parent_ids."""
1402
1183
        return self.branch.last_revision()
1403
1184
 
1404
1185
    def is_locked(self):
1413
1194
            self.branch.unlock()
1414
1195
            raise
1415
1196
 
1416
 
    def lock_tree_write(self):
1417
 
        """See MutableTree.lock_tree_write, and WorkingTree.unlock."""
1418
 
        self.branch.lock_read()
1419
 
        try:
1420
 
            return self._control_files.lock_write()
1421
 
        except:
1422
 
            self.branch.unlock()
1423
 
            raise
1424
 
 
1425
1197
    def lock_write(self):
1426
 
        """See MutableTree.lock_write, and WorkingTree.unlock."""
 
1198
        """See Branch.lock_write, and WorkingTree.unlock."""
1427
1199
        self.branch.lock_write()
1428
1200
        try:
1429
1201
            return self._control_files.lock_write()
1435
1207
        return self._control_files.get_physical_lock_status()
1436
1208
 
1437
1209
    def _basis_inventory_name(self):
1438
 
        return 'basis-inventory-cache'
 
1210
        return 'basis-inventory'
1439
1211
 
1440
 
    @needs_tree_write_lock
 
1212
    @needs_write_lock
1441
1213
    def set_last_revision(self, new_revision):
1442
1214
        """Change the last revision in the working tree."""
1443
1215
        if self._change_last_revision(new_revision):
1459
1231
            self.branch.set_revision_history([new_revision])
1460
1232
        return True
1461
1233
 
1462
 
    def _write_basis_inventory(self, xml):
1463
 
        """Write the basis inventory XML to the basis-inventory file"""
1464
 
        assert isinstance(xml, str), 'serialised xml must be bytestring.'
1465
 
        path = self._basis_inventory_name()
1466
 
        sio = StringIO(xml)
1467
 
        self._control_files.put(path, sio)
1468
 
 
1469
 
    def _create_basis_xml_from_inventory(self, revision_id, inventory):
1470
 
        """Create the text that will be saved in basis-inventory"""
1471
 
        inventory.revision_id = revision_id
1472
 
        return xml6.serializer_v6.write_inventory_to_string(inventory)
1473
 
 
1474
1234
    def _cache_basis_inventory(self, new_revision):
1475
1235
        """Cache new_revision as the basis inventory."""
1476
1236
        # TODO: this should allow the ready-to-use inventory to be passed in,
1488
1248
            # root node id can legitimately look like 'revision_id' but cannot
1489
1249
            # contain a '"'.
1490
1250
            xml = self.branch.repository.get_inventory_xml(new_revision)
1491
 
            firstline = xml.split('\n', 1)[0]
1492
 
            if (not 'revision_id="' in firstline or 
1493
 
                'format="6"' not in firstline):
 
1251
            if not 'revision_id="' in xml.split('\n', 1)[0]:
1494
1252
                inv = self.branch.repository.deserialise_inventory(
1495
1253
                    new_revision, xml)
1496
 
                xml = self._create_basis_xml_from_inventory(new_revision, inv)
1497
 
            self._write_basis_inventory(xml)
 
1254
                inv.revision_id = new_revision
 
1255
                xml = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
 
1256
            assert isinstance(xml, str), 'serialised xml must be bytestring.'
 
1257
            path = self._basis_inventory_name()
 
1258
            sio = StringIO(xml)
 
1259
            self._control_files.put(path, sio)
1498
1260
        except (errors.NoSuchRevision, errors.RevisionNotPresent):
1499
1261
            pass
1500
1262
 
1505
1267
        
1506
1268
    @needs_read_lock
1507
1269
    def read_working_inventory(self):
1508
 
        """Read the working inventory.
1509
 
        
1510
 
        :raises errors.InventoryModified: read_working_inventory will fail
1511
 
            when the current in memory inventory has been modified.
1512
 
        """
1513
 
        # conceptually this should be an implementation detail of the tree. 
1514
 
        # XXX: Deprecate this.
 
1270
        """Read the working inventory."""
1515
1271
        # ElementTree does its own conversion from UTF-8, so open in
1516
1272
        # binary.
1517
 
        if self._inventory_is_modified:
1518
 
            raise errors.InventoryModified(self)
1519
 
        result = xml5.serializer_v5.read_inventory(
 
1273
        result = bzrlib.xml5.serializer_v5.read_inventory(
1520
1274
            self._control_files.get('inventory'))
1521
 
        self._set_inventory(result, dirty=False)
 
1275
        self._set_inventory(result)
1522
1276
        return result
1523
1277
 
1524
 
    @needs_tree_write_lock
 
1278
    @needs_write_lock
1525
1279
    def remove(self, files, verbose=False, to_file=None):
1526
1280
        """Remove nominated files from the working inventory..
1527
1281
 
1556
1310
                    new_status = 'I'
1557
1311
                else:
1558
1312
                    new_status = '?'
1559
 
                textui.show_status(new_status, inv[fid].kind, f,
1560
 
                                   to_file=to_file)
 
1313
                show_status(new_status, inv[fid].kind, f, to_file=to_file)
1561
1314
            del inv[fid]
1562
1315
 
1563
1316
        self._write_inventory(inv)
1564
1317
 
1565
 
    @needs_tree_write_lock
 
1318
    @needs_write_lock
1566
1319
    def revert(self, filenames, old_tree=None, backups=True, 
1567
1320
               pb=DummyProgress()):
1568
 
        from bzrlib.conflicts import resolve
 
1321
        from transform import revert
 
1322
        from conflicts import resolve
1569
1323
        if old_tree is None:
1570
1324
            old_tree = self.basis_tree()
1571
 
        conflicts = transform.revert(self, old_tree, filenames, backups, pb)
 
1325
        conflicts = revert(self, old_tree, filenames, backups, pb)
1572
1326
        if not len(filenames):
1573
 
            self.set_parent_ids(self.get_parent_ids()[:1])
 
1327
            self.set_pending_merges([])
1574
1328
            resolve(self)
1575
1329
        else:
1576
1330
            resolve(self, filenames, ignore_misses=True)
1578
1332
 
1579
1333
    # XXX: This method should be deprecated in favour of taking in a proper
1580
1334
    # new Inventory object.
1581
 
    @needs_tree_write_lock
 
1335
    @needs_write_lock
1582
1336
    def set_inventory(self, new_inventory_list):
1583
1337
        from bzrlib.inventory import (Inventory,
1584
1338
                                      InventoryDirectory,
1601
1355
                raise BzrError("unknown kind %r" % kind)
1602
1356
        self._write_inventory(inv)
1603
1357
 
1604
 
    @needs_tree_write_lock
 
1358
    @needs_write_lock
1605
1359
    def set_root_id(self, file_id):
1606
1360
        """Set the root id for this tree."""
1607
 
        # for compatability 
1608
 
        if file_id is None:
1609
 
            symbol_versioning.warn(symbol_versioning.zero_twelve
1610
 
                % 'WorkingTree.set_root_id with fileid=None',
1611
 
                DeprecationWarning,
1612
 
                stacklevel=3)
1613
 
            file_id = ROOT_ID
1614
 
        inv = self._inventory
 
1361
        inv = self.read_working_inventory()
1615
1362
        orig_root_id = inv.root.file_id
1616
 
        # TODO: it might be nice to exit early if there was nothing
1617
 
        # to do, saving us from trigger a sync on unlock.
1618
 
        self._inventory_is_modified = True
1619
 
        # we preserve the root inventory entry object, but
1620
 
        # unlinkit from the byid index
1621
1363
        del inv._byid[inv.root.file_id]
1622
1364
        inv.root.file_id = file_id
1623
 
        # and link it into the index with the new changed id.
1624
1365
        inv._byid[inv.root.file_id] = inv.root
1625
 
        # and finally update all children to reference the new id.
1626
 
        # XXX: this should be safe to just look at the root.children
1627
 
        # list, not the WHOLE INVENTORY.
1628
1366
        for fid in inv:
1629
1367
            entry = inv[fid]
1630
1368
            if entry.parent_id == orig_root_id:
1631
1369
                entry.parent_id = inv.root.file_id
 
1370
        self._write_inventory(inv)
1632
1371
 
1633
1372
    def unlock(self):
1634
1373
        """See Branch.unlock.
1641
1380
        """
1642
1381
        raise NotImplementedError(self.unlock)
1643
1382
 
 
1383
    @needs_write_lock
1644
1384
    def update(self):
1645
1385
        """Update a working tree along its branch.
1646
1386
 
1647
 
        This will update the branch if its bound too, which means we have
1648
 
        multiple trees involved:
1649
 
 
1650
 
        - The new basis tree of the master.
1651
 
        - The old basis tree of the branch.
1652
 
        - The old basis tree of the working tree.
1653
 
        - The current working tree state.
1654
 
 
1655
 
        Pathologically, all three may be different, and non-ancestors of each
1656
 
        other.  Conceptually we want to:
1657
 
 
1658
 
        - Preserve the wt.basis->wt.state changes
1659
 
        - Transform the wt.basis to the new master basis.
1660
 
        - Apply a merge of the old branch basis to get any 'local' changes from
1661
 
          it into the tree.
1662
 
        - Restore the wt.basis->wt.state changes.
 
1387
        This will update the branch if its bound too, which means we have multiple trees involved:
 
1388
        The new basis tree of the master.
 
1389
        The old basis tree of the branch.
 
1390
        The old basis tree of the working tree.
 
1391
        The current working tree state.
 
1392
        pathologically all three may be different, and non ancestors of each other.
 
1393
        Conceptually we want to:
 
1394
        Preserve the wt.basis->wt.state changes
 
1395
        Transform the wt.basis to the new master basis.
 
1396
        Apply a merge of the old branch basis to get any 'local' changes from it into the tree.
 
1397
        Restore the wt.basis->wt.state changes.
1663
1398
 
1664
1399
        There isn't a single operation at the moment to do that, so we:
1665
 
        - Merge current state -> basis tree of the master w.r.t. the old tree
1666
 
          basis.
1667
 
        - Do a 'normal' merge of the old branch basis if it is relevant.
 
1400
        Merge current state -> basis tree of the master w.r.t. the old tree basis.
 
1401
        Do a 'normal' merge of the old branch basis if it is relevant.
1668
1402
        """
1669
 
        if self.branch.get_master_branch() is not None:
1670
 
            self.lock_write()
1671
 
            update_branch = True
1672
 
        else:
1673
 
            self.lock_tree_write()
1674
 
            update_branch = False
 
1403
        old_tip = self.branch.update()
 
1404
        if old_tip is not None:
 
1405
            self.add_pending_merge(old_tip)
 
1406
        self.branch.lock_read()
1675
1407
        try:
1676
 
            if update_branch:
1677
 
                old_tip = self.branch.update()
1678
 
            else:
1679
 
                old_tip = None
1680
 
            return self._update_tree(old_tip)
 
1408
            result = 0
 
1409
            if self.last_revision() != self.branch.last_revision():
 
1410
                # merge tree state up to new branch tip.
 
1411
                basis = self.basis_tree()
 
1412
                to_tree = self.branch.basis_tree()
 
1413
                result += merge_inner(self.branch,
 
1414
                                      to_tree,
 
1415
                                      basis,
 
1416
                                      this_tree=self)
 
1417
                self.set_last_revision(self.branch.last_revision())
 
1418
            if old_tip and old_tip != self.last_revision():
 
1419
                # our last revision was not the prior branch last revision
 
1420
                # and we have converted that last revision to a pending merge.
 
1421
                # base is somewhere between the branch tip now
 
1422
                # and the now pending merge
 
1423
                from bzrlib.revision import common_ancestor
 
1424
                try:
 
1425
                    base_rev_id = common_ancestor(self.branch.last_revision(),
 
1426
                                                  old_tip,
 
1427
                                                  self.branch.repository)
 
1428
                except errors.NoCommonAncestor:
 
1429
                    base_rev_id = None
 
1430
                base_tree = self.branch.repository.revision_tree(base_rev_id)
 
1431
                other_tree = self.branch.repository.revision_tree(old_tip)
 
1432
                result += merge_inner(self.branch,
 
1433
                                      other_tree,
 
1434
                                      base_tree,
 
1435
                                      this_tree=self)
 
1436
            return result
1681
1437
        finally:
1682
 
            self.unlock()
1683
 
 
1684
 
    @needs_tree_write_lock
1685
 
    def _update_tree(self, old_tip=None):
1686
 
        """Update a tree to the master branch.
1687
 
 
1688
 
        :param old_tip: if supplied, the previous tip revision the branch,
1689
 
            before it was changed to the master branch's tip.
1690
 
        """
1691
 
        # here if old_tip is not None, it is the old tip of the branch before
1692
 
        # it was updated from the master branch. This should become a pending
1693
 
        # merge in the working tree to preserve the user existing work.  we
1694
 
        # cant set that until we update the working trees last revision to be
1695
 
        # one from the new branch, because it will just get absorbed by the
1696
 
        # parent de-duplication logic.
1697
 
        # 
1698
 
        # We MUST save it even if an error occurs, because otherwise the users
1699
 
        # local work is unreferenced and will appear to have been lost.
1700
 
        # 
1701
 
        result = 0
1702
 
        try:
1703
 
            last_rev = self.get_parent_ids()[0]
1704
 
        except IndexError:
1705
 
            last_rev = None
1706
 
        if last_rev != self.branch.last_revision():
1707
 
            # merge tree state up to new branch tip.
1708
 
            basis = self.basis_tree()
1709
 
            to_tree = self.branch.basis_tree()
1710
 
            if basis.inventory.root is None:
1711
 
                self.set_root_id(to_tree.inventory.root.file_id)
1712
 
            result += merge.merge_inner(
1713
 
                                  self.branch,
1714
 
                                  to_tree,
1715
 
                                  basis,
1716
 
                                  this_tree=self)
1717
 
            # TODO - dedup parents list with things merged by pull ?
1718
 
            # reuse the tree we've updated to to set the basis:
1719
 
            parent_trees = [(self.branch.last_revision(), to_tree)]
1720
 
            merges = self.get_parent_ids()[1:]
1721
 
            # Ideally we ask the tree for the trees here, that way the working
1722
 
            # tree can decide whether to give us teh entire tree or give us a
1723
 
            # lazy initialised tree. dirstate for instance will have the trees
1724
 
            # in ram already, whereas a last-revision + basis-inventory tree
1725
 
            # will not, but also does not need them when setting parents.
1726
 
            for parent in merges:
1727
 
                parent_trees.append(
1728
 
                    (parent, self.branch.repository.revision_tree(parent)))
1729
 
            if old_tip is not None:
1730
 
                parent_trees.append(
1731
 
                    (old_tip, self.branch.repository.revision_tree(old_tip)))
1732
 
            self.set_parent_trees(parent_trees)
1733
 
            last_rev = parent_trees[0][0]
1734
 
        else:
1735
 
            # the working tree had the same last-revision as the master
1736
 
            # branch did. We may still have pivot local work from the local
1737
 
            # branch into old_tip:
1738
 
            if old_tip is not None:
1739
 
                self.add_parent_tree_id(old_tip)
1740
 
        if old_tip and old_tip != last_rev:
1741
 
            # our last revision was not the prior branch last revision
1742
 
            # and we have converted that last revision to a pending merge.
1743
 
            # base is somewhere between the branch tip now
1744
 
            # and the now pending merge
1745
 
            from bzrlib.revision import common_ancestor
1746
 
            try:
1747
 
                base_rev_id = common_ancestor(self.branch.last_revision(),
1748
 
                                              old_tip,
1749
 
                                              self.branch.repository)
1750
 
            except errors.NoCommonAncestor:
1751
 
                base_rev_id = None
1752
 
            base_tree = self.branch.repository.revision_tree(base_rev_id)
1753
 
            other_tree = self.branch.repository.revision_tree(old_tip)
1754
 
            result += merge.merge_inner(
1755
 
                                  self.branch,
1756
 
                                  other_tree,
1757
 
                                  base_tree,
1758
 
                                  this_tree=self)
1759
 
        return result
1760
 
 
1761
 
    @needs_tree_write_lock
 
1438
            self.branch.unlock()
 
1439
 
 
1440
    @needs_write_lock
1762
1441
    def _write_inventory(self, inv):
1763
1442
        """Write inventory as the current inventory."""
1764
 
        self._set_inventory(inv, dirty=True)
1765
 
        self.flush()
 
1443
        sio = StringIO()
 
1444
        bzrlib.xml5.serializer_v5.write_inventory(inv, sio)
 
1445
        sio.seek(0)
 
1446
        self._control_files.put('inventory', sio)
 
1447
        self._set_inventory(inv)
 
1448
        mutter('wrote working inventory')
1766
1449
 
1767
1450
    def set_conflicts(self, arg):
1768
1451
        raise UnsupportedOperation(self.set_conflicts, self)
1772
1455
 
1773
1456
    @needs_read_lock
1774
1457
    def conflicts(self):
1775
 
        conflicts = _mod_conflicts.ConflictList()
 
1458
        conflicts = ConflictList()
1776
1459
        for conflicted in self._iter_conflicts():
1777
1460
            text = True
1778
1461
            try:
1791
1474
                    if text == False:
1792
1475
                        break
1793
1476
            ctype = {True: 'text conflict', False: 'contents conflict'}[text]
1794
 
            conflicts.append(_mod_conflicts.Conflict.factory(ctype,
1795
 
                             path=conflicted,
 
1477
            conflicts.append(Conflict.factory(ctype, path=conflicted,
1796
1478
                             file_id=self.path2id(conflicted)))
1797
1479
        return conflicts
1798
1480
 
1805
1487
     - uses the branch last-revision.
1806
1488
    """
1807
1489
 
1808
 
    def lock_tree_write(self):
1809
 
        """See WorkingTree.lock_tree_write().
1810
 
 
1811
 
        In Format2 WorkingTrees we have a single lock for the branch and tree
1812
 
        so lock_tree_write() degrades to lock_write().
1813
 
        """
1814
 
        self.branch.lock_write()
1815
 
        try:
1816
 
            return self._control_files.lock_write()
1817
 
        except:
1818
 
            self.branch.unlock()
1819
 
            raise
1820
 
 
1821
1490
    def unlock(self):
1822
1491
        # we share control files:
1823
 
        if self._control_files._lock_count == 3:
1824
 
            # _inventory_is_modified is always False during a read lock.
1825
 
            if self._inventory_is_modified:
1826
 
                self.flush()
1827
 
            if self._hashcache.needs_write:
1828
 
                self._hashcache.write()
 
1492
        if self._hashcache.needs_write and self._control_files._lock_count==3:
 
1493
            self._hashcache.write()
1829
1494
        # reverse order of locking.
1830
1495
        try:
1831
1496
            return self._control_files.unlock()
1844
1509
    """
1845
1510
 
1846
1511
    @needs_read_lock
1847
 
    def _last_revision(self):
1848
 
        """See Mutable.last_revision."""
 
1512
    def last_revision(self):
 
1513
        """See WorkingTree.last_revision."""
1849
1514
        try:
1850
1515
            return self._control_files.get_utf8('last-revision').read()
1851
1516
        except NoSuchFile:
1863
1528
            self._control_files.put_utf8('last-revision', revision_id)
1864
1529
            return True
1865
1530
 
1866
 
    @needs_tree_write_lock
 
1531
    @needs_write_lock
1867
1532
    def set_conflicts(self, conflicts):
1868
1533
        self._put_rio('conflicts', conflicts.to_stanzas(), 
1869
1534
                      CONFLICT_HEADER_1)
1870
1535
 
1871
 
    @needs_tree_write_lock
 
1536
    @needs_write_lock
1872
1537
    def add_conflicts(self, new_conflicts):
1873
1538
        conflict_set = set(self.conflicts())
1874
1539
        conflict_set.update(set(list(new_conflicts)))
1875
 
        self.set_conflicts(_mod_conflicts.ConflictList(sorted(conflict_set,
1876
 
                                       key=_mod_conflicts.Conflict.sort_key)))
 
1540
        self.set_conflicts(ConflictList(sorted(conflict_set,
 
1541
                                               key=Conflict.sort_key)))
1877
1542
 
1878
1543
    @needs_read_lock
1879
1544
    def conflicts(self):
1880
1545
        try:
1881
1546
            confile = self._control_files.get('conflicts')
1882
1547
        except NoSuchFile:
1883
 
            return _mod_conflicts.ConflictList()
 
1548
            return ConflictList()
1884
1549
        try:
1885
1550
            if confile.next() != CONFLICT_HEADER_1 + '\n':
1886
1551
                raise ConflictFormatError()
1887
1552
        except StopIteration:
1888
1553
            raise ConflictFormatError()
1889
 
        return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
 
1554
        return ConflictList.from_stanzas(RioReader(confile))
1890
1555
 
1891
1556
    def unlock(self):
1892
 
        if self._control_files._lock_count == 1:
1893
 
            # _inventory_is_modified is always False during a read lock.
1894
 
            if self._inventory_is_modified:
1895
 
                self.flush()
1896
 
            if self._hashcache.needs_write:
1897
 
                self._hashcache.write()
 
1557
        if self._hashcache.needs_write and self._control_files._lock_count==1:
 
1558
            self._hashcache.write()
1898
1559
        # reverse order of locking.
1899
1560
        try:
1900
1561
            return self._control_files.unlock()
1903
1564
 
1904
1565
 
1905
1566
def get_conflicted_stem(path):
1906
 
    for suffix in _mod_conflicts.CONFLICT_SUFFIXES:
 
1567
    for suffix in CONFLICT_SUFFIXES:
1907
1568
        if path.endswith(suffix):
1908
1569
            return path[:-len(suffix)]
1909
1570
 
2015
1676
        """
2016
1677
        sio = StringIO()
2017
1678
        inv = Inventory()
2018
 
        xml5.serializer_v5.write_inventory(inv, sio)
 
1679
        bzrlib.xml5.serializer_v5.write_inventory(inv, sio)
2019
1680
        sio.seek(0)
2020
1681
        control_files.put('inventory', sio)
2021
1682
 
2039
1700
            finally:
2040
1701
                branch.unlock()
2041
1702
        revision = branch.last_revision()
2042
 
        inv = Inventory()
 
1703
        inv = Inventory() 
2043
1704
        wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
2044
1705
                         branch,
2045
1706
                         inv,
2046
1707
                         _internal=True,
2047
1708
                         _format=self,
2048
1709
                         _bzrdir=a_bzrdir)
2049
 
        basis_tree = branch.repository.revision_tree(revision)
2050
 
        if basis_tree.inventory.root is not None:
2051
 
            wt.set_root_id(basis_tree.inventory.root.file_id)
2052
 
        # set the parent list and cache the basis tree.
2053
 
        wt.set_parent_trees([(revision, basis_tree)])
2054
 
        transform.build_tree(basis_tree, wt)
 
1710
        wt._write_inventory(inv)
 
1711
        wt.set_root_id(inv.root.file_id)
 
1712
        wt.set_last_revision(revision)
 
1713
        wt.set_pending_merges([])
 
1714
        build_tree(wt.basis_tree(), wt)
2055
1715
        return wt
2056
1716
 
2057
1717
    def __init__(self):
2119
1779
        branch = a_bzrdir.open_branch()
2120
1780
        if revision_id is None:
2121
1781
            revision_id = branch.last_revision()
2122
 
        # WorkingTree3 can handle an inventory which has a unique root id.
2123
 
        # as of bzr 0.12. However, bzr 0.11 and earlier fail to handle
2124
 
        # those trees. And because there isn't a format bump inbetween, we
2125
 
        # are maintaining compatibility with older clients.
2126
 
        # inv = Inventory(root_id=gen_root_id())
2127
 
        inv = Inventory()
 
1782
        inv = Inventory() 
2128
1783
        wt = WorkingTree3(a_bzrdir.root_transport.local_abspath('.'),
2129
1784
                         branch,
2130
1785
                         inv,
2132
1787
                         _format=self,
2133
1788
                         _bzrdir=a_bzrdir,
2134
1789
                         _control_files=control_files)
2135
 
        wt.lock_tree_write()
 
1790
        wt.lock_write()
2136
1791
        try:
2137
 
            basis_tree = branch.repository.revision_tree(revision_id)
2138
 
            # only set an explicit root id if there is one to set.
2139
 
            if basis_tree.inventory.root is not None:
2140
 
                wt.set_root_id(basis_tree.inventory.root.file_id)
2141
 
            if revision_id == NULL_REVISION:
2142
 
                wt.set_parent_trees([])
2143
 
            else:
2144
 
                wt.set_parent_trees([(revision_id, basis_tree)])
2145
 
            transform.build_tree(basis_tree, wt)
 
1792
            wt._write_inventory(inv)
 
1793
            wt.set_root_id(inv.root.file_id)
 
1794
            wt.set_last_revision(revision_id)
 
1795
            wt.set_pending_merges([])
 
1796
            build_tree(wt.basis_tree(), wt)
2146
1797
        finally:
2147
 
            # Unlock in this order so that the unlock-triggers-flush in
2148
 
            # WorkingTree is given a chance to fire.
 
1798
            wt.unlock()
2149
1799
            control_files.unlock()
2150
 
            wt.unlock()
2151
1800
        return wt
2152
1801
 
2153
1802
    def __init__(self):