~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/controldir.py

  • Committer: Jelmer Vernooij
  • Date: 2011-12-16 19:18:39 UTC
  • mto: This revision was merged to the branch mainline in revision 6391.
  • Revision ID: jelmer@samba.org-20111216191839-eg681lxqibi1qxu1
Fix remaining tests.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2010 Canonical Ltd
 
1
# Copyright (C) 2010, 2011 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
28
28
 
29
29
from bzrlib import (
30
30
    errors,
31
 
    graph,
32
 
    registry,
 
31
    hooks,
33
32
    revision as _mod_revision,
34
 
    symbol_versioning,
 
33
    transport as _mod_transport,
 
34
    trace,
 
35
    ui,
35
36
    urlutils,
36
37
    )
 
38
from bzrlib.transport import local
37
39
from bzrlib.push import (
38
40
    PushResult,
39
41
    )
40
 
from bzrlib.trace import (
41
 
    mutter,
42
 
    )
43
 
from bzrlib.transport import (
44
 
    get_transport,
45
 
    local,
46
 
    )
47
42
 
 
43
from bzrlib.i18n import gettext
48
44
""")
49
45
 
 
46
from bzrlib import registry
 
47
 
50
48
 
51
49
class ControlComponent(object):
52
50
    """Abstract base class for control directory components.
108
106
        """Return a sequence of all branches local to this control directory.
109
107
 
110
108
        """
 
109
        return self.get_branches().values()
 
110
 
 
111
    def get_branches(self):
 
112
        """Get all branches in this control directory, as a dictionary.
 
113
        
 
114
        :return: Dictionary mapping branch names to instances.
 
115
        """
111
116
        try:
112
 
            return [self.open_branch()]
 
117
           return { None: self.open_branch() }
113
118
        except (errors.NotBranchError, errors.NoRepositoryPresent):
114
 
            return []
 
119
           return {}
115
120
 
116
121
    def is_control_filename(self, filename):
117
122
        """True if filename is the name of a path which is reserved for
139
144
        """
140
145
        raise NotImplementedError(self.needs_format_conversion)
141
146
 
 
147
    def create_repository(self, shared=False):
 
148
        """Create a new repository in this control directory.
 
149
 
 
150
        :param shared: If a shared repository should be created
 
151
        :return: The newly created repository
 
152
        """
 
153
        raise NotImplementedError(self.create_repository)
 
154
 
142
155
    def destroy_repository(self):
143
156
        """Destroy the repository in this ControlDir."""
144
157
        raise NotImplementedError(self.destroy_repository)
145
158
 
146
 
    def create_branch(self, name=None):
 
159
    def create_branch(self, name=None, repository=None,
 
160
                      append_revisions_only=None):
147
161
        """Create a branch in this ControlDir.
148
162
 
149
163
        :param name: Name of the colocated branch to create, None for
150
164
            the default branch.
 
165
        :param append_revisions_only: Whether this branch should only allow
 
166
            appending new revisions to its history.
151
167
 
152
168
        The controldirs format will control what branch format is created.
153
169
        For more control see BranchFormatXX.create(a_controldir).
191
207
        """
192
208
        raise NotImplementedError(self.destroy_workingtree_metadata)
193
209
 
 
210
    def find_branch_format(self, name=None):
 
211
        """Find the branch 'format' for this controldir.
 
212
 
 
213
        This might be a synthetic object for e.g. RemoteBranch and SVN.
 
214
        """
 
215
        raise NotImplementedError(self.find_branch_format)
 
216
 
194
217
    def get_branch_reference(self, name=None):
195
218
        """Return the referenced URL for the branch in this controldir.
196
219
 
205
228
            raise errors.NoColocatedBranchSupport(self)
206
229
        return None
207
230
 
208
 
    def get_branch_transport(self, branch_format, name=None):
209
 
        """Get the transport for use by branch format in this ControlDir.
210
 
 
211
 
        Note that bzr dirs that do not support format strings will raise
212
 
        IncompatibleFormat if the branch format they are given has
213
 
        a format string, and vice versa.
214
 
 
215
 
        If branch_format is None, the transport is returned with no
216
 
        checking. If it is not None, then the returned transport is
217
 
        guaranteed to point to an existing directory ready for use.
218
 
        """
219
 
        raise NotImplementedError(self.get_branch_transport)
220
 
 
221
 
    def get_repository_transport(self, repository_format):
222
 
        """Get the transport for use by repository format in this ControlDir.
223
 
 
224
 
        Note that bzr dirs that do not support format strings will raise
225
 
        IncompatibleFormat if the repository format they are given has
226
 
        a format string, and vice versa.
227
 
 
228
 
        If repository_format is None, the transport is returned with no
229
 
        checking. If it is not None, then the returned transport is
230
 
        guaranteed to point to an existing directory ready for use.
231
 
        """
232
 
        raise NotImplementedError(self.get_repository_transport)
233
 
 
234
 
    def get_workingtree_transport(self, tree_format):
235
 
        """Get the transport for use by workingtree format in this ControlDir.
236
 
 
237
 
        Note that bzr dirs that do not support format strings will raise
238
 
        IncompatibleFormat if the workingtree format they are given has a
239
 
        format string, and vice versa.
240
 
 
241
 
        If workingtree_format is None, the transport is returned with no
242
 
        checking. If it is not None, then the returned transport is
243
 
        guaranteed to point to an existing directory ready for use.
244
 
        """
245
 
        raise NotImplementedError(self.get_workingtree_transport)
246
 
 
247
231
    def open_branch(self, name=None, unsupported=False,
248
 
                    ignore_fallbacks=False):
 
232
                    ignore_fallbacks=False, possible_transports=None):
249
233
        """Open the branch object at this ControlDir if one is present.
250
234
 
251
 
        If unsupported is True, then no longer supported branch formats can
252
 
        still be opened.
253
 
 
254
 
        TODO: static convenience version of this?
 
235
        :param unsupported: if True, then no longer supported branch formats can
 
236
            still be opened.
 
237
        :param ignore_fallbacks: Whether to open fallback repositories
 
238
        :param possible_transports: Transports to use for opening e.g.
 
239
            fallback repositories.
255
240
        """
256
241
        raise NotImplementedError(self.open_branch)
257
242
 
263
248
        get at a repository.
264
249
 
265
250
        :param _unsupported: a private parameter, not part of the api.
266
 
        TODO: static convenience version of this?
267
251
        """
268
252
        raise NotImplementedError(self.open_repository)
269
253
 
297
281
        branch and discards it, and that's somewhat expensive.)
298
282
        """
299
283
        try:
300
 
            self.open_branch(name)
 
284
            self.open_branch(name, ignore_fallbacks=True)
301
285
            return True
302
286
        except errors.NotBranchError:
303
287
            return False
304
288
 
 
289
    def _get_selected_branch(self):
 
290
        """Return the name of the branch selected by the user.
 
291
 
 
292
        :return: Name of the branch selected by the user, or None.
 
293
        """
 
294
        branch = self.root_transport.get_segment_parameters().get("branch")
 
295
        if branch is not None:
 
296
            branch = urlutils.unescape(branch)
 
297
        return branch
 
298
 
305
299
    def has_workingtree(self):
306
300
        """Tell if this controldir contains a working tree.
307
301
 
334
328
        raise NotImplementedError(self.cloning_metadir)
335
329
 
336
330
    def checkout_metadir(self):
337
 
        """Produce a metadir suitable for checkouts of this controldir."""
 
331
        """Produce a metadir suitable for checkouts of this controldir.
 
332
 
 
333
        :returns: A ControlDirFormat with all component formats
 
334
            either set appropriately or set to None if that component
 
335
            should not be created.
 
336
        """
338
337
        return self.cloning_metadir()
339
338
 
340
339
    def sprout(self, url, revision_id=None, force_new_repo=False,
351
350
        whether one existed before or not; and a local branch is always
352
351
        created.
353
352
 
354
 
        if revision_id is not None, then the clone operation may tune
355
 
            itself to download less data.
 
353
        :param revision_id: if revision_id is not None, then the clone
 
354
            operation may tune itself to download less data.
356
355
        :param accelerator_tree: A tree which can be used for retrieving file
357
356
            contents more quickly than the revision tree, i.e. a workingtree.
358
357
            The revision tree will be used for cases where accelerator_tree's
364
363
        :param create_tree_if_local: If true, a working-tree will be created
365
364
            when working locally.
366
365
        """
367
 
        target_transport = get_transport(url, possible_transports)
368
 
        target_transport.ensure_base()
369
 
        cloning_format = self.cloning_metadir(stacked)
370
 
        # Create/update the result branch
371
 
        result = cloning_format.initialize_on_transport(target_transport)
372
 
        # if a stacked branch wasn't requested, we don't create one
373
 
        # even if the origin was stacked
374
 
        stacked_branch_url = None
375
 
        if source_branch is not None:
376
 
            if stacked:
377
 
                stacked_branch_url = self.root_transport.base
378
 
            source_repository = source_branch.repository
379
 
        else:
380
 
            try:
381
 
                source_branch = self.open_branch()
382
 
                source_repository = source_branch.repository
383
 
                if stacked:
384
 
                    stacked_branch_url = self.root_transport.base
385
 
            except errors.NotBranchError:
386
 
                source_branch = None
387
 
                try:
388
 
                    source_repository = self.open_repository()
389
 
                except errors.NoRepositoryPresent:
390
 
                    source_repository = None
391
 
        repository_policy = result.determine_repository_policy(
392
 
            force_new_repo, stacked_branch_url, require_stacking=stacked)
393
 
        result_repo, is_new_repo = repository_policy.acquire_repository()
394
 
        is_stacked = stacked or (len(result_repo._fallback_repositories) != 0)
395
 
        if is_new_repo and revision_id is not None and not is_stacked:
396
 
            fetch_spec = graph.PendingAncestryResult(
397
 
                [revision_id], source_repository)
398
 
        else:
399
 
            fetch_spec = None
400
 
        if source_repository is not None:
401
 
            # Fetch while stacked to prevent unstacked fetch from
402
 
            # Branch.sprout.
403
 
            if fetch_spec is None:
404
 
                result_repo.fetch(source_repository, revision_id=revision_id)
405
 
            else:
406
 
                result_repo.fetch(source_repository, fetch_spec=fetch_spec)
407
 
 
408
 
        if source_branch is None:
409
 
            # this is for sprouting a controldir without a branch; is that
410
 
            # actually useful?
411
 
            # Not especially, but it's part of the contract.
412
 
            result_branch = result.create_branch()
413
 
        else:
414
 
            result_branch = source_branch.sprout(result,
415
 
                revision_id=revision_id, repository_policy=repository_policy)
416
 
        mutter("created new branch %r" % (result_branch,))
417
 
 
418
 
        # Create/update the result working tree
419
 
        if (create_tree_if_local and
420
 
            isinstance(target_transport, local.LocalTransport) and
421
 
            (result_repo is None or result_repo.make_working_trees())):
422
 
            wt = result.create_workingtree(accelerator_tree=accelerator_tree,
423
 
                hardlink=hardlink)
424
 
            wt.lock_write()
425
 
            try:
426
 
                if wt.path2id('') is None:
427
 
                    try:
428
 
                        wt.set_root_id(self.open_workingtree.get_root_id())
429
 
                    except errors.NoWorkingTree:
430
 
                        pass
431
 
            finally:
432
 
                wt.unlock()
433
 
        else:
434
 
            wt = None
435
 
        if recurse == 'down':
436
 
            if wt is not None:
437
 
                basis = wt.basis_tree()
438
 
                basis.lock_read()
439
 
                subtrees = basis.iter_references()
440
 
            elif result_branch is not None:
441
 
                basis = result_branch.basis_tree()
442
 
                basis.lock_read()
443
 
                subtrees = basis.iter_references()
444
 
            elif source_branch is not None:
445
 
                basis = source_branch.basis_tree()
446
 
                basis.lock_read()
447
 
                subtrees = basis.iter_references()
448
 
            else:
449
 
                subtrees = []
450
 
                basis = None
451
 
            try:
452
 
                for path, file_id in subtrees:
453
 
                    target = urlutils.join(url, urlutils.escape(path))
454
 
                    sublocation = source_branch.reference_parent(file_id, path)
455
 
                    sublocation.bzrdir.sprout(target,
456
 
                        basis.get_reference_revision(file_id, path),
457
 
                        force_new_repo=force_new_repo, recurse=recurse,
458
 
                        stacked=stacked)
459
 
            finally:
460
 
                if basis is not None:
461
 
                    basis.unlock()
462
 
        return result
 
366
        raise NotImplementedError(self.sprout)
463
367
 
464
368
    def push_branch(self, source, revision_id=None, overwrite=False, 
465
369
        remember=False, create_prefix=False):
481
385
        if br_to is None:
482
386
            # We have a repository but no branch, copy the revisions, and then
483
387
            # create a branch.
 
388
            if revision_id is None:
 
389
                # No revision supplied by the user, default to the branch
 
390
                # revision
 
391
                revision_id = source.last_revision()
484
392
            repository_to.fetch(source.repository, revision_id=revision_id)
485
393
            br_to = source.clone(self, revision_id=revision_id)
486
394
            if source.get_push_location() is None or remember:
522
430
        return push_result
523
431
 
524
432
    def _get_tree_branch(self, name=None):
525
 
        """Return the branch and tree, if any, for this bzrdir.
 
433
        """Return the branch and tree, if any, for this controldir.
526
434
 
527
435
        :param name: Name of colocated branch to open.
528
436
 
547
455
        raise NotImplementedError(self.get_config)
548
456
 
549
457
    def check_conversion_target(self, target_format):
550
 
        """Check that a bzrdir as a whole can be converted to a new format."""
 
458
        """Check that a controldir as a whole can be converted to a new format."""
551
459
        raise NotImplementedError(self.check_conversion_target)
552
460
 
553
461
    def clone(self, url, revision_id=None, force_new_repo=False,
554
462
              preserve_stacking=False):
555
 
        """Clone this bzrdir and its contents to url verbatim.
 
463
        """Clone this controldir and its contents to url verbatim.
556
464
 
557
465
        :param url: The url create the clone at.  If url's last component does
558
466
            not exist, it will be created.
564
472
        :param preserve_stacking: When cloning a stacked branch, stack the
565
473
            new branch on top of the other branch's stacked-on branch.
566
474
        """
567
 
        return self.clone_on_transport(get_transport(url),
 
475
        return self.clone_on_transport(_mod_transport.get_transport(url),
568
476
                                       revision_id=revision_id,
569
477
                                       force_new_repo=force_new_repo,
570
478
                                       preserve_stacking=preserve_stacking)
571
479
 
572
480
    def clone_on_transport(self, transport, revision_id=None,
573
481
        force_new_repo=False, preserve_stacking=False, stacked_on=None,
574
 
        create_prefix=False, use_existing_dir=True):
575
 
        """Clone this bzrdir and its contents to transport verbatim.
 
482
        create_prefix=False, use_existing_dir=True, no_tree=False):
 
483
        """Clone this controldir and its contents to transport verbatim.
576
484
 
577
485
        :param transport: The transport for the location to produce the clone
578
486
            at.  If the target directory does not exist, it will be created.
586
494
        :param create_prefix: Create any missing directories leading up to
587
495
            to_transport.
588
496
        :param use_existing_dir: Use an existing directory if one exists.
 
497
        :param no_tree: If set to true prevents creation of a working tree.
589
498
        """
590
499
        raise NotImplementedError(self.clone_on_transport)
591
500
 
 
501
    @classmethod
 
502
    def find_bzrdirs(klass, transport, evaluate=None, list_current=None):
 
503
        """Find control dirs recursively from current location.
 
504
 
 
505
        This is intended primarily as a building block for more sophisticated
 
506
        functionality, like finding trees under a directory, or finding
 
507
        branches that use a given repository.
 
508
 
 
509
        :param evaluate: An optional callable that yields recurse, value,
 
510
            where recurse controls whether this controldir is recursed into
 
511
            and value is the value to yield.  By default, all bzrdirs
 
512
            are recursed into, and the return value is the controldir.
 
513
        :param list_current: if supplied, use this function to list the current
 
514
            directory, instead of Transport.list_dir
 
515
        :return: a generator of found bzrdirs, or whatever evaluate returns.
 
516
        """
 
517
        if list_current is None:
 
518
            def list_current(transport):
 
519
                return transport.list_dir('')
 
520
        if evaluate is None:
 
521
            def evaluate(controldir):
 
522
                return True, controldir
 
523
 
 
524
        pending = [transport]
 
525
        while len(pending) > 0:
 
526
            current_transport = pending.pop()
 
527
            recurse = True
 
528
            try:
 
529
                controldir = klass.open_from_transport(current_transport)
 
530
            except (errors.NotBranchError, errors.PermissionDenied):
 
531
                pass
 
532
            else:
 
533
                recurse, value = evaluate(controldir)
 
534
                yield value
 
535
            try:
 
536
                subdirs = list_current(current_transport)
 
537
            except (errors.NoSuchFile, errors.PermissionDenied):
 
538
                continue
 
539
            if recurse:
 
540
                for subdir in sorted(subdirs, reverse=True):
 
541
                    pending.append(current_transport.clone(subdir))
 
542
 
 
543
    @classmethod
 
544
    def find_branches(klass, transport):
 
545
        """Find all branches under a transport.
 
546
 
 
547
        This will find all branches below the transport, including branches
 
548
        inside other branches.  Where possible, it will use
 
549
        Repository.find_branches.
 
550
 
 
551
        To list all the branches that use a particular Repository, see
 
552
        Repository.find_branches
 
553
        """
 
554
        def evaluate(controldir):
 
555
            try:
 
556
                repository = controldir.open_repository()
 
557
            except errors.NoRepositoryPresent:
 
558
                pass
 
559
            else:
 
560
                return False, ([], repository)
 
561
            return True, (controldir.list_branches(), None)
 
562
        ret = []
 
563
        for branches, repo in klass.find_bzrdirs(
 
564
                transport, evaluate=evaluate):
 
565
            if repo is not None:
 
566
                ret.extend(repo.find_branches())
 
567
            if branches is not None:
 
568
                ret.extend(branches)
 
569
        return ret
 
570
 
 
571
    @classmethod
 
572
    def create_branch_and_repo(klass, base, force_new_repo=False, format=None):
 
573
        """Create a new ControlDir, Branch and Repository at the url 'base'.
 
574
 
 
575
        This will use the current default ControlDirFormat unless one is
 
576
        specified, and use whatever
 
577
        repository format that that uses via controldir.create_branch and
 
578
        create_repository. If a shared repository is available that is used
 
579
        preferentially.
 
580
 
 
581
        The created Branch object is returned.
 
582
 
 
583
        :param base: The URL to create the branch at.
 
584
        :param force_new_repo: If True a new repository is always created.
 
585
        :param format: If supplied, the format of branch to create.  If not
 
586
            supplied, the default is used.
 
587
        """
 
588
        controldir = klass.create(base, format)
 
589
        controldir._find_or_create_repository(force_new_repo)
 
590
        return controldir.create_branch()
 
591
 
 
592
    @classmethod
 
593
    def create_branch_convenience(klass, base, force_new_repo=False,
 
594
                                  force_new_tree=None, format=None,
 
595
                                  possible_transports=None):
 
596
        """Create a new ControlDir, Branch and Repository at the url 'base'.
 
597
 
 
598
        This is a convenience function - it will use an existing repository
 
599
        if possible, can be told explicitly whether to create a working tree or
 
600
        not.
 
601
 
 
602
        This will use the current default ControlDirFormat unless one is
 
603
        specified, and use whatever
 
604
        repository format that that uses via ControlDir.create_branch and
 
605
        create_repository. If a shared repository is available that is used
 
606
        preferentially. Whatever repository is used, its tree creation policy
 
607
        is followed.
 
608
 
 
609
        The created Branch object is returned.
 
610
        If a working tree cannot be made due to base not being a file:// url,
 
611
        no error is raised unless force_new_tree is True, in which case no
 
612
        data is created on disk and NotLocalUrl is raised.
 
613
 
 
614
        :param base: The URL to create the branch at.
 
615
        :param force_new_repo: If True a new repository is always created.
 
616
        :param force_new_tree: If True or False force creation of a tree or
 
617
                               prevent such creation respectively.
 
618
        :param format: Override for the controldir format to create.
 
619
        :param possible_transports: An optional reusable transports list.
 
620
        """
 
621
        if force_new_tree:
 
622
            # check for non local urls
 
623
            t = _mod_transport.get_transport(base, possible_transports)
 
624
            if not isinstance(t, local.LocalTransport):
 
625
                raise errors.NotLocalUrl(base)
 
626
        controldir = klass.create(base, format, possible_transports)
 
627
        repo = controldir._find_or_create_repository(force_new_repo)
 
628
        result = controldir.create_branch()
 
629
        if force_new_tree or (repo.make_working_trees() and
 
630
                              force_new_tree is None):
 
631
            try:
 
632
                controldir.create_workingtree()
 
633
            except errors.NotLocalUrl:
 
634
                pass
 
635
        return result
 
636
 
 
637
    @classmethod
 
638
    def create_standalone_workingtree(klass, base, format=None):
 
639
        """Create a new ControlDir, WorkingTree, Branch and Repository at 'base'.
 
640
 
 
641
        'base' must be a local path or a file:// url.
 
642
 
 
643
        This will use the current default ControlDirFormat unless one is
 
644
        specified, and use whatever
 
645
        repository format that that uses for bzrdirformat.create_workingtree,
 
646
        create_branch and create_repository.
 
647
 
 
648
        :param format: Override for the controldir format to create.
 
649
        :return: The WorkingTree object.
 
650
        """
 
651
        t = _mod_transport.get_transport(base)
 
652
        if not isinstance(t, local.LocalTransport):
 
653
            raise errors.NotLocalUrl(base)
 
654
        controldir = klass.create_branch_and_repo(base,
 
655
                                               force_new_repo=True,
 
656
                                               format=format).bzrdir
 
657
        return controldir.create_workingtree()
 
658
 
 
659
    @classmethod
 
660
    def open_unsupported(klass, base):
 
661
        """Open a branch which is not supported."""
 
662
        return klass.open(base, _unsupported=True)
 
663
 
 
664
    @classmethod
 
665
    def open(klass, base, _unsupported=False, possible_transports=None):
 
666
        """Open an existing controldir, rooted at 'base' (url).
 
667
 
 
668
        :param _unsupported: a private parameter to the ControlDir class.
 
669
        """
 
670
        t = _mod_transport.get_transport(base, possible_transports)
 
671
        return klass.open_from_transport(t, _unsupported=_unsupported)
 
672
 
 
673
    @classmethod
 
674
    def open_from_transport(klass, transport, _unsupported=False,
 
675
                            _server_formats=True):
 
676
        """Open a controldir within a particular directory.
 
677
 
 
678
        :param transport: Transport containing the controldir.
 
679
        :param _unsupported: private.
 
680
        """
 
681
        for hook in klass.hooks['pre_open']:
 
682
            hook(transport)
 
683
        # Keep initial base since 'transport' may be modified while following
 
684
        # the redirections.
 
685
        base = transport.base
 
686
        def find_format(transport):
 
687
            return transport, ControlDirFormat.find_format(
 
688
                transport, _server_formats=_server_formats)
 
689
 
 
690
        def redirected(transport, e, redirection_notice):
 
691
            redirected_transport = transport._redirected_to(e.source, e.target)
 
692
            if redirected_transport is None:
 
693
                raise errors.NotBranchError(base)
 
694
            trace.note(gettext('{0} is{1} redirected to {2}').format(
 
695
                 transport.base, e.permanently, redirected_transport.base))
 
696
            return redirected_transport
 
697
 
 
698
        try:
 
699
            transport, format = _mod_transport.do_catching_redirections(
 
700
                find_format, transport, redirected)
 
701
        except errors.TooManyRedirections:
 
702
            raise errors.NotBranchError(base)
 
703
 
 
704
        format.check_support_status(_unsupported)
 
705
        return format.open(transport, _found=True)
 
706
 
 
707
    @classmethod
 
708
    def open_containing(klass, url, possible_transports=None):
 
709
        """Open an existing branch which contains url.
 
710
 
 
711
        :param url: url to search from.
 
712
 
 
713
        See open_containing_from_transport for more detail.
 
714
        """
 
715
        transport = _mod_transport.get_transport(url, possible_transports)
 
716
        return klass.open_containing_from_transport(transport)
 
717
 
 
718
    @classmethod
 
719
    def open_containing_from_transport(klass, a_transport):
 
720
        """Open an existing branch which contains a_transport.base.
 
721
 
 
722
        This probes for a branch at a_transport, and searches upwards from there.
 
723
 
 
724
        Basically we keep looking up until we find the control directory or
 
725
        run into the root.  If there isn't one, raises NotBranchError.
 
726
        If there is one and it is either an unrecognised format or an unsupported
 
727
        format, UnknownFormatError or UnsupportedFormatError are raised.
 
728
        If there is one, it is returned, along with the unused portion of url.
 
729
 
 
730
        :return: The ControlDir that contains the path, and a Unicode path
 
731
                for the rest of the URL.
 
732
        """
 
733
        # this gets the normalised url back. I.e. '.' -> the full path.
 
734
        url = a_transport.base
 
735
        while True:
 
736
            try:
 
737
                result = klass.open_from_transport(a_transport)
 
738
                return result, urlutils.unescape(a_transport.relpath(url))
 
739
            except errors.NotBranchError, e:
 
740
                pass
 
741
            try:
 
742
                new_t = a_transport.clone('..')
 
743
            except errors.InvalidURLJoin:
 
744
                # reached the root, whatever that may be
 
745
                raise errors.NotBranchError(path=url)
 
746
            if new_t.base == a_transport.base:
 
747
                # reached the root, whatever that may be
 
748
                raise errors.NotBranchError(path=url)
 
749
            a_transport = new_t
 
750
 
 
751
    @classmethod
 
752
    def open_tree_or_branch(klass, location):
 
753
        """Return the branch and working tree at a location.
 
754
 
 
755
        If there is no tree at the location, tree will be None.
 
756
        If there is no branch at the location, an exception will be
 
757
        raised
 
758
        :return: (tree, branch)
 
759
        """
 
760
        controldir = klass.open(location)
 
761
        return controldir._get_tree_branch()
 
762
 
 
763
    @classmethod
 
764
    def open_containing_tree_or_branch(klass, location):
 
765
        """Return the branch and working tree contained by a location.
 
766
 
 
767
        Returns (tree, branch, relpath).
 
768
        If there is no tree at containing the location, tree will be None.
 
769
        If there is no branch containing the location, an exception will be
 
770
        raised
 
771
        relpath is the portion of the path that is contained by the branch.
 
772
        """
 
773
        controldir, relpath = klass.open_containing(location)
 
774
        tree, branch = controldir._get_tree_branch()
 
775
        return tree, branch, relpath
 
776
 
 
777
    @classmethod
 
778
    def open_containing_tree_branch_or_repository(klass, location):
 
779
        """Return the working tree, branch and repo contained by a location.
 
780
 
 
781
        Returns (tree, branch, repository, relpath).
 
782
        If there is no tree containing the location, tree will be None.
 
783
        If there is no branch containing the location, branch will be None.
 
784
        If there is no repository containing the location, repository will be
 
785
        None.
 
786
        relpath is the portion of the path that is contained by the innermost
 
787
        ControlDir.
 
788
 
 
789
        If no tree, branch or repository is found, a NotBranchError is raised.
 
790
        """
 
791
        controldir, relpath = klass.open_containing(location)
 
792
        try:
 
793
            tree, branch = controldir._get_tree_branch()
 
794
        except errors.NotBranchError:
 
795
            try:
 
796
                repo = controldir.find_repository()
 
797
                return None, None, repo, relpath
 
798
            except (errors.NoRepositoryPresent):
 
799
                raise errors.NotBranchError(location)
 
800
        return tree, branch, branch.repository, relpath
 
801
 
 
802
    @classmethod
 
803
    def create(klass, base, format=None, possible_transports=None):
 
804
        """Create a new ControlDir at the url 'base'.
 
805
 
 
806
        :param format: If supplied, the format of branch to create.  If not
 
807
            supplied, the default is used.
 
808
        :param possible_transports: If supplied, a list of transports that
 
809
            can be reused to share a remote connection.
 
810
        """
 
811
        if klass is not ControlDir:
 
812
            raise AssertionError("ControlDir.create always creates the"
 
813
                "default format, not one of %r" % klass)
 
814
        t = _mod_transport.get_transport(base, possible_transports)
 
815
        t.ensure_base()
 
816
        if format is None:
 
817
            format = ControlDirFormat.get_default_format()
 
818
        return format.initialize_on_transport(t)
 
819
 
 
820
 
 
821
class ControlDirHooks(hooks.Hooks):
 
822
    """Hooks for ControlDir operations."""
 
823
 
 
824
    def __init__(self):
 
825
        """Create the default hooks."""
 
826
        hooks.Hooks.__init__(self, "bzrlib.controldir", "ControlDir.hooks")
 
827
        self.add_hook('pre_open',
 
828
            "Invoked before attempting to open a ControlDir with the transport "
 
829
            "that the open will use.", (1, 14))
 
830
        self.add_hook('post_repo_init',
 
831
            "Invoked after a repository has been initialized. "
 
832
            "post_repo_init is called with a "
 
833
            "bzrlib.controldir.RepoInitHookParams.",
 
834
            (2, 2))
 
835
 
 
836
# install the default hooks
 
837
ControlDir.hooks = ControlDirHooks()
 
838
 
 
839
 
 
840
class ControlComponentFormat(object):
 
841
    """A component that can live inside of a .bzr meta directory."""
 
842
 
 
843
    upgrade_recommended = False
 
844
 
 
845
    def get_format_description(self):
 
846
        """Return the short description for this format."""
 
847
        raise NotImplementedError(self.get_format_description)
 
848
 
 
849
    def is_supported(self):
 
850
        """Is this format supported?
 
851
 
 
852
        Supported formats must be initializable and openable.
 
853
        Unsupported formats may not support initialization or committing or
 
854
        some other features depending on the reason for not being supported.
 
855
        """
 
856
        return True
 
857
 
 
858
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
 
859
        basedir=None):
 
860
        """Give an error or warning on old formats.
 
861
 
 
862
        :param allow_unsupported: If true, allow opening
 
863
            formats that are strongly deprecated, and which may
 
864
            have limited functionality.
 
865
 
 
866
        :param recommend_upgrade: If true (default), warn
 
867
            the user through the ui object that they may wish
 
868
            to upgrade the object.
 
869
        """
 
870
        if not allow_unsupported and not self.is_supported():
 
871
            # see open_downlevel to open legacy branches.
 
872
            raise errors.UnsupportedFormatError(format=self)
 
873
        if recommend_upgrade and self.upgrade_recommended:
 
874
            ui.ui_factory.recommend_upgrade(
 
875
                self.get_format_description(), basedir)
 
876
 
 
877
    @classmethod
 
878
    def get_format_string(cls):
 
879
        raise NotImplementedError(cls.get_format_string)
 
880
 
 
881
 
 
882
class ControlComponentFormatRegistry(registry.FormatRegistry):
 
883
    """A registry for control components (branch, workingtree, repository)."""
 
884
 
 
885
    def __init__(self, other_registry=None):
 
886
        super(ControlComponentFormatRegistry, self).__init__(other_registry)
 
887
        self._extra_formats = []
 
888
 
 
889
    def register(self, format):
 
890
        """Register a new format."""
 
891
        super(ControlComponentFormatRegistry, self).register(
 
892
            format.get_format_string(), format)
 
893
 
 
894
    def remove(self, format):
 
895
        """Remove a registered format."""
 
896
        super(ControlComponentFormatRegistry, self).remove(
 
897
            format.get_format_string())
 
898
 
 
899
    def register_extra(self, format):
 
900
        """Register a format that can not be used in a metadir.
 
901
 
 
902
        This is mainly useful to allow custom repository formats, such as older
 
903
        Bazaar formats and foreign formats, to be tested.
 
904
        """
 
905
        self._extra_formats.append(registry._ObjectGetter(format))
 
906
 
 
907
    def remove_extra(self, format):
 
908
        """Remove an extra format.
 
909
        """
 
910
        self._extra_formats.remove(registry._ObjectGetter(format))
 
911
 
 
912
    def register_extra_lazy(self, module_name, member_name):
 
913
        """Register a format lazily.
 
914
        """
 
915
        self._extra_formats.append(
 
916
            registry._LazyObjectGetter(module_name, member_name))
 
917
 
 
918
    def _get_extra(self):
 
919
        """Return all "extra" formats, not usable in meta directories."""
 
920
        result = []
 
921
        for getter in self._extra_formats:
 
922
            f = getter.get_obj()
 
923
            if callable(f):
 
924
                f = f()
 
925
            result.append(f)
 
926
        return result
 
927
 
 
928
    def _get_all(self):
 
929
        """Return all formats, even those not usable in metadirs.
 
930
        """
 
931
        result = []
 
932
        for name in self.keys():
 
933
            fmt = self.get(name)
 
934
            if callable(fmt):
 
935
                fmt = fmt()
 
936
            result.append(fmt)
 
937
        return result + self._get_extra()
 
938
 
 
939
    def _get_all_modules(self):
 
940
        """Return a set of the modules providing objects."""
 
941
        modules = set()
 
942
        for name in self.keys():
 
943
            modules.add(self._get_module(name))
 
944
        for getter in self._extra_formats:
 
945
            modules.add(getter.get_module())
 
946
        return modules
 
947
 
 
948
 
 
949
class Converter(object):
 
950
    """Converts a disk format object from one format to another."""
 
951
 
 
952
    def convert(self, to_convert, pb):
 
953
        """Perform the conversion of to_convert, giving feedback via pb.
 
954
 
 
955
        :param to_convert: The disk object to convert.
 
956
        :param pb: a progress bar to use for progress information.
 
957
        """
 
958
 
 
959
    def step(self, message):
 
960
        """Update the pb by a step."""
 
961
        self.count +=1
 
962
        self.pb.update(message, self.count, self.total)
 
963
 
592
964
 
593
965
class ControlDirFormat(object):
594
966
    """An encapsulation of the initialization and open routines for a format.
614
986
    _default_format = None
615
987
    """The default format used for new control directories."""
616
988
 
617
 
    _formats = []
618
 
    """The registered control formats - .bzr, ....
619
 
 
620
 
    This is a list of ControlDirFormat objects.
621
 
    """
622
 
 
623
989
    _server_probers = []
624
990
    """The registered server format probers, e.g. RemoteBzrProber.
625
991
 
637
1003
    """
638
1004
 
639
1005
    supports_workingtrees = True
 
1006
    """Whether working trees can exist in control directories of this format.
 
1007
    """
 
1008
 
 
1009
    fixed_components = False
 
1010
    """Whether components can not change format independent of the control dir.
 
1011
    """
 
1012
 
 
1013
    upgrade_recommended = False
 
1014
    """Whether an upgrade from this format is recommended."""
640
1015
 
641
1016
    def get_format_description(self):
642
1017
        """Return the short description for this format."""
659
1034
    def is_supported(self):
660
1035
        """Is this format supported?
661
1036
 
662
 
        Supported formats must be initializable and openable.
 
1037
        Supported formats must be openable.
663
1038
        Unsupported formats may not support initialization or committing or
664
1039
        some other features depending on the reason for not being supported.
665
1040
        """
666
1041
        return True
667
1042
 
 
1043
    def is_initializable(self):
 
1044
        """Whether new control directories of this format can be initialized.
 
1045
        """
 
1046
        return self.is_supported()
 
1047
 
 
1048
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
 
1049
        basedir=None):
 
1050
        """Give an error or warning on old formats.
 
1051
 
 
1052
        :param allow_unsupported: If true, allow opening
 
1053
            formats that are strongly deprecated, and which may
 
1054
            have limited functionality.
 
1055
 
 
1056
        :param recommend_upgrade: If true (default), warn
 
1057
            the user through the ui object that they may wish
 
1058
            to upgrade the object.
 
1059
        """
 
1060
        if not allow_unsupported and not self.is_supported():
 
1061
            # see open_downlevel to open legacy branches.
 
1062
            raise errors.UnsupportedFormatError(format=self)
 
1063
        if recommend_upgrade and self.upgrade_recommended:
 
1064
            ui.ui_factory.recommend_upgrade(
 
1065
                self.get_format_description(), basedir)
 
1066
 
668
1067
    def same_model(self, target_format):
669
1068
        return (self.repository_format.rich_root_data ==
670
1069
            target_format.rich_root_data)
674
1073
        """Register a format that does not use '.bzr' for its control dir.
675
1074
 
676
1075
        """
677
 
        klass._formats.append(format)
 
1076
        raise errors.BzrError("ControlDirFormat.register_format() has been "
 
1077
            "removed in Bazaar 2.4. Please upgrade your plugins.")
678
1078
 
679
1079
    @classmethod
680
1080
    def register_prober(klass, prober):
706
1106
        return self.get_format_description().rstrip()
707
1107
 
708
1108
    @classmethod
709
 
    def unregister_format(klass, format):
710
 
        klass._formats.remove(format)
711
 
 
712
 
    @classmethod
713
1109
    def known_formats(klass):
714
1110
        """Return all the known formats.
715
1111
        """
716
 
        return set(klass._formats)
 
1112
        result = set()
 
1113
        for prober_kls in klass._probers + klass._server_probers:
 
1114
            result.update(prober_kls.known_formats())
 
1115
        return result
717
1116
 
718
1117
    @classmethod
719
1118
    def find_format(klass, transport, _server_formats=True):
741
1140
        Subclasses should typically override initialize_on_transport
742
1141
        instead of this method.
743
1142
        """
744
 
        return self.initialize_on_transport(get_transport(url,
745
 
                                                          possible_transports))
 
1143
        return self.initialize_on_transport(
 
1144
            _mod_transport.get_transport(url, possible_transports))
 
1145
 
746
1146
    def initialize_on_transport(self, transport):
747
1147
        """Initialize a new controldir in the base directory of a Transport."""
748
1148
        raise NotImplementedError(self.initialize_on_transport)
806
1206
        """Return the current default format."""
807
1207
        return klass._default_format
808
1208
 
 
1209
    def supports_transport(self, transport):
 
1210
        """Check if this format can be opened over a particular transport.
 
1211
        """
 
1212
        raise NotImplementedError(self.supports_transport)
 
1213
 
809
1214
 
810
1215
class Prober(object):
811
 
    """Abstract class that can be used to detect a particular kind of 
 
1216
    """Abstract class that can be used to detect a particular kind of
812
1217
    control directory.
813
1218
 
814
 
    At the moment this just contains a single method to probe a particular 
815
 
    transport, but it may be extended in the future to e.g. avoid 
 
1219
    At the moment this just contains a single method to probe a particular
 
1220
    transport, but it may be extended in the future to e.g. avoid
816
1221
    multiple levels of probing for Subversion repositories.
 
1222
 
 
1223
    See BzrProber and RemoteBzrProber in bzrlib.bzrdir for the
 
1224
    probers that detect .bzr/ directories and Bazaar smart servers,
 
1225
    respectively.
 
1226
 
 
1227
    Probers should be registered using the register_server_prober or
 
1228
    register_prober methods on ControlDirFormat.
817
1229
    """
818
1230
 
819
1231
    def probe_transport(self, transport):
826
1238
        """
827
1239
        raise NotImplementedError(self.probe_transport)
828
1240
 
 
1241
    @classmethod
 
1242
    def known_formats(klass):
 
1243
        """Return the control dir formats known by this prober.
 
1244
 
 
1245
        Multiple probers can return the same formats, so this should
 
1246
        return a set.
 
1247
 
 
1248
        :return: A set of known formats.
 
1249
        """
 
1250
        raise NotImplementedError(klass.known_formats)
 
1251
 
829
1252
 
830
1253
class ControlDirFormatInfo(object):
831
1254
 
840
1263
    """Registry of user-selectable ControlDir subformats.
841
1264
 
842
1265
    Differs from ControlDirFormat._formats in that it provides sub-formats,
843
 
    e.g. ControlDirMeta1 with weave repository.  Also, it's more user-oriented.
 
1266
    e.g. BzrDirMeta1 with weave repository.  Also, it's more user-oriented.
844
1267
    """
845
1268
 
846
1269
    def __init__(self):
963
1386
            return output
964
1387
 
965
1388
 
 
1389
class RepoInitHookParams(object):
 
1390
    """Object holding parameters passed to `*_repo_init` hooks.
 
1391
 
 
1392
    There are 4 fields that hooks may wish to access:
 
1393
 
 
1394
    :ivar repository: Repository created
 
1395
    :ivar format: Repository format
 
1396
    :ivar bzrdir: The controldir for the repository
 
1397
    :ivar shared: The repository is shared
 
1398
    """
 
1399
 
 
1400
    def __init__(self, repository, format, controldir, shared):
 
1401
        """Create a group of RepoInitHook parameters.
 
1402
 
 
1403
        :param repository: Repository created
 
1404
        :param format: Repository format
 
1405
        :param controldir: The controldir for the repository
 
1406
        :param shared: The repository is shared
 
1407
        """
 
1408
        self.repository = repository
 
1409
        self.format = format
 
1410
        self.bzrdir = controldir
 
1411
        self.shared = shared
 
1412
 
 
1413
    def __eq__(self, other):
 
1414
        return self.__dict__ == other.__dict__
 
1415
 
 
1416
    def __repr__(self):
 
1417
        if self.repository:
 
1418
            return "<%s for %s>" % (self.__class__.__name__,
 
1419
                self.repository)
 
1420
        else:
 
1421
            return "<%s for %s>" % (self.__class__.__name__,
 
1422
                self.bzrdir)
 
1423
 
 
1424
 
966
1425
# Please register new formats after old formats so that formats
967
1426
# appear in chronological order and format descriptions can build
968
1427
# on previous ones.