~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

  • Committer: Vincent Ladeuil
  • Date: 2008-01-03 08:49:38 UTC
  • mfrom: (3111.1.31 175524)
  • mto: This revision was merged to the branch mainline in revision 3158.
  • Revision ID: v.ladeuil+lp@free.fr-20080103084938-7kvurk5uvde2ui54
Fix bug #175524, http test servers are 1.1 compliant

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 
19
19
At format 7 this was split out into Branch, Repository and Checkout control
20
20
directories.
 
21
 
 
22
Note: This module has a lot of ``open`` functions/methods that return
 
23
references to in-memory objects. As a rule, there are no matching ``close``
 
24
methods. To free any associated resources, simply stop referencing the
 
25
objects returned.
21
26
"""
22
27
 
23
 
# TODO: remove unittest dependency; put that stuff inside the test suite
24
 
 
25
 
# TODO: Can we move specific formats into separate modules to make this file
26
 
# smaller?
 
28
# TODO: Move old formats into a plugin to make this file smaller.
27
29
 
28
30
from cStringIO import StringIO
29
31
import os
30
 
import textwrap
 
32
import sys
31
33
 
32
34
from bzrlib.lazy_import import lazy_import
33
35
lazy_import(globals(), """
34
 
from copy import deepcopy
35
36
from stat import S_ISDIR
36
 
import unittest
 
37
import textwrap
 
38
from warnings import warn
37
39
 
38
40
import bzrlib
39
41
from bzrlib import (
40
42
    errors,
 
43
    graph,
41
44
    lockable_files,
42
45
    lockdir,
43
46
    registry,
46
49
    symbol_versioning,
47
50
    ui,
48
51
    urlutils,
 
52
    win32utils,
 
53
    workingtree,
 
54
    workingtree_4,
49
55
    xml4,
50
56
    xml5,
51
 
    workingtree,
52
 
    workingtree_4,
53
57
    )
54
58
from bzrlib.osutils import (
55
 
    safe_unicode,
56
59
    sha_strings,
57
60
    sha_string,
58
61
    )
74
77
    note,
75
78
    )
76
79
from bzrlib.transport.local import LocalTransport
 
80
from bzrlib.symbol_versioning import (
 
81
    deprecated_function,
 
82
    deprecated_method,
 
83
    zero_ninetyone,
 
84
    )
77
85
 
78
86
 
79
87
class BzrDir(object):
85
93
    transport
86
94
        the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
87
95
    root_transport
88
 
        a transport connected to the directory this bzr was opened from.
 
96
        a transport connected to the directory this bzr was opened from
 
97
        (i.e. the parent directory holding the .bzr directory).
89
98
    """
90
99
 
91
100
    def break_lock(self):
148
157
    def clone(self, url, revision_id=None, force_new_repo=False):
149
158
        """Clone this bzrdir and its contents to url verbatim.
150
159
 
151
 
        If urls last component does not exist, it will be created.
 
160
        If url's last component does not exist, it will be created.
152
161
 
153
162
        if revision_id is not None, then the clone operation may tune
154
163
            itself to download less data.
202
211
        except errors.NotBranchError:
203
212
            pass
204
213
        try:
205
 
            self.open_workingtree().clone(result)
206
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
207
 
            pass
 
214
            result_repo = result.find_repository()
 
215
        except errors.NoRepositoryPresent:
 
216
            result_repo = None
 
217
        if result_repo is None or result_repo.make_working_trees():
 
218
            try:
 
219
                self.open_workingtree().clone(result)
 
220
            except (errors.NoWorkingTree, errors.NotLocalUrl):
 
221
                pass
208
222
        return result
209
223
 
210
224
    # TODO: This should be given a Transport, and should chdir up; otherwise
213
227
        t = get_transport(url)
214
228
        t.ensure_base()
215
229
 
216
 
    # TODO: Should take a Transport
217
230
    @classmethod
218
 
    def create(cls, base, format=None):
 
231
    def create(cls, base, format=None, possible_transports=None):
219
232
        """Create a new BzrDir at the url 'base'.
220
233
        
221
 
        This will call the current default formats initialize with base
222
 
        as the only parameter.
223
 
 
224
234
        :param format: If supplied, the format of branch to create.  If not
225
235
            supplied, the default is used.
 
236
        :param possible_transports: If supplied, a list of transports that 
 
237
            can be reused to share a remote connection.
226
238
        """
227
239
        if cls is not BzrDir:
228
240
            raise AssertionError("BzrDir.create always creates the default"
229
241
                " format, not one of %r" % cls)
230
 
        t = get_transport(base)
 
242
        t = get_transport(base, possible_transports)
231
243
        t.ensure_base()
232
244
        if format is None:
233
245
            format = BzrDirFormat.get_default_format()
234
 
        return format.initialize(safe_unicode(base))
 
246
        return format.initialize_on_transport(t)
 
247
 
 
248
    @staticmethod
 
249
    def find_bzrdirs(transport, evaluate=None, list_current=None):
 
250
        """Find bzrdirs recursively from current location.
 
251
 
 
252
        This is intended primarily as a building block for more sophisticated
 
253
        functionality, like finding trees under a directory, or finding
 
254
        branches that use a given repository.
 
255
        :param evaluate: An optional callable that yields recurse, value,
 
256
            where recurse controls whether this bzrdir is recursed into
 
257
            and value is the value to yield.  By default, all bzrdirs
 
258
            are recursed into, and the return value is the bzrdir.
 
259
        :param list_current: if supplied, use this function to list the current
 
260
            directory, instead of Transport.list_dir
 
261
        :return: a generator of found bzrdirs, or whatever evaluate returns.
 
262
        """
 
263
        if list_current is None:
 
264
            def list_current(transport):
 
265
                return transport.list_dir('')
 
266
        if evaluate is None:
 
267
            def evaluate(bzrdir):
 
268
                return True, bzrdir
 
269
 
 
270
        pending = [transport]
 
271
        while len(pending) > 0:
 
272
            current_transport = pending.pop()
 
273
            recurse = True
 
274
            try:
 
275
                bzrdir = BzrDir.open_from_transport(current_transport)
 
276
            except errors.NotBranchError:
 
277
                pass
 
278
            else:
 
279
                recurse, value = evaluate(bzrdir)
 
280
                yield value
 
281
            try:
 
282
                subdirs = list_current(current_transport)
 
283
            except errors.NoSuchFile:
 
284
                continue
 
285
            if recurse:
 
286
                for subdir in sorted(subdirs, reverse=True):
 
287
                    pending.append(current_transport.clone(subdir))
 
288
 
 
289
    @staticmethod
 
290
    def find_branches(transport):
 
291
        """Find all branches under a transport.
 
292
 
 
293
        This will find all branches below the transport, including branches
 
294
        inside other branches.  Where possible, it will use
 
295
        Repository.find_branches.
 
296
 
 
297
        To list all the branches that use a particular Repository, see
 
298
        Repository.find_branches
 
299
        """
 
300
        def evaluate(bzrdir):
 
301
            try:
 
302
                repository = bzrdir.open_repository()
 
303
            except errors.NoRepositoryPresent:
 
304
                pass
 
305
            else:
 
306
                return False, (None, repository)
 
307
            try:
 
308
                branch = bzrdir.open_branch()
 
309
            except errors.NotBranchError:
 
310
                return True, (None, None)
 
311
            else:
 
312
                return True, (branch, None)
 
313
        branches = []
 
314
        for branch, repo in BzrDir.find_bzrdirs(transport, evaluate=evaluate):
 
315
            if repo is not None:
 
316
                branches.extend(repo.find_branches())
 
317
            if branch is not None:
 
318
                branches.append(branch)
 
319
        return branches
 
320
 
 
321
 
 
322
    def destroy_repository(self):
 
323
        """Destroy the repository in this BzrDir"""
 
324
        raise NotImplementedError(self.destroy_repository)
235
325
 
236
326
    def create_branch(self):
237
327
        """Create a branch in this BzrDir.
238
328
 
239
 
        The bzrdirs format will control what branch format is created.
 
329
        The bzrdir's format will control what branch format is created.
240
330
        For more control see BranchFormatXX.create(a_bzrdir).
241
331
        """
242
332
        raise NotImplementedError(self.create_branch)
243
333
 
 
334
    def destroy_branch(self):
 
335
        """Destroy the branch in this BzrDir"""
 
336
        raise NotImplementedError(self.destroy_branch)
 
337
 
244
338
    @staticmethod
245
339
    def create_branch_and_repo(base, force_new_repo=False, format=None):
246
340
        """Create a new BzrDir, Branch and Repository at the url 'base'.
247
341
 
248
 
        This will use the current default BzrDirFormat, and use whatever 
 
342
        This will use the current default BzrDirFormat unless one is
 
343
        specified, and use whatever 
249
344
        repository format that that uses via bzrdir.create_branch and
250
345
        create_repository. If a shared repository is available that is used
251
346
        preferentially.
254
349
 
255
350
        :param base: The URL to create the branch at.
256
351
        :param force_new_repo: If True a new repository is always created.
 
352
        :param format: If supplied, the format of branch to create.  If not
 
353
            supplied, the default is used.
257
354
        """
258
355
        bzrdir = BzrDir.create(base, format)
259
356
        bzrdir._find_or_create_repository(force_new_repo)
270
367
        
271
368
    @staticmethod
272
369
    def create_branch_convenience(base, force_new_repo=False,
273
 
                                  force_new_tree=None, format=None):
 
370
                                  force_new_tree=None, format=None,
 
371
                                  possible_transports=None):
274
372
        """Create a new BzrDir, Branch and Repository at the url 'base'.
275
373
 
276
374
        This is a convenience function - it will use an existing repository
277
375
        if possible, can be told explicitly whether to create a working tree or
278
376
        not.
279
377
 
280
 
        This will use the current default BzrDirFormat, and use whatever 
 
378
        This will use the current default BzrDirFormat unless one is
 
379
        specified, and use whatever 
281
380
        repository format that that uses via bzrdir.create_branch and
282
381
        create_repository. If a shared repository is available that is used
283
382
        preferentially. Whatever repository is used, its tree creation policy
292
391
        :param force_new_repo: If True a new repository is always created.
293
392
        :param force_new_tree: If True or False force creation of a tree or 
294
393
                               prevent such creation respectively.
295
 
        :param format: Override for the for the bzrdir format to create
 
394
        :param format: Override for the bzrdir format to create.
 
395
        :param possible_transports: An optional reusable transports list.
296
396
        """
297
397
        if force_new_tree:
298
398
            # check for non local urls
299
 
            t = get_transport(safe_unicode(base))
 
399
            t = get_transport(base, possible_transports)
300
400
            if not isinstance(t, LocalTransport):
301
401
                raise errors.NotLocalUrl(base)
302
 
        bzrdir = BzrDir.create(base, format)
 
402
        bzrdir = BzrDir.create(base, format, possible_transports)
303
403
        repo = bzrdir._find_or_create_repository(force_new_repo)
304
404
        result = bzrdir.create_branch()
305
 
        if force_new_tree or (repo.make_working_trees() and 
 
405
        if force_new_tree or (repo.make_working_trees() and
306
406
                              force_new_tree is None):
307
407
            try:
308
408
                bzrdir.create_workingtree()
309
409
            except errors.NotLocalUrl:
310
410
                pass
311
411
        return result
312
 
        
 
412
 
313
413
    @staticmethod
 
414
    @deprecated_function(zero_ninetyone)
314
415
    def create_repository(base, shared=False, format=None):
315
416
        """Create a new BzrDir and Repository at the url 'base'.
316
417
 
325
426
        This must be overridden as an instance method in child classes, where
326
427
        it should take no parameters and construct whatever repository format
327
428
        that child class desires.
 
429
 
 
430
        This method is deprecated, please call create_repository on a bzrdir
 
431
        instance instead.
328
432
        """
329
433
        bzrdir = BzrDir.create(base, format)
330
434
        return bzrdir.create_repository(shared)
335
439
 
336
440
        'base' must be a local path or a file:// url.
337
441
 
338
 
        This will use the current default BzrDirFormat, and use whatever 
 
442
        This will use the current default BzrDirFormat unless one is
 
443
        specified, and use whatever 
339
444
        repository format that that uses for bzrdirformat.create_workingtree,
340
445
        create_branch and create_repository.
341
446
 
 
447
        :param format: Override for the bzrdir format to create.
342
448
        :return: The WorkingTree object.
343
449
        """
344
 
        t = get_transport(safe_unicode(base))
 
450
        t = get_transport(base)
345
451
        if not isinstance(t, LocalTransport):
346
452
            raise errors.NotLocalUrl(base)
347
 
        bzrdir = BzrDir.create_branch_and_repo(safe_unicode(base),
 
453
        bzrdir = BzrDir.create_branch_and_repo(base,
348
454
                                               force_new_repo=True,
349
455
                                               format=format).bzrdir
350
456
        return bzrdir.create_workingtree()
351
457
 
352
 
    def create_workingtree(self, revision_id=None):
 
458
    def create_workingtree(self, revision_id=None, from_branch=None,
 
459
        accelerator_tree=None):
353
460
        """Create a working tree at this BzrDir.
354
461
        
355
 
        revision_id: create it as of this revision id.
 
462
        :param revision_id: create it as of this revision id.
 
463
        :param from_branch: override bzrdir branch (for lightweight checkouts)
 
464
        :param accelerator_tree: A tree which can be used for retrieving file
 
465
            contents more quickly than the revision tree, i.e. a workingtree.
 
466
            The revision tree will be used for cases where accelerator_tree's
 
467
            content is different.
356
468
        """
357
469
        raise NotImplementedError(self.create_workingtree)
358
470
 
359
 
    def retire_bzrdir(self):
 
471
    def retire_bzrdir(self, limit=10000):
360
472
        """Permanently disable the bzrdir.
361
473
 
362
474
        This is done by renaming it to give the user some ability to recover
364
476
 
365
477
        This will have horrible consequences if anyone has anything locked or
366
478
        in use.
 
479
        :param limit: number of times to retry
367
480
        """
368
 
        for i in xrange(10000):
 
481
        i  = 0
 
482
        while True:
369
483
            try:
370
484
                to_path = '.bzr.retired.%d' % i
371
485
                self.root_transport.rename('.bzr', to_path)
372
486
                note("renamed %s to %s"
373
487
                    % (self.root_transport.abspath('.bzr'), to_path))
374
 
                break
 
488
                return
375
489
            except (errors.TransportError, IOError, errors.PathError):
376
 
                pass
 
490
                i += 1
 
491
                if i > limit:
 
492
                    raise
 
493
                else:
 
494
                    pass
377
495
 
378
496
    def destroy_workingtree(self):
379
497
        """Destroy the working tree at this BzrDir.
391
509
        raise NotImplementedError(self.destroy_workingtree_metadata)
392
510
 
393
511
    def find_repository(self):
394
 
        """Find the repository that should be used for a_bzrdir.
 
512
        """Find the repository that should be used.
395
513
 
396
514
        This does not require a branch as we use it to find the repo for
397
515
        new branches as well as to hook existing branches up to their
444
562
        a format string, and vice versa.
445
563
 
446
564
        If branch_format is None, the transport is returned with no 
447
 
        checking. if it is not None, then the returned transport is
 
565
        checking. If it is not None, then the returned transport is
448
566
        guaranteed to point to an existing directory ready for use.
449
567
        """
450
568
        raise NotImplementedError(self.get_branch_transport)
457
575
        a format string, and vice versa.
458
576
 
459
577
        If repository_format is None, the transport is returned with no 
460
 
        checking. if it is not None, then the returned transport is
 
578
        checking. If it is not None, then the returned transport is
461
579
        guaranteed to point to an existing directory ready for use.
462
580
        """
463
581
        raise NotImplementedError(self.get_repository_transport)
470
588
        format string, and vice versa.
471
589
 
472
590
        If workingtree_format is None, the transport is returned with no 
473
 
        checking. if it is not None, then the returned transport is
 
591
        checking. If it is not None, then the returned transport is
474
592
        guaranteed to point to an existing directory ready for use.
475
593
        """
476
594
        raise NotImplementedError(self.get_workingtree_transport)
502
620
        # this might be better on the BzrDirFormat class because it refers to 
503
621
        # all the possible bzrdir disk formats. 
504
622
        # This method is tested via the workingtree is_control_filename tests- 
505
 
        # it was extracted from WorkingTree.is_control_filename. If the methods
506
 
        # contract is extended beyond the current trivial  implementation please
 
623
        # it was extracted from WorkingTree.is_control_filename. If the method's
 
624
        # contract is extended beyond the current trivial implementation, please
507
625
        # add new tests for it to the appropriate place.
508
626
        return filename == '.bzr' or filename.startswith('.bzr/')
509
627
 
524
642
        return BzrDir.open(base, _unsupported=True)
525
643
        
526
644
    @staticmethod
527
 
    def open(base, _unsupported=False):
528
 
        """Open an existing bzrdir, rooted at 'base' (url)
 
645
    def open(base, _unsupported=False, possible_transports=None):
 
646
        """Open an existing bzrdir, rooted at 'base' (url).
529
647
        
530
 
        _unsupported is a private parameter to the BzrDir class.
 
648
        :param _unsupported: a private parameter to the BzrDir class.
531
649
        """
532
 
        t = get_transport(base)
 
650
        t = get_transport(base, possible_transports=possible_transports)
533
651
        return BzrDir.open_from_transport(t, _unsupported=_unsupported)
534
652
 
535
653
    @staticmethod
556
674
            note('%s is%s redirected to %s',
557
675
                 transport.base, e.permanently, target)
558
676
            # Let's try with a new transport
559
 
            qualified_target = e.get_target_url()[:-len(relpath)]
560
677
            # FIXME: If 'transport' has a qualifier, this should
561
678
            # be applied again to the new transport *iff* the
562
 
            # schemes used are the same. It's a bit tricky to
563
 
            # verify, so I'll punt for now
 
679
            # schemes used are the same. Uncomment this code
 
680
            # once the function (and tests) exist.
564
681
            # -- vila20070212
 
682
            #target = urlutils.copy_url_qualifiers(original, target)
565
683
            return get_transport(target)
566
684
 
567
685
        try:
585
703
        raise NotImplementedError(self.open_branch)
586
704
 
587
705
    @staticmethod
588
 
    def open_containing(url):
 
706
    def open_containing(url, possible_transports=None):
589
707
        """Open an existing branch which contains url.
590
708
        
591
709
        :param url: url to search from.
592
710
        See open_containing_from_transport for more detail.
593
711
        """
594
 
        return BzrDir.open_containing_from_transport(get_transport(url))
 
712
        transport = get_transport(url, possible_transports)
 
713
        return BzrDir.open_containing_from_transport(transport)
595
714
    
596
715
    @staticmethod
597
716
    def open_containing_from_transport(a_transport):
598
 
        """Open an existing branch which contains a_transport.base
 
717
        """Open an existing branch which contains a_transport.base.
599
718
 
600
719
        This probes for a branch at a_transport, and searches upwards from there.
601
720
 
626
745
                raise errors.NotBranchError(path=url)
627
746
            a_transport = new_t
628
747
 
 
748
    def _get_tree_branch(self):
 
749
        """Return the branch and tree, if any, for this bzrdir.
 
750
 
 
751
        Return None for tree if not present.
 
752
        Raise NotBranchError if no branch is present.
 
753
        :return: (tree, branch)
 
754
        """
 
755
        try:
 
756
            tree = self.open_workingtree()
 
757
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
758
            tree = None
 
759
            branch = self.open_branch()
 
760
        else:
 
761
            branch = tree.branch
 
762
        return tree, branch
 
763
 
 
764
    @classmethod
 
765
    def open_tree_or_branch(klass, location):
 
766
        """Return the branch and working tree at a location.
 
767
 
 
768
        If there is no tree at the location, tree will be None.
 
769
        If there is no branch at the location, an exception will be
 
770
        raised
 
771
        :return: (tree, branch)
 
772
        """
 
773
        bzrdir = klass.open(location)
 
774
        return bzrdir._get_tree_branch()
 
775
 
629
776
    @classmethod
630
777
    def open_containing_tree_or_branch(klass, location):
631
778
        """Return the branch and working tree contained by a location.
637
784
        relpath is the portion of the path that is contained by the branch.
638
785
        """
639
786
        bzrdir, relpath = klass.open_containing(location)
640
 
        try:
641
 
            tree = bzrdir.open_workingtree()
642
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
643
 
            tree = None
644
 
            branch = bzrdir.open_branch()
645
 
        else:
646
 
            branch = tree.branch
 
787
        tree, branch = bzrdir._get_tree_branch()
647
788
        return tree, branch, relpath
648
789
 
649
790
    def open_repository(self, _unsupported=False):
650
791
        """Open the repository object at this BzrDir if one is present.
651
792
 
652
 
        This will not follow the Branch object pointer - its strictly a direct
 
793
        This will not follow the Branch object pointer - it's strictly a direct
653
794
        open facility. Most client code should use open_branch().repository to
654
795
        get at a repository.
655
796
 
656
 
        _unsupported is a private parameter, not part of the api.
 
797
        :param _unsupported: a private parameter, not part of the api.
657
798
        TODO: static convenience version of this?
658
799
        """
659
800
        raise NotImplementedError(self.open_repository)
660
801
 
661
802
    def open_workingtree(self, _unsupported=False,
662
 
            recommend_upgrade=True):
 
803
                         recommend_upgrade=True, from_branch=None):
663
804
        """Open the workingtree object at this BzrDir if one is present.
664
805
 
665
806
        :param recommend_upgrade: Optional keyword parameter, when True (the
666
807
            default), emit through the ui module a recommendation that the user
667
808
            upgrade the working tree when the workingtree being opened is old
668
809
            (but still fully supported).
 
810
        :param from_branch: override bzrdir branch (for lightweight checkouts)
669
811
        """
670
812
        raise NotImplementedError(self.open_workingtree)
671
813
 
699
841
            return False
700
842
 
701
843
    def _cloning_metadir(self):
702
 
        """Produce a metadir suitable for cloning with"""
 
844
        """Produce a metadir suitable for cloning with."""
703
845
        result_format = self._format.__class__()
704
846
        try:
705
847
            try:
732
874
        """Produce a metadir suitable for cloning or sprouting with.
733
875
 
734
876
        These operations may produce workingtrees (yes, even though they're
735
 
        "cloning" something that doesn't have a tree, so a viable workingtree
 
877
        "cloning" something that doesn't have a tree), so a viable workingtree
736
878
        format must be selected.
737
879
        """
738
880
        format, repository = self._cloning_metadir()
747
889
        return self.cloning_metadir()
748
890
 
749
891
    def sprout(self, url, revision_id=None, force_new_repo=False,
750
 
               recurse='down'):
 
892
               recurse='down', possible_transports=None,
 
893
               accelerator_tree=None):
751
894
        """Create a copy of this bzrdir prepared for use as a new line of
752
895
        development.
753
896
 
754
 
        If urls last component does not exist, it will be created.
 
897
        If url's last component does not exist, it will be created.
755
898
 
756
899
        Attributes related to the identity of the source branch like
757
900
        branch nickname will be cleaned, a working tree is created
760
903
 
761
904
        if revision_id is not None, then the clone operation may tune
762
905
            itself to download less data.
 
906
        :param accelerator_tree: A tree which can be used for retrieving file
 
907
            contents more quickly than the revision tree, i.e. a workingtree.
 
908
            The revision tree will be used for cases where accelerator_tree's
 
909
            content is different.
763
910
        """
764
 
        target_transport = get_transport(url)
 
911
        target_transport = get_transport(url, possible_transports)
765
912
        target_transport.ensure_base()
766
913
        cloning_format = self.cloning_metadir()
767
914
        result = cloning_format.initialize_on_transport(target_transport)
788
935
            result.create_repository()
789
936
        elif source_repository is not None and result_repo is None:
790
937
            # have source, and want to make a new target repo
791
 
            result_repo = source_repository.sprout(result, revision_id=revision_id)
 
938
            result_repo = source_repository.sprout(result,
 
939
                                                   revision_id=revision_id)
792
940
        else:
793
941
            # fetch needed content into target.
794
942
            if source_repository is not None:
795
943
                # would rather do 
796
 
                # source_repository.copy_content_into(result_repo, revision_id=revision_id)
 
944
                # source_repository.copy_content_into(result_repo,
 
945
                #                                     revision_id=revision_id)
797
946
                # so we can override the copy method
798
947
                result_repo.fetch(source_repository, revision_id=revision_id)
799
948
        if source_branch is not None:
800
949
            source_branch.sprout(result, revision_id=revision_id)
801
950
        else:
802
951
            result.create_branch()
803
 
        # TODO: jam 20060426 we probably need a test in here in the
804
 
        #       case that the newly sprouted branch is a remote one
805
 
        if result_repo is None or result_repo.make_working_trees():
806
 
            wt = result.create_workingtree()
 
952
        if isinstance(target_transport, LocalTransport) and (
 
953
            result_repo is None or result_repo.make_working_trees()):
 
954
            wt = result.create_workingtree(accelerator_tree=accelerator_tree)
807
955
            wt.lock_write()
808
956
            try:
809
957
                if wt.path2id('') is None:
883
1031
        """See BzrDir.create_branch."""
884
1032
        return self.open_branch()
885
1033
 
 
1034
    def destroy_branch(self):
 
1035
        """See BzrDir.destroy_branch."""
 
1036
        raise errors.UnsupportedOperation(self.destroy_branch, self)
 
1037
 
886
1038
    def create_repository(self, shared=False):
887
1039
        """See BzrDir.create_repository."""
888
1040
        if shared:
889
1041
            raise errors.IncompatibleFormat('shared repository', self._format)
890
1042
        return self.open_repository()
891
1043
 
892
 
    def create_workingtree(self, revision_id=None):
 
1044
    def destroy_repository(self):
 
1045
        """See BzrDir.destroy_repository."""
 
1046
        raise errors.UnsupportedOperation(self.destroy_repository, self)
 
1047
 
 
1048
    def create_workingtree(self, revision_id=None, from_branch=None,
 
1049
                           accelerator_tree=None):
893
1050
        """See BzrDir.create_workingtree."""
894
1051
        # this looks buggy but is not -really-
895
1052
        # because this format creates the workingtree when the bzrdir is
962
1119
        self._check_supported(format, unsupported)
963
1120
        return format.open(self, _found=True)
964
1121
 
965
 
    def sprout(self, url, revision_id=None, force_new_repo=False):
 
1122
    def sprout(self, url, revision_id=None, force_new_repo=False,
 
1123
               possible_transports=None, accelerator_tree=None):
966
1124
        """See BzrDir.sprout()."""
967
1125
        from bzrlib.workingtree import WorkingTreeFormat2
968
1126
        self._make_tail(url)
976
1134
        except errors.NotBranchError:
977
1135
            pass
978
1136
        # we always want a working tree
979
 
        WorkingTreeFormat2().initialize(result)
 
1137
        WorkingTreeFormat2().initialize(result,
 
1138
                                        accelerator_tree=accelerator_tree)
980
1139
        return result
981
1140
 
982
1141
 
1058
1217
        """See BzrDir.create_branch."""
1059
1218
        return self._format.get_branch_format().initialize(self)
1060
1219
 
 
1220
    def destroy_branch(self):
 
1221
        """See BzrDir.create_branch."""
 
1222
        self.transport.delete_tree('branch')
 
1223
 
1061
1224
    def create_repository(self, shared=False):
1062
1225
        """See BzrDir.create_repository."""
1063
1226
        return self._format.repository_format.initialize(self, shared)
1064
1227
 
1065
 
    def create_workingtree(self, revision_id=None):
 
1228
    def destroy_repository(self):
 
1229
        """See BzrDir.destroy_repository."""
 
1230
        self.transport.delete_tree('repository')
 
1231
 
 
1232
    def create_workingtree(self, revision_id=None, from_branch=None,
 
1233
                           accelerator_tree=None):
1066
1234
        """See BzrDir.create_workingtree."""
1067
 
        from bzrlib.workingtree import WorkingTreeFormat
1068
 
        return self._format.workingtree_format.initialize(self, revision_id)
 
1235
        return self._format.workingtree_format.initialize(
 
1236
            self, revision_id, from_branch=from_branch,
 
1237
            accelerator_tree=accelerator_tree)
1069
1238
 
1070
1239
    def destroy_workingtree(self):
1071
1240
        """See BzrDir.destroy_workingtree."""
1072
1241
        wt = self.open_workingtree(recommend_upgrade=False)
1073
1242
        repository = wt.branch.repository
1074
1243
        empty = repository.revision_tree(_mod_revision.NULL_REVISION)
1075
 
        wt.revert([], old_tree=empty)
 
1244
        wt.revert(old_tree=empty)
1076
1245
        self.destroy_workingtree_metadata()
1077
1246
 
1078
1247
    def destroy_workingtree_metadata(self):
1204
1373
     * a format string,
1205
1374
     * an open routine.
1206
1375
 
1207
 
    Formats are placed in an dict by their format string for reference 
 
1376
    Formats are placed in a dict by their format string for reference 
1208
1377
    during bzrdir opening. These should be subclasses of BzrDirFormat
1209
1378
    for consistency.
1210
1379
 
1291
1460
        """
1292
1461
        raise NotImplementedError(self.get_converter)
1293
1462
 
1294
 
    def initialize(self, url):
 
1463
    def initialize(self, url, possible_transports=None):
1295
1464
        """Create a bzr control dir at this url and return an opened copy.
1296
1465
        
1297
1466
        Subclasses should typically override initialize_on_transport
1298
1467
        instead of this method.
1299
1468
        """
1300
 
        return self.initialize_on_transport(get_transport(url))
 
1469
        return self.initialize_on_transport(get_transport(url,
 
1470
                                                          possible_transports))
1301
1471
 
1302
1472
    def initialize_on_transport(self, transport):
1303
1473
        """Initialize a new bzrdir in the base directory of a Transport."""
1309
1479
                                      # FIXME: RBC 20060121 don't peek under
1310
1480
                                      # the covers
1311
1481
                                      mode=temp_control._dir_mode)
 
1482
        if sys.platform == 'win32' and isinstance(transport, LocalTransport):
 
1483
            win32utils.set_file_attr_hidden(transport._abspath('.bzr'))
1312
1484
        file_mode = temp_control._file_mode
1313
1485
        del temp_control
1314
1486
        mutter('created control directory in ' + transport.base)
1420
1592
        klass._default_format = format
1421
1593
 
1422
1594
    def __str__(self):
1423
 
        return self.get_format_string()[:-1]
 
1595
        # Trim the newline
 
1596
        return self.get_format_string().rstrip()
1424
1597
 
1425
1598
    @classmethod
1426
1599
    def unregister_format(klass, format):
1670
1843
        return RepositoryFormat.get_default_format()
1671
1844
 
1672
1845
    def __set_repository_format(self, value):
1673
 
        """Allow changint the repository format for metadir formats."""
 
1846
        """Allow changing the repository format for metadir formats."""
1674
1847
        self._repository_format = value
1675
1848
 
1676
1849
    repository_format = property(__return_repository_format, __set_repository_format)
1700
1873
BzrDirFormat._default_format = __default_format
1701
1874
 
1702
1875
 
1703
 
class BzrDirTestProviderAdapter(object):
1704
 
    """A tool to generate a suite testing multiple bzrdir formats at once.
1705
 
 
1706
 
    This is done by copying the test once for each transport and injecting
1707
 
    the transport_server, transport_readonly_server, and bzrdir_format
1708
 
    classes into each copy. Each copy is also given a new id() to make it
1709
 
    easy to identify.
1710
 
    """
1711
 
 
1712
 
    def __init__(self, vfs_factory, transport_server, transport_readonly_server,
1713
 
        formats):
1714
 
        """Create an object to adapt tests.
1715
 
 
1716
 
        :param vfs_server: A factory to create a Transport Server which has
1717
 
            all the VFS methods working, and is writable.
1718
 
        """
1719
 
        self._vfs_factory = vfs_factory
1720
 
        self._transport_server = transport_server
1721
 
        self._transport_readonly_server = transport_readonly_server
1722
 
        self._formats = formats
1723
 
    
1724
 
    def adapt(self, test):
1725
 
        result = unittest.TestSuite()
1726
 
        for format in self._formats:
1727
 
            new_test = deepcopy(test)
1728
 
            new_test.vfs_transport_factory = self._vfs_factory
1729
 
            new_test.transport_server = self._transport_server
1730
 
            new_test.transport_readonly_server = self._transport_readonly_server
1731
 
            new_test.bzrdir_format = format
1732
 
            def make_new_test_id():
1733
 
                new_id = "%s(%s)" % (new_test.id(), format.__class__.__name__)
1734
 
                return lambda: new_id
1735
 
            new_test.id = make_new_test_id()
1736
 
            result.addTest(new_test)
1737
 
        return result
1738
 
 
1739
 
 
1740
1876
class Converter(object):
1741
1877
    """Converts a disk format object from one format to another."""
1742
1878
 
1829
1965
    def _convert_working_inv(self):
1830
1966
        inv = xml4.serializer_v4.read_inventory(
1831
1967
                    self.branch.control_files.get('inventory'))
1832
 
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
 
1968
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv, working=True)
1833
1969
        # FIXME inventory is a working tree change.
1834
1970
        self.branch.control_files.put('inventory', StringIO(new_inv_xml))
1835
1971
 
1914
2050
        present_parents = [p for p in rev.parent_ids
1915
2051
                           if p not in self.absent_revisions]
1916
2052
        self._convert_revision_contents(rev, inv, present_parents)
1917
 
        self._store_new_weave(rev, inv, present_parents)
 
2053
        self._store_new_inv(rev, inv, present_parents)
1918
2054
        self.converted_revs.add(rev_id)
1919
2055
 
1920
 
    def _store_new_weave(self, rev, inv, present_parents):
 
2056
    def _store_new_inv(self, rev, inv, present_parents):
1921
2057
        # the XML is now updated with text versions
1922
2058
        if __debug__:
1923
2059
            entries = inv.iter_entries()
1928
2064
                    (file_id, rev.revision_id)
1929
2065
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
1930
2066
        new_inv_sha1 = sha_string(new_inv_xml)
1931
 
        self.inv_weave.add_lines(rev.revision_id, 
 
2067
        self.inv_weave.add_lines(rev.revision_id,
1932
2068
                                 present_parents,
1933
2069
                                 new_inv_xml.splitlines(True))
1934
2070
        rev.inventory_sha1 = new_inv_sha1
1959
2095
            w = Weave(file_id)
1960
2096
            self.text_weaves[file_id] = w
1961
2097
        text_changed = False
1962
 
        previous_entries = ie.find_previous_heads(parent_invs,
1963
 
                                                  None,
1964
 
                                                  None,
1965
 
                                                  entry_vf=w)
1966
 
        for old_revision in previous_entries:
1967
 
                # if this fails, its a ghost ?
1968
 
                assert old_revision in self.converted_revs, \
1969
 
                    "Revision {%s} not in converted_revs" % old_revision
 
2098
        parent_candiate_entries = ie.parent_candidates(parent_invs)
 
2099
        for old_revision in parent_candiate_entries.keys():
 
2100
            # if this fails, its a ghost ?
 
2101
            assert old_revision in self.converted_revs, \
 
2102
                "Revision {%s} not in converted_revs" % old_revision
 
2103
        heads = graph.Graph(self).heads(parent_candiate_entries.keys())
 
2104
        # XXX: Note that this is unordered - and this is tolerable because 
 
2105
        # the previous code was also unordered.
 
2106
        previous_entries = dict((head, parent_candiate_entries[head]) for head
 
2107
            in heads)
1970
2108
        self.snapshot_ie(previous_entries, ie, w, rev_id)
1971
2109
        del ie.text_id
1972
2110
        assert getattr(ie, 'revision', None) is not None
1973
2111
 
 
2112
    @symbol_versioning.deprecated_method(symbol_versioning.one_one)
 
2113
    def get_parents(self, revision_ids):
 
2114
        for revision_id in revision_ids:
 
2115
            yield self.revisions[revision_id].parent_ids
 
2116
 
 
2117
    def get_parent_map(self, revision_ids):
 
2118
        """See graph._StackedParentsProvider.get_parent_map"""
 
2119
        return dict((revision_id, self.revisions[revision_id])
 
2120
                    for revision_id in revision_ids
 
2121
                     if revision_id in self.revisions)
 
2122
 
1974
2123
    def snapshot_ie(self, previous_revisions, ie, w, rev_id):
1975
2124
        # TODO: convert this logic, which is ~= snapshot to
1976
2125
        # a call to:. This needs the path figured out. rather than a work_tree
1985
2134
                ie.revision = previous_ie.revision
1986
2135
                return
1987
2136
        if ie.has_text():
1988
 
            text = self.branch.repository.text_store.get(ie.text_id)
 
2137
            text = self.branch.repository.weave_store.get(ie.text_id)
1989
2138
            file_lines = text.readlines()
1990
2139
            assert sha_strings(file_lines) == ie.text_sha1
1991
2140
            assert sum(map(len, file_lines)) == ie.text_size
2258
2407
    def initialize_on_transport(self, transport):
2259
2408
        try:
2260
2409
            # hand off the request to the smart server
2261
 
            medium = transport.get_smart_medium()
 
2410
            shared_medium = transport.get_shared_medium()
2262
2411
        except errors.NoSmartMedium:
2263
2412
            # TODO: lookup the local format from a server hint.
2264
2413
            local_dir_format = BzrDirMetaFormat1()
2265
2414
            return local_dir_format.initialize_on_transport(transport)
2266
 
        client = _SmartClient(medium)
 
2415
        client = _SmartClient(shared_medium)
2267
2416
        path = client.remote_path_from_transport(transport)
2268
 
        response = _SmartClient(medium).call('BzrDirFormat.initialize', path)
 
2417
        response = _SmartClient(shared_medium).call('BzrDirFormat.initialize',
 
2418
                                                    path)
2269
2419
        assert response[0] in ('ok', ), 'unexpected response code %s' % (response,)
2270
2420
        return remote.RemoteBzrDir(transport)
2271
2421
 
2283
2433
 
2284
2434
class BzrDirFormatInfo(object):
2285
2435
 
2286
 
    def __init__(self, native, deprecated, hidden):
 
2436
    def __init__(self, native, deprecated, hidden, experimental):
2287
2437
        self.deprecated = deprecated
2288
2438
        self.native = native
2289
2439
        self.hidden = hidden
 
2440
        self.experimental = experimental
2290
2441
 
2291
2442
 
2292
2443
class BzrDirFormatRegistry(registry.Registry):
2300
2451
             repository_format, help, native=True, deprecated=False,
2301
2452
             branch_format=None,
2302
2453
             tree_format=None,
2303
 
             hidden=False):
 
2454
             hidden=False,
 
2455
             experimental=False):
2304
2456
        """Register a metadir subformat.
2305
2457
 
2306
2458
        These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2338
2490
            if repository_format is not None:
2339
2491
                bd.repository_format = _load(repository_format)
2340
2492
            return bd
2341
 
        self.register(key, helper, help, native, deprecated, hidden)
 
2493
        self.register(key, helper, help, native, deprecated, hidden,
 
2494
            experimental)
2342
2495
 
2343
2496
    def register(self, key, factory, help, native=True, deprecated=False,
2344
 
                 hidden=False):
 
2497
                 hidden=False, experimental=False):
2345
2498
        """Register a BzrDirFormat factory.
2346
2499
        
2347
2500
        The factory must be a callable that takes one parameter: the key.
2351
2504
        supplied directly.
2352
2505
        """
2353
2506
        registry.Registry.register(self, key, factory, help, 
2354
 
            BzrDirFormatInfo(native, deprecated, hidden))
 
2507
            BzrDirFormatInfo(native, deprecated, hidden, experimental))
2355
2508
 
2356
2509
    def register_lazy(self, key, module_name, member_name, help, native=True,
2357
 
                      deprecated=False, hidden=False):
 
2510
                      deprecated=False, hidden=False, experimental=False):
2358
2511
        registry.Registry.register_lazy(self, key, module_name, member_name, 
2359
 
            help, BzrDirFormatInfo(native, deprecated, hidden))
 
2512
            help, BzrDirFormatInfo(native, deprecated, hidden, experimental))
2360
2513
 
2361
2514
    def set_default(self, key):
2362
2515
        """Set the 'default' key to be a clone of the supplied key.
2383
2536
 
2384
2537
    def help_topic(self, topic):
2385
2538
        output = textwrap.dedent("""\
2386
 
            Bazaar directory formats
2387
 
            ------------------------
2388
 
 
2389
2539
            These formats can be used for creating branches, working trees, and
2390
2540
            repositories.
2391
2541
 
2392
2542
            """)
 
2543
        default_realkey = None
2393
2544
        default_help = self.get_help('default')
2394
2545
        help_pairs = []
2395
2546
        for key in self.keys():
2404
2555
        def wrapped(key, help, info):
2405
2556
            if info.native:
2406
2557
                help = '(native) ' + help
2407
 
            return '  %s:\n%s\n\n' % (key, 
 
2558
            return ':%s:\n%s\n\n' % (key, 
2408
2559
                    textwrap.fill(help, initial_indent='    ', 
2409
2560
                    subsequent_indent='    '))
2410
 
        output += wrapped('%s/default' % default_realkey, default_help,
2411
 
                          self.get_info('default'))
 
2561
        if default_realkey is not None:
 
2562
            output += wrapped(default_realkey, '(default) %s' % default_help,
 
2563
                              self.get_info('default'))
2412
2564
        deprecated_pairs = []
 
2565
        experimental_pairs = []
2413
2566
        for key, help in help_pairs:
2414
2567
            info = self.get_info(key)
2415
2568
            if info.hidden:
2416
2569
                continue
2417
2570
            elif info.deprecated:
2418
2571
                deprecated_pairs.append((key, help))
 
2572
            elif info.experimental:
 
2573
                experimental_pairs.append((key, help))
2419
2574
            else:
2420
2575
                output += wrapped(key, help, info)
 
2576
        if len(experimental_pairs) > 0:
 
2577
            output += "Experimental formats are shown below.\n\n"
 
2578
            for key, help in experimental_pairs:
 
2579
                info = self.get_info(key)
 
2580
                output += wrapped(key, help, info)
2421
2581
        if len(deprecated_pairs) > 0:
2422
 
            output += "Deprecated formats\n------------------\n\n"
 
2582
            output += "Deprecated formats are shown below.\n\n"
2423
2583
            for key, help in deprecated_pairs:
2424
2584
                info = self.get_info(key)
2425
2585
                output += wrapped(key, help, info)
2460
2620
    branch_format='bzrlib.branch.BzrBranchFormat6',
2461
2621
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2462
2622
    )
 
2623
format_registry.register_metadir('rich-root',
 
2624
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit4',
 
2625
    help='New in 1.0.  Better handling of tree roots.  Incompatible with'
 
2626
        ' bzr < 1.0',
 
2627
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2628
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2629
    hidden=False,
 
2630
    )
2463
2631
format_registry.register_metadir('dirstate-with-subtree',
2464
2632
    'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
2465
2633
    help='New in 0.15: Fast local operations and improved scaling for '
2469
2637
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2470
2638
    hidden=True,
2471
2639
    )
2472
 
format_registry.set_default('dirstate')
 
2640
format_registry.register_metadir('pack-0.92',
 
2641
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack1',
 
2642
    help='New in 0.92: Pack-based format with data compatible with '
 
2643
        'dirstate-tags format repositories. Interoperates with '
 
2644
        'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
 
2645
        'Previously called knitpack-experimental.  '
 
2646
        'For more information, see '
 
2647
        'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
 
2648
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2649
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2650
    experimental=True,
 
2651
    )
 
2652
format_registry.register_metadir('pack-0.92-subtree',
 
2653
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack3',
 
2654
    help='New in 0.92: Pack-based format with data compatible with '
 
2655
        'dirstate-with-subtree format repositories. Interoperates with '
 
2656
        'bzr repositories before 0.92 but cannot be read by bzr < 0.92. '
 
2657
        'Previously called knitpack-experimental.  '
 
2658
        'For more information, see '
 
2659
        'http://doc.bazaar-vcs.org/latest/developers/packrepo.html.',
 
2660
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2661
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2662
    hidden=True,
 
2663
    experimental=True,
 
2664
    )
 
2665
format_registry.register_metadir('rich-root-pack',
 
2666
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack4',
 
2667
    help='New in 1.0: Pack-based format with data compatible with '
 
2668
        'rich-root format repositories. Incompatible with'
 
2669
        ' bzr < 1.0',
 
2670
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2671
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
2672
    hidden=False,
 
2673
    experimental=True,
 
2674
    )
 
2675
format_registry.set_default('pack-0.92')