~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: 2011-08-17 18:13:57 UTC
  • mfrom: (5268.7.29 transport-segments)
  • Revision ID: pqm@pqm.ubuntu.com-20110817181357-y5q5eth1hk8bl3om
(jelmer) Allow specifying the colocated branch to use in the branch URL,
 and retrieving the branch name using ControlDir._get_selected_branch.
 (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007-2012 Canonical Ltd
 
1
# Copyright (C) 2007-2011 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
22
22
WorkingTree.open(dir).
23
23
"""
24
24
 
25
 
from __future__ import absolute_import
26
 
 
27
25
from cStringIO import StringIO
28
26
import os
29
27
import sys
38
36
    cache_utf8,
39
37
    config,
40
38
    conflicts as _mod_conflicts,
41
 
    controldir,
42
39
    debug,
43
40
    dirstate,
44
41
    errors,
58
55
from bzrlib.lock import LogicalLockResult
59
56
from bzrlib.lockable_files import LockableFiles
60
57
from bzrlib.lockdir import LockDir
61
 
from bzrlib.mutabletree import (
62
 
    MutableTree,
63
 
    needs_tree_write_lock,
64
 
    )
 
58
from bzrlib.mutabletree import needs_tree_write_lock
65
59
from bzrlib.osutils import (
66
60
    file_kind,
67
61
    isdir,
69
63
    realpath,
70
64
    safe_unicode,
71
65
    )
72
 
from bzrlib.symbol_versioning import (
73
 
    deprecated_in,
74
 
    deprecated_method,
75
 
    )
76
66
from bzrlib.transport.local import LocalTransport
77
67
from bzrlib.tree import (
78
68
    InterTree,
81
71
from bzrlib.workingtree import (
82
72
    InventoryWorkingTree,
83
73
    WorkingTree,
84
 
    WorkingTreeFormatMetaDir,
 
74
    WorkingTreeFormat,
85
75
    )
86
76
 
87
77
 
260
250
 
261
251
        :return: an integer. -1 means never save.
262
252
        """
263
 
        conf = self.get_config_stack()
 
253
        # FIXME: We want a WorkingTreeStack here -- vila 20110812
 
254
        conf = config.BranchStack(self.branch)
264
255
        return conf.get('bzr.workingtree.worth_saving_limit')
265
256
 
266
257
    def filter_unversioned_files(self, paths):
419
410
                return link_or_sha1
420
411
        return None
421
412
 
422
 
    def _get_root_inventory(self):
 
413
    def _get_inventory(self):
423
414
        """Get the inventory for the tree. This is only valid within a lock."""
424
415
        if 'evil' in debug.debug_flags:
425
416
            trace.mutter_callsite(2,
430
421
        self._generate_inventory()
431
422
        return self._inventory
432
423
 
433
 
    @deprecated_method(deprecated_in((2, 5, 0)))
434
 
    def _get_inventory(self):
435
 
        return self.root_inventory
436
 
 
437
424
    inventory = property(_get_inventory,
438
425
                         doc="Inventory of this Tree")
439
426
 
440
 
    root_inventory = property(_get_root_inventory,
441
 
        "Root inventory of this tree")
442
 
 
443
427
    @needs_read_lock
444
428
    def get_parent_ids(self):
445
429
        """See Tree.get_parent_ids.
492
476
            return False # Missing entries are not executable
493
477
        return entry[1][0][3] # Executable?
494
478
 
495
 
    def is_executable(self, file_id, path=None):
496
 
        """Test if a file is executable or not.
 
479
    if not osutils.supports_executable():
 
480
        def is_executable(self, file_id, path=None):
 
481
            """Test if a file is executable or not.
497
482
 
498
 
        Note: The caller is expected to take a read-lock before calling this.
499
 
        """
500
 
        if not self._supports_executable():
 
483
            Note: The caller is expected to take a read-lock before calling this.
 
484
            """
501
485
            entry = self._get_entry(file_id=file_id, path=path)
502
486
            if entry == (None, None):
503
487
                return False
504
488
            return entry[1][0][3]
505
 
        else:
 
489
 
 
490
        _is_executable_from_path_and_stat = \
 
491
            _is_executable_from_path_and_stat_from_basis
 
492
    else:
 
493
        def is_executable(self, file_id, path=None):
 
494
            """Test if a file is executable or not.
 
495
 
 
496
            Note: The caller is expected to take a read-lock before calling this.
 
497
            """
506
498
            self._must_be_locked()
507
499
            if not path:
508
500
                path = self.id2path(file_id)
692
684
 
693
685
        if self._inventory is not None:
694
686
            update_inventory = True
695
 
            inv = self.root_inventory
 
687
            inv = self.inventory
696
688
            to_dir_id = to_entry[0][2]
697
689
            to_dir_ie = inv[to_dir_id]
698
690
        else:
894
886
    @needs_read_lock
895
887
    def path2id(self, path):
896
888
        """Return the id for path in this tree."""
897
 
        if isinstance(path, list):
898
 
            if path == []:
899
 
                path = [""]
900
 
            path = osutils.pathjoin(*path)
901
889
        path = path.strip('/')
902
890
        entry = self._get_entry(path=path)
903
891
        if entry == (None, None):
981
969
                    all_versioned = False
982
970
                    break
983
971
            if not all_versioned:
984
 
                raise errors.PathsNotVersionedError(
985
 
                    [p.decode('utf-8') for p in paths])
 
972
                raise errors.PathsNotVersionedError(paths)
986
973
        # -- remove redundancy in supplied paths to prevent over-scanning --
987
974
        search_paths = osutils.minimum_path_selection(paths)
988
975
        # sketch:
1037
1024
            found_dir_names = set(dir_name_id[:2] for dir_name_id in found)
1038
1025
            for dir_name in split_paths:
1039
1026
                if dir_name not in found_dir_names:
1040
 
                    raise errors.PathsNotVersionedError(
1041
 
                        [p.decode('utf-8') for p in paths])
 
1027
                    raise errors.PathsNotVersionedError(paths)
1042
1028
 
1043
1029
        for dir_name_id, trees_info in found.iteritems():
1044
1030
            for index in search_indexes:
1051
1037
 
1052
1038
        This is a meaningless operation for dirstate, but we obey it anyhow.
1053
1039
        """
1054
 
        return self.root_inventory
 
1040
        return self.inventory
1055
1041
 
1056
1042
    @needs_read_lock
1057
1043
    def revision_tree(self, revision_id):
1165
1151
                # _make_delta if we can't get the RevisionTree
1166
1152
                pass
1167
1153
            else:
1168
 
                delta = rev_tree.root_inventory._make_delta(
1169
 
                    basis_tree.root_inventory)
 
1154
                delta = rev_tree.inventory._make_delta(basis_tree.inventory)
1170
1155
                dirstate.update_basis_by_delta(delta, rev_id)
1171
1156
                updated = True
1172
1157
        if not updated:
1343
1328
        # being created.
1344
1329
        self._inventory = None
1345
1330
        # generate a delta,
1346
 
        delta = inv._make_delta(self.root_inventory)
 
1331
        delta = inv._make_delta(self.inventory)
1347
1332
        # and apply it.
1348
1333
        self.apply_inventory_delta(delta)
1349
1334
        if had_inventory:
1369
1354
            base_tree = trees[0][1]
1370
1355
        state = self.current_dirstate()
1371
1356
        # We don't support ghosts yet
1372
 
        state.set_state_from_scratch(base_tree.root_inventory, trees, [])
 
1357
        state.set_state_from_scratch(base_tree.inventory, trees, [])
1373
1358
 
1374
1359
 
1375
1360
class ContentFilterAwareSHA1Provider(dirstate.SHA1Provider):
1461
1446
        return views.PathBasedViews(self)
1462
1447
 
1463
1448
 
1464
 
class DirStateWorkingTreeFormat(WorkingTreeFormatMetaDir):
 
1449
class DirStateWorkingTreeFormat(WorkingTreeFormat):
1465
1450
 
1466
1451
    missing_parent_conflicts = True
1467
1452
 
1497
1482
        control_files = self._open_control_files(a_bzrdir)
1498
1483
        control_files.create_lock()
1499
1484
        control_files.lock_write()
1500
 
        transport.put_bytes('format', self.as_string(),
 
1485
        transport.put_bytes('format', self.get_format_string(),
1501
1486
            mode=a_bzrdir._get_file_mode())
1502
1487
        if from_branch is not None:
1503
1488
            branch = from_branch
1563
1548
                transform.build_tree(basis, wt, accelerator_tree,
1564
1549
                                     hardlink=hardlink,
1565
1550
                                     delta_from_tree=delta_from_tree)
1566
 
                for hook in MutableTree.hooks['post_build_tree']:
1567
 
                    hook(wt)
1568
1551
            finally:
1569
1552
                basis.unlock()
1570
1553
        finally:
1613
1596
    def _get_matchingbzrdir(self):
1614
1597
        """Overrideable method to get a bzrdir for testing."""
1615
1598
        # please test against something that will let us do tree references
1616
 
        return controldir.format_registry.make_bzrdir(
1617
 
            'development-subtree')
 
1599
        return bzrdir.format_registry.make_bzrdir(
 
1600
            'dirstate-with-subtree')
1618
1601
 
1619
1602
    _matchingbzrdir = property(__get_matchingbzrdir)
1620
1603
 
1625
1608
    This format:
1626
1609
        - exists within a metadir controlling .bzr
1627
1610
        - includes an explicit version marker for the workingtree control
1628
 
          files, separate from the ControlDir format
 
1611
          files, separate from the BzrDir format
1629
1612
        - modifies the hash cache format
1630
1613
        - is new in bzr 0.15
1631
1614
        - uses a LockDir to guard access to it.
1635
1618
 
1636
1619
    _tree_class = WorkingTree4
1637
1620
 
1638
 
    @classmethod
1639
 
    def get_format_string(cls):
 
1621
    def get_format_string(self):
1640
1622
        """See WorkingTreeFormat.get_format_string()."""
1641
1623
        return "Bazaar Working Tree Format 4 (bzr 0.15)\n"
1642
1624
 
1653
1635
 
1654
1636
    _tree_class = WorkingTree5
1655
1637
 
1656
 
    @classmethod
1657
 
    def get_format_string(cls):
 
1638
    def get_format_string(self):
1658
1639
        """See WorkingTreeFormat.get_format_string()."""
1659
1640
        return "Bazaar Working Tree Format 5 (bzr 1.11)\n"
1660
1641
 
1674
1655
 
1675
1656
    _tree_class = WorkingTree6
1676
1657
 
1677
 
    @classmethod
1678
 
    def get_format_string(cls):
 
1658
    def get_format_string(self):
1679
1659
        """See WorkingTreeFormat.get_format_string()."""
1680
1660
        return "Bazaar Working Tree Format 6 (bzr 1.14)\n"
1681
1661
 
1693
1673
    def supports_views(self):
1694
1674
        return True
1695
1675
 
1696
 
    def _get_matchingbzrdir(self):
1697
 
        """Overrideable method to get a bzrdir for testing."""
1698
 
        # We use 'development-subtree' instead of '2a', because we have a
1699
 
        # few tests that want to test tree references
1700
 
        return bzrdir.format_registry.make_bzrdir('development-subtree')
1701
 
 
1702
1676
 
1703
1677
class DirStateRevisionTree(InventoryTree):
1704
1678
    """A revision tree pulling the inventory from a dirstate.
1787
1761
        if path is not None:
1788
1762
            path = path.encode('utf8')
1789
1763
        parent_index = self._get_parent_index()
1790
 
        return self._dirstate._get_entry(parent_index, fileid_utf8=file_id,
1791
 
            path_utf8=path)
 
1764
        return self._dirstate._get_entry(parent_index, fileid_utf8=file_id, path_utf8=path)
1792
1765
 
1793
1766
    def _generate_inventory(self):
1794
1767
        """Create and set self.inventory from the dirstate object.
1876
1849
        # Make sure the file exists
1877
1850
        entry = self._get_entry(file_id, path=path)
1878
1851
        if entry == (None, None): # do we raise?
1879
 
            raise errors.NoSuchId(self, file_id)
 
1852
            return None
1880
1853
        parent_index = self._get_parent_index()
1881
1854
        last_changed_revision = entry[1][parent_index][4]
1882
1855
        try:
1895
1868
 
1896
1869
    @needs_read_lock
1897
1870
    def get_file_revision(self, file_id):
1898
 
        inv, inv_file_id = self._unpack_file_id(file_id)
1899
 
        return inv[inv_file_id].revision
 
1871
        return self.inventory[file_id].revision
1900
1872
 
1901
1873
    def get_file(self, file_id, path=None):
1902
1874
        return StringIO(self.get_file_text(file_id))
1903
1875
 
1904
1876
    def get_file_size(self, file_id):
1905
1877
        """See Tree.get_file_size"""
1906
 
        inv, inv_file_id = self._unpack_file_id(file_id)
1907
 
        return inv[inv_file_id].text_size
 
1878
        return self.inventory[file_id].text_size
1908
1879
 
1909
1880
    def get_file_text(self, file_id, path=None):
1910
 
        content = None
1911
 
        for _, content_iter in self.iter_files_bytes([(file_id, None)]):
1912
 
            if content is not None:
1913
 
                raise AssertionError('iter_files_bytes returned'
1914
 
                    ' too many entries')
1915
 
            # For each entry returned by iter_files_bytes, we must consume the
1916
 
            # content_iter before we step the files iterator.
1917
 
            content = ''.join(content_iter)
1918
 
        if content is None:
1919
 
            raise AssertionError('iter_files_bytes did not return'
1920
 
                ' the requested data')
1921
 
        return content
 
1881
        _, content = list(self.iter_files_bytes([(file_id, None)]))[0]
 
1882
        return ''.join(content)
1922
1883
 
1923
1884
    def get_reference_revision(self, file_id, path=None):
1924
 
        inv, inv_file_id = self._unpack_file_id(file_id)
1925
 
        return inv[inv_file_id].reference_revision
 
1885
        return self.inventory[file_id].reference_revision
1926
1886
 
1927
1887
    def iter_files_bytes(self, desired_files):
1928
1888
        """See Tree.iter_files_bytes.
1952
1912
        """Return the revision id for this tree."""
1953
1913
        return self._revision_id
1954
1914
 
1955
 
    def _get_root_inventory(self):
 
1915
    def _get_inventory(self):
1956
1916
        if self._inventory is not None:
1957
1917
            return self._inventory
1958
1918
        self._must_be_locked()
1959
1919
        self._generate_inventory()
1960
1920
        return self._inventory
1961
1921
 
1962
 
    root_inventory = property(_get_root_inventory,
1963
 
                         doc="Inventory of this Tree")
1964
 
 
1965
 
    @deprecated_method(deprecated_in((2, 5, 0)))
1966
 
    def _get_inventory(self):
1967
 
        return self.root_inventory
1968
 
 
1969
1922
    inventory = property(_get_inventory,
1970
1923
                         doc="Inventory of this Tree")
1971
1924
 
1989
1942
 
1990
1943
    def path_content_summary(self, path):
1991
1944
        """See Tree.path_content_summary."""
1992
 
        inv, inv_file_id = self._path2inv_file_id(path)
1993
 
        if inv_file_id is None:
 
1945
        id = self.inventory.path2id(path)
 
1946
        if id is None:
1994
1947
            return ('missing', None, None, None)
1995
 
        entry = inv[inv_file_id]
 
1948
        entry = self._inventory[id]
1996
1949
        kind = entry.kind
1997
1950
        if kind == 'file':
1998
1951
            return (kind, entry.text_size, entry.executable, entry.text_sha1)
2002
1955
            return (kind, None, None, None)
2003
1956
 
2004
1957
    def is_executable(self, file_id, path=None):
2005
 
        inv, inv_file_id = self._unpack_file_id(file_id)
2006
 
        ie = inv[inv_file_id]
 
1958
        ie = self.inventory[file_id]
2007
1959
        if ie.kind != "file":
2008
1960
            return False
2009
1961
        return ie.executable
2014
1966
    def list_files(self, include_root=False, from_dir=None, recursive=True):
2015
1967
        # We use a standard implementation, because DirStateRevisionTree is
2016
1968
        # dealing with one of the parents of the current state
 
1969
        inv = self._get_inventory()
2017
1970
        if from_dir is None:
2018
 
            inv = self.root_inventory
2019
1971
            from_dir_id = None
2020
1972
        else:
2021
 
            inv, from_dir_id = self._path2inv_file_id(from_dir)
 
1973
            from_dir_id = inv.path2id(from_dir)
2022
1974
            if from_dir_id is None:
2023
1975
                # Directory not versioned
2024
1976
                return
2025
 
        # FIXME: Support nested trees
2026
1977
        entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
2027
1978
        if inv.root is not None and not include_root and from_dir is None:
2028
1979
            entries.next()
2050
2001
    def path2id(self, path):
2051
2002
        """Return the id for path in this tree."""
2052
2003
        # lookup by path: faster than splitting and walking the ivnentory.
2053
 
        if isinstance(path, list):
2054
 
            if path == []:
2055
 
                path = [""]
2056
 
            path = osutils.pathjoin(*path)
2057
2004
        entry = self._get_entry(path=path)
2058
2005
        if entry == (None, None):
2059
2006
            return None
2082
2029
        # So for now, we just build up the parent inventory, and extract
2083
2030
        # it the same way RevisionTree does.
2084
2031
        _directory = 'directory'
2085
 
        inv = self._get_root_inventory()
 
2032
        inv = self._get_inventory()
2086
2033
        top_id = inv.path2id(prefix)
2087
2034
        if top_id is None:
2088
2035
            pending = []
2227
2174
                path_entries = state._entries_for_path(path)
2228
2175
                if not path_entries:
2229
2176
                    # this specified path is not present at all: error
2230
 
                    not_versioned.append(path.decode('utf-8'))
 
2177
                    not_versioned.append(path)
2231
2178
                    continue
2232
2179
                found_versioned = False
2233
2180
                # for each id at this path
2241
2188
                if not found_versioned:
2242
2189
                    # none of the indexes was not 'absent' at all ids for this
2243
2190
                    # path.
2244
 
                    not_versioned.append(path.decode('utf-8'))
 
2191
                    not_versioned.append(path)
2245
2192
            if len(not_versioned) > 0:
2246
2193
                raise errors.PathsNotVersionedError(not_versioned)
2247
2194
        # -- remove redundancy in supplied specific_files to prevent over-scanning --
2314
2261
    def update_format(self, tree):
2315
2262
        """Change the format marker."""
2316
2263
        tree._transport.put_bytes('format',
2317
 
            self.target_format.as_string(),
 
2264
            self.target_format.get_format_string(),
2318
2265
            mode=tree.bzrdir._get_file_mode())
2319
2266
 
2320
2267
 
2337
2284
    def update_format(self, tree):
2338
2285
        """Change the format marker."""
2339
2286
        tree._transport.put_bytes('format',
2340
 
            self.target_format.as_string(),
 
2287
            self.target_format.get_format_string(),
2341
2288
            mode=tree.bzrdir._get_file_mode())
2342
2289
 
2343
2290
 
2366
2313
    def update_format(self, tree):
2367
2314
        """Change the format marker."""
2368
2315
        tree._transport.put_bytes('format',
2369
 
            self.target_format.as_string(),
 
2316
            self.target_format.get_format_string(),
2370
2317
            mode=tree.bzrdir._get_file_mode())