~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree_4.py

  • Committer: INADA Naoki
  • Date: 2011-05-05 09:15:34 UTC
  • mto: (5830.3.3 i18n-msgfmt)
  • mto: This revision was merged to the branch mainline in revision 5873.
  • Revision ID: songofacandy@gmail.com-20110505091534-7sv835xpofwrmpt4
Add update-pot command to Makefile and tools/bzrgettext script that
extracts help text from bzr commands.

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-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
31
31
import errno
32
32
import stat
33
33
 
34
 
import bzrlib
35
34
from bzrlib import (
36
35
    bzrdir,
37
36
    cache_utf8,
 
37
    conflicts as _mod_conflicts,
38
38
    debug,
39
39
    dirstate,
40
40
    errors,
 
41
    filters as _mod_filters,
41
42
    generate_ids,
42
43
    osutils,
43
44
    revision as _mod_revision,
46
47
    transform,
47
48
    views,
48
49
    )
49
 
import bzrlib.branch
50
 
import bzrlib.ui
51
50
""")
52
51
 
53
52
from bzrlib.decorators import needs_read_lock, needs_write_lock
54
 
from bzrlib.filters import filtered_input_file, internal_size_sha_file_byname
55
53
from bzrlib.inventory import Inventory, ROOT_ID, entry_factory
56
 
import bzrlib.mutabletree
 
54
from bzrlib.lock import LogicalLockResult
 
55
from bzrlib.lockable_files import LockableFiles
 
56
from bzrlib.lockdir import LockDir
57
57
from bzrlib.mutabletree import needs_tree_write_lock
58
58
from bzrlib.osutils import (
59
59
    file_kind,
62
62
    realpath,
63
63
    safe_unicode,
64
64
    )
65
 
from bzrlib.trace import mutter
66
65
from bzrlib.transport.local import LocalTransport
67
 
from bzrlib.tree import InterTree
68
 
from bzrlib.tree import Tree
69
 
from bzrlib.workingtree import WorkingTree, WorkingTree3, WorkingTreeFormat3
70
 
 
71
 
 
72
 
class DirStateWorkingTree(WorkingTree3):
 
66
from bzrlib.tree import (
 
67
    InterTree,
 
68
    InventoryTree,
 
69
    )
 
70
from bzrlib.workingtree import (
 
71
    InventoryWorkingTree,
 
72
    WorkingTree,
 
73
    WorkingTreeFormat,
 
74
    )
 
75
 
 
76
 
 
77
class DirStateWorkingTree(InventoryWorkingTree):
 
78
 
73
79
    def __init__(self, basedir,
74
80
                 branch,
75
81
                 _control_files=None,
85
91
        self._format = _format
86
92
        self.bzrdir = _bzrdir
87
93
        basedir = safe_unicode(basedir)
88
 
        mutter("opening working tree %r", basedir)
 
94
        trace.mutter("opening working tree %r", basedir)
89
95
        self._branch = branch
90
96
        self.basedir = realpath(basedir)
91
97
        # if branch is at our basedir and is a format 6 or less
125
131
            state.add(f, file_id, kind, None, '')
126
132
        self._make_dirty(reset_inventory=True)
127
133
 
 
134
    def _get_check_refs(self):
 
135
        """Return the references needed to perform a check of this tree."""
 
136
        return [('trees', self.last_revision())]
 
137
 
128
138
    def _make_dirty(self, reset_inventory):
129
139
        """Make the tree state dirty.
130
140
 
182
192
 
183
193
    def _comparison_data(self, entry, path):
184
194
        kind, executable, stat_value = \
185
 
            WorkingTree3._comparison_data(self, entry, path)
 
195
            WorkingTree._comparison_data(self, entry, path)
186
196
        # it looks like a plain directory, but it's really a reference -- see
187
197
        # also kind()
188
198
        if (self._repo_supports_tree_reference and kind == 'directory'
194
204
    def commit(self, message=None, revprops=None, *args, **kwargs):
195
205
        # mark the tree as dirty post commit - commit
196
206
        # can change the current versioned list by doing deletes.
197
 
        result = WorkingTree3.commit(self, message, revprops, *args, **kwargs)
 
207
        result = WorkingTree.commit(self, message, revprops, *args, **kwargs)
198
208
        self._make_dirty(reset_inventory=True)
199
209
        return result
200
210
 
369
379
        state = self.current_dirstate()
370
380
        if stat_value is None:
371
381
            try:
372
 
                stat_value = os.lstat(file_abspath)
 
382
                stat_value = osutils.lstat(file_abspath)
373
383
            except OSError, e:
374
384
                if e.errno == errno.ENOENT:
375
385
                    return None
478
488
            self._must_be_locked()
479
489
            if not path:
480
490
                path = self.id2path(file_id)
481
 
            mode = os.lstat(self.abspath(path)).st_mode
 
491
            mode = osutils.lstat(self.abspath(path)).st_mode
482
492
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
483
493
 
484
494
    def all_file_ids(self):
568
578
            return _mod_revision.NULL_REVISION
569
579
 
570
580
    def lock_read(self):
571
 
        """See Branch.lock_read, and WorkingTree.unlock."""
 
581
        """See Branch.lock_read, and WorkingTree.unlock.
 
582
 
 
583
        :return: A bzrlib.lock.LogicalLockResult.
 
584
        """
572
585
        self.branch.lock_read()
573
586
        try:
574
587
            self._control_files.lock_read()
587
600
        except:
588
601
            self.branch.unlock()
589
602
            raise
 
603
        return LogicalLockResult(self.unlock)
590
604
 
591
605
    def _lock_self_write(self):
592
606
        """This should be called after the branch is locked."""
607
621
        except:
608
622
            self.branch.unlock()
609
623
            raise
 
624
        return LogicalLockResult(self.unlock)
610
625
 
611
626
    def lock_tree_write(self):
612
 
        """See MutableTree.lock_tree_write, and WorkingTree.unlock."""
 
627
        """See MutableTree.lock_tree_write, and WorkingTree.unlock.
 
628
 
 
629
        :return: A bzrlib.lock.LogicalLockResult.
 
630
        """
613
631
        self.branch.lock_read()
614
 
        self._lock_self_write()
 
632
        return self._lock_self_write()
615
633
 
616
634
    def lock_write(self):
617
 
        """See MutableTree.lock_write, and WorkingTree.unlock."""
 
635
        """See MutableTree.lock_write, and WorkingTree.unlock.
 
636
 
 
637
        :return: A bzrlib.lock.LogicalLockResult.
 
638
        """
618
639
        self.branch.lock_write()
619
 
        self._lock_self_write()
 
640
        return self._lock_self_write()
620
641
 
621
642
    @needs_tree_write_lock
622
643
    def move(self, from_paths, to_dir, after=False):
1236
1257
        # have to change the legacy inventory too.
1237
1258
        if self._inventory is not None:
1238
1259
            for file_id in file_ids:
1239
 
                self._inventory.remove_recursive_id(file_id)
 
1260
                if self._inventory.has_id(file_id):
 
1261
                    self._inventory.remove_recursive_id(file_id)
1240
1262
 
1241
1263
    @needs_tree_write_lock
1242
1264
    def rename_one(self, from_rel, to_rel, after=False):
1243
1265
        """See WorkingTree.rename_one"""
1244
1266
        self.flush()
1245
 
        WorkingTree.rename_one(self, from_rel, to_rel, after)
 
1267
        super(DirStateWorkingTree, self).rename_one(from_rel, to_rel, after)
1246
1268
 
1247
1269
    @needs_tree_write_lock
1248
1270
    def apply_inventory_delta(self, changes):
1281
1303
            self._inventory = inv
1282
1304
        self.flush()
1283
1305
 
 
1306
    @needs_tree_write_lock
 
1307
    def reset_state(self, revision_ids=None):
 
1308
        """Reset the state of the working tree.
 
1309
 
 
1310
        This does a hard-reset to a last-known-good state. This is a way to
 
1311
        fix if something got corrupted (like the .bzr/checkout/dirstate file)
 
1312
        """
 
1313
        if revision_ids is None:
 
1314
            revision_ids = self.get_parent_ids()
 
1315
        if not revision_ids:
 
1316
            base_tree = self.branch.repository.revision_tree(
 
1317
                _mod_revision.NULL_REVISION)
 
1318
            trees = []
 
1319
        else:
 
1320
            trees = zip(revision_ids,
 
1321
                        self.branch.repository.revision_trees(revision_ids))
 
1322
            base_tree = trees[0][1]
 
1323
        state = self.current_dirstate()
 
1324
        # We don't support ghosts yet
 
1325
        state.set_state_from_scratch(base_tree.inventory, trees, [])
 
1326
 
1284
1327
 
1285
1328
class ContentFilterAwareSHA1Provider(dirstate.SHA1Provider):
1286
1329
 
1291
1334
        """See dirstate.SHA1Provider.sha1()."""
1292
1335
        filters = self.tree._content_filter_stack(
1293
1336
            self.tree.relpath(osutils.safe_unicode(abspath)))
1294
 
        return internal_size_sha_file_byname(abspath, filters)[1]
 
1337
        return _mod_filters.internal_size_sha_file_byname(abspath, filters)[1]
1295
1338
 
1296
1339
    def stat_and_sha1(self, abspath):
1297
1340
        """See dirstate.SHA1Provider.stat_and_sha1()."""
1301
1344
        try:
1302
1345
            statvalue = os.fstat(file_obj.fileno())
1303
1346
            if filters:
1304
 
                file_obj = filtered_input_file(file_obj, filters)
 
1347
                file_obj = _mod_filters.filtered_input_file(file_obj, filters)
1305
1348
            sha1 = osutils.size_sha_file(file_obj)[1]
1306
1349
        finally:
1307
1350
            file_obj.close()
1318
1361
    def _file_content_summary(self, path, stat_result):
1319
1362
        # This is to support the somewhat obsolete path_content_summary method
1320
1363
        # with content filtering: see
1321
 
        # <https://bugs.edge.launchpad.net/bzr/+bug/415508>.
 
1364
        # <https://bugs.launchpad.net/bzr/+bug/415508>.
1322
1365
        #
1323
1366
        # If the dirstate cache is up to date and knows the hash and size,
1324
1367
        # return that.
1337
1380
class WorkingTree4(DirStateWorkingTree):
1338
1381
    """This is the Format 4 working tree.
1339
1382
 
1340
 
    This differs from WorkingTree3 by:
 
1383
    This differs from WorkingTree by:
1341
1384
     - Having a consolidated internal dirstate, stored in a
1342
1385
       randomly-accessible sorted file on disk.
1343
1386
     - Not having a regular inventory attribute.  One can be synthesized
1371
1414
        return views.PathBasedViews(self)
1372
1415
 
1373
1416
 
1374
 
class DirStateWorkingTreeFormat(WorkingTreeFormat3):
 
1417
class DirStateWorkingTreeFormat(WorkingTreeFormat):
 
1418
 
 
1419
    missing_parent_conflicts = True
 
1420
 
 
1421
    _lock_class = LockDir
 
1422
    _lock_file_name = 'lock'
 
1423
 
 
1424
    def _open_control_files(self, a_bzrdir):
 
1425
        transport = a_bzrdir.get_workingtree_transport(None)
 
1426
        return LockableFiles(transport, self._lock_file_name,
 
1427
                             self._lock_class)
 
1428
 
1375
1429
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1376
1430
                   accelerator_tree=None, hardlink=False):
1377
1431
        """See WorkingTreeFormat.initialize().
1476
1530
        :param wt: the WorkingTree object
1477
1531
        """
1478
1532
 
 
1533
    def open(self, a_bzrdir, _found=False):
 
1534
        """Return the WorkingTree object for a_bzrdir
 
1535
 
 
1536
        _found is a private parameter, do not use it. It is used to indicate
 
1537
               if format probing has already been done.
 
1538
        """
 
1539
        if not _found:
 
1540
            # we are being called directly and must probe.
 
1541
            raise NotImplementedError
 
1542
        if not isinstance(a_bzrdir.transport, LocalTransport):
 
1543
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
 
1544
        wt = self._open(a_bzrdir, self._open_control_files(a_bzrdir))
 
1545
        return wt
 
1546
 
1479
1547
    def _open(self, a_bzrdir, control_files):
1480
1548
        """Open the tree itself.
1481
1549
 
1572
1640
        return True
1573
1641
 
1574
1642
 
1575
 
class DirStateRevisionTree(Tree):
 
1643
class DirStateRevisionTree(InventoryTree):
1576
1644
    """A revision tree pulling the inventory from a dirstate.
1577
1645
    
1578
1646
    Note that this is one of the historical (ie revision) trees cached in the
1597
1665
    def annotate_iter(self, file_id,
1598
1666
                      default_revision=_mod_revision.CURRENT_REVISION):
1599
1667
        """See Tree.annotate_iter"""
1600
 
        text_key = (file_id, self.inventory[file_id].revision)
 
1668
        text_key = (file_id, self.get_file_revision(file_id))
1601
1669
        annotations = self._repository.texts.annotate(text_key)
1602
1670
        return [(key[-1], line) for (key, line) in annotations]
1603
1671
 
1725
1793
                elif kind == 'directory':
1726
1794
                    parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
1727
1795
                elif kind == 'symlink':
1728
 
                    inv_entry.executable = False
1729
 
                    inv_entry.text_size = None
1730
1796
                    inv_entry.symlink_target = utf8_decode(fingerprint)[0]
1731
1797
                elif kind == 'tree-reference':
1732
1798
                    inv_entry.reference_revision = fingerprint or None
1769
1835
            return parent_details[1]
1770
1836
        return None
1771
1837
 
 
1838
    @needs_read_lock
 
1839
    def get_file_revision(self, file_id):
 
1840
        return self.inventory[file_id].revision
 
1841
 
1772
1842
    def get_file(self, file_id, path=None):
1773
1843
        return StringIO(self.get_file_text(file_id))
1774
1844
 
1832
1902
        entry = self._get_entry(file_id=file_id)[1]
1833
1903
        if entry is None:
1834
1904
            raise errors.NoSuchId(tree=self, file_id=file_id)
1835
 
        return dirstate.DirState._minikind_to_kind[entry[1][0]]
 
1905
        parent_index = self._get_parent_index()
 
1906
        return dirstate.DirState._minikind_to_kind[entry[parent_index][0]]
1836
1907
 
1837
1908
    def stored_kind(self, file_id):
1838
1909
        """See Tree.stored_kind"""
1855
1926
    def is_executable(self, file_id, path=None):
1856
1927
        ie = self.inventory[file_id]
1857
1928
        if ie.kind != "file":
1858
 
            return None
 
1929
            return False
1859
1930
        return ie.executable
1860
1931
 
 
1932
    def is_locked(self):
 
1933
        return self._locked
 
1934
 
1861
1935
    def list_files(self, include_root=False, from_dir=None, recursive=True):
1862
1936
        # We use a standard implementation, because DirStateRevisionTree is
1863
1937
        # dealing with one of the parents of the current state
1876
1950
            yield path, 'V', entry.kind, entry.file_id, entry
1877
1951
 
1878
1952
    def lock_read(self):
1879
 
        """Lock the tree for a set of operations."""
 
1953
        """Lock the tree for a set of operations.
 
1954
 
 
1955
        :return: A bzrlib.lock.LogicalLockResult.
 
1956
        """
1880
1957
        if not self._locked:
1881
1958
            self._repository.lock_read()
1882
1959
            if self._dirstate._lock_token is None:
1883
1960
                self._dirstate.lock_read()
1884
1961
                self._dirstate_locked = True
1885
1962
        self._locked += 1
 
1963
        return LogicalLockResult(self.unlock)
1886
1964
 
1887
1965
    def _must_be_locked(self):
1888
1966
        if not self._locked:
1967
2045
    def make_source_parent_tree(source, target):
1968
2046
        """Change the source tree into a parent of the target."""
1969
2047
        revid = source.commit('record tree')
1970
 
        target.branch.repository.fetch(source.branch.repository, revid)
 
2048
        target.branch.fetch(source.branch, revid)
1971
2049
        target.set_parent_ids([revid])
1972
2050
        return target.basis_tree(), target
1973
2051