~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

  • Committer: Aaron Bentley
  • Date: 2007-02-06 14:52:16 UTC
  • mfrom: (2266 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2268.
  • Revision ID: abentley@panoramicfeedback.com-20070206145216-fcpi8o3ufvuzwbp9
Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
18
18
 
19
19
At format 7 this was split out into Branch, Repository and Checkout control
20
20
directories.
21
 
 
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
25
 
objects returned.
26
21
"""
27
22
 
28
 
# TODO: Move old formats into a plugin to make this file smaller.
 
23
# TODO: remove unittest dependency; put that stuff inside the test suite
 
24
 
 
25
# TODO: The Format probe_transport seems a bit redundant with just trying to
 
26
# open the bzrdir. -- mbp
 
27
#
 
28
# TODO: Can we move specific formats into separate modules to make this file
 
29
# smaller?
29
30
 
30
31
from cStringIO import StringIO
31
32
import os
32
 
import sys
 
33
import textwrap
33
34
 
34
35
from bzrlib.lazy_import import lazy_import
35
36
lazy_import(globals(), """
 
37
from copy import deepcopy
36
38
from stat import S_ISDIR
37
 
import textwrap
38
 
from warnings import warn
 
39
import unittest
39
40
 
40
41
import bzrlib
41
42
from bzrlib import (
42
 
    config,
43
43
    errors,
44
 
    graph,
45
44
    lockable_files,
46
45
    lockdir,
47
 
    osutils,
48
46
    registry,
49
 
    remote,
50
47
    revision as _mod_revision,
 
48
    repository as _mod_repository,
51
49
    symbol_versioning,
52
 
    ui,
53
50
    urlutils,
54
 
    versionedfile,
55
 
    win32utils,
56
 
    workingtree,
57
 
    workingtree_4,
58
51
    xml4,
59
52
    xml5,
60
53
    )
61
54
from bzrlib.osutils import (
 
55
    safe_unicode,
62
56
    sha_strings,
63
57
    sha_string,
64
58
    )
65
 
from bzrlib.repository import Repository
66
 
from bzrlib.smart.client import _SmartClient
67
 
from bzrlib.smart import protocol
 
59
from bzrlib.store.revision.text import TextRevisionStore
 
60
from bzrlib.store.text import TextStore
68
61
from bzrlib.store.versioned import WeaveStore
69
62
from bzrlib.transactions import WriteTransaction
70
 
from bzrlib.transport import (
71
 
    do_catching_redirections,
72
 
    get_transport,
73
 
    )
 
63
from bzrlib.transport import get_transport
74
64
from bzrlib.weave import Weave
75
65
""")
76
66
 
77
 
from bzrlib.trace import (
78
 
    mutter,
79
 
    note,
80
 
    )
 
67
from bzrlib.trace import mutter
81
68
from bzrlib.transport.local import LocalTransport
82
 
from bzrlib.symbol_versioning import (
83
 
    deprecated_function,
84
 
    deprecated_method,
85
 
    )
86
69
 
87
70
 
88
71
class BzrDir(object):
91
74
    BzrDir instances let you create or open any of the things that can be
92
75
    found within .bzr - checkouts, branches and repositories.
93
76
    
94
 
    :ivar transport:
 
77
    transport
95
78
        the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
96
 
    :ivar root_transport:
97
 
        a transport connected to the directory this bzr was opened from
98
 
        (i.e. the parent directory holding the .bzr directory).
99
 
 
100
 
    Everything in the bzrdir should have the same file permissions.
 
79
    root_transport
 
80
        a transport connected to the directory this bzr was opened from.
101
81
    """
102
82
 
103
83
    def break_lock(self):
106
86
        If there is a tree, the tree is opened and break_lock() called.
107
87
        Otherwise, branch is tried, and finally repository.
108
88
        """
109
 
        # XXX: This seems more like a UI function than something that really
110
 
        # belongs in this class.
111
89
        try:
112
90
            thing_to_unlock = self.open_workingtree()
113
91
        except (errors.NotLocalUrl, errors.NoWorkingTree):
130
108
        source_repo_format.check_conversion_target(target_repo_format)
131
109
 
132
110
    @staticmethod
133
 
    def _check_supported(format, allow_unsupported,
134
 
        recommend_upgrade=True,
135
 
        basedir=None):
136
 
        """Give an error or warning on old formats.
137
 
 
138
 
        :param format: may be any kind of format - workingtree, branch, 
139
 
        or repository.
140
 
 
141
 
        :param allow_unsupported: If true, allow opening 
142
 
        formats that are strongly deprecated, and which may 
143
 
        have limited functionality.
144
 
 
145
 
        :param recommend_upgrade: If true (default), warn
146
 
        the user through the ui object that they may wish
147
 
        to upgrade the object.
 
111
    def _check_supported(format, allow_unsupported):
 
112
        """Check whether format is a supported format.
 
113
 
 
114
        If allow_unsupported is True, this is a no-op.
148
115
        """
149
 
        # TODO: perhaps move this into a base Format class; it's not BzrDir
150
 
        # specific. mbp 20070323
151
116
        if not allow_unsupported and not format.is_supported():
152
117
            # see open_downlevel to open legacy branches.
153
118
            raise errors.UnsupportedFormatError(format=format)
154
 
        if recommend_upgrade \
155
 
            and getattr(format, 'upgrade_recommended', False):
156
 
            ui.ui_factory.recommend_upgrade(
157
 
                format.get_format_description(),
158
 
                basedir)
159
119
 
160
 
    def clone(self, url, revision_id=None, force_new_repo=False,
161
 
              preserve_stacking=False):
 
120
    def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
162
121
        """Clone this bzrdir and its contents to url verbatim.
163
122
 
164
 
        :param url: The url create the clone at.  If url's last component does
165
 
            not exist, it will be created.
166
 
        :param revision_id: The tip revision-id to use for any branch or
167
 
            working tree.  If not None, then the clone operation may tune
168
 
            itself to download less data.
169
 
        :param force_new_repo: Do not use a shared repository for the target
170
 
                               even if one is available.
171
 
        :param preserve_stacking: When cloning a stacked branch, stack the
172
 
            new branch on top of the other branch's stacked-on branch.
173
 
        """
174
 
        return self.clone_on_transport(get_transport(url),
175
 
                                       revision_id=revision_id,
176
 
                                       force_new_repo=force_new_repo,
177
 
                                       preserve_stacking=preserve_stacking)
178
 
 
179
 
    def clone_on_transport(self, transport, revision_id=None,
180
 
                           force_new_repo=False, preserve_stacking=False):
181
 
        """Clone this bzrdir and its contents to transport verbatim.
182
 
 
183
 
        :param transport: The transport for the location to produce the clone
184
 
            at.  If the target directory does not exist, it will be created.
185
 
        :param revision_id: The tip revision-id to use for any branch or
186
 
            working tree.  If not None, then the clone operation may tune
187
 
            itself to download less data.
188
 
        :param force_new_repo: Do not use a shared repository for the target,
189
 
                               even if one is available.
190
 
        :param preserve_stacking: When cloning a stacked branch, stack the
191
 
            new branch on top of the other branch's stacked-on branch.
192
 
        """
193
 
        transport.ensure_base()
194
 
        result = self.cloning_metadir().initialize_on_transport(transport)
195
 
        repository_policy = None
196
 
        stack_on = None
 
123
        If urls last component does not exist, it will be created.
 
124
 
 
125
        if revision_id is not None, then the clone operation may tune
 
126
            itself to download less data.
 
127
        :param force_new_repo: Do not use a shared repository for the target 
 
128
                               even if one is available.
 
129
        """
 
130
        self._make_tail(url)
 
131
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
 
132
        result = self._format.initialize(url)
197
133
        try:
198
134
            local_repo = self.find_repository()
199
135
        except errors.NoRepositoryPresent:
200
136
            local_repo = None
201
 
        try:
202
 
            local_branch = self.open_branch()
203
 
        except errors.NotBranchError:
204
 
            local_branch = None
205
 
        else:
206
 
            # enable fallbacks when branch is not a branch reference
207
 
            if local_branch.repository.has_same_location(local_repo):
208
 
                local_repo = local_branch.repository
209
 
            if preserve_stacking:
210
 
                try:
211
 
                    stack_on = local_branch.get_stacked_on_url()
212
 
                except (errors.UnstackableBranchFormat,
213
 
                        errors.UnstackableRepositoryFormat,
214
 
                        errors.NotStacked):
215
 
                    pass
216
 
 
217
137
        if local_repo:
218
138
            # may need to copy content in
219
 
            repository_policy = result.determine_repository_policy(
220
 
                force_new_repo, stack_on, self.root_transport.base)
221
 
            make_working_trees = local_repo.make_working_trees()
222
 
            result_repo = repository_policy.acquire_repository(
223
 
                make_working_trees, local_repo.is_shared())
224
 
            result_repo.fetch(local_repo, revision_id=revision_id)
225
 
        else:
226
 
            result_repo = None
 
139
            if force_new_repo:
 
140
                result_repo = local_repo.clone(
 
141
                    result,
 
142
                    revision_id=revision_id,
 
143
                    basis=basis_repo)
 
144
                result_repo.set_make_working_trees(local_repo.make_working_trees())
 
145
            else:
 
146
                try:
 
147
                    result_repo = result.find_repository()
 
148
                    # fetch content this dir needs.
 
149
                    if basis_repo:
 
150
                        # XXX FIXME RBC 20060214 need tests for this when the basis
 
151
                        # is incomplete
 
152
                        result_repo.fetch(basis_repo, revision_id=revision_id)
 
153
                    result_repo.fetch(local_repo, revision_id=revision_id)
 
154
                except errors.NoRepositoryPresent:
 
155
                    # needed to make one anyway.
 
156
                    result_repo = local_repo.clone(
 
157
                        result,
 
158
                        revision_id=revision_id,
 
159
                        basis=basis_repo)
 
160
                    result_repo.set_make_working_trees(local_repo.make_working_trees())
227
161
        # 1 if there is a branch present
228
162
        #   make sure its content is available in the target repository
229
163
        #   clone it.
230
 
        if local_branch is not None:
231
 
            result_branch = local_branch.clone(result, revision_id=revision_id)
232
 
            if repository_policy is not None:
233
 
                repository_policy.configure_branch(result_branch)
234
 
        if result_repo is None or result_repo.make_working_trees():
 
164
        try:
 
165
            self.open_branch().clone(result, revision_id=revision_id)
 
166
        except errors.NotBranchError:
 
167
            pass
 
168
        try:
 
169
            self.open_workingtree().clone(result, basis=basis_tree)
 
170
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
171
            pass
 
172
        return result
 
173
 
 
174
    def _get_basis_components(self, basis):
 
175
        """Retrieve the basis components that are available at basis."""
 
176
        if basis is None:
 
177
            return None, None, None
 
178
        try:
 
179
            basis_tree = basis.open_workingtree()
 
180
            basis_branch = basis_tree.branch
 
181
            basis_repo = basis_branch.repository
 
182
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
183
            basis_tree = None
235
184
            try:
236
 
                self.open_workingtree().clone(result)
237
 
            except (errors.NoWorkingTree, errors.NotLocalUrl):
238
 
                pass
239
 
        return result
 
185
                basis_branch = basis.open_branch()
 
186
                basis_repo = basis_branch.repository
 
187
            except errors.NotBranchError:
 
188
                basis_branch = None
 
189
                try:
 
190
                    basis_repo = basis.open_repository()
 
191
                except errors.NoRepositoryPresent:
 
192
                    basis_repo = None
 
193
        return basis_repo, basis_branch, basis_tree
240
194
 
241
195
    # TODO: This should be given a Transport, and should chdir up; otherwise
242
196
    # this will open a new connection.
243
197
    def _make_tail(self, url):
244
 
        t = get_transport(url)
245
 
        t.ensure_base()
 
198
        head, tail = urlutils.split(url)
 
199
        if tail and tail != '.':
 
200
            t = get_transport(head)
 
201
            try:
 
202
                t.mkdir(tail)
 
203
            except errors.FileExists:
 
204
                pass
246
205
 
 
206
    # TODO: Should take a Transport
247
207
    @classmethod
248
 
    def create(cls, base, format=None, possible_transports=None):
 
208
    def create(cls, base, format=None):
249
209
        """Create a new BzrDir at the url 'base'.
250
210
        
 
211
        This will call the current default formats initialize with base
 
212
        as the only parameter.
 
213
 
251
214
        :param format: If supplied, the format of branch to create.  If not
252
215
            supplied, the default is used.
253
 
        :param possible_transports: If supplied, a list of transports that 
254
 
            can be reused to share a remote connection.
255
216
        """
256
217
        if cls is not BzrDir:
257
218
            raise AssertionError("BzrDir.create always creates the default"
258
219
                " format, not one of %r" % cls)
259
 
        t = get_transport(base, possible_transports)
260
 
        t.ensure_base()
 
220
        head, tail = urlutils.split(base)
 
221
        if tail and tail != '.':
 
222
            t = get_transport(head)
 
223
            try:
 
224
                t.mkdir(tail)
 
225
            except errors.FileExists:
 
226
                pass
261
227
        if format is None:
262
228
            format = BzrDirFormat.get_default_format()
263
 
        return format.initialize_on_transport(t)
264
 
 
265
 
    @staticmethod
266
 
    def find_bzrdirs(transport, evaluate=None, list_current=None):
267
 
        """Find bzrdirs recursively from current location.
268
 
 
269
 
        This is intended primarily as a building block for more sophisticated
270
 
        functionality, like finding trees under a directory, or finding
271
 
        branches that use a given repository.
272
 
        :param evaluate: An optional callable that yields recurse, value,
273
 
            where recurse controls whether this bzrdir is recursed into
274
 
            and value is the value to yield.  By default, all bzrdirs
275
 
            are recursed into, and the return value is the bzrdir.
276
 
        :param list_current: if supplied, use this function to list the current
277
 
            directory, instead of Transport.list_dir
278
 
        :return: a generator of found bzrdirs, or whatever evaluate returns.
279
 
        """
280
 
        if list_current is None:
281
 
            def list_current(transport):
282
 
                return transport.list_dir('')
283
 
        if evaluate is None:
284
 
            def evaluate(bzrdir):
285
 
                return True, bzrdir
286
 
 
287
 
        pending = [transport]
288
 
        while len(pending) > 0:
289
 
            current_transport = pending.pop()
290
 
            recurse = True
291
 
            try:
292
 
                bzrdir = BzrDir.open_from_transport(current_transport)
293
 
            except errors.NotBranchError:
294
 
                pass
295
 
            else:
296
 
                recurse, value = evaluate(bzrdir)
297
 
                yield value
298
 
            try:
299
 
                subdirs = list_current(current_transport)
300
 
            except errors.NoSuchFile:
301
 
                continue
302
 
            if recurse:
303
 
                for subdir in sorted(subdirs, reverse=True):
304
 
                    pending.append(current_transport.clone(subdir))
305
 
 
306
 
    @staticmethod
307
 
    def find_branches(transport):
308
 
        """Find all branches under a transport.
309
 
 
310
 
        This will find all branches below the transport, including branches
311
 
        inside other branches.  Where possible, it will use
312
 
        Repository.find_branches.
313
 
 
314
 
        To list all the branches that use a particular Repository, see
315
 
        Repository.find_branches
316
 
        """
317
 
        def evaluate(bzrdir):
318
 
            try:
319
 
                repository = bzrdir.open_repository()
320
 
            except errors.NoRepositoryPresent:
321
 
                pass
322
 
            else:
323
 
                return False, (None, repository)
324
 
            try:
325
 
                branch = bzrdir.open_branch()
326
 
            except errors.NotBranchError:
327
 
                return True, (None, None)
328
 
            else:
329
 
                return True, (branch, None)
330
 
        branches = []
331
 
        for branch, repo in BzrDir.find_bzrdirs(transport, evaluate=evaluate):
332
 
            if repo is not None:
333
 
                branches.extend(repo.find_branches())
334
 
            if branch is not None:
335
 
                branches.append(branch)
336
 
        return branches
337
 
 
338
 
    def destroy_repository(self):
339
 
        """Destroy the repository in this BzrDir"""
340
 
        raise NotImplementedError(self.destroy_repository)
 
229
        return format.initialize(safe_unicode(base))
341
230
 
342
231
    def create_branch(self):
343
232
        """Create a branch in this BzrDir.
344
233
 
345
 
        The bzrdir's format will control what branch format is created.
 
234
        The bzrdirs format will control what branch format is created.
346
235
        For more control see BranchFormatXX.create(a_bzrdir).
347
236
        """
348
237
        raise NotImplementedError(self.create_branch)
349
238
 
350
 
    def destroy_branch(self):
351
 
        """Destroy the branch in this BzrDir"""
352
 
        raise NotImplementedError(self.destroy_branch)
353
 
 
354
239
    @staticmethod
355
240
    def create_branch_and_repo(base, force_new_repo=False, format=None):
356
241
        """Create a new BzrDir, Branch and Repository at the url 'base'.
357
242
 
358
 
        This will use the current default BzrDirFormat unless one is
359
 
        specified, and use whatever 
 
243
        This will use the current default BzrDirFormat, and use whatever 
360
244
        repository format that that uses via bzrdir.create_branch and
361
245
        create_repository. If a shared repository is available that is used
362
246
        preferentially.
365
249
 
366
250
        :param base: The URL to create the branch at.
367
251
        :param force_new_repo: If True a new repository is always created.
368
 
        :param format: If supplied, the format of branch to create.  If not
369
 
            supplied, the default is used.
370
252
        """
371
253
        bzrdir = BzrDir.create(base, format)
372
254
        bzrdir._find_or_create_repository(force_new_repo)
373
255
        return bzrdir.create_branch()
374
256
 
375
 
    def determine_repository_policy(self, force_new_repo=False, stack_on=None,
376
 
                                    stack_on_pwd=None, require_stacking=False):
377
 
        """Return an object representing a policy to use.
378
 
 
379
 
        This controls whether a new repository is created, or a shared
380
 
        repository used instead.
381
 
 
382
 
        If stack_on is supplied, will not seek a containing shared repo.
383
 
 
384
 
        :param force_new_repo: If True, require a new repository to be created.
385
 
        :param stack_on: If supplied, the location to stack on.  If not
386
 
            supplied, a default_stack_on location may be used.
387
 
        :param stack_on_pwd: If stack_on is relative, the location it is
388
 
            relative to.
389
 
        """
390
 
        def repository_policy(found_bzrdir):
391
 
            stack_on = None
392
 
            stack_on_pwd = None
393
 
            config = found_bzrdir.get_config()
394
 
            stop = False
395
 
            if config is not None:
396
 
                stack_on = config.get_default_stack_on()
397
 
                if stack_on is not None:
398
 
                    stack_on_pwd = found_bzrdir.root_transport.base
399
 
                    stop = True
400
 
                    note('Using default stacking branch %s at %s', stack_on,
401
 
                         stack_on_pwd)
402
 
            # does it have a repository ?
403
 
            try:
404
 
                repository = found_bzrdir.open_repository()
405
 
            except errors.NoRepositoryPresent:
406
 
                repository = None
407
 
            else:
408
 
                if ((found_bzrdir.root_transport.base !=
409
 
                     self.root_transport.base) and not repository.is_shared()):
410
 
                    repository = None
411
 
                else:
412
 
                    stop = True
413
 
            if not stop:
414
 
                return None, False
415
 
            if repository:
416
 
                return UseExistingRepository(repository, stack_on,
417
 
                    stack_on_pwd, require_stacking=require_stacking), True
418
 
            else:
419
 
                return CreateRepository(self, stack_on, stack_on_pwd,
420
 
                    require_stacking=require_stacking), True
421
 
 
422
 
        if not force_new_repo:
423
 
            if stack_on is None:
424
 
                policy = self._find_containing(repository_policy)
425
 
                if policy is not None:
426
 
                    return policy
427
 
            else:
428
 
                try:
429
 
                    return UseExistingRepository(self.open_repository(),
430
 
                        stack_on, stack_on_pwd,
431
 
                        require_stacking=require_stacking)
432
 
                except errors.NoRepositoryPresent:
433
 
                    pass
434
 
        return CreateRepository(self, stack_on, stack_on_pwd,
435
 
                                require_stacking=require_stacking)
436
 
 
437
257
    def _find_or_create_repository(self, force_new_repo):
438
258
        """Create a new repository if needed, returning the repository."""
439
 
        policy = self.determine_repository_policy(force_new_repo)
440
 
        return policy.acquire_repository()
441
 
 
 
259
        if force_new_repo:
 
260
            return self.create_repository()
 
261
        try:
 
262
            return self.find_repository()
 
263
        except errors.NoRepositoryPresent:
 
264
            return self.create_repository()
 
265
        
442
266
    @staticmethod
443
267
    def create_branch_convenience(base, force_new_repo=False,
444
 
                                  force_new_tree=None, format=None,
445
 
                                  possible_transports=None):
 
268
                                  force_new_tree=None, format=None):
446
269
        """Create a new BzrDir, Branch and Repository at the url 'base'.
447
270
 
448
271
        This is a convenience function - it will use an existing repository
449
272
        if possible, can be told explicitly whether to create a working tree or
450
273
        not.
451
274
 
452
 
        This will use the current default BzrDirFormat unless one is
453
 
        specified, and use whatever 
 
275
        This will use the current default BzrDirFormat, and use whatever 
454
276
        repository format that that uses via bzrdir.create_branch and
455
277
        create_repository. If a shared repository is available that is used
456
278
        preferentially. Whatever repository is used, its tree creation policy
465
287
        :param force_new_repo: If True a new repository is always created.
466
288
        :param force_new_tree: If True or False force creation of a tree or 
467
289
                               prevent such creation respectively.
468
 
        :param format: Override for the bzrdir format to create.
469
 
        :param possible_transports: An optional reusable transports list.
 
290
        :param format: Override for the for the bzrdir format to create
470
291
        """
471
292
        if force_new_tree:
472
293
            # check for non local urls
473
 
            t = get_transport(base, possible_transports)
 
294
            t = get_transport(safe_unicode(base))
474
295
            if not isinstance(t, LocalTransport):
475
296
                raise errors.NotLocalUrl(base)
476
 
        bzrdir = BzrDir.create(base, format, possible_transports)
 
297
        bzrdir = BzrDir.create(base, format)
477
298
        repo = bzrdir._find_or_create_repository(force_new_repo)
478
299
        result = bzrdir.create_branch()
479
 
        if force_new_tree or (repo.make_working_trees() and
 
300
        if force_new_tree or (repo.make_working_trees() and 
480
301
                              force_new_tree is None):
481
302
            try:
482
303
                bzrdir.create_workingtree()
483
304
            except errors.NotLocalUrl:
484
305
                pass
485
306
        return result
 
307
        
 
308
    @staticmethod
 
309
    def create_repository(base, shared=False, format=None):
 
310
        """Create a new BzrDir and Repository at the url 'base'.
 
311
 
 
312
        If no format is supplied, this will default to the current default
 
313
        BzrDirFormat by default, and use whatever repository format that that
 
314
        uses for bzrdirformat.create_repository.
 
315
 
 
316
        :param shared: Create a shared repository rather than a standalone
 
317
                       repository.
 
318
        The Repository object is returned.
 
319
 
 
320
        This must be overridden as an instance method in child classes, where
 
321
        it should take no parameters and construct whatever repository format
 
322
        that child class desires.
 
323
        """
 
324
        bzrdir = BzrDir.create(base, format)
 
325
        return bzrdir.create_repository(shared)
486
326
 
487
327
    @staticmethod
488
328
    def create_standalone_workingtree(base, format=None):
490
330
 
491
331
        'base' must be a local path or a file:// url.
492
332
 
493
 
        This will use the current default BzrDirFormat unless one is
494
 
        specified, and use whatever 
 
333
        This will use the current default BzrDirFormat, and use whatever 
495
334
        repository format that that uses for bzrdirformat.create_workingtree,
496
335
        create_branch and create_repository.
497
336
 
498
 
        :param format: Override for the bzrdir format to create.
499
337
        :return: The WorkingTree object.
500
338
        """
501
 
        t = get_transport(base)
 
339
        t = get_transport(safe_unicode(base))
502
340
        if not isinstance(t, LocalTransport):
503
341
            raise errors.NotLocalUrl(base)
504
 
        bzrdir = BzrDir.create_branch_and_repo(base,
 
342
        bzrdir = BzrDir.create_branch_and_repo(safe_unicode(base),
505
343
                                               force_new_repo=True,
506
344
                                               format=format).bzrdir
507
345
        return bzrdir.create_workingtree()
508
346
 
509
 
    def create_workingtree(self, revision_id=None, from_branch=None,
510
 
        accelerator_tree=None, hardlink=False):
 
347
    def create_workingtree(self, revision_id=None):
511
348
        """Create a working tree at this BzrDir.
512
349
        
513
 
        :param revision_id: create it as of this revision id.
514
 
        :param from_branch: override bzrdir branch (for lightweight checkouts)
515
 
        :param accelerator_tree: A tree which can be used for retrieving file
516
 
            contents more quickly than the revision tree, i.e. a workingtree.
517
 
            The revision tree will be used for cases where accelerator_tree's
518
 
            content is different.
 
350
        revision_id: create it as of this revision id.
519
351
        """
520
352
        raise NotImplementedError(self.create_workingtree)
521
353
 
522
 
    def retire_bzrdir(self, limit=10000):
523
 
        """Permanently disable the bzrdir.
524
 
 
525
 
        This is done by renaming it to give the user some ability to recover
526
 
        if there was a problem.
527
 
 
528
 
        This will have horrible consequences if anyone has anything locked or
529
 
        in use.
530
 
        :param limit: number of times to retry
531
 
        """
532
 
        i  = 0
533
 
        while True:
534
 
            try:
535
 
                to_path = '.bzr.retired.%d' % i
536
 
                self.root_transport.rename('.bzr', to_path)
537
 
                note("renamed %s to %s"
538
 
                    % (self.root_transport.abspath('.bzr'), to_path))
539
 
                return
540
 
            except (errors.TransportError, IOError, errors.PathError):
541
 
                i += 1
542
 
                if i > limit:
543
 
                    raise
544
 
                else:
545
 
                    pass
546
 
 
547
354
    def destroy_workingtree(self):
548
355
        """Destroy the working tree at this BzrDir.
549
356
 
559
366
        """
560
367
        raise NotImplementedError(self.destroy_workingtree_metadata)
561
368
 
562
 
    def _find_containing(self, evaluate):
563
 
        """Find something in a containing control directory.
564
 
 
565
 
        This method will scan containing control dirs, until it finds what
566
 
        it is looking for, decides that it will never find it, or runs out
567
 
        of containing control directories to check.
568
 
 
569
 
        It is used to implement find_repository and
570
 
        determine_repository_policy.
571
 
 
572
 
        :param evaluate: A function returning (value, stop).  If stop is True,
573
 
            the value will be returned.
 
369
    def find_repository(self):
 
370
        """Find the repository that should be used for a_bzrdir.
 
371
 
 
372
        This does not require a branch as we use it to find the repo for
 
373
        new branches as well as to hook existing branches up to their
 
374
        repository.
574
375
        """
575
 
        found_bzrdir = self
 
376
        try:
 
377
            return self.open_repository()
 
378
        except errors.NoRepositoryPresent:
 
379
            pass
 
380
        next_transport = self.root_transport.clone('..')
576
381
        while True:
577
 
            result, stop = evaluate(found_bzrdir)
578
 
            if stop:
579
 
                return result
580
 
            next_transport = found_bzrdir.root_transport.clone('..')
581
 
            if (found_bzrdir.root_transport.base == next_transport.base):
582
 
                # top of the file system
583
 
                return None
584
382
            # find the next containing bzrdir
585
383
            try:
586
384
                found_bzrdir = BzrDir.open_containing_from_transport(
587
385
                    next_transport)[0]
588
386
            except errors.NotBranchError:
589
 
                return None
590
 
 
591
 
    def find_repository(self):
592
 
        """Find the repository that should be used.
593
 
 
594
 
        This does not require a branch as we use it to find the repo for
595
 
        new branches as well as to hook existing branches up to their
596
 
        repository.
597
 
        """
598
 
        def usable_repository(found_bzrdir):
 
387
                # none found
 
388
                raise errors.NoRepositoryPresent(self)
599
389
            # does it have a repository ?
600
390
            try:
601
391
                repository = found_bzrdir.open_repository()
602
392
            except errors.NoRepositoryPresent:
603
 
                return None, False
604
 
            if found_bzrdir.root_transport.base == self.root_transport.base:
605
 
                return repository, True
606
 
            elif repository.is_shared():
607
 
                return repository, True
 
393
                next_transport = found_bzrdir.root_transport.clone('..')
 
394
                if (found_bzrdir.root_transport.base == next_transport.base):
 
395
                    # top of the file system
 
396
                    break
 
397
                else:
 
398
                    continue
 
399
            if ((found_bzrdir.root_transport.base == 
 
400
                 self.root_transport.base) or repository.is_shared()):
 
401
                return repository
608
402
            else:
609
 
                return None, True
610
 
 
611
 
        found_repo = self._find_containing(usable_repository)
612
 
        if found_repo is None:
613
 
            raise errors.NoRepositoryPresent(self)
614
 
        return found_repo
615
 
 
616
 
    def get_branch_reference(self):
617
 
        """Return the referenced URL for the branch in this bzrdir.
618
 
 
619
 
        :raises NotBranchError: If there is no Branch.
620
 
        :return: The URL the branch in this bzrdir references if it is a
621
 
            reference branch, or None for regular branches.
622
 
        """
623
 
        return None
 
403
                raise errors.NoRepositoryPresent(self)
 
404
        raise errors.NoRepositoryPresent(self)
624
405
 
625
406
    def get_branch_transport(self, branch_format):
626
407
        """Get the transport for use by branch format in this BzrDir.
630
411
        a format string, and vice versa.
631
412
 
632
413
        If branch_format is None, the transport is returned with no 
633
 
        checking. If it is not None, then the returned transport is
 
414
        checking. if it is not None, then the returned transport is
634
415
        guaranteed to point to an existing directory ready for use.
635
416
        """
636
417
        raise NotImplementedError(self.get_branch_transport)
637
 
 
638
 
    def _find_creation_modes(self):
639
 
        """Determine the appropriate modes for files and directories.
640
 
        
641
 
        They're always set to be consistent with the base directory,
642
 
        assuming that this transport allows setting modes.
643
 
        """
644
 
        # TODO: Do we need or want an option (maybe a config setting) to turn
645
 
        # this off or override it for particular locations? -- mbp 20080512
646
 
        if self._mode_check_done:
647
 
            return
648
 
        self._mode_check_done = True
649
 
        try:
650
 
            st = self.transport.stat('.')
651
 
        except errors.TransportNotPossible:
652
 
            self._dir_mode = None
653
 
            self._file_mode = None
654
 
        else:
655
 
            # Check the directory mode, but also make sure the created
656
 
            # directories and files are read-write for this user. This is
657
 
            # mostly a workaround for filesystems which lie about being able to
658
 
            # write to a directory (cygwin & win32)
659
 
            self._dir_mode = (st.st_mode & 07777) | 00700
660
 
            # Remove the sticky and execute bits for files
661
 
            self._file_mode = self._dir_mode & ~07111
662
 
 
663
 
    def _get_file_mode(self):
664
 
        """Return Unix mode for newly created files, or None.
665
 
        """
666
 
        if not self._mode_check_done:
667
 
            self._find_creation_modes()
668
 
        return self._file_mode
669
 
 
670
 
    def _get_dir_mode(self):
671
 
        """Return Unix mode for newly created directories, or None.
672
 
        """
673
 
        if not self._mode_check_done:
674
 
            self._find_creation_modes()
675
 
        return self._dir_mode
676
418
        
677
419
    def get_repository_transport(self, repository_format):
678
420
        """Get the transport for use by repository format in this BzrDir.
682
424
        a format string, and vice versa.
683
425
 
684
426
        If repository_format is None, the transport is returned with no 
685
 
        checking. If it is not None, then the returned transport is
 
427
        checking. if it is not None, then the returned transport is
686
428
        guaranteed to point to an existing directory ready for use.
687
429
        """
688
430
        raise NotImplementedError(self.get_repository_transport)
691
433
        """Get the transport for use by workingtree format in this BzrDir.
692
434
 
693
435
        Note that bzr dirs that do not support format strings will raise
694
 
        IncompatibleFormat if the workingtree format they are given has a
695
 
        format string, and vice versa.
 
436
        IncompatibleFormat if the workingtree format they are given has
 
437
        a format string, and vice versa.
696
438
 
697
439
        If workingtree_format is None, the transport is returned with no 
698
 
        checking. If it is not None, then the returned transport is
 
440
        checking. if it is not None, then the returned transport is
699
441
        guaranteed to point to an existing directory ready for use.
700
442
        """
701
443
        raise NotImplementedError(self.get_workingtree_transport)
702
 
 
703
 
    def get_config(self):
704
 
        if getattr(self, '_get_config', None) is None:
705
 
            return None
706
 
        return self._get_config()
707
 
 
 
444
        
708
445
    def __init__(self, _transport, _format):
709
446
        """Initialize a Bzr control dir object.
710
447
        
717
454
        self._format = _format
718
455
        self.transport = _transport.clone('.bzr')
719
456
        self.root_transport = _transport
720
 
        self._mode_check_done = False
721
457
 
722
458
    def is_control_filename(self, filename):
723
459
        """True if filename is the name of a path which is reserved for bzrdir's.
733
469
        # this might be better on the BzrDirFormat class because it refers to 
734
470
        # all the possible bzrdir disk formats. 
735
471
        # This method is tested via the workingtree is_control_filename tests- 
736
 
        # it was extracted from WorkingTree.is_control_filename. If the method's
737
 
        # contract is extended beyond the current trivial implementation, please
 
472
        # it was extracted from WorkingTree.is_control_filename. If the methods
 
473
        # contract is extended beyond the current trivial  implementation please
738
474
        # add new tests for it to the appropriate place.
739
475
        return filename == '.bzr' or filename.startswith('.bzr/')
740
476
 
755
491
        return BzrDir.open(base, _unsupported=True)
756
492
        
757
493
    @staticmethod
758
 
    def open(base, _unsupported=False, possible_transports=None):
759
 
        """Open an existing bzrdir, rooted at 'base' (url).
 
494
    def open(base, _unsupported=False):
 
495
        """Open an existing bzrdir, rooted at 'base' (url)
760
496
        
761
 
        :param _unsupported: a private parameter to the BzrDir class.
 
497
        _unsupported is a private parameter to the BzrDir class.
762
498
        """
763
 
        t = get_transport(base, possible_transports=possible_transports)
 
499
        t = get_transport(base)
764
500
        return BzrDir.open_from_transport(t, _unsupported=_unsupported)
765
501
 
766
502
    @staticmethod
767
 
    def open_from_transport(transport, _unsupported=False,
768
 
                            _server_formats=True):
 
503
    def open_from_transport(transport, _unsupported=False):
769
504
        """Open a bzrdir within a particular directory.
770
505
 
771
506
        :param transport: Transport containing the bzrdir.
772
507
        :param _unsupported: private.
773
508
        """
774
 
        base = transport.base
775
 
 
776
 
        def find_format(transport):
777
 
            return transport, BzrDirFormat.find_format(
778
 
                transport, _server_formats=_server_formats)
779
 
 
780
 
        def redirected(transport, e, redirection_notice):
781
 
            qualified_source = e.get_source_url()
782
 
            relpath = transport.relpath(qualified_source)
783
 
            if not e.target.endswith(relpath):
784
 
                # Not redirected to a branch-format, not a branch
785
 
                raise errors.NotBranchError(path=e.target)
786
 
            target = e.target[:-len(relpath)]
787
 
            note('%s is%s redirected to %s',
788
 
                 transport.base, e.permanently, target)
789
 
            # Let's try with a new transport
790
 
            # FIXME: If 'transport' has a qualifier, this should
791
 
            # be applied again to the new transport *iff* the
792
 
            # schemes used are the same. Uncomment this code
793
 
            # once the function (and tests) exist.
794
 
            # -- vila20070212
795
 
            #target = urlutils.copy_url_qualifiers(original, target)
796
 
            return get_transport(target)
797
 
 
798
 
        try:
799
 
            transport, format = do_catching_redirections(find_format,
800
 
                                                         transport,
801
 
                                                         redirected)
802
 
        except errors.TooManyRedirections:
803
 
            raise errors.NotBranchError(base)
804
 
 
 
509
        format = BzrDirFormat.find_format(transport)
805
510
        BzrDir._check_supported(format, _unsupported)
806
511
        return format.open(transport, _found=True)
807
512
 
816
521
        raise NotImplementedError(self.open_branch)
817
522
 
818
523
    @staticmethod
819
 
    def open_containing(url, possible_transports=None):
 
524
    def open_containing(url):
820
525
        """Open an existing branch which contains url.
821
526
        
822
527
        :param url: url to search from.
823
528
        See open_containing_from_transport for more detail.
824
529
        """
825
 
        transport = get_transport(url, possible_transports)
826
 
        return BzrDir.open_containing_from_transport(transport)
 
530
        return BzrDir.open_containing_from_transport(get_transport(url))
827
531
    
828
532
    @staticmethod
829
533
    def open_containing_from_transport(a_transport):
830
 
        """Open an existing branch which contains a_transport.base.
 
534
        """Open an existing branch which contains a_transport.base
831
535
 
832
536
        This probes for a branch at a_transport, and searches upwards from there.
833
537
 
848
552
                return result, urlutils.unescape(a_transport.relpath(url))
849
553
            except errors.NotBranchError, e:
850
554
                pass
851
 
            try:
852
 
                new_t = a_transport.clone('..')
853
 
            except errors.InvalidURLJoin:
854
 
                # reached the root, whatever that may be
855
 
                raise errors.NotBranchError(path=url)
 
555
            new_t = a_transport.clone('..')
856
556
            if new_t.base == a_transport.base:
857
557
                # reached the root, whatever that may be
858
558
                raise errors.NotBranchError(path=url)
859
559
            a_transport = new_t
860
560
 
861
 
    def _get_tree_branch(self):
862
 
        """Return the branch and tree, if any, for this bzrdir.
863
 
 
864
 
        Return None for tree if not present or inaccessible.
865
 
        Raise NotBranchError if no branch is present.
866
 
        :return: (tree, branch)
867
 
        """
868
 
        try:
869
 
            tree = self.open_workingtree()
870
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
871
 
            tree = None
872
 
            branch = self.open_branch()
873
 
        else:
874
 
            branch = tree.branch
875
 
        return tree, branch
876
 
 
877
 
    @classmethod
878
 
    def open_tree_or_branch(klass, location):
879
 
        """Return the branch and working tree at a location.
880
 
 
881
 
        If there is no tree at the location, tree will be None.
882
 
        If there is no branch at the location, an exception will be
883
 
        raised
884
 
        :return: (tree, branch)
885
 
        """
886
 
        bzrdir = klass.open(location)
887
 
        return bzrdir._get_tree_branch()
888
 
 
889
561
    @classmethod
890
562
    def open_containing_tree_or_branch(klass, location):
891
563
        """Return the branch and working tree contained by a location.
897
569
        relpath is the portion of the path that is contained by the branch.
898
570
        """
899
571
        bzrdir, relpath = klass.open_containing(location)
900
 
        tree, branch = bzrdir._get_tree_branch()
 
572
        try:
 
573
            tree = bzrdir.open_workingtree()
 
574
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
575
            tree = None
 
576
            branch = bzrdir.open_branch()
 
577
        else:
 
578
            branch = tree.branch
901
579
        return tree, branch, relpath
902
580
 
903
 
    @classmethod
904
 
    def open_containing_tree_branch_or_repository(klass, location):
905
 
        """Return the working tree, branch and repo contained by a location.
906
 
 
907
 
        Returns (tree, branch, repository, relpath).
908
 
        If there is no tree containing the location, tree will be None.
909
 
        If there is no branch containing the location, branch will be None.
910
 
        If there is no repository containing the location, repository will be
911
 
        None.
912
 
        relpath is the portion of the path that is contained by the innermost
913
 
        BzrDir.
914
 
 
915
 
        If no tree, branch or repository is found, a NotBranchError is raised.
916
 
        """
917
 
        bzrdir, relpath = klass.open_containing(location)
918
 
        try:
919
 
            tree, branch = bzrdir._get_tree_branch()
920
 
        except errors.NotBranchError:
921
 
            try:
922
 
                repo = bzrdir.find_repository()
923
 
                return None, None, repo, relpath
924
 
            except (errors.NoRepositoryPresent):
925
 
                raise errors.NotBranchError(location)
926
 
        return tree, branch, branch.repository, relpath
927
 
 
928
581
    def open_repository(self, _unsupported=False):
929
582
        """Open the repository object at this BzrDir if one is present.
930
583
 
931
 
        This will not follow the Branch object pointer - it's strictly a direct
 
584
        This will not follow the Branch object pointer - its strictly a direct
932
585
        open facility. Most client code should use open_branch().repository to
933
586
        get at a repository.
934
587
 
935
 
        :param _unsupported: a private parameter, not part of the api.
 
588
        _unsupported is a private parameter, not part of the api.
936
589
        TODO: static convenience version of this?
937
590
        """
938
591
        raise NotImplementedError(self.open_repository)
939
592
 
940
 
    def open_workingtree(self, _unsupported=False,
941
 
                         recommend_upgrade=True, from_branch=None):
 
593
    def open_workingtree(self, _unsupported=False):
942
594
        """Open the workingtree object at this BzrDir if one is present.
943
 
 
944
 
        :param recommend_upgrade: Optional keyword parameter, when True (the
945
 
            default), emit through the ui module a recommendation that the user
946
 
            upgrade the working tree when the workingtree being opened is old
947
 
            (but still fully supported).
948
 
        :param from_branch: override bzrdir branch (for lightweight checkouts)
 
595
        
 
596
        TODO: static convenience version of this?
949
597
        """
950
598
        raise NotImplementedError(self.open_workingtree)
951
599
 
973
621
        workingtree and discards it, and that's somewhat expensive.) 
974
622
        """
975
623
        try:
976
 
            self.open_workingtree(recommend_upgrade=False)
 
624
            self.open_workingtree()
977
625
            return True
978
626
        except errors.NoWorkingTree:
979
627
            return False
980
628
 
981
 
    def _cloning_metadir(self):
982
 
        """Produce a metadir suitable for cloning with.
983
 
        
984
 
        :returns: (destination_bzrdir_format, source_repository)
985
 
        """
 
629
    def cloning_metadir(self, basis=None):
 
630
        """Produce a metadir suitable for cloning with"""
 
631
        def related_repository(bzrdir):
 
632
            try:
 
633
                branch = bzrdir.open_branch()
 
634
                return branch.repository
 
635
            except errors.NotBranchError:
 
636
                source_branch = None
 
637
                return bzrdir.open_repository()
986
638
        result_format = self._format.__class__()
987
639
        try:
988
640
            try:
989
 
                branch = self.open_branch()
990
 
                source_repository = branch.repository
991
 
            except errors.NotBranchError:
992
 
                source_branch = None
993
 
                source_repository = self.open_repository()
 
641
                source_repository = related_repository(self)
 
642
            except errors.NoRepositoryPresent:
 
643
                if basis is None:
 
644
                    raise
 
645
                source_repository = related_repository(self)
 
646
            result_format.repository_format = source_repository._format
994
647
        except errors.NoRepositoryPresent:
995
 
            source_repository = None
996
 
        else:
997
 
            # XXX TODO: This isinstance is here because we have not implemented
998
 
            # the fix recommended in bug # 103195 - to delegate this choice the
999
 
            # repository itself.
1000
 
            repo_format = source_repository._format
1001
 
            if not isinstance(repo_format, remote.RemoteRepositoryFormat):
1002
 
                result_format.repository_format = repo_format
1003
 
        try:
1004
 
            # TODO: Couldn't we just probe for the format in these cases,
1005
 
            # rather than opening the whole tree?  It would be a little
1006
 
            # faster. mbp 20070401
1007
 
            tree = self.open_workingtree(recommend_upgrade=False)
1008
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
1009
 
            result_format.workingtree_format = None
1010
 
        else:
1011
 
            result_format.workingtree_format = tree._format.__class__()
1012
 
        return result_format, source_repository
1013
 
 
1014
 
    def cloning_metadir(self):
1015
 
        """Produce a metadir suitable for cloning or sprouting with.
1016
 
 
1017
 
        These operations may produce workingtrees (yes, even though they're
1018
 
        "cloning" something that doesn't have a tree), so a viable workingtree
1019
 
        format must be selected.
1020
 
 
1021
 
        :returns: a BzrDirFormat with all component formats either set
1022
 
            appropriately or set to None if that component should not be 
1023
 
            created.
1024
 
        """
1025
 
        format, repository = self._cloning_metadir()
1026
 
        if format._workingtree_format is None:
1027
 
            if repository is None:
1028
 
                return format
1029
 
            tree_format = repository._format._matchingbzrdir.workingtree_format
1030
 
            format.workingtree_format = tree_format.__class__()
1031
 
        return format
1032
 
 
1033
 
    def checkout_metadir(self):
1034
 
        return self.cloning_metadir()
1035
 
 
1036
 
    def sprout(self, url, revision_id=None, force_new_repo=False,
1037
 
               recurse='down', possible_transports=None,
1038
 
               accelerator_tree=None, hardlink=False, stacked=False):
 
648
            pass
 
649
        return result_format
 
650
 
 
651
    def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
1039
652
        """Create a copy of this bzrdir prepared for use as a new line of
1040
653
        development.
1041
654
 
1042
 
        If url's last component does not exist, it will be created.
 
655
        If urls last component does not exist, it will be created.
1043
656
 
1044
657
        Attributes related to the identity of the source branch like
1045
658
        branch nickname will be cleaned, a working tree is created
1048
661
 
1049
662
        if revision_id is not None, then the clone operation may tune
1050
663
            itself to download less data.
1051
 
        :param accelerator_tree: A tree which can be used for retrieving file
1052
 
            contents more quickly than the revision tree, i.e. a workingtree.
1053
 
            The revision tree will be used for cases where accelerator_tree's
1054
 
            content is different.
1055
 
        :param hardlink: If true, hard-link files from accelerator_tree,
1056
 
            where possible.
1057
 
        :param stacked: If true, create a stacked branch referring to the
1058
 
            location of this control directory.
1059
664
        """
1060
 
        target_transport = get_transport(url, possible_transports)
1061
 
        target_transport.ensure_base()
1062
 
        cloning_format = self.cloning_metadir()
1063
 
        result = cloning_format.initialize_on_transport(target_transport)
 
665
        self._make_tail(url)
 
666
        cloning_format = self.cloning_metadir(basis)
 
667
        result = cloning_format.initialize(url)
 
668
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
1064
669
        try:
1065
670
            source_branch = self.open_branch()
1066
671
            source_repository = source_branch.repository
1067
 
            if stacked:
1068
 
                stacked_branch_url = self.root_transport.base
1069
 
            else:
1070
 
                # if a stacked branch wasn't requested, we don't create one
1071
 
                # even if the origin was stacked
1072
 
                stacked_branch_url = None
1073
672
        except errors.NotBranchError:
1074
673
            source_branch = None
1075
674
            try:
1076
675
                source_repository = self.open_repository()
1077
676
            except errors.NoRepositoryPresent:
1078
 
                source_repository = None
1079
 
            stacked_branch_url = None
1080
 
        repository_policy = result.determine_repository_policy(
1081
 
            force_new_repo, stacked_branch_url, require_stacking=stacked)
1082
 
        result_repo = repository_policy.acquire_repository()
1083
 
        if source_repository is not None:
1084
 
            # XXX: Isn't this redundant with the copy_content_into used below
1085
 
            # after creating the branch? -- mbp 20080724
1086
 
            result_repo.fetch(source_repository, revision_id=revision_id)
1087
 
 
1088
 
        # Create/update the result branch
1089
 
        if ((stacked 
1090
 
             or repository_policy._require_stacking 
1091
 
             or repository_policy._stack_on)
1092
 
            and not result._format.get_branch_format().supports_stacking()):
1093
 
            # force a branch that can support stacking 
1094
 
            from bzrlib.branch import BzrBranchFormat7
1095
 
            format = BzrBranchFormat7()
1096
 
            result_branch = format.initialize(result)
1097
 
            mutter("using %r for stacking" % (format,))
1098
 
        elif source_branch is None:
1099
 
            # this is for sprouting a bzrdir without a branch; is that
1100
 
            # actually useful?
1101
 
            result_branch = result.create_branch()
 
677
                # copy the entire basis one if there is one
 
678
                # but there is no repository.
 
679
                source_repository = basis_repo
 
680
        if force_new_repo:
 
681
            result_repo = None
1102
682
        else:
1103
 
            result_branch = source_branch._format.initialize(result)
1104
 
        mutter("created new branch %r" % (result_branch,))
1105
 
        repository_policy.configure_branch(result_branch)
 
683
            try:
 
684
                result_repo = result.find_repository()
 
685
            except errors.NoRepositoryPresent:
 
686
                result_repo = None
 
687
        if source_repository is None and result_repo is not None:
 
688
            pass
 
689
        elif source_repository is None and result_repo is None:
 
690
            # no repo available, make a new one
 
691
            result.create_repository()
 
692
        elif source_repository is not None and result_repo is None:
 
693
            # have source, and want to make a new target repo
 
694
            # we don't clone the repo because that preserves attributes
 
695
            # like is_shared(), and we have not yet implemented a 
 
696
            # repository sprout().
 
697
            result_repo = result.create_repository()
 
698
        if result_repo is not None:
 
699
            # fetch needed content into target.
 
700
            if basis_repo:
 
701
                # XXX FIXME RBC 20060214 need tests for this when the basis
 
702
                # is incomplete
 
703
                result_repo.fetch(basis_repo, revision_id=revision_id)
 
704
            if source_repository is not None:
 
705
                result_repo.fetch(source_repository, revision_id=revision_id)
1106
706
        if source_branch is not None:
1107
 
            # XXX: this duplicates Branch.sprout(); it probably belongs on an
1108
 
            # InterBranch method? -- mbp 20080724
1109
 
            source_branch.copy_content_into(result_branch,
1110
 
                 revision_id=revision_id)
1111
 
            result_branch.set_parent(self.root_transport.base)
1112
 
 
1113
 
        # Create/update the result working tree
1114
 
        if isinstance(target_transport, LocalTransport) and (
1115
 
            result_repo is None or result_repo.make_working_trees()):
1116
 
            wt = result.create_workingtree(accelerator_tree=accelerator_tree,
1117
 
                hardlink=hardlink)
1118
 
            wt.lock_write()
1119
 
            try:
1120
 
                if wt.path2id('') is None:
1121
 
                    try:
1122
 
                        wt.set_root_id(self.open_workingtree.get_root_id())
1123
 
                    except errors.NoWorkingTree:
1124
 
                        pass
1125
 
            finally:
1126
 
                wt.unlock()
 
707
            source_branch.sprout(result, revision_id=revision_id)
1127
708
        else:
1128
 
            wt = None
1129
 
        if recurse == 'down':
1130
 
            if wt is not None:
1131
 
                basis = wt.basis_tree()
1132
 
                basis.lock_read()
1133
 
                subtrees = basis.iter_references()
1134
 
            elif source_branch is not None:
1135
 
                basis = source_branch.basis_tree()
1136
 
                basis.lock_read()
1137
 
                subtrees = basis.iter_references()
1138
 
            else:
1139
 
                subtrees = []
1140
 
                basis = None
1141
 
            try:
1142
 
                for path, file_id in subtrees:
1143
 
                    target = urlutils.join(url, urlutils.escape(path))
1144
 
                    sublocation = source_branch.reference_parent(file_id, path)
1145
 
                    sublocation.bzrdir.sprout(target,
1146
 
                        basis.get_reference_revision(file_id, path),
1147
 
                        force_new_repo=force_new_repo, recurse=recurse,
1148
 
                        stacked=stacked)
1149
 
            finally:
1150
 
                if basis is not None:
1151
 
                    basis.unlock()
 
709
            result.create_branch()
 
710
        # TODO: jam 20060426 we probably need a test in here in the
 
711
        #       case that the newly sprouted branch is a remote one
 
712
        if result_repo is None or result_repo.make_working_trees():
 
713
            wt = result.create_workingtree()
 
714
            if wt.inventory.root is None:
 
715
                try:
 
716
                    wt.set_root_id(self.open_workingtree.get_root_id())
 
717
                except errors.NoWorkingTree:
 
718
                    pass
1152
719
        return result
1153
720
 
1154
721
 
1158
725
    def __init__(self, _transport, _format):
1159
726
        """See BzrDir.__init__."""
1160
727
        super(BzrDirPreSplitOut, self).__init__(_transport, _format)
 
728
        assert self._format._lock_class == lockable_files.TransportLock
 
729
        assert self._format._lock_file_name == 'branch-lock'
1161
730
        self._control_files = lockable_files.LockableFiles(
1162
731
                                            self.get_branch_transport(None),
1163
732
                                            self._format._lock_file_name,
1167
736
        """Pre-splitout bzrdirs do not suffer from stale locks."""
1168
737
        raise NotImplementedError(self.break_lock)
1169
738
 
1170
 
    def cloning_metadir(self):
1171
 
        """Produce a metadir suitable for cloning with."""
1172
 
        return self._format.__class__()
1173
 
 
1174
 
    def clone(self, url, revision_id=None, force_new_repo=False,
1175
 
              preserve_stacking=False):
1176
 
        """See BzrDir.clone().
1177
 
 
1178
 
        force_new_repo has no effect, since this family of formats always
1179
 
        require a new repository.
1180
 
        preserve_stacking has no effect, since no source branch using this
1181
 
        family of formats can be stacked, so there is no stacking to preserve.
1182
 
        """
 
739
    def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
 
740
        """See BzrDir.clone()."""
1183
741
        from bzrlib.workingtree import WorkingTreeFormat2
1184
742
        self._make_tail(url)
1185
743
        result = self._format._initialize_for_clone(url)
1186
 
        self.open_repository().clone(result, revision_id=revision_id)
 
744
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
 
745
        self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
1187
746
        from_branch = self.open_branch()
1188
747
        from_branch.clone(result, revision_id=revision_id)
1189
748
        try:
1190
 
            self.open_workingtree().clone(result)
 
749
            self.open_workingtree().clone(result, basis=basis_tree)
1191
750
        except errors.NotLocalUrl:
1192
751
            # make a new one, this format always has to have one.
1193
752
            try:
1195
754
            except errors.NotLocalUrl:
1196
755
                # but we cannot do it for remote trees.
1197
756
                to_branch = result.open_branch()
1198
 
                WorkingTreeFormat2()._stub_initialize_remote(to_branch)
 
757
                WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
1199
758
        return result
1200
759
 
1201
760
    def create_branch(self):
1202
761
        """See BzrDir.create_branch."""
1203
762
        return self.open_branch()
1204
763
 
1205
 
    def destroy_branch(self):
1206
 
        """See BzrDir.destroy_branch."""
1207
 
        raise errors.UnsupportedOperation(self.destroy_branch, self)
1208
 
 
1209
764
    def create_repository(self, shared=False):
1210
765
        """See BzrDir.create_repository."""
1211
766
        if shared:
1212
767
            raise errors.IncompatibleFormat('shared repository', self._format)
1213
768
        return self.open_repository()
1214
769
 
1215
 
    def destroy_repository(self):
1216
 
        """See BzrDir.destroy_repository."""
1217
 
        raise errors.UnsupportedOperation(self.destroy_repository, self)
1218
 
 
1219
 
    def create_workingtree(self, revision_id=None, from_branch=None,
1220
 
                           accelerator_tree=None, hardlink=False):
 
770
    def create_workingtree(self, revision_id=None):
1221
771
        """See BzrDir.create_workingtree."""
1222
772
        # this looks buggy but is not -really-
1223
 
        # because this format creates the workingtree when the bzrdir is
1224
 
        # created
1225
773
        # clone and sprout will have set the revision_id
1226
774
        # and that will have set it for us, its only
1227
775
        # specific uses of create_workingtree in isolation
1228
776
        # that can do wonky stuff here, and that only
1229
777
        # happens for creating checkouts, which cannot be 
1230
778
        # done on this format anyway. So - acceptable wart.
1231
 
        result = self.open_workingtree(recommend_upgrade=False)
 
779
        result = self.open_workingtree()
1232
780
        if revision_id is not None:
1233
781
            if revision_id == _mod_revision.NULL_REVISION:
1234
782
                result.set_parent_ids([])
1290
838
        self._check_supported(format, unsupported)
1291
839
        return format.open(self, _found=True)
1292
840
 
1293
 
    def sprout(self, url, revision_id=None, force_new_repo=False,
1294
 
               possible_transports=None, accelerator_tree=None,
1295
 
               hardlink=False, stacked=False):
 
841
    def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
1296
842
        """See BzrDir.sprout()."""
1297
 
        if stacked:
1298
 
            raise errors.UnstackableBranchFormat(
1299
 
                self._format, self.root_transport.base)
1300
843
        from bzrlib.workingtree import WorkingTreeFormat2
1301
844
        self._make_tail(url)
1302
845
        result = self._format._initialize_for_clone(url)
 
846
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
1303
847
        try:
1304
 
            self.open_repository().clone(result, revision_id=revision_id)
 
848
            self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
1305
849
        except errors.NoRepositoryPresent:
1306
850
            pass
1307
851
        try:
1309
853
        except errors.NotBranchError:
1310
854
            pass
1311
855
        # we always want a working tree
1312
 
        WorkingTreeFormat2().initialize(result,
1313
 
                                        accelerator_tree=accelerator_tree,
1314
 
                                        hardlink=hardlink)
 
856
        WorkingTreeFormat2().initialize(result)
1315
857
        return result
1316
858
 
1317
859
 
1331
873
 
1332
874
    def open_repository(self):
1333
875
        """See BzrDir.open_repository."""
1334
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat4
 
876
        from bzrlib.repository import RepositoryFormat4
1335
877
        return RepositoryFormat4().open(self, _found=True)
1336
878
 
1337
879
 
1343
885
 
1344
886
    def open_repository(self):
1345
887
        """See BzrDir.open_repository."""
1346
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
 
888
        from bzrlib.repository import RepositoryFormat5
1347
889
        return RepositoryFormat5().open(self, _found=True)
1348
890
 
1349
 
    def open_workingtree(self, _unsupported=False,
1350
 
            recommend_upgrade=True):
 
891
    def open_workingtree(self, _unsupported=False):
1351
892
        """See BzrDir.create_workingtree."""
1352
893
        from bzrlib.workingtree import WorkingTreeFormat2
1353
 
        wt_format = WorkingTreeFormat2()
1354
 
        # we don't warn here about upgrades; that ought to be handled for the
1355
 
        # bzrdir as a whole
1356
 
        return wt_format.open(self, _found=True)
 
894
        return WorkingTreeFormat2().open(self, _found=True)
1357
895
 
1358
896
 
1359
897
class BzrDir6(BzrDirPreSplitOut):
1364
902
 
1365
903
    def open_repository(self):
1366
904
        """See BzrDir.open_repository."""
1367
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
 
905
        from bzrlib.repository import RepositoryFormat6
1368
906
        return RepositoryFormat6().open(self, _found=True)
1369
907
 
1370
 
    def open_workingtree(self, _unsupported=False,
1371
 
        recommend_upgrade=True):
 
908
    def open_workingtree(self, _unsupported=False):
1372
909
        """See BzrDir.create_workingtree."""
1373
 
        # we don't warn here about upgrades; that ought to be handled for the
1374
 
        # bzrdir as a whole
1375
910
        from bzrlib.workingtree import WorkingTreeFormat2
1376
911
        return WorkingTreeFormat2().open(self, _found=True)
1377
912
 
1391
926
 
1392
927
    def create_branch(self):
1393
928
        """See BzrDir.create_branch."""
1394
 
        return self._format.get_branch_format().initialize(self)
1395
 
 
1396
 
    def destroy_branch(self):
1397
 
        """See BzrDir.create_branch."""
1398
 
        self.transport.delete_tree('branch')
 
929
        from bzrlib.branch import BranchFormat
 
930
        return BranchFormat.get_default_format().initialize(self)
1399
931
 
1400
932
    def create_repository(self, shared=False):
1401
933
        """See BzrDir.create_repository."""
1402
934
        return self._format.repository_format.initialize(self, shared)
1403
935
 
1404
 
    def destroy_repository(self):
1405
 
        """See BzrDir.destroy_repository."""
1406
 
        self.transport.delete_tree('repository')
1407
 
 
1408
 
    def create_workingtree(self, revision_id=None, from_branch=None,
1409
 
                           accelerator_tree=None, hardlink=False):
 
936
    def create_workingtree(self, revision_id=None):
1410
937
        """See BzrDir.create_workingtree."""
1411
 
        return self._format.workingtree_format.initialize(
1412
 
            self, revision_id, from_branch=from_branch,
1413
 
            accelerator_tree=accelerator_tree, hardlink=hardlink)
 
938
        from bzrlib.workingtree import WorkingTreeFormat
 
939
        return WorkingTreeFormat.get_default_format().initialize(self, revision_id)
1414
940
 
1415
941
    def destroy_workingtree(self):
1416
942
        """See BzrDir.destroy_workingtree."""
1417
 
        wt = self.open_workingtree(recommend_upgrade=False)
 
943
        wt = self.open_workingtree()
1418
944
        repository = wt.branch.repository
1419
945
        empty = repository.revision_tree(_mod_revision.NULL_REVISION)
1420
 
        wt.revert(old_tree=empty)
 
946
        wt.revert([], old_tree=empty)
1421
947
        self.destroy_workingtree_metadata()
1422
948
 
1423
949
    def destroy_workingtree_metadata(self):
1424
950
        self.transport.delete_tree('checkout')
1425
951
 
1426
 
    def find_branch_format(self):
1427
 
        """Find the branch 'format' for this bzrdir.
1428
 
 
1429
 
        This might be a synthetic object for e.g. RemoteBranch and SVN.
1430
 
        """
1431
 
        from bzrlib.branch import BranchFormat
1432
 
        return BranchFormat.find_format(self)
1433
 
 
1434
952
    def _get_mkdir_mode(self):
1435
953
        """Figure out the mode to use when creating a bzrdir subdir."""
1436
954
        temp_control = lockable_files.LockableFiles(self.transport, '',
1437
955
                                     lockable_files.TransportLock)
1438
956
        return temp_control._dir_mode
1439
957
 
1440
 
    def get_branch_reference(self):
1441
 
        """See BzrDir.get_branch_reference()."""
1442
 
        from bzrlib.branch import BranchFormat
1443
 
        format = BranchFormat.find_format(self)
1444
 
        return format.get_reference(self)
1445
 
 
1446
958
    def get_branch_transport(self, branch_format):
1447
959
        """See BzrDir.get_branch_transport()."""
1448
960
        if branch_format is None:
1500
1012
                return True
1501
1013
        except errors.NoRepositoryPresent:
1502
1014
            pass
1503
 
        try:
1504
 
            if not isinstance(self.open_branch()._format,
1505
 
                              format.get_branch_format().__class__):
1506
 
                # the branch needs an upgrade.
1507
 
                return True
1508
 
        except errors.NotBranchError:
1509
 
            pass
1510
 
        try:
1511
 
            my_wt = self.open_workingtree(recommend_upgrade=False)
1512
 
            if not isinstance(my_wt._format,
1513
 
                              format.workingtree_format.__class__):
1514
 
                # the workingtree needs an upgrade.
1515
 
                return True
1516
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
1517
 
            pass
 
1015
        # currently there are no other possible conversions for meta1 formats.
1518
1016
        return False
1519
1017
 
1520
1018
    def open_branch(self, unsupported=False):
1521
1019
        """See BzrDir.open_branch."""
1522
 
        format = self.find_branch_format()
 
1020
        from bzrlib.branch import BranchFormat
 
1021
        format = BranchFormat.find_format(self)
1523
1022
        self._check_supported(format, unsupported)
1524
1023
        return format.open(self, _found=True)
1525
1024
 
1530
1029
        self._check_supported(format, unsupported)
1531
1030
        return format.open(self, _found=True)
1532
1031
 
1533
 
    def open_workingtree(self, unsupported=False,
1534
 
            recommend_upgrade=True):
 
1032
    def open_workingtree(self, unsupported=False):
1535
1033
        """See BzrDir.open_workingtree."""
1536
1034
        from bzrlib.workingtree import WorkingTreeFormat
1537
1035
        format = WorkingTreeFormat.find_format(self)
1538
 
        self._check_supported(format, unsupported,
1539
 
            recommend_upgrade,
1540
 
            basedir=self.root_transport.base)
 
1036
        self._check_supported(format, unsupported)
1541
1037
        return format.open(self, _found=True)
1542
1038
 
1543
 
    def _get_config(self):
1544
 
        return config.BzrDirConfig(self.transport)
1545
 
 
1546
1039
 
1547
1040
class BzrDirFormat(object):
1548
1041
    """An encapsulation of the initialization and open routines for a format.
1552
1045
     * a format string,
1553
1046
     * an open routine.
1554
1047
 
1555
 
    Formats are placed in a dict by their format string for reference 
 
1048
    Formats are placed in an dict by their format string for reference 
1556
1049
    during bzrdir opening. These should be subclasses of BzrDirFormat
1557
1050
    for consistency.
1558
1051
 
1573
1066
    This is a list of BzrDirFormat objects.
1574
1067
    """
1575
1068
 
1576
 
    _control_server_formats = []
1577
 
    """The registered control server formats, e.g. RemoteBzrDirs.
1578
 
 
1579
 
    This is a list of BzrDirFormat objects.
1580
 
    """
1581
 
 
1582
1069
    _lock_file_name = 'branch-lock'
1583
1070
 
1584
1071
    # _lock_class must be set in subclasses to the lock type, typ.
1585
1072
    # TransportLock or LockDir
1586
1073
 
1587
1074
    @classmethod
1588
 
    def find_format(klass, transport, _server_formats=True):
 
1075
    def find_format(klass, transport):
1589
1076
        """Return the format present at transport."""
1590
 
        if _server_formats:
1591
 
            formats = klass._control_server_formats + klass._control_formats
1592
 
        else:
1593
 
            formats = klass._control_formats
1594
 
        for format in formats:
 
1077
        for format in klass._control_formats:
1595
1078
            try:
1596
1079
                return format.probe_transport(transport)
1597
1080
            except errors.NotBranchError:
1601
1084
 
1602
1085
    @classmethod
1603
1086
    def probe_transport(klass, transport):
1604
 
        """Return the .bzrdir style format present in a directory."""
 
1087
        """Return the .bzrdir style transport present at URL."""
1605
1088
        try:
1606
1089
            format_string = transport.get(".bzr/branch-format").read()
1607
1090
        except errors.NoSuchFile:
1610
1093
        try:
1611
1094
            return klass._formats[format_string]
1612
1095
        except KeyError:
1613
 
            raise errors.UnknownFormatError(format=format_string, kind='bzrdir')
 
1096
            raise errors.UnknownFormatError(format=format_string)
1614
1097
 
1615
1098
    @classmethod
1616
1099
    def get_default_format(klass):
1639
1122
        """
1640
1123
        raise NotImplementedError(self.get_converter)
1641
1124
 
1642
 
    def initialize(self, url, possible_transports=None):
 
1125
    def initialize(self, url):
1643
1126
        """Create a bzr control dir at this url and return an opened copy.
1644
1127
        
1645
1128
        Subclasses should typically override initialize_on_transport
1646
1129
        instead of this method.
1647
1130
        """
1648
 
        return self.initialize_on_transport(get_transport(url,
1649
 
                                                          possible_transports))
 
1131
        return self.initialize_on_transport(get_transport(url))
1650
1132
 
1651
1133
    def initialize_on_transport(self, transport):
1652
1134
        """Initialize a new bzrdir in the base directory of a Transport."""
1658
1140
                                      # FIXME: RBC 20060121 don't peek under
1659
1141
                                      # the covers
1660
1142
                                      mode=temp_control._dir_mode)
1661
 
        if sys.platform == 'win32' and isinstance(transport, LocalTransport):
1662
 
            win32utils.set_file_attr_hidden(transport._abspath('.bzr'))
1663
1143
        file_mode = temp_control._file_mode
1664
1144
        del temp_control
1665
 
        bzrdir_transport = transport.clone('.bzr')
1666
 
        utf8_files = [('README',
1667
 
                       "This is a Bazaar control directory.\n"
1668
 
                       "Do not change any files in this directory.\n"
1669
 
                       "See http://bazaar-vcs.org/ for more information about Bazaar.\n"),
 
1145
        mutter('created control directory in ' + transport.base)
 
1146
        control = transport.clone('.bzr')
 
1147
        utf8_files = [('README', 
 
1148
                       "This is a Bazaar-NG control directory.\n"
 
1149
                       "Do not change any files in this directory.\n"),
1670
1150
                      ('branch-format', self.get_format_string()),
1671
1151
                      ]
1672
1152
        # NB: no need to escape relative paths that are url safe.
1673
 
        control_files = lockable_files.LockableFiles(bzrdir_transport,
1674
 
            self._lock_file_name, self._lock_class)
 
1153
        control_files = lockable_files.LockableFiles(control,
 
1154
                            self._lock_file_name, self._lock_class)
1675
1155
        control_files.create_lock()
1676
1156
        control_files.lock_write()
1677
1157
        try:
1678
 
            for (filename, content) in utf8_files:
1679
 
                bzrdir_transport.put_bytes(filename, content,
1680
 
                    mode=file_mode)
 
1158
            for file, content in utf8_files:
 
1159
                control_files.put_utf8(file, content)
1681
1160
        finally:
1682
1161
            control_files.unlock()
1683
1162
        return self.open(transport, _found=True)
1741
1220
 
1742
1221
    @classmethod
1743
1222
    def register_control_format(klass, format):
1744
 
        """Register a format that does not use '.bzr' for its control dir.
 
1223
        """Register a format that does not use '.bzrdir' for its control dir.
1745
1224
 
1746
1225
        TODO: This should be pulled up into a 'ControlDirFormat' base class
1747
1226
        which BzrDirFormat can inherit from, and renamed to register_format 
1751
1230
        klass._control_formats.append(format)
1752
1231
 
1753
1232
    @classmethod
1754
 
    def register_control_server_format(klass, format):
1755
 
        """Register a control format for client-server environments.
1756
 
 
1757
 
        These formats will be tried before ones registered with
1758
 
        register_control_format.  This gives implementations that decide to the
1759
 
        chance to grab it before anything looks at the contents of the format
1760
 
        file.
1761
 
        """
1762
 
        klass._control_server_formats.append(format)
 
1233
    @symbol_versioning.deprecated_method(symbol_versioning.zero_fourteen)
 
1234
    def set_default_format(klass, format):
 
1235
        klass._set_default_format(format)
1763
1236
 
1764
1237
    @classmethod
1765
1238
    def _set_default_format(klass, format):
1767
1240
        klass._default_format = format
1768
1241
 
1769
1242
    def __str__(self):
1770
 
        # Trim the newline
1771
 
        return self.get_format_string().rstrip()
 
1243
        return self.get_format_string()[:-1]
1772
1244
 
1773
1245
    @classmethod
1774
1246
    def unregister_format(klass, format):
 
1247
        assert klass._formats[format.get_format_string()] is format
1775
1248
        del klass._formats[format.get_format_string()]
1776
1249
 
1777
1250
    @classmethod
1779
1252
        klass._control_formats.remove(format)
1780
1253
 
1781
1254
 
 
1255
# register BzrDirFormat as a control format
 
1256
BzrDirFormat.register_control_format(BzrDirFormat)
 
1257
 
 
1258
 
1782
1259
class BzrDirFormat4(BzrDirFormat):
1783
1260
    """Bzr dir format 4.
1784
1261
 
1826
1303
 
1827
1304
    def __return_repository_format(self):
1828
1305
        """Circular import protection."""
1829
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat4
 
1306
        from bzrlib.repository import RepositoryFormat4
1830
1307
        return RepositoryFormat4()
1831
1308
    repository_format = property(__return_repository_format)
1832
1309
 
1866
1343
        Except when they are being cloned.
1867
1344
        """
1868
1345
        from bzrlib.branch import BzrBranchFormat4
1869
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
 
1346
        from bzrlib.repository import RepositoryFormat5
1870
1347
        from bzrlib.workingtree import WorkingTreeFormat2
1871
1348
        result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1872
1349
        RepositoryFormat5().initialize(result, _internal=True)
1877
1354
            except errors.NotLocalUrl:
1878
1355
                # Even though we can't access the working tree, we need to
1879
1356
                # create its control files.
1880
 
                WorkingTreeFormat2()._stub_initialize_remote(branch)
 
1357
                WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1881
1358
        return result
1882
1359
 
1883
1360
    def _open(self, transport):
1886
1363
 
1887
1364
    def __return_repository_format(self):
1888
1365
        """Circular import protection."""
1889
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
 
1366
        from bzrlib.repository import RepositoryFormat5
1890
1367
        return RepositoryFormat5()
1891
1368
    repository_format = property(__return_repository_format)
1892
1369
 
1925
1402
        Except when they are being cloned.
1926
1403
        """
1927
1404
        from bzrlib.branch import BzrBranchFormat4
1928
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
 
1405
        from bzrlib.repository import RepositoryFormat6
1929
1406
        from bzrlib.workingtree import WorkingTreeFormat2
1930
1407
        result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1931
1408
        RepositoryFormat6().initialize(result, _internal=True)
1936
1413
            except errors.NotLocalUrl:
1937
1414
                # Even though we can't access the working tree, we need to
1938
1415
                # create its control files.
1939
 
                WorkingTreeFormat2()._stub_initialize_remote(branch)
 
1416
                WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1940
1417
        return result
1941
1418
 
1942
1419
    def _open(self, transport):
1945
1422
 
1946
1423
    def __return_repository_format(self):
1947
1424
        """Circular import protection."""
1948
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
 
1425
        from bzrlib.repository import RepositoryFormat6
1949
1426
        return RepositoryFormat6()
1950
1427
    repository_format = property(__return_repository_format)
1951
1428
 
1963
1440
 
1964
1441
    _lock_class = lockdir.LockDir
1965
1442
 
1966
 
    def __init__(self):
1967
 
        self._workingtree_format = None
1968
 
        self._branch_format = None
1969
 
 
1970
 
    def __eq__(self, other):
1971
 
        if other.__class__ is not self.__class__:
1972
 
            return False
1973
 
        if other.repository_format != self.repository_format:
1974
 
            return False
1975
 
        if other.workingtree_format != self.workingtree_format:
1976
 
            return False
1977
 
        return True
1978
 
 
1979
 
    def __ne__(self, other):
1980
 
        return not self == other
1981
 
 
1982
 
    def get_branch_format(self):
1983
 
        if self._branch_format is None:
1984
 
            from bzrlib.branch import BranchFormat
1985
 
            self._branch_format = BranchFormat.get_default_format()
1986
 
        return self._branch_format
1987
 
 
1988
 
    def set_branch_format(self, format):
1989
 
        self._branch_format = format
1990
 
 
1991
1443
    def get_converter(self, format=None):
1992
1444
        """See BzrDirFormat.get_converter()."""
1993
1445
        if format is None:
2017
1469
        return RepositoryFormat.get_default_format()
2018
1470
 
2019
1471
    def __set_repository_format(self, value):
2020
 
        """Allow changing the repository format for metadir formats."""
 
1472
        """Allow changint the repository format for metadir formats."""
2021
1473
        self._repository_format = value
2022
1474
 
2023
1475
    repository_format = property(__return_repository_format, __set_repository_format)
2024
1476
 
2025
 
    def __get_workingtree_format(self):
2026
 
        if self._workingtree_format is None:
2027
 
            from bzrlib.workingtree import WorkingTreeFormat
2028
 
            self._workingtree_format = WorkingTreeFormat.get_default_format()
2029
 
        return self._workingtree_format
2030
 
 
2031
 
    def __set_workingtree_format(self, wt_format):
2032
 
        self._workingtree_format = wt_format
2033
 
 
2034
 
    workingtree_format = property(__get_workingtree_format,
2035
 
                                  __set_workingtree_format)
2036
 
 
2037
 
 
2038
 
# Register bzr control format
2039
 
BzrDirFormat.register_control_format(BzrDirFormat)
2040
 
 
2041
 
# Register bzr formats
 
1477
 
2042
1478
BzrDirFormat.register_format(BzrDirFormat4())
2043
1479
BzrDirFormat.register_format(BzrDirFormat5())
2044
1480
BzrDirFormat.register_format(BzrDirFormat6())
2047
1483
BzrDirFormat._default_format = __default_format
2048
1484
 
2049
1485
 
 
1486
class BzrDirTestProviderAdapter(object):
 
1487
    """A tool to generate a suite testing multiple bzrdir formats at once.
 
1488
 
 
1489
    This is done by copying the test once for each transport and injecting
 
1490
    the transport_server, transport_readonly_server, and bzrdir_format
 
1491
    classes into each copy. Each copy is also given a new id() to make it
 
1492
    easy to identify.
 
1493
    """
 
1494
 
 
1495
    def __init__(self, transport_server, transport_readonly_server, formats):
 
1496
        self._transport_server = transport_server
 
1497
        self._transport_readonly_server = transport_readonly_server
 
1498
        self._formats = formats
 
1499
    
 
1500
    def adapt(self, test):
 
1501
        result = unittest.TestSuite()
 
1502
        for format in self._formats:
 
1503
            new_test = deepcopy(test)
 
1504
            new_test.transport_server = self._transport_server
 
1505
            new_test.transport_readonly_server = self._transport_readonly_server
 
1506
            new_test.bzrdir_format = format
 
1507
            def make_new_test_id():
 
1508
                new_id = "%s(%s)" % (new_test.id(), format.__class__.__name__)
 
1509
                return lambda: new_id
 
1510
            new_test.id = make_new_test_id()
 
1511
            result.addTest(new_test)
 
1512
        return result
 
1513
 
 
1514
 
2050
1515
class Converter(object):
2051
1516
    """Converts a disk format object from one format to another."""
2052
1517
 
2123
1588
        self.pb.note('  %6d revisions not present', len(self.absent_revisions))
2124
1589
        self.pb.note('  %6d texts', self.text_count)
2125
1590
        self._cleanup_spare_files_after_format4()
2126
 
        self.branch._transport.put_bytes(
2127
 
            'branch-format',
2128
 
            BzrDirFormat5().get_format_string(),
2129
 
            mode=self.bzrdir._get_file_mode())
 
1591
        self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
2130
1592
 
2131
1593
    def _cleanup_spare_files_after_format4(self):
2132
1594
        # FIXME working tree upgrade foo.
2141
1603
 
2142
1604
    def _convert_working_inv(self):
2143
1605
        inv = xml4.serializer_v4.read_inventory(
2144
 
                self.branch._transport.get('inventory'))
2145
 
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv, working=True)
2146
 
        self.branch._transport.put_bytes('inventory', new_inv_xml,
2147
 
            mode=self.bzrdir._get_file_mode())
 
1606
                    self.branch.control_files.get('inventory'))
 
1607
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
 
1608
        # FIXME inventory is a working tree change.
 
1609
        self.branch.control_files.put('inventory', StringIO(new_inv_xml))
2148
1610
 
2149
1611
    def _write_all_weaves(self):
2150
1612
        controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
2170
1632
        self.bzrdir.transport.mkdir('revision-store')
2171
1633
        revision_transport = self.bzrdir.transport.clone('revision-store')
2172
1634
        # TODO permissions
2173
 
        from bzrlib.xml5 import serializer_v5
2174
 
        from bzrlib.repofmt.weaverepo import RevisionTextStore
2175
 
        revision_store = RevisionTextStore(revision_transport,
2176
 
            serializer_v5, False, versionedfile.PrefixMapper(),
2177
 
            lambda:True, lambda:True)
 
1635
        _revision_store = TextRevisionStore(TextStore(revision_transport,
 
1636
                                                      prefixed=False,
 
1637
                                                      compressed=True))
2178
1638
        try:
 
1639
            transaction = WriteTransaction()
2179
1640
            for i, rev_id in enumerate(self.converted_revs):
2180
1641
                self.pb.update('write revision', i, len(self.converted_revs))
2181
 
                text = serializer_v5.write_revision_to_string(
2182
 
                    self.revisions[rev_id])
2183
 
                key = (rev_id,)
2184
 
                revision_store.add_lines(key, None, osutils.split_lines(text))
 
1642
                _revision_store.add_revision(self.revisions[rev_id], transaction)
2185
1643
        finally:
2186
1644
            self.pb.clear()
2187
1645
            
2200
1658
                         rev_id)
2201
1659
            self.absent_revisions.add(rev_id)
2202
1660
        else:
2203
 
            rev = self.branch.repository.get_revision(rev_id)
 
1661
            rev = self.branch.repository._revision_store.get_revision(rev_id,
 
1662
                self.branch.repository.get_transaction())
2204
1663
            for parent_id in rev.parent_ids:
2205
1664
                self.known_revisions.add(parent_id)
2206
1665
                self.to_read.append(parent_id)
2207
1666
            self.revisions[rev_id] = rev
2208
1667
 
2209
1668
    def _load_old_inventory(self, rev_id):
 
1669
        assert rev_id not in self.converted_revs
2210
1670
        old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
2211
1671
        inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
2212
1672
        inv.revision_id = rev_id
2213
1673
        rev = self.revisions[rev_id]
 
1674
        if rev.inventory_sha1:
 
1675
            assert rev.inventory_sha1 == sha_string(old_inv_xml), \
 
1676
                'inventory sha mismatch for {%s}' % rev_id
2214
1677
        return inv
2215
1678
 
2216
1679
    def _load_updated_inventory(self, rev_id):
 
1680
        assert rev_id in self.converted_revs
2217
1681
        inv_xml = self.inv_weave.get_text(rev_id)
2218
 
        inv = xml5.serializer_v5.read_inventory_from_string(inv_xml, rev_id)
 
1682
        inv = xml5.serializer_v5.read_inventory_from_string(inv_xml)
2219
1683
        return inv
2220
1684
 
2221
1685
    def _convert_one_rev(self, rev_id):
2225
1689
        present_parents = [p for p in rev.parent_ids
2226
1690
                           if p not in self.absent_revisions]
2227
1691
        self._convert_revision_contents(rev, inv, present_parents)
2228
 
        self._store_new_inv(rev, inv, present_parents)
 
1692
        self._store_new_weave(rev, inv, present_parents)
2229
1693
        self.converted_revs.add(rev_id)
2230
1694
 
2231
 
    def _store_new_inv(self, rev, inv, present_parents):
 
1695
    def _store_new_weave(self, rev, inv, present_parents):
 
1696
        # the XML is now updated with text versions
 
1697
        if __debug__:
 
1698
            entries = inv.iter_entries()
 
1699
            entries.next()
 
1700
            for path, ie in entries:
 
1701
                assert getattr(ie, 'revision', None) is not None, \
 
1702
                    'no revision on {%s} in {%s}' % \
 
1703
                    (file_id, rev.revision_id)
2232
1704
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
2233
1705
        new_inv_sha1 = sha_string(new_inv_xml)
2234
 
        self.inv_weave.add_lines(rev.revision_id,
 
1706
        self.inv_weave.add_lines(rev.revision_id, 
2235
1707
                                 present_parents,
2236
1708
                                 new_inv_xml.splitlines(True))
2237
1709
        rev.inventory_sha1 = new_inv_sha1
2262
1734
            w = Weave(file_id)
2263
1735
            self.text_weaves[file_id] = w
2264
1736
        text_changed = False
2265
 
        parent_candiate_entries = ie.parent_candidates(parent_invs)
2266
 
        heads = graph.Graph(self).heads(parent_candiate_entries.keys())
2267
 
        # XXX: Note that this is unordered - and this is tolerable because 
2268
 
        # the previous code was also unordered.
2269
 
        previous_entries = dict((head, parent_candiate_entries[head]) for head
2270
 
            in heads)
 
1737
        previous_entries = ie.find_previous_heads(parent_invs,
 
1738
                                                  None,
 
1739
                                                  None,
 
1740
                                                  entry_vf=w)
 
1741
        for old_revision in previous_entries:
 
1742
                # if this fails, its a ghost ?
 
1743
                assert old_revision in self.converted_revs, \
 
1744
                    "Revision {%s} not in converted_revs" % old_revision
2271
1745
        self.snapshot_ie(previous_entries, ie, w, rev_id)
2272
1746
        del ie.text_id
2273
 
 
2274
 
    @symbol_versioning.deprecated_method(symbol_versioning.one_one)
2275
 
    def get_parents(self, revision_ids):
2276
 
        for revision_id in revision_ids:
2277
 
            yield self.revisions[revision_id].parent_ids
2278
 
 
2279
 
    def get_parent_map(self, revision_ids):
2280
 
        """See graph._StackedParentsProvider.get_parent_map"""
2281
 
        return dict((revision_id, self.revisions[revision_id])
2282
 
                    for revision_id in revision_ids
2283
 
                     if revision_id in self.revisions)
 
1747
        assert getattr(ie, 'revision', None) is not None
2284
1748
 
2285
1749
    def snapshot_ie(self, previous_revisions, ie, w, rev_id):
2286
1750
        # TODO: convert this logic, which is ~= snapshot to
2296
1760
                ie.revision = previous_ie.revision
2297
1761
                return
2298
1762
        if ie.has_text():
2299
 
            text = self.branch.repository._text_store.get(ie.text_id)
 
1763
            text = self.branch.repository.text_store.get(ie.text_id)
2300
1764
            file_lines = text.readlines()
 
1765
            assert sha_strings(file_lines) == ie.text_sha1
 
1766
            assert sum(map(len, file_lines)) == ie.text_size
2301
1767
            w.add_lines(rev_id, previous_revisions, file_lines)
2302
1768
            self.text_count += 1
2303
1769
        else:
2350
1816
                if (filename.endswith(".weave") or
2351
1817
                    filename.endswith(".gz") or
2352
1818
                    filename.endswith(".sig")):
2353
 
                    file_id, suffix = os.path.splitext(filename)
 
1819
                    file_id = os.path.splitext(filename)[0]
2354
1820
                else:
2355
1821
                    file_id = filename
2356
 
                    suffix = ''
2357
 
                new_name = store._mapper.map((file_id,)) + suffix
 
1822
                prefix_dir = store.hash_prefix(file_id)
2358
1823
                # FIXME keep track of the dirs made RBC 20060121
2359
1824
                try:
2360
 
                    store_transport.move(filename, new_name)
 
1825
                    store_transport.move(filename, prefix_dir + '/' + filename)
2361
1826
                except errors.NoSuchFile: # catches missing dirs strangely enough
2362
 
                    store_transport.mkdir(osutils.dirname(new_name))
2363
 
                    store_transport.move(filename, new_name)
2364
 
        self.bzrdir.transport.put_bytes(
2365
 
            'branch-format',
2366
 
            BzrDirFormat6().get_format_string(),
2367
 
            mode=self.bzrdir._get_file_mode())
 
1827
                    store_transport.mkdir(prefix_dir)
 
1828
                    store_transport.move(filename, prefix_dir + '/' + filename)
 
1829
        self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
2368
1830
 
2369
1831
 
2370
1832
class ConvertBzrDir6ToMeta(Converter):
2372
1834
 
2373
1835
    def convert(self, to_convert, pb):
2374
1836
        """See Converter.convert()."""
2375
 
        from bzrlib.repofmt.weaverepo import RepositoryFormat7
2376
1837
        from bzrlib.branch import BzrBranchFormat5
2377
1838
        self.bzrdir = to_convert
2378
1839
        self.pb = pb
2379
1840
        self.count = 0
2380
1841
        self.total = 20 # the steps we know about
2381
1842
        self.garbage_inventories = []
2382
 
        self.dir_mode = self.bzrdir._get_dir_mode()
2383
 
        self.file_mode = self.bzrdir._get_file_mode()
2384
1843
 
2385
1844
        self.pb.note('starting upgrade from format 6 to metadir')
2386
 
        self.bzrdir.transport.put_bytes(
2387
 
                'branch-format',
2388
 
                "Converting to format 6",
2389
 
                mode=self.file_mode)
 
1845
        self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
2390
1846
        # its faster to move specific files around than to open and use the apis...
2391
1847
        # first off, nuke ancestry.weave, it was never used.
2392
1848
        try:
2402
1858
            if name.startswith('basis-inventory.'):
2403
1859
                self.garbage_inventories.append(name)
2404
1860
        # create new directories for repository, working tree and branch
 
1861
        self.dir_mode = self.bzrdir._control_files._dir_mode
 
1862
        self.file_mode = self.bzrdir._control_files._file_mode
2405
1863
        repository_names = [('inventory.weave', True),
2406
1864
                            ('revision-store', True),
2407
1865
                            ('weaves', True)]
2411
1869
        # we hard code the formats here because we are converting into
2412
1870
        # the meta format. The meta format upgrader can take this to a 
2413
1871
        # future format within each component.
2414
 
        self.put_format('repository', RepositoryFormat7())
 
1872
        self.put_format('repository', _mod_repository.RepositoryFormat7())
2415
1873
        for entry in repository_names:
2416
1874
            self.move_entry('repository', entry)
2417
1875
 
2455
1913
            for entry in checkout_files:
2456
1914
                self.move_entry('checkout', entry)
2457
1915
            if last_revision is not None:
2458
 
                self.bzrdir.transport.put_bytes(
 
1916
                self.bzrdir._control_files.put_utf8(
2459
1917
                    'checkout/last-revision', last_revision)
2460
 
        self.bzrdir.transport.put_bytes(
2461
 
            'branch-format',
2462
 
            BzrDirMetaFormat1().get_format_string(),
2463
 
            mode=self.file_mode)
 
1918
        self.bzrdir._control_files.put_utf8(
 
1919
            'branch-format', BzrDirMetaFormat1().get_format_string())
2464
1920
        return BzrDir.open(self.bzrdir.root_transport.base)
2465
1921
 
2466
1922
    def make_lock(self, name):
2484
1940
                raise
2485
1941
 
2486
1942
    def put_format(self, dirname, format):
2487
 
        self.bzrdir.transport.put_bytes('%s/format' % dirname,
2488
 
            format.get_format_string(),
2489
 
            self.file_mode)
 
1943
        self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
2490
1944
 
2491
1945
 
2492
1946
class ConvertMetaToMeta(Converter):
2516
1970
                self.pb.note('starting repository conversion')
2517
1971
                converter = CopyConverter(self.target_format.repository_format)
2518
1972
                converter.convert(repo, pb)
2519
 
        try:
2520
 
            branch = self.bzrdir.open_branch()
2521
 
        except errors.NotBranchError:
2522
 
            pass
2523
 
        else:
2524
 
            # TODO: conversions of Branch and Tree should be done by
2525
 
            # InterXFormat lookups/some sort of registry.
2526
 
            # Avoid circular imports
2527
 
            from bzrlib import branch as _mod_branch
2528
 
            old = branch._format.__class__
2529
 
            new = self.target_format.get_branch_format().__class__
2530
 
            while old != new:
2531
 
                if (old == _mod_branch.BzrBranchFormat5 and
2532
 
                    new in (_mod_branch.BzrBranchFormat6,
2533
 
                        _mod_branch.BzrBranchFormat7)):
2534
 
                    branch_converter = _mod_branch.Converter5to6()
2535
 
                elif (old == _mod_branch.BzrBranchFormat6 and
2536
 
                    new == _mod_branch.BzrBranchFormat7):
2537
 
                    branch_converter = _mod_branch.Converter6to7()
2538
 
                else:
2539
 
                    raise errors.BadConversionTarget("No converter", new)
2540
 
                branch_converter.convert(branch)
2541
 
                branch = self.bzrdir.open_branch()
2542
 
                old = branch._format.__class__
2543
 
        try:
2544
 
            tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
2545
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
2546
 
            pass
2547
 
        else:
2548
 
            # TODO: conversions of Branch and Tree should be done by
2549
 
            # InterXFormat lookups
2550
 
            if (isinstance(tree, workingtree.WorkingTree3) and
2551
 
                not isinstance(tree, workingtree_4.WorkingTree4) and
2552
 
                isinstance(self.target_format.workingtree_format,
2553
 
                    workingtree_4.WorkingTreeFormat4)):
2554
 
                workingtree_4.Converter3to4().convert(tree)
2555
1973
        return to_convert
2556
1974
 
2557
1975
 
2558
 
# This is not in remote.py because it's small, and needs to be registered.
2559
 
# Putting it in remote.py creates a circular import problem.
2560
 
# we can make it a lazy object if the control formats is turned into something
2561
 
# like a registry.
2562
 
class RemoteBzrDirFormat(BzrDirMetaFormat1):
2563
 
    """Format representing bzrdirs accessed via a smart server"""
2564
 
 
2565
 
    def get_format_description(self):
2566
 
        return 'bzr remote bzrdir'
2567
 
    
2568
 
    @classmethod
2569
 
    def probe_transport(klass, transport):
2570
 
        """Return a RemoteBzrDirFormat object if it looks possible."""
2571
 
        try:
2572
 
            medium = transport.get_smart_medium()
2573
 
        except (NotImplementedError, AttributeError,
2574
 
                errors.TransportNotPossible, errors.NoSmartMedium,
2575
 
                errors.SmartProtocolError):
2576
 
            # no smart server, so not a branch for this format type.
2577
 
            raise errors.NotBranchError(path=transport.base)
2578
 
        else:
2579
 
            # Decline to open it if the server doesn't support our required
2580
 
            # version (3) so that the VFS-based transport will do it.
2581
 
            if medium.should_probe():
2582
 
                try:
2583
 
                    server_version = medium.protocol_version()
2584
 
                except errors.SmartProtocolError:
2585
 
                    # Apparently there's no usable smart server there, even though
2586
 
                    # the medium supports the smart protocol.
2587
 
                    raise errors.NotBranchError(path=transport.base)
2588
 
                if server_version != '2':
2589
 
                    raise errors.NotBranchError(path=transport.base)
2590
 
            return klass()
2591
 
 
2592
 
    def initialize_on_transport(self, transport):
2593
 
        try:
2594
 
            # hand off the request to the smart server
2595
 
            client_medium = transport.get_smart_medium()
2596
 
        except errors.NoSmartMedium:
2597
 
            # TODO: lookup the local format from a server hint.
2598
 
            local_dir_format = BzrDirMetaFormat1()
2599
 
            return local_dir_format.initialize_on_transport(transport)
2600
 
        client = _SmartClient(client_medium)
2601
 
        path = client.remote_path_from_transport(transport)
2602
 
        response = client.call('BzrDirFormat.initialize', path)
2603
 
        if response[0] != 'ok':
2604
 
            raise errors.SmartProtocolError('unexpected response code %s' % (response,))
2605
 
        return remote.RemoteBzrDir(transport)
2606
 
 
2607
 
    def _open(self, transport):
2608
 
        return remote.RemoteBzrDir(transport)
2609
 
 
2610
 
    def __eq__(self, other):
2611
 
        if not isinstance(other, RemoteBzrDirFormat):
2612
 
            return False
2613
 
        return self.get_format_description() == other.get_format_description()
2614
 
 
2615
 
 
2616
 
BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)
2617
 
 
2618
 
 
2619
1976
class BzrDirFormatInfo(object):
2620
1977
 
2621
 
    def __init__(self, native, deprecated, hidden, experimental):
 
1978
    def __init__(self, native, deprecated):
2622
1979
        self.deprecated = deprecated
2623
1980
        self.native = native
2624
 
        self.hidden = hidden
2625
 
        self.experimental = experimental
2626
1981
 
2627
1982
 
2628
1983
class BzrDirFormatRegistry(registry.Registry):
2632
1987
    e.g. BzrDirMeta1 with weave repository.  Also, it's more user-oriented.
2633
1988
    """
2634
1989
 
2635
 
    def __init__(self):
2636
 
        """Create a BzrDirFormatRegistry."""
2637
 
        self._aliases = set()
2638
 
        super(BzrDirFormatRegistry, self).__init__()
2639
 
 
2640
 
    def aliases(self):
2641
 
        """Return a set of the format names which are aliases."""
2642
 
        return frozenset(self._aliases)
2643
 
 
2644
 
    def register_metadir(self, key,
2645
 
             repository_format, help, native=True, deprecated=False,
2646
 
             branch_format=None,
2647
 
             tree_format=None,
2648
 
             hidden=False,
2649
 
             experimental=False,
2650
 
             alias=False):
 
1990
    def register_metadir(self, key, repo, help, native=True, deprecated=False):
2651
1991
        """Register a metadir subformat.
2652
 
 
2653
 
        These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2654
 
        by the Repository format.
2655
 
 
2656
 
        :param repository_format: The fully-qualified repository format class
2657
 
            name as a string.
2658
 
        :param branch_format: Fully-qualified branch format class name as
2659
 
            a string.
2660
 
        :param tree_format: Fully-qualified tree format class name as
2661
 
            a string.
 
1992
        
 
1993
        repo is the repository format name as a string.
2662
1994
        """
2663
1995
        # This should be expanded to support setting WorkingTree and Branch
2664
1996
        # formats, once BzrDirMetaFormat1 supports that.
2665
 
        def _load(full_name):
2666
 
            mod_name, factory_name = full_name.rsplit('.', 1)
2667
 
            try:
2668
 
                mod = __import__(mod_name, globals(), locals(),
2669
 
                        [factory_name])
2670
 
            except ImportError, e:
2671
 
                raise ImportError('failed to load %s: %s' % (full_name, e))
2672
 
            try:
2673
 
                factory = getattr(mod, factory_name)
2674
 
            except AttributeError:
2675
 
                raise AttributeError('no factory %s in module %r'
2676
 
                    % (full_name, mod))
2677
 
            return factory()
2678
 
 
2679
1997
        def helper():
 
1998
            import bzrlib.repository
 
1999
            repo_format = getattr(bzrlib.repository, repo)
2680
2000
            bd = BzrDirMetaFormat1()
2681
 
            if branch_format is not None:
2682
 
                bd.set_branch_format(_load(branch_format))
2683
 
            if tree_format is not None:
2684
 
                bd.workingtree_format = _load(tree_format)
2685
 
            if repository_format is not None:
2686
 
                bd.repository_format = _load(repository_format)
 
2001
            bd.repository_format = repo_format()
2687
2002
            return bd
2688
 
        self.register(key, helper, help, native, deprecated, hidden,
2689
 
            experimental, alias)
 
2003
        self.register(key, helper, help, native, deprecated)
2690
2004
 
2691
 
    def register(self, key, factory, help, native=True, deprecated=False,
2692
 
                 hidden=False, experimental=False, alias=False):
 
2005
    def register(self, key, factory, help, native=True, deprecated=False):
2693
2006
        """Register a BzrDirFormat factory.
2694
2007
        
2695
2008
        The factory must be a callable that takes one parameter: the key.
2698
2011
        This function mainly exists to prevent the info object from being
2699
2012
        supplied directly.
2700
2013
        """
2701
 
        registry.Registry.register(self, key, factory, help,
2702
 
            BzrDirFormatInfo(native, deprecated, hidden, experimental))
2703
 
        if alias:
2704
 
            self._aliases.add(key)
 
2014
        registry.Registry.register(self, key, factory, help, 
 
2015
            BzrDirFormatInfo(native, deprecated))
2705
2016
 
2706
2017
    def register_lazy(self, key, module_name, member_name, help, native=True,
2707
 
        deprecated=False, hidden=False, experimental=False, alias=False):
2708
 
        registry.Registry.register_lazy(self, key, module_name, member_name,
2709
 
            help, BzrDirFormatInfo(native, deprecated, hidden, experimental))
2710
 
        if alias:
2711
 
            self._aliases.add(key)
 
2018
                      deprecated=False):
 
2019
        registry.Registry.register_lazy(self, key, module_name, member_name, 
 
2020
            help, BzrDirFormatInfo(native, deprecated))
2712
2021
 
2713
2022
    def set_default(self, key):
2714
2023
        """Set the 'default' key to be a clone of the supplied key.
2715
2024
        
2716
2025
        This method must be called once and only once.
2717
2026
        """
2718
 
        registry.Registry.register(self, 'default', self.get(key),
 
2027
        registry.Registry.register(self, 'default', self.get(key), 
2719
2028
            self.get_help(key), info=self.get_info(key))
2720
 
        self._aliases.add('default')
2721
2029
 
2722
2030
    def set_default_repository(self, key):
2723
2031
        """Set the FormatRegistry default and Repository default.
2729
2037
            self.remove('default')
2730
2038
        self.set_default(key)
2731
2039
        format = self.get('default')()
 
2040
        assert isinstance(format, BzrDirMetaFormat1)
2732
2041
 
2733
2042
    def make_bzrdir(self, key):
2734
2043
        return self.get(key)()
2735
2044
 
2736
2045
    def help_topic(self, topic):
2737
2046
        output = textwrap.dedent("""\
 
2047
            Bazaar directory formats
 
2048
            ------------------------
 
2049
 
2738
2050
            These formats can be used for creating branches, working trees, and
2739
2051
            repositories.
2740
2052
 
2741
2053
            """)
2742
 
        default_realkey = None
2743
2054
        default_help = self.get_help('default')
2744
2055
        help_pairs = []
2745
2056
        for key in self.keys():
2754
2065
        def wrapped(key, help, info):
2755
2066
            if info.native:
2756
2067
                help = '(native) ' + help
2757
 
            return ':%s:\n%s\n\n' % (key, 
 
2068
            return '  %s:\n%s\n\n' % (key, 
2758
2069
                    textwrap.fill(help, initial_indent='    ', 
2759
2070
                    subsequent_indent='    '))
2760
 
        if default_realkey is not None:
2761
 
            output += wrapped(default_realkey, '(default) %s' % default_help,
2762
 
                              self.get_info('default'))
 
2071
        output += wrapped('%s/default' % default_realkey, default_help,
 
2072
                          self.get_info('default'))
2763
2073
        deprecated_pairs = []
2764
 
        experimental_pairs = []
2765
2074
        for key, help in help_pairs:
2766
2075
            info = self.get_info(key)
2767
 
            if info.hidden:
2768
 
                continue
2769
 
            elif info.deprecated:
 
2076
            if info.deprecated:
2770
2077
                deprecated_pairs.append((key, help))
2771
 
            elif info.experimental:
2772
 
                experimental_pairs.append((key, help))
2773
2078
            else:
2774
2079
                output += wrapped(key, help, info)
2775
 
        if len(experimental_pairs) > 0:
2776
 
            output += "Experimental formats are shown below.\n\n"
2777
 
            for key, help in experimental_pairs:
2778
 
                info = self.get_info(key)
2779
 
                output += wrapped(key, help, info)
2780
2080
        if len(deprecated_pairs) > 0:
2781
 
            output += "Deprecated formats are shown below.\n\n"
 
2081
            output += "Deprecated formats\n------------------\n\n"
2782
2082
            for key, help in deprecated_pairs:
2783
2083
                info = self.get_info(key)
2784
2084
                output += wrapped(key, help, info)
2786
2086
        return output
2787
2087
 
2788
2088
 
2789
 
class RepositoryAcquisitionPolicy(object):
2790
 
    """Abstract base class for repository acquisition policies.
2791
 
 
2792
 
    A repository acquisition policy decides how a BzrDir acquires a repository
2793
 
    for a branch that is being created.  The most basic policy decision is
2794
 
    whether to create a new repository or use an existing one.
2795
 
    """
2796
 
    def __init__(self, stack_on, stack_on_pwd, require_stacking):
2797
 
        """Constructor.
2798
 
 
2799
 
        :param stack_on: A location to stack on
2800
 
        :param stack_on_pwd: If stack_on is relative, the location it is
2801
 
            relative to.
2802
 
        :param require_stacking: If True, it is a failure to not stack.
2803
 
        """
2804
 
        self._stack_on = stack_on
2805
 
        self._stack_on_pwd = stack_on_pwd
2806
 
        self._require_stacking = require_stacking
2807
 
 
2808
 
    def configure_branch(self, branch):
2809
 
        """Apply any configuration data from this policy to the branch.
2810
 
 
2811
 
        Default implementation sets repository stacking.
2812
 
        """
2813
 
        if self._stack_on is None:
2814
 
            return
2815
 
        if self._stack_on_pwd is None:
2816
 
            stack_on = self._stack_on
2817
 
        else:
2818
 
            try:
2819
 
                stack_on = urlutils.rebase_url(self._stack_on,
2820
 
                    self._stack_on_pwd,
2821
 
                    branch.bzrdir.root_transport.base)
2822
 
            except errors.InvalidRebaseURLs:
2823
 
                stack_on = self._get_full_stack_on()
2824
 
        try:
2825
 
            branch.set_stacked_on_url(stack_on)
2826
 
        except errors.UnstackableBranchFormat:
2827
 
            if self._require_stacking:
2828
 
                raise
2829
 
 
2830
 
    def _get_full_stack_on(self):
2831
 
        """Get a fully-qualified URL for the stack_on location."""
2832
 
        if self._stack_on is None:
2833
 
            return None
2834
 
        if self._stack_on_pwd is None:
2835
 
            return self._stack_on
2836
 
        else:
2837
 
            return urlutils.join(self._stack_on_pwd, self._stack_on)
2838
 
 
2839
 
    def _add_fallback(self, repository):
2840
 
        """Add a fallback to the supplied repository, if stacking is set."""
2841
 
        stack_on = self._get_full_stack_on()
2842
 
        if stack_on is None:
2843
 
            return
2844
 
        stacked_dir = BzrDir.open(stack_on)
2845
 
        try:
2846
 
            stacked_repo = stacked_dir.open_branch().repository
2847
 
        except errors.NotBranchError:
2848
 
            stacked_repo = stacked_dir.open_repository()
2849
 
        try:
2850
 
            repository.add_fallback_repository(stacked_repo)
2851
 
        except errors.UnstackableRepositoryFormat:
2852
 
            if self._require_stacking:
2853
 
                raise
2854
 
 
2855
 
    def acquire_repository(self, make_working_trees=None, shared=False):
2856
 
        """Acquire a repository for this bzrdir.
2857
 
 
2858
 
        Implementations may create a new repository or use a pre-exising
2859
 
        repository.
2860
 
        :param make_working_trees: If creating a repository, set
2861
 
            make_working_trees to this value (if non-None)
2862
 
        :param shared: If creating a repository, make it shared if True
2863
 
        :return: A repository
2864
 
        """
2865
 
        raise NotImplemented(RepositoryAcquisitionPolicy.acquire_repository)
2866
 
 
2867
 
 
2868
 
class CreateRepository(RepositoryAcquisitionPolicy):
2869
 
    """A policy of creating a new repository"""
2870
 
 
2871
 
    def __init__(self, bzrdir, stack_on=None, stack_on_pwd=None,
2872
 
                 require_stacking=False):
2873
 
        """
2874
 
        Constructor.
2875
 
        :param bzrdir: The bzrdir to create the repository on.
2876
 
        :param stack_on: A location to stack on
2877
 
        :param stack_on_pwd: If stack_on is relative, the location it is
2878
 
            relative to.
2879
 
        """
2880
 
        RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
2881
 
                                             require_stacking)
2882
 
        self._bzrdir = bzrdir
2883
 
 
2884
 
    def acquire_repository(self, make_working_trees=None, shared=False):
2885
 
        """Implementation of RepositoryAcquisitionPolicy.acquire_repository
2886
 
 
2887
 
        Creates the desired repository in the bzrdir we already have.
2888
 
        """
2889
 
        if self._stack_on or self._require_stacking:
2890
 
            # we may be coming from a format that doesn't support stacking,
2891
 
            # but we require it in the destination, so force creation of a new
2892
 
            # one here.
2893
 
            #
2894
 
            # TODO: perhaps this should be treated as a distinct repository
2895
 
            # acquisition policy?
2896
 
            repository_format = self._bzrdir._format.repository_format
2897
 
            if not repository_format.supports_external_lookups:
2898
 
                # should possibly be controlled by the registry rather than
2899
 
                # hardcoded here.
2900
 
                from bzrlib.repofmt import pack_repo
2901
 
                if repository_format.rich_root_data:
2902
 
                    repository_format = \
2903
 
                        pack_repo.RepositoryFormatKnitPack5RichRoot()
2904
 
                else:
2905
 
                    repository_format = pack_repo.RepositoryFormatKnitPack5()
2906
 
                note("using %r for stacking" % (repository_format,))
2907
 
            repository = repository_format.initialize(self._bzrdir,
2908
 
                shared=shared)
2909
 
        else:
2910
 
            # let bzrdir choose
2911
 
            repository = self._bzrdir.create_repository(shared=shared)
2912
 
        self._add_fallback(repository)
2913
 
        if make_working_trees is not None:
2914
 
            repository.set_make_working_trees(make_working_trees)
2915
 
        return repository
2916
 
 
2917
 
 
2918
 
class UseExistingRepository(RepositoryAcquisitionPolicy):
2919
 
    """A policy of reusing an existing repository"""
2920
 
 
2921
 
    def __init__(self, repository, stack_on=None, stack_on_pwd=None,
2922
 
                 require_stacking=False):
2923
 
        """Constructor.
2924
 
 
2925
 
        :param repository: The repository to use.
2926
 
        :param stack_on: A location to stack on
2927
 
        :param stack_on_pwd: If stack_on is relative, the location it is
2928
 
            relative to.
2929
 
        """
2930
 
        RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
2931
 
                                             require_stacking)
2932
 
        self._repository = repository
2933
 
 
2934
 
    def acquire_repository(self, make_working_trees=None, shared=False):
2935
 
        """Implementation of RepositoryAcquisitionPolicy.acquire_repository
2936
 
 
2937
 
        Returns an existing repository to use
2938
 
        """
2939
 
        self._add_fallback(self._repository)
2940
 
        return self._repository
2941
 
 
2942
 
 
2943
2089
format_registry = BzrDirFormatRegistry()
2944
2090
format_registry.register('weave', BzrDirFormat6,
2945
2091
    'Pre-0.8 format.  Slower than knit and does not'
2946
 
    ' support checkouts or shared repositories.',
2947
 
    deprecated=True)
2948
 
format_registry.register_metadir('knit',
2949
 
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2950
 
    'Format using knits.  Recommended for interoperation with bzr <= 0.14.',
2951
 
    branch_format='bzrlib.branch.BzrBranchFormat5',
2952
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat3')
2953
 
format_registry.register_metadir('metaweave',
2954
 
    'bzrlib.repofmt.weaverepo.RepositoryFormat7',
 
2092
    ' support checkouts or shared repositories.', deprecated=True)
 
2093
format_registry.register_metadir('knit', 'RepositoryFormatKnit1',
 
2094
    'Format using knits.  Recommended.')
 
2095
format_registry.set_default('knit')
 
2096
format_registry.register_metadir('metaweave', 'RepositoryFormat7',
2955
2097
    'Transitional format in 0.8.  Slower than knit.',
2956
 
    branch_format='bzrlib.branch.BzrBranchFormat5',
2957
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat3',
2958
2098
    deprecated=True)
2959
 
format_registry.register_metadir('dirstate',
2960
 
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2961
 
    help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
2962
 
        'above when accessed over the network.',
2963
 
    branch_format='bzrlib.branch.BzrBranchFormat5',
2964
 
    # this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
2965
 
    # directly from workingtree_4 triggers a circular import.
2966
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2967
 
    )
2968
 
format_registry.register_metadir('dirstate-tags',
2969
 
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2970
 
    help='New in 0.15: Fast local operations and improved scaling for '
2971
 
        'network operations. Additionally adds support for tags.'
2972
 
        ' Incompatible with bzr < 0.15.',
2973
 
    branch_format='bzrlib.branch.BzrBranchFormat6',
2974
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2975
 
    )
2976
 
format_registry.register_metadir('rich-root',
2977
 
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit4',
2978
 
    help='New in 1.0.  Better handling of tree roots.  Incompatible with'
2979
 
        ' bzr < 1.0',
2980
 
    branch_format='bzrlib.branch.BzrBranchFormat6',
2981
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2982
 
    )
2983
 
format_registry.register_metadir('dirstate-with-subtree',
2984
 
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
2985
 
    help='New in 0.15: Fast local operations and improved scaling for '
2986
 
        'network operations. Additionally adds support for versioning nested '
2987
 
        'bzr branches. Incompatible with bzr < 0.15.',
2988
 
    branch_format='bzrlib.branch.BzrBranchFormat6',
2989
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2990
 
    experimental=True,
2991
 
    hidden=True,
2992
 
    )
2993
 
format_registry.register_metadir('pack-0.92',
2994
 
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack1',
2995
 
    help='New in 0.92: Pack-based format with data compatible with '
2996
 
        'dirstate-tags format repositories. Interoperates with '
2997
 
        'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
2998
 
        'Previously called knitpack-experimental.  '
2999
 
        'For more information, see '
3000
 
        'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
3001
 
    branch_format='bzrlib.branch.BzrBranchFormat6',
3002
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3003
 
    )
3004
 
format_registry.register_metadir('pack-0.92-subtree',
3005
 
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack3',
3006
 
    help='New in 0.92: Pack-based format with data compatible with '
3007
 
        'dirstate-with-subtree format repositories. Interoperates with '
3008
 
        'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
3009
 
        'Previously called knitpack-experimental.  '
3010
 
        'For more information, see '
3011
 
        'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
3012
 
    branch_format='bzrlib.branch.BzrBranchFormat6',
3013
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3014
 
    hidden=True,
3015
 
    experimental=True,
3016
 
    )
3017
 
format_registry.register_metadir('rich-root-pack',
3018
 
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack4',
3019
 
    help='New in 1.0: Pack-based format with data compatible with '
3020
 
        'rich-root format repositories. Incompatible with'
3021
 
        ' bzr < 1.0',
3022
 
    branch_format='bzrlib.branch.BzrBranchFormat6',
3023
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3024
 
    )
3025
 
format_registry.register_metadir('1.6',
3026
 
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack5',
3027
 
    help='A branch and pack based repository that supports stacking. ',
3028
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
3029
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3030
 
    )
3031
 
format_registry.register_metadir('1.6-rich-root',
3032
 
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack5RichRoot',
3033
 
    help='A branch and pack based repository that supports stacking '
3034
 
         'and rich root data (needed for bzr-svn). ',
3035
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
3036
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3037
 
    )
3038
 
# The following two formats should always just be aliases.
3039
 
format_registry.register_metadir('development',
3040
 
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment1',
3041
 
    help='Current development format. Can convert data to and from pack-0.92 '
3042
 
        '(and anything compatible with pack-0.92) format repositories. '
3043
 
        'Repositories and branches in this format can only be read by bzr.dev. '
3044
 
        'Please read '
3045
 
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
3046
 
        'before use.',
3047
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
3048
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3049
 
    experimental=True,
3050
 
    alias=True,
3051
 
    )
3052
 
format_registry.register_metadir('development-subtree',
3053
 
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment1Subtree',
3054
 
    help='Current development format, subtree variant. Can convert data to and '
3055
 
        'from pack-0.92-subtree (and anything compatible with '
3056
 
        'pack-0.92-subtree) format repositories. Repositories and branches in '
3057
 
        'this format can only be read by bzr.dev. Please read '
3058
 
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
3059
 
        'before use.',
3060
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
3061
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3062
 
    experimental=True,
3063
 
    alias=True,
3064
 
    )
3065
 
# And the development formats which the will have aliased one of follow:
3066
 
format_registry.register_metadir('development0',
3067
 
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0',
3068
 
    help='Trivial rename of pack-0.92 to provide a development format. '
3069
 
        'Please read '
3070
 
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
3071
 
        'before use.',
3072
 
    branch_format='bzrlib.branch.BzrBranchFormat6',
3073
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3074
 
    hidden=True,
3075
 
    experimental=True,
3076
 
    )
3077
 
format_registry.register_metadir('development0-subtree',
3078
 
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0Subtree',
3079
 
    help='Trivial rename of pack-0.92-subtree to provide a development format. '
3080
 
        'Please read '
3081
 
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
3082
 
        'before use.',
3083
 
    branch_format='bzrlib.branch.BzrBranchFormat6',
3084
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3085
 
    hidden=True,
3086
 
    experimental=True,
3087
 
    )
3088
 
format_registry.register_metadir('development1',
3089
 
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment1',
3090
 
    help='A branch and pack based repository that supports stacking. '
3091
 
        'Please read '
3092
 
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
3093
 
        'before use.',
3094
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
3095
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3096
 
    hidden=True,
3097
 
    experimental=True,
3098
 
    )
3099
 
format_registry.register_metadir('development1-subtree',
3100
 
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment1Subtree',
3101
 
    help='A branch and pack based repository that supports stacking. '
3102
 
        'Please read '
3103
 
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
3104
 
        'before use.',
3105
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
3106
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3107
 
    hidden=True,
3108
 
    experimental=True,
3109
 
    )
3110
 
# The current format that is made on 'bzr init'.
3111
 
format_registry.set_default('pack-0.92')
 
2099
format_registry.register_metadir('experimental-knit2', 'RepositoryFormatKnit2',
 
2100
    'Experimental successor to knit.  Use at your own risk.')