/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: Andrew Bennetts
  • Date: 2009-06-17 02:02:44 UTC
  • mfrom: (4449 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4452.
  • Revision ID: andrew.bennetts@canonical.com-20090617020244-50aantdf95aakvjx
Merge bzr.dev, resolving NEWS conflict.

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():
599
610
                for glob, paths in ignored.items():
600
611
                    match_len += len(paths)
601
612
                self.outf.write("ignored %d file(s).\n" % match_len)
602
 
            self.outf.write("If you wish to add some of these files,"
603
 
                            " please add them by name.\n")
 
613
            self.outf.write("If you wish to add ignored files, "
 
614
                            "please add them explicitly by name. "
 
615
                            "(\"bzr ignored\" gives a list)\n")
604
616
 
605
617
 
606
618
class cmd_mkdir(Command):
871
883
            short_name='d',
872
884
            type=unicode,
873
885
            ),
 
886
        Option('local',
 
887
            help="Perform a local pull in a bound "
 
888
                 "branch.  Local pulls are not applied to "
 
889
                 "the master branch."
 
890
            ),
874
891
        ]
875
892
    takes_args = ['location?']
876
893
    encoding_type = 'replace'
877
894
 
878
895
    def run(self, location=None, remember=False, overwrite=False,
879
896
            revision=None, verbose=False,
880
 
            directory=None):
 
897
            directory=None, local=False):
881
898
        # FIXME: too much stuff is in the command class
882
899
        revision_id = None
883
900
        mergeable = None
889
906
        except errors.NoWorkingTree:
890
907
            tree_to = None
891
908
            branch_to = Branch.open_containing(directory)[0]
 
909
        
 
910
        if local and not branch_to.get_bound_location():
 
911
            raise errors.LocalRequiresBoundBranch()
892
912
 
893
913
        possible_transports = []
894
914
        if location is not None:
926
946
            if branch_to.get_parent() is None or remember:
927
947
                branch_to.set_parent(branch_from.base)
928
948
 
929
 
        if revision is not None:
930
 
            revision_id = revision.as_revision_id(branch_from)
931
 
 
932
 
        branch_to.lock_write()
 
949
        if branch_from is not branch_to:
 
950
            branch_from.lock_read()
933
951
        try:
934
 
            if tree_to is not None:
935
 
                view_info = _get_view_info_for_change_reporter(tree_to)
936
 
                change_reporter = delta._ChangeReporter(
937
 
                    unversioned_filter=tree_to.is_ignored, view_info=view_info)
938
 
                result = tree_to.pull(branch_from, overwrite, revision_id,
939
 
                                      change_reporter,
940
 
                                      possible_transports=possible_transports)
941
 
            else:
942
 
                result = branch_to.pull(branch_from, overwrite, revision_id)
943
 
 
944
 
            result.report(self.outf)
945
 
            if verbose and result.old_revid != result.new_revid:
946
 
                log.show_branch_change(branch_to, self.outf, result.old_revno,
947
 
                                       result.old_revid)
 
952
            if revision is not None:
 
953
                revision_id = revision.as_revision_id(branch_from)
 
954
 
 
955
            branch_to.lock_write()
 
956
            try:
 
957
                if tree_to is not None:
 
958
                    view_info = _get_view_info_for_change_reporter(tree_to)
 
959
                    change_reporter = delta._ChangeReporter(
 
960
                        unversioned_filter=tree_to.is_ignored,
 
961
                        view_info=view_info)
 
962
                    result = tree_to.pull(
 
963
                        branch_from, overwrite, revision_id, change_reporter,
 
964
                        possible_transports=possible_transports, local=local)
 
965
                else:
 
966
                    result = branch_to.pull(
 
967
                        branch_from, overwrite, revision_id, local=local)
 
968
 
 
969
                result.report(self.outf)
 
970
                if verbose and result.old_revid != result.new_revid:
 
971
                    log.show_branch_change(
 
972
                        branch_to, self.outf, result.old_revno,
 
973
                        result.old_revid)
 
974
            finally:
 
975
                branch_to.unlock()
948
976
        finally:
949
 
            branch_to.unlock()
 
977
            if branch_from is not branch_to:
 
978
                branch_from.unlock()
950
979
 
951
980
 
952
981
class cmd_push(Command):
1017
1046
        if revision is not None:
1018
1047
            revision_id = revision.in_history(br_from).rev_id
1019
1048
        else:
1020
 
            revision_id = br_from.last_revision()
 
1049
            revision_id = None
1021
1050
 
1022
1051
        # Get the stacked_on branch, if any
1023
1052
        if stacked_on is not None:
1056
1085
 
1057
1086
 
1058
1087
class cmd_branch(Command):
1059
 
    """Create a new copy of a branch.
 
1088
    """Create a new branch that is a copy of an existing branch.
1060
1089
 
1061
1090
    If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
1062
1091
    be used.  In other words, "branch ../foo/bar" will attempt to create ./bar.
1090
1119
 
1091
1120
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
1092
1121
            from_location)
 
1122
        if (accelerator_tree is not None and
 
1123
            accelerator_tree.supports_content_filtering()):
 
1124
            accelerator_tree = None
1093
1125
        revision = _get_one_revision('branch', revision)
1094
1126
        br_from.lock_read()
1095
1127
        try:
1575
1607
                    "\nYou may supply --create-prefix to create all"
1576
1608
                    " leading parent directories."
1577
1609
                    % location)
1578
 
            _create_prefix(to_transport)
 
1610
            to_transport.create_prefix()
1579
1611
 
1580
1612
        try:
1581
1613
            a_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport)
2068
2100
 
2069
2101
      When exploring non-mainline history on large projects with deep
2070
2102
      history, the performance of log can be greatly improved by installing
2071
 
      the revnocache plugin. This plugin buffers historical information
 
2103
      the historycache plugin. This plugin buffers historical information
2072
2104
      trading disk space for faster speed.
2073
2105
    """
2074
2106
    takes_args = ['file*']
2387
2419
                            continue
2388
2420
                    kindch = entry.kind_character()
2389
2421
                    outstring = fp + kindch
 
2422
                    ui.ui_factory.clear_term()
2390
2423
                    if verbose:
2391
2424
                        outstring = '%-8s %s' % (fc, outstring)
2392
2425
                        if show_ids and fid is not None:
2706
2739
class cmd_commit(Command):
2707
2740
    """Commit changes into a new revision.
2708
2741
 
2709
 
    If no arguments are given, the entire tree is committed.
2710
 
 
2711
 
    If selected files are specified, only changes to those files are
2712
 
    committed.  If a directory is specified then the directory and everything
2713
 
    within it is committed.
2714
 
 
2715
 
    When excludes are given, they take precedence over selected files.
2716
 
    For example, too commit only changes within foo, but not changes within
2717
 
    foo/bar::
2718
 
 
2719
 
      bzr commit foo -x foo/bar
2720
 
 
2721
 
    If author of the change is not the same person as the committer, you can
2722
 
    specify the author's name using the --author option. The name should be
2723
 
    in the same format as a committer-id, e.g. "John Doe <jdoe@example.com>".
2724
 
    If there is more than one author of the change you can specify the option
2725
 
    multiple times, once for each author.
2726
 
 
2727
 
    A selected-file commit may fail in some cases where the committed
2728
 
    tree would be invalid. Consider::
2729
 
 
2730
 
      bzr init foo
2731
 
      mkdir foo/bar
2732
 
      bzr add foo/bar
2733
 
      bzr commit foo -m "committing foo"
2734
 
      bzr mv foo/bar foo/baz
2735
 
      mkdir foo/bar
2736
 
      bzr add foo/bar
2737
 
      bzr commit foo/bar -m "committing bar but not baz"
2738
 
 
2739
 
    In the example above, the last commit will fail by design. This gives
2740
 
    the user the opportunity to decide whether they want to commit the
2741
 
    rename at the same time, separately first, or not at all. (As a general
2742
 
    rule, when in doubt, Bazaar has a policy of Doing the Safe Thing.)
2743
 
 
2744
 
    Note: A selected-file commit after a merge is not yet supported.
 
2742
    An explanatory message needs to be given for each commit. This is
 
2743
    often done by using the --message option (getting the message from the
 
2744
    command line) or by using the --file option (getting the message from
 
2745
    a file). If neither of these options is given, an editor is opened for
 
2746
    the user to enter the message. To see the changed files in the
 
2747
    boilerplate text loaded into the editor, use the --show-diff option.
 
2748
 
 
2749
    By default, the entire tree is committed and the person doing the
 
2750
    commit is assumed to be the author. These defaults can be overridden
 
2751
    as explained below.
 
2752
 
 
2753
    :Selective commits:
 
2754
 
 
2755
      If selected files are specified, only changes to those files are
 
2756
      committed.  If a directory is specified then the directory and
 
2757
      everything within it is committed.
 
2758
  
 
2759
      When excludes are given, they take precedence over selected files.
 
2760
      For example, to commit only changes within foo, but not changes
 
2761
      within foo/bar::
 
2762
  
 
2763
        bzr commit foo -x foo/bar
 
2764
  
 
2765
      A selective commit after a merge is not yet supported.
 
2766
 
 
2767
    :Custom authors:
 
2768
 
 
2769
      If the author of the change is not the same person as the committer,
 
2770
      you can specify the author's name using the --author option. The
 
2771
      name should be in the same format as a committer-id, e.g.
 
2772
      "John Doe <jdoe@example.com>". If there is more than one author of
 
2773
      the change you can specify the option multiple times, once for each
 
2774
      author.
 
2775
  
 
2776
    :Checks:
 
2777
 
 
2778
      A common mistake is to forget to add a new file or directory before
 
2779
      running the commit command. The --strict option checks for unknown
 
2780
      files and aborts the commit if any are found. More advanced pre-commit
 
2781
      checks can be implemented by defining hooks. See ``bzr help hooks``
 
2782
      for details.
 
2783
 
 
2784
    :Things to note:
 
2785
 
 
2786
      If you accidentially commit the wrong changes or make a spelling
 
2787
      mistake in the commit message say, you can use the uncommit command
 
2788
      to undo it. See ``bzr help uncommit`` for details.
 
2789
 
 
2790
      Hooks can also be configured to run after a commit. This allows you
 
2791
      to trigger updates to external systems like bug trackers. The --fixes
 
2792
      option can be used to record the association between a revision and
 
2793
      one or more bugs. See ``bzr help bugs`` for details.
 
2794
 
 
2795
      A selective commit may fail in some cases where the committed
 
2796
      tree would be invalid. Consider::
 
2797
  
 
2798
        bzr init foo
 
2799
        mkdir foo/bar
 
2800
        bzr add foo/bar
 
2801
        bzr commit foo -m "committing foo"
 
2802
        bzr mv foo/bar foo/baz
 
2803
        mkdir foo/bar
 
2804
        bzr add foo/bar
 
2805
        bzr commit foo/bar -m "committing bar but not baz"
 
2806
  
 
2807
      In the example above, the last commit will fail by design. This gives
 
2808
      the user the opportunity to decide whether they want to commit the
 
2809
      rename at the same time, separately first, or not at all. (As a general
 
2810
      rule, when in doubt, Bazaar has a policy of Doing the Safe Thing.)
2745
2811
    """
2746
2812
    # TODO: Run hooks on tree to-be-committed, and after commit.
2747
2813
 
2752
2818
 
2753
2819
    # XXX: verbose currently does nothing
2754
2820
 
2755
 
    _see_also = ['bugs', 'uncommit']
 
2821
    _see_also = ['add', 'bugs', 'hooks', 'uncommit']
2756
2822
    takes_args = ['selected*']
2757
2823
    takes_options = [
2758
2824
            ListOption('exclude', type=str, short_name='x',
2879
2945
        except PointlessCommit:
2880
2946
            # FIXME: This should really happen before the file is read in;
2881
2947
            # perhaps prepare the commit; get the message; then actually commit
2882
 
            raise errors.BzrCommandError("no changes to commit."
2883
 
                              " use --unchanged to commit anyhow")
 
2948
            raise errors.BzrCommandError("No changes to commit."
 
2949
                              " Use --unchanged to commit anyhow.")
2884
2950
        except ConflictsInTree:
2885
2951
            raise errors.BzrCommandError('Conflicts detected in working '
2886
2952
                'tree.  Use "bzr conflicts" to list, "bzr resolve FILE" to'
4486
4552
    takes_options = [
4487
4553
        Option('inet',
4488
4554
               help='Serve on stdin/out for use from inetd or sshd.'),
 
4555
        RegistryOption('protocol', 
 
4556
               help="Protocol to serve.", 
 
4557
               lazy_registry=('bzrlib.transport', 'transport_server_registry'),
 
4558
               value_switches=True),
4489
4559
        Option('port',
4490
4560
               help='Listen for connections on nominated port of the form '
4491
4561
                    '[hostname:]portnumber.  Passing 0 as the port number will '
4492
 
                    'result in a dynamically allocated port.  The default port is '
4493
 
                    '4155.',
 
4562
                    'result in a dynamically allocated port.  The default port '
 
4563
                    'depends on the protocol.',
4494
4564
               type=str),
4495
4565
        Option('directory',
4496
4566
               help='Serve contents of this directory.',
4502
4572
                ),
4503
4573
        ]
4504
4574
 
4505
 
    def run_smart_server(self, smart_server):
4506
 
        """Run 'smart_server' forever, with no UI output at all."""
4507
 
        # For the duration of this server, no UI output is permitted. note
4508
 
        # that this may cause problems with blackbox tests. This should be
4509
 
        # changed with care though, as we dont want to use bandwidth sending
4510
 
        # progress over stderr to smart server clients!
4511
 
        from bzrlib import lockdir
4512
 
        old_factory = ui.ui_factory
4513
 
        old_lockdir_timeout = lockdir._DEFAULT_TIMEOUT_SECONDS
4514
 
        try:
4515
 
            ui.ui_factory = ui.SilentUIFactory()
4516
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = 0
4517
 
            smart_server.serve()
4518
 
        finally:
4519
 
            ui.ui_factory = old_factory
4520
 
            lockdir._DEFAULT_TIMEOUT_SECONDS = old_lockdir_timeout
4521
 
 
4522
4575
    def get_host_and_port(self, port):
4523
4576
        """Return the host and port to run the smart server on.
4524
4577
 
4525
 
        If 'port' is None, the default host (`medium.BZR_DEFAULT_INTERFACE`)
4526
 
        and port (`medium.BZR_DEFAULT_PORT`) will be used.
 
4578
        If 'port' is None, None will be returned for the host and port.
4527
4579
 
4528
4580
        If 'port' has a colon in it, the string before the colon will be
4529
4581
        interpreted as the host.
4532
4584
        :return: A tuple of (host, port), where 'host' is a host name or IP,
4533
4585
            and port is an integer TCP/IP port.
4534
4586
        """
4535
 
        from bzrlib.smart import medium
4536
 
        host = medium.BZR_DEFAULT_INTERFACE
4537
 
        if port is None:
4538
 
            port = medium.BZR_DEFAULT_PORT
4539
 
        else:
 
4587
        host = None
 
4588
        if port is not None:
4540
4589
            if ':' in port:
4541
4590
                host, port = port.split(':')
4542
4591
            port = int(port)
4543
4592
        return host, port
4544
4593
 
4545
 
    def get_smart_server(self, transport, inet, port):
4546
 
        """Construct a smart server.
4547
 
 
4548
 
        :param transport: The base transport from which branches will be
4549
 
            served.
4550
 
        :param inet: If True, serve over stdin and stdout. Used for running
4551
 
            from inet.
4552
 
        :param port: The port to listen on. By default, it's `
4553
 
            medium.BZR_DEFAULT_PORT`. See `get_host_and_port` for more
4554
 
            information.
4555
 
        :return: A smart server.
4556
 
        """
4557
 
        from bzrlib.smart import medium, server
4558
 
        if inet:
4559
 
            smart_server = medium.SmartServerPipeStreamMedium(
4560
 
                sys.stdin, sys.stdout, transport)
4561
 
        else:
4562
 
            host, port = self.get_host_and_port(port)
4563
 
            smart_server = server.SmartTCPServer(
4564
 
                transport, host=host, port=port)
4565
 
            note('listening on port: %s' % smart_server.port)
4566
 
        return smart_server
4567
 
 
4568
 
    def run(self, port=None, inet=False, directory=None, allow_writes=False):
4569
 
        from bzrlib.transport import get_transport
4570
 
        from bzrlib.transport.chroot import ChrootServer
 
4594
    def run(self, port=None, inet=False, directory=None, allow_writes=False,
 
4595
            protocol=None):
 
4596
        from bzrlib.transport import get_transport, transport_server_registry
4571
4597
        if directory is None:
4572
4598
            directory = os.getcwd()
 
4599
        if protocol is None:
 
4600
            protocol = transport_server_registry.get()
 
4601
        host, port = self.get_host_and_port(port)
4573
4602
        url = urlutils.local_path_to_url(directory)
4574
4603
        if not allow_writes:
4575
4604
            url = 'readonly+' + url
4576
 
        chroot_server = ChrootServer(get_transport(url))
4577
 
        chroot_server.setUp()
4578
 
        t = get_transport(chroot_server.get_url())
4579
 
        smart_server = self.get_smart_server(t, inet, port)
4580
 
        self.run_smart_server(smart_server)
 
4605
        transport = get_transport(url)
 
4606
        protocol(transport, host, port, inet)
4581
4607
 
4582
4608
 
4583
4609
class cmd_join(Command):
4649
4675
        try:
4650
4676
            containing_tree.extract(sub_id)
4651
4677
        except errors.RootNotRich:
4652
 
            raise errors.UpgradeRequired(containing_tree.branch.base)
 
4678
            raise errors.RichRootUpgradeRequired(containing_tree.branch.base)
4653
4679
 
4654
4680
 
4655
4681
class cmd_merge_directive(Command):
4829
4855
        'revision',
4830
4856
        'message',
4831
4857
        Option('body', help='Body for the email.', type=unicode),
4832
 
        RegistryOption.from_kwargs('format',
4833
 
        'Use the specified output format.',
4834
 
        **{'4': 'Bundle format 4, Merge Directive 2 (default)',
4835
 
           '0.9': 'Bundle format 0.9, Merge Directive 1',})
 
4858
        RegistryOption('format',
 
4859
                       help='Use the specified output format.', 
 
4860
                       lazy_registry=('bzrlib.send', 'format_registry'))
4836
4861
        ]
4837
4862
 
4838
4863
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4839
4864
            no_patch=False, revision=None, remember=False, output=None,
4840
 
            format='4', mail_to=None, message=None, body=None, **kwargs):
4841
 
        return self._run(submit_branch, revision, public_branch, remember,
 
4865
            format=None, mail_to=None, message=None, body=None, **kwargs):
 
4866
        from bzrlib.send import send
 
4867
        return send(submit_branch, revision, public_branch, remember,
4842
4868
                         format, no_bundle, no_patch, output,
4843
 
                         kwargs.get('from', '.'), mail_to, message, body)
4844
 
 
4845
 
    def _run(self, submit_branch, revision, public_branch, remember, format,
4846
 
             no_bundle, no_patch, output, from_, mail_to, message, body):
4847
 
        from bzrlib.revision import NULL_REVISION
4848
 
        branch = Branch.open_containing(from_)[0]
4849
 
        if output is None:
4850
 
            outfile = cStringIO.StringIO()
4851
 
        elif output == '-':
4852
 
            outfile = self.outf
4853
 
        else:
4854
 
            outfile = open(output, 'wb')
4855
 
        # we may need to write data into branch's repository to calculate
4856
 
        # the data to send.
4857
 
        branch.lock_write()
4858
 
        try:
4859
 
            if output is None:
4860
 
                config = branch.get_config()
4861
 
                if mail_to is None:
4862
 
                    mail_to = config.get_user_option('submit_to')
4863
 
                mail_client = config.get_mail_client()
4864
 
                if (not getattr(mail_client, 'supports_body', False)
4865
 
                    and body is not None):
4866
 
                    raise errors.BzrCommandError(
4867
 
                        'Mail client "%s" does not support specifying body' %
4868
 
                        mail_client.__class__.__name__)
4869
 
            if remember and submit_branch is None:
4870
 
                raise errors.BzrCommandError(
4871
 
                    '--remember requires a branch to be specified.')
4872
 
            stored_submit_branch = branch.get_submit_branch()
4873
 
            remembered_submit_branch = None
4874
 
            if submit_branch is None:
4875
 
                submit_branch = stored_submit_branch
4876
 
                remembered_submit_branch = "submit"
4877
 
            else:
4878
 
                if stored_submit_branch is None or remember:
4879
 
                    branch.set_submit_branch(submit_branch)
4880
 
            if submit_branch is None:
4881
 
                submit_branch = branch.get_parent()
4882
 
                remembered_submit_branch = "parent"
4883
 
            if submit_branch is None:
4884
 
                raise errors.BzrCommandError('No submit branch known or'
4885
 
                                             ' specified')
4886
 
            if remembered_submit_branch is not None:
4887
 
                note('Using saved %s location "%s" to determine what '
4888
 
                        'changes to submit.', remembered_submit_branch,
4889
 
                        submit_branch)
4890
 
 
4891
 
            if mail_to is None:
4892
 
                submit_config = Branch.open(submit_branch).get_config()
4893
 
                mail_to = submit_config.get_user_option("child_submit_to")
4894
 
 
4895
 
            stored_public_branch = branch.get_public_branch()
4896
 
            if public_branch is None:
4897
 
                public_branch = stored_public_branch
4898
 
            elif stored_public_branch is None or remember:
4899
 
                branch.set_public_branch(public_branch)
4900
 
            if no_bundle and public_branch is None:
4901
 
                raise errors.BzrCommandError('No public branch specified or'
4902
 
                                             ' known')
4903
 
            base_revision_id = None
4904
 
            revision_id = None
4905
 
            if revision is not None:
4906
 
                if len(revision) > 2:
4907
 
                    raise errors.BzrCommandError('bzr send takes '
4908
 
                        'at most two one revision identifiers')
4909
 
                revision_id = revision[-1].as_revision_id(branch)
4910
 
                if len(revision) == 2:
4911
 
                    base_revision_id = revision[0].as_revision_id(branch)
4912
 
            if revision_id is None:
4913
 
                revision_id = branch.last_revision()
4914
 
            if revision_id == NULL_REVISION:
4915
 
                raise errors.BzrCommandError('No revisions to submit.')
4916
 
            if format == '4':
4917
 
                directive = merge_directive.MergeDirective2.from_objects(
4918
 
                    branch.repository, revision_id, time.time(),
4919
 
                    osutils.local_time_offset(), submit_branch,
4920
 
                    public_branch=public_branch, include_patch=not no_patch,
4921
 
                    include_bundle=not no_bundle, message=message,
4922
 
                    base_revision_id=base_revision_id)
4923
 
            elif format == '0.9':
4924
 
                if not no_bundle:
4925
 
                    if not no_patch:
4926
 
                        patch_type = 'bundle'
4927
 
                    else:
4928
 
                        raise errors.BzrCommandError('Format 0.9 does not'
4929
 
                            ' permit bundle with no patch')
4930
 
                else:
4931
 
                    if not no_patch:
4932
 
                        patch_type = 'diff'
4933
 
                    else:
4934
 
                        patch_type = None
4935
 
                directive = merge_directive.MergeDirective.from_objects(
4936
 
                    branch.repository, revision_id, time.time(),
4937
 
                    osutils.local_time_offset(), submit_branch,
4938
 
                    public_branch=public_branch, patch_type=patch_type,
4939
 
                    message=message)
4940
 
 
4941
 
            outfile.writelines(directive.to_lines())
4942
 
            if output is None:
4943
 
                subject = '[MERGE] '
4944
 
                if message is not None:
4945
 
                    subject += message
4946
 
                else:
4947
 
                    revision = branch.repository.get_revision(revision_id)
4948
 
                    subject += revision.get_summary()
4949
 
                basename = directive.get_disk_name(branch)
4950
 
                mail_client.compose_merge_request(mail_to, subject,
4951
 
                                                  outfile.getvalue(),
4952
 
                                                  basename, body)
4953
 
        finally:
4954
 
            if output != '-':
4955
 
                outfile.close()
4956
 
            branch.unlock()
 
4869
                         kwargs.get('from', '.'), mail_to, message, body,
 
4870
                         self.outf)
4957
4871
 
4958
4872
 
4959
4873
class cmd_bundle_revisions(cmd_send):
4960
 
 
4961
4874
    """Create a merge-directive for submitting changes.
4962
4875
 
4963
4876
    A merge directive provides many things needed for requesting merges:
5005
4918
        Option('output', short_name='o', help='Write directive to this file.',
5006
4919
               type=unicode),
5007
4920
        'revision',
5008
 
        RegistryOption.from_kwargs('format',
5009
 
        'Use the specified output format.',
5010
 
        **{'4': 'Bundle format 4, Merge Directive 2 (default)',
5011
 
           '0.9': 'Bundle format 0.9, Merge Directive 1',})
 
4921
        RegistryOption('format',
 
4922
                       help='Use the specified output format.',
 
4923
                       lazy_registry=('bzrlib.send', 'format_registry')),
5012
4924
        ]
5013
4925
    aliases = ['bundle']
5014
4926
 
5018
4930
 
5019
4931
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
5020
4932
            no_patch=False, revision=None, remember=False, output=None,
5021
 
            format='4', **kwargs):
 
4933
            format=None, **kwargs):
5022
4934
        if output is None:
5023
4935
            output = '-'
5024
 
        return self._run(submit_branch, revision, public_branch, remember,
 
4936
        from bzrlib.send import send
 
4937
        return send(submit_branch, revision, public_branch, remember,
5025
4938
                         format, no_bundle, no_patch, output,
5026
 
                         kwargs.get('from', '.'), None, None, None)
 
4939
                         kwargs.get('from', '.'), None, None, None,
 
4940
                         self.outf)
5027
4941
 
5028
4942
 
5029
4943
class cmd_tag(Command):
5124
5038
        if not tags:
5125
5039
            return
5126
5040
 
5127
 
        if revision:
5128
 
            branch.lock_read()
5129
 
            try:
 
5041
        branch.lock_read()
 
5042
        try:
 
5043
            if revision:
5130
5044
                graph = branch.repository.get_graph()
5131
5045
                rev1, rev2 = _get_revision_range(revision, branch, self.name())
5132
5046
                revid1, revid2 = rev1.rev_id, rev2.rev_id
5133
5047
                # only show revisions between revid1 and revid2 (inclusive)
5134
5048
                tags = [(tag, revid) for tag, revid in tags if
5135
5049
                    graph.is_between(revid, revid1, revid2)]
5136
 
            finally:
5137
 
                branch.unlock()
5138
 
        if sort == 'alpha':
5139
 
            tags.sort()
5140
 
        elif sort == 'time':
5141
 
            timestamps = {}
5142
 
            for tag, revid in tags:
5143
 
                try:
5144
 
                    revobj = branch.repository.get_revision(revid)
5145
 
                except errors.NoSuchRevision:
5146
 
                    timestamp = sys.maxint # place them at the end
5147
 
                else:
5148
 
                    timestamp = revobj.timestamp
5149
 
                timestamps[revid] = timestamp
5150
 
            tags.sort(key=lambda x: timestamps[x[1]])
5151
 
        if not show_ids:
5152
 
            # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
5153
 
            revno_map = branch.get_revision_id_to_revno_map()
5154
 
            tags = [ (tag, '.'.join(map(str, revno_map.get(revid, ('?',)))))
5155
 
                        for tag, revid in tags ]
 
5050
            if sort == 'alpha':
 
5051
                tags.sort()
 
5052
            elif sort == 'time':
 
5053
                timestamps = {}
 
5054
                for tag, revid in tags:
 
5055
                    try:
 
5056
                        revobj = branch.repository.get_revision(revid)
 
5057
                    except errors.NoSuchRevision:
 
5058
                        timestamp = sys.maxint # place them at the end
 
5059
                    else:
 
5060
                        timestamp = revobj.timestamp
 
5061
                    timestamps[revid] = timestamp
 
5062
                tags.sort(key=lambda x: timestamps[x[1]])
 
5063
            if not show_ids:
 
5064
                # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
 
5065
                for index, (tag, revid) in enumerate(tags):
 
5066
                    try:
 
5067
                        revno = branch.revision_id_to_dotted_revno(revid)
 
5068
                        if isinstance(revno, tuple):
 
5069
                            revno = '.'.join(map(str, revno))
 
5070
                    except errors.NoSuchRevision:
 
5071
                        # Bad tag data/merges can lead to tagged revisions
 
5072
                        # which are not in this branch. Fail gracefully ...
 
5073
                        revno = '?'
 
5074
                    tags[index] = (tag, revno)
 
5075
        finally:
 
5076
            branch.unlock()
5156
5077
        for tag, revspec in tags:
5157
5078
            self.outf.write('%-20s %s\n' % (tag, revspec))
5158
5079
 
5257
5178
        from bzrlib import switch
5258
5179
        tree_location = '.'
5259
5180
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
5260
 
        branch = control_dir.open_branch()
 
5181
        try:
 
5182
            branch = control_dir.open_branch()
 
5183
            had_explicit_nick = branch.get_config().has_explicit_nickname()
 
5184
        except errors.NotBranchError:
 
5185
            had_explicit_nick = False
5261
5186
        try:
5262
5187
            to_branch = Branch.open(to_location)
5263
5188
        except errors.NotBranchError:
5264
 
            this_branch = control_dir.open_branch()
5265
 
            # This may be a heavy checkout, where we want the master branch
5266
 
            this_url = this_branch.get_bound_location()
5267
 
            # If not, use a local sibling
5268
 
            if this_url is None:
5269
 
                this_url = this_branch.base
 
5189
            this_url = self._get_branch_location(control_dir)
5270
5190
            to_branch = Branch.open(
5271
5191
                urlutils.join(this_url, '..', to_location))
5272
5192
        switch.switch(control_dir, to_branch, force)
5273
 
        if branch.get_config().has_explicit_nickname():
 
5193
        if had_explicit_nick:
5274
5194
            branch = control_dir.open_branch() #get the new branch!
5275
5195
            branch.nick = to_branch.nick
5276
5196
        note('Switched to branch: %s',
5277
5197
            urlutils.unescape_for_display(to_branch.base, 'utf-8'))
5278
5198
 
 
5199
    def _get_branch_location(self, control_dir):
 
5200
        """Return location of branch for this control dir."""
 
5201
        try:
 
5202
            this_branch = control_dir.open_branch()
 
5203
            # This may be a heavy checkout, where we want the master branch
 
5204
            master_location = this_branch.get_bound_location()
 
5205
            if master_location is not None:
 
5206
                return master_location
 
5207
            # If not, use a local sibling
 
5208
            return this_branch.base
 
5209
        except errors.NotBranchError:
 
5210
            format = control_dir.find_branch_format()
 
5211
            if getattr(format, 'get_reference', None) is not None:
 
5212
                return format.get_reference(control_dir)
 
5213
            else:
 
5214
                return control_dir.root_transport.base
 
5215
 
5279
5216
 
5280
5217
class cmd_view(Command):
5281
5218
    """Manage filtered views.
5583
5520
                   dry_run=dry_run, no_prompt=force)
5584
5521
 
5585
5522
 
5586
 
def _create_prefix(cur_transport):
5587
 
    needed = [cur_transport]
5588
 
    # Recurse upwards until we can create a directory successfully
5589
 
    while True:
5590
 
        new_transport = cur_transport.clone('..')
5591
 
        if new_transport.base == cur_transport.base:
5592
 
            raise errors.BzrCommandError(
5593
 
                "Failed to create path prefix for %s."
5594
 
                % cur_transport.base)
5595
 
        try:
5596
 
            new_transport.mkdir('.')
5597
 
        except errors.NoSuchFile:
5598
 
            needed.append(new_transport)
5599
 
            cur_transport = new_transport
 
5523
class cmd_reference(Command):
 
5524
    """list, view and set branch locations for nested trees.
 
5525
 
 
5526
    If no arguments are provided, lists the branch locations for nested trees.
 
5527
    If one argument is provided, display the branch location for that tree.
 
5528
    If two arguments are provided, set the branch location for that tree.
 
5529
    """
 
5530
 
 
5531
    hidden = True
 
5532
 
 
5533
    takes_args = ['path?', 'location?']
 
5534
 
 
5535
    def run(self, path=None, location=None):
 
5536
        branchdir = '.'
 
5537
        if path is not None:
 
5538
            branchdir = path
 
5539
        tree, branch, relpath =(
 
5540
            bzrdir.BzrDir.open_containing_tree_or_branch(branchdir))
 
5541
        if path is not None:
 
5542
            path = relpath
 
5543
        if tree is None:
 
5544
            tree = branch.basis_tree()
 
5545
        if path is None:
 
5546
            info = branch._get_all_reference_info().iteritems()
 
5547
            self._display_reference_info(tree, branch, info)
5600
5548
        else:
5601
 
            break
5602
 
    # Now we only need to create child directories
5603
 
    while needed:
5604
 
        cur_transport = needed.pop()
5605
 
        cur_transport.ensure_base()
 
5549
            file_id = tree.path2id(path)
 
5550
            if file_id is None:
 
5551
                raise errors.NotVersionedError(path)
 
5552
            if location is None:
 
5553
                info = [(file_id, branch.get_reference_info(file_id))]
 
5554
                self._display_reference_info(tree, branch, info)
 
5555
            else:
 
5556
                branch.set_reference_info(file_id, path, location)
 
5557
 
 
5558
    def _display_reference_info(self, tree, branch, info):
 
5559
        ref_list = []
 
5560
        for file_id, (path, location) in info:
 
5561
            try:
 
5562
                path = tree.id2path(file_id)
 
5563
            except errors.NoSuchId:
 
5564
                pass
 
5565
            ref_list.append((path, location))
 
5566
        for path, location in sorted(ref_list):
 
5567
            self.outf.write('%s %s\n' % (path, location))
5606
5568
 
5607
5569
 
5608
5570
# these get imported and then picked up by the scan for cmd_*