~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

  • Committer: Martin
  • Date: 2011-04-15 21:22:57 UTC
  • mto: This revision was merged to the branch mainline in revision 5797.
  • Revision ID: gzlist@googlemail.com-20110415212257-jgtovwwp4be7egd9
Add release notes

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,
52
51
    controldir,
53
52
    errors,
 
53
    filters as _mod_filters,
54
54
    generate_ids,
55
55
    globbing,
56
56
    graph as _mod_graph,
60
60
    merge,
61
61
    revision as _mod_revision,
62
62
    revisiontree,
63
 
    trace,
 
63
    rio as _mod_rio,
64
64
    transform,
65
65
    transport,
66
66
    ui,
93
93
    splitpath,
94
94
    supports_executable,
95
95
    )
96
 
from bzrlib.filters import filtered_input_file
97
96
from bzrlib.trace import mutter, note
98
97
from bzrlib.transport.local import LocalTransport
99
98
from bzrlib.revision import CURRENT_REVISION
100
 
from bzrlib.rio import RioReader, rio_file, Stanza
101
99
from bzrlib.symbol_versioning import (
102
100
    deprecated_passed,
103
101
    DEPRECATED_PARAMETER,
168
166
        return ''
169
167
 
170
168
 
171
 
class WorkingTree(bzrlib.mutabletree.MutableTree,
 
169
class WorkingTree(bzrlib.mutabletree.MutableInventoryTree,
172
170
    controldir.ControlComponent):
173
171
    """Working copy tree.
174
172
 
209
207
        else:
210
208
            self._branch = self.bzrdir.open_branch()
211
209
        self.basedir = realpath(basedir)
212
 
        # if branch is at our basedir and is a format 6 or less
213
 
        if isinstance(self._format, WorkingTreeFormat2):
214
 
            # share control object
215
 
            self._control_files = self.branch.control_files
216
 
        else:
217
 
            # assume all other formats have their own control files.
218
 
            self._control_files = _control_files
 
210
        self._control_files = _control_files
219
211
        self._transport = self._control_files._transport
220
212
        # update the whole cache up front and write to disk if anything changed;
221
213
        # in the future we might want to do this more selectively
259
251
    def control_transport(self):
260
252
        return self._transport
261
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
 
262
266
    def _detect_case_handling(self):
263
267
        wt_trans = self.bzrdir.get_workingtree_transport(None)
264
268
        try:
265
 
            wt_trans.stat("FoRMaT")
 
269
            wt_trans.stat(self._format.case_sensitive_filename)
266
270
        except errors.NoSuchFile:
267
271
            self.case_sensitive = True
268
272
        else:
353
357
        return control.open_workingtree(), relpath
354
358
 
355
359
    @staticmethod
356
 
    def open_containing_paths(file_list, default_directory='.',
357
 
        canonicalize=True, apply_view=True):
 
360
    def open_containing_paths(file_list, default_directory=None,
 
361
                              canonicalize=True, apply_view=True):
358
362
        """Open the WorkingTree that contains a set of paths.
359
363
 
360
364
        Fail if the paths given are not all in a single tree.
362
366
        This is used for the many command-line interfaces that take a list of
363
367
        any number of files and that require they all be in the same tree.
364
368
        """
 
369
        if default_directory is None:
 
370
            default_directory = u'.'
365
371
        # recommended replacement for builtins.internal_tree_files
366
372
        if file_list is None or len(file_list) == 0:
367
373
            tree = WorkingTree.open_containing(default_directory)[0]
375
381
                    view_str = views.view_display_str(view_files)
376
382
                    note("Ignoring files outside view. View is %s" % view_str)
377
383
            return tree, file_list
378
 
        tree = WorkingTree.open_containing(file_list[0])[0]
 
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]
379
391
        return tree, tree.safe_relpath_files(file_list, canonicalize,
380
 
            apply_view=apply_view)
 
392
                                             apply_view=apply_view)
381
393
 
382
394
    def safe_relpath_files(self, file_list, canonicalize=True, apply_view=True):
383
395
        """Convert file_list into a list of relpaths in tree.
511
523
        return self.get_file_with_stat(file_id, path, filtered=filtered)[0]
512
524
 
513
525
    def get_file_with_stat(self, file_id, path=None, filtered=True,
514
 
        _fstat=os.fstat):
 
526
                           _fstat=osutils.fstat):
515
527
        """See Tree.get_file_with_stat."""
516
528
        if path is None:
517
529
            path = self.id2path(file_id)
519
531
        stat_value = _fstat(file_obj.fileno())
520
532
        if filtered and self.supports_content_filtering():
521
533
            filters = self._content_filter_stack(path)
522
 
            file_obj = filtered_input_file(file_obj, filters)
 
534
            file_obj = _mod_filters.filtered_input_file(file_obj, filters)
523
535
        return (file_obj, stat_value)
524
536
 
525
537
    def get_file_text(self, file_id, path=None, filtered=True):
534
546
        f = file(path, 'rb')
535
547
        if filtered and self.supports_content_filtering():
536
548
            filters = self._content_filter_stack(filename)
537
 
            return filtered_input_file(f, filters)
 
549
            return _mod_filters.filtered_input_file(f, filters)
538
550
        else:
539
551
            return f
540
552
 
627
639
        """Return the id of this trees root"""
628
640
        return self._inventory.root.file_id
629
641
 
630
 
    def _get_store_filename(self, file_id):
631
 
        ## XXX: badly named; this is not in the store at all
632
 
        return self.abspath(self.id2path(file_id))
633
 
 
634
642
    @needs_read_lock
635
643
    def clone(self, to_bzrdir, revision_id=None):
636
644
        """Duplicate this working tree into to_bzr, including all state.
876
884
            if revision_id in heads and revision_id not in new_revision_ids:
877
885
                new_revision_ids.append(revision_id)
878
886
        if new_revision_ids != revision_ids:
879
 
            trace.mutter('requested to set revision_ids = %s,'
 
887
            mutter('requested to set revision_ids = %s,'
880
888
                         ' but filtered to %s', revision_ids, new_revision_ids)
881
889
        return new_revision_ids
882
890
 
948
956
    def set_merge_modified(self, modified_hashes):
949
957
        def iter_stanzas():
950
958
            for file_id, hash in modified_hashes.iteritems():
951
 
                yield Stanza(file_id=file_id.decode('utf8'), hash=hash)
 
959
                yield _mod_rio.Stanza(file_id=file_id.decode('utf8'),
 
960
                    hash=hash)
952
961
        self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
953
962
 
954
963
    def _sha_from_stat(self, path, stat_result):
963
972
 
964
973
    def _put_rio(self, filename, stanzas, header):
965
974
        self._must_be_locked()
966
 
        my_file = rio_file(stanzas, header)
 
975
        my_file = _mod_rio.rio_file(stanzas, header)
967
976
        self._transport.put_file(filename, my_file,
968
977
            mode=self.bzrdir._get_file_mode())
969
978
 
1033
1042
                    raise errors.MergeModifiedFormatError()
1034
1043
            except StopIteration:
1035
1044
                raise errors.MergeModifiedFormatError()
1036
 
            for s in RioReader(hashfile):
 
1045
            for s in _mod_rio.RioReader(hashfile):
1037
1046
                # RioReader reads in Unicode, so convert file_ids back to utf8
1038
1047
                file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
1039
1048
                if file_id not in self.inventory:
1382
1391
        to_dir_id = inv.path2id(to_dir)
1383
1392
        if to_dir_id is None:
1384
1393
            raise errors.BzrMoveFailedError('',to_dir,
1385
 
                errors.NotVersionedError(path=str(to_dir)))
 
1394
                errors.NotVersionedError(path=to_dir))
1386
1395
 
1387
1396
        to_dir_ie = inv[to_dir_id]
1388
1397
        if to_dir_ie.kind != 'directory':
1395
1404
            from_id = inv.path2id(from_rel)
1396
1405
            if from_id is None:
1397
1406
                raise errors.BzrMoveFailedError(from_rel,to_dir,
1398
 
                    errors.NotVersionedError(path=str(from_rel)))
 
1407
                    errors.NotVersionedError(path=from_rel))
1399
1408
 
1400
1409
            from_entry = inv[from_id]
1401
1410
            from_parent_id = from_entry.parent_id
1443
1452
            # check the inventory for source and destination
1444
1453
            if from_id is None:
1445
1454
                raise errors.BzrMoveFailedError(from_rel,to_rel,
1446
 
                    errors.NotVersionedError(path=str(from_rel)))
 
1455
                    errors.NotVersionedError(path=from_rel))
1447
1456
            if to_id is not None:
1448
1457
                raise errors.BzrMoveFailedError(from_rel,to_rel,
1449
 
                    errors.AlreadyVersionedError(path=str(to_rel)))
 
1458
                    errors.AlreadyVersionedError(path=to_rel))
1450
1459
 
1451
1460
            # try to determine the mode for rename (only change inv or change
1452
1461
            # inv and file system)
1453
1462
            if after:
1454
1463
                if not self.has_filename(to_rel):
1455
1464
                    raise errors.BzrMoveFailedError(from_id,to_rel,
1456
 
                        errors.NoSuchFile(path=str(to_rel),
 
1465
                        errors.NoSuchFile(path=to_rel,
1457
1466
                        extra="New file has not been created yet"))
1458
1467
                only_change_inv = True
1459
1468
            elif not self.has_filename(from_rel) and self.has_filename(to_rel):
1561
1570
            from_id = basis_tree.path2id(from_rel)
1562
1571
            if from_id is None:
1563
1572
                raise errors.BzrRenameFailedError(from_rel,to_rel,
1564
 
                    errors.NotVersionedError(path=str(from_rel)))
 
1573
                    errors.NotVersionedError(path=from_rel))
1565
1574
            # put entry back in the inventory so we can rename it
1566
1575
            from_entry = basis_tree.inventory[from_id].copy()
1567
1576
            inv.add(from_entry)
1585
1594
        # versioned
1586
1595
        if to_dir_id is None:
1587
1596
            raise errors.BzrMoveFailedError(from_rel,to_rel,
1588
 
                errors.NotVersionedError(path=str(to_dir)))
 
1597
                errors.NotVersionedError(path=to_dir))
1589
1598
 
1590
1599
        # all checks done. now we can continue with our actual work
1591
1600
        mutter('rename_one:\n'
1650
1659
            # - RBC 20060907
1651
1660
            self._write_inventory(self._inventory)
1652
1661
 
1653
 
    def _iter_conflicts(self):
1654
 
        conflicted = set()
1655
 
        for info in self.list_files():
1656
 
            path = info[0]
1657
 
            stem = get_conflicted_stem(path)
1658
 
            if stem is None:
1659
 
                continue
1660
 
            if stem not in conflicted:
1661
 
                conflicted.add(stem)
1662
 
                yield stem
1663
 
 
1664
1662
    @needs_write_lock
1665
1663
    def pull(self, source, overwrite=False, stop_revision=None,
1666
1664
             change_reporter=None, possible_transports=None, local=False,
2350
2348
                                             show_base=show_base)
2351
2349
            if nb_conflicts:
2352
2350
                self.add_parent_tree((old_tip, other_tree))
2353
 
                trace.note('Rerun update after fixing the conflicts.')
 
2351
                note('Rerun update after fixing the conflicts.')
2354
2352
                return nb_conflicts
2355
2353
 
2356
2354
        if last_rev != _mod_revision.ensure_null(revision):
2425
2423
    def add_conflicts(self, arg):
2426
2424
        raise errors.UnsupportedOperation(self.add_conflicts, self)
2427
2425
 
2428
 
    @needs_read_lock
2429
2426
    def conflicts(self):
2430
 
        conflicts = _mod_conflicts.ConflictList()
2431
 
        for conflicted in self._iter_conflicts():
2432
 
            text = True
2433
 
            try:
2434
 
                if file_kind(self.abspath(conflicted)) != "file":
2435
 
                    text = False
2436
 
            except errors.NoSuchFile:
2437
 
                text = False
2438
 
            if text is True:
2439
 
                for suffix in ('.THIS', '.OTHER'):
2440
 
                    try:
2441
 
                        kind = file_kind(self.abspath(conflicted+suffix))
2442
 
                        if kind != "file":
2443
 
                            text = False
2444
 
                    except errors.NoSuchFile:
2445
 
                        text = False
2446
 
                    if text == False:
2447
 
                        break
2448
 
            ctype = {True: 'text conflict', False: 'contents conflict'}[text]
2449
 
            conflicts.append(_mod_conflicts.Conflict.factory(ctype,
2450
 
                             path=conflicted,
2451
 
                             file_id=self.path2id(conflicted)))
2452
 
        return conflicts
 
2427
        raise NotImplementedError(self.conflicts)
2453
2428
 
2454
2429
    def walkdirs(self, prefix=""):
2455
2430
        """Walk the directories of this tree.
2673
2648
        """
2674
2649
        return
2675
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
 
2676
2679
    def _get_rules_searcher(self, default_searcher):
2677
2680
        """See Tree._get_rules_searcher."""
2678
2681
        if self._rules_searcher is None:
2686
2689
        return ShelfManager(self, self._transport)
2687
2690
 
2688
2691
 
2689
 
class WorkingTree2(WorkingTree):
2690
 
    """This is the Format 2 working tree.
2691
 
 
2692
 
    This was the first weave based working tree.
2693
 
     - uses os locks for locking.
2694
 
     - uses the branch last-revision.
2695
 
    """
2696
 
 
2697
 
    def __init__(self, *args, **kwargs):
2698
 
        super(WorkingTree2, self).__init__(*args, **kwargs)
2699
 
        # WorkingTree2 has more of a constraint that self._inventory must
2700
 
        # exist. Because this is an older format, we don't mind the overhead
2701
 
        # caused by the extra computation here.
2702
 
 
2703
 
        # Newer WorkingTree's should only have self._inventory set when they
2704
 
        # have a read lock.
2705
 
        if self._inventory is None:
2706
 
            self.read_working_inventory()
2707
 
 
2708
 
    def _get_check_refs(self):
2709
 
        """Return the references needed to perform a check of this tree."""
2710
 
        return [('trees', self.last_revision())]
2711
 
 
2712
 
    def lock_tree_write(self):
2713
 
        """See WorkingTree.lock_tree_write().
2714
 
 
2715
 
        In Format2 WorkingTrees we have a single lock for the branch and tree
2716
 
        so lock_tree_write() degrades to lock_write().
2717
 
 
2718
 
        :return: An object with an unlock method which will release the lock
2719
 
            obtained.
2720
 
        """
2721
 
        self.branch.lock_write()
2722
 
        try:
2723
 
            self._control_files.lock_write()
2724
 
            return self
2725
 
        except:
2726
 
            self.branch.unlock()
2727
 
            raise
2728
 
 
2729
 
    def unlock(self):
2730
 
        # do non-implementation specific cleanup
2731
 
        self._cleanup()
2732
 
 
2733
 
        # we share control files:
2734
 
        if self._control_files._lock_count == 3:
2735
 
            # _inventory_is_modified is always False during a read lock.
2736
 
            if self._inventory_is_modified:
2737
 
                self.flush()
2738
 
            self._write_hashcache_if_dirty()
2739
 
 
2740
 
        # reverse order of locking.
2741
 
        try:
2742
 
            return self._control_files.unlock()
2743
 
        finally:
2744
 
            self.branch.unlock()
2745
 
 
2746
 
 
2747
2692
class WorkingTree3(WorkingTree):
2748
2693
    """This is the Format 3 working tree.
2749
2694
 
2803
2748
                    raise errors.ConflictFormatError()
2804
2749
            except StopIteration:
2805
2750
                raise errors.ConflictFormatError()
2806
 
            return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
 
2751
            reader = _mod_rio.RioReader(confile)
 
2752
            return _mod_conflicts.ConflictList.from_stanzas(reader)
2807
2753
        finally:
2808
2754
            confile.close()
2809
2755
 
2822
2768
            self.branch.unlock()
2823
2769
 
2824
2770
 
2825
 
def get_conflicted_stem(path):
2826
 
    for suffix in _mod_conflicts.CONFLICT_SUFFIXES:
2827
 
        if path.endswith(suffix):
2828
 
            return path[:-len(suffix)]
2829
 
 
2830
 
 
2831
 
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):
2832
2790
    """An encapsulation of the initialization and open routines for a format.
2833
2791
 
2834
2792
    Formats provide three things:
2846
2804
    object will be created every time regardless.
2847
2805
    """
2848
2806
 
2849
 
    _default_format = None
2850
 
    """The default format used for new trees."""
2851
 
 
2852
 
    _formats = {}
2853
 
    """The known formats."""
2854
 
 
2855
2807
    requires_rich_root = False
2856
2808
 
2857
2809
    upgrade_recommended = False
2858
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
 
2859
2818
    @classmethod
2860
2819
    def find_format(klass, a_bzrdir):
2861
2820
        """Return the format for the working tree object in a_bzrdir."""
2862
2821
        try:
2863
2822
            transport = a_bzrdir.get_workingtree_transport(None)
2864
2823
            format_string = transport.get_bytes("format")
2865
 
            return klass._formats[format_string]
 
2824
            return format_registry.get(format_string)
2866
2825
        except errors.NoSuchFile:
2867
2826
            raise errors.NoWorkingTree(base=transport.base)
2868
2827
        except KeyError:
2869
2828
            raise errors.UnknownFormatError(format=format_string,
2870
2829
                                            kind="working tree")
2871
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
 
2872
2848
    def __eq__(self, other):
2873
2849
        return self.__class__ is other.__class__
2874
2850
 
2876
2852
        return not (self == other)
2877
2853
 
2878
2854
    @classmethod
 
2855
    @symbol_versioning.deprecated_method(
 
2856
        symbol_versioning.deprecated_in((2, 4, 0)))
2879
2857
    def get_default_format(klass):
2880
2858
        """Return the current default format."""
2881
 
        return klass._default_format
 
2859
        return format_registry.get_default()
2882
2860
 
2883
2861
    def get_format_string(self):
2884
2862
        """Return the ASCII format string that identifies this format."""
2906
2884
        return False
2907
2885
 
2908
2886
    @classmethod
 
2887
    @symbol_versioning.deprecated_method(
 
2888
        symbol_versioning.deprecated_in((2, 4, 0)))
2909
2889
    def register_format(klass, format):
2910
 
        klass._formats[format.get_format_string()] = format
2911
 
 
2912
 
    @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)))
2913
2913
    def set_default_format(klass, format):
2914
 
        klass._default_format = format
 
2914
        format_registry.set_default(format)
2915
2915
 
2916
2916
    @classmethod
 
2917
    @symbol_versioning.deprecated_method(
 
2918
        symbol_versioning.deprecated_in((2, 4, 0)))
2917
2919
    def unregister_format(klass, format):
2918
 
        del klass._formats[format.get_format_string()]
2919
 
 
2920
 
 
2921
 
class WorkingTreeFormat2(WorkingTreeFormat):
2922
 
    """The second working tree format.
2923
 
 
2924
 
    This format modified the hash cache from the format 1 hash cache.
2925
 
    """
2926
 
 
2927
 
    upgrade_recommended = True
2928
 
 
2929
 
    def get_format_description(self):
2930
 
        """See WorkingTreeFormat.get_format_description()."""
2931
 
        return "Working tree format 2"
2932
 
 
2933
 
    def _stub_initialize_on_transport(self, transport, file_mode):
2934
 
        """Workaround: create control files for a remote working tree.
2935
 
 
2936
 
        This ensures that it can later be updated and dealt with locally,
2937
 
        since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2938
 
        no working tree.  (See bug #43064).
2939
 
        """
2940
 
        sio = StringIO()
2941
 
        inv = inventory.Inventory()
2942
 
        xml5.serializer_v5.write_inventory(inv, sio, working=True)
2943
 
        sio.seek(0)
2944
 
        transport.put_file('inventory', sio, file_mode)
2945
 
        transport.put_bytes('pending-merges', '', file_mode)
2946
 
 
2947
 
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2948
 
                   accelerator_tree=None, hardlink=False):
2949
 
        """See WorkingTreeFormat.initialize()."""
2950
 
        if not isinstance(a_bzrdir.transport, LocalTransport):
2951
 
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
2952
 
        if from_branch is not None:
2953
 
            branch = from_branch
2954
 
        else:
2955
 
            branch = a_bzrdir.open_branch()
2956
 
        if revision_id is None:
2957
 
            revision_id = _mod_revision.ensure_null(branch.last_revision())
2958
 
        branch.lock_write()
2959
 
        try:
2960
 
            branch.generate_revision_history(revision_id)
2961
 
        finally:
2962
 
            branch.unlock()
2963
 
        inv = inventory.Inventory()
2964
 
        wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
2965
 
                         branch,
2966
 
                         inv,
2967
 
                         _internal=True,
2968
 
                         _format=self,
2969
 
                         _bzrdir=a_bzrdir)
2970
 
        basis_tree = branch.repository.revision_tree(revision_id)
2971
 
        if basis_tree.inventory.root is not None:
2972
 
            wt.set_root_id(basis_tree.get_root_id())
2973
 
        # set the parent list and cache the basis tree.
2974
 
        if _mod_revision.is_null(revision_id):
2975
 
            parent_trees = []
2976
 
        else:
2977
 
            parent_trees = [(revision_id, basis_tree)]
2978
 
        wt.set_parent_trees(parent_trees)
2979
 
        transform.build_tree(basis_tree, wt)
2980
 
        return wt
2981
 
 
2982
 
    def __init__(self):
2983
 
        super(WorkingTreeFormat2, self).__init__()
2984
 
        self._matchingbzrdir = bzrdir.BzrDirFormat6()
2985
 
 
2986
 
    def open(self, a_bzrdir, _found=False):
2987
 
        """Return the WorkingTree object for a_bzrdir
2988
 
 
2989
 
        _found is a private parameter, do not use it. It is used to indicate
2990
 
               if format probing has already been done.
2991
 
        """
2992
 
        if not _found:
2993
 
            # we are being called directly and must probe.
2994
 
            raise NotImplementedError
2995
 
        if not isinstance(a_bzrdir.transport, LocalTransport):
2996
 
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
2997
 
        wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
2998
 
                           _internal=True,
2999
 
                           _format=self,
3000
 
                           _bzrdir=a_bzrdir)
3001
 
        return wt
 
2920
        format_registry.remove(format)
 
2921
 
3002
2922
 
3003
2923
class WorkingTreeFormat3(WorkingTreeFormat):
3004
2924
    """The second working tree format updated to record a format marker.
3014
2934
 
3015
2935
    upgrade_recommended = True
3016
2936
 
 
2937
    missing_parent_conflicts = True
 
2938
 
3017
2939
    def get_format_string(self):
3018
2940
        """See WorkingTreeFormat.get_format_string()."""
3019
2941
        return "Bazaar-NG Working Tree format 3"
3132
3054
 
3133
3055
 
3134
3056
__default_format = WorkingTreeFormat6()
3135
 
WorkingTreeFormat.register_format(__default_format)
3136
 
WorkingTreeFormat.register_format(WorkingTreeFormat5())
3137
 
WorkingTreeFormat.register_format(WorkingTreeFormat4())
3138
 
WorkingTreeFormat.register_format(WorkingTreeFormat3())
3139
 
WorkingTreeFormat.set_default_format(__default_format)
3140
 
# formats which have no format string are not discoverable
3141
 
# and not independently creatable, so are not registered.
3142
 
_legacy_formats = [WorkingTreeFormat2(),
3143
 
                   ]
 
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)