/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

  • Committer: Andrew Bennetts
  • Date: 2010-04-13 04:33:55 UTC
  • mfrom: (5147 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5149.
  • Revision ID: andrew.bennetts@canonical.com-20100413043355-lg3id0uwtju0k3zs
MergeĀ lp:bzr.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2008 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
 
        )
 
107
from bzrlib.symbol_versioning import (
 
108
    deprecated_passed,
 
109
    DEPRECATED_PARAMETER,
 
110
    )
115
111
 
116
112
 
117
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.
118
117
CONFLICT_HEADER_1 = "BZR conflict list format 1"
119
118
 
120
119
ERROR_PATH_NOT_FOUND = 3    # WindowsError errno code, equivalent to ENOENT
123
122
class TreeEntry(object):
124
123
    """An entry that implements the minimum interface used by commands.
125
124
 
126
 
    This needs further inspection, it may be better to have 
 
125
    This needs further inspection, it may be better to have
127
126
    InventoryEntries without ids - though that seems wrong. For now,
128
127
    this is a parallel hierarchy to InventoryEntry, and needs to become
129
128
    one of several things: decorates to that hierarchy, children of, or
132
131
    no InventoryEntry available - i.e. for unversioned objects.
133
132
    Perhaps they should be UnversionedEntry et al. ? - RBC 20051003
134
133
    """
135
 
 
 
134
 
136
135
    def __eq__(self, other):
137
136
        # yes, this us ugly, TODO: best practice __eq__ style.
138
137
        return (isinstance(other, TreeEntry)
139
138
                and other.__class__ == self.__class__)
140
 
 
 
139
 
141
140
    def kind_character(self):
142
141
        return "???"
143
142
 
185
184
    not listed in the Inventory and vice versa.
186
185
    """
187
186
 
 
187
    # override this to set the strategy for storing views
 
188
    def _make_views(self):
 
189
        return views.DisabledViews(self)
 
190
 
188
191
    def __init__(self, basedir='.',
189
192
                 branch=DEPRECATED_PARAMETER,
190
193
                 _inventory=None,
225
228
        wt_trans = self.bzrdir.get_workingtree_transport(None)
226
229
        cache_filename = wt_trans.local_abspath('stat-cache')
227
230
        self._hashcache = hashcache.HashCache(basedir, cache_filename,
228
 
            self.bzrdir._get_file_mode())
 
231
            self.bzrdir._get_file_mode(),
 
232
            self._content_filter_stack_provider())
229
233
        hc = self._hashcache
230
234
        hc.read()
231
235
        # is this scan needed ? it makes things kinda slow.
247
251
            self._set_inventory(_inventory, dirty=False)
248
252
        self._detect_case_handling()
249
253
        self._rules_searcher = None
 
254
        self.views = self._make_views()
250
255
 
251
256
    def _detect_case_handling(self):
252
257
        wt_trans = self.bzrdir.get_workingtree_transport(None)
278
283
        self._control_files.break_lock()
279
284
        self.branch.break_lock()
280
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
 
281
296
    def requires_rich_root(self):
282
297
        return self._format.requires_rich_root
283
298
 
284
299
    def supports_tree_reference(self):
285
300
        return False
286
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
 
287
308
    def _set_inventory(self, inv, dirty):
288
309
        """Set the internal cached inventory.
289
310
 
303
324
 
304
325
        """
305
326
        if path is None:
306
 
            path = os.path.getcwdu()
 
327
            path = osutils.getcwd()
307
328
        control = bzrdir.BzrDir.open(path, _unsupported)
308
329
        return control.open_workingtree(_unsupported)
309
 
        
 
330
 
310
331
    @staticmethod
311
332
    def open_containing(path=None):
312
333
        """Open an existing working tree which has its root about path.
313
 
        
 
334
 
314
335
        This probes for a working tree at path and searches upwards from there.
315
336
 
316
337
        Basically we keep looking up until we find the control directory or
377
398
 
378
399
    def basis_tree(self):
379
400
        """Return RevisionTree for the current last revision.
380
 
        
 
401
 
381
402
        If the left most parent is a ghost then the returned tree will be an
382
 
        empty tree - one obtained by calling 
 
403
        empty tree - one obtained by calling
383
404
        repository.revision_tree(NULL_REVISION).
384
405
        """
385
406
        try:
401
422
            return self.branch.repository.revision_tree(revision_id)
402
423
        except (errors.RevisionNotPresent, errors.NoSuchRevision):
403
424
            # the basis tree *may* be a ghost or a low level error may have
404
 
            # 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
405
426
            # its a ghost.
406
427
            if self.branch.repository.has_revision(revision_id):
407
428
                raise
414
435
 
415
436
    def relpath(self, path):
416
437
        """Return the local path portion from a given path.
417
 
        
418
 
        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
419
440
        interpreted relative to the python current working directory.
420
441
        """
421
442
        return osutils.relpath(self.basedir, path)
423
444
    def has_filename(self, filename):
424
445
        return osutils.lexists(self.abspath(filename))
425
446
 
426
 
    def get_file(self, file_id, path=None):
427
 
        return self.get_file_with_stat(file_id, path)[0]
 
447
    def get_file(self, file_id, path=None, filtered=True):
 
448
        return self.get_file_with_stat(file_id, path, filtered=filtered)[0]
428
449
 
429
 
    def get_file_with_stat(self, file_id, path=None, _fstat=os.fstat):
430
 
        """See MutableTree.get_file_with_stat."""
 
450
    def get_file_with_stat(self, file_id, path=None, filtered=True,
 
451
        _fstat=os.fstat):
 
452
        """See Tree.get_file_with_stat."""
431
453
        if path is None:
432
454
            path = self.id2path(file_id)
433
 
        file_obj = self.get_file_byname(path)
434
 
        return (file_obj, _fstat(file_obj.fileno()))
435
 
 
436
 
    def get_file_text(self, file_id):
437
 
        return self.get_file(file_id).read()
438
 
 
439
 
    def get_file_byname(self, filename):
440
 
        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()
441
481
 
442
482
    @needs_read_lock
443
483
    def annotate_iter(self, file_id, default_revision=CURRENT_REVISION):
450
490
        incorrectly attributed to CURRENT_REVISION (but after committing, the
451
491
        attribution will be correct).
452
492
        """
453
 
        basis = self.basis_tree()
454
 
        basis.lock_read()
455
 
        try:
456
 
            changes = self.iter_changes(basis, True, [self.id2path(file_id)],
457
 
                require_versioned=True).next()
458
 
            changed_content, kind = changes[2], changes[6]
459
 
            if not changed_content:
460
 
                return basis.annotate_iter(file_id)
461
 
            if kind[1] is None:
462
 
                return None
463
 
            import annotate
464
 
            if kind[0] != 'file':
465
 
                old_lines = []
466
 
            else:
467
 
                old_lines = list(basis.annotate_iter(file_id))
468
 
            old = [old_lines]
469
 
            for tree in self.branch.repository.revision_trees(
470
 
                self.get_parent_ids()[1:]):
471
 
                if file_id not in tree:
472
 
                    continue
473
 
                old.append(list(tree.annotate_iter(file_id)))
474
 
            return annotate.reannotate(old, self.get_file(file_id).readlines(),
475
 
                                       default_revision)
476
 
        finally:
477
 
            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
478
529
 
479
530
    def _get_ancestors(self, default_revision):
480
531
        ancestors = set([default_revision])
485
536
 
486
537
    def get_parent_ids(self):
487
538
        """See Tree.get_parent_ids.
488
 
        
 
539
 
489
540
        This implementation reads the pending merges list and last_revision
490
541
        value and uses that to decide what the parents list should be.
491
542
        """
495
546
        else:
496
547
            parents = [last_rev]
497
548
        try:
498
 
            merges_file = self._transport.get('pending-merges')
 
549
            merges_bytes = self._transport.get_bytes('pending-merges')
499
550
        except errors.NoSuchFile:
500
551
            pass
501
552
        else:
502
 
            for l in merges_file.readlines():
 
553
            for l in osutils.split_lines(merges_bytes):
503
554
                revision_id = l.rstrip('\n')
504
555
                parents.append(revision_id)
505
556
        return parents
508
559
    def get_root_id(self):
509
560
        """Return the id of this trees root"""
510
561
        return self._inventory.root.file_id
511
 
        
 
562
 
512
563
    def _get_store_filename(self, file_id):
513
564
        ## XXX: badly named; this is not in the store at all
514
565
        return self.abspath(self.id2path(file_id))
516
567
    @needs_read_lock
517
568
    def clone(self, to_bzrdir, revision_id=None):
518
569
        """Duplicate this working tree into to_bzr, including all state.
519
 
        
 
570
 
520
571
        Specifically modified files are kept as modified, but
521
572
        ignored and unknown files are discarded.
522
573
 
523
574
        If you want to make a new line of development, see bzrdir.sprout()
524
575
 
525
576
        revision
526
 
            If not None, the cloned tree will have its last revision set to 
527
 
            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
528
579
            and this one merged in.
529
580
        """
530
581
        # assumes the target bzr dir format is compatible.
564
615
 
565
616
    def get_file_size(self, file_id):
566
617
        """See Tree.get_file_size"""
 
618
        # XXX: this returns the on-disk size; it should probably return the
 
619
        # canonical size
567
620
        try:
568
621
            return os.path.getsize(self.id2abspath(file_id))
569
622
        except OSError, e:
585
638
 
586
639
    def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
587
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
588
645
        return self._inventory[file_id].executable
589
646
 
590
647
    def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
612
669
        """See MutableTree._add."""
613
670
        # TODO: Re-adding a file that is removed in the working copy
614
671
        # should probably put it back with the previous ID.
615
 
        # the read and write working inventory should not occur in this 
 
672
        # the read and write working inventory should not occur in this
616
673
        # function - they should be part of lock_write and unlock.
617
674
        inv = self.inventory
618
675
        for f, file_id, kind in zip(files, ids, kinds):
700
757
            raise
701
758
        kind = _mapper(stat_result.st_mode)
702
759
        if kind == 'file':
703
 
            size = stat_result.st_size
704
 
            # try for a stat cache lookup
705
 
            executable = self._is_executable_from_path_and_stat(path, stat_result)
706
 
            return (kind, size, executable, self._sha_from_stat(
707
 
                path, stat_result))
 
760
            return self._file_content_summary(path, stat_result)
708
761
        elif kind == 'directory':
709
762
            # perhaps it looks like a plain directory, but it's really a
710
763
            # reference.
712
765
                kind = 'tree-reference'
713
766
            return kind, None, None, None
714
767
        elif kind == 'symlink':
715
 
            return ('symlink', None, None, os.readlink(abspath))
 
768
            target = osutils.readlink(abspath)
 
769
            return ('symlink', None, None, target)
716
770
        else:
717
771
            return (kind, None, None, None)
718
772
 
 
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))
 
779
 
719
780
    def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
720
781
        """Common ghost checking functionality from set_parent_*.
721
782
 
731
792
    def _set_merges_from_parent_ids(self, parent_ids):
732
793
        merges = parent_ids[1:]
733
794
        self._transport.put_bytes('pending-merges', '\n'.join(merges),
734
 
            mode=self._control_files._file_mode)
 
795
            mode=self.bzrdir._get_file_mode())
735
796
 
736
797
    def _filter_parent_ids_by_ancestry(self, revision_ids):
737
798
        """Check that all merged revisions are proper 'heads'.
738
799
 
739
800
        This will always return the first revision_id, and any merged revisions
740
 
        which are 
 
801
        which are
741
802
        """
742
803
        if len(revision_ids) == 0:
743
804
            return revision_ids
755
816
    @needs_tree_write_lock
756
817
    def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
757
818
        """Set the parent ids to revision_ids.
758
 
        
 
819
 
759
820
        See also set_parent_trees. This api will try to retrieve the tree data
760
821
        for each element of revision_ids from the trees repository. If you have
761
822
        tree data already available, it is more efficient to use
837
898
        self._must_be_locked()
838
899
        my_file = rio_file(stanzas, header)
839
900
        self._transport.put_file(filename, my_file,
840
 
            mode=self._control_files._file_mode)
 
901
            mode=self.bzrdir._get_file_mode())
841
902
 
842
903
    @needs_write_lock # because merge pulls data into the branch.
843
904
    def merge_from_branch(self, branch, to_revision=None, from_revision=None,
844
 
        merge_type=None):
 
905
                          merge_type=None, force=False):
845
906
        """Merge from a branch into this working tree.
846
907
 
847
908
        :param branch: The branch to merge from.
851
912
            branch.last_revision().
852
913
        """
853
914
        from bzrlib.merge import Merger, Merge3Merger
854
 
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
855
 
        try:
856
 
            merger = Merger(self.branch, this_tree=self, pb=pb)
857
 
            merger.pp = ProgressPhase("Merge phase", 5, pb)
858
 
            merger.pp.next_phase()
859
 
            # check that there are no
860
 
            # local alterations
861
 
            merger.check_basis(check_clean=True, require_commits=False)
862
 
            if to_revision is None:
863
 
                to_revision = _mod_revision.ensure_null(branch.last_revision())
864
 
            merger.other_rev_id = to_revision
865
 
            if _mod_revision.is_null(merger.other_rev_id):
866
 
                raise errors.NoCommits(branch)
867
 
            self.branch.fetch(branch, last_revision=merger.other_rev_id)
868
 
            merger.other_basis = merger.other_rev_id
869
 
            merger.other_tree = self.branch.repository.revision_tree(
870
 
                merger.other_rev_id)
871
 
            merger.other_branch = branch
872
 
            merger.pp.next_phase()
873
 
            if from_revision is None:
874
 
                merger.find_base()
875
 
            else:
876
 
                merger.set_base_revision(from_revision, branch)
877
 
            if merger.base_rev_id == merger.other_rev_id:
878
 
                raise errors.PointlessMerge
879
 
            merger.backup_files = False
880
 
            if merge_type is None:
881
 
                merger.merge_type = Merge3Merger
882
 
            else:
883
 
                merger.merge_type = merge_type
884
 
            merger.set_interesting_files(None)
885
 
            merger.show_base = False
886
 
            merger.reprocess = False
887
 
            conflicts = merger.do_merge()
888
 
            merger.set_pending()
889
 
        finally:
890
 
            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()
891
945
        return conflicts
892
946
 
893
947
    @needs_read_lock
894
948
    def merge_modified(self):
895
949
        """Return a dictionary of files modified by a merge.
896
950
 
897
 
        The list is initialized by WorkingTree.set_merge_modified, which is 
 
951
        The list is initialized by WorkingTree.set_merge_modified, which is
898
952
        typically called after we make some automatic updates to the tree
899
953
        because of a merge.
900
954
 
934
988
        return file_id
935
989
 
936
990
    def get_symlink_target(self, file_id):
937
 
        return os.readlink(self.id2abspath(file_id))
 
991
        abspath = self.id2abspath(file_id)
 
992
        target = osutils.readlink(abspath)
 
993
        return target
938
994
 
939
995
    @needs_write_lock
940
996
    def subsume(self, other_tree):
990
1046
        return False
991
1047
 
992
1048
    def _directory_may_be_tree_reference(self, relpath):
993
 
        # as a special case, if a directory contains control files then 
 
1049
        # as a special case, if a directory contains control files then
994
1050
        # it's a tree reference, except that the root of the tree is not
995
1051
        return relpath and osutils.isdir(self.abspath(relpath) + u"/.bzr")
996
1052
        # TODO: We could ask all the control formats whether they
1007
1063
    @needs_tree_write_lock
1008
1064
    def extract(self, file_id, format=None):
1009
1065
        """Extract a subtree from this tree.
1010
 
        
 
1066
 
1011
1067
        A new branch will be created, relative to the path for this tree.
1012
1068
        """
1013
1069
        self.flush()
1018
1074
                transport = transport.clone(name)
1019
1075
                transport.ensure_base()
1020
1076
            return transport
1021
 
            
 
1077
 
1022
1078
        sub_path = self.id2path(file_id)
1023
1079
        branch_transport = mkdirs(sub_path)
1024
1080
        if format is None:
1038
1094
        tree_transport = self.bzrdir.root_transport.clone(sub_path)
1039
1095
        if tree_transport.base != branch_transport.base:
1040
1096
            tree_bzrdir = format.initialize_on_transport(tree_transport)
1041
 
            branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
 
1097
            branch.BranchReferenceFormat().initialize(tree_bzrdir,
 
1098
                target_branch=new_branch)
1042
1099
        else:
1043
1100
            tree_bzrdir = branch_bzrdir
1044
 
        wt = tree_bzrdir.create_workingtree(NULL_REVISION)
 
1101
        wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
1045
1102
        wt.set_parent_ids(self.get_parent_ids())
1046
1103
        my_inv = self.inventory
1047
 
        child_inv = Inventory(root_id=None)
 
1104
        child_inv = inventory.Inventory(root_id=None)
1048
1105
        new_root = my_inv[file_id]
1049
1106
        my_inv.remove_recursive_id(file_id)
1050
1107
        new_root.parent_id = None
1069
1126
        self._serialize(self._inventory, sio)
1070
1127
        sio.seek(0)
1071
1128
        self._transport.put_file('inventory', sio,
1072
 
            mode=self._control_files._file_mode)
 
1129
            mode=self.bzrdir._get_file_mode())
1073
1130
        self._inventory_is_modified = False
1074
1131
 
1075
1132
    def _kind(self, relpath):
1076
1133
        return osutils.file_kind(self.abspath(relpath))
1077
1134
 
1078
 
    def list_files(self, include_root=False):
1079
 
        """Recursively list all files as (path, class, kind, id, entry).
 
1135
    def list_files(self, include_root=False, from_dir=None, recursive=True):
 
1136
        """List all files as (path, class, kind, id, entry).
1080
1137
 
1081
1138
        Lists, but does not descend into unversioned directories.
1082
 
 
1083
1139
        This does not include files that have been deleted in this
1084
 
        tree.
 
1140
        tree. Skips the control directory.
1085
1141
 
1086
 
        Skips the control directory.
 
1142
        :param include_root: if True, return an entry for the root
 
1143
        :param from_dir: start from this directory or None for the root
 
1144
        :param recursive: whether to recurse into subdirectories or not
1087
1145
        """
1088
1146
        # list_files is an iterator, so @needs_read_lock doesn't work properly
1089
1147
        # with it. So callers should be careful to always read_lock the tree.
1091
1149
            raise errors.ObjectNotLocked(self)
1092
1150
 
1093
1151
        inv = self.inventory
1094
 
        if include_root is True:
 
1152
        if from_dir is None and include_root is True:
1095
1153
            yield ('', 'V', 'directory', inv.root.file_id, inv.root)
1096
1154
        # Convert these into local objects to save lookup times
1097
1155
        pathjoin = osutils.pathjoin
1104
1162
        fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
1105
1163
 
1106
1164
        # directory file_id, relative path, absolute path, reverse sorted children
1107
 
        children = os.listdir(self.basedir)
 
1165
        if from_dir is not None:
 
1166
            from_dir_id = inv.path2id(from_dir)
 
1167
            if from_dir_id is None:
 
1168
                # Directory not versioned
 
1169
                return
 
1170
            from_dir_abspath = pathjoin(self.basedir, from_dir)
 
1171
        else:
 
1172
            from_dir_id = inv.root.file_id
 
1173
            from_dir_abspath = self.basedir
 
1174
        children = os.listdir(from_dir_abspath)
1108
1175
        children.sort()
1109
 
        # jam 20060527 The kernel sized tree seems equivalent whether we 
 
1176
        # jam 20060527 The kernel sized tree seems equivalent whether we
1110
1177
        # use a deque and popleft to keep them sorted, or if we use a plain
1111
1178
        # list and just reverse() them.
1112
1179
        children = collections.deque(children)
1113
 
        stack = [(inv.root.file_id, u'', self.basedir, children)]
 
1180
        stack = [(from_dir_id, u'', from_dir_abspath, children)]
1114
1181
        while stack:
1115
1182
            from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
1116
1183
 
1132
1199
 
1133
1200
                # absolute path
1134
1201
                fap = from_dir_abspath + '/' + f
1135
 
                
 
1202
 
1136
1203
                f_ie = inv.get_child(from_dir_id, f)
1137
1204
                if f_ie:
1138
1205
                    c = 'V'
1170
1237
                    except KeyError:
1171
1238
                        yield fp[1:], c, fk, None, TreeEntry()
1172
1239
                    continue
1173
 
                
 
1240
 
1174
1241
                if fk != 'directory':
1175
1242
                    continue
1176
1243
 
1177
 
                # But do this child first
1178
 
                new_children = os.listdir(fap)
1179
 
                new_children.sort()
1180
 
                new_children = collections.deque(new_children)
1181
 
                stack.append((f_ie.file_id, fp, fap, new_children))
1182
 
                # Break out of inner loop,
1183
 
                # so that we start outer loop with child
1184
 
                break
 
1244
                # But do this child first if recursing down
 
1245
                if recursive:
 
1246
                    new_children = os.listdir(fap)
 
1247
                    new_children.sort()
 
1248
                    new_children = collections.deque(new_children)
 
1249
                    stack.append((f_ie.file_id, fp, fap, new_children))
 
1250
                    # Break out of inner loop,
 
1251
                    # so that we start outer loop with child
 
1252
                    break
1185
1253
            else:
1186
1254
                # if we finished all children, pop it off the stack
1187
1255
                stack.pop()
1193
1261
        to_dir must exist in the inventory.
1194
1262
 
1195
1263
        If to_dir exists and is a directory, the files are moved into
1196
 
        it, keeping their old names.  
 
1264
        it, keeping their old names.
1197
1265
 
1198
1266
        Note that to_dir is only the last component of the new name;
1199
1267
        this doesn't change the directory.
1365
1433
        inv = self.inventory
1366
1434
        for entry in moved:
1367
1435
            try:
1368
 
                self._move_entry(_RenameEntry(entry.to_rel, entry.from_id,
 
1436
                self._move_entry(WorkingTree._RenameEntry(
 
1437
                    entry.to_rel, entry.from_id,
1369
1438
                    entry.to_tail, entry.to_parent_id, entry.from_rel,
1370
1439
                    entry.from_tail, entry.from_parent_id,
1371
1440
                    entry.only_change_inv))
1422
1491
        from_tail = splitpath(from_rel)[-1]
1423
1492
        from_id = inv.path2id(from_rel)
1424
1493
        if from_id is None:
1425
 
            raise errors.BzrRenameFailedError(from_rel,to_rel,
1426
 
                errors.NotVersionedError(path=str(from_rel)))
1427
 
        from_entry = inv[from_id]
 
1494
            # if file is missing in the inventory maybe it's in the basis_tree
 
1495
            basis_tree = self.branch.basis_tree()
 
1496
            from_id = basis_tree.path2id(from_rel)
 
1497
            if from_id is None:
 
1498
                raise errors.BzrRenameFailedError(from_rel,to_rel,
 
1499
                    errors.NotVersionedError(path=str(from_rel)))
 
1500
            # put entry back in the inventory so we can rename it
 
1501
            from_entry = basis_tree.inventory[from_id].copy()
 
1502
            inv.add(from_entry)
 
1503
        else:
 
1504
            from_entry = inv[from_id]
1428
1505
        from_parent_id = from_entry.parent_id
1429
1506
        to_dir, to_tail = os.path.split(to_rel)
1430
1507
        to_dir_id = inv.path2id(to_dir)
1476
1553
        These are files in the working directory that are not versioned or
1477
1554
        control files or ignored.
1478
1555
        """
1479
 
        # force the extras method to be fully executed before returning, to 
 
1556
        # force the extras method to be fully executed before returning, to
1480
1557
        # prevent race conditions with the lock
1481
1558
        return iter(
1482
1559
            [subp for subp in self.extras() if not self.is_ignored(subp)])
1492
1569
        :raises: NoSuchId if any fileid is not currently versioned.
1493
1570
        """
1494
1571
        for file_id in file_ids:
 
1572
            if file_id not in self._inventory:
 
1573
                raise errors.NoSuchId(self, file_id)
 
1574
        for file_id in file_ids:
1495
1575
            if self._inventory.has_id(file_id):
1496
1576
                self._inventory.remove_recursive_id(file_id)
1497
 
            else:
1498
 
                raise errors.NoSuchId(self, file_id)
1499
1577
        if len(file_ids):
1500
 
            # in the future this should just set a dirty bit to wait for the 
 
1578
            # in the future this should just set a dirty bit to wait for the
1501
1579
            # final unlock. However, until all methods of workingtree start
1502
 
            # with the current in -memory inventory rather than triggering 
 
1580
            # with the current in -memory inventory rather than triggering
1503
1581
            # a read, it is more complex - we need to teach read_inventory
1504
1582
            # to know when to read, and when to not read first... and possibly
1505
1583
            # to save first when the in memory one may be corrupted.
1506
1584
            # so for now, we just only write it if it is indeed dirty.
1507
1585
            # - RBC 20060907
1508
1586
            self._write_inventory(self._inventory)
1509
 
    
 
1587
 
1510
1588
    def _iter_conflicts(self):
1511
1589
        conflicted = set()
1512
1590
        for info in self.list_files():
1520
1598
 
1521
1599
    @needs_write_lock
1522
1600
    def pull(self, source, overwrite=False, stop_revision=None,
1523
 
             change_reporter=None, possible_transports=None):
1524
 
        top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
1601
             change_reporter=None, possible_transports=None, local=False):
1525
1602
        source.lock_read()
1526
1603
        try:
1527
 
            pp = ProgressPhase("Pull phase", 2, top_pb)
1528
 
            pp.next_phase()
1529
1604
            old_revision_info = self.branch.last_revision_info()
1530
1605
            basis_tree = self.basis_tree()
1531
1606
            count = self.branch.pull(source, overwrite, stop_revision,
1532
 
                                     possible_transports=possible_transports)
 
1607
                                     possible_transports=possible_transports,
 
1608
                                     local=local)
1533
1609
            new_revision_info = self.branch.last_revision_info()
1534
1610
            if new_revision_info != old_revision_info:
1535
 
                pp.next_phase()
1536
1611
                repository = self.branch.repository
1537
 
                pb = bzrlib.ui.ui_factory.nested_progress_bar()
1538
1612
                basis_tree.lock_read()
1539
1613
                try:
1540
1614
                    new_basis_tree = self.branch.basis_tree()
1543
1617
                                new_basis_tree,
1544
1618
                                basis_tree,
1545
1619
                                this_tree=self,
1546
 
                                pb=pb,
 
1620
                                pb=None,
1547
1621
                                change_reporter=change_reporter)
1548
 
                    if (basis_tree.inventory.root is None and
1549
 
                        new_basis_tree.inventory.root is not None):
1550
 
                        self.set_root_id(new_basis_tree.get_root_id())
 
1622
                    basis_root_id = basis_tree.get_root_id()
 
1623
                    new_root_id = new_basis_tree.get_root_id()
 
1624
                    if basis_root_id != new_root_id:
 
1625
                        self.set_root_id(new_root_id)
1551
1626
                finally:
1552
 
                    pb.finished()
1553
1627
                    basis_tree.unlock()
1554
1628
                # TODO - dedup parents list with things merged by pull ?
1555
1629
                # reuse the revisiontree we merged against to set the new
1556
1630
                # tree data.
1557
1631
                parent_trees = [(self.branch.last_revision(), new_basis_tree)]
1558
 
                # we have to pull the merge trees out again, because 
1559
 
                # merge_inner has set the ids. - this corner is not yet 
 
1632
                # we have to pull the merge trees out again, because
 
1633
                # merge_inner has set the ids. - this corner is not yet
1560
1634
                # layered well enough to prevent double handling.
1561
1635
                # XXX TODO: Fix the double handling: telling the tree about
1562
1636
                # the already known parent data is wasteful.
1568
1642
            return count
1569
1643
        finally:
1570
1644
            source.unlock()
1571
 
            top_pb.finished()
1572
1645
 
1573
1646
    @needs_write_lock
1574
1647
    def put_file_bytes_non_atomic(self, file_id, bytes):
1600
1673
 
1601
1674
            fl = []
1602
1675
            for subf in os.listdir(dirabs):
1603
 
                if subf == '.bzr':
 
1676
                if self.bzrdir.is_control_filename(subf):
1604
1677
                    continue
1605
1678
                if subf not in dir_entry.children:
1606
1679
                    try:
1616
1689
                            fl.append(subf_norm)
1617
1690
                    else:
1618
1691
                        fl.append(subf)
1619
 
            
 
1692
 
1620
1693
            fl.sort()
1621
1694
            for subf in fl:
1622
1695
                subp = pathjoin(path, subf)
1659
1732
        r"""Check whether the filename matches an ignore pattern.
1660
1733
 
1661
1734
        Patterns containing '/' or '\' need to match the whole path;
1662
 
        others match against only the last component.
 
1735
        others match against only the last component.  Patterns starting
 
1736
        with '!' are ignore exceptions.  Exceptions take precedence
 
1737
        over regular patterns and cause the filename to not be ignored.
1663
1738
 
1664
1739
        If the file is ignored, returns the pattern which caused it to
1665
1740
        be ignored, otherwise None.  So this can simply be used as a
1666
1741
        boolean if desired."""
1667
1742
        if getattr(self, '_ignoreglobster', None) is None:
1668
 
            self._ignoreglobster = globbing.Globster(self.get_ignore_list())
 
1743
            self._ignoreglobster = globbing.ExceptionGlobster(self.get_ignore_list())
1669
1744
        return self._ignoreglobster.match(filename)
1670
1745
 
1671
1746
    def kind(self, file_id):
1762
1837
    def _reset_data(self):
1763
1838
        """Reset transient data that cannot be revalidated."""
1764
1839
        self._inventory_is_modified = False
1765
 
        result = self._deserialize(self._transport.get('inventory'))
 
1840
        f = self._transport.get('inventory')
 
1841
        try:
 
1842
            result = self._deserialize(f)
 
1843
        finally:
 
1844
            f.close()
1766
1845
        self._set_inventory(result, dirty=False)
1767
1846
 
1768
1847
    @needs_tree_write_lock
1773
1852
 
1774
1853
    def _change_last_revision(self, new_revision):
1775
1854
        """Template method part of set_last_revision to perform the change.
1776
 
        
 
1855
 
1777
1856
        This is used to allow WorkingTree3 instances to not affect branch
1778
1857
        when their last revision is set.
1779
1858
        """
1792
1871
        path = self._basis_inventory_name()
1793
1872
        sio = StringIO(xml)
1794
1873
        self._transport.put_file(path, sio,
1795
 
            mode=self._control_files._file_mode)
 
1874
            mode=self.bzrdir._get_file_mode())
1796
1875
 
1797
1876
    def _create_basis_xml_from_inventory(self, revision_id, inventory):
1798
1877
        """Create the text that will be saved in basis-inventory"""
1805
1884
        # as commit already has that ready-to-use [while the format is the
1806
1885
        # same, that is].
1807
1886
        try:
1808
 
            # this double handles the inventory - unpack and repack - 
 
1887
            # this double handles the inventory - unpack and repack -
1809
1888
            # but is easier to understand. We can/should put a conditional
1810
1889
            # in here based on whether the inventory is in the latest format
1811
1890
            # - perhaps we should repack all inventories on a repository
1812
1891
            # upgrade ?
1813
1892
            # the fast path is to copy the raw xml from the repository. If the
1814
 
            # xml contains 'revision_id="', then we assume the right 
 
1893
            # xml contains 'revision_id="', then we assume the right
1815
1894
            # revision_id is set. We must check for this full string, because a
1816
1895
            # root node id can legitimately look like 'revision_id' but cannot
1817
1896
            # contain a '"'.
1818
 
            xml = self.branch.repository.get_inventory_xml(new_revision)
 
1897
            xml = self.branch.repository._get_inventory_xml(new_revision)
1819
1898
            firstline = xml.split('\n', 1)[0]
1820
 
            if (not 'revision_id="' in firstline or 
 
1899
            if (not 'revision_id="' in firstline or
1821
1900
                'format="7"' not in firstline):
1822
 
                inv = self.branch.repository.deserialise_inventory(
1823
 
                    new_revision, xml)
 
1901
                inv = self.branch.repository._serializer.read_inventory_from_string(
 
1902
                    xml, new_revision)
1824
1903
                xml = self._create_basis_xml_from_inventory(new_revision, inv)
1825
1904
            self._write_basis_inventory(xml)
1826
1905
        except (errors.NoSuchRevision, errors.RevisionNotPresent):
1830
1909
        """Read the cached basis inventory."""
1831
1910
        path = self._basis_inventory_name()
1832
1911
        return self._transport.get_bytes(path)
1833
 
        
 
1912
 
1834
1913
    @needs_read_lock
1835
1914
    def read_working_inventory(self):
1836
1915
        """Read the working inventory.
1837
 
        
 
1916
 
1838
1917
        :raises errors.InventoryModified: read_working_inventory will fail
1839
1918
            when the current in memory inventory has been modified.
1840
1919
        """
1841
 
        # conceptually this should be an implementation detail of the tree. 
 
1920
        # conceptually this should be an implementation detail of the tree.
1842
1921
        # XXX: Deprecate this.
1843
1922
        # ElementTree does its own conversion from UTF-8, so open in
1844
1923
        # binary.
1845
1924
        if self._inventory_is_modified:
1846
1925
            raise errors.InventoryModified(self)
1847
 
        result = self._deserialize(self._transport.get('inventory'))
 
1926
        f = self._transport.get('inventory')
 
1927
        try:
 
1928
            result = self._deserialize(f)
 
1929
        finally:
 
1930
            f.close()
1848
1931
        self._set_inventory(result, dirty=False)
1849
1932
        return result
1850
1933
 
1865
1948
 
1866
1949
        new_files=set()
1867
1950
        unknown_nested_files=set()
 
1951
        if to_file is None:
 
1952
            to_file = sys.stdout
1868
1953
 
1869
1954
        def recurse_directory_to_add_files(directory):
1870
1955
            # Recurse directory and add all files
1926
2011
                        tree_delta.unversioned.extend((unknown_file,))
1927
2012
                raise errors.BzrRemoveChangedFilesError(tree_delta)
1928
2013
 
1929
 
        # Build inv_delta and delete files where applicaple,
 
2014
        # Build inv_delta and delete files where applicable,
1930
2015
        # do this before any modifications to inventory.
1931
2016
        for f in files:
1932
2017
            fid = self.path2id(f)
1940
2025
                        new_status = 'I'
1941
2026
                    else:
1942
2027
                        new_status = '?'
1943
 
                    textui.show_status(new_status, self.kind(fid), f,
1944
 
                                       to_file=to_file)
 
2028
                    # XXX: Really should be a more abstract reporter interface
 
2029
                    kind_ch = osutils.kind_marker(self.kind(fid))
 
2030
                    to_file.write(new_status + '       ' + f + kind_ch + '\n')
1945
2031
                # Unversion file
1946
2032
                inv_delta.append((f, None, fid, None))
1947
2033
                message = "removed %s" % (f,)
1970
2056
 
1971
2057
    @needs_tree_write_lock
1972
2058
    def revert(self, filenames=None, old_tree=None, backups=True,
1973
 
               pb=DummyProgress(), report_changes=False):
 
2059
               pb=None, report_changes=False):
1974
2060
        from bzrlib.conflicts import resolve
1975
2061
        if filenames == []:
1976
2062
            filenames = None
1989
2075
            if filenames is None and len(self.get_parent_ids()) > 1:
1990
2076
                parent_trees = []
1991
2077
                last_revision = self.last_revision()
1992
 
                if last_revision != NULL_REVISION:
 
2078
                if last_revision != _mod_revision.NULL_REVISION:
1993
2079
                    if basis_tree is None:
1994
2080
                        basis_tree = self.basis_tree()
1995
2081
                        basis_tree.lock_read()
2033
2119
    def set_inventory(self, new_inventory_list):
2034
2120
        from bzrlib.inventory import (Inventory,
2035
2121
                                      InventoryDirectory,
2036
 
                                      InventoryEntry,
2037
2122
                                      InventoryFile,
2038
2123
                                      InventoryLink)
2039
2124
        inv = Inventory(self.get_root_id())
2041
2126
            name = os.path.basename(path)
2042
2127
            if name == "":
2043
2128
                continue
2044
 
            # fixme, there should be a factory function inv,add_?? 
 
2129
            # fixme, there should be a factory function inv,add_??
2045
2130
            if kind == 'directory':
2046
2131
                inv.add(InventoryDirectory(file_id, name, parent))
2047
2132
            elif kind == 'file':
2055
2140
    @needs_tree_write_lock
2056
2141
    def set_root_id(self, file_id):
2057
2142
        """Set the root id for this tree."""
2058
 
        # for compatability 
 
2143
        # for compatability
2059
2144
        if file_id is None:
2060
2145
            raise ValueError(
2061
2146
                'WorkingTree.set_root_id with fileid=None')
2065
2150
    def _set_root_id(self, file_id):
2066
2151
        """Set the root id for this tree, in a format specific manner.
2067
2152
 
2068
 
        :param file_id: The file id to assign to the root. It must not be 
 
2153
        :param file_id: The file id to assign to the root. It must not be
2069
2154
            present in the current inventory or an error will occur. It must
2070
2155
            not be None, but rather a valid file id.
2071
2156
        """
2090
2175
 
2091
2176
    def unlock(self):
2092
2177
        """See Branch.unlock.
2093
 
        
 
2178
 
2094
2179
        WorkingTree locking just uses the Branch locking facilities.
2095
2180
        This is current because all working trees have an embedded branch
2096
2181
        within them. IF in the future, we were to make branch data shareable
2097
 
        between multiple working trees, i.e. via shared storage, then we 
 
2182
        between multiple working trees, i.e. via shared storage, then we
2098
2183
        would probably want to lock both the local tree, and the branch.
2099
2184
        """
2100
2185
        raise NotImplementedError(self.unlock)
2101
2186
 
2102
 
    def update(self, change_reporter=None, possible_transports=None):
 
2187
    _marker = object()
 
2188
 
 
2189
    def update(self, change_reporter=None, possible_transports=None,
 
2190
               revision=None, old_tip=_marker):
2103
2191
        """Update a working tree along its branch.
2104
2192
 
2105
2193
        This will update the branch if its bound too, which means we have
2123
2211
        - Merge current state -> basis tree of the master w.r.t. the old tree
2124
2212
          basis.
2125
2213
        - Do a 'normal' merge of the old branch basis if it is relevant.
 
2214
 
 
2215
        :param revision: The target revision to update to. Must be in the
 
2216
            revision history.
 
2217
        :param old_tip: If branch.update() has already been run, the value it
 
2218
            returned (old tip of the branch or None). _marker is used
 
2219
            otherwise.
2126
2220
        """
2127
2221
        if self.branch.get_bound_location() is not None:
2128
2222
            self.lock_write()
2129
 
            update_branch = True
 
2223
            update_branch = (old_tip is self._marker)
2130
2224
        else:
2131
2225
            self.lock_tree_write()
2132
2226
            update_branch = False
2134
2228
            if update_branch:
2135
2229
                old_tip = self.branch.update(possible_transports)
2136
2230
            else:
2137
 
                old_tip = None
2138
 
            return self._update_tree(old_tip, change_reporter)
 
2231
                if old_tip is self._marker:
 
2232
                    old_tip = None
 
2233
            return self._update_tree(old_tip, change_reporter, revision)
2139
2234
        finally:
2140
2235
            self.unlock()
2141
2236
 
2142
2237
    @needs_tree_write_lock
2143
 
    def _update_tree(self, old_tip=None, change_reporter=None):
 
2238
    def _update_tree(self, old_tip=None, change_reporter=None, revision=None):
2144
2239
        """Update a tree to the master branch.
2145
2240
 
2146
2241
        :param old_tip: if supplied, the previous tip revision the branch,
2152
2247
        # cant set that until we update the working trees last revision to be
2153
2248
        # one from the new branch, because it will just get absorbed by the
2154
2249
        # parent de-duplication logic.
2155
 
        # 
 
2250
        #
2156
2251
        # We MUST save it even if an error occurs, because otherwise the users
2157
2252
        # local work is unreferenced and will appear to have been lost.
2158
 
        # 
2159
 
        result = 0
 
2253
        #
 
2254
        nb_conflicts = 0
2160
2255
        try:
2161
2256
            last_rev = self.get_parent_ids()[0]
2162
2257
        except IndexError:
2163
2258
            last_rev = _mod_revision.NULL_REVISION
2164
 
        if last_rev != _mod_revision.ensure_null(self.branch.last_revision()):
2165
 
            # merge tree state up to new branch tip.
 
2259
        if revision is None:
 
2260
            revision = self.branch.last_revision()
 
2261
 
 
2262
        old_tip = old_tip or _mod_revision.NULL_REVISION
 
2263
 
 
2264
        if not _mod_revision.is_null(old_tip) and old_tip != last_rev:
 
2265
            # the branch we are bound to was updated
 
2266
            # merge those changes in first
 
2267
            base_tree  = self.basis_tree()
 
2268
            other_tree = self.branch.repository.revision_tree(old_tip)
 
2269
            nb_conflicts = merge.merge_inner(self.branch, other_tree,
 
2270
                                             base_tree, this_tree=self,
 
2271
                                             change_reporter=change_reporter)
 
2272
            if nb_conflicts:
 
2273
                self.add_parent_tree((old_tip, other_tree))
 
2274
                trace.note('Rerun update after fixing the conflicts.')
 
2275
                return nb_conflicts
 
2276
 
 
2277
        if last_rev != _mod_revision.ensure_null(revision):
 
2278
            # the working tree is up to date with the branch
 
2279
            # we can merge the specified revision from master
 
2280
            to_tree = self.branch.repository.revision_tree(revision)
 
2281
            to_root_id = to_tree.get_root_id()
 
2282
 
2166
2283
            basis = self.basis_tree()
2167
2284
            basis.lock_read()
2168
2285
            try:
2169
 
                to_tree = self.branch.basis_tree()
2170
 
                if basis.inventory.root is None:
2171
 
                    self.set_root_id(to_tree.get_root_id())
 
2286
                if (basis.inventory.root is None
 
2287
                    or basis.inventory.root.file_id != to_root_id):
 
2288
                    self.set_root_id(to_root_id)
2172
2289
                    self.flush()
2173
 
                result += merge.merge_inner(
2174
 
                                      self.branch,
2175
 
                                      to_tree,
2176
 
                                      basis,
2177
 
                                      this_tree=self,
2178
 
                                      change_reporter=change_reporter)
2179
2290
            finally:
2180
2291
                basis.unlock()
 
2292
 
 
2293
            # determine the branch point
 
2294
            graph = self.branch.repository.get_graph()
 
2295
            base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
 
2296
                                                last_rev)
 
2297
            base_tree = self.branch.repository.revision_tree(base_rev_id)
 
2298
 
 
2299
            nb_conflicts = merge.merge_inner(self.branch, to_tree, base_tree,
 
2300
                                             this_tree=self,
 
2301
                                             change_reporter=change_reporter)
 
2302
            self.set_last_revision(revision)
2181
2303
            # TODO - dedup parents list with things merged by pull ?
2182
2304
            # reuse the tree we've updated to to set the basis:
2183
 
            parent_trees = [(self.branch.last_revision(), to_tree)]
 
2305
            parent_trees = [(revision, to_tree)]
2184
2306
            merges = self.get_parent_ids()[1:]
2185
2307
            # Ideally we ask the tree for the trees here, that way the working
2186
 
            # tree can decide whether to give us teh entire tree or give us a
 
2308
            # tree can decide whether to give us the entire tree or give us a
2187
2309
            # lazy initialised tree. dirstate for instance will have the trees
2188
2310
            # in ram already, whereas a last-revision + basis-inventory tree
2189
2311
            # will not, but also does not need them when setting parents.
2190
2312
            for parent in merges:
2191
2313
                parent_trees.append(
2192
2314
                    (parent, self.branch.repository.revision_tree(parent)))
2193
 
            if (old_tip is not None and not _mod_revision.is_null(old_tip)):
 
2315
            if not _mod_revision.is_null(old_tip):
2194
2316
                parent_trees.append(
2195
2317
                    (old_tip, self.branch.repository.revision_tree(old_tip)))
2196
2318
            self.set_parent_trees(parent_trees)
2197
2319
            last_rev = parent_trees[0][0]
2198
 
        else:
2199
 
            # the working tree had the same last-revision as the master
2200
 
            # branch did. We may still have pivot local work from the local
2201
 
            # branch into old_tip:
2202
 
            if (old_tip is not None and not _mod_revision.is_null(old_tip)):
2203
 
                self.add_parent_tree_id(old_tip)
2204
 
        if (old_tip is not None and not _mod_revision.is_null(old_tip)
2205
 
            and old_tip != last_rev):
2206
 
            # our last revision was not the prior branch last revision
2207
 
            # and we have converted that last revision to a pending merge.
2208
 
            # base is somewhere between the branch tip now
2209
 
            # and the now pending merge
2210
 
 
2211
 
            # Since we just modified the working tree and inventory, flush out
2212
 
            # the current state, before we modify it again.
2213
 
            # TODO: jam 20070214 WorkingTree3 doesn't require this, dirstate
2214
 
            #       requires it only because TreeTransform directly munges the
2215
 
            #       inventory and calls tree._write_inventory(). Ultimately we
2216
 
            #       should be able to remove this extra flush.
2217
 
            self.flush()
2218
 
            graph = self.branch.repository.get_graph()
2219
 
            base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
2220
 
                                                old_tip)
2221
 
            base_tree = self.branch.repository.revision_tree(base_rev_id)
2222
 
            other_tree = self.branch.repository.revision_tree(old_tip)
2223
 
            result += merge.merge_inner(
2224
 
                                  self.branch,
2225
 
                                  other_tree,
2226
 
                                  base_tree,
2227
 
                                  this_tree=self,
2228
 
                                  change_reporter=change_reporter)
2229
 
        return result
 
2320
        return nb_conflicts
2230
2321
 
2231
2322
    def _write_hashcache_if_dirty(self):
2232
2323
        """Write out the hashcache if it is dirty."""
2332
2423
                    bzrdir_loc = bisect_left(cur_disk_dir_content,
2333
2424
                        ('.bzr', '.bzr'))
2334
2425
                    if (bzrdir_loc < len(cur_disk_dir_content)
2335
 
                        and cur_disk_dir_content[bzrdir_loc][0] == '.bzr'):
 
2426
                        and self.bzrdir.is_control_filename(
 
2427
                            cur_disk_dir_content[bzrdir_loc][0])):
2336
2428
                        # we dont yield the contents of, or, .bzr itself.
2337
2429
                        del cur_disk_dir_content[bzrdir_loc]
2338
2430
            if inv_finished:
2472
2564
        return un_resolved, resolved
2473
2565
 
2474
2566
    @needs_read_lock
2475
 
    def _check(self):
 
2567
    def _check(self, references):
 
2568
        """Check the tree for consistency.
 
2569
 
 
2570
        :param references: A dict with keys matching the items returned by
 
2571
            self._get_check_refs(), and values from looking those keys up in
 
2572
            the repository.
 
2573
        """
2476
2574
        tree_basis = self.basis_tree()
2477
2575
        tree_basis.lock_read()
2478
2576
        try:
2479
 
            repo_basis = self.branch.repository.revision_tree(
2480
 
                self.last_revision())
 
2577
            repo_basis = references[('trees', self.last_revision())]
2481
2578
            if len(list(repo_basis.iter_changes(tree_basis))) > 0:
2482
2579
                raise errors.BzrCheckError(
2483
2580
                    "Mismatched basis inventory content.")
2496
2593
        """
2497
2594
        return
2498
2595
 
2499
 
    @needs_read_lock
2500
2596
    def _get_rules_searcher(self, default_searcher):
2501
2597
        """See Tree._get_rules_searcher."""
2502
2598
        if self._rules_searcher is None:
2504
2600
                self)._get_rules_searcher(default_searcher)
2505
2601
        return self._rules_searcher
2506
2602
 
 
2603
    def get_shelf_manager(self):
 
2604
        """Return the ShelfManager for this WorkingTree."""
 
2605
        from bzrlib.shelf import ShelfManager
 
2606
        return ShelfManager(self, self._transport)
 
2607
 
2507
2608
 
2508
2609
class WorkingTree2(WorkingTree):
2509
2610
    """This is the Format 2 working tree.
2510
2611
 
2511
 
    This was the first weave based working tree. 
 
2612
    This was the first weave based working tree.
2512
2613
     - uses os locks for locking.
2513
2614
     - uses the branch last-revision.
2514
2615
    """
2524
2625
        if self._inventory is None:
2525
2626
            self.read_working_inventory()
2526
2627
 
 
2628
    def _get_check_refs(self):
 
2629
        """Return the references needed to perform a check of this tree."""
 
2630
        return [('trees', self.last_revision())]
 
2631
 
2527
2632
    def lock_tree_write(self):
2528
2633
        """See WorkingTree.lock_tree_write().
2529
2634
 
2547
2652
            if self._inventory_is_modified:
2548
2653
                self.flush()
2549
2654
            self._write_hashcache_if_dirty()
2550
 
                    
 
2655
 
2551
2656
        # reverse order of locking.
2552
2657
        try:
2553
2658
            return self._control_files.unlock()
2575
2680
 
2576
2681
    def _change_last_revision(self, revision_id):
2577
2682
        """See WorkingTree._change_last_revision."""
2578
 
        if revision_id is None or revision_id == NULL_REVISION:
 
2683
        if revision_id is None or revision_id == _mod_revision.NULL_REVISION:
2579
2684
            try:
2580
2685
                self._transport.delete('last-revision')
2581
2686
            except errors.NoSuchFile:
2583
2688
            return False
2584
2689
        else:
2585
2690
            self._transport.put_bytes('last-revision', revision_id,
2586
 
                mode=self._control_files._file_mode)
 
2691
                mode=self.bzrdir._get_file_mode())
2587
2692
            return True
2588
2693
 
 
2694
    def _get_check_refs(self):
 
2695
        """Return the references needed to perform a check of this tree."""
 
2696
        return [('trees', self.last_revision())]
 
2697
 
2589
2698
    @needs_tree_write_lock
2590
2699
    def set_conflicts(self, conflicts):
2591
 
        self._put_rio('conflicts', conflicts.to_stanzas(), 
 
2700
        self._put_rio('conflicts', conflicts.to_stanzas(),
2592
2701
                      CONFLICT_HEADER_1)
2593
2702
 
2594
2703
    @needs_tree_write_lock
2643
2752
     * a format string,
2644
2753
     * an open routine.
2645
2754
 
2646
 
    Formats are placed in an dict by their format string for reference 
 
2755
    Formats are placed in an dict by their format string for reference
2647
2756
    during workingtree opening. Its not required that these be instances, they
2648
 
    can be classes themselves with class methods - it simply depends on 
 
2757
    can be classes themselves with class methods - it simply depends on
2649
2758
    whether state is needed for a given format or not.
2650
2759
 
2651
2760
    Once a format is deprecated, just deprecate the initialize and open
2652
 
    methods on the format class. Do not deprecate the object, as the 
 
2761
    methods on the format class. Do not deprecate the object, as the
2653
2762
    object will be created every time regardless.
2654
2763
    """
2655
2764
 
2668
2777
        """Return the format for the working tree object in a_bzrdir."""
2669
2778
        try:
2670
2779
            transport = a_bzrdir.get_workingtree_transport(None)
2671
 
            format_string = transport.get("format").read()
 
2780
            format_string = transport.get_bytes("format")
2672
2781
            return klass._formats[format_string]
2673
2782
        except errors.NoSuchFile:
2674
2783
            raise errors.NoWorkingTree(base=transport.base)
2699
2808
        """Is this format supported?
2700
2809
 
2701
2810
        Supported formats can be initialized and opened.
2702
 
        Unsupported formats may not support initialization or committing or 
 
2811
        Unsupported formats may not support initialization or committing or
2703
2812
        some other features depending on the reason for not being supported.
2704
2813
        """
2705
2814
        return True
2706
2815
 
 
2816
    def supports_content_filtering(self):
 
2817
        """True if this format supports content filtering."""
 
2818
        return False
 
2819
 
 
2820
    def supports_views(self):
 
2821
        """True if this format supports stored views."""
 
2822
        return False
 
2823
 
2707
2824
    @classmethod
2708
2825
    def register_format(klass, format):
2709
2826
        klass._formats[format.get_format_string()] = format
2718
2835
 
2719
2836
 
2720
2837
class WorkingTreeFormat2(WorkingTreeFormat):
2721
 
    """The second working tree format. 
 
2838
    """The second working tree format.
2722
2839
 
2723
2840
    This format modified the hash cache from the format 1 hash cache.
2724
2841
    """
2737
2854
        no working tree.  (See bug #43064).
2738
2855
        """
2739
2856
        sio = StringIO()
2740
 
        inv = Inventory()
 
2857
        inv = inventory.Inventory()
2741
2858
        xml5.serializer_v5.write_inventory(inv, sio, working=True)
2742
2859
        sio.seek(0)
2743
2860
        transport.put_file('inventory', sio, file_mode)
2759
2876
            branch.generate_revision_history(revision_id)
2760
2877
        finally:
2761
2878
            branch.unlock()
2762
 
        inv = Inventory()
 
2879
        inv = inventory.Inventory()
2763
2880
        wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
2764
2881
                         branch,
2765
2882
                         inv,
2810
2927
        - is new in bzr 0.8
2811
2928
        - uses a LockDir to guard access for writes.
2812
2929
    """
2813
 
    
 
2930
 
2814
2931
    upgrade_recommended = True
2815
2932
 
2816
2933
    def get_format_string(self):
2833
2950
 
2834
2951
    def _open_control_files(self, a_bzrdir):
2835
2952
        transport = a_bzrdir.get_workingtree_transport(None)
2836
 
        return LockableFiles(transport, self._lock_file_name, 
 
2953
        return LockableFiles(transport, self._lock_file_name,
2837
2954
                             self._lock_class)
2838
2955
 
2839
2956
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2840
2957
                   accelerator_tree=None, hardlink=False):
2841
2958
        """See WorkingTreeFormat.initialize().
2842
 
        
 
2959
 
2843
2960
        :param revision_id: if supplied, create a working tree at a different
2844
2961
            revision than the branch is at.
2845
2962
        :param accelerator_tree: A tree which can be used for retrieving file
2856
2973
        control_files.create_lock()
2857
2974
        control_files.lock_write()
2858
2975
        transport.put_bytes('format', self.get_format_string(),
2859
 
            mode=control_files._file_mode)
 
2976
            mode=a_bzrdir._get_file_mode())
2860
2977
        if from_branch is not None:
2861
2978
            branch = from_branch
2862
2979
        else:
2882
2999
            # only set an explicit root id if there is one to set.
2883
3000
            if basis_tree.inventory.root is not None:
2884
3001
                wt.set_root_id(basis_tree.get_root_id())
2885
 
            if revision_id == NULL_REVISION:
 
3002
            if revision_id == _mod_revision.NULL_REVISION:
2886
3003
                wt.set_parent_trees([])
2887
3004
            else:
2888
3005
                wt.set_parent_trees([(revision_id, basis_tree)])
2895
3012
        return wt
2896
3013
 
2897
3014
    def _initial_inventory(self):
2898
 
        return Inventory()
 
3015
        return inventory.Inventory()
2899
3016
 
2900
3017
    def __init__(self):
2901
3018
        super(WorkingTreeFormat3, self).__init__()
2916
3033
 
2917
3034
    def _open(self, a_bzrdir, control_files):
2918
3035
        """Open the tree itself.
2919
 
        
 
3036
 
2920
3037
        :param a_bzrdir: the dir for the tree.
2921
3038
        :param control_files: the control files for the tree.
2922
3039
        """
2930
3047
        return self.get_format_string()
2931
3048
 
2932
3049
 
2933
 
__default_format = WorkingTreeFormat4()
 
3050
__default_format = WorkingTreeFormat6()
2934
3051
WorkingTreeFormat.register_format(__default_format)
 
3052
WorkingTreeFormat.register_format(WorkingTreeFormat5())
 
3053
WorkingTreeFormat.register_format(WorkingTreeFormat4())
2935
3054
WorkingTreeFormat.register_format(WorkingTreeFormat3())
2936
3055
WorkingTreeFormat.set_default_format(__default_format)
2937
3056
# formats which have no format string are not discoverable