/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/bzrdir.py

  • Committer: John Arbash Meinel
  • Date: 2006-09-20 14:51:03 UTC
  • mfrom: (0.8.23 version_info)
  • mto: This revision was merged to the branch mainline in revision 2028.
  • Revision ID: john@arbash-meinel.com-20060920145103-02725c6d6c886040
[merge] version-info plugin, and cleanup for layout in bzr

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2005, 2006 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
28
28
# TODO: Can we move specific formats into separate modules to make this file
29
29
# smaller?
30
30
 
 
31
from copy import deepcopy
31
32
from cStringIO import StringIO
32
33
import os
33
 
import textwrap
34
 
 
35
 
from bzrlib.lazy_import import lazy_import
36
 
lazy_import(globals(), """
37
 
from copy import deepcopy
38
34
from stat import S_ISDIR
39
 
import unittest
 
35
from unittest import TestSuite
40
36
 
41
37
import bzrlib
42
 
from bzrlib import (
43
 
    errors,
44
 
    lockable_files,
45
 
    lockdir,
46
 
    registry,
47
 
    revision as _mod_revision,
48
 
    symbol_versioning,
49
 
    ui,
50
 
    urlutils,
51
 
    xml4,
52
 
    xml5,
53
 
    workingtree,
54
 
    workingtree_4,
55
 
    )
 
38
import bzrlib.errors as errors
 
39
from bzrlib.lockable_files import LockableFiles, TransportLock
 
40
from bzrlib.lockdir import LockDir
56
41
from bzrlib.osutils import (
57
 
    safe_unicode,
58
 
    sha_strings,
59
 
    sha_string,
60
 
    )
 
42
                            abspath,
 
43
                            pathjoin,
 
44
                            safe_unicode,
 
45
                            sha_strings,
 
46
                            sha_string,
 
47
                            )
 
48
import bzrlib.revision
61
49
from bzrlib.store.revision.text import TextRevisionStore
62
50
from bzrlib.store.text import TextStore
63
51
from bzrlib.store.versioned import WeaveStore
 
52
from bzrlib.trace import mutter
64
53
from bzrlib.transactions import WriteTransaction
65
 
from bzrlib.transport import (
66
 
    do_catching_redirections,
67
 
    get_transport,
68
 
    )
 
54
from bzrlib.transport import get_transport
 
55
from bzrlib.transport.local import LocalTransport
 
56
import bzrlib.urlutils as urlutils
69
57
from bzrlib.weave import Weave
70
 
""")
71
 
 
72
 
from bzrlib.trace import (
73
 
    mutter,
74
 
    note,
75
 
    )
76
 
from bzrlib.transport.local import LocalTransport
 
58
from bzrlib.xml4 import serializer_v4
 
59
import bzrlib.xml5
77
60
 
78
61
 
79
62
class BzrDir(object):
116
99
        source_repo_format.check_conversion_target(target_repo_format)
117
100
 
118
101
    @staticmethod
119
 
    def _check_supported(format, allow_unsupported,
120
 
        recommend_upgrade=True,
121
 
        basedir=None):
122
 
        """Give an error or warning on old formats.
123
 
 
124
 
        :param format: may be any kind of format - workingtree, branch, 
125
 
        or repository.
126
 
 
127
 
        :param allow_unsupported: If true, allow opening 
128
 
        formats that are strongly deprecated, and which may 
129
 
        have limited functionality.
130
 
 
131
 
        :param recommend_upgrade: If true (default), warn
132
 
        the user through the ui object that they may wish
133
 
        to upgrade the object.
 
102
    def _check_supported(format, allow_unsupported):
 
103
        """Check whether format is a supported format.
 
104
 
 
105
        If allow_unsupported is True, this is a no-op.
134
106
        """
135
 
        # TODO: perhaps move this into a base Format class; it's not BzrDir
136
 
        # specific. mbp 20070323
137
107
        if not allow_unsupported and not format.is_supported():
138
108
            # see open_downlevel to open legacy branches.
139
109
            raise errors.UnsupportedFormatError(format=format)
140
 
        if recommend_upgrade \
141
 
            and getattr(format, 'upgrade_recommended', False):
142
 
            ui.ui_factory.recommend_upgrade(
143
 
                format.get_format_description(),
144
 
                basedir)
145
110
 
146
 
    def clone(self, url, revision_id=None, force_new_repo=False):
 
111
    def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
147
112
        """Clone this bzrdir and its contents to url verbatim.
148
113
 
149
114
        If urls last component does not exist, it will be created.
154
119
                               even if one is available.
155
120
        """
156
121
        self._make_tail(url)
 
122
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
157
123
        result = self._format.initialize(url)
158
124
        try:
159
125
            local_repo = self.find_repository()
164
130
            if force_new_repo:
165
131
                result_repo = local_repo.clone(
166
132
                    result,
167
 
                    revision_id=revision_id)
 
133
                    revision_id=revision_id,
 
134
                    basis=basis_repo)
168
135
                result_repo.set_make_working_trees(local_repo.make_working_trees())
169
136
            else:
170
137
                try:
171
138
                    result_repo = result.find_repository()
172
139
                    # fetch content this dir needs.
 
140
                    if basis_repo:
 
141
                        # XXX FIXME RBC 20060214 need tests for this when the basis
 
142
                        # is incomplete
 
143
                        result_repo.fetch(basis_repo, revision_id=revision_id)
173
144
                    result_repo.fetch(local_repo, revision_id=revision_id)
174
145
                except errors.NoRepositoryPresent:
175
146
                    # needed to make one anyway.
176
147
                    result_repo = local_repo.clone(
177
148
                        result,
178
 
                        revision_id=revision_id)
 
149
                        revision_id=revision_id,
 
150
                        basis=basis_repo)
179
151
                    result_repo.set_make_working_trees(local_repo.make_working_trees())
180
152
        # 1 if there is a branch present
181
153
        #   make sure its content is available in the target repository
185
157
        except errors.NotBranchError:
186
158
            pass
187
159
        try:
188
 
            self.open_workingtree().clone(result)
 
160
            self.open_workingtree().clone(result, basis=basis_tree)
189
161
        except (errors.NoWorkingTree, errors.NotLocalUrl):
190
162
            pass
191
163
        return result
192
164
 
 
165
    def _get_basis_components(self, basis):
 
166
        """Retrieve the basis components that are available at basis."""
 
167
        if basis is None:
 
168
            return None, None, None
 
169
        try:
 
170
            basis_tree = basis.open_workingtree()
 
171
            basis_branch = basis_tree.branch
 
172
            basis_repo = basis_branch.repository
 
173
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
174
            basis_tree = None
 
175
            try:
 
176
                basis_branch = basis.open_branch()
 
177
                basis_repo = basis_branch.repository
 
178
            except errors.NotBranchError:
 
179
                basis_branch = None
 
180
                try:
 
181
                    basis_repo = basis.open_repository()
 
182
                except errors.NoRepositoryPresent:
 
183
                    basis_repo = None
 
184
        return basis_repo, basis_branch, basis_tree
 
185
 
193
186
    # TODO: This should be given a Transport, and should chdir up; otherwise
194
187
    # this will open a new connection.
195
188
    def _make_tail(self, url):
196
189
        head, tail = urlutils.split(url)
197
190
        if tail and tail != '.':
198
 
            t = get_transport(head)
 
191
            t = bzrlib.transport.get_transport(head)
199
192
            try:
200
193
                t.mkdir(tail)
201
194
            except errors.FileExists:
203
196
 
204
197
    # TODO: Should take a Transport
205
198
    @classmethod
206
 
    def create(cls, base, format=None):
 
199
    def create(cls, base):
207
200
        """Create a new BzrDir at the url 'base'.
208
201
        
209
202
        This will call the current default formats initialize with base
210
203
        as the only parameter.
211
204
 
212
 
        :param format: If supplied, the format of branch to create.  If not
213
 
            supplied, the default is used.
 
205
        If you need a specific format, consider creating an instance
 
206
        of that and calling initialize().
214
207
        """
215
208
        if cls is not BzrDir:
216
 
            raise AssertionError("BzrDir.create always creates the default"
217
 
                " format, not one of %r" % cls)
 
209
            raise AssertionError("BzrDir.create always creates the default format, "
 
210
                    "not one of %r" % cls)
218
211
        head, tail = urlutils.split(base)
219
212
        if tail and tail != '.':
220
 
            t = get_transport(head)
 
213
            t = bzrlib.transport.get_transport(head)
221
214
            try:
222
215
                t.mkdir(tail)
223
216
            except errors.FileExists:
224
217
                pass
225
 
        if format is None:
226
 
            format = BzrDirFormat.get_default_format()
227
 
        return format.initialize(safe_unicode(base))
 
218
        return BzrDirFormat.get_default_format().initialize(safe_unicode(base))
228
219
 
229
220
    def create_branch(self):
230
221
        """Create a branch in this BzrDir.
235
226
        raise NotImplementedError(self.create_branch)
236
227
 
237
228
    @staticmethod
238
 
    def create_branch_and_repo(base, force_new_repo=False, format=None):
 
229
    def create_branch_and_repo(base, force_new_repo=False):
239
230
        """Create a new BzrDir, Branch and Repository at the url 'base'.
240
231
 
241
232
        This will use the current default BzrDirFormat, and use whatever 
248
239
        :param base: The URL to create the branch at.
249
240
        :param force_new_repo: If True a new repository is always created.
250
241
        """
251
 
        bzrdir = BzrDir.create(base, format)
 
242
        bzrdir = BzrDir.create(base)
252
243
        bzrdir._find_or_create_repository(force_new_repo)
253
244
        return bzrdir.create_branch()
254
245
 
292
283
            t = get_transport(safe_unicode(base))
293
284
            if not isinstance(t, LocalTransport):
294
285
                raise errors.NotLocalUrl(base)
295
 
        bzrdir = BzrDir.create(base, format)
 
286
        if format is None:
 
287
            bzrdir = BzrDir.create(base)
 
288
        else:
 
289
            bzrdir = format.initialize(base)
296
290
        repo = bzrdir._find_or_create_repository(force_new_repo)
297
291
        result = bzrdir.create_branch()
298
292
        if force_new_tree or (repo.make_working_trees() and 
304
298
        return result
305
299
        
306
300
    @staticmethod
307
 
    def create_repository(base, shared=False, format=None):
 
301
    def create_repository(base, shared=False):
308
302
        """Create a new BzrDir and Repository at the url 'base'.
309
303
 
310
 
        If no format is supplied, this will default to the current default
311
 
        BzrDirFormat by default, and use whatever repository format that that
312
 
        uses for bzrdirformat.create_repository.
 
304
        This will use the current default BzrDirFormat, and use whatever 
 
305
        repository format that that uses for bzrdirformat.create_repository.
313
306
 
314
307
        :param shared: Create a shared repository rather than a standalone
315
308
                       repository.
319
312
        it should take no parameters and construct whatever repository format
320
313
        that child class desires.
321
314
        """
322
 
        bzrdir = BzrDir.create(base, format)
 
315
        bzrdir = BzrDir.create(base)
323
316
        return bzrdir.create_repository(shared)
324
317
 
325
318
    @staticmethod
326
 
    def create_standalone_workingtree(base, format=None):
 
319
    def create_standalone_workingtree(base):
327
320
        """Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
328
321
 
329
322
        'base' must be a local path or a file:// url.
338
331
        if not isinstance(t, LocalTransport):
339
332
            raise errors.NotLocalUrl(base)
340
333
        bzrdir = BzrDir.create_branch_and_repo(safe_unicode(base),
341
 
                                               force_new_repo=True,
342
 
                                               format=format).bzrdir
 
334
                                               force_new_repo=True).bzrdir
343
335
        return bzrdir.create_workingtree()
344
336
 
345
337
    def create_workingtree(self, revision_id=None):
349
341
        """
350
342
        raise NotImplementedError(self.create_workingtree)
351
343
 
352
 
    def retire_bzrdir(self):
353
 
        """Permanently disable the bzrdir.
354
 
 
355
 
        This is done by renaming it to give the user some ability to recover
356
 
        if there was a problem.
357
 
 
358
 
        This will have horrible consequences if anyone has anything locked or
359
 
        in use.
360
 
        """
361
 
        for i in xrange(10000):
362
 
            try:
363
 
                to_path = '.bzr.retired.%d' % i
364
 
                self.root_transport.rename('.bzr', to_path)
365
 
                note("renamed %s to %s"
366
 
                    % (self.root_transport.abspath('.bzr'), to_path))
367
 
                break
368
 
            except (errors.TransportError, IOError, errors.PathError):
369
 
                pass
370
 
 
371
 
    def destroy_workingtree(self):
372
 
        """Destroy the working tree at this BzrDir.
373
 
 
374
 
        Formats that do not support this may raise UnsupportedOperation.
375
 
        """
376
 
        raise NotImplementedError(self.destroy_workingtree)
377
 
 
378
 
    def destroy_workingtree_metadata(self):
379
 
        """Destroy the control files for the working tree at this BzrDir.
380
 
 
381
 
        The contents of working tree files are not affected.
382
 
        Formats that do not support this may raise UnsupportedOperation.
383
 
        """
384
 
        raise NotImplementedError(self.destroy_workingtree_metadata)
385
 
 
386
344
    def find_repository(self):
387
345
        """Find the repository that should be used for a_bzrdir.
388
346
 
450
408
        """Get the transport for use by workingtree format in this BzrDir.
451
409
 
452
410
        Note that bzr dirs that do not support format strings will raise
453
 
        IncompatibleFormat if the workingtree format they are given has a
454
 
        format string, and vice versa.
 
411
        IncompatibleFormat if the workingtree format they are given has
 
412
        a format string, and vice versa.
455
413
 
456
414
        If workingtree_format is None, the transport is returned with no 
457
415
        checking. if it is not None, then the returned transport is
523
481
        :param transport: Transport containing the bzrdir.
524
482
        :param _unsupported: private.
525
483
        """
526
 
        base = transport.base
527
 
 
528
 
        def find_format(transport):
529
 
            return transport, BzrDirFormat.find_format(transport)
530
 
 
531
 
        def redirected(transport, e, redirection_notice):
532
 
            qualified_source = e.get_source_url()
533
 
            relpath = transport.relpath(qualified_source)
534
 
            if not e.target.endswith(relpath):
535
 
                # Not redirected to a branch-format, not a branch
536
 
                raise errors.NotBranchError(path=e.target)
537
 
            target = e.target[:-len(relpath)]
538
 
            note('%s is%s redirected to %s',
539
 
                 transport.base, e.permanently, target)
540
 
            # Let's try with a new transport
541
 
            qualified_target = e.get_target_url()[:-len(relpath)]
542
 
            # FIXME: If 'transport' has a qualifier, this should
543
 
            # be applied again to the new transport *iff* the
544
 
            # schemes used are the same. It's a bit tricky to
545
 
            # verify, so I'll punt for now
546
 
            # -- vila20070212
547
 
            return get_transport(target)
548
 
 
549
 
        try:
550
 
            transport, format = do_catching_redirections(find_format,
551
 
                                                         transport,
552
 
                                                         redirected)
553
 
        except errors.TooManyRedirections:
554
 
            raise errors.NotBranchError(base)
555
 
 
 
484
        format = BzrDirFormat.find_format(transport)
556
485
        BzrDir._check_supported(format, _unsupported)
557
486
        return format.open(transport, _found=True)
558
487
 
604
533
                raise errors.NotBranchError(path=url)
605
534
            a_transport = new_t
606
535
 
607
 
    @classmethod
608
 
    def open_containing_tree_or_branch(klass, location):
609
 
        """Return the branch and working tree contained by a location.
610
 
 
611
 
        Returns (tree, branch, relpath).
612
 
        If there is no tree at containing the location, tree will be None.
613
 
        If there is no branch containing the location, an exception will be
614
 
        raised
615
 
        relpath is the portion of the path that is contained by the branch.
616
 
        """
617
 
        bzrdir, relpath = klass.open_containing(location)
618
 
        try:
619
 
            tree = bzrdir.open_workingtree()
620
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
621
 
            tree = None
622
 
            branch = bzrdir.open_branch()
623
 
        else:
624
 
            branch = tree.branch
625
 
        return tree, branch, relpath
626
 
 
627
536
    def open_repository(self, _unsupported=False):
628
537
        """Open the repository object at this BzrDir if one is present.
629
538
 
667
576
        workingtree and discards it, and that's somewhat expensive.) 
668
577
        """
669
578
        try:
670
 
            self.open_workingtree(recommend_upgrade=False)
 
579
            self.open_workingtree()
671
580
            return True
672
581
        except errors.NoWorkingTree:
673
582
            return False
674
583
 
675
 
    def _cloning_metadir(self):
 
584
    def cloning_metadir(self, basis=None):
 
585
        """Produce a metadir suitable for cloning with"""
 
586
        def related_repository(bzrdir):
 
587
            try:
 
588
                branch = bzrdir.open_branch()
 
589
                return branch.repository
 
590
            except errors.NotBranchError:
 
591
                source_branch = None
 
592
                return bzrdir.open_repository()
676
593
        result_format = self._format.__class__()
677
594
        try:
678
595
            try:
679
 
                branch = self.open_branch()
680
 
                source_repository = branch.repository
681
 
            except errors.NotBranchError:
682
 
                source_branch = None
683
 
                source_repository = self.open_repository()
 
596
                source_repository = related_repository(self)
 
597
            except errors.NoRepositoryPresent:
 
598
                if basis is None:
 
599
                    raise
 
600
                source_repository = related_repository(self)
684
601
            result_format.repository_format = source_repository._format
685
602
        except errors.NoRepositoryPresent:
686
 
            source_repository = None
687
 
        try:
688
 
            # TODO: Couldn't we just probe for the format in these cases,
689
 
            # rather than opening the whole tree?  It would be a little
690
 
            # faster. mbp 20070401
691
 
            tree = self.open_workingtree(recommend_upgrade=False)
692
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
693
 
            result_format.workingtree_format = None
694
 
        else:
695
 
            result_format.workingtree_format = tree._format.__class__()
696
 
        return result_format, source_repository
697
 
 
698
 
    def cloning_metadir(self):
699
 
        """Produce a metadir suitable for cloning or sprouting with.
700
 
 
701
 
        These operations may produce workingtrees (yes, even though they're
702
 
        "cloning" something that doesn't have a tree, so a viable workingtree
703
 
        format must be selected.
704
 
        """
705
 
        format, repository = self._cloning_metadir()
706
 
        if format._workingtree_format is None:
707
 
            if repository is None:
708
 
                return format
709
 
            tree_format = repository._format._matchingbzrdir.workingtree_format
710
 
            format.workingtree_format = tree_format.__class__()
711
 
        return format
712
 
 
713
 
    def checkout_metadir(self):
714
 
        return self.cloning_metadir()
715
 
 
716
 
    def sprout(self, url, revision_id=None, force_new_repo=False,
717
 
               recurse='down'):
 
603
            pass
 
604
        return result_format
 
605
 
 
606
    def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
718
607
        """Create a copy of this bzrdir prepared for use as a new line of
719
608
        development.
720
609
 
729
618
            itself to download less data.
730
619
        """
731
620
        self._make_tail(url)
732
 
        cloning_format = self.cloning_metadir()
 
621
        cloning_format = self.cloning_metadir(basis)
733
622
        result = cloning_format.initialize(url)
 
623
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
734
624
        try:
735
625
            source_branch = self.open_branch()
736
626
            source_repository = source_branch.repository
739
629
            try:
740
630
                source_repository = self.open_repository()
741
631
            except errors.NoRepositoryPresent:
742
 
                source_repository = None
 
632
                # copy the entire basis one if there is one
 
633
                # but there is no repository.
 
634
                source_repository = basis_repo
743
635
        if force_new_repo:
744
636
            result_repo = None
745
637
        else:
760
652
            result_repo = result.create_repository()
761
653
        if result_repo is not None:
762
654
            # fetch needed content into target.
 
655
            if basis_repo:
 
656
                # XXX FIXME RBC 20060214 need tests for this when the basis
 
657
                # is incomplete
 
658
                result_repo.fetch(basis_repo, revision_id=revision_id)
763
659
            if source_repository is not None:
764
660
                result_repo.fetch(source_repository, revision_id=revision_id)
765
661
        if source_branch is not None:
769
665
        # TODO: jam 20060426 we probably need a test in here in the
770
666
        #       case that the newly sprouted branch is a remote one
771
667
        if result_repo is None or result_repo.make_working_trees():
772
 
            wt = result.create_workingtree()
773
 
            wt.lock_write()
774
 
            try:
775
 
                if wt.path2id('') is None:
776
 
                    try:
777
 
                        wt.set_root_id(self.open_workingtree.get_root_id())
778
 
                    except errors.NoWorkingTree:
779
 
                        pass
780
 
            finally:
781
 
                wt.unlock()
782
 
        else:
783
 
            wt = None
784
 
        if recurse == 'down':
785
 
            if wt is not None:
786
 
                basis = wt.basis_tree()
787
 
                basis.lock_read()
788
 
                subtrees = basis.iter_references()
789
 
                recurse_branch = wt.branch
790
 
            elif source_branch is not None:
791
 
                basis = source_branch.basis_tree()
792
 
                basis.lock_read()
793
 
                subtrees = basis.iter_references()
794
 
                recurse_branch = source_branch
795
 
            else:
796
 
                subtrees = []
797
 
                basis = None
798
 
            try:
799
 
                for path, file_id in subtrees:
800
 
                    target = urlutils.join(url, urlutils.escape(path))
801
 
                    sublocation = source_branch.reference_parent(file_id, path)
802
 
                    sublocation.bzrdir.sprout(target,
803
 
                        basis.get_reference_revision(file_id, path),
804
 
                        force_new_repo=force_new_repo, recurse=recurse)
805
 
            finally:
806
 
                if basis is not None:
807
 
                    basis.unlock()
 
668
            result.create_workingtree()
808
669
        return result
809
670
 
810
671
 
814
675
    def __init__(self, _transport, _format):
815
676
        """See BzrDir.__init__."""
816
677
        super(BzrDirPreSplitOut, self).__init__(_transport, _format)
817
 
        assert self._format._lock_class == lockable_files.TransportLock
 
678
        assert self._format._lock_class == TransportLock
818
679
        assert self._format._lock_file_name == 'branch-lock'
819
 
        self._control_files = lockable_files.LockableFiles(
820
 
                                            self.get_branch_transport(None),
 
680
        self._control_files = LockableFiles(self.get_branch_transport(None),
821
681
                                            self._format._lock_file_name,
822
682
                                            self._format._lock_class)
823
683
 
825
685
        """Pre-splitout bzrdirs do not suffer from stale locks."""
826
686
        raise NotImplementedError(self.break_lock)
827
687
 
828
 
    def clone(self, url, revision_id=None, force_new_repo=False):
 
688
    def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
829
689
        """See BzrDir.clone()."""
830
690
        from bzrlib.workingtree import WorkingTreeFormat2
831
691
        self._make_tail(url)
832
692
        result = self._format._initialize_for_clone(url)
833
 
        self.open_repository().clone(result, revision_id=revision_id)
 
693
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
 
694
        self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
834
695
        from_branch = self.open_branch()
835
696
        from_branch.clone(result, revision_id=revision_id)
836
697
        try:
837
 
            self.open_workingtree().clone(result)
 
698
            self.open_workingtree().clone(result, basis=basis_tree)
838
699
        except errors.NotLocalUrl:
839
700
            # make a new one, this format always has to have one.
840
701
            try:
858
719
    def create_workingtree(self, revision_id=None):
859
720
        """See BzrDir.create_workingtree."""
860
721
        # this looks buggy but is not -really-
861
 
        # because this format creates the workingtree when the bzrdir is
862
 
        # created
863
722
        # clone and sprout will have set the revision_id
864
723
        # and that will have set it for us, its only
865
724
        # specific uses of create_workingtree in isolation
866
725
        # that can do wonky stuff here, and that only
867
726
        # happens for creating checkouts, which cannot be 
868
727
        # done on this format anyway. So - acceptable wart.
869
 
        result = self.open_workingtree(recommend_upgrade=False)
 
728
        result = self.open_workingtree()
870
729
        if revision_id is not None:
871
 
            if revision_id == _mod_revision.NULL_REVISION:
 
730
            if revision_id == bzrlib.revision.NULL_REVISION:
872
731
                result.set_parent_ids([])
873
732
            else:
874
733
                result.set_parent_ids([revision_id])
875
734
        return result
876
735
 
877
 
    def destroy_workingtree(self):
878
 
        """See BzrDir.destroy_workingtree."""
879
 
        raise errors.UnsupportedOperation(self.destroy_workingtree, self)
880
 
 
881
 
    def destroy_workingtree_metadata(self):
882
 
        """See BzrDir.destroy_workingtree_metadata."""
883
 
        raise errors.UnsupportedOperation(self.destroy_workingtree_metadata, 
884
 
                                          self)
885
 
 
886
736
    def get_branch_transport(self, branch_format):
887
737
        """See BzrDir.get_branch_transport()."""
888
738
        if branch_format is None:
928
778
        self._check_supported(format, unsupported)
929
779
        return format.open(self, _found=True)
930
780
 
931
 
    def sprout(self, url, revision_id=None, force_new_repo=False):
 
781
    def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
932
782
        """See BzrDir.sprout()."""
933
783
        from bzrlib.workingtree import WorkingTreeFormat2
934
784
        self._make_tail(url)
935
785
        result = self._format._initialize_for_clone(url)
 
786
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
936
787
        try:
937
 
            self.open_repository().clone(result, revision_id=revision_id)
 
788
            self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
938
789
        except errors.NoRepositoryPresent:
939
790
            pass
940
791
        try:
962
813
 
963
814
    def open_repository(self):
964
815
        """See BzrDir.open_repository."""
965
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat4
 
816
        from bzrlib.repository import RepositoryFormat4
966
817
        return RepositoryFormat4().open(self, _found=True)
967
818
 
968
819
 
974
825
 
975
826
    def open_repository(self):
976
827
        """See BzrDir.open_repository."""
977
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
 
828
        from bzrlib.repository import RepositoryFormat5
978
829
        return RepositoryFormat5().open(self, _found=True)
979
830
 
980
 
    def open_workingtree(self, _unsupported=False,
981
 
            recommend_upgrade=True):
 
831
    def open_workingtree(self, _unsupported=False):
982
832
        """See BzrDir.create_workingtree."""
983
833
        from bzrlib.workingtree import WorkingTreeFormat2
984
 
        wt_format = WorkingTreeFormat2()
985
 
        # we don't warn here about upgrades; that ought to be handled for the
986
 
        # bzrdir as a whole
987
 
        return wt_format.open(self, _found=True)
 
834
        return WorkingTreeFormat2().open(self, _found=True)
988
835
 
989
836
 
990
837
class BzrDir6(BzrDirPreSplitOut):
995
842
 
996
843
    def open_repository(self):
997
844
        """See BzrDir.open_repository."""
998
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
 
845
        from bzrlib.repository import RepositoryFormat6
999
846
        return RepositoryFormat6().open(self, _found=True)
1000
847
 
1001
 
    def open_workingtree(self, _unsupported=False,
1002
 
        recommend_upgrade=True):
 
848
    def open_workingtree(self, _unsupported=False):
1003
849
        """See BzrDir.create_workingtree."""
1004
 
        # we don't warn here about upgrades; that ought to be handled for the
1005
 
        # bzrdir as a whole
1006
850
        from bzrlib.workingtree import WorkingTreeFormat2
1007
851
        return WorkingTreeFormat2().open(self, _found=True)
1008
852
 
1022
866
 
1023
867
    def create_branch(self):
1024
868
        """See BzrDir.create_branch."""
1025
 
        return self._format.get_branch_format().initialize(self)
 
869
        from bzrlib.branch import BranchFormat
 
870
        return BranchFormat.get_default_format().initialize(self)
1026
871
 
1027
872
    def create_repository(self, shared=False):
1028
873
        """See BzrDir.create_repository."""
1031
876
    def create_workingtree(self, revision_id=None):
1032
877
        """See BzrDir.create_workingtree."""
1033
878
        from bzrlib.workingtree import WorkingTreeFormat
1034
 
        return self._format.workingtree_format.initialize(self, revision_id)
1035
 
 
1036
 
    def destroy_workingtree(self):
1037
 
        """See BzrDir.destroy_workingtree."""
1038
 
        wt = self.open_workingtree(recommend_upgrade=False)
1039
 
        repository = wt.branch.repository
1040
 
        empty = repository.revision_tree(_mod_revision.NULL_REVISION)
1041
 
        wt.revert([], old_tree=empty)
1042
 
        self.destroy_workingtree_metadata()
1043
 
 
1044
 
    def destroy_workingtree_metadata(self):
1045
 
        self.transport.delete_tree('checkout')
 
879
        return WorkingTreeFormat.get_default_format().initialize(self, revision_id)
1046
880
 
1047
881
    def _get_mkdir_mode(self):
1048
882
        """Figure out the mode to use when creating a bzrdir subdir."""
1049
 
        temp_control = lockable_files.LockableFiles(self.transport, '',
1050
 
                                     lockable_files.TransportLock)
 
883
        temp_control = LockableFiles(self.transport, '', TransportLock)
1051
884
        return temp_control._dir_mode
1052
885
 
1053
886
    def get_branch_transport(self, branch_format):
1107
940
                return True
1108
941
        except errors.NoRepositoryPresent:
1109
942
            pass
1110
 
        try:
1111
 
            if not isinstance(self.open_branch()._format,
1112
 
                              format.get_branch_format().__class__):
1113
 
                # the branch needs an upgrade.
1114
 
                return True
1115
 
        except errors.NotBranchError:
1116
 
            pass
1117
 
        try:
1118
 
            my_wt = self.open_workingtree(recommend_upgrade=False)
1119
 
            if not isinstance(my_wt._format,
1120
 
                              format.workingtree_format.__class__):
1121
 
                # the workingtree needs an upgrade.
1122
 
                return True
1123
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
1124
 
            pass
 
943
        # currently there are no other possible conversions for meta1 formats.
1125
944
        return False
1126
945
 
1127
946
    def open_branch(self, unsupported=False):
1138
957
        self._check_supported(format, unsupported)
1139
958
        return format.open(self, _found=True)
1140
959
 
1141
 
    def open_workingtree(self, unsupported=False,
1142
 
            recommend_upgrade=True):
 
960
    def open_workingtree(self, unsupported=False):
1143
961
        """See BzrDir.open_workingtree."""
1144
962
        from bzrlib.workingtree import WorkingTreeFormat
1145
963
        format = WorkingTreeFormat.find_format(self)
1146
 
        self._check_supported(format, unsupported,
1147
 
            recommend_upgrade,
1148
 
            basedir=self.root_transport.base)
 
964
        self._check_supported(format, unsupported)
1149
965
        return format.open(self, _found=True)
1150
966
 
1151
967
 
1246
1062
        """Initialize a new bzrdir in the base directory of a Transport."""
1247
1063
        # Since we don't have a .bzr directory, inherit the
1248
1064
        # mode from the root directory
1249
 
        temp_control = lockable_files.LockableFiles(transport,
1250
 
                            '', lockable_files.TransportLock)
 
1065
        temp_control = LockableFiles(transport, '', TransportLock)
1251
1066
        temp_control._transport.mkdir('.bzr',
1252
1067
                                      # FIXME: RBC 20060121 don't peek under
1253
1068
                                      # the covers
1262
1077
                      ('branch-format', self.get_format_string()),
1263
1078
                      ]
1264
1079
        # NB: no need to escape relative paths that are url safe.
1265
 
        control_files = lockable_files.LockableFiles(control,
1266
 
                            self._lock_file_name, self._lock_class)
 
1080
        control_files = LockableFiles(control, self._lock_file_name, 
 
1081
                                      self._lock_class)
1267
1082
        control_files.create_lock()
1268
1083
        control_files.lock_write()
1269
1084
        try:
1311
1126
        _found is a private parameter, do not use it.
1312
1127
        """
1313
1128
        if not _found:
1314
 
            found_format = BzrDirFormat.find_format(transport)
1315
 
            if not isinstance(found_format, self.__class__):
1316
 
                raise AssertionError("%s was asked to open %s, but it seems to need "
1317
 
                        "format %s" 
1318
 
                        % (self, transport, found_format))
 
1129
            assert isinstance(BzrDirFormat.find_format(transport),
 
1130
                              self.__class__)
1319
1131
        return self._open(transport)
1320
1132
 
1321
1133
    def _open(self, transport):
1332
1144
 
1333
1145
    @classmethod
1334
1146
    def register_control_format(klass, format):
1335
 
        """Register a format that does not use '.bzr' for its control dir.
 
1147
        """Register a format that does not use '.bzrdir' for its control dir.
1336
1148
 
1337
1149
        TODO: This should be pulled up into a 'ControlDirFormat' base class
1338
1150
        which BzrDirFormat can inherit from, and renamed to register_format 
1342
1154
        klass._control_formats.append(format)
1343
1155
 
1344
1156
    @classmethod
1345
 
    @symbol_versioning.deprecated_method(symbol_versioning.zero_fourteen)
1346
1157
    def set_default_format(klass, format):
1347
 
        klass._set_default_format(format)
1348
 
 
1349
 
    @classmethod
1350
 
    def _set_default_format(klass, format):
1351
 
        """Set default format (for testing behavior of defaults only)"""
1352
1158
        klass._default_format = format
1353
1159
 
1354
1160
    def __str__(self):
1364
1170
        klass._control_formats.remove(format)
1365
1171
 
1366
1172
 
 
1173
# register BzrDirFormat as a control format
 
1174
BzrDirFormat.register_control_format(BzrDirFormat)
 
1175
 
 
1176
 
1367
1177
class BzrDirFormat4(BzrDirFormat):
1368
1178
    """Bzr dir format 4.
1369
1179
 
1377
1187
    removed in format 5; write support for this format has been removed.
1378
1188
    """
1379
1189
 
1380
 
    _lock_class = lockable_files.TransportLock
 
1190
    _lock_class = TransportLock
1381
1191
 
1382
1192
    def get_format_string(self):
1383
1193
        """See BzrDirFormat.get_format_string()."""
1411
1221
 
1412
1222
    def __return_repository_format(self):
1413
1223
        """Circular import protection."""
1414
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat4
 
1224
        from bzrlib.repository import RepositoryFormat4
1415
1225
        return RepositoryFormat4()
1416
1226
    repository_format = property(__return_repository_format)
1417
1227
 
1427
1237
       Unhashed stores in the repository.
1428
1238
    """
1429
1239
 
1430
 
    _lock_class = lockable_files.TransportLock
 
1240
    _lock_class = TransportLock
1431
1241
 
1432
1242
    def get_format_string(self):
1433
1243
        """See BzrDirFormat.get_format_string()."""
1451
1261
        Except when they are being cloned.
1452
1262
        """
1453
1263
        from bzrlib.branch import BzrBranchFormat4
1454
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
 
1264
        from bzrlib.repository import RepositoryFormat5
1455
1265
        from bzrlib.workingtree import WorkingTreeFormat2
1456
1266
        result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1457
1267
        RepositoryFormat5().initialize(result, _internal=True)
1471
1281
 
1472
1282
    def __return_repository_format(self):
1473
1283
        """Circular import protection."""
1474
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
 
1284
        from bzrlib.repository import RepositoryFormat5
1475
1285
        return RepositoryFormat5()
1476
1286
    repository_format = property(__return_repository_format)
1477
1287
 
1486
1296
     - Format 6 repositories [always]
1487
1297
    """
1488
1298
 
1489
 
    _lock_class = lockable_files.TransportLock
 
1299
    _lock_class = TransportLock
1490
1300
 
1491
1301
    def get_format_string(self):
1492
1302
        """See BzrDirFormat.get_format_string()."""
1510
1320
        Except when they are being cloned.
1511
1321
        """
1512
1322
        from bzrlib.branch import BzrBranchFormat4
1513
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
 
1323
        from bzrlib.repository import RepositoryFormat6
1514
1324
        from bzrlib.workingtree import WorkingTreeFormat2
1515
1325
        result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1516
1326
        RepositoryFormat6().initialize(result, _internal=True)
1530
1340
 
1531
1341
    def __return_repository_format(self):
1532
1342
        """Circular import protection."""
1533
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
 
1343
        from bzrlib.repository import RepositoryFormat6
1534
1344
        return RepositoryFormat6()
1535
1345
    repository_format = property(__return_repository_format)
1536
1346
 
1546
1356
     - Format 7 repositories [optional]
1547
1357
    """
1548
1358
 
1549
 
    _lock_class = lockdir.LockDir
1550
 
 
1551
 
    def __init__(self):
1552
 
        self._workingtree_format = None
1553
 
        self._branch_format = None
1554
 
 
1555
 
    def __eq__(self, other):
1556
 
        if other.__class__ is not self.__class__:
1557
 
            return False
1558
 
        if other.repository_format != self.repository_format:
1559
 
            return False
1560
 
        if other.workingtree_format != self.workingtree_format:
1561
 
            return False
1562
 
        return True
1563
 
 
1564
 
    def __ne__(self, other):
1565
 
        return not self == other
1566
 
 
1567
 
    def get_branch_format(self):
1568
 
        if self._branch_format is None:
1569
 
            from bzrlib.branch import BranchFormat
1570
 
            self._branch_format = BranchFormat.get_default_format()
1571
 
        return self._branch_format
1572
 
 
1573
 
    def set_branch_format(self, format):
1574
 
        self._branch_format = format
 
1359
    _lock_class = LockDir
1575
1360
 
1576
1361
    def get_converter(self, format=None):
1577
1362
        """See BzrDirFormat.get_converter()."""
1607
1392
 
1608
1393
    repository_format = property(__return_repository_format, __set_repository_format)
1609
1394
 
1610
 
    def __get_workingtree_format(self):
1611
 
        if self._workingtree_format is None:
1612
 
            from bzrlib.workingtree import WorkingTreeFormat
1613
 
            self._workingtree_format = WorkingTreeFormat.get_default_format()
1614
 
        return self._workingtree_format
1615
 
 
1616
 
    def __set_workingtree_format(self, wt_format):
1617
 
        self._workingtree_format = wt_format
1618
 
 
1619
 
    workingtree_format = property(__get_workingtree_format,
1620
 
                                  __set_workingtree_format)
1621
 
 
1622
 
 
1623
 
# Register bzr control format
1624
 
BzrDirFormat.register_control_format(BzrDirFormat)
1625
 
 
1626
 
# Register bzr formats
 
1395
 
1627
1396
BzrDirFormat.register_format(BzrDirFormat4())
1628
1397
BzrDirFormat.register_format(BzrDirFormat5())
1629
1398
BzrDirFormat.register_format(BzrDirFormat6())
1630
1399
__default_format = BzrDirMetaFormat1()
1631
1400
BzrDirFormat.register_format(__default_format)
1632
 
BzrDirFormat._default_format = __default_format
 
1401
BzrDirFormat.set_default_format(__default_format)
1633
1402
 
1634
1403
 
1635
1404
class BzrDirTestProviderAdapter(object):
1647
1416
        self._formats = formats
1648
1417
    
1649
1418
    def adapt(self, test):
1650
 
        result = unittest.TestSuite()
 
1419
        result = TestSuite()
1651
1420
        for format in self._formats:
1652
1421
            new_test = deepcopy(test)
1653
1422
            new_test.transport_server = self._transport_server
1751
1520
        self.bzrdir.transport.delete_tree('text-store')
1752
1521
 
1753
1522
    def _convert_working_inv(self):
1754
 
        inv = xml4.serializer_v4.read_inventory(
1755
 
                    self.branch.control_files.get('inventory'))
1756
 
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
 
1523
        inv = serializer_v4.read_inventory(self.branch.control_files.get('inventory'))
 
1524
        new_inv_xml = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
1757
1525
        # FIXME inventory is a working tree change.
1758
1526
        self.branch.control_files.put('inventory', StringIO(new_inv_xml))
1759
1527
 
1785
1553
                                                      prefixed=False,
1786
1554
                                                      compressed=True))
1787
1555
        try:
1788
 
            transaction = WriteTransaction()
 
1556
            transaction = bzrlib.transactions.WriteTransaction()
1789
1557
            for i, rev_id in enumerate(self.converted_revs):
1790
1558
                self.pb.update('write revision', i, len(self.converted_revs))
1791
1559
                _revision_store.add_revision(self.revisions[rev_id], transaction)
1817
1585
    def _load_old_inventory(self, rev_id):
1818
1586
        assert rev_id not in self.converted_revs
1819
1587
        old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
1820
 
        inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
 
1588
        inv = serializer_v4.read_inventory_from_string(old_inv_xml)
1821
1589
        inv.revision_id = rev_id
1822
1590
        rev = self.revisions[rev_id]
1823
1591
        if rev.inventory_sha1:
1828
1596
    def _load_updated_inventory(self, rev_id):
1829
1597
        assert rev_id in self.converted_revs
1830
1598
        inv_xml = self.inv_weave.get_text(rev_id)
1831
 
        inv = xml5.serializer_v5.read_inventory_from_string(inv_xml)
 
1599
        inv = bzrlib.xml5.serializer_v5.read_inventory_from_string(inv_xml)
1832
1600
        return inv
1833
1601
 
1834
1602
    def _convert_one_rev(self, rev_id):
1850
1618
                assert getattr(ie, 'revision', None) is not None, \
1851
1619
                    'no revision on {%s} in {%s}' % \
1852
1620
                    (file_id, rev.revision_id)
1853
 
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
 
1621
        new_inv_xml = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
1854
1622
        new_inv_sha1 = sha_string(new_inv_xml)
1855
1623
        self.inv_weave.add_lines(rev.revision_id, 
1856
1624
                                 present_parents,
1889
1657
                                                  entry_vf=w)
1890
1658
        for old_revision in previous_entries:
1891
1659
                # if this fails, its a ghost ?
1892
 
                assert old_revision in self.converted_revs, \
1893
 
                    "Revision {%s} not in converted_revs" % old_revision
 
1660
                assert old_revision in self.converted_revs 
1894
1661
        self.snapshot_ie(previous_entries, ie, w, rev_id)
1895
1662
        del ie.text_id
1896
1663
        assert getattr(ie, 'revision', None) is not None
1983
1750
 
1984
1751
    def convert(self, to_convert, pb):
1985
1752
        """See Converter.convert()."""
1986
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat7
1987
 
        from bzrlib.branch import BzrBranchFormat5
1988
1753
        self.bzrdir = to_convert
1989
1754
        self.pb = pb
1990
1755
        self.count = 0
2019
1784
        # we hard code the formats here because we are converting into
2020
1785
        # the meta format. The meta format upgrader can take this to a 
2021
1786
        # future format within each component.
2022
 
        self.put_format('repository', RepositoryFormat7())
 
1787
        self.put_format('repository', bzrlib.repository.RepositoryFormat7())
2023
1788
        for entry in repository_names:
2024
1789
            self.move_entry('repository', entry)
2025
1790
 
2026
1791
        self.step('Upgrading branch      ')
2027
1792
        self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
2028
1793
        self.make_lock('branch')
2029
 
        self.put_format('branch', BzrBranchFormat5())
 
1794
        self.put_format('branch', bzrlib.branch.BzrBranchFormat5())
2030
1795
        branch_files = [('revision-history', True),
2031
1796
                        ('branch-name', True),
2032
1797
                        ('parent', False)]
2052
1817
                if name in bzrcontents:
2053
1818
                    self.bzrdir.transport.delete(name)
2054
1819
        else:
2055
 
            from bzrlib.workingtree import WorkingTreeFormat3
2056
1820
            self.step('Upgrading working tree')
2057
1821
            self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
2058
1822
            self.make_lock('checkout')
2059
1823
            self.put_format(
2060
 
                'checkout', WorkingTreeFormat3())
 
1824
                'checkout', bzrlib.workingtree.WorkingTreeFormat3())
2061
1825
            self.bzrdir.transport.delete_multi(
2062
1826
                self.garbage_inventories, self.pb)
2063
1827
            for entry in checkout_files:
2072
1836
    def make_lock(self, name):
2073
1837
        """Make a lock for the new control dir name."""
2074
1838
        self.step('Make %s lock' % name)
2075
 
        ld = lockdir.LockDir(self.bzrdir.transport,
2076
 
                             '%s/lock' % name,
2077
 
                             file_modebits=self.file_mode,
2078
 
                             dir_modebits=self.dir_mode)
 
1839
        ld = LockDir(self.bzrdir.transport, 
 
1840
                     '%s/lock' % name,
 
1841
                     file_modebits=self.file_mode,
 
1842
                     dir_modebits=self.dir_mode)
2079
1843
        ld.create()
2080
1844
 
2081
1845
    def move_entry(self, new_dir, entry):
2120
1884
                self.pb.note('starting repository conversion')
2121
1885
                converter = CopyConverter(self.target_format.repository_format)
2122
1886
                converter.convert(repo, pb)
2123
 
        try:
2124
 
            branch = self.bzrdir.open_branch()
2125
 
        except errors.NotBranchError:
2126
 
            pass
2127
 
        else:
2128
 
            # TODO: conversions of Branch and Tree should be done by
2129
 
            # InterXFormat lookups
2130
 
            # Avoid circular imports
2131
 
            from bzrlib import branch as _mod_branch
2132
 
            if (branch._format.__class__ is _mod_branch.BzrBranchFormat5 and
2133
 
                self.target_format.get_branch_format().__class__ is
2134
 
                _mod_branch.BzrBranchFormat6):
2135
 
                branch_converter = _mod_branch.Converter5to6()
2136
 
                branch_converter.convert(branch)
2137
 
        try:
2138
 
            tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
2139
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
2140
 
            pass
2141
 
        else:
2142
 
            # TODO: conversions of Branch and Tree should be done by
2143
 
            # InterXFormat lookups
2144
 
            if (isinstance(tree, workingtree.WorkingTree3) and
2145
 
                not isinstance(tree, workingtree_4.WorkingTree4) and
2146
 
                isinstance(self.target_format.workingtree_format,
2147
 
                    workingtree_4.WorkingTreeFormat4)):
2148
 
                workingtree_4.Converter3to4().convert(tree)
2149
1887
        return to_convert
2150
 
 
2151
 
 
2152
 
class BzrDirFormatInfo(object):
2153
 
 
2154
 
    def __init__(self, native, deprecated, hidden):
2155
 
        self.deprecated = deprecated
2156
 
        self.native = native
2157
 
        self.hidden = hidden
2158
 
 
2159
 
 
2160
 
class BzrDirFormatRegistry(registry.Registry):
2161
 
    """Registry of user-selectable BzrDir subformats.
2162
 
    
2163
 
    Differs from BzrDirFormat._control_formats in that it provides sub-formats,
2164
 
    e.g. BzrDirMeta1 with weave repository.  Also, it's more user-oriented.
2165
 
    """
2166
 
 
2167
 
    def register_metadir(self, key,
2168
 
             repository_format, help, native=True, deprecated=False,
2169
 
             branch_format=None,
2170
 
             tree_format=None,
2171
 
             hidden=False):
2172
 
        """Register a metadir subformat.
2173
 
 
2174
 
        These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2175
 
        by the Repository format.
2176
 
 
2177
 
        :param repository_format: The fully-qualified repository format class
2178
 
            name as a string.
2179
 
        :param branch_format: Fully-qualified branch format class name as
2180
 
            a string.
2181
 
        :param tree_format: Fully-qualified tree format class name as
2182
 
            a string.
2183
 
        """
2184
 
        # This should be expanded to support setting WorkingTree and Branch
2185
 
        # formats, once BzrDirMetaFormat1 supports that.
2186
 
        def _load(full_name):
2187
 
            mod_name, factory_name = full_name.rsplit('.', 1)
2188
 
            try:
2189
 
                mod = __import__(mod_name, globals(), locals(),
2190
 
                        [factory_name])
2191
 
            except ImportError, e:
2192
 
                raise ImportError('failed to load %s: %s' % (full_name, e))
2193
 
            try:
2194
 
                factory = getattr(mod, factory_name)
2195
 
            except AttributeError:
2196
 
                raise AttributeError('no factory %s in module %r'
2197
 
                    % (full_name, mod))
2198
 
            return factory()
2199
 
 
2200
 
        def helper():
2201
 
            bd = BzrDirMetaFormat1()
2202
 
            if branch_format is not None:
2203
 
                bd.set_branch_format(_load(branch_format))
2204
 
            if tree_format is not None:
2205
 
                bd.workingtree_format = _load(tree_format)
2206
 
            if repository_format is not None:
2207
 
                bd.repository_format = _load(repository_format)
2208
 
            return bd
2209
 
        self.register(key, helper, help, native, deprecated, hidden)
2210
 
 
2211
 
    def register(self, key, factory, help, native=True, deprecated=False,
2212
 
                 hidden=False):
2213
 
        """Register a BzrDirFormat factory.
2214
 
        
2215
 
        The factory must be a callable that takes one parameter: the key.
2216
 
        It must produce an instance of the BzrDirFormat when called.
2217
 
 
2218
 
        This function mainly exists to prevent the info object from being
2219
 
        supplied directly.
2220
 
        """
2221
 
        registry.Registry.register(self, key, factory, help, 
2222
 
            BzrDirFormatInfo(native, deprecated, hidden))
2223
 
 
2224
 
    def register_lazy(self, key, module_name, member_name, help, native=True,
2225
 
                      deprecated=False, hidden=False):
2226
 
        registry.Registry.register_lazy(self, key, module_name, member_name, 
2227
 
            help, BzrDirFormatInfo(native, deprecated, hidden))
2228
 
 
2229
 
    def set_default(self, key):
2230
 
        """Set the 'default' key to be a clone of the supplied key.
2231
 
        
2232
 
        This method must be called once and only once.
2233
 
        """
2234
 
        registry.Registry.register(self, 'default', self.get(key), 
2235
 
            self.get_help(key), info=self.get_info(key))
2236
 
 
2237
 
    def set_default_repository(self, key):
2238
 
        """Set the FormatRegistry default and Repository default.
2239
 
        
2240
 
        This is a transitional method while Repository.set_default_format
2241
 
        is deprecated.
2242
 
        """
2243
 
        if 'default' in self:
2244
 
            self.remove('default')
2245
 
        self.set_default(key)
2246
 
        format = self.get('default')()
2247
 
        assert isinstance(format, BzrDirMetaFormat1)
2248
 
 
2249
 
    def make_bzrdir(self, key):
2250
 
        return self.get(key)()
2251
 
 
2252
 
    def help_topic(self, topic):
2253
 
        output = textwrap.dedent("""\
2254
 
            Bazaar directory formats
2255
 
            ------------------------
2256
 
 
2257
 
            These formats can be used for creating branches, working trees, and
2258
 
            repositories.
2259
 
 
2260
 
            """)
2261
 
        default_help = self.get_help('default')
2262
 
        help_pairs = []
2263
 
        for key in self.keys():
2264
 
            if key == 'default':
2265
 
                continue
2266
 
            help = self.get_help(key)
2267
 
            if help == default_help:
2268
 
                default_realkey = key
2269
 
            else:
2270
 
                help_pairs.append((key, help))
2271
 
 
2272
 
        def wrapped(key, help, info):
2273
 
            if info.native:
2274
 
                help = '(native) ' + help
2275
 
            return '  %s:\n%s\n\n' % (key, 
2276
 
                    textwrap.fill(help, initial_indent='    ', 
2277
 
                    subsequent_indent='    '))
2278
 
        output += wrapped('%s/default' % default_realkey, default_help,
2279
 
                          self.get_info('default'))
2280
 
        deprecated_pairs = []
2281
 
        for key, help in help_pairs:
2282
 
            info = self.get_info(key)
2283
 
            if info.hidden:
2284
 
                continue
2285
 
            elif info.deprecated:
2286
 
                deprecated_pairs.append((key, help))
2287
 
            else:
2288
 
                output += wrapped(key, help, info)
2289
 
        if len(deprecated_pairs) > 0:
2290
 
            output += "Deprecated formats\n------------------\n\n"
2291
 
            for key, help in deprecated_pairs:
2292
 
                info = self.get_info(key)
2293
 
                output += wrapped(key, help, info)
2294
 
 
2295
 
        return output
2296
 
 
2297
 
 
2298
 
format_registry = BzrDirFormatRegistry()
2299
 
format_registry.register('weave', BzrDirFormat6,
2300
 
    'Pre-0.8 format.  Slower than knit and does not'
2301
 
    ' support checkouts or shared repositories.',
2302
 
    deprecated=True)
2303
 
format_registry.register_metadir('knit',
2304
 
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2305
 
    'Format using knits.  Recommended for interoperation with bzr <= 0.14.',
2306
 
    branch_format='bzrlib.branch.BzrBranchFormat5',
2307
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat3')
2308
 
format_registry.register_metadir('metaweave',
2309
 
    'bzrlib.repofmt.weaverepo.RepositoryFormat7',
2310
 
    'Transitional format in 0.8.  Slower than knit.',
2311
 
    branch_format='bzrlib.branch.BzrBranchFormat5',
2312
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat3',
2313
 
    deprecated=True)
2314
 
format_registry.register_metadir('dirstate',
2315
 
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2316
 
    help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
2317
 
        'above when accessed over the network.',
2318
 
    branch_format='bzrlib.branch.BzrBranchFormat5',
2319
 
    # this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
2320
 
    # directly from workingtree_4 triggers a circular import.
2321
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2322
 
    )
2323
 
format_registry.register_metadir('dirstate-tags',
2324
 
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2325
 
    help='New in 0.15: Fast local operations and improved scaling for '
2326
 
        'network operations. Additionally adds support for tags.'
2327
 
        ' Incompatible with bzr < 0.15.',
2328
 
    branch_format='bzrlib.branch.BzrBranchFormat6',
2329
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2330
 
    )
2331
 
format_registry.register_metadir('dirstate-with-subtree',
2332
 
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
2333
 
    help='New in 0.15: Fast local operations and improved scaling for '
2334
 
        'network operations. Additionally adds support for versioning nested '
2335
 
        'bzr branches. Incompatible with bzr < 0.15.',
2336
 
    branch_format='bzrlib.branch.BzrBranchFormat6',
2337
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2338
 
    hidden=True,
2339
 
    )
2340
 
format_registry.set_default('dirstate')