/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: 2008-03-27 06:10:18 UTC
  • mfrom: (3309 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3320.
  • Revision ID: andrew.bennetts@canonical.com-20080327061018-dxztpxyv6yoeg3am
Merge from bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
534
534
        if len(names_list) < 2:
535
535
            raise errors.BzrCommandError("missing file argument")
536
536
        tree, rel_names = tree_files(names_list)
537
 
        
538
 
        if os.path.isdir(names_list[-1]):
 
537
        tree.lock_write()
 
538
        try:
 
539
            self._run(tree, names_list, rel_names, after)
 
540
        finally:
 
541
            tree.unlock()
 
542
 
 
543
    def _run(self, tree, names_list, rel_names, after):
 
544
        into_existing = osutils.isdir(names_list[-1])
 
545
        if into_existing and len(names_list) == 2:
 
546
            # special cases:
 
547
            # a. case-insensitive filesystem and change case of dir
 
548
            # b. move directory after the fact (if the source used to be
 
549
            #    a directory, but now doesn't exist in the working tree
 
550
            #    and the target is an existing directory, just rename it)
 
551
            if (not tree.case_sensitive
 
552
                and rel_names[0].lower() == rel_names[1].lower()):
 
553
                into_existing = False
 
554
            else:
 
555
                inv = tree.inventory
 
556
                from_id = tree.path2id(rel_names[0])
 
557
                if (not osutils.lexists(names_list[0]) and
 
558
                    from_id and inv.get_file_kind(from_id) == "directory"):
 
559
                    into_existing = False
 
560
        # move/rename
 
561
        if into_existing:
539
562
            # move into existing directory
540
563
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
541
564
                self.outf.write("%s => %s\n" % pair)
546
569
                                             ' directory')
547
570
            tree.rename_one(rel_names[0], rel_names[1], after=after)
548
571
            self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
549
 
            
550
 
    
 
572
 
 
573
 
551
574
class cmd_pull(Command):
552
575
    """Turn this branch into a mirror of another branch.
553
576
 
599
622
 
600
623
        possible_transports = []
601
624
        if location is not None:
602
 
            mergeable, location_transport = _get_mergeable_helper(location)
603
 
            possible_transports.append(location_transport)
 
625
            try:
 
626
                mergeable = bundle.read_mergeable_from_url(location,
 
627
                    possible_transports=possible_transports)
 
628
            except errors.NotABundle:
 
629
                mergeable = None
604
630
 
605
631
        stored_loc = branch_to.get_parent()
606
632
        if location is None:
610
636
            else:
611
637
                display_url = urlutils.unescape_for_display(stored_loc,
612
638
                        self.outf.encoding)
613
 
                self.outf.write("Using saved location: %s\n" % display_url)
 
639
                if not is_quiet():
 
640
                    self.outf.write("Using saved location: %s\n" % display_url)
614
641
                location = stored_loc
615
 
                location_transport = transport.get_transport(
616
 
                    location, possible_transports=possible_transports)
617
642
 
618
643
        if mergeable is not None:
619
644
            if revision is not None:
624
649
                mergeable.get_merge_request(branch_to.repository)
625
650
            branch_from = branch_to
626
651
        else:
627
 
            branch_from = Branch.open_from_transport(location_transport)
 
652
            branch_from = Branch.open(location,
 
653
                possible_transports=possible_transports)
628
654
 
629
655
            if branch_to.get_parent() is None or remember:
630
656
                branch_to.set_parent(branch_from.base)
681
707
    """
682
708
 
683
709
    _see_also = ['pull', 'update', 'working-trees']
684
 
    takes_options = ['remember', 'overwrite', 'verbose',
 
710
    takes_options = ['remember', 'overwrite', 'verbose', 'revision',
685
711
        Option('create-prefix',
686
712
               help='Create the path leading up to the branch '
687
713
                    'if it does not already exist.'),
701
727
    encoding_type = 'replace'
702
728
 
703
729
    def run(self, location=None, remember=False, overwrite=False,
704
 
            create_prefix=False, verbose=False,
 
730
            create_prefix=False, verbose=False, revision=None,
705
731
            use_existing_dir=False,
706
732
            directory=None):
707
733
        # FIXME: Way too big!  Put this into a function called from the
740
766
            else:
741
767
                # Found a branch, so we must have found a repository
742
768
                repository_to = br_to.repository
 
769
 
 
770
        if revision is not None:
 
771
            if len(revision) == 1:
 
772
                revision_id = revision[0].in_history(br_from).rev_id
 
773
            else:
 
774
                raise errors.BzrCommandError(
 
775
                    'bzr push --revision takes one value.')
 
776
        else:
 
777
            revision_id = br_from.last_revision()
 
778
 
743
779
        push_result = None
744
780
        if verbose:
745
781
            old_rh = []
780
816
            # directory. So we need to create it, along with any work to create
781
817
            # all of the dependent branches, etc.
782
818
            dir_to = br_from.bzrdir.clone_on_transport(to_transport,
783
 
                revision_id=br_from.last_revision())
 
819
                                                       revision_id=revision_id)
784
820
            br_to = dir_to.open_branch()
785
821
            # TODO: Some more useful message about what was copied
786
822
            note('Created new branch.')
798
834
        elif br_to is None:
799
835
            # We have a repository but no branch, copy the revisions, and then
800
836
            # create a branch.
801
 
            last_revision_id = br_from.last_revision()
802
 
            repository_to.fetch(br_from.repository,
803
 
                                revision_id=last_revision_id)
804
 
            br_to = br_from.clone(dir_to, revision_id=last_revision_id)
 
837
            repository_to.fetch(br_from.repository, revision_id=revision_id)
 
838
            br_to = br_from.clone(dir_to, revision_id=revision_id)
805
839
            note('Created new branch.')
806
840
            if br_from.get_push_location() is None or remember:
807
841
                br_from.set_push_location(br_to.base)
819
853
                    warning("This transport does not update the working " 
820
854
                            "tree of: %s. See 'bzr help working-trees' for "
821
855
                            "more information." % br_to.base)
822
 
                    push_result = br_from.push(br_to, overwrite)
 
856
                    push_result = br_from.push(br_to, overwrite,
 
857
                                               stop_revision=revision_id)
823
858
                except errors.NoWorkingTree:
824
 
                    push_result = br_from.push(br_to, overwrite)
 
859
                    push_result = br_from.push(br_to, overwrite,
 
860
                                               stop_revision=revision_id)
825
861
                else:
826
862
                    tree_to.lock_write()
827
863
                    try:
828
 
                        push_result = br_from.push(tree_to.branch, overwrite)
 
864
                        push_result = br_from.push(tree_to.branch, overwrite,
 
865
                                                   stop_revision=revision_id)
829
866
                        tree_to.update()
830
867
                    finally:
831
868
                        tree_to.unlock()
863
900
 
864
901
    _see_also = ['checkout']
865
902
    takes_args = ['from_location', 'to_location?']
866
 
    takes_options = ['revision']
 
903
    takes_options = ['revision', Option('hardlink',
 
904
        help='Hard-link working tree files where possible.')]
867
905
    aliases = ['get', 'clone']
868
906
 
869
 
    def run(self, from_location, to_location=None, revision=None):
 
907
    def run(self, from_location, to_location=None, revision=None,
 
908
            hardlink=False):
870
909
        from bzrlib.tag import _merge_tags_if_possible
871
910
        if revision is None:
872
911
            revision = [None]
904
943
                # preserve whatever source format we have.
905
944
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
906
945
                                            possible_transports=[to_transport],
907
 
                                            accelerator_tree=accelerator_tree)
 
946
                                            accelerator_tree=accelerator_tree,
 
947
                                            hardlink=hardlink)
908
948
                branch = dir.open_branch()
909
949
            except errors.NoSuchRevision:
910
950
                to_transport.delete_tree('.')
949
989
                                 "common operations like diff and status without "
950
990
                                 "such access, and also support local commits."
951
991
                            ),
952
 
                     Option('files-from',
953
 
                            help="Get file contents from this tree.", type=str)
 
992
                     Option('files-from', type=str,
 
993
                            help="Get file contents from this tree."),
 
994
                     Option('hardlink',
 
995
                            help='Hard-link working tree files where possible.'
 
996
                            ),
954
997
                     ]
955
998
    aliases = ['co']
956
999
 
957
1000
    def run(self, branch_location=None, to_location=None, revision=None,
958
 
            lightweight=False, files_from=None):
 
1001
            lightweight=False, files_from=None, hardlink=False):
959
1002
        if revision is None:
960
1003
            revision = [None]
961
1004
        elif len(revision) > 1:
986
1029
                source.bzrdir.create_workingtree(revision_id)
987
1030
                return
988
1031
        source.create_checkout(to_location, revision_id, lightweight,
989
 
                               accelerator_tree)
 
1032
                               accelerator_tree, hardlink)
990
1033
 
991
1034
 
992
1035
class cmd_renames(Command):
1928
1971
        Ignore .o files under the lib directory::
1929
1972
 
1930
1973
            bzr ignore "RE:lib/.*\.o"
 
1974
 
 
1975
        Ignore everything but the "debian" toplevel directory::
 
1976
 
 
1977
            bzr ignore "RE:(?!debian/).*"
1931
1978
    """
1932
1979
 
1933
1980
    _see_also = ['status', 'ignored']
2397
2444
                try:
2398
2445
                    repo_basis = tree.branch.repository.revision_tree(
2399
2446
                        tree.last_revision())
2400
 
                    if len(list(repo_basis._iter_changes(tree_basis))):
 
2447
                    if len(list(repo_basis.iter_changes(tree_basis))):
2401
2448
                        raise errors.BzrCheckError(
2402
2449
                            "Mismatched basis inventory content.")
2403
2450
                    tree._validate()
2598
2645
                                 ' expression.'),
2599
2646
                     Option('strict', help='Fail on missing dependencies or '
2600
2647
                            'known failures.'),
2601
 
                     Option('coverage', type=str, argname="DIRECTORY",
2602
 
                            help='Generate line coverage report in this '
2603
 
                                 'directory.'),
 
2648
                     Option('load-list', type=str, argname='TESTLISTFILE',
 
2649
                            help='Load a test id list from a text file.'),
2604
2650
                     ]
2605
2651
    encoding_type = 'replace'
2606
2652
 
2608
2654
            transport=None, benchmark=None,
2609
2655
            lsprof_timed=None, cache_dir=None,
2610
2656
            first=False, list_only=False,
2611
 
            randomize=None, exclude=None, strict=False, coverage=None):
 
2657
            randomize=None, exclude=None, strict=False,
 
2658
            load_list=None):
2612
2659
        import bzrlib.ui
2613
2660
        from bzrlib.tests import selftest
2614
2661
        import bzrlib.benchmarks as benchmarks
2621
2668
            print '   %s (%s python%s)' % (
2622
2669
                    bzrlib.__path__[0],
2623
2670
                    bzrlib.version_string,
2624
 
                    '.'.join(map(str, sys.version_info)),
 
2671
                    bzrlib._format_version_tuple(sys.version_info),
2625
2672
                    )
2626
2673
        print
2627
2674
        if testspecs_list is not None:
2650
2697
                              random_seed=randomize,
2651
2698
                              exclude_pattern=exclude,
2652
2699
                              strict=strict,
2653
 
                              coverage_dir=coverage,
 
2700
                              load_list=load_list,
2654
2701
                              )
2655
2702
        finally:
2656
2703
            if benchfile is not None:
2657
2704
                benchfile.close()
2658
2705
        if result:
2659
 
            info('tests passed')
 
2706
            note('tests passed')
2660
2707
        else:
2661
 
            info('tests failed')
 
2708
            note('tests failed')
2662
2709
        return int(not result)
2663
2710
 
2664
2711
 
2759
2806
            bzr merge -r 81..82 ../bzr.dev
2760
2807
    """
2761
2808
 
 
2809
    encoding_type = 'exact'
2762
2810
    _see_also = ['update', 'remerge', 'status-flags']
2763
2811
    takes_args = ['branch?']
2764
2812
    takes_options = [
2783
2831
               short_name='d',
2784
2832
               type=unicode,
2785
2833
               ),
 
2834
        Option('preview', help='Instead of merging, show a diff of the merge.')
2786
2835
    ]
2787
2836
 
2788
2837
    def run(self, branch=None, revision=None, force=False, merge_type=None,
2789
2838
            show_base=False, reprocess=False, remember=False,
2790
2839
            uncommitted=False, pull=False,
2791
2840
            directory=None,
 
2841
            preview=False,
2792
2842
            ):
2793
2843
        # This is actually a branch (or merge-directive) *location*.
2794
2844
        location = branch
2812
2862
            tree.lock_write()
2813
2863
            cleanups.append(tree.unlock)
2814
2864
            if location is not None:
2815
 
                mergeable, other_transport = _get_mergeable_helper(location)
2816
 
                if mergeable:
 
2865
                try:
 
2866
                    mergeable = bundle.read_mergeable_from_url(location,
 
2867
                        possible_transports=possible_transports)
 
2868
                except errors.NotABundle:
 
2869
                    mergeable = None
 
2870
                else:
2817
2871
                    if uncommitted:
2818
2872
                        raise errors.BzrCommandError('Cannot use --uncommitted'
2819
2873
                            ' with bundles or merge directives.')
2823
2877
                            'Cannot use -r with merge directives or bundles')
2824
2878
                    merger, verified = _mod_merge.Merger.from_mergeable(tree,
2825
2879
                       mergeable, pb)
2826
 
                possible_transports.append(other_transport)
2827
2880
 
2828
2881
            if merger is None and uncommitted:
2829
2882
                if revision is not None and len(revision) > 0:
2844
2897
            merger.merge_type = merge_type
2845
2898
            merger.reprocess = reprocess
2846
2899
            merger.show_base = show_base
2847
 
            merger.change_reporter = change_reporter
2848
2900
            self.sanity_check_merger(merger)
2849
2901
            if (merger.base_rev_id == merger.other_rev_id and
2850
2902
                merger.other_rev_id != None):
2859
2911
                    result.report(self.outf)
2860
2912
                    return 0
2861
2913
            merger.check_basis(not force)
2862
 
            conflict_count = merger.do_merge()
2863
 
            if allow_pending:
2864
 
                merger.set_pending()
2865
 
            if verified == 'failed':
2866
 
                warning('Preview patch does not match changes')
2867
 
            if conflict_count != 0:
2868
 
                return 1
 
2914
            if preview:
 
2915
                return self._do_preview(merger)
2869
2916
            else:
2870
 
                return 0
 
2917
                return self._do_merge(merger, change_reporter, allow_pending,
 
2918
                                      verified)
2871
2919
        finally:
2872
2920
            for cleanup in reversed(cleanups):
2873
2921
                cleanup()
2874
2922
 
 
2923
    def _do_preview(self, merger):
 
2924
        from bzrlib.diff import show_diff_trees
 
2925
        tree_merger = merger.make_merger()
 
2926
        tt = tree_merger.make_preview_transform()
 
2927
        try:
 
2928
            result_tree = tt.get_preview_tree()
 
2929
            show_diff_trees(merger.this_tree, result_tree, self.outf,
 
2930
                            old_label='', new_label='')
 
2931
        finally:
 
2932
            tt.finalize()
 
2933
 
 
2934
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
 
2935
        merger.change_reporter = change_reporter
 
2936
        conflict_count = merger.do_merge()
 
2937
        if allow_pending:
 
2938
            merger.set_pending()
 
2939
        if verified == 'failed':
 
2940
            warning('Preview patch does not match changes')
 
2941
        if conflict_count != 0:
 
2942
            return 1
 
2943
        else:
 
2944
            return 0
 
2945
 
2875
2946
    def sanity_check_merger(self, merger):
2876
2947
        if (merger.show_base and
2877
2948
            not merger.merge_type is _mod_merge.Merge3Merger):
2891
2962
        from bzrlib.tag import _merge_tags_if_possible
2892
2963
        assert revision is None or len(revision) < 3
2893
2964
        # find the branch locations
2894
 
        other_loc, location = self._select_branch_location(tree, location,
 
2965
        other_loc, user_location = self._select_branch_location(tree, location,
2895
2966
            revision, -1)
2896
2967
        if revision is not None and len(revision) == 2:
2897
 
            base_loc, location = self._select_branch_location(tree, location,
2898
 
                                                              revision, 0)
 
2968
            base_loc, _unused = self._select_branch_location(tree,
 
2969
                location, revision, 0)
2899
2970
        else:
2900
2971
            base_loc = other_loc
2901
2972
        # Open the branches
2922
2993
        else:
2923
2994
            base_revision_id = None
2924
2995
        # Remember where we merge from
2925
 
        if ((tree.branch.get_parent() is None or remember) and
2926
 
            other_branch is not None):
2927
 
            tree.branch.set_parent(other_branch.base)
 
2996
        if ((remember or tree.branch.get_submit_branch() is None) and
 
2997
             user_location is not None):
 
2998
            tree.branch.set_submit_branch(other_branch.base)
2928
2999
        _merge_tags_if_possible(other_branch, tree.branch)
2929
3000
        merger = _mod_merge.Merger.from_revision_ids(pb, tree,
2930
3001
            other_revision_id, base_revision_id, other_branch, base_branch)
2935
3006
            allow_pending = True
2936
3007
        return merger, allow_pending
2937
3008
 
2938
 
    def _select_branch_location(self, tree, location, revision=None,
 
3009
    def _select_branch_location(self, tree, user_location, revision=None,
2939
3010
                                index=None):
2940
3011
        """Select a branch location, according to possible inputs.
2941
3012
 
2943
3014
        ``revision`` and ``index`` must be supplied.)
2944
3015
 
2945
3016
        Otherwise, the ``location`` parameter is used.  If it is None, then the
2946
 
        ``parent`` location is used, and a note is printed.
 
3017
        ``submit`` or ``parent`` location is used, and a note is printed.
2947
3018
 
2948
3019
        :param tree: The working tree to select a branch for merging into
2949
3020
        :param location: The location entered by the user
2950
3021
        :param revision: The revision parameter to the command
2951
3022
        :param index: The index to use for the revision parameter.  Negative
2952
3023
            indices are permitted.
2953
 
        :return: (selected_location, default_location).  The default location
2954
 
            will be the user-entered location, if any, or else the remembered
2955
 
            location.
 
3024
        :return: (selected_location, user_location).  The default location
 
3025
            will be the user-entered location.
2956
3026
        """
2957
3027
        if (revision is not None and index is not None
2958
3028
            and revision[index] is not None):
2959
3029
            branch = revision[index].get_branch()
2960
3030
            if branch is not None:
2961
 
                return branch, location
2962
 
        location = self._get_remembered_parent(tree, location, 'Merging from')
2963
 
        return location, location
 
3031
                return branch, branch
 
3032
        if user_location is None:
 
3033
            location = self._get_remembered(tree, 'Merging from')
 
3034
        else:
 
3035
            location = user_location
 
3036
        return location, user_location
2964
3037
 
2965
 
    # TODO: move up to common parent; this isn't merge-specific anymore. 
2966
 
    def _get_remembered_parent(self, tree, supplied_location, verb_string):
 
3038
    def _get_remembered(self, tree, verb_string):
2967
3039
        """Use tree.branch's parent if none was supplied.
2968
3040
 
2969
3041
        Report if the remembered location was used.
2970
3042
        """
2971
 
        if supplied_location is not None:
2972
 
            return supplied_location
2973
 
        stored_location = tree.branch.get_parent()
 
3043
        stored_location = tree.branch.get_submit_branch()
 
3044
        if stored_location is None:
 
3045
            stored_location = tree.branch.get_parent()
2974
3046
        mutter("%s", stored_location)
2975
3047
        if stored_location is None:
2976
3048
            raise errors.BzrCommandError("No location specified or remembered")
2977
 
        display_url = urlutils.unescape_for_display(stored_location,
2978
 
            self.outf.encoding)
2979
 
        self.outf.write("%s remembered location %s\n" % (verb_string,
2980
 
            display_url))
 
3049
        display_url = urlutils.unescape_for_display(stored_location, 'utf-8')
 
3050
        note(u"%s remembered location %s", verb_string, display_url)
2981
3051
        return stored_location
2982
3052
 
2983
3053
 
3326
3396
class cmd_plugins(Command):
3327
3397
    """List the installed plugins.
3328
3398
    
3329
 
    This command displays the list of installed plugins including the
3330
 
    path where each one is located and a short description of each.
 
3399
    This command displays the list of installed plugins including
 
3400
    version of plugin and a short description of each.
 
3401
 
 
3402
    --verbose shows the path where each plugin is located.
3331
3403
 
3332
3404
    A plugin is an external component for Bazaar that extends the
3333
3405
    revision control system, by adding or replacing code in Bazaar.
3340
3412
    install them. Instructions are also provided there on how to
3341
3413
    write new plugins using the Python programming language.
3342
3414
    """
 
3415
    takes_options = ['verbose']
3343
3416
 
3344
3417
    @display_command
3345
 
    def run(self):
 
3418
    def run(self, verbose=False):
3346
3419
        import bzrlib.plugin
3347
3420
        from inspect import getdoc
 
3421
        result = []
3348
3422
        for name, plugin in bzrlib.plugin.plugins().items():
3349
 
            print plugin.path(), "[%s]" % plugin.__version__
 
3423
            version = plugin.__version__
 
3424
            if version == 'unknown':
 
3425
                version = ''
 
3426
            name_ver = '%s %s' % (name, version)
3350
3427
            d = getdoc(plugin.module)
3351
3428
            if d:
3352
 
                print '\t', d.split('\n')[0]
 
3429
                doc = d.split('\n')[0]
 
3430
            else:
 
3431
                doc = '(no description)'
 
3432
            result.append((name_ver, doc, plugin.path()))
 
3433
        for name_ver, doc, path in sorted(result):
 
3434
            print name_ver
 
3435
            print '   ', doc
 
3436
            if verbose:
 
3437
                print '   ', path
 
3438
            print
3353
3439
 
3354
3440
 
3355
3441
class cmd_testament(Command):
3576
3662
    _see_also = ['commit']
3577
3663
    takes_options = ['verbose', 'revision',
3578
3664
                    Option('dry-run', help='Don\'t actually make changes.'),
3579
 
                    Option('force', help='Say yes to all questions.')]
 
3665
                    Option('force', help='Say yes to all questions.'),
 
3666
                    Option('local',
 
3667
                           help="Only remove the commits from the local branch"
 
3668
                                " when in a checkout."
 
3669
                           ),
 
3670
                    ]
3580
3671
    takes_args = ['location?']
3581
3672
    aliases = []
3582
3673
    encoding_type = 'replace'
3583
3674
 
3584
3675
    def run(self, location=None,
3585
3676
            dry_run=False, verbose=False,
3586
 
            revision=None, force=False):
 
3677
            revision=None, force=False, local=False):
3587
3678
        if location is None:
3588
3679
            location = u'.'
3589
3680
        control, relpath = bzrdir.BzrDir.open_containing(location)
3599
3690
        else:
3600
3691
            b.lock_write()
3601
3692
        try:
3602
 
            return self._run(b, tree, dry_run, verbose, revision, force)
 
3693
            return self._run(b, tree, dry_run, verbose, revision, force,
 
3694
                             local=local)
3603
3695
        finally:
3604
3696
            if tree is not None:
3605
3697
                tree.unlock()
3606
3698
            else:
3607
3699
                b.unlock()
3608
3700
 
3609
 
    def _run(self, b, tree, dry_run, verbose, revision, force):
 
3701
    def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
3610
3702
        from bzrlib.log import log_formatter, show_log
3611
3703
        from bzrlib.uncommit import uncommit
3612
3704
 
3654
3746
                    return 0
3655
3747
 
3656
3748
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
3657
 
                 revno=revno)
 
3749
                 revno=revno, local=local)
3658
3750
 
3659
3751
 
3660
3752
class cmd_break_lock(Command):
3977
4069
    generic options are "default", "editor", "mapi", and "xdg-email".
3978
4070
 
3979
4071
    If mail is being sent, a to address is required.  This can be supplied
3980
 
    either on the commandline, or by setting the submit_to configuration
3981
 
    option.
 
4072
    either on the commandline, by setting the submit_to configuration
 
4073
    option in the branch itself or the child_submit_to configuration option 
 
4074
    in the submit branch.
3982
4075
 
3983
4076
    Two formats are currently supported: "4" uses revision bundle format 4 and
3984
4077
    merge directive format 2.  It is significantly faster and smaller than
4063
4156
            if remembered_submit_branch:
4064
4157
                note('Using saved location: %s', submit_branch)
4065
4158
 
 
4159
            if mail_to is None:
 
4160
                submit_config = Branch.open(submit_branch).get_config()
 
4161
                mail_to = submit_config.get_user_option("child_submit_to")
 
4162
 
4066
4163
            stored_public_branch = branch.get_public_branch()
4067
4164
            if public_branch is None:
4068
4165
                public_branch = stored_public_branch
4117
4214
                else:
4118
4215
                    revision = branch.repository.get_revision(revision_id)
4119
4216
                    subject += revision.get_summary()
 
4217
                basename = directive.get_disk_name(branch)
4120
4218
                mail_client.compose_merge_request(mail_to, subject,
4121
 
                                                  outfile.getvalue())
 
4219
                                                  outfile.getvalue(), basename)
4122
4220
        finally:
4123
4221
            if output != '-':
4124
4222
                outfile.close()
4383
4481
            urlutils.unescape_for_display(to_branch.base, 'utf-8'))
4384
4482
 
4385
4483
 
 
4484
class cmd_hooks(Command):
 
4485
    """Show a branch's currently registered hooks.
 
4486
    """
 
4487
 
 
4488
    hidden = True
 
4489
    takes_args = ['path?']
 
4490
 
 
4491
    def run(self, path=None):
 
4492
        if path is None:
 
4493
            path = '.'
 
4494
        branch_hooks = Branch.open(path).hooks
 
4495
        for hook_type in branch_hooks:
 
4496
            hooks = branch_hooks[hook_type]
 
4497
            self.outf.write("%s:\n" % (hook_type,))
 
4498
            if hooks:
 
4499
                for hook in hooks:
 
4500
                    self.outf.write("  %s\n" %
 
4501
                                    (branch_hooks.get_hook_name(hook),))
 
4502
            else:
 
4503
                self.outf.write("  <no hooks installed>\n")
 
4504
 
 
4505
 
4386
4506
def _create_prefix(cur_transport):
4387
4507
    needed = [cur_transport]
4388
4508
    # Recurse upwards until we can create a directory successfully
4405
4525
        cur_transport.ensure_base()
4406
4526
 
4407
4527
 
4408
 
def _get_mergeable_helper(location):
4409
 
    """Get a merge directive or bundle if 'location' points to one.
4410
 
 
4411
 
    Try try to identify a bundle and returns its mergeable form. If it's not,
4412
 
    we return the tried transport anyway so that it can reused to access the
4413
 
    branch
4414
 
 
4415
 
    :param location: can point to a bundle or a branch.
4416
 
 
4417
 
    :return: mergeable, transport
4418
 
    """
4419
 
    mergeable = None
4420
 
    url = urlutils.normalize_url(location)
4421
 
    url, filename = urlutils.split(url, exclude_trailing_slash=False)
4422
 
    location_transport = transport.get_transport(url)
4423
 
    if filename:
4424
 
        try:
4425
 
            # There may be redirections but we ignore the intermediate
4426
 
            # and final transports used
4427
 
            read = bundle.read_mergeable_from_transport
4428
 
            mergeable, t = read(location_transport, filename)
4429
 
        except errors.NotABundle:
4430
 
            # Continue on considering this url a Branch but adjust the
4431
 
            # location_transport
4432
 
            location_transport = location_transport.clone(filename)
4433
 
    return mergeable, location_transport
4434
 
 
4435
 
 
4436
4528
# these get imported and then picked up by the scan for cmd_*
4437
4529
# TODO: Some more consistent way to split command definitions across files;
4438
4530
# we do need to load at least some information about them to know of