~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

  • Committer: Ian Clatworthy
  • Date: 2009-01-19 02:24:15 UTC
  • mto: This revision was merged to the branch mainline in revision 3944.
  • Revision ID: ian.clatworthy@canonical.com-20090119022415-mo0mcfeiexfktgwt
apply jam's log --short fix (Ian Clatworthy)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
2
 
 
 
1
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
 
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
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
 
 
7
#
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
18
 
19
19
At format 7 this was split out into Branch, Repository and Checkout control
20
20
directories.
 
21
 
 
22
Note: This module has a lot of ``open`` functions/methods that return
 
23
references to in-memory objects. As a rule, there are no matching ``close``
 
24
methods. To free any associated resources, simply stop referencing the
 
25
objects returned.
21
26
"""
22
27
 
23
 
from copy import deepcopy
 
28
# TODO: Move old formats into a plugin to make this file smaller.
 
29
 
24
30
import os
25
 
from cStringIO import StringIO
26
 
from unittest import TestSuite
 
31
import sys
 
32
 
 
33
from bzrlib.lazy_import import lazy_import
 
34
lazy_import(globals(), """
 
35
from stat import S_ISDIR
 
36
import textwrap
27
37
 
28
38
import bzrlib
29
 
import bzrlib.errors as errors
30
 
from bzrlib.lockable_files import LockableFiles, TransportLock
31
 
from bzrlib.lockdir import LockDir
 
39
from bzrlib import (
 
40
    config,
 
41
    errors,
 
42
    graph,
 
43
    lockable_files,
 
44
    lockdir,
 
45
    osutils,
 
46
    remote,
 
47
    revision as _mod_revision,
 
48
    ui,
 
49
    urlutils,
 
50
    versionedfile,
 
51
    win32utils,
 
52
    workingtree,
 
53
    workingtree_4,
 
54
    xml4,
 
55
    xml5,
 
56
    )
32
57
from bzrlib.osutils import (
33
 
                            abspath,
34
 
                            pathjoin,
35
 
                            safe_unicode,
36
 
                            sha_strings,
37
 
                            sha_string,
38
 
                            )
39
 
from bzrlib.store.revision.text import TextRevisionStore
40
 
from bzrlib.store.text import TextStore
 
58
    sha_string,
 
59
    )
 
60
from bzrlib.smart.client import _SmartClient
41
61
from bzrlib.store.versioned import WeaveStore
42
 
from bzrlib.symbol_versioning import *
43
 
from bzrlib.trace import mutter
44
62
from bzrlib.transactions import WriteTransaction
45
 
from bzrlib.transport import get_transport
46
 
from bzrlib.transport.local import LocalTransport
47
 
import bzrlib.urlutils as urlutils
 
63
from bzrlib.transport import (
 
64
    do_catching_redirections,
 
65
    get_transport,
 
66
    local,
 
67
    )
48
68
from bzrlib.weave import Weave
49
 
from bzrlib.xml4 import serializer_v4
50
 
import bzrlib.xml5
 
69
""")
 
70
 
 
71
from bzrlib.trace import (
 
72
    mutter,
 
73
    note,
 
74
    )
 
75
 
 
76
from bzrlib import (
 
77
    registry,
 
78
    symbol_versioning,
 
79
    )
51
80
 
52
81
 
53
82
class BzrDir(object):
56
85
    BzrDir instances let you create or open any of the things that can be
57
86
    found within .bzr - checkouts, branches and repositories.
58
87
    
59
 
    transport
 
88
    :ivar transport:
60
89
        the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
61
 
    root_transport
62
 
        a transport connected to the directory this bzr was opened from.
 
90
    :ivar root_transport:
 
91
        a transport connected to the directory this bzr was opened from
 
92
        (i.e. the parent directory holding the .bzr directory).
 
93
 
 
94
    Everything in the bzrdir should have the same file permissions.
63
95
    """
64
96
 
65
97
    def break_lock(self):
68
100
        If there is a tree, the tree is opened and break_lock() called.
69
101
        Otherwise, branch is tried, and finally repository.
70
102
        """
 
103
        # XXX: This seems more like a UI function than something that really
 
104
        # belongs in this class.
71
105
        try:
72
106
            thing_to_unlock = self.open_workingtree()
73
107
        except (errors.NotLocalUrl, errors.NoWorkingTree):
84
118
        """Return true if this bzrdir is one whose format we can convert from."""
85
119
        return True
86
120
 
 
121
    def check_conversion_target(self, target_format):
 
122
        target_repo_format = target_format.repository_format
 
123
        source_repo_format = self._format.repository_format
 
124
        source_repo_format.check_conversion_target(target_repo_format)
 
125
 
87
126
    @staticmethod
88
 
    def _check_supported(format, allow_unsupported):
89
 
        """Check whether format is a supported format.
90
 
 
91
 
        If allow_unsupported is True, this is a no-op.
 
127
    def _check_supported(format, allow_unsupported,
 
128
        recommend_upgrade=True,
 
129
        basedir=None):
 
130
        """Give an error or warning on old formats.
 
131
 
 
132
        :param format: may be any kind of format - workingtree, branch, 
 
133
        or repository.
 
134
 
 
135
        :param allow_unsupported: If true, allow opening 
 
136
        formats that are strongly deprecated, and which may 
 
137
        have limited functionality.
 
138
 
 
139
        :param recommend_upgrade: If true (default), warn
 
140
        the user through the ui object that they may wish
 
141
        to upgrade the object.
92
142
        """
 
143
        # TODO: perhaps move this into a base Format class; it's not BzrDir
 
144
        # specific. mbp 20070323
93
145
        if not allow_unsupported and not format.is_supported():
94
146
            # see open_downlevel to open legacy branches.
95
 
            raise errors.UnsupportedFormatError(
96
 
                    'sorry, format %s not supported' % format,
97
 
                    ['use a different bzr version',
98
 
                     'or remove the .bzr directory'
99
 
                     ' and "bzr init" again'])
 
147
            raise errors.UnsupportedFormatError(format=format)
 
148
        if recommend_upgrade \
 
149
            and getattr(format, 'upgrade_recommended', False):
 
150
            ui.ui_factory.recommend_upgrade(
 
151
                format.get_format_description(),
 
152
                basedir)
100
153
 
101
 
    def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
 
154
    def clone(self, url, revision_id=None, force_new_repo=False,
 
155
              preserve_stacking=False):
102
156
        """Clone this bzrdir and its contents to url verbatim.
103
157
 
104
 
        If urls last component does not exist, it will be created.
105
 
 
106
 
        if revision_id is not None, then the clone operation may tune
107
 
            itself to download less data.
108
 
        :param force_new_repo: Do not use a shared repository for the target 
109
 
                               even if one is available.
110
 
        """
111
 
        self._make_tail(url)
112
 
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
113
 
        result = self._format.initialize(url)
 
158
        :param url: The url create the clone at.  If url's last component does
 
159
            not exist, it will be created.
 
160
        :param revision_id: The tip revision-id to use for any branch or
 
161
            working tree.  If not None, then the clone operation may tune
 
162
            itself to download less data.
 
163
        :param force_new_repo: Do not use a shared repository for the target
 
164
                               even if one is available.
 
165
        :param preserve_stacking: When cloning a stacked branch, stack the
 
166
            new branch on top of the other branch's stacked-on branch.
 
167
        """
 
168
        return self.clone_on_transport(get_transport(url),
 
169
                                       revision_id=revision_id,
 
170
                                       force_new_repo=force_new_repo,
 
171
                                       preserve_stacking=preserve_stacking)
 
172
 
 
173
    def clone_on_transport(self, transport, revision_id=None,
 
174
                           force_new_repo=False, preserve_stacking=False,
 
175
                           stacked_on=None):
 
176
        """Clone this bzrdir and its contents to transport verbatim.
 
177
 
 
178
        :param transport: The transport for the location to produce the clone
 
179
            at.  If the target directory does not exist, it will be created.
 
180
        :param revision_id: The tip revision-id to use for any branch or
 
181
            working tree.  If not None, then the clone operation may tune
 
182
            itself to download less data.
 
183
        :param force_new_repo: Do not use a shared repository for the target,
 
184
                               even if one is available.
 
185
        :param preserve_stacking: When cloning a stacked branch, stack the
 
186
            new branch on top of the other branch's stacked-on branch.
 
187
        """
 
188
        transport.ensure_base()
 
189
        require_stacking = (stacked_on is not None)
 
190
        metadir = self.cloning_metadir(require_stacking)
 
191
        result = metadir.initialize_on_transport(transport)
 
192
        repository_policy = None
114
193
        try:
115
194
            local_repo = self.find_repository()
116
195
        except errors.NoRepositoryPresent:
117
196
            local_repo = None
 
197
        try:
 
198
            local_branch = self.open_branch()
 
199
        except errors.NotBranchError:
 
200
            local_branch = None
 
201
        else:
 
202
            # enable fallbacks when branch is not a branch reference
 
203
            if local_branch.repository.has_same_location(local_repo):
 
204
                local_repo = local_branch.repository
 
205
            if preserve_stacking:
 
206
                try:
 
207
                    stacked_on = local_branch.get_stacked_on_url()
 
208
                except (errors.UnstackableBranchFormat,
 
209
                        errors.UnstackableRepositoryFormat,
 
210
                        errors.NotStacked):
 
211
                    pass
 
212
 
118
213
        if local_repo:
119
214
            # may need to copy content in
120
 
            if force_new_repo:
121
 
                result_repo = local_repo.clone(
122
 
                    result,
123
 
                    revision_id=revision_id,
124
 
                    basis=basis_repo)
125
 
                result_repo.set_make_working_trees(local_repo.make_working_trees())
126
 
            else:
127
 
                try:
128
 
                    result_repo = result.find_repository()
129
 
                    # fetch content this dir needs.
130
 
                    if basis_repo:
131
 
                        # XXX FIXME RBC 20060214 need tests for this when the basis
132
 
                        # is incomplete
133
 
                        result_repo.fetch(basis_repo, revision_id=revision_id)
134
 
                    result_repo.fetch(local_repo, revision_id=revision_id)
135
 
                except errors.NoRepositoryPresent:
136
 
                    # needed to make one anyway.
137
 
                    result_repo = local_repo.clone(
138
 
                        result,
139
 
                        revision_id=revision_id,
140
 
                        basis=basis_repo)
141
 
                    result_repo.set_make_working_trees(local_repo.make_working_trees())
 
215
            repository_policy = result.determine_repository_policy(
 
216
                force_new_repo, stacked_on, self.root_transport.base,
 
217
                require_stacking=require_stacking)
 
218
            make_working_trees = local_repo.make_working_trees()
 
219
            result_repo = repository_policy.acquire_repository(
 
220
                make_working_trees, local_repo.is_shared())
 
221
            if not require_stacking and repository_policy._require_stacking:
 
222
                require_stacking = True
 
223
                result._format.require_stacking()
 
224
            result_repo.fetch(local_repo, revision_id=revision_id)
 
225
        else:
 
226
            result_repo = None
142
227
        # 1 if there is a branch present
143
228
        #   make sure its content is available in the target repository
144
229
        #   clone it.
145
 
        try:
146
 
            self.open_branch().clone(result, revision_id=revision_id)
147
 
        except errors.NotBranchError:
148
 
            pass
149
 
        try:
150
 
            self.open_workingtree().clone(result, basis=basis_tree)
151
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
152
 
            pass
 
230
        if local_branch is not None:
 
231
            result_branch = local_branch.clone(result, revision_id=revision_id)
 
232
            if repository_policy is not None:
 
233
                repository_policy.configure_branch(result_branch)
 
234
        if result_repo is None or result_repo.make_working_trees():
 
235
            try:
 
236
                self.open_workingtree().clone(result)
 
237
            except (errors.NoWorkingTree, errors.NotLocalUrl):
 
238
                pass
153
239
        return result
154
240
 
155
 
    def _get_basis_components(self, basis):
156
 
        """Retrieve the basis components that are available at basis."""
157
 
        if basis is None:
158
 
            return None, None, None
159
 
        try:
160
 
            basis_tree = basis.open_workingtree()
161
 
            basis_branch = basis_tree.branch
162
 
            basis_repo = basis_branch.repository
163
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
164
 
            basis_tree = None
165
 
            try:
166
 
                basis_branch = basis.open_branch()
167
 
                basis_repo = basis_branch.repository
168
 
            except errors.NotBranchError:
169
 
                basis_branch = None
170
 
                try:
171
 
                    basis_repo = basis.open_repository()
172
 
                except errors.NoRepositoryPresent:
173
 
                    basis_repo = None
174
 
        return basis_repo, basis_branch, basis_tree
175
 
 
176
241
    # TODO: This should be given a Transport, and should chdir up; otherwise
177
242
    # this will open a new connection.
178
243
    def _make_tail(self, url):
179
 
        head, tail = urlutils.split(url)
180
 
        if tail and tail != '.':
181
 
            t = bzrlib.transport.get_transport(head)
182
 
            try:
183
 
                t.mkdir(tail)
184
 
            except errors.FileExists:
185
 
                pass
 
244
        t = get_transport(url)
 
245
        t.ensure_base()
186
246
 
187
 
    # TODO: Should take a Transport
188
247
    @classmethod
189
 
    def create(cls, base):
 
248
    def create(cls, base, format=None, possible_transports=None):
190
249
        """Create a new BzrDir at the url 'base'.
191
250
        
192
 
        This will call the current default formats initialize with base
193
 
        as the only parameter.
194
 
 
195
 
        If you need a specific format, consider creating an instance
196
 
        of that and calling initialize().
 
251
        :param format: If supplied, the format of branch to create.  If not
 
252
            supplied, the default is used.
 
253
        :param possible_transports: If supplied, a list of transports that 
 
254
            can be reused to share a remote connection.
197
255
        """
198
256
        if cls is not BzrDir:
199
 
            raise AssertionError("BzrDir.create always creates the default format, "
200
 
                    "not one of %r" % cls)
201
 
        head, tail = urlutils.split(base)
202
 
        if tail and tail != '.':
203
 
            t = bzrlib.transport.get_transport(head)
204
 
            try:
205
 
                t.mkdir(tail)
206
 
            except errors.FileExists:
207
 
                pass
208
 
        return BzrDirFormat.get_default_format().initialize(safe_unicode(base))
 
257
            raise AssertionError("BzrDir.create always creates the default"
 
258
                " format, not one of %r" % cls)
 
259
        t = get_transport(base, possible_transports)
 
260
        t.ensure_base()
 
261
        if format is None:
 
262
            format = BzrDirFormat.get_default_format()
 
263
        return format.initialize_on_transport(t)
 
264
 
 
265
    @staticmethod
 
266
    def find_bzrdirs(transport, evaluate=None, list_current=None):
 
267
        """Find bzrdirs recursively from current location.
 
268
 
 
269
        This is intended primarily as a building block for more sophisticated
 
270
        functionality, like finding trees under a directory, or finding
 
271
        branches that use a given repository.
 
272
        :param evaluate: An optional callable that yields recurse, value,
 
273
            where recurse controls whether this bzrdir is recursed into
 
274
            and value is the value to yield.  By default, all bzrdirs
 
275
            are recursed into, and the return value is the bzrdir.
 
276
        :param list_current: if supplied, use this function to list the current
 
277
            directory, instead of Transport.list_dir
 
278
        :return: a generator of found bzrdirs, or whatever evaluate returns.
 
279
        """
 
280
        if list_current is None:
 
281
            def list_current(transport):
 
282
                return transport.list_dir('')
 
283
        if evaluate is None:
 
284
            def evaluate(bzrdir):
 
285
                return True, bzrdir
 
286
 
 
287
        pending = [transport]
 
288
        while len(pending) > 0:
 
289
            current_transport = pending.pop()
 
290
            recurse = True
 
291
            try:
 
292
                bzrdir = BzrDir.open_from_transport(current_transport)
 
293
            except errors.NotBranchError:
 
294
                pass
 
295
            else:
 
296
                recurse, value = evaluate(bzrdir)
 
297
                yield value
 
298
            try:
 
299
                subdirs = list_current(current_transport)
 
300
            except errors.NoSuchFile:
 
301
                continue
 
302
            if recurse:
 
303
                for subdir in sorted(subdirs, reverse=True):
 
304
                    pending.append(current_transport.clone(subdir))
 
305
 
 
306
    @staticmethod
 
307
    def find_branches(transport):
 
308
        """Find all branches under a transport.
 
309
 
 
310
        This will find all branches below the transport, including branches
 
311
        inside other branches.  Where possible, it will use
 
312
        Repository.find_branches.
 
313
 
 
314
        To list all the branches that use a particular Repository, see
 
315
        Repository.find_branches
 
316
        """
 
317
        def evaluate(bzrdir):
 
318
            try:
 
319
                repository = bzrdir.open_repository()
 
320
            except errors.NoRepositoryPresent:
 
321
                pass
 
322
            else:
 
323
                return False, (None, repository)
 
324
            try:
 
325
                branch = bzrdir.open_branch()
 
326
            except errors.NotBranchError:
 
327
                return True, (None, None)
 
328
            else:
 
329
                return True, (branch, None)
 
330
        branches = []
 
331
        for branch, repo in BzrDir.find_bzrdirs(transport, evaluate=evaluate):
 
332
            if repo is not None:
 
333
                branches.extend(repo.find_branches())
 
334
            if branch is not None:
 
335
                branches.append(branch)
 
336
        return branches
 
337
 
 
338
    def destroy_repository(self):
 
339
        """Destroy the repository in this BzrDir"""
 
340
        raise NotImplementedError(self.destroy_repository)
209
341
 
210
342
    def create_branch(self):
211
343
        """Create a branch in this BzrDir.
212
344
 
213
 
        The bzrdirs format will control what branch format is created.
 
345
        The bzrdir's format will control what branch format is created.
214
346
        For more control see BranchFormatXX.create(a_bzrdir).
215
347
        """
216
348
        raise NotImplementedError(self.create_branch)
217
349
 
 
350
    def destroy_branch(self):
 
351
        """Destroy the branch in this BzrDir"""
 
352
        raise NotImplementedError(self.destroy_branch)
 
353
 
218
354
    @staticmethod
219
 
    def create_branch_and_repo(base, force_new_repo=False):
 
355
    def create_branch_and_repo(base, force_new_repo=False, format=None):
220
356
        """Create a new BzrDir, Branch and Repository at the url 'base'.
221
357
 
222
 
        This will use the current default BzrDirFormat, and use whatever 
 
358
        This will use the current default BzrDirFormat unless one is
 
359
        specified, and use whatever 
223
360
        repository format that that uses via bzrdir.create_branch and
224
361
        create_repository. If a shared repository is available that is used
225
362
        preferentially.
228
365
 
229
366
        :param base: The URL to create the branch at.
230
367
        :param force_new_repo: If True a new repository is always created.
 
368
        :param format: If supplied, the format of branch to create.  If not
 
369
            supplied, the default is used.
231
370
        """
232
 
        bzrdir = BzrDir.create(base)
 
371
        bzrdir = BzrDir.create(base, format)
233
372
        bzrdir._find_or_create_repository(force_new_repo)
234
373
        return bzrdir.create_branch()
235
374
 
 
375
    def determine_repository_policy(self, force_new_repo=False, stack_on=None,
 
376
                                    stack_on_pwd=None, require_stacking=False):
 
377
        """Return an object representing a policy to use.
 
378
 
 
379
        This controls whether a new repository is created, or a shared
 
380
        repository used instead.
 
381
 
 
382
        If stack_on is supplied, will not seek a containing shared repo.
 
383
 
 
384
        :param force_new_repo: If True, require a new repository to be created.
 
385
        :param stack_on: If supplied, the location to stack on.  If not
 
386
            supplied, a default_stack_on location may be used.
 
387
        :param stack_on_pwd: If stack_on is relative, the location it is
 
388
            relative to.
 
389
        """
 
390
        def repository_policy(found_bzrdir):
 
391
            stack_on = None
 
392
            stack_on_pwd = None
 
393
            config = found_bzrdir.get_config()
 
394
            stop = False
 
395
            if config is not None:
 
396
                stack_on = config.get_default_stack_on()
 
397
                if stack_on is not None:
 
398
                    stack_on_pwd = found_bzrdir.root_transport.base
 
399
                    stop = True
 
400
                    note('Using default stacking branch %s at %s', stack_on,
 
401
                         stack_on_pwd)
 
402
            # does it have a repository ?
 
403
            try:
 
404
                repository = found_bzrdir.open_repository()
 
405
            except errors.NoRepositoryPresent:
 
406
                repository = None
 
407
            else:
 
408
                if ((found_bzrdir.root_transport.base !=
 
409
                     self.root_transport.base) and not repository.is_shared()):
 
410
                    repository = None
 
411
                else:
 
412
                    stop = True
 
413
            if not stop:
 
414
                return None, False
 
415
            if repository:
 
416
                return UseExistingRepository(repository, stack_on,
 
417
                    stack_on_pwd, require_stacking=require_stacking), True
 
418
            else:
 
419
                return CreateRepository(self, stack_on, stack_on_pwd,
 
420
                    require_stacking=require_stacking), True
 
421
 
 
422
        if not force_new_repo:
 
423
            if stack_on is None:
 
424
                policy = self._find_containing(repository_policy)
 
425
                if policy is not None:
 
426
                    return policy
 
427
            else:
 
428
                try:
 
429
                    return UseExistingRepository(self.open_repository(),
 
430
                        stack_on, stack_on_pwd,
 
431
                        require_stacking=require_stacking)
 
432
                except errors.NoRepositoryPresent:
 
433
                    pass
 
434
        return CreateRepository(self, stack_on, stack_on_pwd,
 
435
                                require_stacking=require_stacking)
 
436
 
236
437
    def _find_or_create_repository(self, force_new_repo):
237
438
        """Create a new repository if needed, returning the repository."""
238
 
        if force_new_repo:
239
 
            return self.create_repository()
240
 
        try:
241
 
            return self.find_repository()
242
 
        except errors.NoRepositoryPresent:
243
 
            return self.create_repository()
244
 
        
 
439
        policy = self.determine_repository_policy(force_new_repo)
 
440
        return policy.acquire_repository()
 
441
 
245
442
    @staticmethod
246
443
    def create_branch_convenience(base, force_new_repo=False,
247
 
                                  force_new_tree=None, format=None):
 
444
                                  force_new_tree=None, format=None,
 
445
                                  possible_transports=None):
248
446
        """Create a new BzrDir, Branch and Repository at the url 'base'.
249
447
 
250
448
        This is a convenience function - it will use an existing repository
251
449
        if possible, can be told explicitly whether to create a working tree or
252
450
        not.
253
451
 
254
 
        This will use the current default BzrDirFormat, and use whatever 
 
452
        This will use the current default BzrDirFormat unless one is
 
453
        specified, and use whatever 
255
454
        repository format that that uses via bzrdir.create_branch and
256
455
        create_repository. If a shared repository is available that is used
257
456
        preferentially. Whatever repository is used, its tree creation policy
266
465
        :param force_new_repo: If True a new repository is always created.
267
466
        :param force_new_tree: If True or False force creation of a tree or 
268
467
                               prevent such creation respectively.
269
 
        :param format: Override for the for the bzrdir format to create
 
468
        :param format: Override for the bzrdir format to create.
 
469
        :param possible_transports: An optional reusable transports list.
270
470
        """
271
471
        if force_new_tree:
272
472
            # check for non local urls
273
 
            t = get_transport(safe_unicode(base))
274
 
            if not isinstance(t, LocalTransport):
 
473
            t = get_transport(base, possible_transports)
 
474
            if not isinstance(t, local.LocalTransport):
275
475
                raise errors.NotLocalUrl(base)
276
 
        if format is None:
277
 
            bzrdir = BzrDir.create(base)
278
 
        else:
279
 
            bzrdir = format.initialize(base)
 
476
        bzrdir = BzrDir.create(base, format, possible_transports)
280
477
        repo = bzrdir._find_or_create_repository(force_new_repo)
281
478
        result = bzrdir.create_branch()
282
 
        if force_new_tree or (repo.make_working_trees() and 
 
479
        if force_new_tree or (repo.make_working_trees() and
283
480
                              force_new_tree is None):
284
481
            try:
285
482
                bzrdir.create_workingtree()
286
483
            except errors.NotLocalUrl:
287
484
                pass
288
485
        return result
289
 
        
290
 
    @staticmethod
291
 
    def create_repository(base, shared=False):
292
 
        """Create a new BzrDir and Repository at the url 'base'.
293
 
 
294
 
        This will use the current default BzrDirFormat, and use whatever 
295
 
        repository format that that uses for bzrdirformat.create_repository.
296
 
 
297
 
        ;param shared: Create a shared repository rather than a standalone
298
 
                       repository.
299
 
        The Repository object is returned.
300
 
 
301
 
        This must be overridden as an instance method in child classes, where
302
 
        it should take no parameters and construct whatever repository format
303
 
        that child class desires.
304
 
        """
305
 
        bzrdir = BzrDir.create(base)
306
 
        return bzrdir.create_repository()
307
 
 
308
 
    @staticmethod
309
 
    def create_standalone_workingtree(base):
 
486
 
 
487
    @staticmethod
 
488
    def create_standalone_workingtree(base, format=None):
310
489
        """Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
311
490
 
312
491
        'base' must be a local path or a file:// url.
313
492
 
314
 
        This will use the current default BzrDirFormat, and use whatever 
 
493
        This will use the current default BzrDirFormat unless one is
 
494
        specified, and use whatever 
315
495
        repository format that that uses for bzrdirformat.create_workingtree,
316
496
        create_branch and create_repository.
317
497
 
318
 
        The WorkingTree object is returned.
 
498
        :param format: Override for the bzrdir format to create.
 
499
        :return: The WorkingTree object.
319
500
        """
320
 
        t = get_transport(safe_unicode(base))
321
 
        if not isinstance(t, LocalTransport):
 
501
        t = get_transport(base)
 
502
        if not isinstance(t, local.LocalTransport):
322
503
            raise errors.NotLocalUrl(base)
323
 
        bzrdir = BzrDir.create_branch_and_repo(safe_unicode(base),
324
 
                                               force_new_repo=True).bzrdir
 
504
        bzrdir = BzrDir.create_branch_and_repo(base,
 
505
                                               force_new_repo=True,
 
506
                                               format=format).bzrdir
325
507
        return bzrdir.create_workingtree()
326
508
 
327
 
    def create_workingtree(self, revision_id=None):
 
509
    def create_workingtree(self, revision_id=None, from_branch=None,
 
510
        accelerator_tree=None, hardlink=False):
328
511
        """Create a working tree at this BzrDir.
329
512
        
330
 
        revision_id: create it as of this revision id.
 
513
        :param revision_id: create it as of this revision id.
 
514
        :param from_branch: override bzrdir branch (for lightweight checkouts)
 
515
        :param accelerator_tree: A tree which can be used for retrieving file
 
516
            contents more quickly than the revision tree, i.e. a workingtree.
 
517
            The revision tree will be used for cases where accelerator_tree's
 
518
            content is different.
331
519
        """
332
520
        raise NotImplementedError(self.create_workingtree)
333
521
 
 
522
    def backup_bzrdir(self):
 
523
        """Backup this bzr control directory.
 
524
        
 
525
        :return: Tuple with old path name and new path name
 
526
        """
 
527
        self.root_transport.copy_tree('.bzr', 'backup.bzr')
 
528
        return (self.root_transport.abspath('.bzr'),
 
529
                self.root_transport.abspath('backup.bzr'))
 
530
 
 
531
    def retire_bzrdir(self, limit=10000):
 
532
        """Permanently disable the bzrdir.
 
533
 
 
534
        This is done by renaming it to give the user some ability to recover
 
535
        if there was a problem.
 
536
 
 
537
        This will have horrible consequences if anyone has anything locked or
 
538
        in use.
 
539
        :param limit: number of times to retry
 
540
        """
 
541
        i  = 0
 
542
        while True:
 
543
            try:
 
544
                to_path = '.bzr.retired.%d' % i
 
545
                self.root_transport.rename('.bzr', to_path)
 
546
                note("renamed %s to %s"
 
547
                    % (self.root_transport.abspath('.bzr'), to_path))
 
548
                return
 
549
            except (errors.TransportError, IOError, errors.PathError):
 
550
                i += 1
 
551
                if i > limit:
 
552
                    raise
 
553
                else:
 
554
                    pass
 
555
 
 
556
    def destroy_workingtree(self):
 
557
        """Destroy the working tree at this BzrDir.
 
558
 
 
559
        Formats that do not support this may raise UnsupportedOperation.
 
560
        """
 
561
        raise NotImplementedError(self.destroy_workingtree)
 
562
 
 
563
    def destroy_workingtree_metadata(self):
 
564
        """Destroy the control files for the working tree at this BzrDir.
 
565
 
 
566
        The contents of working tree files are not affected.
 
567
        Formats that do not support this may raise UnsupportedOperation.
 
568
        """
 
569
        raise NotImplementedError(self.destroy_workingtree_metadata)
 
570
 
 
571
    def _find_containing(self, evaluate):
 
572
        """Find something in a containing control directory.
 
573
 
 
574
        This method will scan containing control dirs, until it finds what
 
575
        it is looking for, decides that it will never find it, or runs out
 
576
        of containing control directories to check.
 
577
 
 
578
        It is used to implement find_repository and
 
579
        determine_repository_policy.
 
580
 
 
581
        :param evaluate: A function returning (value, stop).  If stop is True,
 
582
            the value will be returned.
 
583
        """
 
584
        found_bzrdir = self
 
585
        while True:
 
586
            result, stop = evaluate(found_bzrdir)
 
587
            if stop:
 
588
                return result
 
589
            next_transport = found_bzrdir.root_transport.clone('..')
 
590
            if (found_bzrdir.root_transport.base == next_transport.base):
 
591
                # top of the file system
 
592
                return None
 
593
            # find the next containing bzrdir
 
594
            try:
 
595
                found_bzrdir = BzrDir.open_containing_from_transport(
 
596
                    next_transport)[0]
 
597
            except errors.NotBranchError:
 
598
                return None
 
599
 
334
600
    def find_repository(self):
335
 
        """Find the repository that should be used for a_bzrdir.
 
601
        """Find the repository that should be used.
336
602
 
337
603
        This does not require a branch as we use it to find the repo for
338
604
        new branches as well as to hook existing branches up to their
339
605
        repository.
340
606
        """
341
 
        try:
342
 
            return self.open_repository()
343
 
        except errors.NoRepositoryPresent:
344
 
            pass
345
 
        next_transport = self.root_transport.clone('..')
346
 
        while True:
347
 
            # find the next containing bzrdir
348
 
            try:
349
 
                found_bzrdir = BzrDir.open_containing_from_transport(
350
 
                    next_transport)[0]
351
 
            except errors.NotBranchError:
352
 
                # none found
353
 
                raise errors.NoRepositoryPresent(self)
 
607
        def usable_repository(found_bzrdir):
354
608
            # does it have a repository ?
355
609
            try:
356
610
                repository = found_bzrdir.open_repository()
357
611
            except errors.NoRepositoryPresent:
358
 
                next_transport = found_bzrdir.root_transport.clone('..')
359
 
                if (found_bzrdir.root_transport.base == next_transport.base):
360
 
                    # top of the file system
361
 
                    break
362
 
                else:
363
 
                    continue
364
 
            if ((found_bzrdir.root_transport.base == 
365
 
                 self.root_transport.base) or repository.is_shared()):
366
 
                return repository
 
612
                return None, False
 
613
            if found_bzrdir.root_transport.base == self.root_transport.base:
 
614
                return repository, True
 
615
            elif repository.is_shared():
 
616
                return repository, True
367
617
            else:
368
 
                raise errors.NoRepositoryPresent(self)
369
 
        raise errors.NoRepositoryPresent(self)
 
618
                return None, True
 
619
 
 
620
        found_repo = self._find_containing(usable_repository)
 
621
        if found_repo is None:
 
622
            raise errors.NoRepositoryPresent(self)
 
623
        return found_repo
 
624
 
 
625
    def get_branch_reference(self):
 
626
        """Return the referenced URL for the branch in this bzrdir.
 
627
 
 
628
        :raises NotBranchError: If there is no Branch.
 
629
        :return: The URL the branch in this bzrdir references if it is a
 
630
            reference branch, or None for regular branches.
 
631
        """
 
632
        return None
370
633
 
371
634
    def get_branch_transport(self, branch_format):
372
635
        """Get the transport for use by branch format in this BzrDir.
376
639
        a format string, and vice versa.
377
640
 
378
641
        If branch_format is None, the transport is returned with no 
379
 
        checking. if it is not None, then the returned transport is
 
642
        checking. If it is not None, then the returned transport is
380
643
        guaranteed to point to an existing directory ready for use.
381
644
        """
382
645
        raise NotImplementedError(self.get_branch_transport)
 
646
 
 
647
    def _find_creation_modes(self):
 
648
        """Determine the appropriate modes for files and directories.
 
649
 
 
650
        They're always set to be consistent with the base directory,
 
651
        assuming that this transport allows setting modes.
 
652
        """
 
653
        # TODO: Do we need or want an option (maybe a config setting) to turn
 
654
        # this off or override it for particular locations? -- mbp 20080512
 
655
        if self._mode_check_done:
 
656
            return
 
657
        self._mode_check_done = True
 
658
        try:
 
659
            st = self.transport.stat('.')
 
660
        except errors.TransportNotPossible:
 
661
            self._dir_mode = None
 
662
            self._file_mode = None
 
663
        else:
 
664
            # Check the directory mode, but also make sure the created
 
665
            # directories and files are read-write for this user. This is
 
666
            # mostly a workaround for filesystems which lie about being able to
 
667
            # write to a directory (cygwin & win32)
 
668
            if (st.st_mode & 07777 == 00000):
 
669
                # FTP allows stat but does not return dir/file modes
 
670
                self._dir_mode = None
 
671
                self._file_mode = None
 
672
            else:
 
673
                self._dir_mode = (st.st_mode & 07777) | 00700
 
674
                # Remove the sticky and execute bits for files
 
675
                self._file_mode = self._dir_mode & ~07111
 
676
 
 
677
    def _get_file_mode(self):
 
678
        """Return Unix mode for newly created files, or None.
 
679
        """
 
680
        if not self._mode_check_done:
 
681
            self._find_creation_modes()
 
682
        return self._file_mode
 
683
 
 
684
    def _get_dir_mode(self):
 
685
        """Return Unix mode for newly created directories, or None.
 
686
        """
 
687
        if not self._mode_check_done:
 
688
            self._find_creation_modes()
 
689
        return self._dir_mode
383
690
        
384
691
    def get_repository_transport(self, repository_format):
385
692
        """Get the transport for use by repository format in this BzrDir.
389
696
        a format string, and vice versa.
390
697
 
391
698
        If repository_format is None, the transport is returned with no 
392
 
        checking. if it is not None, then the returned transport is
 
699
        checking. If it is not None, then the returned transport is
393
700
        guaranteed to point to an existing directory ready for use.
394
701
        """
395
702
        raise NotImplementedError(self.get_repository_transport)
398
705
        """Get the transport for use by workingtree format in this BzrDir.
399
706
 
400
707
        Note that bzr dirs that do not support format strings will raise
401
 
        IncompatibleFormat if the workingtree format they are given has
402
 
        a format string, and vice versa.
 
708
        IncompatibleFormat if the workingtree format they are given has a
 
709
        format string, and vice versa.
403
710
 
404
711
        If workingtree_format is None, the transport is returned with no 
405
 
        checking. if it is not None, then the returned transport is
 
712
        checking. If it is not None, then the returned transport is
406
713
        guaranteed to point to an existing directory ready for use.
407
714
        """
408
715
        raise NotImplementedError(self.get_workingtree_transport)
409
 
        
 
716
 
 
717
    def get_config(self):
 
718
        if getattr(self, '_get_config', None) is None:
 
719
            return None
 
720
        return self._get_config()
 
721
 
410
722
    def __init__(self, _transport, _format):
411
723
        """Initialize a Bzr control dir object.
412
724
        
419
731
        self._format = _format
420
732
        self.transport = _transport.clone('.bzr')
421
733
        self.root_transport = _transport
 
734
        self._mode_check_done = False
422
735
 
423
736
    def is_control_filename(self, filename):
424
737
        """True if filename is the name of a path which is reserved for bzrdir's.
434
747
        # this might be better on the BzrDirFormat class because it refers to 
435
748
        # all the possible bzrdir disk formats. 
436
749
        # This method is tested via the workingtree is_control_filename tests- 
437
 
        # it was extracted from WorkingTree.is_control_filename. If the methods
438
 
        # contract is extended beyond the current trivial  implementation please
 
750
        # it was extracted from WorkingTree.is_control_filename. If the method's
 
751
        # contract is extended beyond the current trivial implementation, please
439
752
        # add new tests for it to the appropriate place.
440
753
        return filename == '.bzr' or filename.startswith('.bzr/')
441
754
 
456
769
        return BzrDir.open(base, _unsupported=True)
457
770
        
458
771
    @staticmethod
459
 
    def open(base, _unsupported=False):
460
 
        """Open an existing bzrdir, rooted at 'base' (url)
 
772
    def open(base, _unsupported=False, possible_transports=None):
 
773
        """Open an existing bzrdir, rooted at 'base' (url).
461
774
        
462
 
        _unsupported is a private parameter to the BzrDir class.
463
 
        """
464
 
        t = get_transport(base)
465
 
        mutter("trying to open %r with transport %r", base, t)
466
 
        format = BzrDirFormat.find_format(t)
 
775
        :param _unsupported: a private parameter to the BzrDir class.
 
776
        """
 
777
        t = get_transport(base, possible_transports=possible_transports)
 
778
        return BzrDir.open_from_transport(t, _unsupported=_unsupported)
 
779
 
 
780
    @staticmethod
 
781
    def open_from_transport(transport, _unsupported=False,
 
782
                            _server_formats=True):
 
783
        """Open a bzrdir within a particular directory.
 
784
 
 
785
        :param transport: Transport containing the bzrdir.
 
786
        :param _unsupported: private.
 
787
        """
 
788
        # Keep initial base since 'transport' may be modified while following
 
789
        # the redirections.
 
790
        base = transport.base
 
791
        def find_format(transport):
 
792
            return transport, BzrDirFormat.find_format(
 
793
                transport, _server_formats=_server_formats)
 
794
 
 
795
        def redirected(transport, e, redirection_notice):
 
796
            redirected_transport = transport._redirected_to(e.source, e.target)
 
797
            if redirected_transport is None:
 
798
                raise errors.NotBranchError(base)
 
799
            note('%s is%s redirected to %s',
 
800
                 transport.base, e.permanently, redirected_transport.base)
 
801
            return redirected_transport
 
802
 
 
803
        try:
 
804
            transport, format = do_catching_redirections(find_format,
 
805
                                                         transport,
 
806
                                                         redirected)
 
807
        except errors.TooManyRedirections:
 
808
            raise errors.NotBranchError(base)
 
809
 
467
810
        BzrDir._check_supported(format, _unsupported)
468
 
        return format.open(t, _found=True)
 
811
        return format.open(transport, _found=True)
469
812
 
470
813
    def open_branch(self, unsupported=False):
471
814
        """Open the branch object at this BzrDir if one is present.
478
821
        raise NotImplementedError(self.open_branch)
479
822
 
480
823
    @staticmethod
481
 
    def open_containing(url):
 
824
    def open_containing(url, possible_transports=None):
482
825
        """Open an existing branch which contains url.
483
826
        
484
827
        :param url: url to search from.
485
828
        See open_containing_from_transport for more detail.
486
829
        """
487
 
        return BzrDir.open_containing_from_transport(get_transport(url))
 
830
        transport = get_transport(url, possible_transports)
 
831
        return BzrDir.open_containing_from_transport(transport)
488
832
    
489
833
    @staticmethod
490
834
    def open_containing_from_transport(a_transport):
491
 
        """Open an existing branch which contains a_transport.base
 
835
        """Open an existing branch which contains a_transport.base.
492
836
 
493
837
        This probes for a branch at a_transport, and searches upwards from there.
494
838
 
505
849
        url = a_transport.base
506
850
        while True:
507
851
            try:
508
 
                format = BzrDirFormat.find_format(a_transport)
509
 
                BzrDir._check_supported(format, False)
510
 
                return format.open(a_transport), urlutils.unescape(a_transport.relpath(url))
 
852
                result = BzrDir.open_from_transport(a_transport)
 
853
                return result, urlutils.unescape(a_transport.relpath(url))
511
854
            except errors.NotBranchError, e:
512
 
                ## mutter('not a branch in: %r %s', a_transport.base, e)
513
855
                pass
514
 
            new_t = a_transport.clone('..')
 
856
            try:
 
857
                new_t = a_transport.clone('..')
 
858
            except errors.InvalidURLJoin:
 
859
                # reached the root, whatever that may be
 
860
                raise errors.NotBranchError(path=url)
515
861
            if new_t.base == a_transport.base:
516
862
                # reached the root, whatever that may be
517
863
                raise errors.NotBranchError(path=url)
518
864
            a_transport = new_t
519
865
 
 
866
    def _get_tree_branch(self):
 
867
        """Return the branch and tree, if any, for this bzrdir.
 
868
 
 
869
        Return None for tree if not present or inaccessible.
 
870
        Raise NotBranchError if no branch is present.
 
871
        :return: (tree, branch)
 
872
        """
 
873
        try:
 
874
            tree = self.open_workingtree()
 
875
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
876
            tree = None
 
877
            branch = self.open_branch()
 
878
        else:
 
879
            branch = tree.branch
 
880
        return tree, branch
 
881
 
 
882
    @classmethod
 
883
    def open_tree_or_branch(klass, location):
 
884
        """Return the branch and working tree at a location.
 
885
 
 
886
        If there is no tree at the location, tree will be None.
 
887
        If there is no branch at the location, an exception will be
 
888
        raised
 
889
        :return: (tree, branch)
 
890
        """
 
891
        bzrdir = klass.open(location)
 
892
        return bzrdir._get_tree_branch()
 
893
 
 
894
    @classmethod
 
895
    def open_containing_tree_or_branch(klass, location):
 
896
        """Return the branch and working tree contained by a location.
 
897
 
 
898
        Returns (tree, branch, relpath).
 
899
        If there is no tree at containing the location, tree will be None.
 
900
        If there is no branch containing the location, an exception will be
 
901
        raised
 
902
        relpath is the portion of the path that is contained by the branch.
 
903
        """
 
904
        bzrdir, relpath = klass.open_containing(location)
 
905
        tree, branch = bzrdir._get_tree_branch()
 
906
        return tree, branch, relpath
 
907
 
 
908
    @classmethod
 
909
    def open_containing_tree_branch_or_repository(klass, location):
 
910
        """Return the working tree, branch and repo contained by a location.
 
911
 
 
912
        Returns (tree, branch, repository, relpath).
 
913
        If there is no tree containing the location, tree will be None.
 
914
        If there is no branch containing the location, branch will be None.
 
915
        If there is no repository containing the location, repository will be
 
916
        None.
 
917
        relpath is the portion of the path that is contained by the innermost
 
918
        BzrDir.
 
919
 
 
920
        If no tree, branch or repository is found, a NotBranchError is raised.
 
921
        """
 
922
        bzrdir, relpath = klass.open_containing(location)
 
923
        try:
 
924
            tree, branch = bzrdir._get_tree_branch()
 
925
        except errors.NotBranchError:
 
926
            try:
 
927
                repo = bzrdir.find_repository()
 
928
                return None, None, repo, relpath
 
929
            except (errors.NoRepositoryPresent):
 
930
                raise errors.NotBranchError(location)
 
931
        return tree, branch, branch.repository, relpath
 
932
 
520
933
    def open_repository(self, _unsupported=False):
521
934
        """Open the repository object at this BzrDir if one is present.
522
935
 
523
 
        This will not follow the Branch object pointer - its strictly a direct
 
936
        This will not follow the Branch object pointer - it's strictly a direct
524
937
        open facility. Most client code should use open_branch().repository to
525
938
        get at a repository.
526
939
 
527
 
        _unsupported is a private parameter, not part of the api.
 
940
        :param _unsupported: a private parameter, not part of the api.
528
941
        TODO: static convenience version of this?
529
942
        """
530
943
        raise NotImplementedError(self.open_repository)
531
944
 
532
 
    def open_workingtree(self, _unsupported=False):
 
945
    def open_workingtree(self, _unsupported=False,
 
946
                         recommend_upgrade=True, from_branch=None):
533
947
        """Open the workingtree object at this BzrDir if one is present.
534
 
        
535
 
        TODO: static convenience version of this?
 
948
 
 
949
        :param recommend_upgrade: Optional keyword parameter, when True (the
 
950
            default), emit through the ui module a recommendation that the user
 
951
            upgrade the working tree when the workingtree being opened is old
 
952
            (but still fully supported).
 
953
        :param from_branch: override bzrdir branch (for lightweight checkouts)
536
954
        """
537
955
        raise NotImplementedError(self.open_workingtree)
538
956
 
560
978
        workingtree and discards it, and that's somewhat expensive.) 
561
979
        """
562
980
        try:
563
 
            self.open_workingtree()
 
981
            self.open_workingtree(recommend_upgrade=False)
564
982
            return True
565
983
        except errors.NoWorkingTree:
566
984
            return False
567
985
 
568
 
    def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
 
986
    def _cloning_metadir(self):
 
987
        """Produce a metadir suitable for cloning with.
 
988
        
 
989
        :returns: (destination_bzrdir_format, source_repository)
 
990
        """
 
991
        result_format = self._format.__class__()
 
992
        try:
 
993
            try:
 
994
                branch = self.open_branch()
 
995
                source_repository = branch.repository
 
996
                result_format._branch_format = branch._format
 
997
            except errors.NotBranchError:
 
998
                source_branch = None
 
999
                source_repository = self.open_repository()
 
1000
        except errors.NoRepositoryPresent:
 
1001
            source_repository = None
 
1002
        else:
 
1003
            # XXX TODO: This isinstance is here because we have not implemented
 
1004
            # the fix recommended in bug # 103195 - to delegate this choice the
 
1005
            # repository itself.
 
1006
            repo_format = source_repository._format
 
1007
            if isinstance(repo_format, remote.RemoteRepositoryFormat):
 
1008
                source_repository._ensure_real()
 
1009
                repo_format = source_repository._real_repository._format
 
1010
            result_format.repository_format = repo_format
 
1011
        try:
 
1012
            # TODO: Couldn't we just probe for the format in these cases,
 
1013
            # rather than opening the whole tree?  It would be a little
 
1014
            # faster. mbp 20070401
 
1015
            tree = self.open_workingtree(recommend_upgrade=False)
 
1016
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
1017
            result_format.workingtree_format = None
 
1018
        else:
 
1019
            result_format.workingtree_format = tree._format.__class__()
 
1020
        return result_format, source_repository
 
1021
 
 
1022
    def cloning_metadir(self, require_stacking=False):
 
1023
        """Produce a metadir suitable for cloning or sprouting with.
 
1024
 
 
1025
        These operations may produce workingtrees (yes, even though they're
 
1026
        "cloning" something that doesn't have a tree), so a viable workingtree
 
1027
        format must be selected.
 
1028
 
 
1029
        :require_stacking: If True, non-stackable formats will be upgraded
 
1030
            to similar stackable formats.
 
1031
        :returns: a BzrDirFormat with all component formats either set
 
1032
            appropriately or set to None if that component should not be
 
1033
            created.
 
1034
        """
 
1035
        format, repository = self._cloning_metadir()
 
1036
        if format._workingtree_format is None:
 
1037
            if repository is None:
 
1038
                return format
 
1039
            tree_format = repository._format._matchingbzrdir.workingtree_format
 
1040
            format.workingtree_format = tree_format.__class__()
 
1041
        if require_stacking:
 
1042
            format.require_stacking()
 
1043
        return format
 
1044
 
 
1045
    def checkout_metadir(self):
 
1046
        return self.cloning_metadir()
 
1047
 
 
1048
    def sprout(self, url, revision_id=None, force_new_repo=False,
 
1049
               recurse='down', possible_transports=None,
 
1050
               accelerator_tree=None, hardlink=False, stacked=False,
 
1051
               source_branch=None):
569
1052
        """Create a copy of this bzrdir prepared for use as a new line of
570
1053
        development.
571
1054
 
572
 
        If urls last component does not exist, it will be created.
 
1055
        If url's last component does not exist, it will be created.
573
1056
 
574
1057
        Attributes related to the identity of the source branch like
575
1058
        branch nickname will be cleaned, a working tree is created
578
1061
 
579
1062
        if revision_id is not None, then the clone operation may tune
580
1063
            itself to download less data.
 
1064
        :param accelerator_tree: A tree which can be used for retrieving file
 
1065
            contents more quickly than the revision tree, i.e. a workingtree.
 
1066
            The revision tree will be used for cases where accelerator_tree's
 
1067
            content is different.
 
1068
        :param hardlink: If true, hard-link files from accelerator_tree,
 
1069
            where possible.
 
1070
        :param stacked: If true, create a stacked branch referring to the
 
1071
            location of this control directory.
581
1072
        """
582
 
        self._make_tail(url)
583
 
        result = self._format.initialize(url)
584
 
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
585
 
        try:
586
 
            source_branch = self.open_branch()
 
1073
        target_transport = get_transport(url, possible_transports)
 
1074
        target_transport.ensure_base()
 
1075
        cloning_format = self.cloning_metadir(stacked)
 
1076
        # Create/update the result branch
 
1077
        result = cloning_format.initialize_on_transport(target_transport)
 
1078
        # if a stacked branch wasn't requested, we don't create one
 
1079
        # even if the origin was stacked
 
1080
        stacked_branch_url = None
 
1081
        if source_branch is not None:
 
1082
            if stacked:
 
1083
                stacked_branch_url = self.root_transport.base
587
1084
            source_repository = source_branch.repository
588
 
        except errors.NotBranchError:
589
 
            source_branch = None
590
 
            try:
591
 
                source_repository = self.open_repository()
592
 
            except errors.NoRepositoryPresent:
593
 
                # copy the entire basis one if there is one
594
 
                # but there is no repository.
595
 
                source_repository = basis_repo
596
 
        if force_new_repo:
597
 
            result_repo = None
598
1085
        else:
599
1086
            try:
600
 
                result_repo = result.find_repository()
601
 
            except errors.NoRepositoryPresent:
602
 
                result_repo = None
603
 
        if source_repository is None and result_repo is not None:
604
 
            pass
605
 
        elif source_repository is None and result_repo is None:
606
 
            # no repo available, make a new one
607
 
            result.create_repository()
608
 
        elif source_repository is not None and result_repo is None:
609
 
            # have source, and want to make a new target repo
610
 
            # we don't clone the repo because that preserves attributes
611
 
            # like is_shared(), and we have not yet implemented a 
612
 
            # repository sprout().
613
 
            result_repo = result.create_repository()
614
 
        if result_repo is not None:
615
 
            # fetch needed content into target.
616
 
            if basis_repo:
617
 
                # XXX FIXME RBC 20060214 need tests for this when the basis
618
 
                # is incomplete
619
 
                result_repo.fetch(basis_repo, revision_id=revision_id)
 
1087
                source_branch = self.open_branch()
 
1088
                source_repository = source_branch.repository
 
1089
                if stacked:
 
1090
                    stacked_branch_url = self.root_transport.base
 
1091
            except errors.NotBranchError:
 
1092
                source_branch = None
 
1093
                try:
 
1094
                    source_repository = self.open_repository()
 
1095
                except errors.NoRepositoryPresent:
 
1096
                    source_repository = None
 
1097
        repository_policy = result.determine_repository_policy(
 
1098
            force_new_repo, stacked_branch_url, require_stacking=stacked)
 
1099
        result_repo = repository_policy.acquire_repository()
 
1100
        if source_repository is not None:
 
1101
            # Fetch while stacked to prevent unstacked fetch from
 
1102
            # Branch.sprout.
620
1103
            result_repo.fetch(source_repository, revision_id=revision_id)
 
1104
 
 
1105
        if source_branch is None:
 
1106
            # this is for sprouting a bzrdir without a branch; is that
 
1107
            # actually useful?
 
1108
            # Not especially, but it's part of the contract.
 
1109
            result_branch = result.create_branch()
 
1110
        else:
 
1111
            # Force NULL revision to avoid using repository before stacking
 
1112
            # is configured.
 
1113
            result_branch = source_branch.sprout(
 
1114
                result, revision_id=_mod_revision.NULL_REVISION)
 
1115
            parent_location = result_branch.get_parent()
 
1116
        mutter("created new branch %r" % (result_branch,))
 
1117
        repository_policy.configure_branch(result_branch)
621
1118
        if source_branch is not None:
622
 
            source_branch.sprout(result, revision_id=revision_id)
 
1119
            source_branch.copy_content_into(result_branch, revision_id)
 
1120
            # Override copy_content_into
 
1121
            result_branch.set_parent(parent_location)
 
1122
 
 
1123
        # Create/update the result working tree
 
1124
        if isinstance(target_transport, local.LocalTransport) and (
 
1125
            result_repo is None or result_repo.make_working_trees()):
 
1126
            wt = result.create_workingtree(accelerator_tree=accelerator_tree,
 
1127
                hardlink=hardlink)
 
1128
            wt.lock_write()
 
1129
            try:
 
1130
                if wt.path2id('') is None:
 
1131
                    try:
 
1132
                        wt.set_root_id(self.open_workingtree.get_root_id())
 
1133
                    except errors.NoWorkingTree:
 
1134
                        pass
 
1135
            finally:
 
1136
                wt.unlock()
623
1137
        else:
624
 
            result.create_branch()
625
 
        # TODO: jam 20060426 we probably need a test in here in the
626
 
        #       case that the newly sprouted branch is a remote one
627
 
        if result_repo is None or result_repo.make_working_trees():
628
 
            result.create_workingtree()
 
1138
            wt = None
 
1139
        if recurse == 'down':
 
1140
            if wt is not None:
 
1141
                basis = wt.basis_tree()
 
1142
                basis.lock_read()
 
1143
                subtrees = basis.iter_references()
 
1144
            elif result_branch is not None:
 
1145
                basis = result_branch.basis_tree()
 
1146
                basis.lock_read()
 
1147
                subtrees = basis.iter_references()
 
1148
            elif source_branch is not None:
 
1149
                basis = source_branch.basis_tree()
 
1150
                basis.lock_read()
 
1151
                subtrees = basis.iter_references()
 
1152
            else:
 
1153
                subtrees = []
 
1154
                basis = None
 
1155
            try:
 
1156
                for path, file_id in subtrees:
 
1157
                    target = urlutils.join(url, urlutils.escape(path))
 
1158
                    sublocation = source_branch.reference_parent(file_id, path)
 
1159
                    sublocation.bzrdir.sprout(target,
 
1160
                        basis.get_reference_revision(file_id, path),
 
1161
                        force_new_repo=force_new_repo, recurse=recurse,
 
1162
                        stacked=stacked)
 
1163
            finally:
 
1164
                if basis is not None:
 
1165
                    basis.unlock()
629
1166
        return result
630
1167
 
631
1168
 
635
1172
    def __init__(self, _transport, _format):
636
1173
        """See BzrDir.__init__."""
637
1174
        super(BzrDirPreSplitOut, self).__init__(_transport, _format)
638
 
        assert self._format._lock_class == TransportLock
639
 
        assert self._format._lock_file_name == 'branch-lock'
640
 
        self._control_files = LockableFiles(self.get_branch_transport(None),
 
1175
        self._control_files = lockable_files.LockableFiles(
 
1176
                                            self.get_branch_transport(None),
641
1177
                                            self._format._lock_file_name,
642
1178
                                            self._format._lock_class)
643
1179
 
645
1181
        """Pre-splitout bzrdirs do not suffer from stale locks."""
646
1182
        raise NotImplementedError(self.break_lock)
647
1183
 
648
 
    def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
649
 
        """See BzrDir.clone()."""
650
 
        from bzrlib.workingtree import WorkingTreeFormat2
 
1184
    def cloning_metadir(self, require_stacking=False):
 
1185
        """Produce a metadir suitable for cloning with."""
 
1186
        if require_stacking:
 
1187
            return format_registry.make_bzrdir('1.6')
 
1188
        return self._format.__class__()
 
1189
 
 
1190
    def clone(self, url, revision_id=None, force_new_repo=False,
 
1191
              preserve_stacking=False):
 
1192
        """See BzrDir.clone().
 
1193
 
 
1194
        force_new_repo has no effect, since this family of formats always
 
1195
        require a new repository.
 
1196
        preserve_stacking has no effect, since no source branch using this
 
1197
        family of formats can be stacked, so there is no stacking to preserve.
 
1198
        """
651
1199
        self._make_tail(url)
652
1200
        result = self._format._initialize_for_clone(url)
653
 
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
654
 
        self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
 
1201
        self.open_repository().clone(result, revision_id=revision_id)
655
1202
        from_branch = self.open_branch()
656
1203
        from_branch.clone(result, revision_id=revision_id)
657
1204
        try:
658
 
            self.open_workingtree().clone(result, basis=basis_tree)
 
1205
            tree = self.open_workingtree()
659
1206
        except errors.NotLocalUrl:
660
1207
            # make a new one, this format always has to have one.
661
 
            try:
662
 
                WorkingTreeFormat2().initialize(result)
663
 
            except errors.NotLocalUrl:
664
 
                # but we cannot do it for remote trees.
665
 
                to_branch = result.open_branch()
666
 
                WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
 
1208
            result._init_workingtree()
 
1209
        else:
 
1210
            tree.clone(result)
667
1211
        return result
668
1212
 
669
1213
    def create_branch(self):
670
1214
        """See BzrDir.create_branch."""
671
 
        return self.open_branch()
 
1215
        return self._format.get_branch_format().initialize(self)
 
1216
 
 
1217
    def destroy_branch(self):
 
1218
        """See BzrDir.destroy_branch."""
 
1219
        raise errors.UnsupportedOperation(self.destroy_branch, self)
672
1220
 
673
1221
    def create_repository(self, shared=False):
674
1222
        """See BzrDir.create_repository."""
676
1224
            raise errors.IncompatibleFormat('shared repository', self._format)
677
1225
        return self.open_repository()
678
1226
 
679
 
    def create_workingtree(self, revision_id=None):
 
1227
    def destroy_repository(self):
 
1228
        """See BzrDir.destroy_repository."""
 
1229
        raise errors.UnsupportedOperation(self.destroy_repository, self)
 
1230
 
 
1231
    def create_workingtree(self, revision_id=None, from_branch=None,
 
1232
                           accelerator_tree=None, hardlink=False):
680
1233
        """See BzrDir.create_workingtree."""
 
1234
        # The workingtree is sometimes created when the bzrdir is created,
 
1235
        # but not when cloning.
 
1236
 
681
1237
        # this looks buggy but is not -really-
 
1238
        # because this format creates the workingtree when the bzrdir is
 
1239
        # created
682
1240
        # clone and sprout will have set the revision_id
683
1241
        # and that will have set it for us, its only
684
1242
        # specific uses of create_workingtree in isolation
685
1243
        # that can do wonky stuff here, and that only
686
1244
        # happens for creating checkouts, which cannot be 
687
1245
        # done on this format anyway. So - acceptable wart.
688
 
        result = self.open_workingtree()
 
1246
        try:
 
1247
            result = self.open_workingtree(recommend_upgrade=False)
 
1248
        except errors.NoSuchFile:
 
1249
            result = self._init_workingtree()
689
1250
        if revision_id is not None:
690
 
            result.set_last_revision(revision_id)
 
1251
            if revision_id == _mod_revision.NULL_REVISION:
 
1252
                result.set_parent_ids([])
 
1253
            else:
 
1254
                result.set_parent_ids([revision_id])
691
1255
        return result
692
1256
 
 
1257
    def _init_workingtree(self):
 
1258
        from bzrlib.workingtree import WorkingTreeFormat2
 
1259
        try:
 
1260
            return WorkingTreeFormat2().initialize(self)
 
1261
        except errors.NotLocalUrl:
 
1262
            # Even though we can't access the working tree, we need to
 
1263
            # create its control files.
 
1264
            return WorkingTreeFormat2()._stub_initialize_on_transport(
 
1265
                self.transport, self._control_files._file_mode)
 
1266
 
 
1267
    def destroy_workingtree(self):
 
1268
        """See BzrDir.destroy_workingtree."""
 
1269
        raise errors.UnsupportedOperation(self.destroy_workingtree, self)
 
1270
 
 
1271
    def destroy_workingtree_metadata(self):
 
1272
        """See BzrDir.destroy_workingtree_metadata."""
 
1273
        raise errors.UnsupportedOperation(self.destroy_workingtree_metadata, 
 
1274
                                          self)
 
1275
 
693
1276
    def get_branch_transport(self, branch_format):
694
1277
        """See BzrDir.get_branch_transport()."""
695
1278
        if branch_format is None:
735
1318
        self._check_supported(format, unsupported)
736
1319
        return format.open(self, _found=True)
737
1320
 
738
 
    def sprout(self, url, revision_id=None, basis=None):
 
1321
    def sprout(self, url, revision_id=None, force_new_repo=False,
 
1322
               possible_transports=None, accelerator_tree=None,
 
1323
               hardlink=False, stacked=False):
739
1324
        """See BzrDir.sprout()."""
 
1325
        if stacked:
 
1326
            raise errors.UnstackableBranchFormat(
 
1327
                self._format, self.root_transport.base)
740
1328
        from bzrlib.workingtree import WorkingTreeFormat2
741
1329
        self._make_tail(url)
742
1330
        result = self._format._initialize_for_clone(url)
743
 
        basis_repo, basis_branch, basis_tree = self._get_basis_components(basis)
744
1331
        try:
745
 
            self.open_repository().clone(result, revision_id=revision_id, basis=basis_repo)
 
1332
            self.open_repository().clone(result, revision_id=revision_id)
746
1333
        except errors.NoRepositoryPresent:
747
1334
            pass
748
1335
        try:
750
1337
        except errors.NotBranchError:
751
1338
            pass
752
1339
        # we always want a working tree
753
 
        WorkingTreeFormat2().initialize(result)
 
1340
        WorkingTreeFormat2().initialize(result,
 
1341
                                        accelerator_tree=accelerator_tree,
 
1342
                                        hardlink=hardlink)
754
1343
        return result
755
1344
 
756
1345
 
770
1359
 
771
1360
    def open_repository(self):
772
1361
        """See BzrDir.open_repository."""
773
 
        from bzrlib.repository import RepositoryFormat4
 
1362
        from bzrlib.repofmt.weaverepo import RepositoryFormat4
774
1363
        return RepositoryFormat4().open(self, _found=True)
775
1364
 
776
1365
 
782
1371
 
783
1372
    def open_repository(self):
784
1373
        """See BzrDir.open_repository."""
785
 
        from bzrlib.repository import RepositoryFormat5
 
1374
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
786
1375
        return RepositoryFormat5().open(self, _found=True)
787
1376
 
788
 
    def open_workingtree(self, _unsupported=False):
 
1377
    def open_workingtree(self, _unsupported=False,
 
1378
            recommend_upgrade=True):
789
1379
        """See BzrDir.create_workingtree."""
790
1380
        from bzrlib.workingtree import WorkingTreeFormat2
791
 
        return WorkingTreeFormat2().open(self, _found=True)
 
1381
        wt_format = WorkingTreeFormat2()
 
1382
        # we don't warn here about upgrades; that ought to be handled for the
 
1383
        # bzrdir as a whole
 
1384
        return wt_format.open(self, _found=True)
792
1385
 
793
1386
 
794
1387
class BzrDir6(BzrDirPreSplitOut):
799
1392
 
800
1393
    def open_repository(self):
801
1394
        """See BzrDir.open_repository."""
802
 
        from bzrlib.repository import RepositoryFormat6
 
1395
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
803
1396
        return RepositoryFormat6().open(self, _found=True)
804
1397
 
805
 
    def open_workingtree(self, _unsupported=False):
 
1398
    def open_workingtree(self, _unsupported=False,
 
1399
        recommend_upgrade=True):
806
1400
        """See BzrDir.create_workingtree."""
 
1401
        # we don't warn here about upgrades; that ought to be handled for the
 
1402
        # bzrdir as a whole
807
1403
        from bzrlib.workingtree import WorkingTreeFormat2
808
1404
        return WorkingTreeFormat2().open(self, _found=True)
809
1405
 
823
1419
 
824
1420
    def create_branch(self):
825
1421
        """See BzrDir.create_branch."""
826
 
        from bzrlib.branch import BranchFormat
827
 
        return BranchFormat.get_default_format().initialize(self)
 
1422
        return self._format.get_branch_format().initialize(self)
 
1423
 
 
1424
    def destroy_branch(self):
 
1425
        """See BzrDir.create_branch."""
 
1426
        self.transport.delete_tree('branch')
828
1427
 
829
1428
    def create_repository(self, shared=False):
830
1429
        """See BzrDir.create_repository."""
831
1430
        return self._format.repository_format.initialize(self, shared)
832
1431
 
833
 
    def create_workingtree(self, revision_id=None):
 
1432
    def destroy_repository(self):
 
1433
        """See BzrDir.destroy_repository."""
 
1434
        self.transport.delete_tree('repository')
 
1435
 
 
1436
    def create_workingtree(self, revision_id=None, from_branch=None,
 
1437
                           accelerator_tree=None, hardlink=False):
834
1438
        """See BzrDir.create_workingtree."""
835
 
        from bzrlib.workingtree import WorkingTreeFormat
836
 
        return WorkingTreeFormat.get_default_format().initialize(self, revision_id)
 
1439
        return self._format.workingtree_format.initialize(
 
1440
            self, revision_id, from_branch=from_branch,
 
1441
            accelerator_tree=accelerator_tree, hardlink=hardlink)
 
1442
 
 
1443
    def destroy_workingtree(self):
 
1444
        """See BzrDir.destroy_workingtree."""
 
1445
        wt = self.open_workingtree(recommend_upgrade=False)
 
1446
        repository = wt.branch.repository
 
1447
        empty = repository.revision_tree(_mod_revision.NULL_REVISION)
 
1448
        wt.revert(old_tree=empty)
 
1449
        self.destroy_workingtree_metadata()
 
1450
 
 
1451
    def destroy_workingtree_metadata(self):
 
1452
        self.transport.delete_tree('checkout')
 
1453
 
 
1454
    def find_branch_format(self):
 
1455
        """Find the branch 'format' for this bzrdir.
 
1456
 
 
1457
        This might be a synthetic object for e.g. RemoteBranch and SVN.
 
1458
        """
 
1459
        from bzrlib.branch import BranchFormat
 
1460
        return BranchFormat.find_format(self)
837
1461
 
838
1462
    def _get_mkdir_mode(self):
839
1463
        """Figure out the mode to use when creating a bzrdir subdir."""
840
 
        temp_control = LockableFiles(self.transport, '', TransportLock)
 
1464
        temp_control = lockable_files.LockableFiles(self.transport, '',
 
1465
                                     lockable_files.TransportLock)
841
1466
        return temp_control._dir_mode
842
1467
 
 
1468
    def get_branch_reference(self):
 
1469
        """See BzrDir.get_branch_reference()."""
 
1470
        from bzrlib.branch import BranchFormat
 
1471
        format = BranchFormat.find_format(self)
 
1472
        return format.get_reference(self)
 
1473
 
843
1474
    def get_branch_transport(self, branch_format):
844
1475
        """See BzrDir.get_branch_transport()."""
845
1476
        if branch_format is None:
897
1528
                return True
898
1529
        except errors.NoRepositoryPresent:
899
1530
            pass
900
 
        # currently there are no other possible conversions for meta1 formats.
 
1531
        try:
 
1532
            if not isinstance(self.open_branch()._format,
 
1533
                              format.get_branch_format().__class__):
 
1534
                # the branch needs an upgrade.
 
1535
                return True
 
1536
        except errors.NotBranchError:
 
1537
            pass
 
1538
        try:
 
1539
            my_wt = self.open_workingtree(recommend_upgrade=False)
 
1540
            if not isinstance(my_wt._format,
 
1541
                              format.workingtree_format.__class__):
 
1542
                # the workingtree needs an upgrade.
 
1543
                return True
 
1544
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
1545
            pass
901
1546
        return False
902
1547
 
903
1548
    def open_branch(self, unsupported=False):
904
1549
        """See BzrDir.open_branch."""
905
 
        from bzrlib.branch import BranchFormat
906
 
        format = BranchFormat.find_format(self)
 
1550
        format = self.find_branch_format()
907
1551
        self._check_supported(format, unsupported)
908
1552
        return format.open(self, _found=True)
909
1553
 
914
1558
        self._check_supported(format, unsupported)
915
1559
        return format.open(self, _found=True)
916
1560
 
917
 
    def open_workingtree(self, unsupported=False):
 
1561
    def open_workingtree(self, unsupported=False,
 
1562
            recommend_upgrade=True):
918
1563
        """See BzrDir.open_workingtree."""
919
1564
        from bzrlib.workingtree import WorkingTreeFormat
920
1565
        format = WorkingTreeFormat.find_format(self)
921
 
        self._check_supported(format, unsupported)
 
1566
        self._check_supported(format, unsupported,
 
1567
            recommend_upgrade,
 
1568
            basedir=self.root_transport.base)
922
1569
        return format.open(self, _found=True)
923
1570
 
 
1571
    def _get_config(self):
 
1572
        return config.BzrDirConfig(self.transport)
 
1573
 
924
1574
 
925
1575
class BzrDirFormat(object):
926
1576
    """An encapsulation of the initialization and open routines for a format.
930
1580
     * a format string,
931
1581
     * an open routine.
932
1582
 
933
 
    Formats are placed in an dict by their format string for reference 
 
1583
    Formats are placed in a dict by their format string for reference 
934
1584
    during bzrdir opening. These should be subclasses of BzrDirFormat
935
1585
    for consistency.
936
1586
 
951
1601
    This is a list of BzrDirFormat objects.
952
1602
    """
953
1603
 
 
1604
    _control_server_formats = []
 
1605
    """The registered control server formats, e.g. RemoteBzrDirs.
 
1606
 
 
1607
    This is a list of BzrDirFormat objects.
 
1608
    """
 
1609
 
954
1610
    _lock_file_name = 'branch-lock'
955
1611
 
956
1612
    # _lock_class must be set in subclasses to the lock type, typ.
957
1613
    # TransportLock or LockDir
958
1614
 
959
1615
    @classmethod
960
 
    def find_format(klass, transport):
 
1616
    def find_format(klass, transport, _server_formats=True):
961
1617
        """Return the format present at transport."""
962
 
        for format in klass._control_formats:
 
1618
        if _server_formats:
 
1619
            formats = klass._control_server_formats + klass._control_formats
 
1620
        else:
 
1621
            formats = klass._control_formats
 
1622
        for format in formats:
963
1623
            try:
964
1624
                return format.probe_transport(transport)
965
1625
            except errors.NotBranchError:
969
1629
 
970
1630
    @classmethod
971
1631
    def probe_transport(klass, transport):
972
 
        """Return the .bzrdir style transport present at URL."""
 
1632
        """Return the .bzrdir style format present in a directory."""
973
1633
        try:
974
1634
            format_string = transport.get(".bzr/branch-format").read()
 
1635
        except errors.NoSuchFile:
 
1636
            raise errors.NotBranchError(path=transport.base)
 
1637
 
 
1638
        try:
975
1639
            return klass._formats[format_string]
976
 
        except errors.NoSuchFile:
977
 
            raise errors.NotBranchError(path=transport.base)
978
1640
        except KeyError:
979
 
            raise errors.UnknownFormatError(format_string)
 
1641
            raise errors.UnknownFormatError(format=format_string, kind='bzrdir')
980
1642
 
981
1643
    @classmethod
982
1644
    def get_default_format(klass):
1005
1667
        """
1006
1668
        raise NotImplementedError(self.get_converter)
1007
1669
 
1008
 
    def initialize(self, url):
 
1670
    def initialize(self, url, possible_transports=None):
1009
1671
        """Create a bzr control dir at this url and return an opened copy.
1010
1672
        
1011
1673
        Subclasses should typically override initialize_on_transport
1012
1674
        instead of this method.
1013
1675
        """
1014
 
        return self.initialize_on_transport(get_transport(url))
 
1676
        return self.initialize_on_transport(get_transport(url,
 
1677
                                                          possible_transports))
1015
1678
 
1016
1679
    def initialize_on_transport(self, transport):
1017
1680
        """Initialize a new bzrdir in the base directory of a Transport."""
1018
1681
        # Since we don't have a .bzr directory, inherit the
1019
1682
        # mode from the root directory
1020
 
        temp_control = LockableFiles(transport, '', TransportLock)
 
1683
        temp_control = lockable_files.LockableFiles(transport,
 
1684
                            '', lockable_files.TransportLock)
1021
1685
        temp_control._transport.mkdir('.bzr',
1022
1686
                                      # FIXME: RBC 20060121 don't peek under
1023
1687
                                      # the covers
1024
1688
                                      mode=temp_control._dir_mode)
 
1689
        if sys.platform == 'win32' and isinstance(transport, local.LocalTransport):
 
1690
            win32utils.set_file_attr_hidden(transport._abspath('.bzr'))
1025
1691
        file_mode = temp_control._file_mode
1026
1692
        del temp_control
1027
 
        mutter('created control directory in ' + transport.base)
1028
 
        control = transport.clone('.bzr')
1029
 
        utf8_files = [('README', 
1030
 
                       "This is a Bazaar-NG control directory.\n"
1031
 
                       "Do not change any files in this directory.\n"),
 
1693
        bzrdir_transport = transport.clone('.bzr')
 
1694
        utf8_files = [('README',
 
1695
                       "This is a Bazaar control directory.\n"
 
1696
                       "Do not change any files in this directory.\n"
 
1697
                       "See http://bazaar-vcs.org/ for more information about Bazaar.\n"),
1032
1698
                      ('branch-format', self.get_format_string()),
1033
1699
                      ]
1034
1700
        # NB: no need to escape relative paths that are url safe.
1035
 
        control_files = LockableFiles(control, self._lock_file_name, 
1036
 
                                      self._lock_class)
 
1701
        control_files = lockable_files.LockableFiles(bzrdir_transport,
 
1702
            self._lock_file_name, self._lock_class)
1037
1703
        control_files.create_lock()
1038
1704
        control_files.lock_write()
1039
1705
        try:
1040
 
            for file, content in utf8_files:
1041
 
                control_files.put_utf8(file, content)
 
1706
            for (filename, content) in utf8_files:
 
1707
                bzrdir_transport.put_bytes(filename, content,
 
1708
                    mode=file_mode)
1042
1709
        finally:
1043
1710
            control_files.unlock()
1044
1711
        return self.open(transport, _found=True)
1052
1719
        """
1053
1720
        return True
1054
1721
 
 
1722
    def same_model(self, target_format):
 
1723
        return (self.repository_format.rich_root_data == 
 
1724
            target_format.rich_root_data)
 
1725
 
1055
1726
    @classmethod
1056
1727
    def known_formats(klass):
1057
1728
        """Return all the known formats.
1077
1748
        _found is a private parameter, do not use it.
1078
1749
        """
1079
1750
        if not _found:
1080
 
            assert isinstance(BzrDirFormat.find_format(transport),
1081
 
                              self.__class__)
 
1751
            found_format = BzrDirFormat.find_format(transport)
 
1752
            if not isinstance(found_format, self.__class__):
 
1753
                raise AssertionError("%s was asked to open %s, but it seems to need "
 
1754
                        "format %s" 
 
1755
                        % (self, transport, found_format))
1082
1756
        return self._open(transport)
1083
1757
 
1084
1758
    def _open(self, transport):
1095
1769
 
1096
1770
    @classmethod
1097
1771
    def register_control_format(klass, format):
1098
 
        """Register a format that does not use '.bzrdir' for its control dir.
 
1772
        """Register a format that does not use '.bzr' for its control dir.
1099
1773
 
1100
1774
        TODO: This should be pulled up into a 'ControlDirFormat' base class
1101
1775
        which BzrDirFormat can inherit from, and renamed to register_format 
1105
1779
        klass._control_formats.append(format)
1106
1780
 
1107
1781
    @classmethod
1108
 
    def set_default_format(klass, format):
 
1782
    def register_control_server_format(klass, format):
 
1783
        """Register a control format for client-server environments.
 
1784
 
 
1785
        These formats will be tried before ones registered with
 
1786
        register_control_format.  This gives implementations that decide to the
 
1787
        chance to grab it before anything looks at the contents of the format
 
1788
        file.
 
1789
        """
 
1790
        klass._control_server_formats.append(format)
 
1791
 
 
1792
    @classmethod
 
1793
    def _set_default_format(klass, format):
 
1794
        """Set default format (for testing behavior of defaults only)"""
1109
1795
        klass._default_format = format
1110
1796
 
1111
1797
    def __str__(self):
1112
 
        return self.get_format_string()[:-1]
 
1798
        # Trim the newline
 
1799
        return self.get_format_string().rstrip()
1113
1800
 
1114
1801
    @classmethod
1115
1802
    def unregister_format(klass, format):
1116
 
        assert klass._formats[format.get_format_string()] is format
1117
1803
        del klass._formats[format.get_format_string()]
1118
1804
 
1119
1805
    @classmethod
1121
1807
        klass._control_formats.remove(format)
1122
1808
 
1123
1809
 
1124
 
# register BzrDirFormat as a control format
1125
 
BzrDirFormat.register_control_format(BzrDirFormat)
1126
 
 
1127
 
 
1128
1810
class BzrDirFormat4(BzrDirFormat):
1129
1811
    """Bzr dir format 4.
1130
1812
 
1138
1820
    removed in format 5; write support for this format has been removed.
1139
1821
    """
1140
1822
 
1141
 
    _lock_class = TransportLock
 
1823
    _lock_class = lockable_files.TransportLock
1142
1824
 
1143
1825
    def get_format_string(self):
1144
1826
        """See BzrDirFormat.get_format_string()."""
1172
1854
 
1173
1855
    def __return_repository_format(self):
1174
1856
        """Circular import protection."""
1175
 
        from bzrlib.repository import RepositoryFormat4
1176
 
        return RepositoryFormat4(self)
 
1857
        from bzrlib.repofmt.weaverepo import RepositoryFormat4
 
1858
        return RepositoryFormat4()
1177
1859
    repository_format = property(__return_repository_format)
1178
1860
 
1179
1861
 
1188
1870
       Unhashed stores in the repository.
1189
1871
    """
1190
1872
 
1191
 
    _lock_class = TransportLock
 
1873
    _lock_class = lockable_files.TransportLock
1192
1874
 
1193
1875
    def get_format_string(self):
1194
1876
        """See BzrDirFormat.get_format_string()."""
1195
1877
        return "Bazaar-NG branch, format 5\n"
1196
1878
 
 
1879
    def get_branch_format(self):
 
1880
        from bzrlib import branch
 
1881
        return branch.BzrBranchFormat4()
 
1882
 
1197
1883
    def get_format_description(self):
1198
1884
        """See BzrDirFormat.get_format_description()."""
1199
1885
        return "All-in-one format 5"
1212
1898
        Except when they are being cloned.
1213
1899
        """
1214
1900
        from bzrlib.branch import BzrBranchFormat4
1215
 
        from bzrlib.repository import RepositoryFormat5
1216
 
        from bzrlib.workingtree import WorkingTreeFormat2
 
1901
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
1217
1902
        result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1218
1903
        RepositoryFormat5().initialize(result, _internal=True)
1219
1904
        if not _cloning:
1220
 
            BzrBranchFormat4().initialize(result)
1221
 
            WorkingTreeFormat2().initialize(result)
 
1905
            branch = BzrBranchFormat4().initialize(result)
 
1906
            result._init_workingtree()
1222
1907
        return result
1223
1908
 
1224
1909
    def _open(self, transport):
1227
1912
 
1228
1913
    def __return_repository_format(self):
1229
1914
        """Circular import protection."""
1230
 
        from bzrlib.repository import RepositoryFormat5
1231
 
        return RepositoryFormat5(self)
 
1915
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
 
1916
        return RepositoryFormat5()
1232
1917
    repository_format = property(__return_repository_format)
1233
1918
 
1234
1919
 
1242
1927
     - Format 6 repositories [always]
1243
1928
    """
1244
1929
 
1245
 
    _lock_class = TransportLock
 
1930
    _lock_class = lockable_files.TransportLock
1246
1931
 
1247
1932
    def get_format_string(self):
1248
1933
        """See BzrDirFormat.get_format_string()."""
1252
1937
        """See BzrDirFormat.get_format_description()."""
1253
1938
        return "All-in-one format 6"
1254
1939
 
 
1940
    def get_branch_format(self):
 
1941
        from bzrlib import branch
 
1942
        return branch.BzrBranchFormat4()
 
1943
 
1255
1944
    def get_converter(self, format=None):
1256
1945
        """See BzrDirFormat.get_converter()."""
1257
1946
        # there is one and only one upgrade path here.
1266
1955
        Except when they are being cloned.
1267
1956
        """
1268
1957
        from bzrlib.branch import BzrBranchFormat4
1269
 
        from bzrlib.repository import RepositoryFormat6
1270
 
        from bzrlib.workingtree import WorkingTreeFormat2
 
1958
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
1271
1959
        result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1272
1960
        RepositoryFormat6().initialize(result, _internal=True)
1273
1961
        if not _cloning:
1274
 
            BzrBranchFormat4().initialize(result)
1275
 
            try:
1276
 
                WorkingTreeFormat2().initialize(result)
1277
 
            except errors.NotLocalUrl:
1278
 
                # emulate pre-check behaviour for working tree and silently 
1279
 
                # fail.
1280
 
                pass
 
1962
            branch = BzrBranchFormat4().initialize(result)
 
1963
            result._init_workingtree()
1281
1964
        return result
1282
1965
 
1283
1966
    def _open(self, transport):
1286
1969
 
1287
1970
    def __return_repository_format(self):
1288
1971
        """Circular import protection."""
1289
 
        from bzrlib.repository import RepositoryFormat6
1290
 
        return RepositoryFormat6(self)
 
1972
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
 
1973
        return RepositoryFormat6()
1291
1974
    repository_format = property(__return_repository_format)
1292
1975
 
1293
1976
 
1302
1985
     - Format 7 repositories [optional]
1303
1986
    """
1304
1987
 
1305
 
    _lock_class = LockDir
 
1988
    _lock_class = lockdir.LockDir
 
1989
 
 
1990
    def __init__(self):
 
1991
        self._workingtree_format = None
 
1992
        self._branch_format = None
 
1993
 
 
1994
    def __eq__(self, other):
 
1995
        if other.__class__ is not self.__class__:
 
1996
            return False
 
1997
        if other.repository_format != self.repository_format:
 
1998
            return False
 
1999
        if other.workingtree_format != self.workingtree_format:
 
2000
            return False
 
2001
        return True
 
2002
 
 
2003
    def __ne__(self, other):
 
2004
        return not self == other
 
2005
 
 
2006
    def get_branch_format(self):
 
2007
        if self._branch_format is None:
 
2008
            from bzrlib.branch import BranchFormat
 
2009
            self._branch_format = BranchFormat.get_default_format()
 
2010
        return self._branch_format
 
2011
 
 
2012
    def set_branch_format(self, format):
 
2013
        self._branch_format = format
 
2014
 
 
2015
    def require_stacking(self):
 
2016
        if not self.get_branch_format().supports_stacking():
 
2017
            # We need to make a stacked branch, but the default format for the
 
2018
            # target doesn't support stacking.  So force a branch that *can*
 
2019
            # support stacking.
 
2020
            from bzrlib.branch import BzrBranchFormat7
 
2021
            self._branch_format = BzrBranchFormat7()
 
2022
            mutter("using %r for stacking" % (self._branch_format,))
 
2023
            from bzrlib.repofmt import pack_repo
 
2024
            if self.repository_format.rich_root_data:
 
2025
                bzrdir_format_name = '1.6.1-rich-root'
 
2026
                repo_format = pack_repo.RepositoryFormatKnitPack5RichRoot()
 
2027
            else:
 
2028
                bzrdir_format_name = '1.6'
 
2029
                repo_format = pack_repo.RepositoryFormatKnitPack5()
 
2030
            note('Source format does not support stacking, using format:'
 
2031
                 ' \'%s\'\n  %s\n',
 
2032
                 bzrdir_format_name, repo_format.get_format_description())
 
2033
            self.repository_format = repo_format
1306
2034
 
1307
2035
    def get_converter(self, format=None):
1308
2036
        """See BzrDirFormat.get_converter()."""
1333
2061
        return RepositoryFormat.get_default_format()
1334
2062
 
1335
2063
    def __set_repository_format(self, value):
1336
 
        """Allow changint the repository format for metadir formats."""
 
2064
        """Allow changing the repository format for metadir formats."""
1337
2065
        self._repository_format = value
1338
2066
 
1339
2067
    repository_format = property(__return_repository_format, __set_repository_format)
1340
2068
 
1341
 
 
 
2069
    def __get_workingtree_format(self):
 
2070
        if self._workingtree_format is None:
 
2071
            from bzrlib.workingtree import WorkingTreeFormat
 
2072
            self._workingtree_format = WorkingTreeFormat.get_default_format()
 
2073
        return self._workingtree_format
 
2074
 
 
2075
    def __set_workingtree_format(self, wt_format):
 
2076
        self._workingtree_format = wt_format
 
2077
 
 
2078
    workingtree_format = property(__get_workingtree_format,
 
2079
                                  __set_workingtree_format)
 
2080
 
 
2081
 
 
2082
# Register bzr control format
 
2083
BzrDirFormat.register_control_format(BzrDirFormat)
 
2084
 
 
2085
# Register bzr formats
1342
2086
BzrDirFormat.register_format(BzrDirFormat4())
1343
2087
BzrDirFormat.register_format(BzrDirFormat5())
1344
2088
BzrDirFormat.register_format(BzrDirFormat6())
1345
2089
__default_format = BzrDirMetaFormat1()
1346
2090
BzrDirFormat.register_format(__default_format)
1347
 
BzrDirFormat.set_default_format(__default_format)
1348
 
 
1349
 
 
1350
 
class BzrDirTestProviderAdapter(object):
1351
 
    """A tool to generate a suite testing multiple bzrdir formats at once.
1352
 
 
1353
 
    This is done by copying the test once for each transport and injecting
1354
 
    the transport_server, transport_readonly_server, and bzrdir_format
1355
 
    classes into each copy. Each copy is also given a new id() to make it
1356
 
    easy to identify.
1357
 
    """
1358
 
 
1359
 
    def __init__(self, transport_server, transport_readonly_server, formats):
1360
 
        self._transport_server = transport_server
1361
 
        self._transport_readonly_server = transport_readonly_server
1362
 
        self._formats = formats
1363
 
    
1364
 
    def adapt(self, test):
1365
 
        result = TestSuite()
1366
 
        for format in self._formats:
1367
 
            new_test = deepcopy(test)
1368
 
            new_test.transport_server = self._transport_server
1369
 
            new_test.transport_readonly_server = self._transport_readonly_server
1370
 
            new_test.bzrdir_format = format
1371
 
            def make_new_test_id():
1372
 
                new_id = "%s(%s)" % (new_test.id(), format.__class__.__name__)
1373
 
                return lambda: new_id
1374
 
            new_test.id = make_new_test_id()
1375
 
            result.addTest(new_test)
1376
 
        return result
1377
 
 
1378
 
 
1379
 
class ScratchDir(BzrDir6):
1380
 
    """Special test class: a bzrdir that cleans up itself..
1381
 
 
1382
 
    >>> d = ScratchDir()
1383
 
    >>> base = d.transport.base
1384
 
    >>> isdir(base)
1385
 
    True
1386
 
    >>> b.transport.__del__()
1387
 
    >>> isdir(base)
1388
 
    False
1389
 
    """
1390
 
 
1391
 
    def __init__(self, files=[], dirs=[], transport=None):
1392
 
        """Make a test branch.
1393
 
 
1394
 
        This creates a temporary directory and runs init-tree in it.
1395
 
 
1396
 
        If any files are listed, they are created in the working copy.
1397
 
        """
1398
 
        if transport is None:
1399
 
            transport = bzrlib.transport.local.ScratchTransport()
1400
 
            # local import for scope restriction
1401
 
            BzrDirFormat6().initialize(transport.base)
1402
 
            super(ScratchDir, self).__init__(transport, BzrDirFormat6())
1403
 
            self.create_repository()
1404
 
            self.create_branch()
1405
 
            self.create_workingtree()
1406
 
        else:
1407
 
            super(ScratchDir, self).__init__(transport, BzrDirFormat6())
1408
 
 
1409
 
        # BzrBranch creates a clone to .bzr and then forgets about the
1410
 
        # original transport. A ScratchTransport() deletes itself and
1411
 
        # everything underneath it when it goes away, so we need to
1412
 
        # grab a local copy to prevent that from happening
1413
 
        self._transport = transport
1414
 
 
1415
 
        for d in dirs:
1416
 
            self._transport.mkdir(d)
1417
 
            
1418
 
        for f in files:
1419
 
            self._transport.put(f, 'content of %s' % f)
1420
 
 
1421
 
    def clone(self):
1422
 
        """
1423
 
        >>> orig = ScratchDir(files=["file1", "file2"])
1424
 
        >>> os.listdir(orig.base)
1425
 
        [u'.bzr', u'file1', u'file2']
1426
 
        >>> clone = orig.clone()
1427
 
        >>> if os.name != 'nt':
1428
 
        ...   os.path.samefile(orig.base, clone.base)
1429
 
        ... else:
1430
 
        ...   orig.base == clone.base
1431
 
        ...
1432
 
        False
1433
 
        >>> os.listdir(clone.base)
1434
 
        [u'.bzr', u'file1', u'file2']
1435
 
        """
1436
 
        from shutil import copytree
1437
 
        from bzrlib.osutils import mkdtemp
1438
 
        base = mkdtemp()
1439
 
        os.rmdir(base)
1440
 
        copytree(self.base, base, symlinks=True)
1441
 
        return ScratchDir(
1442
 
            transport=bzrlib.transport.local.ScratchTransport(base))
 
2091
BzrDirFormat._default_format = __default_format
1443
2092
 
1444
2093
 
1445
2094
class Converter(object):
1473
2122
        self.bzrdir = to_convert
1474
2123
        self.pb = pb
1475
2124
        self.pb.note('starting upgrade from format 4 to 5')
1476
 
        if isinstance(self.bzrdir.transport, LocalTransport):
 
2125
        if isinstance(self.bzrdir.transport, local.LocalTransport):
1477
2126
            self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
1478
2127
        self._convert_to_weaves()
1479
2128
        return BzrDir.open(self.bzrdir.root_transport.base)
1518
2167
        self.pb.note('  %6d revisions not present', len(self.absent_revisions))
1519
2168
        self.pb.note('  %6d texts', self.text_count)
1520
2169
        self._cleanup_spare_files_after_format4()
1521
 
        self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
 
2170
        self.branch._transport.put_bytes(
 
2171
            'branch-format',
 
2172
            BzrDirFormat5().get_format_string(),
 
2173
            mode=self.bzrdir._get_file_mode())
1522
2174
 
1523
2175
    def _cleanup_spare_files_after_format4(self):
1524
2176
        # FIXME working tree upgrade foo.
1532
2184
        self.bzrdir.transport.delete_tree('text-store')
1533
2185
 
1534
2186
    def _convert_working_inv(self):
1535
 
        inv = serializer_v4.read_inventory(self.branch.control_files.get('inventory'))
1536
 
        new_inv_xml = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
1537
 
        # FIXME inventory is a working tree change.
1538
 
        self.branch.control_files.put('inventory', new_inv_xml)
 
2187
        inv = xml4.serializer_v4.read_inventory(
 
2188
                self.branch._transport.get('inventory'))
 
2189
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv, working=True)
 
2190
        self.branch._transport.put_bytes('inventory', new_inv_xml,
 
2191
            mode=self.bzrdir._get_file_mode())
1539
2192
 
1540
2193
    def _write_all_weaves(self):
1541
2194
        controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
1561
2214
        self.bzrdir.transport.mkdir('revision-store')
1562
2215
        revision_transport = self.bzrdir.transport.clone('revision-store')
1563
2216
        # TODO permissions
1564
 
        _revision_store = TextRevisionStore(TextStore(revision_transport,
1565
 
                                                      prefixed=False,
1566
 
                                                      compressed=True))
 
2217
        from bzrlib.xml5 import serializer_v5
 
2218
        from bzrlib.repofmt.weaverepo import RevisionTextStore
 
2219
        revision_store = RevisionTextStore(revision_transport,
 
2220
            serializer_v5, False, versionedfile.PrefixMapper(),
 
2221
            lambda:True, lambda:True)
1567
2222
        try:
1568
 
            transaction = bzrlib.transactions.WriteTransaction()
1569
2223
            for i, rev_id in enumerate(self.converted_revs):
1570
2224
                self.pb.update('write revision', i, len(self.converted_revs))
1571
 
                _revision_store.add_revision(self.revisions[rev_id], transaction)
 
2225
                text = serializer_v5.write_revision_to_string(
 
2226
                    self.revisions[rev_id])
 
2227
                key = (rev_id,)
 
2228
                revision_store.add_lines(key, None, osutils.split_lines(text))
1572
2229
        finally:
1573
2230
            self.pb.clear()
1574
2231
            
1587
2244
                         rev_id)
1588
2245
            self.absent_revisions.add(rev_id)
1589
2246
        else:
1590
 
            rev = self.branch.repository._revision_store.get_revision(rev_id,
1591
 
                self.branch.repository.get_transaction())
 
2247
            rev = self.branch.repository.get_revision(rev_id)
1592
2248
            for parent_id in rev.parent_ids:
1593
2249
                self.known_revisions.add(parent_id)
1594
2250
                self.to_read.append(parent_id)
1595
2251
            self.revisions[rev_id] = rev
1596
2252
 
1597
2253
    def _load_old_inventory(self, rev_id):
1598
 
        assert rev_id not in self.converted_revs
1599
2254
        old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
1600
 
        inv = serializer_v4.read_inventory_from_string(old_inv_xml)
 
2255
        inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
 
2256
        inv.revision_id = rev_id
1601
2257
        rev = self.revisions[rev_id]
1602
 
        if rev.inventory_sha1:
1603
 
            assert rev.inventory_sha1 == sha_string(old_inv_xml), \
1604
 
                'inventory sha mismatch for {%s}' % rev_id
1605
2258
        return inv
1606
2259
 
1607
2260
    def _load_updated_inventory(self, rev_id):
1608
 
        assert rev_id in self.converted_revs
1609
2261
        inv_xml = self.inv_weave.get_text(rev_id)
1610
 
        inv = bzrlib.xml5.serializer_v5.read_inventory_from_string(inv_xml)
 
2262
        inv = xml5.serializer_v5.read_inventory_from_string(inv_xml, rev_id)
1611
2263
        return inv
1612
2264
 
1613
2265
    def _convert_one_rev(self, rev_id):
1617
2269
        present_parents = [p for p in rev.parent_ids
1618
2270
                           if p not in self.absent_revisions]
1619
2271
        self._convert_revision_contents(rev, inv, present_parents)
1620
 
        self._store_new_weave(rev, inv, present_parents)
 
2272
        self._store_new_inv(rev, inv, present_parents)
1621
2273
        self.converted_revs.add(rev_id)
1622
2274
 
1623
 
    def _store_new_weave(self, rev, inv, present_parents):
1624
 
        # the XML is now updated with text versions
1625
 
        if __debug__:
1626
 
            for file_id in inv:
1627
 
                ie = inv[file_id]
1628
 
                if ie.kind == 'root_directory':
1629
 
                    continue
1630
 
                assert hasattr(ie, 'revision'), \
1631
 
                    'no revision on {%s} in {%s}' % \
1632
 
                    (file_id, rev.revision_id)
1633
 
        new_inv_xml = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
 
2275
    def _store_new_inv(self, rev, inv, present_parents):
 
2276
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
1634
2277
        new_inv_sha1 = sha_string(new_inv_xml)
1635
 
        self.inv_weave.add_lines(rev.revision_id, 
 
2278
        self.inv_weave.add_lines(rev.revision_id,
1636
2279
                                 present_parents,
1637
2280
                                 new_inv_xml.splitlines(True))
1638
2281
        rev.inventory_sha1 = new_inv_sha1
1645
2288
        mutter('converting texts of revision {%s}',
1646
2289
               rev_id)
1647
2290
        parent_invs = map(self._load_updated_inventory, present_parents)
1648
 
        for file_id in inv:
1649
 
            ie = inv[file_id]
 
2291
        entries = inv.iter_entries()
 
2292
        entries.next()
 
2293
        for path, ie in entries:
1650
2294
            self._convert_file_version(rev, ie, parent_invs)
1651
2295
 
1652
2296
    def _convert_file_version(self, rev, ie, parent_invs):
1655
2299
        The file needs to be added into the weave if it is a merge
1656
2300
        of >=2 parents or if it's changed from its parent.
1657
2301
        """
1658
 
        if ie.kind == 'root_directory':
1659
 
            return
1660
2302
        file_id = ie.file_id
1661
2303
        rev_id = rev.revision_id
1662
2304
        w = self.text_weaves.get(file_id)
1664
2306
            w = Weave(file_id)
1665
2307
            self.text_weaves[file_id] = w
1666
2308
        text_changed = False
1667
 
        previous_entries = ie.find_previous_heads(parent_invs,
1668
 
                                                  None,
1669
 
                                                  None,
1670
 
                                                  entry_vf=w)
1671
 
        for old_revision in previous_entries:
1672
 
                # if this fails, its a ghost ?
1673
 
                assert old_revision in self.converted_revs 
 
2309
        parent_candiate_entries = ie.parent_candidates(parent_invs)
 
2310
        heads = graph.Graph(self).heads(parent_candiate_entries.keys())
 
2311
        # XXX: Note that this is unordered - and this is tolerable because 
 
2312
        # the previous code was also unordered.
 
2313
        previous_entries = dict((head, parent_candiate_entries[head]) for head
 
2314
            in heads)
1674
2315
        self.snapshot_ie(previous_entries, ie, w, rev_id)
1675
2316
        del ie.text_id
1676
 
        assert getattr(ie, 'revision', None) is not None
 
2317
 
 
2318
    @symbol_versioning.deprecated_method(symbol_versioning.one_one)
 
2319
    def get_parents(self, revision_ids):
 
2320
        for revision_id in revision_ids:
 
2321
            yield self.revisions[revision_id].parent_ids
 
2322
 
 
2323
    def get_parent_map(self, revision_ids):
 
2324
        """See graph._StackedParentsProvider.get_parent_map"""
 
2325
        return dict((revision_id, self.revisions[revision_id])
 
2326
                    for revision_id in revision_ids
 
2327
                     if revision_id in self.revisions)
1677
2328
 
1678
2329
    def snapshot_ie(self, previous_revisions, ie, w, rev_id):
1679
2330
        # TODO: convert this logic, which is ~= snapshot to
1689
2340
                ie.revision = previous_ie.revision
1690
2341
                return
1691
2342
        if ie.has_text():
1692
 
            text = self.branch.repository.text_store.get(ie.text_id)
 
2343
            text = self.branch.repository._text_store.get(ie.text_id)
1693
2344
            file_lines = text.readlines()
1694
 
            assert sha_strings(file_lines) == ie.text_sha1
1695
 
            assert sum(map(len, file_lines)) == ie.text_size
1696
2345
            w.add_lines(rev_id, previous_revisions, file_lines)
1697
2346
            self.text_count += 1
1698
2347
        else:
1745
2394
                if (filename.endswith(".weave") or
1746
2395
                    filename.endswith(".gz") or
1747
2396
                    filename.endswith(".sig")):
1748
 
                    file_id = os.path.splitext(filename)[0]
 
2397
                    file_id, suffix = os.path.splitext(filename)
1749
2398
                else:
1750
2399
                    file_id = filename
1751
 
                prefix_dir = store.hash_prefix(file_id)
 
2400
                    suffix = ''
 
2401
                new_name = store._mapper.map((file_id,)) + suffix
1752
2402
                # FIXME keep track of the dirs made RBC 20060121
1753
2403
                try:
1754
 
                    store_transport.move(filename, prefix_dir + '/' + filename)
 
2404
                    store_transport.move(filename, new_name)
1755
2405
                except errors.NoSuchFile: # catches missing dirs strangely enough
1756
 
                    store_transport.mkdir(prefix_dir)
1757
 
                    store_transport.move(filename, prefix_dir + '/' + filename)
1758
 
        self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
 
2406
                    store_transport.mkdir(osutils.dirname(new_name))
 
2407
                    store_transport.move(filename, new_name)
 
2408
        self.bzrdir.transport.put_bytes(
 
2409
            'branch-format',
 
2410
            BzrDirFormat6().get_format_string(),
 
2411
            mode=self.bzrdir._get_file_mode())
1759
2412
 
1760
2413
 
1761
2414
class ConvertBzrDir6ToMeta(Converter):
1763
2416
 
1764
2417
    def convert(self, to_convert, pb):
1765
2418
        """See Converter.convert()."""
 
2419
        from bzrlib.repofmt.weaverepo import RepositoryFormat7
 
2420
        from bzrlib.branch import BzrBranchFormat5
1766
2421
        self.bzrdir = to_convert
1767
2422
        self.pb = pb
1768
2423
        self.count = 0
1769
2424
        self.total = 20 # the steps we know about
1770
2425
        self.garbage_inventories = []
 
2426
        self.dir_mode = self.bzrdir._get_dir_mode()
 
2427
        self.file_mode = self.bzrdir._get_file_mode()
1771
2428
 
1772
2429
        self.pb.note('starting upgrade from format 6 to metadir')
1773
 
        self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
 
2430
        self.bzrdir.transport.put_bytes(
 
2431
                'branch-format',
 
2432
                "Converting to format 6",
 
2433
                mode=self.file_mode)
1774
2434
        # its faster to move specific files around than to open and use the apis...
1775
2435
        # first off, nuke ancestry.weave, it was never used.
1776
2436
        try:
1786
2446
            if name.startswith('basis-inventory.'):
1787
2447
                self.garbage_inventories.append(name)
1788
2448
        # create new directories for repository, working tree and branch
1789
 
        self.dir_mode = self.bzrdir._control_files._dir_mode
1790
 
        self.file_mode = self.bzrdir._control_files._file_mode
1791
2449
        repository_names = [('inventory.weave', True),
1792
2450
                            ('revision-store', True),
1793
2451
                            ('weaves', True)]
1797
2455
        # we hard code the formats here because we are converting into
1798
2456
        # the meta format. The meta format upgrader can take this to a 
1799
2457
        # future format within each component.
1800
 
        self.put_format('repository', bzrlib.repository.RepositoryFormat7())
 
2458
        self.put_format('repository', RepositoryFormat7())
1801
2459
        for entry in repository_names:
1802
2460
            self.move_entry('repository', entry)
1803
2461
 
1804
2462
        self.step('Upgrading branch      ')
1805
2463
        self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
1806
2464
        self.make_lock('branch')
1807
 
        self.put_format('branch', bzrlib.branch.BzrBranchFormat5())
 
2465
        self.put_format('branch', BzrBranchFormat5())
1808
2466
        branch_files = [('revision-history', True),
1809
2467
                        ('branch-name', True),
1810
2468
                        ('parent', False)]
1811
2469
        for entry in branch_files:
1812
2470
            self.move_entry('branch', entry)
1813
2471
 
1814
 
        self.step('Upgrading working tree')
1815
 
        self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
1816
 
        self.make_lock('checkout')
1817
 
        self.put_format('checkout', bzrlib.workingtree.WorkingTreeFormat3())
1818
 
        self.bzrdir.transport.delete_multi(self.garbage_inventories, self.pb)
1819
2472
        checkout_files = [('pending-merges', True),
1820
2473
                          ('inventory', True),
1821
2474
                          ('stat-cache', False)]
1822
 
        for entry in checkout_files:
1823
 
            self.move_entry('checkout', entry)
1824
 
        if last_revision is not None:
1825
 
            self.bzrdir._control_files.put_utf8('checkout/last-revision',
1826
 
                                                last_revision)
1827
 
        self.bzrdir._control_files.put_utf8('branch-format', BzrDirMetaFormat1().get_format_string())
 
2475
        # If a mandatory checkout file is not present, the branch does not have
 
2476
        # a functional checkout. Do not create a checkout in the converted
 
2477
        # branch.
 
2478
        for name, mandatory in checkout_files:
 
2479
            if mandatory and name not in bzrcontents:
 
2480
                has_checkout = False
 
2481
                break
 
2482
        else:
 
2483
            has_checkout = True
 
2484
        if not has_checkout:
 
2485
            self.pb.note('No working tree.')
 
2486
            # If some checkout files are there, we may as well get rid of them.
 
2487
            for name, mandatory in checkout_files:
 
2488
                if name in bzrcontents:
 
2489
                    self.bzrdir.transport.delete(name)
 
2490
        else:
 
2491
            from bzrlib.workingtree import WorkingTreeFormat3
 
2492
            self.step('Upgrading working tree')
 
2493
            self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
 
2494
            self.make_lock('checkout')
 
2495
            self.put_format(
 
2496
                'checkout', WorkingTreeFormat3())
 
2497
            self.bzrdir.transport.delete_multi(
 
2498
                self.garbage_inventories, self.pb)
 
2499
            for entry in checkout_files:
 
2500
                self.move_entry('checkout', entry)
 
2501
            if last_revision is not None:
 
2502
                self.bzrdir.transport.put_bytes(
 
2503
                    'checkout/last-revision', last_revision)
 
2504
        self.bzrdir.transport.put_bytes(
 
2505
            'branch-format',
 
2506
            BzrDirMetaFormat1().get_format_string(),
 
2507
            mode=self.file_mode)
1828
2508
        return BzrDir.open(self.bzrdir.root_transport.base)
1829
2509
 
1830
2510
    def make_lock(self, name):
1831
2511
        """Make a lock for the new control dir name."""
1832
2512
        self.step('Make %s lock' % name)
1833
 
        ld = LockDir(self.bzrdir.transport, 
1834
 
                     '%s/lock' % name,
1835
 
                     file_modebits=self.file_mode,
1836
 
                     dir_modebits=self.dir_mode)
 
2513
        ld = lockdir.LockDir(self.bzrdir.transport,
 
2514
                             '%s/lock' % name,
 
2515
                             file_modebits=self.file_mode,
 
2516
                             dir_modebits=self.dir_mode)
1837
2517
        ld.create()
1838
2518
 
1839
2519
    def move_entry(self, new_dir, entry):
1848
2528
                raise
1849
2529
 
1850
2530
    def put_format(self, dirname, format):
1851
 
        self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
 
2531
        self.bzrdir.transport.put_bytes('%s/format' % dirname,
 
2532
            format.get_format_string(),
 
2533
            self.file_mode)
1852
2534
 
1853
2535
 
1854
2536
class ConvertMetaToMeta(Converter):
1878
2560
                self.pb.note('starting repository conversion')
1879
2561
                converter = CopyConverter(self.target_format.repository_format)
1880
2562
                converter.convert(repo, pb)
 
2563
        try:
 
2564
            branch = self.bzrdir.open_branch()
 
2565
        except errors.NotBranchError:
 
2566
            pass
 
2567
        else:
 
2568
            # TODO: conversions of Branch and Tree should be done by
 
2569
            # InterXFormat lookups/some sort of registry.
 
2570
            # Avoid circular imports
 
2571
            from bzrlib import branch as _mod_branch
 
2572
            old = branch._format.__class__
 
2573
            new = self.target_format.get_branch_format().__class__
 
2574
            while old != new:
 
2575
                if (old == _mod_branch.BzrBranchFormat5 and
 
2576
                    new in (_mod_branch.BzrBranchFormat6,
 
2577
                        _mod_branch.BzrBranchFormat7)):
 
2578
                    branch_converter = _mod_branch.Converter5to6()
 
2579
                elif (old == _mod_branch.BzrBranchFormat6 and
 
2580
                    new == _mod_branch.BzrBranchFormat7):
 
2581
                    branch_converter = _mod_branch.Converter6to7()
 
2582
                else:
 
2583
                    raise errors.BadConversionTarget("No converter", new)
 
2584
                branch_converter.convert(branch)
 
2585
                branch = self.bzrdir.open_branch()
 
2586
                old = branch._format.__class__
 
2587
        try:
 
2588
            tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
 
2589
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
2590
            pass
 
2591
        else:
 
2592
            # TODO: conversions of Branch and Tree should be done by
 
2593
            # InterXFormat lookups
 
2594
            if (isinstance(tree, workingtree.WorkingTree3) and
 
2595
                not isinstance(tree, workingtree_4.DirStateWorkingTree) and
 
2596
                isinstance(self.target_format.workingtree_format,
 
2597
                    workingtree_4.DirStateWorkingTreeFormat)):
 
2598
                workingtree_4.Converter3to4().convert(tree)
 
2599
            if (isinstance(tree, workingtree_4.DirStateWorkingTree) and
 
2600
                not isinstance(tree, workingtree_4.WorkingTree5) and
 
2601
                isinstance(self.target_format.workingtree_format,
 
2602
                    workingtree_4.WorkingTreeFormat5)):
 
2603
                workingtree_4.Converter4to5().convert(tree)
1881
2604
        return to_convert
 
2605
 
 
2606
 
 
2607
# This is not in remote.py because it's small, and needs to be registered.
 
2608
# Putting it in remote.py creates a circular import problem.
 
2609
# we can make it a lazy object if the control formats is turned into something
 
2610
# like a registry.
 
2611
class RemoteBzrDirFormat(BzrDirMetaFormat1):
 
2612
    """Format representing bzrdirs accessed via a smart server"""
 
2613
 
 
2614
    def get_format_description(self):
 
2615
        return 'bzr remote bzrdir'
 
2616
    
 
2617
    @classmethod
 
2618
    def probe_transport(klass, transport):
 
2619
        """Return a RemoteBzrDirFormat object if it looks possible."""
 
2620
        try:
 
2621
            medium = transport.get_smart_medium()
 
2622
        except (NotImplementedError, AttributeError,
 
2623
                errors.TransportNotPossible, errors.NoSmartMedium,
 
2624
                errors.SmartProtocolError):
 
2625
            # no smart server, so not a branch for this format type.
 
2626
            raise errors.NotBranchError(path=transport.base)
 
2627
        else:
 
2628
            # Decline to open it if the server doesn't support our required
 
2629
            # version (3) so that the VFS-based transport will do it.
 
2630
            if medium.should_probe():
 
2631
                try:
 
2632
                    server_version = medium.protocol_version()
 
2633
                except errors.SmartProtocolError:
 
2634
                    # Apparently there's no usable smart server there, even though
 
2635
                    # the medium supports the smart protocol.
 
2636
                    raise errors.NotBranchError(path=transport.base)
 
2637
                if server_version != '2':
 
2638
                    raise errors.NotBranchError(path=transport.base)
 
2639
            return klass()
 
2640
 
 
2641
    def initialize_on_transport(self, transport):
 
2642
        try:
 
2643
            # hand off the request to the smart server
 
2644
            client_medium = transport.get_smart_medium()
 
2645
        except errors.NoSmartMedium:
 
2646
            # TODO: lookup the local format from a server hint.
 
2647
            local_dir_format = BzrDirMetaFormat1()
 
2648
            return local_dir_format.initialize_on_transport(transport)
 
2649
        client = _SmartClient(client_medium)
 
2650
        path = client.remote_path_from_transport(transport)
 
2651
        response = client.call('BzrDirFormat.initialize', path)
 
2652
        if response[0] != 'ok':
 
2653
            raise errors.SmartProtocolError('unexpected response code %s' % (response,))
 
2654
        return remote.RemoteBzrDir(transport)
 
2655
 
 
2656
    def _open(self, transport):
 
2657
        return remote.RemoteBzrDir(transport)
 
2658
 
 
2659
    def __eq__(self, other):
 
2660
        if not isinstance(other, RemoteBzrDirFormat):
 
2661
            return False
 
2662
        return self.get_format_description() == other.get_format_description()
 
2663
 
 
2664
    @property
 
2665
    def repository_format(self):
 
2666
        # Using a property to avoid early loading of remote
 
2667
        return remote.RemoteRepositoryFormat()
 
2668
 
 
2669
 
 
2670
BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)
 
2671
 
 
2672
 
 
2673
class BzrDirFormatInfo(object):
 
2674
 
 
2675
    def __init__(self, native, deprecated, hidden, experimental):
 
2676
        self.deprecated = deprecated
 
2677
        self.native = native
 
2678
        self.hidden = hidden
 
2679
        self.experimental = experimental
 
2680
 
 
2681
 
 
2682
class BzrDirFormatRegistry(registry.Registry):
 
2683
    """Registry of user-selectable BzrDir subformats.
 
2684
    
 
2685
    Differs from BzrDirFormat._control_formats in that it provides sub-formats,
 
2686
    e.g. BzrDirMeta1 with weave repository.  Also, it's more user-oriented.
 
2687
    """
 
2688
 
 
2689
    def __init__(self):
 
2690
        """Create a BzrDirFormatRegistry."""
 
2691
        self._aliases = set()
 
2692
        self._registration_order = list()
 
2693
        super(BzrDirFormatRegistry, self).__init__()
 
2694
 
 
2695
    def aliases(self):
 
2696
        """Return a set of the format names which are aliases."""
 
2697
        return frozenset(self._aliases)
 
2698
 
 
2699
    def register_metadir(self, key,
 
2700
             repository_format, help, native=True, deprecated=False,
 
2701
             branch_format=None,
 
2702
             tree_format=None,
 
2703
             hidden=False,
 
2704
             experimental=False,
 
2705
             alias=False):
 
2706
        """Register a metadir subformat.
 
2707
 
 
2708
        These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
 
2709
        by the Repository format.
 
2710
 
 
2711
        :param repository_format: The fully-qualified repository format class
 
2712
            name as a string.
 
2713
        :param branch_format: Fully-qualified branch format class name as
 
2714
            a string.
 
2715
        :param tree_format: Fully-qualified tree format class name as
 
2716
            a string.
 
2717
        """
 
2718
        # This should be expanded to support setting WorkingTree and Branch
 
2719
        # formats, once BzrDirMetaFormat1 supports that.
 
2720
        def _load(full_name):
 
2721
            mod_name, factory_name = full_name.rsplit('.', 1)
 
2722
            try:
 
2723
                mod = __import__(mod_name, globals(), locals(),
 
2724
                        [factory_name])
 
2725
            except ImportError, e:
 
2726
                raise ImportError('failed to load %s: %s' % (full_name, e))
 
2727
            try:
 
2728
                factory = getattr(mod, factory_name)
 
2729
            except AttributeError:
 
2730
                raise AttributeError('no factory %s in module %r'
 
2731
                    % (full_name, mod))
 
2732
            return factory()
 
2733
 
 
2734
        def helper():
 
2735
            bd = BzrDirMetaFormat1()
 
2736
            if branch_format is not None:
 
2737
                bd.set_branch_format(_load(branch_format))
 
2738
            if tree_format is not None:
 
2739
                bd.workingtree_format = _load(tree_format)
 
2740
            if repository_format is not None:
 
2741
                bd.repository_format = _load(repository_format)
 
2742
            return bd
 
2743
        self.register(key, helper, help, native, deprecated, hidden,
 
2744
            experimental, alias)
 
2745
 
 
2746
    def register(self, key, factory, help, native=True, deprecated=False,
 
2747
                 hidden=False, experimental=False, alias=False):
 
2748
        """Register a BzrDirFormat factory.
 
2749
        
 
2750
        The factory must be a callable that takes one parameter: the key.
 
2751
        It must produce an instance of the BzrDirFormat when called.
 
2752
 
 
2753
        This function mainly exists to prevent the info object from being
 
2754
        supplied directly.
 
2755
        """
 
2756
        registry.Registry.register(self, key, factory, help,
 
2757
            BzrDirFormatInfo(native, deprecated, hidden, experimental))
 
2758
        if alias:
 
2759
            self._aliases.add(key)
 
2760
        self._registration_order.append(key)
 
2761
 
 
2762
    def register_lazy(self, key, module_name, member_name, help, native=True,
 
2763
        deprecated=False, hidden=False, experimental=False, alias=False):
 
2764
        registry.Registry.register_lazy(self, key, module_name, member_name,
 
2765
            help, BzrDirFormatInfo(native, deprecated, hidden, experimental))
 
2766
        if alias:
 
2767
            self._aliases.add(key)
 
2768
        self._registration_order.append(key)
 
2769
 
 
2770
    def set_default(self, key):
 
2771
        """Set the 'default' key to be a clone of the supplied key.
 
2772
        
 
2773
        This method must be called once and only once.
 
2774
        """
 
2775
        registry.Registry.register(self, 'default', self.get(key),
 
2776
            self.get_help(key), info=self.get_info(key))
 
2777
        self._aliases.add('default')
 
2778
 
 
2779
    def set_default_repository(self, key):
 
2780
        """Set the FormatRegistry default and Repository default.
 
2781
        
 
2782
        This is a transitional method while Repository.set_default_format
 
2783
        is deprecated.
 
2784
        """
 
2785
        if 'default' in self:
 
2786
            self.remove('default')
 
2787
        self.set_default(key)
 
2788
        format = self.get('default')()
 
2789
 
 
2790
    def make_bzrdir(self, key):
 
2791
        return self.get(key)()
 
2792
 
 
2793
    def help_topic(self, topic):
 
2794
        output = ""
 
2795
        default_realkey = None
 
2796
        default_help = self.get_help('default')
 
2797
        help_pairs = []
 
2798
        for key in self._registration_order:
 
2799
            if key == 'default':
 
2800
                continue
 
2801
            help = self.get_help(key)
 
2802
            if help == default_help:
 
2803
                default_realkey = key
 
2804
            else:
 
2805
                help_pairs.append((key, help))
 
2806
 
 
2807
        def wrapped(key, help, info):
 
2808
            if info.native:
 
2809
                help = '(native) ' + help
 
2810
            return ':%s:\n%s\n\n' % (key, 
 
2811
                    textwrap.fill(help, initial_indent='    ', 
 
2812
                    subsequent_indent='    '))
 
2813
        if default_realkey is not None:
 
2814
            output += wrapped(default_realkey, '(default) %s' % default_help,
 
2815
                              self.get_info('default'))
 
2816
        deprecated_pairs = []
 
2817
        experimental_pairs = []
 
2818
        for key, help in help_pairs:
 
2819
            info = self.get_info(key)
 
2820
            if info.hidden:
 
2821
                continue
 
2822
            elif info.deprecated:
 
2823
                deprecated_pairs.append((key, help))
 
2824
            elif info.experimental:
 
2825
                experimental_pairs.append((key, help))
 
2826
            else:
 
2827
                output += wrapped(key, help, info)
 
2828
        output += "\nSee ``bzr help formats`` for more about storage formats."
 
2829
        other_output = ""
 
2830
        if len(experimental_pairs) > 0:
 
2831
            other_output += "Experimental formats are shown below.\n\n"
 
2832
            for key, help in experimental_pairs:
 
2833
                info = self.get_info(key)
 
2834
                other_output += wrapped(key, help, info)
 
2835
        else:
 
2836
            other_output += \
 
2837
                "No experimental formats are available.\n\n"
 
2838
        if len(deprecated_pairs) > 0:
 
2839
            other_output += "\nDeprecated formats are shown below.\n\n"
 
2840
            for key, help in deprecated_pairs:
 
2841
                info = self.get_info(key)
 
2842
                other_output += wrapped(key, help, info)
 
2843
        else:
 
2844
            other_output += \
 
2845
                "\nNo deprecated formats are available.\n\n"
 
2846
        other_output += \
 
2847
            "\nSee ``bzr help formats`` for more about storage formats."
 
2848
 
 
2849
        if topic == 'other-formats':
 
2850
            return other_output
 
2851
        else:
 
2852
            return output
 
2853
 
 
2854
 
 
2855
class RepositoryAcquisitionPolicy(object):
 
2856
    """Abstract base class for repository acquisition policies.
 
2857
 
 
2858
    A repository acquisition policy decides how a BzrDir acquires a repository
 
2859
    for a branch that is being created.  The most basic policy decision is
 
2860
    whether to create a new repository or use an existing one.
 
2861
    """
 
2862
    def __init__(self, stack_on, stack_on_pwd, require_stacking):
 
2863
        """Constructor.
 
2864
 
 
2865
        :param stack_on: A location to stack on
 
2866
        :param stack_on_pwd: If stack_on is relative, the location it is
 
2867
            relative to.
 
2868
        :param require_stacking: If True, it is a failure to not stack.
 
2869
        """
 
2870
        self._stack_on = stack_on
 
2871
        self._stack_on_pwd = stack_on_pwd
 
2872
        self._require_stacking = require_stacking
 
2873
 
 
2874
    def configure_branch(self, branch):
 
2875
        """Apply any configuration data from this policy to the branch.
 
2876
 
 
2877
        Default implementation sets repository stacking.
 
2878
        """
 
2879
        if self._stack_on is None:
 
2880
            return
 
2881
        if self._stack_on_pwd is None:
 
2882
            stack_on = self._stack_on
 
2883
        else:
 
2884
            try:
 
2885
                stack_on = urlutils.rebase_url(self._stack_on,
 
2886
                    self._stack_on_pwd,
 
2887
                    branch.bzrdir.root_transport.base)
 
2888
            except errors.InvalidRebaseURLs:
 
2889
                stack_on = self._get_full_stack_on()
 
2890
        try:
 
2891
            branch.set_stacked_on_url(stack_on)
 
2892
        except errors.UnstackableBranchFormat:
 
2893
            if self._require_stacking:
 
2894
                raise
 
2895
 
 
2896
    def _get_full_stack_on(self):
 
2897
        """Get a fully-qualified URL for the stack_on location."""
 
2898
        if self._stack_on is None:
 
2899
            return None
 
2900
        if self._stack_on_pwd is None:
 
2901
            return self._stack_on
 
2902
        else:
 
2903
            return urlutils.join(self._stack_on_pwd, self._stack_on)
 
2904
 
 
2905
    def _add_fallback(self, repository, possible_transports=None):
 
2906
        """Add a fallback to the supplied repository, if stacking is set."""
 
2907
        stack_on = self._get_full_stack_on()
 
2908
        if stack_on is None:
 
2909
            return
 
2910
        stacked_dir = BzrDir.open(stack_on,
 
2911
                                  possible_transports=possible_transports)
 
2912
        try:
 
2913
            stacked_repo = stacked_dir.open_branch().repository
 
2914
        except errors.NotBranchError:
 
2915
            stacked_repo = stacked_dir.open_repository()
 
2916
        try:
 
2917
            repository.add_fallback_repository(stacked_repo)
 
2918
        except errors.UnstackableRepositoryFormat:
 
2919
            if self._require_stacking:
 
2920
                raise
 
2921
        else:
 
2922
            self._require_stacking = True
 
2923
 
 
2924
    def acquire_repository(self, make_working_trees=None, shared=False):
 
2925
        """Acquire a repository for this bzrdir.
 
2926
 
 
2927
        Implementations may create a new repository or use a pre-exising
 
2928
        repository.
 
2929
        :param make_working_trees: If creating a repository, set
 
2930
            make_working_trees to this value (if non-None)
 
2931
        :param shared: If creating a repository, make it shared if True
 
2932
        :return: A repository
 
2933
        """
 
2934
        raise NotImplemented(RepositoryAcquisitionPolicy.acquire_repository)
 
2935
 
 
2936
 
 
2937
class CreateRepository(RepositoryAcquisitionPolicy):
 
2938
    """A policy of creating a new repository"""
 
2939
 
 
2940
    def __init__(self, bzrdir, stack_on=None, stack_on_pwd=None,
 
2941
                 require_stacking=False):
 
2942
        """
 
2943
        Constructor.
 
2944
        :param bzrdir: The bzrdir to create the repository on.
 
2945
        :param stack_on: A location to stack on
 
2946
        :param stack_on_pwd: If stack_on is relative, the location it is
 
2947
            relative to.
 
2948
        """
 
2949
        RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
 
2950
                                             require_stacking)
 
2951
        self._bzrdir = bzrdir
 
2952
 
 
2953
    def acquire_repository(self, make_working_trees=None, shared=False):
 
2954
        """Implementation of RepositoryAcquisitionPolicy.acquire_repository
 
2955
 
 
2956
        Creates the desired repository in the bzrdir we already have.
 
2957
        """
 
2958
        repository = self._bzrdir.create_repository(shared=shared)
 
2959
        self._add_fallback(repository,
 
2960
                           possible_transports=[self._bzrdir.transport])
 
2961
        if make_working_trees is not None:
 
2962
            repository.set_make_working_trees(make_working_trees)
 
2963
        return repository
 
2964
 
 
2965
 
 
2966
class UseExistingRepository(RepositoryAcquisitionPolicy):
 
2967
    """A policy of reusing an existing repository"""
 
2968
 
 
2969
    def __init__(self, repository, stack_on=None, stack_on_pwd=None,
 
2970
                 require_stacking=False):
 
2971
        """Constructor.
 
2972
 
 
2973
        :param repository: The repository to use.
 
2974
        :param stack_on: A location to stack on
 
2975
        :param stack_on_pwd: If stack_on is relative, the location it is
 
2976
            relative to.
 
2977
        """
 
2978
        RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
 
2979
                                             require_stacking)
 
2980
        self._repository = repository
 
2981
 
 
2982
    def acquire_repository(self, make_working_trees=None, shared=False):
 
2983
        """Implementation of RepositoryAcquisitionPolicy.acquire_repository
 
2984
 
 
2985
        Returns an existing repository to use
 
2986
        """
 
2987
        self._add_fallback(self._repository,
 
2988
                       possible_transports=[self._repository.bzrdir.transport])
 
2989
        return self._repository
 
2990
 
 
2991
 
 
2992
# Please register new formats after old formats so that formats
 
2993
# appear in chronological order and format descriptions can build
 
2994
# on previous ones.
 
2995
format_registry = BzrDirFormatRegistry()
 
2996
format_registry.register('weave', BzrDirFormat6,
 
2997
    'Pre-0.8 format.  Slower than knit and does not'
 
2998
    ' support checkouts or shared repositories.',
 
2999
    deprecated=True)
 
3000
format_registry.register_metadir('metaweave',
 
3001
    'bzrlib.repofmt.weaverepo.RepositoryFormat7',
 
3002
    'Transitional format in 0.8.  Slower than knit.',
 
3003
    branch_format='bzrlib.branch.BzrBranchFormat5',
 
3004
    tree_format='bzrlib.workingtree.WorkingTreeFormat3',
 
3005
    deprecated=True)
 
3006
format_registry.register_metadir('knit',
 
3007
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
 
3008
    'Format using knits.  Recommended for interoperation with bzr <= 0.14.',
 
3009
    branch_format='bzrlib.branch.BzrBranchFormat5',
 
3010
    tree_format='bzrlib.workingtree.WorkingTreeFormat3',
 
3011
    deprecated=True)
 
3012
format_registry.register_metadir('dirstate',
 
3013
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
 
3014
    help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
 
3015
        'above when accessed over the network.',
 
3016
    branch_format='bzrlib.branch.BzrBranchFormat5',
 
3017
    # this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
 
3018
    # directly from workingtree_4 triggers a circular import.
 
3019
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3020
    deprecated=True)
 
3021
format_registry.register_metadir('dirstate-tags',
 
3022
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
 
3023
    help='New in 0.15: Fast local operations and improved scaling for '
 
3024
        'network operations. Additionally adds support for tags.'
 
3025
        ' Incompatible with bzr < 0.15.',
 
3026
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
3027
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3028
    deprecated=True)
 
3029
format_registry.register_metadir('rich-root',
 
3030
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit4',
 
3031
    help='New in 1.0.  Better handling of tree roots.  Incompatible with'
 
3032
        ' bzr < 1.0.',
 
3033
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
3034
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3035
    deprecated=True)
 
3036
format_registry.register_metadir('dirstate-with-subtree',
 
3037
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
 
3038
    help='New in 0.15: Fast local operations and improved scaling for '
 
3039
        'network operations. Additionally adds support for versioning nested '
 
3040
        'bzr branches. Incompatible with bzr < 0.15.',
 
3041
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
3042
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3043
    experimental=True,
 
3044
    hidden=True,
 
3045
    )
 
3046
format_registry.register_metadir('pack-0.92',
 
3047
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack1',
 
3048
    help='New in 0.92: Pack-based format with data compatible with '
 
3049
        'dirstate-tags format repositories. Interoperates with '
 
3050
        'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
 
3051
        'Previously called knitpack-experimental.  '
 
3052
        'For more information, see '
 
3053
        'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
 
3054
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
3055
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3056
    )
 
3057
format_registry.register_metadir('pack-0.92-subtree',
 
3058
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack3',
 
3059
    help='New in 0.92: Pack-based format with data compatible with '
 
3060
        'dirstate-with-subtree format repositories. Interoperates with '
 
3061
        'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
 
3062
        'Previously called knitpack-experimental.  '
 
3063
        'For more information, see '
 
3064
        'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
 
3065
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
3066
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3067
    hidden=True,
 
3068
    experimental=True,
 
3069
    )
 
3070
format_registry.register_metadir('rich-root-pack',
 
3071
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack4',
 
3072
    help='New in 1.0: A variant of pack-0.92 that supports rich-root data '
 
3073
         '(needed for bzr-svn).',
 
3074
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
3075
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3076
    )
 
3077
format_registry.register_metadir('1.6',
 
3078
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack5',
 
3079
    help='A format that allows a branch to indicate that there is another '
 
3080
         '(stacked) repository that should be used to access data that is '
 
3081
         'not present locally.',
 
3082
    branch_format='bzrlib.branch.BzrBranchFormat7',
 
3083
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3084
    )
 
3085
format_registry.register_metadir('1.6.1-rich-root',
 
3086
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack5RichRoot',
 
3087
    help='A variant of 1.6 that supports rich-root data '
 
3088
         '(needed for bzr-svn).',
 
3089
    branch_format='bzrlib.branch.BzrBranchFormat7',
 
3090
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3091
    )
 
3092
format_registry.register_metadir('1.9',
 
3093
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6',
 
3094
    help='A repository format using B+tree indexes. These indexes '
 
3095
         'are smaller in size, have smarter caching and provide faster '
 
3096
         'performance for most operations.',
 
3097
    branch_format='bzrlib.branch.BzrBranchFormat7',
 
3098
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3099
    )
 
3100
format_registry.register_metadir('1.9-rich-root',
 
3101
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6RichRoot',
 
3102
    help='A variant of 1.9 that supports rich-root data '
 
3103
         '(needed for bzr-svn).',
 
3104
    branch_format='bzrlib.branch.BzrBranchFormat7',
 
3105
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3106
    )
 
3107
format_registry.register_metadir('1.12-preview',
 
3108
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6',
 
3109
    help='A working-tree format that supports views and content filtering.',
 
3110
    branch_format='bzrlib.branch.BzrBranchFormat7',
 
3111
    tree_format='bzrlib.workingtree_4.WorkingTreeFormat5',
 
3112
    experimental=True,
 
3113
    )
 
3114
format_registry.register_metadir('1.12-preview-rich-root',
 
3115
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack6RichRoot',
 
3116
    help='A variant of 1.12-preview that supports rich-root data '
 
3117
         '(needed for bzr-svn).',
 
3118
    branch_format='bzrlib.branch.BzrBranchFormat7',
 
3119
    tree_format='bzrlib.workingtree_4.WorkingTreeFormat5',
 
3120
    experimental=True,
 
3121
    )
 
3122
# The following two formats should always just be aliases.
 
3123
format_registry.register_metadir('development',
 
3124
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment2',
 
3125
    help='Current development format. Can convert data to and from pack-0.92 '
 
3126
        '(and anything compatible with pack-0.92) format repositories. '
 
3127
        'Repositories and branches in this format can only be read by bzr.dev. '
 
3128
        'Please read '
 
3129
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
 
3130
        'before use.',
 
3131
    branch_format='bzrlib.branch.BzrBranchFormat7',
 
3132
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3133
    experimental=True,
 
3134
    alias=True,
 
3135
    )
 
3136
format_registry.register_metadir('development-subtree',
 
3137
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment2Subtree',
 
3138
    help='Current development format, subtree variant. Can convert data to and '
 
3139
        'from pack-0.92-subtree (and anything compatible with '
 
3140
        'pack-0.92-subtree) format repositories. Repositories and branches in '
 
3141
        'this format can only be read by bzr.dev. Please read '
 
3142
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
 
3143
        'before use.',
 
3144
    branch_format='bzrlib.branch.BzrBranchFormat7',
 
3145
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3146
    experimental=True,
 
3147
    alias=True,
 
3148
    )
 
3149
# And the development formats above will have aliased one of the following:
 
3150
format_registry.register_metadir('development2',
 
3151
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment2',
 
3152
    help='1.6.1 with B+Tree based index. '
 
3153
        'Please read '
 
3154
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
 
3155
        'before use.',
 
3156
    branch_format='bzrlib.branch.BzrBranchFormat7',
 
3157
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3158
    hidden=True,
 
3159
    experimental=True,
 
3160
    )
 
3161
format_registry.register_metadir('development2-subtree',
 
3162
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment2Subtree',
 
3163
    help='1.6.1-subtree with B+Tree based index. '
 
3164
        'Please read '
 
3165
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
 
3166
        'before use.',
 
3167
    branch_format='bzrlib.branch.BzrBranchFormat7',
 
3168
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3169
    hidden=True,
 
3170
    experimental=True,
 
3171
    )
 
3172
# The current format that is made on 'bzr init'.
 
3173
format_registry.set_default('pack-0.92')