1# Copyright (C) 2006-2011 Canonical Ltd
2#
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 2 of the License, or
6# (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program; if not, write to the Free Software
15# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
17"""BzrDir logic. The BzrDir is the basic control directory used by bzr.
18
19At format 7 this was split out into Branch, Repository and Checkout control
20directories.
21
22Note: This module has a lot of ``open`` functions/methods that return
23references to in-memory objects. As a rule, there are no matching ``close``
24methods. To free any associated resources, simply stop referencing the
25objects returned.
26"""
27
28import sys
29
30from ..lazy_import import lazy_import
31lazy_import(globals(), """
32import contextlib
33
34from breezy import (
35    branch as _mod_branch,
36    lockable_files,
37    lockdir,
38    osutils,
39    repository,
40    revision as _mod_revision,
41    transport as _mod_transport,
42    ui,
43    urlutils,
44    win32utils,
45    )
46from breezy.bzr import (
47    branch as _mod_bzrbranch,
48    fetch,
49    remote,
50    vf_search,
51    workingtree_3,
52    workingtree_4,
53    )
54from breezy.bzr import fullhistory as fullhistorybranch
55from breezy.bzr import knitpack_repo
56from breezy.transport import (
57    do_catching_redirections,
58    local,
59    )
60from breezy.i18n import gettext
61""")
62
63from ..trace import (
64    mutter,
65    note,
66    warning,
67    )
68
69from .. import (
70    config,
71    controldir,
72    errors,
73    )
74
75
76class MissingFeature(errors.BzrError):
77
78    _fmt = ("Missing feature %(feature)s not provided by this "
79            "version of Bazaar or any plugin.")
80
81    def __init__(self, feature):
82        self.feature = feature
83
84
85class FeatureAlreadyRegistered(errors.BzrError):
86
87    _fmt = 'The feature %(feature)s has already been registered.'
88
89    def __init__(self, feature):
90        self.feature = feature
91
92
93class BzrDir(controldir.ControlDir):
94    """A .bzr control diretory.
95
96    BzrDir instances let you create or open any of the things that can be
97    found within .bzr - checkouts, branches and repositories.
98
99    :ivar transport:
100        the transport which this bzr dir is rooted at (i.e. file:///.../.bzr/)
101    :ivar root_transport:
102        a transport connected to the directory this bzr was opened from
103        (i.e. the parent directory holding the .bzr directory).
104
105    Everything in the bzrdir should have the same file permissions.
106
107    :cvar hooks: An instance of BzrDirHooks.
108    """
109
110    def break_lock(self):
111        """Invoke break_lock on the first object in the bzrdir.
112
113        If there is a tree, the tree is opened and break_lock() called.
114        Otherwise, branch is tried, and finally repository.
115        """
116        # XXX: This seems more like a UI function than something that really
117        # belongs in this class.
118        try:
119            thing_to_unlock = self.open_workingtree()
120        except (errors.NotLocalUrl, errors.NoWorkingTree):
121            try:
122                thing_to_unlock = self.open_branch()
123            except errors.NotBranchError:
124                try:
125                    thing_to_unlock = self.open_repository()
126                except errors.NoRepositoryPresent:
127                    return
128        thing_to_unlock.break_lock()
129
130    def check_conversion_target(self, target_format):
131        """Check that a bzrdir as a whole can be converted to a new format."""
132        # The only current restriction is that the repository content can be
133        # fetched compatibly with the target.
134        target_repo_format = target_format.repository_format
135        try:
136            self.open_repository()._format.check_conversion_target(
137                target_repo_format)
138        except errors.NoRepositoryPresent:
139            # No repo, no problem.
140            pass
141
142    def clone_on_transport(self, transport, revision_id=None,
143                           force_new_repo=False, preserve_stacking=False, stacked_on=None,
144                           create_prefix=False, use_existing_dir=True, no_tree=False,
145                           tag_selector=None):
146        """Clone this bzrdir and its contents to transport verbatim.
147
148        :param transport: The transport for the location to produce the clone
149            at.  If the target directory does not exist, it will be created.
150        :param revision_id: The tip revision-id to use for any branch or
151            working tree.  If not None, then the clone operation may tune
152            itself to download less data.
153        :param force_new_repo: Do not use a shared repository for the target,
154                               even if one is available.
155        :param preserve_stacking: When cloning a stacked branch, stack the
156            new branch on top of the other branch's stacked-on branch.
157        :param create_prefix: Create any missing directories leading up to
158            to_transport.
159        :param use_existing_dir: Use an existing directory if one exists.
160        :param no_tree: If set to true prevents creation of a working tree.
161        """
162        # Overview: put together a broad description of what we want to end up
163        # with; then make as few api calls as possible to do it.
164
165        # We may want to create a repo/branch/tree, if we do so what format
166        # would we want for each:
167        require_stacking = (stacked_on is not None)
168        format = self.cloning_metadir(require_stacking)
169
170        # Figure out what objects we want:
171        try:
172            local_repo = self.find_repository()
173        except errors.NoRepositoryPresent:
174            local_repo = None
175        local_branches = self.get_branches()
176        try:
177            local_active_branch = local_branches['']
178        except KeyError:
179            pass
180        else:
181            # enable fallbacks when branch is not a branch reference
182            if local_active_branch.repository.has_same_location(local_repo):
183                local_repo = local_active_branch.repository
184            if preserve_stacking:
185                try:
186                    stacked_on = local_active_branch.get_stacked_on_url()
187                except (_mod_branch.UnstackableBranchFormat,
188                        errors.UnstackableRepositoryFormat,
189                        errors.NotStacked):
190                    pass
191        # Bug: We create a metadir without knowing if it can support stacking,
192        # we should look up the policy needs first, or just use it as a hint,
193        # or something.
194        if local_repo:
195            make_working_trees = (local_repo.make_working_trees() and
196                                  not no_tree)
197            want_shared = local_repo.is_shared()
198            repo_format_name = format.repository_format.network_name()
199        else:
200            make_working_trees = False
201            want_shared = False
202            repo_format_name = None
203
204        result_repo, result, require_stacking, repository_policy = \
205            format.initialize_on_transport_ex(
206                transport, use_existing_dir=use_existing_dir,
207                create_prefix=create_prefix, force_new_repo=force_new_repo,
208                stacked_on=stacked_on, stack_on_pwd=self.root_transport.base,
209                repo_format_name=repo_format_name,
210                make_working_trees=make_working_trees, shared_repo=want_shared)
211        if repo_format_name:
212            try:
213                # If the result repository is in the same place as the
214                # resulting bzr dir, it will have no content, further if the
215                # result is not stacked then we know all content should be
216                # copied, and finally if we are copying up to a specific
217                # revision_id then we can use the pending-ancestry-result which
218                # does not require traversing all of history to describe it.
219                if (result_repo.user_url == result.user_url
220                    and not require_stacking
221                        and revision_id is not None):
222                    fetch_spec = vf_search.PendingAncestryResult(
223                        [revision_id], local_repo)
224                    result_repo.fetch(local_repo, fetch_spec=fetch_spec)
225                else:
226                    result_repo.fetch(local_repo, revision_id=revision_id)
227            finally:
228                result_repo.unlock()
229        else:
230            if result_repo is not None:
231                raise AssertionError('result_repo not None(%r)' % result_repo)
232        # 1 if there is a branch present
233        #   make sure its content is available in the target repository
234        #   clone it.
235        for name, local_branch in local_branches.items():
236            local_branch.clone(
237                result, revision_id=(None if name != '' else revision_id),
238                repository_policy=repository_policy,
239                name=name, tag_selector=tag_selector)
240        try:
241            # Cheaper to check if the target is not local, than to try making
242            # the tree and fail.
243            result.root_transport.local_abspath('.')
244            if result_repo is None or result_repo.make_working_trees():
245                self.open_workingtree().clone(result, revision_id=revision_id)
246        except (errors.NoWorkingTree, errors.NotLocalUrl):
247            pass
248        return result
249
250    # TODO: This should be given a Transport, and should chdir up; otherwise
251    # this will open a new connection.
252    def _make_tail(self, url):
253        t = _mod_transport.get_transport(url)
254        t.ensure_base()
255
256    def determine_repository_policy(self, force_new_repo=False, stack_on=None,
257                                    stack_on_pwd=None, require_stacking=False):
258        """Return an object representing a policy to use.
259
260        This controls whether a new repository is created, and the format of
261        that repository, or some existing shared repository used instead.
262
263        If stack_on is supplied, will not seek a containing shared repo.
264
265        :param force_new_repo: If True, require a new repository to be created.
266        :param stack_on: If supplied, the location to stack on.  If not
267            supplied, a default_stack_on location may be used.
268        :param stack_on_pwd: If stack_on is relative, the location it is
269            relative to.
270        """
271        def repository_policy(found_bzrdir):
272            stack_on = None
273            stack_on_pwd = None
274            config = found_bzrdir.get_config()
275            stop = False
276            stack_on = config.get_default_stack_on()
277            if stack_on is not None:
278                stack_on_pwd = found_bzrdir.user_url
279                stop = True
280            # does it have a repository ?
281            try:
282                repository = found_bzrdir.open_repository()
283            except errors.NoRepositoryPresent:
284                repository = None
285            else:
286                if (found_bzrdir.user_url != self.user_url and
287                        not repository.is_shared()):
288                    # Don't look higher, can't use a higher shared repo.
289                    repository = None
290                    stop = True
291                else:
292                    stop = True
293            if not stop:
294                return None, False
295            if repository:
296                return UseExistingRepository(
297                    repository, stack_on, stack_on_pwd,
298                    require_stacking=require_stacking), True
299            else:
300                return CreateRepository(
301                    self, stack_on, stack_on_pwd,
302                    require_stacking=require_stacking), True
303
304        if not force_new_repo:
305            if stack_on is None:
306                policy = self._find_containing(repository_policy)
307                if policy is not None:
308                    return policy
309            else:
310                try:
311                    return UseExistingRepository(
312                        self.open_repository(), stack_on, stack_on_pwd,
313                        require_stacking=require_stacking)
314                except errors.NoRepositoryPresent:
315                    pass
316        return CreateRepository(self, stack_on, stack_on_pwd,
317                                require_stacking=require_stacking)
318
319    def _find_or_create_repository(self, force_new_repo):
320        """Create a new repository if needed, returning the repository."""
321        policy = self.determine_repository_policy(force_new_repo)
322        return policy.acquire_repository()[0]
323
324    def _find_source_repo(self, exit_stack, source_branch):
325        """Find the source branch and repo for a sprout operation.
326
327        This is helper intended for use by _sprout.
328
329        :returns: (source_branch, source_repository).  Either or both may be
330            None.  If not None, they will be read-locked (and their unlock(s)
331            scheduled via the exit_stack param).
332        """
333        if source_branch is not None:
334            exit_stack.enter_context(source_branch.lock_read())
335            return source_branch, source_branch.repository
336        try:
337            source_branch = self.open_branch()
338            source_repository = source_branch.repository
339        except errors.NotBranchError:
340            source_branch = None
341            try:
342                source_repository = self.open_repository()
343            except errors.NoRepositoryPresent:
344                source_repository = None
345            else:
346                exit_stack.enter_context(source_repository.lock_read())
347        else:
348            exit_stack.enter_context(source_branch.lock_read())
349        return source_branch, source_repository
350
351    def sprout(self, url, revision_id=None, force_new_repo=False,
352               recurse='down', possible_transports=None,
353               accelerator_tree=None, hardlink=False, stacked=False,
354               source_branch=None, create_tree_if_local=True,
355               lossy=False):
356        """Create a copy of this controldir prepared for use as a new line of
357        development.
358
359        If url's last component does not exist, it will be created.
360
361        Attributes related to the identity of the source branch like
362        branch nickname will be cleaned, a working tree is created
363        whether one existed before or not; and a local branch is always
364        created.
365
366        if revision_id is not None, then the clone operation may tune
367            itself to download less data.
368
369        :param accelerator_tree: A tree which can be used for retrieving file
370            contents more quickly than the revision tree, i.e. a workingtree.
371            The revision tree will be used for cases where accelerator_tree's
372            content is different.
373        :param hardlink: If true, hard-link files from accelerator_tree,
374            where possible.
375        :param stacked: If true, create a stacked branch referring to the
376            location of this control directory.
377        :param create_tree_if_local: If true, a working-tree will be created
378            when working locally.
379        :return: The created control directory
380        """
381        with contextlib.ExitStack() as stack:
382            fetch_spec_factory = fetch.FetchSpecFactory()
383            if revision_id is not None:
384                fetch_spec_factory.add_revision_ids([revision_id])
385                fetch_spec_factory.source_branch_stop_revision_id = revision_id
386            if possible_transports is None:
387                possible_transports = []
388            else:
389                possible_transports = list(possible_transports) + [
390                    self.root_transport]
391            target_transport = _mod_transport.get_transport(url,
392                                                            possible_transports)
393            target_transport.ensure_base()
394            cloning_format = self.cloning_metadir(stacked)
395            # Create/update the result branch
396            try:
397                result = controldir.ControlDir.open_from_transport(
398                    target_transport)
399            except errors.NotBranchError:
400                result = cloning_format.initialize_on_transport(target_transport)
401            source_branch, source_repository = self._find_source_repo(
402                stack, source_branch)
403            fetch_spec_factory.source_branch = source_branch
404            # if a stacked branch wasn't requested, we don't create one
405            # even if the origin was stacked
406            if stacked and source_branch is not None:
407                stacked_branch_url = self.root_transport.base
408            else:
409                stacked_branch_url = None
410            repository_policy = result.determine_repository_policy(
411                force_new_repo, stacked_branch_url, require_stacking=stacked)
412            result_repo, is_new_repo = repository_policy.acquire_repository(
413                possible_transports=possible_transports)
414            stack.enter_context(result_repo.lock_write())
415            fetch_spec_factory.source_repo = source_repository
416            fetch_spec_factory.target_repo = result_repo
417            if stacked or (len(result_repo._fallback_repositories) != 0):
418                target_repo_kind = fetch.TargetRepoKinds.STACKED
419            elif is_new_repo:
420                target_repo_kind = fetch.TargetRepoKinds.EMPTY
421            else:
422                target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
423            fetch_spec_factory.target_repo_kind = target_repo_kind
424            if source_repository is not None:
425                fetch_spec = fetch_spec_factory.make_fetch_spec()
426                result_repo.fetch(source_repository, fetch_spec=fetch_spec)
427
428            if source_branch is None:
429                # this is for sprouting a controldir without a branch; is that
430                # actually useful?
431                # Not especially, but it's part of the contract.
432                result_branch = result.create_branch()
433                if revision_id is not None:
434                    result_branch.generate_revision_history(revision_id)
435            else:
436                result_branch = source_branch.sprout(
437                    result, revision_id=revision_id,
438                    repository_policy=repository_policy, repository=result_repo)
439            mutter("created new branch %r" % (result_branch,))
440
441            # Create/update the result working tree
442            if (create_tree_if_local and not result.has_workingtree()
443                    and isinstance(target_transport, local.LocalTransport)
444                    and (result_repo is None or result_repo.make_working_trees())
445                    and result.open_branch(
446                        name="",
447                        possible_transports=possible_transports).name == result_branch.name):
448                wt = result.create_workingtree(
449                    accelerator_tree=accelerator_tree, hardlink=hardlink,
450                    from_branch=result_branch)
451                with wt.lock_write():
452                    if not wt.is_versioned(''):
453                        try:
454                            wt.set_root_id(self.open_workingtree.path2id(''))
455                        except errors.NoWorkingTree:
456                            pass
457            else:
458                wt = None
459            if recurse == 'down':
460                tree = None
461                if wt is not None:
462                    tree = wt
463                    basis = tree.basis_tree()
464                    stack.enter_context(basis.lock_read())
465                elif result_branch is not None:
466                    basis = tree = result_branch.basis_tree()
467                elif source_branch is not None:
468                    basis = tree = source_branch.basis_tree()
469                if tree is not None:
470                    stack.enter_context(tree.lock_read())
471                    subtrees = tree.iter_references()
472                else:
473                    subtrees = []
474                for path in subtrees:
475                    target = urlutils.join(url, urlutils.escape(path))
476                    sublocation = tree.reference_parent(
477                        path, branch=result_branch,
478                        possible_transports=possible_transports)
479                    if sublocation is None:
480                        warning(
481                            'Ignoring nested tree %s, parent location unknown.',
482                            path)
483                        continue
484                    sublocation.controldir.sprout(
485                        target, basis.get_reference_revision(path),
486                        force_new_repo=force_new_repo, recurse=recurse,
487                        stacked=stacked)
488            return result
489
490    def _available_backup_name(self, base):
491        """Find a non-existing backup file name based on base.
492
493        See breezy.osutils.available_backup_name about race conditions.
494        """
495        return osutils.available_backup_name(base, self.root_transport.has)
496
497    def backup_bzrdir(self):
498        """Backup this bzr control directory.
499
500        :return: Tuple with old path name and new path name
501        """
502
503        with ui.ui_factory.nested_progress_bar():
504            old_path = self.root_transport.abspath('.bzr')
505            backup_dir = self._available_backup_name('backup.bzr')
506            new_path = self.root_transport.abspath(backup_dir)
507            ui.ui_factory.note(
508                gettext('making backup of {0}\n  to {1}').format(
509                    urlutils.unescape_for_display(old_path, 'utf-8'),
510                    urlutils.unescape_for_display(new_path, 'utf-8')))
511            self.root_transport.copy_tree('.bzr', backup_dir)
512            return (old_path, new_path)
513
514    def retire_bzrdir(self, limit=10000):
515        """Permanently disable the bzrdir.
516
517        This is done by renaming it to give the user some ability to recover
518        if there was a problem.
519
520        This will have horrible consequences if anyone has anything locked or
521        in use.
522        :param limit: number of times to retry
523        """
524        i = 0
525        while True:
526            try:
527                to_path = '.bzr.retired.%d' % i
528                self.root_transport.rename('.bzr', to_path)
529                note(gettext("renamed {0} to {1}").format(
530                    self.root_transport.abspath('.bzr'), to_path))
531                return
532            except (errors.TransportError, IOError, errors.PathError):
533                i += 1
534                if i > limit:
535                    raise
536                else:
537                    pass
538
539    def _find_containing(self, evaluate):
540        """Find something in a containing control directory.
541
542        This method will scan containing control dirs, until it finds what
543        it is looking for, decides that it will never find it, or runs out
544        of containing control directories to check.
545
546        It is used to implement find_repository and
547        determine_repository_policy.
548
549        :param evaluate: A function returning (value, stop).  If stop is True,
550            the value will be returned.
551        """
552        found_bzrdir = self
553        while True:
554            result, stop = evaluate(found_bzrdir)
555            if stop:
556                return result
557            next_transport = found_bzrdir.root_transport.clone('..')
558            if (found_bzrdir.user_url == next_transport.base):
559                # top of the file system
560                return None
561            # find the next containing bzrdir
562            try:
563                found_bzrdir = self.open_containing_from_transport(
564                    next_transport)[0]
565            except errors.NotBranchError:
566                return None
567
568    def find_repository(self):
569        """Find the repository that should be used.
570
571        This does not require a branch as we use it to find the repo for
572        new branches as well as to hook existing branches up to their
573        repository.
574        """
575        def usable_repository(found_bzrdir):
576            # does it have a repository ?
577            try:
578                repository = found_bzrdir.open_repository()
579            except errors.NoRepositoryPresent:
580                return None, False
581            if found_bzrdir.user_url == self.user_url:
582                return repository, True
583            elif repository.is_shared():
584                return repository, True
585            else:
586                return None, True
587
588        found_repo = self._find_containing(usable_repository)
589        if found_repo is None:
590            raise errors.NoRepositoryPresent(self)
591        return found_repo
592
593    def _find_creation_modes(self):
594        """Determine the appropriate modes for files and directories.
595
596        They're always set to be consistent with the base directory,
597        assuming that this transport allows setting modes.
598        """
599        # TODO: Do we need or want an option (maybe a config setting) to turn
600        # this off or override it for particular locations? -- mbp 20080512
601        if self._mode_check_done:
602            return
603        self._mode_check_done = True
604        try:
605            st = self.transport.stat('.')
606        except errors.TransportNotPossible:
607            self._dir_mode = None
608            self._file_mode = None
609        else:
610            # Check the directory mode, but also make sure the created
611            # directories and files are read-write for this user. This is
612            # mostly a workaround for filesystems which lie about being able to
613            # write to a directory (cygwin & win32)
614            if (st.st_mode & 0o7777 == 00000):
615                # FTP allows stat but does not return dir/file modes
616                self._dir_mode = None
617                self._file_mode = None
618            else:
619                self._dir_mode = (st.st_mode & 0o7777) | 0o0700
620                # Remove the sticky and execute bits for files
621                self._file_mode = self._dir_mode & ~0o7111
622
623    def _get_file_mode(self):
624        """Return Unix mode for newly created files, or None.
625        """
626        if not self._mode_check_done:
627            self._find_creation_modes()
628        return self._file_mode
629
630    def _get_dir_mode(self):
631        """Return Unix mode for newly created directories, or None.
632        """
633        if not self._mode_check_done:
634            self._find_creation_modes()
635        return self._dir_mode
636
637    def get_config(self):
638        """Get configuration for this BzrDir."""
639        return config.BzrDirConfig(self)
640
641    def _get_config(self):
642        """By default, no configuration is available."""
643        return None
644
645    def __init__(self, _transport, _format):
646        """Initialize a Bzr control dir object.
647
648        Only really common logic should reside here, concrete classes should be
649        made with varying behaviours.
650
651        :param _format: the format that is creating this BzrDir instance.
652        :param _transport: the transport this dir is based at.
653        """
654        self._format = _format
655        # these are also under the more standard names of
656        # control_transport and user_transport
657        self.transport = _transport.clone('.bzr')
658        self.root_transport = _transport
659        self._mode_check_done = False
660
661    @property
662    def user_transport(self):
663        return self.root_transport
664
665    @property
666    def control_transport(self):
667        return self.transport
668
669    def _cloning_metadir(self):
670        """Produce a metadir suitable for cloning with.
671
672        :returns: (destination_bzrdir_format, source_repository)
673        """
674        result_format = self._format.__class__()
675        try:
676            try:
677                branch = self.open_branch(ignore_fallbacks=True)
678                source_repository = branch.repository
679                result_format._branch_format = branch._format
680            except errors.NotBranchError:
681                source_repository = self.open_repository()
682        except errors.NoRepositoryPresent:
683            source_repository = None
684        else:
685            # XXX TODO: This isinstance is here because we have not implemented
686            # the fix recommended in bug # 103195 - to delegate this choice the
687            # repository itself.
688            repo_format = source_repository._format
689            if isinstance(repo_format, remote.RemoteRepositoryFormat):
690                source_repository._ensure_real()
691                repo_format = source_repository._real_repository._format
692            result_format.repository_format = repo_format
693        try:
694            # TODO: Couldn't we just probe for the format in these cases,
695            # rather than opening the whole tree?  It would be a little
696            # faster. mbp 20070401
697            tree = self.open_workingtree(recommend_upgrade=False)
698        except (errors.NoWorkingTree, errors.NotLocalUrl):
699            result_format.workingtree_format = None
700        else:
701            result_format.workingtree_format = tree._format.__class__()
702        return result_format, source_repository
703
704    def cloning_metadir(self, require_stacking=False):
705        """Produce a metadir suitable for cloning or sprouting with.
706
707        These operations may produce workingtrees (yes, even though they're
708        "cloning" something that doesn't have a tree), so a viable workingtree
709        format must be selected.
710
711        :require_stacking: If True, non-stackable formats will be upgraded
712            to similar stackable formats.
713        :returns: a ControlDirFormat with all component formats either set
714            appropriately or set to None if that component should not be
715            created.
716        """
717        format, repository = self._cloning_metadir()
718        if format._workingtree_format is None:
719            # No tree in self.
720            if repository is None:
721                # No repository either
722                return format
723            # We have a repository, so set a working tree? (Why? This seems to
724            # contradict the stated return value in the docstring).
725            tree_format = (
726                repository._format._matchingcontroldir.workingtree_format)
727            format.workingtree_format = tree_format.__class__()
728        if require_stacking:
729            format.require_stacking()
730        return format
731
732    def get_branch_transport(self, branch_format, name=None):
733        """Get the transport for use by branch format in this BzrDir.
734
735        Note that bzr dirs that do not support format strings will raise
736        IncompatibleFormat if the branch format they are given has
737        a format string, and vice versa.
738
739        If branch_format is None, the transport is returned with no
740        checking. If it is not None, then the returned transport is
741        guaranteed to point to an existing directory ready for use.
742        """
743        raise NotImplementedError(self.get_branch_transport)
744
745    def get_repository_transport(self, repository_format):
746        """Get the transport for use by repository format in this BzrDir.
747
748        Note that bzr dirs that do not support format strings will raise
749        IncompatibleFormat if the repository format they are given has
750        a format string, and vice versa.
751
752        If repository_format is None, the transport is returned with no
753        checking. If it is not None, then the returned transport is
754        guaranteed to point to an existing directory ready for use.
755        """
756        raise NotImplementedError(self.get_repository_transport)
757
758    def get_workingtree_transport(self, tree_format):
759        """Get the transport for use by workingtree format in this BzrDir.
760
761        Note that bzr dirs that do not support format strings will raise
762        IncompatibleFormat if the workingtree format they are given has a
763        format string, and vice versa.
764
765        If workingtree_format is None, the transport is returned with no
766        checking. If it is not None, then the returned transport is
767        guaranteed to point to an existing directory ready for use.
768        """
769        raise NotImplementedError(self.get_workingtree_transport)
770
771    @classmethod
772    def create(cls, base, format=None, possible_transports=None):
773        """Create a new BzrDir at the url 'base'.
774
775        :param format: If supplied, the format of branch to create.  If not
776            supplied, the default is used.
777        :param possible_transports: If supplied, a list of transports that
778            can be reused to share a remote connection.
779        """
780        if cls is not BzrDir:
781            raise AssertionError("BzrDir.create always creates the "
782                                 "default format, not one of %r" % cls)
783        return controldir.ControlDir.create(
784            base, format=format, possible_transports=possible_transports)
785
786    def __repr__(self):
787        return "<%s at %r>" % (self.__class__.__name__, self.user_url)
788
789    def update_feature_flags(self, updated_flags):
790        """Update the features required by this bzrdir.
791
792        :param updated_flags: Dictionary mapping feature names to necessities
793            A necessity can be None to indicate the feature should be removed
794        """
795        self.control_files.lock_write()
796        try:
797            self._format._update_feature_flags(updated_flags)
798            self.transport.put_bytes('branch-format', self._format.as_string())
799        finally:
800            self.control_files.unlock()
801
802
803class BzrDirMeta1(BzrDir):
804    """A .bzr meta version 1 control object.
805
806    This is the first control object where the
807    individual aspects are really split out: there are separate repository,
808    workingtree and branch subdirectories and any subset of the three can be
809    present within a BzrDir.
810    """
811
812    def _get_branch_path(self, name):
813        """Obtain the branch path to use.
814
815        This uses the API specified branch name first, and then falls back to
816        the branch name specified in the URL. If neither of those is specified,
817        it uses the default branch.
818
819        :param name: Optional branch name to use
820        :return: Relative path to branch
821        """
822        if name == "":
823            return 'branch'
824        return urlutils.join('branches', urlutils.escape(name))
825
826    def _read_branch_list(self):
827        """Read the branch list.
828
829        :return: List of branch names.
830        """
831        try:
832            f = self.control_transport.get('branch-list')
833        except errors.NoSuchFile:
834            return []
835
836        ret = []
837        try:
838            for name in f:
839                ret.append(name.rstrip(b"\n").decode('utf-8'))
840        finally:
841            f.close()
842        return ret
843
844    def _write_branch_list(self, branches):
845        """Write out the branch list.
846
847        :param branches: List of utf-8 branch names to write
848        """
849        self.transport.put_bytes(
850            'branch-list',
851            b"".join([name.encode('utf-8') + b"\n" for name in branches]))
852
853    def __init__(self, _transport, _format):
854        super(BzrDirMeta1, self).__init__(_transport, _format)
855        self.control_files = lockable_files.LockableFiles(
856            self.control_transport, self._format._lock_file_name,
857            self._format._lock_class)
858
859    def can_convert_format(self):
860        """See BzrDir.can_convert_format()."""
861        return True
862
863    def create_branch(self, name=None, repository=None,
864                      append_revisions_only=None):
865        """See ControlDir.create_branch."""
866        if name is None:
867            name = self._get_selected_branch()
868        return self._format.get_branch_format().initialize(
869            self, name=name, repository=repository,
870            append_revisions_only=append_revisions_only)
871
872    def destroy_branch(self, name=None):
873        """See ControlDir.destroy_branch."""
874        if name is None:
875            name = self._get_selected_branch()
876        path = self._get_branch_path(name)
877        if name != u"":
878            self.control_files.lock_write()
879            try:
880                branches = self._read_branch_list()
881                try:
882                    branches.remove(name)
883                except ValueError:
884                    raise errors.NotBranchError(name)
885                self._write_branch_list(branches)
886            finally:
887                self.control_files.unlock()
888        try:
889            self.transport.delete_tree(path)
890        except errors.NoSuchFile:
891            raise errors.NotBranchError(
892                path=urlutils.join(self.transport.base, path), controldir=self)
893
894    def create_repository(self, shared=False):
895        """See BzrDir.create_repository."""
896        return self._format.repository_format.initialize(self, shared)
897
898    def destroy_repository(self):
899        """See BzrDir.destroy_repository."""
900        try:
901            self.transport.delete_tree('repository')
902        except errors.NoSuchFile:
903            raise errors.NoRepositoryPresent(self)
904
905    def create_workingtree(self, revision_id=None, from_branch=None,
906                           accelerator_tree=None, hardlink=False):
907        """See BzrDir.create_workingtree."""
908        return self._format.workingtree_format.initialize(
909            self, revision_id, from_branch=from_branch,
910            accelerator_tree=accelerator_tree, hardlink=hardlink)
911
912    def destroy_workingtree(self):
913        """See BzrDir.destroy_workingtree."""
914        wt = self.open_workingtree(recommend_upgrade=False)
915        repository = wt.branch.repository
916        empty = repository.revision_tree(_mod_revision.NULL_REVISION)
917        # We ignore the conflicts returned by wt.revert since we're about to
918        # delete the wt metadata anyway, all that should be left here are
919        # detritus. But see bug #634470 about subtree .bzr dirs.
920        wt.revert(old_tree=empty)
921        self.destroy_workingtree_metadata()
922
923    def destroy_workingtree_metadata(self):
924        self.transport.delete_tree('checkout')
925
926    def find_branch_format(self, name=None):
927        """Find the branch 'format' for this bzrdir.
928
929        This might be a synthetic object for e.g. RemoteBranch and SVN.
930        """
931        from .branch import BranchFormatMetadir
932        return BranchFormatMetadir.find_format(self, name=name)
933
934    def _get_mkdir_mode(self):
935        """Figure out the mode to use when creating a bzrdir subdir."""
936        temp_control = lockable_files.LockableFiles(
937            self.transport, '', lockable_files.TransportLock)
938        return temp_control._dir_mode
939
940    def get_branch_reference(self, name=None):
941        """See BzrDir.get_branch_reference()."""
942        from .branch import BranchFormatMetadir
943        format = BranchFormatMetadir.find_format(self, name=name)
944        return format.get_reference(self, name=name)
945
946    def set_branch_reference(self, target_branch, name=None):
947        format = _mod_bzrbranch.BranchReferenceFormat()
948        if (self.control_url == target_branch.controldir.control_url
949                and name == target_branch.name):
950            raise controldir.BranchReferenceLoop(target_branch)
951        return format.initialize(self, target_branch=target_branch, name=name)
952
953    def get_branch_transport(self, branch_format, name=None):
954        """See BzrDir.get_branch_transport()."""
955        if name is None:
956            name = self._get_selected_branch()
957        path = self._get_branch_path(name)
958        # XXX: this shouldn't implicitly create the directory if it's just
959        # promising to get a transport -- mbp 20090727
960        if branch_format is None:
961            return self.transport.clone(path)
962        try:
963            branch_format.get_format_string()
964        except NotImplementedError:
965            raise errors.IncompatibleFormat(branch_format, self._format)
966        if name != "":
967            branches = self._read_branch_list()
968            if name not in branches:
969                self.control_files.lock_write()
970                try:
971                    branches = self._read_branch_list()
972                    dirname = urlutils.dirname(name)
973                    if dirname != u"" and dirname in branches:
974                        raise errors.ParentBranchExists(name)
975                    child_branches = [
976                        b.startswith(name + u"/") for b in branches]
977                    if any(child_branches):
978                        raise errors.AlreadyBranchError(name)
979                    branches.append(name)
980                    self._write_branch_list(branches)
981                finally:
982                    self.control_files.unlock()
983        branch_transport = self.transport.clone(path)
984        mode = self._get_mkdir_mode()
985        branch_transport.create_prefix(mode=mode)
986        try:
987            self.transport.mkdir(path, mode=mode)
988        except errors.FileExists:
989            pass
990        return self.transport.clone(path)
991
992    def get_repository_transport(self, repository_format):
993        """See BzrDir.get_repository_transport()."""
994        if repository_format is None:
995            return self.transport.clone('repository')
996        try:
997            repository_format.get_format_string()
998        except NotImplementedError:
999            raise errors.IncompatibleFormat(repository_format, self._format)
1000        try:
1001            self.transport.mkdir('repository', mode=self._get_mkdir_mode())
1002        except errors.FileExists:
1003            pass
1004        return self.transport.clone('repository')
1005
1006    def get_workingtree_transport(self, workingtree_format):
1007        """See BzrDir.get_workingtree_transport()."""
1008        if workingtree_format is None:
1009            return self.transport.clone('checkout')
1010        try:
1011            workingtree_format.get_format_string()
1012        except NotImplementedError:
1013            raise errors.IncompatibleFormat(workingtree_format, self._format)
1014        try:
1015            self.transport.mkdir('checkout', mode=self._get_mkdir_mode())
1016        except errors.FileExists:
1017            pass
1018        return self.transport.clone('checkout')
1019
1020    def branch_names(self):
1021        """See ControlDir.branch_names."""
1022        ret = []
1023        try:
1024            self.get_branch_reference()
1025        except errors.NotBranchError:
1026            pass
1027        else:
1028            ret.append("")
1029        ret.extend(self._read_branch_list())
1030        return ret
1031
1032    def get_branches(self):
1033        """See ControlDir.get_branches."""
1034        ret = {}
1035        try:
1036            ret[""] = self.open_branch(name="")
1037        except (errors.NotBranchError, errors.NoRepositoryPresent):
1038            pass
1039
1040        for name in self._read_branch_list():
1041            ret[name] = self.open_branch(name=name)
1042
1043        return ret
1044
1045    def has_workingtree(self):
1046        """Tell if this bzrdir contains a working tree.
1047
1048        Note: if you're going to open the working tree, you should just go
1049        ahead and try, and not ask permission first.
1050        """
1051        from .workingtree import WorkingTreeFormatMetaDir
1052        try:
1053            WorkingTreeFormatMetaDir.find_format_string(self)
1054        except errors.NoWorkingTree:
1055            return False
1056        return True
1057
1058    def needs_format_conversion(self, format):
1059        """See BzrDir.needs_format_conversion()."""
1060        if (not isinstance(self._format, format.__class__)
1061                or self._format.get_format_string() != format.get_format_string()):
1062            # it is not a meta dir format, conversion is needed.
1063            return True
1064        # we might want to push this down to the repository?
1065        try:
1066            if not isinstance(self.open_repository()._format,
1067                              format.repository_format.__class__):
1068                # the repository needs an upgrade.
1069                return True
1070        except errors.NoRepositoryPresent:
1071            pass
1072        for branch in self.list_branches():
1073            if not isinstance(branch._format,
1074                              format.get_branch_format().__class__):
1075                # the branch needs an upgrade.
1076                return True
1077        try:
1078            my_wt = self.open_workingtree(recommend_upgrade=False)
1079            if not isinstance(my_wt._format,
1080                              format.workingtree_format.__class__):
1081                # the workingtree needs an upgrade.
1082                return True
1083        except (errors.NoWorkingTree, errors.NotLocalUrl):
1084            pass
1085        return False
1086
1087    def open_branch(self, name=None, unsupported=False,
1088                    ignore_fallbacks=False, possible_transports=None):
1089        """See ControlDir.open_branch."""
1090        if name is None:
1091            name = self._get_selected_branch()
1092        format = self.find_branch_format(name=name)
1093        format.check_support_status(unsupported)
1094        if possible_transports is None:
1095            possible_transports = []
1096        else:
1097            possible_transports = list(possible_transports)
1098        possible_transports.append(self.root_transport)
1099        return format.open(self, name=name,
1100                           _found=True, ignore_fallbacks=ignore_fallbacks,
1101                           possible_transports=possible_transports)
1102
1103    def open_repository(self, unsupported=False):
1104        """See BzrDir.open_repository."""
1105        from .repository import RepositoryFormatMetaDir
1106        format = RepositoryFormatMetaDir.find_format(self)
1107        format.check_support_status(unsupported)
1108        return format.open(self, _found=True)
1109
1110    def open_workingtree(self, unsupported=False,
1111                         recommend_upgrade=True):
1112        """See BzrDir.open_workingtree."""
1113        from .workingtree import WorkingTreeFormatMetaDir
1114        format = WorkingTreeFormatMetaDir.find_format(self)
1115        format.check_support_status(unsupported, recommend_upgrade,
1116                                    basedir=self.root_transport.base)
1117        return format.open(self, _found=True)
1118
1119    def _get_config(self):
1120        return config.TransportConfig(self.transport, 'control.conf')
1121
1122
1123class BzrFormat(object):
1124    """Base class for all formats of things living in metadirs.
1125
1126    This class manages the format string that is stored in the 'format'
1127    or 'branch-format' file.
1128
1129    All classes for (branch-, repository-, workingtree-) formats that
1130    live in meta directories and have their own 'format' file
1131    (i.e. different from .bzr/branch-format) derive from this class,
1132    as well as the relevant base class for their kind
1133    (BranchFormat, WorkingTreeFormat, RepositoryFormat).
1134
1135    Each format is identified by a "format" or "branch-format" file with a
1136    single line containing the base format name and then an optional list of
1137    feature flags.
1138
1139    Feature flags are supported as of bzr 2.5. Setting feature flags on formats
1140    will render them inaccessible to older versions of bzr.
1141
1142    :ivar features: Dictionary mapping feature names to their necessity
1143    """
1144
1145    _present_features = set()
1146
1147    def __init__(self):
1148        self.features = {}
1149
1150    @classmethod
1151    def register_feature(cls, name):
1152        """Register a feature as being present.
1153
1154        :param name: Name of the feature
1155        """
1156        if b" " in name:
1157            raise ValueError("spaces are not allowed in feature names")
1158        if name in cls._present_features:
1159            raise FeatureAlreadyRegistered(name)
1160        cls._present_features.add(name)
1161
1162    @classmethod
1163    def unregister_feature(cls, name):
1164        """Unregister a feature."""
1165        cls._present_features.remove(name)
1166
1167    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
1168                             basedir=None):
1169        for name, necessity in self.features.items():
1170            if name in self._present_features:
1171                continue
1172            if necessity == b"optional":
1173                mutter("ignoring optional missing feature %s", name)
1174                continue
1175            elif necessity == b"required":
1176                raise MissingFeature(name)
1177            else:
1178                mutter("treating unknown necessity as require for %s",
1179                       name)
1180                raise MissingFeature(name)
1181
1182    @classmethod
1183    def get_format_string(cls):
1184        """Return the ASCII format string that identifies this format."""
1185        raise NotImplementedError(cls.get_format_string)
1186
1187    @classmethod
1188    def from_string(cls, text):
1189        format_string = cls.get_format_string()
1190        if not text.startswith(format_string):
1191            raise AssertionError(
1192                "Invalid format header %r for %r" % (text, cls))
1193        lines = text[len(format_string):].splitlines()
1194        ret = cls()
1195        for lineno, line in enumerate(lines):
1196            try:
1197                (necessity, feature) = line.split(b" ", 1)
1198            except ValueError:
1199                raise errors.ParseFormatError(format=cls, lineno=lineno + 2,
1200                                              line=line, text=text)
1201            ret.features[feature] = necessity
1202        return ret
1203
1204    def as_string(self):
1205        """Return the string representation of this format.
1206        """
1207        lines = [self.get_format_string()]
1208        lines.extend([(item[1] + b" " + item[0] + b"\n")
1209                      for item in sorted(self.features.items())])
1210        return b"".join(lines)
1211
1212    @classmethod
1213    def _find_format(klass, registry, kind, format_string):
1214        try:
1215            first_line = format_string[:format_string.index(b"\n") + 1]
1216        except ValueError:
1217            first_line = format_string
1218        try:
1219            cls = registry.get(first_line)
1220        except KeyError:
1221            raise errors.UnknownFormatError(format=first_line, kind=kind)
1222        return cls.from_string(format_string)
1223
1224    def network_name(self):
1225        """A simple byte string uniquely identifying this format for RPC calls.
1226
1227        Metadir branch formats use their format string.
1228        """
1229        return self.as_string()
1230
1231    def __eq__(self, other):
1232        return (self.__class__ is other.__class__
1233                and self.features == other.features)
1234
1235    def _update_feature_flags(self, updated_flags):
1236        """Update the feature flags in this format.
1237
1238        :param updated_flags: Updated feature flags
1239        """
1240        for name, necessity in updated_flags.items():
1241            if necessity is None:
1242                try:
1243                    del self.features[name]
1244                except KeyError:
1245                    pass
1246            else:
1247                self.features[name] = necessity
1248
1249
1250class BzrDirFormat(BzrFormat, controldir.ControlDirFormat):
1251    """ControlDirFormat base class for .bzr/ directories.
1252
1253    Formats are placed in a dict by their format string for reference
1254    during bzrdir opening. These should be subclasses of BzrDirFormat
1255    for consistency.
1256
1257    Once a format is deprecated, just deprecate the initialize and open
1258    methods on the format class. Do not deprecate the object, as the
1259    object will be created every system load.
1260    """
1261
1262    _lock_file_name = 'branch-lock'
1263
1264    # _lock_class must be set in subclasses to the lock type, typ.
1265    # TransportLock or LockDir
1266
1267    def initialize_on_transport(self, transport):
1268        """Initialize a new bzrdir in the base directory of a Transport."""
1269        try:
1270            # can we hand off the request to the smart server rather than using
1271            # vfs calls?
1272            client_medium = transport.get_smart_medium()
1273        except errors.NoSmartMedium:
1274            return self._initialize_on_transport_vfs(transport)
1275        else:
1276            # Current RPC's only know how to create bzr metadir1 instances, so
1277            # we still delegate to vfs methods if the requested format is not a
1278            # metadir1
1279            if not isinstance(self, BzrDirMetaFormat1):
1280                return self._initialize_on_transport_vfs(transport)
1281            from .remote import RemoteBzrDirFormat
1282            remote_format = RemoteBzrDirFormat()
1283            self._supply_sub_formats_to(remote_format)
1284            return remote_format.initialize_on_transport(transport)
1285
1286    def initialize_on_transport_ex(self, transport, use_existing_dir=False,
1287                                   create_prefix=False, force_new_repo=False, stacked_on=None,
1288                                   stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
1289                                   shared_repo=False, vfs_only=False):
1290        """Create this format on transport.
1291
1292        The directory to initialize will be created.
1293
1294        :param force_new_repo: Do not use a shared repository for the target,
1295                               even if one is available.
1296        :param create_prefix: Create any missing directories leading up to
1297            to_transport.
1298        :param use_existing_dir: Use an existing directory if one exists.
1299        :param stacked_on: A url to stack any created branch on, None to follow
1300            any target stacking policy.
1301        :param stack_on_pwd: If stack_on is relative, the location it is
1302            relative to.
1303        :param repo_format_name: If non-None, a repository will be
1304            made-or-found. Should none be found, or if force_new_repo is True
1305            the repo_format_name is used to select the format of repository to
1306            create.
1307        :param make_working_trees: Control the setting of make_working_trees
1308            for a new shared repository when one is made. None to use whatever
1309            default the format has.
1310        :param shared_repo: Control whether made repositories are shared or
1311            not.
1312        :param vfs_only: If True do not attempt to use a smart server
1313        :return: repo, controldir, require_stacking, repository_policy. repo is
1314            None if none was created or found, bzrdir is always valid.
1315            require_stacking is the result of examining the stacked_on
1316            parameter and any stacking policy found for the target.
1317        """
1318        if not vfs_only:
1319            # Try to hand off to a smart server
1320            try:
1321                client_medium = transport.get_smart_medium()
1322            except errors.NoSmartMedium:
1323                pass
1324            else:
1325                from .remote import RemoteBzrDirFormat
1326                # TODO: lookup the local format from a server hint.
1327                remote_dir_format = RemoteBzrDirFormat()
1328                remote_dir_format._network_name = self.network_name()
1329                self._supply_sub_formats_to(remote_dir_format)
1330                return remote_dir_format.initialize_on_transport_ex(
1331                    transport, use_existing_dir=use_existing_dir,
1332                    create_prefix=create_prefix, force_new_repo=force_new_repo,
1333                    stacked_on=stacked_on, stack_on_pwd=stack_on_pwd,
1334                    repo_format_name=repo_format_name,
1335                    make_working_trees=make_working_trees,
1336                    shared_repo=shared_repo)
1337        # XXX: Refactor the create_prefix/no_create_prefix code into a
1338        #      common helper function
1339        # The destination may not exist - if so make it according to policy.
1340
1341        def make_directory(transport):
1342            transport.mkdir('.')
1343            return transport
1344
1345        def redirected(transport, e, redirection_notice):
1346            note(redirection_notice)
1347            return transport._redirected_to(e.source, e.target)
1348        try:
1349            transport = do_catching_redirections(make_directory, transport,
1350                                                 redirected)
1351        except errors.FileExists:
1352            if not use_existing_dir:
1353                raise
1354        except errors.NoSuchFile:
1355            if not create_prefix:
1356                raise
1357            transport.create_prefix()
1358
1359        require_stacking = (stacked_on is not None)
1360        # Now the target directory exists, but doesn't have a .bzr
1361        # directory. So we need to create it, along with any work to create
1362        # all of the dependent branches, etc.
1363
1364        result = self.initialize_on_transport(transport)
1365        if repo_format_name:
1366            try:
1367                # use a custom format
1368                result._format.repository_format = \
1369                    repository.network_format_registry.get(repo_format_name)
1370            except AttributeError:
1371                # The format didn't permit it to be set.
1372                pass
1373            # A repository is desired, either in-place or shared.
1374            repository_policy = result.determine_repository_policy(
1375                force_new_repo, stacked_on, stack_on_pwd,
1376                require_stacking=require_stacking)
1377            result_repo, is_new_repo = repository_policy.acquire_repository(
1378                make_working_trees, shared_repo)
1379            if not require_stacking and repository_policy._require_stacking:
1380                require_stacking = True
1381                result._format.require_stacking()
1382            result_repo.lock_write()
1383        else:
1384            result_repo = None
1385            repository_policy = None
1386        return result_repo, result, require_stacking, repository_policy
1387
1388    def _initialize_on_transport_vfs(self, transport):
1389        """Initialize a new bzrdir using VFS calls.
1390
1391        :param transport: The transport to create the .bzr directory in.
1392        :return: A
1393        """
1394        # Since we are creating a .bzr directory, inherit the
1395        # mode from the root directory
1396        temp_control = lockable_files.LockableFiles(transport,
1397                                                    '', lockable_files.TransportLock)
1398        try:
1399            temp_control._transport.mkdir('.bzr',
1400                                          # FIXME: RBC 20060121 don't peek under
1401                                          # the covers
1402                                          mode=temp_control._dir_mode)
1403        except errors.FileExists:
1404            raise errors.AlreadyControlDirError(transport.base)
1405        if sys.platform == 'win32' and isinstance(transport, local.LocalTransport):
1406            win32utils.set_file_attr_hidden(transport._abspath('.bzr'))
1407        file_mode = temp_control._file_mode
1408        del temp_control
1409        bzrdir_transport = transport.clone('.bzr')
1410        utf8_files = [('README',
1411                       b"This is a Bazaar control directory.\n"
1412                       b"Do not change any files in this directory.\n"
1413                       b"See http://bazaar.canonical.com/ for more information about Bazaar.\n"),
1414                      ('branch-format', self.as_string()),
1415                      ]
1416        # NB: no need to escape relative paths that are url safe.
1417        control_files = lockable_files.LockableFiles(bzrdir_transport,
1418                                                     self._lock_file_name, self._lock_class)
1419        control_files.create_lock()
1420        control_files.lock_write()
1421        try:
1422            for (filename, content) in utf8_files:
1423                bzrdir_transport.put_bytes(filename, content,
1424                                           mode=file_mode)
1425        finally:
1426            control_files.unlock()
1427        return self.open(transport, _found=True)
1428
1429    def open(self, transport, _found=False):
1430        """Return an instance of this format for the dir transport points at.
1431
1432        _found is a private parameter, do not use it.
1433        """
1434        if not _found:
1435            found_format = controldir.ControlDirFormat.find_format(transport)
1436            if not isinstance(found_format, self.__class__):
1437                raise AssertionError("%s was asked to open %s, but it seems to need "
1438                                     "format %s"
1439                                     % (self, transport, found_format))
1440            # Allow subclasses - use the found format.
1441            self._supply_sub_formats_to(found_format)
1442            return found_format._open(transport)
1443        return self._open(transport)
1444
1445    def _open(self, transport):
1446        """Template method helper for opening BzrDirectories.
1447
1448        This performs the actual open and any additional logic or parameter
1449        passing.
1450        """
1451        raise NotImplementedError(self._open)
1452
1453    def _supply_sub_formats_to(self, other_format):
1454        """Give other_format the same values for sub formats as this has.
1455
1456        This method is expected to be used when parameterising a
1457        RemoteBzrDirFormat instance with the parameters from a
1458        BzrDirMetaFormat1 instance.
1459
1460        :param other_format: other_format is a format which should be
1461            compatible with whatever sub formats are supported by self.
1462        :return: None.
1463        """
1464        other_format.features = dict(self.features)
1465
1466    def supports_transport(self, transport):
1467        # bzr formats can be opened over all known transports
1468        return True
1469
1470    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
1471                             basedir=None):
1472        controldir.ControlDirFormat.check_support_status(self,
1473                                                         allow_unsupported=allow_unsupported, recommend_upgrade=recommend_upgrade,
1474                                                         basedir=basedir)
1475        BzrFormat.check_support_status(self, allow_unsupported=allow_unsupported,
1476                                       recommend_upgrade=recommend_upgrade, basedir=basedir)
1477
1478    @classmethod
1479    def is_control_filename(klass, filename):
1480        """True if filename is the name of a path which is reserved for bzrdir's.
1481
1482        :param filename: A filename within the root transport of this bzrdir.
1483
1484        This is true IF and ONLY IF the filename is part of the namespace
1485        reserved for bzr control dirs. Currently this is the '.bzr' directory
1486        in the root of the root_transport.
1487        """
1488        # this might be better on the BzrDirFormat class because it refers to
1489        # all the possible bzrdir disk formats.
1490        # This method is tested via the workingtree is_control_filename tests-
1491        # it was extracted from WorkingTree.is_control_filename. If the
1492        # method's contract is extended beyond the current trivial
1493        # implementation, please add new tests for it to the appropriate place.
1494        return filename == '.bzr' or filename.startswith('.bzr/')
1495
1496    @classmethod
1497    def get_default_format(klass):
1498        """Return the current default format."""
1499        return controldir.format_registry.get('bzr')()
1500
1501
1502class BzrDirMetaFormat1(BzrDirFormat):
1503    """Bzr meta control format 1
1504
1505    This is the first format with split out working tree, branch and repository
1506    disk storage.
1507
1508    It has:
1509
1510    - Format 3 working trees [optional]
1511    - Format 5 branches [optional]
1512    - Format 7 repositories [optional]
1513    """
1514
1515    _lock_class = lockdir.LockDir
1516
1517    fixed_components = False
1518
1519    colocated_branches = True
1520
1521    def __init__(self):
1522        BzrDirFormat.__init__(self)
1523        self._workingtree_format = None
1524        self._branch_format = None
1525        self._repository_format = None
1526
1527    def __eq__(self, other):
1528        if other.__class__ is not self.__class__:
1529            return False
1530        if other.repository_format != self.repository_format:
1531            return False
1532        if other.workingtree_format != self.workingtree_format:
1533            return False
1534        if other.features != self.features:
1535            return False
1536        return True
1537
1538    def __ne__(self, other):
1539        return not self == other
1540
1541    def get_branch_format(self):
1542        if self._branch_format is None:
1543            from .branch import format_registry as branch_format_registry
1544            self._branch_format = branch_format_registry.get_default()
1545        return self._branch_format
1546
1547    def set_branch_format(self, format):
1548        self._branch_format = format
1549
1550    def require_stacking(self, stack_on=None, possible_transports=None,
1551                         _skip_repo=False):
1552        """We have a request to stack, try to ensure the formats support it.
1553
1554        :param stack_on: If supplied, it is the URL to a branch that we want to
1555            stack on. Check to see if that format supports stacking before
1556            forcing an upgrade.
1557        """
1558        # Stacking is desired. requested by the target, but does the place it
1559        # points at support stacking? If it doesn't then we should
1560        # not implicitly upgrade. We check this here.
1561        new_repo_format = None
1562        new_branch_format = None
1563
1564        # a bit of state for get_target_branch so that we don't try to open it
1565        # 2 times, for both repo *and* branch
1566        target = [None, False, None]  # target_branch, checked, upgrade anyway
1567
1568        def get_target_branch():
1569            if target[1]:
1570                # We've checked, don't check again
1571                return target
1572            if stack_on is None:
1573                # No target format, that means we want to force upgrading
1574                target[:] = [None, True, True]
1575                return target
1576            try:
1577                target_dir = BzrDir.open(stack_on,
1578                                         possible_transports=possible_transports)
1579            except errors.NotBranchError:
1580                # Nothing there, don't change formats
1581                target[:] = [None, True, False]
1582                return target
1583            except errors.JailBreak:
1584                # JailBreak, JFDI and upgrade anyway
1585                target[:] = [None, True, True]
1586                return target
1587            try:
1588                target_branch = target_dir.open_branch()
1589            except errors.NotBranchError:
1590                # No branch, don't upgrade formats
1591                target[:] = [None, True, False]
1592                return target
1593            target[:] = [target_branch, True, False]
1594            return target
1595
1596        if (not _skip_repo
1597                and not self.repository_format.supports_external_lookups):
1598            # We need to upgrade the Repository.
1599            target_branch, _, do_upgrade = get_target_branch()
1600            if target_branch is None:
1601                # We don't have a target branch, should we upgrade anyway?
1602                if do_upgrade:
1603                    # stack_on is inaccessible, JFDI.
1604                    # TODO: bad monkey, hard-coded formats...
1605                    if self.repository_format.rich_root_data:
1606                        new_repo_format = knitpack_repo.RepositoryFormatKnitPack5RichRoot()
1607                    else:
1608                        new_repo_format = knitpack_repo.RepositoryFormatKnitPack5()
1609            else:
1610                # If the target already supports stacking, then we know the
1611                # project is already able to use stacking, so auto-upgrade
1612                # for them
1613                new_repo_format = target_branch.repository._format
1614                if not new_repo_format.supports_external_lookups:
1615                    # target doesn't, source doesn't, so don't auto upgrade
1616                    # repo
1617                    new_repo_format = None
1618            if new_repo_format is not None:
1619                self.repository_format = new_repo_format
1620                note(gettext('Source repository format does not support stacking,'
1621                             ' using format:\n  %s'),
1622                     new_repo_format.get_format_description())
1623
1624        if not self.get_branch_format().supports_stacking():
1625            # We just checked the repo, now lets check if we need to
1626            # upgrade the branch format
1627            target_branch, _, do_upgrade = get_target_branch()
1628            if target_branch is None:
1629                if do_upgrade:
1630                    # TODO: bad monkey, hard-coded formats...
1631                    from .branch import BzrBranchFormat7
1632                    new_branch_format = BzrBranchFormat7()
1633            else:
1634                new_branch_format = target_branch._format
1635                if not new_branch_format.supports_stacking():
1636                    new_branch_format = None
1637            if new_branch_format is not None:
1638                # Does support stacking, use its format.
1639                self.set_branch_format(new_branch_format)
1640                note(gettext('Source branch format does not support stacking,'
1641                             ' using format:\n  %s'),
1642                     new_branch_format.get_format_description())
1643
1644    def get_converter(self, format=None):
1645        """See BzrDirFormat.get_converter()."""
1646        if format is None:
1647            format = BzrDirFormat.get_default_format()
1648        if (isinstance(self, BzrDirMetaFormat1)
1649                and isinstance(format, BzrDirMetaFormat1Colo)):
1650            return ConvertMetaToColo(format)
1651        if (isinstance(self, BzrDirMetaFormat1Colo)
1652                and isinstance(format, BzrDirMetaFormat1)):
1653            return ConvertMetaToColo(format)
1654        if not isinstance(self, format.__class__):
1655            # converting away from metadir is not implemented
1656            raise NotImplementedError(self.get_converter)
1657        return ConvertMetaToMeta(format)
1658
1659    @classmethod
1660    def get_format_string(cls):
1661        """See BzrDirFormat.get_format_string()."""
1662        return b"Bazaar-NG meta directory, format 1\n"
1663
1664    def get_format_description(self):
1665        """See BzrDirFormat.get_format_description()."""
1666        return "Meta directory format 1"
1667
1668    def _open(self, transport):
1669        """See BzrDirFormat._open."""
1670        # Create a new format instance because otherwise initialisation of new
1671        # metadirs share the global default format object leading to alias
1672        # problems.
1673        format = BzrDirMetaFormat1()
1674        self._supply_sub_formats_to(format)
1675        return BzrDirMeta1(transport, format)
1676
1677    def __return_repository_format(self):
1678        """Circular import protection."""
1679        if self._repository_format:
1680            return self._repository_format
1681        from .repository import format_registry
1682        return format_registry.get_default()
1683
1684    def _set_repository_format(self, value):
1685        """Allow changing the repository format for metadir formats."""
1686        self._repository_format = value
1687
1688    repository_format = property(__return_repository_format,
1689                                 _set_repository_format)
1690
1691    def _supply_sub_formats_to(self, other_format):
1692        """Give other_format the same values for sub formats as this has.
1693
1694        This method is expected to be used when parameterising a
1695        RemoteBzrDirFormat instance with the parameters from a
1696        BzrDirMetaFormat1 instance.
1697
1698        :param other_format: other_format is a format which should be
1699            compatible with whatever sub formats are supported by self.
1700        :return: None.
1701        """
1702        super(BzrDirMetaFormat1, self)._supply_sub_formats_to(other_format)
1703        if getattr(self, '_repository_format', None) is not None:
1704            other_format.repository_format = self.repository_format
1705        if self._branch_format is not None:
1706            other_format._branch_format = self._branch_format
1707        if self._workingtree_format is not None:
1708            other_format.workingtree_format = self.workingtree_format
1709
1710    def __get_workingtree_format(self):
1711        if self._workingtree_format is None:
1712            from .workingtree import (
1713                format_registry as wt_format_registry,
1714                )
1715            self._workingtree_format = wt_format_registry.get_default()
1716        return self._workingtree_format
1717
1718    def __set_workingtree_format(self, wt_format):
1719        self._workingtree_format = wt_format
1720
1721    def __repr__(self):
1722        return "<%r>" % (self.__class__.__name__,)
1723
1724    workingtree_format = property(__get_workingtree_format,
1725                                  __set_workingtree_format)
1726
1727
1728class BzrDirMetaFormat1Colo(BzrDirMetaFormat1):
1729    """BzrDirMeta1 format with support for colocated branches."""
1730
1731    colocated_branches = True
1732
1733    @classmethod
1734    def get_format_string(cls):
1735        """See BzrDirFormat.get_format_string()."""
1736        return b"Bazaar meta directory, format 1 (with colocated branches)\n"
1737
1738    def get_format_description(self):
1739        """See BzrDirFormat.get_format_description()."""
1740        return "Meta directory format 1 with support for colocated branches"
1741
1742    def _open(self, transport):
1743        """See BzrDirFormat._open."""
1744        # Create a new format instance because otherwise initialisation of new
1745        # metadirs share the global default format object leading to alias
1746        # problems.
1747        format = BzrDirMetaFormat1Colo()
1748        self._supply_sub_formats_to(format)
1749        return BzrDirMeta1(transport, format)
1750
1751
1752class ConvertMetaToMeta(controldir.Converter):
1753    """Converts the components of metadirs."""
1754
1755    def __init__(self, target_format):
1756        """Create a metadir to metadir converter.
1757
1758        :param target_format: The final metadir format that is desired.
1759        """
1760        self.target_format = target_format
1761
1762    def convert(self, to_convert, pb):
1763        """See Converter.convert()."""
1764        self.controldir = to_convert
1765        with ui.ui_factory.nested_progress_bar() as self.pb:
1766            self.count = 0
1767            self.total = 1
1768            self.step('checking repository format')
1769            try:
1770                repo = self.controldir.open_repository()
1771            except errors.NoRepositoryPresent:
1772                pass
1773            else:
1774                repo_fmt = self.target_format.repository_format
1775                if not isinstance(repo._format, repo_fmt.__class__):
1776                    from ..repository import CopyConverter
1777                    ui.ui_factory.note(gettext('starting repository conversion'))
1778                    if not repo_fmt.supports_overriding_transport:
1779                        raise AssertionError(
1780                            "Repository in metadir does not support "
1781                            "overriding transport")
1782                    converter = CopyConverter(self.target_format.repository_format)
1783                    converter.convert(repo, pb)
1784            for branch in self.controldir.list_branches():
1785                # TODO: conversions of Branch and Tree should be done by
1786                # InterXFormat lookups/some sort of registry.
1787                # Avoid circular imports
1788                old = branch._format.__class__
1789                new = self.target_format.get_branch_format().__class__
1790                while old != new:
1791                    if (old == fullhistorybranch.BzrBranchFormat5
1792                        and new in (_mod_bzrbranch.BzrBranchFormat6,
1793                                    _mod_bzrbranch.BzrBranchFormat7,
1794                                    _mod_bzrbranch.BzrBranchFormat8)):
1795                        branch_converter = _mod_bzrbranch.Converter5to6()
1796                    elif (old == _mod_bzrbranch.BzrBranchFormat6
1797                          and new in (_mod_bzrbranch.BzrBranchFormat7,
1798                                      _mod_bzrbranch.BzrBranchFormat8)):
1799                        branch_converter = _mod_bzrbranch.Converter6to7()
1800                    elif (old == _mod_bzrbranch.BzrBranchFormat7
1801                          and new is _mod_bzrbranch.BzrBranchFormat8):
1802                        branch_converter = _mod_bzrbranch.Converter7to8()
1803                    else:
1804                        raise errors.BadConversionTarget("No converter", new,
1805                                                         branch._format)
1806                    branch_converter.convert(branch)
1807                    branch = self.controldir.open_branch()
1808                    old = branch._format.__class__
1809            try:
1810                tree = self.controldir.open_workingtree(recommend_upgrade=False)
1811            except (errors.NoWorkingTree, errors.NotLocalUrl):
1812                pass
1813            else:
1814                # TODO: conversions of Branch and Tree should be done by
1815                # InterXFormat lookups
1816                if (isinstance(tree, workingtree_3.WorkingTree3)
1817                    and not isinstance(tree, workingtree_4.DirStateWorkingTree)
1818                    and isinstance(self.target_format.workingtree_format,
1819                                   workingtree_4.DirStateWorkingTreeFormat)):
1820                    workingtree_4.Converter3to4().convert(tree)
1821                if (isinstance(tree, workingtree_4.DirStateWorkingTree)
1822                    and not isinstance(tree, workingtree_4.WorkingTree5)
1823                    and isinstance(self.target_format.workingtree_format,
1824                                   workingtree_4.WorkingTreeFormat5)):
1825                    workingtree_4.Converter4to5().convert(tree)
1826                if (isinstance(tree, workingtree_4.DirStateWorkingTree)
1827                    and not isinstance(tree, workingtree_4.WorkingTree6)
1828                    and isinstance(self.target_format.workingtree_format,
1829                                   workingtree_4.WorkingTreeFormat6)):
1830                    workingtree_4.Converter4or5to6().convert(tree)
1831        return to_convert
1832
1833
1834class ConvertMetaToColo(controldir.Converter):
1835    """Add colocated branch support."""
1836
1837    def __init__(self, target_format):
1838        """Create a converter.that upgrades a metadir to the colo format.
1839
1840        :param target_format: The final metadir format that is desired.
1841        """
1842        self.target_format = target_format
1843
1844    def convert(self, to_convert, pb):
1845        """See Converter.convert()."""
1846        to_convert.transport.put_bytes('branch-format',
1847                                       self.target_format.as_string())
1848        return BzrDir.open_from_transport(to_convert.root_transport)
1849
1850
1851class ConvertMetaToColo(controldir.Converter):
1852    """Convert a 'development-colo' bzrdir to a '2a' bzrdir."""
1853
1854    def __init__(self, target_format):
1855        """Create a converter that converts a 'development-colo' metadir
1856        to a '2a' metadir.
1857
1858        :param target_format: The final metadir format that is desired.
1859        """
1860        self.target_format = target_format
1861
1862    def convert(self, to_convert, pb):
1863        """See Converter.convert()."""
1864        to_convert.transport.put_bytes('branch-format',
1865                                       self.target_format.as_string())
1866        return BzrDir.open_from_transport(to_convert.root_transport)
1867
1868
1869class CreateRepository(controldir.RepositoryAcquisitionPolicy):
1870    """A policy of creating a new repository"""
1871
1872    def __init__(self, controldir, stack_on=None, stack_on_pwd=None,
1873                 require_stacking=False):
1874        """Constructor.
1875
1876        :param controldir: The controldir to create the repository on.
1877        :param stack_on: A location to stack on
1878        :param stack_on_pwd: If stack_on is relative, the location it is
1879            relative to.
1880        """
1881        super(CreateRepository, self).__init__(
1882            stack_on, stack_on_pwd, require_stacking)
1883        self._controldir = controldir
1884
1885    def acquire_repository(self, make_working_trees=None, shared=False,
1886                           possible_transports=None):
1887        """Implementation of RepositoryAcquisitionPolicy.acquire_repository
1888
1889        Creates the desired repository in the controldir we already have.
1890        """
1891        if possible_transports is None:
1892            possible_transports = []
1893        else:
1894            possible_transports = list(possible_transports)
1895        possible_transports.append(self._controldir.root_transport)
1896        stack_on = self._get_full_stack_on()
1897        if stack_on:
1898            format = self._controldir._format
1899            format.require_stacking(stack_on=stack_on,
1900                                    possible_transports=possible_transports)
1901            if not self._require_stacking:
1902                # We have picked up automatic stacking somewhere.
1903                note(gettext('Using default stacking branch {0} at {1}').format(
1904                    self._stack_on, self._stack_on_pwd))
1905        repository = self._controldir.create_repository(shared=shared)
1906        self._add_fallback(repository,
1907                           possible_transports=possible_transports)
1908        if make_working_trees is not None:
1909            repository.set_make_working_trees(make_working_trees)
1910        return repository, True
1911
1912
1913class UseExistingRepository(controldir.RepositoryAcquisitionPolicy):
1914    """A policy of reusing an existing repository"""
1915
1916    def __init__(self, repository, stack_on=None, stack_on_pwd=None,
1917                 require_stacking=False):
1918        """Constructor.
1919
1920        :param repository: The repository to use.
1921        :param stack_on: A location to stack on
1922        :param stack_on_pwd: If stack_on is relative, the location it is
1923            relative to.
1924        """
1925        super(UseExistingRepository, self).__init__(
1926            stack_on, stack_on_pwd, require_stacking)
1927        self._repository = repository
1928
1929    def acquire_repository(self, make_working_trees=None, shared=False,
1930                           possible_transports=None):
1931        """Implementation of RepositoryAcquisitionPolicy.acquire_repository
1932
1933        Returns an existing repository to use.
1934        """
1935        if possible_transports is None:
1936            possible_transports = []
1937        else:
1938            possible_transports = list(possible_transports)
1939        possible_transports.append(self._repository.controldir.transport)
1940        self._add_fallback(self._repository,
1941                           possible_transports=possible_transports)
1942        return self._repository, False
1943
1944
1945controldir.ControlDirFormat._default_format = BzrDirMetaFormat1()
1946