/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/builtins.py

  • Committer: Jelmer Vernooij
  • Date: 2009-05-28 16:04:39 UTC
  • mfrom: (4387 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4405.
  • Revision ID: jelmer@samba.org-20090528160439-4z0xlrk5nejobm7q
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
79
79
 
80
80
 
81
81
def tree_files_for_add(file_list):
82
 
    """Add handles files a bit differently so it a custom implementation."""
 
82
    """
 
83
    Return a tree and list of absolute paths from a file list.
 
84
 
 
85
    Similar to tree_files, but add handles files a bit differently, so it a
 
86
    custom implementation.  In particular, MutableTreeTree.smart_add expects
 
87
    absolute paths, which it immediately converts to relative paths.
 
88
    """
 
89
    # FIXME Would be nice to just return the relative paths like
 
90
    # internal_tree_files does, but there are a large number of unit tests
 
91
    # that assume the current interface to mutabletree.smart_add
83
92
    if file_list:
84
 
        tree = WorkingTree.open_containing(file_list[0])[0]
 
93
        tree, relpath = WorkingTree.open_containing(file_list[0])
85
94
        if tree.supports_views():
86
95
            view_files = tree.views.lookup_view()
87
96
            if view_files:
88
97
                for filename in file_list:
89
98
                    if not osutils.is_inside_any(view_files, filename):
90
99
                        raise errors.FileOutsideView(filename, view_files)
 
100
        file_list = file_list[:]
 
101
        file_list[0] = tree.abspath(relpath)
91
102
    else:
92
103
        tree = WorkingTree.open_containing(u'.')[0]
93
104
        if tree.supports_views():
871
882
            short_name='d',
872
883
            type=unicode,
873
884
            ),
 
885
        Option('local',
 
886
            help="Perform a local pull in a bound "
 
887
                 "branch.  Local pulls are not applied to "
 
888
                 "the master branch."
 
889
            ),
874
890
        ]
875
891
    takes_args = ['location?']
876
892
    encoding_type = 'replace'
877
893
 
878
894
    def run(self, location=None, remember=False, overwrite=False,
879
895
            revision=None, verbose=False,
880
 
            directory=None):
 
896
            directory=None, local=False):
881
897
        # FIXME: too much stuff is in the command class
882
898
        revision_id = None
883
899
        mergeable = None
889
905
        except errors.NoWorkingTree:
890
906
            tree_to = None
891
907
            branch_to = Branch.open_containing(directory)[0]
 
908
        
 
909
        if local and not branch_to.get_bound_location():
 
910
            raise errors.LocalRequiresBoundBranch()
892
911
 
893
912
        possible_transports = []
894
913
        if location is not None:
937
956
                    unversioned_filter=tree_to.is_ignored, view_info=view_info)
938
957
                result = tree_to.pull(branch_from, overwrite, revision_id,
939
958
                                      change_reporter,
940
 
                                      possible_transports=possible_transports)
 
959
                                      possible_transports=possible_transports,
 
960
                                      local=local)
941
961
            else:
942
 
                result = branch_to.pull(branch_from, overwrite, revision_id)
 
962
                result = branch_to.pull(branch_from, overwrite, revision_id,
 
963
                                      local=local)
943
964
 
944
965
            result.report(self.outf)
945
966
            if verbose and result.old_revid != result.new_revid:
1017
1038
        if revision is not None:
1018
1039
            revision_id = revision.in_history(br_from).rev_id
1019
1040
        else:
1020
 
            revision_id = br_from.last_revision()
 
1041
            revision_id = None
1021
1042
 
1022
1043
        # Get the stacked_on branch, if any
1023
1044
        if stacked_on is not None:
1575
1596
                    "\nYou may supply --create-prefix to create all"
1576
1597
                    " leading parent directories."
1577
1598
                    % location)
1578
 
            _create_prefix(to_transport)
 
1599
            to_transport.create_prefix()
1579
1600
 
1580
1601
        try:
1581
1602
            a_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport)
2068
2089
 
2069
2090
      When exploring non-mainline history on large projects with deep
2070
2091
      history, the performance of log can be greatly improved by installing
2071
 
      the revnocache plugin. This plugin buffers historical information
 
2092
      the historycache plugin. This plugin buffers historical information
2072
2093
      trading disk space for faster speed.
2073
2094
    """
2074
2095
    takes_args = ['file*']
2105
2126
            Option('show-diff',
2106
2127
                   short_name='p',
2107
2128
                   help='Show changes made in each revision as a patch.'),
 
2129
            Option('include-merges',
 
2130
                   help='Show merged revisions like --levels 0 does.'),
2108
2131
            ]
2109
2132
    encoding_type = 'replace'
2110
2133
 
2119
2142
            levels=None,
2120
2143
            message=None,
2121
2144
            limit=None,
2122
 
            show_diff=False):
 
2145
            show_diff=False,
 
2146
            include_merges=False):
2123
2147
        from bzrlib.log import (
2124
2148
            Logger,
2125
2149
            make_log_request_dict,
2126
2150
            _get_info_for_log_files,
2127
2151
            )
2128
2152
        direction = (forward and 'forward') or 'reverse'
 
2153
        if include_merges:
 
2154
            if levels is None:
 
2155
                levels = 0
 
2156
            else:
 
2157
                raise errors.BzrCommandError(
 
2158
                    '--levels and --include-merges are mutually exclusive')
2129
2159
 
2130
2160
        if change is not None:
2131
2161
            if len(change) > 1:
2188
2218
            lf = log_format(show_ids=show_ids, to_file=self.outf,
2189
2219
                            show_timezone=timezone,
2190
2220
                            delta_format=get_verbosity_level(),
2191
 
                            levels=levels)
 
2221
                            levels=levels,
 
2222
                            show_advice=levels is None)
2192
2223
 
2193
2224
            # Choose the algorithm for doing the logging. It's annoying
2194
2225
            # having multiple code paths like this but necessary until
2298
2329
 
2299
2330
    _see_also = ['status', 'cat']
2300
2331
    takes_args = ['path?']
2301
 
    # TODO: Take a revision or remote path and list that tree instead.
2302
2332
    takes_options = [
2303
2333
            'verbose',
2304
2334
            'revision',
2305
 
            Option('non-recursive',
2306
 
                   help='Don\'t recurse into subdirectories.'),
 
2335
            Option('recursive', short_name='R',
 
2336
                   help='Recurse into subdirectories.'),
2307
2337
            Option('from-root',
2308
2338
                   help='Print paths relative to the root of the branch.'),
2309
2339
            Option('unknown', help='Print unknown files.'),
2320
2350
            ]
2321
2351
    @display_command
2322
2352
    def run(self, revision=None, verbose=False,
2323
 
            non_recursive=False, from_root=False,
 
2353
            recursive=False, from_root=False,
2324
2354
            unknown=False, versioned=False, ignored=False,
2325
2355
            null=False, kind=None, show_ids=False, path=None):
2326
2356
 
2363
2393
        try:
2364
2394
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False):
2365
2395
                if fp.startswith(relpath):
2366
 
                    fp = osutils.pathjoin(prefix, fp[len(relpath):])
2367
 
                    if non_recursive and '/' in fp:
 
2396
                    rp = fp[len(relpath):]
 
2397
                    fp = osutils.pathjoin(prefix, rp)
 
2398
                    if not recursive and '/' in rp:
2368
2399
                        continue
2369
2400
                    if not all and not selection[fc]:
2370
2401
                        continue
2696
2727
class cmd_commit(Command):
2697
2728
    """Commit changes into a new revision.
2698
2729
 
2699
 
    If no arguments are given, the entire tree is committed.
2700
 
 
2701
 
    If selected files are specified, only changes to those files are
2702
 
    committed.  If a directory is specified then the directory and everything
2703
 
    within it is committed.
2704
 
 
2705
 
    When excludes are given, they take precedence over selected files.
2706
 
    For example, too commit only changes within foo, but not changes within
2707
 
    foo/bar::
2708
 
 
2709
 
      bzr commit foo -x foo/bar
2710
 
 
2711
 
    If author of the change is not the same person as the committer, you can
2712
 
    specify the author's name using the --author option. The name should be
2713
 
    in the same format as a committer-id, e.g. "John Doe <jdoe@example.com>".
2714
 
    If there is more than one author of the change you can specify the option
2715
 
    multiple times, once for each author.
2716
 
 
2717
 
    A selected-file commit may fail in some cases where the committed
2718
 
    tree would be invalid. Consider::
2719
 
 
2720
 
      bzr init foo
2721
 
      mkdir foo/bar
2722
 
      bzr add foo/bar
2723
 
      bzr commit foo -m "committing foo"
2724
 
      bzr mv foo/bar foo/baz
2725
 
      mkdir foo/bar
2726
 
      bzr add foo/bar
2727
 
      bzr commit foo/bar -m "committing bar but not baz"
2728
 
 
2729
 
    In the example above, the last commit will fail by design. This gives
2730
 
    the user the opportunity to decide whether they want to commit the
2731
 
    rename at the same time, separately first, or not at all. (As a general
2732
 
    rule, when in doubt, Bazaar has a policy of Doing the Safe Thing.)
2733
 
 
2734
 
    Note: A selected-file commit after a merge is not yet supported.
 
2730
    An explanatory message needs to be given for each commit. This is
 
2731
    often done by using the --message option (getting the message from the
 
2732
    command line) or by using the --file option (getting the message from
 
2733
    a file). If neither of these options is given, an editor is opened for
 
2734
    the user to enter the message. To see the changed files in the
 
2735
    boilerplate text loaded into the editor, use the --show-diff option.
 
2736
 
 
2737
    By default, the entire tree is committed and the person doing the
 
2738
    commit is assumed to be the author. These defaults can be overridden
 
2739
    as explained below.
 
2740
 
 
2741
    :Selective commits:
 
2742
 
 
2743
      If selected files are specified, only changes to those files are
 
2744
      committed.  If a directory is specified then the directory and
 
2745
      everything within it is committed.
 
2746
  
 
2747
      When excludes are given, they take precedence over selected files.
 
2748
      For example, to commit only changes within foo, but not changes
 
2749
      within foo/bar::
 
2750
  
 
2751
        bzr commit foo -x foo/bar
 
2752
  
 
2753
      A selective commit after a merge is not yet supported.
 
2754
 
 
2755
    :Custom authors:
 
2756
 
 
2757
      If the author of the change is not the same person as the committer,
 
2758
      you can specify the author's name using the --author option. The
 
2759
      name should be in the same format as a committer-id, e.g.
 
2760
      "John Doe <jdoe@example.com>". If there is more than one author of
 
2761
      the change you can specify the option multiple times, once for each
 
2762
      author.
 
2763
  
 
2764
    :Checks:
 
2765
 
 
2766
      A common mistake is to forget to add a new file or directory before
 
2767
      running the commit command. The --strict option checks for unknown
 
2768
      files and aborts the commit if any are found. More advanced pre-commit
 
2769
      checks can be implemented by defining hooks. See ``bzr help hooks``
 
2770
      for details.
 
2771
 
 
2772
    :Things to note:
 
2773
 
 
2774
      If you accidentially commit the wrong changes or make a spelling
 
2775
      mistake in the commit message say, you can use the uncommit command
 
2776
      to undo it. See ``bzr help uncommit`` for details.
 
2777
 
 
2778
      Hooks can also be configured to run after a commit. This allows you
 
2779
      to trigger updates to external systems like bug trackers. The --fixes
 
2780
      option can be used to record the association between a revision and
 
2781
      one or more bugs. See ``bzr help bugs`` for details.
 
2782
 
 
2783
      A selective commit may fail in some cases where the committed
 
2784
      tree would be invalid. Consider::
 
2785
  
 
2786
        bzr init foo
 
2787
        mkdir foo/bar
 
2788
        bzr add foo/bar
 
2789
        bzr commit foo -m "committing foo"
 
2790
        bzr mv foo/bar foo/baz
 
2791
        mkdir foo/bar
 
2792
        bzr add foo/bar
 
2793
        bzr commit foo/bar -m "committing bar but not baz"
 
2794
  
 
2795
      In the example above, the last commit will fail by design. This gives
 
2796
      the user the opportunity to decide whether they want to commit the
 
2797
      rename at the same time, separately first, or not at all. (As a general
 
2798
      rule, when in doubt, Bazaar has a policy of Doing the Safe Thing.)
2735
2799
    """
2736
2800
    # TODO: Run hooks on tree to-be-committed, and after commit.
2737
2801
 
2742
2806
 
2743
2807
    # XXX: verbose currently does nothing
2744
2808
 
2745
 
    _see_also = ['bugs', 'uncommit']
 
2809
    _see_also = ['add', 'bugs', 'hooks', 'uncommit']
2746
2810
    takes_args = ['selected*']
2747
2811
    takes_options = [
2748
2812
            ListOption('exclude', type=str, short_name='x',
2869
2933
        except PointlessCommit:
2870
2934
            # FIXME: This should really happen before the file is read in;
2871
2935
            # perhaps prepare the commit; get the message; then actually commit
2872
 
            raise errors.BzrCommandError("no changes to commit."
2873
 
                              " use --unchanged to commit anyhow")
 
2936
            raise errors.BzrCommandError("No changes to commit."
 
2937
                              " Use --unchanged to commit anyhow.")
2874
2938
        except ConflictsInTree:
2875
2939
            raise errors.BzrCommandError('Conflicts detected in working '
2876
2940
                'tree.  Use "bzr conflicts" to list, "bzr resolve FILE" to'
3246
3310
 
3247
3311
        if cache_dir is not None:
3248
3312
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
3249
 
        if not list_only:
3250
 
            print 'testing: %s' % (osutils.realpath(sys.argv[0]),)
3251
 
            print '   %s (%s python%s)' % (
3252
 
                    bzrlib.__path__[0],
3253
 
                    bzrlib.version_string,
3254
 
                    bzrlib._format_version_tuple(sys.version_info),
3255
 
                    )
3256
 
        print
3257
3313
        if testspecs_list is not None:
3258
3314
            pattern = '|'.join(testspecs_list)
3259
3315
        else:
3299
3355
        finally:
3300
3356
            if benchfile is not None:
3301
3357
                benchfile.close()
3302
 
        if result:
3303
 
            note('tests passed')
3304
 
        else:
3305
 
            note('tests failed')
3306
3358
        return int(not result)
3307
3359
 
3308
3360
 
4488
4540
    takes_options = [
4489
4541
        Option('inet',
4490
4542
               help='Serve on stdin/out for use from inetd or sshd.'),
 
4543
        RegistryOption('protocol', 
 
4544
               help="Protocol to serve.", 
 
4545
               lazy_registry=('bzrlib.transport', 'transport_server_registry'),
 
4546
               value_switches=True),
4491
4547
        Option('port',
4492
4548
               help='Listen for connections on nominated port of the form '
4493
4549
                    '[hostname:]portnumber.  Passing 0 as the port number will '
4494
 
                    'result in a dynamically allocated port.  The default port is '
4495
 
                    '4155.',
 
4550
                    'result in a dynamically allocated port.  The default port '
 
4551
                    'depends on the protocol.',
4496
4552
               type=str),
4497
4553
        Option('directory',
4498
4554
               help='Serve contents of this directory.',
4504
4560
                ),
4505
4561
        ]
4506
4562
 
4507
 
    def run_smart_server(self, smart_server):
4508
 
        """Run 'smart_server' forever, with no UI output at all."""
4509
 
        # For the duration of this server, no UI output is permitted. note
4510
 
        # that this may cause problems with blackbox tests. This should be
4511
 
        # changed with care though, as we dont want to use bandwidth sending
4512
 
        # progress over stderr to smart server clients!
4513
 
        from bzrlib import lockdir
4514
 
        old_factory = ui.ui_factory
4515
 
        old_lockdir_timeout = lockdir._DEFAULT_TIMEOUT_SECONDS
4516
 
        try:
4517
 
            ui.ui_factory = ui.SilentUIFactory()
4518
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = 0
4519
 
            smart_server.serve()
4520
 
        finally:
4521
 
            ui.ui_factory = old_factory
4522
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = old_lockdir_timeout
4523
 
 
4524
4563
    def get_host_and_port(self, port):
4525
4564
        """Return the host and port to run the smart server on.
4526
4565
 
4527
 
        If 'port' is None, the default host (`medium.BZR_DEFAULT_INTERFACE`)
4528
 
        and port (`medium.BZR_DEFAULT_PORT`) will be used.
 
4566
        If 'port' is None, None will be returned for the host and port.
4529
4567
 
4530
4568
        If 'port' has a colon in it, the string before the colon will be
4531
4569
        interpreted as the host.
4534
4572
        :return: A tuple of (host, port), where 'host' is a host name or IP,
4535
4573
            and port is an integer TCP/IP port.
4536
4574
        """
4537
 
        from bzrlib.smart import medium
4538
 
        host = medium.BZR_DEFAULT_INTERFACE
4539
 
        if port is None:
4540
 
            port = medium.BZR_DEFAULT_PORT
4541
 
        else:
 
4575
        host = None
 
4576
        if port is not None:
4542
4577
            if ':' in port:
4543
4578
                host, port = port.split(':')
4544
4579
            port = int(port)
4545
4580
        return host, port
4546
4581
 
4547
 
    def get_smart_server(self, transport, inet, port):
4548
 
        """Construct a smart server.
4549
 
 
4550
 
        :param transport: The base transport from which branches will be
4551
 
            served.
4552
 
        :param inet: If True, serve over stdin and stdout. Used for running
4553
 
            from inet.
4554
 
        :param port: The port to listen on. By default, it's `
4555
 
            medium.BZR_DEFAULT_PORT`. See `get_host_and_port` for more
4556
 
            information.
4557
 
        :return: A smart server.
4558
 
        """
4559
 
        from bzrlib.smart import medium, server
4560
 
        if inet:
4561
 
            smart_server = medium.SmartServerPipeStreamMedium(
4562
 
                sys.stdin, sys.stdout, transport)
4563
 
        else:
4564
 
            host, port = self.get_host_and_port(port)
4565
 
            smart_server = server.SmartTCPServer(
4566
 
                transport, host=host, port=port)
4567
 
            note('listening on port: %s' % smart_server.port)
4568
 
        return smart_server
4569
 
 
4570
 
    def run(self, port=None, inet=False, directory=None, allow_writes=False):
4571
 
        from bzrlib.transport import get_transport
4572
 
        from bzrlib.transport.chroot import ChrootServer
 
4582
    def run(self, port=None, inet=False, directory=None, allow_writes=False,
 
4583
            protocol=None):
 
4584
        from bzrlib.transport import get_transport, transport_server_registry
4573
4585
        if directory is None:
4574
4586
            directory = os.getcwd()
 
4587
        if protocol is None:
 
4588
            protocol = transport_server_registry.get()
 
4589
        host, port = self.get_host_and_port(port)
4575
4590
        url = urlutils.local_path_to_url(directory)
4576
4591
        if not allow_writes:
4577
4592
            url = 'readonly+' + url
4578
 
        chroot_server = ChrootServer(get_transport(url))
4579
 
        chroot_server.setUp()
4580
 
        t = get_transport(chroot_server.get_url())
4581
 
        smart_server = self.get_smart_server(t, inet, port)
4582
 
        self.run_smart_server(smart_server)
 
4593
        transport = get_transport(url)
 
4594
        protocol(transport, host, port, inet)
4583
4595
 
4584
4596
 
4585
4597
class cmd_join(Command):
4839
4851
 
4840
4852
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4841
4853
            no_patch=False, revision=None, remember=False, output=None,
4842
 
            format='4', mail_to=None, message=None, body=None, **kwargs):
 
4854
            format=None, mail_to=None, message=None, body=None, **kwargs):
4843
4855
        return self._run(submit_branch, revision, public_branch, remember,
4844
4856
                         format, no_bundle, no_patch, output,
4845
4857
                         kwargs.get('from', '.'), mail_to, message, body)
4847
4859
    def _run(self, submit_branch, revision, public_branch, remember, format,
4848
4860
             no_bundle, no_patch, output, from_, mail_to, message, body):
4849
4861
        from bzrlib.revision import NULL_REVISION
4850
 
        branch = Branch.open_containing(from_)[0]
4851
 
        if output is None:
4852
 
            outfile = cStringIO.StringIO()
4853
 
        elif output == '-':
4854
 
            outfile = self.outf
4855
 
        else:
4856
 
            outfile = open(output, 'wb')
 
4862
        tree, branch = bzrdir.BzrDir.open_containing_tree_or_branch(from_)[:2]
4857
4863
        # we may need to write data into branch's repository to calculate
4858
4864
        # the data to send.
4859
4865
        branch.lock_write()
4890
4896
                        'changes to submit.', remembered_submit_branch,
4891
4897
                        submit_branch)
4892
4898
 
4893
 
            if mail_to is None:
4894
 
                submit_config = Branch.open(submit_branch).get_config()
4895
 
                mail_to = submit_config.get_user_option("child_submit_to")
 
4899
            if mail_to is None or format is None:
 
4900
                submit_br = Branch.open(submit_branch)
 
4901
                submit_config = submit_br.get_config()
 
4902
                if mail_to is None:
 
4903
                    mail_to = submit_config.get_user_option("child_submit_to")
 
4904
                if format is None:
 
4905
                    format = submit_br.get_child_submit_format()
4896
4906
 
4897
4907
            stored_public_branch = branch.get_public_branch()
4898
4908
            if public_branch is None:
4915
4925
                revision_id = branch.last_revision()
4916
4926
            if revision_id == NULL_REVISION:
4917
4927
                raise errors.BzrCommandError('No revisions to submit.')
 
4928
            if format is None:
 
4929
                format = '4'
4918
4930
            if format == '4':
4919
4931
                directive = merge_directive.MergeDirective2.from_objects(
4920
4932
                    branch.repository, revision_id, time.time(),
4939
4951
                    osutils.local_time_offset(), submit_branch,
4940
4952
                    public_branch=public_branch, patch_type=patch_type,
4941
4953
                    message=message)
 
4954
            else:
 
4955
                raise errors.BzrCommandError("No such send format '%s'." % 
 
4956
                                             format)
4942
4957
 
4943
 
            outfile.writelines(directive.to_lines())
4944
4958
            if output is None:
4945
 
                subject = '[MERGE] '
4946
 
                if message is not None:
4947
 
                    subject += message
 
4959
                directive.compose_merge_request(mail_client, mail_to, body,
 
4960
                                                branch, tree)
 
4961
            else:
 
4962
                if output == '-':
 
4963
                    outfile = self.outf
4948
4964
                else:
4949
 
                    revision = branch.repository.get_revision(revision_id)
4950
 
                    subject += revision.get_summary()
4951
 
                basename = directive.get_disk_name(branch)
4952
 
                mail_client.compose_merge_request(mail_to, subject,
4953
 
                                                  outfile.getvalue(),
4954
 
                                                  basename, body)
 
4965
                    outfile = open(output, 'wb')
 
4966
                try:
 
4967
                    outfile.writelines(directive.to_lines())
 
4968
                finally:
 
4969
                    if outfile is not self.outf:
 
4970
                        outfile.close()
4955
4971
        finally:
4956
 
            if output != '-':
4957
 
                outfile.close()
4958
4972
            branch.unlock()
4959
4973
 
4960
4974
 
5020
5034
 
5021
5035
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
5022
5036
            no_patch=False, revision=None, remember=False, output=None,
5023
 
            format='4', **kwargs):
 
5037
            format=None, **kwargs):
5024
5038
        if output is None:
5025
5039
            output = '-'
5026
5040
        return self._run(submit_branch, revision, public_branch, remember,
5259
5273
        from bzrlib import switch
5260
5274
        tree_location = '.'
5261
5275
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
5262
 
        branch = control_dir.open_branch()
 
5276
        try:
 
5277
            branch = control_dir.open_branch()
 
5278
            had_explicit_nick = branch.get_config().has_explicit_nickname()
 
5279
        except errors.NotBranchError:
 
5280
            had_explicit_nick = False
5263
5281
        try:
5264
5282
            to_branch = Branch.open(to_location)
5265
5283
        except errors.NotBranchError:
5266
 
            this_branch = control_dir.open_branch()
5267
 
            # This may be a heavy checkout, where we want the master branch
5268
 
            this_url = this_branch.get_bound_location()
5269
 
            # If not, use a local sibling
5270
 
            if this_url is None:
5271
 
                this_url = this_branch.base
 
5284
            this_url = self._get_branch_location(control_dir)
5272
5285
            to_branch = Branch.open(
5273
5286
                urlutils.join(this_url, '..', to_location))
5274
5287
        switch.switch(control_dir, to_branch, force)
5275
 
        if branch.get_config().has_explicit_nickname():
 
5288
        if had_explicit_nick:
5276
5289
            branch = control_dir.open_branch() #get the new branch!
5277
5290
            branch.nick = to_branch.nick
5278
5291
        note('Switched to branch: %s',
5279
5292
            urlutils.unescape_for_display(to_branch.base, 'utf-8'))
5280
5293
 
 
5294
    def _get_branch_location(self, control_dir):
 
5295
        """Return location of branch for this control dir."""
 
5296
        try:
 
5297
            this_branch = control_dir.open_branch()
 
5298
            # This may be a heavy checkout, where we want the master branch
 
5299
            master_location = this_branch.get_bound_location()
 
5300
            if master_location is not None:
 
5301
                return master_location
 
5302
            # If not, use a local sibling
 
5303
            return this_branch.base
 
5304
        except errors.NotBranchError:
 
5305
            format = control_dir.find_branch_format()
 
5306
            if getattr(format, 'get_reference', None) is not None:
 
5307
                return format.get_reference(control_dir)
 
5308
            else:
 
5309
                return control_dir.root_transport.base
 
5310
 
5281
5311
 
5282
5312
class cmd_view(Command):
5283
5313
    """Manage filtered views.
5585
5615
                   dry_run=dry_run, no_prompt=force)
5586
5616
 
5587
5617
 
5588
 
def _create_prefix(cur_transport):
5589
 
    needed = [cur_transport]
5590
 
    # Recurse upwards until we can create a directory successfully
5591
 
    while True:
5592
 
        new_transport = cur_transport.clone('..')
5593
 
        if new_transport.base == cur_transport.base:
5594
 
            raise errors.BzrCommandError(
5595
 
                "Failed to create path prefix for %s."
5596
 
                % cur_transport.base)
5597
 
        try:
5598
 
            new_transport.mkdir('.')
5599
 
        except errors.NoSuchFile:
5600
 
            needed.append(new_transport)
5601
 
            cur_transport = new_transport
 
5618
class cmd_reference(Command):
 
5619
    """list, view and set branch locations for nested trees.
 
5620
 
 
5621
    If no arguments are provided, lists the branch locations for nested trees.
 
5622
    If one argument is provided, display the branch location for that tree.
 
5623
    If two arguments are provided, set the branch location for that tree.
 
5624
    """
 
5625
 
 
5626
    hidden = True
 
5627
 
 
5628
    takes_args = ['path?', 'location?']
 
5629
 
 
5630
    def run(self, path=None, location=None):
 
5631
        branchdir = '.'
 
5632
        if path is not None:
 
5633
            branchdir = path
 
5634
        tree, branch, relpath =(
 
5635
            bzrdir.BzrDir.open_containing_tree_or_branch(branchdir))
 
5636
        if path is not None:
 
5637
            path = relpath
 
5638
        if tree is None:
 
5639
            tree = branch.basis_tree()
 
5640
        if path is None:
 
5641
            info = branch._get_all_reference_info().iteritems()
 
5642
            self._display_reference_info(tree, branch, info)
5602
5643
        else:
5603
 
            break
5604
 
    # Now we only need to create child directories
5605
 
    while needed:
5606
 
        cur_transport = needed.pop()
5607
 
        cur_transport.ensure_base()
 
5644
            file_id = tree.path2id(path)
 
5645
            if file_id is None:
 
5646
                raise errors.NotVersionedError(path)
 
5647
            if location is None:
 
5648
                info = [(file_id, branch.get_reference_info(file_id))]
 
5649
                self._display_reference_info(tree, branch, info)
 
5650
            else:
 
5651
                branch.set_reference_info(file_id, path, location)
 
5652
 
 
5653
    def _display_reference_info(self, tree, branch, info):
 
5654
        ref_list = []
 
5655
        for file_id, (path, location) in info:
 
5656
            try:
 
5657
                path = tree.id2path(file_id)
 
5658
            except errors.NoSuchId:
 
5659
                pass
 
5660
            ref_list.append((path, location))
 
5661
        for path, location in sorted(ref_list):
 
5662
            self.outf.write('%s %s\n' % (path, location))
5608
5663
 
5609
5664
 
5610
5665
# these get imported and then picked up by the scan for cmd_*
5617
5672
from bzrlib.bundle.commands import (
5618
5673
    cmd_bundle_info,
5619
5674
    )
 
5675
from bzrlib.foreign import cmd_dpush
5620
5676
from bzrlib.sign_my_commits import cmd_sign_my_commits
5621
5677
from bzrlib.weave_commands import cmd_versionedfile_list, \
5622
5678
        cmd_weave_plan_merge, cmd_weave_merge_text