~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2008-03-16 16:58:03 UTC
  • mfrom: (3224.3.1 news-typo)
  • Revision ID: pqm@pqm.ubuntu.com-20080316165803-tisoc9mpob9z544o
(Matt Nordhoff) Trivial NEWS typo fix

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2011 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007 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
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
"""BzrDir logic. The BzrDir is the basic control directory used by bzr.
18
18
 
25
25
objects returned.
26
26
"""
27
27
 
 
28
# TODO: Move old formats into a plugin to make this file smaller.
 
29
 
 
30
from cStringIO import StringIO
 
31
import os
28
32
import sys
29
33
 
30
34
from bzrlib.lazy_import import lazy_import
31
35
lazy_import(globals(), """
 
36
from stat import S_ISDIR
 
37
import textwrap
 
38
from warnings import warn
 
39
 
32
40
import bzrlib
33
41
from bzrlib import (
34
 
    branch as _mod_branch,
35
 
    cleanup,
36
42
    errors,
37
 
    fetch,
38
43
    graph,
39
44
    lockable_files,
40
45
    lockdir,
41
 
    osutils,
42
 
    pyutils,
 
46
    registry,
43
47
    remote,
44
 
    repository,
45
48
    revision as _mod_revision,
46
 
    transport as _mod_transport,
 
49
    symbol_versioning,
47
50
    ui,
48
51
    urlutils,
49
52
    win32utils,
50
 
    workingtree_3,
 
53
    workingtree,
51
54
    workingtree_4,
52
 
    )
53
 
from bzrlib.repofmt import knitpack_repo
 
55
    xml4,
 
56
    xml5,
 
57
    )
 
58
from bzrlib.osutils import (
 
59
    sha_strings,
 
60
    sha_string,
 
61
    )
 
62
from bzrlib.smart.client import _SmartClient
 
63
from bzrlib.smart import protocol
 
64
from bzrlib.store.revision.text import TextRevisionStore
 
65
from bzrlib.store.text import TextStore
 
66
from bzrlib.store.versioned import WeaveStore
 
67
from bzrlib.transactions import WriteTransaction
54
68
from bzrlib.transport import (
55
69
    do_catching_redirections,
56
 
    local,
 
70
    get_transport,
57
71
    )
58
 
from bzrlib.i18n import gettext
 
72
from bzrlib.weave import Weave
59
73
""")
60
74
 
61
75
from bzrlib.trace import (
62
76
    mutter,
63
77
    note,
64
78
    )
65
 
 
66
 
from bzrlib import (
67
 
    config,
68
 
    controldir,
69
 
    registry,
70
 
    )
 
79
from bzrlib.transport.local import LocalTransport
71
80
from bzrlib.symbol_versioning import (
72
 
    deprecated_in,
 
81
    deprecated_function,
73
82
    deprecated_method,
 
83
    zero_ninetyone,
74
84
    )
75
85
 
76
86
 
77
 
class BzrDir(controldir.ControlDir):
 
87
class BzrDir(object):
78
88
    """A .bzr control diretory.
79
 
 
 
89
    
80
90
    BzrDir instances let you create or open any of the things that can be
81
91
    found within .bzr - checkouts, branches and repositories.
82
 
 
83
 
    :ivar transport:
 
92
    
 
93
    transport
84
94
        the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
85
 
    :ivar root_transport:
 
95
    root_transport
86
96
        a transport connected to the directory this bzr was opened from
87
97
        (i.e. the parent directory holding the .bzr directory).
88
 
 
89
 
    Everything in the bzrdir should have the same file permissions.
90
 
 
91
 
    :cvar hooks: An instance of BzrDirHooks.
92
98
    """
93
99
 
94
100
    def break_lock(self):
111
117
                    return
112
118
        thing_to_unlock.break_lock()
113
119
 
 
120
    def can_convert_format(self):
 
121
        """Return true if this bzrdir is one whose format we can convert from."""
 
122
        return True
 
123
 
114
124
    def check_conversion_target(self, target_format):
115
 
        """Check that a bzrdir as a whole can be converted to a new format."""
116
 
        # The only current restriction is that the repository content can be 
117
 
        # fetched compatibly with the target.
118
125
        target_repo_format = target_format.repository_format
119
 
        try:
120
 
            self.open_repository()._format.check_conversion_target(
121
 
                target_repo_format)
122
 
        except errors.NoRepositoryPresent:
123
 
            # No repo, no problem.
124
 
            pass
 
126
        source_repo_format = self._format.repository_format
 
127
        source_repo_format.check_conversion_target(target_repo_format)
 
128
 
 
129
    @staticmethod
 
130
    def _check_supported(format, allow_unsupported,
 
131
        recommend_upgrade=True,
 
132
        basedir=None):
 
133
        """Give an error or warning on old formats.
 
134
 
 
135
        :param format: may be any kind of format - workingtree, branch, 
 
136
        or repository.
 
137
 
 
138
        :param allow_unsupported: If true, allow opening 
 
139
        formats that are strongly deprecated, and which may 
 
140
        have limited functionality.
 
141
 
 
142
        :param recommend_upgrade: If true (default), warn
 
143
        the user through the ui object that they may wish
 
144
        to upgrade the object.
 
145
        """
 
146
        # TODO: perhaps move this into a base Format class; it's not BzrDir
 
147
        # specific. mbp 20070323
 
148
        if not allow_unsupported and not format.is_supported():
 
149
            # see open_downlevel to open legacy branches.
 
150
            raise errors.UnsupportedFormatError(format=format)
 
151
        if recommend_upgrade \
 
152
            and getattr(format, 'upgrade_recommended', False):
 
153
            ui.ui_factory.recommend_upgrade(
 
154
                format.get_format_description(),
 
155
                basedir)
 
156
 
 
157
    def clone(self, url, revision_id=None, force_new_repo=False):
 
158
        """Clone this bzrdir and its contents to url verbatim.
 
159
 
 
160
        If url's last component does not exist, it will be created.
 
161
 
 
162
        if revision_id is not None, then the clone operation may tune
 
163
            itself to download less data.
 
164
        :param force_new_repo: Do not use a shared repository for the target 
 
165
                               even if one is available.
 
166
        """
 
167
        return self.clone_on_transport(get_transport(url),
 
168
                                       revision_id=revision_id,
 
169
                                       force_new_repo=force_new_repo)
125
170
 
126
171
    def clone_on_transport(self, transport, revision_id=None,
127
 
        force_new_repo=False, preserve_stacking=False, stacked_on=None,
128
 
        create_prefix=False, use_existing_dir=True, no_tree=False):
 
172
                           force_new_repo=False):
129
173
        """Clone this bzrdir and its contents to transport verbatim.
130
174
 
131
 
        :param transport: The transport for the location to produce the clone
132
 
            at.  If the target directory does not exist, it will be created.
133
 
        :param revision_id: The tip revision-id to use for any branch or
134
 
            working tree.  If not None, then the clone operation may tune
 
175
        If the target directory does not exist, it will be created.
 
176
 
 
177
        if revision_id is not None, then the clone operation may tune
135
178
            itself to download less data.
136
 
        :param force_new_repo: Do not use a shared repository for the target,
 
179
        :param force_new_repo: Do not use a shared repository for the target 
137
180
                               even if one is available.
138
 
        :param preserve_stacking: When cloning a stacked branch, stack the
139
 
            new branch on top of the other branch's stacked-on branch.
140
 
        :param create_prefix: Create any missing directories leading up to
141
 
            to_transport.
142
 
        :param use_existing_dir: Use an existing directory if one exists.
143
 
        :param no_tree: If set to true prevents creation of a working tree.
144
181
        """
145
 
        # Overview: put together a broad description of what we want to end up
146
 
        # with; then make as few api calls as possible to do it.
147
 
 
148
 
        # We may want to create a repo/branch/tree, if we do so what format
149
 
        # would we want for each:
150
 
        require_stacking = (stacked_on is not None)
151
 
        format = self.cloning_metadir(require_stacking)
152
 
 
153
 
        # Figure out what objects we want:
 
182
        transport.ensure_base()
 
183
        result = self._format.initialize_on_transport(transport)
154
184
        try:
155
185
            local_repo = self.find_repository()
156
186
        except errors.NoRepositoryPresent:
157
187
            local_repo = None
158
 
        try:
159
 
            local_branch = self.open_branch()
160
 
        except errors.NotBranchError:
161
 
            local_branch = None
162
 
        else:
163
 
            # enable fallbacks when branch is not a branch reference
164
 
            if local_branch.repository.has_same_location(local_repo):
165
 
                local_repo = local_branch.repository
166
 
            if preserve_stacking:
167
 
                try:
168
 
                    stacked_on = local_branch.get_stacked_on_url()
169
 
                except (errors.UnstackableBranchFormat,
170
 
                        errors.UnstackableRepositoryFormat,
171
 
                        errors.NotStacked):
172
 
                    pass
173
 
        # Bug: We create a metadir without knowing if it can support stacking,
174
 
        # we should look up the policy needs first, or just use it as a hint,
175
 
        # or something.
176
188
        if local_repo:
177
 
            make_working_trees = local_repo.make_working_trees() and not no_tree
178
 
            want_shared = local_repo.is_shared()
179
 
            repo_format_name = format.repository_format.network_name()
180
 
        else:
181
 
            make_working_trees = False
182
 
            want_shared = False
183
 
            repo_format_name = None
184
 
 
185
 
        result_repo, result, require_stacking, repository_policy = \
186
 
            format.initialize_on_transport_ex(transport,
187
 
            use_existing_dir=use_existing_dir, create_prefix=create_prefix,
188
 
            force_new_repo=force_new_repo, stacked_on=stacked_on,
189
 
            stack_on_pwd=self.root_transport.base,
190
 
            repo_format_name=repo_format_name,
191
 
            make_working_trees=make_working_trees, shared_repo=want_shared)
192
 
        if repo_format_name:
193
 
            try:
194
 
                # If the result repository is in the same place as the
195
 
                # resulting bzr dir, it will have no content, further if the
196
 
                # result is not stacked then we know all content should be
197
 
                # copied, and finally if we are copying up to a specific
198
 
                # revision_id then we can use the pending-ancestry-result which
199
 
                # does not require traversing all of history to describe it.
200
 
                if (result_repo.user_url == result.user_url
201
 
                    and not require_stacking and
202
 
                    revision_id is not None):
203
 
                    fetch_spec = graph.PendingAncestryResult(
204
 
                        [revision_id], local_repo)
205
 
                    result_repo.fetch(local_repo, fetch_spec=fetch_spec)
206
 
                else:
 
189
            # may need to copy content in
 
190
            if force_new_repo:
 
191
                result_repo = local_repo.clone(
 
192
                    result,
 
193
                    revision_id=revision_id)
 
194
                result_repo.set_make_working_trees(local_repo.make_working_trees())
 
195
            else:
 
196
                try:
 
197
                    result_repo = result.find_repository()
 
198
                    # fetch content this dir needs.
207
199
                    result_repo.fetch(local_repo, revision_id=revision_id)
208
 
            finally:
209
 
                result_repo.unlock()
210
 
        else:
211
 
            if result_repo is not None:
212
 
                raise AssertionError('result_repo not None(%r)' % result_repo)
 
200
                except errors.NoRepositoryPresent:
 
201
                    # needed to make one anyway.
 
202
                    result_repo = local_repo.clone(
 
203
                        result,
 
204
                        revision_id=revision_id)
 
205
                    result_repo.set_make_working_trees(local_repo.make_working_trees())
213
206
        # 1 if there is a branch present
214
207
        #   make sure its content is available in the target repository
215
208
        #   clone it.
216
 
        if local_branch is not None:
217
 
            result_branch = local_branch.clone(result, revision_id=revision_id,
218
 
                repository_policy=repository_policy)
219
209
        try:
220
 
            # Cheaper to check if the target is not local, than to try making
221
 
            # the tree and fail.
222
 
            result.root_transport.local_abspath('.')
223
 
            if result_repo is None or result_repo.make_working_trees():
224
 
                self.open_workingtree().clone(result, revision_id=revision_id)
225
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
210
            self.open_branch().clone(result, revision_id=revision_id)
 
211
        except errors.NotBranchError:
226
212
            pass
 
213
        try:
 
214
            result_repo = result.find_repository()
 
215
        except errors.NoRepositoryPresent:
 
216
            result_repo = None
 
217
        if result_repo is None or result_repo.make_working_trees():
 
218
            try:
 
219
                self.open_workingtree().clone(result)
 
220
            except (errors.NoWorkingTree, errors.NotLocalUrl):
 
221
                pass
227
222
        return result
228
223
 
229
224
    # TODO: This should be given a Transport, and should chdir up; otherwise
230
225
    # this will open a new connection.
231
226
    def _make_tail(self, url):
232
 
        t = _mod_transport.get_transport(url)
233
 
        t.ensure_base()
234
 
 
235
 
    def determine_repository_policy(self, force_new_repo=False, stack_on=None,
236
 
                                    stack_on_pwd=None, require_stacking=False):
237
 
        """Return an object representing a policy to use.
238
 
 
239
 
        This controls whether a new repository is created, and the format of
240
 
        that repository, or some existing shared repository used instead.
241
 
 
242
 
        If stack_on is supplied, will not seek a containing shared repo.
243
 
 
244
 
        :param force_new_repo: If True, require a new repository to be created.
245
 
        :param stack_on: If supplied, the location to stack on.  If not
246
 
            supplied, a default_stack_on location may be used.
247
 
        :param stack_on_pwd: If stack_on is relative, the location it is
248
 
            relative to.
249
 
        """
250
 
        def repository_policy(found_bzrdir):
251
 
            stack_on = None
252
 
            stack_on_pwd = None
253
 
            config = found_bzrdir.get_config()
254
 
            stop = False
255
 
            stack_on = config.get_default_stack_on()
256
 
            if stack_on is not None:
257
 
                stack_on_pwd = found_bzrdir.user_url
258
 
                stop = True
259
 
            # does it have a repository ?
260
 
            try:
261
 
                repository = found_bzrdir.open_repository()
 
227
        t = get_transport(url)
 
228
        t.ensure_base()
 
229
 
 
230
    @classmethod
 
231
    def create(cls, base, format=None, possible_transports=None):
 
232
        """Create a new BzrDir at the url 'base'.
 
233
        
 
234
        :param format: If supplied, the format of branch to create.  If not
 
235
            supplied, the default is used.
 
236
        :param possible_transports: If supplied, a list of transports that 
 
237
            can be reused to share a remote connection.
 
238
        """
 
239
        if cls is not BzrDir:
 
240
            raise AssertionError("BzrDir.create always creates the default"
 
241
                " format, not one of %r" % cls)
 
242
        t = get_transport(base, possible_transports)
 
243
        t.ensure_base()
 
244
        if format is None:
 
245
            format = BzrDirFormat.get_default_format()
 
246
        return format.initialize_on_transport(t)
 
247
 
 
248
    @staticmethod
 
249
    def find_bzrdirs(transport, evaluate=None, list_current=None):
 
250
        """Find bzrdirs recursively from current location.
 
251
 
 
252
        This is intended primarily as a building block for more sophisticated
 
253
        functionality, like finding trees under a directory, or finding
 
254
        branches that use a given repository.
 
255
        :param evaluate: An optional callable that yields recurse, value,
 
256
            where recurse controls whether this bzrdir is recursed into
 
257
            and value is the value to yield.  By default, all bzrdirs
 
258
            are recursed into, and the return value is the bzrdir.
 
259
        :param list_current: if supplied, use this function to list the current
 
260
            directory, instead of Transport.list_dir
 
261
        :return: a generator of found bzrdirs, or whatever evaluate returns.
 
262
        """
 
263
        if list_current is None:
 
264
            def list_current(transport):
 
265
                return transport.list_dir('')
 
266
        if evaluate is None:
 
267
            def evaluate(bzrdir):
 
268
                return True, bzrdir
 
269
 
 
270
        pending = [transport]
 
271
        while len(pending) > 0:
 
272
            current_transport = pending.pop()
 
273
            recurse = True
 
274
            try:
 
275
                bzrdir = BzrDir.open_from_transport(current_transport)
 
276
            except errors.NotBranchError:
 
277
                pass
 
278
            else:
 
279
                recurse, value = evaluate(bzrdir)
 
280
                yield value
 
281
            try:
 
282
                subdirs = list_current(current_transport)
 
283
            except errors.NoSuchFile:
 
284
                continue
 
285
            if recurse:
 
286
                for subdir in sorted(subdirs, reverse=True):
 
287
                    pending.append(current_transport.clone(subdir))
 
288
 
 
289
    @staticmethod
 
290
    def find_branches(transport):
 
291
        """Find all branches under a transport.
 
292
 
 
293
        This will find all branches below the transport, including branches
 
294
        inside other branches.  Where possible, it will use
 
295
        Repository.find_branches.
 
296
 
 
297
        To list all the branches that use a particular Repository, see
 
298
        Repository.find_branches
 
299
        """
 
300
        def evaluate(bzrdir):
 
301
            try:
 
302
                repository = bzrdir.open_repository()
262
303
            except errors.NoRepositoryPresent:
263
 
                repository = None
264
 
            else:
265
 
                if (found_bzrdir.user_url != self.user_url 
266
 
                    and not repository.is_shared()):
267
 
                    # Don't look higher, can't use a higher shared repo.
268
 
                    repository = None
269
 
                    stop = True
270
 
                else:
271
 
                    stop = True
272
 
            if not stop:
273
 
                return None, False
274
 
            if repository:
275
 
                return UseExistingRepository(repository, stack_on,
276
 
                    stack_on_pwd, require_stacking=require_stacking), True
277
 
            else:
278
 
                return CreateRepository(self, stack_on, stack_on_pwd,
279
 
                    require_stacking=require_stacking), True
280
 
 
281
 
        if not force_new_repo:
282
 
            if stack_on is None:
283
 
                policy = self._find_containing(repository_policy)
284
 
                if policy is not None:
285
 
                    return policy
286
 
            else:
287
 
                try:
288
 
                    return UseExistingRepository(self.open_repository(),
289
 
                        stack_on, stack_on_pwd,
290
 
                        require_stacking=require_stacking)
291
 
                except errors.NoRepositoryPresent:
292
 
                    pass
293
 
        return CreateRepository(self, stack_on, stack_on_pwd,
294
 
                                require_stacking=require_stacking)
 
304
                pass
 
305
            else:
 
306
                return False, (None, repository)
 
307
            try:
 
308
                branch = bzrdir.open_branch()
 
309
            except errors.NotBranchError:
 
310
                return True, (None, None)
 
311
            else:
 
312
                return True, (branch, None)
 
313
        branches = []
 
314
        for branch, repo in BzrDir.find_bzrdirs(transport, evaluate=evaluate):
 
315
            if repo is not None:
 
316
                branches.extend(repo.find_branches())
 
317
            if branch is not None:
 
318
                branches.append(branch)
 
319
        return branches
 
320
 
 
321
 
 
322
    def destroy_repository(self):
 
323
        """Destroy the repository in this BzrDir"""
 
324
        raise NotImplementedError(self.destroy_repository)
 
325
 
 
326
    def create_branch(self):
 
327
        """Create a branch in this BzrDir.
 
328
 
 
329
        The bzrdir's format will control what branch format is created.
 
330
        For more control see BranchFormatXX.create(a_bzrdir).
 
331
        """
 
332
        raise NotImplementedError(self.create_branch)
 
333
 
 
334
    def destroy_branch(self):
 
335
        """Destroy the branch in this BzrDir"""
 
336
        raise NotImplementedError(self.destroy_branch)
 
337
 
 
338
    @staticmethod
 
339
    def create_branch_and_repo(base, force_new_repo=False, format=None):
 
340
        """Create a new BzrDir, Branch and Repository at the url 'base'.
 
341
 
 
342
        This will use the current default BzrDirFormat unless one is
 
343
        specified, and use whatever 
 
344
        repository format that that uses via bzrdir.create_branch and
 
345
        create_repository. If a shared repository is available that is used
 
346
        preferentially.
 
347
 
 
348
        The created Branch object is returned.
 
349
 
 
350
        :param base: The URL to create the branch at.
 
351
        :param force_new_repo: If True a new repository is always created.
 
352
        :param format: If supplied, the format of branch to create.  If not
 
353
            supplied, the default is used.
 
354
        """
 
355
        bzrdir = BzrDir.create(base, format)
 
356
        bzrdir._find_or_create_repository(force_new_repo)
 
357
        return bzrdir.create_branch()
295
358
 
296
359
    def _find_or_create_repository(self, force_new_repo):
297
360
        """Create a new repository if needed, returning the repository."""
298
 
        policy = self.determine_repository_policy(force_new_repo)
299
 
        return policy.acquire_repository()[0]
300
 
 
301
 
    def _find_source_repo(self, add_cleanup, source_branch):
302
 
        """Find the source branch and repo for a sprout operation.
303
 
        
304
 
        This is helper intended for use by _sprout.
305
 
 
306
 
        :returns: (source_branch, source_repository).  Either or both may be
307
 
            None.  If not None, they will be read-locked (and their unlock(s)
308
 
            scheduled via the add_cleanup param).
309
 
        """
310
 
        if source_branch is not None:
311
 
            add_cleanup(source_branch.lock_read().unlock)
312
 
            return source_branch, source_branch.repository
 
361
        if force_new_repo:
 
362
            return self.create_repository()
313
363
        try:
314
 
            source_branch = self.open_branch()
315
 
            source_repository = source_branch.repository
316
 
        except errors.NotBranchError:
317
 
            source_branch = None
 
364
            return self.find_repository()
 
365
        except errors.NoRepositoryPresent:
 
366
            return self.create_repository()
 
367
        
 
368
    @staticmethod
 
369
    def create_branch_convenience(base, force_new_repo=False,
 
370
                                  force_new_tree=None, format=None,
 
371
                                  possible_transports=None):
 
372
        """Create a new BzrDir, Branch and Repository at the url 'base'.
 
373
 
 
374
        This is a convenience function - it will use an existing repository
 
375
        if possible, can be told explicitly whether to create a working tree or
 
376
        not.
 
377
 
 
378
        This will use the current default BzrDirFormat unless one is
 
379
        specified, and use whatever 
 
380
        repository format that that uses via bzrdir.create_branch and
 
381
        create_repository. If a shared repository is available that is used
 
382
        preferentially. Whatever repository is used, its tree creation policy
 
383
        is followed.
 
384
 
 
385
        The created Branch object is returned.
 
386
        If a working tree cannot be made due to base not being a file:// url,
 
387
        no error is raised unless force_new_tree is True, in which case no 
 
388
        data is created on disk and NotLocalUrl is raised.
 
389
 
 
390
        :param base: The URL to create the branch at.
 
391
        :param force_new_repo: If True a new repository is always created.
 
392
        :param force_new_tree: If True or False force creation of a tree or 
 
393
                               prevent such creation respectively.
 
394
        :param format: Override for the bzrdir format to create.
 
395
        :param possible_transports: An optional reusable transports list.
 
396
        """
 
397
        if force_new_tree:
 
398
            # check for non local urls
 
399
            t = get_transport(base, possible_transports)
 
400
            if not isinstance(t, LocalTransport):
 
401
                raise errors.NotLocalUrl(base)
 
402
        bzrdir = BzrDir.create(base, format, possible_transports)
 
403
        repo = bzrdir._find_or_create_repository(force_new_repo)
 
404
        result = bzrdir.create_branch()
 
405
        if force_new_tree or (repo.make_working_trees() and
 
406
                              force_new_tree is None):
318
407
            try:
319
 
                source_repository = self.open_repository()
320
 
            except errors.NoRepositoryPresent:
321
 
                source_repository = None
322
 
            else:
323
 
                add_cleanup(source_repository.lock_read().unlock)
324
 
        else:
325
 
            add_cleanup(source_branch.lock_read().unlock)
326
 
        return source_branch, source_repository
327
 
 
328
 
    def sprout(self, url, revision_id=None, force_new_repo=False,
329
 
               recurse='down', possible_transports=None,
330
 
               accelerator_tree=None, hardlink=False, stacked=False,
331
 
               source_branch=None, create_tree_if_local=True):
332
 
        """Create a copy of this controldir prepared for use as a new line of
333
 
        development.
334
 
 
335
 
        If url's last component does not exist, it will be created.
336
 
 
337
 
        Attributes related to the identity of the source branch like
338
 
        branch nickname will be cleaned, a working tree is created
339
 
        whether one existed before or not; and a local branch is always
340
 
        created.
341
 
 
342
 
        if revision_id is not None, then the clone operation may tune
343
 
            itself to download less data.
344
 
 
 
408
                bzrdir.create_workingtree()
 
409
            except errors.NotLocalUrl:
 
410
                pass
 
411
        return result
 
412
 
 
413
    @staticmethod
 
414
    @deprecated_function(zero_ninetyone)
 
415
    def create_repository(base, shared=False, format=None):
 
416
        """Create a new BzrDir and Repository at the url 'base'.
 
417
 
 
418
        If no format is supplied, this will default to the current default
 
419
        BzrDirFormat by default, and use whatever repository format that that
 
420
        uses for bzrdirformat.create_repository.
 
421
 
 
422
        :param shared: Create a shared repository rather than a standalone
 
423
                       repository.
 
424
        The Repository object is returned.
 
425
 
 
426
        This must be overridden as an instance method in child classes, where
 
427
        it should take no parameters and construct whatever repository format
 
428
        that child class desires.
 
429
 
 
430
        This method is deprecated, please call create_repository on a bzrdir
 
431
        instance instead.
 
432
        """
 
433
        bzrdir = BzrDir.create(base, format)
 
434
        return bzrdir.create_repository(shared)
 
435
 
 
436
    @staticmethod
 
437
    def create_standalone_workingtree(base, format=None):
 
438
        """Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
 
439
 
 
440
        'base' must be a local path or a file:// url.
 
441
 
 
442
        This will use the current default BzrDirFormat unless one is
 
443
        specified, and use whatever 
 
444
        repository format that that uses for bzrdirformat.create_workingtree,
 
445
        create_branch and create_repository.
 
446
 
 
447
        :param format: Override for the bzrdir format to create.
 
448
        :return: The WorkingTree object.
 
449
        """
 
450
        t = get_transport(base)
 
451
        if not isinstance(t, LocalTransport):
 
452
            raise errors.NotLocalUrl(base)
 
453
        bzrdir = BzrDir.create_branch_and_repo(base,
 
454
                                               force_new_repo=True,
 
455
                                               format=format).bzrdir
 
456
        return bzrdir.create_workingtree()
 
457
 
 
458
    def create_workingtree(self, revision_id=None, from_branch=None,
 
459
        accelerator_tree=None, hardlink=False):
 
460
        """Create a working tree at this BzrDir.
 
461
        
 
462
        :param revision_id: create it as of this revision id.
 
463
        :param from_branch: override bzrdir branch (for lightweight checkouts)
345
464
        :param accelerator_tree: A tree which can be used for retrieving file
346
465
            contents more quickly than the revision tree, i.e. a workingtree.
347
466
            The revision tree will be used for cases where accelerator_tree's
348
467
            content is different.
349
 
        :param hardlink: If true, hard-link files from accelerator_tree,
350
 
            where possible.
351
 
        :param stacked: If true, create a stacked branch referring to the
352
 
            location of this control directory.
353
 
        :param create_tree_if_local: If true, a working-tree will be created
354
 
            when working locally.
355
 
        """
356
 
        operation = cleanup.OperationWithCleanups(self._sprout)
357
 
        return operation.run(url, revision_id=revision_id,
358
 
            force_new_repo=force_new_repo, recurse=recurse,
359
 
            possible_transports=possible_transports,
360
 
            accelerator_tree=accelerator_tree, hardlink=hardlink,
361
 
            stacked=stacked, source_branch=source_branch,
362
 
            create_tree_if_local=create_tree_if_local)
363
 
 
364
 
    def _sprout(self, op, url, revision_id=None, force_new_repo=False,
365
 
               recurse='down', possible_transports=None,
366
 
               accelerator_tree=None, hardlink=False, stacked=False,
367
 
               source_branch=None, create_tree_if_local=True):
368
 
        add_cleanup = op.add_cleanup
369
 
        fetch_spec_factory = fetch.FetchSpecFactory()
370
 
        if revision_id is not None:
371
 
            fetch_spec_factory.add_revision_ids([revision_id])
372
 
            fetch_spec_factory.source_branch_stop_revision_id = revision_id
373
 
        target_transport = _mod_transport.get_transport(url,
374
 
            possible_transports)
375
 
        target_transport.ensure_base()
376
 
        cloning_format = self.cloning_metadir(stacked)
377
 
        # Create/update the result branch
378
 
        result = cloning_format.initialize_on_transport(target_transport)
379
 
        source_branch, source_repository = self._find_source_repo(
380
 
            add_cleanup, source_branch)
381
 
        fetch_spec_factory.source_branch = source_branch
382
 
        # if a stacked branch wasn't requested, we don't create one
383
 
        # even if the origin was stacked
384
 
        if stacked and source_branch is not None:
385
 
            stacked_branch_url = self.root_transport.base
386
 
        else:
387
 
            stacked_branch_url = None
388
 
        repository_policy = result.determine_repository_policy(
389
 
            force_new_repo, stacked_branch_url, require_stacking=stacked)
390
 
        result_repo, is_new_repo = repository_policy.acquire_repository()
391
 
        add_cleanup(result_repo.lock_write().unlock)
392
 
        fetch_spec_factory.source_repo = source_repository
393
 
        fetch_spec_factory.target_repo = result_repo
394
 
        if stacked or (len(result_repo._fallback_repositories) != 0):
395
 
            target_repo_kind = fetch.TargetRepoKinds.STACKED
396
 
        elif is_new_repo:
397
 
            target_repo_kind = fetch.TargetRepoKinds.EMPTY
398
 
        else:
399
 
            target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
400
 
        fetch_spec_factory.target_repo_kind = target_repo_kind
401
 
        if source_repository is not None:
402
 
            fetch_spec = fetch_spec_factory.make_fetch_spec()
403
 
            result_repo.fetch(source_repository, fetch_spec=fetch_spec)
404
 
 
405
 
        if source_branch is None:
406
 
            # this is for sprouting a controldir without a branch; is that
407
 
            # actually useful?
408
 
            # Not especially, but it's part of the contract.
409
 
            result_branch = result.create_branch()
410
 
        else:
411
 
            result_branch = source_branch.sprout(result,
412
 
                revision_id=revision_id, repository_policy=repository_policy,
413
 
                repository=result_repo)
414
 
        mutter("created new branch %r" % (result_branch,))
415
 
 
416
 
        # Create/update the result working tree
417
 
        if (create_tree_if_local and
418
 
            isinstance(target_transport, local.LocalTransport) and
419
 
            (result_repo is None or result_repo.make_working_trees())):
420
 
            wt = result.create_workingtree(accelerator_tree=accelerator_tree,
421
 
                hardlink=hardlink, from_branch=result_branch)
422
 
            wt.lock_write()
423
 
            try:
424
 
                if wt.path2id('') is None:
425
 
                    try:
426
 
                        wt.set_root_id(self.open_workingtree.get_root_id())
427
 
                    except errors.NoWorkingTree:
428
 
                        pass
429
 
            finally:
430
 
                wt.unlock()
431
 
        else:
432
 
            wt = None
433
 
        if recurse == 'down':
434
 
            basis = None
435
 
            if wt is not None:
436
 
                basis = wt.basis_tree()
437
 
            elif result_branch is not None:
438
 
                basis = result_branch.basis_tree()
439
 
            elif source_branch is not None:
440
 
                basis = source_branch.basis_tree()
441
 
            if basis is not None:
442
 
                add_cleanup(basis.lock_read().unlock)
443
 
                subtrees = basis.iter_references()
444
 
            else:
445
 
                subtrees = []
446
 
            for path, file_id in subtrees:
447
 
                target = urlutils.join(url, urlutils.escape(path))
448
 
                sublocation = source_branch.reference_parent(file_id, path)
449
 
                sublocation.bzrdir.sprout(target,
450
 
                    basis.get_reference_revision(file_id, path),
451
 
                    force_new_repo=force_new_repo, recurse=recurse,
452
 
                    stacked=stacked)
453
 
        return result
454
 
 
455
 
    @deprecated_method(deprecated_in((2, 3, 0)))
456
 
    def generate_backup_name(self, base):
457
 
        return self._available_backup_name(base)
458
 
 
459
 
    def _available_backup_name(self, base):
460
 
        """Find a non-existing backup file name based on base.
461
 
 
462
 
        See bzrlib.osutils.available_backup_name about race conditions.
463
 
        """
464
 
        return osutils.available_backup_name(base, self.root_transport.has)
465
 
 
466
 
    def backup_bzrdir(self):
467
 
        """Backup this bzr control directory.
468
 
 
469
 
        :return: Tuple with old path name and new path name
470
 
        """
471
 
 
472
 
        pb = ui.ui_factory.nested_progress_bar()
473
 
        try:
474
 
            old_path = self.root_transport.abspath('.bzr')
475
 
            backup_dir = self._available_backup_name('backup.bzr')
476
 
            new_path = self.root_transport.abspath(backup_dir)
477
 
            ui.ui_factory.note(gettext('making backup of {0}\n  to {1}').format(
478
 
                urlutils.unescape_for_display(old_path, 'utf-8'),
479
 
                urlutils.unescape_for_display(new_path, 'utf-8')))
480
 
            self.root_transport.copy_tree('.bzr', backup_dir)
481
 
            return (old_path, new_path)
482
 
        finally:
483
 
            pb.finished()
 
468
        """
 
469
        raise NotImplementedError(self.create_workingtree)
484
470
 
485
471
    def retire_bzrdir(self, limit=10000):
486
472
        """Permanently disable the bzrdir.
497
483
            try:
498
484
                to_path = '.bzr.retired.%d' % i
499
485
                self.root_transport.rename('.bzr', to_path)
500
 
                note(gettext("renamed {0} to {1}").format(
501
 
                    self.root_transport.abspath('.bzr'), to_path))
 
486
                note("renamed %s to %s"
 
487
                    % (self.root_transport.abspath('.bzr'), to_path))
502
488
                return
503
489
            except (errors.TransportError, IOError, errors.PathError):
504
490
                i += 1
507
493
                else:
508
494
                    pass
509
495
 
510
 
    def _find_containing(self, evaluate):
511
 
        """Find something in a containing control directory.
512
 
 
513
 
        This method will scan containing control dirs, until it finds what
514
 
        it is looking for, decides that it will never find it, or runs out
515
 
        of containing control directories to check.
516
 
 
517
 
        It is used to implement find_repository and
518
 
        determine_repository_policy.
519
 
 
520
 
        :param evaluate: A function returning (value, stop).  If stop is True,
521
 
            the value will be returned.
522
 
        """
523
 
        found_bzrdir = self
524
 
        while True:
525
 
            result, stop = evaluate(found_bzrdir)
526
 
            if stop:
527
 
                return result
528
 
            next_transport = found_bzrdir.root_transport.clone('..')
529
 
            if (found_bzrdir.user_url == next_transport.base):
530
 
                # top of the file system
531
 
                return None
532
 
            # find the next containing bzrdir
533
 
            try:
534
 
                found_bzrdir = self.open_containing_from_transport(
535
 
                    next_transport)[0]
536
 
            except errors.NotBranchError:
537
 
                return None
 
496
    def destroy_workingtree(self):
 
497
        """Destroy the working tree at this BzrDir.
 
498
 
 
499
        Formats that do not support this may raise UnsupportedOperation.
 
500
        """
 
501
        raise NotImplementedError(self.destroy_workingtree)
 
502
 
 
503
    def destroy_workingtree_metadata(self):
 
504
        """Destroy the control files for the working tree at this BzrDir.
 
505
 
 
506
        The contents of working tree files are not affected.
 
507
        Formats that do not support this may raise UnsupportedOperation.
 
508
        """
 
509
        raise NotImplementedError(self.destroy_workingtree_metadata)
538
510
 
539
511
    def find_repository(self):
540
512
        """Find the repository that should be used.
543
515
        new branches as well as to hook existing branches up to their
544
516
        repository.
545
517
        """
546
 
        def usable_repository(found_bzrdir):
 
518
        try:
 
519
            return self.open_repository()
 
520
        except errors.NoRepositoryPresent:
 
521
            pass
 
522
        next_transport = self.root_transport.clone('..')
 
523
        while True:
 
524
            # find the next containing bzrdir
 
525
            try:
 
526
                found_bzrdir = BzrDir.open_containing_from_transport(
 
527
                    next_transport)[0]
 
528
            except errors.NotBranchError:
 
529
                # none found
 
530
                raise errors.NoRepositoryPresent(self)
547
531
            # does it have a repository ?
548
532
            try:
549
533
                repository = found_bzrdir.open_repository()
550
534
            except errors.NoRepositoryPresent:
551
 
                return None, False
552
 
            if found_bzrdir.user_url == self.user_url:
553
 
                return repository, True
554
 
            elif repository.is_shared():
555
 
                return repository, True
556
 
            else:
557
 
                return None, True
558
 
 
559
 
        found_repo = self._find_containing(usable_repository)
560
 
        if found_repo is None:
561
 
            raise errors.NoRepositoryPresent(self)
562
 
        return found_repo
563
 
 
564
 
    def _find_creation_modes(self):
565
 
        """Determine the appropriate modes for files and directories.
566
 
 
567
 
        They're always set to be consistent with the base directory,
568
 
        assuming that this transport allows setting modes.
569
 
        """
570
 
        # TODO: Do we need or want an option (maybe a config setting) to turn
571
 
        # this off or override it for particular locations? -- mbp 20080512
572
 
        if self._mode_check_done:
573
 
            return
574
 
        self._mode_check_done = True
575
 
        try:
576
 
            st = self.transport.stat('.')
577
 
        except errors.TransportNotPossible:
578
 
            self._dir_mode = None
579
 
            self._file_mode = None
580
 
        else:
581
 
            # Check the directory mode, but also make sure the created
582
 
            # directories and files are read-write for this user. This is
583
 
            # mostly a workaround for filesystems which lie about being able to
584
 
            # write to a directory (cygwin & win32)
585
 
            if (st.st_mode & 07777 == 00000):
586
 
                # FTP allows stat but does not return dir/file modes
587
 
                self._dir_mode = None
588
 
                self._file_mode = None
589
 
            else:
590
 
                self._dir_mode = (st.st_mode & 07777) | 00700
591
 
                # Remove the sticky and execute bits for files
592
 
                self._file_mode = self._dir_mode & ~07111
593
 
 
594
 
    def _get_file_mode(self):
595
 
        """Return Unix mode for newly created files, or None.
596
 
        """
597
 
        if not self._mode_check_done:
598
 
            self._find_creation_modes()
599
 
        return self._file_mode
600
 
 
601
 
    def _get_dir_mode(self):
602
 
        """Return Unix mode for newly created directories, or None.
603
 
        """
604
 
        if not self._mode_check_done:
605
 
            self._find_creation_modes()
606
 
        return self._dir_mode
607
 
 
608
 
    def get_config(self):
609
 
        """Get configuration for this BzrDir."""
610
 
        return config.BzrDirConfig(self)
611
 
 
612
 
    def _get_config(self):
613
 
        """By default, no configuration is available."""
 
535
                next_transport = found_bzrdir.root_transport.clone('..')
 
536
                if (found_bzrdir.root_transport.base == next_transport.base):
 
537
                    # top of the file system
 
538
                    break
 
539
                else:
 
540
                    continue
 
541
            if ((found_bzrdir.root_transport.base ==
 
542
                 self.root_transport.base) or repository.is_shared()):
 
543
                return repository
 
544
            else:
 
545
                raise errors.NoRepositoryPresent(self)
 
546
        raise errors.NoRepositoryPresent(self)
 
547
 
 
548
    def get_branch_reference(self):
 
549
        """Return the referenced URL for the branch in this bzrdir.
 
550
 
 
551
        :raises NotBranchError: If there is no Branch.
 
552
        :return: The URL the branch in this bzrdir references if it is a
 
553
            reference branch, or None for regular branches.
 
554
        """
614
555
        return None
615
556
 
 
557
    def get_branch_transport(self, branch_format):
 
558
        """Get the transport for use by branch format in this BzrDir.
 
559
 
 
560
        Note that bzr dirs that do not support format strings will raise
 
561
        IncompatibleFormat if the branch format they are given has
 
562
        a format string, and vice versa.
 
563
 
 
564
        If branch_format is None, the transport is returned with no 
 
565
        checking. If it is not None, then the returned transport is
 
566
        guaranteed to point to an existing directory ready for use.
 
567
        """
 
568
        raise NotImplementedError(self.get_branch_transport)
 
569
        
 
570
    def get_repository_transport(self, repository_format):
 
571
        """Get the transport for use by repository format in this BzrDir.
 
572
 
 
573
        Note that bzr dirs that do not support format strings will raise
 
574
        IncompatibleFormat if the repository format they are given has
 
575
        a format string, and vice versa.
 
576
 
 
577
        If repository_format is None, the transport is returned with no 
 
578
        checking. If it is not None, then the returned transport is
 
579
        guaranteed to point to an existing directory ready for use.
 
580
        """
 
581
        raise NotImplementedError(self.get_repository_transport)
 
582
        
 
583
    def get_workingtree_transport(self, tree_format):
 
584
        """Get the transport for use by workingtree format in this BzrDir.
 
585
 
 
586
        Note that bzr dirs that do not support format strings will raise
 
587
        IncompatibleFormat if the workingtree format they are given has a
 
588
        format string, and vice versa.
 
589
 
 
590
        If workingtree_format is None, the transport is returned with no 
 
591
        checking. If it is not None, then the returned transport is
 
592
        guaranteed to point to an existing directory ready for use.
 
593
        """
 
594
        raise NotImplementedError(self.get_workingtree_transport)
 
595
        
616
596
    def __init__(self, _transport, _format):
617
597
        """Initialize a Bzr control dir object.
618
 
 
 
598
        
619
599
        Only really common logic should reside here, concrete classes should be
620
600
        made with varying behaviours.
621
601
 
623
603
        :param _transport: the transport this dir is based at.
624
604
        """
625
605
        self._format = _format
626
 
        # these are also under the more standard names of 
627
 
        # control_transport and user_transport
628
606
        self.transport = _transport.clone('.bzr')
629
607
        self.root_transport = _transport
630
 
        self._mode_check_done = False
631
 
 
632
 
    @property 
633
 
    def user_transport(self):
634
 
        return self.root_transport
635
 
 
636
 
    @property
637
 
    def control_transport(self):
638
 
        return self.transport
639
608
 
640
609
    def is_control_filename(self, filename):
641
610
        """True if filename is the name of a path which is reserved for bzrdir's.
642
 
 
 
611
        
643
612
        :param filename: A filename within the root transport of this bzrdir.
644
613
 
645
614
        This is true IF and ONLY IF the filename is part of the namespace reserved
646
615
        for bzr control dirs. Currently this is the '.bzr' directory in the root
647
 
        of the root_transport. 
 
616
        of the root_transport. it is expected that plugins will need to extend
 
617
        this in the future - for instance to make bzr talk with svn working
 
618
        trees.
648
619
        """
649
 
        # this might be better on the BzrDirFormat class because it refers to
650
 
        # all the possible bzrdir disk formats.
651
 
        # This method is tested via the workingtree is_control_filename tests-
 
620
        # this might be better on the BzrDirFormat class because it refers to 
 
621
        # all the possible bzrdir disk formats. 
 
622
        # This method is tested via the workingtree is_control_filename tests- 
652
623
        # it was extracted from WorkingTree.is_control_filename. If the method's
653
624
        # contract is extended beyond the current trivial implementation, please
654
625
        # add new tests for it to the appropriate place.
655
626
        return filename == '.bzr' or filename.startswith('.bzr/')
656
627
 
 
628
    def needs_format_conversion(self, format=None):
 
629
        """Return true if this bzrdir needs convert_format run on it.
 
630
        
 
631
        For instance, if the repository format is out of date but the 
 
632
        branch and working tree are not, this should return True.
 
633
 
 
634
        :param format: Optional parameter indicating a specific desired
 
635
                       format we plan to arrive at.
 
636
        """
 
637
        raise NotImplementedError(self.needs_format_conversion)
 
638
 
 
639
    @staticmethod
 
640
    def open_unsupported(base):
 
641
        """Open a branch which is not supported."""
 
642
        return BzrDir.open(base, _unsupported=True)
 
643
        
 
644
    @staticmethod
 
645
    def open(base, _unsupported=False, possible_transports=None):
 
646
        """Open an existing bzrdir, rooted at 'base' (url).
 
647
        
 
648
        :param _unsupported: a private parameter to the BzrDir class.
 
649
        """
 
650
        t = get_transport(base, possible_transports=possible_transports)
 
651
        return BzrDir.open_from_transport(t, _unsupported=_unsupported)
 
652
 
 
653
    @staticmethod
 
654
    def open_from_transport(transport, _unsupported=False,
 
655
                            _server_formats=True):
 
656
        """Open a bzrdir within a particular directory.
 
657
 
 
658
        :param transport: Transport containing the bzrdir.
 
659
        :param _unsupported: private.
 
660
        """
 
661
        base = transport.base
 
662
 
 
663
        def find_format(transport):
 
664
            return transport, BzrDirFormat.find_format(
 
665
                transport, _server_formats=_server_formats)
 
666
 
 
667
        def redirected(transport, e, redirection_notice):
 
668
            qualified_source = e.get_source_url()
 
669
            relpath = transport.relpath(qualified_source)
 
670
            if not e.target.endswith(relpath):
 
671
                # Not redirected to a branch-format, not a branch
 
672
                raise errors.NotBranchError(path=e.target)
 
673
            target = e.target[:-len(relpath)]
 
674
            note('%s is%s redirected to %s',
 
675
                 transport.base, e.permanently, target)
 
676
            # Let's try with a new transport
 
677
            # FIXME: If 'transport' has a qualifier, this should
 
678
            # be applied again to the new transport *iff* the
 
679
            # schemes used are the same. Uncomment this code
 
680
            # once the function (and tests) exist.
 
681
            # -- vila20070212
 
682
            #target = urlutils.copy_url_qualifiers(original, target)
 
683
            return get_transport(target)
 
684
 
 
685
        try:
 
686
            transport, format = do_catching_redirections(find_format,
 
687
                                                         transport,
 
688
                                                         redirected)
 
689
        except errors.TooManyRedirections:
 
690
            raise errors.NotBranchError(base)
 
691
 
 
692
        BzrDir._check_supported(format, _unsupported)
 
693
        return format.open(transport, _found=True)
 
694
 
 
695
    def open_branch(self, unsupported=False):
 
696
        """Open the branch object at this BzrDir if one is present.
 
697
 
 
698
        If unsupported is True, then no longer supported branch formats can
 
699
        still be opened.
 
700
        
 
701
        TODO: static convenience version of this?
 
702
        """
 
703
        raise NotImplementedError(self.open_branch)
 
704
 
 
705
    @staticmethod
 
706
    def open_containing(url, possible_transports=None):
 
707
        """Open an existing branch which contains url.
 
708
        
 
709
        :param url: url to search from.
 
710
        See open_containing_from_transport for more detail.
 
711
        """
 
712
        transport = get_transport(url, possible_transports)
 
713
        return BzrDir.open_containing_from_transport(transport)
 
714
    
 
715
    @staticmethod
 
716
    def open_containing_from_transport(a_transport):
 
717
        """Open an existing branch which contains a_transport.base.
 
718
 
 
719
        This probes for a branch at a_transport, and searches upwards from there.
 
720
 
 
721
        Basically we keep looking up until we find the control directory or
 
722
        run into the root.  If there isn't one, raises NotBranchError.
 
723
        If there is one and it is either an unrecognised format or an unsupported 
 
724
        format, UnknownFormatError or UnsupportedFormatError are raised.
 
725
        If there is one, it is returned, along with the unused portion of url.
 
726
 
 
727
        :return: The BzrDir that contains the path, and a Unicode path 
 
728
                for the rest of the URL.
 
729
        """
 
730
        # this gets the normalised url back. I.e. '.' -> the full path.
 
731
        url = a_transport.base
 
732
        while True:
 
733
            try:
 
734
                result = BzrDir.open_from_transport(a_transport)
 
735
                return result, urlutils.unescape(a_transport.relpath(url))
 
736
            except errors.NotBranchError, e:
 
737
                pass
 
738
            try:
 
739
                new_t = a_transport.clone('..')
 
740
            except errors.InvalidURLJoin:
 
741
                # reached the root, whatever that may be
 
742
                raise errors.NotBranchError(path=url)
 
743
            if new_t.base == a_transport.base:
 
744
                # reached the root, whatever that may be
 
745
                raise errors.NotBranchError(path=url)
 
746
            a_transport = new_t
 
747
 
 
748
    def _get_tree_branch(self):
 
749
        """Return the branch and tree, if any, for this bzrdir.
 
750
 
 
751
        Return None for tree if not present or inaccessible.
 
752
        Raise NotBranchError if no branch is present.
 
753
        :return: (tree, branch)
 
754
        """
 
755
        try:
 
756
            tree = self.open_workingtree()
 
757
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
758
            tree = None
 
759
            branch = self.open_branch()
 
760
        else:
 
761
            branch = tree.branch
 
762
        return tree, branch
 
763
 
 
764
    @classmethod
 
765
    def open_tree_or_branch(klass, location):
 
766
        """Return the branch and working tree at a location.
 
767
 
 
768
        If there is no tree at the location, tree will be None.
 
769
        If there is no branch at the location, an exception will be
 
770
        raised
 
771
        :return: (tree, branch)
 
772
        """
 
773
        bzrdir = klass.open(location)
 
774
        return bzrdir._get_tree_branch()
 
775
 
 
776
    @classmethod
 
777
    def open_containing_tree_or_branch(klass, location):
 
778
        """Return the branch and working tree contained by a location.
 
779
 
 
780
        Returns (tree, branch, relpath).
 
781
        If there is no tree at containing the location, tree will be None.
 
782
        If there is no branch containing the location, an exception will be
 
783
        raised
 
784
        relpath is the portion of the path that is contained by the branch.
 
785
        """
 
786
        bzrdir, relpath = klass.open_containing(location)
 
787
        tree, branch = bzrdir._get_tree_branch()
 
788
        return tree, branch, relpath
 
789
 
 
790
    def open_repository(self, _unsupported=False):
 
791
        """Open the repository object at this BzrDir if one is present.
 
792
 
 
793
        This will not follow the Branch object pointer - it's strictly a direct
 
794
        open facility. Most client code should use open_branch().repository to
 
795
        get at a repository.
 
796
 
 
797
        :param _unsupported: a private parameter, not part of the api.
 
798
        TODO: static convenience version of this?
 
799
        """
 
800
        raise NotImplementedError(self.open_repository)
 
801
 
 
802
    def open_workingtree(self, _unsupported=False,
 
803
                         recommend_upgrade=True, from_branch=None):
 
804
        """Open the workingtree object at this BzrDir if one is present.
 
805
 
 
806
        :param recommend_upgrade: Optional keyword parameter, when True (the
 
807
            default), emit through the ui module a recommendation that the user
 
808
            upgrade the working tree when the workingtree being opened is old
 
809
            (but still fully supported).
 
810
        :param from_branch: override bzrdir branch (for lightweight checkouts)
 
811
        """
 
812
        raise NotImplementedError(self.open_workingtree)
 
813
 
 
814
    def has_branch(self):
 
815
        """Tell if this bzrdir contains a branch.
 
816
        
 
817
        Note: if you're going to open the branch, you should just go ahead
 
818
        and try, and not ask permission first.  (This method just opens the 
 
819
        branch and discards it, and that's somewhat expensive.) 
 
820
        """
 
821
        try:
 
822
            self.open_branch()
 
823
            return True
 
824
        except errors.NotBranchError:
 
825
            return False
 
826
 
 
827
    def has_workingtree(self):
 
828
        """Tell if this bzrdir contains a working tree.
 
829
 
 
830
        This will still raise an exception if the bzrdir has a workingtree that
 
831
        is remote & inaccessible.
 
832
        
 
833
        Note: if you're going to open the working tree, you should just go ahead
 
834
        and try, and not ask permission first.  (This method just opens the 
 
835
        workingtree and discards it, and that's somewhat expensive.) 
 
836
        """
 
837
        try:
 
838
            self.open_workingtree(recommend_upgrade=False)
 
839
            return True
 
840
        except errors.NoWorkingTree:
 
841
            return False
 
842
 
657
843
    def _cloning_metadir(self):
658
 
        """Produce a metadir suitable for cloning with.
659
 
 
660
 
        :returns: (destination_bzrdir_format, source_repository)
661
 
        """
 
844
        """Produce a metadir suitable for cloning with."""
662
845
        result_format = self._format.__class__()
663
846
        try:
664
847
            try:
665
 
                branch = self.open_branch(ignore_fallbacks=True)
 
848
                branch = self.open_branch()
666
849
                source_repository = branch.repository
667
 
                result_format._branch_format = branch._format
668
850
            except errors.NotBranchError:
669
851
                source_branch = None
670
852
                source_repository = self.open_repository()
675
857
            # the fix recommended in bug # 103195 - to delegate this choice the
676
858
            # repository itself.
677
859
            repo_format = source_repository._format
678
 
            if isinstance(repo_format, remote.RemoteRepositoryFormat):
679
 
                source_repository._ensure_real()
680
 
                repo_format = source_repository._real_repository._format
681
 
            result_format.repository_format = repo_format
 
860
            if not isinstance(repo_format, remote.RemoteRepositoryFormat):
 
861
                result_format.repository_format = repo_format
682
862
        try:
683
863
            # TODO: Couldn't we just probe for the format in these cases,
684
864
            # rather than opening the whole tree?  It would be a little
690
870
            result_format.workingtree_format = tree._format.__class__()
691
871
        return result_format, source_repository
692
872
 
693
 
    def cloning_metadir(self, require_stacking=False):
 
873
    def cloning_metadir(self):
694
874
        """Produce a metadir suitable for cloning or sprouting with.
695
875
 
696
876
        These operations may produce workingtrees (yes, even though they're
697
877
        "cloning" something that doesn't have a tree), so a viable workingtree
698
878
        format must be selected.
699
 
 
700
 
        :require_stacking: If True, non-stackable formats will be upgraded
701
 
            to similar stackable formats.
702
 
        :returns: a ControlDirFormat with all component formats either set
703
 
            appropriately or set to None if that component should not be
704
 
            created.
705
879
        """
706
880
        format, repository = self._cloning_metadir()
707
881
        if format._workingtree_format is None:
708
 
            # No tree in self.
709
882
            if repository is None:
710
 
                # No repository either
711
883
                return format
712
 
            # We have a repository, so set a working tree? (Why? This seems to
713
 
            # contradict the stated return value in the docstring).
714
884
            tree_format = repository._format._matchingbzrdir.workingtree_format
715
885
            format.workingtree_format = tree_format.__class__()
716
 
        if require_stacking:
717
 
            format.require_stacking()
718
886
        return format
719
887
 
720
 
    def get_branch_transport(self, branch_format, name=None):
721
 
        """Get the transport for use by branch format in this BzrDir.
722
 
 
723
 
        Note that bzr dirs that do not support format strings will raise
724
 
        IncompatibleFormat if the branch format they are given has
725
 
        a format string, and vice versa.
726
 
 
727
 
        If branch_format is None, the transport is returned with no
728
 
        checking. If it is not None, then the returned transport is
729
 
        guaranteed to point to an existing directory ready for use.
 
888
    def checkout_metadir(self):
 
889
        return self.cloning_metadir()
 
890
 
 
891
    def sprout(self, url, revision_id=None, force_new_repo=False,
 
892
               recurse='down', possible_transports=None,
 
893
               accelerator_tree=None, hardlink=False):
 
894
        """Create a copy of this bzrdir prepared for use as a new line of
 
895
        development.
 
896
 
 
897
        If url's last component does not exist, it will be created.
 
898
 
 
899
        Attributes related to the identity of the source branch like
 
900
        branch nickname will be cleaned, a working tree is created
 
901
        whether one existed before or not; and a local branch is always
 
902
        created.
 
903
 
 
904
        if revision_id is not None, then the clone operation may tune
 
905
            itself to download less data.
 
906
        :param accelerator_tree: A tree which can be used for retrieving file
 
907
            contents more quickly than the revision tree, i.e. a workingtree.
 
908
            The revision tree will be used for cases where accelerator_tree's
 
909
            content is different.
 
910
        :param hardlink: If true, hard-link files from accelerator_tree,
 
911
            where possible.
730
912
        """
731
 
        raise NotImplementedError(self.get_branch_transport)
 
913
        target_transport = get_transport(url, possible_transports)
 
914
        target_transport.ensure_base()
 
915
        cloning_format = self.cloning_metadir()
 
916
        result = cloning_format.initialize_on_transport(target_transport)
 
917
        try:
 
918
            source_branch = self.open_branch()
 
919
            source_repository = source_branch.repository
 
920
        except errors.NotBranchError:
 
921
            source_branch = None
 
922
            try:
 
923
                source_repository = self.open_repository()
 
924
            except errors.NoRepositoryPresent:
 
925
                source_repository = None
 
926
        if force_new_repo:
 
927
            result_repo = None
 
928
        else:
 
929
            try:
 
930
                result_repo = result.find_repository()
 
931
            except errors.NoRepositoryPresent:
 
932
                result_repo = None
 
933
        if source_repository is None and result_repo is not None:
 
934
            pass
 
935
        elif source_repository is None and result_repo is None:
 
936
            # no repo available, make a new one
 
937
            result.create_repository()
 
938
        elif source_repository is not None and result_repo is None:
 
939
            # have source, and want to make a new target repo
 
940
            result_repo = source_repository.sprout(result,
 
941
                                                   revision_id=revision_id)
 
942
        else:
 
943
            # fetch needed content into target.
 
944
            if source_repository is not None:
 
945
                # would rather do 
 
946
                # source_repository.copy_content_into(result_repo,
 
947
                #                                     revision_id=revision_id)
 
948
                # so we can override the copy method
 
949
                result_repo.fetch(source_repository, revision_id=revision_id)
 
950
        if source_branch is not None:
 
951
            source_branch.sprout(result, revision_id=revision_id)
 
952
        else:
 
953
            result.create_branch()
 
954
        if isinstance(target_transport, LocalTransport) and (
 
955
            result_repo is None or result_repo.make_working_trees()):
 
956
            wt = result.create_workingtree(accelerator_tree=accelerator_tree,
 
957
                hardlink=hardlink)
 
958
            wt.lock_write()
 
959
            try:
 
960
                if wt.path2id('') is None:
 
961
                    try:
 
962
                        wt.set_root_id(self.open_workingtree.get_root_id())
 
963
                    except errors.NoWorkingTree:
 
964
                        pass
 
965
            finally:
 
966
                wt.unlock()
 
967
        else:
 
968
            wt = None
 
969
        if recurse == 'down':
 
970
            if wt is not None:
 
971
                basis = wt.basis_tree()
 
972
                basis.lock_read()
 
973
                subtrees = basis.iter_references()
 
974
                recurse_branch = wt.branch
 
975
            elif source_branch is not None:
 
976
                basis = source_branch.basis_tree()
 
977
                basis.lock_read()
 
978
                subtrees = basis.iter_references()
 
979
                recurse_branch = source_branch
 
980
            else:
 
981
                subtrees = []
 
982
                basis = None
 
983
            try:
 
984
                for path, file_id in subtrees:
 
985
                    target = urlutils.join(url, urlutils.escape(path))
 
986
                    sublocation = source_branch.reference_parent(file_id, path)
 
987
                    sublocation.bzrdir.sprout(target,
 
988
                        basis.get_reference_revision(file_id, path),
 
989
                        force_new_repo=force_new_repo, recurse=recurse)
 
990
            finally:
 
991
                if basis is not None:
 
992
                    basis.unlock()
 
993
        return result
 
994
 
 
995
 
 
996
class BzrDirPreSplitOut(BzrDir):
 
997
    """A common class for the all-in-one formats."""
 
998
 
 
999
    def __init__(self, _transport, _format):
 
1000
        """See BzrDir.__init__."""
 
1001
        super(BzrDirPreSplitOut, self).__init__(_transport, _format)
 
1002
        assert self._format._lock_class == lockable_files.TransportLock
 
1003
        assert self._format._lock_file_name == 'branch-lock'
 
1004
        self._control_files = lockable_files.LockableFiles(
 
1005
                                            self.get_branch_transport(None),
 
1006
                                            self._format._lock_file_name,
 
1007
                                            self._format._lock_class)
 
1008
 
 
1009
    def break_lock(self):
 
1010
        """Pre-splitout bzrdirs do not suffer from stale locks."""
 
1011
        raise NotImplementedError(self.break_lock)
 
1012
 
 
1013
    def clone(self, url, revision_id=None, force_new_repo=False):
 
1014
        """See BzrDir.clone()."""
 
1015
        from bzrlib.workingtree import WorkingTreeFormat2
 
1016
        self._make_tail(url)
 
1017
        result = self._format._initialize_for_clone(url)
 
1018
        self.open_repository().clone(result, revision_id=revision_id)
 
1019
        from_branch = self.open_branch()
 
1020
        from_branch.clone(result, revision_id=revision_id)
 
1021
        try:
 
1022
            self.open_workingtree().clone(result)
 
1023
        except errors.NotLocalUrl:
 
1024
            # make a new one, this format always has to have one.
 
1025
            try:
 
1026
                WorkingTreeFormat2().initialize(result)
 
1027
            except errors.NotLocalUrl:
 
1028
                # but we cannot do it for remote trees.
 
1029
                to_branch = result.open_branch()
 
1030
                WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
 
1031
        return result
 
1032
 
 
1033
    def create_branch(self):
 
1034
        """See BzrDir.create_branch."""
 
1035
        return self.open_branch()
 
1036
 
 
1037
    def destroy_branch(self):
 
1038
        """See BzrDir.destroy_branch."""
 
1039
        raise errors.UnsupportedOperation(self.destroy_branch, self)
 
1040
 
 
1041
    def create_repository(self, shared=False):
 
1042
        """See BzrDir.create_repository."""
 
1043
        if shared:
 
1044
            raise errors.IncompatibleFormat('shared repository', self._format)
 
1045
        return self.open_repository()
 
1046
 
 
1047
    def destroy_repository(self):
 
1048
        """See BzrDir.destroy_repository."""
 
1049
        raise errors.UnsupportedOperation(self.destroy_repository, self)
 
1050
 
 
1051
    def create_workingtree(self, revision_id=None, from_branch=None,
 
1052
                           accelerator_tree=None, hardlink=False):
 
1053
        """See BzrDir.create_workingtree."""
 
1054
        # this looks buggy but is not -really-
 
1055
        # because this format creates the workingtree when the bzrdir is
 
1056
        # created
 
1057
        # clone and sprout will have set the revision_id
 
1058
        # and that will have set it for us, its only
 
1059
        # specific uses of create_workingtree in isolation
 
1060
        # that can do wonky stuff here, and that only
 
1061
        # happens for creating checkouts, which cannot be 
 
1062
        # done on this format anyway. So - acceptable wart.
 
1063
        result = self.open_workingtree(recommend_upgrade=False)
 
1064
        if revision_id is not None:
 
1065
            if revision_id == _mod_revision.NULL_REVISION:
 
1066
                result.set_parent_ids([])
 
1067
            else:
 
1068
                result.set_parent_ids([revision_id])
 
1069
        return result
 
1070
 
 
1071
    def destroy_workingtree(self):
 
1072
        """See BzrDir.destroy_workingtree."""
 
1073
        raise errors.UnsupportedOperation(self.destroy_workingtree, self)
 
1074
 
 
1075
    def destroy_workingtree_metadata(self):
 
1076
        """See BzrDir.destroy_workingtree_metadata."""
 
1077
        raise errors.UnsupportedOperation(self.destroy_workingtree_metadata, 
 
1078
                                          self)
 
1079
 
 
1080
    def get_branch_transport(self, branch_format):
 
1081
        """See BzrDir.get_branch_transport()."""
 
1082
        if branch_format is None:
 
1083
            return self.transport
 
1084
        try:
 
1085
            branch_format.get_format_string()
 
1086
        except NotImplementedError:
 
1087
            return self.transport
 
1088
        raise errors.IncompatibleFormat(branch_format, self._format)
732
1089
 
733
1090
    def get_repository_transport(self, repository_format):
734
 
        """Get the transport for use by repository format in this BzrDir.
735
 
 
736
 
        Note that bzr dirs that do not support format strings will raise
737
 
        IncompatibleFormat if the repository format they are given has
738
 
        a format string, and vice versa.
739
 
 
740
 
        If repository_format is None, the transport is returned with no
741
 
        checking. If it is not None, then the returned transport is
742
 
        guaranteed to point to an existing directory ready for use.
743
 
        """
744
 
        raise NotImplementedError(self.get_repository_transport)
745
 
 
746
 
    def get_workingtree_transport(self, tree_format):
747
 
        """Get the transport for use by workingtree format in this BzrDir.
748
 
 
749
 
        Note that bzr dirs that do not support format strings will raise
750
 
        IncompatibleFormat if the workingtree format they are given has a
751
 
        format string, and vice versa.
752
 
 
753
 
        If workingtree_format is None, the transport is returned with no
754
 
        checking. If it is not None, then the returned transport is
755
 
        guaranteed to point to an existing directory ready for use.
756
 
        """
757
 
        raise NotImplementedError(self.get_workingtree_transport)
758
 
 
759
 
    @classmethod
760
 
    def create(cls, base, format=None, possible_transports=None):
761
 
        """Create a new BzrDir at the url 'base'.
762
 
 
763
 
        :param format: If supplied, the format of branch to create.  If not
764
 
            supplied, the default is used.
765
 
        :param possible_transports: If supplied, a list of transports that
766
 
            can be reused to share a remote connection.
767
 
        """
768
 
        if cls is not BzrDir:
769
 
            raise AssertionError("BzrDir.create always creates the "
770
 
                "default format, not one of %r" % cls)
771
 
        return controldir.ControlDir.create(base, format=format,
772
 
                possible_transports=possible_transports)
 
1091
        """See BzrDir.get_repository_transport()."""
 
1092
        if repository_format is None:
 
1093
            return self.transport
 
1094
        try:
 
1095
            repository_format.get_format_string()
 
1096
        except NotImplementedError:
 
1097
            return self.transport
 
1098
        raise errors.IncompatibleFormat(repository_format, self._format)
 
1099
 
 
1100
    def get_workingtree_transport(self, workingtree_format):
 
1101
        """See BzrDir.get_workingtree_transport()."""
 
1102
        if workingtree_format is None:
 
1103
            return self.transport
 
1104
        try:
 
1105
            workingtree_format.get_format_string()
 
1106
        except NotImplementedError:
 
1107
            return self.transport
 
1108
        raise errors.IncompatibleFormat(workingtree_format, self._format)
 
1109
 
 
1110
    def needs_format_conversion(self, format=None):
 
1111
        """See BzrDir.needs_format_conversion()."""
 
1112
        # if the format is not the same as the system default,
 
1113
        # an upgrade is needed.
 
1114
        if format is None:
 
1115
            format = BzrDirFormat.get_default_format()
 
1116
        return not isinstance(self._format, format.__class__)
 
1117
 
 
1118
    def open_branch(self, unsupported=False):
 
1119
        """See BzrDir.open_branch."""
 
1120
        from bzrlib.branch import BzrBranchFormat4
 
1121
        format = BzrBranchFormat4()
 
1122
        self._check_supported(format, unsupported)
 
1123
        return format.open(self, _found=True)
 
1124
 
 
1125
    def sprout(self, url, revision_id=None, force_new_repo=False,
 
1126
               possible_transports=None, accelerator_tree=None,
 
1127
               hardlink=False):
 
1128
        """See BzrDir.sprout()."""
 
1129
        from bzrlib.workingtree import WorkingTreeFormat2
 
1130
        self._make_tail(url)
 
1131
        result = self._format._initialize_for_clone(url)
 
1132
        try:
 
1133
            self.open_repository().clone(result, revision_id=revision_id)
 
1134
        except errors.NoRepositoryPresent:
 
1135
            pass
 
1136
        try:
 
1137
            self.open_branch().sprout(result, revision_id=revision_id)
 
1138
        except errors.NotBranchError:
 
1139
            pass
 
1140
        # we always want a working tree
 
1141
        WorkingTreeFormat2().initialize(result,
 
1142
                                        accelerator_tree=accelerator_tree,
 
1143
                                        hardlink=hardlink)
 
1144
        return result
 
1145
 
 
1146
 
 
1147
class BzrDir4(BzrDirPreSplitOut):
 
1148
    """A .bzr version 4 control object.
 
1149
    
 
1150
    This is a deprecated format and may be removed after sept 2006.
 
1151
    """
 
1152
 
 
1153
    def create_repository(self, shared=False):
 
1154
        """See BzrDir.create_repository."""
 
1155
        return self._format.repository_format.initialize(self, shared)
 
1156
 
 
1157
    def needs_format_conversion(self, format=None):
 
1158
        """Format 4 dirs are always in need of conversion."""
 
1159
        return True
 
1160
 
 
1161
    def open_repository(self):
 
1162
        """See BzrDir.open_repository."""
 
1163
        from bzrlib.repofmt.weaverepo import RepositoryFormat4
 
1164
        return RepositoryFormat4().open(self, _found=True)
 
1165
 
 
1166
 
 
1167
class BzrDir5(BzrDirPreSplitOut):
 
1168
    """A .bzr version 5 control object.
 
1169
 
 
1170
    This is a deprecated format and may be removed after sept 2006.
 
1171
    """
 
1172
 
 
1173
    def open_repository(self):
 
1174
        """See BzrDir.open_repository."""
 
1175
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
 
1176
        return RepositoryFormat5().open(self, _found=True)
 
1177
 
 
1178
    def open_workingtree(self, _unsupported=False,
 
1179
            recommend_upgrade=True):
 
1180
        """See BzrDir.create_workingtree."""
 
1181
        from bzrlib.workingtree import WorkingTreeFormat2
 
1182
        wt_format = WorkingTreeFormat2()
 
1183
        # we don't warn here about upgrades; that ought to be handled for the
 
1184
        # bzrdir as a whole
 
1185
        return wt_format.open(self, _found=True)
 
1186
 
 
1187
 
 
1188
class BzrDir6(BzrDirPreSplitOut):
 
1189
    """A .bzr version 6 control object.
 
1190
 
 
1191
    This is a deprecated format and may be removed after sept 2006.
 
1192
    """
 
1193
 
 
1194
    def open_repository(self):
 
1195
        """See BzrDir.open_repository."""
 
1196
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
 
1197
        return RepositoryFormat6().open(self, _found=True)
 
1198
 
 
1199
    def open_workingtree(self, _unsupported=False,
 
1200
        recommend_upgrade=True):
 
1201
        """See BzrDir.create_workingtree."""
 
1202
        # we don't warn here about upgrades; that ought to be handled for the
 
1203
        # bzrdir as a whole
 
1204
        from bzrlib.workingtree import WorkingTreeFormat2
 
1205
        return WorkingTreeFormat2().open(self, _found=True)
773
1206
 
774
1207
 
775
1208
class BzrDirMeta1(BzrDir):
776
1209
    """A .bzr meta version 1 control object.
777
 
 
778
 
    This is the first control object where the
 
1210
    
 
1211
    This is the first control object where the 
779
1212
    individual aspects are really split out: there are separate repository,
780
1213
    workingtree and branch subdirectories and any subset of the three can be
781
1214
    present within a BzrDir.
785
1218
        """See BzrDir.can_convert_format()."""
786
1219
        return True
787
1220
 
788
 
    def create_branch(self, name=None, repository=None,
789
 
            append_revisions_only=None):
 
1221
    def create_branch(self):
790
1222
        """See BzrDir.create_branch."""
791
 
        return self._format.get_branch_format().initialize(self, name=name,
792
 
                repository=repository,
793
 
                append_revisions_only=append_revisions_only)
 
1223
        return self._format.get_branch_format().initialize(self)
794
1224
 
795
 
    def destroy_branch(self, name=None):
 
1225
    def destroy_branch(self):
796
1226
        """See BzrDir.create_branch."""
797
 
        if name is not None:
798
 
            raise errors.NoColocatedBranchSupport(self)
799
1227
        self.transport.delete_tree('branch')
800
1228
 
801
1229
    def create_repository(self, shared=False):
818
1246
        wt = self.open_workingtree(recommend_upgrade=False)
819
1247
        repository = wt.branch.repository
820
1248
        empty = repository.revision_tree(_mod_revision.NULL_REVISION)
821
 
        # We ignore the conflicts returned by wt.revert since we're about to
822
 
        # delete the wt metadata anyway, all that should be left here are
823
 
        # detritus. But see bug #634470 about subtree .bzr dirs.
824
 
        conflicts = wt.revert(old_tree=empty)
 
1249
        wt.revert(old_tree=empty)
825
1250
        self.destroy_workingtree_metadata()
826
1251
 
827
1252
    def destroy_workingtree_metadata(self):
828
1253
        self.transport.delete_tree('checkout')
829
1254
 
830
 
    def find_branch_format(self, name=None):
 
1255
    def find_branch_format(self):
831
1256
        """Find the branch 'format' for this bzrdir.
832
1257
 
833
1258
        This might be a synthetic object for e.g. RemoteBranch and SVN.
834
1259
        """
835
1260
        from bzrlib.branch import BranchFormat
836
 
        return BranchFormat.find_format(self, name=name)
 
1261
        return BranchFormat.find_format(self)
837
1262
 
838
1263
    def _get_mkdir_mode(self):
839
1264
        """Figure out the mode to use when creating a bzrdir subdir."""
841
1266
                                     lockable_files.TransportLock)
842
1267
        return temp_control._dir_mode
843
1268
 
844
 
    def get_branch_reference(self, name=None):
 
1269
    def get_branch_reference(self):
845
1270
        """See BzrDir.get_branch_reference()."""
846
1271
        from bzrlib.branch import BranchFormat
847
 
        format = BranchFormat.find_format(self, name=name)
848
 
        return format.get_reference(self, name=name)
 
1272
        format = BranchFormat.find_format(self)
 
1273
        return format.get_reference(self)
849
1274
 
850
 
    def get_branch_transport(self, branch_format, name=None):
 
1275
    def get_branch_transport(self, branch_format):
851
1276
        """See BzrDir.get_branch_transport()."""
852
 
        if name is not None:
853
 
            raise errors.NoColocatedBranchSupport(self)
854
 
        # XXX: this shouldn't implicitly create the directory if it's just
855
 
        # promising to get a transport -- mbp 20090727
856
1277
        if branch_format is None:
857
1278
            return self.transport.clone('branch')
858
1279
        try:
893
1314
            pass
894
1315
        return self.transport.clone('checkout')
895
1316
 
896
 
    def has_workingtree(self):
897
 
        """Tell if this bzrdir contains a working tree.
898
 
 
899
 
        Note: if you're going to open the working tree, you should just go
900
 
        ahead and try, and not ask permission first.
901
 
        """
902
 
        from bzrlib.workingtree import WorkingTreeFormat
903
 
        try:
904
 
            WorkingTreeFormat.find_format_string(self)
905
 
        except errors.NoWorkingTree:
906
 
            return False
907
 
        return True
908
 
 
909
 
    def needs_format_conversion(self, format):
 
1317
    def needs_format_conversion(self, format=None):
910
1318
        """See BzrDir.needs_format_conversion()."""
911
 
        if (not isinstance(self._format, format.__class__) or
912
 
            self._format.get_format_string() != format.get_format_string()):
 
1319
        if format is None:
 
1320
            format = BzrDirFormat.get_default_format()
 
1321
        if not isinstance(self._format, format.__class__):
913
1322
            # it is not a meta dir format, conversion is needed.
914
1323
            return True
915
1324
        # we might want to push this down to the repository?
920
1329
                return True
921
1330
        except errors.NoRepositoryPresent:
922
1331
            pass
923
 
        for branch in self.list_branches():
924
 
            if not isinstance(branch._format,
 
1332
        try:
 
1333
            if not isinstance(self.open_branch()._format,
925
1334
                              format.get_branch_format().__class__):
926
1335
                # the branch needs an upgrade.
927
1336
                return True
 
1337
        except errors.NotBranchError:
 
1338
            pass
928
1339
        try:
929
1340
            my_wt = self.open_workingtree(recommend_upgrade=False)
930
1341
            if not isinstance(my_wt._format,
935
1346
            pass
936
1347
        return False
937
1348
 
938
 
    def open_branch(self, name=None, unsupported=False,
939
 
                    ignore_fallbacks=False):
 
1349
    def open_branch(self, unsupported=False):
940
1350
        """See BzrDir.open_branch."""
941
 
        format = self.find_branch_format(name=name)
942
 
        format.check_support_status(unsupported)
943
 
        return format.open(self, name=name,
944
 
            _found=True, ignore_fallbacks=ignore_fallbacks)
 
1351
        format = self.find_branch_format()
 
1352
        self._check_supported(format, unsupported)
 
1353
        return format.open(self, _found=True)
945
1354
 
946
1355
    def open_repository(self, unsupported=False):
947
1356
        """See BzrDir.open_repository."""
948
1357
        from bzrlib.repository import RepositoryFormat
949
1358
        format = RepositoryFormat.find_format(self)
950
 
        format.check_support_status(unsupported)
 
1359
        self._check_supported(format, unsupported)
951
1360
        return format.open(self, _found=True)
952
1361
 
953
1362
    def open_workingtree(self, unsupported=False,
955
1364
        """See BzrDir.open_workingtree."""
956
1365
        from bzrlib.workingtree import WorkingTreeFormat
957
1366
        format = WorkingTreeFormat.find_format(self)
958
 
        format.check_support_status(unsupported, recommend_upgrade,
 
1367
        self._check_supported(format, unsupported,
 
1368
            recommend_upgrade,
959
1369
            basedir=self.root_transport.base)
960
1370
        return format.open(self, _found=True)
961
1371
 
962
 
    def _get_config(self):
963
 
        return config.TransportConfig(self.transport, 'control.conf')
964
 
 
965
 
 
966
 
class BzrDirMeta1Colo(BzrDirMeta1):
967
 
    """BzrDirMeta1 with support for colocated branches.
968
 
 
969
 
    This format is experimental, and will eventually be merged back into
970
 
    BzrDirMeta1.
971
 
    """
972
 
 
973
 
    def __init__(self, _transport, _format):
974
 
        super(BzrDirMeta1Colo, self).__init__(_transport, _format)
975
 
        self.control_files = lockable_files.LockableFiles(_transport,
976
 
            self._format._lock_file_name, self._format._lock_class)
977
 
 
978
 
    def _get_branch_path(self, name):
979
 
        """Obtain the branch path to use.
980
 
 
981
 
        This uses the API specified branch name first, and then falls back to
982
 
        the branch name specified in the URL. If neither of those is specified,
983
 
        it uses the default branch.
984
 
 
985
 
        :param name: Optional branch name to use
986
 
        :return: Relative path to branch, branch name
987
 
        """
988
 
        if name is None:
989
 
            name = self._get_selected_branch()
990
 
        if name is None:
991
 
            return 'branch', None
992
 
        return urlutils.join('branches', name), name
993
 
 
994
 
    def _read_branch_list(self):
995
 
        """Read the branch list.
996
 
 
997
 
        :return: List of utf-8 encoded branch names.
998
 
        """
999
 
        try:
1000
 
            f = self.control_transport.get('branch-list')
1001
 
        except errors.NoSuchFile:
1002
 
            return []
1003
 
 
1004
 
        ret = []
1005
 
        try:
1006
 
            for name in f:
1007
 
                ret.append(name.rstrip("\n"))
1008
 
        finally:
1009
 
            f.close()
1010
 
        return ret
1011
 
 
1012
 
    def _write_branch_list(self, branches):
1013
 
        """Write out the branch list.
1014
 
 
1015
 
        :param branches: List of utf-8 branch names to write
1016
 
        """
1017
 
        self.transport.put_bytes('branch-list',
1018
 
            "".join([name+"\n" for name in branches]))
1019
 
 
1020
 
    def destroy_branch(self, name=None):
1021
 
        """See BzrDir.create_branch."""
1022
 
        path, name = self._get_branch_path(name)
1023
 
        if name is not None:
1024
 
            self.control_files.lock_write()
1025
 
            try:
1026
 
                branches = self._read_branch_list()
1027
 
                try:
1028
 
                    branches.remove(name)
1029
 
                except ValueError:
1030
 
                    raise errors.NotBranchError(name)
1031
 
                self._write_branch_list(name)
1032
 
            finally:
1033
 
                self.control_files.unlock()
1034
 
        self.transport.delete_tree(path)
1035
 
 
1036
 
    def list_branches(self):
1037
 
        """See ControlDir.list_branches."""
1038
 
        ret = []
1039
 
        # Default branch
1040
 
        try:
1041
 
            ret.append(self.open_branch())
1042
 
        except (errors.NotBranchError, errors.NoRepositoryPresent):
1043
 
            pass
1044
 
 
1045
 
        # colocated branches
1046
 
        ret.extend([self.open_branch(name) for name in
1047
 
                    self._read_branch_list()])
1048
 
 
1049
 
        return ret
1050
 
 
1051
 
    def get_branch_transport(self, branch_format, name=None):
1052
 
        """See BzrDir.get_branch_transport()."""
1053
 
        path, name = self._get_branch_path(name)
1054
 
        # XXX: this shouldn't implicitly create the directory if it's just
1055
 
        # promising to get a transport -- mbp 20090727
1056
 
        if branch_format is None:
1057
 
            return self.transport.clone(path)
1058
 
        try:
1059
 
            branch_format.get_format_string()
1060
 
        except NotImplementedError:
1061
 
            raise errors.IncompatibleFormat(branch_format, self._format)
1062
 
        if name is not None:
1063
 
            try:
1064
 
                self.transport.mkdir('branches', mode=self._get_mkdir_mode())
1065
 
            except errors.FileExists:
1066
 
                pass
1067
 
            branches = self._read_branch_list()
1068
 
            if not name in branches:
1069
 
                self.control_files.lock_write()
1070
 
                try:
1071
 
                    branches = self._read_branch_list()
1072
 
                    branches.append(name)
1073
 
                    self._write_branch_list(branches)
1074
 
                finally:
1075
 
                    self.control_files.unlock()
1076
 
        try:
1077
 
            self.transport.mkdir(path, mode=self._get_mkdir_mode())
1078
 
        except errors.FileExists:
1079
 
            pass
1080
 
        return self.transport.clone(path)
1081
 
 
1082
 
 
1083
 
class BzrProber(controldir.Prober):
1084
 
    """Prober for formats that use a .bzr/ control directory."""
1085
 
 
1086
 
    formats = registry.FormatRegistry(controldir.network_format_registry)
1087
 
    """The known .bzr formats."""
1088
 
 
1089
 
    @classmethod
1090
 
    @deprecated_method(deprecated_in((2, 4, 0)))
1091
 
    def register_bzrdir_format(klass, format):
1092
 
        klass.formats.register(format.get_format_string(), format)
1093
 
 
1094
 
    @classmethod
1095
 
    @deprecated_method(deprecated_in((2, 4, 0)))
1096
 
    def unregister_bzrdir_format(klass, format):
1097
 
        klass.formats.remove(format.get_format_string())
1098
 
 
1099
 
    @classmethod
1100
 
    def probe_transport(klass, transport):
1101
 
        """Return the .bzrdir style format present in a directory."""
1102
 
        try:
1103
 
            format_string = transport.get_bytes(".bzr/branch-format")
1104
 
        except errors.NoSuchFile:
1105
 
            raise errors.NotBranchError(path=transport.base)
1106
 
        try:
1107
 
            return klass.formats.get(format_string)
1108
 
        except KeyError:
1109
 
            raise errors.UnknownFormatError(format=format_string, kind='bzrdir')
1110
 
 
1111
 
    @classmethod
1112
 
    def known_formats(cls):
1113
 
        result = set()
1114
 
        for name, format in cls.formats.iteritems():
1115
 
            if callable(format):
1116
 
                format = format()
1117
 
            result.add(format)
1118
 
        return result
1119
 
 
1120
 
 
1121
 
controldir.ControlDirFormat.register_prober(BzrProber)
1122
 
 
1123
 
 
1124
 
class RemoteBzrProber(controldir.Prober):
1125
 
    """Prober for remote servers that provide a Bazaar smart server."""
1126
 
 
1127
 
    @classmethod
1128
 
    def probe_transport(klass, transport):
1129
 
        """Return a RemoteBzrDirFormat object if it looks possible."""
1130
 
        try:
1131
 
            medium = transport.get_smart_medium()
1132
 
        except (NotImplementedError, AttributeError,
1133
 
                errors.TransportNotPossible, errors.NoSmartMedium,
1134
 
                errors.SmartProtocolError):
1135
 
            # no smart server, so not a branch for this format type.
1136
 
            raise errors.NotBranchError(path=transport.base)
1137
 
        else:
1138
 
            # Decline to open it if the server doesn't support our required
1139
 
            # version (3) so that the VFS-based transport will do it.
1140
 
            if medium.should_probe():
1141
 
                try:
1142
 
                    server_version = medium.protocol_version()
1143
 
                except errors.SmartProtocolError:
1144
 
                    # Apparently there's no usable smart server there, even though
1145
 
                    # the medium supports the smart protocol.
1146
 
                    raise errors.NotBranchError(path=transport.base)
1147
 
                if server_version != '2':
1148
 
                    raise errors.NotBranchError(path=transport.base)
1149
 
            from bzrlib.remote import RemoteBzrDirFormat
1150
 
            return RemoteBzrDirFormat()
1151
 
 
1152
 
    @classmethod
1153
 
    def known_formats(cls):
1154
 
        from bzrlib.remote import RemoteBzrDirFormat
1155
 
        return set([RemoteBzrDirFormat()])
1156
 
 
1157
 
 
1158
 
class BzrDirFormat(controldir.ControlDirFormat):
1159
 
    """ControlDirFormat base class for .bzr/ directories.
1160
 
 
1161
 
    Formats are placed in a dict by their format string for reference
 
1372
 
 
1373
class BzrDirFormat(object):
 
1374
    """An encapsulation of the initialization and open routines for a format.
 
1375
 
 
1376
    Formats provide three things:
 
1377
     * An initialization routine,
 
1378
     * a format string,
 
1379
     * an open routine.
 
1380
 
 
1381
    Formats are placed in a dict by their format string for reference 
1162
1382
    during bzrdir opening. These should be subclasses of BzrDirFormat
1163
1383
    for consistency.
1164
1384
 
1165
1385
    Once a format is deprecated, just deprecate the initialize and open
1166
 
    methods on the format class. Do not deprecate the object, as the
 
1386
    methods on the format class. Do not deprecate the object, as the 
1167
1387
    object will be created every system load.
1168
1388
    """
1169
1389
 
 
1390
    _default_format = None
 
1391
    """The default format used for new .bzr dirs."""
 
1392
 
 
1393
    _formats = {}
 
1394
    """The known formats."""
 
1395
 
 
1396
    _control_formats = []
 
1397
    """The registered control formats - .bzr, ....
 
1398
    
 
1399
    This is a list of BzrDirFormat objects.
 
1400
    """
 
1401
 
 
1402
    _control_server_formats = []
 
1403
    """The registered control server formats, e.g. RemoteBzrDirs.
 
1404
 
 
1405
    This is a list of BzrDirFormat objects.
 
1406
    """
 
1407
 
1170
1408
    _lock_file_name = 'branch-lock'
1171
1409
 
1172
1410
    # _lock_class must be set in subclasses to the lock type, typ.
1173
1411
    # TransportLock or LockDir
1174
1412
 
1175
1413
    @classmethod
1176
 
    def get_format_string(cls):
 
1414
    def find_format(klass, transport, _server_formats=True):
 
1415
        """Return the format present at transport."""
 
1416
        if _server_formats:
 
1417
            formats = klass._control_server_formats + klass._control_formats
 
1418
        else:
 
1419
            formats = klass._control_formats
 
1420
        for format in formats:
 
1421
            try:
 
1422
                return format.probe_transport(transport)
 
1423
            except errors.NotBranchError:
 
1424
                # this format does not find a control dir here.
 
1425
                pass
 
1426
        raise errors.NotBranchError(path=transport.base)
 
1427
 
 
1428
    @classmethod
 
1429
    def probe_transport(klass, transport):
 
1430
        """Return the .bzrdir style format present in a directory."""
 
1431
        try:
 
1432
            format_string = transport.get(".bzr/branch-format").read()
 
1433
        except errors.NoSuchFile:
 
1434
            raise errors.NotBranchError(path=transport.base)
 
1435
 
 
1436
        try:
 
1437
            return klass._formats[format_string]
 
1438
        except KeyError:
 
1439
            raise errors.UnknownFormatError(format=format_string, kind='bzrdir')
 
1440
 
 
1441
    @classmethod
 
1442
    def get_default_format(klass):
 
1443
        """Return the current default format."""
 
1444
        return klass._default_format
 
1445
 
 
1446
    def get_format_string(self):
1177
1447
        """Return the ASCII format string that identifies this format."""
1178
 
        raise NotImplementedError(cls.get_format_string)
 
1448
        raise NotImplementedError(self.get_format_string)
 
1449
 
 
1450
    def get_format_description(self):
 
1451
        """Return the short description for this format."""
 
1452
        raise NotImplementedError(self.get_format_description)
 
1453
 
 
1454
    def get_converter(self, format=None):
 
1455
        """Return the converter to use to convert bzrdirs needing converts.
 
1456
 
 
1457
        This returns a bzrlib.bzrdir.Converter object.
 
1458
 
 
1459
        This should return the best upgrader to step this format towards the
 
1460
        current default format. In the case of plugins we can/should provide
 
1461
        some means for them to extend the range of returnable converters.
 
1462
 
 
1463
        :param format: Optional format to override the default format of the 
 
1464
                       library.
 
1465
        """
 
1466
        raise NotImplementedError(self.get_converter)
 
1467
 
 
1468
    def initialize(self, url, possible_transports=None):
 
1469
        """Create a bzr control dir at this url and return an opened copy.
 
1470
        
 
1471
        Subclasses should typically override initialize_on_transport
 
1472
        instead of this method.
 
1473
        """
 
1474
        return self.initialize_on_transport(get_transport(url,
 
1475
                                                          possible_transports))
1179
1476
 
1180
1477
    def initialize_on_transport(self, transport):
1181
1478
        """Initialize a new bzrdir in the base directory of a Transport."""
1182
 
        try:
1183
 
            # can we hand off the request to the smart server rather than using
1184
 
            # vfs calls?
1185
 
            client_medium = transport.get_smart_medium()
1186
 
        except errors.NoSmartMedium:
1187
 
            return self._initialize_on_transport_vfs(transport)
1188
 
        else:
1189
 
            # Current RPC's only know how to create bzr metadir1 instances, so
1190
 
            # we still delegate to vfs methods if the requested format is not a
1191
 
            # metadir1
1192
 
            if type(self) != BzrDirMetaFormat1:
1193
 
                return self._initialize_on_transport_vfs(transport)
1194
 
            from bzrlib.remote import RemoteBzrDirFormat
1195
 
            remote_format = RemoteBzrDirFormat()
1196
 
            self._supply_sub_formats_to(remote_format)
1197
 
            return remote_format.initialize_on_transport(transport)
1198
 
 
1199
 
    def initialize_on_transport_ex(self, transport, use_existing_dir=False,
1200
 
        create_prefix=False, force_new_repo=False, stacked_on=None,
1201
 
        stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
1202
 
        shared_repo=False, vfs_only=False):
1203
 
        """Create this format on transport.
1204
 
 
1205
 
        The directory to initialize will be created.
1206
 
 
1207
 
        :param force_new_repo: Do not use a shared repository for the target,
1208
 
                               even if one is available.
1209
 
        :param create_prefix: Create any missing directories leading up to
1210
 
            to_transport.
1211
 
        :param use_existing_dir: Use an existing directory if one exists.
1212
 
        :param stacked_on: A url to stack any created branch on, None to follow
1213
 
            any target stacking policy.
1214
 
        :param stack_on_pwd: If stack_on is relative, the location it is
1215
 
            relative to.
1216
 
        :param repo_format_name: If non-None, a repository will be
1217
 
            made-or-found. Should none be found, or if force_new_repo is True
1218
 
            the repo_format_name is used to select the format of repository to
1219
 
            create.
1220
 
        :param make_working_trees: Control the setting of make_working_trees
1221
 
            for a new shared repository when one is made. None to use whatever
1222
 
            default the format has.
1223
 
        :param shared_repo: Control whether made repositories are shared or
1224
 
            not.
1225
 
        :param vfs_only: If True do not attempt to use a smart server
1226
 
        :return: repo, bzrdir, require_stacking, repository_policy. repo is
1227
 
            None if none was created or found, bzrdir is always valid.
1228
 
            require_stacking is the result of examining the stacked_on
1229
 
            parameter and any stacking policy found for the target.
1230
 
        """
1231
 
        if not vfs_only:
1232
 
            # Try to hand off to a smart server 
1233
 
            try:
1234
 
                client_medium = transport.get_smart_medium()
1235
 
            except errors.NoSmartMedium:
1236
 
                pass
1237
 
            else:
1238
 
                from bzrlib.remote import RemoteBzrDirFormat
1239
 
                # TODO: lookup the local format from a server hint.
1240
 
                remote_dir_format = RemoteBzrDirFormat()
1241
 
                remote_dir_format._network_name = self.network_name()
1242
 
                self._supply_sub_formats_to(remote_dir_format)
1243
 
                return remote_dir_format.initialize_on_transport_ex(transport,
1244
 
                    use_existing_dir=use_existing_dir, create_prefix=create_prefix,
1245
 
                    force_new_repo=force_new_repo, stacked_on=stacked_on,
1246
 
                    stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
1247
 
                    make_working_trees=make_working_trees, shared_repo=shared_repo)
1248
 
        # XXX: Refactor the create_prefix/no_create_prefix code into a
1249
 
        #      common helper function
1250
 
        # The destination may not exist - if so make it according to policy.
1251
 
        def make_directory(transport):
1252
 
            transport.mkdir('.')
1253
 
            return transport
1254
 
        def redirected(transport, e, redirection_notice):
1255
 
            note(redirection_notice)
1256
 
            return transport._redirected_to(e.source, e.target)
1257
 
        try:
1258
 
            transport = do_catching_redirections(make_directory, transport,
1259
 
                redirected)
1260
 
        except errors.FileExists:
1261
 
            if not use_existing_dir:
1262
 
                raise
1263
 
        except errors.NoSuchFile:
1264
 
            if not create_prefix:
1265
 
                raise
1266
 
            transport.create_prefix()
1267
 
 
1268
 
        require_stacking = (stacked_on is not None)
1269
 
        # Now the target directory exists, but doesn't have a .bzr
1270
 
        # directory. So we need to create it, along with any work to create
1271
 
        # all of the dependent branches, etc.
1272
 
 
1273
 
        result = self.initialize_on_transport(transport)
1274
 
        if repo_format_name:
1275
 
            try:
1276
 
                # use a custom format
1277
 
                result._format.repository_format = \
1278
 
                    repository.network_format_registry.get(repo_format_name)
1279
 
            except AttributeError:
1280
 
                # The format didn't permit it to be set.
1281
 
                pass
1282
 
            # A repository is desired, either in-place or shared.
1283
 
            repository_policy = result.determine_repository_policy(
1284
 
                force_new_repo, stacked_on, stack_on_pwd,
1285
 
                require_stacking=require_stacking)
1286
 
            result_repo, is_new_repo = repository_policy.acquire_repository(
1287
 
                make_working_trees, shared_repo)
1288
 
            if not require_stacking and repository_policy._require_stacking:
1289
 
                require_stacking = True
1290
 
                result._format.require_stacking()
1291
 
            result_repo.lock_write()
1292
 
        else:
1293
 
            result_repo = None
1294
 
            repository_policy = None
1295
 
        return result_repo, result, require_stacking, repository_policy
1296
 
 
1297
 
    def _initialize_on_transport_vfs(self, transport):
1298
 
        """Initialize a new bzrdir using VFS calls.
1299
 
 
1300
 
        :param transport: The transport to create the .bzr directory in.
1301
 
        :return: A
1302
 
        """
1303
 
        # Since we are creating a .bzr directory, inherit the
 
1479
        # Since we don't have a .bzr directory, inherit the
1304
1480
        # mode from the root directory
1305
1481
        temp_control = lockable_files.LockableFiles(transport,
1306
1482
                            '', lockable_files.TransportLock)
1308
1484
                                      # FIXME: RBC 20060121 don't peek under
1309
1485
                                      # the covers
1310
1486
                                      mode=temp_control._dir_mode)
1311
 
        if sys.platform == 'win32' and isinstance(transport, local.LocalTransport):
 
1487
        if sys.platform == 'win32' and isinstance(transport, LocalTransport):
1312
1488
            win32utils.set_file_attr_hidden(transport._abspath('.bzr'))
1313
1489
        file_mode = temp_control._file_mode
1314
1490
        del temp_control
1315
 
        bzrdir_transport = transport.clone('.bzr')
1316
 
        utf8_files = [('README',
 
1491
        mutter('created control directory in ' + transport.base)
 
1492
        control = transport.clone('.bzr')
 
1493
        utf8_files = [('README', 
1317
1494
                       "This is a Bazaar control directory.\n"
1318
1495
                       "Do not change any files in this directory.\n"
1319
 
                       "See http://bazaar.canonical.com/ for more information about Bazaar.\n"),
 
1496
                       "See http://bazaar-vcs.org/ for more information about Bazaar.\n"),
1320
1497
                      ('branch-format', self.get_format_string()),
1321
1498
                      ]
1322
1499
        # NB: no need to escape relative paths that are url safe.
1323
 
        control_files = lockable_files.LockableFiles(bzrdir_transport,
1324
 
            self._lock_file_name, self._lock_class)
 
1500
        control_files = lockable_files.LockableFiles(control,
 
1501
                            self._lock_file_name, self._lock_class)
1325
1502
        control_files.create_lock()
1326
1503
        control_files.lock_write()
1327
1504
        try:
1328
 
            for (filename, content) in utf8_files:
1329
 
                bzrdir_transport.put_bytes(filename, content,
1330
 
                    mode=file_mode)
 
1505
            for file, content in utf8_files:
 
1506
                control_files.put_utf8(file, content)
1331
1507
        finally:
1332
1508
            control_files.unlock()
1333
1509
        return self.open(transport, _found=True)
1334
1510
 
 
1511
    def is_supported(self):
 
1512
        """Is this format supported?
 
1513
 
 
1514
        Supported formats must be initializable and openable.
 
1515
        Unsupported formats may not support initialization or committing or 
 
1516
        some other features depending on the reason for not being supported.
 
1517
        """
 
1518
        return True
 
1519
 
 
1520
    def same_model(self, target_format):
 
1521
        return (self.repository_format.rich_root_data == 
 
1522
            target_format.rich_root_data)
 
1523
 
 
1524
    @classmethod
 
1525
    def known_formats(klass):
 
1526
        """Return all the known formats.
 
1527
        
 
1528
        Concrete formats should override _known_formats.
 
1529
        """
 
1530
        # There is double indirection here to make sure that control 
 
1531
        # formats used by more than one dir format will only be probed 
 
1532
        # once. This can otherwise be quite expensive for remote connections.
 
1533
        result = set()
 
1534
        for format in klass._control_formats:
 
1535
            result.update(format._known_formats())
 
1536
        return result
 
1537
    
 
1538
    @classmethod
 
1539
    def _known_formats(klass):
 
1540
        """Return the known format instances for this control format."""
 
1541
        return set(klass._formats.values())
 
1542
 
1335
1543
    def open(self, transport, _found=False):
1336
1544
        """Return an instance of this format for the dir transport points at.
1337
 
 
 
1545
        
1338
1546
        _found is a private parameter, do not use it.
1339
1547
        """
1340
1548
        if not _found:
1341
 
            found_format = controldir.ControlDirFormat.find_format(transport)
 
1549
            found_format = BzrDirFormat.find_format(transport)
1342
1550
            if not isinstance(found_format, self.__class__):
1343
1551
                raise AssertionError("%s was asked to open %s, but it seems to need "
1344
 
                        "format %s"
 
1552
                        "format %s" 
1345
1553
                        % (self, transport, found_format))
1346
 
            # Allow subclasses - use the found format.
1347
 
            self._supply_sub_formats_to(found_format)
1348
 
            return found_format._open(transport)
1349
1554
        return self._open(transport)
1350
1555
 
1351
1556
    def _open(self, transport):
1356
1561
        """
1357
1562
        raise NotImplementedError(self._open)
1358
1563
 
1359
 
    def _supply_sub_formats_to(self, other_format):
1360
 
        """Give other_format the same values for sub formats as this has.
1361
 
 
1362
 
        This method is expected to be used when parameterising a
1363
 
        RemoteBzrDirFormat instance with the parameters from a
1364
 
        BzrDirMetaFormat1 instance.
1365
 
 
1366
 
        :param other_format: other_format is a format which should be
1367
 
            compatible with whatever sub formats are supported by self.
1368
 
        :return: None.
1369
 
        """
1370
 
 
1371
 
    def supports_transport(self, transport):
1372
 
        # bzr formats can be opened over all known transports
1373
 
        return True
 
1564
    @classmethod
 
1565
    def register_format(klass, format):
 
1566
        klass._formats[format.get_format_string()] = format
 
1567
 
 
1568
    @classmethod
 
1569
    def register_control_format(klass, format):
 
1570
        """Register a format that does not use '.bzr' for its control dir.
 
1571
 
 
1572
        TODO: This should be pulled up into a 'ControlDirFormat' base class
 
1573
        which BzrDirFormat can inherit from, and renamed to register_format 
 
1574
        there. It has been done without that for now for simplicity of
 
1575
        implementation.
 
1576
        """
 
1577
        klass._control_formats.append(format)
 
1578
 
 
1579
    @classmethod
 
1580
    def register_control_server_format(klass, format):
 
1581
        """Register a control format for client-server environments.
 
1582
 
 
1583
        These formats will be tried before ones registered with
 
1584
        register_control_format.  This gives implementations that decide to the
 
1585
        chance to grab it before anything looks at the contents of the format
 
1586
        file.
 
1587
        """
 
1588
        klass._control_server_formats.append(format)
 
1589
 
 
1590
    @classmethod
 
1591
    @symbol_versioning.deprecated_method(symbol_versioning.zero_fourteen)
 
1592
    def set_default_format(klass, format):
 
1593
        klass._set_default_format(format)
 
1594
 
 
1595
    @classmethod
 
1596
    def _set_default_format(klass, format):
 
1597
        """Set default format (for testing behavior of defaults only)"""
 
1598
        klass._default_format = format
 
1599
 
 
1600
    def __str__(self):
 
1601
        # Trim the newline
 
1602
        return self.get_format_string().rstrip()
 
1603
 
 
1604
    @classmethod
 
1605
    def unregister_format(klass, format):
 
1606
        assert klass._formats[format.get_format_string()] is format
 
1607
        del klass._formats[format.get_format_string()]
 
1608
 
 
1609
    @classmethod
 
1610
    def unregister_control_format(klass, format):
 
1611
        klass._control_formats.remove(format)
 
1612
 
 
1613
 
 
1614
class BzrDirFormat4(BzrDirFormat):
 
1615
    """Bzr dir format 4.
 
1616
 
 
1617
    This format is a combined format for working tree, branch and repository.
 
1618
    It has:
 
1619
     - Format 1 working trees [always]
 
1620
     - Format 4 branches [always]
 
1621
     - Format 4 repositories [always]
 
1622
 
 
1623
    This format is deprecated: it indexes texts using a text it which is
 
1624
    removed in format 5; write support for this format has been removed.
 
1625
    """
 
1626
 
 
1627
    _lock_class = lockable_files.TransportLock
 
1628
 
 
1629
    def get_format_string(self):
 
1630
        """See BzrDirFormat.get_format_string()."""
 
1631
        return "Bazaar-NG branch, format 0.0.4\n"
 
1632
 
 
1633
    def get_format_description(self):
 
1634
        """See BzrDirFormat.get_format_description()."""
 
1635
        return "All-in-one format 4"
 
1636
 
 
1637
    def get_converter(self, format=None):
 
1638
        """See BzrDirFormat.get_converter()."""
 
1639
        # there is one and only one upgrade path here.
 
1640
        return ConvertBzrDir4To5()
 
1641
        
 
1642
    def initialize_on_transport(self, transport):
 
1643
        """Format 4 branches cannot be created."""
 
1644
        raise errors.UninitializableFormat(self)
 
1645
 
 
1646
    def is_supported(self):
 
1647
        """Format 4 is not supported.
 
1648
 
 
1649
        It is not supported because the model changed from 4 to 5 and the
 
1650
        conversion logic is expensive - so doing it on the fly was not 
 
1651
        feasible.
 
1652
        """
 
1653
        return False
 
1654
 
 
1655
    def _open(self, transport):
 
1656
        """See BzrDirFormat._open."""
 
1657
        return BzrDir4(transport, self)
 
1658
 
 
1659
    def __return_repository_format(self):
 
1660
        """Circular import protection."""
 
1661
        from bzrlib.repofmt.weaverepo import RepositoryFormat4
 
1662
        return RepositoryFormat4()
 
1663
    repository_format = property(__return_repository_format)
 
1664
 
 
1665
 
 
1666
class BzrDirFormat5(BzrDirFormat):
 
1667
    """Bzr control format 5.
 
1668
 
 
1669
    This format is a combined format for working tree, branch and repository.
 
1670
    It has:
 
1671
     - Format 2 working trees [always] 
 
1672
     - Format 4 branches [always] 
 
1673
     - Format 5 repositories [always]
 
1674
       Unhashed stores in the repository.
 
1675
    """
 
1676
 
 
1677
    _lock_class = lockable_files.TransportLock
 
1678
 
 
1679
    def get_format_string(self):
 
1680
        """See BzrDirFormat.get_format_string()."""
 
1681
        return "Bazaar-NG branch, format 5\n"
 
1682
 
 
1683
    def get_format_description(self):
 
1684
        """See BzrDirFormat.get_format_description()."""
 
1685
        return "All-in-one format 5"
 
1686
 
 
1687
    def get_converter(self, format=None):
 
1688
        """See BzrDirFormat.get_converter()."""
 
1689
        # there is one and only one upgrade path here.
 
1690
        return ConvertBzrDir5To6()
 
1691
 
 
1692
    def _initialize_for_clone(self, url):
 
1693
        return self.initialize_on_transport(get_transport(url), _cloning=True)
 
1694
        
 
1695
    def initialize_on_transport(self, transport, _cloning=False):
 
1696
        """Format 5 dirs always have working tree, branch and repository.
 
1697
        
 
1698
        Except when they are being cloned.
 
1699
        """
 
1700
        from bzrlib.branch import BzrBranchFormat4
 
1701
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
 
1702
        from bzrlib.workingtree import WorkingTreeFormat2
 
1703
        result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
 
1704
        RepositoryFormat5().initialize(result, _internal=True)
 
1705
        if not _cloning:
 
1706
            branch = BzrBranchFormat4().initialize(result)
 
1707
            try:
 
1708
                WorkingTreeFormat2().initialize(result)
 
1709
            except errors.NotLocalUrl:
 
1710
                # Even though we can't access the working tree, we need to
 
1711
                # create its control files.
 
1712
                WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
 
1713
        return result
 
1714
 
 
1715
    def _open(self, transport):
 
1716
        """See BzrDirFormat._open."""
 
1717
        return BzrDir5(transport, self)
 
1718
 
 
1719
    def __return_repository_format(self):
 
1720
        """Circular import protection."""
 
1721
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
 
1722
        return RepositoryFormat5()
 
1723
    repository_format = property(__return_repository_format)
 
1724
 
 
1725
 
 
1726
class BzrDirFormat6(BzrDirFormat):
 
1727
    """Bzr control format 6.
 
1728
 
 
1729
    This format is a combined format for working tree, branch and repository.
 
1730
    It has:
 
1731
     - Format 2 working trees [always] 
 
1732
     - Format 4 branches [always] 
 
1733
     - Format 6 repositories [always]
 
1734
    """
 
1735
 
 
1736
    _lock_class = lockable_files.TransportLock
 
1737
 
 
1738
    def get_format_string(self):
 
1739
        """See BzrDirFormat.get_format_string()."""
 
1740
        return "Bazaar-NG branch, format 6\n"
 
1741
 
 
1742
    def get_format_description(self):
 
1743
        """See BzrDirFormat.get_format_description()."""
 
1744
        return "All-in-one format 6"
 
1745
 
 
1746
    def get_converter(self, format=None):
 
1747
        """See BzrDirFormat.get_converter()."""
 
1748
        # there is one and only one upgrade path here.
 
1749
        return ConvertBzrDir6ToMeta()
 
1750
        
 
1751
    def _initialize_for_clone(self, url):
 
1752
        return self.initialize_on_transport(get_transport(url), _cloning=True)
 
1753
 
 
1754
    def initialize_on_transport(self, transport, _cloning=False):
 
1755
        """Format 6 dirs always have working tree, branch and repository.
 
1756
        
 
1757
        Except when they are being cloned.
 
1758
        """
 
1759
        from bzrlib.branch import BzrBranchFormat4
 
1760
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
 
1761
        from bzrlib.workingtree import WorkingTreeFormat2
 
1762
        result = super(BzrDirFormat6, self).initialize_on_transport(transport)
 
1763
        RepositoryFormat6().initialize(result, _internal=True)
 
1764
        if not _cloning:
 
1765
            branch = BzrBranchFormat4().initialize(result)
 
1766
            try:
 
1767
                WorkingTreeFormat2().initialize(result)
 
1768
            except errors.NotLocalUrl:
 
1769
                # Even though we can't access the working tree, we need to
 
1770
                # create its control files.
 
1771
                WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
 
1772
        return result
 
1773
 
 
1774
    def _open(self, transport):
 
1775
        """See BzrDirFormat._open."""
 
1776
        return BzrDir6(transport, self)
 
1777
 
 
1778
    def __return_repository_format(self):
 
1779
        """Circular import protection."""
 
1780
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
 
1781
        return RepositoryFormat6()
 
1782
    repository_format = property(__return_repository_format)
1374
1783
 
1375
1784
 
1376
1785
class BzrDirMetaFormat1(BzrDirFormat):
1378
1787
 
1379
1788
    This is the first format with split out working tree, branch and repository
1380
1789
    disk storage.
1381
 
 
1382
1790
    It has:
1383
 
 
1384
 
    - Format 3 working trees [optional]
1385
 
    - Format 5 branches [optional]
1386
 
    - Format 7 repositories [optional]
 
1791
     - Format 3 working trees [optional]
 
1792
     - Format 5 branches [optional]
 
1793
     - Format 7 repositories [optional]
1387
1794
    """
1388
1795
 
1389
1796
    _lock_class = lockdir.LockDir
1390
1797
 
1391
 
    fixed_components = False
1392
 
 
1393
 
    colocated_branches = False
1394
 
 
1395
1798
    def __init__(self):
1396
1799
        self._workingtree_format = None
1397
1800
        self._branch_format = None
1398
 
        self._repository_format = None
1399
1801
 
1400
1802
    def __eq__(self, other):
1401
1803
        if other.__class__ is not self.__class__:
1411
1813
 
1412
1814
    def get_branch_format(self):
1413
1815
        if self._branch_format is None:
1414
 
            from bzrlib.branch import format_registry as branch_format_registry
1415
 
            self._branch_format = branch_format_registry.get_default()
 
1816
            from bzrlib.branch import BranchFormat
 
1817
            self._branch_format = BranchFormat.get_default_format()
1416
1818
        return self._branch_format
1417
1819
 
1418
1820
    def set_branch_format(self, format):
1419
1821
        self._branch_format = format
1420
1822
 
1421
 
    def require_stacking(self, stack_on=None, possible_transports=None,
1422
 
            _skip_repo=False):
1423
 
        """We have a request to stack, try to ensure the formats support it.
1424
 
 
1425
 
        :param stack_on: If supplied, it is the URL to a branch that we want to
1426
 
            stack on. Check to see if that format supports stacking before
1427
 
            forcing an upgrade.
1428
 
        """
1429
 
        # Stacking is desired. requested by the target, but does the place it
1430
 
        # points at support stacking? If it doesn't then we should
1431
 
        # not implicitly upgrade. We check this here.
1432
 
        new_repo_format = None
1433
 
        new_branch_format = None
1434
 
 
1435
 
        # a bit of state for get_target_branch so that we don't try to open it
1436
 
        # 2 times, for both repo *and* branch
1437
 
        target = [None, False, None] # target_branch, checked, upgrade anyway
1438
 
        def get_target_branch():
1439
 
            if target[1]:
1440
 
                # We've checked, don't check again
1441
 
                return target
1442
 
            if stack_on is None:
1443
 
                # No target format, that means we want to force upgrading
1444
 
                target[:] = [None, True, True]
1445
 
                return target
1446
 
            try:
1447
 
                target_dir = BzrDir.open(stack_on,
1448
 
                    possible_transports=possible_transports)
1449
 
            except errors.NotBranchError:
1450
 
                # Nothing there, don't change formats
1451
 
                target[:] = [None, True, False]
1452
 
                return target
1453
 
            except errors.JailBreak:
1454
 
                # JailBreak, JFDI and upgrade anyway
1455
 
                target[:] = [None, True, True]
1456
 
                return target
1457
 
            try:
1458
 
                target_branch = target_dir.open_branch()
1459
 
            except errors.NotBranchError:
1460
 
                # No branch, don't upgrade formats
1461
 
                target[:] = [None, True, False]
1462
 
                return target
1463
 
            target[:] = [target_branch, True, False]
1464
 
            return target
1465
 
 
1466
 
        if (not _skip_repo and
1467
 
                 not self.repository_format.supports_external_lookups):
1468
 
            # We need to upgrade the Repository.
1469
 
            target_branch, _, do_upgrade = get_target_branch()
1470
 
            if target_branch is None:
1471
 
                # We don't have a target branch, should we upgrade anyway?
1472
 
                if do_upgrade:
1473
 
                    # stack_on is inaccessible, JFDI.
1474
 
                    # TODO: bad monkey, hard-coded formats...
1475
 
                    if self.repository_format.rich_root_data:
1476
 
                        new_repo_format = knitpack_repo.RepositoryFormatKnitPack5RichRoot()
1477
 
                    else:
1478
 
                        new_repo_format = knitpack_repo.RepositoryFormatKnitPack5()
1479
 
            else:
1480
 
                # If the target already supports stacking, then we know the
1481
 
                # project is already able to use stacking, so auto-upgrade
1482
 
                # for them
1483
 
                new_repo_format = target_branch.repository._format
1484
 
                if not new_repo_format.supports_external_lookups:
1485
 
                    # target doesn't, source doesn't, so don't auto upgrade
1486
 
                    # repo
1487
 
                    new_repo_format = None
1488
 
            if new_repo_format is not None:
1489
 
                self.repository_format = new_repo_format
1490
 
                note(gettext('Source repository format does not support stacking,'
1491
 
                     ' using format:\n  %s'),
1492
 
                     new_repo_format.get_format_description())
1493
 
 
1494
 
        if not self.get_branch_format().supports_stacking():
1495
 
            # We just checked the repo, now lets check if we need to
1496
 
            # upgrade the branch format
1497
 
            target_branch, _, do_upgrade = get_target_branch()
1498
 
            if target_branch is None:
1499
 
                if do_upgrade:
1500
 
                    # TODO: bad monkey, hard-coded formats...
1501
 
                    from bzrlib.branch import BzrBranchFormat7
1502
 
                    new_branch_format = BzrBranchFormat7()
1503
 
            else:
1504
 
                new_branch_format = target_branch._format
1505
 
                if not new_branch_format.supports_stacking():
1506
 
                    new_branch_format = None
1507
 
            if new_branch_format is not None:
1508
 
                # Does support stacking, use its format.
1509
 
                self.set_branch_format(new_branch_format)
1510
 
                note(gettext('Source branch format does not support stacking,'
1511
 
                     ' using format:\n  %s'),
1512
 
                     new_branch_format.get_format_description())
1513
 
 
1514
1823
    def get_converter(self, format=None):
1515
1824
        """See BzrDirFormat.get_converter()."""
1516
1825
        if format is None:
1517
1826
            format = BzrDirFormat.get_default_format()
1518
 
        if (type(self) is BzrDirMetaFormat1 and
1519
 
            type(format) is BzrDirMetaFormat1Colo):
1520
 
            return ConvertMetaToColo(format)
1521
 
        if (type(self) is BzrDirMetaFormat1Colo and
1522
 
            type(format) is BzrDirMetaFormat1):
1523
 
            return ConvertMetaRemoveColo(format)
1524
1827
        if not isinstance(self, format.__class__):
1525
1828
            # converting away from metadir is not implemented
1526
1829
            raise NotImplementedError(self.get_converter)
1527
1830
        return ConvertMetaToMeta(format)
1528
1831
 
1529
 
    @classmethod
1530
 
    def get_format_string(cls):
 
1832
    def get_format_string(self):
1531
1833
        """See BzrDirFormat.get_format_string()."""
1532
1834
        return "Bazaar-NG meta directory, format 1\n"
1533
1835
 
1535
1837
        """See BzrDirFormat.get_format_description()."""
1536
1838
        return "Meta directory format 1"
1537
1839
 
1538
 
    def network_name(self):
1539
 
        return self.get_format_string()
1540
 
 
1541
1840
    def _open(self, transport):
1542
1841
        """See BzrDirFormat._open."""
1543
 
        # Create a new format instance because otherwise initialisation of new
1544
 
        # metadirs share the global default format object leading to alias
1545
 
        # problems.
1546
 
        format = BzrDirMetaFormat1()
1547
 
        self._supply_sub_formats_to(format)
1548
 
        return BzrDirMeta1(transport, format)
 
1842
        return BzrDirMeta1(transport, self)
1549
1843
 
1550
1844
    def __return_repository_format(self):
1551
1845
        """Circular import protection."""
1552
 
        if self._repository_format:
 
1846
        if getattr(self, '_repository_format', None):
1553
1847
            return self._repository_format
1554
 
        from bzrlib.repository import format_registry
1555
 
        return format_registry.get_default()
 
1848
        from bzrlib.repository import RepositoryFormat
 
1849
        return RepositoryFormat.get_default_format()
1556
1850
 
1557
 
    def _set_repository_format(self, value):
 
1851
    def __set_repository_format(self, value):
1558
1852
        """Allow changing the repository format for metadir formats."""
1559
1853
        self._repository_format = value
1560
1854
 
1561
 
    repository_format = property(__return_repository_format,
1562
 
        _set_repository_format)
1563
 
 
1564
 
    def _supply_sub_formats_to(self, other_format):
1565
 
        """Give other_format the same values for sub formats as this has.
1566
 
 
1567
 
        This method is expected to be used when parameterising a
1568
 
        RemoteBzrDirFormat instance with the parameters from a
1569
 
        BzrDirMetaFormat1 instance.
1570
 
 
1571
 
        :param other_format: other_format is a format which should be
1572
 
            compatible with whatever sub formats are supported by self.
1573
 
        :return: None.
1574
 
        """
1575
 
        if getattr(self, '_repository_format', None) is not None:
1576
 
            other_format.repository_format = self.repository_format
1577
 
        if self._branch_format is not None:
1578
 
            other_format._branch_format = self._branch_format
1579
 
        if self._workingtree_format is not None:
1580
 
            other_format.workingtree_format = self.workingtree_format
 
1855
    repository_format = property(__return_repository_format, __set_repository_format)
1581
1856
 
1582
1857
    def __get_workingtree_format(self):
1583
1858
        if self._workingtree_format is None:
1584
 
            from bzrlib.workingtree import (
1585
 
                format_registry as wt_format_registry,
1586
 
                )
1587
 
            self._workingtree_format = wt_format_registry.get_default()
 
1859
            from bzrlib.workingtree import WorkingTreeFormat
 
1860
            self._workingtree_format = WorkingTreeFormat.get_default_format()
1588
1861
        return self._workingtree_format
1589
1862
 
1590
1863
    def __set_workingtree_format(self, wt_format):
1594
1867
                                  __set_workingtree_format)
1595
1868
 
1596
1869
 
 
1870
# Register bzr control format
 
1871
BzrDirFormat.register_control_format(BzrDirFormat)
 
1872
 
1597
1873
# Register bzr formats
1598
 
BzrProber.formats.register(BzrDirMetaFormat1.get_format_string(),
1599
 
    BzrDirMetaFormat1)
1600
 
controldir.ControlDirFormat._default_format = BzrDirMetaFormat1()
1601
 
 
1602
 
 
1603
 
class BzrDirMetaFormat1Colo(BzrDirMetaFormat1):
1604
 
    """BzrDirMeta1 format with support for colocated branches."""
1605
 
 
1606
 
    colocated_branches = True
1607
 
 
1608
 
    @classmethod
1609
 
    def get_format_string(cls):
1610
 
        """See BzrDirFormat.get_format_string()."""
1611
 
        return "Bazaar meta directory, format 1 (with colocated branches)\n"
1612
 
 
1613
 
    def get_format_description(self):
1614
 
        """See BzrDirFormat.get_format_description()."""
1615
 
        return "Meta directory format 1 with support for colocated branches"
1616
 
 
1617
 
    def _open(self, transport):
1618
 
        """See BzrDirFormat._open."""
1619
 
        # Create a new format instance because otherwise initialisation of new
1620
 
        # metadirs share the global default format object leading to alias
1621
 
        # problems.
1622
 
        format = BzrDirMetaFormat1Colo()
1623
 
        self._supply_sub_formats_to(format)
1624
 
        return BzrDirMeta1Colo(transport, format)
1625
 
 
1626
 
 
1627
 
BzrProber.formats.register(BzrDirMetaFormat1Colo.get_format_string(),
1628
 
    BzrDirMetaFormat1Colo)
1629
 
 
1630
 
 
1631
 
class ConvertMetaToMeta(controldir.Converter):
 
1874
BzrDirFormat.register_format(BzrDirFormat4())
 
1875
BzrDirFormat.register_format(BzrDirFormat5())
 
1876
BzrDirFormat.register_format(BzrDirFormat6())
 
1877
__default_format = BzrDirMetaFormat1()
 
1878
BzrDirFormat.register_format(__default_format)
 
1879
BzrDirFormat._default_format = __default_format
 
1880
 
 
1881
 
 
1882
class Converter(object):
 
1883
    """Converts a disk format object from one format to another."""
 
1884
 
 
1885
    def convert(self, to_convert, pb):
 
1886
        """Perform the conversion of to_convert, giving feedback via pb.
 
1887
 
 
1888
        :param to_convert: The disk object to convert.
 
1889
        :param pb: a progress bar to use for progress information.
 
1890
        """
 
1891
 
 
1892
    def step(self, message):
 
1893
        """Update the pb by a step."""
 
1894
        self.count +=1
 
1895
        self.pb.update(message, self.count, self.total)
 
1896
 
 
1897
 
 
1898
class ConvertBzrDir4To5(Converter):
 
1899
    """Converts format 4 bzr dirs to format 5."""
 
1900
 
 
1901
    def __init__(self):
 
1902
        super(ConvertBzrDir4To5, self).__init__()
 
1903
        self.converted_revs = set()
 
1904
        self.absent_revisions = set()
 
1905
        self.text_count = 0
 
1906
        self.revisions = {}
 
1907
        
 
1908
    def convert(self, to_convert, pb):
 
1909
        """See Converter.convert()."""
 
1910
        self.bzrdir = to_convert
 
1911
        self.pb = pb
 
1912
        self.pb.note('starting upgrade from format 4 to 5')
 
1913
        if isinstance(self.bzrdir.transport, LocalTransport):
 
1914
            self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
 
1915
        self._convert_to_weaves()
 
1916
        return BzrDir.open(self.bzrdir.root_transport.base)
 
1917
 
 
1918
    def _convert_to_weaves(self):
 
1919
        self.pb.note('note: upgrade may be faster if all store files are ungzipped first')
 
1920
        try:
 
1921
            # TODO permissions
 
1922
            stat = self.bzrdir.transport.stat('weaves')
 
1923
            if not S_ISDIR(stat.st_mode):
 
1924
                self.bzrdir.transport.delete('weaves')
 
1925
                self.bzrdir.transport.mkdir('weaves')
 
1926
        except errors.NoSuchFile:
 
1927
            self.bzrdir.transport.mkdir('weaves')
 
1928
        # deliberately not a WeaveFile as we want to build it up slowly.
 
1929
        self.inv_weave = Weave('inventory')
 
1930
        # holds in-memory weaves for all files
 
1931
        self.text_weaves = {}
 
1932
        self.bzrdir.transport.delete('branch-format')
 
1933
        self.branch = self.bzrdir.open_branch()
 
1934
        self._convert_working_inv()
 
1935
        rev_history = self.branch.revision_history()
 
1936
        # to_read is a stack holding the revisions we still need to process;
 
1937
        # appending to it adds new highest-priority revisions
 
1938
        self.known_revisions = set(rev_history)
 
1939
        self.to_read = rev_history[-1:]
 
1940
        while self.to_read:
 
1941
            rev_id = self.to_read.pop()
 
1942
            if (rev_id not in self.revisions
 
1943
                and rev_id not in self.absent_revisions):
 
1944
                self._load_one_rev(rev_id)
 
1945
        self.pb.clear()
 
1946
        to_import = self._make_order()
 
1947
        for i, rev_id in enumerate(to_import):
 
1948
            self.pb.update('converting revision', i, len(to_import))
 
1949
            self._convert_one_rev(rev_id)
 
1950
        self.pb.clear()
 
1951
        self._write_all_weaves()
 
1952
        self._write_all_revs()
 
1953
        self.pb.note('upgraded to weaves:')
 
1954
        self.pb.note('  %6d revisions and inventories', len(self.revisions))
 
1955
        self.pb.note('  %6d revisions not present', len(self.absent_revisions))
 
1956
        self.pb.note('  %6d texts', self.text_count)
 
1957
        self._cleanup_spare_files_after_format4()
 
1958
        self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
 
1959
 
 
1960
    def _cleanup_spare_files_after_format4(self):
 
1961
        # FIXME working tree upgrade foo.
 
1962
        for n in 'merged-patches', 'pending-merged-patches':
 
1963
            try:
 
1964
                ## assert os.path.getsize(p) == 0
 
1965
                self.bzrdir.transport.delete(n)
 
1966
            except errors.NoSuchFile:
 
1967
                pass
 
1968
        self.bzrdir.transport.delete_tree('inventory-store')
 
1969
        self.bzrdir.transport.delete_tree('text-store')
 
1970
 
 
1971
    def _convert_working_inv(self):
 
1972
        inv = xml4.serializer_v4.read_inventory(
 
1973
                    self.branch.control_files.get('inventory'))
 
1974
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv, working=True)
 
1975
        # FIXME inventory is a working tree change.
 
1976
        self.branch.control_files.put('inventory', StringIO(new_inv_xml))
 
1977
 
 
1978
    def _write_all_weaves(self):
 
1979
        controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
 
1980
        weave_transport = self.bzrdir.transport.clone('weaves')
 
1981
        weaves = WeaveStore(weave_transport, prefixed=False)
 
1982
        transaction = WriteTransaction()
 
1983
 
 
1984
        try:
 
1985
            i = 0
 
1986
            for file_id, file_weave in self.text_weaves.items():
 
1987
                self.pb.update('writing weave', i, len(self.text_weaves))
 
1988
                weaves._put_weave(file_id, file_weave, transaction)
 
1989
                i += 1
 
1990
            self.pb.update('inventory', 0, 1)
 
1991
            controlweaves._put_weave('inventory', self.inv_weave, transaction)
 
1992
            self.pb.update('inventory', 1, 1)
 
1993
        finally:
 
1994
            self.pb.clear()
 
1995
 
 
1996
    def _write_all_revs(self):
 
1997
        """Write all revisions out in new form."""
 
1998
        self.bzrdir.transport.delete_tree('revision-store')
 
1999
        self.bzrdir.transport.mkdir('revision-store')
 
2000
        revision_transport = self.bzrdir.transport.clone('revision-store')
 
2001
        # TODO permissions
 
2002
        _revision_store = TextRevisionStore(TextStore(revision_transport,
 
2003
                                                      prefixed=False,
 
2004
                                                      compressed=True))
 
2005
        try:
 
2006
            transaction = WriteTransaction()
 
2007
            for i, rev_id in enumerate(self.converted_revs):
 
2008
                self.pb.update('write revision', i, len(self.converted_revs))
 
2009
                _revision_store.add_revision(self.revisions[rev_id], transaction)
 
2010
        finally:
 
2011
            self.pb.clear()
 
2012
            
 
2013
    def _load_one_rev(self, rev_id):
 
2014
        """Load a revision object into memory.
 
2015
 
 
2016
        Any parents not either loaded or abandoned get queued to be
 
2017
        loaded."""
 
2018
        self.pb.update('loading revision',
 
2019
                       len(self.revisions),
 
2020
                       len(self.known_revisions))
 
2021
        if not self.branch.repository.has_revision(rev_id):
 
2022
            self.pb.clear()
 
2023
            self.pb.note('revision {%s} not present in branch; '
 
2024
                         'will be converted as a ghost',
 
2025
                         rev_id)
 
2026
            self.absent_revisions.add(rev_id)
 
2027
        else:
 
2028
            rev = self.branch.repository._revision_store.get_revision(rev_id,
 
2029
                self.branch.repository.get_transaction())
 
2030
            for parent_id in rev.parent_ids:
 
2031
                self.known_revisions.add(parent_id)
 
2032
                self.to_read.append(parent_id)
 
2033
            self.revisions[rev_id] = rev
 
2034
 
 
2035
    def _load_old_inventory(self, rev_id):
 
2036
        assert rev_id not in self.converted_revs
 
2037
        old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
 
2038
        inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
 
2039
        inv.revision_id = rev_id
 
2040
        rev = self.revisions[rev_id]
 
2041
        if rev.inventory_sha1:
 
2042
            assert rev.inventory_sha1 == sha_string(old_inv_xml), \
 
2043
                'inventory sha mismatch for {%s}' % rev_id
 
2044
        return inv
 
2045
 
 
2046
    def _load_updated_inventory(self, rev_id):
 
2047
        assert rev_id in self.converted_revs
 
2048
        inv_xml = self.inv_weave.get_text(rev_id)
 
2049
        inv = xml5.serializer_v5.read_inventory_from_string(inv_xml, rev_id)
 
2050
        return inv
 
2051
 
 
2052
    def _convert_one_rev(self, rev_id):
 
2053
        """Convert revision and all referenced objects to new format."""
 
2054
        rev = self.revisions[rev_id]
 
2055
        inv = self._load_old_inventory(rev_id)
 
2056
        present_parents = [p for p in rev.parent_ids
 
2057
                           if p not in self.absent_revisions]
 
2058
        self._convert_revision_contents(rev, inv, present_parents)
 
2059
        self._store_new_inv(rev, inv, present_parents)
 
2060
        self.converted_revs.add(rev_id)
 
2061
 
 
2062
    def _store_new_inv(self, rev, inv, present_parents):
 
2063
        # the XML is now updated with text versions
 
2064
        if __debug__:
 
2065
            entries = inv.iter_entries()
 
2066
            entries.next()
 
2067
            for path, ie in entries:
 
2068
                assert getattr(ie, 'revision', None) is not None, \
 
2069
                    'no revision on {%s} in {%s}' % \
 
2070
                    (file_id, rev.revision_id)
 
2071
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
 
2072
        new_inv_sha1 = sha_string(new_inv_xml)
 
2073
        self.inv_weave.add_lines(rev.revision_id,
 
2074
                                 present_parents,
 
2075
                                 new_inv_xml.splitlines(True))
 
2076
        rev.inventory_sha1 = new_inv_sha1
 
2077
 
 
2078
    def _convert_revision_contents(self, rev, inv, present_parents):
 
2079
        """Convert all the files within a revision.
 
2080
 
 
2081
        Also upgrade the inventory to refer to the text revision ids."""
 
2082
        rev_id = rev.revision_id
 
2083
        mutter('converting texts of revision {%s}',
 
2084
               rev_id)
 
2085
        parent_invs = map(self._load_updated_inventory, present_parents)
 
2086
        entries = inv.iter_entries()
 
2087
        entries.next()
 
2088
        for path, ie in entries:
 
2089
            self._convert_file_version(rev, ie, parent_invs)
 
2090
 
 
2091
    def _convert_file_version(self, rev, ie, parent_invs):
 
2092
        """Convert one version of one file.
 
2093
 
 
2094
        The file needs to be added into the weave if it is a merge
 
2095
        of >=2 parents or if it's changed from its parent.
 
2096
        """
 
2097
        file_id = ie.file_id
 
2098
        rev_id = rev.revision_id
 
2099
        w = self.text_weaves.get(file_id)
 
2100
        if w is None:
 
2101
            w = Weave(file_id)
 
2102
            self.text_weaves[file_id] = w
 
2103
        text_changed = False
 
2104
        parent_candiate_entries = ie.parent_candidates(parent_invs)
 
2105
        for old_revision in parent_candiate_entries.keys():
 
2106
            # if this fails, its a ghost ?
 
2107
            assert old_revision in self.converted_revs, \
 
2108
                "Revision {%s} not in converted_revs" % old_revision
 
2109
        heads = graph.Graph(self).heads(parent_candiate_entries.keys())
 
2110
        # XXX: Note that this is unordered - and this is tolerable because 
 
2111
        # the previous code was also unordered.
 
2112
        previous_entries = dict((head, parent_candiate_entries[head]) for head
 
2113
            in heads)
 
2114
        self.snapshot_ie(previous_entries, ie, w, rev_id)
 
2115
        del ie.text_id
 
2116
        assert getattr(ie, 'revision', None) is not None
 
2117
 
 
2118
    @symbol_versioning.deprecated_method(symbol_versioning.one_one)
 
2119
    def get_parents(self, revision_ids):
 
2120
        for revision_id in revision_ids:
 
2121
            yield self.revisions[revision_id].parent_ids
 
2122
 
 
2123
    def get_parent_map(self, revision_ids):
 
2124
        """See graph._StackedParentsProvider.get_parent_map"""
 
2125
        return dict((revision_id, self.revisions[revision_id])
 
2126
                    for revision_id in revision_ids
 
2127
                     if revision_id in self.revisions)
 
2128
 
 
2129
    def snapshot_ie(self, previous_revisions, ie, w, rev_id):
 
2130
        # TODO: convert this logic, which is ~= snapshot to
 
2131
        # a call to:. This needs the path figured out. rather than a work_tree
 
2132
        # a v4 revision_tree can be given, or something that looks enough like
 
2133
        # one to give the file content to the entry if it needs it.
 
2134
        # and we need something that looks like a weave store for snapshot to 
 
2135
        # save against.
 
2136
        #ie.snapshot(rev, PATH, previous_revisions, REVISION_TREE, InMemoryWeaveStore(self.text_weaves))
 
2137
        if len(previous_revisions) == 1:
 
2138
            previous_ie = previous_revisions.values()[0]
 
2139
            if ie._unchanged(previous_ie):
 
2140
                ie.revision = previous_ie.revision
 
2141
                return
 
2142
        if ie.has_text():
 
2143
            text = self.branch.repository.weave_store.get(ie.text_id)
 
2144
            file_lines = text.readlines()
 
2145
            assert sha_strings(file_lines) == ie.text_sha1
 
2146
            assert sum(map(len, file_lines)) == ie.text_size
 
2147
            w.add_lines(rev_id, previous_revisions, file_lines)
 
2148
            self.text_count += 1
 
2149
        else:
 
2150
            w.add_lines(rev_id, previous_revisions, [])
 
2151
        ie.revision = rev_id
 
2152
 
 
2153
    def _make_order(self):
 
2154
        """Return a suitable order for importing revisions.
 
2155
 
 
2156
        The order must be such that an revision is imported after all
 
2157
        its (present) parents.
 
2158
        """
 
2159
        todo = set(self.revisions.keys())
 
2160
        done = self.absent_revisions.copy()
 
2161
        order = []
 
2162
        while todo:
 
2163
            # scan through looking for a revision whose parents
 
2164
            # are all done
 
2165
            for rev_id in sorted(list(todo)):
 
2166
                rev = self.revisions[rev_id]
 
2167
                parent_ids = set(rev.parent_ids)
 
2168
                if parent_ids.issubset(done):
 
2169
                    # can take this one now
 
2170
                    order.append(rev_id)
 
2171
                    todo.remove(rev_id)
 
2172
                    done.add(rev_id)
 
2173
        return order
 
2174
 
 
2175
 
 
2176
class ConvertBzrDir5To6(Converter):
 
2177
    """Converts format 5 bzr dirs to format 6."""
 
2178
 
 
2179
    def convert(self, to_convert, pb):
 
2180
        """See Converter.convert()."""
 
2181
        self.bzrdir = to_convert
 
2182
        self.pb = pb
 
2183
        self.pb.note('starting upgrade from format 5 to 6')
 
2184
        self._convert_to_prefixed()
 
2185
        return BzrDir.open(self.bzrdir.root_transport.base)
 
2186
 
 
2187
    def _convert_to_prefixed(self):
 
2188
        from bzrlib.store import TransportStore
 
2189
        self.bzrdir.transport.delete('branch-format')
 
2190
        for store_name in ["weaves", "revision-store"]:
 
2191
            self.pb.note("adding prefixes to %s" % store_name)
 
2192
            store_transport = self.bzrdir.transport.clone(store_name)
 
2193
            store = TransportStore(store_transport, prefixed=True)
 
2194
            for urlfilename in store_transport.list_dir('.'):
 
2195
                filename = urlutils.unescape(urlfilename)
 
2196
                if (filename.endswith(".weave") or
 
2197
                    filename.endswith(".gz") or
 
2198
                    filename.endswith(".sig")):
 
2199
                    file_id = os.path.splitext(filename)[0]
 
2200
                else:
 
2201
                    file_id = filename
 
2202
                prefix_dir = store.hash_prefix(file_id)
 
2203
                # FIXME keep track of the dirs made RBC 20060121
 
2204
                try:
 
2205
                    store_transport.move(filename, prefix_dir + '/' + filename)
 
2206
                except errors.NoSuchFile: # catches missing dirs strangely enough
 
2207
                    store_transport.mkdir(prefix_dir)
 
2208
                    store_transport.move(filename, prefix_dir + '/' + filename)
 
2209
        self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
 
2210
 
 
2211
 
 
2212
class ConvertBzrDir6ToMeta(Converter):
 
2213
    """Converts format 6 bzr dirs to metadirs."""
 
2214
 
 
2215
    def convert(self, to_convert, pb):
 
2216
        """See Converter.convert()."""
 
2217
        from bzrlib.repofmt.weaverepo import RepositoryFormat7
 
2218
        from bzrlib.branch import BzrBranchFormat5
 
2219
        self.bzrdir = to_convert
 
2220
        self.pb = pb
 
2221
        self.count = 0
 
2222
        self.total = 20 # the steps we know about
 
2223
        self.garbage_inventories = []
 
2224
 
 
2225
        self.pb.note('starting upgrade from format 6 to metadir')
 
2226
        self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
 
2227
        # its faster to move specific files around than to open and use the apis...
 
2228
        # first off, nuke ancestry.weave, it was never used.
 
2229
        try:
 
2230
            self.step('Removing ancestry.weave')
 
2231
            self.bzrdir.transport.delete('ancestry.weave')
 
2232
        except errors.NoSuchFile:
 
2233
            pass
 
2234
        # find out whats there
 
2235
        self.step('Finding branch files')
 
2236
        last_revision = self.bzrdir.open_branch().last_revision()
 
2237
        bzrcontents = self.bzrdir.transport.list_dir('.')
 
2238
        for name in bzrcontents:
 
2239
            if name.startswith('basis-inventory.'):
 
2240
                self.garbage_inventories.append(name)
 
2241
        # create new directories for repository, working tree and branch
 
2242
        self.dir_mode = self.bzrdir._control_files._dir_mode
 
2243
        self.file_mode = self.bzrdir._control_files._file_mode
 
2244
        repository_names = [('inventory.weave', True),
 
2245
                            ('revision-store', True),
 
2246
                            ('weaves', True)]
 
2247
        self.step('Upgrading repository  ')
 
2248
        self.bzrdir.transport.mkdir('repository', mode=self.dir_mode)
 
2249
        self.make_lock('repository')
 
2250
        # we hard code the formats here because we are converting into
 
2251
        # the meta format. The meta format upgrader can take this to a 
 
2252
        # future format within each component.
 
2253
        self.put_format('repository', RepositoryFormat7())
 
2254
        for entry in repository_names:
 
2255
            self.move_entry('repository', entry)
 
2256
 
 
2257
        self.step('Upgrading branch      ')
 
2258
        self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
 
2259
        self.make_lock('branch')
 
2260
        self.put_format('branch', BzrBranchFormat5())
 
2261
        branch_files = [('revision-history', True),
 
2262
                        ('branch-name', True),
 
2263
                        ('parent', False)]
 
2264
        for entry in branch_files:
 
2265
            self.move_entry('branch', entry)
 
2266
 
 
2267
        checkout_files = [('pending-merges', True),
 
2268
                          ('inventory', True),
 
2269
                          ('stat-cache', False)]
 
2270
        # If a mandatory checkout file is not present, the branch does not have
 
2271
        # a functional checkout. Do not create a checkout in the converted
 
2272
        # branch.
 
2273
        for name, mandatory in checkout_files:
 
2274
            if mandatory and name not in bzrcontents:
 
2275
                has_checkout = False
 
2276
                break
 
2277
        else:
 
2278
            has_checkout = True
 
2279
        if not has_checkout:
 
2280
            self.pb.note('No working tree.')
 
2281
            # If some checkout files are there, we may as well get rid of them.
 
2282
            for name, mandatory in checkout_files:
 
2283
                if name in bzrcontents:
 
2284
                    self.bzrdir.transport.delete(name)
 
2285
        else:
 
2286
            from bzrlib.workingtree import WorkingTreeFormat3
 
2287
            self.step('Upgrading working tree')
 
2288
            self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
 
2289
            self.make_lock('checkout')
 
2290
            self.put_format(
 
2291
                'checkout', WorkingTreeFormat3())
 
2292
            self.bzrdir.transport.delete_multi(
 
2293
                self.garbage_inventories, self.pb)
 
2294
            for entry in checkout_files:
 
2295
                self.move_entry('checkout', entry)
 
2296
            if last_revision is not None:
 
2297
                self.bzrdir._control_files.put_utf8(
 
2298
                    'checkout/last-revision', last_revision)
 
2299
        self.bzrdir._control_files.put_utf8(
 
2300
            'branch-format', BzrDirMetaFormat1().get_format_string())
 
2301
        return BzrDir.open(self.bzrdir.root_transport.base)
 
2302
 
 
2303
    def make_lock(self, name):
 
2304
        """Make a lock for the new control dir name."""
 
2305
        self.step('Make %s lock' % name)
 
2306
        ld = lockdir.LockDir(self.bzrdir.transport,
 
2307
                             '%s/lock' % name,
 
2308
                             file_modebits=self.file_mode,
 
2309
                             dir_modebits=self.dir_mode)
 
2310
        ld.create()
 
2311
 
 
2312
    def move_entry(self, new_dir, entry):
 
2313
        """Move then entry name into new_dir."""
 
2314
        name = entry[0]
 
2315
        mandatory = entry[1]
 
2316
        self.step('Moving %s' % name)
 
2317
        try:
 
2318
            self.bzrdir.transport.move(name, '%s/%s' % (new_dir, name))
 
2319
        except errors.NoSuchFile:
 
2320
            if mandatory:
 
2321
                raise
 
2322
 
 
2323
    def put_format(self, dirname, format):
 
2324
        self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
 
2325
 
 
2326
 
 
2327
class ConvertMetaToMeta(Converter):
1632
2328
    """Converts the components of metadirs."""
1633
2329
 
1634
2330
    def __init__(self, target_format):
1641
2337
    def convert(self, to_convert, pb):
1642
2338
        """See Converter.convert()."""
1643
2339
        self.bzrdir = to_convert
1644
 
        self.pb = ui.ui_factory.nested_progress_bar()
 
2340
        self.pb = pb
1645
2341
        self.count = 0
1646
2342
        self.total = 1
1647
2343
        self.step('checking repository format')
1652
2348
        else:
1653
2349
            if not isinstance(repo._format, self.target_format.repository_format.__class__):
1654
2350
                from bzrlib.repository import CopyConverter
1655
 
                ui.ui_factory.note(gettext('starting repository conversion'))
 
2351
                self.pb.note('starting repository conversion')
1656
2352
                converter = CopyConverter(self.target_format.repository_format)
1657
2353
                converter.convert(repo, pb)
1658
 
        for branch in self.bzrdir.list_branches():
 
2354
        try:
 
2355
            branch = self.bzrdir.open_branch()
 
2356
        except errors.NotBranchError:
 
2357
            pass
 
2358
        else:
1659
2359
            # TODO: conversions of Branch and Tree should be done by
1660
 
            # InterXFormat lookups/some sort of registry.
 
2360
            # InterXFormat lookups
1661
2361
            # Avoid circular imports
1662
 
            old = branch._format.__class__
1663
 
            new = self.target_format.get_branch_format().__class__
1664
 
            while old != new:
1665
 
                if (old == _mod_branch.BzrBranchFormat5 and
1666
 
                    new in (_mod_branch.BzrBranchFormat6,
1667
 
                        _mod_branch.BzrBranchFormat7,
1668
 
                        _mod_branch.BzrBranchFormat8)):
1669
 
                    branch_converter = _mod_branch.Converter5to6()
1670
 
                elif (old == _mod_branch.BzrBranchFormat6 and
1671
 
                    new in (_mod_branch.BzrBranchFormat7,
1672
 
                            _mod_branch.BzrBranchFormat8)):
1673
 
                    branch_converter = _mod_branch.Converter6to7()
1674
 
                elif (old == _mod_branch.BzrBranchFormat7 and
1675
 
                      new is _mod_branch.BzrBranchFormat8):
1676
 
                    branch_converter = _mod_branch.Converter7to8()
1677
 
                else:
1678
 
                    raise errors.BadConversionTarget("No converter", new,
1679
 
                        branch._format)
 
2362
            from bzrlib import branch as _mod_branch
 
2363
            if (branch._format.__class__ is _mod_branch.BzrBranchFormat5 and
 
2364
                self.target_format.get_branch_format().__class__ is
 
2365
                _mod_branch.BzrBranchFormat6):
 
2366
                branch_converter = _mod_branch.Converter5to6()
1680
2367
                branch_converter.convert(branch)
1681
 
                branch = self.bzrdir.open_branch()
1682
 
                old = branch._format.__class__
1683
2368
        try:
1684
2369
            tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
1685
2370
        except (errors.NoWorkingTree, errors.NotLocalUrl):
1687
2372
        else:
1688
2373
            # TODO: conversions of Branch and Tree should be done by
1689
2374
            # InterXFormat lookups
1690
 
            if (isinstance(tree, workingtree_3.WorkingTree3) and
1691
 
                not isinstance(tree, workingtree_4.DirStateWorkingTree) and
 
2375
            if (isinstance(tree, workingtree.WorkingTree3) and
 
2376
                not isinstance(tree, workingtree_4.WorkingTree4) and
1692
2377
                isinstance(self.target_format.workingtree_format,
1693
 
                    workingtree_4.DirStateWorkingTreeFormat)):
 
2378
                    workingtree_4.WorkingTreeFormat4)):
1694
2379
                workingtree_4.Converter3to4().convert(tree)
1695
 
            if (isinstance(tree, workingtree_4.DirStateWorkingTree) and
1696
 
                not isinstance(tree, workingtree_4.WorkingTree5) and
1697
 
                isinstance(self.target_format.workingtree_format,
1698
 
                    workingtree_4.WorkingTreeFormat5)):
1699
 
                workingtree_4.Converter4to5().convert(tree)
1700
 
            if (isinstance(tree, workingtree_4.DirStateWorkingTree) and
1701
 
                not isinstance(tree, workingtree_4.WorkingTree6) and
1702
 
                isinstance(self.target_format.workingtree_format,
1703
 
                    workingtree_4.WorkingTreeFormat6)):
1704
 
                workingtree_4.Converter4or5to6().convert(tree)
1705
 
        self.pb.finished()
1706
2380
        return to_convert
1707
2381
 
1708
2382
 
1709
 
class ConvertMetaToColo(controldir.Converter):
1710
 
    """Add colocated branch support."""
1711
 
 
1712
 
    def __init__(self, target_format):
1713
 
        """Create a converter.that upgrades a metadir to the colo format.
1714
 
 
1715
 
        :param target_format: The final metadir format that is desired.
1716
 
        """
1717
 
        self.target_format = target_format
1718
 
 
1719
 
    def convert(self, to_convert, pb):
1720
 
        """See Converter.convert()."""
1721
 
        to_convert.transport.put_bytes('branch-format',
1722
 
            self.target_format.get_format_string())
1723
 
        return BzrDir.open_from_transport(to_convert.root_transport)
1724
 
 
1725
 
 
1726
 
class ConvertMetaRemoveColo(controldir.Converter):
1727
 
    """Remove colocated branch support from a bzrdir."""
1728
 
 
1729
 
    def __init__(self, target_format):
1730
 
        """Create a converter.that downgrades a colocated branch metadir
1731
 
        to a regular metadir.
1732
 
 
1733
 
        :param target_format: The final metadir format that is desired.
1734
 
        """
1735
 
        self.target_format = target_format
1736
 
 
1737
 
    def convert(self, to_convert, pb):
1738
 
        """See Converter.convert()."""
1739
 
        to_convert.control_files.lock_write()
1740
 
        try:
1741
 
            branches = to_convert.list_branches()
1742
 
            if len(branches) > 1:
1743
 
                raise errors.BzrError("remove all but a single "
1744
 
                    "colocated branch when downgrading")
1745
 
        finally:
1746
 
            to_convert.control_files.unlock()
1747
 
        to_convert.transport.put_bytes('branch-format',
1748
 
            self.target_format.get_format_string())
1749
 
        return BzrDir.open_from_transport(to_convert.root_transport)
1750
 
 
1751
 
 
1752
 
controldir.ControlDirFormat.register_server_prober(RemoteBzrProber)
1753
 
 
1754
 
 
1755
 
class RepositoryAcquisitionPolicy(object):
1756
 
    """Abstract base class for repository acquisition policies.
1757
 
 
1758
 
    A repository acquisition policy decides how a BzrDir acquires a repository
1759
 
    for a branch that is being created.  The most basic policy decision is
1760
 
    whether to create a new repository or use an existing one.
1761
 
    """
1762
 
    def __init__(self, stack_on, stack_on_pwd, require_stacking):
1763
 
        """Constructor.
1764
 
 
1765
 
        :param stack_on: A location to stack on
1766
 
        :param stack_on_pwd: If stack_on is relative, the location it is
1767
 
            relative to.
1768
 
        :param require_stacking: If True, it is a failure to not stack.
1769
 
        """
1770
 
        self._stack_on = stack_on
1771
 
        self._stack_on_pwd = stack_on_pwd
1772
 
        self._require_stacking = require_stacking
1773
 
 
1774
 
    def configure_branch(self, branch):
1775
 
        """Apply any configuration data from this policy to the branch.
1776
 
 
1777
 
        Default implementation sets repository stacking.
1778
 
        """
1779
 
        if self._stack_on is None:
1780
 
            return
1781
 
        if self._stack_on_pwd is None:
1782
 
            stack_on = self._stack_on
1783
 
        else:
1784
 
            try:
1785
 
                stack_on = urlutils.rebase_url(self._stack_on,
1786
 
                    self._stack_on_pwd,
1787
 
                    branch.user_url)
1788
 
            except errors.InvalidRebaseURLs:
1789
 
                stack_on = self._get_full_stack_on()
1790
 
        try:
1791
 
            branch.set_stacked_on_url(stack_on)
1792
 
        except (errors.UnstackableBranchFormat,
1793
 
                errors.UnstackableRepositoryFormat):
1794
 
            if self._require_stacking:
1795
 
                raise
1796
 
 
1797
 
    def requires_stacking(self):
1798
 
        """Return True if this policy requires stacking."""
1799
 
        return self._stack_on is not None and self._require_stacking
1800
 
 
1801
 
    def _get_full_stack_on(self):
1802
 
        """Get a fully-qualified URL for the stack_on location."""
1803
 
        if self._stack_on is None:
1804
 
            return None
1805
 
        if self._stack_on_pwd is None:
1806
 
            return self._stack_on
1807
 
        else:
1808
 
            return urlutils.join(self._stack_on_pwd, self._stack_on)
1809
 
 
1810
 
    def _add_fallback(self, repository, possible_transports=None):
1811
 
        """Add a fallback to the supplied repository, if stacking is set."""
1812
 
        stack_on = self._get_full_stack_on()
1813
 
        if stack_on is None:
1814
 
            return
1815
 
        try:
1816
 
            stacked_dir = BzrDir.open(stack_on,
1817
 
                                      possible_transports=possible_transports)
1818
 
        except errors.JailBreak:
1819
 
            # We keep the stacking details, but we are in the server code so
1820
 
            # actually stacking is not needed.
1821
 
            return
1822
 
        try:
1823
 
            stacked_repo = stacked_dir.open_branch().repository
1824
 
        except errors.NotBranchError:
1825
 
            stacked_repo = stacked_dir.open_repository()
1826
 
        try:
1827
 
            repository.add_fallback_repository(stacked_repo)
1828
 
        except errors.UnstackableRepositoryFormat:
1829
 
            if self._require_stacking:
1830
 
                raise
1831
 
        else:
1832
 
            self._require_stacking = True
1833
 
 
1834
 
    def acquire_repository(self, make_working_trees=None, shared=False):
1835
 
        """Acquire a repository for this bzrdir.
1836
 
 
1837
 
        Implementations may create a new repository or use a pre-exising
1838
 
        repository.
1839
 
 
1840
 
        :param make_working_trees: If creating a repository, set
1841
 
            make_working_trees to this value (if non-None)
1842
 
        :param shared: If creating a repository, make it shared if True
1843
 
        :return: A repository, is_new_flag (True if the repository was
1844
 
            created).
1845
 
        """
1846
 
        raise NotImplemented(RepositoryAcquisitionPolicy.acquire_repository)
1847
 
 
1848
 
 
1849
 
class CreateRepository(RepositoryAcquisitionPolicy):
1850
 
    """A policy of creating a new repository"""
1851
 
 
1852
 
    def __init__(self, bzrdir, stack_on=None, stack_on_pwd=None,
1853
 
                 require_stacking=False):
1854
 
        """Constructor.
1855
 
 
1856
 
        :param bzrdir: The bzrdir to create the repository on.
1857
 
        :param stack_on: A location to stack on
1858
 
        :param stack_on_pwd: If stack_on is relative, the location it is
1859
 
            relative to.
1860
 
        """
1861
 
        RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
1862
 
                                             require_stacking)
1863
 
        self._bzrdir = bzrdir
1864
 
 
1865
 
    def acquire_repository(self, make_working_trees=None, shared=False):
1866
 
        """Implementation of RepositoryAcquisitionPolicy.acquire_repository
1867
 
 
1868
 
        Creates the desired repository in the bzrdir we already have.
1869
 
        """
1870
 
        stack_on = self._get_full_stack_on()
1871
 
        if stack_on:
1872
 
            format = self._bzrdir._format
1873
 
            format.require_stacking(stack_on=stack_on,
1874
 
                                    possible_transports=[self._bzrdir.root_transport])
1875
 
            if not self._require_stacking:
1876
 
                # We have picked up automatic stacking somewhere.
1877
 
                note(gettext('Using default stacking branch {0} at {1}').format(
1878
 
                    self._stack_on, self._stack_on_pwd))
1879
 
        repository = self._bzrdir.create_repository(shared=shared)
1880
 
        self._add_fallback(repository,
1881
 
                           possible_transports=[self._bzrdir.transport])
1882
 
        if make_working_trees is not None:
1883
 
            repository.set_make_working_trees(make_working_trees)
1884
 
        return repository, True
1885
 
 
1886
 
 
1887
 
class UseExistingRepository(RepositoryAcquisitionPolicy):
1888
 
    """A policy of reusing an existing repository"""
1889
 
 
1890
 
    def __init__(self, repository, stack_on=None, stack_on_pwd=None,
1891
 
                 require_stacking=False):
1892
 
        """Constructor.
1893
 
 
1894
 
        :param repository: The repository to use.
1895
 
        :param stack_on: A location to stack on
1896
 
        :param stack_on_pwd: If stack_on is relative, the location it is
1897
 
            relative to.
1898
 
        """
1899
 
        RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
1900
 
                                             require_stacking)
1901
 
        self._repository = repository
1902
 
 
1903
 
    def acquire_repository(self, make_working_trees=None, shared=False):
1904
 
        """Implementation of RepositoryAcquisitionPolicy.acquire_repository
1905
 
 
1906
 
        Returns an existing repository to use.
1907
 
        """
1908
 
        self._add_fallback(self._repository,
1909
 
                       possible_transports=[self._repository.bzrdir.transport])
1910
 
        return self._repository, False
1911
 
 
1912
 
 
1913
 
def register_metadir(registry, key,
1914
 
         repository_format, help, native=True, deprecated=False,
1915
 
         branch_format=None,
1916
 
         tree_format=None,
1917
 
         hidden=False,
1918
 
         experimental=False,
1919
 
         alias=False, bzrdir_format=None):
1920
 
    """Register a metadir subformat.
1921
 
 
1922
 
    These all use a meta bzrdir, but can be parameterized by the
1923
 
    Repository/Branch/WorkingTreeformats.
1924
 
 
1925
 
    :param repository_format: The fully-qualified repository format class
1926
 
        name as a string.
1927
 
    :param branch_format: Fully-qualified branch format class name as
1928
 
        a string.
1929
 
    :param tree_format: Fully-qualified tree format class name as
1930
 
        a string.
1931
 
    """
1932
 
    if bzrdir_format is None:
1933
 
        bzrdir_format = BzrDirMetaFormat1
1934
 
    # This should be expanded to support setting WorkingTree and Branch
1935
 
    # formats, once the API supports that.
1936
 
    def _load(full_name):
1937
 
        mod_name, factory_name = full_name.rsplit('.', 1)
1938
 
        try:
1939
 
            factory = pyutils.get_named_object(mod_name, factory_name)
1940
 
        except ImportError, e:
1941
 
            raise ImportError('failed to load %s: %s' % (full_name, e))
1942
 
        except AttributeError:
1943
 
            raise AttributeError('no factory %s in module %r'
1944
 
                % (full_name, sys.modules[mod_name]))
1945
 
        return factory()
1946
 
 
1947
 
    def helper():
1948
 
        bd = bzrdir_format()
1949
 
        if branch_format is not None:
1950
 
            bd.set_branch_format(_load(branch_format))
1951
 
        if tree_format is not None:
1952
 
            bd.workingtree_format = _load(tree_format)
1953
 
        if repository_format is not None:
1954
 
            bd.repository_format = _load(repository_format)
1955
 
        return bd
1956
 
    registry.register(key, helper, help, native, deprecated, hidden,
1957
 
        experimental, alias)
1958
 
 
1959
 
register_metadir(controldir.format_registry, 'knit',
 
2383
# This is not in remote.py because it's small, and needs to be registered.
 
2384
# Putting it in remote.py creates a circular import problem.
 
2385
# we can make it a lazy object if the control formats is turned into something
 
2386
# like a registry.
 
2387
class RemoteBzrDirFormat(BzrDirMetaFormat1):
 
2388
    """Format representing bzrdirs accessed via a smart server"""
 
2389
 
 
2390
    def get_format_description(self):
 
2391
        return 'bzr remote bzrdir'
 
2392
    
 
2393
    @classmethod
 
2394
    def probe_transport(klass, transport):
 
2395
        """Return a RemoteBzrDirFormat object if it looks possible."""
 
2396
        try:
 
2397
            client = transport.get_smart_client()
 
2398
        except (NotImplementedError, AttributeError,
 
2399
                errors.TransportNotPossible):
 
2400
            # no smart server, so not a branch for this format type.
 
2401
            raise errors.NotBranchError(path=transport.base)
 
2402
        else:
 
2403
            # Send a 'hello' request in protocol version one, and decline to
 
2404
            # open it if the server doesn't support our required version (2) so
 
2405
            # that the VFS-based transport will do it.
 
2406
            request = client.get_request()
 
2407
            smart_protocol = protocol.SmartClientRequestProtocolOne(request)
 
2408
            server_version = smart_protocol.query_version()
 
2409
            if server_version != 2:
 
2410
                raise errors.NotBranchError(path=transport.base)
 
2411
            return klass()
 
2412
 
 
2413
    def initialize_on_transport(self, transport):
 
2414
        try:
 
2415
            # hand off the request to the smart server
 
2416
            shared_medium = transport.get_shared_medium()
 
2417
        except errors.NoSmartMedium:
 
2418
            # TODO: lookup the local format from a server hint.
 
2419
            local_dir_format = BzrDirMetaFormat1()
 
2420
            return local_dir_format.initialize_on_transport(transport)
 
2421
        client = _SmartClient(shared_medium)
 
2422
        path = client.remote_path_from_transport(transport)
 
2423
        response = _SmartClient(shared_medium).call('BzrDirFormat.initialize',
 
2424
                                                    path)
 
2425
        assert response[0] in ('ok', ), 'unexpected response code %s' % (response,)
 
2426
        return remote.RemoteBzrDir(transport)
 
2427
 
 
2428
    def _open(self, transport):
 
2429
        return remote.RemoteBzrDir(transport)
 
2430
 
 
2431
    def __eq__(self, other):
 
2432
        if not isinstance(other, RemoteBzrDirFormat):
 
2433
            return False
 
2434
        return self.get_format_description() == other.get_format_description()
 
2435
 
 
2436
 
 
2437
BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)
 
2438
 
 
2439
 
 
2440
class BzrDirFormatInfo(object):
 
2441
 
 
2442
    def __init__(self, native, deprecated, hidden, experimental):
 
2443
        self.deprecated = deprecated
 
2444
        self.native = native
 
2445
        self.hidden = hidden
 
2446
        self.experimental = experimental
 
2447
 
 
2448
 
 
2449
class BzrDirFormatRegistry(registry.Registry):
 
2450
    """Registry of user-selectable BzrDir subformats.
 
2451
    
 
2452
    Differs from BzrDirFormat._control_formats in that it provides sub-formats,
 
2453
    e.g. BzrDirMeta1 with weave repository.  Also, it's more user-oriented.
 
2454
    """
 
2455
 
 
2456
    def __init__(self):
 
2457
        """Create a BzrDirFormatRegistry."""
 
2458
        self._aliases = set()
 
2459
        super(BzrDirFormatRegistry, self).__init__()
 
2460
 
 
2461
    def aliases(self):
 
2462
        """Return a set of the format names which are aliases."""
 
2463
        return frozenset(self._aliases)
 
2464
 
 
2465
    def register_metadir(self, key,
 
2466
             repository_format, help, native=True, deprecated=False,
 
2467
             branch_format=None,
 
2468
             tree_format=None,
 
2469
             hidden=False,
 
2470
             experimental=False,
 
2471
             alias=False):
 
2472
        """Register a metadir subformat.
 
2473
 
 
2474
        These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
 
2475
        by the Repository format.
 
2476
 
 
2477
        :param repository_format: The fully-qualified repository format class
 
2478
            name as a string.
 
2479
        :param branch_format: Fully-qualified branch format class name as
 
2480
            a string.
 
2481
        :param tree_format: Fully-qualified tree format class name as
 
2482
            a string.
 
2483
        """
 
2484
        # This should be expanded to support setting WorkingTree and Branch
 
2485
        # formats, once BzrDirMetaFormat1 supports that.
 
2486
        def _load(full_name):
 
2487
            mod_name, factory_name = full_name.rsplit('.', 1)
 
2488
            try:
 
2489
                mod = __import__(mod_name, globals(), locals(),
 
2490
                        [factory_name])
 
2491
            except ImportError, e:
 
2492
                raise ImportError('failed to load %s: %s' % (full_name, e))
 
2493
            try:
 
2494
                factory = getattr(mod, factory_name)
 
2495
            except AttributeError:
 
2496
                raise AttributeError('no factory %s in module %r'
 
2497
                    % (full_name, mod))
 
2498
            return factory()
 
2499
 
 
2500
        def helper():
 
2501
            bd = BzrDirMetaFormat1()
 
2502
            if branch_format is not None:
 
2503
                bd.set_branch_format(_load(branch_format))
 
2504
            if tree_format is not None:
 
2505
                bd.workingtree_format = _load(tree_format)
 
2506
            if repository_format is not None:
 
2507
                bd.repository_format = _load(repository_format)
 
2508
            return bd
 
2509
        self.register(key, helper, help, native, deprecated, hidden,
 
2510
            experimental, alias)
 
2511
 
 
2512
    def register(self, key, factory, help, native=True, deprecated=False,
 
2513
                 hidden=False, experimental=False, alias=False):
 
2514
        """Register a BzrDirFormat factory.
 
2515
        
 
2516
        The factory must be a callable that takes one parameter: the key.
 
2517
        It must produce an instance of the BzrDirFormat when called.
 
2518
 
 
2519
        This function mainly exists to prevent the info object from being
 
2520
        supplied directly.
 
2521
        """
 
2522
        registry.Registry.register(self, key, factory, help,
 
2523
            BzrDirFormatInfo(native, deprecated, hidden, experimental))
 
2524
        if alias:
 
2525
            self._aliases.add(key)
 
2526
 
 
2527
    def register_lazy(self, key, module_name, member_name, help, native=True,
 
2528
        deprecated=False, hidden=False, experimental=False, alias=False):
 
2529
        registry.Registry.register_lazy(self, key, module_name, member_name,
 
2530
            help, BzrDirFormatInfo(native, deprecated, hidden, experimental))
 
2531
        if alias:
 
2532
            self._aliases.add(key)
 
2533
 
 
2534
    def set_default(self, key):
 
2535
        """Set the 'default' key to be a clone of the supplied key.
 
2536
        
 
2537
        This method must be called once and only once.
 
2538
        """
 
2539
        registry.Registry.register(self, 'default', self.get(key),
 
2540
            self.get_help(key), info=self.get_info(key))
 
2541
        self._aliases.add('default')
 
2542
 
 
2543
    def set_default_repository(self, key):
 
2544
        """Set the FormatRegistry default and Repository default.
 
2545
        
 
2546
        This is a transitional method while Repository.set_default_format
 
2547
        is deprecated.
 
2548
        """
 
2549
        if 'default' in self:
 
2550
            self.remove('default')
 
2551
        self.set_default(key)
 
2552
        format = self.get('default')()
 
2553
        assert isinstance(format, BzrDirMetaFormat1)
 
2554
 
 
2555
    def make_bzrdir(self, key):
 
2556
        return self.get(key)()
 
2557
 
 
2558
    def help_topic(self, topic):
 
2559
        output = textwrap.dedent("""\
 
2560
            These formats can be used for creating branches, working trees, and
 
2561
            repositories.
 
2562
 
 
2563
            """)
 
2564
        default_realkey = None
 
2565
        default_help = self.get_help('default')
 
2566
        help_pairs = []
 
2567
        for key in self.keys():
 
2568
            if key == 'default':
 
2569
                continue
 
2570
            help = self.get_help(key)
 
2571
            if help == default_help:
 
2572
                default_realkey = key
 
2573
            else:
 
2574
                help_pairs.append((key, help))
 
2575
 
 
2576
        def wrapped(key, help, info):
 
2577
            if info.native:
 
2578
                help = '(native) ' + help
 
2579
            return ':%s:\n%s\n\n' % (key, 
 
2580
                    textwrap.fill(help, initial_indent='    ', 
 
2581
                    subsequent_indent='    '))
 
2582
        if default_realkey is not None:
 
2583
            output += wrapped(default_realkey, '(default) %s' % default_help,
 
2584
                              self.get_info('default'))
 
2585
        deprecated_pairs = []
 
2586
        experimental_pairs = []
 
2587
        for key, help in help_pairs:
 
2588
            info = self.get_info(key)
 
2589
            if info.hidden:
 
2590
                continue
 
2591
            elif info.deprecated:
 
2592
                deprecated_pairs.append((key, help))
 
2593
            elif info.experimental:
 
2594
                experimental_pairs.append((key, help))
 
2595
            else:
 
2596
                output += wrapped(key, help, info)
 
2597
        if len(experimental_pairs) > 0:
 
2598
            output += "Experimental formats are shown below.\n\n"
 
2599
            for key, help in experimental_pairs:
 
2600
                info = self.get_info(key)
 
2601
                output += wrapped(key, help, info)
 
2602
        if len(deprecated_pairs) > 0:
 
2603
            output += "Deprecated formats are shown below.\n\n"
 
2604
            for key, help in deprecated_pairs:
 
2605
                info = self.get_info(key)
 
2606
                output += wrapped(key, help, info)
 
2607
 
 
2608
        return output
 
2609
 
 
2610
 
 
2611
format_registry = BzrDirFormatRegistry()
 
2612
format_registry.register('weave', BzrDirFormat6,
 
2613
    'Pre-0.8 format.  Slower than knit and does not'
 
2614
    ' support checkouts or shared repositories.',
 
2615
    deprecated=True)
 
2616
format_registry.register_metadir('knit',
1960
2617
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
1961
2618
    'Format using knits.  Recommended for interoperation with bzr <= 0.14.',
1962
2619
    branch_format='bzrlib.branch.BzrBranchFormat5',
1963
 
    tree_format='bzrlib.workingtree_3.WorkingTreeFormat3',
1964
 
    hidden=True,
 
2620
    tree_format='bzrlib.workingtree.WorkingTreeFormat3')
 
2621
format_registry.register_metadir('metaweave',
 
2622
    'bzrlib.repofmt.weaverepo.RepositoryFormat7',
 
2623
    'Transitional format in 0.8.  Slower than knit.',
 
2624
    branch_format='bzrlib.branch.BzrBranchFormat5',
 
2625
    tree_format='bzrlib.workingtree.WorkingTreeFormat3',
1965
2626
    deprecated=True)
1966
 
register_metadir(controldir.format_registry, 'dirstate',
 
2627
format_registry.register_metadir('dirstate',
1967
2628
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
1968
2629
    help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
1969
2630
        'above when accessed over the network.',
1970
2631
    branch_format='bzrlib.branch.BzrBranchFormat5',
1971
 
    tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
1972
 
    hidden=True,
1973
 
    deprecated=True)
1974
 
register_metadir(controldir.format_registry, 'dirstate-tags',
 
2632
    # this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
 
2633
    # directly from workingtree_4 triggers a circular import.
 
2634
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2635
    )
 
2636
format_registry.register_metadir('dirstate-tags',
1975
2637
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
1976
2638
    help='New in 0.15: Fast local operations and improved scaling for '
1977
2639
        'network operations. Additionally adds support for tags.'
1978
2640
        ' Incompatible with bzr < 0.15.',
1979
2641
    branch_format='bzrlib.branch.BzrBranchFormat6',
1980
 
    tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
1981
 
    hidden=True,
1982
 
    deprecated=True)
1983
 
register_metadir(controldir.format_registry, 'rich-root',
 
2642
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2643
    )
 
2644
format_registry.register_metadir('rich-root',
1984
2645
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit4',
1985
2646
    help='New in 1.0.  Better handling of tree roots.  Incompatible with'
1986
 
        ' bzr < 1.0.',
 
2647
        ' bzr < 1.0',
1987
2648
    branch_format='bzrlib.branch.BzrBranchFormat6',
1988
 
    tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
1989
 
    hidden=True,
1990
 
    deprecated=True)
1991
 
register_metadir(controldir.format_registry, 'dirstate-with-subtree',
 
2649
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2650
    )
 
2651
format_registry.register_metadir('dirstate-with-subtree',
1992
2652
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
1993
2653
    help='New in 0.15: Fast local operations and improved scaling for '
1994
2654
        'network operations. Additionally adds support for versioning nested '
1995
2655
        'bzr branches. Incompatible with bzr < 0.15.',
1996
2656
    branch_format='bzrlib.branch.BzrBranchFormat6',
1997
 
    tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
 
2657
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
1998
2658
    experimental=True,
1999
2659
    hidden=True,
2000
2660
    )
2001
 
register_metadir(controldir.format_registry, 'pack-0.92',
2002
 
    'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack1',
 
2661
format_registry.register_metadir('pack-0.92',
 
2662
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack1',
2003
2663
    help='New in 0.92: Pack-based format with data compatible with '
2004
2664
        'dirstate-tags format repositories. Interoperates with '
2005
2665
        'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
2006
 
        ,
 
2666
        'Previously called knitpack-experimental.  '
 
2667
        'For more information, see '
 
2668
        'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
2007
2669
    branch_format='bzrlib.branch.BzrBranchFormat6',
2008
 
    tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
 
2670
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2009
2671
    )
2010
 
register_metadir(controldir.format_registry, 'pack-0.92-subtree',
2011
 
    'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack3',
 
2672
format_registry.register_metadir('pack-0.92-subtree',
 
2673
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack3',
2012
2674
    help='New in 0.92: Pack-based format with data compatible with '
2013
2675
        'dirstate-with-subtree format repositories. Interoperates with '
2014
2676
        'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
2015
 
        ,
2016
 
    branch_format='bzrlib.branch.BzrBranchFormat6',
2017
 
    tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2018
 
    hidden=True,
2019
 
    experimental=True,
2020
 
    )
2021
 
register_metadir(controldir.format_registry, 'rich-root-pack',
2022
 
    'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack4',
2023
 
    help='New in 1.0: A variant of pack-0.92 that supports rich-root data '
2024
 
         '(needed for bzr-svn and bzr-git).',
2025
 
    branch_format='bzrlib.branch.BzrBranchFormat6',
2026
 
    tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2027
 
    hidden=True,
2028
 
    )
2029
 
register_metadir(controldir.format_registry, '1.6',
2030
 
    'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack5',
2031
 
    help='A format that allows a branch to indicate that there is another '
2032
 
         '(stacked) repository that should be used to access data that is '
2033
 
         'not present locally.',
2034
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
2035
 
    tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2036
 
    hidden=True,
2037
 
    )
2038
 
register_metadir(controldir.format_registry, '1.6.1-rich-root',
2039
 
    'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack5RichRoot',
2040
 
    help='A variant of 1.6 that supports rich-root data '
2041
 
         '(needed for bzr-svn and bzr-git).',
2042
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
2043
 
    tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2044
 
    hidden=True,
2045
 
    )
2046
 
register_metadir(controldir.format_registry, '1.9',
2047
 
    'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack6',
2048
 
    help='A repository format using B+tree indexes. These indexes '
2049
 
         'are smaller in size, have smarter caching and provide faster '
2050
 
         'performance for most operations.',
2051
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
2052
 
    tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2053
 
    hidden=True,
2054
 
    )
2055
 
register_metadir(controldir.format_registry, '1.9-rich-root',
2056
 
    'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack6RichRoot',
2057
 
    help='A variant of 1.9 that supports rich-root data '
2058
 
         '(needed for bzr-svn and bzr-git).',
2059
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
2060
 
    tree_format='bzrlib.workingtree_4.WorkingTreeFormat4',
2061
 
    hidden=True,
2062
 
    )
2063
 
register_metadir(controldir.format_registry, '1.14',
2064
 
    'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack6',
2065
 
    help='A working-tree format that supports content filtering.',
2066
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
2067
 
    tree_format='bzrlib.workingtree_4.WorkingTreeFormat5',
2068
 
    )
2069
 
register_metadir(controldir.format_registry, '1.14-rich-root',
2070
 
    'bzrlib.repofmt.knitpack_repo.RepositoryFormatKnitPack6RichRoot',
2071
 
    help='A variant of 1.14 that supports rich-root data '
2072
 
         '(needed for bzr-svn and bzr-git).',
2073
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
2074
 
    tree_format='bzrlib.workingtree_4.WorkingTreeFormat5',
2075
 
    )
2076
 
# The following un-numbered 'development' formats should always just be aliases.
2077
 
register_metadir(controldir.format_registry, 'development-subtree',
2078
 
    'bzrlib.repofmt.groupcompress_repo.RepositoryFormat2aSubtree',
 
2677
        'Previously called knitpack-experimental.  '
 
2678
        'For more information, see '
 
2679
        'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
 
2680
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2681
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2682
    hidden=True,
 
2683
    experimental=True,
 
2684
    )
 
2685
format_registry.register_metadir('rich-root-pack',
 
2686
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack4',
 
2687
    help='New in 1.0: Pack-based format with data compatible with '
 
2688
        'rich-root format repositories. Incompatible with'
 
2689
        ' bzr < 1.0',
 
2690
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2691
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2692
    )
 
2693
# The following two formats should always just be aliases.
 
2694
format_registry.register_metadir('development',
 
2695
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0',
 
2696
    help='Current development format. Can convert data to and from pack-0.92 '
 
2697
        '(and anything compatible with pack-0.92) format repositories. '
 
2698
        'Repositories in this format can only be read by bzr.dev. '
 
2699
        'Please read '
 
2700
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
 
2701
        'before use.',
 
2702
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2703
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2704
    experimental=True,
 
2705
    alias=True,
 
2706
    )
 
2707
format_registry.register_metadir('development-subtree',
 
2708
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0Subtree',
2079
2709
    help='Current development format, subtree variant. Can convert data to and '
2080
 
        'from pack-0.92-subtree (and anything compatible with '
2081
 
        'pack-0.92-subtree) format repositories. Repositories and branches in '
2082
 
        'this format can only be read by bzr.dev. Please read '
2083
 
        'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
2084
 
        'before use.',
2085
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
2086
 
    tree_format='bzrlib.workingtree_4.WorkingTreeFormat6',
2087
 
    experimental=True,
2088
 
    hidden=True,
2089
 
    alias=False, # Restore to being an alias when an actual development subtree format is added
2090
 
                 # This current non-alias status is simply because we did not introduce a
2091
 
                 # chk based subtree format.
2092
 
    )
2093
 
register_metadir(controldir.format_registry, 'development5-subtree',
2094
 
    'bzrlib.repofmt.knitpack_repo.RepositoryFormatPackDevelopment2Subtree',
2095
 
    help='Development format, subtree variant. Can convert data to and '
2096
 
        'from pack-0.92-subtree (and anything compatible with '
2097
 
        'pack-0.92-subtree) format repositories. Repositories and branches in '
2098
 
        'this format can only be read by bzr.dev. Please read '
2099
 
        'http://doc.bazaar.canonical.com/latest/developers/development-repo.html '
2100
 
        'before use.',
2101
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
2102
 
    tree_format='bzrlib.workingtree_4.WorkingTreeFormat6',
2103
 
    experimental=True,
2104
 
    hidden=True,
2105
 
    alias=False,
2106
 
    )
2107
 
 
2108
 
register_metadir(controldir.format_registry, 'development-colo',
2109
 
    'bzrlib.repofmt.groupcompress_repo.RepositoryFormat2a',
2110
 
    help='The 2a format with experimental support for colocated branches.\n',
2111
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
2112
 
    tree_format='bzrlib.workingtree_4.WorkingTreeFormat6',
2113
 
    experimental=False,
2114
 
    bzrdir_format=BzrDirMetaFormat1Colo,
2115
 
    )
2116
 
 
2117
 
 
2118
 
# And the development formats above will have aliased one of the following:
2119
 
 
2120
 
# Finally, the current format.
2121
 
register_metadir(controldir.format_registry, '2a',
2122
 
    'bzrlib.repofmt.groupcompress_repo.RepositoryFormat2a',
2123
 
    help='First format for bzr 2.0 series.\n'
2124
 
        'Uses group-compress storage.\n'
2125
 
        'Provides rich roots which are a one-way transition.\n',
2126
 
        # 'storage in packs, 255-way hashed CHK inventory, bencode revision, group compress, '
2127
 
        # 'rich roots. Supported by bzr 1.16 and later.',
2128
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
2129
 
    tree_format='bzrlib.workingtree_4.WorkingTreeFormat6',
2130
 
    experimental=False,
2131
 
    )
2132
 
 
2133
 
# The following format should be an alias for the rich root equivalent 
2134
 
# of the default format
2135
 
register_metadir(controldir.format_registry, 'default-rich-root',
2136
 
    'bzrlib.repofmt.groupcompress_repo.RepositoryFormat2a',
2137
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
2138
 
    tree_format='bzrlib.workingtree_4.WorkingTreeFormat6',
 
2710
        'from pack-0.92 (and anything compatible with pack-0.92) format '
 
2711
        'repositories. Repositories in this format can only be read by '
 
2712
        'bzr.dev. Please read '
 
2713
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
 
2714
        'before use.',
 
2715
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2716
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2717
    experimental=True,
2139
2718
    alias=True,
2140
 
    hidden=True,
2141
 
    help='Same as 2a.')
2142
 
 
2143
 
# The current format that is made on 'bzr init'.
2144
 
format_name = config.GlobalStack().get('default_format')
2145
 
controldir.format_registry.set_default(format_name)
2146
 
 
2147
 
# XXX 2010-08-20 JRV: There is still a lot of code relying on
2148
 
# bzrlib.bzrdir.format_registry existing. When BzrDir.create/BzrDir.open/etc
2149
 
# get changed to ControlDir.create/ControlDir.open/etc this should be removed.
2150
 
format_registry = controldir.format_registry
 
2719
    )
 
2720
# And the development formats which the will have aliased one of follow:
 
2721
format_registry.register_metadir('development0',
 
2722
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0',
 
2723
    help='Trivial rename of pack-0.92 to provide a development format. '
 
2724
        'Please read '
 
2725
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
 
2726
        'before use.',
 
2727
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2728
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2729
    hidden=True,
 
2730
    experimental=True,
 
2731
    )
 
2732
format_registry.register_metadir('development0-subtree',
 
2733
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0Subtree',
 
2734
    help='Trivial rename of pack-0.92-subtree to provide a development format. '
 
2735
        'Please read '
 
2736
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
 
2737
        'before use.',
 
2738
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2739
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2740
    hidden=True,
 
2741
    experimental=True,
 
2742
    )
 
2743
format_registry.set_default('pack-0.92')