~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree_4.py

merge 2.0 branch rev 4647

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
 
29
29
from bzrlib.lazy_import import lazy_import
30
30
lazy_import(globals(), """
31
 
from bisect import bisect_left
32
 
import collections
33
 
from copy import deepcopy
34
31
import errno
35
 
import itertools
36
 
import operator
37
32
import stat
38
 
from time import time
39
 
import warnings
40
33
 
41
34
import bzrlib
42
35
from bzrlib import (
43
36
    bzrdir,
44
37
    cache_utf8,
45
 
    conflicts as _mod_conflicts,
46
38
    debug,
47
 
    delta,
48
39
    dirstate,
49
40
    errors,
50
41
    generate_ids,
51
 
    globbing,
52
 
    ignores,
53
 
    merge,
54
42
    osutils,
55
43
    revision as _mod_revision,
56
44
    revisiontree,
57
 
    textui,
58
45
    trace,
59
46
    transform,
60
 
    urlutils,
61
47
    views,
62
 
    xml5,
63
 
    xml6,
64
48
    )
65
49
import bzrlib.branch
66
 
from bzrlib.transport import get_transport
67
50
import bzrlib.ui
68
51
""")
69
52
 
70
 
from bzrlib import symbol_versioning
71
53
from bzrlib.decorators import needs_read_lock, needs_write_lock
72
54
from bzrlib.filters import filtered_input_file, internal_size_sha_file_byname
73
 
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, entry_factory
 
55
from bzrlib.inventory import Inventory, ROOT_ID, entry_factory
74
56
import bzrlib.mutabletree
75
57
from bzrlib.mutabletree import needs_tree_write_lock
76
58
from bzrlib.osutils import (
77
59
    file_kind,
78
60
    isdir,
79
 
    normpath,
80
61
    pathjoin,
81
 
    rand_chars,
82
62
    realpath,
83
63
    safe_unicode,
84
 
    splitpath,
85
64
    )
86
 
from bzrlib.trace import mutter, note
 
65
from bzrlib.trace import mutter
87
66
from bzrlib.transport.local import LocalTransport
88
67
from bzrlib.tree import InterTree
89
 
from bzrlib.progress import DummyProgress, ProgressPhase
90
 
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
91
 
from bzrlib.rio import RioReader, rio_file, Stanza
92
 
from bzrlib.symbol_versioning import (deprecated_passed,
93
 
        deprecated_method,
94
 
        deprecated_function,
95
 
        DEPRECATED_PARAMETER,
96
 
        )
97
68
from bzrlib.tree import Tree
98
69
from bzrlib.workingtree import WorkingTree, WorkingTree3, WorkingTreeFormat3
99
70
 
464
435
        return osutils.lexists(pathjoin(
465
436
                    self.basedir, row[0].decode('utf8'), row[1].decode('utf8')))
466
437
 
 
438
    def has_or_had_id(self, file_id):
 
439
        state = self.current_dirstate()
 
440
        row, parents = self._get_entry(file_id=file_id)
 
441
        return row is not None
 
442
 
467
443
    @needs_read_lock
468
444
    def id2path(self, file_id):
469
445
        "Convert a file-id to a path."
716
692
            from_entry = self._get_entry(path=from_rel)
717
693
            if from_entry == (None, None):
718
694
                raise errors.BzrMoveFailedError(from_rel,to_dir,
719
 
                    errors.NotVersionedError(path=str(from_rel)))
 
695
                    errors.NotVersionedError(path=from_rel))
720
696
 
721
697
            from_id = from_entry[0][2]
722
698
            to_rel = pathjoin(to_dir, from_tail)
1051
1027
    def set_last_revision(self, new_revision):
1052
1028
        """Change the last revision in the working tree."""
1053
1029
        parents = self.get_parent_ids()
1054
 
        if new_revision in (NULL_REVISION, None):
 
1030
        if new_revision in (_mod_revision.NULL_REVISION, None):
1055
1031
            if len(parents) >= 2:
1056
1032
                raise AssertionError(
1057
1033
                    "setting the last parent to none with a pending merge is "
1224
1200
                # just forget the whole block.
1225
1201
                entry_index = 0
1226
1202
                while entry_index < len(block[1]):
1227
 
                    # Mark this file id as having been removed
1228
1203
                    entry = block[1][entry_index]
1229
 
                    ids_to_unversion.discard(entry[0][2])
1230
 
                    if (entry[1][0][0] in 'ar' # don't remove absent or renamed
1231
 
                                               # entries
1232
 
                        or not state._make_absent(entry)):
 
1204
                    if entry[1][0][0] in 'ar':
 
1205
                        # don't remove absent or renamed entries
1233
1206
                        entry_index += 1
 
1207
                    else:
 
1208
                        # Mark this file id as having been removed
 
1209
                        ids_to_unversion.discard(entry[0][2])
 
1210
                        if not state._make_absent(entry):
 
1211
                            # The block has not shrunk.
 
1212
                            entry_index += 1
1234
1213
                # go to the next block. (At the moment we dont delete empty
1235
1214
                # dirblocks)
1236
1215
                block_index += 1
1321
1300
        return statvalue, sha1
1322
1301
 
1323
1302
 
 
1303
class ContentFilteringDirStateWorkingTree(DirStateWorkingTree):
 
1304
    """Dirstate working tree that supports content filtering.
 
1305
 
 
1306
    The dirstate holds the hash and size of the canonical form of the file, 
 
1307
    and most methods must return that.
 
1308
    """
 
1309
 
 
1310
    def _file_content_summary(self, path, stat_result):
 
1311
        # This is to support the somewhat obsolete path_content_summary method
 
1312
        # with content filtering: see
 
1313
        # <https://bugs.edge.launchpad.net/bzr/+bug/415508>.
 
1314
        #
 
1315
        # If the dirstate cache is up to date and knows the hash and size,
 
1316
        # return that.
 
1317
        # Otherwise if there are no content filters, return the on-disk size
 
1318
        # and leave the hash blank.
 
1319
        # Otherwise, read and filter the on-disk file and use its size and
 
1320
        # hash.
 
1321
        #
 
1322
        # The dirstate doesn't store the size of the canonical form so we
 
1323
        # can't trust it for content-filtered trees.  We just return None.
 
1324
        dirstate_sha1 = self._dirstate.sha1_from_stat(path, stat_result)
 
1325
        executable = self._is_executable_from_path_and_stat(path, stat_result)
 
1326
        return ('file', None, executable, dirstate_sha1)
 
1327
 
 
1328
 
1324
1329
class WorkingTree4(DirStateWorkingTree):
1325
1330
    """This is the Format 4 working tree.
1326
1331
 
1334
1339
    """
1335
1340
 
1336
1341
 
1337
 
class WorkingTree5(DirStateWorkingTree):
 
1342
class WorkingTree5(ContentFilteringDirStateWorkingTree):
1338
1343
    """This is the Format 5 working tree.
1339
1344
 
1340
1345
    This differs from WorkingTree4 by:
1344
1349
    """
1345
1350
 
1346
1351
 
1347
 
class WorkingTree6(DirStateWorkingTree):
 
1352
class WorkingTree6(ContentFilteringDirStateWorkingTree):
1348
1353
    """This is the Format 6 working tree.
1349
1354
 
1350
1355
    This differs from WorkingTree5 by:
1403
1408
        wt.lock_tree_write()
1404
1409
        try:
1405
1410
            self._init_custom_control_files(wt)
1406
 
            if revision_id in (None, NULL_REVISION):
 
1411
            if revision_id in (None, _mod_revision.NULL_REVISION):
1407
1412
                if branch.repository.supports_rich_root():
1408
1413
                    wt._set_root_id(generate_ids.gen_root_id())
1409
1414
                else:
1420
1425
                    pass
1421
1426
            if basis is None:
1422
1427
                basis = branch.repository.revision_tree(revision_id)
1423
 
            if revision_id == NULL_REVISION:
 
1428
            if revision_id == _mod_revision.NULL_REVISION:
1424
1429
                parents_list = []
1425
1430
            else:
1426
1431
                parents_list = [(revision_id, basis)]
1444
1449
                # applied so we can't safely build the inventory delta from
1445
1450
                # the source tree.
1446
1451
                if wt.supports_content_filtering():
 
1452
                    if hardlink:
 
1453
                        # see https://bugs.edge.launchpad.net/bzr/+bug/408193
 
1454
                        trace.warning("hardlinking working copy files is not currently "
 
1455
                            "supported in %r" % (wt,))
1447
1456
                    accelerator_tree = None
1448
1457
                    delta_from_tree = False
1449
1458
                else:
1567
1576
 
1568
1577
 
1569
1578
class DirStateRevisionTree(Tree):
1570
 
    """A revision tree pulling the inventory from a dirstate."""
 
1579
    """A revision tree pulling the inventory from a dirstate.
 
1580
    
 
1581
    Note that this is one of the historical (ie revision) trees cached in the
 
1582
    dirstate for easy access, not the workingtree.
 
1583
    """
1571
1584
 
1572
1585
    def __init__(self, dirstate, revision_id, repository):
1573
1586
        self._dirstate = dirstate
1844
1857
            return None
1845
1858
        return ie.executable
1846
1859
 
1847
 
    def list_files(self, include_root=False):
 
1860
    def list_files(self, include_root=False, from_dir=None, recursive=True):
1848
1861
        # We use a standard implementation, because DirStateRevisionTree is
1849
1862
        # dealing with one of the parents of the current state
1850
1863
        inv = self._get_inventory()
1851
 
        entries = inv.iter_entries()
1852
 
        if self.inventory.root is not None and not include_root:
 
1864
        if from_dir is None:
 
1865
            from_dir_id = None
 
1866
        else:
 
1867
            from_dir_id = inv.path2id(from_dir)
 
1868
            if from_dir_id is None:
 
1869
                # Directory not versioned
 
1870
                return
 
1871
        entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
 
1872
        if inv.root is not None and not include_root and from_dir is None:
1853
1873
            entries.next()
1854
1874
        for path, entry in entries:
1855
1875
            yield path, 'V', entry.kind, entry.file_id, entry
1963
1983
        if not CompiledDirstateHelpersFeature.available():
1964
1984
            from bzrlib.tests import UnavailableFeature
1965
1985
            raise UnavailableFeature(CompiledDirstateHelpersFeature)
1966
 
        from bzrlib._dirstate_helpers_c import ProcessEntryC
 
1986
        from bzrlib._dirstate_helpers_pyx import ProcessEntryC
1967
1987
        result = klass.make_source_parent_tree(source, target)
1968
1988
        result[1]._iter_changes = ProcessEntryC
1969
1989
        return result
2009
2029
                require_versioned, want_unversioned=want_unversioned)
2010
2030
        parent_ids = self.target.get_parent_ids()
2011
2031
        if not (self.source._revision_id in parent_ids
2012
 
                or self.source._revision_id == NULL_REVISION):
 
2032
                or self.source._revision_id == _mod_revision.NULL_REVISION):
2013
2033
            raise AssertionError(
2014
2034
                "revision {%s} is not stored in {%s}, but %s "
2015
2035
                "can only be used for trees stored in the dirstate"
2016
2036
                % (self.source._revision_id, self.target, self.iter_changes))
2017
2037
        target_index = 0
2018
 
        if self.source._revision_id == NULL_REVISION:
 
2038
        if self.source._revision_id == _mod_revision.NULL_REVISION:
2019
2039
            source_index = None
2020
2040
            indices = (target_index,)
2021
2041
        else:
2042
2062
        state._read_dirblocks_if_needed()
2043
2063
        if require_versioned:
2044
2064
            # -- check all supplied paths are versioned in a search tree. --
2045
 
            all_versioned = True
 
2065
            not_versioned = []
2046
2066
            for path in specific_files:
2047
2067
                path_entries = state._entries_for_path(path)
2048
2068
                if not path_entries:
2049
2069
                    # this specified path is not present at all: error
2050
 
                    all_versioned = False
2051
 
                    break
 
2070
                    not_versioned.append(path)
 
2071
                    continue
2052
2072
                found_versioned = False
2053
2073
                # for each id at this path
2054
2074
                for entry in path_entries:
2061
2081
                if not found_versioned:
2062
2082
                    # none of the indexes was not 'absent' at all ids for this
2063
2083
                    # path.
2064
 
                    all_versioned = False
2065
 
                    break
2066
 
            if not all_versioned:
2067
 
                raise errors.PathsNotVersionedError(specific_files)
 
2084
                    not_versioned.append(path)
 
2085
            if len(not_versioned) > 0:
 
2086
                raise errors.PathsNotVersionedError(not_versioned)
2068
2087
        # -- remove redundancy in supplied specific_files to prevent over-scanning --
2069
2088
        search_specific_files = osutils.minimum_path_selection(specific_files)
2070
2089
 
2084
2103
            (revisiontree.RevisionTree, DirStateRevisionTree)):
2085
2104
            return False
2086
2105
        # the source revid must be in the target dirstate
2087
 
        if not (source._revision_id == NULL_REVISION or
 
2106
        if not (source._revision_id == _mod_revision.NULL_REVISION or
2088
2107
            source._revision_id in target.get_parent_ids()):
2089
2108
            # TODO: what about ghosts? it may well need to
2090
2109
            # check for them explicitly.