~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

  • Committer: John Arbash Meinel
  • Date: 2006-10-11 23:08:27 UTC
  • mto: This revision was merged to the branch mainline in revision 2080.
  • Revision ID: john@arbash-meinel.com-20061011230827-2bdfc45020695281
Change Copyright .. by Canonical to Copyright ... Canonical

Show diffs side-by-side

added added

removed removed

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