~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree_4.py

  • Committer: Rory Yorke
  • Date: 2010-10-20 14:38:53 UTC
  • mto: This revision was merged to the branch mainline in revision 5519.
  • Revision ID: rory.yorke@gmail.com-20101020143853-9kfd2ldcjfroh8jw
Show missing files in bzr status (bug 134168).

"bzr status" will now show missing files, that is, those added with "bzr
add" and then removed by non bzr means (e.g., rm).

Blackbox tests were added for this case, and tests were also added to
test_delta, since the implementation change is in bzrlib.delta.

Might also affect bug 189709.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007-2011 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
31
31
import errno
32
32
import stat
33
33
 
 
34
import bzrlib
34
35
from bzrlib import (
35
36
    bzrdir,
36
37
    cache_utf8,
37
 
    conflicts as _mod_conflicts,
38
38
    debug,
39
39
    dirstate,
40
40
    errors,
41
 
    filters as _mod_filters,
42
41
    generate_ids,
43
42
    osutils,
44
43
    revision as _mod_revision,
47
46
    transform,
48
47
    views,
49
48
    )
 
49
import bzrlib.branch
 
50
import bzrlib.ui
50
51
""")
51
52
 
52
53
from bzrlib.decorators import needs_read_lock, needs_write_lock
 
54
from bzrlib.filters import filtered_input_file, internal_size_sha_file_byname
53
55
from bzrlib.inventory import Inventory, ROOT_ID, entry_factory
54
56
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
65
66
from bzrlib.transport.local import LocalTransport
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
 
 
 
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):
79
73
    def __init__(self, basedir,
80
74
                 branch,
81
75
                 _control_files=None,
91
85
        self._format = _format
92
86
        self.bzrdir = _bzrdir
93
87
        basedir = safe_unicode(basedir)
94
 
        trace.mutter("opening working tree %r", basedir)
 
88
        mutter("opening working tree %r", basedir)
95
89
        self._branch = branch
96
90
        self.basedir = realpath(basedir)
97
91
        # if branch is at our basedir and is a format 6 or less
131
125
            state.add(f, file_id, kind, None, '')
132
126
        self._make_dirty(reset_inventory=True)
133
127
 
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
 
 
138
128
    def _make_dirty(self, reset_inventory):
139
129
        """Make the tree state dirty.
140
130
 
192
182
 
193
183
    def _comparison_data(self, entry, path):
194
184
        kind, executable, stat_value = \
195
 
            WorkingTree._comparison_data(self, entry, path)
 
185
            WorkingTree3._comparison_data(self, entry, path)
196
186
        # it looks like a plain directory, but it's really a reference -- see
197
187
        # also kind()
198
188
        if (self._repo_supports_tree_reference and kind == 'directory'
204
194
    def commit(self, message=None, revprops=None, *args, **kwargs):
205
195
        # mark the tree as dirty post commit - commit
206
196
        # can change the current versioned list by doing deletes.
207
 
        result = WorkingTree.commit(self, message, revprops, *args, **kwargs)
 
197
        result = WorkingTree3.commit(self, message, revprops, *args, **kwargs)
208
198
        self._make_dirty(reset_inventory=True)
209
199
        return result
210
200
 
379
369
        state = self.current_dirstate()
380
370
        if stat_value is None:
381
371
            try:
382
 
                stat_value = osutils.lstat(file_abspath)
 
372
                stat_value = os.lstat(file_abspath)
383
373
            except OSError, e:
384
374
                if e.errno == errno.ENOENT:
385
375
                    return None
488
478
            self._must_be_locked()
489
479
            if not path:
490
480
                path = self.id2path(file_id)
491
 
            mode = osutils.lstat(self.abspath(path)).st_mode
 
481
            mode = os.lstat(self.abspath(path)).st_mode
492
482
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
493
483
 
494
484
    def all_file_ids(self):
1264
1254
    def rename_one(self, from_rel, to_rel, after=False):
1265
1255
        """See WorkingTree.rename_one"""
1266
1256
        self.flush()
1267
 
        super(DirStateWorkingTree, self).rename_one(from_rel, to_rel, after)
 
1257
        WorkingTree.rename_one(self, from_rel, to_rel, after)
1268
1258
 
1269
1259
    @needs_tree_write_lock
1270
1260
    def apply_inventory_delta(self, changes):
1303
1293
            self._inventory = inv
1304
1294
        self.flush()
1305
1295
 
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
 
 
1327
1296
 
1328
1297
class ContentFilterAwareSHA1Provider(dirstate.SHA1Provider):
1329
1298
 
1334
1303
        """See dirstate.SHA1Provider.sha1()."""
1335
1304
        filters = self.tree._content_filter_stack(
1336
1305
            self.tree.relpath(osutils.safe_unicode(abspath)))
1337
 
        return _mod_filters.internal_size_sha_file_byname(abspath, filters)[1]
 
1306
        return internal_size_sha_file_byname(abspath, filters)[1]
1338
1307
 
1339
1308
    def stat_and_sha1(self, abspath):
1340
1309
        """See dirstate.SHA1Provider.stat_and_sha1()."""
1344
1313
        try:
1345
1314
            statvalue = os.fstat(file_obj.fileno())
1346
1315
            if filters:
1347
 
                file_obj = _mod_filters.filtered_input_file(file_obj, filters)
 
1316
                file_obj = filtered_input_file(file_obj, filters)
1348
1317
            sha1 = osutils.size_sha_file(file_obj)[1]
1349
1318
        finally:
1350
1319
            file_obj.close()
1380
1349
class WorkingTree4(DirStateWorkingTree):
1381
1350
    """This is the Format 4 working tree.
1382
1351
 
1383
 
    This differs from WorkingTree by:
 
1352
    This differs from WorkingTree3 by:
1384
1353
     - Having a consolidated internal dirstate, stored in a
1385
1354
       randomly-accessible sorted file on disk.
1386
1355
     - Not having a regular inventory attribute.  One can be synthesized
1414
1383
        return views.PathBasedViews(self)
1415
1384
 
1416
1385
 
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)
 
1386
class DirStateWorkingTreeFormat(WorkingTreeFormat3):
1428
1387
 
1429
1388
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1430
1389
                   accelerator_tree=None, hardlink=False):
1530
1489
        :param wt: the WorkingTree object
1531
1490
        """
1532
1491
 
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
 
 
1547
1492
    def _open(self, a_bzrdir, control_files):
1548
1493
        """Open the tree itself.
1549
1494
 
1640
1585
        return True
1641
1586
 
1642
1587
 
1643
 
class DirStateRevisionTree(InventoryTree):
 
1588
class DirStateRevisionTree(Tree):
1644
1589
    """A revision tree pulling the inventory from a dirstate.
1645
1590
    
1646
1591
    Note that this is one of the historical (ie revision) trees cached in the
1665
1610
    def annotate_iter(self, file_id,
1666
1611
                      default_revision=_mod_revision.CURRENT_REVISION):
1667
1612
        """See Tree.annotate_iter"""
1668
 
        text_key = (file_id, self.get_file_revision(file_id))
 
1613
        text_key = (file_id, self.inventory[file_id].revision)
1669
1614
        annotations = self._repository.texts.annotate(text_key)
1670
1615
        return [(key[-1], line) for (key, line) in annotations]
1671
1616
 
1835
1780
            return parent_details[1]
1836
1781
        return None
1837
1782
 
1838
 
    @needs_read_lock
1839
 
    def get_file_revision(self, file_id):
1840
 
        return self.inventory[file_id].revision
1841
 
 
1842
1783
    def get_file(self, file_id, path=None):
1843
1784
        return StringIO(self.get_file_text(file_id))
1844
1785
 
1926
1867
    def is_executable(self, file_id, path=None):
1927
1868
        ie = self.inventory[file_id]
1928
1869
        if ie.kind != "file":
1929
 
            return False
 
1870
            return None
1930
1871
        return ie.executable
1931
1872
 
1932
1873
    def is_locked(self):
2045
1986
    def make_source_parent_tree(source, target):
2046
1987
        """Change the source tree into a parent of the target."""
2047
1988
        revid = source.commit('record tree')
2048
 
        target.branch.fetch(source.branch, revid)
 
1989
        target.branch.repository.fetch(source.branch.repository, revid)
2049
1990
        target.set_parent_ids([revid])
2050
1991
        return target.basis_tree(), target
2051
1992