/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-13 02:09:37 UTC
  • mto: This revision was merged to the branch mainline in revision 2004.
  • Revision ID: john@arbash-meinel.com-20060913020937-2df2f49f9a28ec43
Update HACKING and docstrings

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
22
22
 
23
23
# TODO: remove unittest dependency; put that stuff inside the test suite
24
24
 
25
 
# TODO: The Format probe_transport seems a bit redundant with just trying to
26
 
# open the bzrdir. -- mbp
27
 
#
28
 
# TODO: Can we move specific formats into separate modules to make this file
29
 
# smaller?
30
 
 
 
25
from copy import deepcopy
31
26
from cStringIO import StringIO
32
27
import os
33
 
import textwrap
34
 
 
35
 
from bzrlib.lazy_import import lazy_import
36
 
lazy_import(globals(), """
37
 
from copy import deepcopy
38
28
from stat import S_ISDIR
39
 
import unittest
 
29
from unittest import TestSuite
40
30
 
41
31
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
 
    )
 
32
import bzrlib.errors as errors
 
33
from bzrlib.lockable_files import LockableFiles, TransportLock
 
34
from bzrlib.lockdir import LockDir
56
35
from bzrlib.osutils import (
57
 
    safe_unicode,
58
 
    sha_strings,
59
 
    sha_string,
60
 
    )
 
36
                            abspath,
 
37
                            pathjoin,
 
38
                            safe_unicode,
 
39
                            sha_strings,
 
40
                            sha_string,
 
41
                            )
 
42
import bzrlib.revision
61
43
from bzrlib.store.revision.text import TextRevisionStore
62
44
from bzrlib.store.text import TextStore
63
45
from bzrlib.store.versioned import WeaveStore
 
46
from bzrlib.trace import mutter
64
47
from bzrlib.transactions import WriteTransaction
65
 
from bzrlib.transport import (
66
 
    do_catching_redirections,
67
 
    get_transport,
68
 
    )
 
48
from bzrlib.transport import get_transport
 
49
from bzrlib.transport.local import LocalTransport
 
50
import bzrlib.urlutils as urlutils
69
51
from bzrlib.weave import Weave
70
 
""")
71
 
 
72
 
from bzrlib.trace import (
73
 
    mutter,
74
 
    note,
75
 
    )
76
 
from bzrlib.transport.local import LocalTransport
 
52
from bzrlib.xml4 import serializer_v4
 
53
import bzrlib.xml5
77
54
 
78
55
 
79
56
class BzrDir(object):
116
93
        source_repo_format.check_conversion_target(target_repo_format)
117
94
 
118
95
    @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.
 
96
    def _check_supported(format, allow_unsupported):
 
97
        """Check whether format is a supported format.
 
98
 
 
99
        If allow_unsupported is True, this is a no-op.
134
100
        """
135
 
        # TODO: perhaps move this into a base Format class; it's not BzrDir
136
 
        # specific. mbp 20070323
137
101
        if not allow_unsupported and not format.is_supported():
138
102
            # see open_downlevel to open legacy branches.
139
103
            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
104
 
146
 
    def clone(self, url, revision_id=None, force_new_repo=False):
 
105
    def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
147
106
        """Clone this bzrdir and its contents to url verbatim.
148
107
 
149
108
        If urls last component does not exist, it will be created.
154
113
                               even if one is available.
155
114
        """
156
115
        self._make_tail(url)
 
116
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
157
117
        result = self._format.initialize(url)
158
118
        try:
159
119
            local_repo = self.find_repository()
164
124
            if force_new_repo:
165
125
                result_repo = local_repo.clone(
166
126
                    result,
167
 
                    revision_id=revision_id)
 
127
                    revision_id=revision_id,
 
128
                    basis=basis_repo)
168
129
                result_repo.set_make_working_trees(local_repo.make_working_trees())
169
130
            else:
170
131
                try:
171
132
                    result_repo = result.find_repository()
172
133
                    # fetch content this dir needs.
 
134
                    if basis_repo:
 
135
                        # XXX FIXME RBC 20060214 need tests for this when the basis
 
136
                        # is incomplete
 
137
                        result_repo.fetch(basis_repo, revision_id=revision_id)
173
138
                    result_repo.fetch(local_repo, revision_id=revision_id)
174
139
                except errors.NoRepositoryPresent:
175
140
                    # needed to make one anyway.
176
141
                    result_repo = local_repo.clone(
177
142
                        result,
178
 
                        revision_id=revision_id)
 
143
                        revision_id=revision_id,
 
144
                        basis=basis_repo)
179
145
                    result_repo.set_make_working_trees(local_repo.make_working_trees())
180
146
        # 1 if there is a branch present
181
147
        #   make sure its content is available in the target repository
185
151
        except errors.NotBranchError:
186
152
            pass
187
153
        try:
188
 
            self.open_workingtree().clone(result)
 
154
            self.open_workingtree().clone(result, basis=basis_tree)
189
155
        except (errors.NoWorkingTree, errors.NotLocalUrl):
190
156
            pass
191
157
        return result
192
158
 
 
159
    def _get_basis_components(self, basis):
 
160
        """Retrieve the basis components that are available at basis."""
 
161
        if basis is None:
 
162
            return None, None, None
 
163
        try:
 
164
            basis_tree = basis.open_workingtree()
 
165
            basis_branch = basis_tree.branch
 
166
            basis_repo = basis_branch.repository
 
167
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
168
            basis_tree = None
 
169
            try:
 
170
                basis_branch = basis.open_branch()
 
171
                basis_repo = basis_branch.repository
 
172
            except errors.NotBranchError:
 
173
                basis_branch = None
 
174
                try:
 
175
                    basis_repo = basis.open_repository()
 
176
                except errors.NoRepositoryPresent:
 
177
                    basis_repo = None
 
178
        return basis_repo, basis_branch, basis_tree
 
179
 
193
180
    # TODO: This should be given a Transport, and should chdir up; otherwise
194
181
    # this will open a new connection.
195
182
    def _make_tail(self, url):
196
183
        head, tail = urlutils.split(url)
197
184
        if tail and tail != '.':
198
 
            t = get_transport(head)
 
185
            t = bzrlib.transport.get_transport(head)
199
186
            try:
200
187
                t.mkdir(tail)
201
188
            except errors.FileExists:
203
190
 
204
191
    # TODO: Should take a Transport
205
192
    @classmethod
206
 
    def create(cls, base, format=None):
 
193
    def create(cls, base):
207
194
        """Create a new BzrDir at the url 'base'.
208
195
        
209
196
        This will call the current default formats initialize with base
210
197
        as the only parameter.
211
198
 
212
 
        :param format: If supplied, the format of branch to create.  If not
213
 
            supplied, the default is used.
 
199
        If you need a specific format, consider creating an instance
 
200
        of that and calling initialize().
214
201
        """
215
202
        if cls is not BzrDir:
216
 
            raise AssertionError("BzrDir.create always creates the default"
217
 
                " format, not one of %r" % cls)
 
203
            raise AssertionError("BzrDir.create always creates the default format, "
 
204
                    "not one of %r" % cls)
218
205
        head, tail = urlutils.split(base)
219
206
        if tail and tail != '.':
220
 
            t = get_transport(head)
 
207
            t = bzrlib.transport.get_transport(head)
221
208
            try:
222
209
                t.mkdir(tail)
223
210
            except errors.FileExists:
224
211
                pass
225
 
        if format is None:
226
 
            format = BzrDirFormat.get_default_format()
227
 
        return format.initialize(safe_unicode(base))
 
212
        return BzrDirFormat.get_default_format().initialize(safe_unicode(base))
228
213
 
229
214
    def create_branch(self):
230
215
        """Create a branch in this BzrDir.
235
220
        raise NotImplementedError(self.create_branch)
236
221
 
237
222
    @staticmethod
238
 
    def create_branch_and_repo(base, force_new_repo=False, format=None):
 
223
    def create_branch_and_repo(base, force_new_repo=False):
239
224
        """Create a new BzrDir, Branch and Repository at the url 'base'.
240
225
 
241
226
        This will use the current default BzrDirFormat, and use whatever 
248
233
        :param base: The URL to create the branch at.
249
234
        :param force_new_repo: If True a new repository is always created.
250
235
        """
251
 
        bzrdir = BzrDir.create(base, format)
 
236
        bzrdir = BzrDir.create(base)
252
237
        bzrdir._find_or_create_repository(force_new_repo)
253
238
        return bzrdir.create_branch()
254
239
 
292
277
            t = get_transport(safe_unicode(base))
293
278
            if not isinstance(t, LocalTransport):
294
279
                raise errors.NotLocalUrl(base)
295
 
        bzrdir = BzrDir.create(base, format)
 
280
        if format is None:
 
281
            bzrdir = BzrDir.create(base)
 
282
        else:
 
283
            bzrdir = format.initialize(base)
296
284
        repo = bzrdir._find_or_create_repository(force_new_repo)
297
285
        result = bzrdir.create_branch()
298
286
        if force_new_tree or (repo.make_working_trees() and 
304
292
        return result
305
293
        
306
294
    @staticmethod
307
 
    def create_repository(base, shared=False, format=None):
 
295
    def create_repository(base, shared=False):
308
296
        """Create a new BzrDir and Repository at the url 'base'.
309
297
 
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.
 
298
        This will use the current default BzrDirFormat, and use whatever 
 
299
        repository format that that uses for bzrdirformat.create_repository.
313
300
 
314
 
        :param shared: Create a shared repository rather than a standalone
 
301
        ;param shared: Create a shared repository rather than a standalone
315
302
                       repository.
316
303
        The Repository object is returned.
317
304
 
319
306
        it should take no parameters and construct whatever repository format
320
307
        that child class desires.
321
308
        """
322
 
        bzrdir = BzrDir.create(base, format)
 
309
        bzrdir = BzrDir.create(base)
323
310
        return bzrdir.create_repository(shared)
324
311
 
325
312
    @staticmethod
326
 
    def create_standalone_workingtree(base, format=None):
 
313
    def create_standalone_workingtree(base):
327
314
        """Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
328
315
 
329
316
        'base' must be a local path or a file:// url.
332
319
        repository format that that uses for bzrdirformat.create_workingtree,
333
320
        create_branch and create_repository.
334
321
 
335
 
        :return: The WorkingTree object.
 
322
        The WorkingTree object is returned.
336
323
        """
337
324
        t = get_transport(safe_unicode(base))
338
325
        if not isinstance(t, LocalTransport):
339
326
            raise errors.NotLocalUrl(base)
340
327
        bzrdir = BzrDir.create_branch_and_repo(safe_unicode(base),
341
 
                                               force_new_repo=True,
342
 
                                               format=format).bzrdir
 
328
                                               force_new_repo=True).bzrdir
343
329
        return bzrdir.create_workingtree()
344
330
 
345
331
    def create_workingtree(self, revision_id=None):
349
335
        """
350
336
        raise NotImplementedError(self.create_workingtree)
351
337
 
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
338
    def find_repository(self):
387
339
        """Find the repository that should be used for a_bzrdir.
388
340
 
450
402
        """Get the transport for use by workingtree format in this BzrDir.
451
403
 
452
404
        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.
 
405
        IncompatibleFormat if the workingtree format they are given has
 
406
        a format string, and vice versa.
455
407
 
456
408
        If workingtree_format is None, the transport is returned with no 
457
409
        checking. if it is not None, then the returned transport is
514
466
        _unsupported is a private parameter to the BzrDir class.
515
467
        """
516
468
        t = get_transport(base)
517
 
        return BzrDir.open_from_transport(t, _unsupported=_unsupported)
518
 
 
519
 
    @staticmethod
520
 
    def open_from_transport(transport, _unsupported=False):
521
 
        """Open a bzrdir within a particular directory.
522
 
 
523
 
        :param transport: Transport containing the bzrdir.
524
 
        :param _unsupported: private.
525
 
        """
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
 
 
 
469
        # mutter("trying to open %r with transport %r", base, t)
 
470
        format = BzrDirFormat.find_format(t)
556
471
        BzrDir._check_supported(format, _unsupported)
557
 
        return format.open(transport, _found=True)
 
472
        return format.open(t, _found=True)
558
473
 
559
474
    def open_branch(self, unsupported=False):
560
475
        """Open the branch object at this BzrDir if one is present.
594
509
        url = a_transport.base
595
510
        while True:
596
511
            try:
597
 
                result = BzrDir.open_from_transport(a_transport)
598
 
                return result, urlutils.unescape(a_transport.relpath(url))
 
512
                format = BzrDirFormat.find_format(a_transport)
 
513
                BzrDir._check_supported(format, False)
 
514
                return format.open(a_transport), urlutils.unescape(a_transport.relpath(url))
599
515
            except errors.NotBranchError, e:
 
516
                ## mutter('not a branch in: %r %s', a_transport.base, e)
600
517
                pass
601
518
            new_t = a_transport.clone('..')
602
519
            if new_t.base == a_transport.base:
604
521
                raise errors.NotBranchError(path=url)
605
522
            a_transport = new_t
606
523
 
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
524
    def open_repository(self, _unsupported=False):
628
525
        """Open the repository object at this BzrDir if one is present.
629
526
 
667
564
        workingtree and discards it, and that's somewhat expensive.) 
668
565
        """
669
566
        try:
670
 
            self.open_workingtree(recommend_upgrade=False)
 
567
            self.open_workingtree()
671
568
            return True
672
569
        except errors.NoWorkingTree:
673
570
            return False
674
571
 
675
 
    def _cloning_metadir(self):
 
572
    def cloning_metadir(self, basis=None):
 
573
        """Produce a metadir suitable for cloning with"""
 
574
        def related_repository(bzrdir):
 
575
            try:
 
576
                branch = bzrdir.open_branch()
 
577
                return branch.repository
 
578
            except errors.NotBranchError:
 
579
                source_branch = None
 
580
                return bzrdir.open_repository()
676
581
        result_format = self._format.__class__()
677
582
        try:
678
583
            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()
 
584
                source_repository = related_repository(self)
 
585
            except errors.NoRepositoryPresent:
 
586
                if basis is None:
 
587
                    raise
 
588
                source_repository = related_repository(self)
684
589
            result_format.repository_format = source_repository._format
685
590
        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'):
 
591
            pass
 
592
        return result_format
 
593
 
 
594
    def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
718
595
        """Create a copy of this bzrdir prepared for use as a new line of
719
596
        development.
720
597
 
729
606
            itself to download less data.
730
607
        """
731
608
        self._make_tail(url)
732
 
        cloning_format = self.cloning_metadir()
 
609
        cloning_format = self.cloning_metadir(basis)
733
610
        result = cloning_format.initialize(url)
 
611
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
734
612
        try:
735
613
            source_branch = self.open_branch()
736
614
            source_repository = source_branch.repository
739
617
            try:
740
618
                source_repository = self.open_repository()
741
619
            except errors.NoRepositoryPresent:
742
 
                source_repository = None
 
620
                # copy the entire basis one if there is one
 
621
                # but there is no repository.
 
622
                source_repository = basis_repo
743
623
        if force_new_repo:
744
624
            result_repo = None
745
625
        else:
760
640
            result_repo = result.create_repository()
761
641
        if result_repo is not None:
762
642
            # fetch needed content into target.
 
643
            if basis_repo:
 
644
                # XXX FIXME RBC 20060214 need tests for this when the basis
 
645
                # is incomplete
 
646
                result_repo.fetch(basis_repo, revision_id=revision_id)
763
647
            if source_repository is not None:
764
648
                result_repo.fetch(source_repository, revision_id=revision_id)
765
649
        if source_branch is not None:
769
653
        # TODO: jam 20060426 we probably need a test in here in the
770
654
        #       case that the newly sprouted branch is a remote one
771
655
        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()
 
656
            result.create_workingtree()
808
657
        return result
809
658
 
810
659
 
814
663
    def __init__(self, _transport, _format):
815
664
        """See BzrDir.__init__."""
816
665
        super(BzrDirPreSplitOut, self).__init__(_transport, _format)
817
 
        assert self._format._lock_class == lockable_files.TransportLock
 
666
        assert self._format._lock_class == TransportLock
818
667
        assert self._format._lock_file_name == 'branch-lock'
819
 
        self._control_files = lockable_files.LockableFiles(
820
 
                                            self.get_branch_transport(None),
 
668
        self._control_files = LockableFiles(self.get_branch_transport(None),
821
669
                                            self._format._lock_file_name,
822
670
                                            self._format._lock_class)
823
671
 
825
673
        """Pre-splitout bzrdirs do not suffer from stale locks."""
826
674
        raise NotImplementedError(self.break_lock)
827
675
 
828
 
    def clone(self, url, revision_id=None, force_new_repo=False):
 
676
    def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
829
677
        """See BzrDir.clone()."""
830
678
        from bzrlib.workingtree import WorkingTreeFormat2
831
679
        self._make_tail(url)
832
680
        result = self._format._initialize_for_clone(url)
833
 
        self.open_repository().clone(result, revision_id=revision_id)
 
681
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
 
682
        self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
834
683
        from_branch = self.open_branch()
835
684
        from_branch.clone(result, revision_id=revision_id)
836
685
        try:
837
 
            self.open_workingtree().clone(result)
 
686
            self.open_workingtree().clone(result, basis=basis_tree)
838
687
        except errors.NotLocalUrl:
839
688
            # make a new one, this format always has to have one.
840
689
            try:
858
707
    def create_workingtree(self, revision_id=None):
859
708
        """See BzrDir.create_workingtree."""
860
709
        # this looks buggy but is not -really-
861
 
        # because this format creates the workingtree when the bzrdir is
862
 
        # created
863
710
        # clone and sprout will have set the revision_id
864
711
        # and that will have set it for us, its only
865
712
        # specific uses of create_workingtree in isolation
866
713
        # that can do wonky stuff here, and that only
867
714
        # happens for creating checkouts, which cannot be 
868
715
        # done on this format anyway. So - acceptable wart.
869
 
        result = self.open_workingtree(recommend_upgrade=False)
 
716
        result = self.open_workingtree()
870
717
        if revision_id is not None:
871
 
            if revision_id == _mod_revision.NULL_REVISION:
 
718
            if revision_id == bzrlib.revision.NULL_REVISION:
872
719
                result.set_parent_ids([])
873
720
            else:
874
721
                result.set_parent_ids([revision_id])
875
722
        return result
876
723
 
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
724
    def get_branch_transport(self, branch_format):
887
725
        """See BzrDir.get_branch_transport()."""
888
726
        if branch_format is None:
928
766
        self._check_supported(format, unsupported)
929
767
        return format.open(self, _found=True)
930
768
 
931
 
    def sprout(self, url, revision_id=None, force_new_repo=False):
 
769
    def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
932
770
        """See BzrDir.sprout()."""
933
771
        from bzrlib.workingtree import WorkingTreeFormat2
934
772
        self._make_tail(url)
935
773
        result = self._format._initialize_for_clone(url)
 
774
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
936
775
        try:
937
 
            self.open_repository().clone(result, revision_id=revision_id)
 
776
            self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
938
777
        except errors.NoRepositoryPresent:
939
778
            pass
940
779
        try:
962
801
 
963
802
    def open_repository(self):
964
803
        """See BzrDir.open_repository."""
965
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat4
 
804
        from bzrlib.repository import RepositoryFormat4
966
805
        return RepositoryFormat4().open(self, _found=True)
967
806
 
968
807
 
974
813
 
975
814
    def open_repository(self):
976
815
        """See BzrDir.open_repository."""
977
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
 
816
        from bzrlib.repository import RepositoryFormat5
978
817
        return RepositoryFormat5().open(self, _found=True)
979
818
 
980
 
    def open_workingtree(self, _unsupported=False,
981
 
            recommend_upgrade=True):
 
819
    def open_workingtree(self, _unsupported=False):
982
820
        """See BzrDir.create_workingtree."""
983
821
        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)
 
822
        return WorkingTreeFormat2().open(self, _found=True)
988
823
 
989
824
 
990
825
class BzrDir6(BzrDirPreSplitOut):
995
830
 
996
831
    def open_repository(self):
997
832
        """See BzrDir.open_repository."""
998
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
 
833
        from bzrlib.repository import RepositoryFormat6
999
834
        return RepositoryFormat6().open(self, _found=True)
1000
835
 
1001
 
    def open_workingtree(self, _unsupported=False,
1002
 
        recommend_upgrade=True):
 
836
    def open_workingtree(self, _unsupported=False):
1003
837
        """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
838
        from bzrlib.workingtree import WorkingTreeFormat2
1007
839
        return WorkingTreeFormat2().open(self, _found=True)
1008
840
 
1022
854
 
1023
855
    def create_branch(self):
1024
856
        """See BzrDir.create_branch."""
1025
 
        return self._format.get_branch_format().initialize(self)
 
857
        from bzrlib.branch import BranchFormat
 
858
        return BranchFormat.get_default_format().initialize(self)
1026
859
 
1027
860
    def create_repository(self, shared=False):
1028
861
        """See BzrDir.create_repository."""
1031
864
    def create_workingtree(self, revision_id=None):
1032
865
        """See BzrDir.create_workingtree."""
1033
866
        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')
 
867
        return WorkingTreeFormat.get_default_format().initialize(self, revision_id)
1046
868
 
1047
869
    def _get_mkdir_mode(self):
1048
870
        """Figure out the mode to use when creating a bzrdir subdir."""
1049
 
        temp_control = lockable_files.LockableFiles(self.transport, '',
1050
 
                                     lockable_files.TransportLock)
 
871
        temp_control = LockableFiles(self.transport, '', TransportLock)
1051
872
        return temp_control._dir_mode
1052
873
 
1053
874
    def get_branch_transport(self, branch_format):
1107
928
                return True
1108
929
        except errors.NoRepositoryPresent:
1109
930
            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
 
931
        # currently there are no other possible conversions for meta1 formats.
1125
932
        return False
1126
933
 
1127
934
    def open_branch(self, unsupported=False):
1138
945
        self._check_supported(format, unsupported)
1139
946
        return format.open(self, _found=True)
1140
947
 
1141
 
    def open_workingtree(self, unsupported=False,
1142
 
            recommend_upgrade=True):
 
948
    def open_workingtree(self, unsupported=False):
1143
949
        """See BzrDir.open_workingtree."""
1144
950
        from bzrlib.workingtree import WorkingTreeFormat
1145
951
        format = WorkingTreeFormat.find_format(self)
1146
 
        self._check_supported(format, unsupported,
1147
 
            recommend_upgrade,
1148
 
            basedir=self.root_transport.base)
 
952
        self._check_supported(format, unsupported)
1149
953
        return format.open(self, _found=True)
1150
954
 
1151
955
 
1246
1050
        """Initialize a new bzrdir in the base directory of a Transport."""
1247
1051
        # Since we don't have a .bzr directory, inherit the
1248
1052
        # mode from the root directory
1249
 
        temp_control = lockable_files.LockableFiles(transport,
1250
 
                            '', lockable_files.TransportLock)
 
1053
        temp_control = LockableFiles(transport, '', TransportLock)
1251
1054
        temp_control._transport.mkdir('.bzr',
1252
1055
                                      # FIXME: RBC 20060121 don't peek under
1253
1056
                                      # the covers
1262
1065
                      ('branch-format', self.get_format_string()),
1263
1066
                      ]
1264
1067
        # 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)
 
1068
        control_files = LockableFiles(control, self._lock_file_name, 
 
1069
                                      self._lock_class)
1267
1070
        control_files.create_lock()
1268
1071
        control_files.lock_write()
1269
1072
        try:
1311
1114
        _found is a private parameter, do not use it.
1312
1115
        """
1313
1116
        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))
 
1117
            assert isinstance(BzrDirFormat.find_format(transport),
 
1118
                              self.__class__)
1319
1119
        return self._open(transport)
1320
1120
 
1321
1121
    def _open(self, transport):
1332
1132
 
1333
1133
    @classmethod
1334
1134
    def register_control_format(klass, format):
1335
 
        """Register a format that does not use '.bzr' for its control dir.
 
1135
        """Register a format that does not use '.bzrdir' for its control dir.
1336
1136
 
1337
1137
        TODO: This should be pulled up into a 'ControlDirFormat' base class
1338
1138
        which BzrDirFormat can inherit from, and renamed to register_format 
1342
1142
        klass._control_formats.append(format)
1343
1143
 
1344
1144
    @classmethod
1345
 
    @symbol_versioning.deprecated_method(symbol_versioning.zero_fourteen)
1346
1145
    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
1146
        klass._default_format = format
1353
1147
 
1354
1148
    def __str__(self):
1364
1158
        klass._control_formats.remove(format)
1365
1159
 
1366
1160
 
 
1161
# register BzrDirFormat as a control format
 
1162
BzrDirFormat.register_control_format(BzrDirFormat)
 
1163
 
 
1164
 
1367
1165
class BzrDirFormat4(BzrDirFormat):
1368
1166
    """Bzr dir format 4.
1369
1167
 
1377
1175
    removed in format 5; write support for this format has been removed.
1378
1176
    """
1379
1177
 
1380
 
    _lock_class = lockable_files.TransportLock
 
1178
    _lock_class = TransportLock
1381
1179
 
1382
1180
    def get_format_string(self):
1383
1181
        """See BzrDirFormat.get_format_string()."""
1411
1209
 
1412
1210
    def __return_repository_format(self):
1413
1211
        """Circular import protection."""
1414
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat4
 
1212
        from bzrlib.repository import RepositoryFormat4
1415
1213
        return RepositoryFormat4()
1416
1214
    repository_format = property(__return_repository_format)
1417
1215
 
1427
1225
       Unhashed stores in the repository.
1428
1226
    """
1429
1227
 
1430
 
    _lock_class = lockable_files.TransportLock
 
1228
    _lock_class = TransportLock
1431
1229
 
1432
1230
    def get_format_string(self):
1433
1231
        """See BzrDirFormat.get_format_string()."""
1451
1249
        Except when they are being cloned.
1452
1250
        """
1453
1251
        from bzrlib.branch import BzrBranchFormat4
1454
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
 
1252
        from bzrlib.repository import RepositoryFormat5
1455
1253
        from bzrlib.workingtree import WorkingTreeFormat2
1456
1254
        result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1457
1255
        RepositoryFormat5().initialize(result, _internal=True)
1471
1269
 
1472
1270
    def __return_repository_format(self):
1473
1271
        """Circular import protection."""
1474
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
 
1272
        from bzrlib.repository import RepositoryFormat5
1475
1273
        return RepositoryFormat5()
1476
1274
    repository_format = property(__return_repository_format)
1477
1275
 
1486
1284
     - Format 6 repositories [always]
1487
1285
    """
1488
1286
 
1489
 
    _lock_class = lockable_files.TransportLock
 
1287
    _lock_class = TransportLock
1490
1288
 
1491
1289
    def get_format_string(self):
1492
1290
        """See BzrDirFormat.get_format_string()."""
1510
1308
        Except when they are being cloned.
1511
1309
        """
1512
1310
        from bzrlib.branch import BzrBranchFormat4
1513
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
 
1311
        from bzrlib.repository import RepositoryFormat6
1514
1312
        from bzrlib.workingtree import WorkingTreeFormat2
1515
1313
        result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1516
1314
        RepositoryFormat6().initialize(result, _internal=True)
1530
1328
 
1531
1329
    def __return_repository_format(self):
1532
1330
        """Circular import protection."""
1533
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
 
1331
        from bzrlib.repository import RepositoryFormat6
1534
1332
        return RepositoryFormat6()
1535
1333
    repository_format = property(__return_repository_format)
1536
1334
 
1546
1344
     - Format 7 repositories [optional]
1547
1345
    """
1548
1346
 
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
 
1347
    _lock_class = LockDir
1575
1348
 
1576
1349
    def get_converter(self, format=None):
1577
1350
        """See BzrDirFormat.get_converter()."""
1607
1380
 
1608
1381
    repository_format = property(__return_repository_format, __set_repository_format)
1609
1382
 
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
 
1383
 
1627
1384
BzrDirFormat.register_format(BzrDirFormat4())
1628
1385
BzrDirFormat.register_format(BzrDirFormat5())
1629
1386
BzrDirFormat.register_format(BzrDirFormat6())
1630
1387
__default_format = BzrDirMetaFormat1()
1631
1388
BzrDirFormat.register_format(__default_format)
1632
 
BzrDirFormat._default_format = __default_format
 
1389
BzrDirFormat.set_default_format(__default_format)
1633
1390
 
1634
1391
 
1635
1392
class BzrDirTestProviderAdapter(object):
1647
1404
        self._formats = formats
1648
1405
    
1649
1406
    def adapt(self, test):
1650
 
        result = unittest.TestSuite()
 
1407
        result = TestSuite()
1651
1408
        for format in self._formats:
1652
1409
            new_test = deepcopy(test)
1653
1410
            new_test.transport_server = self._transport_server
1751
1508
        self.bzrdir.transport.delete_tree('text-store')
1752
1509
 
1753
1510
    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)
 
1511
        inv = serializer_v4.read_inventory(self.branch.control_files.get('inventory'))
 
1512
        new_inv_xml = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
1757
1513
        # FIXME inventory is a working tree change.
1758
1514
        self.branch.control_files.put('inventory', StringIO(new_inv_xml))
1759
1515
 
1785
1541
                                                      prefixed=False,
1786
1542
                                                      compressed=True))
1787
1543
        try:
1788
 
            transaction = WriteTransaction()
 
1544
            transaction = bzrlib.transactions.WriteTransaction()
1789
1545
            for i, rev_id in enumerate(self.converted_revs):
1790
1546
                self.pb.update('write revision', i, len(self.converted_revs))
1791
1547
                _revision_store.add_revision(self.revisions[rev_id], transaction)
1817
1573
    def _load_old_inventory(self, rev_id):
1818
1574
        assert rev_id not in self.converted_revs
1819
1575
        old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
1820
 
        inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
 
1576
        inv = serializer_v4.read_inventory_from_string(old_inv_xml)
1821
1577
        inv.revision_id = rev_id
1822
1578
        rev = self.revisions[rev_id]
1823
1579
        if rev.inventory_sha1:
1828
1584
    def _load_updated_inventory(self, rev_id):
1829
1585
        assert rev_id in self.converted_revs
1830
1586
        inv_xml = self.inv_weave.get_text(rev_id)
1831
 
        inv = xml5.serializer_v5.read_inventory_from_string(inv_xml)
 
1587
        inv = bzrlib.xml5.serializer_v5.read_inventory_from_string(inv_xml)
1832
1588
        return inv
1833
1589
 
1834
1590
    def _convert_one_rev(self, rev_id):
1850
1606
                assert getattr(ie, 'revision', None) is not None, \
1851
1607
                    'no revision on {%s} in {%s}' % \
1852
1608
                    (file_id, rev.revision_id)
1853
 
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
 
1609
        new_inv_xml = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
1854
1610
        new_inv_sha1 = sha_string(new_inv_xml)
1855
1611
        self.inv_weave.add_lines(rev.revision_id, 
1856
1612
                                 present_parents,
1889
1645
                                                  entry_vf=w)
1890
1646
        for old_revision in previous_entries:
1891
1647
                # if this fails, its a ghost ?
1892
 
                assert old_revision in self.converted_revs, \
1893
 
                    "Revision {%s} not in converted_revs" % old_revision
 
1648
                assert old_revision in self.converted_revs 
1894
1649
        self.snapshot_ie(previous_entries, ie, w, rev_id)
1895
1650
        del ie.text_id
1896
1651
        assert getattr(ie, 'revision', None) is not None
1983
1738
 
1984
1739
    def convert(self, to_convert, pb):
1985
1740
        """See Converter.convert()."""
1986
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat7
1987
 
        from bzrlib.branch import BzrBranchFormat5
1988
1741
        self.bzrdir = to_convert
1989
1742
        self.pb = pb
1990
1743
        self.count = 0
2019
1772
        # we hard code the formats here because we are converting into
2020
1773
        # the meta format. The meta format upgrader can take this to a 
2021
1774
        # future format within each component.
2022
 
        self.put_format('repository', RepositoryFormat7())
 
1775
        self.put_format('repository', bzrlib.repository.RepositoryFormat7())
2023
1776
        for entry in repository_names:
2024
1777
            self.move_entry('repository', entry)
2025
1778
 
2026
1779
        self.step('Upgrading branch      ')
2027
1780
        self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
2028
1781
        self.make_lock('branch')
2029
 
        self.put_format('branch', BzrBranchFormat5())
 
1782
        self.put_format('branch', bzrlib.branch.BzrBranchFormat5())
2030
1783
        branch_files = [('revision-history', True),
2031
1784
                        ('branch-name', True),
2032
1785
                        ('parent', False)]
2052
1805
                if name in bzrcontents:
2053
1806
                    self.bzrdir.transport.delete(name)
2054
1807
        else:
2055
 
            from bzrlib.workingtree import WorkingTreeFormat3
2056
1808
            self.step('Upgrading working tree')
2057
1809
            self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
2058
1810
            self.make_lock('checkout')
2059
1811
            self.put_format(
2060
 
                'checkout', WorkingTreeFormat3())
 
1812
                'checkout', bzrlib.workingtree.WorkingTreeFormat3())
2061
1813
            self.bzrdir.transport.delete_multi(
2062
1814
                self.garbage_inventories, self.pb)
2063
1815
            for entry in checkout_files:
2072
1824
    def make_lock(self, name):
2073
1825
        """Make a lock for the new control dir name."""
2074
1826
        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)
 
1827
        ld = LockDir(self.bzrdir.transport, 
 
1828
                     '%s/lock' % name,
 
1829
                     file_modebits=self.file_mode,
 
1830
                     dir_modebits=self.dir_mode)
2079
1831
        ld.create()
2080
1832
 
2081
1833
    def move_entry(self, new_dir, entry):
2120
1872
                self.pb.note('starting repository conversion')
2121
1873
                converter = CopyConverter(self.target_format.repository_format)
2122
1874
                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
1875
        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')