~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

  • Committer: Ian Clatworthy
  • Date: 2009-06-10 09:01:17 UTC
  • mto: (4427.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 4428.
  • Revision ID: ian.clatworthy@canonical.com-20090610090117-tdfn0tqx6b23ohl2
add NEWS item

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007, 2008 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
51
53
import re
52
54
 
53
55
import bzrlib
55
57
    branch,
56
58
    bzrdir,
57
59
    conflicts as _mod_conflicts,
 
60
    dirstate,
58
61
    errors,
59
62
    generate_ids,
60
63
    globbing,
61
 
    graph as _mod_graph,
62
64
    hashcache,
63
65
    ignores,
64
 
    inventory,
65
66
    merge,
66
67
    revision as _mod_revision,
67
68
    revisiontree,
 
69
    repository,
68
70
    textui,
69
71
    trace,
70
72
    transform,
71
73
    ui,
 
74
    urlutils,
72
75
    views,
73
76
    xml5,
 
77
    xml6,
74
78
    xml7,
75
79
    )
76
80
import bzrlib.branch
77
81
from bzrlib.transport import get_transport
 
82
import bzrlib.ui
78
83
from bzrlib.workingtree_4 import (
79
84
    WorkingTreeFormat4,
80
85
    WorkingTreeFormat5,
84
89
 
85
90
from bzrlib import symbol_versioning
86
91
from bzrlib.decorators import needs_read_lock, needs_write_lock
 
92
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, TreeReference
87
93
from bzrlib.lockable_files import LockableFiles
88
94
from bzrlib.lockdir import LockDir
89
95
import bzrlib.mutabletree
90
96
from bzrlib.mutabletree import needs_tree_write_lock
91
97
from bzrlib import osutils
92
98
from bzrlib.osutils import (
 
99
    compact_date,
93
100
    file_kind,
94
101
    isdir,
95
102
    normpath,
96
103
    pathjoin,
 
104
    rand_chars,
97
105
    realpath,
98
106
    safe_unicode,
99
107
    splitpath,
103
111
from bzrlib.trace import mutter, note
104
112
from bzrlib.transport.local import LocalTransport
105
113
from bzrlib.progress import DummyProgress, ProgressPhase
106
 
from bzrlib.revision import CURRENT_REVISION
 
114
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
107
115
from bzrlib.rio import RioReader, rio_file, Stanza
108
 
from bzrlib.symbol_versioning import (
109
 
    deprecated_passed,
110
 
    DEPRECATED_PARAMETER,
111
 
    )
 
116
from bzrlib.symbol_versioning import (deprecated_passed,
 
117
        deprecated_method,
 
118
        deprecated_function,
 
119
        DEPRECATED_PARAMETER,
 
120
        )
112
121
 
113
122
 
114
123
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
442
451
            path = self.id2path(file_id)
443
452
        file_obj = self.get_file_byname(path, filtered=False)
444
453
        stat_value = _fstat(file_obj.fileno())
445
 
        if filtered and self.supports_content_filtering():
 
454
        if self.supports_content_filtering() and filtered:
446
455
            filters = self._content_filter_stack(path)
447
456
            file_obj = filtered_input_file(file_obj, filters)
448
457
        return (file_obj, stat_value)
453
462
    def get_file_byname(self, filename, filtered=True):
454
463
        path = self.abspath(filename)
455
464
        f = file(path, 'rb')
456
 
        if filtered and self.supports_content_filtering():
 
465
        if self.supports_content_filtering() and filtered:
457
466
            filters = self._content_filter_stack(filename)
458
467
            return filtered_input_file(f, filters)
459
468
        else:
478
487
        incorrectly attributed to CURRENT_REVISION (but after committing, the
479
488
        attribution will be correct).
480
489
        """
481
 
        maybe_file_parent_keys = []
482
 
        for parent_id in self.get_parent_ids():
483
 
            try:
484
 
                parent_tree = self.revision_tree(parent_id)
485
 
            except errors.NoSuchRevisionInTree:
486
 
                parent_tree = self.branch.repository.revision_tree(parent_id)
487
 
            parent_tree.lock_read()
488
 
            try:
489
 
                if file_id not in parent_tree:
490
 
                    continue
491
 
                ie = parent_tree.inventory[file_id]
492
 
                if ie.kind != 'file':
493
 
                    # Note: this is slightly unnecessary, because symlinks and
494
 
                    # directories have a "text" which is the empty text, and we
495
 
                    # know that won't mess up annotations. But it seems cleaner
496
 
                    continue
497
 
                parent_text_key = (file_id, ie.revision)
498
 
                if parent_text_key not in maybe_file_parent_keys:
499
 
                    maybe_file_parent_keys.append(parent_text_key)
500
 
            finally:
501
 
                parent_tree.unlock()
502
 
        graph = _mod_graph.Graph(self.branch.repository.texts)
503
 
        heads = graph.heads(maybe_file_parent_keys)
504
 
        file_parent_keys = []
505
 
        for key in maybe_file_parent_keys:
506
 
            if key in heads:
507
 
                file_parent_keys.append(key)
508
 
 
509
 
        # Now we have the parents of this content
510
 
        annotator = self.branch.repository.texts.get_annotator()
511
 
        text = self.get_file(file_id).read()
512
 
        this_key =(file_id, default_revision)
513
 
        annotator.add_special_text(this_key, file_parent_keys, text)
514
 
        annotations = [(key[-1], line)
515
 
                       for key, line in annotator.annotate_flat(this_key)]
516
 
        return annotations
 
490
        basis = self.basis_tree()
 
491
        basis.lock_read()
 
492
        try:
 
493
            changes = self.iter_changes(basis, True, [self.id2path(file_id)],
 
494
                require_versioned=True).next()
 
495
            changed_content, kind = changes[2], changes[6]
 
496
            if not changed_content:
 
497
                return basis.annotate_iter(file_id)
 
498
            if kind[1] is None:
 
499
                return None
 
500
            import annotate
 
501
            if kind[0] != 'file':
 
502
                old_lines = []
 
503
            else:
 
504
                old_lines = list(basis.annotate_iter(file_id))
 
505
            old = [old_lines]
 
506
            for tree in self.branch.repository.revision_trees(
 
507
                self.get_parent_ids()[1:]):
 
508
                if file_id not in tree:
 
509
                    continue
 
510
                old.append(list(tree.annotate_iter(file_id)))
 
511
            return annotate.reannotate(old, self.get_file(file_id).readlines(),
 
512
                                       default_revision)
 
513
        finally:
 
514
            basis.unlock()
517
515
 
518
516
    def _get_ancestors(self, default_revision):
519
517
        ancestors = set([default_revision])
891
889
            branch.last_revision().
892
890
        """
893
891
        from bzrlib.merge import Merger, Merge3Merger
894
 
        pb = ui.ui_factory.nested_progress_bar()
 
892
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
895
893
        try:
896
894
            merger = Merger(self.branch, this_tree=self, pb=pb)
897
895
            merger.pp = ProgressPhase("Merge phase", 5, pb)
1083
1081
            branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
1084
1082
        else:
1085
1083
            tree_bzrdir = branch_bzrdir
1086
 
        wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
 
1084
        wt = tree_bzrdir.create_workingtree(NULL_REVISION)
1087
1085
        wt.set_parent_ids(self.get_parent_ids())
1088
1086
        my_inv = self.inventory
1089
 
        child_inv = inventory.Inventory(root_id=None)
 
1087
        child_inv = Inventory(root_id=None)
1090
1088
        new_root = my_inv[file_id]
1091
1089
        my_inv.remove_recursive_id(file_id)
1092
1090
        new_root.parent_id = None
1117
1115
    def _kind(self, relpath):
1118
1116
        return osutils.file_kind(self.abspath(relpath))
1119
1117
 
1120
 
    def list_files(self, include_root=False, from_dir=None, recursive=True):
1121
 
        """List all files as (path, class, kind, id, entry).
 
1118
    def list_files(self, include_root=False):
 
1119
        """Recursively list all files as (path, class, kind, id, entry).
1122
1120
 
1123
1121
        Lists, but does not descend into unversioned directories.
 
1122
 
1124
1123
        This does not include files that have been deleted in this
1125
 
        tree. Skips the control directory.
 
1124
        tree.
1126
1125
 
1127
 
        :param include_root: if True, do not return an entry for the root
1128
 
        :param from_dir: start from this directory or None for the root
1129
 
        :param recursive: whether to recurse into subdirectories or not
 
1126
        Skips the control directory.
1130
1127
        """
1131
1128
        # list_files is an iterator, so @needs_read_lock doesn't work properly
1132
1129
        # with it. So callers should be careful to always read_lock the tree.
1134
1131
            raise errors.ObjectNotLocked(self)
1135
1132
 
1136
1133
        inv = self.inventory
1137
 
        if from_dir is None and include_root is True:
 
1134
        if include_root is True:
1138
1135
            yield ('', 'V', 'directory', inv.root.file_id, inv.root)
1139
1136
        # Convert these into local objects to save lookup times
1140
1137
        pathjoin = osutils.pathjoin
1147
1144
        fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
1148
1145
 
1149
1146
        # directory file_id, relative path, absolute path, reverse sorted children
1150
 
        if from_dir is not None:
1151
 
            from_dir_id = inv.path2id(from_dir)
1152
 
            if from_dir_id is None:
1153
 
                # Directory not versioned
1154
 
                return
1155
 
            from_dir_abspath = pathjoin(self.basedir, from_dir)
1156
 
        else:
1157
 
            from_dir_id = inv.root.file_id
1158
 
            from_dir_abspath = self.basedir
1159
 
        children = os.listdir(from_dir_abspath)
 
1147
        children = os.listdir(self.basedir)
1160
1148
        children.sort()
1161
1149
        # jam 20060527 The kernel sized tree seems equivalent whether we
1162
1150
        # use a deque and popleft to keep them sorted, or if we use a plain
1163
1151
        # list and just reverse() them.
1164
1152
        children = collections.deque(children)
1165
 
        stack = [(from_dir_id, u'', from_dir_abspath, children)]
 
1153
        stack = [(inv.root.file_id, u'', self.basedir, children)]
1166
1154
        while stack:
1167
1155
            from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
1168
1156
 
1226
1214
                if fk != 'directory':
1227
1215
                    continue
1228
1216
 
1229
 
                # But do this child first if recursing down
1230
 
                if recursive:
1231
 
                    new_children = os.listdir(fap)
1232
 
                    new_children.sort()
1233
 
                    new_children = collections.deque(new_children)
1234
 
                    stack.append((f_ie.file_id, fp, fap, new_children))
1235
 
                    # Break out of inner loop,
1236
 
                    # so that we start outer loop with child
1237
 
                    break
 
1217
                # But do this child first
 
1218
                new_children = os.listdir(fap)
 
1219
                new_children.sort()
 
1220
                new_children = collections.deque(new_children)
 
1221
                stack.append((f_ie.file_id, fp, fap, new_children))
 
1222
                # Break out of inner loop,
 
1223
                # so that we start outer loop with child
 
1224
                break
1238
1225
            else:
1239
1226
                # if we finished all children, pop it off the stack
1240
1227
                stack.pop()
1418
1405
        inv = self.inventory
1419
1406
        for entry in moved:
1420
1407
            try:
1421
 
                self._move_entry(WorkingTree._RenameEntry(
1422
 
                    entry.to_rel, entry.from_id,
 
1408
                self._move_entry(_RenameEntry(entry.to_rel, entry.from_id,
1423
1409
                    entry.to_tail, entry.to_parent_id, entry.from_rel,
1424
1410
                    entry.from_tail, entry.from_parent_id,
1425
1411
                    entry.only_change_inv))
1576
1562
    @needs_write_lock
1577
1563
    def pull(self, source, overwrite=False, stop_revision=None,
1578
1564
             change_reporter=None, possible_transports=None, local=False):
1579
 
        top_pb = ui.ui_factory.nested_progress_bar()
 
1565
        top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1580
1566
        source.lock_read()
1581
1567
        try:
1582
1568
            pp = ProgressPhase("Pull phase", 2, top_pb)
1590
1576
            if new_revision_info != old_revision_info:
1591
1577
                pp.next_phase()
1592
1578
                repository = self.branch.repository
1593
 
                pb = ui.ui_factory.nested_progress_bar()
 
1579
                pb = bzrlib.ui.ui_factory.nested_progress_bar()
1594
1580
                basis_tree.lock_read()
1595
1581
                try:
1596
1582
                    new_basis_tree = self.branch.basis_tree()
2045
2031
            if filenames is None and len(self.get_parent_ids()) > 1:
2046
2032
                parent_trees = []
2047
2033
                last_revision = self.last_revision()
2048
 
                if last_revision != _mod_revision.NULL_REVISION:
 
2034
                if last_revision != NULL_REVISION:
2049
2035
                    if basis_tree is None:
2050
2036
                        basis_tree = self.basis_tree()
2051
2037
                        basis_tree.lock_read()
2089
2075
    def set_inventory(self, new_inventory_list):
2090
2076
        from bzrlib.inventory import (Inventory,
2091
2077
                                      InventoryDirectory,
 
2078
                                      InventoryEntry,
2092
2079
                                      InventoryFile,
2093
2080
                                      InventoryLink)
2094
2081
        inv = Inventory(self.get_root_id())
2636
2623
 
2637
2624
    def _change_last_revision(self, revision_id):
2638
2625
        """See WorkingTree._change_last_revision."""
2639
 
        if revision_id is None or revision_id == _mod_revision.NULL_REVISION:
 
2626
        if revision_id is None or revision_id == NULL_REVISION:
2640
2627
            try:
2641
2628
                self._transport.delete('last-revision')
2642
2629
            except errors.NoSuchFile:
2806
2793
        no working tree.  (See bug #43064).
2807
2794
        """
2808
2795
        sio = StringIO()
2809
 
        inv = inventory.Inventory()
 
2796
        inv = Inventory()
2810
2797
        xml5.serializer_v5.write_inventory(inv, sio, working=True)
2811
2798
        sio.seek(0)
2812
2799
        transport.put_file('inventory', sio, file_mode)
2828
2815
            branch.generate_revision_history(revision_id)
2829
2816
        finally:
2830
2817
            branch.unlock()
2831
 
        inv = inventory.Inventory()
 
2818
        inv = Inventory()
2832
2819
        wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
2833
2820
                         branch,
2834
2821
                         inv,
2951
2938
            # only set an explicit root id if there is one to set.
2952
2939
            if basis_tree.inventory.root is not None:
2953
2940
                wt.set_root_id(basis_tree.get_root_id())
2954
 
            if revision_id == _mod_revision.NULL_REVISION:
 
2941
            if revision_id == NULL_REVISION:
2955
2942
                wt.set_parent_trees([])
2956
2943
            else:
2957
2944
                wt.set_parent_trees([(revision_id, basis_tree)])
2964
2951
        return wt
2965
2952
 
2966
2953
    def _initial_inventory(self):
2967
 
        return inventory.Inventory()
 
2954
        return Inventory()
2968
2955
 
2969
2956
    def __init__(self):
2970
2957
        super(WorkingTreeFormat3, self).__init__()