~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

 * Hook up the new remote method ``RemoteBzrDir.find_repositoryV2`` so
   that it is now attempted first when lookup up repositories, leading to
   an extra round trip on older bzr smart servers but supporting the
   feature on newer servers. (Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
27
27
 
28
28
# TODO: Move old formats into a plugin to make this file smaller.
29
29
 
 
30
from cStringIO import StringIO
30
31
import os
31
32
import sys
32
33
 
34
35
lazy_import(globals(), """
35
36
from stat import S_ISDIR
36
37
import textwrap
 
38
from warnings import warn
37
39
 
38
40
import bzrlib
39
41
from bzrlib import (
40
 
    config,
41
42
    errors,
42
43
    graph,
43
44
    lockable_files,
44
45
    lockdir,
45
 
    osutils,
 
46
    registry,
46
47
    remote,
47
48
    revision as _mod_revision,
 
49
    symbol_versioning,
48
50
    ui,
49
51
    urlutils,
50
 
    versionedfile,
51
52
    win32utils,
52
53
    workingtree,
53
54
    workingtree_4,
55
56
    xml5,
56
57
    )
57
58
from bzrlib.osutils import (
 
59
    sha_strings,
58
60
    sha_string,
59
61
    )
60
62
from bzrlib.smart.client import _SmartClient
 
63
from bzrlib.smart import protocol
 
64
from bzrlib.store.revision.text import TextRevisionStore
 
65
from bzrlib.store.text import TextStore
61
66
from bzrlib.store.versioned import WeaveStore
62
67
from bzrlib.transactions import WriteTransaction
63
68
from bzrlib.transport import (
64
69
    do_catching_redirections,
65
70
    get_transport,
66
 
    local,
67
71
    )
68
72
from bzrlib.weave import Weave
69
73
""")
72
76
    mutter,
73
77
    note,
74
78
    )
75
 
 
76
 
from bzrlib import (
77
 
    registry,
78
 
    symbol_versioning,
 
79
from bzrlib.transport.local import LocalTransport
 
80
from bzrlib.symbol_versioning import (
 
81
    deprecated_function,
 
82
    deprecated_method,
 
83
    zero_ninetyone,
79
84
    )
80
85
 
81
86
 
85
90
    BzrDir instances let you create or open any of the things that can be
86
91
    found within .bzr - checkouts, branches and repositories.
87
92
    
88
 
    :ivar transport:
 
93
    transport
89
94
        the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
90
 
    :ivar root_transport:
 
95
    root_transport
91
96
        a transport connected to the directory this bzr was opened from
92
97
        (i.e. the parent directory holding the .bzr directory).
93
 
 
94
 
    Everything in the bzrdir should have the same file permissions.
95
98
    """
96
99
 
97
100
    def break_lock(self):
151
154
                format.get_format_description(),
152
155
                basedir)
153
156
 
154
 
    def clone(self, url, revision_id=None, force_new_repo=False,
155
 
              preserve_stacking=False):
 
157
    def clone(self, url, revision_id=None, force_new_repo=False):
156
158
        """Clone this bzrdir and its contents to url verbatim.
157
159
 
158
 
        :param url: The url create the clone at.  If url's last component does
159
 
            not exist, it will be created.
160
 
        :param revision_id: The tip revision-id to use for any branch or
161
 
            working tree.  If not None, then the clone operation may tune
 
160
        If url's last component does not exist, it will be created.
 
161
 
 
162
        if revision_id is not None, then the clone operation may tune
162
163
            itself to download less data.
163
 
        :param force_new_repo: Do not use a shared repository for the target
 
164
        :param force_new_repo: Do not use a shared repository for the target 
164
165
                               even if one is available.
165
 
        :param preserve_stacking: When cloning a stacked branch, stack the
166
 
            new branch on top of the other branch's stacked-on branch.
167
166
        """
168
167
        return self.clone_on_transport(get_transport(url),
169
168
                                       revision_id=revision_id,
170
 
                                       force_new_repo=force_new_repo,
171
 
                                       preserve_stacking=preserve_stacking)
 
169
                                       force_new_repo=force_new_repo)
172
170
 
173
171
    def clone_on_transport(self, transport, revision_id=None,
174
 
                           force_new_repo=False, preserve_stacking=False,
175
 
                           stacked_on=None):
 
172
                           force_new_repo=False):
176
173
        """Clone this bzrdir and its contents to transport verbatim.
177
174
 
178
 
        :param transport: The transport for the location to produce the clone
179
 
            at.  If the target directory does not exist, it will be created.
180
 
        :param revision_id: The tip revision-id to use for any branch or
181
 
            working tree.  If not None, then the clone operation may tune
 
175
        If the target directory does not exist, it will be created.
 
176
 
 
177
        if revision_id is not None, then the clone operation may tune
182
178
            itself to download less data.
183
 
        :param force_new_repo: Do not use a shared repository for the target,
 
179
        :param force_new_repo: Do not use a shared repository for the target 
184
180
                               even if one is available.
185
 
        :param preserve_stacking: When cloning a stacked branch, stack the
186
 
            new branch on top of the other branch's stacked-on branch.
187
181
        """
188
182
        transport.ensure_base()
189
 
        require_stacking = (stacked_on is not None)
190
 
        metadir = self.cloning_metadir(require_stacking)
191
 
        result = metadir.initialize_on_transport(transport)
192
 
        repository_policy = None
 
183
        result = self._format.initialize_on_transport(transport)
193
184
        try:
194
185
            local_repo = self.find_repository()
195
186
        except errors.NoRepositoryPresent:
196
187
            local_repo = None
197
 
        try:
198
 
            local_branch = self.open_branch()
199
 
        except errors.NotBranchError:
200
 
            local_branch = None
201
 
        else:
202
 
            # enable fallbacks when branch is not a branch reference
203
 
            if local_branch.repository.has_same_location(local_repo):
204
 
                local_repo = local_branch.repository
205
 
            if preserve_stacking:
206
 
                try:
207
 
                    stacked_on = local_branch.get_stacked_on_url()
208
 
                except (errors.UnstackableBranchFormat,
209
 
                        errors.UnstackableRepositoryFormat,
210
 
                        errors.NotStacked):
211
 
                    pass
212
 
 
213
188
        if local_repo:
214
189
            # may need to copy content in
215
 
            repository_policy = result.determine_repository_policy(
216
 
                force_new_repo, stacked_on, self.root_transport.base,
217
 
                require_stacking=require_stacking)
218
 
            make_working_trees = local_repo.make_working_trees()
219
 
            result_repo = repository_policy.acquire_repository(
220
 
                make_working_trees, local_repo.is_shared())
221
 
            result_repo.fetch(local_repo, revision_id=revision_id)
222
 
        else:
223
 
            result_repo = None
 
190
            if force_new_repo:
 
191
                result_repo = local_repo.clone(
 
192
                    result,
 
193
                    revision_id=revision_id)
 
194
                result_repo.set_make_working_trees(local_repo.make_working_trees())
 
195
            else:
 
196
                try:
 
197
                    result_repo = result.find_repository()
 
198
                    # fetch content this dir needs.
 
199
                    result_repo.fetch(local_repo, revision_id=revision_id)
 
200
                except errors.NoRepositoryPresent:
 
201
                    # needed to make one anyway.
 
202
                    result_repo = local_repo.clone(
 
203
                        result,
 
204
                        revision_id=revision_id)
 
205
                    result_repo.set_make_working_trees(local_repo.make_working_trees())
224
206
        # 1 if there is a branch present
225
207
        #   make sure its content is available in the target repository
226
208
        #   clone it.
227
 
        if local_branch is not None:
228
 
            result_branch = local_branch.clone(result, revision_id=revision_id)
229
 
            if repository_policy is not None:
230
 
                repository_policy.configure_branch(result_branch)
 
209
        try:
 
210
            self.open_branch().clone(result, revision_id=revision_id)
 
211
        except errors.NotBranchError:
 
212
            pass
 
213
        try:
 
214
            result_repo = result.find_repository()
 
215
        except errors.NoRepositoryPresent:
 
216
            result_repo = None
231
217
        if result_repo is None or result_repo.make_working_trees():
232
218
            try:
233
219
                self.open_workingtree().clone(result)
332
318
                branches.append(branch)
333
319
        return branches
334
320
 
 
321
 
335
322
    def destroy_repository(self):
336
323
        """Destroy the repository in this BzrDir"""
337
324
        raise NotImplementedError(self.destroy_repository)
369
356
        bzrdir._find_or_create_repository(force_new_repo)
370
357
        return bzrdir.create_branch()
371
358
 
372
 
    def determine_repository_policy(self, force_new_repo=False, stack_on=None,
373
 
                                    stack_on_pwd=None, require_stacking=False):
374
 
        """Return an object representing a policy to use.
375
 
 
376
 
        This controls whether a new repository is created, or a shared
377
 
        repository used instead.
378
 
 
379
 
        If stack_on is supplied, will not seek a containing shared repo.
380
 
 
381
 
        :param force_new_repo: If True, require a new repository to be created.
382
 
        :param stack_on: If supplied, the location to stack on.  If not
383
 
            supplied, a default_stack_on location may be used.
384
 
        :param stack_on_pwd: If stack_on is relative, the location it is
385
 
            relative to.
386
 
        """
387
 
        def repository_policy(found_bzrdir):
388
 
            stack_on = None
389
 
            stack_on_pwd = None
390
 
            config = found_bzrdir.get_config()
391
 
            stop = False
392
 
            if config is not None:
393
 
                stack_on = config.get_default_stack_on()
394
 
                if stack_on is not None:
395
 
                    stack_on_pwd = found_bzrdir.root_transport.base
396
 
                    stop = True
397
 
                    note('Using default stacking branch %s at %s', stack_on,
398
 
                         stack_on_pwd)
399
 
            # does it have a repository ?
400
 
            try:
401
 
                repository = found_bzrdir.open_repository()
402
 
            except errors.NoRepositoryPresent:
403
 
                repository = None
404
 
            else:
405
 
                if ((found_bzrdir.root_transport.base !=
406
 
                     self.root_transport.base) and not repository.is_shared()):
407
 
                    repository = None
408
 
                else:
409
 
                    stop = True
410
 
            if not stop:
411
 
                return None, False
412
 
            if repository:
413
 
                return UseExistingRepository(repository, stack_on,
414
 
                    stack_on_pwd, require_stacking=require_stacking), True
415
 
            else:
416
 
                return CreateRepository(self, stack_on, stack_on_pwd,
417
 
                    require_stacking=require_stacking), True
418
 
 
419
 
        if not force_new_repo:
420
 
            if stack_on is None:
421
 
                policy = self._find_containing(repository_policy)
422
 
                if policy is not None:
423
 
                    return policy
424
 
            else:
425
 
                try:
426
 
                    return UseExistingRepository(self.open_repository(),
427
 
                        stack_on, stack_on_pwd,
428
 
                        require_stacking=require_stacking)
429
 
                except errors.NoRepositoryPresent:
430
 
                    pass
431
 
        return CreateRepository(self, stack_on, stack_on_pwd,
432
 
                                require_stacking=require_stacking)
433
 
 
434
359
    def _find_or_create_repository(self, force_new_repo):
435
360
        """Create a new repository if needed, returning the repository."""
436
 
        policy = self.determine_repository_policy(force_new_repo)
437
 
        return policy.acquire_repository()
438
 
 
 
361
        if force_new_repo:
 
362
            return self.create_repository()
 
363
        try:
 
364
            return self.find_repository()
 
365
        except errors.NoRepositoryPresent:
 
366
            return self.create_repository()
 
367
        
439
368
    @staticmethod
440
369
    def create_branch_convenience(base, force_new_repo=False,
441
370
                                  force_new_tree=None, format=None,
468
397
        if force_new_tree:
469
398
            # check for non local urls
470
399
            t = get_transport(base, possible_transports)
471
 
            if not isinstance(t, local.LocalTransport):
 
400
            if not isinstance(t, LocalTransport):
472
401
                raise errors.NotLocalUrl(base)
473
402
        bzrdir = BzrDir.create(base, format, possible_transports)
474
403
        repo = bzrdir._find_or_create_repository(force_new_repo)
482
411
        return result
483
412
 
484
413
    @staticmethod
 
414
    @deprecated_function(zero_ninetyone)
 
415
    def create_repository(base, shared=False, format=None):
 
416
        """Create a new BzrDir and Repository at the url 'base'.
 
417
 
 
418
        If no format is supplied, this will default to the current default
 
419
        BzrDirFormat by default, and use whatever repository format that that
 
420
        uses for bzrdirformat.create_repository.
 
421
 
 
422
        :param shared: Create a shared repository rather than a standalone
 
423
                       repository.
 
424
        The Repository object is returned.
 
425
 
 
426
        This must be overridden as an instance method in child classes, where
 
427
        it should take no parameters and construct whatever repository format
 
428
        that child class desires.
 
429
 
 
430
        This method is deprecated, please call create_repository on a bzrdir
 
431
        instance instead.
 
432
        """
 
433
        bzrdir = BzrDir.create(base, format)
 
434
        return bzrdir.create_repository(shared)
 
435
 
 
436
    @staticmethod
485
437
    def create_standalone_workingtree(base, format=None):
486
438
        """Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
487
439
 
496
448
        :return: The WorkingTree object.
497
449
        """
498
450
        t = get_transport(base)
499
 
        if not isinstance(t, local.LocalTransport):
 
451
        if not isinstance(t, LocalTransport):
500
452
            raise errors.NotLocalUrl(base)
501
453
        bzrdir = BzrDir.create_branch_and_repo(base,
502
454
                                               force_new_repo=True,
504
456
        return bzrdir.create_workingtree()
505
457
 
506
458
    def create_workingtree(self, revision_id=None, from_branch=None,
507
 
        accelerator_tree=None, hardlink=False):
 
459
        accelerator_tree=None):
508
460
        """Create a working tree at this BzrDir.
509
461
        
510
462
        :param revision_id: create it as of this revision id.
556
508
        """
557
509
        raise NotImplementedError(self.destroy_workingtree_metadata)
558
510
 
559
 
    def _find_containing(self, evaluate):
560
 
        """Find something in a containing control directory.
561
 
 
562
 
        This method will scan containing control dirs, until it finds what
563
 
        it is looking for, decides that it will never find it, or runs out
564
 
        of containing control directories to check.
565
 
 
566
 
        It is used to implement find_repository and
567
 
        determine_repository_policy.
568
 
 
569
 
        :param evaluate: A function returning (value, stop).  If stop is True,
570
 
            the value will be returned.
571
 
        """
572
 
        found_bzrdir = self
573
 
        while True:
574
 
            result, stop = evaluate(found_bzrdir)
575
 
            if stop:
576
 
                return result
577
 
            next_transport = found_bzrdir.root_transport.clone('..')
578
 
            if (found_bzrdir.root_transport.base == next_transport.base):
579
 
                # top of the file system
580
 
                return None
581
 
            # find the next containing bzrdir
582
 
            try:
583
 
                found_bzrdir = BzrDir.open_containing_from_transport(
584
 
                    next_transport)[0]
585
 
            except errors.NotBranchError:
586
 
                return None
587
 
 
588
511
    def find_repository(self):
589
512
        """Find the repository that should be used.
590
513
 
592
515
        new branches as well as to hook existing branches up to their
593
516
        repository.
594
517
        """
595
 
        def usable_repository(found_bzrdir):
 
518
        try:
 
519
            return self.open_repository()
 
520
        except errors.NoRepositoryPresent:
 
521
            pass
 
522
        next_transport = self.root_transport.clone('..')
 
523
        while True:
 
524
            # find the next containing bzrdir
 
525
            try:
 
526
                found_bzrdir = BzrDir.open_containing_from_transport(
 
527
                    next_transport)[0]
 
528
            except errors.NotBranchError:
 
529
                # none found
 
530
                raise errors.NoRepositoryPresent(self)
596
531
            # does it have a repository ?
597
532
            try:
598
533
                repository = found_bzrdir.open_repository()
599
534
            except errors.NoRepositoryPresent:
600
 
                return None, False
601
 
            if found_bzrdir.root_transport.base == self.root_transport.base:
602
 
                return repository, True
603
 
            elif repository.is_shared():
604
 
                return repository, True
 
535
                next_transport = found_bzrdir.root_transport.clone('..')
 
536
                if (found_bzrdir.root_transport.base == next_transport.base):
 
537
                    # top of the file system
 
538
                    break
 
539
                else:
 
540
                    continue
 
541
            if ((found_bzrdir.root_transport.base ==
 
542
                 self.root_transport.base) or repository.is_shared()):
 
543
                return repository
605
544
            else:
606
 
                return None, True
607
 
 
608
 
        found_repo = self._find_containing(usable_repository)
609
 
        if found_repo is None:
610
 
            raise errors.NoRepositoryPresent(self)
611
 
        return found_repo
 
545
                raise errors.NoRepositoryPresent(self)
 
546
        raise errors.NoRepositoryPresent(self)
612
547
 
613
548
    def get_branch_reference(self):
614
549
        """Return the referenced URL for the branch in this bzrdir.
631
566
        guaranteed to point to an existing directory ready for use.
632
567
        """
633
568
        raise NotImplementedError(self.get_branch_transport)
634
 
 
635
 
    def _find_creation_modes(self):
636
 
        """Determine the appropriate modes for files and directories.
637
 
 
638
 
        They're always set to be consistent with the base directory,
639
 
        assuming that this transport allows setting modes.
640
 
        """
641
 
        # TODO: Do we need or want an option (maybe a config setting) to turn
642
 
        # this off or override it for particular locations? -- mbp 20080512
643
 
        if self._mode_check_done:
644
 
            return
645
 
        self._mode_check_done = True
646
 
        try:
647
 
            st = self.transport.stat('.')
648
 
        except errors.TransportNotPossible:
649
 
            self._dir_mode = None
650
 
            self._file_mode = None
651
 
        else:
652
 
            # Check the directory mode, but also make sure the created
653
 
            # directories and files are read-write for this user. This is
654
 
            # mostly a workaround for filesystems which lie about being able to
655
 
            # write to a directory (cygwin & win32)
656
 
            if (st.st_mode & 07777 == 00000):
657
 
                # FTP allows stat but does not return dir/file modes
658
 
                self._dir_mode = None
659
 
                self._file_mode = None
660
 
            else:
661
 
                self._dir_mode = (st.st_mode & 07777) | 00700
662
 
                # Remove the sticky and execute bits for files
663
 
                self._file_mode = self._dir_mode & ~07111
664
 
 
665
 
    def _get_file_mode(self):
666
 
        """Return Unix mode for newly created files, or None.
667
 
        """
668
 
        if not self._mode_check_done:
669
 
            self._find_creation_modes()
670
 
        return self._file_mode
671
 
 
672
 
    def _get_dir_mode(self):
673
 
        """Return Unix mode for newly created directories, or None.
674
 
        """
675
 
        if not self._mode_check_done:
676
 
            self._find_creation_modes()
677
 
        return self._dir_mode
678
569
        
679
570
    def get_repository_transport(self, repository_format):
680
571
        """Get the transport for use by repository format in this BzrDir.
701
592
        guaranteed to point to an existing directory ready for use.
702
593
        """
703
594
        raise NotImplementedError(self.get_workingtree_transport)
704
 
 
705
 
    def get_config(self):
706
 
        if getattr(self, '_get_config', None) is None:
707
 
            return None
708
 
        return self._get_config()
709
 
 
 
595
        
710
596
    def __init__(self, _transport, _format):
711
597
        """Initialize a Bzr control dir object.
712
598
        
719
605
        self._format = _format
720
606
        self.transport = _transport.clone('.bzr')
721
607
        self.root_transport = _transport
722
 
        self._mode_check_done = False
723
608
 
724
609
    def is_control_filename(self, filename):
725
610
        """True if filename is the name of a path which is reserved for bzrdir's.
902
787
        tree, branch = bzrdir._get_tree_branch()
903
788
        return tree, branch, relpath
904
789
 
905
 
    @classmethod
906
 
    def open_containing_tree_branch_or_repository(klass, location):
907
 
        """Return the working tree, branch and repo contained by a location.
908
 
 
909
 
        Returns (tree, branch, repository, relpath).
910
 
        If there is no tree containing the location, tree will be None.
911
 
        If there is no branch containing the location, branch will be None.
912
 
        If there is no repository containing the location, repository will be
913
 
        None.
914
 
        relpath is the portion of the path that is contained by the innermost
915
 
        BzrDir.
916
 
 
917
 
        If no tree, branch or repository is found, a NotBranchError is raised.
918
 
        """
919
 
        bzrdir, relpath = klass.open_containing(location)
920
 
        try:
921
 
            tree, branch = bzrdir._get_tree_branch()
922
 
        except errors.NotBranchError:
923
 
            try:
924
 
                repo = bzrdir.find_repository()
925
 
                return None, None, repo, relpath
926
 
            except (errors.NoRepositoryPresent):
927
 
                raise errors.NotBranchError(location)
928
 
        return tree, branch, branch.repository, relpath
929
 
 
930
790
    def open_repository(self, _unsupported=False):
931
791
        """Open the repository object at this BzrDir if one is present.
932
792
 
981
841
            return False
982
842
 
983
843
    def _cloning_metadir(self):
984
 
        """Produce a metadir suitable for cloning with.
985
 
        
986
 
        :returns: (destination_bzrdir_format, source_repository)
987
 
        """
 
844
        """Produce a metadir suitable for cloning with."""
988
845
        result_format = self._format.__class__()
989
846
        try:
990
847
            try:
991
848
                branch = self.open_branch()
992
849
                source_repository = branch.repository
993
 
                result_format._branch_format = branch._format
994
850
            except errors.NotBranchError:
995
851
                source_branch = None
996
852
                source_repository = self.open_repository()
1001
857
            # the fix recommended in bug # 103195 - to delegate this choice the
1002
858
            # repository itself.
1003
859
            repo_format = source_repository._format
1004
 
            if isinstance(repo_format, remote.RemoteRepositoryFormat):
1005
 
                source_repository._ensure_real()
1006
 
                repo_format = source_repository._real_repository._format
1007
 
            result_format.repository_format = repo_format
 
860
            if not isinstance(repo_format, remote.RemoteRepositoryFormat):
 
861
                result_format.repository_format = repo_format
1008
862
        try:
1009
863
            # TODO: Couldn't we just probe for the format in these cases,
1010
864
            # rather than opening the whole tree?  It would be a little
1016
870
            result_format.workingtree_format = tree._format.__class__()
1017
871
        return result_format, source_repository
1018
872
 
1019
 
    def cloning_metadir(self, require_stacking=False):
 
873
    def cloning_metadir(self):
1020
874
        """Produce a metadir suitable for cloning or sprouting with.
1021
875
 
1022
876
        These operations may produce workingtrees (yes, even though they're
1023
877
        "cloning" something that doesn't have a tree), so a viable workingtree
1024
878
        format must be selected.
1025
 
 
1026
 
        :require_stacking: If True, non-stackable formats will be upgraded
1027
 
            to similar stackable formats.
1028
 
        :returns: a BzrDirFormat with all component formats either set
1029
 
            appropriately or set to None if that component should not be
1030
 
            created.
1031
879
        """
1032
880
        format, repository = self._cloning_metadir()
1033
881
        if format._workingtree_format is None:
1035
883
                return format
1036
884
            tree_format = repository._format._matchingbzrdir.workingtree_format
1037
885
            format.workingtree_format = tree_format.__class__()
1038
 
        if (require_stacking and not
1039
 
            format.get_branch_format().supports_stacking()):
1040
 
            # We need to make a stacked branch, but the default format for the
1041
 
            # target doesn't support stacking.  So force a branch that *can*
1042
 
            # support stacking.
1043
 
            from bzrlib.branch import BzrBranchFormat7
1044
 
            format._branch_format = BzrBranchFormat7()
1045
 
            mutter("using %r for stacking" % (format._branch_format,))
1046
 
            from bzrlib.repofmt import pack_repo
1047
 
            if format.repository_format.rich_root_data:
1048
 
                bzrdir_format_name = '1.6.1-rich-root'
1049
 
                repo_format = pack_repo.RepositoryFormatKnitPack5RichRoot()
1050
 
            else:
1051
 
                bzrdir_format_name = '1.6'
1052
 
                repo_format = pack_repo.RepositoryFormatKnitPack5()
1053
 
            note('Source format does not support stacking, using format:'
1054
 
                 ' \'%s\'\n  %s\n',
1055
 
                 bzrdir_format_name, repo_format.get_format_description())
1056
 
            format.repository_format = repo_format
1057
886
        return format
1058
887
 
1059
888
    def checkout_metadir(self):
1061
890
 
1062
891
    def sprout(self, url, revision_id=None, force_new_repo=False,
1063
892
               recurse='down', possible_transports=None,
1064
 
               accelerator_tree=None, hardlink=False, stacked=False):
 
893
               accelerator_tree=None):
1065
894
        """Create a copy of this bzrdir prepared for use as a new line of
1066
895
        development.
1067
896
 
1078
907
            contents more quickly than the revision tree, i.e. a workingtree.
1079
908
            The revision tree will be used for cases where accelerator_tree's
1080
909
            content is different.
1081
 
        :param hardlink: If true, hard-link files from accelerator_tree,
1082
 
            where possible.
1083
 
        :param stacked: If true, create a stacked branch referring to the
1084
 
            location of this control directory.
1085
910
        """
1086
911
        target_transport = get_transport(url, possible_transports)
1087
912
        target_transport.ensure_base()
1088
 
        cloning_format = self.cloning_metadir(stacked)
1089
 
        # Create/update the result branch
 
913
        cloning_format = self.cloning_metadir()
1090
914
        result = cloning_format.initialize_on_transport(target_transport)
1091
915
        try:
1092
916
            source_branch = self.open_branch()
1093
917
            source_repository = source_branch.repository
1094
 
            if stacked:
1095
 
                stacked_branch_url = self.root_transport.base
1096
 
            else:
1097
 
                # if a stacked branch wasn't requested, we don't create one
1098
 
                # even if the origin was stacked
1099
 
                stacked_branch_url = None
1100
918
        except errors.NotBranchError:
1101
919
            source_branch = None
1102
920
            try:
1103
921
                source_repository = self.open_repository()
1104
922
            except errors.NoRepositoryPresent:
1105
923
                source_repository = None
1106
 
            stacked_branch_url = None
1107
 
        repository_policy = result.determine_repository_policy(
1108
 
            force_new_repo, stacked_branch_url, require_stacking=stacked)
1109
 
        result_repo = repository_policy.acquire_repository()
1110
 
        if source_repository is not None:
1111
 
            # Fetch while stacked to prevent unstacked fetch from
1112
 
            # Branch.sprout.
1113
 
            result_repo.fetch(source_repository, revision_id=revision_id)
1114
 
 
1115
 
        if source_branch is None:
1116
 
            # this is for sprouting a bzrdir without a branch; is that
1117
 
            # actually useful?
1118
 
            # Not especially, but it's part of the contract.
1119
 
            result_branch = result.create_branch()
1120
 
        else:
1121
 
            # Force NULL revision to avoid using repository before stacking
1122
 
            # is configured.
1123
 
            result_branch = source_branch.sprout(
1124
 
                result, revision_id=_mod_revision.NULL_REVISION)
1125
 
            parent_location = result_branch.get_parent()
1126
 
        mutter("created new branch %r" % (result_branch,))
1127
 
        repository_policy.configure_branch(result_branch)
 
924
        if force_new_repo:
 
925
            result_repo = None
 
926
        else:
 
927
            try:
 
928
                result_repo = result.find_repository()
 
929
            except errors.NoRepositoryPresent:
 
930
                result_repo = None
 
931
        if source_repository is None and result_repo is not None:
 
932
            pass
 
933
        elif source_repository is None and result_repo is None:
 
934
            # no repo available, make a new one
 
935
            result.create_repository()
 
936
        elif source_repository is not None and result_repo is None:
 
937
            # have source, and want to make a new target repo
 
938
            result_repo = source_repository.sprout(result,
 
939
                                                   revision_id=revision_id)
 
940
        else:
 
941
            # fetch needed content into target.
 
942
            if source_repository is not None:
 
943
                # would rather do 
 
944
                # source_repository.copy_content_into(result_repo,
 
945
                #                                     revision_id=revision_id)
 
946
                # so we can override the copy method
 
947
                result_repo.fetch(source_repository, revision_id=revision_id)
1128
948
        if source_branch is not None:
1129
 
            source_branch.copy_content_into(result_branch, revision_id)
1130
 
            # Override copy_content_into
1131
 
            result_branch.set_parent(parent_location)
1132
 
 
1133
 
        # Create/update the result working tree
1134
 
        if isinstance(target_transport, local.LocalTransport) and (
 
949
            source_branch.sprout(result, revision_id=revision_id)
 
950
        else:
 
951
            result.create_branch()
 
952
        if isinstance(target_transport, LocalTransport) and (
1135
953
            result_repo is None or result_repo.make_working_trees()):
1136
 
            wt = result.create_workingtree(accelerator_tree=accelerator_tree,
1137
 
                hardlink=hardlink)
 
954
            wt = result.create_workingtree(accelerator_tree=accelerator_tree)
1138
955
            wt.lock_write()
1139
956
            try:
1140
957
                if wt.path2id('') is None:
1151
968
                basis = wt.basis_tree()
1152
969
                basis.lock_read()
1153
970
                subtrees = basis.iter_references()
1154
 
            elif result_branch is not None:
1155
 
                basis = result_branch.basis_tree()
1156
 
                basis.lock_read()
1157
 
                subtrees = basis.iter_references()
 
971
                recurse_branch = wt.branch
1158
972
            elif source_branch is not None:
1159
973
                basis = source_branch.basis_tree()
1160
974
                basis.lock_read()
1161
975
                subtrees = basis.iter_references()
 
976
                recurse_branch = source_branch
1162
977
            else:
1163
978
                subtrees = []
1164
979
                basis = None
1168
983
                    sublocation = source_branch.reference_parent(file_id, path)
1169
984
                    sublocation.bzrdir.sprout(target,
1170
985
                        basis.get_reference_revision(file_id, path),
1171
 
                        force_new_repo=force_new_repo, recurse=recurse,
1172
 
                        stacked=stacked)
 
986
                        force_new_repo=force_new_repo, recurse=recurse)
1173
987
            finally:
1174
988
                if basis is not None:
1175
989
                    basis.unlock()
1182
996
    def __init__(self, _transport, _format):
1183
997
        """See BzrDir.__init__."""
1184
998
        super(BzrDirPreSplitOut, self).__init__(_transport, _format)
 
999
        assert self._format._lock_class == lockable_files.TransportLock
 
1000
        assert self._format._lock_file_name == 'branch-lock'
1185
1001
        self._control_files = lockable_files.LockableFiles(
1186
1002
                                            self.get_branch_transport(None),
1187
1003
                                            self._format._lock_file_name,
1191
1007
        """Pre-splitout bzrdirs do not suffer from stale locks."""
1192
1008
        raise NotImplementedError(self.break_lock)
1193
1009
 
1194
 
    def cloning_metadir(self, require_stacking=False):
1195
 
        """Produce a metadir suitable for cloning with."""
1196
 
        if require_stacking:
1197
 
            return format_registry.make_bzrdir('1.6')
1198
 
        return self._format.__class__()
1199
 
 
1200
 
    def clone(self, url, revision_id=None, force_new_repo=False,
1201
 
              preserve_stacking=False):
1202
 
        """See BzrDir.clone().
1203
 
 
1204
 
        force_new_repo has no effect, since this family of formats always
1205
 
        require a new repository.
1206
 
        preserve_stacking has no effect, since no source branch using this
1207
 
        family of formats can be stacked, so there is no stacking to preserve.
1208
 
        """
 
1010
    def clone(self, url, revision_id=None, force_new_repo=False):
 
1011
        """See BzrDir.clone()."""
 
1012
        from bzrlib.workingtree import WorkingTreeFormat2
1209
1013
        self._make_tail(url)
1210
1014
        result = self._format._initialize_for_clone(url)
1211
1015
        self.open_repository().clone(result, revision_id=revision_id)
1212
1016
        from_branch = self.open_branch()
1213
1017
        from_branch.clone(result, revision_id=revision_id)
1214
1018
        try:
1215
 
            tree = self.open_workingtree()
 
1019
            self.open_workingtree().clone(result)
1216
1020
        except errors.NotLocalUrl:
1217
1021
            # make a new one, this format always has to have one.
1218
 
            result._init_workingtree()
1219
 
        else:
1220
 
            tree.clone(result)
 
1022
            try:
 
1023
                WorkingTreeFormat2().initialize(result)
 
1024
            except errors.NotLocalUrl:
 
1025
                # but we cannot do it for remote trees.
 
1026
                to_branch = result.open_branch()
 
1027
                WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
1221
1028
        return result
1222
1029
 
1223
1030
    def create_branch(self):
1224
1031
        """See BzrDir.create_branch."""
1225
 
        return self._format.get_branch_format().initialize(self)
 
1032
        return self.open_branch()
1226
1033
 
1227
1034
    def destroy_branch(self):
1228
1035
        """See BzrDir.destroy_branch."""
1239
1046
        raise errors.UnsupportedOperation(self.destroy_repository, self)
1240
1047
 
1241
1048
    def create_workingtree(self, revision_id=None, from_branch=None,
1242
 
                           accelerator_tree=None, hardlink=False):
 
1049
                           accelerator_tree=None):
1243
1050
        """See BzrDir.create_workingtree."""
1244
 
        # The workingtree is sometimes created when the bzrdir is created,
1245
 
        # but not when cloning.
1246
 
 
1247
1051
        # this looks buggy but is not -really-
1248
1052
        # because this format creates the workingtree when the bzrdir is
1249
1053
        # created
1253
1057
        # that can do wonky stuff here, and that only
1254
1058
        # happens for creating checkouts, which cannot be 
1255
1059
        # done on this format anyway. So - acceptable wart.
1256
 
        try:
1257
 
            result = self.open_workingtree(recommend_upgrade=False)
1258
 
        except errors.NoSuchFile:
1259
 
            result = self._init_workingtree()
 
1060
        result = self.open_workingtree(recommend_upgrade=False)
1260
1061
        if revision_id is not None:
1261
1062
            if revision_id == _mod_revision.NULL_REVISION:
1262
1063
                result.set_parent_ids([])
1264
1065
                result.set_parent_ids([revision_id])
1265
1066
        return result
1266
1067
 
1267
 
    def _init_workingtree(self):
1268
 
        from bzrlib.workingtree import WorkingTreeFormat2
1269
 
        try:
1270
 
            return WorkingTreeFormat2().initialize(self)
1271
 
        except errors.NotLocalUrl:
1272
 
            # Even though we can't access the working tree, we need to
1273
 
            # create its control files.
1274
 
            return WorkingTreeFormat2()._stub_initialize_on_transport(
1275
 
                self.transport, self._control_files._file_mode)
1276
 
 
1277
1068
    def destroy_workingtree(self):
1278
1069
        """See BzrDir.destroy_workingtree."""
1279
1070
        raise errors.UnsupportedOperation(self.destroy_workingtree, self)
1329
1120
        return format.open(self, _found=True)
1330
1121
 
1331
1122
    def sprout(self, url, revision_id=None, force_new_repo=False,
1332
 
               possible_transports=None, accelerator_tree=None,
1333
 
               hardlink=False, stacked=False):
 
1123
               possible_transports=None, accelerator_tree=None):
1334
1124
        """See BzrDir.sprout()."""
1335
 
        if stacked:
1336
 
            raise errors.UnstackableBranchFormat(
1337
 
                self._format, self.root_transport.base)
1338
1125
        from bzrlib.workingtree import WorkingTreeFormat2
1339
1126
        self._make_tail(url)
1340
1127
        result = self._format._initialize_for_clone(url)
1348
1135
            pass
1349
1136
        # we always want a working tree
1350
1137
        WorkingTreeFormat2().initialize(result,
1351
 
                                        accelerator_tree=accelerator_tree,
1352
 
                                        hardlink=hardlink)
 
1138
                                        accelerator_tree=accelerator_tree)
1353
1139
        return result
1354
1140
 
1355
1141
 
1444
1230
        self.transport.delete_tree('repository')
1445
1231
 
1446
1232
    def create_workingtree(self, revision_id=None, from_branch=None,
1447
 
                           accelerator_tree=None, hardlink=False):
 
1233
                           accelerator_tree=None):
1448
1234
        """See BzrDir.create_workingtree."""
1449
1235
        return self._format.workingtree_format.initialize(
1450
1236
            self, revision_id, from_branch=from_branch,
1451
 
            accelerator_tree=accelerator_tree, hardlink=hardlink)
 
1237
            accelerator_tree=accelerator_tree)
1452
1238
 
1453
1239
    def destroy_workingtree(self):
1454
1240
        """See BzrDir.destroy_workingtree."""
1578
1364
            basedir=self.root_transport.base)
1579
1365
        return format.open(self, _found=True)
1580
1366
 
1581
 
    def _get_config(self):
1582
 
        return config.BzrDirConfig(self.transport)
1583
 
 
1584
1367
 
1585
1368
class BzrDirFormat(object):
1586
1369
    """An encapsulation of the initialization and open routines for a format.
1648
1431
        try:
1649
1432
            return klass._formats[format_string]
1650
1433
        except KeyError:
1651
 
            raise errors.UnknownFormatError(format=format_string, kind='bzrdir')
 
1434
            raise errors.UnknownFormatError(format=format_string)
1652
1435
 
1653
1436
    @classmethod
1654
1437
    def get_default_format(klass):
1696
1479
                                      # FIXME: RBC 20060121 don't peek under
1697
1480
                                      # the covers
1698
1481
                                      mode=temp_control._dir_mode)
1699
 
        if sys.platform == 'win32' and isinstance(transport, local.LocalTransport):
 
1482
        if sys.platform == 'win32' and isinstance(transport, LocalTransport):
1700
1483
            win32utils.set_file_attr_hidden(transport._abspath('.bzr'))
1701
1484
        file_mode = temp_control._file_mode
1702
1485
        del temp_control
1703
 
        bzrdir_transport = transport.clone('.bzr')
1704
 
        utf8_files = [('README',
1705
 
                       "This is a Bazaar control directory.\n"
1706
 
                       "Do not change any files in this directory.\n"
1707
 
                       "See http://bazaar-vcs.org/ for more information about Bazaar.\n"),
 
1486
        mutter('created control directory in ' + transport.base)
 
1487
        control = transport.clone('.bzr')
 
1488
        utf8_files = [('README', 
 
1489
                       "This is a Bazaar-NG control directory.\n"
 
1490
                       "Do not change any files in this directory.\n"),
1708
1491
                      ('branch-format', self.get_format_string()),
1709
1492
                      ]
1710
1493
        # NB: no need to escape relative paths that are url safe.
1711
 
        control_files = lockable_files.LockableFiles(bzrdir_transport,
1712
 
            self._lock_file_name, self._lock_class)
 
1494
        control_files = lockable_files.LockableFiles(control,
 
1495
                            self._lock_file_name, self._lock_class)
1713
1496
        control_files.create_lock()
1714
1497
        control_files.lock_write()
1715
1498
        try:
1716
 
            for (filename, content) in utf8_files:
1717
 
                bzrdir_transport.put_bytes(filename, content,
1718
 
                    mode=file_mode)
 
1499
            for file, content in utf8_files:
 
1500
                control_files.put_utf8(file, content)
1719
1501
        finally:
1720
1502
            control_files.unlock()
1721
1503
        return self.open(transport, _found=True)
1800
1582
        klass._control_server_formats.append(format)
1801
1583
 
1802
1584
    @classmethod
 
1585
    @symbol_versioning.deprecated_method(symbol_versioning.zero_fourteen)
 
1586
    def set_default_format(klass, format):
 
1587
        klass._set_default_format(format)
 
1588
 
 
1589
    @classmethod
1803
1590
    def _set_default_format(klass, format):
1804
1591
        """Set default format (for testing behavior of defaults only)"""
1805
1592
        klass._default_format = format
1810
1597
 
1811
1598
    @classmethod
1812
1599
    def unregister_format(klass, format):
 
1600
        assert klass._formats[format.get_format_string()] is format
1813
1601
        del klass._formats[format.get_format_string()]
1814
1602
 
1815
1603
    @classmethod
1886
1674
        """See BzrDirFormat.get_format_string()."""
1887
1675
        return "Bazaar-NG branch, format 5\n"
1888
1676
 
1889
 
    def get_branch_format(self):
1890
 
        from bzrlib import branch
1891
 
        return branch.BzrBranchFormat4()
1892
 
 
1893
1677
    def get_format_description(self):
1894
1678
        """See BzrDirFormat.get_format_description()."""
1895
1679
        return "All-in-one format 5"
1909
1693
        """
1910
1694
        from bzrlib.branch import BzrBranchFormat4
1911
1695
        from bzrlib.repofmt.weaverepo import RepositoryFormat5
 
1696
        from bzrlib.workingtree import WorkingTreeFormat2
1912
1697
        result = (super(BzrDirFormat5, self).initialize_on_transport(transport))
1913
1698
        RepositoryFormat5().initialize(result, _internal=True)
1914
1699
        if not _cloning:
1915
1700
            branch = BzrBranchFormat4().initialize(result)
1916
 
            result._init_workingtree()
 
1701
            try:
 
1702
                WorkingTreeFormat2().initialize(result)
 
1703
            except errors.NotLocalUrl:
 
1704
                # Even though we can't access the working tree, we need to
 
1705
                # create its control files.
 
1706
                WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1917
1707
        return result
1918
1708
 
1919
1709
    def _open(self, transport):
1947
1737
        """See BzrDirFormat.get_format_description()."""
1948
1738
        return "All-in-one format 6"
1949
1739
 
1950
 
    def get_branch_format(self):
1951
 
        from bzrlib import branch
1952
 
        return branch.BzrBranchFormat4()
1953
 
 
1954
1740
    def get_converter(self, format=None):
1955
1741
        """See BzrDirFormat.get_converter()."""
1956
1742
        # there is one and only one upgrade path here.
1966
1752
        """
1967
1753
        from bzrlib.branch import BzrBranchFormat4
1968
1754
        from bzrlib.repofmt.weaverepo import RepositoryFormat6
 
1755
        from bzrlib.workingtree import WorkingTreeFormat2
1969
1756
        result = super(BzrDirFormat6, self).initialize_on_transport(transport)
1970
1757
        RepositoryFormat6().initialize(result, _internal=True)
1971
1758
        if not _cloning:
1972
1759
            branch = BzrBranchFormat4().initialize(result)
1973
 
            result._init_workingtree()
 
1760
            try:
 
1761
                WorkingTreeFormat2().initialize(result)
 
1762
            except errors.NotLocalUrl:
 
1763
                # Even though we can't access the working tree, we need to
 
1764
                # create its control files.
 
1765
                WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
1974
1766
        return result
1975
1767
 
1976
1768
    def _open(self, transport):
2112
1904
        self.bzrdir = to_convert
2113
1905
        self.pb = pb
2114
1906
        self.pb.note('starting upgrade from format 4 to 5')
2115
 
        if isinstance(self.bzrdir.transport, local.LocalTransport):
 
1907
        if isinstance(self.bzrdir.transport, LocalTransport):
2116
1908
            self.bzrdir.get_workingtree_transport(None).delete('stat-cache')
2117
1909
        self._convert_to_weaves()
2118
1910
        return BzrDir.open(self.bzrdir.root_transport.base)
2157
1949
        self.pb.note('  %6d revisions not present', len(self.absent_revisions))
2158
1950
        self.pb.note('  %6d texts', self.text_count)
2159
1951
        self._cleanup_spare_files_after_format4()
2160
 
        self.branch._transport.put_bytes(
2161
 
            'branch-format',
2162
 
            BzrDirFormat5().get_format_string(),
2163
 
            mode=self.bzrdir._get_file_mode())
 
1952
        self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
2164
1953
 
2165
1954
    def _cleanup_spare_files_after_format4(self):
2166
1955
        # FIXME working tree upgrade foo.
2175
1964
 
2176
1965
    def _convert_working_inv(self):
2177
1966
        inv = xml4.serializer_v4.read_inventory(
2178
 
                self.branch._transport.get('inventory'))
 
1967
                    self.branch.control_files.get('inventory'))
2179
1968
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv, working=True)
2180
 
        self.branch._transport.put_bytes('inventory', new_inv_xml,
2181
 
            mode=self.bzrdir._get_file_mode())
 
1969
        # FIXME inventory is a working tree change.
 
1970
        self.branch.control_files.put('inventory', StringIO(new_inv_xml))
2182
1971
 
2183
1972
    def _write_all_weaves(self):
2184
1973
        controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
2204
1993
        self.bzrdir.transport.mkdir('revision-store')
2205
1994
        revision_transport = self.bzrdir.transport.clone('revision-store')
2206
1995
        # TODO permissions
2207
 
        from bzrlib.xml5 import serializer_v5
2208
 
        from bzrlib.repofmt.weaverepo import RevisionTextStore
2209
 
        revision_store = RevisionTextStore(revision_transport,
2210
 
            serializer_v5, False, versionedfile.PrefixMapper(),
2211
 
            lambda:True, lambda:True)
 
1996
        _revision_store = TextRevisionStore(TextStore(revision_transport,
 
1997
                                                      prefixed=False,
 
1998
                                                      compressed=True))
2212
1999
        try:
 
2000
            transaction = WriteTransaction()
2213
2001
            for i, rev_id in enumerate(self.converted_revs):
2214
2002
                self.pb.update('write revision', i, len(self.converted_revs))
2215
 
                text = serializer_v5.write_revision_to_string(
2216
 
                    self.revisions[rev_id])
2217
 
                key = (rev_id,)
2218
 
                revision_store.add_lines(key, None, osutils.split_lines(text))
 
2003
                _revision_store.add_revision(self.revisions[rev_id], transaction)
2219
2004
        finally:
2220
2005
            self.pb.clear()
2221
2006
            
2234
2019
                         rev_id)
2235
2020
            self.absent_revisions.add(rev_id)
2236
2021
        else:
2237
 
            rev = self.branch.repository.get_revision(rev_id)
 
2022
            rev = self.branch.repository._revision_store.get_revision(rev_id,
 
2023
                self.branch.repository.get_transaction())
2238
2024
            for parent_id in rev.parent_ids:
2239
2025
                self.known_revisions.add(parent_id)
2240
2026
                self.to_read.append(parent_id)
2241
2027
            self.revisions[rev_id] = rev
2242
2028
 
2243
2029
    def _load_old_inventory(self, rev_id):
 
2030
        assert rev_id not in self.converted_revs
2244
2031
        old_inv_xml = self.branch.repository.inventory_store.get(rev_id).read()
2245
2032
        inv = xml4.serializer_v4.read_inventory_from_string(old_inv_xml)
2246
2033
        inv.revision_id = rev_id
2247
2034
        rev = self.revisions[rev_id]
 
2035
        if rev.inventory_sha1:
 
2036
            assert rev.inventory_sha1 == sha_string(old_inv_xml), \
 
2037
                'inventory sha mismatch for {%s}' % rev_id
2248
2038
        return inv
2249
2039
 
2250
2040
    def _load_updated_inventory(self, rev_id):
 
2041
        assert rev_id in self.converted_revs
2251
2042
        inv_xml = self.inv_weave.get_text(rev_id)
2252
2043
        inv = xml5.serializer_v5.read_inventory_from_string(inv_xml, rev_id)
2253
2044
        return inv
2263
2054
        self.converted_revs.add(rev_id)
2264
2055
 
2265
2056
    def _store_new_inv(self, rev, inv, present_parents):
 
2057
        # the XML is now updated with text versions
 
2058
        if __debug__:
 
2059
            entries = inv.iter_entries()
 
2060
            entries.next()
 
2061
            for path, ie in entries:
 
2062
                assert getattr(ie, 'revision', None) is not None, \
 
2063
                    'no revision on {%s} in {%s}' % \
 
2064
                    (file_id, rev.revision_id)
2266
2065
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv)
2267
2066
        new_inv_sha1 = sha_string(new_inv_xml)
2268
2067
        self.inv_weave.add_lines(rev.revision_id,
2297
2096
            self.text_weaves[file_id] = w
2298
2097
        text_changed = False
2299
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
2300
2103
        heads = graph.Graph(self).heads(parent_candiate_entries.keys())
2301
2104
        # XXX: Note that this is unordered - and this is tolerable because 
2302
2105
        # the previous code was also unordered.
2304
2107
            in heads)
2305
2108
        self.snapshot_ie(previous_entries, ie, w, rev_id)
2306
2109
        del ie.text_id
 
2110
        assert getattr(ie, 'revision', None) is not None
2307
2111
 
2308
2112
    @symbol_versioning.deprecated_method(symbol_versioning.one_one)
2309
2113
    def get_parents(self, revision_ids):
2330
2134
                ie.revision = previous_ie.revision
2331
2135
                return
2332
2136
        if ie.has_text():
2333
 
            text = self.branch.repository._text_store.get(ie.text_id)
 
2137
            text = self.branch.repository.weave_store.get(ie.text_id)
2334
2138
            file_lines = text.readlines()
 
2139
            assert sha_strings(file_lines) == ie.text_sha1
 
2140
            assert sum(map(len, file_lines)) == ie.text_size
2335
2141
            w.add_lines(rev_id, previous_revisions, file_lines)
2336
2142
            self.text_count += 1
2337
2143
        else:
2384
2190
                if (filename.endswith(".weave") or
2385
2191
                    filename.endswith(".gz") or
2386
2192
                    filename.endswith(".sig")):
2387
 
                    file_id, suffix = os.path.splitext(filename)
 
2193
                    file_id = os.path.splitext(filename)[0]
2388
2194
                else:
2389
2195
                    file_id = filename
2390
 
                    suffix = ''
2391
 
                new_name = store._mapper.map((file_id,)) + suffix
 
2196
                prefix_dir = store.hash_prefix(file_id)
2392
2197
                # FIXME keep track of the dirs made RBC 20060121
2393
2198
                try:
2394
 
                    store_transport.move(filename, new_name)
 
2199
                    store_transport.move(filename, prefix_dir + '/' + filename)
2395
2200
                except errors.NoSuchFile: # catches missing dirs strangely enough
2396
 
                    store_transport.mkdir(osutils.dirname(new_name))
2397
 
                    store_transport.move(filename, new_name)
2398
 
        self.bzrdir.transport.put_bytes(
2399
 
            'branch-format',
2400
 
            BzrDirFormat6().get_format_string(),
2401
 
            mode=self.bzrdir._get_file_mode())
 
2201
                    store_transport.mkdir(prefix_dir)
 
2202
                    store_transport.move(filename, prefix_dir + '/' + filename)
 
2203
        self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
2402
2204
 
2403
2205
 
2404
2206
class ConvertBzrDir6ToMeta(Converter):
2413
2215
        self.count = 0
2414
2216
        self.total = 20 # the steps we know about
2415
2217
        self.garbage_inventories = []
2416
 
        self.dir_mode = self.bzrdir._get_dir_mode()
2417
 
        self.file_mode = self.bzrdir._get_file_mode()
2418
2218
 
2419
2219
        self.pb.note('starting upgrade from format 6 to metadir')
2420
 
        self.bzrdir.transport.put_bytes(
2421
 
                'branch-format',
2422
 
                "Converting to format 6",
2423
 
                mode=self.file_mode)
 
2220
        self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
2424
2221
        # its faster to move specific files around than to open and use the apis...
2425
2222
        # first off, nuke ancestry.weave, it was never used.
2426
2223
        try:
2436
2233
            if name.startswith('basis-inventory.'):
2437
2234
                self.garbage_inventories.append(name)
2438
2235
        # create new directories for repository, working tree and branch
 
2236
        self.dir_mode = self.bzrdir._control_files._dir_mode
 
2237
        self.file_mode = self.bzrdir._control_files._file_mode
2439
2238
        repository_names = [('inventory.weave', True),
2440
2239
                            ('revision-store', True),
2441
2240
                            ('weaves', True)]
2489
2288
            for entry in checkout_files:
2490
2289
                self.move_entry('checkout', entry)
2491
2290
            if last_revision is not None:
2492
 
                self.bzrdir.transport.put_bytes(
 
2291
                self.bzrdir._control_files.put_utf8(
2493
2292
                    'checkout/last-revision', last_revision)
2494
 
        self.bzrdir.transport.put_bytes(
2495
 
            'branch-format',
2496
 
            BzrDirMetaFormat1().get_format_string(),
2497
 
            mode=self.file_mode)
 
2293
        self.bzrdir._control_files.put_utf8(
 
2294
            'branch-format', BzrDirMetaFormat1().get_format_string())
2498
2295
        return BzrDir.open(self.bzrdir.root_transport.base)
2499
2296
 
2500
2297
    def make_lock(self, name):
2518
2315
                raise
2519
2316
 
2520
2317
    def put_format(self, dirname, format):
2521
 
        self.bzrdir.transport.put_bytes('%s/format' % dirname,
2522
 
            format.get_format_string(),
2523
 
            self.file_mode)
 
2318
        self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
2524
2319
 
2525
2320
 
2526
2321
class ConvertMetaToMeta(Converter):
2556
2351
            pass
2557
2352
        else:
2558
2353
            # TODO: conversions of Branch and Tree should be done by
2559
 
            # InterXFormat lookups/some sort of registry.
 
2354
            # InterXFormat lookups
2560
2355
            # Avoid circular imports
2561
2356
            from bzrlib import branch as _mod_branch
2562
 
            old = branch._format.__class__
2563
 
            new = self.target_format.get_branch_format().__class__
2564
 
            while old != new:
2565
 
                if (old == _mod_branch.BzrBranchFormat5 and
2566
 
                    new in (_mod_branch.BzrBranchFormat6,
2567
 
                        _mod_branch.BzrBranchFormat7)):
2568
 
                    branch_converter = _mod_branch.Converter5to6()
2569
 
                elif (old == _mod_branch.BzrBranchFormat6 and
2570
 
                    new == _mod_branch.BzrBranchFormat7):
2571
 
                    branch_converter = _mod_branch.Converter6to7()
2572
 
                else:
2573
 
                    raise errors.BadConversionTarget("No converter", new)
 
2357
            if (branch._format.__class__ is _mod_branch.BzrBranchFormat5 and
 
2358
                self.target_format.get_branch_format().__class__ is
 
2359
                _mod_branch.BzrBranchFormat6):
 
2360
                branch_converter = _mod_branch.Converter5to6()
2574
2361
                branch_converter.convert(branch)
2575
 
                branch = self.bzrdir.open_branch()
2576
 
                old = branch._format.__class__
2577
2362
        try:
2578
2363
            tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
2579
2364
        except (errors.NoWorkingTree, errors.NotLocalUrl):
2603
2388
    def probe_transport(klass, transport):
2604
2389
        """Return a RemoteBzrDirFormat object if it looks possible."""
2605
2390
        try:
2606
 
            medium = transport.get_smart_medium()
 
2391
            client = transport.get_smart_client()
2607
2392
        except (NotImplementedError, AttributeError,
2608
 
                errors.TransportNotPossible, errors.NoSmartMedium,
2609
 
                errors.SmartProtocolError):
 
2393
                errors.TransportNotPossible):
2610
2394
            # no smart server, so not a branch for this format type.
2611
2395
            raise errors.NotBranchError(path=transport.base)
2612
2396
        else:
2613
 
            # Decline to open it if the server doesn't support our required
2614
 
            # version (3) so that the VFS-based transport will do it.
2615
 
            if medium.should_probe():
2616
 
                try:
2617
 
                    server_version = medium.protocol_version()
2618
 
                except errors.SmartProtocolError:
2619
 
                    # Apparently there's no usable smart server there, even though
2620
 
                    # the medium supports the smart protocol.
2621
 
                    raise errors.NotBranchError(path=transport.base)
2622
 
                if server_version != '2':
2623
 
                    raise errors.NotBranchError(path=transport.base)
 
2397
            # Send a 'hello' request in protocol version one, and decline to
 
2398
            # open it if the server doesn't support our required version (2) so
 
2399
            # that the VFS-based transport will do it.
 
2400
            request = client.get_request()
 
2401
            smart_protocol = protocol.SmartClientRequestProtocolOne(request)
 
2402
            server_version = smart_protocol.query_version()
 
2403
            if server_version != 2:
 
2404
                raise errors.NotBranchError(path=transport.base)
2624
2405
            return klass()
2625
2406
 
2626
2407
    def initialize_on_transport(self, transport):
2627
2408
        try:
2628
2409
            # hand off the request to the smart server
2629
 
            client_medium = transport.get_smart_medium()
 
2410
            shared_medium = transport.get_shared_medium()
2630
2411
        except errors.NoSmartMedium:
2631
2412
            # TODO: lookup the local format from a server hint.
2632
2413
            local_dir_format = BzrDirMetaFormat1()
2633
2414
            return local_dir_format.initialize_on_transport(transport)
2634
 
        client = _SmartClient(client_medium)
 
2415
        client = _SmartClient(shared_medium)
2635
2416
        path = client.remote_path_from_transport(transport)
2636
 
        response = client.call('BzrDirFormat.initialize', path)
2637
 
        if response[0] != 'ok':
2638
 
            raise errors.SmartProtocolError('unexpected response code %s' % (response,))
 
2417
        response = _SmartClient(shared_medium).call('BzrDirFormat.initialize',
 
2418
                                                    path)
 
2419
        assert response[0] in ('ok', ), 'unexpected response code %s' % (response,)
2639
2420
        return remote.RemoteBzrDir(transport)
2640
2421
 
2641
2422
    def _open(self, transport):
2666
2447
    e.g. BzrDirMeta1 with weave repository.  Also, it's more user-oriented.
2667
2448
    """
2668
2449
 
2669
 
    def __init__(self):
2670
 
        """Create a BzrDirFormatRegistry."""
2671
 
        self._aliases = set()
2672
 
        super(BzrDirFormatRegistry, self).__init__()
2673
 
 
2674
 
    def aliases(self):
2675
 
        """Return a set of the format names which are aliases."""
2676
 
        return frozenset(self._aliases)
2677
 
 
2678
2450
    def register_metadir(self, key,
2679
2451
             repository_format, help, native=True, deprecated=False,
2680
2452
             branch_format=None,
2681
2453
             tree_format=None,
2682
2454
             hidden=False,
2683
 
             experimental=False,
2684
 
             alias=False):
 
2455
             experimental=False):
2685
2456
        """Register a metadir subformat.
2686
2457
 
2687
2458
        These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2720
2491
                bd.repository_format = _load(repository_format)
2721
2492
            return bd
2722
2493
        self.register(key, helper, help, native, deprecated, hidden,
2723
 
            experimental, alias)
 
2494
            experimental)
2724
2495
 
2725
2496
    def register(self, key, factory, help, native=True, deprecated=False,
2726
 
                 hidden=False, experimental=False, alias=False):
 
2497
                 hidden=False, experimental=False):
2727
2498
        """Register a BzrDirFormat factory.
2728
2499
        
2729
2500
        The factory must be a callable that takes one parameter: the key.
2732
2503
        This function mainly exists to prevent the info object from being
2733
2504
        supplied directly.
2734
2505
        """
2735
 
        registry.Registry.register(self, key, factory, help,
 
2506
        registry.Registry.register(self, key, factory, help, 
2736
2507
            BzrDirFormatInfo(native, deprecated, hidden, experimental))
2737
 
        if alias:
2738
 
            self._aliases.add(key)
2739
2508
 
2740
2509
    def register_lazy(self, key, module_name, member_name, help, native=True,
2741
 
        deprecated=False, hidden=False, experimental=False, alias=False):
2742
 
        registry.Registry.register_lazy(self, key, module_name, member_name,
 
2510
                      deprecated=False, hidden=False, experimental=False):
 
2511
        registry.Registry.register_lazy(self, key, module_name, member_name, 
2743
2512
            help, BzrDirFormatInfo(native, deprecated, hidden, experimental))
2744
 
        if alias:
2745
 
            self._aliases.add(key)
2746
2513
 
2747
2514
    def set_default(self, key):
2748
2515
        """Set the 'default' key to be a clone of the supplied key.
2749
2516
        
2750
2517
        This method must be called once and only once.
2751
2518
        """
2752
 
        registry.Registry.register(self, 'default', self.get(key),
 
2519
        registry.Registry.register(self, 'default', self.get(key), 
2753
2520
            self.get_help(key), info=self.get_info(key))
2754
 
        self._aliases.add('default')
2755
2521
 
2756
2522
    def set_default_repository(self, key):
2757
2523
        """Set the FormatRegistry default and Repository default.
2763
2529
            self.remove('default')
2764
2530
        self.set_default(key)
2765
2531
        format = self.get('default')()
 
2532
        assert isinstance(format, BzrDirMetaFormat1)
2766
2533
 
2767
2534
    def make_bzrdir(self, key):
2768
2535
        return self.get(key)()
2820
2587
        return output
2821
2588
 
2822
2589
 
2823
 
class RepositoryAcquisitionPolicy(object):
2824
 
    """Abstract base class for repository acquisition policies.
2825
 
 
2826
 
    A repository acquisition policy decides how a BzrDir acquires a repository
2827
 
    for a branch that is being created.  The most basic policy decision is
2828
 
    whether to create a new repository or use an existing one.
2829
 
    """
2830
 
    def __init__(self, stack_on, stack_on_pwd, require_stacking):
2831
 
        """Constructor.
2832
 
 
2833
 
        :param stack_on: A location to stack on
2834
 
        :param stack_on_pwd: If stack_on is relative, the location it is
2835
 
            relative to.
2836
 
        :param require_stacking: If True, it is a failure to not stack.
2837
 
        """
2838
 
        self._stack_on = stack_on
2839
 
        self._stack_on_pwd = stack_on_pwd
2840
 
        self._require_stacking = require_stacking
2841
 
 
2842
 
    def configure_branch(self, branch):
2843
 
        """Apply any configuration data from this policy to the branch.
2844
 
 
2845
 
        Default implementation sets repository stacking.
2846
 
        """
2847
 
        if self._stack_on is None:
2848
 
            return
2849
 
        if self._stack_on_pwd is None:
2850
 
            stack_on = self._stack_on
2851
 
        else:
2852
 
            try:
2853
 
                stack_on = urlutils.rebase_url(self._stack_on,
2854
 
                    self._stack_on_pwd,
2855
 
                    branch.bzrdir.root_transport.base)
2856
 
            except errors.InvalidRebaseURLs:
2857
 
                stack_on = self._get_full_stack_on()
2858
 
        try:
2859
 
            branch.set_stacked_on_url(stack_on)
2860
 
        except errors.UnstackableBranchFormat:
2861
 
            if self._require_stacking:
2862
 
                raise
2863
 
 
2864
 
    def _get_full_stack_on(self):
2865
 
        """Get a fully-qualified URL for the stack_on location."""
2866
 
        if self._stack_on is None:
2867
 
            return None
2868
 
        if self._stack_on_pwd is None:
2869
 
            return self._stack_on
2870
 
        else:
2871
 
            return urlutils.join(self._stack_on_pwd, self._stack_on)
2872
 
 
2873
 
    def _add_fallback(self, repository):
2874
 
        """Add a fallback to the supplied repository, if stacking is set."""
2875
 
        stack_on = self._get_full_stack_on()
2876
 
        if stack_on is None:
2877
 
            return
2878
 
        stacked_dir = BzrDir.open(stack_on)
2879
 
        try:
2880
 
            stacked_repo = stacked_dir.open_branch().repository
2881
 
        except errors.NotBranchError:
2882
 
            stacked_repo = stacked_dir.open_repository()
2883
 
        try:
2884
 
            repository.add_fallback_repository(stacked_repo)
2885
 
        except errors.UnstackableRepositoryFormat:
2886
 
            if self._require_stacking:
2887
 
                raise
2888
 
 
2889
 
    def acquire_repository(self, make_working_trees=None, shared=False):
2890
 
        """Acquire a repository for this bzrdir.
2891
 
 
2892
 
        Implementations may create a new repository or use a pre-exising
2893
 
        repository.
2894
 
        :param make_working_trees: If creating a repository, set
2895
 
            make_working_trees to this value (if non-None)
2896
 
        :param shared: If creating a repository, make it shared if True
2897
 
        :return: A repository
2898
 
        """
2899
 
        raise NotImplemented(RepositoryAcquisitionPolicy.acquire_repository)
2900
 
 
2901
 
 
2902
 
class CreateRepository(RepositoryAcquisitionPolicy):
2903
 
    """A policy of creating a new repository"""
2904
 
 
2905
 
    def __init__(self, bzrdir, stack_on=None, stack_on_pwd=None,
2906
 
                 require_stacking=False):
2907
 
        """
2908
 
        Constructor.
2909
 
        :param bzrdir: The bzrdir to create the repository on.
2910
 
        :param stack_on: A location to stack on
2911
 
        :param stack_on_pwd: If stack_on is relative, the location it is
2912
 
            relative to.
2913
 
        """
2914
 
        RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
2915
 
                                             require_stacking)
2916
 
        self._bzrdir = bzrdir
2917
 
 
2918
 
    def acquire_repository(self, make_working_trees=None, shared=False):
2919
 
        """Implementation of RepositoryAcquisitionPolicy.acquire_repository
2920
 
 
2921
 
        Creates the desired repository in the bzrdir we already have.
2922
 
        """
2923
 
        repository = self._bzrdir.create_repository(shared=shared)
2924
 
        self._add_fallback(repository)
2925
 
        if make_working_trees is not None:
2926
 
            repository.set_make_working_trees(make_working_trees)
2927
 
        return repository
2928
 
 
2929
 
 
2930
 
class UseExistingRepository(RepositoryAcquisitionPolicy):
2931
 
    """A policy of reusing an existing repository"""
2932
 
 
2933
 
    def __init__(self, repository, stack_on=None, stack_on_pwd=None,
2934
 
                 require_stacking=False):
2935
 
        """Constructor.
2936
 
 
2937
 
        :param repository: The repository to use.
2938
 
        :param stack_on: A location to stack on
2939
 
        :param stack_on_pwd: If stack_on is relative, the location it is
2940
 
            relative to.
2941
 
        """
2942
 
        RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
2943
 
                                             require_stacking)
2944
 
        self._repository = repository
2945
 
 
2946
 
    def acquire_repository(self, make_working_trees=None, shared=False):
2947
 
        """Implementation of RepositoryAcquisitionPolicy.acquire_repository
2948
 
 
2949
 
        Returns an existing repository to use
2950
 
        """
2951
 
        self._add_fallback(self._repository)
2952
 
        return self._repository
2953
 
 
2954
 
 
2955
2590
format_registry = BzrDirFormatRegistry()
2956
2591
format_registry.register('weave', BzrDirFormat6,
2957
2592
    'Pre-0.8 format.  Slower than knit and does not'
3034
2669
    branch_format='bzrlib.branch.BzrBranchFormat6',
3035
2670
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3036
2671
    )
3037
 
format_registry.register_metadir('1.6',
3038
 
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack5',
3039
 
    help='A branch and pack based repository that supports stacking. ',
3040
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
3041
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3042
 
    )
3043
 
format_registry.register_metadir('1.6.1-rich-root',
3044
 
    'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack5RichRoot',
3045
 
    help='A branch and pack based repository that supports stacking '
3046
 
         'and rich root data (needed for bzr-svn). ',
3047
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
3048
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3049
 
    )
3050
 
# The following two formats should always just be aliases.
3051
 
format_registry.register_metadir('development',
3052
 
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment2',
3053
 
    help='Current development format. Can convert data to and from pack-0.92 '
3054
 
        '(and anything compatible with pack-0.92) format repositories. '
3055
 
        'Repositories and branches in this format can only be read by bzr.dev. '
3056
 
        'Please read '
3057
 
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
3058
 
        'before use.',
3059
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
3060
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3061
 
    experimental=True,
3062
 
    alias=True,
3063
 
    )
3064
 
format_registry.register_metadir('development-subtree',
3065
 
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment2Subtree',
3066
 
    help='Current development format, subtree variant. Can convert data to and '
3067
 
        'from pack-0.92-subtree (and anything compatible with '
3068
 
        'pack-0.92-subtree) format repositories. Repositories and branches in '
3069
 
        'this format can only be read by bzr.dev. Please read '
3070
 
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
3071
 
        'before use.',
3072
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
3073
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3074
 
    experimental=True,
3075
 
    alias=True,
3076
 
    )
3077
 
# And the development formats above will have aliased one of the following:
3078
 
format_registry.register_metadir('development2',
3079
 
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment2',
3080
 
    help='1.6.1 with B+Tree based index. '
3081
 
        'Please read '
3082
 
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
3083
 
        'before use.',
3084
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
3085
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3086
 
    hidden=True,
3087
 
    experimental=True,
3088
 
    )
3089
 
format_registry.register_metadir('development2-subtree',
3090
 
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment2Subtree',
3091
 
    help='1.6.1-subtree with B+Tree based index. '
3092
 
        'Please read '
3093
 
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
3094
 
        'before use.',
3095
 
    branch_format='bzrlib.branch.BzrBranchFormat7',
3096
 
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
3097
 
    hidden=True,
3098
 
    experimental=True,
3099
 
    )
3100
 
# The current format that is made on 'bzr init'.
3101
2672
format_registry.set_default('pack-0.92')