~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

Merge trunk

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
 
 
538
        dest = names_list[-1]
 
539
        isdir = os.path.isdir(dest)
 
540
        if (isdir and not tree.case_sensitive and len(rel_names) == 2
 
541
            and rel_names[0].lower() == rel_names[1].lower()):
 
542
                isdir = False
 
543
        if isdir:
539
544
            # move into existing directory
540
545
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
541
546
                self.outf.write("%s => %s\n" % pair)
546
551
                                             ' directory')
547
552
            tree.rename_one(rel_names[0], rel_names[1], after=after)
548
553
            self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
549
 
            
550
 
    
 
554
 
 
555
 
551
556
class cmd_pull(Command):
552
557
    """Turn this branch into a mirror of another branch.
553
558
 
610
615
            else:
611
616
                display_url = urlutils.unescape_for_display(stored_loc,
612
617
                        self.outf.encoding)
613
 
                self.outf.write("Using saved location: %s\n" % display_url)
 
618
                if not is_quiet():
 
619
                    self.outf.write("Using saved location: %s\n" % display_url)
614
620
                location = stored_loc
615
621
                location_transport = transport.get_transport(
616
622
                    location, possible_transports=possible_transports)
681
687
    """
682
688
 
683
689
    _see_also = ['pull', 'update', 'working-trees']
684
 
    takes_options = ['remember', 'overwrite', 'verbose',
 
690
    takes_options = ['remember', 'overwrite', 'verbose', 'revision',
685
691
        Option('create-prefix',
686
692
               help='Create the path leading up to the branch '
687
693
                    'if it does not already exist.'),
701
707
    encoding_type = 'replace'
702
708
 
703
709
    def run(self, location=None, remember=False, overwrite=False,
704
 
            create_prefix=False, verbose=False,
 
710
            create_prefix=False, verbose=False, revision=None,
705
711
            use_existing_dir=False,
706
712
            directory=None):
707
713
        # FIXME: Way too big!  Put this into a function called from the
740
746
            else:
741
747
                # Found a branch, so we must have found a repository
742
748
                repository_to = br_to.repository
 
749
 
 
750
        if revision is not None:
 
751
            if len(revision) == 1:
 
752
                revision_id = revision[0].in_history(br_from).rev_id
 
753
            else:
 
754
                raise errors.BzrCommandError(
 
755
                    'bzr push --revision takes one value.')
 
756
        else:
 
757
            revision_id = br_from.last_revision()
 
758
 
743
759
        push_result = None
744
760
        if verbose:
745
761
            old_rh = []
780
796
            # directory. So we need to create it, along with any work to create
781
797
            # all of the dependent branches, etc.
782
798
            dir_to = br_from.bzrdir.clone_on_transport(to_transport,
783
 
                revision_id=br_from.last_revision())
 
799
                                                       revision_id=revision_id)
784
800
            br_to = dir_to.open_branch()
785
801
            # TODO: Some more useful message about what was copied
786
802
            note('Created new branch.')
798
814
        elif br_to is None:
799
815
            # We have a repository but no branch, copy the revisions, and then
800
816
            # 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)
 
817
            repository_to.fetch(br_from.repository, revision_id=revision_id)
 
818
            br_to = br_from.clone(dir_to, revision_id=revision_id)
805
819
            note('Created new branch.')
806
820
            if br_from.get_push_location() is None or remember:
807
821
                br_from.set_push_location(br_to.base)
819
833
                    warning("This transport does not update the working " 
820
834
                            "tree of: %s. See 'bzr help working-trees' for "
821
835
                            "more information." % br_to.base)
822
 
                    push_result = br_from.push(br_to, overwrite)
 
836
                    push_result = br_from.push(br_to, overwrite,
 
837
                                               stop_revision=revision_id)
823
838
                except errors.NoWorkingTree:
824
 
                    push_result = br_from.push(br_to, overwrite)
 
839
                    push_result = br_from.push(br_to, overwrite,
 
840
                                               stop_revision=revision_id)
825
841
                else:
826
842
                    tree_to.lock_write()
827
843
                    try:
828
 
                        push_result = br_from.push(tree_to.branch, overwrite)
 
844
                        push_result = br_from.push(tree_to.branch, overwrite,
 
845
                                                   stop_revision=revision_id)
829
846
                        tree_to.update()
830
847
                    finally:
831
848
                        tree_to.unlock()
863
880
 
864
881
    _see_also = ['checkout']
865
882
    takes_args = ['from_location', 'to_location?']
866
 
    takes_options = ['revision']
 
883
    takes_options = ['revision', Option('hardlink',
 
884
        help='Hard-link working tree files where possible.')]
867
885
    aliases = ['get', 'clone']
868
886
 
869
 
    def run(self, from_location, to_location=None, revision=None):
 
887
    def run(self, from_location, to_location=None, revision=None,
 
888
            hardlink=False):
870
889
        from bzrlib.tag import _merge_tags_if_possible
871
890
        if revision is None:
872
891
            revision = [None]
904
923
                # preserve whatever source format we have.
905
924
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
906
925
                                            possible_transports=[to_transport],
907
 
                                            accelerator_tree=accelerator_tree)
 
926
                                            accelerator_tree=accelerator_tree,
 
927
                                            hardlink=hardlink)
908
928
                branch = dir.open_branch()
909
929
            except errors.NoSuchRevision:
910
930
                to_transport.delete_tree('.')
949
969
                                 "common operations like diff and status without "
950
970
                                 "such access, and also support local commits."
951
971
                            ),
952
 
                     Option('files-from',
953
 
                            help="Get file contents from this tree.", type=str)
 
972
                     Option('files-from', type=str,
 
973
                            help="Get file contents from this tree."),
 
974
                     Option('hardlink',
 
975
                            help='Hard-link working tree files where possible.'
 
976
                            ),
954
977
                     ]
955
978
    aliases = ['co']
956
979
 
957
980
    def run(self, branch_location=None, to_location=None, revision=None,
958
 
            lightweight=False, files_from=None):
 
981
            lightweight=False, files_from=None, hardlink=False):
959
982
        if revision is None:
960
983
            revision = [None]
961
984
        elif len(revision) > 1:
986
1009
                source.bzrdir.create_workingtree(revision_id)
987
1010
                return
988
1011
        source.create_checkout(to_location, revision_id, lightweight,
989
 
                               accelerator_tree)
 
1012
                               accelerator_tree, hardlink)
990
1013
 
991
1014
 
992
1015
class cmd_renames(Command):
1928
1951
        Ignore .o files under the lib directory::
1929
1952
 
1930
1953
            bzr ignore "RE:lib/.*\.o"
 
1954
 
 
1955
        Ignore everything but the "debian" toplevel directory::
 
1956
 
 
1957
            bzr ignore "RE:(?!debian/).*"
1931
1958
    """
1932
1959
 
1933
1960
    _see_also = ['status', 'ignored']
2397
2424
                try:
2398
2425
                    repo_basis = tree.branch.repository.revision_tree(
2399
2426
                        tree.last_revision())
2400
 
                    if len(list(repo_basis._iter_changes(tree_basis))):
 
2427
                    if len(list(repo_basis.iter_changes(tree_basis))):
2401
2428
                        raise errors.BzrCheckError(
2402
2429
                            "Mismatched basis inventory content.")
2403
2430
                    tree._validate()
2598
2625
                                 ' expression.'),
2599
2626
                     Option('strict', help='Fail on missing dependencies or '
2600
2627
                            'known failures.'),
2601
 
                     Option('coverage', type=str, argname="DIRECTORY",
2602
 
                            help='Generate line coverage report in this '
2603
 
                                 'directory.'),
 
2628
                     Option('load-list', type=str, argname='TESTLISTFILE',
 
2629
                            help='Load a test id list from a text file.'),
2604
2630
                     ]
2605
2631
    encoding_type = 'replace'
2606
2632
 
2608
2634
            transport=None, benchmark=None,
2609
2635
            lsprof_timed=None, cache_dir=None,
2610
2636
            first=False, list_only=False,
2611
 
            randomize=None, exclude=None, strict=False, coverage=None):
 
2637
            randomize=None, exclude=None, strict=False,
 
2638
            load_list=None):
2612
2639
        import bzrlib.ui
2613
2640
        from bzrlib.tests import selftest
2614
2641
        import bzrlib.benchmarks as benchmarks
2650
2677
                              random_seed=randomize,
2651
2678
                              exclude_pattern=exclude,
2652
2679
                              strict=strict,
2653
 
                              coverage_dir=coverage,
 
2680
                              load_list=load_list,
2654
2681
                              )
2655
2682
        finally:
2656
2683
            if benchfile is not None:
2657
2684
                benchfile.close()
2658
2685
        if result:
2659
 
            info('tests passed')
 
2686
            note('tests passed')
2660
2687
        else:
2661
 
            info('tests failed')
 
2688
            note('tests failed')
2662
2689
        return int(not result)
2663
2690
 
2664
2691
 
2759
2786
            bzr merge -r 81..82 ../bzr.dev
2760
2787
    """
2761
2788
 
 
2789
    encoding_type = 'exact'
2762
2790
    _see_also = ['update', 'remerge', 'status-flags']
2763
2791
    takes_args = ['branch?']
2764
2792
    takes_options = [
2783
2811
               short_name='d',
2784
2812
               type=unicode,
2785
2813
               ),
 
2814
        Option('preview', help='Instead of merging, show a diff of the merge.')
2786
2815
    ]
2787
2816
 
2788
2817
    def run(self, branch=None, revision=None, force=False, merge_type=None,
2789
2818
            show_base=False, reprocess=False, remember=False,
2790
2819
            uncommitted=False, pull=False,
2791
2820
            directory=None,
 
2821
            preview=False,
2792
2822
            ):
2793
2823
        # This is actually a branch (or merge-directive) *location*.
2794
2824
        location = branch
2844
2874
            merger.merge_type = merge_type
2845
2875
            merger.reprocess = reprocess
2846
2876
            merger.show_base = show_base
2847
 
            merger.change_reporter = change_reporter
2848
2877
            self.sanity_check_merger(merger)
2849
2878
            if (merger.base_rev_id == merger.other_rev_id and
2850
2879
                merger.other_rev_id != None):
2859
2888
                    result.report(self.outf)
2860
2889
                    return 0
2861
2890
            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
 
2891
            if preview:
 
2892
                return self._do_preview(merger)
2869
2893
            else:
2870
 
                return 0
 
2894
                return self._do_merge(merger, change_reporter, allow_pending,
 
2895
                                      verified)
2871
2896
        finally:
2872
2897
            for cleanup in reversed(cleanups):
2873
2898
                cleanup()
2874
2899
 
 
2900
    def _do_preview(self, merger):
 
2901
        from bzrlib.diff import show_diff_trees
 
2902
        tree_merger = merger.make_merger()
 
2903
        tt = tree_merger.make_preview_transform()
 
2904
        try:
 
2905
            result_tree = tt.get_preview_tree()
 
2906
            show_diff_trees(merger.this_tree, result_tree, self.outf,
 
2907
                            old_label='', new_label='')
 
2908
        finally:
 
2909
            tt.finalize()
 
2910
 
 
2911
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
 
2912
        merger.change_reporter = change_reporter
 
2913
        conflict_count = merger.do_merge()
 
2914
        if allow_pending:
 
2915
            merger.set_pending()
 
2916
        if verified == 'failed':
 
2917
            warning('Preview patch does not match changes')
 
2918
        if conflict_count != 0:
 
2919
            return 1
 
2920
        else:
 
2921
            return 0
 
2922
 
2875
2923
    def sanity_check_merger(self, merger):
2876
2924
        if (merger.show_base and
2877
2925
            not merger.merge_type is _mod_merge.Merge3Merger):
2891
2939
        from bzrlib.tag import _merge_tags_if_possible
2892
2940
        assert revision is None or len(revision) < 3
2893
2941
        # find the branch locations
2894
 
        other_loc, location = self._select_branch_location(tree, location,
 
2942
        other_loc, user_location = self._select_branch_location(tree, location,
2895
2943
            revision, -1)
2896
2944
        if revision is not None and len(revision) == 2:
2897
 
            base_loc, location = self._select_branch_location(tree, location,
2898
 
                                                              revision, 0)
 
2945
            base_loc, _unused = self._select_branch_location(tree,
 
2946
                location, revision, 0)
2899
2947
        else:
2900
2948
            base_loc = other_loc
2901
2949
        # Open the branches
2922
2970
        else:
2923
2971
            base_revision_id = None
2924
2972
        # 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)
 
2973
        if ((remember or tree.branch.get_submit_branch() is None) and
 
2974
             user_location is not None):
 
2975
            tree.branch.set_submit_branch(other_branch.base)
2928
2976
        _merge_tags_if_possible(other_branch, tree.branch)
2929
2977
        merger = _mod_merge.Merger.from_revision_ids(pb, tree,
2930
2978
            other_revision_id, base_revision_id, other_branch, base_branch)
2935
2983
            allow_pending = True
2936
2984
        return merger, allow_pending
2937
2985
 
2938
 
    def _select_branch_location(self, tree, location, revision=None,
 
2986
    def _select_branch_location(self, tree, user_location, revision=None,
2939
2987
                                index=None):
2940
2988
        """Select a branch location, according to possible inputs.
2941
2989
 
2943
2991
        ``revision`` and ``index`` must be supplied.)
2944
2992
 
2945
2993
        Otherwise, the ``location`` parameter is used.  If it is None, then the
2946
 
        ``parent`` location is used, and a note is printed.
 
2994
        ``submit`` or ``parent`` location is used, and a note is printed.
2947
2995
 
2948
2996
        :param tree: The working tree to select a branch for merging into
2949
2997
        :param location: The location entered by the user
2950
2998
        :param revision: The revision parameter to the command
2951
2999
        :param index: The index to use for the revision parameter.  Negative
2952
3000
            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.
 
3001
        :return: (selected_location, user_location).  The default location
 
3002
            will be the user-entered location.
2956
3003
        """
2957
3004
        if (revision is not None and index is not None
2958
3005
            and revision[index] is not None):
2959
3006
            branch = revision[index].get_branch()
2960
3007
            if branch is not None:
2961
 
                return branch, location
2962
 
        location = self._get_remembered_parent(tree, location, 'Merging from')
2963
 
        return location, location
 
3008
                return branch, branch
 
3009
        if user_location is None:
 
3010
            location = self._get_remembered(tree, 'Merging from')
 
3011
        else:
 
3012
            location = user_location
 
3013
        return location, user_location
2964
3014
 
2965
 
    # TODO: move up to common parent; this isn't merge-specific anymore. 
2966
 
    def _get_remembered_parent(self, tree, supplied_location, verb_string):
 
3015
    def _get_remembered(self, tree, verb_string):
2967
3016
        """Use tree.branch's parent if none was supplied.
2968
3017
 
2969
3018
        Report if the remembered location was used.
2970
3019
        """
2971
 
        if supplied_location is not None:
2972
 
            return supplied_location
2973
 
        stored_location = tree.branch.get_parent()
 
3020
        stored_location = tree.branch.get_submit_branch()
 
3021
        if stored_location is None:
 
3022
            stored_location = tree.branch.get_parent()
2974
3023
        mutter("%s", stored_location)
2975
3024
        if stored_location is None:
2976
3025
            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))
 
3026
        display_url = urlutils.unescape_for_display(stored_location, 'utf-8')
 
3027
        note(u"%s remembered location %s", verb_string, display_url)
2981
3028
        return stored_location
2982
3029
 
2983
3030
 
3326
3373
class cmd_plugins(Command):
3327
3374
    """List the installed plugins.
3328
3375
    
3329
 
    This command displays the list of installed plugins including the
3330
 
    path where each one is located and a short description of each.
 
3376
    This command displays the list of installed plugins including
 
3377
    version of plugin and a short description of each.
 
3378
 
 
3379
    --verbose shows the path where each plugin is located.
3331
3380
 
3332
3381
    A plugin is an external component for Bazaar that extends the
3333
3382
    revision control system, by adding or replacing code in Bazaar.
3340
3389
    install them. Instructions are also provided there on how to
3341
3390
    write new plugins using the Python programming language.
3342
3391
    """
 
3392
    takes_options = ['verbose']
3343
3393
 
3344
3394
    @display_command
3345
 
    def run(self):
 
3395
    def run(self, verbose=False):
3346
3396
        import bzrlib.plugin
3347
3397
        from inspect import getdoc
 
3398
        result = []
3348
3399
        for name, plugin in bzrlib.plugin.plugins().items():
3349
 
            print plugin.path(), "[%s]" % plugin.__version__
 
3400
            version = plugin.__version__
 
3401
            if version == 'unknown':
 
3402
                version = ''
 
3403
            name_ver = '%s %s' % (name, version)
3350
3404
            d = getdoc(plugin.module)
3351
3405
            if d:
3352
 
                print '\t', d.split('\n')[0]
 
3406
                doc = d.split('\n')[0]
 
3407
            else:
 
3408
                doc = '(no description)'
 
3409
            result.append((name_ver, doc, plugin.path()))
 
3410
        for name_ver, doc, path in sorted(result):
 
3411
            print name_ver
 
3412
            print '   ', doc
 
3413
            if verbose:
 
3414
                print '   ', path
 
3415
            print
3353
3416
 
3354
3417
 
3355
3418
class cmd_testament(Command):
3977
4040
    generic options are "default", "editor", "mapi", and "xdg-email".
3978
4041
 
3979
4042
    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.
 
4043
    either on the commandline, by setting the submit_to configuration
 
4044
    option in the branch itself or the child_submit_to configuration option 
 
4045
    in the submit branch.
3982
4046
 
3983
4047
    Two formats are currently supported: "4" uses revision bundle format 4 and
3984
4048
    merge directive format 2.  It is significantly faster and smaller than
4063
4127
            if remembered_submit_branch:
4064
4128
                note('Using saved location: %s', submit_branch)
4065
4129
 
 
4130
            if mail_to is None:
 
4131
                submit_config = Branch.open(submit_branch).get_config()
 
4132
                mail_to = submit_config.get_user_option("child_submit_to")
 
4133
 
4066
4134
            stored_public_branch = branch.get_public_branch()
4067
4135
            if public_branch is None:
4068
4136
                public_branch = stored_public_branch
4117
4185
                else:
4118
4186
                    revision = branch.repository.get_revision(revision_id)
4119
4187
                    subject += revision.get_summary()
 
4188
                basename = directive.get_disk_name(branch)
4120
4189
                mail_client.compose_merge_request(mail_to, subject,
4121
 
                                                  outfile.getvalue())
 
4190
                                                  outfile.getvalue(), basename)
4122
4191
        finally:
4123
4192
            if output != '-':
4124
4193
                outfile.close()
4383
4452
            urlutils.unescape_for_display(to_branch.base, 'utf-8'))
4384
4453
 
4385
4454
 
 
4455
class cmd_hooks(Command):
 
4456
    """Show a branch's currently registered hooks.
 
4457
    """
 
4458
 
 
4459
    hidden = True
 
4460
    takes_args = ['path?']
 
4461
 
 
4462
    def run(self, path=None):
 
4463
        if path is None:
 
4464
            path = '.'
 
4465
        branch_hooks = Branch.open(path).hooks
 
4466
        for hook_type in branch_hooks:
 
4467
            hooks = branch_hooks[hook_type]
 
4468
            self.outf.write("%s:\n" % (hook_type,))
 
4469
            if hooks:
 
4470
                for hook in hooks:
 
4471
                    self.outf.write("  %s\n" %
 
4472
                                    (branch_hooks.get_hook_name(hook),))
 
4473
            else:
 
4474
                self.outf.write("  <no hooks installed>\n")
 
4475
 
 
4476
 
4386
4477
def _create_prefix(cur_transport):
4387
4478
    needed = [cur_transport]
4388
4479
    # Recurse upwards until we can create a directory successfully