/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: Martin Pool
  • Date: 2011-04-14 07:53:38 UTC
  • mto: This revision was merged to the branch mainline in revision 5788.
  • Revision ID: mbp@sourcefrog.net-20110414075338-0cwknb7zokfouzwj
Stop using failIf, failUnless, etc

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005-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
44
44
import stat
45
45
import re
46
46
 
47
 
import bzrlib
48
47
from bzrlib import (
49
48
    branch,
50
49
    bzrdir,
51
50
    conflicts as _mod_conflicts,
 
51
    controldir,
52
52
    errors,
 
53
    filters as _mod_filters,
53
54
    generate_ids,
54
55
    globbing,
55
56
    graph as _mod_graph,
59
60
    merge,
60
61
    revision as _mod_revision,
61
62
    revisiontree,
62
 
    trace,
 
63
    rio as _mod_rio,
63
64
    transform,
 
65
    transport,
64
66
    ui,
65
67
    views,
66
68
    xml5,
67
69
    xml7,
68
70
    )
69
 
import bzrlib.branch
70
 
from bzrlib.transport import get_transport
71
71
from bzrlib.workingtree_4 import (
72
72
    WorkingTreeFormat4,
73
73
    WorkingTreeFormat5,
77
77
 
78
78
from bzrlib import symbol_versioning
79
79
from bzrlib.decorators import needs_read_lock, needs_write_lock
 
80
from bzrlib.lock import LogicalLockResult
80
81
from bzrlib.lockable_files import LockableFiles
81
82
from bzrlib.lockdir import LockDir
82
83
import bzrlib.mutabletree
92
93
    splitpath,
93
94
    supports_executable,
94
95
    )
95
 
from bzrlib.filters import filtered_input_file
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
100
99
from bzrlib.symbol_versioning import (
101
100
    deprecated_passed,
102
101
    DEPRECATED_PARAMETER,
167
166
        return ''
168
167
 
169
168
 
170
 
class WorkingTree(bzrlib.mutabletree.MutableTree,
171
 
    bzrdir.ControlComponent):
 
169
class WorkingTree(bzrlib.mutabletree.MutableInventoryTree,
 
170
    controldir.ControlComponent):
172
171
    """Working copy tree.
173
172
 
174
173
    The inventory is held in the `Branch` working-inventory, and the
176
175
 
177
176
    It is possible for a `WorkingTree` to have a filename which is
178
177
    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).
179
181
    """
180
182
 
181
183
    # override this to set the strategy for storing views
205
207
        else:
206
208
            self._branch = self.bzrdir.open_branch()
207
209
        self.basedir = realpath(basedir)
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
 
210
        self._control_files = _control_files
215
211
        self._transport = self._control_files._transport
216
212
        # update the whole cache up front and write to disk if anything changed;
217
213
        # in the future we might want to do this more selectively
255
251
    def control_transport(self):
256
252
        return self._transport
257
253
 
 
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
 
258
266
    def _detect_case_handling(self):
259
267
        wt_trans = self.bzrdir.get_workingtree_transport(None)
260
268
        try:
261
 
            wt_trans.stat("FoRMaT")
 
269
            wt_trans.stat(self._format.case_sensitive_filename)
262
270
        except errors.NoSuchFile:
263
271
            self.case_sensitive = True
264
272
        else:
346
354
        if path is None:
347
355
            path = osutils.getcwd()
348
356
        control, relpath = bzrdir.BzrDir.open_containing(path)
349
 
 
350
357
        return control.open_workingtree(), relpath
351
358
 
352
359
    @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
353
426
    def open_downlevel(path=None):
354
427
        """Open an unsupported working tree.
355
428
 
368
441
                return True, None
369
442
            else:
370
443
                return True, tree
371
 
        transport = get_transport(location)
372
 
        iterator = bzrdir.BzrDir.find_bzrdirs(transport, evaluate=evaluate,
 
444
        t = transport.get_transport(location)
 
445
        iterator = bzrdir.BzrDir.find_bzrdirs(t, evaluate=evaluate,
373
446
                                              list_current=list_current)
374
 
        return [t for t in iterator if t is not None]
 
447
        return [tr for tr in iterator if tr is not None]
375
448
 
376
449
    # should be deprecated - this is slow and in any case treating them as a
377
450
    # container is (we now know) bad style -- mbp 20070302
450
523
        return self.get_file_with_stat(file_id, path, filtered=filtered)[0]
451
524
 
452
525
    def get_file_with_stat(self, file_id, path=None, filtered=True,
453
 
        _fstat=os.fstat):
 
526
                           _fstat=osutils.fstat):
454
527
        """See Tree.get_file_with_stat."""
455
528
        if path is None:
456
529
            path = self.id2path(file_id)
458
531
        stat_value = _fstat(file_obj.fileno())
459
532
        if filtered and self.supports_content_filtering():
460
533
            filters = self._content_filter_stack(path)
461
 
            file_obj = filtered_input_file(file_obj, filters)
 
534
            file_obj = _mod_filters.filtered_input_file(file_obj, filters)
462
535
        return (file_obj, stat_value)
463
536
 
464
537
    def get_file_text(self, file_id, path=None, filtered=True):
465
 
        return self.get_file(file_id, path=path, filtered=filtered).read()
 
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()
466
543
 
467
544
    def get_file_byname(self, filename, filtered=True):
468
545
        path = self.abspath(filename)
469
546
        f = file(path, 'rb')
470
547
        if filtered and self.supports_content_filtering():
471
548
            filters = self._content_filter_stack(filename)
472
 
            return filtered_input_file(f, filters)
 
549
            return _mod_filters.filtered_input_file(f, filters)
473
550
        else:
474
551
            return f
475
552
 
522
599
 
523
600
        # Now we have the parents of this content
524
601
        annotator = self.branch.repository.texts.get_annotator()
525
 
        text = self.get_file(file_id).read()
 
602
        text = self.get_file_text(file_id)
526
603
        this_key =(file_id, default_revision)
527
604
        annotator.add_special_text(this_key, file_parent_keys, text)
528
605
        annotations = [(key[-1], line)
562
639
        """Return the id of this trees root"""
563
640
        return self._inventory.root.file_id
564
641
 
565
 
    def _get_store_filename(self, file_id):
566
 
        ## XXX: badly named; this is not in the store at all
567
 
        return self.abspath(self.id2path(file_id))
568
 
 
569
642
    @needs_read_lock
570
643
    def clone(self, to_bzrdir, revision_id=None):
571
644
        """Duplicate this working tree into to_bzr, including all state.
811
884
            if revision_id in heads and revision_id not in new_revision_ids:
812
885
                new_revision_ids.append(revision_id)
813
886
        if new_revision_ids != revision_ids:
814
 
            trace.mutter('requested to set revision_ids = %s,'
 
887
            mutter('requested to set revision_ids = %s,'
815
888
                         ' but filtered to %s', revision_ids, new_revision_ids)
816
889
        return new_revision_ids
817
890
 
883
956
    def set_merge_modified(self, modified_hashes):
884
957
        def iter_stanzas():
885
958
            for file_id, hash in modified_hashes.iteritems():
886
 
                yield Stanza(file_id=file_id.decode('utf8'), hash=hash)
 
959
                yield _mod_rio.Stanza(file_id=file_id.decode('utf8'),
 
960
                    hash=hash)
887
961
        self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
888
962
 
889
963
    def _sha_from_stat(self, path, stat_result):
898
972
 
899
973
    def _put_rio(self, filename, stanzas, header):
900
974
        self._must_be_locked()
901
 
        my_file = rio_file(stanzas, header)
 
975
        my_file = _mod_rio.rio_file(stanzas, header)
902
976
        self._transport.put_file(filename, my_file,
903
977
            mode=self.bzrdir._get_file_mode())
904
978
 
968
1042
                    raise errors.MergeModifiedFormatError()
969
1043
            except StopIteration:
970
1044
                raise errors.MergeModifiedFormatError()
971
 
            for s in RioReader(hashfile):
 
1045
            for s in _mod_rio.RioReader(hashfile):
972
1046
                # RioReader reads in Unicode, so convert file_ids back to utf8
973
1047
                file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
974
1048
                if file_id not in self.inventory:
1202
1276
                # absolute path
1203
1277
                fap = from_dir_abspath + '/' + f
1204
1278
 
1205
 
                f_ie = inv.get_child(from_dir_id, f)
 
1279
                dir_ie = inv[from_dir_id]
 
1280
                if dir_ie.kind == 'directory':
 
1281
                    f_ie = dir_ie.children.get(f)
 
1282
                else:
 
1283
                    f_ie = None
1206
1284
                if f_ie:
1207
1285
                    c = 'V'
1208
1286
                elif self.is_ignored(fp[1:]):
1209
1287
                    c = 'I'
1210
1288
                else:
1211
 
                    # we may not have found this file, because of a unicode issue
 
1289
                    # we may not have found this file, because of a unicode
 
1290
                    # issue, or because the directory was actually a symlink.
1212
1291
                    f_norm, can_access = osutils.normalized_filename(f)
1213
1292
                    if f == f_norm or not can_access:
1214
1293
                        # No change, so treat this file normally
1257
1336
                stack.pop()
1258
1337
 
1259
1338
    @needs_tree_write_lock
1260
 
    def move(self, from_paths, to_dir=None, after=False, **kwargs):
 
1339
    def move(self, from_paths, to_dir=None, after=False):
1261
1340
        """Rename files.
1262
1341
 
1263
1342
        to_dir must exist in the inventory.
1297
1376
 
1298
1377
        # check for deprecated use of signature
1299
1378
        if to_dir is None:
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
 
 
 
1379
            raise TypeError('You must supply a target directory')
1308
1380
        # check destination directory
1309
1381
        if isinstance(from_paths, basestring):
1310
1382
            raise ValueError()
1319
1391
        to_dir_id = inv.path2id(to_dir)
1320
1392
        if to_dir_id is None:
1321
1393
            raise errors.BzrMoveFailedError('',to_dir,
1322
 
                errors.NotVersionedError(path=str(to_dir)))
 
1394
                errors.NotVersionedError(path=to_dir))
1323
1395
 
1324
1396
        to_dir_ie = inv[to_dir_id]
1325
1397
        if to_dir_ie.kind != 'directory':
1332
1404
            from_id = inv.path2id(from_rel)
1333
1405
            if from_id is None:
1334
1406
                raise errors.BzrMoveFailedError(from_rel,to_dir,
1335
 
                    errors.NotVersionedError(path=str(from_rel)))
 
1407
                    errors.NotVersionedError(path=from_rel))
1336
1408
 
1337
1409
            from_entry = inv[from_id]
1338
1410
            from_parent_id = from_entry.parent_id
1380
1452
            # check the inventory for source and destination
1381
1453
            if from_id is None:
1382
1454
                raise errors.BzrMoveFailedError(from_rel,to_rel,
1383
 
                    errors.NotVersionedError(path=str(from_rel)))
 
1455
                    errors.NotVersionedError(path=from_rel))
1384
1456
            if to_id is not None:
1385
1457
                raise errors.BzrMoveFailedError(from_rel,to_rel,
1386
 
                    errors.AlreadyVersionedError(path=str(to_rel)))
 
1458
                    errors.AlreadyVersionedError(path=to_rel))
1387
1459
 
1388
1460
            # try to determine the mode for rename (only change inv or change
1389
1461
            # inv and file system)
1390
1462
            if after:
1391
1463
                if not self.has_filename(to_rel):
1392
1464
                    raise errors.BzrMoveFailedError(from_id,to_rel,
1393
 
                        errors.NoSuchFile(path=str(to_rel),
 
1465
                        errors.NoSuchFile(path=to_rel,
1394
1466
                        extra="New file has not been created yet"))
1395
1467
                only_change_inv = True
1396
1468
            elif not self.has_filename(from_rel) and self.has_filename(to_rel):
1498
1570
            from_id = basis_tree.path2id(from_rel)
1499
1571
            if from_id is None:
1500
1572
                raise errors.BzrRenameFailedError(from_rel,to_rel,
1501
 
                    errors.NotVersionedError(path=str(from_rel)))
 
1573
                    errors.NotVersionedError(path=from_rel))
1502
1574
            # put entry back in the inventory so we can rename it
1503
1575
            from_entry = basis_tree.inventory[from_id].copy()
1504
1576
            inv.add(from_entry)
1522
1594
        # versioned
1523
1595
        if to_dir_id is None:
1524
1596
            raise errors.BzrMoveFailedError(from_rel,to_rel,
1525
 
                errors.NotVersionedError(path=str(to_dir)))
 
1597
                errors.NotVersionedError(path=to_dir))
1526
1598
 
1527
1599
        # all checks done. now we can continue with our actual work
1528
1600
        mutter('rename_one:\n'
1587
1659
            # - RBC 20060907
1588
1660
            self._write_inventory(self._inventory)
1589
1661
 
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
 
 
1601
1662
    @needs_write_lock
1602
1663
    def pull(self, source, overwrite=False, stop_revision=None,
1603
 
             change_reporter=None, possible_transports=None, local=False):
 
1664
             change_reporter=None, possible_transports=None, local=False,
 
1665
             show_base=False):
1604
1666
        source.lock_read()
1605
1667
        try:
1606
1668
            old_revision_info = self.branch.last_revision_info()
1620
1682
                                basis_tree,
1621
1683
                                this_tree=self,
1622
1684
                                pb=None,
1623
 
                                change_reporter=change_reporter)
 
1685
                                change_reporter=change_reporter,
 
1686
                                show_base=show_base)
1624
1687
                    basis_root_id = basis_tree.get_root_id()
1625
1688
                    new_root_id = new_basis_tree.get_root_id()
1626
1689
                    if basis_root_id != new_root_id:
1798
1861
            raise errors.ObjectNotLocked(self)
1799
1862
 
1800
1863
    def lock_read(self):
1801
 
        """See Branch.lock_read, and WorkingTree.unlock."""
 
1864
        """Lock the tree for reading.
 
1865
 
 
1866
        This also locks the branch, and can be unlocked via self.unlock().
 
1867
 
 
1868
        :return: A bzrlib.lock.LogicalLockResult.
 
1869
        """
1802
1870
        if not self.is_locked():
1803
1871
            self._reset_data()
1804
1872
        self.branch.lock_read()
1805
1873
        try:
1806
 
            return self._control_files.lock_read()
 
1874
            self._control_files.lock_read()
 
1875
            return LogicalLockResult(self.unlock)
1807
1876
        except:
1808
1877
            self.branch.unlock()
1809
1878
            raise
1810
1879
 
1811
1880
    def lock_tree_write(self):
1812
 
        """See MutableTree.lock_tree_write, and WorkingTree.unlock."""
 
1881
        """See MutableTree.lock_tree_write, and WorkingTree.unlock.
 
1882
 
 
1883
        :return: A bzrlib.lock.LogicalLockResult.
 
1884
        """
1813
1885
        if not self.is_locked():
1814
1886
            self._reset_data()
1815
1887
        self.branch.lock_read()
1816
1888
        try:
1817
 
            return self._control_files.lock_write()
 
1889
            self._control_files.lock_write()
 
1890
            return LogicalLockResult(self.unlock)
1818
1891
        except:
1819
1892
            self.branch.unlock()
1820
1893
            raise
1821
1894
 
1822
1895
    def lock_write(self):
1823
 
        """See MutableTree.lock_write, and WorkingTree.unlock."""
 
1896
        """See MutableTree.lock_write, and WorkingTree.unlock.
 
1897
 
 
1898
        :return: A bzrlib.lock.LogicalLockResult.
 
1899
        """
1824
1900
        if not self.is_locked():
1825
1901
            self._reset_data()
1826
1902
        self.branch.lock_write()
1827
1903
        try:
1828
 
            return self._control_files.lock_write()
 
1904
            self._control_files.lock_write()
 
1905
            return LogicalLockResult(self.unlock)
1829
1906
        except:
1830
1907
            self.branch.unlock()
1831
1908
            raise
1948
2025
 
1949
2026
        inv_delta = []
1950
2027
 
1951
 
        new_files=set()
 
2028
        all_files = set() # specified and nested files 
1952
2029
        unknown_nested_files=set()
1953
2030
        if to_file is None:
1954
2031
            to_file = sys.stdout
1955
2032
 
 
2033
        files_to_backup = []
 
2034
 
1956
2035
        def recurse_directory_to_add_files(directory):
1957
2036
            # Recurse directory and add all files
1958
2037
            # so we can check if they have changed.
1959
 
            for parent_info, file_infos in\
1960
 
                self.walkdirs(directory):
 
2038
            for parent_info, file_infos in self.walkdirs(directory):
1961
2039
                for relpath, basename, kind, lstat, fileid, kind in file_infos:
1962
2040
                    # Is it versioned or ignored?
1963
 
                    if self.path2id(relpath) or self.is_ignored(relpath):
 
2041
                    if self.path2id(relpath):
1964
2042
                        # Add nested content for deletion.
1965
 
                        new_files.add(relpath)
 
2043
                        all_files.add(relpath)
1966
2044
                    else:
1967
 
                        # Files which are not versioned and not ignored
 
2045
                        # Files which are not versioned
1968
2046
                        # should be treated as unknown.
1969
 
                        unknown_nested_files.add((relpath, None, kind))
 
2047
                        files_to_backup.append(relpath)
1970
2048
 
1971
2049
        for filename in files:
1972
2050
            # Get file name into canonical form.
1973
2051
            abspath = self.abspath(filename)
1974
2052
            filename = self.relpath(abspath)
1975
2053
            if len(filename) > 0:
1976
 
                new_files.add(filename)
 
2054
                all_files.add(filename)
1977
2055
                recurse_directory_to_add_files(filename)
1978
2056
 
1979
 
        files = list(new_files)
 
2057
        files = list(all_files)
1980
2058
 
1981
2059
        if len(files) == 0:
1982
2060
            return # nothing to do
1986
2064
 
1987
2065
        # Bail out if we are going to delete files we shouldn't
1988
2066
        if not keep_files and not force:
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
 
2067
            for (file_id, path, content_change, versioned, parent_id, name,
 
2068
                 kind, executable) in self.iter_changes(self.basis_tree(),
 
2069
                     include_unchanged=True, require_versioned=False,
 
2070
                     want_unversioned=True, specific_files=files):
 
2071
                if versioned[0] == False:
 
2072
                    # The record is unknown or newly added
 
2073
                    files_to_backup.append(path[1])
 
2074
                elif (content_change and (kind[1] is not None) and
 
2075
                        osutils.is_inside_any(files, path[1])):
 
2076
                    # Versioned and changed, but not deleted, and still
 
2077
                    # in one of the dirs to be deleted.
 
2078
                    files_to_backup.append(path[1])
2005
2079
 
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)
 
2080
        def backup(file_to_backup):
 
2081
            backup_name = self.bzrdir._available_backup_name(file_to_backup)
 
2082
            osutils.rename(abs_path, self.abspath(backup_name))
 
2083
            return "removed %s (but kept a copy: %s)" % (file_to_backup,
 
2084
                                                         backup_name)
2015
2085
 
2016
2086
        # Build inv_delta and delete files where applicable,
2017
2087
        # do this before any modifications to inventory.
2041
2111
                        len(os.listdir(abs_path)) > 0):
2042
2112
                        if force:
2043
2113
                            osutils.rmtree(abs_path)
 
2114
                            message = "deleted %s" % (f,)
2044
2115
                        else:
2045
 
                            message = "%s is not an empty directory "\
2046
 
                                "and won't be deleted." % (f,)
 
2116
                            message = backup(f)
2047
2117
                    else:
2048
 
                        osutils.delete_any(abs_path)
2049
 
                        message = "deleted %s" % (f,)
 
2118
                        if f in files_to_backup:
 
2119
                            message = backup(f)
 
2120
                        else:
 
2121
                            osutils.delete_any(abs_path)
 
2122
                            message = "deleted %s" % (f,)
2050
2123
                elif message is not None:
2051
2124
                    # Only care if we haven't done anything yet.
2052
2125
                    message = "%s does not exist." % (f,)
2189
2262
    _marker = object()
2190
2263
 
2191
2264
    def update(self, change_reporter=None, possible_transports=None,
2192
 
               revision=None, old_tip=_marker):
 
2265
               revision=None, old_tip=_marker, show_base=False):
2193
2266
        """Update a working tree along its branch.
2194
2267
 
2195
2268
        This will update the branch if its bound too, which means we have
2232
2305
            else:
2233
2306
                if old_tip is self._marker:
2234
2307
                    old_tip = None
2235
 
            return self._update_tree(old_tip, change_reporter, revision)
 
2308
            return self._update_tree(old_tip, change_reporter, revision, show_base)
2236
2309
        finally:
2237
2310
            self.unlock()
2238
2311
 
2239
2312
    @needs_tree_write_lock
2240
 
    def _update_tree(self, old_tip=None, change_reporter=None, revision=None):
 
2313
    def _update_tree(self, old_tip=None, change_reporter=None, revision=None,
 
2314
                     show_base=False):
2241
2315
        """Update a tree to the master branch.
2242
2316
 
2243
2317
        :param old_tip: if supplied, the previous tip revision the branch,
2270
2344
            other_tree = self.branch.repository.revision_tree(old_tip)
2271
2345
            nb_conflicts = merge.merge_inner(self.branch, other_tree,
2272
2346
                                             base_tree, this_tree=self,
2273
 
                                             change_reporter=change_reporter)
 
2347
                                             change_reporter=change_reporter,
 
2348
                                             show_base=show_base)
2274
2349
            if nb_conflicts:
2275
2350
                self.add_parent_tree((old_tip, other_tree))
2276
 
                trace.note('Rerun update after fixing the conflicts.')
 
2351
                note('Rerun update after fixing the conflicts.')
2277
2352
                return nb_conflicts
2278
2353
 
2279
2354
        if last_rev != _mod_revision.ensure_null(revision):
2300
2375
 
2301
2376
            nb_conflicts = merge.merge_inner(self.branch, to_tree, base_tree,
2302
2377
                                             this_tree=self,
2303
 
                                             change_reporter=change_reporter)
 
2378
                                             change_reporter=change_reporter,
 
2379
                                             show_base=show_base)
2304
2380
            self.set_last_revision(revision)
2305
2381
            # TODO - dedup parents list with things merged by pull ?
2306
2382
            # reuse the tree we've updated to to set the basis:
2347
2423
    def add_conflicts(self, arg):
2348
2424
        raise errors.UnsupportedOperation(self.add_conflicts, self)
2349
2425
 
2350
 
    @needs_read_lock
2351
2426
    def conflicts(self):
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
 
2427
        raise NotImplementedError(self.conflicts)
2375
2428
 
2376
2429
    def walkdirs(self, prefix=""):
2377
2430
        """Walk the directories of this tree.
2595
2648
        """
2596
2649
        return
2597
2650
 
 
2651
    @needs_read_lock
 
2652
    def check_state(self):
 
2653
        """Check that the working state is/isn't valid."""
 
2654
        check_refs = self._get_check_refs()
 
2655
        refs = {}
 
2656
        for ref in check_refs:
 
2657
            kind, value = ref
 
2658
            if kind == 'trees':
 
2659
                refs[ref] = self.branch.repository.revision_tree(value)
 
2660
        self._check(refs)
 
2661
 
 
2662
    @needs_tree_write_lock
 
2663
    def reset_state(self, revision_ids=None):
 
2664
        """Reset the state of the working tree.
 
2665
 
 
2666
        This does a hard-reset to a last-known-good state. This is a way to
 
2667
        fix if something got corrupted (like the .bzr/checkout/dirstate file)
 
2668
        """
 
2669
        if revision_ids is None:
 
2670
            revision_ids = self.get_parent_ids()
 
2671
        if not revision_ids:
 
2672
            rt = self.branch.repository.revision_tree(
 
2673
                _mod_revision.NULL_REVISION)
 
2674
        else:
 
2675
            rt = self.branch.repository.revision_tree(revision_ids[0])
 
2676
        self._write_inventory(rt.inventory)
 
2677
        self.set_parent_ids(revision_ids)
 
2678
 
2598
2679
    def _get_rules_searcher(self, default_searcher):
2599
2680
        """See Tree._get_rules_searcher."""
2600
2681
        if self._rules_searcher is None:
2608
2689
        return ShelfManager(self, self._transport)
2609
2690
 
2610
2691
 
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
 
 
2665
2692
class WorkingTree3(WorkingTree):
2666
2693
    """This is the Format 3 working tree.
2667
2694
 
2721
2748
                    raise errors.ConflictFormatError()
2722
2749
            except StopIteration:
2723
2750
                raise errors.ConflictFormatError()
2724
 
            return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
 
2751
            reader = _mod_rio.RioReader(confile)
 
2752
            return _mod_conflicts.ConflictList.from_stanzas(reader)
2725
2753
        finally:
2726
2754
            confile.close()
2727
2755
 
2740
2768
            self.branch.unlock()
2741
2769
 
2742
2770
 
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):
 
2771
class WorkingTreeFormatRegistry(controldir.ControlComponentFormatRegistry):
 
2772
    """Registry for working tree formats."""
 
2773
 
 
2774
    def __init__(self, other_registry=None):
 
2775
        super(WorkingTreeFormatRegistry, self).__init__(other_registry)
 
2776
        self._default_format = None
 
2777
 
 
2778
    def get_default(self):
 
2779
        """Return the current default format."""
 
2780
        return self._default_format
 
2781
 
 
2782
    def set_default(self, format):
 
2783
        self._default_format = format
 
2784
 
 
2785
 
 
2786
format_registry = WorkingTreeFormatRegistry()
 
2787
 
 
2788
 
 
2789
class WorkingTreeFormat(controldir.ControlComponentFormat):
2750
2790
    """An encapsulation of the initialization and open routines for a format.
2751
2791
 
2752
2792
    Formats provide three things:
2764
2804
    object will be created every time regardless.
2765
2805
    """
2766
2806
 
2767
 
    _default_format = None
2768
 
    """The default format used for new trees."""
2769
 
 
2770
 
    _formats = {}
2771
 
    """The known formats."""
2772
 
 
2773
2807
    requires_rich_root = False
2774
2808
 
2775
2809
    upgrade_recommended = False
2776
2810
 
 
2811
    requires_normalized_unicode_filenames = False
 
2812
 
 
2813
    case_sensitive_filename = "FoRMaT"
 
2814
 
 
2815
    missing_parent_conflicts = False
 
2816
    """If this format supports missing parent conflicts."""
 
2817
 
2777
2818
    @classmethod
2778
2819
    def find_format(klass, a_bzrdir):
2779
2820
        """Return the format for the working tree object in a_bzrdir."""
2780
2821
        try:
2781
2822
            transport = a_bzrdir.get_workingtree_transport(None)
2782
2823
            format_string = transport.get_bytes("format")
2783
 
            return klass._formats[format_string]
 
2824
            return format_registry.get(format_string)
2784
2825
        except errors.NoSuchFile:
2785
2826
            raise errors.NoWorkingTree(base=transport.base)
2786
2827
        except KeyError:
2787
2828
            raise errors.UnknownFormatError(format=format_string,
2788
2829
                                            kind="working tree")
2789
2830
 
 
2831
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
 
2832
                   accelerator_tree=None, hardlink=False):
 
2833
        """Initialize a new working tree in a_bzrdir.
 
2834
 
 
2835
        :param a_bzrdir: BzrDir to initialize the working tree in.
 
2836
        :param revision_id: allows creating a working tree at a different
 
2837
            revision than the branch is at.
 
2838
        :param from_branch: Branch to checkout
 
2839
        :param accelerator_tree: A tree which can be used for retrieving file
 
2840
            contents more quickly than the revision tree, i.e. a workingtree.
 
2841
            The revision tree will be used for cases where accelerator_tree's
 
2842
            content is different.
 
2843
        :param hardlink: If true, hard-link files from accelerator_tree,
 
2844
            where possible.
 
2845
        """
 
2846
        raise NotImplementedError(self.initialize)
 
2847
 
2790
2848
    def __eq__(self, other):
2791
2849
        return self.__class__ is other.__class__
2792
2850
 
2794
2852
        return not (self == other)
2795
2853
 
2796
2854
    @classmethod
 
2855
    @symbol_versioning.deprecated_method(
 
2856
        symbol_versioning.deprecated_in((2, 4, 0)))
2797
2857
    def get_default_format(klass):
2798
2858
        """Return the current default format."""
2799
 
        return klass._default_format
 
2859
        return format_registry.get_default()
2800
2860
 
2801
2861
    def get_format_string(self):
2802
2862
        """Return the ASCII format string that identifies this format."""
2824
2884
        return False
2825
2885
 
2826
2886
    @classmethod
 
2887
    @symbol_versioning.deprecated_method(
 
2888
        symbol_versioning.deprecated_in((2, 4, 0)))
2827
2889
    def register_format(klass, format):
2828
 
        klass._formats[format.get_format_string()] = format
2829
 
 
2830
 
    @classmethod
 
2890
        format_registry.register(format)
 
2891
 
 
2892
    @classmethod
 
2893
    @symbol_versioning.deprecated_method(
 
2894
        symbol_versioning.deprecated_in((2, 4, 0)))
 
2895
    def register_extra_format(klass, format):
 
2896
        format_registry.register_extra(format)
 
2897
 
 
2898
    @classmethod
 
2899
    @symbol_versioning.deprecated_method(
 
2900
        symbol_versioning.deprecated_in((2, 4, 0)))
 
2901
    def unregister_extra_format(klass, format):
 
2902
        format_registry.unregister_extra(format)
 
2903
 
 
2904
    @classmethod
 
2905
    @symbol_versioning.deprecated_method(
 
2906
        symbol_versioning.deprecated_in((2, 4, 0)))
 
2907
    def get_formats(klass):
 
2908
        return format_registry._get_all()
 
2909
 
 
2910
    @classmethod
 
2911
    @symbol_versioning.deprecated_method(
 
2912
        symbol_versioning.deprecated_in((2, 4, 0)))
2831
2913
    def set_default_format(klass, format):
2832
 
        klass._default_format = format
 
2914
        format_registry.set_default(format)
2833
2915
 
2834
2916
    @classmethod
 
2917
    @symbol_versioning.deprecated_method(
 
2918
        symbol_versioning.deprecated_in((2, 4, 0)))
2835
2919
    def unregister_format(klass, format):
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
 
2920
        format_registry.remove(format)
 
2921
 
2920
2922
 
2921
2923
class WorkingTreeFormat3(WorkingTreeFormat):
2922
2924
    """The second working tree format updated to record a format marker.
2932
2934
 
2933
2935
    upgrade_recommended = True
2934
2936
 
 
2937
    missing_parent_conflicts = True
 
2938
 
2935
2939
    def get_format_string(self):
2936
2940
        """See WorkingTreeFormat.get_format_string()."""
2937
2941
        return "Bazaar-NG Working Tree format 3"
3050
3054
 
3051
3055
 
3052
3056
__default_format = WorkingTreeFormat6()
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
 
                   ]
 
3057
format_registry.register_lazy("Bazaar Working Tree Format 4 (bzr 0.15)\n",
 
3058
    "bzrlib.workingtree_4", "WorkingTreeFormat4")
 
3059
format_registry.register_lazy("Bazaar Working Tree Format 5 (bzr 1.11)\n",
 
3060
    "bzrlib.workingtree_4", "WorkingTreeFormat5")
 
3061
format_registry.register_lazy("Bazaar Working Tree Format 6 (bzr 1.14)\n",
 
3062
    "bzrlib.workingtree_4", "WorkingTreeFormat6")
 
3063
format_registry.register(WorkingTreeFormat3())
 
3064
format_registry.set_default(__default_format)