1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
 
3
# This program is free software; you can redistribute it and/or modify
 
 
4
# it under the terms of the GNU General Public License as published by
 
 
5
# the Free Software Foundation; either version 2 of the License, or
 
 
6
# (at your option) any later version.
 
 
8
# This program is distributed in the hope that it will be useful,
 
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 
11
# GNU General Public License for more details.
 
 
13
# You should have received a copy of the GNU General Public License
 
 
14
# along with this program; if not, write to the Free Software
 
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 
17
"""BzrDir logic. The BzrDir is the basic control directory used by bzr.
 
 
19
At format 7 this was split out into Branch, Repository and Checkout control
 
 
22
Note: This module has a lot of ``open`` functions/methods that return
 
 
23
references to in-memory objects. As a rule, there are no matching ``close``
 
 
24
methods. To free any associated resources, simply stop referencing the
 
 
28
# TODO: Move old formats into a plugin to make this file smaller.
 
 
30
from cStringIO import StringIO
 
 
33
from bzrlib.lazy_import import lazy_import
 
 
34
lazy_import(globals(), """
 
 
35
from stat import S_ISDIR
 
 
37
from warnings import warn
 
 
47
    revision as _mod_revision,
 
 
56
from bzrlib.osutils import (
 
 
60
from bzrlib.smart.client import _SmartClient
 
 
61
from bzrlib.smart import protocol
 
 
62
from bzrlib.store.revision.text import TextRevisionStore
 
 
63
from bzrlib.store.text import TextStore
 
 
64
from bzrlib.store.versioned import WeaveStore
 
 
65
from bzrlib.transactions import WriteTransaction
 
 
66
from bzrlib.transport import (
 
 
67
    do_catching_redirections,
 
 
70
from bzrlib.weave import Weave
 
 
73
from bzrlib.trace import (
 
 
77
from bzrlib.transport.local import LocalTransport
 
 
78
from bzrlib.symbol_versioning import (
 
 
86
    """A .bzr control diretory.
 
 
88
    BzrDir instances let you create or open any of the things that can be
 
 
89
    found within .bzr - checkouts, branches and repositories.
 
 
92
        the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
 
 
94
        a transport connected to the directory this bzr was opened from
 
 
95
        (i.e. the parent directory holding the .bzr directory).
 
 
99
        """Invoke break_lock on the first object in the bzrdir.
 
 
101
        If there is a tree, the tree is opened and break_lock() called.
 
 
102
        Otherwise, branch is tried, and finally repository.
 
 
104
        # XXX: This seems more like a UI function than something that really
 
 
105
        # belongs in this class.
 
 
107
            thing_to_unlock = self.open_workingtree()
 
 
108
        except (errors.NotLocalUrl, errors.NoWorkingTree):
 
 
110
                thing_to_unlock = self.open_branch()
 
 
111
            except errors.NotBranchError:
 
 
113
                    thing_to_unlock = self.open_repository()
 
 
114
                except errors.NoRepositoryPresent:
 
 
116
        thing_to_unlock.break_lock()
 
 
118
    def can_convert_format(self):
 
 
119
        """Return true if this bzrdir is one whose format we can convert from."""
 
 
122
    def check_conversion_target(self, target_format):
 
 
123
        target_repo_format = target_format.repository_format
 
 
124
        source_repo_format = self._format.repository_format
 
 
125
        source_repo_format.check_conversion_target(target_repo_format)
 
 
128
    def _check_supported(format, allow_unsupported,
 
 
129
        recommend_upgrade=True,
 
 
131
        """Give an error or warning on old formats.
 
 
133
        :param format: may be any kind of format - workingtree, branch, 
 
 
136
        :param allow_unsupported: If true, allow opening 
 
 
137
        formats that are strongly deprecated, and which may 
 
 
138
        have limited functionality.
 
 
140
        :param recommend_upgrade: If true (default), warn
 
 
141
        the user through the ui object that they may wish
 
 
142
        to upgrade the object.
 
 
144
        # TODO: perhaps move this into a base Format class; it's not BzrDir
 
 
145
        # specific. mbp 20070323
 
 
146
        if not allow_unsupported and not format.is_supported():
 
 
147
            # see open_downlevel to open legacy branches.
 
 
148
            raise errors.UnsupportedFormatError(format=format)
 
 
149
        if recommend_upgrade \
 
 
150
            and getattr(format, 'upgrade_recommended', False):
 
 
151
            ui.ui_factory.recommend_upgrade(
 
 
152
                format.get_format_description(),
 
 
155
    def clone(self, url, revision_id=None, force_new_repo=False):
 
 
156
        """Clone this bzrdir and its contents to url verbatim.
 
 
158
        If url's last component does not exist, it will be created.
 
 
160
        if revision_id is not None, then the clone operation may tune
 
 
161
            itself to download less data.
 
 
162
        :param force_new_repo: Do not use a shared repository for the target 
 
 
163
                               even if one is available.
 
 
165
        return self.clone_on_transport(get_transport(url),
 
 
166
                                       revision_id=revision_id,
 
 
167
                                       force_new_repo=force_new_repo)
 
 
169
    def clone_on_transport(self, transport, revision_id=None,
 
 
170
                           force_new_repo=False):
 
 
171
        """Clone this bzrdir and its contents to transport verbatim.
 
 
173
        If the target directory does not exist, it will be created.
 
 
175
        if revision_id is not None, then the clone operation may tune
 
 
176
            itself to download less data.
 
 
177
        :param force_new_repo: Do not use a shared repository for the target 
 
 
178
                               even if one is available.
 
 
180
        transport.ensure_base()
 
 
181
        result = self._format.initialize_on_transport(transport)
 
 
183
            local_repo = self.find_repository()
 
 
184
        except errors.NoRepositoryPresent:
 
 
187
            # may need to copy content in
 
 
189
                result_repo = local_repo.clone(
 
 
191
                    revision_id=revision_id)
 
 
192
                result_repo.set_make_working_trees(local_repo.make_working_trees())
 
 
195
                    result_repo = result.find_repository()
 
 
196
                    # fetch content this dir needs.
 
 
197
                    result_repo.fetch(local_repo, revision_id=revision_id)
 
 
198
                except errors.NoRepositoryPresent:
 
 
199
                    # needed to make one anyway.
 
 
200
                    result_repo = local_repo.clone(
 
 
202
                        revision_id=revision_id)
 
 
203
                    result_repo.set_make_working_trees(local_repo.make_working_trees())
 
 
204
        # 1 if there is a branch present
 
 
205
        #   make sure its content is available in the target repository
 
 
208
            self.open_branch().clone(result, revision_id=revision_id)
 
 
209
        except errors.NotBranchError:
 
 
212
            self.open_workingtree().clone(result)
 
 
213
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
 
217
    # TODO: This should be given a Transport, and should chdir up; otherwise
 
 
218
    # this will open a new connection.
 
 
219
    def _make_tail(self, url):
 
 
220
        t = get_transport(url)
 
 
224
    def create(cls, base, format=None, possible_transports=None):
 
 
225
        """Create a new BzrDir at the url 'base'.
 
 
227
        :param format: If supplied, the format of branch to create.  If not
 
 
228
            supplied, the default is used.
 
 
229
        :param possible_transports: If supplied, a list of transports that 
 
 
230
            can be reused to share a remote connection.
 
 
232
        if cls is not BzrDir:
 
 
233
            raise AssertionError("BzrDir.create always creates the default"
 
 
234
                " format, not one of %r" % cls)
 
 
235
        t = get_transport(base, possible_transports)
 
 
238
            format = BzrDirFormat.get_default_format()
 
 
239
        return format.initialize_on_transport(t)
 
 
241
    def create_branch(self):
 
 
242
        """Create a branch in this BzrDir.
 
 
244
        The bzrdir's format will control what branch format is created.
 
 
245
        For more control see BranchFormatXX.create(a_bzrdir).
 
 
247
        raise NotImplementedError(self.create_branch)
 
 
249
    def destroy_branch(self):
 
 
250
        """Destroy the branch in this BzrDir"""
 
 
251
        raise NotImplementedError(self.destroy_branch)
 
 
254
    def create_branch_and_repo(base, force_new_repo=False, format=None):
 
 
255
        """Create a new BzrDir, Branch and Repository at the url 'base'.
 
 
257
        This will use the current default BzrDirFormat unless one is
 
 
258
        specified, and use whatever 
 
 
259
        repository format that that uses via bzrdir.create_branch and
 
 
260
        create_repository. If a shared repository is available that is used
 
 
263
        The created Branch object is returned.
 
 
265
        :param base: The URL to create the branch at.
 
 
266
        :param force_new_repo: If True a new repository is always created.
 
 
267
        :param format: If supplied, the format of branch to create.  If not
 
 
268
            supplied, the default is used.
 
 
270
        bzrdir = BzrDir.create(base, format)
 
 
271
        bzrdir._find_or_create_repository(force_new_repo)
 
 
272
        return bzrdir.create_branch()
 
 
274
    def _find_or_create_repository(self, force_new_repo):
 
 
275
        """Create a new repository if needed, returning the repository."""
 
 
277
            return self.create_repository()
 
 
279
            return self.find_repository()
 
 
280
        except errors.NoRepositoryPresent:
 
 
281
            return self.create_repository()
 
 
284
    def create_branch_convenience(base, force_new_repo=False,
 
 
285
                                  force_new_tree=None, format=None,
 
 
286
                                  possible_transports=None):
 
 
287
        """Create a new BzrDir, Branch and Repository at the url 'base'.
 
 
289
        This is a convenience function - it will use an existing repository
 
 
290
        if possible, can be told explicitly whether to create a working tree or
 
 
293
        This will use the current default BzrDirFormat unless one is
 
 
294
        specified, and use whatever 
 
 
295
        repository format that that uses via bzrdir.create_branch and
 
 
296
        create_repository. If a shared repository is available that is used
 
 
297
        preferentially. Whatever repository is used, its tree creation policy
 
 
300
        The created Branch object is returned.
 
 
301
        If a working tree cannot be made due to base not being a file:// url,
 
 
302
        no error is raised unless force_new_tree is True, in which case no 
 
 
303
        data is created on disk and NotLocalUrl is raised.
 
 
305
        :param base: The URL to create the branch at.
 
 
306
        :param force_new_repo: If True a new repository is always created.
 
 
307
        :param force_new_tree: If True or False force creation of a tree or 
 
 
308
                               prevent such creation respectively.
 
 
309
        :param format: Override for the bzrdir format to create.
 
 
310
        :param possible_transports: An optional reusable transports list.
 
 
313
            # check for non local urls
 
 
314
            t = get_transport(base, possible_transports)
 
 
315
            if not isinstance(t, LocalTransport):
 
 
316
                raise errors.NotLocalUrl(base)
 
 
317
        bzrdir = BzrDir.create(base, format, possible_transports)
 
 
318
        repo = bzrdir._find_or_create_repository(force_new_repo)
 
 
319
        result = bzrdir.create_branch()
 
 
320
        if force_new_tree or (repo.make_working_trees() and
 
 
321
                              force_new_tree is None):
 
 
323
                bzrdir.create_workingtree()
 
 
324
            except errors.NotLocalUrl:
 
 
329
    @deprecated_function(zero_ninetyone)
 
 
330
    def create_repository(base, shared=False, format=None):
 
 
331
        """Create a new BzrDir and Repository at the url 'base'.
 
 
333
        If no format is supplied, this will default to the current default
 
 
334
        BzrDirFormat by default, and use whatever repository format that that
 
 
335
        uses for bzrdirformat.create_repository.
 
 
337
        :param shared: Create a shared repository rather than a standalone
 
 
339
        The Repository object is returned.
 
 
341
        This must be overridden as an instance method in child classes, where
 
 
342
        it should take no parameters and construct whatever repository format
 
 
343
        that child class desires.
 
 
345
        This method is deprecated, please call create_repository on a bzrdir
 
 
348
        bzrdir = BzrDir.create(base, format)
 
 
349
        return bzrdir.create_repository(shared)
 
 
352
    def create_standalone_workingtree(base, format=None):
 
 
353
        """Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
 
 
355
        'base' must be a local path or a file:// url.
 
 
357
        This will use the current default BzrDirFormat unless one is
 
 
358
        specified, and use whatever 
 
 
359
        repository format that that uses for bzrdirformat.create_workingtree,
 
 
360
        create_branch and create_repository.
 
 
362
        :param format: Override for the bzrdir format to create.
 
 
363
        :return: The WorkingTree object.
 
 
365
        t = get_transport(base)
 
 
366
        if not isinstance(t, LocalTransport):
 
 
367
            raise errors.NotLocalUrl(base)
 
 
368
        bzrdir = BzrDir.create_branch_and_repo(base,
 
 
370
                                               format=format).bzrdir
 
 
371
        return bzrdir.create_workingtree()
 
 
373
    def create_workingtree(self, revision_id=None, from_branch=None):
 
 
374
        """Create a working tree at this BzrDir.
 
 
376
        :param revision_id: create it as of this revision id.
 
 
377
        :param from_branch: override bzrdir branch (for lightweight checkouts)
 
 
379
        raise NotImplementedError(self.create_workingtree)
 
 
381
    def retire_bzrdir(self, limit=10000):
 
 
382
        """Permanently disable the bzrdir.
 
 
384
        This is done by renaming it to give the user some ability to recover
 
 
385
        if there was a problem.
 
 
387
        This will have horrible consequences if anyone has anything locked or
 
 
389
        :param limit: number of times to retry
 
 
394
                to_path = '.bzr.retired.%d' % i
 
 
395
                self.root_transport.rename('.bzr', to_path)
 
 
396
                note("renamed %s to %s"
 
 
397
                    % (self.root_transport.abspath('.bzr'), to_path))
 
 
399
            except (errors.TransportError, IOError, errors.PathError):
 
 
406
    def destroy_workingtree(self):
 
 
407
        """Destroy the working tree at this BzrDir.
 
 
409
        Formats that do not support this may raise UnsupportedOperation.
 
 
411
        raise NotImplementedError(self.destroy_workingtree)
 
 
413
    def destroy_workingtree_metadata(self):
 
 
414
        """Destroy the control files for the working tree at this BzrDir.
 
 
416
        The contents of working tree files are not affected.
 
 
417
        Formats that do not support this may raise UnsupportedOperation.
 
 
419
        raise NotImplementedError(self.destroy_workingtree_metadata)
 
 
421
    def find_repository(self):
 
 
422
        """Find the repository that should be used.
 
 
424
        This does not require a branch as we use it to find the repo for
 
 
425
        new branches as well as to hook existing branches up to their
 
 
429
            return self.open_repository()
 
 
430
        except errors.NoRepositoryPresent:
 
 
432
        next_transport = self.root_transport.clone('..')
 
 
434
            # find the next containing bzrdir
 
 
436
                found_bzrdir = BzrDir.open_containing_from_transport(
 
 
438
            except errors.NotBranchError:
 
 
440
                raise errors.NoRepositoryPresent(self)
 
 
441
            # does it have a repository ?
 
 
443
                repository = found_bzrdir.open_repository()
 
 
444
            except errors.NoRepositoryPresent:
 
 
445
                next_transport = found_bzrdir.root_transport.clone('..')
 
 
446
                if (found_bzrdir.root_transport.base == next_transport.base):
 
 
447
                    # top of the file system
 
 
451
            if ((found_bzrdir.root_transport.base ==
 
 
452
                 self.root_transport.base) or repository.is_shared()):
 
 
455
                raise errors.NoRepositoryPresent(self)
 
 
456
        raise errors.NoRepositoryPresent(self)
 
 
458
    def get_branch_reference(self):
 
 
459
        """Return the referenced URL for the branch in this bzrdir.
 
 
461
        :raises NotBranchError: If there is no Branch.
 
 
462
        :return: The URL the branch in this bzrdir references if it is a
 
 
463
            reference branch, or None for regular branches.
 
 
467
    def get_branch_transport(self, branch_format):
 
 
468
        """Get the transport for use by branch format in this BzrDir.
 
 
470
        Note that bzr dirs that do not support format strings will raise
 
 
471
        IncompatibleFormat if the branch format they are given has
 
 
472
        a format string, and vice versa.
 
 
474
        If branch_format is None, the transport is returned with no 
 
 
475
        checking. If it is not None, then the returned transport is
 
 
476
        guaranteed to point to an existing directory ready for use.
 
 
478
        raise NotImplementedError(self.get_branch_transport)
 
 
480
    def get_repository_transport(self, repository_format):
 
 
481
        """Get the transport for use by repository format in this BzrDir.
 
 
483
        Note that bzr dirs that do not support format strings will raise
 
 
484
        IncompatibleFormat if the repository format they are given has
 
 
485
        a format string, and vice versa.
 
 
487
        If repository_format is None, the transport is returned with no 
 
 
488
        checking. If it is not None, then the returned transport is
 
 
489
        guaranteed to point to an existing directory ready for use.
 
 
491
        raise NotImplementedError(self.get_repository_transport)
 
 
493
    def get_workingtree_transport(self, tree_format):
 
 
494
        """Get the transport for use by workingtree format in this BzrDir.
 
 
496
        Note that bzr dirs that do not support format strings will raise
 
 
497
        IncompatibleFormat if the workingtree format they are given has a
 
 
498
        format string, and vice versa.
 
 
500
        If workingtree_format is None, the transport is returned with no 
 
 
501
        checking. If it is not None, then the returned transport is
 
 
502
        guaranteed to point to an existing directory ready for use.
 
 
504
        raise NotImplementedError(self.get_workingtree_transport)
 
 
506
    def __init__(self, _transport, _format):
 
 
507
        """Initialize a Bzr control dir object.
 
 
509
        Only really common logic should reside here, concrete classes should be
 
 
510
        made with varying behaviours.
 
 
512
        :param _format: the format that is creating this BzrDir instance.
 
 
513
        :param _transport: the transport this dir is based at.
 
 
515
        self._format = _format
 
 
516
        self.transport = _transport.clone('.bzr')
 
 
517
        self.root_transport = _transport
 
 
519
    def is_control_filename(self, filename):
 
 
520
        """True if filename is the name of a path which is reserved for bzrdir's.
 
 
522
        :param filename: A filename within the root transport of this bzrdir.
 
 
524
        This is true IF and ONLY IF the filename is part of the namespace reserved
 
 
525
        for bzr control dirs. Currently this is the '.bzr' directory in the root
 
 
526
        of the root_transport. it is expected that plugins will need to extend
 
 
527
        this in the future - for instance to make bzr talk with svn working
 
 
530
        # this might be better on the BzrDirFormat class because it refers to 
 
 
531
        # all the possible bzrdir disk formats. 
 
 
532
        # This method is tested via the workingtree is_control_filename tests- 
 
 
533
        # it was extracted from WorkingTree.is_control_filename. If the method's
 
 
534
        # contract is extended beyond the current trivial implementation, please
 
 
535
        # add new tests for it to the appropriate place.
 
 
536
        return filename == '.bzr' or filename.startswith('.bzr/')
 
 
538
    def needs_format_conversion(self, format=None):
 
 
539
        """Return true if this bzrdir needs convert_format run on it.
 
 
541
        For instance, if the repository format is out of date but the 
 
 
542
        branch and working tree are not, this should return True.
 
 
544
        :param format: Optional parameter indicating a specific desired
 
 
545
                       format we plan to arrive at.
 
 
547
        raise NotImplementedError(self.needs_format_conversion)
 
 
550
    def open_unsupported(base):
 
 
551
        """Open a branch which is not supported."""
 
 
552
        return BzrDir.open(base, _unsupported=True)
 
 
555
    def open(base, _unsupported=False, possible_transports=None):
 
 
556
        """Open an existing bzrdir, rooted at 'base' (url).
 
 
558
        :param _unsupported: a private parameter to the BzrDir class.
 
 
560
        t = get_transport(base, possible_transports=possible_transports)
 
 
561
        return BzrDir.open_from_transport(t, _unsupported=_unsupported)
 
 
564
    def open_from_transport(transport, _unsupported=False,
 
 
565
                            _server_formats=True):
 
 
566
        """Open a bzrdir within a particular directory.
 
 
568
        :param transport: Transport containing the bzrdir.
 
 
569
        :param _unsupported: private.
 
 
571
        base = transport.base
 
 
573
        def find_format(transport):
 
 
574
            return transport, BzrDirFormat.find_format(
 
 
575
                transport, _server_formats=_server_formats)
 
 
577
        def redirected(transport, e, redirection_notice):
 
 
578
            qualified_source = e.get_source_url()
 
 
579
            relpath = transport.relpath(qualified_source)
 
 
580
            if not e.target.endswith(relpath):
 
 
581
                # Not redirected to a branch-format, not a branch
 
 
582
                raise errors.NotBranchError(path=e.target)
 
 
583
            target = e.target[:-len(relpath)]
 
 
584
            note('%s is%s redirected to %s',
 
 
585
                 transport.base, e.permanently, target)
 
 
586
            # Let's try with a new transport
 
 
587
            # FIXME: If 'transport' has a qualifier, this should
 
 
588
            # be applied again to the new transport *iff* the
 
 
589
            # schemes used are the same. Uncomment this code
 
 
590
            # once the function (and tests) exist.
 
 
592
            #target = urlutils.copy_url_qualifiers(original, target)
 
 
593
            return get_transport(target)
 
 
596
            transport, format = do_catching_redirections(find_format,
 
 
599
        except errors.TooManyRedirections:
 
 
600
            raise errors.NotBranchError(base)
 
 
602
        BzrDir._check_supported(format, _unsupported)
 
 
603
        return format.open(transport, _found=True)
 
 
605
    def open_branch(self, unsupported=False):
 
 
606
        """Open the branch object at this BzrDir if one is present.
 
 
608
        If unsupported is True, then no longer supported branch formats can
 
 
611
        TODO: static convenience version of this?
 
 
613
        raise NotImplementedError(self.open_branch)
 
 
616
    def open_containing(url, possible_transports=None):
 
 
617
        """Open an existing branch which contains url.
 
 
619
        :param url: url to search from.
 
 
620
        See open_containing_from_transport for more detail.
 
 
622
        transport = get_transport(url, possible_transports)
 
 
623
        return BzrDir.open_containing_from_transport(transport)
 
 
626
    def open_containing_from_transport(a_transport):
 
 
627
        """Open an existing branch which contains a_transport.base.
 
 
629
        This probes for a branch at a_transport, and searches upwards from there.
 
 
631
        Basically we keep looking up until we find the control directory or
 
 
632
        run into the root.  If there isn't one, raises NotBranchError.
 
 
633
        If there is one and it is either an unrecognised format or an unsupported 
 
 
634
        format, UnknownFormatError or UnsupportedFormatError are raised.
 
 
635
        If there is one, it is returned, along with the unused portion of url.
 
 
637
        :return: The BzrDir that contains the path, and a Unicode path 
 
 
638
                for the rest of the URL.
 
 
640
        # this gets the normalised url back. I.e. '.' -> the full path.
 
 
641
        url = a_transport.base
 
 
644
                result = BzrDir.open_from_transport(a_transport)
 
 
645
                return result, urlutils.unescape(a_transport.relpath(url))
 
 
646
            except errors.NotBranchError, e:
 
 
649
                new_t = a_transport.clone('..')
 
 
650
            except errors.InvalidURLJoin:
 
 
651
                # reached the root, whatever that may be
 
 
652
                raise errors.NotBranchError(path=url)
 
 
653
            if new_t.base == a_transport.base:
 
 
654
                # reached the root, whatever that may be
 
 
655
                raise errors.NotBranchError(path=url)
 
 
659
    def open_containing_tree_or_branch(klass, location):
 
 
660
        """Return the branch and working tree contained by a location.
 
 
662
        Returns (tree, branch, relpath).
 
 
663
        If there is no tree at containing the location, tree will be None.
 
 
664
        If there is no branch containing the location, an exception will be
 
 
666
        relpath is the portion of the path that is contained by the branch.
 
 
668
        bzrdir, relpath = klass.open_containing(location)
 
 
670
            tree = bzrdir.open_workingtree()
 
 
671
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
 
673
            branch = bzrdir.open_branch()
 
 
676
        return tree, branch, relpath
 
 
678
    def open_repository(self, _unsupported=False):
 
 
679
        """Open the repository object at this BzrDir if one is present.
 
 
681
        This will not follow the Branch object pointer - it's strictly a direct
 
 
682
        open facility. Most client code should use open_branch().repository to
 
 
685
        :param _unsupported: a private parameter, not part of the api.
 
 
686
        TODO: static convenience version of this?
 
 
688
        raise NotImplementedError(self.open_repository)
 
 
690
    def open_workingtree(self, _unsupported=False,
 
 
691
                         recommend_upgrade=True, from_branch=None):
 
 
692
        """Open the workingtree object at this BzrDir if one is present.
 
 
694
        :param recommend_upgrade: Optional keyword parameter, when True (the
 
 
695
            default), emit through the ui module a recommendation that the user
 
 
696
            upgrade the working tree when the workingtree being opened is old
 
 
697
            (but still fully supported).
 
 
698
        :param from_branch: override bzrdir branch (for lightweight checkouts)
 
 
700
        raise NotImplementedError(self.open_workingtree)
 
 
702
    def has_branch(self):
 
 
703
        """Tell if this bzrdir contains a branch.
 
 
705
        Note: if you're going to open the branch, you should just go ahead
 
 
706
        and try, and not ask permission first.  (This method just opens the 
 
 
707
        branch and discards it, and that's somewhat expensive.) 
 
 
712
        except errors.NotBranchError:
 
 
715
    def has_workingtree(self):
 
 
716
        """Tell if this bzrdir contains a working tree.
 
 
718
        This will still raise an exception if the bzrdir has a workingtree that
 
 
719
        is remote & inaccessible.
 
 
721
        Note: if you're going to open the working tree, you should just go ahead
 
 
722
        and try, and not ask permission first.  (This method just opens the 
 
 
723
        workingtree and discards it, and that's somewhat expensive.) 
 
 
726
            self.open_workingtree(recommend_upgrade=False)
 
 
728
        except errors.NoWorkingTree:
 
 
731
    def _cloning_metadir(self):
 
 
732
        """Produce a metadir suitable for cloning with."""
 
 
733
        result_format = self._format.__class__()
 
 
736
                branch = self.open_branch()
 
 
737
                source_repository = branch.repository
 
 
738
            except errors.NotBranchError:
 
 
740
                source_repository = self.open_repository()
 
 
741
        except errors.NoRepositoryPresent:
 
 
742
            source_repository = None
 
 
744
            # XXX TODO: This isinstance is here because we have not implemented
 
 
745
            # the fix recommended in bug # 103195 - to delegate this choice the
 
 
747
            repo_format = source_repository._format
 
 
748
            if not isinstance(repo_format, remote.RemoteRepositoryFormat):
 
 
749
                result_format.repository_format = repo_format
 
 
751
            # TODO: Couldn't we just probe for the format in these cases,
 
 
752
            # rather than opening the whole tree?  It would be a little
 
 
753
            # faster. mbp 20070401
 
 
754
            tree = self.open_workingtree(recommend_upgrade=False)
 
 
755
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
 
756
            result_format.workingtree_format = None
 
 
758
            result_format.workingtree_format = tree._format.__class__()
 
 
759
        return result_format, source_repository
 
 
761
    def cloning_metadir(self):
 
 
762
        """Produce a metadir suitable for cloning or sprouting with.
 
 
764
        These operations may produce workingtrees (yes, even though they're
 
 
765
        "cloning" something that doesn't have a tree), so a viable workingtree
 
 
766
        format must be selected.
 
 
768
        format, repository = self._cloning_metadir()
 
 
769
        if format._workingtree_format is None:
 
 
770
            if repository is None:
 
 
772
            tree_format = repository._format._matchingbzrdir.workingtree_format
 
 
773
            format.workingtree_format = tree_format.__class__()
 
 
776
    def checkout_metadir(self):
 
 
777
        return self.cloning_metadir()
 
 
779
    def sprout(self, url, revision_id=None, force_new_repo=False,
 
 
780
               recurse='down', possible_transports=None):
 
 
781
        """Create a copy of this bzrdir prepared for use as a new line of
 
 
784
        If url's last component does not exist, it will be created.
 
 
786
        Attributes related to the identity of the source branch like
 
 
787
        branch nickname will be cleaned, a working tree is created
 
 
788
        whether one existed before or not; and a local branch is always
 
 
791
        if revision_id is not None, then the clone operation may tune
 
 
792
            itself to download less data.
 
 
794
        target_transport = get_transport(url, possible_transports)
 
 
795
        target_transport.ensure_base()
 
 
796
        cloning_format = self.cloning_metadir()
 
 
797
        result = cloning_format.initialize_on_transport(target_transport)
 
 
799
            source_branch = self.open_branch()
 
 
800
            source_repository = source_branch.repository
 
 
801
        except errors.NotBranchError:
 
 
804
                source_repository = self.open_repository()
 
 
805
            except errors.NoRepositoryPresent:
 
 
806
                source_repository = None
 
 
811
                result_repo = result.find_repository()
 
 
812
            except errors.NoRepositoryPresent:
 
 
814
        if source_repository is None and result_repo is not None:
 
 
816
        elif source_repository is None and result_repo is None:
 
 
817
            # no repo available, make a new one
 
 
818
            result.create_repository()
 
 
819
        elif source_repository is not None and result_repo is None:
 
 
820
            # have source, and want to make a new target repo
 
 
821
            result_repo = source_repository.sprout(result,
 
 
822
                                                   revision_id=revision_id)
 
 
824
            # fetch needed content into target.
 
 
825
            if source_repository is not None:
 
 
827
                # source_repository.copy_content_into(result_repo,
 
 
828
                #                                     revision_id=revision_id)
 
 
829
                # so we can override the copy method
 
 
830
                result_repo.fetch(source_repository, revision_id=revision_id)
 
 
831
        if source_branch is not None:
 
 
832
            source_branch.sprout(result, revision_id=revision_id)
 
 
834
            result.create_branch()
 
 
835
        if isinstance(target_transport, LocalTransport) and (
 
 
836
            result_repo is None or result_repo.make_working_trees()):
 
 
837
            wt = result.create_workingtree()
 
 
840
                if wt.path2id('') is None:
 
 
842
                        wt.set_root_id(self.open_workingtree.get_root_id())
 
 
843
                    except errors.NoWorkingTree:
 
 
849
        if recurse == 'down':
 
 
851
                basis = wt.basis_tree()
 
 
853
                subtrees = basis.iter_references()
 
 
854
                recurse_branch = wt.branch
 
 
855
            elif source_branch is not None:
 
 
856
                basis = source_branch.basis_tree()
 
 
858
                subtrees = basis.iter_references()
 
 
859
                recurse_branch = source_branch
 
 
864
                for path, file_id in subtrees:
 
 
865
                    target = urlutils.join(url, urlutils.escape(path))
 
 
866
                    sublocation = source_branch.reference_parent(file_id, path)
 
 
867
                    sublocation.bzrdir.sprout(target,
 
 
868
                        basis.get_reference_revision(file_id, path),
 
 
869
                        force_new_repo=force_new_repo, recurse=recurse)
 
 
871
                if basis is not None:
 
 
876
class BzrDirPreSplitOut(BzrDir):
 
 
877
    """A common class for the all-in-one formats."""
 
 
879
    def __init__(self, _transport, _format):
 
 
880
        """See BzrDir.__init__."""
 
 
881
        super(BzrDirPreSplitOut, self).__init__(_transport, _format)
 
 
882
        assert self._format._lock_class == lockable_files.TransportLock
 
 
883
        assert self._format._lock_file_name == 'branch-lock'
 
 
884
        self._control_files = lockable_files.LockableFiles(
 
 
885
                                            self.get_branch_transport(None),
 
 
886
                                            self._format._lock_file_name,
 
 
887
                                            self._format._lock_class)
 
 
889
    def break_lock(self):
 
 
890
        """Pre-splitout bzrdirs do not suffer from stale locks."""
 
 
891
        raise NotImplementedError(self.break_lock)
 
 
893
    def clone(self, url, revision_id=None, force_new_repo=False):
 
 
894
        """See BzrDir.clone()."""
 
 
895
        from bzrlib.workingtree import WorkingTreeFormat2
 
 
897
        result = self._format._initialize_for_clone(url)
 
 
898
        self.open_repository().clone(result, revision_id=revision_id)
 
 
899
        from_branch = self.open_branch()
 
 
900
        from_branch.clone(result, revision_id=revision_id)
 
 
902
            self.open_workingtree().clone(result)
 
 
903
        except errors.NotLocalUrl:
 
 
904
            # make a new one, this format always has to have one.
 
 
906
                WorkingTreeFormat2().initialize(result)
 
 
907
            except errors.NotLocalUrl:
 
 
908
                # but we cannot do it for remote trees.
 
 
909
                to_branch = result.open_branch()
 
 
910
                WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
 
 
913
    def create_branch(self):
 
 
914
        """See BzrDir.create_branch."""
 
 
915
        return self.open_branch()
 
 
917
    def destroy_branch(self):
 
 
918
        """See BzrDir.destroy_branch."""
 
 
919
        raise errors.UnsupportedOperation(self.destroy_branch, self)
 
 
921
    def create_repository(self, shared=False):
 
 
922
        """See BzrDir.create_repository."""
 
 
924
            raise errors.IncompatibleFormat('shared repository', self._format)
 
 
925
        return self.open_repository()
 
 
927
    def create_workingtree(self, revision_id=None, from_branch=None):
 
 
928
        """See BzrDir.create_workingtree."""
 
 
929
        # this looks buggy but is not -really-
 
 
930
        # because this format creates the workingtree when the bzrdir is
 
 
932
        # clone and sprout will have set the revision_id
 
 
933
        # and that will have set it for us, its only
 
 
934
        # specific uses of create_workingtree in isolation
 
 
935
        # that can do wonky stuff here, and that only
 
 
936
        # happens for creating checkouts, which cannot be 
 
 
937
        # done on this format anyway. So - acceptable wart.
 
 
938
        result = self.open_workingtree(recommend_upgrade=False)
 
 
939
        if revision_id is not None:
 
 
940
            if revision_id == _mod_revision.NULL_REVISION:
 
 
941
                result.set_parent_ids([])
 
 
943
                result.set_parent_ids([revision_id])
 
 
946
    def destroy_workingtree(self):
 
 
947
        """See BzrDir.destroy_workingtree."""
 
 
948
        raise errors.UnsupportedOperation(self.destroy_workingtree, self)
 
 
950
    def destroy_workingtree_metadata(self):
 
 
951
        """See BzrDir.destroy_workingtree_metadata."""
 
 
952
        raise errors.UnsupportedOperation(self.destroy_workingtree_metadata, 
 
 
955
    def get_branch_transport(self, branch_format):
 
 
956
        """See BzrDir.get_branch_transport()."""
 
 
957
        if branch_format is None:
 
 
958
            return self.transport
 
 
960
            branch_format.get_format_string()
 
 
961
        except NotImplementedError:
 
 
962
            return self.transport
 
 
963
        raise errors.IncompatibleFormat(branch_format, self._format)
 
 
965
    def get_repository_transport(self, repository_format):
 
 
966
        """See BzrDir.get_repository_transport()."""
 
 
967
        if repository_format is None:
 
 
968
            return self.transport
 
 
970
            repository_format.get_format_string()
 
 
971
        except NotImplementedError:
 
 
972
            return self.transport
 
 
973
        raise errors.IncompatibleFormat(repository_format, self._format)
 
 
975
    def get_workingtree_transport(self, workingtree_format):
 
 
976
        """See BzrDir.get_workingtree_transport()."""
 
 
977
        if workingtree_format is None:
 
 
978
            return self.transport
 
 
980
            workingtree_format.get_format_string()
 
 
981
        except NotImplementedError:
 
 
982
            return self.transport
 
 
983
        raise errors.IncompatibleFormat(workingtree_format, self._format)
 
 
985
    def needs_format_conversion(self, format=None):
 
 
986
        """See BzrDir.needs_format_conversion()."""
 
 
987
        # if the format is not the same as the system default,
 
 
988
        # an upgrade is needed.
 
 
990
            format = BzrDirFormat.get_default_format()
 
 
991
        return not isinstance(self._format, format.__class__)
 
 
993
    def open_branch(self, unsupported=False):
 
 
994
        """See BzrDir.open_branch."""
 
 
995
        from bzrlib.branch import BzrBranchFormat4
 
 
996
        format = BzrBranchFormat4()
 
 
997
        self._check_supported(format, unsupported)
 
 
998
        return format.open(self, _found=True)
 
 
1000
    def sprout(self, url, revision_id=None, force_new_repo=False,
 
 
1001
               possible_transports=None):
 
 
1002
        """See BzrDir.sprout()."""
 
 
1003
        from bzrlib.workingtree import WorkingTreeFormat2
 
 
1004
        self._make_tail(url)
 
 
1005
        result = self._format._initialize_for_clone(url)
 
 
1007
            self.open_repository().clone(result, revision_id=revision_id)
 
 
1008
        except errors.NoRepositoryPresent:
 
 
1011
            self.open_branch().sprout(result, revision_id=revision_id)
 
 
1012
        except errors.NotBranchError:
 
 
1014
        # we always want a working tree
 
 
1015
        WorkingTreeFormat2().initialize(result)
 
 
1019
class BzrDir4(BzrDirPreSplitOut):
 
 
1020
    """A .bzr version 4 control object.
 
 
1022
    This is a deprecated format and may be removed after sept 2006.
 
 
1025
    def create_repository(self, shared=False):
 
 
1026
        """See BzrDir.create_repository."""
 
 
1027
        return self._format.repository_format.initialize(self, shared)
 
 
1029
    def needs_format_conversion(self, format=None):
 
 
1030
        """Format 4 dirs are always in need of conversion."""
 
 
1033
    def open_repository(self):
 
 
1034
        """See BzrDir.open_repository."""
 
 
1035
        from bzrlib.repofmt.weaverepo import RepositoryFormat4
 
 
1036
        return RepositoryFormat4().open(self, _found=True)
 
 
1039
class BzrDir5(BzrDirPreSplitOut):
 
 
1040
    """A .bzr version 5 control object.
 
 
1042
    This is a deprecated format and may be removed after sept 2006.
 
 
1045
    def open_repository(self):
 
 
1046
        """See BzrDir.open_repository."""
 
 
1047
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
 
 
1048
        return RepositoryFormat5().open(self, _found=True)
 
 
1050
    def open_workingtree(self, _unsupported=False,
 
 
1051
            recommend_upgrade=True):
 
 
1052
        """See BzrDir.create_workingtree."""
 
 
1053
        from bzrlib.workingtree import WorkingTreeFormat2
 
 
1054
        wt_format = WorkingTreeFormat2()
 
 
1055
        # we don't warn here about upgrades; that ought to be handled for the
 
 
1057
        return wt_format.open(self, _found=True)
 
 
1060
class BzrDir6(BzrDirPreSplitOut):
 
 
1061
    """A .bzr version 6 control object.
 
 
1063
    This is a deprecated format and may be removed after sept 2006.
 
 
1066
    def open_repository(self):
 
 
1067
        """See BzrDir.open_repository."""
 
 
1068
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
 
 
1069
        return RepositoryFormat6().open(self, _found=True)
 
 
1071
    def open_workingtree(self, _unsupported=False,
 
 
1072
        recommend_upgrade=True):
 
 
1073
        """See BzrDir.create_workingtree."""
 
 
1074
        # we don't warn here about upgrades; that ought to be handled for the
 
 
1076
        from bzrlib.workingtree import WorkingTreeFormat2
 
 
1077
        return WorkingTreeFormat2().open(self, _found=True)
 
 
1080
class BzrDirMeta1(BzrDir):
 
 
1081
    """A .bzr meta version 1 control object.
 
 
1083
    This is the first control object where the 
 
 
1084
    individual aspects are really split out: there are separate repository,
 
 
1085
    workingtree and branch subdirectories and any subset of the three can be
 
 
1086
    present within a BzrDir.
 
 
1089
    def can_convert_format(self):
 
 
1090
        """See BzrDir.can_convert_format()."""
 
 
1093
    def create_branch(self):
 
 
1094
        """See BzrDir.create_branch."""
 
 
1095
        return self._format.get_branch_format().initialize(self)
 
 
1097
    def destroy_branch(self):
 
 
1098
        """See BzrDir.create_branch."""
 
 
1099
        self.transport.delete_tree('branch')
 
 
1101
    def create_repository(self, shared=False):
 
 
1102
        """See BzrDir.create_repository."""
 
 
1103
        return self._format.repository_format.initialize(self, shared)
 
 
1105
    def create_workingtree(self, revision_id=None, from_branch=None):
 
 
1106
        """See BzrDir.create_workingtree."""
 
 
1107
        return self._format.workingtree_format.initialize(
 
 
1108
            self, revision_id, from_branch=from_branch)
 
 
1110
    def destroy_workingtree(self):
 
 
1111
        """See BzrDir.destroy_workingtree."""
 
 
1112
        wt = self.open_workingtree(recommend_upgrade=False)
 
 
1113
        repository = wt.branch.repository
 
 
1114
        empty = repository.revision_tree(_mod_revision.NULL_REVISION)
 
 
1115
        wt.revert(old_tree=empty)
 
 
1116
        self.destroy_workingtree_metadata()
 
 
1118
    def destroy_workingtree_metadata(self):
 
 
1119
        self.transport.delete_tree('checkout')
 
 
1121
    def find_branch_format(self):
 
 
1122
        """Find the branch 'format' for this bzrdir.
 
 
1124
        This might be a synthetic object for e.g. RemoteBranch and SVN.
 
 
1126
        from bzrlib.branch import BranchFormat
 
 
1127
        return BranchFormat.find_format(self)
 
 
1129
    def _get_mkdir_mode(self):
 
 
1130
        """Figure out the mode to use when creating a bzrdir subdir."""
 
 
1131
        temp_control = lockable_files.LockableFiles(self.transport, '',
 
 
1132
                                     lockable_files.TransportLock)
 
 
1133
        return temp_control._dir_mode
 
 
1135
    def get_branch_reference(self):
 
 
1136
        """See BzrDir.get_branch_reference()."""
 
 
1137
        from bzrlib.branch import BranchFormat
 
 
1138
        format = BranchFormat.find_format(self)
 
 
1139
        return format.get_reference(self)
 
 
1141
    def get_branch_transport(self, branch_format):
 
 
1142
        """See BzrDir.get_branch_transport()."""
 
 
1143
        if branch_format is None:
 
 
1144
            return self.transport.clone('branch')
 
 
1146
            branch_format.get_format_string()
 
 
1147
        except NotImplementedError:
 
 
1148
            raise errors.IncompatibleFormat(branch_format, self._format)
 
 
1150
            self.transport.mkdir('branch', mode=self._get_mkdir_mode())
 
 
1151
        except errors.FileExists:
 
 
1153
        return self.transport.clone('branch')
 
 
1155
    def get_repository_transport(self, repository_format):
 
 
1156
        """See BzrDir.get_repository_transport()."""
 
 
1157
        if repository_format is None:
 
 
1158
            return self.transport.clone('repository')
 
 
1160
            repository_format.get_format_string()
 
 
1161
        except NotImplementedError:
 
 
1162
            raise errors.IncompatibleFormat(repository_format, self._format)
 
 
1164
            self.transport.mkdir('repository', mode=self._get_mkdir_mode())
 
 
1165
        except errors.FileExists:
 
 
1167
        return self.transport.clone('repository')
 
 
1169
    def get_workingtree_transport(self, workingtree_format):
 
 
1170
        """See BzrDir.get_workingtree_transport()."""
 
 
1171
        if workingtree_format is None:
 
 
1172
            return self.transport.clone('checkout')
 
 
1174
            workingtree_format.get_format_string()
 
 
1175
        except NotImplementedError:
 
 
1176
            raise errors.IncompatibleFormat(workingtree_format, self._format)
 
 
1178
            self.transport.mkdir('checkout', mode=self._get_mkdir_mode())
 
 
1179
        except errors.FileExists:
 
 
1181
        return self.transport.clone('checkout')
 
 
1183
    def needs_format_conversion(self, format=None):
 
 
1184
        """See BzrDir.needs_format_conversion()."""
 
 
1186
            format = BzrDirFormat.get_default_format()
 
 
1187
        if not isinstance(self._format, format.__class__):
 
 
1188
            # it is not a meta dir format, conversion is needed.
 
 
1190
        # we might want to push this down to the repository?
 
 
1192
            if not isinstance(self.open_repository()._format,
 
 
1193
                              format.repository_format.__class__):
 
 
1194
                # the repository needs an upgrade.
 
 
1196
        except errors.NoRepositoryPresent:
 
 
1199
            if not isinstance(self.open_branch()._format,
 
 
1200
                              format.get_branch_format().__class__):
 
 
1201
                # the branch needs an upgrade.
 
 
1203
        except errors.NotBranchError:
 
 
1206
            my_wt = self.open_workingtree(recommend_upgrade=False)
 
 
1207
            if not isinstance(my_wt._format,
 
 
1208
                              format.workingtree_format.__class__):
 
 
1209
                # the workingtree needs an upgrade.
 
 
1211
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
 
1215
    def open_branch(self, unsupported=False):
 
 
1216
        """See BzrDir.open_branch."""
 
 
1217
        format = self.find_branch_format()
 
 
1218
        self._check_supported(format, unsupported)
 
 
1219
        return format.open(self, _found=True)
 
 
1221
    def open_repository(self, unsupported=False):
 
 
1222
        """See BzrDir.open_repository."""
 
 
1223
        from bzrlib.repository import RepositoryFormat
 
 
1224
        format = RepositoryFormat.find_format(self)
 
 
1225
        self._check_supported(format, unsupported)
 
 
1226
        return format.open(self, _found=True)
 
 
1228
    def open_workingtree(self, unsupported=False,
 
 
1229
            recommend_upgrade=True):
 
 
1230
        """See BzrDir.open_workingtree."""
 
 
1231
        from bzrlib.workingtree import WorkingTreeFormat
 
 
1232
        format = WorkingTreeFormat.find_format(self)
 
 
1233
        self._check_supported(format, unsupported,
 
 
1235
            basedir=self.root_transport.base)
 
 
1236
        return format.open(self, _found=True)
 
 
1239
class BzrDirFormat(object):
 
 
1240
    """An encapsulation of the initialization and open routines for a format.
 
 
1242
    Formats provide three things:
 
 
1243
     * An initialization routine,
 
 
1247
    Formats are placed in a dict by their format string for reference 
 
 
1248
    during bzrdir opening. These should be subclasses of BzrDirFormat
 
 
1251
    Once a format is deprecated, just deprecate the initialize and open
 
 
1252
    methods on the format class. Do not deprecate the object, as the 
 
 
1253
    object will be created every system load.
 
 
1256
    _default_format = None
 
 
1257
    """The default format used for new .bzr dirs."""
 
 
1260
    """The known formats."""
 
 
1262
    _control_formats = []
 
 
1263
    """The registered control formats - .bzr, ....
 
 
1265
    This is a list of BzrDirFormat objects.
 
 
1268
    _control_server_formats = []
 
 
1269
    """The registered control server formats, e.g. RemoteBzrDirs.
 
 
1271
    This is a list of BzrDirFormat objects.
 
 
1274
    _lock_file_name = 'branch-lock'
 
 
1276
    # _lock_class must be set in subclasses to the lock type, typ.
 
 
1277
    # TransportLock or LockDir
 
 
1280
    def find_format(klass, transport, _server_formats=True):
 
 
1281
        """Return the format present at transport."""
 
 
1283
            formats = klass._control_server_formats + klass._control_formats
 
 
1285
            formats = klass._control_formats
 
 
1286
        for format in formats:
 
 
1288
                return format.probe_transport(transport)
 
 
1289
            except errors.NotBranchError:
 
 
1290
                # this format does not find a control dir here.
 
 
1292
        raise errors.NotBranchError(path=transport.base)
 
 
1295
    def probe_transport(klass, transport):
 
 
1296
        """Return the .bzrdir style format present in a directory."""
 
 
1298
            format_string = transport.get(".bzr/branch-format").read()
 
 
1299
        except errors.NoSuchFile:
 
 
1300
            raise errors.NotBranchError(path=transport.base)
 
 
1303
            return klass._formats[format_string]
 
 
1305
            raise errors.UnknownFormatError(format=format_string)
 
 
1308
    def get_default_format(klass):
 
 
1309
        """Return the current default format."""
 
 
1310
        return klass._default_format
 
 
1312
    def get_format_string(self):
 
 
1313
        """Return the ASCII format string that identifies this format."""
 
 
1314
        raise NotImplementedError(self.get_format_string)
 
 
1316
    def get_format_description(self):
 
 
1317
        """Return the short description for this format."""
 
 
1318
        raise NotImplementedError(self.get_format_description)
 
 
1320
    def get_converter(self, format=None):
 
 
1321
        """Return the converter to use to convert bzrdirs needing converts.
 
 
1323
        This returns a bzrlib.bzrdir.Converter object.
 
 
1325
        This should return the best upgrader to step this format towards the
 
 
1326
        current default format. In the case of plugins we can/should provide
 
 
1327
        some means for them to extend the range of returnable converters.
 
 
1329
        :param format: Optional format to override the default format of the 
 
 
1332
        raise NotImplementedError(self.get_converter)
 
 
1334
    def initialize(self, url, possible_transports=None):
 
 
1335
        """Create a bzr control dir at this url and return an opened copy.
 
 
1337
        Subclasses should typically override initialize_on_transport
 
 
1338
        instead of this method.
 
 
1340
        return self.initialize_on_transport(get_transport(url,
 
 
1341
                                                          possible_transports))
 
 
1343
    def initialize_on_transport(self, transport):
 
 
1344
        """Initialize a new bzrdir in the base directory of a Transport."""
 
 
1345
        # Since we don't have a .bzr directory, inherit the
 
 
1346
        # mode from the root directory
 
 
1347
        temp_control = lockable_files.LockableFiles(transport,
 
 
1348
                            '', lockable_files.TransportLock)
 
 
1349
        temp_control._transport.mkdir('.bzr',
 
 
1350
                                      # FIXME: RBC 20060121 don't peek under
 
 
1352
                                      mode=temp_control._dir_mode)
 
 
1353
        file_mode = temp_control._file_mode
 
 
1355
        mutter('created control directory in ' + transport.base)
 
 
1356
        control = transport.clone('.bzr')
 
 
1357
        utf8_files = [('README', 
 
 
1358
                       "This is a Bazaar-NG control directory.\n"
 
 
1359
                       "Do not change any files in this directory.\n"),
 
 
1360
                      ('branch-format', self.get_format_string()),
 
 
1362
        # NB: no need to escape relative paths that are url safe.
 
 
1363
        control_files = lockable_files.LockableFiles(control,
 
 
1364
                            self._lock_file_name, self._lock_class)
 
 
1365
        control_files.create_lock()
 
 
1366
        control_files.lock_write()
 
 
1368
            for file, content in utf8_files:
 
 
1369
                control_files.put_utf8(file, content)
 
 
1371
            control_files.unlock()
 
 
1372
        return self.open(transport, _found=True)
 
 
1374
    def is_supported(self):
 
 
1375
        """Is this format supported?
 
 
1377
        Supported formats must be initializable and openable.
 
 
1378
        Unsupported formats may not support initialization or committing or 
 
 
1379
        some other features depending on the reason for not being supported.
 
 
1383
    def same_model(self, target_format):
 
 
1384
        return (self.repository_format.rich_root_data == 
 
 
1385
            target_format.rich_root_data)
 
 
1388
    def known_formats(klass):
 
 
1389
        """Return all the known formats.
 
 
1391
        Concrete formats should override _known_formats.
 
 
1393
        # There is double indirection here to make sure that control 
 
 
1394
        # formats used by more than one dir format will only be probed 
 
 
1395
        # once. This can otherwise be quite expensive for remote connections.
 
 
1397
        for format in klass._control_formats:
 
 
1398
            result.update(format._known_formats())
 
 
1402
    def _known_formats(klass):
 
 
1403
        """Return the known format instances for this control format."""
 
 
1404
        return set(klass._formats.values())
 
 
1406
    def open(self, transport, _found=False):
 
 
1407
        """Return an instance of this format for the dir transport points at.
 
 
1409
        _found is a private parameter, do not use it.
 
 
1412
            found_format = BzrDirFormat.find_format(transport)
 
 
1413
            if not isinstance(found_format, self.__class__):
 
 
1414
                raise AssertionError("%s was asked to open %s, but it seems to need "
 
 
1416
                        % (self, transport, found_format))
 
 
1417
        return self._open(transport)
 
 
1419
    def _open(self, transport):
 
 
1420
        """Template method helper for opening BzrDirectories.
 
 
1422
        This performs the actual open and any additional logic or parameter
 
 
1425
        raise NotImplementedError(self._open)
 
 
1428
    def register_format(klass, format):
 
 
1429
        klass._formats[format.get_format_string()] = format
 
 
1432
    def register_control_format(klass, format):
 
 
1433
        """Register a format that does not use '.bzr' for its control dir.
 
 
1435
        TODO: This should be pulled up into a 'ControlDirFormat' base class
 
 
1436
        which BzrDirFormat can inherit from, and renamed to register_format 
 
 
1437
        there. It has been done without that for now for simplicity of
 
 
1440
        klass._control_formats.append(format)
 
 
1443
    def register_control_server_format(klass, format):
 
 
1444
        """Register a control format for client-server environments.
 
 
1446
        These formats will be tried before ones registered with
 
 
1447
        register_control_format.  This gives implementations that decide to the
 
 
1448
        chance to grab it before anything looks at the contents of the format
 
 
1451
        klass._control_server_formats.append(format)
 
 
1454
    @symbol_versioning.deprecated_method(symbol_versioning.zero_fourteen)
 
 
1455
    def set_default_format(klass, format):
 
 
1456
        klass._set_default_format(format)
 
 
1459
    def _set_default_format(klass, format):
 
 
1460
        """Set default format (for testing behavior of defaults only)"""
 
 
1461
        klass._default_format = format
 
 
1465
        return self.get_format_string().rstrip()
 
 
1468
    def unregister_format(klass, format):
 
 
1469
        assert klass._formats[format.get_format_string()] is format
 
 
1470
        del klass._formats[format.get_format_string()]
 
 
1473
    def unregister_control_format(klass, format):
 
 
1474
        klass._control_formats.remove(format)
 
 
1477
class BzrDirFormat4(BzrDirFormat):
 
 
1478
    """Bzr dir format 4.
 
 
1480
    This format is a combined format for working tree, branch and repository.
 
 
1482
     - Format 1 working trees [always]
 
 
1483
     - Format 4 branches [always]
 
 
1484
     - Format 4 repositories [always]
 
 
1486
    This format is deprecated: it indexes texts using a text it which is
 
 
1487
    removed in format 5; write support for this format has been removed.
 
 
1490
    _lock_class = lockable_files.TransportLock
 
 
1492
    def get_format_string(self):
 
 
1493
        """See BzrDirFormat.get_format_string()."""
 
 
1494
        return "Bazaar-NG branch, format 0.0.4\n"
 
 
1496
    def get_format_description(self):
 
 
1497
        """See BzrDirFormat.get_format_description()."""
 
 
1498
        return "All-in-one format 4"
 
 
1500
    def get_converter(self, format=None):
 
 
1501
        """See BzrDirFormat.get_converter()."""
 
 
1502
        # there is one and only one upgrade path here.
 
 
1503
        return ConvertBzrDir4To5()
 
 
1505
    def initialize_on_transport(self, transport):
 
 
1506
        """Format 4 branches cannot be created."""
 
 
1507
        raise errors.UninitializableFormat(self)
 
 
1509
    def is_supported(self):
 
 
1510
        """Format 4 is not supported.
 
 
1512
        It is not supported because the model changed from 4 to 5 and the
 
 
1513
        conversion logic is expensive - so doing it on the fly was not 
 
 
1518
    def _open(self, transport):
 
 
1519
        """See BzrDirFormat._open."""
 
 
1520
        return BzrDir4(transport, self)
 
 
1522
    def __return_repository_format(self):
 
 
1523
        """Circular import protection."""
 
 
1524
        from bzrlib.repofmt.weaverepo import RepositoryFormat4
 
 
1525
        return RepositoryFormat4()
 
 
1526
    repository_format = property(__return_repository_format)
 
 
1529
class BzrDirFormat5(BzrDirFormat):
 
 
1530
    """Bzr control format 5.
 
 
1532
    This format is a combined format for working tree, branch and repository.
 
 
1534
     - Format 2 working trees [always] 
 
 
1535
     - Format 4 branches [always] 
 
 
1536
     - Format 5 repositories [always]
 
 
1537
       Unhashed stores in the repository.
 
 
1540
    _lock_class = lockable_files.TransportLock
 
 
1542
    def get_format_string(self):
 
 
1543
        """See BzrDirFormat.get_format_string()."""
 
 
1544
        return "Bazaar-NG branch, format 5\n"
 
 
1546
    def get_format_description(self):
 
 
1547
        """See BzrDirFormat.get_format_description()."""
 
 
1548
        return "All-in-one format 5"
 
 
1550
    def get_converter(self, format=None):
 
 
1551
        """See BzrDirFormat.get_converter()."""
 
 
1552
        # there is one and only one upgrade path here.
 
 
1553
        return ConvertBzrDir5To6()
 
 
1555
    def _initialize_for_clone(self, url):
 
 
1556
        return self.initialize_on_transport(get_transport(url), _cloning=True)
 
 
1558
    def initialize_on_transport(self, transport, _cloning=False):
 
 
1559
        """Format 5 dirs always have working tree, branch and repository.
 
 
1561
        Except when they are being cloned.
 
 
1563
        from bzrlib.branch import BzrBranchFormat4
 
 
1564
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
 
 
1565
        from bzrlib.workingtree import WorkingTreeFormat2
 
 
1566
        result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
 
 
1567
        RepositoryFormat5().initialize(result, _internal=True)
 
 
1569
            branch = BzrBranchFormat4().initialize(result)
 
 
1571
                WorkingTreeFormat2().initialize(result)
 
 
1572
            except errors.NotLocalUrl:
 
 
1573
                # Even though we can't access the working tree, we need to
 
 
1574
                # create its control files.
 
 
1575
                WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
 
 
1578
    def _open(self, transport):
 
 
1579
        """See BzrDirFormat._open."""
 
 
1580
        return BzrDir5(transport, self)
 
 
1582
    def __return_repository_format(self):
 
 
1583
        """Circular import protection."""
 
 
1584
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
 
 
1585
        return RepositoryFormat5()
 
 
1586
    repository_format = property(__return_repository_format)
 
 
1589
class BzrDirFormat6(BzrDirFormat):
 
 
1590
    """Bzr control format 6.
 
 
1592
    This format is a combined format for working tree, branch and repository.
 
 
1594
     - Format 2 working trees [always] 
 
 
1595
     - Format 4 branches [always] 
 
 
1596
     - Format 6 repositories [always]
 
 
1599
    _lock_class = lockable_files.TransportLock
 
 
1601
    def get_format_string(self):
 
 
1602
        """See BzrDirFormat.get_format_string()."""
 
 
1603
        return "Bazaar-NG branch, format 6\n"
 
 
1605
    def get_format_description(self):
 
 
1606
        """See BzrDirFormat.get_format_description()."""
 
 
1607
        return "All-in-one format 6"
 
 
1609
    def get_converter(self, format=None):
 
 
1610
        """See BzrDirFormat.get_converter()."""
 
 
1611
        # there is one and only one upgrade path here.
 
 
1612
        return ConvertBzrDir6ToMeta()
 
 
1614
    def _initialize_for_clone(self, url):
 
 
1615
        return self.initialize_on_transport(get_transport(url), _cloning=True)
 
 
1617
    def initialize_on_transport(self, transport, _cloning=False):
 
 
1618
        """Format 6 dirs always have working tree, branch and repository.
 
 
1620
        Except when they are being cloned.
 
 
1622
        from bzrlib.branch import BzrBranchFormat4
 
 
1623
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
 
 
1624
        from bzrlib.workingtree import WorkingTreeFormat2
 
 
1625
        result = super(BzrDirFormat6, self).initialize_on_transport(transport)
 
 
1626
        RepositoryFormat6().initialize(result, _internal=True)
 
 
1628
            branch = BzrBranchFormat4().initialize(result)
 
 
1630
                WorkingTreeFormat2().initialize(result)
 
 
1631
            except errors.NotLocalUrl:
 
 
1632
                # Even though we can't access the working tree, we need to
 
 
1633
                # create its control files.
 
 
1634
                WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
 
 
1637
    def _open(self, transport):
 
 
1638
        """See BzrDirFormat._open."""
 
 
1639
        return BzrDir6(transport, self)
 
 
1641
    def __return_repository_format(self):
 
 
1642
        """Circular import protection."""
 
 
1643
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
 
 
1644
        return RepositoryFormat6()
 
 
1645
    repository_format = property(__return_repository_format)
 
 
1648
class BzrDirMetaFormat1(BzrDirFormat):
 
 
1649
    """Bzr meta control format 1
 
 
1651
    This is the first format with split out working tree, branch and repository
 
 
1654
     - Format 3 working trees [optional]
 
 
1655
     - Format 5 branches [optional]
 
 
1656
     - Format 7 repositories [optional]
 
 
1659
    _lock_class = lockdir.LockDir
 
 
1662
        self._workingtree_format = None
 
 
1663
        self._branch_format = None
 
 
1665
    def __eq__(self, other):
 
 
1666
        if other.__class__ is not self.__class__:
 
 
1668
        if other.repository_format != self.repository_format:
 
 
1670
        if other.workingtree_format != self.workingtree_format:
 
 
1674
    def __ne__(self, other):
 
 
1675
        return not self == other
 
 
1677
    def get_branch_format(self):
 
 
1678
        if self._branch_format is None:
 
 
1679
            from bzrlib.branch import BranchFormat
 
 
1680
            self._branch_format = BranchFormat.get_default_format()
 
 
1681
        return self._branch_format
 
 
1683
    def set_branch_format(self, format):
 
 
1684
        self._branch_format = format
 
 
1686
    def get_converter(self, format=None):
 
 
1687
        """See BzrDirFormat.get_converter()."""
 
 
1689
            format = BzrDirFormat.get_default_format()
 
 
1690
        if not isinstance(self, format.__class__):
 
 
1691
            # converting away from metadir is not implemented
 
 
1692
            raise NotImplementedError(self.get_converter)
 
 
1693
        return ConvertMetaToMeta(format)
 
 
1695
    def get_format_string(self):
 
 
1696
        """See BzrDirFormat.get_format_string()."""
 
 
1697
        return "Bazaar-NG meta directory, format 1\n"
 
 
1699
    def get_format_description(self):
 
 
1700
        """See BzrDirFormat.get_format_description()."""
 
 
1701
        return "Meta directory format 1"
 
 
1703
    def _open(self, transport):
 
 
1704
        """See BzrDirFormat._open."""
 
 
1705
        return BzrDirMeta1(transport, self)
 
 
1707
    def __return_repository_format(self):
 
 
1708
        """Circular import protection."""
 
 
1709
        if getattr(self, '_repository_format', None):
 
 
1710
            return self._repository_format
 
 
1711
        from bzrlib.repository import RepositoryFormat
 
 
1712
        return RepositoryFormat.get_default_format()
 
 
1714
    def __set_repository_format(self, value):
 
 
1715
        """Allow changint the repository format for metadir formats."""
 
 
1716
        self._repository_format = value
 
 
1718
    repository_format = property(__return_repository_format, __set_repository_format)
 
 
1720
    def __get_workingtree_format(self):
 
 
1721
        if self._workingtree_format is None:
 
 
1722
            from bzrlib.workingtree import WorkingTreeFormat
 
 
1723
            self._workingtree_format = WorkingTreeFormat.get_default_format()
 
 
1724
        return self._workingtree_format
 
 
1726
    def __set_workingtree_format(self, wt_format):
 
 
1727
        self._workingtree_format = wt_format
 
 
1729
    workingtree_format = property(__get_workingtree_format,
 
 
1730
                                  __set_workingtree_format)
 
 
1733
# Register bzr control format
 
 
1734
BzrDirFormat.register_control_format(BzrDirFormat)
 
 
1736
# Register bzr formats
 
 
1737
BzrDirFormat.register_format(BzrDirFormat4())
 
 
1738
BzrDirFormat.register_format(BzrDirFormat5())
 
 
1739
BzrDirFormat.register_format(BzrDirFormat6())
 
 
1740
__default_format = BzrDirMetaFormat1()
 
 
1741
BzrDirFormat.register_format(__default_format)
 
 
1742
BzrDirFormat._default_format = __default_format
 
 
1745
class Converter(object):
 
 
1746
    """Converts a disk format object from one format to another."""
 
 
1748
    def convert(self, to_convert, pb):
 
 
1749
        """Perform the conversion of to_convert, giving feedback via pb.
 
 
1751
        :param to_convert: The disk object to convert.
 
 
1752
        :param pb: a progress bar to use for progress information.
 
 
1755
    def step(self, message):
 
 
1756
        """Update the pb by a step."""
 
 
1758
        self.pb.update(message, self.count, self.total)
 
 
1761
class ConvertBzrDir4To5(Converter):
 
 
1762
    """Converts format 4 bzr dirs to format 5."""
 
 
1765
        super(ConvertBzrDir4To5, self).__init__()
 
 
1766
        self.converted_revs = set()
 
 
1767
        self.absent_revisions = set()
 
 
1771
    def convert(self, to_convert, pb):
 
 
1772
        """See Converter.convert()."""
 
 
1773
        self.bzrdir = to_convert
 
 
1775
        self.pb.note('starting upgrade from format 4 to 5')
 
 
1776
        if isinstance(self.bzrdir.transport, LocalTransport):
 
 
1777
            self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
 
 
1778
        self._convert_to_weaves()
 
 
1779
        return BzrDir.open(self.bzrdir.root_transport.base)
 
 
1781
    def _convert_to_weaves(self):
 
 
1782
        self.pb.note('note: upgrade may be faster if all store files are ungzipped first')
 
 
1785
            stat = self.bzrdir.transport.stat('weaves')
 
 
1786
            if not S_ISDIR(stat.st_mode):
 
 
1787
                self.bzrdir.transport.delete('weaves')
 
 
1788
                self.bzrdir.transport.mkdir('weaves')
 
 
1789
        except errors.NoSuchFile:
 
 
1790
            self.bzrdir.transport.mkdir('weaves')
 
 
1791
        # deliberately not a WeaveFile as we want to build it up slowly.
 
 
1792
        self.inv_weave = Weave('inventory')
 
 
1793
        # holds in-memory weaves for all files
 
 
1794
        self.text_weaves = {}
 
 
1795
        self.bzrdir.transport.delete('branch-format')
 
 
1796
        self.branch = self.bzrdir.open_branch()
 
 
1797
        self._convert_working_inv()
 
 
1798
        rev_history = self.branch.revision_history()
 
 
1799
        # to_read is a stack holding the revisions we still need to process;
 
 
1800
        # appending to it adds new highest-priority revisions
 
 
1801
        self.known_revisions = set(rev_history)
 
 
1802
        self.to_read = rev_history[-1:]
 
 
1804
            rev_id = self.to_read.pop()
 
 
1805
            if (rev_id not in self.revisions
 
 
1806
                and rev_id not in self.absent_revisions):
 
 
1807
                self._load_one_rev(rev_id)
 
 
1809
        to_import = self._make_order()
 
 
1810
        for i, rev_id in enumerate(to_import):
 
 
1811
            self.pb.update('converting revision', i, len(to_import))
 
 
1812
            self._convert_one_rev(rev_id)
 
 
1814
        self._write_all_weaves()
 
 
1815
        self._write_all_revs()
 
 
1816
        self.pb.note('upgraded to weaves:')
 
 
1817
        self.pb.note('  %6d revisions and inventories', len(self.revisions))
 
 
1818
        self.pb.note('  %6d revisions not present', len(self.absent_revisions))
 
 
1819
        self.pb.note('  %6d texts', self.text_count)
 
 
1820
        self._cleanup_spare_files_after_format4()
 
 
1821
        self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
 
 
1823
    def _cleanup_spare_files_after_format4(self):
 
 
1824
        # FIXME working tree upgrade foo.
 
 
1825
        for n in 'merged-patches', 'pending-merged-patches':
 
 
1827
                ## assert os.path.getsize(p) == 0
 
 
1828
                self.bzrdir.transport.delete(n)
 
 
1829
            except errors.NoSuchFile:
 
 
1831
        self.bzrdir.transport.delete_tree('inventory-store')
 
 
1832
        self.bzrdir.transport.delete_tree('text-store')
 
 
1834
    def _convert_working_inv(self):
 
 
1835
        inv = xml4.serializer_v4.read_inventory(
 
 
1836
                    self.branch.control_files.get('inventory'))
 
 
1837
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv, working=True)
 
 
1838
        # FIXME inventory is a working tree change.
 
 
1839
        self.branch.control_files.put('inventory', StringIO(new_inv_xml))
 
 
1841
    def _write_all_weaves(self):
 
 
1842
        controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
 
 
1843
        weave_transport = self.bzrdir.transport.clone('weaves')
 
 
1844
        weaves = WeaveStore(weave_transport, prefixed=False)
 
 
1845
        transaction = WriteTransaction()
 
 
1849
            for file_id, file_weave in self.text_weaves.items():
 
 
1850
                self.pb.update('writing weave', i, len(self.text_weaves))
 
 
1851
                weaves._put_weave(file_id, file_weave, transaction)
 
 
1853
            self.pb.update('inventory', 0, 1)
 
 
1854
            controlweaves._put_weave('inventory', self.inv_weave, transaction)
 
 
1855
            self.pb.update('inventory', 1, 1)
 
 
1859
    def _write_all_revs(self):
 
 
1860
        """Write all revisions out in new form."""
 
 
1861
        self.bzrdir.transport.delete_tree('revision-store')
 
 
1862
        self.bzrdir.transport.mkdir('revision-store')
 
 
1863
        revision_transport = self.bzrdir.transport.clone('revision-store')
 
 
1865
        _revision_store = TextRevisionStore(TextStore(revision_transport,
 
 
1869
            transaction = WriteTransaction()
 
 
1870
            for i, rev_id in enumerate(self.converted_revs):
 
 
1871
                self.pb.update('write revision', i, len(self.converted_revs))
 
 
1872
                _revision_store.add_revision(self.revisions[rev_id], transaction)
 
 
1876
    def _load_one_rev(self, rev_id):
 
 
1877
        """Load a revision object into memory.
 
 
1879
        Any parents not either loaded or abandoned get queued to be
 
 
1881
        self.pb.update('loading revision',
 
 
1882
                       len(self.revisions),
 
 
1883
                       len(self.known_revisions))
 
 
1884
        if not self.branch.repository.has_revision(rev_id):
 
 
1886
            self.pb.note('revision {%s} not present in branch; '
 
 
1887
                         'will be converted as a ghost',
 
 
1889
            self.absent_revisions.add(rev_id)
 
 
1891
            rev = self.branch.repository._revision_store.get_revision(rev_id,
 
 
1892
                self.branch.repository.get_transaction())
 
 
1893
            for parent_id in rev.parent_ids:
 
 
1894
                self.known_revisions.add(parent_id)
 
 
1895
                self.to_read.append(parent_id)
 
 
1896
            self.revisions[rev_id] = rev
 
 
1898
    def _load_old_inventory(self, rev_id):
 
 
1899
        assert rev_id not in self.converted_revs
 
 
1900
        old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
 
 
1901
        inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
 
 
1902
        inv.revision_id = rev_id
 
 
1903
        rev = self.revisions[rev_id]
 
 
1904
        if rev.inventory_sha1:
 
 
1905
            assert rev.inventory_sha1 == sha_string(old_inv_xml), \
 
 
1906
                'inventory sha mismatch for {%s}' % rev_id
 
 
1909
    def _load_updated_inventory(self, rev_id):
 
 
1910
        assert rev_id in self.converted_revs
 
 
1911
        inv_xml = self.inv_weave.get_text(rev_id)
 
 
1912
        inv = xml5.serializer_v5.read_inventory_from_string(inv_xml)
 
 
1915
    def _convert_one_rev(self, rev_id):
 
 
1916
        """Convert revision and all referenced objects to new format."""
 
 
1917
        rev = self.revisions[rev_id]
 
 
1918
        inv = self._load_old_inventory(rev_id)
 
 
1919
        present_parents = [p for p in rev.parent_ids
 
 
1920
                           if p not in self.absent_revisions]
 
 
1921
        self._convert_revision_contents(rev, inv, present_parents)
 
 
1922
        self._store_new_inv(rev, inv, present_parents)
 
 
1923
        self.converted_revs.add(rev_id)
 
 
1925
    def _store_new_inv(self, rev, inv, present_parents):
 
 
1926
        # the XML is now updated with text versions
 
 
1928
            entries = inv.iter_entries()
 
 
1930
            for path, ie in entries:
 
 
1931
                assert getattr(ie, 'revision', None) is not None, \
 
 
1932
                    'no revision on {%s} in {%s}' % \
 
 
1933
                    (file_id, rev.revision_id)
 
 
1934
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
 
 
1935
        new_inv_sha1 = sha_string(new_inv_xml)
 
 
1936
        self.inv_weave.add_lines(rev.revision_id,
 
 
1938
                                 new_inv_xml.splitlines(True))
 
 
1939
        rev.inventory_sha1 = new_inv_sha1
 
 
1941
    def _convert_revision_contents(self, rev, inv, present_parents):
 
 
1942
        """Convert all the files within a revision.
 
 
1944
        Also upgrade the inventory to refer to the text revision ids."""
 
 
1945
        rev_id = rev.revision_id
 
 
1946
        mutter('converting texts of revision {%s}',
 
 
1948
        parent_invs = map(self._load_updated_inventory, present_parents)
 
 
1949
        entries = inv.iter_entries()
 
 
1951
        for path, ie in entries:
 
 
1952
            self._convert_file_version(rev, ie, parent_invs)
 
 
1954
    def _convert_file_version(self, rev, ie, parent_invs):
 
 
1955
        """Convert one version of one file.
 
 
1957
        The file needs to be added into the weave if it is a merge
 
 
1958
        of >=2 parents or if it's changed from its parent.
 
 
1960
        file_id = ie.file_id
 
 
1961
        rev_id = rev.revision_id
 
 
1962
        w = self.text_weaves.get(file_id)
 
 
1965
            self.text_weaves[file_id] = w
 
 
1966
        text_changed = False
 
 
1967
        parent_candiate_entries = ie.parent_candidates(parent_invs)
 
 
1968
        for old_revision in parent_candiate_entries.keys():
 
 
1969
            # if this fails, its a ghost ?
 
 
1970
            assert old_revision in self.converted_revs, \
 
 
1971
                "Revision {%s} not in converted_revs" % old_revision
 
 
1972
        heads = graph.Graph(self).heads(parent_candiate_entries.keys())
 
 
1973
        # XXX: Note that this is unordered - and this is tolerable because 
 
 
1974
        # the previous code was also unordered.
 
 
1975
        previous_entries = dict((head, parent_candiate_entries[head]) for head
 
 
1977
        self.snapshot_ie(previous_entries, ie, w, rev_id)
 
 
1979
        assert getattr(ie, 'revision', None) is not None
 
 
1981
    def get_parents(self, revision_ids):
 
 
1982
        for revision_id in revision_ids:
 
 
1983
            yield self.revisions[revision_id].parent_ids
 
 
1985
    def snapshot_ie(self, previous_revisions, ie, w, rev_id):
 
 
1986
        # TODO: convert this logic, which is ~= snapshot to
 
 
1987
        # a call to:. This needs the path figured out. rather than a work_tree
 
 
1988
        # a v4 revision_tree can be given, or something that looks enough like
 
 
1989
        # one to give the file content to the entry if it needs it.
 
 
1990
        # and we need something that looks like a weave store for snapshot to 
 
 
1992
        #ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
 
 
1993
        if len(previous_revisions) == 1:
 
 
1994
            previous_ie = previous_revisions.values()[0]
 
 
1995
            if ie._unchanged(previous_ie):
 
 
1996
                ie.revision = previous_ie.revision
 
 
1999
            text = self.branch.repository.weave_store.get(ie.text_id)
 
 
2000
            file_lines = text.readlines()
 
 
2001
            assert sha_strings(file_lines) == ie.text_sha1
 
 
2002
            assert sum(map(len, file_lines)) == ie.text_size
 
 
2003
            w.add_lines(rev_id, previous_revisions, file_lines)
 
 
2004
            self.text_count += 1
 
 
2006
            w.add_lines(rev_id, previous_revisions, [])
 
 
2007
        ie.revision = rev_id
 
 
2009
    def _make_order(self):
 
 
2010
        """Return a suitable order for importing revisions.
 
 
2012
        The order must be such that an revision is imported after all
 
 
2013
        its (present) parents.
 
 
2015
        todo = set(self.revisions.keys())
 
 
2016
        done = self.absent_revisions.copy()
 
 
2019
            # scan through looking for a revision whose parents
 
 
2021
            for rev_id in sorted(list(todo)):
 
 
2022
                rev = self.revisions[rev_id]
 
 
2023
                parent_ids = set(rev.parent_ids)
 
 
2024
                if parent_ids.issubset(done):
 
 
2025
                    # can take this one now
 
 
2026
                    order.append(rev_id)
 
 
2032
class ConvertBzrDir5To6(Converter):
 
 
2033
    """Converts format 5 bzr dirs to format 6."""
 
 
2035
    def convert(self, to_convert, pb):
 
 
2036
        """See Converter.convert()."""
 
 
2037
        self.bzrdir = to_convert
 
 
2039
        self.pb.note('starting upgrade from format 5 to 6')
 
 
2040
        self._convert_to_prefixed()
 
 
2041
        return BzrDir.open(self.bzrdir.root_transport.base)
 
 
2043
    def _convert_to_prefixed(self):
 
 
2044
        from bzrlib.store import TransportStore
 
 
2045
        self.bzrdir.transport.delete('branch-format')
 
 
2046
        for store_name in ["weaves", "revision-store"]:
 
 
2047
            self.pb.note("adding prefixes to %s" % store_name)
 
 
2048
            store_transport = self.bzrdir.transport.clone(store_name)
 
 
2049
            store = TransportStore(store_transport, prefixed=True)
 
 
2050
            for urlfilename in store_transport.list_dir('.'):
 
 
2051
                filename = urlutils.unescape(urlfilename)
 
 
2052
                if (filename.endswith(".weave") or
 
 
2053
                    filename.endswith(".gz") or
 
 
2054
                    filename.endswith(".sig")):
 
 
2055
                    file_id = os.path.splitext(filename)[0]
 
 
2058
                prefix_dir = store.hash_prefix(file_id)
 
 
2059
                # FIXME keep track of the dirs made RBC 20060121
 
 
2061
                    store_transport.move(filename, prefix_dir + '/' + filename)
 
 
2062
                except errors.NoSuchFile: # catches missing dirs strangely enough
 
 
2063
                    store_transport.mkdir(prefix_dir)
 
 
2064
                    store_transport.move(filename, prefix_dir + '/' + filename)
 
 
2065
        self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
 
 
2068
class ConvertBzrDir6ToMeta(Converter):
 
 
2069
    """Converts format 6 bzr dirs to metadirs."""
 
 
2071
    def convert(self, to_convert, pb):
 
 
2072
        """See Converter.convert()."""
 
 
2073
        from bzrlib.repofmt.weaverepo import RepositoryFormat7
 
 
2074
        from bzrlib.branch import BzrBranchFormat5
 
 
2075
        self.bzrdir = to_convert
 
 
2078
        self.total = 20 # the steps we know about
 
 
2079
        self.garbage_inventories = []
 
 
2081
        self.pb.note('starting upgrade from format 6 to metadir')
 
 
2082
        self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
 
 
2083
        # its faster to move specific files around than to open and use the apis...
 
 
2084
        # first off, nuke ancestry.weave, it was never used.
 
 
2086
            self.step('Removing ancestry.weave')
 
 
2087
            self.bzrdir.transport.delete('ancestry.weave')
 
 
2088
        except errors.NoSuchFile:
 
 
2090
        # find out whats there
 
 
2091
        self.step('Finding branch files')
 
 
2092
        last_revision = self.bzrdir.open_branch().last_revision()
 
 
2093
        bzrcontents = self.bzrdir.transport.list_dir('.')
 
 
2094
        for name in bzrcontents:
 
 
2095
            if name.startswith('basis-inventory.'):
 
 
2096
                self.garbage_inventories.append(name)
 
 
2097
        # create new directories for repository, working tree and branch
 
 
2098
        self.dir_mode = self.bzrdir._control_files._dir_mode
 
 
2099
        self.file_mode = self.bzrdir._control_files._file_mode
 
 
2100
        repository_names = [('inventory.weave', True),
 
 
2101
                            ('revision-store', True),
 
 
2103
        self.step('Upgrading repository  ')
 
 
2104
        self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
 
 
2105
        self.make_lock('repository')
 
 
2106
        # we hard code the formats here because we are converting into
 
 
2107
        # the meta format. The meta format upgrader can take this to a 
 
 
2108
        # future format within each component.
 
 
2109
        self.put_format('repository', RepositoryFormat7())
 
 
2110
        for entry in repository_names:
 
 
2111
            self.move_entry('repository', entry)
 
 
2113
        self.step('Upgrading branch      ')
 
 
2114
        self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
 
 
2115
        self.make_lock('branch')
 
 
2116
        self.put_format('branch', BzrBranchFormat5())
 
 
2117
        branch_files = [('revision-history', True),
 
 
2118
                        ('branch-name', True),
 
 
2120
        for entry in branch_files:
 
 
2121
            self.move_entry('branch', entry)
 
 
2123
        checkout_files = [('pending-merges', True),
 
 
2124
                          ('inventory', True),
 
 
2125
                          ('stat-cache', False)]
 
 
2126
        # If a mandatory checkout file is not present, the branch does not have
 
 
2127
        # a functional checkout. Do not create a checkout in the converted
 
 
2129
        for name, mandatory in checkout_files:
 
 
2130
            if mandatory and name not in bzrcontents:
 
 
2131
                has_checkout = False
 
 
2135
        if not has_checkout:
 
 
2136
            self.pb.note('No working tree.')
 
 
2137
            # If some checkout files are there, we may as well get rid of them.
 
 
2138
            for name, mandatory in checkout_files:
 
 
2139
                if name in bzrcontents:
 
 
2140
                    self.bzrdir.transport.delete(name)
 
 
2142
            from bzrlib.workingtree import WorkingTreeFormat3
 
 
2143
            self.step('Upgrading working tree')
 
 
2144
            self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
 
 
2145
            self.make_lock('checkout')
 
 
2147
                'checkout', WorkingTreeFormat3())
 
 
2148
            self.bzrdir.transport.delete_multi(
 
 
2149
                self.garbage_inventories, self.pb)
 
 
2150
            for entry in checkout_files:
 
 
2151
                self.move_entry('checkout', entry)
 
 
2152
            if last_revision is not None:
 
 
2153
                self.bzrdir._control_files.put_utf8(
 
 
2154
                    'checkout/last-revision', last_revision)
 
 
2155
        self.bzrdir._control_files.put_utf8(
 
 
2156
            'branch-format', BzrDirMetaFormat1().get_format_string())
 
 
2157
        return BzrDir.open(self.bzrdir.root_transport.base)
 
 
2159
    def make_lock(self, name):
 
 
2160
        """Make a lock for the new control dir name."""
 
 
2161
        self.step('Make %s lock' % name)
 
 
2162
        ld = lockdir.LockDir(self.bzrdir.transport,
 
 
2164
                             file_modebits=self.file_mode,
 
 
2165
                             dir_modebits=self.dir_mode)
 
 
2168
    def move_entry(self, new_dir, entry):
 
 
2169
        """Move then entry name into new_dir."""
 
 
2171
        mandatory = entry[1]
 
 
2172
        self.step('Moving %s' % name)
 
 
2174
            self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
 
 
2175
        except errors.NoSuchFile:
 
 
2179
    def put_format(self, dirname, format):
 
 
2180
        self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
 
 
2183
class ConvertMetaToMeta(Converter):
 
 
2184
    """Converts the components of metadirs."""
 
 
2186
    def __init__(self, target_format):
 
 
2187
        """Create a metadir to metadir converter.
 
 
2189
        :param target_format: The final metadir format that is desired.
 
 
2191
        self.target_format = target_format
 
 
2193
    def convert(self, to_convert, pb):
 
 
2194
        """See Converter.convert()."""
 
 
2195
        self.bzrdir = to_convert
 
 
2199
        self.step('checking repository format')
 
 
2201
            repo = self.bzrdir.open_repository()
 
 
2202
        except errors.NoRepositoryPresent:
 
 
2205
            if not isinstance(repo._format, self.target_format.repository_format.__class__):
 
 
2206
                from bzrlib.repository import CopyConverter
 
 
2207
                self.pb.note('starting repository conversion')
 
 
2208
                converter = CopyConverter(self.target_format.repository_format)
 
 
2209
                converter.convert(repo, pb)
 
 
2211
            branch = self.bzrdir.open_branch()
 
 
2212
        except errors.NotBranchError:
 
 
2215
            # TODO: conversions of Branch and Tree should be done by
 
 
2216
            # InterXFormat lookups
 
 
2217
            # Avoid circular imports
 
 
2218
            from bzrlib import branch as _mod_branch
 
 
2219
            if (branch._format.__class__ is _mod_branch.BzrBranchFormat5 and
 
 
2220
                self.target_format.get_branch_format().__class__ is
 
 
2221
                _mod_branch.BzrBranchFormat6):
 
 
2222
                branch_converter = _mod_branch.Converter5to6()
 
 
2223
                branch_converter.convert(branch)
 
 
2225
            tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
 
 
2226
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
 
2229
            # TODO: conversions of Branch and Tree should be done by
 
 
2230
            # InterXFormat lookups
 
 
2231
            if (isinstance(tree, workingtree.WorkingTree3) and
 
 
2232
                not isinstance(tree, workingtree_4.WorkingTree4) and
 
 
2233
                isinstance(self.target_format.workingtree_format,
 
 
2234
                    workingtree_4.WorkingTreeFormat4)):
 
 
2235
                workingtree_4.Converter3to4().convert(tree)
 
 
2239
# This is not in remote.py because it's small, and needs to be registered.
 
 
2240
# Putting it in remote.py creates a circular import problem.
 
 
2241
# we can make it a lazy object if the control formats is turned into something
 
 
2243
class RemoteBzrDirFormat(BzrDirMetaFormat1):
 
 
2244
    """Format representing bzrdirs accessed via a smart server"""
 
 
2246
    def get_format_description(self):
 
 
2247
        return 'bzr remote bzrdir'
 
 
2250
    def probe_transport(klass, transport):
 
 
2251
        """Return a RemoteBzrDirFormat object if it looks possible."""
 
 
2253
            client = transport.get_smart_client()
 
 
2254
        except (NotImplementedError, AttributeError,
 
 
2255
                errors.TransportNotPossible):
 
 
2256
            # no smart server, so not a branch for this format type.
 
 
2257
            raise errors.NotBranchError(path=transport.base)
 
 
2259
            # Send a 'hello' request in protocol version one, and decline to
 
 
2260
            # open it if the server doesn't support our required version (2) so
 
 
2261
            # that the VFS-based transport will do it.
 
 
2262
            request = client.get_request()
 
 
2263
            smart_protocol = protocol.SmartClientRequestProtocolOne(request)
 
 
2264
            server_version = smart_protocol.query_version()
 
 
2265
            if server_version != 2:
 
 
2266
                raise errors.NotBranchError(path=transport.base)
 
 
2269
    def initialize_on_transport(self, transport):
 
 
2271
            # hand off the request to the smart server
 
 
2272
            shared_medium = transport.get_shared_medium()
 
 
2273
        except errors.NoSmartMedium:
 
 
2274
            # TODO: lookup the local format from a server hint.
 
 
2275
            local_dir_format = BzrDirMetaFormat1()
 
 
2276
            return local_dir_format.initialize_on_transport(transport)
 
 
2277
        client = _SmartClient(shared_medium)
 
 
2278
        path = client.remote_path_from_transport(transport)
 
 
2279
        response = _SmartClient(shared_medium).call('BzrDirFormat.initialize',
 
 
2281
        assert response[0] in ('ok', ), 'unexpected response code %s' % (response,)
 
 
2282
        return remote.RemoteBzrDir(transport)
 
 
2284
    def _open(self, transport):
 
 
2285
        return remote.RemoteBzrDir(transport)
 
 
2287
    def __eq__(self, other):
 
 
2288
        if not isinstance(other, RemoteBzrDirFormat):
 
 
2290
        return self.get_format_description() == other.get_format_description()
 
 
2293
BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)
 
 
2296
class BzrDirFormatInfo(object):
 
 
2298
    def __init__(self, native, deprecated, hidden, experimental):
 
 
2299
        self.deprecated = deprecated
 
 
2300
        self.native = native
 
 
2301
        self.hidden = hidden
 
 
2302
        self.experimental = experimental
 
 
2305
class BzrDirFormatRegistry(registry.Registry):
 
 
2306
    """Registry of user-selectable BzrDir subformats.
 
 
2308
    Differs from BzrDirFormat._control_formats in that it provides sub-formats,
 
 
2309
    e.g. BzrDirMeta1 with weave repository.  Also, it's more user-oriented.
 
 
2312
    def register_metadir(self, key,
 
 
2313
             repository_format, help, native=True, deprecated=False,
 
 
2317
             experimental=False):
 
 
2318
        """Register a metadir subformat.
 
 
2320
        These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
 
 
2321
        by the Repository format.
 
 
2323
        :param repository_format: The fully-qualified repository format class
 
 
2325
        :param branch_format: Fully-qualified branch format class name as
 
 
2327
        :param tree_format: Fully-qualified tree format class name as
 
 
2330
        # This should be expanded to support setting WorkingTree and Branch
 
 
2331
        # formats, once BzrDirMetaFormat1 supports that.
 
 
2332
        def _load(full_name):
 
 
2333
            mod_name, factory_name = full_name.rsplit('.', 1)
 
 
2335
                mod = __import__(mod_name, globals(), locals(),
 
 
2337
            except ImportError, e:
 
 
2338
                raise ImportError('failed to load %s: %s' % (full_name, e))
 
 
2340
                factory = getattr(mod, factory_name)
 
 
2341
            except AttributeError:
 
 
2342
                raise AttributeError('no factory %s in module %r'
 
 
2347
            bd = BzrDirMetaFormat1()
 
 
2348
            if branch_format is not None:
 
 
2349
                bd.set_branch_format(_load(branch_format))
 
 
2350
            if tree_format is not None:
 
 
2351
                bd.workingtree_format = _load(tree_format)
 
 
2352
            if repository_format is not None:
 
 
2353
                bd.repository_format = _load(repository_format)
 
 
2355
        self.register(key, helper, help, native, deprecated, hidden,
 
 
2358
    def register(self, key, factory, help, native=True, deprecated=False,
 
 
2359
                 hidden=False, experimental=False):
 
 
2360
        """Register a BzrDirFormat factory.
 
 
2362
        The factory must be a callable that takes one parameter: the key.
 
 
2363
        It must produce an instance of the BzrDirFormat when called.
 
 
2365
        This function mainly exists to prevent the info object from being
 
 
2368
        registry.Registry.register(self, key, factory, help, 
 
 
2369
            BzrDirFormatInfo(native, deprecated, hidden, experimental))
 
 
2371
    def register_lazy(self, key, module_name, member_name, help, native=True,
 
 
2372
                      deprecated=False, hidden=False, experimental=False):
 
 
2373
        registry.Registry.register_lazy(self, key, module_name, member_name, 
 
 
2374
            help, BzrDirFormatInfo(native, deprecated, hidden, experimental))
 
 
2376
    def set_default(self, key):
 
 
2377
        """Set the 'default' key to be a clone of the supplied key.
 
 
2379
        This method must be called once and only once.
 
 
2381
        registry.Registry.register(self, 'default', self.get(key), 
 
 
2382
            self.get_help(key), info=self.get_info(key))
 
 
2384
    def set_default_repository(self, key):
 
 
2385
        """Set the FormatRegistry default and Repository default.
 
 
2387
        This is a transitional method while Repository.set_default_format
 
 
2390
        if 'default' in self:
 
 
2391
            self.remove('default')
 
 
2392
        self.set_default(key)
 
 
2393
        format = self.get('default')()
 
 
2394
        assert isinstance(format, BzrDirMetaFormat1)
 
 
2396
    def make_bzrdir(self, key):
 
 
2397
        return self.get(key)()
 
 
2399
    def help_topic(self, topic):
 
 
2400
        output = textwrap.dedent("""\
 
 
2401
            These formats can be used for creating branches, working trees, and
 
 
2405
        default_realkey = None
 
 
2406
        default_help = self.get_help('default')
 
 
2408
        for key in self.keys():
 
 
2409
            if key == 'default':
 
 
2411
            help = self.get_help(key)
 
 
2412
            if help == default_help:
 
 
2413
                default_realkey = key
 
 
2415
                help_pairs.append((key, help))
 
 
2417
        def wrapped(key, help, info):
 
 
2419
                help = '(native) ' + help
 
 
2420
            return ':%s:\n%s\n\n' % (key, 
 
 
2421
                    textwrap.fill(help, initial_indent='    ', 
 
 
2422
                    subsequent_indent='    '))
 
 
2423
        if default_realkey is not None:
 
 
2424
            output += wrapped(default_realkey, '(default) %s' % default_help,
 
 
2425
                              self.get_info('default'))
 
 
2426
        deprecated_pairs = []
 
 
2427
        experimental_pairs = []
 
 
2428
        for key, help in help_pairs:
 
 
2429
            info = self.get_info(key)
 
 
2432
            elif info.deprecated:
 
 
2433
                deprecated_pairs.append((key, help))
 
 
2434
            elif info.experimental:
 
 
2435
                experimental_pairs.append((key, help))
 
 
2437
                output += wrapped(key, help, info)
 
 
2438
        if len(experimental_pairs) > 0:
 
 
2439
            output += "Experimental formats are shown below.\n\n"
 
 
2440
            for key, help in experimental_pairs:
 
 
2441
                info = self.get_info(key)
 
 
2442
                output += wrapped(key, help, info)
 
 
2443
        if len(deprecated_pairs) > 0:
 
 
2444
            output += "Deprecated formats are shown below.\n\n"
 
 
2445
            for key, help in deprecated_pairs:
 
 
2446
                info = self.get_info(key)
 
 
2447
                output += wrapped(key, help, info)
 
 
2452
format_registry = BzrDirFormatRegistry()
 
 
2453
format_registry.register('weave', BzrDirFormat6,
 
 
2454
    'Pre-0.8 format.  Slower than knit and does not'
 
 
2455
    ' support checkouts or shared repositories.',
 
 
2457
format_registry.register_metadir('knit',
 
 
2458
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
 
 
2459
    'Format using knits.  Recommended for interoperation with bzr <= 0.14.',
 
 
2460
    branch_format='bzrlib.branch.BzrBranchFormat5',
 
 
2461
    tree_format='bzrlib.workingtree.WorkingTreeFormat3')
 
 
2462
format_registry.register_metadir('metaweave',
 
 
2463
    'bzrlib.repofmt.weaverepo.RepositoryFormat7',
 
 
2464
    'Transitional format in 0.8.  Slower than knit.',
 
 
2465
    branch_format='bzrlib.branch.BzrBranchFormat5',
 
 
2466
    tree_format='bzrlib.workingtree.WorkingTreeFormat3',
 
 
2468
format_registry.register_metadir('dirstate',
 
 
2469
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
 
 
2470
    help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
 
 
2471
        'above when accessed over the network.',
 
 
2472
    branch_format='bzrlib.branch.BzrBranchFormat5',
 
 
2473
    # this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
 
 
2474
    # directly from workingtree_4 triggers a circular import.
 
 
2475
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
 
2477
format_registry.register_metadir('dirstate-tags',
 
 
2478
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
 
 
2479
    help='New in 0.15: Fast local operations and improved scaling for '
 
 
2480
        'network operations. Additionally adds support for tags.'
 
 
2481
        ' Incompatible with bzr < 0.15.',
 
 
2482
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
 
2483
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
 
2485
format_registry.register_metadir('dirstate-with-subtree',
 
 
2486
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
 
 
2487
    help='New in 0.15: Fast local operations and improved scaling for '
 
 
2488
        'network operations. Additionally adds support for versioning nested '
 
 
2489
        'bzr branches. Incompatible with bzr < 0.15.',
 
 
2490
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
 
2491
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
 
2494
format_registry.register_metadir('knitpack-experimental',
 
 
2495
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack1',
 
 
2496
    help='New in 0.92: Pack-based format with data compatible with '
 
 
2497
        'dirstate-tags format repositories. Interoperates with '
 
 
2498
        'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
 
 
2499
        'NOTE: This format is experimental. Before using it, please read '
 
 
2500
        'http://doc.bazaar-vcs.org/latest/developers/knitpack.html.',
 
 
2501
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
 
2502
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
 
2505
format_registry.register_metadir('knitpack-subtree-experimental',
 
 
2506
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack3',
 
 
2507
    help='New in 0.92: Pack-based format with data compatible with '
 
 
2508
        'dirstate-with-subtree format repositories. Interoperates with '
 
 
2509
        'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
 
 
2510
        'NOTE: This format is experimental. Before using it, please read '
 
 
2511
        'http://doc.bazaar-vcs.org/latest/developers/knitpack.html.',
 
 
2512
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
 
2513
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
 
2517
format_registry.set_default('dirstate-tags')