~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree_4.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-09-29 22:03:03 UTC
  • mfrom: (5416.2.6 jam-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20100929220303-cr95h8iwtggco721
(mbp) Add 'break-lock --force'

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) 2007-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
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
74
 
import bzrlib.mutabletree
 
55
from bzrlib.inventory import Inventory, ROOT_ID, entry_factory
 
56
from bzrlib.lock import LogicalLockResult
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."
592
568
            return _mod_revision.NULL_REVISION
593
569
 
594
570
    def lock_read(self):
595
 
        """See Branch.lock_read, and WorkingTree.unlock."""
 
571
        """See Branch.lock_read, and WorkingTree.unlock.
 
572
 
 
573
        :return: A bzrlib.lock.LogicalLockResult.
 
574
        """
596
575
        self.branch.lock_read()
597
576
        try:
598
577
            self._control_files.lock_read()
611
590
        except:
612
591
            self.branch.unlock()
613
592
            raise
 
593
        return LogicalLockResult(self.unlock)
614
594
 
615
595
    def _lock_self_write(self):
616
596
        """This should be called after the branch is locked."""
631
611
        except:
632
612
            self.branch.unlock()
633
613
            raise
 
614
        return LogicalLockResult(self.unlock)
634
615
 
635
616
    def lock_tree_write(self):
636
 
        """See MutableTree.lock_tree_write, and WorkingTree.unlock."""
 
617
        """See MutableTree.lock_tree_write, and WorkingTree.unlock.
 
618
 
 
619
        :return: A bzrlib.lock.LogicalLockResult.
 
620
        """
637
621
        self.branch.lock_read()
638
 
        self._lock_self_write()
 
622
        return self._lock_self_write()
639
623
 
640
624
    def lock_write(self):
641
 
        """See MutableTree.lock_write, and WorkingTree.unlock."""
 
625
        """See MutableTree.lock_write, and WorkingTree.unlock.
 
626
 
 
627
        :return: A bzrlib.lock.LogicalLockResult.
 
628
        """
642
629
        self.branch.lock_write()
643
 
        self._lock_self_write()
 
630
        return self._lock_self_write()
644
631
 
645
632
    @needs_tree_write_lock
646
633
    def move(self, from_paths, to_dir, after=False):
716
703
            from_entry = self._get_entry(path=from_rel)
717
704
            if from_entry == (None, None):
718
705
                raise errors.BzrMoveFailedError(from_rel,to_dir,
719
 
                    errors.NotVersionedError(path=str(from_rel)))
 
706
                    errors.NotVersionedError(path=from_rel))
720
707
 
721
708
            from_id = from_entry[0][2]
722
709
            to_rel = pathjoin(to_dir, from_tail)
1051
1038
    def set_last_revision(self, new_revision):
1052
1039
        """Change the last revision in the working tree."""
1053
1040
        parents = self.get_parent_ids()
1054
 
        if new_revision in (NULL_REVISION, None):
 
1041
        if new_revision in (_mod_revision.NULL_REVISION, None):
1055
1042
            if len(parents) >= 2:
1056
1043
                raise AssertionError(
1057
1044
                    "setting the last parent to none with a pending merge is "
1224
1211
                # just forget the whole block.
1225
1212
                entry_index = 0
1226
1213
                while entry_index < len(block[1]):
1227
 
                    # Mark this file id as having been removed
1228
1214
                    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)):
 
1215
                    if entry[1][0][0] in 'ar':
 
1216
                        # don't remove absent or renamed entries
1233
1217
                        entry_index += 1
 
1218
                    else:
 
1219
                        # Mark this file id as having been removed
 
1220
                        ids_to_unversion.discard(entry[0][2])
 
1221
                        if not state._make_absent(entry):
 
1222
                            # The block has not shrunk.
 
1223
                            entry_index += 1
1234
1224
                # go to the next block. (At the moment we dont delete empty
1235
1225
                # dirblocks)
1236
1226
                block_index += 1
1257
1247
        # have to change the legacy inventory too.
1258
1248
        if self._inventory is not None:
1259
1249
            for file_id in file_ids:
1260
 
                self._inventory.remove_recursive_id(file_id)
 
1250
                if self._inventory.has_id(file_id):
 
1251
                    self._inventory.remove_recursive_id(file_id)
1261
1252
 
1262
1253
    @needs_tree_write_lock
1263
1254
    def rename_one(self, from_rel, to_rel, after=False):
1288
1279
        if self._dirty:
1289
1280
            raise AssertionError("attempting to write an inventory when the "
1290
1281
                "dirstate is dirty will lose pending changes")
1291
 
        self.current_dirstate().set_state_from_inventory(inv)
1292
 
        self._make_dirty(reset_inventory=False)
1293
 
        if self._inventory is not None:
 
1282
        had_inventory = self._inventory is not None
 
1283
        # Setting self._inventory = None forces the dirstate to regenerate the
 
1284
        # working inventory. We do this because self.inventory may be inv, or
 
1285
        # may have been modified, and either case would prevent a clean delta
 
1286
        # being created.
 
1287
        self._inventory = None
 
1288
        # generate a delta,
 
1289
        delta = inv._make_delta(self.inventory)
 
1290
        # and apply it.
 
1291
        self.apply_inventory_delta(delta)
 
1292
        if had_inventory:
1294
1293
            self._inventory = inv
1295
1294
        self.flush()
1296
1295
 
1321
1320
        return statvalue, sha1
1322
1321
 
1323
1322
 
 
1323
class ContentFilteringDirStateWorkingTree(DirStateWorkingTree):
 
1324
    """Dirstate working tree that supports content filtering.
 
1325
 
 
1326
    The dirstate holds the hash and size of the canonical form of the file, 
 
1327
    and most methods must return that.
 
1328
    """
 
1329
 
 
1330
    def _file_content_summary(self, path, stat_result):
 
1331
        # This is to support the somewhat obsolete path_content_summary method
 
1332
        # with content filtering: see
 
1333
        # <https://bugs.launchpad.net/bzr/+bug/415508>.
 
1334
        #
 
1335
        # If the dirstate cache is up to date and knows the hash and size,
 
1336
        # return that.
 
1337
        # Otherwise if there are no content filters, return the on-disk size
 
1338
        # and leave the hash blank.
 
1339
        # Otherwise, read and filter the on-disk file and use its size and
 
1340
        # hash.
 
1341
        #
 
1342
        # The dirstate doesn't store the size of the canonical form so we
 
1343
        # can't trust it for content-filtered trees.  We just return None.
 
1344
        dirstate_sha1 = self._dirstate.sha1_from_stat(path, stat_result)
 
1345
        executable = self._is_executable_from_path_and_stat(path, stat_result)
 
1346
        return ('file', None, executable, dirstate_sha1)
 
1347
 
 
1348
 
1324
1349
class WorkingTree4(DirStateWorkingTree):
1325
1350
    """This is the Format 4 working tree.
1326
1351
 
1334
1359
    """
1335
1360
 
1336
1361
 
1337
 
class WorkingTree5(DirStateWorkingTree):
 
1362
class WorkingTree5(ContentFilteringDirStateWorkingTree):
1338
1363
    """This is the Format 5 working tree.
1339
1364
 
1340
1365
    This differs from WorkingTree4 by:
1344
1369
    """
1345
1370
 
1346
1371
 
1347
 
class WorkingTree6(DirStateWorkingTree):
 
1372
class WorkingTree6(ContentFilteringDirStateWorkingTree):
1348
1373
    """This is the Format 6 working tree.
1349
1374
 
1350
1375
    This differs from WorkingTree5 by:
1359
1384
 
1360
1385
 
1361
1386
class DirStateWorkingTreeFormat(WorkingTreeFormat3):
 
1387
 
1362
1388
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1363
1389
                   accelerator_tree=None, hardlink=False):
1364
1390
        """See WorkingTreeFormat.initialize().
1403
1429
        wt.lock_tree_write()
1404
1430
        try:
1405
1431
            self._init_custom_control_files(wt)
1406
 
            if revision_id in (None, NULL_REVISION):
 
1432
            if revision_id in (None, _mod_revision.NULL_REVISION):
1407
1433
                if branch.repository.supports_rich_root():
1408
1434
                    wt._set_root_id(generate_ids.gen_root_id())
1409
1435
                else:
1420
1446
                    pass
1421
1447
            if basis is None:
1422
1448
                basis = branch.repository.revision_tree(revision_id)
1423
 
            if revision_id == NULL_REVISION:
 
1449
            if revision_id == _mod_revision.NULL_REVISION:
1424
1450
                parents_list = []
1425
1451
            else:
1426
1452
                parents_list = [(revision_id, basis)]
1434
1460
                if basis_root_id is not None:
1435
1461
                    wt._set_root_id(basis_root_id)
1436
1462
                    wt.flush()
1437
 
                # If content filtering is supported, do not use the accelerator
1438
 
                # tree - the cost of transforming the content both ways and
1439
 
                # checking for changed content can outweight the gains it gives.
1440
 
                # Note: do NOT move this logic up higher - using the basis from
1441
 
                # the accelerator tree is still desirable because that can save
1442
 
                # a minute or more of processing on large trees!
1443
 
                # The original tree may not have the same content filters
1444
 
                # applied so we can't safely build the inventory delta from
1445
 
                # the source tree.
1446
1463
                if wt.supports_content_filtering():
1447
 
                    accelerator_tree = None
 
1464
                    # The original tree may not have the same content filters
 
1465
                    # applied so we can't safely build the inventory delta from
 
1466
                    # the source tree.
1448
1467
                    delta_from_tree = False
1449
1468
                else:
1450
1469
                    delta_from_tree = True
1567
1586
 
1568
1587
 
1569
1588
class DirStateRevisionTree(Tree):
1570
 
    """A revision tree pulling the inventory from a dirstate."""
 
1589
    """A revision tree pulling the inventory from a dirstate.
 
1590
    
 
1591
    Note that this is one of the historical (ie revision) trees cached in the
 
1592
    dirstate for easy access, not the workingtree.
 
1593
    """
1571
1594
 
1572
1595
    def __init__(self, dirstate, revision_id, repository):
1573
1596
        self._dirstate = dirstate
1715
1738
                elif kind == 'directory':
1716
1739
                    parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
1717
1740
                elif kind == 'symlink':
1718
 
                    inv_entry.executable = False
1719
 
                    inv_entry.text_size = None
1720
1741
                    inv_entry.symlink_target = utf8_decode(fingerprint)[0]
1721
1742
                elif kind == 'tree-reference':
1722
1743
                    inv_entry.reference_revision = fingerprint or None
1745
1766
            return None
1746
1767
        parent_index = self._get_parent_index()
1747
1768
        last_changed_revision = entry[1][parent_index][4]
1748
 
        return self._repository.get_revision(last_changed_revision).timestamp
 
1769
        try:
 
1770
            rev = self._repository.get_revision(last_changed_revision)
 
1771
        except errors.NoSuchRevision:
 
1772
            raise errors.FileTimestampUnavailable(self.id2path(file_id))
 
1773
        return rev.timestamp
1749
1774
 
1750
1775
    def get_file_sha1(self, file_id, path=None, stat_value=None):
1751
1776
        entry = self._get_entry(file_id=file_id, path=path)
1818
1843
        entry = self._get_entry(file_id=file_id)[1]
1819
1844
        if entry is None:
1820
1845
            raise errors.NoSuchId(tree=self, file_id=file_id)
1821
 
        return dirstate.DirState._minikind_to_kind[entry[1][0]]
 
1846
        parent_index = self._get_parent_index()
 
1847
        return dirstate.DirState._minikind_to_kind[entry[parent_index][0]]
1822
1848
 
1823
1849
    def stored_kind(self, file_id):
1824
1850
        """See Tree.stored_kind"""
1844
1870
            return None
1845
1871
        return ie.executable
1846
1872
 
 
1873
    def is_locked(self):
 
1874
        return self._locked
 
1875
 
1847
1876
    def list_files(self, include_root=False, from_dir=None, recursive=True):
1848
1877
        # We use a standard implementation, because DirStateRevisionTree is
1849
1878
        # dealing with one of the parents of the current state
1862
1891
            yield path, 'V', entry.kind, entry.file_id, entry
1863
1892
 
1864
1893
    def lock_read(self):
1865
 
        """Lock the tree for a set of operations."""
 
1894
        """Lock the tree for a set of operations.
 
1895
 
 
1896
        :return: A bzrlib.lock.LogicalLockResult.
 
1897
        """
1866
1898
        if not self._locked:
1867
1899
            self._repository.lock_read()
1868
1900
            if self._dirstate._lock_token is None:
1869
1901
                self._dirstate.lock_read()
1870
1902
                self._dirstate_locked = True
1871
1903
        self._locked += 1
 
1904
        return LogicalLockResult(self.unlock)
1872
1905
 
1873
1906
    def _must_be_locked(self):
1874
1907
        if not self._locked:
1964
1997
        return result
1965
1998
 
1966
1999
    @classmethod
1967
 
    def make_source_parent_tree_compiled_dirstate(klass, test_case, source, target):
 
2000
    def make_source_parent_tree_compiled_dirstate(klass, test_case, source,
 
2001
                                                  target):
1968
2002
        from bzrlib.tests.test__dirstate_helpers import \
1969
 
            CompiledDirstateHelpersFeature
1970
 
        if not CompiledDirstateHelpersFeature.available():
1971
 
            from bzrlib.tests import UnavailableFeature
1972
 
            raise UnavailableFeature(CompiledDirstateHelpersFeature)
1973
 
        from bzrlib._dirstate_helpers_c import ProcessEntryC
 
2003
            compiled_dirstate_helpers_feature
 
2004
        test_case.requireFeature(compiled_dirstate_helpers_feature)
 
2005
        from bzrlib._dirstate_helpers_pyx import ProcessEntryC
1974
2006
        result = klass.make_source_parent_tree(source, target)
1975
2007
        result[1]._iter_changes = ProcessEntryC
1976
2008
        return result
2006
2038
            output. An unversioned file is defined as one with (False, False)
2007
2039
            for the versioned pair.
2008
2040
        """
2009
 
        # NB: show_status depends on being able to pass in non-versioned files
2010
 
        # and report them as unknown
2011
2041
        # TODO: handle extra trees in the dirstate.
2012
2042
        if (extra_trees or specific_files == []):
2013
2043
            # we can't fast-path these cases (yet)
2016
2046
                require_versioned, want_unversioned=want_unversioned)
2017
2047
        parent_ids = self.target.get_parent_ids()
2018
2048
        if not (self.source._revision_id in parent_ids
2019
 
                or self.source._revision_id == NULL_REVISION):
 
2049
                or self.source._revision_id == _mod_revision.NULL_REVISION):
2020
2050
            raise AssertionError(
2021
2051
                "revision {%s} is not stored in {%s}, but %s "
2022
2052
                "can only be used for trees stored in the dirstate"
2023
2053
                % (self.source._revision_id, self.target, self.iter_changes))
2024
2054
        target_index = 0
2025
 
        if self.source._revision_id == NULL_REVISION:
 
2055
        if self.source._revision_id == _mod_revision.NULL_REVISION:
2026
2056
            source_index = None
2027
2057
            indices = (target_index,)
2028
2058
        else:
2049
2079
        state._read_dirblocks_if_needed()
2050
2080
        if require_versioned:
2051
2081
            # -- check all supplied paths are versioned in a search tree. --
2052
 
            all_versioned = True
 
2082
            not_versioned = []
2053
2083
            for path in specific_files:
2054
2084
                path_entries = state._entries_for_path(path)
2055
2085
                if not path_entries:
2056
2086
                    # this specified path is not present at all: error
2057
 
                    all_versioned = False
2058
 
                    break
 
2087
                    not_versioned.append(path)
 
2088
                    continue
2059
2089
                found_versioned = False
2060
2090
                # for each id at this path
2061
2091
                for entry in path_entries:
2068
2098
                if not found_versioned:
2069
2099
                    # none of the indexes was not 'absent' at all ids for this
2070
2100
                    # path.
2071
 
                    all_versioned = False
2072
 
                    break
2073
 
            if not all_versioned:
2074
 
                raise errors.PathsNotVersionedError(specific_files)
 
2101
                    not_versioned.append(path)
 
2102
            if len(not_versioned) > 0:
 
2103
                raise errors.PathsNotVersionedError(not_versioned)
2075
2104
        # -- remove redundancy in supplied specific_files to prevent over-scanning --
2076
2105
        search_specific_files = osutils.minimum_path_selection(specific_files)
2077
2106
 
2091
2120
            (revisiontree.RevisionTree, DirStateRevisionTree)):
2092
2121
            return False
2093
2122
        # the source revid must be in the target dirstate
2094
 
        if not (source._revision_id == NULL_REVISION or
 
2123
        if not (source._revision_id == _mod_revision.NULL_REVISION or
2095
2124
            source._revision_id in target.get_parent_ids()):
2096
2125
            # TODO: what about ghosts? it may well need to
2097
2126
            # check for them explicitly.