~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

  • Committer: Vincent Ladeuil
  • Date: 2009-05-05 15:31:34 UTC
  • mto: (4343.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 4344.
  • Revision ID: v.ladeuil+lp@free.fr-20090505153134-q4bp4is9gywsmzrv
Clean up test for log formats.

* bzrlib/tests/blackbox/test_logformats.py:
Update tests to actual style.

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"
281
290
        self._control_files.break_lock()
282
291
        self.branch.break_lock()
283
292
 
284
 
    def _get_check_refs(self):
285
 
        """Return the references needed to perform a check of this tree.
286
 
        
287
 
        The default implementation returns no refs, and is only suitable for
288
 
        trees that have no local caching and can commit on ghosts at any time.
289
 
 
290
 
        :seealso: bzrlib.check for details about check_refs.
291
 
        """
292
 
        return []
293
 
 
294
293
    def requires_rich_root(self):
295
294
        return self._format.requires_rich_root
296
295
 
447
446
 
448
447
    def get_file_with_stat(self, file_id, path=None, filtered=True,
449
448
        _fstat=os.fstat):
450
 
        """See Tree.get_file_with_stat."""
 
449
        """See MutableTree.get_file_with_stat."""
451
450
        if path is None:
452
451
            path = self.id2path(file_id)
453
452
        file_obj = self.get_file_byname(path, filtered=False)
454
453
        stat_value = _fstat(file_obj.fileno())
455
 
        if filtered and self.supports_content_filtering():
 
454
        if self.supports_content_filtering() and filtered:
456
455
            filters = self._content_filter_stack(path)
457
456
            file_obj = filtered_input_file(file_obj, filters)
458
457
        return (file_obj, stat_value)
463
462
    def get_file_byname(self, filename, filtered=True):
464
463
        path = self.abspath(filename)
465
464
        f = file(path, 'rb')
466
 
        if filtered and self.supports_content_filtering():
 
465
        if self.supports_content_filtering() and filtered:
467
466
            filters = self._content_filter_stack(filename)
468
467
            return filtered_input_file(f, filters)
469
468
        else:
488
487
        incorrectly attributed to CURRENT_REVISION (but after committing, the
489
488
        attribution will be correct).
490
489
        """
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
 
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()
527
515
 
528
516
    def _get_ancestors(self, default_revision):
529
517
        ancestors = set([default_revision])
761
749
                kind = 'tree-reference'
762
750
            return kind, None, None, None
763
751
        elif kind == 'symlink':
764
 
            target = osutils.readlink(abspath)
765
 
            return ('symlink', None, None, target)
 
752
            return ('symlink', None, None,
 
753
                    os.readlink(abspath.encode(osutils._fs_enc)
 
754
                                ).decode(osutils._fs_enc))
766
755
        else:
767
756
            return (kind, None, None, None)
768
757
 
901
890
            branch.last_revision().
902
891
        """
903
892
        from bzrlib.merge import Merger, Merge3Merger
904
 
        pb = ui.ui_factory.nested_progress_bar()
 
893
        pb = bzrlib.ui.ui_factory.nested_progress_bar()
905
894
        try:
906
895
            merger = Merger(self.branch, this_tree=self, pb=pb)
907
896
            merger.pp = ProgressPhase("Merge phase", 5, pb)
984
973
        return file_id
985
974
 
986
975
    def get_symlink_target(self, file_id):
987
 
        abspath = self.id2abspath(file_id)
988
 
        target = osutils.readlink(abspath)
989
 
        return target
 
976
        return os.readlink(self.id2abspath(file_id).encode(osutils._fs_enc)
 
977
            ).decode(osutils._fs_enc)
990
978
 
991
979
    @needs_write_lock
992
980
    def subsume(self, other_tree):
1093
1081
            branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
1094
1082
        else:
1095
1083
            tree_bzrdir = branch_bzrdir
1096
 
        wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
 
1084
        wt = tree_bzrdir.create_workingtree(NULL_REVISION)
1097
1085
        wt.set_parent_ids(self.get_parent_ids())
1098
1086
        my_inv = self.inventory
1099
 
        child_inv = inventory.Inventory(root_id=None)
 
1087
        child_inv = Inventory(root_id=None)
1100
1088
        new_root = my_inv[file_id]
1101
1089
        my_inv.remove_recursive_id(file_id)
1102
1090
        new_root.parent_id = None
1127
1115
    def _kind(self, relpath):
1128
1116
        return osutils.file_kind(self.abspath(relpath))
1129
1117
 
1130
 
    def list_files(self, include_root=False, from_dir=None, recursive=True):
1131
 
        """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).
1132
1120
 
1133
1121
        Lists, but does not descend into unversioned directories.
 
1122
 
1134
1123
        This does not include files that have been deleted in this
1135
 
        tree. Skips the control directory.
 
1124
        tree.
1136
1125
 
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
 
1126
        Skips the control directory.
1140
1127
        """
1141
1128
        # list_files is an iterator, so @needs_read_lock doesn't work properly
1142
1129
        # with it. So callers should be careful to always read_lock the tree.
1144
1131
            raise errors.ObjectNotLocked(self)
1145
1132
 
1146
1133
        inv = self.inventory
1147
 
        if from_dir is None and include_root is True:
 
1134
        if include_root is True:
1148
1135
            yield ('', 'V', 'directory', inv.root.file_id, inv.root)
1149
1136
        # Convert these into local objects to save lookup times
1150
1137
        pathjoin = osutils.pathjoin
1157
1144
        fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
1158
1145
 
1159
1146
        # directory file_id, relative path, absolute path, reverse sorted children
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)
 
1147
        children = os.listdir(self.basedir)
1170
1148
        children.sort()
1171
1149
        # jam 20060527 The kernel sized tree seems equivalent whether we
1172
1150
        # use a deque and popleft to keep them sorted, or if we use a plain
1173
1151
        # list and just reverse() them.
1174
1152
        children = collections.deque(children)
1175
 
        stack = [(from_dir_id, u'', from_dir_abspath, children)]
 
1153
        stack = [(inv.root.file_id, u'', self.basedir, children)]
1176
1154
        while stack:
1177
1155
            from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
1178
1156
 
1236
1214
                if fk != 'directory':
1237
1215
                    continue
1238
1216
 
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
 
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
1248
1225
            else:
1249
1226
                # if we finished all children, pop it off the stack
1250
1227
                stack.pop()
1428
1405
        inv = self.inventory
1429
1406
        for entry in moved:
1430
1407
            try:
1431
 
                self._move_entry(WorkingTree._RenameEntry(
1432
 
                    entry.to_rel, entry.from_id,
 
1408
                self._move_entry(_RenameEntry(entry.to_rel, entry.from_id,
1433
1409
                    entry.to_tail, entry.to_parent_id, entry.from_rel,
1434
1410
                    entry.from_tail, entry.from_parent_id,
1435
1411
                    entry.only_change_inv))
1486
1462
        from_tail = splitpath(from_rel)[-1]
1487
1463
        from_id = inv.path2id(from_rel)
1488
1464
        if from_id is None:
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]
 
1465
            raise errors.BzrRenameFailedError(from_rel,to_rel,
 
1466
                errors.NotVersionedError(path=str(from_rel)))
 
1467
        from_entry = inv[from_id]
1500
1468
        from_parent_id = from_entry.parent_id
1501
1469
        to_dir, to_tail = os.path.split(to_rel)
1502
1470
        to_dir_id = inv.path2id(to_dir)
1593
1561
 
1594
1562
    @needs_write_lock
1595
1563
    def pull(self, source, overwrite=False, stop_revision=None,
1596
 
             change_reporter=None, possible_transports=None, local=False):
1597
 
        top_pb = ui.ui_factory.nested_progress_bar()
 
1564
             change_reporter=None, possible_transports=None):
 
1565
        top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1598
1566
        source.lock_read()
1599
1567
        try:
1600
1568
            pp = ProgressPhase("Pull phase", 2, top_pb)
1602
1570
            old_revision_info = self.branch.last_revision_info()
1603
1571
            basis_tree = self.basis_tree()
1604
1572
            count = self.branch.pull(source, overwrite, stop_revision,
1605
 
                                     possible_transports=possible_transports,
1606
 
                                     local=local)
 
1573
                                     possible_transports=possible_transports)
1607
1574
            new_revision_info = self.branch.last_revision_info()
1608
1575
            if new_revision_info != old_revision_info:
1609
1576
                pp.next_phase()
1610
1577
                repository = self.branch.repository
1611
 
                pb = ui.ui_factory.nested_progress_bar()
 
1578
                pb = bzrlib.ui.ui_factory.nested_progress_bar()
1612
1579
                basis_tree.lock_read()
1613
1580
                try:
1614
1581
                    new_basis_tree = self.branch.basis_tree()
1674
1641
 
1675
1642
            fl = []
1676
1643
            for subf in os.listdir(dirabs):
1677
 
                if self.bzrdir.is_control_filename(subf):
 
1644
                if subf == '.bzr':
1678
1645
                    continue
1679
1646
                if subf not in dir_entry.children:
1680
1647
                    try:
2063
2030
            if filenames is None and len(self.get_parent_ids()) > 1:
2064
2031
                parent_trees = []
2065
2032
                last_revision = self.last_revision()
2066
 
                if last_revision != _mod_revision.NULL_REVISION:
 
2033
                if last_revision != NULL_REVISION:
2067
2034
                    if basis_tree is None:
2068
2035
                        basis_tree = self.basis_tree()
2069
2036
                        basis_tree.lock_read()
2107
2074
    def set_inventory(self, new_inventory_list):
2108
2075
        from bzrlib.inventory import (Inventory,
2109
2076
                                      InventoryDirectory,
 
2077
                                      InventoryEntry,
2110
2078
                                      InventoryFile,
2111
2079
                                      InventoryLink)
2112
2080
        inv = Inventory(self.get_root_id())
2405
2373
                    bzrdir_loc = bisect_left(cur_disk_dir_content,
2406
2374
                        ('.bzr', '.bzr'))
2407
2375
                    if (bzrdir_loc < len(cur_disk_dir_content)
2408
 
                        and self.bzrdir.is_control_filename(
2409
 
                            cur_disk_dir_content[bzrdir_loc][0])):
 
2376
                        and cur_disk_dir_content[bzrdir_loc][0] == '.bzr'):
2410
2377
                        # we dont yield the contents of, or, .bzr itself.
2411
2378
                        del cur_disk_dir_content[bzrdir_loc]
2412
2379
            if inv_finished:
2546
2513
        return un_resolved, resolved
2547
2514
 
2548
2515
    @needs_read_lock
2549
 
    def _check(self, references):
2550
 
        """Check the tree for consistency.
2551
 
 
2552
 
        :param references: A dict with keys matching the items returned by
2553
 
            self._get_check_refs(), and values from looking those keys up in
2554
 
            the repository.
2555
 
        """
 
2516
    def _check(self):
2556
2517
        tree_basis = self.basis_tree()
2557
2518
        tree_basis.lock_read()
2558
2519
        try:
2559
 
            repo_basis = references[('trees', self.last_revision())]
 
2520
            repo_basis = self.branch.repository.revision_tree(
 
2521
                self.last_revision())
2560
2522
            if len(list(repo_basis.iter_changes(tree_basis))) > 0:
2561
2523
                raise errors.BzrCheckError(
2562
2524
                    "Mismatched basis inventory content.")
2608
2570
        if self._inventory is None:
2609
2571
            self.read_working_inventory()
2610
2572
 
2611
 
    def _get_check_refs(self):
2612
 
        """Return the references needed to perform a check of this tree."""
2613
 
        return [('trees', self.last_revision())]
2614
 
 
2615
2573
    def lock_tree_write(self):
2616
2574
        """See WorkingTree.lock_tree_write().
2617
2575
 
2663
2621
 
2664
2622
    def _change_last_revision(self, revision_id):
2665
2623
        """See WorkingTree._change_last_revision."""
2666
 
        if revision_id is None or revision_id == _mod_revision.NULL_REVISION:
 
2624
        if revision_id is None or revision_id == NULL_REVISION:
2667
2625
            try:
2668
2626
                self._transport.delete('last-revision')
2669
2627
            except errors.NoSuchFile:
2674
2632
                mode=self.bzrdir._get_file_mode())
2675
2633
            return True
2676
2634
 
2677
 
    def _get_check_refs(self):
2678
 
        """Return the references needed to perform a check of this tree."""
2679
 
        return [('trees', self.last_revision())]
2680
 
 
2681
2635
    @needs_tree_write_lock
2682
2636
    def set_conflicts(self, conflicts):
2683
2637
        self._put_rio('conflicts', conflicts.to_stanzas(),
2837
2791
        no working tree.  (See bug #43064).
2838
2792
        """
2839
2793
        sio = StringIO()
2840
 
        inv = inventory.Inventory()
 
2794
        inv = Inventory()
2841
2795
        xml5.serializer_v5.write_inventory(inv, sio, working=True)
2842
2796
        sio.seek(0)
2843
2797
        transport.put_file('inventory', sio, file_mode)
2859
2813
            branch.generate_revision_history(revision_id)
2860
2814
        finally:
2861
2815
            branch.unlock()
2862
 
        inv = inventory.Inventory()
 
2816
        inv = Inventory()
2863
2817
        wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
2864
2818
                         branch,
2865
2819
                         inv,
2982
2936
            # only set an explicit root id if there is one to set.
2983
2937
            if basis_tree.inventory.root is not None:
2984
2938
                wt.set_root_id(basis_tree.get_root_id())
2985
 
            if revision_id == _mod_revision.NULL_REVISION:
 
2939
            if revision_id == NULL_REVISION:
2986
2940
                wt.set_parent_trees([])
2987
2941
            else:
2988
2942
                wt.set_parent_trees([(revision_id, basis_tree)])
2995
2949
        return wt
2996
2950
 
2997
2951
    def _initial_inventory(self):
2998
 
        return inventory.Inventory()
 
2952
        return Inventory()
2999
2953
 
3000
2954
    def __init__(self):
3001
2955
        super(WorkingTreeFormat3, self).__init__()