~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Robert Collins
  • Date: 2010-04-08 04:34:03 UTC
  • mfrom: (5138 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5139.
  • Revision ID: robertc@robertcollins.net-20100408043403-56z0d07vdqrx7f3t
Update bugfix for 528114 to trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
54
54
    )
55
55
from bzrlib.branch import Branch
56
56
from bzrlib.conflicts import ConflictList
 
57
from bzrlib.transport import memory
57
58
from bzrlib.revisionspec import RevisionSpec, RevisionInfo
58
59
from bzrlib.smtp_connection import SMTPConnection
59
60
from bzrlib.workingtree import WorkingTree
60
61
""")
61
62
 
62
 
from bzrlib.commands import Command, display_command
 
63
from bzrlib.commands import (
 
64
    Command,
 
65
    builtin_command_registry,
 
66
    display_command,
 
67
    )
63
68
from bzrlib.option import (
64
69
    ListOption,
65
70
    Option,
339
344
    # cat-revision is more for frontends so should be exact
340
345
    encoding = 'strict'
341
346
 
 
347
    def print_revision(self, revisions, revid):
 
348
        stream = revisions.get_record_stream([(revid,)], 'unordered', True)
 
349
        record = stream.next()
 
350
        if record.storage_kind == 'absent':
 
351
            raise errors.NoSuchRevision(revisions, revid)
 
352
        revtext = record.get_bytes_as('fulltext')
 
353
        self.outf.write(revtext.decode('utf-8'))
 
354
 
342
355
    @display_command
343
356
    def run(self, revision_id=None, revision=None):
344
357
        if revision_id is not None and revision is not None:
349
362
                                         ' --revision or a revision_id')
350
363
        b = WorkingTree.open_containing(u'.')[0].branch
351
364
 
352
 
        # TODO: jam 20060112 should cat-revision always output utf-8?
353
 
        if revision_id is not None:
354
 
            revision_id = osutils.safe_revision_id(revision_id, warn=False)
355
 
            try:
356
 
                self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
357
 
            except errors.NoSuchRevision:
358
 
                msg = "The repository %s contains no revision %s." % (b.repository.base,
359
 
                    revision_id)
360
 
                raise errors.BzrCommandError(msg)
361
 
        elif revision is not None:
362
 
            for rev in revision:
363
 
                if rev is None:
364
 
                    raise errors.BzrCommandError('You cannot specify a NULL'
365
 
                                                 ' revision.')
366
 
                rev_id = rev.as_revision_id(b)
367
 
                self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
 
365
        revisions = b.repository.revisions
 
366
        if revisions is None:
 
367
            raise errors.BzrCommandError('Repository %r does not support '
 
368
                'access to raw revision texts')
368
369
 
 
370
        b.repository.lock_read()
 
371
        try:
 
372
            # TODO: jam 20060112 should cat-revision always output utf-8?
 
373
            if revision_id is not None:
 
374
                revision_id = osutils.safe_revision_id(revision_id, warn=False)
 
375
                try:
 
376
                    self.print_revision(revisions, revision_id)
 
377
                except errors.NoSuchRevision:
 
378
                    msg = "The repository %s contains no revision %s." % (
 
379
                        b.repository.base, revision_id)
 
380
                    raise errors.BzrCommandError(msg)
 
381
            elif revision is not None:
 
382
                for rev in revision:
 
383
                    if rev is None:
 
384
                        raise errors.BzrCommandError(
 
385
                            'You cannot specify a NULL revision.')
 
386
                    rev_id = rev.as_revision_id(b)
 
387
                    self.print_revision(revisions, rev_id)
 
388
        finally:
 
389
            b.repository.unlock()
 
390
        
369
391
 
370
392
class cmd_dump_btree(Command):
371
393
    """Dump the contents of a btree index file to stdout.
438
460
        for node in bt.iter_all_entries():
439
461
            # Node is made up of:
440
462
            # (index, key, value, [references])
441
 
            refs_as_tuples = static_tuple.as_tuples(node[3])
 
463
            try:
 
464
                refs = node[3]
 
465
            except IndexError:
 
466
                refs_as_tuples = None
 
467
            else:
 
468
                refs_as_tuples = static_tuple.as_tuples(refs)
442
469
            as_tuple = (tuple(node[1]), node[2], refs_as_tuples)
443
470
            self.outf.write('%s\n' % (as_tuple,))
444
471
 
452
479
    To re-create the working tree, use "bzr checkout".
453
480
    """
454
481
    _see_also = ['checkout', 'working-trees']
455
 
    takes_args = ['location?']
 
482
    takes_args = ['location*']
456
483
    takes_options = [
457
484
        Option('force',
458
485
               help='Remove the working tree even if it has '
459
486
                    'uncommitted changes.'),
460
487
        ]
461
488
 
462
 
    def run(self, location='.', force=False):
463
 
        d = bzrdir.BzrDir.open(location)
464
 
 
465
 
        try:
466
 
            working = d.open_workingtree()
467
 
        except errors.NoWorkingTree:
468
 
            raise errors.BzrCommandError("No working tree to remove")
469
 
        except errors.NotLocalUrl:
470
 
            raise errors.BzrCommandError("You cannot remove the working tree"
471
 
                                         " of a remote path")
472
 
        if not force:
473
 
            if (working.has_changes()):
474
 
                raise errors.UncommittedChanges(working)
475
 
 
476
 
        working_path = working.bzrdir.root_transport.base
477
 
        branch_path = working.branch.bzrdir.root_transport.base
478
 
        if working_path != branch_path:
479
 
            raise errors.BzrCommandError("You cannot remove the working tree"
480
 
                                         " from a lightweight checkout")
481
 
 
482
 
        d.destroy_workingtree()
 
489
    def run(self, location_list, force=False):
 
490
        if not location_list:
 
491
            location_list=['.']
 
492
 
 
493
        for location in location_list:
 
494
            d = bzrdir.BzrDir.open(location)
 
495
            
 
496
            try:
 
497
                working = d.open_workingtree()
 
498
            except errors.NoWorkingTree:
 
499
                raise errors.BzrCommandError("No working tree to remove")
 
500
            except errors.NotLocalUrl:
 
501
                raise errors.BzrCommandError("You cannot remove the working tree"
 
502
                                             " of a remote path")
 
503
            if not force:
 
504
                if (working.has_changes()):
 
505
                    raise errors.UncommittedChanges(working)
 
506
 
 
507
            working_path = working.bzrdir.root_transport.base
 
508
            branch_path = working.branch.bzrdir.root_transport.base
 
509
            if working_path != branch_path:
 
510
                raise errors.BzrCommandError("You cannot remove the working tree"
 
511
                                             " from a lightweight checkout")
 
512
 
 
513
            d.destroy_workingtree()
483
514
 
484
515
 
485
516
class cmd_revno(Command):
677
708
 
678
709
    def run(self, dir_list):
679
710
        for d in dir_list:
680
 
            os.mkdir(d)
681
711
            wt, dd = WorkingTree.open_containing(d)
682
 
            wt.add([dd])
683
 
            self.outf.write('added %s\n' % d)
 
712
            base = os.path.dirname(dd)
 
713
            id = wt.path2id(base)
 
714
            if id != None:
 
715
                os.mkdir(d)
 
716
                wt.add([dd])
 
717
                self.outf.write('added %s\n' % d)
 
718
            else:
 
719
                raise errors.NotVersionedError(path=base)
684
720
 
685
721
 
686
722
class cmd_relpath(Command):
1396
1432
            branch_location = tree.branch.base
1397
1433
        self.add_cleanup(tree.unlock)
1398
1434
        # get rid of the final '/' and be ready for display
1399
 
        branch_location = urlutils.unescape_for_display(branch_location[:-1],
1400
 
                                                        self.outf.encoding)
 
1435
        branch_location = urlutils.unescape_for_display(
 
1436
            branch_location.rstrip('/'),
 
1437
            self.outf.encoding)
1401
1438
        existing_pending_merges = tree.get_parent_ids()[1:]
1402
1439
        if master is None:
1403
1440
            old_tip = None
1917
1954
            help='Use this command to compare files.',
1918
1955
            type=unicode,
1919
1956
            ),
 
1957
        RegistryOption('format',
 
1958
            help='Diff format to use.',
 
1959
            lazy_registry=('bzrlib.diff', 'format_registry'),
 
1960
            value_switches=False, title='Diff format'),
1920
1961
        ]
1921
1962
    aliases = ['di', 'dif']
1922
1963
    encoding_type = 'exact'
1923
1964
 
1924
1965
    @display_command
1925
1966
    def run(self, revision=None, file_list=None, diff_options=None,
1926
 
            prefix=None, old=None, new=None, using=None):
1927
 
        from bzrlib.diff import get_trees_and_branches_to_diff, show_diff_trees
 
1967
            prefix=None, old=None, new=None, using=None, format=None):
 
1968
        from bzrlib.diff import (get_trees_and_branches_to_diff,
 
1969
            show_diff_trees)
1928
1970
 
1929
1971
        if (prefix is None) or (prefix == '0'):
1930
1972
            # diff -p0 format
1944
1986
            raise errors.BzrCommandError('bzr diff --revision takes exactly'
1945
1987
                                         ' one or two revision specifiers')
1946
1988
 
 
1989
        if using is not None and format is not None:
 
1990
            raise errors.BzrCommandError('--using and --format are mutually '
 
1991
                'exclusive.')
 
1992
 
1947
1993
        (old_tree, new_tree,
1948
1994
         old_branch, new_branch,
1949
1995
         specific_files, extra_trees) = get_trees_and_branches_to_diff(
1952
1998
                               specific_files=specific_files,
1953
1999
                               external_diff_options=diff_options,
1954
2000
                               old_label=old_label, new_label=new_label,
1955
 
                               extra_trees=extra_trees, using=using)
 
2001
                               extra_trees=extra_trees, using=using,
 
2002
                               format_cls=format)
1956
2003
 
1957
2004
 
1958
2005
class cmd_deleted(Command):
2191
2238
    :Tips & tricks:
2192
2239
 
2193
2240
      GUI tools and IDEs are often better at exploring history than command
2194
 
      line tools. You may prefer qlog or glog from the QBzr and Bzr-Gtk packages
2195
 
      respectively for example. (TortoiseBzr uses qlog for displaying logs.) See
2196
 
      http://bazaar-vcs.org/BzrPlugins and http://bazaar-vcs.org/IDEIntegration.
2197
 
 
2198
 
      Web interfaces are often better at exploring history than command line
2199
 
      tools, particularly for branches on servers. You may prefer Loggerhead
2200
 
      or one of its alternatives. See http://bazaar-vcs.org/WebInterface.
 
2241
      line tools: you may prefer qlog or viz from qbzr or bzr-gtk, the
 
2242
      bzr-explorer shell, or the Loggerhead web interface.  See the Plugin
 
2243
      Guide <http://doc.bazaar.canonical.com/plugins/en/> and
 
2244
      <http://wiki.bazaar.canonical.com/IDEIntegration>.  
2201
2245
 
2202
2246
      You may find it useful to add the aliases below to ``bazaar.conf``::
2203
2247
 
2409
2453
            raise errors.BzrCommandError(
2410
2454
                "bzr %s doesn't accept two revisions in different"
2411
2455
                " branches." % command_name)
2412
 
        rev1 = start_spec.in_history(branch)
 
2456
        if start_spec.spec is None:
 
2457
            # Avoid loading all the history.
 
2458
            rev1 = RevisionInfo(branch, None, None)
 
2459
        else:
 
2460
            rev1 = start_spec.in_history(branch)
2413
2461
        # Avoid loading all of history when we know a missing
2414
2462
        # end of range means the last revision ...
2415
2463
        if end_spec.spec is None:
2665
2713
        if old_default_rules is not None:
2666
2714
            # dump the rules and exit
2667
2715
            for pattern in ignores.OLD_DEFAULTS:
2668
 
                print pattern
 
2716
                self.outf.write("%s\n" % pattern)
2669
2717
            return
2670
2718
        if not name_pattern_list:
2671
2719
            raise errors.BzrCommandError("ignore requires at least one "
2687
2735
            if id is not None:
2688
2736
                filename = entry[0]
2689
2737
                if ignored.match(filename):
2690
 
                    matches.append(filename.encode('utf-8'))
 
2738
                    matches.append(filename)
2691
2739
        tree.unlock()
2692
2740
        if len(matches) > 0:
2693
 
            print "Warning: the following files are version controlled and" \
2694
 
                  " match your ignore pattern:\n%s" \
2695
 
                  "\nThese files will continue to be version controlled" \
2696
 
                  " unless you 'bzr remove' them." % ("\n".join(matches),)
 
2741
            self.outf.write("Warning: the following files are version controlled and"
 
2742
                  " match your ignore pattern:\n%s"
 
2743
                  "\nThese files will continue to be version controlled"
 
2744
                  " unless you 'bzr remove' them.\n" % ("\n".join(matches),))
2697
2745
 
2698
2746
 
2699
2747
class cmd_ignored(Command):
2737
2785
        try:
2738
2786
            revno = int(revno)
2739
2787
        except ValueError:
2740
 
            raise errors.BzrCommandError("not a valid revision-number: %r" % revno)
2741
 
 
2742
 
        print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
 
2788
            raise errors.BzrCommandError("not a valid revision-number: %r"
 
2789
                                         % revno)
 
2790
        revid = WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
 
2791
        self.outf.write("%s\n" % revid)
2743
2792
 
2744
2793
 
2745
2794
class cmd_export(Command):
2781
2830
        Option('root',
2782
2831
               type=str,
2783
2832
               help="Name of the root directory inside the exported file."),
 
2833
        Option('per-file-timestamps',
 
2834
               help='Set modification time of files to that of the last '
 
2835
                    'revision in which it was changed.'),
2784
2836
        ]
2785
2837
    def run(self, dest, branch_or_subdir=None, revision=None, format=None,
2786
 
        root=None, filters=False):
 
2838
        root=None, filters=False, per_file_timestamps=False):
2787
2839
        from bzrlib.export import export
2788
2840
 
2789
2841
        if branch_or_subdir is None:
2796
2848
 
2797
2849
        rev_tree = _get_one_revision_tree('export', revision, branch=b, tree=tree)
2798
2850
        try:
2799
 
            export(rev_tree, dest, format, root, subdir, filtered=filters)
 
2851
            export(rev_tree, dest, format, root, subdir, filtered=filters,
 
2852
                   per_file_timestamps=per_file_timestamps)
2800
2853
        except errors.NoSuchExportFormat, e:
2801
2854
            raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
2802
2855
 
2892
2945
    hidden = True
2893
2946
    @display_command
2894
2947
    def run(self):
2895
 
        print osutils.local_time_offset()
 
2948
        self.outf.write("%s\n" % osutils.local_time_offset())
2896
2949
 
2897
2950
 
2898
2951
 
3097
3150
                    '(use --file "%(f)s" to take commit message from that file)'
3098
3151
                    % { 'f': message })
3099
3152
                ui.ui_factory.show_warning(warning_msg)
 
3153
            if '\r' in message:
 
3154
                message = message.replace('\r\n', '\n')
 
3155
                message = message.replace('\r', '\n')
 
3156
            if file:
 
3157
                raise errors.BzrCommandError(
 
3158
                    "please specify either --message or --file")
3100
3159
 
3101
3160
        def get_message(commit_obj):
3102
3161
            """Callback to get commit message"""
3103
 
            my_message = message
3104
 
            if my_message is not None and '\r' in my_message:
3105
 
                my_message = my_message.replace('\r\n', '\n')
3106
 
                my_message = my_message.replace('\r', '\n')
3107
 
            if my_message is None and not file:
3108
 
                t = make_commit_message_template_encoded(tree,
 
3162
            if file:
 
3163
                my_message = codecs.open(
 
3164
                    file, 'rt', osutils.get_user_encoding()).read()
 
3165
            elif message is not None:
 
3166
                my_message = message
 
3167
            else:
 
3168
                # No message supplied: make one up.
 
3169
                # text is the status of the tree
 
3170
                text = make_commit_message_template_encoded(tree,
3109
3171
                        selected_list, diff=show_diff,
3110
3172
                        output_encoding=osutils.get_user_encoding())
 
3173
                # start_message is the template generated from hooks
 
3174
                # XXX: Warning - looks like hooks return unicode,
 
3175
                # make_commit_message_template_encoded returns user encoding.
 
3176
                # We probably want to be using edit_commit_message instead to
 
3177
                # avoid this.
3111
3178
                start_message = generate_commit_message_template(commit_obj)
3112
 
                my_message = edit_commit_message_encoded(t,
 
3179
                my_message = edit_commit_message_encoded(text,
3113
3180
                    start_message=start_message)
3114
3181
                if my_message is None:
3115
3182
                    raise errors.BzrCommandError("please specify a commit"
3116
3183
                        " message with either --message or --file")
3117
 
            elif my_message and file:
3118
 
                raise errors.BzrCommandError(
3119
 
                    "please specify either --message or --file")
3120
 
            if file:
3121
 
                my_message = codecs.open(file, 'rt',
3122
 
                                         osutils.get_user_encoding()).read()
3123
3184
            if my_message == "":
3124
3185
                raise errors.BzrCommandError("empty commit message specified")
3125
3186
            return my_message
3137
3198
                        timezone=offset,
3138
3199
                        exclude=safe_relpath_files(tree, exclude))
3139
3200
        except PointlessCommit:
3140
 
            # FIXME: This should really happen before the file is read in;
3141
 
            # perhaps prepare the commit; get the message; then actually commit
3142
3201
            raise errors.BzrCommandError("No changes to commit."
3143
3202
                              " Use --unchanged to commit anyhow.")
3144
3203
        except ConflictsInTree:
3149
3208
            raise errors.BzrCommandError("Commit refused because there are"
3150
3209
                              " unknown files in the working tree.")
3151
3210
        except errors.BoundBranchOutOfDate, e:
3152
 
            raise errors.BzrCommandError(str(e) + "\n"
3153
 
            'To commit to master branch, run update and then commit.\n'
3154
 
            'You can also pass --local to commit to continue working '
3155
 
            'disconnected.')
 
3211
            e.extra_help = ("\n"
 
3212
                'To commit to master branch, run update and then commit.\n'
 
3213
                'You can also pass --local to commit to continue working '
 
3214
                'disconnected.')
 
3215
            raise
3156
3216
 
3157
3217
 
3158
3218
class cmd_check(Command):
3320
3380
 
3321
3381
    @display_command
3322
3382
    def printme(self, branch):
3323
 
        print branch.nick
 
3383
        self.outf.write('%s\n' % branch.nick)
3324
3384
 
3325
3385
 
3326
3386
class cmd_alias(Command):
3447
3507
            from bzrlib.tests import stub_sftp
3448
3508
            return stub_sftp.SFTPAbsoluteServer
3449
3509
        if typestring == "memory":
3450
 
            from bzrlib.transport.memory import MemoryServer
3451
 
            return MemoryServer
 
3510
            from bzrlib.tests import test_server
 
3511
            return memory.MemoryServer
3452
3512
        if typestring == "fakenfs":
3453
 
            from bzrlib.transport.fakenfs import FakeNFSServer
3454
 
            return FakeNFSServer
 
3513
            from bzrlib.tests import test_server
 
3514
            return test_server.FakeNFSServer
3455
3515
        msg = "No known transport type %s. Supported types are: sftp\n" %\
3456
3516
            (typestring)
3457
3517
        raise errors.BzrCommandError(msg)
3600
3660
 
3601
3661
    @display_command
3602
3662
    def run(self):
3603
 
        print "It sure does!"
 
3663
        self.outf.write("It sure does!\n")
3604
3664
 
3605
3665
 
3606
3666
class cmd_find_merge_base(Command):
3626
3686
        graph = branch1.repository.get_graph(branch2.repository)
3627
3687
        base_rev_id = graph.find_unique_lca(last1, last2)
3628
3688
 
3629
 
        print 'merge base is revision %s' % base_rev_id
 
3689
        self.outf.write('merge base is revision %s\n' % base_rev_id)
3630
3690
 
3631
3691
 
3632
3692
class cmd_merge(Command):
3780
3840
                    raise errors.BzrCommandError(
3781
3841
                        'Cannot use -r with merge directives or bundles')
3782
3842
                merger, verified = _mod_merge.Merger.from_mergeable(tree,
3783
 
                   mergeable, pb)
 
3843
                   mergeable, None)
3784
3844
 
3785
3845
        if merger is None and uncommitted:
3786
3846
            if revision is not None and len(revision) > 0:
3787
3847
                raise errors.BzrCommandError('Cannot use --uncommitted and'
3788
3848
                    ' --revision at the same time.')
3789
 
            merger = self.get_merger_from_uncommitted(tree, location, pb)
 
3849
            merger = self.get_merger_from_uncommitted(tree, location, None)
3790
3850
            allow_pending = False
3791
3851
 
3792
3852
        if merger is None:
3793
3853
            merger, allow_pending = self._get_merger_from_branch(tree,
3794
 
                location, revision, remember, possible_transports, pb)
 
3854
                location, revision, remember, possible_transports, None)
3795
3855
 
3796
3856
        merger.merge_type = merge_type
3797
3857
        merger.reprocess = reprocess
4022
4082
 
4023
4083
    def run(self, file_list=None, merge_type=None, show_base=False,
4024
4084
            reprocess=False):
 
4085
        from bzrlib.conflicts import restore
4025
4086
        if merge_type is None:
4026
4087
            merge_type = _mod_merge.Merge3Merger
4027
4088
        tree, file_list = tree_files(file_list)
4068
4129
        # list, we imply that the working tree text has seen and rejected
4069
4130
        # all the changes from the other tree, when in fact those changes
4070
4131
        # have not yet been seen.
4071
 
        pb = ui.ui_factory.nested_progress_bar()
4072
4132
        tree.set_parent_ids(parents[:1])
4073
4133
        try:
4074
 
            merger = _mod_merge.Merger.from_revision_ids(pb,
4075
 
                                                         tree, parents[1])
 
4134
            merger = _mod_merge.Merger.from_revision_ids(None, tree, parents[1])
4076
4135
            merger.interesting_ids = interesting_ids
4077
4136
            merger.merge_type = merge_type
4078
4137
            merger.show_base = show_base
4080
4139
            conflicts = merger.do_merge()
4081
4140
        finally:
4082
4141
            tree.set_parent_ids(parents)
4083
 
            pb.finished()
4084
4142
        if conflicts > 0:
4085
4143
            return 1
4086
4144
        else:
4155
4213
    @staticmethod
4156
4214
    def _revert_tree_to_revision(tree, revision, file_list, no_backup):
4157
4215
        rev_tree = _get_one_revision_tree('revert', revision, tree=tree)
4158
 
        pb = ui.ui_factory.nested_progress_bar()
4159
 
        try:
4160
 
            tree.revert(file_list, rev_tree, not no_backup, pb,
4161
 
                report_changes=True)
4162
 
        finally:
4163
 
            pb.finished()
 
4216
        tree.revert(file_list, rev_tree, not no_backup, None,
 
4217
            report_changes=True)
4164
4218
 
4165
4219
 
4166
4220
class cmd_assert_fail(Command):
4408
4462
    adding new commands, providing additional network transports and
4409
4463
    customizing log output.
4410
4464
 
4411
 
    See the Bazaar web site, http://bazaar-vcs.org, for further
4412
 
    information on plugins including where to find them and how to
4413
 
    install them. Instructions are also provided there on how to
4414
 
    write new plugins using the Python programming language.
 
4465
    See the Bazaar Plugin Guide <http://doc.bazaar.canonical.com/plugins/en/>
 
4466
    for further information on plugins including where to find them and how to
 
4467
    install them. Instructions are also provided there on how to write new
 
4468
    plugins using the Python programming language.
4415
4469
    """
4416
4470
    takes_options = ['verbose']
4417
4471
 
4432
4486
                doc = '(no description)'
4433
4487
            result.append((name_ver, doc, plugin.path()))
4434
4488
        for name_ver, doc, path in sorted(result):
4435
 
            print name_ver
4436
 
            print '   ', doc
 
4489
            self.outf.write("%s\n" % name_ver)
 
4490
            self.outf.write("   %s\n" % doc)
4437
4491
            if verbose:
4438
 
                print '   ', path
4439
 
            print
 
4492
                self.outf.write("   %s\n" % path)
 
4493
            self.outf.write("\n")
4440
4494
 
4441
4495
 
4442
4496
class cmd_testament(Command):
4615
4669
                    'This format does not remember old locations.')
4616
4670
            else:
4617
4671
                if location is None:
4618
 
                    raise errors.BzrCommandError('No location supplied and no '
4619
 
                        'previous location known')
 
4672
                    if b.get_bound_location() is not None:
 
4673
                        raise errors.BzrCommandError('Branch is already bound')
 
4674
                    else:
 
4675
                        raise errors.BzrCommandError('No location supplied '
 
4676
                            'and no previous location known')
4620
4677
        b_other = Branch.open(location)
4621
4678
        try:
4622
4679
            b.bind(b_other)
4734
4791
                 end_revision=last_revno)
4735
4792
 
4736
4793
        if dry_run:
4737
 
            print 'Dry-run, pretending to remove the above revisions.'
4738
 
            if not force:
4739
 
                val = raw_input('Press <enter> to continue')
 
4794
            self.outf.write('Dry-run, pretending to remove'
 
4795
                            ' the above revisions.\n')
4740
4796
        else:
4741
 
            print 'The above revision(s) will be removed.'
4742
 
            if not force:
4743
 
                val = raw_input('Are you sure [y/N]? ')
4744
 
                if val.lower() not in ('y', 'yes'):
4745
 
                    print 'Canceled'
4746
 
                    return 0
 
4797
            self.outf.write('The above revision(s) will be removed.\n')
 
4798
 
 
4799
        if not force:
 
4800
            if not ui.ui_factory.get_boolean('Are you sure'):
 
4801
                self.outf.write('Canceled')
 
4802
                return 0
4747
4803
 
4748
4804
        mutter('Uncommitting from {%s} to {%s}',
4749
4805
               last_rev_id, rev_id)
4750
4806
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
4751
4807
                 revno=revno, local=local)
4752
 
        note('You can restore the old tip by running:\n'
4753
 
             '  bzr pull . -r revid:%s', last_rev_id)
 
4808
        self.outf.write('You can restore the old tip by running:\n'
 
4809
             '  bzr pull . -r revid:%s\n' % last_rev_id)
4754
4810
 
4755
4811
 
4756
4812
class cmd_break_lock(Command):
5118
5174
               short_name='f',
5119
5175
               type=unicode),
5120
5176
        Option('output', short_name='o',
5121
 
               help='Write merge directive to this file; '
 
5177
               help='Write merge directive to this file or directory; '
5122
5178
                    'use - for stdout.',
5123
5179
               type=unicode),
5124
5180
        Option('strict',
5234
5290
 
5235
5291
    To rename a tag (change the name but keep it on the same revsion), run ``bzr
5236
5292
    tag new-name -r tag:old-name`` and then ``bzr tag --delete oldname``.
 
5293
 
 
5294
    If no tag name is specified it will be determined through the 
 
5295
    'automatic_tag_name' hook. This can e.g. be used to automatically tag
 
5296
    upstream releases by reading configure.ac. See ``bzr help hooks`` for
 
5297
    details.
5237
5298
    """
5238
5299
 
5239
5300
    _see_also = ['commit', 'tags']
5240
 
    takes_args = ['tag_name']
 
5301
    takes_args = ['tag_name?']
5241
5302
    takes_options = [
5242
5303
        Option('delete',
5243
5304
            help='Delete this tag rather than placing it.',
5253
5314
        'revision',
5254
5315
        ]
5255
5316
 
5256
 
    def run(self, tag_name,
 
5317
    def run(self, tag_name=None,
5257
5318
            delete=None,
5258
5319
            directory='.',
5259
5320
            force=None,
5263
5324
        branch.lock_write()
5264
5325
        self.add_cleanup(branch.unlock)
5265
5326
        if delete:
 
5327
            if tag_name is None:
 
5328
                raise errors.BzrCommandError("No tag specified to delete.")
5266
5329
            branch.tags.delete_tag(tag_name)
5267
5330
            self.outf.write('Deleted tag %s.\n' % tag_name)
5268
5331
        else:
5274
5337
                revision_id = revision[0].as_revision_id(branch)
5275
5338
            else:
5276
5339
                revision_id = branch.last_revision()
 
5340
            if tag_name is None:
 
5341
                tag_name = branch.automatic_tag_name(revision_id)
 
5342
                if tag_name is None:
 
5343
                    raise errors.BzrCommandError(
 
5344
                        "Please specify a tag name.")
5277
5345
            if (not force) and branch.tags.has_tag(tag_name):
5278
5346
                raise errors.TagAlreadyExists(tag_name)
5279
5347
            branch.tags.set_tag(tag_name, revision_id)
5715
5783
                    self.outf.write("    <no hooks installed>\n")
5716
5784
 
5717
5785
 
 
5786
class cmd_remove_branch(Command):
 
5787
    """Remove a branch.
 
5788
 
 
5789
    This will remove the branch from the specified location but 
 
5790
    will keep any working tree or repository in place.
 
5791
 
 
5792
    :Examples:
 
5793
 
 
5794
      Remove the branch at repo/trunk::
 
5795
 
 
5796
        bzr remove-branch repo/trunk
 
5797
 
 
5798
    """
 
5799
 
 
5800
    takes_args = ["location?"]
 
5801
 
 
5802
    aliases = ["rmbranch"]
 
5803
 
 
5804
    def run(self, location=None):
 
5805
        if location is None:
 
5806
            location = "."
 
5807
        branch = Branch.open_containing(location)[0]
 
5808
        branch.bzrdir.destroy_branch()
 
5809
        
 
5810
 
5718
5811
class cmd_shelve(Command):
5719
5812
    """Temporarily set aside some changes from the current tree.
5720
5813
 
5903
5996
            self.outf.write('%s %s\n' % (path, location))
5904
5997
 
5905
5998
 
5906
 
# these get imported and then picked up by the scan for cmd_*
5907
 
# TODO: Some more consistent way to split command definitions across files;
5908
 
# we do need to load at least some information about them to know of
5909
 
# aliases.  ideally we would avoid loading the implementation until the
5910
 
# details were needed.
5911
 
from bzrlib.cmd_version_info import cmd_version_info
5912
 
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
5913
 
from bzrlib.bundle.commands import (
5914
 
    cmd_bundle_info,
5915
 
    )
5916
 
from bzrlib.foreign import cmd_dpush
5917
 
from bzrlib.sign_my_commits import cmd_sign_my_commits
5918
 
from bzrlib.weave_commands import cmd_versionedfile_list, \
5919
 
        cmd_weave_plan_merge, cmd_weave_merge_text
 
5999
def _register_lazy_builtins():
 
6000
    # register lazy builtins from other modules; called at startup and should
 
6001
    # be only called once.
 
6002
    for (name, aliases, module_name) in [
 
6003
        ('cmd_bundle_info', [], 'bzrlib.bundle.commands'),
 
6004
        ('cmd_dpush', [], 'bzrlib.foreign'),
 
6005
        ('cmd_version_info', [], 'bzrlib.cmd_version_info'),
 
6006
        ('cmd_resolve', ['resolved'], 'bzrlib.conflicts'),
 
6007
        ('cmd_conflicts', [], 'bzrlib.conflicts'),
 
6008
        ('cmd_sign_my_commits', [], 'bzrlib.sign_my_commits'),
 
6009
        ]:
 
6010
        builtin_command_registry.register_lazy(name, aliases, module_name)