/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

Merged unnecessary-test-applicable into weave-fmt-plugin.

Show diffs side-by-side

added added

removed removed

Lines of Context:
49
49
    branch,
50
50
    bzrdir,
51
51
    conflicts as _mod_conflicts,
 
52
    controldir,
52
53
    errors,
53
54
    generate_ids,
54
55
    globbing,
61
62
    revisiontree,
62
63
    trace,
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
168
169
 
169
170
 
170
171
class WorkingTree(bzrlib.mutabletree.MutableTree,
171
 
    bzrdir.ControlComponent):
 
172
    controldir.ControlComponent):
172
173
    """Working copy tree.
173
174
 
174
175
    The inventory is held in the `Branch` working-inventory, and the
176
177
 
177
178
    It is possible for a `WorkingTree` to have a filename which is
178
179
    not listed in the Inventory and vice versa.
 
180
 
 
181
    :ivar basedir: The root of the tree on disk. This is a unicode path object
 
182
        (as opposed to a URL).
179
183
    """
180
184
 
181
185
    # override this to set the strategy for storing views
205
209
        else:
206
210
            self._branch = self.bzrdir.open_branch()
207
211
        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
 
212
        self._control_files = _control_files
215
213
        self._transport = self._control_files._transport
216
214
        # update the whole cache up front and write to disk if anything changed;
217
215
        # in the future we might want to do this more selectively
346
344
        if path is None:
347
345
            path = osutils.getcwd()
348
346
        control, relpath = bzrdir.BzrDir.open_containing(path)
349
 
 
350
347
        return control.open_workingtree(), relpath
351
348
 
352
349
    @staticmethod
 
350
    def open_containing_paths(file_list, default_directory=None,
 
351
                              canonicalize=True, apply_view=True):
 
352
        """Open the WorkingTree that contains a set of paths.
 
353
 
 
354
        Fail if the paths given are not all in a single tree.
 
355
 
 
356
        This is used for the many command-line interfaces that take a list of
 
357
        any number of files and that require they all be in the same tree.
 
358
        """
 
359
        if default_directory is None:
 
360
            default_directory = u'.'
 
361
        # recommended replacement for builtins.internal_tree_files
 
362
        if file_list is None or len(file_list) == 0:
 
363
            tree = WorkingTree.open_containing(default_directory)[0]
 
364
            # XXX: doesn't really belong here, and seems to have the strange
 
365
            # side effect of making it return a bunch of files, not the whole
 
366
            # tree -- mbp 20100716
 
367
            if tree.supports_views() and apply_view:
 
368
                view_files = tree.views.lookup_view()
 
369
                if view_files:
 
370
                    file_list = view_files
 
371
                    view_str = views.view_display_str(view_files)
 
372
                    note("Ignoring files outside view. View is %s" % view_str)
 
373
            return tree, file_list
 
374
        if default_directory == u'.':
 
375
            seed = file_list[0]
 
376
        else:
 
377
            seed = default_directory
 
378
            file_list = [osutils.pathjoin(default_directory, f)
 
379
                         for f in file_list]
 
380
        tree = WorkingTree.open_containing(seed)[0]
 
381
        return tree, tree.safe_relpath_files(file_list, canonicalize,
 
382
                                             apply_view=apply_view)
 
383
 
 
384
    def safe_relpath_files(self, file_list, canonicalize=True, apply_view=True):
 
385
        """Convert file_list into a list of relpaths in tree.
 
386
 
 
387
        :param self: A tree to operate on.
 
388
        :param file_list: A list of user provided paths or None.
 
389
        :param apply_view: if True and a view is set, apply it or check that
 
390
            specified files are within it
 
391
        :return: A list of relative paths.
 
392
        :raises errors.PathNotChild: When a provided path is in a different self
 
393
            than self.
 
394
        """
 
395
        if file_list is None:
 
396
            return None
 
397
        if self.supports_views() and apply_view:
 
398
            view_files = self.views.lookup_view()
 
399
        else:
 
400
            view_files = []
 
401
        new_list = []
 
402
        # self.relpath exists as a "thunk" to osutils, but canonical_relpath
 
403
        # doesn't - fix that up here before we enter the loop.
 
404
        if canonicalize:
 
405
            fixer = lambda p: osutils.canonical_relpath(self.basedir, p)
 
406
        else:
 
407
            fixer = self.relpath
 
408
        for filename in file_list:
 
409
            relpath = fixer(osutils.dereference_path(filename))
 
410
            if view_files and not osutils.is_inside_any(view_files, relpath):
 
411
                raise errors.FileOutsideView(filename, view_files)
 
412
            new_list.append(relpath)
 
413
        return new_list
 
414
 
 
415
    @staticmethod
353
416
    def open_downlevel(path=None):
354
417
        """Open an unsupported working tree.
355
418
 
368
431
                return True, None
369
432
            else:
370
433
                return True, tree
371
 
        transport = get_transport(location)
372
 
        iterator = bzrdir.BzrDir.find_bzrdirs(transport, evaluate=evaluate,
 
434
        t = transport.get_transport(location)
 
435
        iterator = bzrdir.BzrDir.find_bzrdirs(t, evaluate=evaluate,
373
436
                                              list_current=list_current)
374
 
        return [t for t in iterator if t is not None]
 
437
        return [tr for tr in iterator if tr is not None]
375
438
 
376
439
    # should be deprecated - this is slow and in any case treating them as a
377
440
    # container is (we now know) bad style -- mbp 20070302
462
525
        return (file_obj, stat_value)
463
526
 
464
527
    def get_file_text(self, file_id, path=None, filtered=True):
465
 
        return self.get_file(file_id, path=path, filtered=filtered).read()
 
528
        my_file = self.get_file(file_id, path=path, filtered=filtered)
 
529
        try:
 
530
            return my_file.read()
 
531
        finally:
 
532
            my_file.close()
466
533
 
467
534
    def get_file_byname(self, filename, filtered=True):
468
535
        path = self.abspath(filename)
522
589
 
523
590
        # Now we have the parents of this content
524
591
        annotator = self.branch.repository.texts.get_annotator()
525
 
        text = self.get_file(file_id).read()
 
592
        text = self.get_file_text(file_id)
526
593
        this_key =(file_id, default_revision)
527
594
        annotator.add_special_text(this_key, file_parent_keys, text)
528
595
        annotations = [(key[-1], line)
1202
1269
                # absolute path
1203
1270
                fap = from_dir_abspath + '/' + f
1204
1271
 
1205
 
                f_ie = inv.get_child(from_dir_id, f)
 
1272
                dir_ie = inv[from_dir_id]
 
1273
                if dir_ie.kind == 'directory':
 
1274
                    f_ie = dir_ie.children.get(f)
 
1275
                else:
 
1276
                    f_ie = None
1206
1277
                if f_ie:
1207
1278
                    c = 'V'
1208
1279
                elif self.is_ignored(fp[1:]):
1209
1280
                    c = 'I'
1210
1281
                else:
1211
 
                    # we may not have found this file, because of a unicode issue
 
1282
                    # we may not have found this file, because of a unicode
 
1283
                    # issue, or because the directory was actually a symlink.
1212
1284
                    f_norm, can_access = osutils.normalized_filename(f)
1213
1285
                    if f == f_norm or not can_access:
1214
1286
                        # No change, so treat this file normally
1257
1329
                stack.pop()
1258
1330
 
1259
1331
    @needs_tree_write_lock
1260
 
    def move(self, from_paths, to_dir=None, after=False, **kwargs):
 
1332
    def move(self, from_paths, to_dir=None, after=False):
1261
1333
        """Rename files.
1262
1334
 
1263
1335
        to_dir must exist in the inventory.
1297
1369
 
1298
1370
        # check for deprecated use of signature
1299
1371
        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
 
 
 
1372
            raise TypeError('You must supply a target directory')
1308
1373
        # check destination directory
1309
1374
        if isinstance(from_paths, basestring):
1310
1375
            raise ValueError()
1600
1665
 
1601
1666
    @needs_write_lock
1602
1667
    def pull(self, source, overwrite=False, stop_revision=None,
1603
 
             change_reporter=None, possible_transports=None, local=False):
 
1668
             change_reporter=None, possible_transports=None, local=False,
 
1669
             show_base=False):
1604
1670
        source.lock_read()
1605
1671
        try:
1606
1672
            old_revision_info = self.branch.last_revision_info()
1620
1686
                                basis_tree,
1621
1687
                                this_tree=self,
1622
1688
                                pb=None,
1623
 
                                change_reporter=change_reporter)
 
1689
                                change_reporter=change_reporter,
 
1690
                                show_base=show_base)
1624
1691
                    basis_root_id = basis_tree.get_root_id()
1625
1692
                    new_root_id = new_basis_tree.get_root_id()
1626
1693
                    if basis_root_id != new_root_id:
1798
1865
            raise errors.ObjectNotLocked(self)
1799
1866
 
1800
1867
    def lock_read(self):
1801
 
        """See Branch.lock_read, and WorkingTree.unlock."""
 
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
        """
1802
1874
        if not self.is_locked():
1803
1875
            self._reset_data()
1804
1876
        self.branch.lock_read()
1805
1877
        try:
1806
 
            return self._control_files.lock_read()
 
1878
            self._control_files.lock_read()
 
1879
            return LogicalLockResult(self.unlock)
1807
1880
        except:
1808
1881
            self.branch.unlock()
1809
1882
            raise
1810
1883
 
1811
1884
    def lock_tree_write(self):
1812
 
        """See MutableTree.lock_tree_write, and WorkingTree.unlock."""
 
1885
        """See MutableTree.lock_tree_write, and WorkingTree.unlock.
 
1886
 
 
1887
        :return: A bzrlib.lock.LogicalLockResult.
 
1888
        """
1813
1889
        if not self.is_locked():
1814
1890
            self._reset_data()
1815
1891
        self.branch.lock_read()
1816
1892
        try:
1817
 
            return self._control_files.lock_write()
 
1893
            self._control_files.lock_write()
 
1894
            return LogicalLockResult(self.unlock)
1818
1895
        except:
1819
1896
            self.branch.unlock()
1820
1897
            raise
1821
1898
 
1822
1899
    def lock_write(self):
1823
 
        """See MutableTree.lock_write, and WorkingTree.unlock."""
 
1900
        """See MutableTree.lock_write, and WorkingTree.unlock.
 
1901
 
 
1902
        :return: A bzrlib.lock.LogicalLockResult.
 
1903
        """
1824
1904
        if not self.is_locked():
1825
1905
            self._reset_data()
1826
1906
        self.branch.lock_write()
1827
1907
        try:
1828
 
            return self._control_files.lock_write()
 
1908
            self._control_files.lock_write()
 
1909
            return LogicalLockResult(self.unlock)
1829
1910
        except:
1830
1911
            self.branch.unlock()
1831
1912
            raise
1948
2029
 
1949
2030
        inv_delta = []
1950
2031
 
1951
 
        new_files=set()
 
2032
        all_files = set() # specified and nested files 
1952
2033
        unknown_nested_files=set()
1953
2034
        if to_file is None:
1954
2035
            to_file = sys.stdout
1955
2036
 
 
2037
        files_to_backup = []
 
2038
 
1956
2039
        def recurse_directory_to_add_files(directory):
1957
2040
            # Recurse directory and add all files
1958
2041
            # so we can check if they have changed.
1959
 
            for parent_info, file_infos in\
1960
 
                self.walkdirs(directory):
 
2042
            for parent_info, file_infos in self.walkdirs(directory):
1961
2043
                for relpath, basename, kind, lstat, fileid, kind in file_infos:
1962
2044
                    # Is it versioned or ignored?
1963
 
                    if self.path2id(relpath) or self.is_ignored(relpath):
 
2045
                    if self.path2id(relpath):
1964
2046
                        # Add nested content for deletion.
1965
 
                        new_files.add(relpath)
 
2047
                        all_files.add(relpath)
1966
2048
                    else:
1967
 
                        # Files which are not versioned and not ignored
 
2049
                        # Files which are not versioned
1968
2050
                        # should be treated as unknown.
1969
 
                        unknown_nested_files.add((relpath, None, kind))
 
2051
                        files_to_backup.append(relpath)
1970
2052
 
1971
2053
        for filename in files:
1972
2054
            # Get file name into canonical form.
1973
2055
            abspath = self.abspath(filename)
1974
2056
            filename = self.relpath(abspath)
1975
2057
            if len(filename) > 0:
1976
 
                new_files.add(filename)
 
2058
                all_files.add(filename)
1977
2059
                recurse_directory_to_add_files(filename)
1978
2060
 
1979
 
        files = list(new_files)
 
2061
        files = list(all_files)
1980
2062
 
1981
2063
        if len(files) == 0:
1982
2064
            return # nothing to do
1986
2068
 
1987
2069
        # Bail out if we are going to delete files we shouldn't
1988
2070
        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
 
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])
2005
2083
 
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)
 
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)
2015
2089
 
2016
2090
        # Build inv_delta and delete files where applicable,
2017
2091
        # do this before any modifications to inventory.
2041
2115
                        len(os.listdir(abs_path)) > 0):
2042
2116
                        if force:
2043
2117
                            osutils.rmtree(abs_path)
 
2118
                            message = "deleted %s" % (f,)
2044
2119
                        else:
2045
 
                            message = "%s is not an empty directory "\
2046
 
                                "and won't be deleted." % (f,)
 
2120
                            message = backup(f)
2047
2121
                    else:
2048
 
                        osutils.delete_any(abs_path)
2049
 
                        message = "deleted %s" % (f,)
 
2122
                        if f in files_to_backup:
 
2123
                            message = backup(f)
 
2124
                        else:
 
2125
                            osutils.delete_any(abs_path)
 
2126
                            message = "deleted %s" % (f,)
2050
2127
                elif message is not None:
2051
2128
                    # Only care if we haven't done anything yet.
2052
2129
                    message = "%s does not exist." % (f,)
2189
2266
    _marker = object()
2190
2267
 
2191
2268
    def update(self, change_reporter=None, possible_transports=None,
2192
 
               revision=None, old_tip=_marker):
 
2269
               revision=None, old_tip=_marker, show_base=False):
2193
2270
        """Update a working tree along its branch.
2194
2271
 
2195
2272
        This will update the branch if its bound too, which means we have
2232
2309
            else:
2233
2310
                if old_tip is self._marker:
2234
2311
                    old_tip = None
2235
 
            return self._update_tree(old_tip, change_reporter, revision)
 
2312
            return self._update_tree(old_tip, change_reporter, revision, show_base)
2236
2313
        finally:
2237
2314
            self.unlock()
2238
2315
 
2239
2316
    @needs_tree_write_lock
2240
 
    def _update_tree(self, old_tip=None, change_reporter=None, revision=None):
 
2317
    def _update_tree(self, old_tip=None, change_reporter=None, revision=None,
 
2318
                     show_base=False):
2241
2319
        """Update a tree to the master branch.
2242
2320
 
2243
2321
        :param old_tip: if supplied, the previous tip revision the branch,
2270
2348
            other_tree = self.branch.repository.revision_tree(old_tip)
2271
2349
            nb_conflicts = merge.merge_inner(self.branch, other_tree,
2272
2350
                                             base_tree, this_tree=self,
2273
 
                                             change_reporter=change_reporter)
 
2351
                                             change_reporter=change_reporter,
 
2352
                                             show_base=show_base)
2274
2353
            if nb_conflicts:
2275
2354
                self.add_parent_tree((old_tip, other_tree))
2276
2355
                trace.note('Rerun update after fixing the conflicts.')
2300
2379
 
2301
2380
            nb_conflicts = merge.merge_inner(self.branch, to_tree, base_tree,
2302
2381
                                             this_tree=self,
2303
 
                                             change_reporter=change_reporter)
 
2382
                                             change_reporter=change_reporter,
 
2383
                                             show_base=show_base)
2304
2384
            self.set_last_revision(revision)
2305
2385
            # TODO - dedup parents list with things merged by pull ?
2306
2386
            # reuse the tree we've updated to to set the basis:
2608
2688
        return ShelfManager(self, self._transport)
2609
2689
 
2610
2690
 
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
2691
class WorkingTree3(WorkingTree):
2666
2692
    """This is the Format 3 working tree.
2667
2693
 
2836
2862
        del klass._formats[format.get_format_string()]
2837
2863
 
2838
2864
 
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
 
 
2921
2865
class WorkingTreeFormat3(WorkingTreeFormat):
2922
2866
    """The second working tree format updated to record a format marker.
2923
2867
 
3055
2999
WorkingTreeFormat.register_format(WorkingTreeFormat4())
3056
3000
WorkingTreeFormat.register_format(WorkingTreeFormat3())
3057
3001
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
 
                   ]
 
3002