~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

  • Committer: Jelmer Vernooij
  • Date: 2009-01-28 18:42:55 UTC
  • mto: This revision was merged to the branch mainline in revision 3968.
  • Revision ID: jelmer@samba.org-20090128184255-bdmklkvm83ltk191
Update NEWS

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 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.
21
26
"""
22
27
 
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?
30
 
 
31
 
from cStringIO import StringIO
 
28
# TODO: Move old formats into a plugin to make this file smaller.
 
29
 
32
30
import os
33
 
import textwrap
 
31
import sys
34
32
 
35
33
from bzrlib.lazy_import import lazy_import
36
34
lazy_import(globals(), """
37
 
from copy import deepcopy
38
35
from stat import S_ISDIR
39
 
import unittest
 
36
import textwrap
40
37
 
41
38
import bzrlib
42
39
from bzrlib import (
 
40
    config,
43
41
    errors,
 
42
    graph,
44
43
    lockable_files,
45
44
    lockdir,
46
 
    registry,
 
45
    osutils,
 
46
    remote,
47
47
    revision as _mod_revision,
48
 
    symbol_versioning,
 
48
    ui,
49
49
    urlutils,
 
50
    versionedfile,
 
51
    win32utils,
 
52
    workingtree,
 
53
    workingtree_4,
50
54
    xml4,
51
55
    xml5,
52
56
    )
53
57
from bzrlib.osutils import (
54
 
    safe_unicode,
55
 
    sha_strings,
56
58
    sha_string,
57
59
    )
58
 
from bzrlib.store.revision.text import TextRevisionStore
59
 
from bzrlib.store.text import TextStore
 
60
from bzrlib.smart.client import _SmartClient
60
61
from bzrlib.store.versioned import WeaveStore
61
62
from bzrlib.transactions import WriteTransaction
62
 
from bzrlib.transport import get_transport
 
63
from bzrlib.transport import (
 
64
    do_catching_redirections,
 
65
    get_transport,
 
66
    local,
 
67
    )
63
68
from bzrlib.weave import Weave
64
69
""")
65
70
 
66
 
from bzrlib.trace import mutter
67
 
from bzrlib.transport.local import LocalTransport
 
71
from bzrlib.trace import (
 
72
    mutter,
 
73
    note,
 
74
    )
 
75
 
 
76
from bzrlib import (
 
77
    registry,
 
78
    symbol_versioning,
 
79
    )
68
80
 
69
81
 
70
82
class BzrDir(object):
73
85
    BzrDir instances let you create or open any of the things that can be
74
86
    found within .bzr - checkouts, branches and repositories.
75
87
    
76
 
    transport
 
88
    :ivar transport:
77
89
        the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
78
 
    root_transport
79
 
        a transport connected to the directory this bzr was opened from.
 
90
    :ivar root_transport:
 
91
        a transport connected to the directory this bzr was opened from
 
92
        (i.e. the parent directory holding the .bzr directory).
 
93
 
 
94
    Everything in the bzrdir should have the same file permissions.
80
95
    """
81
96
 
82
97
    def break_lock(self):
85
100
        If there is a tree, the tree is opened and break_lock() called.
86
101
        Otherwise, branch is tried, and finally repository.
87
102
        """
 
103
        # XXX: This seems more like a UI function than something that really
 
104
        # belongs in this class.
88
105
        try:
89
106
            thing_to_unlock = self.open_workingtree()
90
107
        except (errors.NotLocalUrl, errors.NoWorkingTree):
107
124
        source_repo_format.check_conversion_target(target_repo_format)
108
125
 
109
126
    @staticmethod
110
 
    def _check_supported(format, allow_unsupported):
111
 
        """Check whether format is a supported format.
112
 
 
113
 
        If allow_unsupported is True, this is a no-op.
 
127
    def _check_supported(format, allow_unsupported,
 
128
        recommend_upgrade=True,
 
129
        basedir=None):
 
130
        """Give an error or warning on old formats.
 
131
 
 
132
        :param format: may be any kind of format - workingtree, branch, 
 
133
        or repository.
 
134
 
 
135
        :param allow_unsupported: If true, allow opening 
 
136
        formats that are strongly deprecated, and which may 
 
137
        have limited functionality.
 
138
 
 
139
        :param recommend_upgrade: If true (default), warn
 
140
        the user through the ui object that they may wish
 
141
        to upgrade the object.
114
142
        """
 
143
        # TODO: perhaps move this into a base Format class; it's not BzrDir
 
144
        # specific. mbp 20070323
115
145
        if not allow_unsupported and not format.is_supported():
116
146
            # see open_downlevel to open legacy branches.
117
147
            raise errors.UnsupportedFormatError(format=format)
 
148
        if recommend_upgrade \
 
149
            and getattr(format, 'upgrade_recommended', False):
 
150
            ui.ui_factory.recommend_upgrade(
 
151
                format.get_format_description(),
 
152
                basedir)
118
153
 
119
 
    def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
 
154
    def clone(self, url, revision_id=None, force_new_repo=False,
 
155
              preserve_stacking=False):
120
156
        """Clone this bzrdir and its contents to url verbatim.
121
157
 
122
 
        If urls last component does not exist, it will be created.
123
 
 
124
 
        if revision_id is not None, then the clone operation may tune
125
 
            itself to download less data.
126
 
        :param force_new_repo: Do not use a shared repository for the target 
127
 
                               even if one is available.
128
 
        """
129
 
        self._make_tail(url)
130
 
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
131
 
        result = self._format.initialize(url)
 
158
        :param url: The url create the clone at.  If url's last component does
 
159
            not exist, it will be created.
 
160
        :param revision_id: The tip revision-id to use for any branch or
 
161
            working tree.  If not None, then the clone operation may tune
 
162
            itself to download less data.
 
163
        :param force_new_repo: Do not use a shared repository for the target
 
164
                               even if one is available.
 
165
        :param preserve_stacking: When cloning a stacked branch, stack the
 
166
            new branch on top of the other branch's stacked-on branch.
 
167
        """
 
168
        return self.clone_on_transport(get_transport(url),
 
169
                                       revision_id=revision_id,
 
170
                                       force_new_repo=force_new_repo,
 
171
                                       preserve_stacking=preserve_stacking)
 
172
 
 
173
    def clone_on_transport(self, transport, revision_id=None,
 
174
                           force_new_repo=False, preserve_stacking=False,
 
175
                           stacked_on=None):
 
176
        """Clone this bzrdir and its contents to transport verbatim.
 
177
 
 
178
        :param transport: The transport for the location to produce the clone
 
179
            at.  If the target directory does not exist, it will be created.
 
180
        :param revision_id: The tip revision-id to use for any branch or
 
181
            working tree.  If not None, then the clone operation may tune
 
182
            itself to download less data.
 
183
        :param force_new_repo: Do not use a shared repository for the target,
 
184
                               even if one is available.
 
185
        :param preserve_stacking: When cloning a stacked branch, stack the
 
186
            new branch on top of the other branch's stacked-on branch.
 
187
        """
 
188
        transport.ensure_base()
 
189
        require_stacking = (stacked_on is not None)
 
190
        metadir = self.cloning_metadir(require_stacking)
 
191
        result = metadir.initialize_on_transport(transport)
 
192
        repository_policy = None
132
193
        try:
133
194
            local_repo = self.find_repository()
134
195
        except errors.NoRepositoryPresent:
135
196
            local_repo = None
 
197
        try:
 
198
            local_branch = self.open_branch()
 
199
        except errors.NotBranchError:
 
200
            local_branch = None
 
201
        else:
 
202
            # enable fallbacks when branch is not a branch reference
 
203
            if local_branch.repository.has_same_location(local_repo):
 
204
                local_repo = local_branch.repository
 
205
            if preserve_stacking:
 
206
                try:
 
207
                    stacked_on = local_branch.get_stacked_on_url()
 
208
                except (errors.UnstackableBranchFormat,
 
209
                        errors.UnstackableRepositoryFormat,
 
210
                        errors.NotStacked):
 
211
                    pass
 
212
 
136
213
        if local_repo:
137
214
            # may need to copy content in
138
 
            if force_new_repo:
139
 
                result_repo = local_repo.clone(
140
 
                    result,
141
 
                    revision_id=revision_id,
142
 
                    basis=basis_repo)
143
 
                result_repo.set_make_working_trees(local_repo.make_working_trees())
144
 
            else:
145
 
                try:
146
 
                    result_repo = result.find_repository()
147
 
                    # fetch content this dir needs.
148
 
                    if basis_repo:
149
 
                        # XXX FIXME RBC 20060214 need tests for this when the basis
150
 
                        # is incomplete
151
 
                        result_repo.fetch(basis_repo, revision_id=revision_id)
152
 
                    result_repo.fetch(local_repo, revision_id=revision_id)
153
 
                except errors.NoRepositoryPresent:
154
 
                    # needed to make one anyway.
155
 
                    result_repo = local_repo.clone(
156
 
                        result,
157
 
                        revision_id=revision_id,
158
 
                        basis=basis_repo)
159
 
                    result_repo.set_make_working_trees(local_repo.make_working_trees())
 
215
            repository_policy = result.determine_repository_policy(
 
216
                force_new_repo, stacked_on, self.root_transport.base,
 
217
                require_stacking=require_stacking)
 
218
            make_working_trees = local_repo.make_working_trees()
 
219
            result_repo = repository_policy.acquire_repository(
 
220
                make_working_trees, local_repo.is_shared())
 
221
            if not require_stacking and repository_policy._require_stacking:
 
222
                require_stacking = True
 
223
                result._format.require_stacking()
 
224
            result_repo.fetch(local_repo, revision_id=revision_id)
 
225
        else:
 
226
            result_repo = None
160
227
        # 1 if there is a branch present
161
228
        #   make sure its content is available in the target repository
162
229
        #   clone it.
163
 
        try:
164
 
            self.open_branch().clone(result, revision_id=revision_id)
165
 
        except errors.NotBranchError:
166
 
            pass
167
 
        try:
168
 
            self.open_workingtree().clone(result, basis=basis_tree)
169
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
170
 
            pass
 
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():
 
235
            try:
 
236
                self.open_workingtree().clone(result)
 
237
            except (errors.NoWorkingTree, errors.NotLocalUrl):
 
238
                pass
171
239
        return result
172
240
 
173
 
    def _get_basis_components(self, basis):
174
 
        """Retrieve the basis components that are available at basis."""
175
 
        if basis is None:
176
 
            return None, None, None
177
 
        try:
178
 
            basis_tree = basis.open_workingtree()
179
 
            basis_branch = basis_tree.branch
180
 
            basis_repo = basis_branch.repository
181
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
182
 
            basis_tree = None
183
 
            try:
184
 
                basis_branch = basis.open_branch()
185
 
                basis_repo = basis_branch.repository
186
 
            except errors.NotBranchError:
187
 
                basis_branch = None
188
 
                try:
189
 
                    basis_repo = basis.open_repository()
190
 
                except errors.NoRepositoryPresent:
191
 
                    basis_repo = None
192
 
        return basis_repo, basis_branch, basis_tree
193
 
 
194
241
    # TODO: This should be given a Transport, and should chdir up; otherwise
195
242
    # this will open a new connection.
196
243
    def _make_tail(self, url):
197
 
        head, tail = urlutils.split(url)
198
 
        if tail and tail != '.':
199
 
            t = get_transport(head)
200
 
            try:
201
 
                t.mkdir(tail)
202
 
            except errors.FileExists:
203
 
                pass
 
244
        t = get_transport(url)
 
245
        t.ensure_base()
204
246
 
205
 
    # TODO: Should take a Transport
206
247
    @classmethod
207
 
    def create(cls, base, format=None):
 
248
    def create(cls, base, format=None, possible_transports=None):
208
249
        """Create a new BzrDir at the url 'base'.
209
250
        
210
 
        This will call the current default formats initialize with base
211
 
        as the only parameter.
212
 
 
213
251
        :param format: If supplied, the format of branch to create.  If not
214
252
            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.
215
255
        """
216
256
        if cls is not BzrDir:
217
257
            raise AssertionError("BzrDir.create always creates the default"
218
258
                " format, not one of %r" % cls)
219
 
        head, tail = urlutils.split(base)
220
 
        if tail and tail != '.':
221
 
            t = get_transport(head)
222
 
            try:
223
 
                t.mkdir(tail)
224
 
            except errors.FileExists:
225
 
                pass
 
259
        t = get_transport(base, possible_transports)
 
260
        t.ensure_base()
226
261
        if format is None:
227
262
            format = BzrDirFormat.get_default_format()
228
 
        return format.initialize(safe_unicode(base))
 
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
341
 
230
342
    def create_branch(self):
231
343
        """Create a branch in this BzrDir.
232
344
 
233
 
        The bzrdirs format will control what branch format is created.
 
345
        The bzrdir's format will control what branch format is created.
234
346
        For more control see BranchFormatXX.create(a_bzrdir).
235
347
        """
236
348
        raise NotImplementedError(self.create_branch)
237
349
 
 
350
    def destroy_branch(self):
 
351
        """Destroy the branch in this BzrDir"""
 
352
        raise NotImplementedError(self.destroy_branch)
 
353
 
238
354
    @staticmethod
239
355
    def create_branch_and_repo(base, force_new_repo=False, format=None):
240
356
        """Create a new BzrDir, Branch and Repository at the url 'base'.
241
357
 
242
 
        This will use the current default BzrDirFormat, and use whatever 
 
358
        This will use the current default BzrDirFormat unless one is
 
359
        specified, and use whatever 
243
360
        repository format that that uses via bzrdir.create_branch and
244
361
        create_repository. If a shared repository is available that is used
245
362
        preferentially.
248
365
 
249
366
        :param base: The URL to create the branch at.
250
367
        :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.
251
370
        """
252
371
        bzrdir = BzrDir.create(base, format)
253
372
        bzrdir._find_or_create_repository(force_new_repo)
254
373
        return bzrdir.create_branch()
255
374
 
 
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
 
256
437
    def _find_or_create_repository(self, force_new_repo):
257
438
        """Create a new repository if needed, returning the repository."""
258
 
        if force_new_repo:
259
 
            return self.create_repository()
260
 
        try:
261
 
            return self.find_repository()
262
 
        except errors.NoRepositoryPresent:
263
 
            return self.create_repository()
264
 
        
 
439
        policy = self.determine_repository_policy(force_new_repo)
 
440
        return policy.acquire_repository()
 
441
 
265
442
    @staticmethod
266
443
    def create_branch_convenience(base, force_new_repo=False,
267
 
                                  force_new_tree=None, format=None):
 
444
                                  force_new_tree=None, format=None,
 
445
                                  possible_transports=None):
268
446
        """Create a new BzrDir, Branch and Repository at the url 'base'.
269
447
 
270
448
        This is a convenience function - it will use an existing repository
271
449
        if possible, can be told explicitly whether to create a working tree or
272
450
        not.
273
451
 
274
 
        This will use the current default BzrDirFormat, and use whatever 
 
452
        This will use the current default BzrDirFormat unless one is
 
453
        specified, and use whatever 
275
454
        repository format that that uses via bzrdir.create_branch and
276
455
        create_repository. If a shared repository is available that is used
277
456
        preferentially. Whatever repository is used, its tree creation policy
286
465
        :param force_new_repo: If True a new repository is always created.
287
466
        :param force_new_tree: If True or False force creation of a tree or 
288
467
                               prevent such creation respectively.
289
 
        :param format: Override for the for the bzrdir format to create
 
468
        :param format: Override for the bzrdir format to create.
 
469
        :param possible_transports: An optional reusable transports list.
290
470
        """
291
471
        if force_new_tree:
292
472
            # check for non local urls
293
 
            t = get_transport(safe_unicode(base))
294
 
            if not isinstance(t, LocalTransport):
 
473
            t = get_transport(base, possible_transports)
 
474
            if not isinstance(t, local.LocalTransport):
295
475
                raise errors.NotLocalUrl(base)
296
 
        bzrdir = BzrDir.create(base, format)
 
476
        bzrdir = BzrDir.create(base, format, possible_transports)
297
477
        repo = bzrdir._find_or_create_repository(force_new_repo)
298
478
        result = bzrdir.create_branch()
299
 
        if force_new_tree or (repo.make_working_trees() and 
 
479
        if force_new_tree or (repo.make_working_trees() and
300
480
                              force_new_tree is None):
301
481
            try:
302
482
                bzrdir.create_workingtree()
303
483
            except errors.NotLocalUrl:
304
484
                pass
305
485
        return result
306
 
        
307
 
    @staticmethod
308
 
    def create_repository(base, shared=False, format=None):
309
 
        """Create a new BzrDir and Repository at the url 'base'.
310
 
 
311
 
        If no format is supplied, this will default to the current default
312
 
        BzrDirFormat by default, and use whatever repository format that that
313
 
        uses for bzrdirformat.create_repository.
314
 
 
315
 
        :param shared: Create a shared repository rather than a standalone
316
 
                       repository.
317
 
        The Repository object is returned.
318
 
 
319
 
        This must be overridden as an instance method in child classes, where
320
 
        it should take no parameters and construct whatever repository format
321
 
        that child class desires.
322
 
        """
323
 
        bzrdir = BzrDir.create(base, format)
324
 
        return bzrdir.create_repository(shared)
325
486
 
326
487
    @staticmethod
327
488
    def create_standalone_workingtree(base, format=None):
329
490
 
330
491
        'base' must be a local path or a file:// url.
331
492
 
332
 
        This will use the current default BzrDirFormat, and use whatever 
 
493
        This will use the current default BzrDirFormat unless one is
 
494
        specified, and use whatever 
333
495
        repository format that that uses for bzrdirformat.create_workingtree,
334
496
        create_branch and create_repository.
335
497
 
 
498
        :param format: Override for the bzrdir format to create.
336
499
        :return: The WorkingTree object.
337
500
        """
338
 
        t = get_transport(safe_unicode(base))
339
 
        if not isinstance(t, LocalTransport):
 
501
        t = get_transport(base)
 
502
        if not isinstance(t, local.LocalTransport):
340
503
            raise errors.NotLocalUrl(base)
341
 
        bzrdir = BzrDir.create_branch_and_repo(safe_unicode(base),
 
504
        bzrdir = BzrDir.create_branch_and_repo(base,
342
505
                                               force_new_repo=True,
343
506
                                               format=format).bzrdir
344
507
        return bzrdir.create_workingtree()
345
508
 
346
 
    def create_workingtree(self, revision_id=None):
 
509
    def create_workingtree(self, revision_id=None, from_branch=None,
 
510
        accelerator_tree=None, hardlink=False):
347
511
        """Create a working tree at this BzrDir.
348
512
        
349
 
        revision_id: create it as of this revision id.
 
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
519
        """
351
520
        raise NotImplementedError(self.create_workingtree)
352
521
 
 
522
    def backup_bzrdir(self):
 
523
        """Backup this bzr control directory.
 
524
        
 
525
        :return: Tuple with old path name and new path name
 
526
        """
 
527
        pb = ui.ui_factory.nested_progress_bar()
 
528
        try:
 
529
            # FIXME: bug 300001 -- the backup fails if the backup directory
 
530
            # already exists, but it should instead either remove it or make
 
531
            # a new backup directory.
 
532
            #
 
533
            # FIXME: bug 262450 -- the backup directory should have the same 
 
534
            # permissions as the .bzr directory (probably a bug in copy_tree)
 
535
            old_path = self.root_transport.abspath('.bzr')
 
536
            new_path = self.root_transport.abspath('backup.bzr')
 
537
            pb.note('making backup of %s' % (old_path,))
 
538
            pb.note('  to %s' % (new_path,))
 
539
            self.root_transport.copy_tree('.bzr', 'backup.bzr')
 
540
            return (old_path, new_path)
 
541
        finally:
 
542
            pb.finished()
 
543
 
 
544
    def retire_bzrdir(self, limit=10000):
 
545
        """Permanently disable the bzrdir.
 
546
 
 
547
        This is done by renaming it to give the user some ability to recover
 
548
        if there was a problem.
 
549
 
 
550
        This will have horrible consequences if anyone has anything locked or
 
551
        in use.
 
552
        :param limit: number of times to retry
 
553
        """
 
554
        i  = 0
 
555
        while True:
 
556
            try:
 
557
                to_path = '.bzr.retired.%d' % i
 
558
                self.root_transport.rename('.bzr', to_path)
 
559
                note("renamed %s to %s"
 
560
                    % (self.root_transport.abspath('.bzr'), to_path))
 
561
                return
 
562
            except (errors.TransportError, IOError, errors.PathError):
 
563
                i += 1
 
564
                if i > limit:
 
565
                    raise
 
566
                else:
 
567
                    pass
 
568
 
353
569
    def destroy_workingtree(self):
354
570
        """Destroy the working tree at this BzrDir.
355
571
 
365
581
        """
366
582
        raise NotImplementedError(self.destroy_workingtree_metadata)
367
583
 
 
584
    def _find_containing(self, evaluate):
 
585
        """Find something in a containing control directory.
 
586
 
 
587
        This method will scan containing control dirs, until it finds what
 
588
        it is looking for, decides that it will never find it, or runs out
 
589
        of containing control directories to check.
 
590
 
 
591
        It is used to implement find_repository and
 
592
        determine_repository_policy.
 
593
 
 
594
        :param evaluate: A function returning (value, stop).  If stop is True,
 
595
            the value will be returned.
 
596
        """
 
597
        found_bzrdir = self
 
598
        while True:
 
599
            result, stop = evaluate(found_bzrdir)
 
600
            if stop:
 
601
                return result
 
602
            next_transport = found_bzrdir.root_transport.clone('..')
 
603
            if (found_bzrdir.root_transport.base == next_transport.base):
 
604
                # top of the file system
 
605
                return None
 
606
            # find the next containing bzrdir
 
607
            try:
 
608
                found_bzrdir = BzrDir.open_containing_from_transport(
 
609
                    next_transport)[0]
 
610
            except errors.NotBranchError:
 
611
                return None
 
612
 
368
613
    def find_repository(self):
369
 
        """Find the repository that should be used for a_bzrdir.
 
614
        """Find the repository that should be used.
370
615
 
371
616
        This does not require a branch as we use it to find the repo for
372
617
        new branches as well as to hook existing branches up to their
373
618
        repository.
374
619
        """
375
 
        try:
376
 
            return self.open_repository()
377
 
        except errors.NoRepositoryPresent:
378
 
            pass
379
 
        next_transport = self.root_transport.clone('..')
380
 
        while True:
381
 
            # find the next containing bzrdir
382
 
            try:
383
 
                found_bzrdir = BzrDir.open_containing_from_transport(
384
 
                    next_transport)[0]
385
 
            except errors.NotBranchError:
386
 
                # none found
387
 
                raise errors.NoRepositoryPresent(self)
 
620
        def usable_repository(found_bzrdir):
388
621
            # does it have a repository ?
389
622
            try:
390
623
                repository = found_bzrdir.open_repository()
391
624
            except errors.NoRepositoryPresent:
392
 
                next_transport = found_bzrdir.root_transport.clone('..')
393
 
                if (found_bzrdir.root_transport.base == next_transport.base):
394
 
                    # top of the file system
395
 
                    break
396
 
                else:
397
 
                    continue
398
 
            if ((found_bzrdir.root_transport.base == 
399
 
                 self.root_transport.base) or repository.is_shared()):
400
 
                return repository
 
625
                return None, False
 
626
            if found_bzrdir.root_transport.base == self.root_transport.base:
 
627
                return repository, True
 
628
            elif repository.is_shared():
 
629
                return repository, True
401
630
            else:
402
 
                raise errors.NoRepositoryPresent(self)
403
 
        raise errors.NoRepositoryPresent(self)
 
631
                return None, True
 
632
 
 
633
        found_repo = self._find_containing(usable_repository)
 
634
        if found_repo is None:
 
635
            raise errors.NoRepositoryPresent(self)
 
636
        return found_repo
 
637
 
 
638
    def get_branch_reference(self):
 
639
        """Return the referenced URL for the branch in this bzrdir.
 
640
 
 
641
        :raises NotBranchError: If there is no Branch.
 
642
        :return: The URL the branch in this bzrdir references if it is a
 
643
            reference branch, or None for regular branches.
 
644
        """
 
645
        return None
404
646
 
405
647
    def get_branch_transport(self, branch_format):
406
648
        """Get the transport for use by branch format in this BzrDir.
410
652
        a format string, and vice versa.
411
653
 
412
654
        If branch_format is None, the transport is returned with no 
413
 
        checking. if it is not None, then the returned transport is
 
655
        checking. If it is not None, then the returned transport is
414
656
        guaranteed to point to an existing directory ready for use.
415
657
        """
416
658
        raise NotImplementedError(self.get_branch_transport)
 
659
 
 
660
    def _find_creation_modes(self):
 
661
        """Determine the appropriate modes for files and directories.
 
662
 
 
663
        They're always set to be consistent with the base directory,
 
664
        assuming that this transport allows setting modes.
 
665
        """
 
666
        # TODO: Do we need or want an option (maybe a config setting) to turn
 
667
        # this off or override it for particular locations? -- mbp 20080512
 
668
        if self._mode_check_done:
 
669
            return
 
670
        self._mode_check_done = True
 
671
        try:
 
672
            st = self.transport.stat('.')
 
673
        except errors.TransportNotPossible:
 
674
            self._dir_mode = None
 
675
            self._file_mode = None
 
676
        else:
 
677
            # Check the directory mode, but also make sure the created
 
678
            # directories and files are read-write for this user. This is
 
679
            # mostly a workaround for filesystems which lie about being able to
 
680
            # write to a directory (cygwin & win32)
 
681
            if (st.st_mode & 07777 == 00000):
 
682
                # FTP allows stat but does not return dir/file modes
 
683
                self._dir_mode = None
 
684
                self._file_mode = None
 
685
            else:
 
686
                self._dir_mode = (st.st_mode & 07777) | 00700
 
687
                # Remove the sticky and execute bits for files
 
688
                self._file_mode = self._dir_mode & ~07111
 
689
 
 
690
    def _get_file_mode(self):
 
691
        """Return Unix mode for newly created files, or None.
 
692
        """
 
693
        if not self._mode_check_done:
 
694
            self._find_creation_modes()
 
695
        return self._file_mode
 
696
 
 
697
    def _get_dir_mode(self):
 
698
        """Return Unix mode for newly created directories, or None.
 
699
        """
 
700
        if not self._mode_check_done:
 
701
            self._find_creation_modes()
 
702
        return self._dir_mode
417
703
        
418
704
    def get_repository_transport(self, repository_format):
419
705
        """Get the transport for use by repository format in this BzrDir.
423
709
        a format string, and vice versa.
424
710
 
425
711
        If repository_format is None, the transport is returned with no 
426
 
        checking. if it is not None, then the returned transport is
 
712
        checking. If it is not None, then the returned transport is
427
713
        guaranteed to point to an existing directory ready for use.
428
714
        """
429
715
        raise NotImplementedError(self.get_repository_transport)
432
718
        """Get the transport for use by workingtree format in this BzrDir.
433
719
 
434
720
        Note that bzr dirs that do not support format strings will raise
435
 
        IncompatibleFormat if the workingtree format they are given has
436
 
        a format string, and vice versa.
 
721
        IncompatibleFormat if the workingtree format they are given has a
 
722
        format string, and vice versa.
437
723
 
438
724
        If workingtree_format is None, the transport is returned with no 
439
 
        checking. if it is not None, then the returned transport is
 
725
        checking. If it is not None, then the returned transport is
440
726
        guaranteed to point to an existing directory ready for use.
441
727
        """
442
728
        raise NotImplementedError(self.get_workingtree_transport)
443
 
        
 
729
 
 
730
    def get_config(self):
 
731
        if getattr(self, '_get_config', None) is None:
 
732
            return None
 
733
        return self._get_config()
 
734
 
444
735
    def __init__(self, _transport, _format):
445
736
        """Initialize a Bzr control dir object.
446
737
        
453
744
        self._format = _format
454
745
        self.transport = _transport.clone('.bzr')
455
746
        self.root_transport = _transport
 
747
        self._mode_check_done = False
456
748
 
457
749
    def is_control_filename(self, filename):
458
750
        """True if filename is the name of a path which is reserved for bzrdir's.
468
760
        # this might be better on the BzrDirFormat class because it refers to 
469
761
        # all the possible bzrdir disk formats. 
470
762
        # This method is tested via the workingtree is_control_filename tests- 
471
 
        # it was extracted from WorkingTree.is_control_filename. If the methods
472
 
        # contract is extended beyond the current trivial  implementation please
 
763
        # it was extracted from WorkingTree.is_control_filename. If the method's
 
764
        # contract is extended beyond the current trivial implementation, please
473
765
        # add new tests for it to the appropriate place.
474
766
        return filename == '.bzr' or filename.startswith('.bzr/')
475
767
 
490
782
        return BzrDir.open(base, _unsupported=True)
491
783
        
492
784
    @staticmethod
493
 
    def open(base, _unsupported=False):
494
 
        """Open an existing bzrdir, rooted at 'base' (url)
 
785
    def open(base, _unsupported=False, possible_transports=None):
 
786
        """Open an existing bzrdir, rooted at 'base' (url).
495
787
        
496
 
        _unsupported is a private parameter to the BzrDir class.
 
788
        :param _unsupported: a private parameter to the BzrDir class.
497
789
        """
498
 
        t = get_transport(base)
 
790
        t = get_transport(base, possible_transports=possible_transports)
499
791
        return BzrDir.open_from_transport(t, _unsupported=_unsupported)
500
792
 
501
793
    @staticmethod
502
 
    def open_from_transport(transport, _unsupported=False):
 
794
    def open_from_transport(transport, _unsupported=False,
 
795
                            _server_formats=True):
503
796
        """Open a bzrdir within a particular directory.
504
797
 
505
798
        :param transport: Transport containing the bzrdir.
506
799
        :param _unsupported: private.
507
800
        """
508
 
        format = BzrDirFormat.find_format(transport)
 
801
        # Keep initial base since 'transport' may be modified while following
 
802
        # the redirections.
 
803
        base = transport.base
 
804
        def find_format(transport):
 
805
            return transport, BzrDirFormat.find_format(
 
806
                transport, _server_formats=_server_formats)
 
807
 
 
808
        def redirected(transport, e, redirection_notice):
 
809
            redirected_transport = transport._redirected_to(e.source, e.target)
 
810
            if redirected_transport is None:
 
811
                raise errors.NotBranchError(base)
 
812
            note('%s is%s redirected to %s',
 
813
                 transport.base, e.permanently, redirected_transport.base)
 
814
            return redirected_transport
 
815
 
 
816
        try:
 
817
            transport, format = do_catching_redirections(find_format,
 
818
                                                         transport,
 
819
                                                         redirected)
 
820
        except errors.TooManyRedirections:
 
821
            raise errors.NotBranchError(base)
 
822
 
509
823
        BzrDir._check_supported(format, _unsupported)
510
824
        return format.open(transport, _found=True)
511
825
 
520
834
        raise NotImplementedError(self.open_branch)
521
835
 
522
836
    @staticmethod
523
 
    def open_containing(url):
 
837
    def open_containing(url, possible_transports=None):
524
838
        """Open an existing branch which contains url.
525
839
        
526
840
        :param url: url to search from.
527
841
        See open_containing_from_transport for more detail.
528
842
        """
529
 
        return BzrDir.open_containing_from_transport(get_transport(url))
 
843
        transport = get_transport(url, possible_transports)
 
844
        return BzrDir.open_containing_from_transport(transport)
530
845
    
531
846
    @staticmethod
532
847
    def open_containing_from_transport(a_transport):
533
 
        """Open an existing branch which contains a_transport.base
 
848
        """Open an existing branch which contains a_transport.base.
534
849
 
535
850
        This probes for a branch at a_transport, and searches upwards from there.
536
851
 
551
866
                return result, urlutils.unescape(a_transport.relpath(url))
552
867
            except errors.NotBranchError, e:
553
868
                pass
554
 
            new_t = a_transport.clone('..')
 
869
            try:
 
870
                new_t = a_transport.clone('..')
 
871
            except errors.InvalidURLJoin:
 
872
                # reached the root, whatever that may be
 
873
                raise errors.NotBranchError(path=url)
555
874
            if new_t.base == a_transport.base:
556
875
                # reached the root, whatever that may be
557
876
                raise errors.NotBranchError(path=url)
558
877
            a_transport = new_t
559
878
 
 
879
    def _get_tree_branch(self):
 
880
        """Return the branch and tree, if any, for this bzrdir.
 
881
 
 
882
        Return None for tree if not present or inaccessible.
 
883
        Raise NotBranchError if no branch is present.
 
884
        :return: (tree, branch)
 
885
        """
 
886
        try:
 
887
            tree = self.open_workingtree()
 
888
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
889
            tree = None
 
890
            branch = self.open_branch()
 
891
        else:
 
892
            branch = tree.branch
 
893
        return tree, branch
 
894
 
 
895
    @classmethod
 
896
    def open_tree_or_branch(klass, location):
 
897
        """Return the branch and working tree at a location.
 
898
 
 
899
        If there is no tree at the location, tree will be None.
 
900
        If there is no branch at the location, an exception will be
 
901
        raised
 
902
        :return: (tree, branch)
 
903
        """
 
904
        bzrdir = klass.open(location)
 
905
        return bzrdir._get_tree_branch()
 
906
 
560
907
    @classmethod
561
908
    def open_containing_tree_or_branch(klass, location):
562
909
        """Return the branch and working tree contained by a location.
568
915
        relpath is the portion of the path that is contained by the branch.
569
916
        """
570
917
        bzrdir, relpath = klass.open_containing(location)
571
 
        try:
572
 
            tree = bzrdir.open_workingtree()
573
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
574
 
            tree = None
575
 
            branch = bzrdir.open_branch()
576
 
        else:
577
 
            branch = tree.branch
 
918
        tree, branch = bzrdir._get_tree_branch()
578
919
        return tree, branch, relpath
579
920
 
 
921
    @classmethod
 
922
    def open_containing_tree_branch_or_repository(klass, location):
 
923
        """Return the working tree, branch and repo contained by a location.
 
924
 
 
925
        Returns (tree, branch, repository, relpath).
 
926
        If there is no tree containing the location, tree will be None.
 
927
        If there is no branch containing the location, branch will be None.
 
928
        If there is no repository containing the location, repository will be
 
929
        None.
 
930
        relpath is the portion of the path that is contained by the innermost
 
931
        BzrDir.
 
932
 
 
933
        If no tree, branch or repository is found, a NotBranchError is raised.
 
934
        """
 
935
        bzrdir, relpath = klass.open_containing(location)
 
936
        try:
 
937
            tree, branch = bzrdir._get_tree_branch()
 
938
        except errors.NotBranchError:
 
939
            try:
 
940
                repo = bzrdir.find_repository()
 
941
                return None, None, repo, relpath
 
942
            except (errors.NoRepositoryPresent):
 
943
                raise errors.NotBranchError(location)
 
944
        return tree, branch, branch.repository, relpath
 
945
 
580
946
    def open_repository(self, _unsupported=False):
581
947
        """Open the repository object at this BzrDir if one is present.
582
948
 
583
 
        This will not follow the Branch object pointer - its strictly a direct
 
949
        This will not follow the Branch object pointer - it's strictly a direct
584
950
        open facility. Most client code should use open_branch().repository to
585
951
        get at a repository.
586
952
 
587
 
        _unsupported is a private parameter, not part of the api.
 
953
        :param _unsupported: a private parameter, not part of the api.
588
954
        TODO: static convenience version of this?
589
955
        """
590
956
        raise NotImplementedError(self.open_repository)
591
957
 
592
 
    def open_workingtree(self, _unsupported=False):
 
958
    def open_workingtree(self, _unsupported=False,
 
959
                         recommend_upgrade=True, from_branch=None):
593
960
        """Open the workingtree object at this BzrDir if one is present.
594
 
        
595
 
        TODO: static convenience version of this?
 
961
 
 
962
        :param recommend_upgrade: Optional keyword parameter, when True (the
 
963
            default), emit through the ui module a recommendation that the user
 
964
            upgrade the working tree when the workingtree being opened is old
 
965
            (but still fully supported).
 
966
        :param from_branch: override bzrdir branch (for lightweight checkouts)
596
967
        """
597
968
        raise NotImplementedError(self.open_workingtree)
598
969
 
620
991
        workingtree and discards it, and that's somewhat expensive.) 
621
992
        """
622
993
        try:
623
 
            self.open_workingtree()
 
994
            self.open_workingtree(recommend_upgrade=False)
624
995
            return True
625
996
        except errors.NoWorkingTree:
626
997
            return False
627
998
 
628
 
    def cloning_metadir(self, basis=None):
629
 
        """Produce a metadir suitable for cloning with"""
630
 
        def related_repository(bzrdir):
631
 
            try:
632
 
                branch = bzrdir.open_branch()
633
 
                return branch.repository
634
 
            except errors.NotBranchError:
635
 
                source_branch = None
636
 
                return bzrdir.open_repository()
 
999
    def _cloning_metadir(self):
 
1000
        """Produce a metadir suitable for cloning with.
 
1001
        
 
1002
        :returns: (destination_bzrdir_format, source_repository)
 
1003
        """
637
1004
        result_format = self._format.__class__()
638
1005
        try:
639
1006
            try:
640
 
                source_repository = related_repository(self)
641
 
            except errors.NoRepositoryPresent:
642
 
                if basis is None:
643
 
                    raise
644
 
                source_repository = related_repository(self)
645
 
            result_format.repository_format = source_repository._format
 
1007
                branch = self.open_branch()
 
1008
                source_repository = branch.repository
 
1009
                result_format._branch_format = branch._format
 
1010
            except errors.NotBranchError:
 
1011
                source_branch = None
 
1012
                source_repository = self.open_repository()
646
1013
        except errors.NoRepositoryPresent:
647
 
            pass
648
 
        return result_format
649
 
 
650
 
    def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
 
1014
            source_repository = None
 
1015
        else:
 
1016
            # XXX TODO: This isinstance is here because we have not implemented
 
1017
            # the fix recommended in bug # 103195 - to delegate this choice the
 
1018
            # repository itself.
 
1019
            repo_format = source_repository._format
 
1020
            if isinstance(repo_format, remote.RemoteRepositoryFormat):
 
1021
                source_repository._ensure_real()
 
1022
                repo_format = source_repository._real_repository._format
 
1023
            result_format.repository_format = repo_format
 
1024
        try:
 
1025
            # TODO: Couldn't we just probe for the format in these cases,
 
1026
            # rather than opening the whole tree?  It would be a little
 
1027
            # faster. mbp 20070401
 
1028
            tree = self.open_workingtree(recommend_upgrade=False)
 
1029
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
1030
            result_format.workingtree_format = None
 
1031
        else:
 
1032
            result_format.workingtree_format = tree._format.__class__()
 
1033
        return result_format, source_repository
 
1034
 
 
1035
    def cloning_metadir(self, require_stacking=False):
 
1036
        """Produce a metadir suitable for cloning or sprouting with.
 
1037
 
 
1038
        These operations may produce workingtrees (yes, even though they're
 
1039
        "cloning" something that doesn't have a tree), so a viable workingtree
 
1040
        format must be selected.
 
1041
 
 
1042
        :require_stacking: If True, non-stackable formats will be upgraded
 
1043
            to similar stackable formats.
 
1044
        :returns: a BzrDirFormat with all component formats either set
 
1045
            appropriately or set to None if that component should not be
 
1046
            created.
 
1047
        """
 
1048
        format, repository = self._cloning_metadir()
 
1049
        if format._workingtree_format is None:
 
1050
            if repository is None:
 
1051
                return format
 
1052
            tree_format = repository._format._matchingbzrdir.workingtree_format
 
1053
            format.workingtree_format = tree_format.__class__()
 
1054
        if require_stacking:
 
1055
            format.require_stacking()
 
1056
        return format
 
1057
 
 
1058
    def checkout_metadir(self):
 
1059
        return self.cloning_metadir()
 
1060
 
 
1061
    def sprout(self, url, revision_id=None, force_new_repo=False,
 
1062
               recurse='down', possible_transports=None,
 
1063
               accelerator_tree=None, hardlink=False, stacked=False,
 
1064
               source_branch=None):
651
1065
        """Create a copy of this bzrdir prepared for use as a new line of
652
1066
        development.
653
1067
 
654
 
        If urls last component does not exist, it will be created.
 
1068
        If url's last component does not exist, it will be created.
655
1069
 
656
1070
        Attributes related to the identity of the source branch like
657
1071
        branch nickname will be cleaned, a working tree is created
660
1074
 
661
1075
        if revision_id is not None, then the clone operation may tune
662
1076
            itself to download less data.
 
1077
        :param accelerator_tree: A tree which can be used for retrieving file
 
1078
            contents more quickly than the revision tree, i.e. a workingtree.
 
1079
            The revision tree will be used for cases where accelerator_tree's
 
1080
            content is different.
 
1081
        :param hardlink: If true, hard-link files from accelerator_tree,
 
1082
            where possible.
 
1083
        :param stacked: If true, create a stacked branch referring to the
 
1084
            location of this control directory.
663
1085
        """
664
 
        self._make_tail(url)
665
 
        cloning_format = self.cloning_metadir(basis)
666
 
        result = cloning_format.initialize(url)
667
 
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
668
 
        try:
669
 
            source_branch = self.open_branch()
 
1086
        target_transport = get_transport(url, possible_transports)
 
1087
        target_transport.ensure_base()
 
1088
        cloning_format = self.cloning_metadir(stacked)
 
1089
        # Create/update the result branch
 
1090
        result = cloning_format.initialize_on_transport(target_transport)
 
1091
        # if a stacked branch wasn't requested, we don't create one
 
1092
        # even if the origin was stacked
 
1093
        stacked_branch_url = None
 
1094
        if source_branch is not None:
 
1095
            if stacked:
 
1096
                stacked_branch_url = self.root_transport.base
670
1097
            source_repository = source_branch.repository
671
 
        except errors.NotBranchError:
672
 
            source_branch = None
673
 
            try:
674
 
                source_repository = self.open_repository()
675
 
            except errors.NoRepositoryPresent:
676
 
                # copy the entire basis one if there is one
677
 
                # but there is no repository.
678
 
                source_repository = basis_repo
679
 
        if force_new_repo:
680
 
            result_repo = None
681
 
        else:
682
 
            try:
683
 
                result_repo = result.find_repository()
684
 
            except errors.NoRepositoryPresent:
685
 
                result_repo = None
686
 
        if source_repository is None and result_repo is not None:
687
 
            pass
688
 
        elif source_repository is None and result_repo is None:
689
 
            # no repo available, make a new one
690
 
            result.create_repository()
691
 
        elif source_repository is not None and result_repo is None:
692
 
            # have source, and want to make a new target repo
693
 
            # we don't clone the repo because that preserves attributes
694
 
            # like is_shared(), and we have not yet implemented a 
695
 
            # repository sprout().
696
 
            result_repo = result.create_repository()
697
 
        if result_repo is not None:
698
 
            # fetch needed content into target.
699
 
            if basis_repo:
700
 
                # XXX FIXME RBC 20060214 need tests for this when the basis
701
 
                # is incomplete
702
 
                result_repo.fetch(basis_repo, revision_id=revision_id)
703
 
            if source_repository is not None:
704
 
                result_repo.fetch(source_repository, revision_id=revision_id)
 
1098
        else:
 
1099
            try:
 
1100
                source_branch = self.open_branch()
 
1101
                source_repository = source_branch.repository
 
1102
                if stacked:
 
1103
                    stacked_branch_url = self.root_transport.base
 
1104
            except errors.NotBranchError:
 
1105
                source_branch = None
 
1106
                try:
 
1107
                    source_repository = self.open_repository()
 
1108
                except errors.NoRepositoryPresent:
 
1109
                    source_repository = None
 
1110
        repository_policy = result.determine_repository_policy(
 
1111
            force_new_repo, stacked_branch_url, require_stacking=stacked)
 
1112
        result_repo = repository_policy.acquire_repository()
 
1113
        if source_repository is not None:
 
1114
            # Fetch while stacked to prevent unstacked fetch from
 
1115
            # Branch.sprout.
 
1116
            result_repo.fetch(source_repository, revision_id=revision_id)
 
1117
 
 
1118
        if source_branch is None:
 
1119
            # this is for sprouting a bzrdir without a branch; is that
 
1120
            # actually useful?
 
1121
            # Not especially, but it's part of the contract.
 
1122
            result_branch = result.create_branch()
 
1123
        else:
 
1124
            # Force NULL revision to avoid using repository before stacking
 
1125
            # is configured.
 
1126
            result_branch = source_branch.sprout(
 
1127
                result, revision_id=_mod_revision.NULL_REVISION)
 
1128
            parent_location = result_branch.get_parent()
 
1129
        mutter("created new branch %r" % (result_branch,))
 
1130
        repository_policy.configure_branch(result_branch)
705
1131
        if source_branch is not None:
706
 
            source_branch.sprout(result, revision_id=revision_id)
707
 
        else:
708
 
            result.create_branch()
709
 
        # TODO: jam 20060426 we probably need a test in here in the
710
 
        #       case that the newly sprouted branch is a remote one
711
 
        if result_repo is None or result_repo.make_working_trees():
712
 
            wt = result.create_workingtree()
 
1132
            source_branch.copy_content_into(result_branch, revision_id)
 
1133
            # Override copy_content_into
 
1134
            result_branch.set_parent(parent_location)
 
1135
 
 
1136
        # Create/update the result working tree
 
1137
        if isinstance(target_transport, local.LocalTransport) and (
 
1138
            result_repo is None or result_repo.make_working_trees()):
 
1139
            wt = result.create_workingtree(accelerator_tree=accelerator_tree,
 
1140
                hardlink=hardlink)
713
1141
            wt.lock_write()
714
1142
            try:
715
1143
                if wt.path2id('') is None:
719
1147
                        pass
720
1148
            finally:
721
1149
                wt.unlock()
 
1150
        else:
 
1151
            wt = None
 
1152
        if recurse == 'down':
 
1153
            if wt is not None:
 
1154
                basis = wt.basis_tree()
 
1155
                basis.lock_read()
 
1156
                subtrees = basis.iter_references()
 
1157
            elif result_branch is not None:
 
1158
                basis = result_branch.basis_tree()
 
1159
                basis.lock_read()
 
1160
                subtrees = basis.iter_references()
 
1161
            elif source_branch is not None:
 
1162
                basis = source_branch.basis_tree()
 
1163
                basis.lock_read()
 
1164
                subtrees = basis.iter_references()
 
1165
            else:
 
1166
                subtrees = []
 
1167
                basis = None
 
1168
            try:
 
1169
                for path, file_id in subtrees:
 
1170
                    target = urlutils.join(url, urlutils.escape(path))
 
1171
                    sublocation = source_branch.reference_parent(file_id, path)
 
1172
                    sublocation.bzrdir.sprout(target,
 
1173
                        basis.get_reference_revision(file_id, path),
 
1174
                        force_new_repo=force_new_repo, recurse=recurse,
 
1175
                        stacked=stacked)
 
1176
            finally:
 
1177
                if basis is not None:
 
1178
                    basis.unlock()
722
1179
        return result
723
1180
 
724
1181
 
728
1185
    def __init__(self, _transport, _format):
729
1186
        """See BzrDir.__init__."""
730
1187
        super(BzrDirPreSplitOut, self).__init__(_transport, _format)
731
 
        assert self._format._lock_class == lockable_files.TransportLock
732
 
        assert self._format._lock_file_name == 'branch-lock'
733
1188
        self._control_files = lockable_files.LockableFiles(
734
1189
                                            self.get_branch_transport(None),
735
1190
                                            self._format._lock_file_name,
739
1194
        """Pre-splitout bzrdirs do not suffer from stale locks."""
740
1195
        raise NotImplementedError(self.break_lock)
741
1196
 
742
 
    def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
743
 
        """See BzrDir.clone()."""
744
 
        from bzrlib.workingtree import WorkingTreeFormat2
 
1197
    def cloning_metadir(self, require_stacking=False):
 
1198
        """Produce a metadir suitable for cloning with."""
 
1199
        if require_stacking:
 
1200
            return format_registry.make_bzrdir('1.6')
 
1201
        return self._format.__class__()
 
1202
 
 
1203
    def clone(self, url, revision_id=None, force_new_repo=False,
 
1204
              preserve_stacking=False):
 
1205
        """See BzrDir.clone().
 
1206
 
 
1207
        force_new_repo has no effect, since this family of formats always
 
1208
        require a new repository.
 
1209
        preserve_stacking has no effect, since no source branch using this
 
1210
        family of formats can be stacked, so there is no stacking to preserve.
 
1211
        """
745
1212
        self._make_tail(url)
746
1213
        result = self._format._initialize_for_clone(url)
747
 
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
748
 
        self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
 
1214
        self.open_repository().clone(result, revision_id=revision_id)
749
1215
        from_branch = self.open_branch()
750
1216
        from_branch.clone(result, revision_id=revision_id)
751
1217
        try:
752
 
            self.open_workingtree().clone(result, basis=basis_tree)
 
1218
            tree = self.open_workingtree()
753
1219
        except errors.NotLocalUrl:
754
1220
            # make a new one, this format always has to have one.
755
 
            try:
756
 
                WorkingTreeFormat2().initialize(result)
757
 
            except errors.NotLocalUrl:
758
 
                # but we cannot do it for remote trees.
759
 
                to_branch = result.open_branch()
760
 
                WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
 
1221
            result._init_workingtree()
 
1222
        else:
 
1223
            tree.clone(result)
761
1224
        return result
762
1225
 
763
1226
    def create_branch(self):
764
1227
        """See BzrDir.create_branch."""
765
 
        return self.open_branch()
 
1228
        return self._format.get_branch_format().initialize(self)
 
1229
 
 
1230
    def destroy_branch(self):
 
1231
        """See BzrDir.destroy_branch."""
 
1232
        raise errors.UnsupportedOperation(self.destroy_branch, self)
766
1233
 
767
1234
    def create_repository(self, shared=False):
768
1235
        """See BzrDir.create_repository."""
770
1237
            raise errors.IncompatibleFormat('shared repository', self._format)
771
1238
        return self.open_repository()
772
1239
 
773
 
    def create_workingtree(self, revision_id=None):
 
1240
    def destroy_repository(self):
 
1241
        """See BzrDir.destroy_repository."""
 
1242
        raise errors.UnsupportedOperation(self.destroy_repository, self)
 
1243
 
 
1244
    def create_workingtree(self, revision_id=None, from_branch=None,
 
1245
                           accelerator_tree=None, hardlink=False):
774
1246
        """See BzrDir.create_workingtree."""
 
1247
        # The workingtree is sometimes created when the bzrdir is created,
 
1248
        # but not when cloning.
 
1249
 
775
1250
        # this looks buggy but is not -really-
 
1251
        # because this format creates the workingtree when the bzrdir is
 
1252
        # created
776
1253
        # clone and sprout will have set the revision_id
777
1254
        # and that will have set it for us, its only
778
1255
        # specific uses of create_workingtree in isolation
779
1256
        # that can do wonky stuff here, and that only
780
1257
        # happens for creating checkouts, which cannot be 
781
1258
        # done on this format anyway. So - acceptable wart.
782
 
        result = self.open_workingtree()
 
1259
        try:
 
1260
            result = self.open_workingtree(recommend_upgrade=False)
 
1261
        except errors.NoSuchFile:
 
1262
            result = self._init_workingtree()
783
1263
        if revision_id is not None:
784
1264
            if revision_id == _mod_revision.NULL_REVISION:
785
1265
                result.set_parent_ids([])
787
1267
                result.set_parent_ids([revision_id])
788
1268
        return result
789
1269
 
 
1270
    def _init_workingtree(self):
 
1271
        from bzrlib.workingtree import WorkingTreeFormat2
 
1272
        try:
 
1273
            return WorkingTreeFormat2().initialize(self)
 
1274
        except errors.NotLocalUrl:
 
1275
            # Even though we can't access the working tree, we need to
 
1276
            # create its control files.
 
1277
            return WorkingTreeFormat2()._stub_initialize_on_transport(
 
1278
                self.transport, self._control_files._file_mode)
 
1279
 
790
1280
    def destroy_workingtree(self):
791
1281
        """See BzrDir.destroy_workingtree."""
792
1282
        raise errors.UnsupportedOperation(self.destroy_workingtree, self)
831
1321
        # if the format is not the same as the system default,
832
1322
        # an upgrade is needed.
833
1323
        if format is None:
 
1324
            symbol_versioning.warn(symbol_versioning.deprecated_in((1, 13, 0))
 
1325
                % 'needs_format_conversion(format=None)')
834
1326
            format = BzrDirFormat.get_default_format()
835
1327
        return not isinstance(self._format, format.__class__)
836
1328
 
841
1333
        self._check_supported(format, unsupported)
842
1334
        return format.open(self, _found=True)
843
1335
 
844
 
    def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
 
1336
    def sprout(self, url, revision_id=None, force_new_repo=False,
 
1337
               possible_transports=None, accelerator_tree=None,
 
1338
               hardlink=False, stacked=False):
845
1339
        """See BzrDir.sprout()."""
 
1340
        if stacked:
 
1341
            raise errors.UnstackableBranchFormat(
 
1342
                self._format, self.root_transport.base)
846
1343
        from bzrlib.workingtree import WorkingTreeFormat2
847
1344
        self._make_tail(url)
848
1345
        result = self._format._initialize_for_clone(url)
849
 
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
850
1346
        try:
851
 
            self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
 
1347
            self.open_repository().clone(result, revision_id=revision_id)
852
1348
        except errors.NoRepositoryPresent:
853
1349
            pass
854
1350
        try:
856
1352
        except errors.NotBranchError:
857
1353
            pass
858
1354
        # we always want a working tree
859
 
        WorkingTreeFormat2().initialize(result)
 
1355
        WorkingTreeFormat2().initialize(result,
 
1356
                                        accelerator_tree=accelerator_tree,
 
1357
                                        hardlink=hardlink)
860
1358
        return result
861
1359
 
862
1360
 
872
1370
 
873
1371
    def needs_format_conversion(self, format=None):
874
1372
        """Format 4 dirs are always in need of conversion."""
 
1373
        if format is None:
 
1374
            symbol_versioning.warn(symbol_versioning.deprecated_in((1, 13, 0))
 
1375
                % 'needs_format_conversion(format=None)')
875
1376
        return True
876
1377
 
877
1378
    def open_repository(self):
891
1392
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
892
1393
        return RepositoryFormat5().open(self, _found=True)
893
1394
 
894
 
    def open_workingtree(self, _unsupported=False):
 
1395
    def open_workingtree(self, _unsupported=False,
 
1396
            recommend_upgrade=True):
895
1397
        """See BzrDir.create_workingtree."""
896
1398
        from bzrlib.workingtree import WorkingTreeFormat2
897
 
        return WorkingTreeFormat2().open(self, _found=True)
 
1399
        wt_format = WorkingTreeFormat2()
 
1400
        # we don't warn here about upgrades; that ought to be handled for the
 
1401
        # bzrdir as a whole
 
1402
        return wt_format.open(self, _found=True)
898
1403
 
899
1404
 
900
1405
class BzrDir6(BzrDirPreSplitOut):
908
1413
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
909
1414
        return RepositoryFormat6().open(self, _found=True)
910
1415
 
911
 
    def open_workingtree(self, _unsupported=False):
 
1416
    def open_workingtree(self, _unsupported=False,
 
1417
        recommend_upgrade=True):
912
1418
        """See BzrDir.create_workingtree."""
 
1419
        # we don't warn here about upgrades; that ought to be handled for the
 
1420
        # bzrdir as a whole
913
1421
        from bzrlib.workingtree import WorkingTreeFormat2
914
1422
        return WorkingTreeFormat2().open(self, _found=True)
915
1423
 
931
1439
        """See BzrDir.create_branch."""
932
1440
        return self._format.get_branch_format().initialize(self)
933
1441
 
 
1442
    def destroy_branch(self):
 
1443
        """See BzrDir.create_branch."""
 
1444
        self.transport.delete_tree('branch')
 
1445
 
934
1446
    def create_repository(self, shared=False):
935
1447
        """See BzrDir.create_repository."""
936
1448
        return self._format.repository_format.initialize(self, shared)
937
1449
 
938
 
    def create_workingtree(self, revision_id=None):
 
1450
    def destroy_repository(self):
 
1451
        """See BzrDir.destroy_repository."""
 
1452
        self.transport.delete_tree('repository')
 
1453
 
 
1454
    def create_workingtree(self, revision_id=None, from_branch=None,
 
1455
                           accelerator_tree=None, hardlink=False):
939
1456
        """See BzrDir.create_workingtree."""
940
 
        from bzrlib.workingtree import WorkingTreeFormat
941
 
        return WorkingTreeFormat.get_default_format().initialize(self, revision_id)
 
1457
        return self._format.workingtree_format.initialize(
 
1458
            self, revision_id, from_branch=from_branch,
 
1459
            accelerator_tree=accelerator_tree, hardlink=hardlink)
942
1460
 
943
1461
    def destroy_workingtree(self):
944
1462
        """See BzrDir.destroy_workingtree."""
945
 
        wt = self.open_workingtree()
 
1463
        wt = self.open_workingtree(recommend_upgrade=False)
946
1464
        repository = wt.branch.repository
947
1465
        empty = repository.revision_tree(_mod_revision.NULL_REVISION)
948
 
        wt.revert([], old_tree=empty)
 
1466
        wt.revert(old_tree=empty)
949
1467
        self.destroy_workingtree_metadata()
950
1468
 
951
1469
    def destroy_workingtree_metadata(self):
952
1470
        self.transport.delete_tree('checkout')
953
1471
 
 
1472
    def find_branch_format(self):
 
1473
        """Find the branch 'format' for this bzrdir.
 
1474
 
 
1475
        This might be a synthetic object for e.g. RemoteBranch and SVN.
 
1476
        """
 
1477
        from bzrlib.branch import BranchFormat
 
1478
        return BranchFormat.find_format(self)
 
1479
 
954
1480
    def _get_mkdir_mode(self):
955
1481
        """Figure out the mode to use when creating a bzrdir subdir."""
956
1482
        temp_control = lockable_files.LockableFiles(self.transport, '',
957
1483
                                     lockable_files.TransportLock)
958
1484
        return temp_control._dir_mode
959
1485
 
 
1486
    def get_branch_reference(self):
 
1487
        """See BzrDir.get_branch_reference()."""
 
1488
        from bzrlib.branch import BranchFormat
 
1489
        format = BranchFormat.find_format(self)
 
1490
        return format.get_reference(self)
 
1491
 
960
1492
    def get_branch_transport(self, branch_format):
961
1493
        """See BzrDir.get_branch_transport()."""
962
1494
        if branch_format is None:
1002
1534
    def needs_format_conversion(self, format=None):
1003
1535
        """See BzrDir.needs_format_conversion()."""
1004
1536
        if format is None:
 
1537
            symbol_versioning.warn(symbol_versioning.deprecated_in((1, 13, 0))
 
1538
                % 'needs_format_conversion(format=None)')
 
1539
        if format is None:
1005
1540
            format = BzrDirFormat.get_default_format()
1006
1541
        if not isinstance(self._format, format.__class__):
1007
1542
            # it is not a meta dir format, conversion is needed.
1017
1552
        try:
1018
1553
            if not isinstance(self.open_branch()._format,
1019
1554
                              format.get_branch_format().__class__):
1020
 
                # the repository needs an upgrade.
 
1555
                # the branch needs an upgrade.
1021
1556
                return True
1022
1557
        except errors.NotBranchError:
1023
1558
            pass
1024
 
        # currently there are no other possible conversions for meta1 formats.
 
1559
        try:
 
1560
            my_wt = self.open_workingtree(recommend_upgrade=False)
 
1561
            if not isinstance(my_wt._format,
 
1562
                              format.workingtree_format.__class__):
 
1563
                # the workingtree needs an upgrade.
 
1564
                return True
 
1565
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
1566
            pass
1025
1567
        return False
1026
1568
 
1027
1569
    def open_branch(self, unsupported=False):
1028
1570
        """See BzrDir.open_branch."""
1029
 
        from bzrlib.branch import BranchFormat
1030
 
        format = BranchFormat.find_format(self)
 
1571
        format = self.find_branch_format()
1031
1572
        self._check_supported(format, unsupported)
1032
1573
        return format.open(self, _found=True)
1033
1574
 
1038
1579
        self._check_supported(format, unsupported)
1039
1580
        return format.open(self, _found=True)
1040
1581
 
1041
 
    def open_workingtree(self, unsupported=False):
 
1582
    def open_workingtree(self, unsupported=False,
 
1583
            recommend_upgrade=True):
1042
1584
        """See BzrDir.open_workingtree."""
1043
1585
        from bzrlib.workingtree import WorkingTreeFormat
1044
1586
        format = WorkingTreeFormat.find_format(self)
1045
 
        self._check_supported(format, unsupported)
 
1587
        self._check_supported(format, unsupported,
 
1588
            recommend_upgrade,
 
1589
            basedir=self.root_transport.base)
1046
1590
        return format.open(self, _found=True)
1047
1591
 
 
1592
    def _get_config(self):
 
1593
        return config.BzrDirConfig(self.transport)
 
1594
 
1048
1595
 
1049
1596
class BzrDirFormat(object):
1050
1597
    """An encapsulation of the initialization and open routines for a format.
1054
1601
     * a format string,
1055
1602
     * an open routine.
1056
1603
 
1057
 
    Formats are placed in an dict by their format string for reference 
 
1604
    Formats are placed in a dict by their format string for reference 
1058
1605
    during bzrdir opening. These should be subclasses of BzrDirFormat
1059
1606
    for consistency.
1060
1607
 
1075
1622
    This is a list of BzrDirFormat objects.
1076
1623
    """
1077
1624
 
 
1625
    _control_server_formats = []
 
1626
    """The registered control server formats, e.g. RemoteBzrDirs.
 
1627
 
 
1628
    This is a list of BzrDirFormat objects.
 
1629
    """
 
1630
 
1078
1631
    _lock_file_name = 'branch-lock'
1079
1632
 
1080
1633
    # _lock_class must be set in subclasses to the lock type, typ.
1081
1634
    # TransportLock or LockDir
1082
1635
 
1083
1636
    @classmethod
1084
 
    def find_format(klass, transport):
 
1637
    def find_format(klass, transport, _server_formats=True):
1085
1638
        """Return the format present at transport."""
1086
 
        for format in klass._control_formats:
 
1639
        if _server_formats:
 
1640
            formats = klass._control_server_formats + klass._control_formats
 
1641
        else:
 
1642
            formats = klass._control_formats
 
1643
        for format in formats:
1087
1644
            try:
1088
1645
                return format.probe_transport(transport)
1089
1646
            except errors.NotBranchError:
1093
1650
 
1094
1651
    @classmethod
1095
1652
    def probe_transport(klass, transport):
1096
 
        """Return the .bzrdir style transport present at URL."""
 
1653
        """Return the .bzrdir style format present in a directory."""
1097
1654
        try:
1098
1655
            format_string = transport.get(".bzr/branch-format").read()
1099
1656
        except errors.NoSuchFile:
1102
1659
        try:
1103
1660
            return klass._formats[format_string]
1104
1661
        except KeyError:
1105
 
            raise errors.UnknownFormatError(format=format_string)
 
1662
            raise errors.UnknownFormatError(format=format_string, kind='bzrdir')
1106
1663
 
1107
1664
    @classmethod
1108
1665
    def get_default_format(klass):
1131
1688
        """
1132
1689
        raise NotImplementedError(self.get_converter)
1133
1690
 
1134
 
    def initialize(self, url):
 
1691
    def initialize(self, url, possible_transports=None):
1135
1692
        """Create a bzr control dir at this url and return an opened copy.
1136
1693
        
1137
1694
        Subclasses should typically override initialize_on_transport
1138
1695
        instead of this method.
1139
1696
        """
1140
 
        return self.initialize_on_transport(get_transport(url))
 
1697
        return self.initialize_on_transport(get_transport(url,
 
1698
                                                          possible_transports))
1141
1699
 
1142
1700
    def initialize_on_transport(self, transport):
1143
1701
        """Initialize a new bzrdir in the base directory of a Transport."""
1149
1707
                                      # FIXME: RBC 20060121 don't peek under
1150
1708
                                      # the covers
1151
1709
                                      mode=temp_control._dir_mode)
 
1710
        if sys.platform == 'win32' and isinstance(transport, local.LocalTransport):
 
1711
            win32utils.set_file_attr_hidden(transport._abspath('.bzr'))
1152
1712
        file_mode = temp_control._file_mode
1153
1713
        del temp_control
1154
 
        mutter('created control directory in ' + transport.base)
1155
 
        control = transport.clone('.bzr')
1156
 
        utf8_files = [('README', 
1157
 
                       "This is a Bazaar-NG control directory.\n"
1158
 
                       "Do not change any files in this directory.\n"),
 
1714
        bzrdir_transport = transport.clone('.bzr')
 
1715
        utf8_files = [('README',
 
1716
                       "This is a Bazaar control directory.\n"
 
1717
                       "Do not change any files in this directory.\n"
 
1718
                       "See http://bazaar-vcs.org/ for more information about Bazaar.\n"),
1159
1719
                      ('branch-format', self.get_format_string()),
1160
1720
                      ]
1161
1721
        # NB: no need to escape relative paths that are url safe.
1162
 
        control_files = lockable_files.LockableFiles(control,
1163
 
                            self._lock_file_name, self._lock_class)
 
1722
        control_files = lockable_files.LockableFiles(bzrdir_transport,
 
1723
            self._lock_file_name, self._lock_class)
1164
1724
        control_files.create_lock()
1165
1725
        control_files.lock_write()
1166
1726
        try:
1167
 
            for file, content in utf8_files:
1168
 
                control_files.put_utf8(file, content)
 
1727
            for (filename, content) in utf8_files:
 
1728
                bzrdir_transport.put_bytes(filename, content,
 
1729
                    mode=file_mode)
1169
1730
        finally:
1170
1731
            control_files.unlock()
1171
1732
        return self.open(transport, _found=True)
1229
1790
 
1230
1791
    @classmethod
1231
1792
    def register_control_format(klass, format):
1232
 
        """Register a format that does not use '.bzrdir' for its control dir.
 
1793
        """Register a format that does not use '.bzr' for its control dir.
1233
1794
 
1234
1795
        TODO: This should be pulled up into a 'ControlDirFormat' base class
1235
1796
        which BzrDirFormat can inherit from, and renamed to register_format 
1239
1800
        klass._control_formats.append(format)
1240
1801
 
1241
1802
    @classmethod
1242
 
    @symbol_versioning.deprecated_method(symbol_versioning.zero_fourteen)
1243
 
    def set_default_format(klass, format):
1244
 
        klass._set_default_format(format)
 
1803
    def register_control_server_format(klass, format):
 
1804
        """Register a control format for client-server environments.
 
1805
 
 
1806
        These formats will be tried before ones registered with
 
1807
        register_control_format.  This gives implementations that decide to the
 
1808
        chance to grab it before anything looks at the contents of the format
 
1809
        file.
 
1810
        """
 
1811
        klass._control_server_formats.append(format)
1245
1812
 
1246
1813
    @classmethod
1247
1814
    def _set_default_format(klass, format):
1249
1816
        klass._default_format = format
1250
1817
 
1251
1818
    def __str__(self):
1252
 
        return self.get_format_string()[:-1]
 
1819
        # Trim the newline
 
1820
        return self.get_format_string().rstrip()
1253
1821
 
1254
1822
    @classmethod
1255
1823
    def unregister_format(klass, format):
1256
 
        assert klass._formats[format.get_format_string()] is format
1257
1824
        del klass._formats[format.get_format_string()]
1258
1825
 
1259
1826
    @classmethod
1261
1828
        klass._control_formats.remove(format)
1262
1829
 
1263
1830
 
1264
 
# register BzrDirFormat as a control format
1265
 
BzrDirFormat.register_control_format(BzrDirFormat)
1266
 
 
1267
 
 
1268
1831
class BzrDirFormat4(BzrDirFormat):
1269
1832
    """Bzr dir format 4.
1270
1833
 
1334
1897
        """See BzrDirFormat.get_format_string()."""
1335
1898
        return "Bazaar-NG branch, format 5\n"
1336
1899
 
 
1900
    def get_branch_format(self):
 
1901
        from bzrlib import branch
 
1902
        return branch.BzrBranchFormat4()
 
1903
 
1337
1904
    def get_format_description(self):
1338
1905
        """See BzrDirFormat.get_format_description()."""
1339
1906
        return "All-in-one format 5"
1353
1920
        """
1354
1921
        from bzrlib.branch import BzrBranchFormat4
1355
1922
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
1356
 
        from bzrlib.workingtree import WorkingTreeFormat2
1357
1923
        result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1358
1924
        RepositoryFormat5().initialize(result, _internal=True)
1359
1925
        if not _cloning:
1360
1926
            branch = BzrBranchFormat4().initialize(result)
1361
 
            try:
1362
 
                WorkingTreeFormat2().initialize(result)
1363
 
            except errors.NotLocalUrl:
1364
 
                # Even though we can't access the working tree, we need to
1365
 
                # create its control files.
1366
 
                WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
 
1927
            result._init_workingtree()
1367
1928
        return result
1368
1929
 
1369
1930
    def _open(self, transport):
1397
1958
        """See BzrDirFormat.get_format_description()."""
1398
1959
        return "All-in-one format 6"
1399
1960
 
 
1961
    def get_branch_format(self):
 
1962
        from bzrlib import branch
 
1963
        return branch.BzrBranchFormat4()
 
1964
 
1400
1965
    def get_converter(self, format=None):
1401
1966
        """See BzrDirFormat.get_converter()."""
1402
1967
        # there is one and only one upgrade path here.
1412
1977
        """
1413
1978
        from bzrlib.branch import BzrBranchFormat4
1414
1979
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
1415
 
        from bzrlib.workingtree import WorkingTreeFormat2
1416
1980
        result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1417
1981
        RepositoryFormat6().initialize(result, _internal=True)
1418
1982
        if not _cloning:
1419
1983
            branch = BzrBranchFormat4().initialize(result)
1420
 
            try:
1421
 
                WorkingTreeFormat2().initialize(result)
1422
 
            except errors.NotLocalUrl:
1423
 
                # Even though we can't access the working tree, we need to
1424
 
                # create its control files.
1425
 
                WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
 
1984
            result._init_workingtree()
1426
1985
        return result
1427
1986
 
1428
1987
    def _open(self, transport):
1450
2009
    _lock_class = lockdir.LockDir
1451
2010
 
1452
2011
    def __init__(self):
 
2012
        self._workingtree_format = None
1453
2013
        self._branch_format = None
1454
2014
 
 
2015
    def __eq__(self, other):
 
2016
        if other.__class__ is not self.__class__:
 
2017
            return False
 
2018
        if other.repository_format != self.repository_format:
 
2019
            return False
 
2020
        if other.workingtree_format != self.workingtree_format:
 
2021
            return False
 
2022
        return True
 
2023
 
 
2024
    def __ne__(self, other):
 
2025
        return not self == other
 
2026
 
1455
2027
    def get_branch_format(self):
1456
2028
        if self._branch_format is None:
1457
2029
            from bzrlib.branch import BranchFormat
1461
2033
    def set_branch_format(self, format):
1462
2034
        self._branch_format = format
1463
2035
 
 
2036
    def require_stacking(self):
 
2037
        if not self.get_branch_format().supports_stacking():
 
2038
            # We need to make a stacked branch, but the default format for the
 
2039
            # target doesn't support stacking.  So force a branch that *can*
 
2040
            # support stacking.
 
2041
            from bzrlib.branch import BzrBranchFormat7
 
2042
            self._branch_format = BzrBranchFormat7()
 
2043
            mutter("using %r for stacking" % (self._branch_format,))
 
2044
            from bzrlib.repofmt import pack_repo
 
2045
            if self.repository_format.rich_root_data:
 
2046
                bzrdir_format_name = '1.6.1-rich-root'
 
2047
                repo_format = pack_repo.RepositoryFormatKnitPack5RichRoot()
 
2048
            else:
 
2049
                bzrdir_format_name = '1.6'
 
2050
                repo_format = pack_repo.RepositoryFormatKnitPack5()
 
2051
            note('Source format does not support stacking, using format:'
 
2052
                 ' \'%s\'\n  %s\n',
 
2053
                 bzrdir_format_name, repo_format.get_format_description())
 
2054
            self.repository_format = repo_format
 
2055
 
1464
2056
    def get_converter(self, format=None):
1465
2057
        """See BzrDirFormat.get_converter()."""
1466
2058
        if format is None:
1490
2082
        return RepositoryFormat.get_default_format()
1491
2083
 
1492
2084
    def __set_repository_format(self, value):
1493
 
        """Allow changint the repository format for metadir formats."""
 
2085
        """Allow changing the repository format for metadir formats."""
1494
2086
        self._repository_format = value
1495
2087
 
1496
2088
    repository_format = property(__return_repository_format, __set_repository_format)
1497
2089
 
1498
 
 
 
2090
    def __get_workingtree_format(self):
 
2091
        if self._workingtree_format is None:
 
2092
            from bzrlib.workingtree import WorkingTreeFormat
 
2093
            self._workingtree_format = WorkingTreeFormat.get_default_format()
 
2094
        return self._workingtree_format
 
2095
 
 
2096
    def __set_workingtree_format(self, wt_format):
 
2097
        self._workingtree_format = wt_format
 
2098
 
 
2099
    workingtree_format = property(__get_workingtree_format,
 
2100
                                  __set_workingtree_format)
 
2101
 
 
2102
 
 
2103
# Register bzr control format
 
2104
BzrDirFormat.register_control_format(BzrDirFormat)
 
2105
 
 
2106
# Register bzr formats
1499
2107
BzrDirFormat.register_format(BzrDirFormat4())
1500
2108
BzrDirFormat.register_format(BzrDirFormat5())
1501
2109
BzrDirFormat.register_format(BzrDirFormat6())
1504
2112
BzrDirFormat._default_format = __default_format
1505
2113
 
1506
2114
 
1507
 
class BzrDirTestProviderAdapter(object):
1508
 
    """A tool to generate a suite testing multiple bzrdir formats at once.
1509
 
 
1510
 
    This is done by copying the test once for each transport and injecting
1511
 
    the transport_server, transport_readonly_server, and bzrdir_format
1512
 
    classes into each copy. Each copy is also given a new id() to make it
1513
 
    easy to identify.
1514
 
    """
1515
 
 
1516
 
    def __init__(self, transport_server, transport_readonly_server, formats):
1517
 
        self._transport_server = transport_server
1518
 
        self._transport_readonly_server = transport_readonly_server
1519
 
        self._formats = formats
1520
 
    
1521
 
    def adapt(self, test):
1522
 
        result = unittest.TestSuite()
1523
 
        for format in self._formats:
1524
 
            new_test = deepcopy(test)
1525
 
            new_test.transport_server = self._transport_server
1526
 
            new_test.transport_readonly_server = self._transport_readonly_server
1527
 
            new_test.bzrdir_format = format
1528
 
            def make_new_test_id():
1529
 
                new_id = "%s(%s)" % (new_test.id(), format.__class__.__name__)
1530
 
                return lambda: new_id
1531
 
            new_test.id = make_new_test_id()
1532
 
            result.addTest(new_test)
1533
 
        return result
1534
 
 
1535
 
 
1536
2115
class Converter(object):
1537
2116
    """Converts a disk format object from one format to another."""
1538
2117
 
1564
2143
        self.bzrdir = to_convert
1565
2144
        self.pb = pb
1566
2145
        self.pb.note('starting upgrade from format 4 to 5')
1567
 
        if isinstance(self.bzrdir.transport, LocalTransport):
 
2146
        if isinstance(self.bzrdir.transport, local.LocalTransport):
1568
2147
            self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
1569
2148
        self._convert_to_weaves()
1570
2149
        return BzrDir.open(self.bzrdir.root_transport.base)
1609
2188
        self.pb.note('  %6d revisions not present', len(self.absent_revisions))
1610
2189
        self.pb.note('  %6d texts', self.text_count)
1611
2190
        self._cleanup_spare_files_after_format4()
1612
 
        self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
 
2191
        self.branch._transport.put_bytes(
 
2192
            'branch-format',
 
2193
            BzrDirFormat5().get_format_string(),
 
2194
            mode=self.bzrdir._get_file_mode())
1613
2195
 
1614
2196
    def _cleanup_spare_files_after_format4(self):
1615
2197
        # FIXME working tree upgrade foo.
1624
2206
 
1625
2207
    def _convert_working_inv(self):
1626
2208
        inv = xml4.serializer_v4.read_inventory(
1627
 
                    self.branch.control_files.get('inventory'))
1628
 
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
1629
 
        # FIXME inventory is a working tree change.
1630
 
        self.branch.control_files.put('inventory', StringIO(new_inv_xml))
 
2209
                self.branch._transport.get('inventory'))
 
2210
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv, working=True)
 
2211
        self.branch._transport.put_bytes('inventory', new_inv_xml,
 
2212
            mode=self.bzrdir._get_file_mode())
1631
2213
 
1632
2214
    def _write_all_weaves(self):
1633
2215
        controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
1653
2235
        self.bzrdir.transport.mkdir('revision-store')
1654
2236
        revision_transport = self.bzrdir.transport.clone('revision-store')
1655
2237
        # TODO permissions
1656
 
        _revision_store = TextRevisionStore(TextStore(revision_transport,
1657
 
                                                      prefixed=False,
1658
 
                                                      compressed=True))
 
2238
        from bzrlib.xml5 import serializer_v5
 
2239
        from bzrlib.repofmt.weaverepo import RevisionTextStore
 
2240
        revision_store = RevisionTextStore(revision_transport,
 
2241
            serializer_v5, False, versionedfile.PrefixMapper(),
 
2242
            lambda:True, lambda:True)
1659
2243
        try:
1660
 
            transaction = WriteTransaction()
1661
2244
            for i, rev_id in enumerate(self.converted_revs):
1662
2245
                self.pb.update('write revision', i, len(self.converted_revs))
1663
 
                _revision_store.add_revision(self.revisions[rev_id], transaction)
 
2246
                text = serializer_v5.write_revision_to_string(
 
2247
                    self.revisions[rev_id])
 
2248
                key = (rev_id,)
 
2249
                revision_store.add_lines(key, None, osutils.split_lines(text))
1664
2250
        finally:
1665
2251
            self.pb.clear()
1666
2252
            
1679
2265
                         rev_id)
1680
2266
            self.absent_revisions.add(rev_id)
1681
2267
        else:
1682
 
            rev = self.branch.repository._revision_store.get_revision(rev_id,
1683
 
                self.branch.repository.get_transaction())
 
2268
            rev = self.branch.repository.get_revision(rev_id)
1684
2269
            for parent_id in rev.parent_ids:
1685
2270
                self.known_revisions.add(parent_id)
1686
2271
                self.to_read.append(parent_id)
1687
2272
            self.revisions[rev_id] = rev
1688
2273
 
1689
2274
    def _load_old_inventory(self, rev_id):
1690
 
        assert rev_id not in self.converted_revs
1691
2275
        old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
1692
2276
        inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
1693
2277
        inv.revision_id = rev_id
1694
2278
        rev = self.revisions[rev_id]
1695
 
        if rev.inventory_sha1:
1696
 
            assert rev.inventory_sha1 == sha_string(old_inv_xml), \
1697
 
                'inventory sha mismatch for {%s}' % rev_id
1698
2279
        return inv
1699
2280
 
1700
2281
    def _load_updated_inventory(self, rev_id):
1701
 
        assert rev_id in self.converted_revs
1702
2282
        inv_xml = self.inv_weave.get_text(rev_id)
1703
 
        inv = xml5.serializer_v5.read_inventory_from_string(inv_xml)
 
2283
        inv = xml5.serializer_v5.read_inventory_from_string(inv_xml, rev_id)
1704
2284
        return inv
1705
2285
 
1706
2286
    def _convert_one_rev(self, rev_id):
1710
2290
        present_parents = [p for p in rev.parent_ids
1711
2291
                           if p not in self.absent_revisions]
1712
2292
        self._convert_revision_contents(rev, inv, present_parents)
1713
 
        self._store_new_weave(rev, inv, present_parents)
 
2293
        self._store_new_inv(rev, inv, present_parents)
1714
2294
        self.converted_revs.add(rev_id)
1715
2295
 
1716
 
    def _store_new_weave(self, rev, inv, present_parents):
1717
 
        # the XML is now updated with text versions
1718
 
        if __debug__:
1719
 
            entries = inv.iter_entries()
1720
 
            entries.next()
1721
 
            for path, ie in entries:
1722
 
                assert getattr(ie, 'revision', None) is not None, \
1723
 
                    'no revision on {%s} in {%s}' % \
1724
 
                    (file_id, rev.revision_id)
 
2296
    def _store_new_inv(self, rev, inv, present_parents):
1725
2297
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
1726
2298
        new_inv_sha1 = sha_string(new_inv_xml)
1727
 
        self.inv_weave.add_lines(rev.revision_id, 
 
2299
        self.inv_weave.add_lines(rev.revision_id,
1728
2300
                                 present_parents,
1729
2301
                                 new_inv_xml.splitlines(True))
1730
2302
        rev.inventory_sha1 = new_inv_sha1
1755
2327
            w = Weave(file_id)
1756
2328
            self.text_weaves[file_id] = w
1757
2329
        text_changed = False
1758
 
        previous_entries = ie.find_previous_heads(parent_invs,
1759
 
                                                  None,
1760
 
                                                  None,
1761
 
                                                  entry_vf=w)
1762
 
        for old_revision in previous_entries:
1763
 
                # if this fails, its a ghost ?
1764
 
                assert old_revision in self.converted_revs, \
1765
 
                    "Revision {%s} not in converted_revs" % old_revision
 
2330
        parent_candiate_entries = ie.parent_candidates(parent_invs)
 
2331
        heads = graph.Graph(self).heads(parent_candiate_entries.keys())
 
2332
        # XXX: Note that this is unordered - and this is tolerable because 
 
2333
        # the previous code was also unordered.
 
2334
        previous_entries = dict((head, parent_candiate_entries[head]) for head
 
2335
            in heads)
1766
2336
        self.snapshot_ie(previous_entries, ie, w, rev_id)
1767
2337
        del ie.text_id
1768
 
        assert getattr(ie, 'revision', None) is not None
 
2338
 
 
2339
    @symbol_versioning.deprecated_method(symbol_versioning.one_one)
 
2340
    def get_parents(self, revision_ids):
 
2341
        for revision_id in revision_ids:
 
2342
            yield self.revisions[revision_id].parent_ids
 
2343
 
 
2344
    def get_parent_map(self, revision_ids):
 
2345
        """See graph._StackedParentsProvider.get_parent_map"""
 
2346
        return dict((revision_id, self.revisions[revision_id])
 
2347
                    for revision_id in revision_ids
 
2348
                     if revision_id in self.revisions)
1769
2349
 
1770
2350
    def snapshot_ie(self, previous_revisions, ie, w, rev_id):
1771
2351
        # TODO: convert this logic, which is ~= snapshot to
1781
2361
                ie.revision = previous_ie.revision
1782
2362
                return
1783
2363
        if ie.has_text():
1784
 
            text = self.branch.repository.text_store.get(ie.text_id)
 
2364
            text = self.branch.repository._text_store.get(ie.text_id)
1785
2365
            file_lines = text.readlines()
1786
 
            assert sha_strings(file_lines) == ie.text_sha1
1787
 
            assert sum(map(len, file_lines)) == ie.text_size
1788
2366
            w.add_lines(rev_id, previous_revisions, file_lines)
1789
2367
            self.text_count += 1
1790
2368
        else:
1837
2415
                if (filename.endswith(".weave") or
1838
2416
                    filename.endswith(".gz") or
1839
2417
                    filename.endswith(".sig")):
1840
 
                    file_id = os.path.splitext(filename)[0]
 
2418
                    file_id, suffix = os.path.splitext(filename)
1841
2419
                else:
1842
2420
                    file_id = filename
1843
 
                prefix_dir = store.hash_prefix(file_id)
 
2421
                    suffix = ''
 
2422
                new_name = store._mapper.map((file_id,)) + suffix
1844
2423
                # FIXME keep track of the dirs made RBC 20060121
1845
2424
                try:
1846
 
                    store_transport.move(filename, prefix_dir + '/' + filename)
 
2425
                    store_transport.move(filename, new_name)
1847
2426
                except errors.NoSuchFile: # catches missing dirs strangely enough
1848
 
                    store_transport.mkdir(prefix_dir)
1849
 
                    store_transport.move(filename, prefix_dir + '/' + filename)
1850
 
        self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
 
2427
                    store_transport.mkdir(osutils.dirname(new_name))
 
2428
                    store_transport.move(filename, new_name)
 
2429
        self.bzrdir.transport.put_bytes(
 
2430
            'branch-format',
 
2431
            BzrDirFormat6().get_format_string(),
 
2432
            mode=self.bzrdir._get_file_mode())
1851
2433
 
1852
2434
 
1853
2435
class ConvertBzrDir6ToMeta(Converter):
1862
2444
        self.count = 0
1863
2445
        self.total = 20 # the steps we know about
1864
2446
        self.garbage_inventories = []
 
2447
        self.dir_mode = self.bzrdir._get_dir_mode()
 
2448
        self.file_mode = self.bzrdir._get_file_mode()
1865
2449
 
1866
2450
        self.pb.note('starting upgrade from format 6 to metadir')
1867
 
        self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
 
2451
        self.bzrdir.transport.put_bytes(
 
2452
                'branch-format',
 
2453
                "Converting to format 6",
 
2454
                mode=self.file_mode)
1868
2455
        # its faster to move specific files around than to open and use the apis...
1869
2456
        # first off, nuke ancestry.weave, it was never used.
1870
2457
        try:
1880
2467
            if name.startswith('basis-inventory.'):
1881
2468
                self.garbage_inventories.append(name)
1882
2469
        # create new directories for repository, working tree and branch
1883
 
        self.dir_mode = self.bzrdir._control_files._dir_mode
1884
 
        self.file_mode = self.bzrdir._control_files._file_mode
1885
2470
        repository_names = [('inventory.weave', True),
1886
2471
                            ('revision-store', True),
1887
2472
                            ('weaves', True)]
1935
2520
            for entry in checkout_files:
1936
2521
                self.move_entry('checkout', entry)
1937
2522
            if last_revision is not None:
1938
 
                self.bzrdir._control_files.put_utf8(
 
2523
                self.bzrdir.transport.put_bytes(
1939
2524
                    'checkout/last-revision', last_revision)
1940
 
        self.bzrdir._control_files.put_utf8(
1941
 
            'branch-format', BzrDirMetaFormat1().get_format_string())
 
2525
        self.bzrdir.transport.put_bytes(
 
2526
            'branch-format',
 
2527
            BzrDirMetaFormat1().get_format_string(),
 
2528
            mode=self.file_mode)
1942
2529
        return BzrDir.open(self.bzrdir.root_transport.base)
1943
2530
 
1944
2531
    def make_lock(self, name):
1962
2549
                raise
1963
2550
 
1964
2551
    def put_format(self, dirname, format):
1965
 
        self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
 
2552
        self.bzrdir.transport.put_bytes('%s/format' % dirname,
 
2553
            format.get_format_string(),
 
2554
            self.file_mode)
1966
2555
 
1967
2556
 
1968
2557
class ConvertMetaToMeta(Converter):
1997
2586
        except errors.NotBranchError:
1998
2587
            pass
1999
2588
        else:
 
2589
            # TODO: conversions of Branch and Tree should be done by
 
2590
            # InterXFormat lookups/some sort of registry.
2000
2591
            # Avoid circular imports
2001
2592
            from bzrlib import branch as _mod_branch
2002
 
            if (branch._format.__class__ is _mod_branch.BzrBranchFormat5 and
2003
 
                self.target_format.get_branch_format().__class__ is
2004
 
                _mod_branch.BzrBranchFormat6):
2005
 
                branch_converter = _mod_branch.Converter5to6()
 
2593
            old = branch._format.__class__
 
2594
            new = self.target_format.get_branch_format().__class__
 
2595
            while old != new:
 
2596
                if (old == _mod_branch.BzrBranchFormat5 and
 
2597
                    new in (_mod_branch.BzrBranchFormat6,
 
2598
                        _mod_branch.BzrBranchFormat7)):
 
2599
                    branch_converter = _mod_branch.Converter5to6()
 
2600
                elif (old == _mod_branch.BzrBranchFormat6 and
 
2601
                    new == _mod_branch.BzrBranchFormat7):
 
2602
                    branch_converter = _mod_branch.Converter6to7()
 
2603
                else:
 
2604
                    raise errors.BadConversionTarget("No converter", new)
2006
2605
                branch_converter.convert(branch)
 
2606
                branch = self.bzrdir.open_branch()
 
2607
                old = branch._format.__class__
 
2608
        try:
 
2609
            tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
 
2610
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
2611
            pass
 
2612
        else:
 
2613
            # TODO: conversions of Branch and Tree should be done by
 
2614
            # InterXFormat lookups
 
2615
            if (isinstance(tree, workingtree.WorkingTree3) and
 
2616
                not isinstance(tree, workingtree_4.DirStateWorkingTree) and
 
2617
                isinstance(self.target_format.workingtree_format,
 
2618
                    workingtree_4.DirStateWorkingTreeFormat)):
 
2619
                workingtree_4.Converter3to4().convert(tree)
 
2620
            if (isinstance(tree, workingtree_4.DirStateWorkingTree) and
 
2621
                not isinstance(tree, workingtree_4.WorkingTree5) and
 
2622
                isinstance(self.target_format.workingtree_format,
 
2623
                    workingtree_4.WorkingTreeFormat5)):
 
2624
                workingtree_4.Converter4to5().convert(tree)
2007
2625
        return to_convert
2008
2626
 
2009
2627
 
 
2628
# This is not in remote.py because it's small, and needs to be registered.
 
2629
# Putting it in remote.py creates a circular import problem.
 
2630
# we can make it a lazy object if the control formats is turned into something
 
2631
# like a registry.
 
2632
class RemoteBzrDirFormat(BzrDirMetaFormat1):
 
2633
    """Format representing bzrdirs accessed via a smart server"""
 
2634
 
 
2635
    def get_format_description(self):
 
2636
        return 'bzr remote bzrdir'
 
2637
    
 
2638
    @classmethod
 
2639
    def probe_transport(klass, transport):
 
2640
        """Return a RemoteBzrDirFormat object if it looks possible."""
 
2641
        try:
 
2642
            medium = transport.get_smart_medium()
 
2643
        except (NotImplementedError, AttributeError,
 
2644
                errors.TransportNotPossible, errors.NoSmartMedium,
 
2645
                errors.SmartProtocolError):
 
2646
            # no smart server, so not a branch for this format type.
 
2647
            raise errors.NotBranchError(path=transport.base)
 
2648
        else:
 
2649
            # Decline to open it if the server doesn't support our required
 
2650
            # version (3) so that the VFS-based transport will do it.
 
2651
            if medium.should_probe():
 
2652
                try:
 
2653
                    server_version = medium.protocol_version()
 
2654
                except errors.SmartProtocolError:
 
2655
                    # Apparently there's no usable smart server there, even though
 
2656
                    # the medium supports the smart protocol.
 
2657
                    raise errors.NotBranchError(path=transport.base)
 
2658
                if server_version != '2':
 
2659
                    raise errors.NotBranchError(path=transport.base)
 
2660
            return klass()
 
2661
 
 
2662
    def initialize_on_transport(self, transport):
 
2663
        try:
 
2664
            # hand off the request to the smart server
 
2665
            client_medium = transport.get_smart_medium()
 
2666
        except errors.NoSmartMedium:
 
2667
            # TODO: lookup the local format from a server hint.
 
2668
            local_dir_format = BzrDirMetaFormat1()
 
2669
            return local_dir_format.initialize_on_transport(transport)
 
2670
        client = _SmartClient(client_medium)
 
2671
        path = client.remote_path_from_transport(transport)
 
2672
        response = client.call('BzrDirFormat.initialize', path)
 
2673
        if response[0] != 'ok':
 
2674
            raise errors.SmartProtocolError('unexpected response code %s' % (response,))
 
2675
        return remote.RemoteBzrDir(transport)
 
2676
 
 
2677
    def _open(self, transport):
 
2678
        return remote.RemoteBzrDir(transport)
 
2679
 
 
2680
    def __eq__(self, other):
 
2681
        if not isinstance(other, RemoteBzrDirFormat):
 
2682
            return False
 
2683
        return self.get_format_description() == other.get_format_description()
 
2684
 
 
2685
    @property
 
2686
    def repository_format(self):
 
2687
        # Using a property to avoid early loading of remote
 
2688
        return remote.RemoteRepositoryFormat()
 
2689
 
 
2690
 
 
2691
BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)
 
2692
 
 
2693
 
2010
2694
class BzrDirFormatInfo(object):
2011
2695
 
2012
 
    def __init__(self, native, deprecated):
 
2696
    def __init__(self, native, deprecated, hidden, experimental):
2013
2697
        self.deprecated = deprecated
2014
2698
        self.native = native
 
2699
        self.hidden = hidden
 
2700
        self.experimental = experimental
2015
2701
 
2016
2702
 
2017
2703
class BzrDirFormatRegistry(registry.Registry):
2021
2707
    e.g. BzrDirMeta1 with weave repository.  Also, it's more user-oriented.
2022
2708
    """
2023
2709
 
2024
 
    def register_metadir(self, key, repo, help, native=True, deprecated=False,
2025
 
                         branch_format=None):
 
2710
    def __init__(self):
 
2711
        """Create a BzrDirFormatRegistry."""
 
2712
        self._aliases = set()
 
2713
        self._registration_order = list()
 
2714
        super(BzrDirFormatRegistry, self).__init__()
 
2715
 
 
2716
    def aliases(self):
 
2717
        """Return a set of the format names which are aliases."""
 
2718
        return frozenset(self._aliases)
 
2719
 
 
2720
    def register_metadir(self, key,
 
2721
             repository_format, help, native=True, deprecated=False,
 
2722
             branch_format=None,
 
2723
             tree_format=None,
 
2724
             hidden=False,
 
2725
             experimental=False,
 
2726
             alias=False):
2026
2727
        """Register a metadir subformat.
2027
2728
 
2028
2729
        These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2029
2730
        by the Repository format.
2030
2731
 
2031
 
        :param repo: The fully-qualified repository format class name as a
2032
 
        string.
 
2732
        :param repository_format: The fully-qualified repository format class
 
2733
            name as a string.
 
2734
        :param branch_format: Fully-qualified branch format class name as
 
2735
            a string.
 
2736
        :param tree_format: Fully-qualified tree format class name as
 
2737
            a string.
2033
2738
        """
2034
2739
        # This should be expanded to support setting WorkingTree and Branch
2035
2740
        # formats, once BzrDirMetaFormat1 supports that.
2036
 
        def helper():
2037
 
            import bzrlib.branch
2038
 
            mod_name, repo_factory_name = repo.rsplit('.', 1)
 
2741
        def _load(full_name):
 
2742
            mod_name, factory_name = full_name.rsplit('.', 1)
2039
2743
            try:
2040
2744
                mod = __import__(mod_name, globals(), locals(),
2041
 
                        [repo_factory_name])
 
2745
                        [factory_name])
2042
2746
            except ImportError, e:
2043
 
                raise ImportError('failed to load repository %s: %s'
2044
 
                    % (repo, e))
 
2747
                raise ImportError('failed to load %s: %s' % (full_name, e))
2045
2748
            try:
2046
 
                repo_format_class = getattr(mod, repo_factory_name)
 
2749
                factory = getattr(mod, factory_name)
2047
2750
            except AttributeError:
2048
 
                raise AttributeError('no repository format %r in module %r' 
2049
 
                    % (repo, mod))
 
2751
                raise AttributeError('no factory %s in module %r'
 
2752
                    % (full_name, mod))
 
2753
            return factory()
 
2754
 
 
2755
        def helper():
2050
2756
            bd = BzrDirMetaFormat1()
2051
 
            bd.repository_format = repo_format_class()
2052
2757
            if branch_format is not None:
2053
 
                bd.set_branch_format(getattr(bzrlib.branch, branch_format)())
 
2758
                bd.set_branch_format(_load(branch_format))
 
2759
            if tree_format is not None:
 
2760
                bd.workingtree_format = _load(tree_format)
 
2761
            if repository_format is not None:
 
2762
                bd.repository_format = _load(repository_format)
2054
2763
            return bd
2055
 
        self.register(key, helper, help, native, deprecated)
 
2764
        self.register(key, helper, help, native, deprecated, hidden,
 
2765
            experimental, alias)
2056
2766
 
2057
 
    def register(self, key, factory, help, native=True, deprecated=False):
 
2767
    def register(self, key, factory, help, native=True, deprecated=False,
 
2768
                 hidden=False, experimental=False, alias=False):
2058
2769
        """Register a BzrDirFormat factory.
2059
2770
        
2060
2771
        The factory must be a callable that takes one parameter: the key.
2063
2774
        This function mainly exists to prevent the info object from being
2064
2775
        supplied directly.
2065
2776
        """
2066
 
        registry.Registry.register(self, key, factory, help, 
2067
 
            BzrDirFormatInfo(native, deprecated))
 
2777
        registry.Registry.register(self, key, factory, help,
 
2778
            BzrDirFormatInfo(native, deprecated, hidden, experimental))
 
2779
        if alias:
 
2780
            self._aliases.add(key)
 
2781
        self._registration_order.append(key)
2068
2782
 
2069
2783
    def register_lazy(self, key, module_name, member_name, help, native=True,
2070
 
                      deprecated=False):
2071
 
        registry.Registry.register_lazy(self, key, module_name, member_name, 
2072
 
            help, BzrDirFormatInfo(native, deprecated))
 
2784
        deprecated=False, hidden=False, experimental=False, alias=False):
 
2785
        registry.Registry.register_lazy(self, key, module_name, member_name,
 
2786
            help, BzrDirFormatInfo(native, deprecated, hidden, experimental))
 
2787
        if alias:
 
2788
            self._aliases.add(key)
 
2789
        self._registration_order.append(key)
2073
2790
 
2074
2791
    def set_default(self, key):
2075
2792
        """Set the 'default' key to be a clone of the supplied key.
2076
2793
        
2077
2794
        This method must be called once and only once.
2078
2795
        """
2079
 
        registry.Registry.register(self, 'default', self.get(key), 
 
2796
        registry.Registry.register(self, 'default', self.get(key),
2080
2797
            self.get_help(key), info=self.get_info(key))
 
2798
        self._aliases.add('default')
2081
2799
 
2082
2800
    def set_default_repository(self, key):
2083
2801
        """Set the FormatRegistry default and Repository default.
2089
2807
            self.remove('default')
2090
2808
        self.set_default(key)
2091
2809
        format = self.get('default')()
2092
 
        assert isinstance(format, BzrDirMetaFormat1)
2093
2810
 
2094
2811
    def make_bzrdir(self, key):
2095
2812
        return self.get(key)()
2096
2813
 
2097
2814
    def help_topic(self, topic):
2098
 
        output = textwrap.dedent("""\
2099
 
            Bazaar directory formats
2100
 
            ------------------------
2101
 
 
2102
 
            These formats can be used for creating branches, working trees, and
2103
 
            repositories.
2104
 
 
2105
 
            """)
 
2815
        output = ""
 
2816
        default_realkey = None
2106
2817
        default_help = self.get_help('default')
2107
2818
        help_pairs = []
2108
 
        for key in self.keys():
 
2819
        for key in self._registration_order:
2109
2820
            if key == 'default':
2110
2821
                continue
2111
2822
            help = self.get_help(key)
2117
2828
        def wrapped(key, help, info):
2118
2829
            if info.native:
2119
2830
                help = '(native) ' + help
2120
 
            return '  %s:\n%s\n\n' % (key, 
 
2831
            return ':%s:\n%s\n\n' % (key, 
2121
2832
                    textwrap.fill(help, initial_indent='    ', 
2122
2833
                    subsequent_indent='    '))
2123
 
        output += wrapped('%s/default' % default_realkey, default_help,
2124
 
                          self.get_info('default'))
 
2834
        if default_realkey is not None:
 
2835
            output += wrapped(default_realkey, '(default) %s' % default_help,
 
2836
                              self.get_info('default'))
2125
2837
        deprecated_pairs = []
 
2838
        experimental_pairs = []
2126
2839
        for key, help in help_pairs:
2127
2840
            info = self.get_info(key)
2128
 
            if info.deprecated:
 
2841
            if info.hidden:
 
2842
                continue
 
2843
            elif info.deprecated:
2129
2844
                deprecated_pairs.append((key, help))
 
2845
            elif info.experimental:
 
2846
                experimental_pairs.append((key, help))
2130
2847
            else:
2131
2848
                output += wrapped(key, help, info)
 
2849
        output += "\nSee ``bzr help formats`` for more about storage formats."
 
2850
        other_output = ""
 
2851
        if len(experimental_pairs) > 0:
 
2852
            other_output += "Experimental formats are shown below.\n\n"
 
2853
            for key, help in experimental_pairs:
 
2854
                info = self.get_info(key)
 
2855
                other_output += wrapped(key, help, info)
 
2856
        else:
 
2857
            other_output += \
 
2858
                "No experimental formats are available.\n\n"
2132
2859
        if len(deprecated_pairs) > 0:
2133
 
            output += "Deprecated formats\n------------------\n\n"
 
2860
            other_output += "\nDeprecated formats are shown below.\n\n"
2134
2861
            for key, help in deprecated_pairs:
2135
2862
                info = self.get_info(key)
2136
 
                output += wrapped(key, help, info)
2137
 
 
2138
 
        return output
2139
 
 
2140
 
 
 
2863
                other_output += wrapped(key, help, info)
 
2864
        else:
 
2865
            other_output += \
 
2866
                "\nNo deprecated formats are available.\n\n"
 
2867
        other_output += \
 
2868
            "\nSee ``bzr help formats`` for more about storage formats."
 
2869
 
 
2870
        if topic == 'other-formats':
 
2871
            return other_output
 
2872
        else:
 
2873
            return output
 
2874
 
 
2875
 
 
2876
class RepositoryAcquisitionPolicy(object):
 
2877
    """Abstract base class for repository acquisition policies.
 
2878
 
 
2879
    A repository acquisition policy decides how a BzrDir acquires a repository
 
2880
    for a branch that is being created.  The most basic policy decision is
 
2881
    whether to create a new repository or use an existing one.
 
2882
    """
 
2883
    def __init__(self, stack_on, stack_on_pwd, require_stacking):
 
2884
        """Constructor.
 
2885
 
 
2886
        :param stack_on: A location to stack on
 
2887
        :param stack_on_pwd: If stack_on is relative, the location it is
 
2888
            relative to.
 
2889
        :param require_stacking: If True, it is a failure to not stack.
 
2890
        """
 
2891
        self._stack_on = stack_on
 
2892
        self._stack_on_pwd = stack_on_pwd
 
2893
        self._require_stacking = require_stacking
 
2894
 
 
2895
    def configure_branch(self, branch):
 
2896
        """Apply any configuration data from this policy to the branch.
 
2897
 
 
2898
        Default implementation sets repository stacking.
 
2899
        """
 
2900
        if self._stack_on is None:
 
2901
            return
 
2902
        if self._stack_on_pwd is None:
 
2903
            stack_on = self._stack_on
 
2904
        else:
 
2905
            try:
 
2906
                stack_on = urlutils.rebase_url(self._stack_on,
 
2907
                    self._stack_on_pwd,
 
2908
                    branch.bzrdir.root_transport.base)
 
2909
            except errors.InvalidRebaseURLs:
 
2910
                stack_on = self._get_full_stack_on()
 
2911
        try:
 
2912
            branch.set_stacked_on_url(stack_on)
 
2913
        except errors.UnstackableBranchFormat:
 
2914
            if self._require_stacking:
 
2915
                raise
 
2916
 
 
2917
    def _get_full_stack_on(self):
 
2918
        """Get a fully-qualified URL for the stack_on location."""
 
2919
        if self._stack_on is None:
 
2920
            return None
 
2921
        if self._stack_on_pwd is None:
 
2922
            return self._stack_on
 
2923
        else:
 
2924
            return urlutils.join(self._stack_on_pwd, self._stack_on)
 
2925
 
 
2926
    def _add_fallback(self, repository, possible_transports=None):
 
2927
        """Add a fallback to the supplied repository, if stacking is set."""
 
2928
        stack_on = self._get_full_stack_on()
 
2929
        if stack_on is None:
 
2930
            return
 
2931
        stacked_dir = BzrDir.open(stack_on,
 
2932
                                  possible_transports=possible_transports)
 
2933
        try:
 
2934
            stacked_repo = stacked_dir.open_branch().repository
 
2935
        except errors.NotBranchError:
 
2936
            stacked_repo = stacked_dir.open_repository()
 
2937
        try:
 
2938
            repository.add_fallback_repository(stacked_repo)
 
2939
        except errors.UnstackableRepositoryFormat:
 
2940
            if self._require_stacking:
 
2941
                raise
 
2942
        else:
 
2943
            self._require_stacking = True
 
2944
 
 
2945
    def acquire_repository(self, make_working_trees=None, shared=False):
 
2946
        """Acquire a repository for this bzrdir.
 
2947
 
 
2948
        Implementations may create a new repository or use a pre-exising
 
2949
        repository.
 
2950
        :param make_working_trees: If creating a repository, set
 
2951
            make_working_trees to this value (if non-None)
 
2952
        :param shared: If creating a repository, make it shared if True
 
2953
        :return: A repository
 
2954
        """
 
2955
        raise NotImplemented(RepositoryAcquisitionPolicy.acquire_repository)
 
2956
 
 
2957
 
 
2958
class CreateRepository(RepositoryAcquisitionPolicy):
 
2959
    """A policy of creating a new repository"""
 
2960
 
 
2961
    def __init__(self, bzrdir, stack_on=None, stack_on_pwd=None,
 
2962
                 require_stacking=False):
 
2963
        """
 
2964
        Constructor.
 
2965
        :param bzrdir: The bzrdir to create the repository on.
 
2966
        :param stack_on: A location to stack on
 
2967
        :param stack_on_pwd: If stack_on is relative, the location it is
 
2968
            relative to.
 
2969
        """
 
2970
        RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
 
2971
                                             require_stacking)
 
2972
        self._bzrdir = bzrdir
 
2973
 
 
2974
    def acquire_repository(self, make_working_trees=None, shared=False):
 
2975
        """Implementation of RepositoryAcquisitionPolicy.acquire_repository
 
2976
 
 
2977
        Creates the desired repository in the bzrdir we already have.
 
2978
        """
 
2979
        repository = self._bzrdir.create_repository(shared=shared)
 
2980
        self._add_fallback(repository,
 
2981
                           possible_transports=[self._bzrdir.transport])
 
2982
        if make_working_trees is not None:
 
2983
            repository.set_make_working_trees(make_working_trees)
 
2984
        return repository
 
2985
 
 
2986
 
 
2987
class UseExistingRepository(RepositoryAcquisitionPolicy):
 
2988
    """A policy of reusing an existing repository"""
 
2989
 
 
2990
    def __init__(self, repository, stack_on=None, stack_on_pwd=None,
 
2991
                 require_stacking=False):
 
2992
        """Constructor.
 
2993
 
 
2994
        :param repository: The repository to use.
 
2995
        :param stack_on: A location to stack on
 
2996
        :param stack_on_pwd: If stack_on is relative, the location it is
 
2997
            relative to.
 
2998
        """
 
2999
        RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
 
3000
                                             require_stacking)
 
3001
        self._repository = repository
 
3002
 
 
3003
    def acquire_repository(self, make_working_trees=None, shared=False):
 
3004
        """Implementation of RepositoryAcquisitionPolicy.acquire_repository
 
3005
 
 
3006
        Returns an existing repository to use
 
3007
        """
 
3008
        self._add_fallback(self._repository,
 
3009
                       possible_transports=[self._repository.bzrdir.transport])
 
3010
        return self._repository
 
3011
 
 
3012
 
 
3013
# Please register new formats after old formats so that formats
 
3014
# appear in chronological order and format descriptions can build
 
3015
# on previous ones.
2141
3016
format_registry = BzrDirFormatRegistry()
2142
3017
format_registry.register('weave', BzrDirFormat6,
2143
3018
    'Pre-0.8 format.  Slower than knit and does not'
2144
3019
    ' support checkouts or shared repositories.',
2145
3020
    deprecated=True)
2146
 
format_registry.register_metadir('knit',
2147
 
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2148
 
    'Format using knits.  Recommended.',
2149
 
    branch_format='BzrBranchFormat5')
2150
 
format_registry.set_default('knit')
2151
3021
format_registry.register_metadir('metaweave',
2152
3022
    'bzrlib.repofmt.weaverepo.RepositoryFormat7',
2153
3023
    'Transitional format in 0.8.  Slower than knit.',
2154
 
    deprecated=True,
2155
 
    )
2156
 
format_registry.register_metadir('experimental-knit2',
2157
 
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit2',
2158
 
    'Experimental successor to knit.  Use at your own risk.',
2159
 
    branch_format='BzrBranchFormat5')
2160
 
format_registry.register_metadir('experimental-branch6',
2161
 
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2162
 
    'Experimental successor to knit.  Use at your own risk.',
2163
 
    branch_format='BzrBranchFormat6')
 
3024
    branch_format='bzrlib.branch.BzrBranchFormat5',
 
3025
    tree_format='bzrlib.workingtree.WorkingTreeFormat3',
 
3026
    deprecated=True)
 
3027
format_registry.register_metadir('knit',
 
3028
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
 
3029
    'Format using knits.  Recommended for interoperation with bzr <= 0.14.',
 
3030
    branch_format='bzrlib.branch.BzrBranchFormat5',
 
3031
    tree_format='bzrlib.workingtree.WorkingTreeFormat3',
 
3032
    deprecated=True)
 
3033
format_registry.register_metadir('dirstate',
 
3034
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
 
3035
    help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
 
3036
        'above when accessed over the network.',
 
3037
    branch_format='bzrlib.branch.BzrBranchFormat5',
 
3038
    # this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
 
3039
    # directly from workingtree_4 triggers a circular import.
 
3040
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3041
    deprecated=True)
 
3042
format_registry.register_metadir('dirstate-tags',
 
3043
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
 
3044
    help='New in 0.15: Fast local operations and improved scaling for '
 
3045
        'network operations. Additionally adds support for tags.'
 
3046
        ' Incompatible with bzr < 0.15.',
 
3047
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
3048
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3049
    deprecated=True)
 
3050
format_registry.register_metadir('rich-root',
 
3051
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit4',
 
3052
    help='New in 1.0.  Better handling of tree roots.  Incompatible with'
 
3053
        ' bzr < 1.0.',
 
3054
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
3055
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3056
    deprecated=True)
 
3057
format_registry.register_metadir('dirstate-with-subtree',
 
3058
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
 
3059
    help='New in 0.15: Fast local operations and improved scaling for '
 
3060
        'network operations. Additionally adds support for versioning nested '
 
3061
        'bzr branches. Incompatible with bzr < 0.15.',
 
3062
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
3063
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3064
    experimental=True,
 
3065
    hidden=True,
 
3066
    )
 
3067
format_registry.register_metadir('pack-0.92',
 
3068
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack1',
 
3069
    help='New in 0.92: Pack-based format with data compatible with '
 
3070
        'dirstate-tags format repositories. Interoperates with '
 
3071
        'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
 
3072
        'Previously called knitpack-experimental.  '
 
3073
        'For more information, see '
 
3074
        'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
 
3075
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
3076
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3077
    )
 
3078
format_registry.register_metadir('pack-0.92-subtree',
 
3079
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack3',
 
3080
    help='New in 0.92: Pack-based format with data compatible with '
 
3081
        'dirstate-with-subtree format repositories. Interoperates with '
 
3082
        'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
 
3083
        'Previously called knitpack-experimental.  '
 
3084
        'For more information, see '
 
3085
        'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
 
3086
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
3087
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3088
    hidden=True,
 
3089
    experimental=True,
 
3090
    )
 
3091
format_registry.register_metadir('rich-root-pack',
 
3092
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack4',
 
3093
    help='New in 1.0: A variant of pack-0.92 that supports rich-root data '
 
3094
         '(needed for bzr-svn).',
 
3095
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
3096
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3097
    )
 
3098
format_registry.register_metadir('1.6',
 
3099
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack5',
 
3100
    help='A format that allows a branch to indicate that there is another '
 
3101
         '(stacked) repository that should be used to access data that is '
 
3102
         'not present locally.',
 
3103
    branch_format='bzrlib.branch.BzrBranchFormat7',
 
3104
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3105
    )
 
3106
format_registry.register_metadir('1.6.1-rich-root',
 
3107
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack5RichRoot',
 
3108
    help='A variant of 1.6 that supports rich-root data '
 
3109
         '(needed for bzr-svn).',
 
3110
    branch_format='bzrlib.branch.BzrBranchFormat7',
 
3111
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3112
    )
 
3113
format_registry.register_metadir('1.9',
 
3114
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6',
 
3115
    help='A repository format using B+tree indexes. These indexes '
 
3116
         'are smaller in size, have smarter caching and provide faster '
 
3117
         'performance for most operations.',
 
3118
    branch_format='bzrlib.branch.BzrBranchFormat7',
 
3119
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3120
    )
 
3121
format_registry.register_metadir('1.9-rich-root',
 
3122
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6RichRoot',
 
3123
    help='A variant of 1.9 that supports rich-root data '
 
3124
         '(needed for bzr-svn).',
 
3125
    branch_format='bzrlib.branch.BzrBranchFormat7',
 
3126
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3127
    )
 
3128
format_registry.register_metadir('1.12-preview',
 
3129
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6',
 
3130
    help='A working-tree format that supports views and content filtering.',
 
3131
    branch_format='bzrlib.branch.BzrBranchFormat7',
 
3132
    tree_format='bzrlib.workingtree_4.WorkingTreeFormat5',
 
3133
    experimental=True,
 
3134
    )
 
3135
format_registry.register_metadir('1.12-preview-rich-root',
 
3136
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6RichRoot',
 
3137
    help='A variant of 1.12-preview that supports rich-root data '
 
3138
         '(needed for bzr-svn).',
 
3139
    branch_format='bzrlib.branch.BzrBranchFormat7',
 
3140
    tree_format='bzrlib.workingtree_4.WorkingTreeFormat5',
 
3141
    experimental=True,
 
3142
    )
 
3143
# The following two formats should always just be aliases.
 
3144
format_registry.register_metadir('development',
 
3145
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment2',
 
3146
    help='Current development format. Can convert data to and from pack-0.92 '
 
3147
        '(and anything compatible with pack-0.92) format repositories. '
 
3148
        'Repositories and branches in this format can only be read by bzr.dev. '
 
3149
        'Please read '
 
3150
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
 
3151
        'before use.',
 
3152
    branch_format='bzrlib.branch.BzrBranchFormat7',
 
3153
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3154
    experimental=True,
 
3155
    alias=True,
 
3156
    )
 
3157
format_registry.register_metadir('development-subtree',
 
3158
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment2Subtree',
 
3159
    help='Current development format, subtree variant. Can convert data to and '
 
3160
        'from pack-0.92-subtree (and anything compatible with '
 
3161
        'pack-0.92-subtree) format repositories. Repositories and branches in '
 
3162
        'this format can only be read by bzr.dev. Please read '
 
3163
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
 
3164
        'before use.',
 
3165
    branch_format='bzrlib.branch.BzrBranchFormat7',
 
3166
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3167
    experimental=True,
 
3168
    alias=True,
 
3169
    )
 
3170
# And the development formats above will have aliased one of the following:
 
3171
format_registry.register_metadir('development2',
 
3172
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment2',
 
3173
    help='1.6.1 with B+Tree based index. '
 
3174
        'Please read '
 
3175
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
 
3176
        'before use.',
 
3177
    branch_format='bzrlib.branch.BzrBranchFormat7',
 
3178
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3179
    hidden=True,
 
3180
    experimental=True,
 
3181
    )
 
3182
format_registry.register_metadir('development2-subtree',
 
3183
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment2Subtree',
 
3184
    help='1.6.1-subtree with B+Tree based index. '
 
3185
        'Please read '
 
3186
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
 
3187
        'before use.',
 
3188
    branch_format='bzrlib.branch.BzrBranchFormat7',
 
3189
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3190
    hidden=True,
 
3191
    experimental=True,
 
3192
    )
 
3193
# The current format that is made on 'bzr init'.
 
3194
format_registry.set_default('pack-0.92')