~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Andrew Bennetts
  • Date: 2007-08-02 06:40:58 UTC
  • mfrom: (2666 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2668.
  • Revision ID: andrew.bennetts@canonical.com-20070802064058-09eblz1qbc01fcr3
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
53
53
    urlutils,
54
54
    )
55
55
from bzrlib.branch import Branch
56
 
from bzrlib.bundle.apply_bundle import install_bundle, merge_bundle
57
56
from bzrlib.conflicts import ConflictList
58
57
from bzrlib.revisionspec import RevisionSpec
59
58
from bzrlib.smtp_connection import SMTPConnection
582
581
    def run(self, location=None, remember=False, overwrite=False,
583
582
            revision=None, verbose=False,
584
583
            directory=None):
585
 
        from bzrlib.tag import _merge_tags_if_possible
586
584
        # FIXME: too much stuff is in the command class
587
585
        revision_id = None
588
586
        mergeable = None
595
593
            tree_to = None
596
594
            branch_to = Branch.open_containing(directory)[0]
597
595
 
598
 
        reader = None
599
596
        if location is not None:
600
 
            try:
601
 
                mergeable = bundle.read_mergeable_from_url(
602
 
                    location)
603
 
            except errors.NotABundle:
604
 
                pass # Continue on considering this url a Branch
 
597
            mergeable, location_transport = _get_mergeable_helper(location)
605
598
 
606
599
        stored_loc = branch_to.get_parent()
607
600
        if location is None:
613
606
                        self.outf.encoding)
614
607
                self.outf.write("Using saved location: %s\n" % display_url)
615
608
                location = stored_loc
 
609
                location_transport = transport.get_transport(location)
616
610
 
617
611
        if mergeable is not None:
618
612
            if revision is not None:
619
613
                raise errors.BzrCommandError(
620
614
                    'Cannot use -r with merge directives or bundles')
621
 
            revision_id = mergeable.install_revisions(branch_to.repository)
 
615
            mergeable.install_revisions(branch_to.repository)
 
616
            base_revision_id, revision_id, verified = \
 
617
                mergeable.get_merge_request(branch_to.repository)
622
618
            branch_from = branch_to
623
619
        else:
624
 
            branch_from = Branch.open(location)
 
620
            branch_from = Branch.open_from_transport(location_transport)
625
621
 
626
622
            if branch_to.get_parent() is None or remember:
627
623
                branch_to.set_parent(branch_from.base)
633
629
                raise errors.BzrCommandError(
634
630
                    'bzr pull --revision takes one value.')
635
631
 
636
 
        old_rh = branch_to.revision_history()
 
632
        if verbose:
 
633
            old_rh = branch_to.revision_history()
637
634
        if tree_to is not None:
638
635
            result = tree_to.pull(branch_from, overwrite, revision_id,
639
636
                delta._ChangeReporter(unversioned_filter=tree_to.is_ignored))
735
732
                # Found a branch, so we must have found a repository
736
733
                repository_to = br_to.repository
737
734
        push_result = None
738
 
        old_rh = []
 
735
        if verbose:
 
736
            old_rh = []
739
737
        if dir_to is None:
740
738
            # The destination doesn't exist; create it.
741
739
            # XXX: Refactor the create_prefix/no_create_prefix code into a
791
789
            # we don't need to successfully push because of possible divergence.
792
790
            if br_from.get_push_location() is None or remember:
793
791
                br_from.set_push_location(br_to.base)
794
 
            old_rh = br_to.revision_history()
 
792
            if verbose:
 
793
                old_rh = br_to.revision_history()
795
794
            try:
796
795
                try:
797
796
                    tree_to = dir_to.open_workingtree()
881
880
                                             % to_location)
882
881
            try:
883
882
                # preserve whatever source format we have.
884
 
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id)
 
883
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
 
884
                                            possible_transports=[to_transport])
885
885
                branch = dir.open_branch()
886
886
            except errors.NoSuchRevision:
887
887
                to_transport.delete_tree('.')
941
941
            to_location = branch_location
942
942
        source = Branch.open(branch_location)
943
943
        if len(revision) == 1 and revision[0] is not None:
944
 
            revision_id = revision[0].in_history(source)[1]
 
944
            revision_id = _mod_revision.ensure_null(
 
945
                revision[0].in_history(source)[1])
945
946
        else:
946
947
            revision_id = None
947
948
        if to_location is None:
954
955
            try:
955
956
                source.bzrdir.open_workingtree()
956
957
            except errors.NoWorkingTree:
957
 
                source.bzrdir.create_workingtree()
 
958
                source.bzrdir.create_workingtree(revision_id)
958
959
                return
959
960
        try:
960
961
            os.mkdir(to_location)
1010
1011
    'bzr revert' instead of 'bzr commit' after the update.
1011
1012
    """
1012
1013
 
1013
 
    _see_also = ['pull', 'working-trees']
 
1014
    _see_also = ['pull', 'working-trees', 'status-flags']
1014
1015
    takes_args = ['dir?']
1015
1016
    aliases = ['up']
1016
1017
 
1027
1028
            if last_rev == _mod_revision.ensure_null(
1028
1029
                tree.branch.last_revision()):
1029
1030
                # may be up to date, check master too.
1030
 
                master = tree.branch.get_master_branch()
1031
1031
                if master is None or last_rev == _mod_revision.ensure_null(
1032
1032
                    master.last_revision()):
1033
1033
                    revno = tree.branch.revision_id_to_revno(last_rev)
1295
1295
            _create_prefix(to_transport)
1296
1296
 
1297
1297
        try:
1298
 
            existing_bzrdir = bzrdir.BzrDir.open(location)
 
1298
            existing_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport)
1299
1299
        except errors.NotBranchError:
1300
1300
            # really a NotBzrDir error...
1301
 
            branch = bzrdir.BzrDir.create_branch_convenience(to_transport.base,
1302
 
                                                             format=format)
 
1301
            create_branch = bzrdir.BzrDir.create_branch_convenience
 
1302
            branch = create_branch(to_transport.base, format=format,
 
1303
                                   possible_transports=[to_transport])
1303
1304
        else:
1304
1305
            from bzrlib.transport.local import LocalTransport
1305
1306
            if existing_bzrdir.has_branch():
2637
2638
            directory=None,
2638
2639
            ):
2639
2640
        from bzrlib.tag import _merge_tags_if_possible
2640
 
        other_revision_id = None
 
2641
        # This is actually a branch (or merge-directive) *location*.
 
2642
        location = branch
 
2643
        del branch
 
2644
 
2641
2645
        if merge_type is None:
2642
2646
            merge_type = _mod_merge.Merge3Merger
2643
2647
 
2644
2648
        if directory is None: directory = u'.'
2645
 
        # XXX: jam 20070225 WorkingTree should be locked before you extract its
2646
 
        #      inventory. Because merge is a mutating operation, it really
2647
 
        #      should be a lock_write() for the whole cmd_merge operation.
2648
 
        #      However, cmd_merge open's its own tree in _merge_helper, which
2649
 
        #      means if we lock here, the later lock_write() will always block.
2650
 
        #      Either the merge helper code should be updated to take a tree,
2651
 
        #      (What about tree.merge_from_branch?)
 
2649
        possible_transports = []
 
2650
        merger = None
 
2651
        allow_pending = True
 
2652
        verified = 'inapplicable'
2652
2653
        tree = WorkingTree.open_containing(directory)[0]
2653
2654
        change_reporter = delta._ChangeReporter(
2654
2655
            unversioned_filter=tree.is_ignored)
2655
 
 
2656
 
        if branch is not None:
2657
 
            try:
2658
 
                mergeable = bundle.read_mergeable_from_url(
2659
 
                    branch)
2660
 
            except errors.NotABundle:
2661
 
                pass # Continue on considering this url a Branch
2662
 
            else:
2663
 
                if revision is not None:
2664
 
                    raise errors.BzrCommandError(
2665
 
                        'Cannot use -r with merge directives or bundles')
2666
 
                other_revision_id = mergeable.install_revisions(
2667
 
                    tree.branch.repository)
2668
 
                revision = [RevisionSpec.from_string(
2669
 
                    'revid:' + other_revision_id)]
2670
 
 
2671
 
        if revision is None \
2672
 
                or len(revision) < 1 or revision[0].needs_branch():
2673
 
            branch = self._get_remembered_parent(tree, branch, 'Merging from')
2674
 
 
2675
 
        if revision is None or len(revision) < 1:
2676
 
            if uncommitted:
2677
 
                base = [branch, -1]
2678
 
                other = [branch, None]
2679
 
            else:
2680
 
                base = [None, None]
2681
 
                other = [branch, -1]
2682
 
            other_branch, path = Branch.open_containing(branch)
2683
 
        else:
2684
 
            if uncommitted:
2685
 
                raise errors.BzrCommandError('Cannot use --uncommitted and'
2686
 
                                             ' --revision at the same time.')
2687
 
            branch = revision[0].get_branch() or branch
2688
 
            if len(revision) == 1:
2689
 
                base = [None, None]
2690
 
                if other_revision_id is not None:
2691
 
                    other_branch = None
2692
 
                    path = ""
2693
 
                    other = None
2694
 
                else:
2695
 
                    other_branch, path = Branch.open_containing(branch)
2696
 
                    revno = revision[0].in_history(other_branch).revno
2697
 
                    other = [branch, revno]
2698
 
            else:
2699
 
                assert len(revision) == 2
2700
 
                if None in revision:
2701
 
                    raise errors.BzrCommandError(
2702
 
                        "Merge doesn't permit empty revision specifier.")
2703
 
                base_branch, path = Branch.open_containing(branch)
2704
 
                branch1 = revision[1].get_branch() or branch
2705
 
                other_branch, path1 = Branch.open_containing(branch1)
2706
 
                if revision[0].get_branch() is not None:
2707
 
                    # then path was obtained from it, and is None.
2708
 
                    path = path1
2709
 
 
2710
 
                base = [branch, revision[0].in_history(base_branch).revno]
2711
 
                other = [branch1, revision[1].in_history(other_branch).revno]
2712
 
 
 
2656
        cleanups = []
 
2657
        try:
 
2658
            pb = ui.ui_factory.nested_progress_bar()
 
2659
            cleanups.append(pb.finished)
 
2660
            tree.lock_write()
 
2661
            cleanups.append(tree.unlock)
 
2662
            if location is not None:
 
2663
                mergeable, other_transport = _get_mergeable_helper(location)
 
2664
                if mergeable:
 
2665
                    if uncommitted:
 
2666
                        raise errors.BzrCommandError('Cannot use --uncommitted'
 
2667
                            ' with bundles or merge directives.')
 
2668
 
 
2669
                    if revision is not None:
 
2670
                        raise errors.BzrCommandError(
 
2671
                            'Cannot use -r with merge directives or bundles')
 
2672
                    merger, verified = _mod_merge.Merger.from_mergeable(tree,
 
2673
                       mergeable, pb)
 
2674
                possible_transports.append(other_transport)
 
2675
 
 
2676
            if merger is None and uncommitted:
 
2677
                if revision is not None and len(revision) > 0:
 
2678
                    raise errors.BzrCommandError('Cannot use --uncommitted and'
 
2679
                        ' --revision at the same time.')
 
2680
                location = self._select_branch_location(tree, location)[0]
 
2681
                other_tree, other_path = WorkingTree.open_containing(location)
 
2682
                merger = _mod_merge.Merger.from_uncommitted(tree, other_tree,
 
2683
                    pb)
 
2684
                allow_pending = False
 
2685
 
 
2686
            if merger is None:
 
2687
                merger, allow_pending = self._get_merger_from_branch(tree,
 
2688
                    location, revision, remember, possible_transports, pb)
 
2689
 
 
2690
            merger.merge_type = merge_type
 
2691
            merger.reprocess = reprocess
 
2692
            merger.show_base = show_base
 
2693
            merger.change_reporter = change_reporter
 
2694
            self.sanity_check_merger(merger)
 
2695
            if (merger.base_rev_id == merger.other_rev_id and
 
2696
                merger.other_rev_id != None):
 
2697
                note('Nothing to do.')
 
2698
                return 0
 
2699
            if pull:
 
2700
                if merger.interesting_files is not None:
 
2701
                    raise BzrCommandError('Cannot pull individual files')
 
2702
                if (merger.base_rev_id == tree.last_revision()):
 
2703
                    result = tree.pull(merger.other_branch, False,
 
2704
                                       merger.other_rev_id)
 
2705
                    result.report(self.outf)
 
2706
                    return 0
 
2707
            merger.check_basis(not force)
 
2708
            conflict_count = merger.do_merge()
 
2709
            if allow_pending:
 
2710
                merger.set_pending()
 
2711
            if verified == 'failed':
 
2712
                warning('Preview patch does not match changes')
 
2713
            if conflict_count != 0:
 
2714
                return 1
 
2715
            else:
 
2716
                return 0
 
2717
        finally:
 
2718
            for cleanup in reversed(cleanups):
 
2719
                cleanup()
 
2720
 
 
2721
    def sanity_check_merger(self, merger):
 
2722
        if (merger.show_base and
 
2723
            not merger.merge_type is _mod_merge.Merge3Merger):
 
2724
            raise errors.BzrCommandError("Show-base is not supported for this"
 
2725
                                         " merge type. %s" % merge_type)
 
2726
        if merger.reprocess and not merger.merge_type.supports_reprocess:
 
2727
            raise errors.BzrCommandError("Conflict reduction is not supported"
 
2728
                                         " for merge type %s." % merge_type)
 
2729
        if merger.reprocess and merger.show_base:
 
2730
            raise errors.BzrCommandError("Cannot do conflict reduction and"
 
2731
                                         " show base.")
 
2732
 
 
2733
    def _get_merger_from_branch(self, tree, location, revision, remember,
 
2734
                                possible_transports, pb):
 
2735
        """Produce a merger from a location, assuming it refers to a branch."""
 
2736
        from bzrlib.tag import _merge_tags_if_possible
 
2737
        assert revision is None or len(revision) < 3
 
2738
        # find the branch locations
 
2739
        other_loc, location = self._select_branch_location(tree, location,
 
2740
            revision, -1)
 
2741
        if revision is not None and len(revision) == 2:
 
2742
            base_loc, location = self._select_branch_location(tree, location,
 
2743
                                                              revision, 0)
 
2744
        else:
 
2745
            base_loc = other_loc
 
2746
        # Open the branches
 
2747
        other_branch, other_path = Branch.open_containing(other_loc,
 
2748
            possible_transports)
 
2749
        if base_loc == other_loc:
 
2750
            base_branch = other_branch
 
2751
        else:
 
2752
            base_branch, base_path = Branch.open_containing(base_loc,
 
2753
                possible_transports)
 
2754
        # Find the revision ids
 
2755
        if revision is None or len(revision) < 1 or revision[-1] is None:
 
2756
            other_revision_id = _mod_revision.ensure_null(
 
2757
                other_branch.last_revision())
 
2758
        else:
 
2759
            other_revision_id = \
 
2760
                _mod_revision.ensure_null(
 
2761
                    revision[-1].in_history(other_branch).rev_id)
 
2762
        if (revision is not None and len(revision) == 2
 
2763
            and revision[0] is not None):
 
2764
            base_revision_id = \
 
2765
                _mod_revision.ensure_null(
 
2766
                    revision[0].in_history(base_branch).rev_id)
 
2767
        else:
 
2768
            base_revision_id = None
 
2769
        # Remember where we merge from
2713
2770
        if ((tree.branch.get_parent() is None or remember) and
2714
2771
            other_branch is not None):
2715
2772
            tree.branch.set_parent(other_branch.base)
2716
 
 
2717
 
        # pull tags now... it's a bit inconsistent to do it ahead of copying
2718
 
        # the history but that's done inside the merge code
2719
 
        if other_branch is not None:
2720
 
            _merge_tags_if_possible(other_branch, tree.branch)
2721
 
 
2722
 
        if path != "":
2723
 
            interesting_files = [path]
 
2773
        _merge_tags_if_possible(other_branch, tree.branch)
 
2774
        merger = _mod_merge.Merger.from_revision_ids(pb, tree,
 
2775
            other_revision_id, base_revision_id, other_branch, base_branch)
 
2776
        if other_path != '':
 
2777
            allow_pending = False
 
2778
            merger.interesting_files = [other_path]
2724
2779
        else:
2725
 
            interesting_files = None
2726
 
        pb = ui.ui_factory.nested_progress_bar()
2727
 
        try:
2728
 
            try:
2729
 
                conflict_count = _merge_helper(
2730
 
                    other, base, other_rev_id=other_revision_id,
2731
 
                    check_clean=(not force),
2732
 
                    merge_type=merge_type,
2733
 
                    reprocess=reprocess,
2734
 
                    show_base=show_base,
2735
 
                    pull=pull,
2736
 
                    this_dir=directory,
2737
 
                    pb=pb, file_list=interesting_files,
2738
 
                    change_reporter=change_reporter)
2739
 
            finally:
2740
 
                pb.finished()
2741
 
            if conflict_count != 0:
2742
 
                return 1
2743
 
            else:
2744
 
                return 0
2745
 
        except errors.AmbiguousBase, e:
2746
 
            m = ("sorry, bzr can't determine the right merge base yet\n"
2747
 
                 "candidates are:\n  "
2748
 
                 + "\n  ".join(e.bases)
2749
 
                 + "\n"
2750
 
                 "please specify an explicit base with -r,\n"
2751
 
                 "and (if you want) report this to the bzr developers\n")
2752
 
            log_error(m)
 
2780
            allow_pending = True
 
2781
        return merger, allow_pending
 
2782
 
 
2783
    def _select_branch_location(self, tree, location, revision=None,
 
2784
                                index=None):
 
2785
        """Select a branch location, according to possible inputs.
 
2786
 
 
2787
        If provided, branches from ``revision`` are preferred.  (Both
 
2788
        ``revision`` and ``index`` must be supplied.)
 
2789
 
 
2790
        Otherwise, the ``location`` parameter is used.  If it is None, then the
 
2791
        ``parent`` location is used, and a note is printed.
 
2792
 
 
2793
        :param tree: The working tree to select a branch for merging into
 
2794
        :param location: The location entered by the user
 
2795
        :param revision: The revision parameter to the command
 
2796
        :param index: The index to use for the revision parameter.  Negative
 
2797
            indices are permitted.
 
2798
        :return: (selected_location, default_location).  The default location
 
2799
            will be the user-entered location, if any, or else the remembered
 
2800
            location.
 
2801
        """
 
2802
        if (revision is not None and index is not None
 
2803
            and revision[index] is not None):
 
2804
            branch = revision[index].get_branch()
 
2805
            if branch is not None:
 
2806
                return branch, location
 
2807
        location = self._get_remembered_parent(tree, location, 'Merging from')
 
2808
        return location, location
2753
2809
 
2754
2810
    # TODO: move up to common parent; this isn't merge-specific anymore. 
2755
2811
    def _get_remembered_parent(self, tree, supplied_location, verb_string):
2763
2819
        mutter("%s", stored_location)
2764
2820
        if stored_location is None:
2765
2821
            raise errors.BzrCommandError("No location specified or remembered")
2766
 
        display_url = urlutils.unescape_for_display(stored_location, self.outf.encoding)
2767
 
        self.outf.write("%s remembered location %s\n" % (verb_string, display_url))
 
2822
        display_url = urlutils.unescape_for_display(stored_location,
 
2823
            self.outf.encoding)
 
2824
        self.outf.write("%s remembered location %s\n" % (verb_string,
 
2825
            display_url))
2768
2826
        return stored_location
2769
2827
 
2770
2828
 
2844
2902
                    restore(tree.abspath(filename))
2845
2903
                except errors.NotConflicted:
2846
2904
                    pass
2847
 
            conflicts = _mod_merge.merge_inner(
2848
 
                                      tree.branch, other_tree, base_tree,
2849
 
                                      this_tree=tree,
2850
 
                                      interesting_ids=interesting_ids,
2851
 
                                      other_rev_id=parents[1],
2852
 
                                      merge_type=merge_type,
2853
 
                                      show_base=show_base,
2854
 
                                      reprocess=reprocess)
 
2905
            # Disable pending merges, because the file texts we are remerging
 
2906
            # have not had those merges performed.  If we use the wrong parents
 
2907
            # list, we imply that the working tree text has seen and rejected
 
2908
            # all the changes from the other tree, when in fact those changes
 
2909
            # have not yet been seen.
 
2910
            tree.set_parent_ids(parents[:1])
 
2911
            try:
 
2912
                conflicts = _mod_merge.merge_inner(
 
2913
                                          tree.branch, other_tree, base_tree,
 
2914
                                          this_tree=tree,
 
2915
                                          interesting_ids=interesting_ids,
 
2916
                                          other_rev_id=parents[1],
 
2917
                                          merge_type=merge_type,
 
2918
                                          show_base=show_base,
 
2919
                                          reprocess=reprocess)
 
2920
            finally:
 
2921
                tree.set_parent_ids(parents)
2855
2922
        finally:
2856
2923
            tree.unlock()
2857
2924
        if conflicts > 0:
3010
3077
        if other_branch is None:
3011
3078
            other_branch = parent
3012
3079
            if other_branch is None:
3013
 
                raise errors.BzrCommandError("No peer location known or specified.")
 
3080
                raise errors.BzrCommandError("No peer location known"
 
3081
                                             " or specified.")
3014
3082
            display_url = urlutils.unescape_for_display(parent,
3015
3083
                                                        self.outf.encoding)
3016
 
            print "Using last location: " + display_url
 
3084
            self.outf.write("Using last location: " + display_url + "\n")
3017
3085
 
3018
3086
        remote_branch = Branch.open(other_branch)
3019
3087
        if remote_branch.base == local_branch.base:
3022
3090
        try:
3023
3091
            remote_branch.lock_read()
3024
3092
            try:
3025
 
                local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
3026
 
                if (log_format is None):
3027
 
                    log_format = log.log_formatter_registry.get_default(
3028
 
                        local_branch)
 
3093
                local_extra, remote_extra = find_unmerged(local_branch,
 
3094
                                                          remote_branch)
 
3095
                if log_format is None:
 
3096
                    registry = log.log_formatter_registry
 
3097
                    log_format = registry.get_default(local_branch)
3029
3098
                lf = log_format(to_file=self.outf,
3030
3099
                                show_ids=show_ids,
3031
3100
                                show_timezone='original')
3033
3102
                    local_extra.reverse()
3034
3103
                    remote_extra.reverse()
3035
3104
                if local_extra and not theirs_only:
3036
 
                    print "You have %d extra revision(s):" % len(local_extra)
3037
 
                    for revision in iter_log_revisions(local_extra, 
 
3105
                    self.outf.write("You have %d extra revision(s):\n" %
 
3106
                                    len(local_extra))
 
3107
                    for revision in iter_log_revisions(local_extra,
3038
3108
                                        local_branch.repository,
3039
3109
                                        verbose):
3040
3110
                        lf.log_revision(revision)
3043
3113
                    printed_local = False
3044
3114
                if remote_extra and not mine_only:
3045
3115
                    if printed_local is True:
3046
 
                        print "\n\n"
3047
 
                    print "You are missing %d revision(s):" % len(remote_extra)
3048
 
                    for revision in iter_log_revisions(remote_extra, 
3049
 
                                        remote_branch.repository, 
 
3116
                        self.outf.write("\n\n\n")
 
3117
                    self.outf.write("You are missing %d revision(s):\n" %
 
3118
                                    len(remote_extra))
 
3119
                    for revision in iter_log_revisions(remote_extra,
 
3120
                                        remote_branch.repository,
3050
3121
                                        verbose):
3051
3122
                        lf.log_revision(revision)
3052
3123
                if not remote_extra and not local_extra:
3053
3124
                    status_code = 0
3054
 
                    print "Branches are up to date."
 
3125
                    self.outf.write("Branches are up to date.\n")
3055
3126
                else:
3056
3127
                    status_code = 1
3057
3128
            finally:
3086
3157
 
3087
3158
 
3088
3159
class cmd_plugins(Command):
3089
 
    """List plugins"""
3090
 
    hidden = True
 
3160
    """List the installed plugins.
 
3161
    
 
3162
    This command displays the list of installed plugins including the
 
3163
    path where each one is located and a short description of each.
 
3164
 
 
3165
    A plugin is an external component for Bazaar that extends the
 
3166
    revision control system, by adding or replacing code in Bazaar.
 
3167
    Plugins can do a variety of things, including overriding commands,
 
3168
    adding new commands, providing additional network transports and
 
3169
    customizing log output.
 
3170
 
 
3171
    See the Bazaar web site, http://bazaar-vcs.org, for further
 
3172
    information on plugins including where to find them and how to
 
3173
    install them. Instructions are also provided there on how to
 
3174
    write new plugins using the Python programming language.
 
3175
    """
 
3176
 
3091
3177
    @display_command
3092
3178
    def run(self):
3093
3179
        import bzrlib.plugin
3556
3642
 
3557
3643
    takes_args = ['submit_branch?', 'public_branch?']
3558
3644
 
 
3645
    hidden = True
 
3646
 
 
3647
    _see_also = ['submit']
 
3648
 
3559
3649
    takes_options = [
3560
3650
        RegistryOption.from_kwargs('patch-type',
3561
3651
            'The type of patch to include in the directive',
3577
3667
    def run(self, submit_branch=None, public_branch=None, patch_type='bundle',
3578
3668
            sign=False, revision=None, mail_to=None, message=None):
3579
3669
        from bzrlib.revision import ensure_null, NULL_REVISION
3580
 
        if patch_type == 'plain':
3581
 
            patch_type = None
 
3670
        include_patch, include_bundle = {
 
3671
            'plain': (False, False),
 
3672
            'diff': (True, False),
 
3673
            'bundle': (True, True),
 
3674
            }[patch_type]
3582
3675
        branch = Branch.open('.')
3583
3676
        stored_submit_branch = branch.get_submit_branch()
3584
3677
        if submit_branch is None:
3596
3689
            public_branch = stored_public_branch
3597
3690
        elif stored_public_branch is None:
3598
3691
            branch.set_public_branch(public_branch)
3599
 
        if patch_type != "bundle" and public_branch is None:
 
3692
        if not include_bundle and public_branch is None:
3600
3693
            raise errors.BzrCommandError('No public branch specified or'
3601
3694
                                         ' known')
 
3695
        base_revision_id = None
3602
3696
        if revision is not None:
3603
 
            if len(revision) != 1:
 
3697
            if len(revision) > 2:
3604
3698
                raise errors.BzrCommandError('bzr merge-directive takes '
3605
 
                    'exactly one revision identifier')
3606
 
            else:
3607
 
                revision_id = revision[0].in_history(branch).rev_id
 
3699
                    'at most two one revision identifiers')
 
3700
            revision_id = revision[-1].in_history(branch).rev_id
 
3701
            if len(revision) == 2:
 
3702
                base_revision_id = revision[0].in_history(branch).rev_id
 
3703
                base_revision_id = ensure_null(base_revision_id)
3608
3704
        else:
3609
3705
            revision_id = branch.last_revision()
3610
3706
        revision_id = ensure_null(revision_id)
3611
3707
        if revision_id == NULL_REVISION:
3612
3708
            raise errors.BzrCommandError('No revisions to bundle.')
3613
 
        directive = merge_directive.MergeDirective.from_objects(
 
3709
        directive = merge_directive.MergeDirective2.from_objects(
3614
3710
            branch.repository, revision_id, time.time(),
3615
3711
            osutils.local_time_offset(), submit_branch,
3616
 
            public_branch=public_branch, patch_type=patch_type,
3617
 
            message=message)
 
3712
            public_branch=public_branch, include_patch=include_patch,
 
3713
            include_bundle=include_bundle, message=message,
 
3714
            base_revision_id=base_revision_id)
3618
3715
        if mail_to is None:
3619
3716
            if sign:
3620
3717
                self.outf.write(directive.to_signed(branch))
3626
3723
            s.send_email(message)
3627
3724
 
3628
3725
 
 
3726
class cmd_send(Command):
 
3727
    """Create a merge-directive for submiting changes.
 
3728
 
 
3729
    A merge directive provides many things needed for requesting merges:
 
3730
    - A machine-readable description of the merge to perform
 
3731
    - An optional patch that is a preview of the changes requested
 
3732
    - An optional bundle of revision data, so that the changes can be applied
 
3733
      directly from the merge directive, without retrieving data from a
 
3734
      branch.
 
3735
 
 
3736
    If --no-bundle is specified, then public_branch is needed (and must be
 
3737
    up-to-date), so that the receiver can perform the merge using the
 
3738
    public_branch.  The public_branch is always included if known, so that
 
3739
    people can check it later.
 
3740
 
 
3741
    The submit branch defaults to the parent, but can be overridden.  Both
 
3742
    submit branch and public branch will be remembered if supplied.
 
3743
 
 
3744
    If a public_branch is known for the submit_branch, that public submit
 
3745
    branch is used in the merge instructions.  This means that a local mirror
 
3746
    can be used as your actual submit branch, once you have set public_branch
 
3747
    for that mirror.
 
3748
    """
 
3749
 
 
3750
    encoding_type = 'exact'
 
3751
 
 
3752
    aliases = ['bundle', 'bundle-revisions']
 
3753
 
 
3754
    _see_also = ['merge']
 
3755
 
 
3756
    takes_args = ['submit_branch?', 'public_branch?']
 
3757
 
 
3758
    takes_options = [
 
3759
        Option('no-bundle',
 
3760
               help='Do not include a bundle in the merge directive.'),
 
3761
        Option('no-patch', help='Do not include a preview patch in the merge'
 
3762
               ' directive.'),
 
3763
        Option('remember',
 
3764
               help='Remember submit and public branch.'),
 
3765
        Option('from',
 
3766
               help='Branch to generate the submission from, '
 
3767
               'rather than the one containing the working directory.',
 
3768
               short_name='f',
 
3769
               type=unicode),
 
3770
        Option('output', short_name='o', help='Write directive to this file.',
 
3771
               type=unicode),
 
3772
        'revision',
 
3773
        ]
 
3774
 
 
3775
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
 
3776
            no_patch=False, revision=None, remember=False, output=None,
 
3777
            **kwargs):
 
3778
        from bzrlib.revision import ensure_null, NULL_REVISION
 
3779
        if output is None:
 
3780
            raise errors.BzrCommandError('File must be specified with'
 
3781
                                         ' --output')
 
3782
        elif output == '-':
 
3783
            outfile = self.outf
 
3784
        else:
 
3785
            outfile = open(output, 'wb')
 
3786
        try:
 
3787
            from_ = kwargs.get('from', '.')
 
3788
            branch = Branch.open_containing(from_)[0]
 
3789
            if remember and submit_branch is None:
 
3790
                raise errors.BzrCommandError(
 
3791
                    '--remember requires a branch to be specified.')
 
3792
            stored_submit_branch = branch.get_submit_branch()
 
3793
            remembered_submit_branch = False
 
3794
            if submit_branch is None:
 
3795
                submit_branch = stored_submit_branch
 
3796
                remembered_submit_branch = True
 
3797
            else:
 
3798
                if stored_submit_branch is None or remember:
 
3799
                    branch.set_submit_branch(submit_branch)
 
3800
            if submit_branch is None:
 
3801
                submit_branch = branch.get_parent()
 
3802
                remembered_submit_branch = True
 
3803
            if submit_branch is None:
 
3804
                raise errors.BzrCommandError('No submit branch known or'
 
3805
                                             ' specified')
 
3806
            if remembered_submit_branch:
 
3807
                note('Using saved location: %s', submit_branch)
 
3808
 
 
3809
            stored_public_branch = branch.get_public_branch()
 
3810
            if public_branch is None:
 
3811
                public_branch = stored_public_branch
 
3812
            elif stored_public_branch is None or remember:
 
3813
                branch.set_public_branch(public_branch)
 
3814
            if no_bundle and public_branch is None:
 
3815
                raise errors.BzrCommandError('No public branch specified or'
 
3816
                                             ' known')
 
3817
            base_revision_id = None
 
3818
            if revision is not None:
 
3819
                if len(revision) > 2:
 
3820
                    raise errors.BzrCommandError('bzr send takes '
 
3821
                        'at most two one revision identifiers')
 
3822
                revision_id = revision[-1].in_history(branch).rev_id
 
3823
                if len(revision) == 2:
 
3824
                    base_revision_id = revision[0].in_history(branch).rev_id
 
3825
                    base_revision_id = ensure_null(base_revision_id)
 
3826
            else:
 
3827
                revision_id = branch.last_revision()
 
3828
            revision_id = ensure_null(revision_id)
 
3829
            if revision_id == NULL_REVISION:
 
3830
                raise errors.BzrCommandError('No revisions to submit.')
 
3831
            directive = merge_directive.MergeDirective2.from_objects(
 
3832
                branch.repository, revision_id, time.time(),
 
3833
                osutils.local_time_offset(), submit_branch,
 
3834
                public_branch=public_branch, include_patch=not no_patch,
 
3835
                include_bundle=not no_bundle, message=None,
 
3836
                base_revision_id=base_revision_id)
 
3837
            outfile.writelines(directive.to_lines())
 
3838
        finally:
 
3839
            if output != '-':
 
3840
                outfile.close()
 
3841
 
 
3842
 
3629
3843
class cmd_tag(Command):
3630
 
    """Create a tag naming a revision.
 
3844
    """Create, remove or modify a tag naming a revision.
3631
3845
    
3632
3846
    Tags give human-meaningful names to revisions.  Commands that take a -r
3633
3847
    (--revision) option can be given -rtag:X, where X is any previously
3710
3924
            self.outf.write('%-20s %s\n' % (tag_name, target))
3711
3925
 
3712
3926
 
3713
 
# command-line interpretation helper for merge-related commands
3714
 
def _merge_helper(other_revision, base_revision,
3715
 
                  check_clean=True, ignore_zero=False,
3716
 
                  this_dir=None, backup_files=False,
3717
 
                  merge_type=None,
3718
 
                  file_list=None, show_base=False, reprocess=False,
3719
 
                  pull=False,
3720
 
                  pb=DummyProgress(),
3721
 
                  change_reporter=None,
3722
 
                  other_rev_id=None):
3723
 
    """Merge changes into a tree.
3724
 
 
3725
 
    base_revision
3726
 
        list(path, revno) Base for three-way merge.  
3727
 
        If [None, None] then a base will be automatically determined.
3728
 
    other_revision
3729
 
        list(path, revno) Other revision for three-way merge.
3730
 
    this_dir
3731
 
        Directory to merge changes into; '.' by default.
3732
 
    check_clean
3733
 
        If true, this_dir must have no uncommitted changes before the
3734
 
        merge begins.
3735
 
    ignore_zero - If true, suppress the "zero conflicts" message when 
3736
 
        there are no conflicts; should be set when doing something we expect
3737
 
        to complete perfectly.
3738
 
    file_list - If supplied, merge only changes to selected files.
3739
 
 
3740
 
    All available ancestors of other_revision and base_revision are
3741
 
    automatically pulled into the branch.
3742
 
 
3743
 
    The revno may be -1 to indicate the last revision on the branch, which is
3744
 
    the typical case.
3745
 
 
3746
 
    This function is intended for use from the command line; programmatic
3747
 
    clients might prefer to call merge.merge_inner(), which has less magic 
3748
 
    behavior.
3749
 
    """
3750
 
    # Loading it late, so that we don't always have to import bzrlib.merge
3751
 
    if merge_type is None:
3752
 
        merge_type = _mod_merge.Merge3Merger
3753
 
    if this_dir is None:
3754
 
        this_dir = u'.'
3755
 
    this_tree = WorkingTree.open_containing(this_dir)[0]
3756
 
    if show_base and not merge_type is _mod_merge.Merge3Merger:
3757
 
        raise errors.BzrCommandError("Show-base is not supported for this merge"
3758
 
                                     " type. %s" % merge_type)
3759
 
    if reprocess and not merge_type.supports_reprocess:
3760
 
        raise errors.BzrCommandError("Conflict reduction is not supported for merge"
3761
 
                                     " type %s." % merge_type)
3762
 
    if reprocess and show_base:
3763
 
        raise errors.BzrCommandError("Cannot do conflict reduction and show base.")
3764
 
    # TODO: jam 20070226 We should really lock these trees earlier. However, we
3765
 
    #       only want to take out a lock_tree_write() if we don't have to pull
3766
 
    #       any ancestry. But merge might fetch ancestry in the middle, in
3767
 
    #       which case we would need a lock_write().
3768
 
    #       Because we cannot upgrade locks, for now we live with the fact that
3769
 
    #       the tree will be locked multiple times during a merge. (Maybe
3770
 
    #       read-only some of the time, but it means things will get read
3771
 
    #       multiple times.)
3772
 
    try:
3773
 
        merger = _mod_merge.Merger(this_tree.branch, this_tree=this_tree,
3774
 
                                   pb=pb, change_reporter=change_reporter)
3775
 
        merger.pp = ProgressPhase("Merge phase", 5, pb)
3776
 
        merger.pp.next_phase()
3777
 
        merger.check_basis(check_clean)
3778
 
        if other_rev_id is not None:
3779
 
            merger.set_other_revision(other_rev_id, this_tree.branch)
3780
 
        else:
3781
 
            merger.set_other(other_revision)
3782
 
        merger.pp.next_phase()
3783
 
        merger.set_base(base_revision)
3784
 
        if merger.base_rev_id == merger.other_rev_id:
3785
 
            note('Nothing to do.')
3786
 
            return 0
3787
 
        if file_list is None:
3788
 
            if pull and merger.base_rev_id == merger.this_rev_id:
3789
 
                # FIXME: deduplicate with pull
3790
 
                result = merger.this_tree.pull(merger.this_branch,
3791
 
                        False, merger.other_rev_id)
3792
 
                if result.old_revid == result.new_revid:
3793
 
                    note('No revisions to pull.')
3794
 
                else:
3795
 
                    note('Now on revision %d.' % result.new_revno)
3796
 
                return 0
3797
 
        merger.backup_files = backup_files
3798
 
        merger.merge_type = merge_type 
3799
 
        merger.set_interesting_files(file_list)
3800
 
        merger.show_base = show_base 
3801
 
        merger.reprocess = reprocess
3802
 
        conflicts = merger.do_merge()
3803
 
        if file_list is None:
3804
 
            merger.set_pending()
3805
 
    finally:
3806
 
        pb.clear()
3807
 
    return conflicts
3808
 
 
3809
 
 
3810
3927
def _create_prefix(cur_transport):
3811
3928
    needed = [cur_transport]
3812
3929
    # Recurse upwards until we can create a directory successfully
3829
3946
        cur_transport.ensure_base()
3830
3947
 
3831
3948
 
3832
 
# Compatibility
3833
 
merge = _merge_helper
 
3949
def _get_mergeable_helper(location):
 
3950
    """Get a merge directive or bundle if 'location' points to one.
 
3951
 
 
3952
    Try try to identify a bundle and returns its mergeable form. If it's not,
 
3953
    we return the tried transport anyway so that it can reused to access the
 
3954
    branch
 
3955
 
 
3956
    :param location: can point to a bundle or a branch.
 
3957
 
 
3958
    :return: mergeable, transport
 
3959
    """
 
3960
    mergeable = None
 
3961
    url = urlutils.normalize_url(location)
 
3962
    url, filename = urlutils.split(url, exclude_trailing_slash=False)
 
3963
    location_transport = transport.get_transport(url)
 
3964
    if filename:
 
3965
        try:
 
3966
            # There may be redirections but we ignore the intermediate
 
3967
            # and final transports used
 
3968
            read = bundle.read_mergeable_from_transport
 
3969
            mergeable, t = read(location_transport, filename)
 
3970
        except errors.NotABundle:
 
3971
            # Continue on considering this url a Branch but adjust the
 
3972
            # location_transport
 
3973
            location_transport = location_transport.clone(filename)
 
3974
    return mergeable, location_transport
3834
3975
 
3835
3976
 
3836
3977
# these get imported and then picked up by the scan for cmd_*
3840
3981
# details were needed.
3841
3982
from bzrlib.cmd_version_info import cmd_version_info
3842
3983
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
3843
 
from bzrlib.bundle.commands import cmd_bundle_revisions
 
3984
from bzrlib.bundle.commands import (
 
3985
    cmd_bundle_info,
 
3986
    )
3844
3987
from bzrlib.sign_my_commits import cmd_sign_my_commits
3845
3988
from bzrlib.weave_commands import cmd_versionedfile_list, cmd_weave_join, \
3846
3989
        cmd_weave_plan_merge, cmd_weave_merge_text