/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

merge bzr.dev r3564

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007, 2008 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
39
39
 
40
40
import bzrlib
41
41
from bzrlib import (
 
42
    config,
42
43
    errors,
43
44
    graph,
44
45
    lockable_files,
45
46
    lockdir,
 
47
    osutils,
46
48
    registry,
47
49
    remote,
48
50
    revision as _mod_revision,
49
51
    symbol_versioning,
50
52
    ui,
51
53
    urlutils,
 
54
    versionedfile,
52
55
    win32utils,
53
56
    workingtree,
54
57
    workingtree_4,
59
62
    sha_strings,
60
63
    sha_string,
61
64
    )
 
65
from bzrlib.repository import Repository
62
66
from bzrlib.smart.client import _SmartClient
63
67
from bzrlib.smart import protocol
64
 
from bzrlib.store.revision.text import TextRevisionStore
65
 
from bzrlib.store.text import TextStore
66
68
from bzrlib.store.versioned import WeaveStore
67
69
from bzrlib.transactions import WriteTransaction
68
70
from bzrlib.transport import (
89
91
    BzrDir instances let you create or open any of the things that can be
90
92
    found within .bzr - checkouts, branches and repositories.
91
93
    
92
 
    transport
 
94
    :ivar transport:
93
95
        the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
94
 
    root_transport
 
96
    :ivar root_transport:
95
97
        a transport connected to the directory this bzr was opened from
96
98
        (i.e. the parent directory holding the .bzr directory).
 
99
 
 
100
    Everything in the bzrdir should have the same file permissions.
97
101
    """
98
102
 
99
103
    def break_lock(self):
153
157
                format.get_format_description(),
154
158
                basedir)
155
159
 
156
 
    def clone(self, url, revision_id=None, force_new_repo=False):
 
160
    def clone(self, url, revision_id=None, force_new_repo=False,
 
161
              preserve_stacking=False):
157
162
        """Clone this bzrdir and its contents to url verbatim.
158
163
 
159
 
        If url's last component does not exist, it will be created.
160
 
 
161
 
        if revision_id is not None, then the clone operation may tune
 
164
        :param url: The url create the clone at.  If url's last component does
 
165
            not exist, it will be created.
 
166
        :param revision_id: The tip revision-id to use for any branch or
 
167
            working tree.  If not None, then the clone operation may tune
162
168
            itself to download less data.
163
 
        :param force_new_repo: Do not use a shared repository for the target 
 
169
        :param force_new_repo: Do not use a shared repository for the target
164
170
                               even if one is available.
 
171
        :param preserve_stacking: When cloning a stacked branch, stack the
 
172
            new branch on top of the other branch's stacked-on branch.
165
173
        """
166
174
        return self.clone_on_transport(get_transport(url),
167
175
                                       revision_id=revision_id,
168
 
                                       force_new_repo=force_new_repo)
 
176
                                       force_new_repo=force_new_repo,
 
177
                                       preserve_stacking=preserve_stacking)
169
178
 
170
179
    def clone_on_transport(self, transport, revision_id=None,
171
 
                           force_new_repo=False):
 
180
                           force_new_repo=False, preserve_stacking=False):
172
181
        """Clone this bzrdir and its contents to transport verbatim.
173
182
 
174
 
        If the target directory does not exist, it will be created.
175
 
 
176
 
        if revision_id is not None, then the clone operation may tune
 
183
        :param transport: The transport for the location to produce the clone
 
184
            at.  If the target directory does not exist, it will be created.
 
185
        :param revision_id: The tip revision-id to use for any branch or
 
186
            working tree.  If not None, then the clone operation may tune
177
187
            itself to download less data.
178
 
        :param force_new_repo: Do not use a shared repository for the target 
 
188
        :param force_new_repo: Do not use a shared repository for the target,
179
189
                               even if one is available.
 
190
        :param preserve_stacking: When cloning a stacked branch, stack the
 
191
            new branch on top of the other branch's stacked-on branch.
180
192
        """
181
193
        transport.ensure_base()
182
194
        result = self.cloning_metadir().initialize_on_transport(transport)
183
195
        repository_policy = None
 
196
        stack_on = None
184
197
        try:
185
198
            local_repo = self.find_repository()
186
199
        except errors.NoRepositoryPresent:
187
200
            local_repo = None
 
201
        try:
 
202
            local_branch = self.open_branch()
 
203
        except errors.NotBranchError:
 
204
            local_branch = None
 
205
        else:
 
206
            # enable fallbacks when branch is not a branch reference
 
207
            if local_branch.repository.has_same_location(local_repo):
 
208
                local_repo = local_branch.repository
 
209
            if preserve_stacking:
 
210
                try:
 
211
                    stack_on = local_branch.get_stacked_on_url()
 
212
                except (errors.UnstackableBranchFormat,
 
213
                        errors.UnstackableRepositoryFormat,
 
214
                        errors.NotStacked):
 
215
                    pass
 
216
 
188
217
        if local_repo:
189
218
            # may need to copy content in
190
219
            repository_policy = result.determine_repository_policy(
191
 
                force_new_repo)
 
220
                force_new_repo, stack_on)
192
221
            make_working_trees = local_repo.make_working_trees()
193
222
            result_repo = repository_policy.acquire_repository(
194
223
                make_working_trees, local_repo.is_shared())
195
224
            result_repo.fetch(local_repo, revision_id=revision_id)
 
225
        else:
 
226
            result_repo = None
196
227
        # 1 if there is a branch present
197
228
        #   make sure its content is available in the target repository
198
229
        #   clone it.
199
 
        try:
200
 
            local_branch = self.open_branch()
201
 
        except errors.NotBranchError:
202
 
            pass
203
 
        else:
 
230
        if local_branch is not None:
204
231
            result_branch = local_branch.clone(result, revision_id=revision_id)
205
232
            if repository_policy is not None:
206
233
                repository_policy.configure_branch(result_branch)
207
 
        try:
208
 
            result_repo = result.find_repository()
209
 
        except errors.NoRepositoryPresent:
210
 
            result_repo = None
211
234
        if result_repo is None or result_repo.make_working_trees():
212
235
            try:
213
236
                self.open_workingtree().clone(result)
312
335
                branches.append(branch)
313
336
        return branches
314
337
 
315
 
 
316
338
    def destroy_repository(self):
317
339
        """Destroy the repository in this BzrDir"""
318
340
        raise NotImplementedError(self.destroy_repository)
350
372
        bzrdir._find_or_create_repository(force_new_repo)
351
373
        return bzrdir.create_branch()
352
374
 
353
 
    def determine_repository_policy(self, force_new_repo=False):
 
375
    def determine_repository_policy(self, force_new_repo=False, stack_on=None,
 
376
                                    stack_on_pwd=None, require_stacking=False):
354
377
        """Return an object representing a policy to use.
355
378
 
356
379
        This controls whether a new repository is created, or a shared
357
380
        repository used instead.
 
381
 
 
382
        If stack_on is supplied, will not seek a containing shared repo.
 
383
        :param force_new_repo: If True, require a new repository to be created.
 
384
        :param stack_on: If supplied, the location to stack on.  If not
 
385
            supplied, a default_stack_on location may be used.
 
386
        :param stack_on_pwd: If stack_on is relative, the location it is
 
387
            relative to.
358
388
        """
359
389
        def repository_policy(found_bzrdir):
 
390
            stack_on = None
 
391
            stack_on_pwd = None
 
392
            config = found_bzrdir.get_config()
360
393
            stop = False
 
394
            if config is not None:
 
395
                stack_on = config.get_default_stack_on()
 
396
                if stack_on is not None:
 
397
                    stack_on_pwd = found_bzrdir.root_transport.base
 
398
                    stop = True
 
399
                    note('Using default stacking branch %s at %s', stack_on,
 
400
                         stack_on_pwd)
361
401
            # does it have a repository ?
362
402
            try:
363
403
                repository = found_bzrdir.open_repository()
372
412
            if not stop:
373
413
                return None, False
374
414
            if repository:
375
 
                return UseExistingRepository(repository), True
 
415
                return UseExistingRepository(repository, stack_on,
 
416
                    stack_on_pwd, require_stacking=require_stacking), True
376
417
            else:
377
 
                return CreateRepository(self), True
 
418
                return CreateRepository(self, stack_on, stack_on_pwd,
 
419
                    require_stacking=require_stacking), True
378
420
 
379
421
        if not force_new_repo:
380
 
            policy = self._find_containing(repository_policy)
381
 
            if policy is not None:
382
 
                return policy
383
 
        return CreateRepository(self)
 
422
            if stack_on is None:
 
423
                policy = self._find_containing(repository_policy)
 
424
                if policy is not None:
 
425
                    return policy
 
426
            else:
 
427
                try:
 
428
                    return UseExistingRepository(self.open_repository(),
 
429
                        stack_on, stack_on_pwd,
 
430
                        require_stacking=require_stacking)
 
431
                except errors.NoRepositoryPresent:
 
432
                    pass
 
433
        return CreateRepository(self, stack_on, stack_on_pwd,
 
434
                                require_stacking=require_stacking)
384
435
 
385
436
    def _find_or_create_repository(self, force_new_repo):
386
437
        """Create a new repository if needed, returning the repository."""
582
633
        guaranteed to point to an existing directory ready for use.
583
634
        """
584
635
        raise NotImplementedError(self.get_branch_transport)
 
636
 
 
637
    def _find_creation_modes(self):
 
638
        """Determine the appropriate modes for files and directories.
 
639
        
 
640
        They're always set to be consistent with the base directory,
 
641
        assuming that this transport allows setting modes.
 
642
        """
 
643
        # TODO: Do we need or want an option (maybe a config setting) to turn
 
644
        # this off or override it for particular locations? -- mbp 20080512
 
645
        if self._mode_check_done:
 
646
            return
 
647
        self._mode_check_done = True
 
648
        try:
 
649
            st = self.transport.stat('.')
 
650
        except errors.TransportNotPossible:
 
651
            self._dir_mode = None
 
652
            self._file_mode = None
 
653
        else:
 
654
            # Check the directory mode, but also make sure the created
 
655
            # directories and files are read-write for this user. This is
 
656
            # mostly a workaround for filesystems which lie about being able to
 
657
            # write to a directory (cygwin & win32)
 
658
            self._dir_mode = (st.st_mode & 07777) | 00700
 
659
            # Remove the sticky and execute bits for files
 
660
            self._file_mode = self._dir_mode & ~07111
 
661
 
 
662
    def _get_file_mode(self):
 
663
        """Return Unix mode for newly created files, or None.
 
664
        """
 
665
        if not self._mode_check_done:
 
666
            self._find_creation_modes()
 
667
        return self._file_mode
 
668
 
 
669
    def _get_dir_mode(self):
 
670
        """Return Unix mode for newly created directories, or None.
 
671
        """
 
672
        if not self._mode_check_done:
 
673
            self._find_creation_modes()
 
674
        return self._dir_mode
585
675
        
586
676
    def get_repository_transport(self, repository_format):
587
677
        """Get the transport for use by repository format in this BzrDir.
608
698
        guaranteed to point to an existing directory ready for use.
609
699
        """
610
700
        raise NotImplementedError(self.get_workingtree_transport)
611
 
        
 
701
 
 
702
    def get_config(self):
 
703
        if getattr(self, '_get_config', None) is None:
 
704
            return None
 
705
        return self._get_config()
 
706
 
612
707
    def __init__(self, _transport, _format):
613
708
        """Initialize a Bzr control dir object.
614
709
        
621
716
        self._format = _format
622
717
        self.transport = _transport.clone('.bzr')
623
718
        self.root_transport = _transport
 
719
        self._mode_check_done = False
624
720
 
625
721
    def is_control_filename(self, filename):
626
722
        """True if filename is the name of a path which is reserved for bzrdir's.
803
899
        tree, branch = bzrdir._get_tree_branch()
804
900
        return tree, branch, relpath
805
901
 
 
902
    @classmethod
 
903
    def open_containing_tree_branch_or_repository(klass, location):
 
904
        """Return the working tree, branch and repo contained by a location.
 
905
 
 
906
        Returns (tree, branch, repository, relpath).
 
907
        If there is no tree containing the location, tree will be None.
 
908
        If there is no branch containing the location, branch will be None.
 
909
        If there is no repository containing the location, repository will be
 
910
        None.
 
911
        relpath is the portion of the path that is contained by the innermost
 
912
        BzrDir.
 
913
 
 
914
        If no tree, branch or repository is found, a NotBranchError is raised.
 
915
        """
 
916
        bzrdir, relpath = klass.open_containing(location)
 
917
        try:
 
918
            tree, branch = bzrdir._get_tree_branch()
 
919
        except errors.NotBranchError:
 
920
            try:
 
921
                repo = bzrdir.find_repository()
 
922
                return None, None, repo, relpath
 
923
            except (errors.NoRepositoryPresent):
 
924
                raise errors.NotBranchError(location)
 
925
        return tree, branch, branch.repository, relpath
 
926
 
806
927
    def open_repository(self, _unsupported=False):
807
928
        """Open the repository object at this BzrDir if one is present.
808
929
 
906
1027
 
907
1028
    def sprout(self, url, revision_id=None, force_new_repo=False,
908
1029
               recurse='down', possible_transports=None,
909
 
               accelerator_tree=None, hardlink=False):
 
1030
               accelerator_tree=None, hardlink=False, stacked=False):
910
1031
        """Create a copy of this bzrdir prepared for use as a new line of
911
1032
        development.
912
1033
 
925
1046
            content is different.
926
1047
        :param hardlink: If true, hard-link files from accelerator_tree,
927
1048
            where possible.
 
1049
        :param stacked: If true, create a stacked branch referring to the
 
1050
            location of this control directory.
928
1051
        """
929
1052
        target_transport = get_transport(url, possible_transports)
930
1053
        target_transport.ensure_base()
933
1056
        try:
934
1057
            source_branch = self.open_branch()
935
1058
            source_repository = source_branch.repository
 
1059
            if stacked:
 
1060
                stacked_branch_url = self.root_transport.base
 
1061
            else:
 
1062
                # if a stacked branch wasn't requested, we don't create one
 
1063
                # even if the origin was stacked
 
1064
                stacked_branch_url = None
936
1065
        except errors.NotBranchError:
937
1066
            source_branch = None
938
1067
            try:
939
1068
                source_repository = self.open_repository()
940
1069
            except errors.NoRepositoryPresent:
941
1070
                source_repository = None
942
 
        if force_new_repo:
943
 
            result_repo = None
944
 
        else:
945
 
            try:
946
 
                result_repo = result.find_repository()
947
 
            except errors.NoRepositoryPresent:
948
 
                result_repo = None
949
 
        if source_repository is None and result_repo is not None:
950
 
            pass
951
 
        elif source_repository is None and result_repo is None:
952
 
            # no repo available, make a new one
953
 
            result.create_repository()
954
 
        elif source_repository is not None and result_repo is None:
955
 
            # have source, and want to make a new target repo
956
 
            result_repo = source_repository.sprout(result,
957
 
                                                   revision_id=revision_id)
958
 
        else:
959
 
            # fetch needed content into target.
960
 
            if source_repository is not None:
961
 
                # would rather do 
962
 
                # source_repository.copy_content_into(result_repo,
963
 
                #                                     revision_id=revision_id)
964
 
                # so we can override the copy method
965
 
                result_repo.fetch(source_repository, revision_id=revision_id)
 
1071
            stacked_branch_url = None
 
1072
        repository_policy = result.determine_repository_policy(
 
1073
            force_new_repo, stacked_branch_url, require_stacking=stacked)
 
1074
        result_repo = repository_policy.acquire_repository()
 
1075
        if source_repository is not None:
 
1076
            result_repo.fetch(source_repository, revision_id=revision_id)
 
1077
 
 
1078
        # Create/update the result branch
966
1079
        if source_branch is not None:
967
 
            source_branch.sprout(result, revision_id=revision_id)
 
1080
            result_branch = source_branch.sprout(result,
 
1081
                revision_id=revision_id)
968
1082
        else:
969
 
            result.create_branch()
 
1083
            result_branch = result.create_branch()
 
1084
        repository_policy.configure_branch(result_branch)
 
1085
 
 
1086
        # Create/update the result working tree
970
1087
        if isinstance(target_transport, LocalTransport) and (
971
1088
            result_repo is None or result_repo.make_working_trees()):
972
1089
            wt = result.create_workingtree(accelerator_tree=accelerator_tree,
987
1104
                basis = wt.basis_tree()
988
1105
                basis.lock_read()
989
1106
                subtrees = basis.iter_references()
990
 
                recurse_branch = wt.branch
991
1107
            elif source_branch is not None:
992
1108
                basis = source_branch.basis_tree()
993
1109
                basis.lock_read()
994
1110
                subtrees = basis.iter_references()
995
 
                recurse_branch = source_branch
996
1111
            else:
997
1112
                subtrees = []
998
1113
                basis = None
1002
1117
                    sublocation = source_branch.reference_parent(file_id, path)
1003
1118
                    sublocation.bzrdir.sprout(target,
1004
1119
                        basis.get_reference_revision(file_id, path),
1005
 
                        force_new_repo=force_new_repo, recurse=recurse)
 
1120
                        force_new_repo=force_new_repo, recurse=recurse,
 
1121
                        stacked=stacked)
1006
1122
            finally:
1007
1123
                if basis is not None:
1008
1124
                    basis.unlock()
1028
1144
        """Produce a metadir suitable for cloning with."""
1029
1145
        return self._format.__class__()
1030
1146
 
1031
 
    def clone(self, url, revision_id=None, force_new_repo=False):
1032
 
        """See BzrDir.clone()."""
 
1147
    def clone(self, url, revision_id=None, force_new_repo=False,
 
1148
              preserve_stacking=False):
 
1149
        """See BzrDir.clone().
 
1150
 
 
1151
        force_new_repo has no effect, since this family of formats always
 
1152
        require a new repository.
 
1153
        preserve_stacking has no effect, since no source branch using this
 
1154
        family of formats can be stacked, so there is no stacking to preserve.
 
1155
        """
1033
1156
        from bzrlib.workingtree import WorkingTreeFormat2
1034
1157
        self._make_tail(url)
1035
1158
        result = self._format._initialize_for_clone(url)
1045
1168
            except errors.NotLocalUrl:
1046
1169
                # but we cannot do it for remote trees.
1047
1170
                to_branch = result.open_branch()
1048
 
                WorkingTreeFormat2().stub_initialize_remote(to_branch.control_files)
 
1171
                WorkingTreeFormat2()._stub_initialize_remote(to_branch)
1049
1172
        return result
1050
1173
 
1051
1174
    def create_branch(self):
1142
1265
 
1143
1266
    def sprout(self, url, revision_id=None, force_new_repo=False,
1144
1267
               possible_transports=None, accelerator_tree=None,
1145
 
               hardlink=False):
 
1268
               hardlink=False, stacked=False):
1146
1269
        """See BzrDir.sprout()."""
 
1270
        if stacked:
 
1271
            raise errors.UnstackableBranchFormat(
 
1272
                self._format, self.root_transport.base)
1147
1273
        from bzrlib.workingtree import WorkingTreeFormat2
1148
1274
        self._make_tail(url)
1149
1275
        result = self._format._initialize_for_clone(url)
1387
1513
            basedir=self.root_transport.base)
1388
1514
        return format.open(self, _found=True)
1389
1515
 
 
1516
    def _get_config(self):
 
1517
        return config.BzrDirConfig(self.transport)
 
1518
 
1390
1519
 
1391
1520
class BzrDirFormat(object):
1392
1521
    """An encapsulation of the initialization and open routines for a format.
1506
1635
            win32utils.set_file_attr_hidden(transport._abspath('.bzr'))
1507
1636
        file_mode = temp_control._file_mode
1508
1637
        del temp_control
1509
 
        mutter('created control directory in ' + transport.base)
1510
 
        control = transport.clone('.bzr')
1511
 
        utf8_files = [('README', 
 
1638
        bzrdir_transport = transport.clone('.bzr')
 
1639
        utf8_files = [('README',
1512
1640
                       "This is a Bazaar control directory.\n"
1513
1641
                       "Do not change any files in this directory.\n"
1514
1642
                       "See http://bazaar-vcs.org/ for more information about Bazaar.\n"),
1515
1643
                      ('branch-format', self.get_format_string()),
1516
1644
                      ]
1517
1645
        # NB: no need to escape relative paths that are url safe.
1518
 
        control_files = lockable_files.LockableFiles(control,
1519
 
                            self._lock_file_name, self._lock_class)
 
1646
        control_files = lockable_files.LockableFiles(bzrdir_transport,
 
1647
            self._lock_file_name, self._lock_class)
1520
1648
        control_files.create_lock()
1521
1649
        control_files.lock_write()
1522
1650
        try:
1523
 
            for file, content in utf8_files:
1524
 
                control_files.put_utf8(file, content)
 
1651
            for (filename, content) in utf8_files:
 
1652
                bzrdir_transport.put_bytes(filename, content,
 
1653
                    mode=file_mode)
1525
1654
        finally:
1526
1655
            control_files.unlock()
1527
1656
        return self.open(transport, _found=True)
1721
1850
            except errors.NotLocalUrl:
1722
1851
                # Even though we can't access the working tree, we need to
1723
1852
                # create its control files.
1724
 
                WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
 
1853
                WorkingTreeFormat2()._stub_initialize_remote(branch)
1725
1854
        return result
1726
1855
 
1727
1856
    def _open(self, transport):
1780
1909
            except errors.NotLocalUrl:
1781
1910
                # Even though we can't access the working tree, we need to
1782
1911
                # create its control files.
1783
 
                WorkingTreeFormat2().stub_initialize_remote(branch.control_files)
 
1912
                WorkingTreeFormat2()._stub_initialize_remote(branch)
1784
1913
        return result
1785
1914
 
1786
1915
    def _open(self, transport):
1967
2096
        self.pb.note('  %6d revisions not present', len(self.absent_revisions))
1968
2097
        self.pb.note('  %6d texts', self.text_count)
1969
2098
        self._cleanup_spare_files_after_format4()
1970
 
        self.branch.control_files.put_utf8('branch-format', BzrDirFormat5().get_format_string())
 
2099
        self.branch._transport.put_bytes(
 
2100
            'branch-format',
 
2101
            BzrDirFormat5().get_format_string(),
 
2102
            mode=self.bzrdir._get_file_mode())
1971
2103
 
1972
2104
    def _cleanup_spare_files_after_format4(self):
1973
2105
        # FIXME working tree upgrade foo.
1982
2114
 
1983
2115
    def _convert_working_inv(self):
1984
2116
        inv = xml4.serializer_v4.read_inventory(
1985
 
                    self.branch.control_files.get('inventory'))
 
2117
                self.branch._transport.get('inventory'))
1986
2118
        new_inv_xml = xml5.serializer_v5.write_inventory_to_string(inv, working=True)
1987
 
        # FIXME inventory is a working tree change.
1988
 
        self.branch.control_files.put('inventory', StringIO(new_inv_xml))
 
2119
        self.branch._transport.put_bytes('inventory', new_inv_xml,
 
2120
            mode=self.bzrdir._get_file_mode())
1989
2121
 
1990
2122
    def _write_all_weaves(self):
1991
2123
        controlweaves = WeaveStore(self.bzrdir.transport, prefixed=False)
2011
2143
        self.bzrdir.transport.mkdir('revision-store')
2012
2144
        revision_transport = self.bzrdir.transport.clone('revision-store')
2013
2145
        # TODO permissions
2014
 
        _revision_store = TextRevisionStore(TextStore(revision_transport,
2015
 
                                                      prefixed=False,
2016
 
                                                      compressed=True))
 
2146
        from bzrlib.xml5 import serializer_v5
 
2147
        from bzrlib.repofmt.weaverepo import RevisionTextStore
 
2148
        revision_store = RevisionTextStore(revision_transport,
 
2149
            serializer_v5, False, versionedfile.PrefixMapper(),
 
2150
            lambda:True, lambda:True)
2017
2151
        try:
2018
 
            transaction = WriteTransaction()
2019
2152
            for i, rev_id in enumerate(self.converted_revs):
2020
2153
                self.pb.update('write revision', i, len(self.converted_revs))
2021
 
                _revision_store.add_revision(self.revisions[rev_id], transaction)
 
2154
                text = serializer_v5.write_revision_to_string(
 
2155
                    self.revisions[rev_id])
 
2156
                key = (rev_id,)
 
2157
                revision_store.add_lines(key, None, osutils.split_lines(text))
2022
2158
        finally:
2023
2159
            self.pb.clear()
2024
2160
            
2037
2173
                         rev_id)
2038
2174
            self.absent_revisions.add(rev_id)
2039
2175
        else:
2040
 
            rev = self.branch.repository._revision_store.get_revision(rev_id,
2041
 
                self.branch.repository.get_transaction())
 
2176
            rev = self.branch.repository.get_revision(rev_id)
2042
2177
            for parent_id in rev.parent_ids:
2043
2178
                self.known_revisions.add(parent_id)
2044
2179
                self.to_read.append(parent_id)
2134
2269
                ie.revision = previous_ie.revision
2135
2270
                return
2136
2271
        if ie.has_text():
2137
 
            text = self.branch.repository.weave_store.get(ie.text_id)
 
2272
            text = self.branch.repository._text_store.get(ie.text_id)
2138
2273
            file_lines = text.readlines()
2139
2274
            w.add_lines(rev_id, previous_revisions, file_lines)
2140
2275
            self.text_count += 1
2188
2323
                if (filename.endswith(".weave") or
2189
2324
                    filename.endswith(".gz") or
2190
2325
                    filename.endswith(".sig")):
2191
 
                    file_id = os.path.splitext(filename)[0]
 
2326
                    file_id, suffix = os.path.splitext(filename)
2192
2327
                else:
2193
2328
                    file_id = filename
2194
 
                prefix_dir = store.hash_prefix(file_id)
 
2329
                    suffix = ''
 
2330
                new_name = store._mapper.map((file_id,)) + suffix
2195
2331
                # FIXME keep track of the dirs made RBC 20060121
2196
2332
                try:
2197
 
                    store_transport.move(filename, prefix_dir + '/' + filename)
 
2333
                    store_transport.move(filename, new_name)
2198
2334
                except errors.NoSuchFile: # catches missing dirs strangely enough
2199
 
                    store_transport.mkdir(prefix_dir)
2200
 
                    store_transport.move(filename, prefix_dir + '/' + filename)
2201
 
        self.bzrdir._control_files.put_utf8('branch-format', BzrDirFormat6().get_format_string())
 
2335
                    store_transport.mkdir(osutils.dirname(new_name))
 
2336
                    store_transport.move(filename, new_name)
 
2337
        self.bzrdir.transport.put_bytes(
 
2338
            'branch-format',
 
2339
            BzrDirFormat6().get_format_string(),
 
2340
            mode=self.bzrdir._get_file_mode())
2202
2341
 
2203
2342
 
2204
2343
class ConvertBzrDir6ToMeta(Converter):
2213
2352
        self.count = 0
2214
2353
        self.total = 20 # the steps we know about
2215
2354
        self.garbage_inventories = []
 
2355
        self.dir_mode = self.bzrdir._get_dir_mode()
 
2356
        self.file_mode = self.bzrdir._get_file_mode()
2216
2357
 
2217
2358
        self.pb.note('starting upgrade from format 6 to metadir')
2218
 
        self.bzrdir._control_files.put_utf8('branch-format', "Converting to format 6")
 
2359
        self.bzrdir.transport.put_bytes(
 
2360
                'branch-format',
 
2361
                "Converting to format 6",
 
2362
                mode=self.file_mode)
2219
2363
        # its faster to move specific files around than to open and use the apis...
2220
2364
        # first off, nuke ancestry.weave, it was never used.
2221
2365
        try:
2231
2375
            if name.startswith('basis-inventory.'):
2232
2376
                self.garbage_inventories.append(name)
2233
2377
        # create new directories for repository, working tree and branch
2234
 
        self.dir_mode = self.bzrdir._control_files._dir_mode
2235
 
        self.file_mode = self.bzrdir._control_files._file_mode
2236
2378
        repository_names = [('inventory.weave', True),
2237
2379
                            ('revision-store', True),
2238
2380
                            ('weaves', True)]
2286
2428
            for entry in checkout_files:
2287
2429
                self.move_entry('checkout', entry)
2288
2430
            if last_revision is not None:
2289
 
                self.bzrdir._control_files.put_utf8(
 
2431
                self.bzrdir.transport.put_bytes(
2290
2432
                    'checkout/last-revision', last_revision)
2291
 
        self.bzrdir._control_files.put_utf8(
2292
 
            'branch-format', BzrDirMetaFormat1().get_format_string())
 
2433
        self.bzrdir.transport.put_bytes(
 
2434
            'branch-format',
 
2435
            BzrDirMetaFormat1().get_format_string(),
 
2436
            mode=self.file_mode)
2293
2437
        return BzrDir.open(self.bzrdir.root_transport.base)
2294
2438
 
2295
2439
    def make_lock(self, name):
2313
2457
                raise
2314
2458
 
2315
2459
    def put_format(self, dirname, format):
2316
 
        self.bzrdir._control_files.put_utf8('%s/format' % dirname, format.get_format_string())
 
2460
        self.bzrdir.transport.put_bytes('%s/format' % dirname,
 
2461
            format.get_format_string(),
 
2462
            self.file_mode)
2317
2463
 
2318
2464
 
2319
2465
class ConvertMetaToMeta(Converter):
2349
2495
            pass
2350
2496
        else:
2351
2497
            # TODO: conversions of Branch and Tree should be done by
2352
 
            # InterXFormat lookups
 
2498
            # InterXFormat lookups/some sort of registry.
2353
2499
            # Avoid circular imports
2354
2500
            from bzrlib import branch as _mod_branch
2355
 
            if (branch._format.__class__ is _mod_branch.BzrBranchFormat5 and
2356
 
                self.target_format.get_branch_format().__class__ is
2357
 
                _mod_branch.BzrBranchFormat6):
2358
 
                branch_converter = _mod_branch.Converter5to6()
 
2501
            old = branch._format.__class__
 
2502
            new = self.target_format.get_branch_format().__class__
 
2503
            while old != new:
 
2504
                if (old == _mod_branch.BzrBranchFormat5 and
 
2505
                    new in (_mod_branch.BzrBranchFormat6,
 
2506
                        _mod_branch.BzrBranchFormat7)):
 
2507
                    branch_converter = _mod_branch.Converter5to6()
 
2508
                elif (old == _mod_branch.BzrBranchFormat6 and
 
2509
                    new == _mod_branch.BzrBranchFormat7):
 
2510
                    branch_converter = _mod_branch.Converter6to7()
 
2511
                else:
 
2512
                    raise errors.BadConversionTarget("No converter", new)
2359
2513
                branch_converter.convert(branch)
 
2514
                branch = self.bzrdir.open_branch()
 
2515
                old = branch._format.__class__
2360
2516
        try:
2361
2517
            tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
2362
2518
        except (errors.NoWorkingTree, errors.NotLocalUrl):
2388
2544
        try:
2389
2545
            medium = transport.get_smart_medium()
2390
2546
        except (NotImplementedError, AttributeError,
2391
 
                errors.TransportNotPossible, errors.NoSmartMedium):
 
2547
                errors.TransportNotPossible, errors.NoSmartMedium,
 
2548
                errors.SmartProtocolError):
2392
2549
            # no smart server, so not a branch for this format type.
2393
2550
            raise errors.NotBranchError(path=transport.base)
2394
2551
        else:
2395
2552
            # Decline to open it if the server doesn't support our required
2396
 
            # version (2) so that the VFS-based transport will do it.
2397
 
            try:
2398
 
                server_version = medium.protocol_version()
2399
 
            except errors.SmartProtocolError:
2400
 
                # Apparently there's no usable smart server there, even though
2401
 
                # the medium supports the smart protocol.
2402
 
                raise errors.NotBranchError(path=transport.base)
2403
 
            if server_version != 2:
2404
 
                raise errors.NotBranchError(path=transport.base)
 
2553
            # version (3) so that the VFS-based transport will do it.
 
2554
            if medium.should_probe():
 
2555
                try:
 
2556
                    server_version = medium.protocol_version()
 
2557
                except errors.SmartProtocolError:
 
2558
                    # Apparently there's no usable smart server there, even though
 
2559
                    # the medium supports the smart protocol.
 
2560
                    raise errors.NotBranchError(path=transport.base)
 
2561
                if server_version != '2':
 
2562
                    raise errors.NotBranchError(path=transport.base)
2405
2563
            return klass()
2406
2564
 
2407
2565
    def initialize_on_transport(self, transport):
2412
2570
            # TODO: lookup the local format from a server hint.
2413
2571
            local_dir_format = BzrDirMetaFormat1()
2414
2572
            return local_dir_format.initialize_on_transport(transport)
2415
 
        client = _SmartClient(client_medium, transport.base)
 
2573
        client = _SmartClient(client_medium)
2416
2574
        path = client.remote_path_from_transport(transport)
2417
2575
        response = client.call('BzrDirFormat.initialize', path)
2418
2576
        if response[0] != 'ok':
2608
2766
    for a branch that is being created.  The most basic policy decision is
2609
2767
    whether to create a new repository or use an existing one.
2610
2768
    """
 
2769
    def __init__(self, stack_on, stack_on_pwd, require_stacking):
 
2770
        """Constructor.
 
2771
 
 
2772
        :param stack_on: A location to stack on
 
2773
        :param stack_on_pwd: If stack_on is relative, the location it is
 
2774
            relative to.
 
2775
        :param require_stacking: If True, it is a failure to not stack.
 
2776
        """
 
2777
        self._stack_on = stack_on
 
2778
        self._stack_on_pwd = stack_on_pwd
 
2779
        self._require_stacking = require_stacking
2611
2780
 
2612
2781
    def configure_branch(self, branch):
2613
2782
        """Apply any configuration data from this policy to the branch.
2614
2783
 
2615
 
        Default implementation does nothing.
 
2784
        Default implementation sets repository stacking.
2616
2785
        """
2617
 
        pass
 
2786
        if self._stack_on is None:
 
2787
            return
 
2788
        if self._stack_on_pwd is None:
 
2789
            stack_on = self._stack_on
 
2790
        else:
 
2791
            try:
 
2792
                stack_on = urlutils.rebase_url(self._stack_on,
 
2793
                    self._stack_on_pwd,
 
2794
                    branch.bzrdir.root_transport.base)
 
2795
            except errors.InvalidRebaseURLs:
 
2796
                stack_on = self._get_full_stack_on()
 
2797
        try:
 
2798
            branch.set_stacked_on_url(stack_on)
 
2799
        except errors.UnstackableBranchFormat:
 
2800
            if self._require_stacking:
 
2801
                raise
 
2802
 
 
2803
    def _get_full_stack_on(self):
 
2804
        """Get a fully-qualified URL for the stack_on location."""
 
2805
        if self._stack_on is None:
 
2806
            return None
 
2807
        if self._stack_on_pwd is None:
 
2808
            return self._stack_on
 
2809
        else:
 
2810
            return urlutils.join(self._stack_on_pwd, self._stack_on)
 
2811
 
 
2812
    def _add_fallback(self, repository):
 
2813
        """Add a fallback to the supplied repository, if stacking is set."""
 
2814
        stack_on = self._get_full_stack_on()
 
2815
        if stack_on is None:
 
2816
            return
 
2817
        stacked_dir = BzrDir.open(stack_on)
 
2818
        try:
 
2819
            stacked_repo = stacked_dir.open_branch().repository
 
2820
        except errors.NotBranchError:
 
2821
            stacked_repo = stacked_dir.open_repository()
 
2822
        try:
 
2823
            repository.add_fallback_repository(stacked_repo)
 
2824
        except errors.UnstackableRepositoryFormat:
 
2825
            if self._require_stacking:
 
2826
                raise
2618
2827
 
2619
2828
    def acquire_repository(self, make_working_trees=None, shared=False):
2620
2829
        """Acquire a repository for this bzrdir.
2632
2841
class CreateRepository(RepositoryAcquisitionPolicy):
2633
2842
    """A policy of creating a new repository"""
2634
2843
 
2635
 
    def __init__(self, bzrdir):
2636
 
        RepositoryAcquisitionPolicy.__init__(self)
 
2844
    def __init__(self, bzrdir, stack_on=None, stack_on_pwd=None,
 
2845
                 require_stacking=False):
 
2846
        """
 
2847
        Constructor.
 
2848
        :param bzrdir: The bzrdir to create the repository on.
 
2849
        :param stack_on: A location to stack on
 
2850
        :param stack_on_pwd: If stack_on is relative, the location it is
 
2851
            relative to.
 
2852
        """
 
2853
        RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
 
2854
                                             require_stacking)
2637
2855
        self._bzrdir = bzrdir
2638
2856
 
2639
2857
    def acquire_repository(self, make_working_trees=None, shared=False):
2642
2860
        Creates the desired repository in the bzrdir we already have.
2643
2861
        """
2644
2862
        repository = self._bzrdir.create_repository(shared=shared)
 
2863
        self._add_fallback(repository)
2645
2864
        if make_working_trees is not None:
2646
2865
            repository.set_make_working_trees(make_working_trees)
2647
2866
        return repository
2650
2869
class UseExistingRepository(RepositoryAcquisitionPolicy):
2651
2870
    """A policy of reusing an existing repository"""
2652
2871
 
2653
 
    def __init__(self, repository):
2654
 
        RepositoryAcquisitionPolicy.__init__(self)
 
2872
    def __init__(self, repository, stack_on=None, stack_on_pwd=None,
 
2873
                 require_stacking=False):
 
2874
        """Constructor.
 
2875
 
 
2876
        :param repository: The repository to use.
 
2877
        :param stack_on: A location to stack on
 
2878
        :param stack_on_pwd: If stack_on is relative, the location it is
 
2879
            relative to.
 
2880
        """
 
2881
        RepositoryAcquisitionPolicy.__init__(self, stack_on, stack_on_pwd,
 
2882
                                             require_stacking)
2655
2883
        self._repository = repository
2656
2884
 
2657
2885
    def acquire_repository(self, make_working_trees=None, shared=False):
2659
2887
 
2660
2888
        Returns an existing repository to use
2661
2889
        """
 
2890
        self._add_fallback(self._repository)
2662
2891
        return self._repository
2663
2892
 
2664
2893
 
2746
2975
    )
2747
2976
# The following two formats should always just be aliases.
2748
2977
format_registry.register_metadir('development',
2749
 
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0',
 
2978
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment1',
2750
2979
    help='Current development format. Can convert data to and from pack-0.92 '
2751
2980
        '(and anything compatible with pack-0.92) format repositories. '
2752
 
        'Repositories in this format can only be read by bzr.dev. '
 
2981
        'Repositories and branches in this format can only be read by bzr.dev. '
2753
2982
        'Please read '
2754
2983
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
2755
2984
        'before use.',
2756
 
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2985
    branch_format='bzrlib.branch.BzrBranchFormat7',
2757
2986
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2758
2987
    experimental=True,
2759
2988
    alias=True,
2760
2989
    )
2761
2990
format_registry.register_metadir('development-subtree',
2762
 
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0Subtree',
 
2991
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment1Subtree',
2763
2992
    help='Current development format, subtree variant. Can convert data to and '
2764
 
        'from pack-0.92 (and anything compatible with pack-0.92) format '
2765
 
        'repositories. Repositories in this format can only be read by '
2766
 
        'bzr.dev. Please read '
 
2993
        'from pack-0.92-subtree (and anything compatible with '
 
2994
        'pack-0.92-subtree) format repositories. Repositories and branches in '
 
2995
        'this format can only be read by bzr.dev. Please read '
2767
2996
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
2768
2997
        'before use.',
2769
 
    branch_format='bzrlib.branch.BzrBranchFormat6',
 
2998
    branch_format='bzrlib.branch.BzrBranchFormat7',
2770
2999
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2771
3000
    experimental=True,
2772
3001
    alias=True,
2794
3023
    hidden=True,
2795
3024
    experimental=True,
2796
3025
    )
 
3026
format_registry.register_metadir('development1',
 
3027
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment1',
 
3028
    help='A branch and pack based repository that supports stacking. '
 
3029
        'Please read '
 
3030
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
 
3031
        'before use.',
 
3032
    branch_format='bzrlib.branch.BzrBranchFormat7',
 
3033
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3034
    hidden=True,
 
3035
    experimental=True,
 
3036
    )
 
3037
format_registry.register_metadir('development1-subtree',
 
3038
    'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment1Subtree',
 
3039
    help='A branch and pack based repository that supports stacking. '
 
3040
        'Please read '
 
3041
        'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
 
3042
        'before use.',
 
3043
    branch_format='bzrlib.branch.BzrBranchFormat7',
 
3044
    tree_format='bzrlib.workingtree.WorkingTreeFormat4',
 
3045
    hidden=True,
 
3046
    experimental=True,
 
3047
    )
 
3048
# The current format that is made on 'bzr init'.
2797
3049
format_registry.set_default('pack-0.92')