/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

  • Committer: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005-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
44
44
import stat
45
45
import re
46
46
 
 
47
import bzrlib
47
48
from bzrlib import (
48
49
    branch,
49
50
    bzrdir,
50
51
    conflicts as _mod_conflicts,
51
 
    controldir,
52
52
    errors,
53
53
    generate_ids,
54
54
    globbing,
59
59
    merge,
60
60
    revision as _mod_revision,
61
61
    revisiontree,
62
 
    rio as _mod_rio,
 
62
    trace,
63
63
    transform,
64
 
    transport,
65
64
    ui,
66
65
    views,
67
66
    xml5,
68
67
    xml7,
69
68
    )
 
69
import bzrlib.branch
 
70
from bzrlib.transport import get_transport
70
71
from bzrlib.workingtree_4 import (
71
72
    WorkingTreeFormat4,
72
73
    WorkingTreeFormat5,
76
77
 
77
78
from bzrlib import symbol_versioning
78
79
from bzrlib.decorators import needs_read_lock, needs_write_lock
79
 
from bzrlib.lock import LogicalLockResult
80
80
from bzrlib.lockable_files import LockableFiles
81
81
from bzrlib.lockdir import LockDir
82
82
import bzrlib.mutabletree
96
96
from bzrlib.trace import mutter, note
97
97
from bzrlib.transport.local import LocalTransport
98
98
from bzrlib.revision import CURRENT_REVISION
 
99
from bzrlib.rio import RioReader, rio_file, Stanza
99
100
from bzrlib.symbol_versioning import (
100
101
    deprecated_passed,
101
102
    DEPRECATED_PARAMETER,
167
168
 
168
169
 
169
170
class WorkingTree(bzrlib.mutabletree.MutableTree,
170
 
    controldir.ControlComponent):
 
171
    bzrdir.ControlComponent):
171
172
    """Working copy tree.
172
173
 
173
174
    The inventory is held in the `Branch` working-inventory, and the
175
176
 
176
177
    It is possible for a `WorkingTree` to have a filename which is
177
178
    not listed in the Inventory and vice versa.
178
 
 
179
 
    :ivar basedir: The root of the tree on disk. This is a unicode path object
180
 
        (as opposed to a URL).
181
179
    """
182
180
 
183
181
    # override this to set the strategy for storing views
207
205
        else:
208
206
            self._branch = self.bzrdir.open_branch()
209
207
        self.basedir = realpath(basedir)
210
 
        self._control_files = _control_files
 
208
        # if branch is at our basedir and is a format 6 or less
 
209
        if isinstance(self._format, WorkingTreeFormat2):
 
210
            # share control object
 
211
            self._control_files = self.branch.control_files
 
212
        else:
 
213
            # assume all other formats have their own control files.
 
214
            self._control_files = _control_files
211
215
        self._transport = self._control_files._transport
212
216
        # update the whole cache up front and write to disk if anything changed;
213
217
        # in the future we might want to do this more selectively
251
255
    def control_transport(self):
252
256
        return self._transport
253
257
 
254
 
    def is_control_filename(self, filename):
255
 
        """True if filename is the name of a control file in this tree.
256
 
 
257
 
        :param filename: A filename within the tree. This is a relative path
258
 
        from the root of this tree.
259
 
 
260
 
        This is true IF and ONLY IF the filename is part of the meta data
261
 
        that bzr controls in this tree. I.E. a random .bzr directory placed
262
 
        on disk will not be a control file for this tree.
263
 
        """
264
 
        return self.bzrdir.is_control_filename(filename)
265
 
 
266
258
    def _detect_case_handling(self):
267
259
        wt_trans = self.bzrdir.get_workingtree_transport(None)
268
260
        try:
269
 
            wt_trans.stat(self._format.case_sensitive_filename)
 
261
            wt_trans.stat("FoRMaT")
270
262
        except errors.NoSuchFile:
271
263
            self.case_sensitive = True
272
264
        else:
354
346
        if path is None:
355
347
            path = osutils.getcwd()
356
348
        control, relpath = bzrdir.BzrDir.open_containing(path)
 
349
 
357
350
        return control.open_workingtree(), relpath
358
351
 
359
352
    @staticmethod
360
 
    def open_containing_paths(file_list, default_directory=None,
361
 
                              canonicalize=True, apply_view=True):
362
 
        """Open the WorkingTree that contains a set of paths.
363
 
 
364
 
        Fail if the paths given are not all in a single tree.
365
 
 
366
 
        This is used for the many command-line interfaces that take a list of
367
 
        any number of files and that require they all be in the same tree.
368
 
        """
369
 
        if default_directory is None:
370
 
            default_directory = u'.'
371
 
        # recommended replacement for builtins.internal_tree_files
372
 
        if file_list is None or len(file_list) == 0:
373
 
            tree = WorkingTree.open_containing(default_directory)[0]
374
 
            # XXX: doesn't really belong here, and seems to have the strange
375
 
            # side effect of making it return a bunch of files, not the whole
376
 
            # tree -- mbp 20100716
377
 
            if tree.supports_views() and apply_view:
378
 
                view_files = tree.views.lookup_view()
379
 
                if view_files:
380
 
                    file_list = view_files
381
 
                    view_str = views.view_display_str(view_files)
382
 
                    note("Ignoring files outside view. View is %s" % view_str)
383
 
            return tree, file_list
384
 
        if default_directory == u'.':
385
 
            seed = file_list[0]
386
 
        else:
387
 
            seed = default_directory
388
 
            file_list = [osutils.pathjoin(default_directory, f)
389
 
                         for f in file_list]
390
 
        tree = WorkingTree.open_containing(seed)[0]
391
 
        return tree, tree.safe_relpath_files(file_list, canonicalize,
392
 
                                             apply_view=apply_view)
393
 
 
394
 
    def safe_relpath_files(self, file_list, canonicalize=True, apply_view=True):
395
 
        """Convert file_list into a list of relpaths in tree.
396
 
 
397
 
        :param self: A tree to operate on.
398
 
        :param file_list: A list of user provided paths or None.
399
 
        :param apply_view: if True and a view is set, apply it or check that
400
 
            specified files are within it
401
 
        :return: A list of relative paths.
402
 
        :raises errors.PathNotChild: When a provided path is in a different self
403
 
            than self.
404
 
        """
405
 
        if file_list is None:
406
 
            return None
407
 
        if self.supports_views() and apply_view:
408
 
            view_files = self.views.lookup_view()
409
 
        else:
410
 
            view_files = []
411
 
        new_list = []
412
 
        # self.relpath exists as a "thunk" to osutils, but canonical_relpath
413
 
        # doesn't - fix that up here before we enter the loop.
414
 
        if canonicalize:
415
 
            fixer = lambda p: osutils.canonical_relpath(self.basedir, p)
416
 
        else:
417
 
            fixer = self.relpath
418
 
        for filename in file_list:
419
 
            relpath = fixer(osutils.dereference_path(filename))
420
 
            if view_files and not osutils.is_inside_any(view_files, relpath):
421
 
                raise errors.FileOutsideView(filename, view_files)
422
 
            new_list.append(relpath)
423
 
        return new_list
424
 
 
425
 
    @staticmethod
426
353
    def open_downlevel(path=None):
427
354
        """Open an unsupported working tree.
428
355
 
441
368
                return True, None
442
369
            else:
443
370
                return True, tree
444
 
        t = transport.get_transport(location)
445
 
        iterator = bzrdir.BzrDir.find_bzrdirs(t, evaluate=evaluate,
 
371
        transport = get_transport(location)
 
372
        iterator = bzrdir.BzrDir.find_bzrdirs(transport, evaluate=evaluate,
446
373
                                              list_current=list_current)
447
 
        return [tr for tr in iterator if tr is not None]
 
374
        return [t for t in iterator if t is not None]
448
375
 
449
376
    # should be deprecated - this is slow and in any case treating them as a
450
377
    # container is (we now know) bad style -- mbp 20070302
523
450
        return self.get_file_with_stat(file_id, path, filtered=filtered)[0]
524
451
 
525
452
    def get_file_with_stat(self, file_id, path=None, filtered=True,
526
 
                           _fstat=osutils.fstat):
 
453
        _fstat=os.fstat):
527
454
        """See Tree.get_file_with_stat."""
528
455
        if path is None:
529
456
            path = self.id2path(file_id)
535
462
        return (file_obj, stat_value)
536
463
 
537
464
    def get_file_text(self, file_id, path=None, filtered=True):
538
 
        my_file = self.get_file(file_id, path=path, filtered=filtered)
539
 
        try:
540
 
            return my_file.read()
541
 
        finally:
542
 
            my_file.close()
 
465
        return self.get_file(file_id, path=path, filtered=filtered).read()
543
466
 
544
467
    def get_file_byname(self, filename, filtered=True):
545
468
        path = self.abspath(filename)
599
522
 
600
523
        # Now we have the parents of this content
601
524
        annotator = self.branch.repository.texts.get_annotator()
602
 
        text = self.get_file_text(file_id)
 
525
        text = self.get_file(file_id).read()
603
526
        this_key =(file_id, default_revision)
604
527
        annotator.add_special_text(this_key, file_parent_keys, text)
605
528
        annotations = [(key[-1], line)
888
811
            if revision_id in heads and revision_id not in new_revision_ids:
889
812
                new_revision_ids.append(revision_id)
890
813
        if new_revision_ids != revision_ids:
891
 
            mutter('requested to set revision_ids = %s,'
 
814
            trace.mutter('requested to set revision_ids = %s,'
892
815
                         ' but filtered to %s', revision_ids, new_revision_ids)
893
816
        return new_revision_ids
894
817
 
960
883
    def set_merge_modified(self, modified_hashes):
961
884
        def iter_stanzas():
962
885
            for file_id, hash in modified_hashes.iteritems():
963
 
                yield _mod_rio.Stanza(file_id=file_id.decode('utf8'),
964
 
                    hash=hash)
 
886
                yield Stanza(file_id=file_id.decode('utf8'), hash=hash)
965
887
        self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
966
888
 
967
889
    def _sha_from_stat(self, path, stat_result):
976
898
 
977
899
    def _put_rio(self, filename, stanzas, header):
978
900
        self._must_be_locked()
979
 
        my_file = _mod_rio.rio_file(stanzas, header)
 
901
        my_file = rio_file(stanzas, header)
980
902
        self._transport.put_file(filename, my_file,
981
903
            mode=self.bzrdir._get_file_mode())
982
904
 
1046
968
                    raise errors.MergeModifiedFormatError()
1047
969
            except StopIteration:
1048
970
                raise errors.MergeModifiedFormatError()
1049
 
            for s in _mod_rio.RioReader(hashfile):
 
971
            for s in RioReader(hashfile):
1050
972
                # RioReader reads in Unicode, so convert file_ids back to utf8
1051
973
                file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
1052
974
                if file_id not in self.inventory:
1280
1202
                # absolute path
1281
1203
                fap = from_dir_abspath + '/' + f
1282
1204
 
1283
 
                dir_ie = inv[from_dir_id]
1284
 
                if dir_ie.kind == 'directory':
1285
 
                    f_ie = dir_ie.children.get(f)
1286
 
                else:
1287
 
                    f_ie = None
 
1205
                f_ie = inv.get_child(from_dir_id, f)
1288
1206
                if f_ie:
1289
1207
                    c = 'V'
1290
1208
                elif self.is_ignored(fp[1:]):
1291
1209
                    c = 'I'
1292
1210
                else:
1293
 
                    # we may not have found this file, because of a unicode
1294
 
                    # issue, or because the directory was actually a symlink.
 
1211
                    # we may not have found this file, because of a unicode issue
1295
1212
                    f_norm, can_access = osutils.normalized_filename(f)
1296
1213
                    if f == f_norm or not can_access:
1297
1214
                        # No change, so treat this file normally
1340
1257
                stack.pop()
1341
1258
 
1342
1259
    @needs_tree_write_lock
1343
 
    def move(self, from_paths, to_dir=None, after=False):
 
1260
    def move(self, from_paths, to_dir=None, after=False, **kwargs):
1344
1261
        """Rename files.
1345
1262
 
1346
1263
        to_dir must exist in the inventory.
1380
1297
 
1381
1298
        # check for deprecated use of signature
1382
1299
        if to_dir is None:
1383
 
            raise TypeError('You must supply a target directory')
 
1300
            to_dir = kwargs.get('to_name', None)
 
1301
            if to_dir is None:
 
1302
                raise TypeError('You must supply a target directory')
 
1303
            else:
 
1304
                symbol_versioning.warn('The parameter to_name was deprecated'
 
1305
                                       ' in version 0.13. Use to_dir instead',
 
1306
                                       DeprecationWarning)
 
1307
 
1384
1308
        # check destination directory
1385
1309
        if isinstance(from_paths, basestring):
1386
1310
            raise ValueError()
1395
1319
        to_dir_id = inv.path2id(to_dir)
1396
1320
        if to_dir_id is None:
1397
1321
            raise errors.BzrMoveFailedError('',to_dir,
1398
 
                errors.NotVersionedError(path=to_dir))
 
1322
                errors.NotVersionedError(path=str(to_dir)))
1399
1323
 
1400
1324
        to_dir_ie = inv[to_dir_id]
1401
1325
        if to_dir_ie.kind != 'directory':
1408
1332
            from_id = inv.path2id(from_rel)
1409
1333
            if from_id is None:
1410
1334
                raise errors.BzrMoveFailedError(from_rel,to_dir,
1411
 
                    errors.NotVersionedError(path=from_rel))
 
1335
                    errors.NotVersionedError(path=str(from_rel)))
1412
1336
 
1413
1337
            from_entry = inv[from_id]
1414
1338
            from_parent_id = from_entry.parent_id
1456
1380
            # check the inventory for source and destination
1457
1381
            if from_id is None:
1458
1382
                raise errors.BzrMoveFailedError(from_rel,to_rel,
1459
 
                    errors.NotVersionedError(path=from_rel))
 
1383
                    errors.NotVersionedError(path=str(from_rel)))
1460
1384
            if to_id is not None:
1461
1385
                raise errors.BzrMoveFailedError(from_rel,to_rel,
1462
 
                    errors.AlreadyVersionedError(path=to_rel))
 
1386
                    errors.AlreadyVersionedError(path=str(to_rel)))
1463
1387
 
1464
1388
            # try to determine the mode for rename (only change inv or change
1465
1389
            # inv and file system)
1466
1390
            if after:
1467
1391
                if not self.has_filename(to_rel):
1468
1392
                    raise errors.BzrMoveFailedError(from_id,to_rel,
1469
 
                        errors.NoSuchFile(path=to_rel,
 
1393
                        errors.NoSuchFile(path=str(to_rel),
1470
1394
                        extra="New file has not been created yet"))
1471
1395
                only_change_inv = True
1472
1396
            elif not self.has_filename(from_rel) and self.has_filename(to_rel):
1574
1498
            from_id = basis_tree.path2id(from_rel)
1575
1499
            if from_id is None:
1576
1500
                raise errors.BzrRenameFailedError(from_rel,to_rel,
1577
 
                    errors.NotVersionedError(path=from_rel))
 
1501
                    errors.NotVersionedError(path=str(from_rel)))
1578
1502
            # put entry back in the inventory so we can rename it
1579
1503
            from_entry = basis_tree.inventory[from_id].copy()
1580
1504
            inv.add(from_entry)
1598
1522
        # versioned
1599
1523
        if to_dir_id is None:
1600
1524
            raise errors.BzrMoveFailedError(from_rel,to_rel,
1601
 
                errors.NotVersionedError(path=to_dir))
 
1525
                errors.NotVersionedError(path=str(to_dir)))
1602
1526
 
1603
1527
        # all checks done. now we can continue with our actual work
1604
1528
        mutter('rename_one:\n'
1663
1587
            # - RBC 20060907
1664
1588
            self._write_inventory(self._inventory)
1665
1589
 
 
1590
    def _iter_conflicts(self):
 
1591
        conflicted = set()
 
1592
        for info in self.list_files():
 
1593
            path = info[0]
 
1594
            stem = get_conflicted_stem(path)
 
1595
            if stem is None:
 
1596
                continue
 
1597
            if stem not in conflicted:
 
1598
                conflicted.add(stem)
 
1599
                yield stem
 
1600
 
1666
1601
    @needs_write_lock
1667
1602
    def pull(self, source, overwrite=False, stop_revision=None,
1668
 
             change_reporter=None, possible_transports=None, local=False,
1669
 
             show_base=False):
 
1603
             change_reporter=None, possible_transports=None, local=False):
1670
1604
        source.lock_read()
1671
1605
        try:
1672
1606
            old_revision_info = self.branch.last_revision_info()
1686
1620
                                basis_tree,
1687
1621
                                this_tree=self,
1688
1622
                                pb=None,
1689
 
                                change_reporter=change_reporter,
1690
 
                                show_base=show_base)
 
1623
                                change_reporter=change_reporter)
1691
1624
                    basis_root_id = basis_tree.get_root_id()
1692
1625
                    new_root_id = new_basis_tree.get_root_id()
1693
1626
                    if basis_root_id != new_root_id:
1865
1798
            raise errors.ObjectNotLocked(self)
1866
1799
 
1867
1800
    def lock_read(self):
1868
 
        """Lock the tree for reading.
1869
 
 
1870
 
        This also locks the branch, and can be unlocked via self.unlock().
1871
 
 
1872
 
        :return: A bzrlib.lock.LogicalLockResult.
1873
 
        """
 
1801
        """See Branch.lock_read, and WorkingTree.unlock."""
1874
1802
        if not self.is_locked():
1875
1803
            self._reset_data()
1876
1804
        self.branch.lock_read()
1877
1805
        try:
1878
 
            self._control_files.lock_read()
1879
 
            return LogicalLockResult(self.unlock)
 
1806
            return self._control_files.lock_read()
1880
1807
        except:
1881
1808
            self.branch.unlock()
1882
1809
            raise
1883
1810
 
1884
1811
    def lock_tree_write(self):
1885
 
        """See MutableTree.lock_tree_write, and WorkingTree.unlock.
1886
 
 
1887
 
        :return: A bzrlib.lock.LogicalLockResult.
1888
 
        """
 
1812
        """See MutableTree.lock_tree_write, and WorkingTree.unlock."""
1889
1813
        if not self.is_locked():
1890
1814
            self._reset_data()
1891
1815
        self.branch.lock_read()
1892
1816
        try:
1893
 
            self._control_files.lock_write()
1894
 
            return LogicalLockResult(self.unlock)
 
1817
            return self._control_files.lock_write()
1895
1818
        except:
1896
1819
            self.branch.unlock()
1897
1820
            raise
1898
1821
 
1899
1822
    def lock_write(self):
1900
 
        """See MutableTree.lock_write, and WorkingTree.unlock.
1901
 
 
1902
 
        :return: A bzrlib.lock.LogicalLockResult.
1903
 
        """
 
1823
        """See MutableTree.lock_write, and WorkingTree.unlock."""
1904
1824
        if not self.is_locked():
1905
1825
            self._reset_data()
1906
1826
        self.branch.lock_write()
1907
1827
        try:
1908
 
            self._control_files.lock_write()
1909
 
            return LogicalLockResult(self.unlock)
 
1828
            return self._control_files.lock_write()
1910
1829
        except:
1911
1830
            self.branch.unlock()
1912
1831
            raise
2029
1948
 
2030
1949
        inv_delta = []
2031
1950
 
2032
 
        all_files = set() # specified and nested files 
 
1951
        new_files=set()
2033
1952
        unknown_nested_files=set()
2034
1953
        if to_file is None:
2035
1954
            to_file = sys.stdout
2036
1955
 
2037
 
        files_to_backup = []
2038
 
 
2039
1956
        def recurse_directory_to_add_files(directory):
2040
1957
            # Recurse directory and add all files
2041
1958
            # so we can check if they have changed.
2042
 
            for parent_info, file_infos in self.walkdirs(directory):
 
1959
            for parent_info, file_infos in\
 
1960
                self.walkdirs(directory):
2043
1961
                for relpath, basename, kind, lstat, fileid, kind in file_infos:
2044
1962
                    # Is it versioned or ignored?
2045
 
                    if self.path2id(relpath):
 
1963
                    if self.path2id(relpath) or self.is_ignored(relpath):
2046
1964
                        # Add nested content for deletion.
2047
 
                        all_files.add(relpath)
 
1965
                        new_files.add(relpath)
2048
1966
                    else:
2049
 
                        # Files which are not versioned
 
1967
                        # Files which are not versioned and not ignored
2050
1968
                        # should be treated as unknown.
2051
 
                        files_to_backup.append(relpath)
 
1969
                        unknown_nested_files.add((relpath, None, kind))
2052
1970
 
2053
1971
        for filename in files:
2054
1972
            # Get file name into canonical form.
2055
1973
            abspath = self.abspath(filename)
2056
1974
            filename = self.relpath(abspath)
2057
1975
            if len(filename) > 0:
2058
 
                all_files.add(filename)
 
1976
                new_files.add(filename)
2059
1977
                recurse_directory_to_add_files(filename)
2060
1978
 
2061
 
        files = list(all_files)
 
1979
        files = list(new_files)
2062
1980
 
2063
1981
        if len(files) == 0:
2064
1982
            return # nothing to do
2068
1986
 
2069
1987
        # Bail out if we are going to delete files we shouldn't
2070
1988
        if not keep_files and not force:
2071
 
            for (file_id, path, content_change, versioned, parent_id, name,
2072
 
                 kind, executable) in self.iter_changes(self.basis_tree(),
2073
 
                     include_unchanged=True, require_versioned=False,
2074
 
                     want_unversioned=True, specific_files=files):
2075
 
                if versioned[0] == False:
2076
 
                    # The record is unknown or newly added
2077
 
                    files_to_backup.append(path[1])
2078
 
                elif (content_change and (kind[1] is not None) and
2079
 
                        osutils.is_inside_any(files, path[1])):
2080
 
                    # Versioned and changed, but not deleted, and still
2081
 
                    # in one of the dirs to be deleted.
2082
 
                    files_to_backup.append(path[1])
 
1989
            has_changed_files = len(unknown_nested_files) > 0
 
1990
            if not has_changed_files:
 
1991
                for (file_id, path, content_change, versioned, parent_id, name,
 
1992
                     kind, executable) in self.iter_changes(self.basis_tree(),
 
1993
                         include_unchanged=True, require_versioned=False,
 
1994
                         want_unversioned=True, specific_files=files):
 
1995
                    if versioned == (False, False):
 
1996
                        # The record is unknown ...
 
1997
                        if not self.is_ignored(path[1]):
 
1998
                            # ... but not ignored
 
1999
                            has_changed_files = True
 
2000
                            break
 
2001
                    elif content_change and (kind[1] is not None):
 
2002
                        # Versioned and changed, but not deleted
 
2003
                        has_changed_files = True
 
2004
                        break
2083
2005
 
2084
 
        def backup(file_to_backup):
2085
 
            backup_name = self.bzrdir._available_backup_name(file_to_backup)
2086
 
            osutils.rename(abs_path, self.abspath(backup_name))
2087
 
            return "removed %s (but kept a copy: %s)" % (file_to_backup,
2088
 
                                                         backup_name)
 
2006
            if has_changed_files:
 
2007
                # Make delta show ALL applicable changes in error message.
 
2008
                tree_delta = self.changes_from(self.basis_tree(),
 
2009
                    require_versioned=False, want_unversioned=True,
 
2010
                    specific_files=files)
 
2011
                for unknown_file in unknown_nested_files:
 
2012
                    if unknown_file not in tree_delta.unversioned:
 
2013
                        tree_delta.unversioned.extend((unknown_file,))
 
2014
                raise errors.BzrRemoveChangedFilesError(tree_delta)
2089
2015
 
2090
2016
        # Build inv_delta and delete files where applicable,
2091
2017
        # do this before any modifications to inventory.
2115
2041
                        len(os.listdir(abs_path)) > 0):
2116
2042
                        if force:
2117
2043
                            osutils.rmtree(abs_path)
2118
 
                            message = "deleted %s" % (f,)
2119
2044
                        else:
2120
 
                            message = backup(f)
 
2045
                            message = "%s is not an empty directory "\
 
2046
                                "and won't be deleted." % (f,)
2121
2047
                    else:
2122
 
                        if f in files_to_backup:
2123
 
                            message = backup(f)
2124
 
                        else:
2125
 
                            osutils.delete_any(abs_path)
2126
 
                            message = "deleted %s" % (f,)
 
2048
                        osutils.delete_any(abs_path)
 
2049
                        message = "deleted %s" % (f,)
2127
2050
                elif message is not None:
2128
2051
                    # Only care if we haven't done anything yet.
2129
2052
                    message = "%s does not exist." % (f,)
2266
2189
    _marker = object()
2267
2190
 
2268
2191
    def update(self, change_reporter=None, possible_transports=None,
2269
 
               revision=None, old_tip=_marker, show_base=False):
 
2192
               revision=None, old_tip=_marker):
2270
2193
        """Update a working tree along its branch.
2271
2194
 
2272
2195
        This will update the branch if its bound too, which means we have
2309
2232
            else:
2310
2233
                if old_tip is self._marker:
2311
2234
                    old_tip = None
2312
 
            return self._update_tree(old_tip, change_reporter, revision, show_base)
 
2235
            return self._update_tree(old_tip, change_reporter, revision)
2313
2236
        finally:
2314
2237
            self.unlock()
2315
2238
 
2316
2239
    @needs_tree_write_lock
2317
 
    def _update_tree(self, old_tip=None, change_reporter=None, revision=None,
2318
 
                     show_base=False):
 
2240
    def _update_tree(self, old_tip=None, change_reporter=None, revision=None):
2319
2241
        """Update a tree to the master branch.
2320
2242
 
2321
2243
        :param old_tip: if supplied, the previous tip revision the branch,
2348
2270
            other_tree = self.branch.repository.revision_tree(old_tip)
2349
2271
            nb_conflicts = merge.merge_inner(self.branch, other_tree,
2350
2272
                                             base_tree, this_tree=self,
2351
 
                                             change_reporter=change_reporter,
2352
 
                                             show_base=show_base)
 
2273
                                             change_reporter=change_reporter)
2353
2274
            if nb_conflicts:
2354
2275
                self.add_parent_tree((old_tip, other_tree))
2355
 
                note('Rerun update after fixing the conflicts.')
 
2276
                trace.note('Rerun update after fixing the conflicts.')
2356
2277
                return nb_conflicts
2357
2278
 
2358
2279
        if last_rev != _mod_revision.ensure_null(revision):
2379
2300
 
2380
2301
            nb_conflicts = merge.merge_inner(self.branch, to_tree, base_tree,
2381
2302
                                             this_tree=self,
2382
 
                                             change_reporter=change_reporter,
2383
 
                                             show_base=show_base)
 
2303
                                             change_reporter=change_reporter)
2384
2304
            self.set_last_revision(revision)
2385
2305
            # TODO - dedup parents list with things merged by pull ?
2386
2306
            # reuse the tree we've updated to to set the basis:
2427
2347
    def add_conflicts(self, arg):
2428
2348
        raise errors.UnsupportedOperation(self.add_conflicts, self)
2429
2349
 
 
2350
    @needs_read_lock
2430
2351
    def conflicts(self):
2431
 
        raise NotImplementedError(self.conflicts)
 
2352
        conflicts = _mod_conflicts.ConflictList()
 
2353
        for conflicted in self._iter_conflicts():
 
2354
            text = True
 
2355
            try:
 
2356
                if file_kind(self.abspath(conflicted)) != "file":
 
2357
                    text = False
 
2358
            except errors.NoSuchFile:
 
2359
                text = False
 
2360
            if text is True:
 
2361
                for suffix in ('.THIS', '.OTHER'):
 
2362
                    try:
 
2363
                        kind = file_kind(self.abspath(conflicted+suffix))
 
2364
                        if kind != "file":
 
2365
                            text = False
 
2366
                    except errors.NoSuchFile:
 
2367
                        text = False
 
2368
                    if text == False:
 
2369
                        break
 
2370
            ctype = {True: 'text conflict', False: 'contents conflict'}[text]
 
2371
            conflicts.append(_mod_conflicts.Conflict.factory(ctype,
 
2372
                             path=conflicted,
 
2373
                             file_id=self.path2id(conflicted)))
 
2374
        return conflicts
2432
2375
 
2433
2376
    def walkdirs(self, prefix=""):
2434
2377
        """Walk the directories of this tree.
2652
2595
        """
2653
2596
        return
2654
2597
 
2655
 
    @needs_read_lock
2656
 
    def check_state(self):
2657
 
        """Check that the working state is/isn't valid."""
2658
 
        check_refs = self._get_check_refs()
2659
 
        refs = {}
2660
 
        for ref in check_refs:
2661
 
            kind, value = ref
2662
 
            if kind == 'trees':
2663
 
                refs[ref] = self.branch.repository.revision_tree(value)
2664
 
        self._check(refs)
2665
 
 
2666
 
    @needs_tree_write_lock
2667
 
    def reset_state(self, revision_ids=None):
2668
 
        """Reset the state of the working tree.
2669
 
 
2670
 
        This does a hard-reset to a last-known-good state. This is a way to
2671
 
        fix if something got corrupted (like the .bzr/checkout/dirstate file)
2672
 
        """
2673
 
        if revision_ids is None:
2674
 
            revision_ids = self.get_parent_ids()
2675
 
        if not revision_ids:
2676
 
            rt = self.branch.repository.revision_tree(
2677
 
                _mod_revision.NULL_REVISION)
2678
 
        else:
2679
 
            rt = self.branch.repository.revision_tree(revision_ids[0])
2680
 
        self._write_inventory(rt.inventory)
2681
 
        self.set_parent_ids(revision_ids)
2682
 
 
2683
2598
    def _get_rules_searcher(self, default_searcher):
2684
2599
        """See Tree._get_rules_searcher."""
2685
2600
        if self._rules_searcher is None:
2693
2608
        return ShelfManager(self, self._transport)
2694
2609
 
2695
2610
 
 
2611
class WorkingTree2(WorkingTree):
 
2612
    """This is the Format 2 working tree.
 
2613
 
 
2614
    This was the first weave based working tree.
 
2615
     - uses os locks for locking.
 
2616
     - uses the branch last-revision.
 
2617
    """
 
2618
 
 
2619
    def __init__(self, *args, **kwargs):
 
2620
        super(WorkingTree2, self).__init__(*args, **kwargs)
 
2621
        # WorkingTree2 has more of a constraint that self._inventory must
 
2622
        # exist. Because this is an older format, we don't mind the overhead
 
2623
        # caused by the extra computation here.
 
2624
 
 
2625
        # Newer WorkingTree's should only have self._inventory set when they
 
2626
        # have a read lock.
 
2627
        if self._inventory is None:
 
2628
            self.read_working_inventory()
 
2629
 
 
2630
    def _get_check_refs(self):
 
2631
        """Return the references needed to perform a check of this tree."""
 
2632
        return [('trees', self.last_revision())]
 
2633
 
 
2634
    def lock_tree_write(self):
 
2635
        """See WorkingTree.lock_tree_write().
 
2636
 
 
2637
        In Format2 WorkingTrees we have a single lock for the branch and tree
 
2638
        so lock_tree_write() degrades to lock_write().
 
2639
        """
 
2640
        self.branch.lock_write()
 
2641
        try:
 
2642
            return self._control_files.lock_write()
 
2643
        except:
 
2644
            self.branch.unlock()
 
2645
            raise
 
2646
 
 
2647
    def unlock(self):
 
2648
        # do non-implementation specific cleanup
 
2649
        self._cleanup()
 
2650
 
 
2651
        # we share control files:
 
2652
        if self._control_files._lock_count == 3:
 
2653
            # _inventory_is_modified is always False during a read lock.
 
2654
            if self._inventory_is_modified:
 
2655
                self.flush()
 
2656
            self._write_hashcache_if_dirty()
 
2657
 
 
2658
        # reverse order of locking.
 
2659
        try:
 
2660
            return self._control_files.unlock()
 
2661
        finally:
 
2662
            self.branch.unlock()
 
2663
 
 
2664
 
2696
2665
class WorkingTree3(WorkingTree):
2697
2666
    """This is the Format 3 working tree.
2698
2667
 
2752
2721
                    raise errors.ConflictFormatError()
2753
2722
            except StopIteration:
2754
2723
                raise errors.ConflictFormatError()
2755
 
            reader = _mod_rio.RioReader(confile)
2756
 
            return _mod_conflicts.ConflictList.from_stanzas(reader)
 
2724
            return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
2757
2725
        finally:
2758
2726
            confile.close()
2759
2727
 
2772
2740
            self.branch.unlock()
2773
2741
 
2774
2742
 
2775
 
class WorkingTreeFormatRegistry(controldir.ControlComponentFormatRegistry):
2776
 
    """Registry for working tree formats."""
2777
 
 
2778
 
    def __init__(self, other_registry=None):
2779
 
        super(WorkingTreeFormatRegistry, self).__init__(other_registry)
2780
 
        self._default_format = None
2781
 
 
2782
 
    def get_default(self):
2783
 
        """Return the current default format."""
2784
 
        return self._default_format
2785
 
 
2786
 
    def set_default(self, format):
2787
 
        self._default_format = format
2788
 
 
2789
 
 
2790
 
format_registry = WorkingTreeFormatRegistry()
2791
 
 
2792
 
 
2793
 
class WorkingTreeFormat(controldir.ControlComponentFormat):
 
2743
def get_conflicted_stem(path):
 
2744
    for suffix in _mod_conflicts.CONFLICT_SUFFIXES:
 
2745
        if path.endswith(suffix):
 
2746
            return path[:-len(suffix)]
 
2747
 
 
2748
 
 
2749
class WorkingTreeFormat(object):
2794
2750
    """An encapsulation of the initialization and open routines for a format.
2795
2751
 
2796
2752
    Formats provide three things:
2808
2764
    object will be created every time regardless.
2809
2765
    """
2810
2766
 
 
2767
    _default_format = None
 
2768
    """The default format used for new trees."""
 
2769
 
 
2770
    _formats = {}
 
2771
    """The known formats."""
 
2772
 
2811
2773
    requires_rich_root = False
2812
2774
 
2813
2775
    upgrade_recommended = False
2814
2776
 
2815
 
    requires_normalized_unicode_filenames = False
2816
 
 
2817
 
    case_sensitive_filename = "FoRMaT"
2818
 
 
2819
 
    missing_parent_conflicts = False
2820
 
    """If this format supports missing parent conflicts."""
2821
 
 
2822
2777
    @classmethod
2823
2778
    def find_format(klass, a_bzrdir):
2824
2779
        """Return the format for the working tree object in a_bzrdir."""
2825
2780
        try:
2826
2781
            transport = a_bzrdir.get_workingtree_transport(None)
2827
2782
            format_string = transport.get_bytes("format")
2828
 
            return format_registry.get(format_string)
 
2783
            return klass._formats[format_string]
2829
2784
        except errors.NoSuchFile:
2830
2785
            raise errors.NoWorkingTree(base=transport.base)
2831
2786
        except KeyError:
2832
2787
            raise errors.UnknownFormatError(format=format_string,
2833
2788
                                            kind="working tree")
2834
2789
 
2835
 
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2836
 
                   accelerator_tree=None, hardlink=False):
2837
 
        """Initialize a new working tree in a_bzrdir.
2838
 
 
2839
 
        :param a_bzrdir: BzrDir to initialize the working tree in.
2840
 
        :param revision_id: allows creating a working tree at a different
2841
 
            revision than the branch is at.
2842
 
        :param from_branch: Branch to checkout
2843
 
        :param accelerator_tree: A tree which can be used for retrieving file
2844
 
            contents more quickly than the revision tree, i.e. a workingtree.
2845
 
            The revision tree will be used for cases where accelerator_tree's
2846
 
            content is different.
2847
 
        :param hardlink: If true, hard-link files from accelerator_tree,
2848
 
            where possible.
2849
 
        """
2850
 
        raise NotImplementedError(self.initialize)
2851
 
 
2852
2790
    def __eq__(self, other):
2853
2791
        return self.__class__ is other.__class__
2854
2792
 
2856
2794
        return not (self == other)
2857
2795
 
2858
2796
    @classmethod
2859
 
    @symbol_versioning.deprecated_method(
2860
 
        symbol_versioning.deprecated_in((2, 4, 0)))
2861
2797
    def get_default_format(klass):
2862
2798
        """Return the current default format."""
2863
 
        return format_registry.get_default()
 
2799
        return klass._default_format
2864
2800
 
2865
2801
    def get_format_string(self):
2866
2802
        """Return the ASCII format string that identifies this format."""
2888
2824
        return False
2889
2825
 
2890
2826
    @classmethod
2891
 
    @symbol_versioning.deprecated_method(
2892
 
        symbol_versioning.deprecated_in((2, 4, 0)))
2893
2827
    def register_format(klass, format):
2894
 
        format_registry.register(format)
2895
 
 
2896
 
    @classmethod
2897
 
    @symbol_versioning.deprecated_method(
2898
 
        symbol_versioning.deprecated_in((2, 4, 0)))
2899
 
    def register_extra_format(klass, format):
2900
 
        format_registry.register_extra(format)
2901
 
 
2902
 
    @classmethod
2903
 
    @symbol_versioning.deprecated_method(
2904
 
        symbol_versioning.deprecated_in((2, 4, 0)))
2905
 
    def unregister_extra_format(klass, format):
2906
 
        format_registry.unregister_extra(format)
2907
 
 
2908
 
    @classmethod
2909
 
    @symbol_versioning.deprecated_method(
2910
 
        symbol_versioning.deprecated_in((2, 4, 0)))
2911
 
    def get_formats(klass):
2912
 
        return format_registry._get_all()
2913
 
 
2914
 
    @classmethod
2915
 
    @symbol_versioning.deprecated_method(
2916
 
        symbol_versioning.deprecated_in((2, 4, 0)))
 
2828
        klass._formats[format.get_format_string()] = format
 
2829
 
 
2830
    @classmethod
2917
2831
    def set_default_format(klass, format):
2918
 
        format_registry.set_default(format)
 
2832
        klass._default_format = format
2919
2833
 
2920
2834
    @classmethod
2921
 
    @symbol_versioning.deprecated_method(
2922
 
        symbol_versioning.deprecated_in((2, 4, 0)))
2923
2835
    def unregister_format(klass, format):
2924
 
        format_registry.remove(format)
2925
 
 
 
2836
        del klass._formats[format.get_format_string()]
 
2837
 
 
2838
 
 
2839
class WorkingTreeFormat2(WorkingTreeFormat):
 
2840
    """The second working tree format.
 
2841
 
 
2842
    This format modified the hash cache from the format 1 hash cache.
 
2843
    """
 
2844
 
 
2845
    upgrade_recommended = True
 
2846
 
 
2847
    def get_format_description(self):
 
2848
        """See WorkingTreeFormat.get_format_description()."""
 
2849
        return "Working tree format 2"
 
2850
 
 
2851
    def _stub_initialize_on_transport(self, transport, file_mode):
 
2852
        """Workaround: create control files for a remote working tree.
 
2853
 
 
2854
        This ensures that it can later be updated and dealt with locally,
 
2855
        since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
 
2856
        no working tree.  (See bug #43064).
 
2857
        """
 
2858
        sio = StringIO()
 
2859
        inv = inventory.Inventory()
 
2860
        xml5.serializer_v5.write_inventory(inv, sio, working=True)
 
2861
        sio.seek(0)
 
2862
        transport.put_file('inventory', sio, file_mode)
 
2863
        transport.put_bytes('pending-merges', '', file_mode)
 
2864
 
 
2865
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
 
2866
                   accelerator_tree=None, hardlink=False):
 
2867
        """See WorkingTreeFormat.initialize()."""
 
2868
        if not isinstance(a_bzrdir.transport, LocalTransport):
 
2869
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
 
2870
        if from_branch is not None:
 
2871
            branch = from_branch
 
2872
        else:
 
2873
            branch = a_bzrdir.open_branch()
 
2874
        if revision_id is None:
 
2875
            revision_id = _mod_revision.ensure_null(branch.last_revision())
 
2876
        branch.lock_write()
 
2877
        try:
 
2878
            branch.generate_revision_history(revision_id)
 
2879
        finally:
 
2880
            branch.unlock()
 
2881
        inv = inventory.Inventory()
 
2882
        wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
 
2883
                         branch,
 
2884
                         inv,
 
2885
                         _internal=True,
 
2886
                         _format=self,
 
2887
                         _bzrdir=a_bzrdir)
 
2888
        basis_tree = branch.repository.revision_tree(revision_id)
 
2889
        if basis_tree.inventory.root is not None:
 
2890
            wt.set_root_id(basis_tree.get_root_id())
 
2891
        # set the parent list and cache the basis tree.
 
2892
        if _mod_revision.is_null(revision_id):
 
2893
            parent_trees = []
 
2894
        else:
 
2895
            parent_trees = [(revision_id, basis_tree)]
 
2896
        wt.set_parent_trees(parent_trees)
 
2897
        transform.build_tree(basis_tree, wt)
 
2898
        return wt
 
2899
 
 
2900
    def __init__(self):
 
2901
        super(WorkingTreeFormat2, self).__init__()
 
2902
        self._matchingbzrdir = bzrdir.BzrDirFormat6()
 
2903
 
 
2904
    def open(self, a_bzrdir, _found=False):
 
2905
        """Return the WorkingTree object for a_bzrdir
 
2906
 
 
2907
        _found is a private parameter, do not use it. It is used to indicate
 
2908
               if format probing has already been done.
 
2909
        """
 
2910
        if not _found:
 
2911
            # we are being called directly and must probe.
 
2912
            raise NotImplementedError
 
2913
        if not isinstance(a_bzrdir.transport, LocalTransport):
 
2914
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
 
2915
        wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
 
2916
                           _internal=True,
 
2917
                           _format=self,
 
2918
                           _bzrdir=a_bzrdir)
 
2919
        return wt
2926
2920
 
2927
2921
class WorkingTreeFormat3(WorkingTreeFormat):
2928
2922
    """The second working tree format updated to record a format marker.
2938
2932
 
2939
2933
    upgrade_recommended = True
2940
2934
 
2941
 
    missing_parent_conflicts = True
2942
 
 
2943
2935
    def get_format_string(self):
2944
2936
        """See WorkingTreeFormat.get_format_string()."""
2945
2937
        return "Bazaar-NG Working Tree format 3"
3058
3050
 
3059
3051
 
3060
3052
__default_format = WorkingTreeFormat6()
3061
 
format_registry.register_lazy("Bazaar Working Tree Format 4 (bzr 0.15)\n",
3062
 
    "bzrlib.workingtree_4", "WorkingTreeFormat4")
3063
 
format_registry.register_lazy("Bazaar Working Tree Format 5 (bzr 1.11)\n",
3064
 
    "bzrlib.workingtree_4", "WorkingTreeFormat5")
3065
 
format_registry.register_lazy("Bazaar Working Tree Format 6 (bzr 1.14)\n",
3066
 
    "bzrlib.workingtree_4", "WorkingTreeFormat6")
3067
 
format_registry.register(WorkingTreeFormat3())
3068
 
format_registry.set_default(__default_format)
 
3053
WorkingTreeFormat.register_format(__default_format)
 
3054
WorkingTreeFormat.register_format(WorkingTreeFormat5())
 
3055
WorkingTreeFormat.register_format(WorkingTreeFormat4())
 
3056
WorkingTreeFormat.register_format(WorkingTreeFormat3())
 
3057
WorkingTreeFormat.set_default_format(__default_format)
 
3058
# formats which have no format string are not discoverable
 
3059
# and not independently creatable, so are not registered.
 
3060
_legacy_formats = [WorkingTreeFormat2(),
 
3061
                   ]