/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: Robert Collins
  • Date: 2009-08-04 04:36:34 UTC
  • mfrom: (4583 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4593.
  • Revision ID: robertc@robertcollins.net-20090804043634-2iu9wpcgs273i97s
Merge bzr.dev.

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, 2006, 2007, 2008, 2009 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
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
68
    textui,
71
69
    trace,
72
70
    transform,
73
71
    ui,
74
 
    urlutils,
75
72
    views,
76
73
    xml5,
77
 
    xml6,
78
74
    xml7,
79
75
    )
80
76
import bzrlib.branch
81
77
from bzrlib.transport import get_transport
82
 
import bzrlib.ui
83
78
from bzrlib.workingtree_4 import (
84
79
    WorkingTreeFormat4,
85
80
    WorkingTreeFormat5,
89
84
 
90
85
from bzrlib import symbol_versioning
91
86
from bzrlib.decorators import needs_read_lock, needs_write_lock
92
 
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, TreeReference
93
87
from bzrlib.lockable_files import LockableFiles
94
88
from bzrlib.lockdir import LockDir
95
89
import bzrlib.mutabletree
96
90
from bzrlib.mutabletree import needs_tree_write_lock
97
91
from bzrlib import osutils
98
92
from bzrlib.osutils import (
99
 
    compact_date,
100
93
    file_kind,
101
94
    isdir,
102
95
    normpath,
103
96
    pathjoin,
104
 
    rand_chars,
105
97
    realpath,
106
98
    safe_unicode,
107
99
    splitpath,
111
103
from bzrlib.trace import mutter, note
112
104
from bzrlib.transport.local import LocalTransport
113
105
from bzrlib.progress import DummyProgress, ProgressPhase
114
 
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
 
106
from bzrlib.revision import CURRENT_REVISION
115
107
from bzrlib.rio import RioReader, rio_file, Stanza
116
 
from bzrlib.symbol_versioning import (deprecated_passed,
117
 
        deprecated_method,
118
 
        deprecated_function,
119
 
        DEPRECATED_PARAMETER,
120
 
        )
 
108
from bzrlib.symbol_versioning import (
 
109
    deprecated_passed,
 
110
    DEPRECATED_PARAMETER,
 
111
    )
121
112
 
122
113
 
123
114
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
497
488
        incorrectly attributed to CURRENT_REVISION (but after committing, the
498
489
        attribution will be correct).
499
490
        """
500
 
        basis = self.basis_tree()
501
 
        basis.lock_read()
502
 
        try:
503
 
            changes = self.iter_changes(basis, True, [self.id2path(file_id)],
504
 
                require_versioned=True).next()
505
 
            changed_content, kind = changes[2], changes[6]
506
 
            if not changed_content:
507
 
                return basis.annotate_iter(file_id)
508
 
            if kind[1] is None:
509
 
                return None
510
 
            import annotate
511
 
            if kind[0] != 'file':
512
 
                old_lines = []
513
 
            else:
514
 
                old_lines = list(basis.annotate_iter(file_id))
515
 
            old = [old_lines]
516
 
            for tree in self.branch.repository.revision_trees(
517
 
                self.get_parent_ids()[1:]):
518
 
                if file_id not in tree:
519
 
                    continue
520
 
                old.append(list(tree.annotate_iter(file_id)))
521
 
            return annotate.reannotate(old, self.get_file(file_id).readlines(),
522
 
                                       default_revision)
523
 
        finally:
524
 
            basis.unlock()
 
491
        maybe_file_parent_keys = []
 
492
        for parent_id in self.get_parent_ids():
 
493
            try:
 
494
                parent_tree = self.revision_tree(parent_id)
 
495
            except errors.NoSuchRevisionInTree:
 
496
                parent_tree = self.branch.repository.revision_tree(parent_id)
 
497
            parent_tree.lock_read()
 
498
            try:
 
499
                if file_id not in parent_tree:
 
500
                    continue
 
501
                ie = parent_tree.inventory[file_id]
 
502
                if ie.kind != 'file':
 
503
                    # Note: this is slightly unnecessary, because symlinks and
 
504
                    # directories have a "text" which is the empty text, and we
 
505
                    # know that won't mess up annotations. But it seems cleaner
 
506
                    continue
 
507
                parent_text_key = (file_id, ie.revision)
 
508
                if parent_text_key not in maybe_file_parent_keys:
 
509
                    maybe_file_parent_keys.append(parent_text_key)
 
510
            finally:
 
511
                parent_tree.unlock()
 
512
        graph = _mod_graph.Graph(self.branch.repository.texts)
 
513
        heads = graph.heads(maybe_file_parent_keys)
 
514
        file_parent_keys = []
 
515
        for key in maybe_file_parent_keys:
 
516
            if key in heads:
 
517
                file_parent_keys.append(key)
 
518
 
 
519
        # Now we have the parents of this content
 
520
        annotator = self.branch.repository.texts.get_annotator()
 
521
        text = self.get_file(file_id).read()
 
522
        this_key =(file_id, default_revision)
 
523
        annotator.add_special_text(this_key, file_parent_keys, text)
 
524
        annotations = [(key[-1], line)
 
525
                       for key, line in annotator.annotate_flat(this_key)]
 
526
        return annotations
525
527
 
526
528
    def _get_ancestors(self, default_revision):
527
529
        ancestors = set([default_revision])
899
901
            branch.last_revision().
900
902
        """
901
903
        from bzrlib.merge import Merger, Merge3Merger
902
 
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
904
        pb = ui.ui_factory.nested_progress_bar()
903
905
        try:
904
906
            merger = Merger(self.branch, this_tree=self, pb=pb)
905
907
            merger.pp = ProgressPhase("Merge phase", 5, pb)
1091
1093
            branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
1092
1094
        else:
1093
1095
            tree_bzrdir = branch_bzrdir
1094
 
        wt = tree_bzrdir.create_workingtree(NULL_REVISION)
 
1096
        wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
1095
1097
        wt.set_parent_ids(self.get_parent_ids())
1096
1098
        my_inv = self.inventory
1097
 
        child_inv = Inventory(root_id=None)
 
1099
        child_inv = inventory.Inventory(root_id=None)
1098
1100
        new_root = my_inv[file_id]
1099
1101
        my_inv.remove_recursive_id(file_id)
1100
1102
        new_root.parent_id = None
1125
1127
    def _kind(self, relpath):
1126
1128
        return osutils.file_kind(self.abspath(relpath))
1127
1129
 
1128
 
    def list_files(self, include_root=False):
1129
 
        """Recursively list all files as (path, class, kind, id, entry).
 
1130
    def list_files(self, include_root=False, from_dir=None, recursive=True):
 
1131
        """List all files as (path, class, kind, id, entry).
1130
1132
 
1131
1133
        Lists, but does not descend into unversioned directories.
1132
 
 
1133
1134
        This does not include files that have been deleted in this
1134
 
        tree.
 
1135
        tree. Skips the control directory.
1135
1136
 
1136
 
        Skips the control directory.
 
1137
        :param include_root: if True, do not return an entry for the root
 
1138
        :param from_dir: start from this directory or None for the root
 
1139
        :param recursive: whether to recurse into subdirectories or not
1137
1140
        """
1138
1141
        # list_files is an iterator, so @needs_read_lock doesn't work properly
1139
1142
        # with it. So callers should be careful to always read_lock the tree.
1141
1144
            raise errors.ObjectNotLocked(self)
1142
1145
 
1143
1146
        inv = self.inventory
1144
 
        if include_root is True:
 
1147
        if from_dir is None and include_root is True:
1145
1148
            yield ('', 'V', 'directory', inv.root.file_id, inv.root)
1146
1149
        # Convert these into local objects to save lookup times
1147
1150
        pathjoin = osutils.pathjoin
1154
1157
        fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
1155
1158
 
1156
1159
        # directory file_id, relative path, absolute path, reverse sorted children
1157
 
        children = os.listdir(self.basedir)
 
1160
        if from_dir is not None:
 
1161
            from_dir_id = inv.path2id(from_dir)
 
1162
            if from_dir_id is None:
 
1163
                # Directory not versioned
 
1164
                return
 
1165
            from_dir_abspath = pathjoin(self.basedir, from_dir)
 
1166
        else:
 
1167
            from_dir_id = inv.root.file_id
 
1168
            from_dir_abspath = self.basedir
 
1169
        children = os.listdir(from_dir_abspath)
1158
1170
        children.sort()
1159
1171
        # jam 20060527 The kernel sized tree seems equivalent whether we
1160
1172
        # use a deque and popleft to keep them sorted, or if we use a plain
1161
1173
        # list and just reverse() them.
1162
1174
        children = collections.deque(children)
1163
 
        stack = [(inv.root.file_id, u'', self.basedir, children)]
 
1175
        stack = [(from_dir_id, u'', from_dir_abspath, children)]
1164
1176
        while stack:
1165
1177
            from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
1166
1178
 
1224
1236
                if fk != 'directory':
1225
1237
                    continue
1226
1238
 
1227
 
                # But do this child first
1228
 
                new_children = os.listdir(fap)
1229
 
                new_children.sort()
1230
 
                new_children = collections.deque(new_children)
1231
 
                stack.append((f_ie.file_id, fp, fap, new_children))
1232
 
                # Break out of inner loop,
1233
 
                # so that we start outer loop with child
1234
 
                break
 
1239
                # But do this child first if recursing down
 
1240
                if recursive:
 
1241
                    new_children = os.listdir(fap)
 
1242
                    new_children.sort()
 
1243
                    new_children = collections.deque(new_children)
 
1244
                    stack.append((f_ie.file_id, fp, fap, new_children))
 
1245
                    # Break out of inner loop,
 
1246
                    # so that we start outer loop with child
 
1247
                    break
1235
1248
            else:
1236
1249
                # if we finished all children, pop it off the stack
1237
1250
                stack.pop()
1415
1428
        inv = self.inventory
1416
1429
        for entry in moved:
1417
1430
            try:
1418
 
                self._move_entry(_RenameEntry(entry.to_rel, entry.from_id,
 
1431
                self._move_entry(WorkingTree._RenameEntry(
 
1432
                    entry.to_rel, entry.from_id,
1419
1433
                    entry.to_tail, entry.to_parent_id, entry.from_rel,
1420
1434
                    entry.from_tail, entry.from_parent_id,
1421
1435
                    entry.only_change_inv))
1472
1486
        from_tail = splitpath(from_rel)[-1]
1473
1487
        from_id = inv.path2id(from_rel)
1474
1488
        if from_id is None:
1475
 
            raise errors.BzrRenameFailedError(from_rel,to_rel,
1476
 
                errors.NotVersionedError(path=str(from_rel)))
1477
 
        from_entry = inv[from_id]
 
1489
            # if file is missing in the inventory maybe it's in the basis_tree
 
1490
            basis_tree = self.branch.basis_tree()
 
1491
            from_id = basis_tree.path2id(from_rel)
 
1492
            if from_id is None:
 
1493
                raise errors.BzrRenameFailedError(from_rel,to_rel,
 
1494
                    errors.NotVersionedError(path=str(from_rel)))
 
1495
            # put entry back in the inventory so we can rename it
 
1496
            from_entry = basis_tree.inventory[from_id].copy()
 
1497
            inv.add(from_entry)
 
1498
        else:
 
1499
            from_entry = inv[from_id]
1478
1500
        from_parent_id = from_entry.parent_id
1479
1501
        to_dir, to_tail = os.path.split(to_rel)
1480
1502
        to_dir_id = inv.path2id(to_dir)
1572
1594
    @needs_write_lock
1573
1595
    def pull(self, source, overwrite=False, stop_revision=None,
1574
1596
             change_reporter=None, possible_transports=None, local=False):
1575
 
        top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
1597
        top_pb = ui.ui_factory.nested_progress_bar()
1576
1598
        source.lock_read()
1577
1599
        try:
1578
1600
            pp = ProgressPhase("Pull phase", 2, top_pb)
1586
1608
            if new_revision_info != old_revision_info:
1587
1609
                pp.next_phase()
1588
1610
                repository = self.branch.repository
1589
 
                pb = bzrlib.ui.ui_factory.nested_progress_bar()
 
1611
                pb = ui.ui_factory.nested_progress_bar()
1590
1612
                basis_tree.lock_read()
1591
1613
                try:
1592
1614
                    new_basis_tree = self.branch.basis_tree()
2041
2063
            if filenames is None and len(self.get_parent_ids()) > 1:
2042
2064
                parent_trees = []
2043
2065
                last_revision = self.last_revision()
2044
 
                if last_revision != NULL_REVISION:
 
2066
                if last_revision != _mod_revision.NULL_REVISION:
2045
2067
                    if basis_tree is None:
2046
2068
                        basis_tree = self.basis_tree()
2047
2069
                        basis_tree.lock_read()
2085
2107
    def set_inventory(self, new_inventory_list):
2086
2108
        from bzrlib.inventory import (Inventory,
2087
2109
                                      InventoryDirectory,
2088
 
                                      InventoryEntry,
2089
2110
                                      InventoryFile,
2090
2111
                                      InventoryLink)
2091
2112
        inv = Inventory(self.get_root_id())
2642
2663
 
2643
2664
    def _change_last_revision(self, revision_id):
2644
2665
        """See WorkingTree._change_last_revision."""
2645
 
        if revision_id is None or revision_id == NULL_REVISION:
 
2666
        if revision_id is None or revision_id == _mod_revision.NULL_REVISION:
2646
2667
            try:
2647
2668
                self._transport.delete('last-revision')
2648
2669
            except errors.NoSuchFile:
2816
2837
        no working tree.  (See bug #43064).
2817
2838
        """
2818
2839
        sio = StringIO()
2819
 
        inv = Inventory()
 
2840
        inv = inventory.Inventory()
2820
2841
        xml5.serializer_v5.write_inventory(inv, sio, working=True)
2821
2842
        sio.seek(0)
2822
2843
        transport.put_file('inventory', sio, file_mode)
2838
2859
            branch.generate_revision_history(revision_id)
2839
2860
        finally:
2840
2861
            branch.unlock()
2841
 
        inv = Inventory()
 
2862
        inv = inventory.Inventory()
2842
2863
        wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
2843
2864
                         branch,
2844
2865
                         inv,
2961
2982
            # only set an explicit root id if there is one to set.
2962
2983
            if basis_tree.inventory.root is not None:
2963
2984
                wt.set_root_id(basis_tree.get_root_id())
2964
 
            if revision_id == NULL_REVISION:
 
2985
            if revision_id == _mod_revision.NULL_REVISION:
2965
2986
                wt.set_parent_trees([])
2966
2987
            else:
2967
2988
                wt.set_parent_trees([(revision_id, basis_tree)])
2974
2995
        return wt
2975
2996
 
2976
2997
    def _initial_inventory(self):
2977
 
        return Inventory()
 
2998
        return inventory.Inventory()
2978
2999
 
2979
3000
    def __init__(self):
2980
3001
        super(WorkingTreeFormat3, self).__init__()