~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: IWATA Hidetaka
  • Date: 2010-12-26 13:19:11 UTC
  • mto: This revision was merged to the branch mainline in revision 5593.
  • Revision ID: iwata0303@gmail.com-20101226131911-o7txs0fnji5zekq1
add icon resources tbzrcommand(w)

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
 
21
21
from bzrlib.lazy_import import lazy_import
22
22
lazy_import(globals(), """
23
 
import codecs
24
23
import cStringIO
 
24
import itertools
 
25
import re
25
26
import sys
26
27
import time
27
28
 
33
34
    bzrdir,
34
35
    directory_service,
35
36
    delta,
36
 
    config,
 
37
    config as _mod_config,
37
38
    errors,
38
39
    globbing,
39
40
    hooks,
60
61
from bzrlib.workingtree import WorkingTree
61
62
""")
62
63
 
63
 
from bzrlib.commands import Command, display_command
 
64
from bzrlib.commands import (
 
65
    Command,
 
66
    builtin_command_registry,
 
67
    display_command,
 
68
    )
64
69
from bzrlib.option import (
65
70
    ListOption,
66
71
    Option,
71
76
from bzrlib.trace import mutter, note, warning, is_quiet, get_verbosity_level
72
77
 
73
78
 
 
79
@symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
74
80
def tree_files(file_list, default_branch=u'.', canonicalize=True,
75
81
    apply_view=True):
76
 
    try:
77
 
        return internal_tree_files(file_list, default_branch, canonicalize,
78
 
            apply_view)
79
 
    except errors.FileInWrongBranch, e:
80
 
        raise errors.BzrCommandError("%s is not in the same branch as %s" %
81
 
                                     (e.path, file_list[0]))
 
82
    return internal_tree_files(file_list, default_branch, canonicalize,
 
83
        apply_view)
82
84
 
83
85
 
84
86
def tree_files_for_add(file_list):
148
150
 
149
151
# XXX: Bad function name; should possibly also be a class method of
150
152
# WorkingTree rather than a function.
 
153
@symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
151
154
def internal_tree_files(file_list, default_branch=u'.', canonicalize=True,
152
155
    apply_view=True):
153
156
    """Convert command-line paths to a WorkingTree and relative paths.
154
157
 
 
158
    Deprecated: use WorkingTree.open_containing_paths instead.
 
159
 
155
160
    This is typically used for command-line processors that take one or
156
161
    more filenames, and infer the workingtree that contains them.
157
162
 
167
172
 
168
173
    :return: workingtree, [relative_paths]
169
174
    """
170
 
    if file_list is None or len(file_list) == 0:
171
 
        tree = WorkingTree.open_containing(default_branch)[0]
172
 
        if tree.supports_views() and apply_view:
173
 
            view_files = tree.views.lookup_view()
174
 
            if view_files:
175
 
                file_list = view_files
176
 
                view_str = views.view_display_str(view_files)
177
 
                note("Ignoring files outside view. View is %s" % view_str)
178
 
        return tree, file_list
179
 
    tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
180
 
    return tree, safe_relpath_files(tree, file_list, canonicalize,
181
 
        apply_view=apply_view)
182
 
 
183
 
 
184
 
def safe_relpath_files(tree, file_list, canonicalize=True, apply_view=True):
185
 
    """Convert file_list into a list of relpaths in tree.
186
 
 
187
 
    :param tree: A tree to operate on.
188
 
    :param file_list: A list of user provided paths or None.
189
 
    :param apply_view: if True and a view is set, apply it or check that
190
 
        specified files are within it
191
 
    :return: A list of relative paths.
192
 
    :raises errors.PathNotChild: When a provided path is in a different tree
193
 
        than tree.
194
 
    """
195
 
    if file_list is None:
196
 
        return None
197
 
    if tree.supports_views() and apply_view:
198
 
        view_files = tree.views.lookup_view()
199
 
    else:
200
 
        view_files = []
201
 
    new_list = []
202
 
    # tree.relpath exists as a "thunk" to osutils, but canonical_relpath
203
 
    # doesn't - fix that up here before we enter the loop.
204
 
    if canonicalize:
205
 
        fixer = lambda p: osutils.canonical_relpath(tree.basedir, p)
206
 
    else:
207
 
        fixer = tree.relpath
208
 
    for filename in file_list:
209
 
        try:
210
 
            relpath = fixer(osutils.dereference_path(filename))
211
 
            if  view_files and not osutils.is_inside_any(view_files, relpath):
212
 
                raise errors.FileOutsideView(filename, view_files)
213
 
            new_list.append(relpath)
214
 
        except errors.PathNotChild:
215
 
            raise errors.FileInWrongBranch(tree.branch, filename)
216
 
    return new_list
 
175
    return WorkingTree.open_containing_paths(
 
176
        file_list, default_directory='.',
 
177
        canonicalize=True,
 
178
        apply_view=True)
217
179
 
218
180
 
219
181
def _get_view_info_for_change_reporter(tree):
228
190
    return view_info
229
191
 
230
192
 
 
193
def _open_directory_or_containing_tree_or_branch(filename, directory):
 
194
    """Open the tree or branch containing the specified file, unless
 
195
    the --directory option is used to specify a different branch."""
 
196
    if directory is not None:
 
197
        return (None, Branch.open(directory), filename)
 
198
    return bzrdir.BzrDir.open_containing_tree_or_branch(filename)
 
199
 
 
200
 
231
201
# TODO: Make sure no commands unconditionally use the working directory as a
232
202
# branch.  If a filename argument is used, the first of them should be used to
233
203
# specify the branch.  (Perhaps this can be factored out into some kind of
235
205
# opens the branch?)
236
206
 
237
207
class cmd_status(Command):
238
 
    """Display status summary.
 
208
    __doc__ = """Display status summary.
239
209
 
240
210
    This reports on versioned and unknown files, reporting them
241
211
    grouped by state.  Possible states are:
282
252
    To skip the display of pending merge information altogether, use
283
253
    the no-pending option or specify a file/directory.
284
254
 
285
 
    If a revision argument is given, the status is calculated against
286
 
    that revision, or between two revisions if two are provided.
 
255
    To compare the working directory to a specific revision, pass a
 
256
    single revision to the revision argument.
 
257
 
 
258
    To see which files have changed in a specific revision, or between
 
259
    two revisions, pass a revision range to the revision argument.
 
260
    This will produce the same results as calling 'bzr diff --summarize'.
287
261
    """
288
262
 
289
263
    # TODO: --no-recurse, --recurse options
311
285
            raise errors.BzrCommandError('bzr status --revision takes exactly'
312
286
                                         ' one or two revision specifiers')
313
287
 
314
 
        tree, relfile_list = tree_files(file_list)
 
288
        tree, relfile_list = WorkingTree.open_containing_paths(file_list)
315
289
        # Avoid asking for specific files when that is not needed.
316
290
        if relfile_list == ['']:
317
291
            relfile_list = None
328
302
 
329
303
 
330
304
class cmd_cat_revision(Command):
331
 
    """Write out metadata for a revision.
 
305
    __doc__ = """Write out metadata for a revision.
332
306
 
333
307
    The revision to print can either be specified by a specific
334
308
    revision identifier, or you can use --revision.
336
310
 
337
311
    hidden = True
338
312
    takes_args = ['revision_id?']
339
 
    takes_options = ['revision']
 
313
    takes_options = ['directory', 'revision']
340
314
    # cat-revision is more for frontends so should be exact
341
315
    encoding = 'strict'
342
316
 
349
323
        self.outf.write(revtext.decode('utf-8'))
350
324
 
351
325
    @display_command
352
 
    def run(self, revision_id=None, revision=None):
 
326
    def run(self, revision_id=None, revision=None, directory=u'.'):
353
327
        if revision_id is not None and revision is not None:
354
328
            raise errors.BzrCommandError('You can only supply one of'
355
329
                                         ' revision_id or --revision')
356
330
        if revision_id is None and revision is None:
357
331
            raise errors.BzrCommandError('You must supply either'
358
332
                                         ' --revision or a revision_id')
359
 
        b = WorkingTree.open_containing(u'.')[0].branch
 
333
        b = WorkingTree.open_containing(directory)[0].branch
360
334
 
361
335
        revisions = b.repository.revisions
362
336
        if revisions is None:
386
360
        
387
361
 
388
362
class cmd_dump_btree(Command):
389
 
    """Dump the contents of a btree index file to stdout.
 
363
    __doc__ = """Dump the contents of a btree index file to stdout.
390
364
 
391
365
    PATH is a btree index file, it can be any URL. This includes things like
392
366
    .bzr/repository/pack-names, or .bzr/repository/indices/a34b3a...ca4a4.iix
467
441
 
468
442
 
469
443
class cmd_remove_tree(Command):
470
 
    """Remove the working tree from a given branch/checkout.
 
444
    __doc__ = """Remove the working tree from a given branch/checkout.
471
445
 
472
446
    Since a lightweight checkout is little more than a working tree
473
447
    this will refuse to run against one.
479
453
    takes_options = [
480
454
        Option('force',
481
455
               help='Remove the working tree even if it has '
482
 
                    'uncommitted changes.'),
 
456
                    'uncommitted or shelved changes.'),
483
457
        ]
484
458
 
485
459
    def run(self, location_list, force=False):
499
473
            if not force:
500
474
                if (working.has_changes()):
501
475
                    raise errors.UncommittedChanges(working)
 
476
                if working.get_shelf_manager().last_shelf() is not None:
 
477
                    raise errors.ShelvedChanges(working)
502
478
 
503
 
            working_path = working.bzrdir.root_transport.base
504
 
            branch_path = working.branch.bzrdir.root_transport.base
505
 
            if working_path != branch_path:
 
479
            if working.user_url != working.branch.user_url:
506
480
                raise errors.BzrCommandError("You cannot remove the working tree"
507
481
                                             " from a lightweight checkout")
508
482
 
510
484
 
511
485
 
512
486
class cmd_revno(Command):
513
 
    """Show current revision number.
 
487
    __doc__ = """Show current revision number.
514
488
 
515
489
    This is equal to the number of revisions on this branch.
516
490
    """
526
500
        if tree:
527
501
            try:
528
502
                wt = WorkingTree.open_containing(location)[0]
529
 
                wt.lock_read()
 
503
                self.add_cleanup(wt.lock_read().unlock)
530
504
            except (errors.NoWorkingTree, errors.NotLocalUrl):
531
505
                raise errors.NoWorkingTree(location)
532
 
            self.add_cleanup(wt.unlock)
533
506
            revid = wt.last_revision()
534
507
            try:
535
508
                revno_t = wt.branch.revision_id_to_dotted_revno(revid)
538
511
            revno = ".".join(str(n) for n in revno_t)
539
512
        else:
540
513
            b = Branch.open_containing(location)[0]
541
 
            b.lock_read()
542
 
            self.add_cleanup(b.unlock)
 
514
            self.add_cleanup(b.lock_read().unlock)
543
515
            revno = b.revno()
544
516
        self.cleanup_now()
545
517
        self.outf.write(str(revno) + '\n')
546
518
 
547
519
 
548
520
class cmd_revision_info(Command):
549
 
    """Show revision number and revision id for a given revision identifier.
 
521
    __doc__ = """Show revision number and revision id for a given revision identifier.
550
522
    """
551
523
    hidden = True
552
524
    takes_args = ['revision_info*']
553
525
    takes_options = [
554
526
        'revision',
555
 
        Option('directory',
 
527
        custom_help('directory',
556
528
            help='Branch to examine, '
557
 
                 'rather than the one containing the working directory.',
558
 
            short_name='d',
559
 
            type=unicode,
560
 
            ),
 
529
                 'rather than the one containing the working directory.'),
561
530
        Option('tree', help='Show revno of working tree'),
562
531
        ]
563
532
 
568
537
        try:
569
538
            wt = WorkingTree.open_containing(directory)[0]
570
539
            b = wt.branch
571
 
            wt.lock_read()
572
 
            self.add_cleanup(wt.unlock)
 
540
            self.add_cleanup(wt.lock_read().unlock)
573
541
        except (errors.NoWorkingTree, errors.NotLocalUrl):
574
542
            wt = None
575
543
            b = Branch.open_containing(directory)[0]
576
 
            b.lock_read()
577
 
            self.add_cleanup(b.unlock)
 
544
            self.add_cleanup(b.lock_read().unlock)
578
545
        revision_ids = []
579
546
        if revision is not None:
580
547
            revision_ids.extend(rev.as_revision_id(b) for rev in revision)
608
575
 
609
576
 
610
577
class cmd_add(Command):
611
 
    """Add specified files or directories.
 
578
    __doc__ = """Add specified files or directories.
612
579
 
613
580
    In non-recursive mode, all the named items are added, regardless
614
581
    of whether they were previously ignored.  A warning is given if
679
646
                should_print=(not is_quiet()))
680
647
 
681
648
        if base_tree:
682
 
            base_tree.lock_read()
683
 
            self.add_cleanup(base_tree.unlock)
 
649
            self.add_cleanup(base_tree.lock_read().unlock)
684
650
        tree, file_list = tree_files_for_add(file_list)
685
651
        added, ignored = tree.smart_add(file_list, not
686
652
            no_recurse, action=action, save=not dry_run)
694
660
 
695
661
 
696
662
class cmd_mkdir(Command):
697
 
    """Create a new versioned directory.
 
663
    __doc__ = """Create a new versioned directory.
698
664
 
699
665
    This is equivalent to creating the directory and then adding it.
700
666
    """
716
682
 
717
683
 
718
684
class cmd_relpath(Command):
719
 
    """Show path of a file relative to root"""
 
685
    __doc__ = """Show path of a file relative to root"""
720
686
 
721
687
    takes_args = ['filename']
722
688
    hidden = True
731
697
 
732
698
 
733
699
class cmd_inventory(Command):
734
 
    """Show inventory of the current working copy or a revision.
 
700
    __doc__ = """Show inventory of the current working copy or a revision.
735
701
 
736
702
    It is possible to limit the output to a particular entry
737
703
    type using the --kind option.  For example: --kind file.
757
723
            raise errors.BzrCommandError('invalid kind %r specified' % (kind,))
758
724
 
759
725
        revision = _get_one_revision('inventory', revision)
760
 
        work_tree, file_list = tree_files(file_list)
761
 
        work_tree.lock_read()
762
 
        self.add_cleanup(work_tree.unlock)
 
726
        work_tree, file_list = WorkingTree.open_containing_paths(file_list)
 
727
        self.add_cleanup(work_tree.lock_read().unlock)
763
728
        if revision is not None:
764
729
            tree = revision.as_tree(work_tree.branch)
765
730
 
766
731
            extra_trees = [work_tree]
767
 
            tree.lock_read()
768
 
            self.add_cleanup(tree.unlock)
 
732
            self.add_cleanup(tree.lock_read().unlock)
769
733
        else:
770
734
            tree = work_tree
771
735
            extra_trees = []
792
756
 
793
757
 
794
758
class cmd_mv(Command):
795
 
    """Move or rename a file.
 
759
    __doc__ = """Move or rename a file.
796
760
 
797
761
    :Usage:
798
762
        bzr mv OLDNAME NEWNAME
830
794
            names_list = []
831
795
        if len(names_list) < 2:
832
796
            raise errors.BzrCommandError("missing file argument")
833
 
        tree, rel_names = tree_files(names_list, canonicalize=False)
834
 
        tree.lock_tree_write()
835
 
        self.add_cleanup(tree.unlock)
 
797
        tree, rel_names = WorkingTree.open_containing_paths(names_list, canonicalize=False)
 
798
        self.add_cleanup(tree.lock_tree_write().unlock)
836
799
        self._run(tree, names_list, rel_names, after)
837
800
 
838
801
    def run_auto(self, names_list, after, dry_run):
842
805
        if after:
843
806
            raise errors.BzrCommandError('--after cannot be specified with'
844
807
                                         ' --auto.')
845
 
        work_tree, file_list = tree_files(names_list, default_branch='.')
846
 
        work_tree.lock_tree_write()
847
 
        self.add_cleanup(work_tree.unlock)
 
808
        work_tree, file_list = WorkingTree.open_containing_paths(
 
809
            names_list, default_directory='.')
 
810
        self.add_cleanup(work_tree.lock_tree_write().unlock)
848
811
        rename_map.RenameMap.guess_renames(work_tree, dry_run)
849
812
 
850
813
    def _run(self, tree, names_list, rel_names, after):
929
892
 
930
893
 
931
894
class cmd_pull(Command):
932
 
    """Turn this branch into a mirror of another branch.
 
895
    __doc__ = """Turn this branch into a mirror of another branch.
933
896
 
934
897
    By default, this command only works on branches that have not diverged.
935
898
    Branches are considered diverged if the destination branch's most recent 
958
921
    takes_options = ['remember', 'overwrite', 'revision',
959
922
        custom_help('verbose',
960
923
            help='Show logs of pulled revisions.'),
961
 
        Option('directory',
 
924
        custom_help('directory',
962
925
            help='Branch to pull into, '
963
 
                 'rather than the one containing the working directory.',
964
 
            short_name='d',
965
 
            type=unicode,
966
 
            ),
 
926
                 'rather than the one containing the working directory.'),
967
927
        Option('local',
968
928
            help="Perform a local pull in a bound "
969
929
                 "branch.  Local pulls are not applied to "
970
930
                 "the master branch."
971
931
            ),
 
932
        Option('show-base',
 
933
            help="Show base revision text in conflicts.")
972
934
        ]
973
935
    takes_args = ['location?']
974
936
    encoding_type = 'replace'
975
937
 
976
938
    def run(self, location=None, remember=False, overwrite=False,
977
939
            revision=None, verbose=False,
978
 
            directory=None, local=False):
 
940
            directory=None, local=False,
 
941
            show_base=False):
979
942
        # FIXME: too much stuff is in the command class
980
943
        revision_id = None
981
944
        mergeable = None
984
947
        try:
985
948
            tree_to = WorkingTree.open_containing(directory)[0]
986
949
            branch_to = tree_to.branch
 
950
            self.add_cleanup(tree_to.lock_write().unlock)
987
951
        except errors.NoWorkingTree:
988
952
            tree_to = None
989
953
            branch_to = Branch.open_containing(directory)[0]
990
 
        
 
954
            self.add_cleanup(branch_to.lock_write().unlock)
 
955
 
 
956
        if tree_to is None and show_base:
 
957
            raise errors.BzrCommandError("Need working tree for --show-base.")
 
958
 
991
959
        if local and not branch_to.get_bound_location():
992
960
            raise errors.LocalRequiresBoundBranch()
993
961
 
1023
991
        else:
1024
992
            branch_from = Branch.open(location,
1025
993
                possible_transports=possible_transports)
 
994
            self.add_cleanup(branch_from.lock_read().unlock)
1026
995
 
1027
996
            if branch_to.get_parent() is None or remember:
1028
997
                branch_to.set_parent(branch_from.base)
1029
998
 
1030
 
        if branch_from is not branch_to:
1031
 
            branch_from.lock_read()
1032
 
            self.add_cleanup(branch_from.unlock)
1033
999
        if revision is not None:
1034
1000
            revision_id = revision.as_revision_id(branch_from)
1035
1001
 
1036
 
        branch_to.lock_write()
1037
 
        self.add_cleanup(branch_to.unlock)
1038
1002
        if tree_to is not None:
1039
1003
            view_info = _get_view_info_for_change_reporter(tree_to)
1040
1004
            change_reporter = delta._ChangeReporter(
1042
1006
                view_info=view_info)
1043
1007
            result = tree_to.pull(
1044
1008
                branch_from, overwrite, revision_id, change_reporter,
1045
 
                possible_transports=possible_transports, local=local)
 
1009
                possible_transports=possible_transports, local=local,
 
1010
                show_base=show_base)
1046
1011
        else:
1047
1012
            result = branch_to.pull(
1048
1013
                branch_from, overwrite, revision_id, local=local)
1055
1020
 
1056
1021
 
1057
1022
class cmd_push(Command):
1058
 
    """Update a mirror of this branch.
 
1023
    __doc__ = """Update a mirror of this branch.
1059
1024
 
1060
1025
    The target branch will not have its working tree populated because this
1061
1026
    is both expensive, and is not supported on remote file systems.
1085
1050
        Option('create-prefix',
1086
1051
               help='Create the path leading up to the branch '
1087
1052
                    'if it does not already exist.'),
1088
 
        Option('directory',
 
1053
        custom_help('directory',
1089
1054
            help='Branch to push from, '
1090
 
                 'rather than the one containing the working directory.',
1091
 
            short_name='d',
1092
 
            type=unicode,
1093
 
            ),
 
1055
                 'rather than the one containing the working directory.'),
1094
1056
        Option('use-existing-dir',
1095
1057
               help='By default push will fail if the target'
1096
1058
                    ' directory exists, but does not already'
1107
1069
        Option('strict',
1108
1070
               help='Refuse to push if there are uncommitted changes in'
1109
1071
               ' the working tree, --no-strict disables the check.'),
 
1072
        Option('no-tree',
 
1073
               help="Don't populate the working tree, even for protocols"
 
1074
               " that support it."),
1110
1075
        ]
1111
1076
    takes_args = ['location?']
1112
1077
    encoding_type = 'replace'
1114
1079
    def run(self, location=None, remember=False, overwrite=False,
1115
1080
        create_prefix=False, verbose=False, revision=None,
1116
1081
        use_existing_dir=False, directory=None, stacked_on=None,
1117
 
        stacked=False, strict=None):
 
1082
        stacked=False, strict=None, no_tree=False):
1118
1083
        from bzrlib.push import _show_push_branch
1119
1084
 
1120
1085
        if directory is None:
1122
1087
        # Get the source branch
1123
1088
        (tree, br_from,
1124
1089
         _unused) = bzrdir.BzrDir.open_containing_tree_or_branch(directory)
1125
 
        if strict is None:
1126
 
            strict = br_from.get_config().get_user_option_as_bool('push_strict')
1127
 
        if strict is None: strict = True # default value
1128
1090
        # Get the tip's revision_id
1129
1091
        revision = _get_one_revision('push', revision)
1130
1092
        if revision is not None:
1131
1093
            revision_id = revision.in_history(br_from).rev_id
1132
1094
        else:
1133
1095
            revision_id = None
1134
 
        if strict and tree is not None and revision_id is None:
1135
 
            if (tree.has_changes()):
1136
 
                raise errors.UncommittedChanges(
1137
 
                    tree, more='Use --no-strict to force the push.')
1138
 
            if tree.last_revision() != tree.branch.last_revision():
1139
 
                # The tree has lost sync with its branch, there is little
1140
 
                # chance that the user is aware of it but he can still force
1141
 
                # the push with --no-strict
1142
 
                raise errors.OutOfDateTree(
1143
 
                    tree, more='Use --no-strict to force the push.')
1144
 
 
 
1096
        if tree is not None and revision_id is None:
 
1097
            tree.check_changed_or_out_of_date(
 
1098
                strict, 'push_strict',
 
1099
                more_error='Use --no-strict to force the push.',
 
1100
                more_warning='Uncommitted changes will not be pushed.')
1145
1101
        # Get the stacked_on branch, if any
1146
1102
        if stacked_on is not None:
1147
1103
            stacked_on = urlutils.normalize_url(stacked_on)
1175
1131
        _show_push_branch(br_from, revision_id, location, self.outf,
1176
1132
            verbose=verbose, overwrite=overwrite, remember=remember,
1177
1133
            stacked_on=stacked_on, create_prefix=create_prefix,
1178
 
            use_existing_dir=use_existing_dir)
 
1134
            use_existing_dir=use_existing_dir, no_tree=no_tree)
1179
1135
 
1180
1136
 
1181
1137
class cmd_branch(Command):
1182
 
    """Create a new branch that is a copy of an existing branch.
 
1138
    __doc__ = """Create a new branch that is a copy of an existing branch.
1183
1139
 
1184
1140
    If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
1185
1141
    be used.  In other words, "branch ../foo/bar" will attempt to create ./bar.
1194
1150
 
1195
1151
    _see_also = ['checkout']
1196
1152
    takes_args = ['from_location', 'to_location?']
1197
 
    takes_options = ['revision', Option('hardlink',
1198
 
        help='Hard-link working tree files where possible.'),
 
1153
    takes_options = ['revision',
 
1154
        Option('hardlink', help='Hard-link working tree files where possible.'),
 
1155
        Option('files-from', type=str,
 
1156
               help="Get file contents from this tree."),
1199
1157
        Option('no-tree',
1200
1158
            help="Create a branch without a working-tree."),
1201
1159
        Option('switch',
1219
1177
 
1220
1178
    def run(self, from_location, to_location=None, revision=None,
1221
1179
            hardlink=False, stacked=False, standalone=False, no_tree=False,
1222
 
            use_existing_dir=False, switch=False, bind=False):
 
1180
            use_existing_dir=False, switch=False, bind=False,
 
1181
            files_from=None):
1223
1182
        from bzrlib import switch as _mod_switch
1224
1183
        from bzrlib.tag import _merge_tags_if_possible
1225
1184
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
1226
1185
            from_location)
 
1186
        if not (hardlink or files_from):
 
1187
            # accelerator_tree is usually slower because you have to read N
 
1188
            # files (no readahead, lots of seeks, etc), but allow the user to
 
1189
            # explicitly request it
 
1190
            accelerator_tree = None
 
1191
        if files_from is not None and files_from != from_location:
 
1192
            accelerator_tree = WorkingTree.open(files_from)
1227
1193
        revision = _get_one_revision('branch', revision)
1228
 
        br_from.lock_read()
1229
 
        self.add_cleanup(br_from.unlock)
 
1194
        self.add_cleanup(br_from.lock_read().unlock)
1230
1195
        if revision is not None:
1231
1196
            revision_id = revision.as_revision_id(br_from)
1232
1197
        else:
1292
1257
 
1293
1258
 
1294
1259
class cmd_checkout(Command):
1295
 
    """Create a new checkout of an existing branch.
 
1260
    __doc__ = """Create a new checkout of an existing branch.
1296
1261
 
1297
1262
    If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree for
1298
1263
    the branch found in '.'. This is useful if you have removed the working tree
1337
1302
            to_location = branch_location
1338
1303
        accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch(
1339
1304
            branch_location)
 
1305
        if not (hardlink or files_from):
 
1306
            # accelerator_tree is usually slower because you have to read N
 
1307
            # files (no readahead, lots of seeks, etc), but allow the user to
 
1308
            # explicitly request it
 
1309
            accelerator_tree = None
1340
1310
        revision = _get_one_revision('checkout', revision)
1341
 
        if files_from is not None:
 
1311
        if files_from is not None and files_from != branch_location:
1342
1312
            accelerator_tree = WorkingTree.open(files_from)
1343
1313
        if revision is not None:
1344
1314
            revision_id = revision.as_revision_id(source)
1361
1331
 
1362
1332
 
1363
1333
class cmd_renames(Command):
1364
 
    """Show list of renamed files.
 
1334
    __doc__ = """Show list of renamed files.
1365
1335
    """
1366
1336
    # TODO: Option to show renames between two historical versions.
1367
1337
 
1372
1342
    @display_command
1373
1343
    def run(self, dir=u'.'):
1374
1344
        tree = WorkingTree.open_containing(dir)[0]
1375
 
        tree.lock_read()
1376
 
        self.add_cleanup(tree.unlock)
 
1345
        self.add_cleanup(tree.lock_read().unlock)
1377
1346
        new_inv = tree.inventory
1378
1347
        old_tree = tree.basis_tree()
1379
 
        old_tree.lock_read()
1380
 
        self.add_cleanup(old_tree.unlock)
 
1348
        self.add_cleanup(old_tree.lock_read().unlock)
1381
1349
        old_inv = old_tree.inventory
1382
1350
        renames = []
1383
1351
        iterator = tree.iter_changes(old_tree, include_unchanged=True)
1393
1361
 
1394
1362
 
1395
1363
class cmd_update(Command):
1396
 
    """Update a tree to have the latest code committed to its branch.
 
1364
    __doc__ = """Update a tree to have the latest code committed to its branch.
1397
1365
 
1398
1366
    This will perform a merge into the working tree, and may generate
1399
1367
    conflicts. If you have any local changes, you will still
1402
1370
    If you want to discard your local changes, you can just do a
1403
1371
    'bzr revert' instead of 'bzr commit' after the update.
1404
1372
 
 
1373
    If you want to restore a file that has been removed locally, use
 
1374
    'bzr revert' instead of 'bzr update'.
 
1375
 
1405
1376
    If the tree's branch is bound to a master branch, it will also update
1406
1377
    the branch from the master.
1407
1378
    """
1408
1379
 
1409
1380
    _see_also = ['pull', 'working-trees', 'status-flags']
1410
1381
    takes_args = ['dir?']
1411
 
    takes_options = ['revision']
 
1382
    takes_options = ['revision',
 
1383
                     Option('show-base',
 
1384
                            help="Show base revision text in conflicts."),
 
1385
                     ]
1412
1386
    aliases = ['up']
1413
1387
 
1414
 
    def run(self, dir='.', revision=None):
 
1388
    def run(self, dir='.', revision=None, show_base=None):
1415
1389
        if revision is not None and len(revision) != 1:
1416
1390
            raise errors.BzrCommandError(
1417
1391
                        "bzr update --revision takes exactly one revision")
1421
1395
        master = branch.get_master_branch(
1422
1396
            possible_transports=possible_transports)
1423
1397
        if master is not None:
1424
 
            tree.lock_write()
1425
1398
            branch_location = master.base
 
1399
            tree.lock_write()
1426
1400
        else:
 
1401
            branch_location = tree.branch.base
1427
1402
            tree.lock_tree_write()
1428
 
            branch_location = tree.branch.base
1429
1403
        self.add_cleanup(tree.unlock)
1430
1404
        # get rid of the final '/' and be ready for display
1431
1405
        branch_location = urlutils.unescape_for_display(
1444
1418
        else:
1445
1419
            revision_id = branch.last_revision()
1446
1420
        if revision_id == _mod_revision.ensure_null(tree.last_revision()):
1447
 
            revno = branch.revision_id_to_revno(revision_id)
1448
 
            note("Tree is up to date at revision %d of branch %s" %
1449
 
                (revno, branch_location))
 
1421
            revno = branch.revision_id_to_dotted_revno(revision_id)
 
1422
            note("Tree is up to date at revision %s of branch %s" %
 
1423
                ('.'.join(map(str, revno)), branch_location))
1450
1424
            return 0
1451
1425
        view_info = _get_view_info_for_change_reporter(tree)
1452
1426
        change_reporter = delta._ChangeReporter(
1457
1431
                change_reporter,
1458
1432
                possible_transports=possible_transports,
1459
1433
                revision=revision_id,
1460
 
                old_tip=old_tip)
 
1434
                old_tip=old_tip,
 
1435
                show_base=show_base)
1461
1436
        except errors.NoSuchRevision, e:
1462
1437
            raise errors.BzrCommandError(
1463
1438
                                  "branch has no revision %s\n"
1464
1439
                                  "bzr update --revision only works"
1465
1440
                                  " for a revision in the branch history"
1466
1441
                                  % (e.revision))
1467
 
        revno = tree.branch.revision_id_to_revno(
 
1442
        revno = tree.branch.revision_id_to_dotted_revno(
1468
1443
            _mod_revision.ensure_null(tree.last_revision()))
1469
 
        note('Updated to revision %d of branch %s' %
1470
 
             (revno, branch_location))
1471
 
        if tree.get_parent_ids()[1:] != existing_pending_merges:
 
1444
        note('Updated to revision %s of branch %s' %
 
1445
             ('.'.join(map(str, revno)), branch_location))
 
1446
        parent_ids = tree.get_parent_ids()
 
1447
        if parent_ids[1:] and parent_ids[1:] != existing_pending_merges:
1472
1448
            note('Your local commits will now show as pending merges with '
1473
1449
                 "'bzr status', and can be committed with 'bzr commit'.")
1474
1450
        if conflicts != 0:
1478
1454
 
1479
1455
 
1480
1456
class cmd_info(Command):
1481
 
    """Show information about a working tree, branch or repository.
 
1457
    __doc__ = """Show information about a working tree, branch or repository.
1482
1458
 
1483
1459
    This command will show all known locations and formats associated to the
1484
1460
    tree, branch or repository.
1522
1498
 
1523
1499
 
1524
1500
class cmd_remove(Command):
1525
 
    """Remove files or directories.
 
1501
    __doc__ = """Remove files or directories.
1526
1502
 
1527
 
    This makes bzr stop tracking changes to the specified files. bzr will delete
1528
 
    them if they can easily be recovered using revert. If no options or
1529
 
    parameters are given bzr will scan for files that are being tracked by bzr
1530
 
    but missing in your tree and stop tracking them for you.
 
1503
    This makes Bazaar stop tracking changes to the specified files. Bazaar will
 
1504
    delete them if they can easily be recovered using revert otherwise they
 
1505
    will be backed up (adding an extention of the form .~#~). If no options or
 
1506
    parameters are given Bazaar will scan for files that are being tracked by
 
1507
    Bazaar but missing in your tree and stop tracking them for you.
1531
1508
    """
1532
1509
    takes_args = ['file*']
1533
1510
    takes_options = ['verbose',
1535
1512
        RegistryOption.from_kwargs('file-deletion-strategy',
1536
1513
            'The file deletion mode to be used.',
1537
1514
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1538
 
            safe='Only delete files if they can be'
1539
 
                 ' safely recovered (default).',
 
1515
            safe='Backup changed files (default).',
1540
1516
            keep='Delete from bzr but leave the working copy.',
 
1517
            no_backup='Don\'t backup changed files.',
1541
1518
            force='Delete all the specified files, even if they can not be '
1542
 
                'recovered and even if they are non-empty directories.')]
 
1519
                'recovered and even if they are non-empty directories. '
 
1520
                '(deprecated, use no-backup)')]
1543
1521
    aliases = ['rm', 'del']
1544
1522
    encoding_type = 'replace'
1545
1523
 
1546
1524
    def run(self, file_list, verbose=False, new=False,
1547
1525
        file_deletion_strategy='safe'):
1548
 
        tree, file_list = tree_files(file_list)
 
1526
        if file_deletion_strategy == 'force':
 
1527
            note("(The --force option is deprecated, rather use --no-backup "
 
1528
                "in future.)")
 
1529
            file_deletion_strategy = 'no-backup'
 
1530
 
 
1531
        tree, file_list = WorkingTree.open_containing_paths(file_list)
1549
1532
 
1550
1533
        if file_list is not None:
1551
1534
            file_list = [f for f in file_list]
1552
1535
 
1553
 
        tree.lock_write()
1554
 
        self.add_cleanup(tree.unlock)
 
1536
        self.add_cleanup(tree.lock_write().unlock)
1555
1537
        # Heuristics should probably all move into tree.remove_smart or
1556
1538
        # some such?
1557
1539
        if new:
1572
1554
            file_deletion_strategy = 'keep'
1573
1555
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
1574
1556
            keep_files=file_deletion_strategy=='keep',
1575
 
            force=file_deletion_strategy=='force')
 
1557
            force=(file_deletion_strategy=='no-backup'))
1576
1558
 
1577
1559
 
1578
1560
class cmd_file_id(Command):
1579
 
    """Print file_id of a particular file or directory.
 
1561
    __doc__ = """Print file_id of a particular file or directory.
1580
1562
 
1581
1563
    The file_id is assigned when the file is first added and remains the
1582
1564
    same through all revisions where the file exists, even when it is
1598
1580
 
1599
1581
 
1600
1582
class cmd_file_path(Command):
1601
 
    """Print path of file_ids to a file or directory.
 
1583
    __doc__ = """Print path of file_ids to a file or directory.
1602
1584
 
1603
1585
    This prints one line for each directory down to the target,
1604
1586
    starting at the branch root.
1620
1602
 
1621
1603
 
1622
1604
class cmd_reconcile(Command):
1623
 
    """Reconcile bzr metadata in a branch.
 
1605
    __doc__ = """Reconcile bzr metadata in a branch.
1624
1606
 
1625
1607
    This can correct data mismatches that may have been caused by
1626
1608
    previous ghost operations or bzr upgrades. You should only
1640
1622
 
1641
1623
    _see_also = ['check']
1642
1624
    takes_args = ['branch?']
 
1625
    takes_options = [
 
1626
        Option('canonicalize-chks',
 
1627
               help='Make sure CHKs are in canonical form (repairs '
 
1628
                    'bug 522637).',
 
1629
               hidden=True),
 
1630
        ]
1643
1631
 
1644
 
    def run(self, branch="."):
 
1632
    def run(self, branch=".", canonicalize_chks=False):
1645
1633
        from bzrlib.reconcile import reconcile
1646
1634
        dir = bzrdir.BzrDir.open(branch)
1647
 
        reconcile(dir)
 
1635
        reconcile(dir, canonicalize_chks=canonicalize_chks)
1648
1636
 
1649
1637
 
1650
1638
class cmd_revision_history(Command):
1651
 
    """Display the list of revision ids on a branch."""
 
1639
    __doc__ = """Display the list of revision ids on a branch."""
1652
1640
 
1653
1641
    _see_also = ['log']
1654
1642
    takes_args = ['location?']
1664
1652
 
1665
1653
 
1666
1654
class cmd_ancestry(Command):
1667
 
    """List all revisions merged into this branch."""
 
1655
    __doc__ = """List all revisions merged into this branch."""
1668
1656
 
1669
1657
    _see_also = ['log', 'revision-history']
1670
1658
    takes_args = ['location?']
1689
1677
 
1690
1678
 
1691
1679
class cmd_init(Command):
1692
 
    """Make a directory into a versioned branch.
 
1680
    __doc__ = """Make a directory into a versioned branch.
1693
1681
 
1694
1682
    Use this to create an empty branch, or before importing an
1695
1683
    existing project.
1727
1715
                ),
1728
1716
         Option('append-revisions-only',
1729
1717
                help='Never change revnos or the existing log.'
1730
 
                '  Append revisions to it only.')
 
1718
                '  Append revisions to it only.'),
 
1719
         Option('no-tree',
 
1720
                'Create a branch without a working tree.')
1731
1721
         ]
1732
1722
    def run(self, location=None, format=None, append_revisions_only=False,
1733
 
            create_prefix=False):
 
1723
            create_prefix=False, no_tree=False):
1734
1724
        if format is None:
1735
1725
            format = bzrdir.format_registry.make_bzrdir('default')
1736
1726
        if location is None:
1759
1749
        except errors.NotBranchError:
1760
1750
            # really a NotBzrDir error...
1761
1751
            create_branch = bzrdir.BzrDir.create_branch_convenience
 
1752
            if no_tree:
 
1753
                force_new_tree = False
 
1754
            else:
 
1755
                force_new_tree = None
1762
1756
            branch = create_branch(to_transport.base, format=format,
1763
 
                                   possible_transports=[to_transport])
 
1757
                                   possible_transports=[to_transport],
 
1758
                                   force_new_tree=force_new_tree)
1764
1759
            a_bzrdir = branch.bzrdir
1765
1760
        else:
1766
1761
            from bzrlib.transport.local import LocalTransport
1770
1765
                        raise errors.BranchExistsWithoutWorkingTree(location)
1771
1766
                raise errors.AlreadyBranchError(location)
1772
1767
            branch = a_bzrdir.create_branch()
1773
 
            a_bzrdir.create_workingtree()
 
1768
            if not no_tree:
 
1769
                a_bzrdir.create_workingtree()
1774
1770
        if append_revisions_only:
1775
1771
            try:
1776
1772
                branch.set_append_revisions_only(True)
1798
1794
 
1799
1795
 
1800
1796
class cmd_init_repository(Command):
1801
 
    """Create a shared repository for branches to share storage space.
 
1797
    __doc__ = """Create a shared repository for branches to share storage space.
1802
1798
 
1803
1799
    New branches created under the repository directory will store their
1804
1800
    revisions in the repository, not in the branch directory.  For branches
1858
1854
 
1859
1855
 
1860
1856
class cmd_diff(Command):
1861
 
    """Show differences in the working tree, between revisions or branches.
 
1857
    __doc__ = """Show differences in the working tree, between revisions or branches.
1862
1858
 
1863
1859
    If no arguments are given, all changes for the current tree are listed.
1864
1860
    If files are given, only the changes in those files are listed.
1870
1866
    "bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1871
1867
    produces patches suitable for "patch -p1".
1872
1868
 
 
1869
    Note that when using the -r argument with a range of revisions, the
 
1870
    differences are computed between the two specified revisions.  That
 
1871
    is, the command does not show the changes introduced by the first 
 
1872
    revision in the range.  This differs from the interpretation of 
 
1873
    revision ranges used by "bzr log" which includes the first revision
 
1874
    in the range.
 
1875
 
1873
1876
    :Exit values:
1874
1877
        1 - changed
1875
1878
        2 - unrepresentable changes
1893
1896
 
1894
1897
            bzr diff -r1..3 xxx
1895
1898
 
1896
 
        To see the changes introduced in revision X::
 
1899
        The changes introduced by revision 2 (equivalent to -r1..2)::
 
1900
 
 
1901
            bzr diff -c2
 
1902
 
 
1903
        To see the changes introduced by revision X::
1897
1904
        
1898
1905
            bzr diff -cX
1899
1906
 
1903
1910
 
1904
1911
            bzr diff -r<chosen_parent>..X
1905
1912
 
1906
 
        The changes introduced by revision 2 (equivalent to -r1..2)::
 
1913
        The changes between the current revision and the previous revision
 
1914
        (equivalent to -c-1 and -r-2..-1)
1907
1915
 
1908
 
            bzr diff -c2
 
1916
            bzr diff -r-2..
1909
1917
 
1910
1918
        Show just the differences for file NEWS::
1911
1919
 
1926
1934
        Same as 'bzr diff' but prefix paths with old/ and new/::
1927
1935
 
1928
1936
            bzr diff --prefix old/:new/
 
1937
            
 
1938
        Show the differences using a custom diff program with options::
 
1939
        
 
1940
            bzr diff --using /usr/bin/diff --diff-options -wu
1929
1941
    """
1930
1942
    _see_also = ['status']
1931
1943
    takes_args = ['file*']
1950
1962
            help='Use this command to compare files.',
1951
1963
            type=unicode,
1952
1964
            ),
 
1965
        RegistryOption('format',
 
1966
            help='Diff format to use.',
 
1967
            lazy_registry=('bzrlib.diff', 'format_registry'),
 
1968
            value_switches=False, title='Diff format'),
1953
1969
        ]
1954
1970
    aliases = ['di', 'dif']
1955
1971
    encoding_type = 'exact'
1956
1972
 
1957
1973
    @display_command
1958
1974
    def run(self, revision=None, file_list=None, diff_options=None,
1959
 
            prefix=None, old=None, new=None, using=None):
1960
 
        from bzrlib.diff import get_trees_and_branches_to_diff, show_diff_trees
 
1975
            prefix=None, old=None, new=None, using=None, format=None):
 
1976
        from bzrlib.diff import (get_trees_and_branches_to_diff_locked,
 
1977
            show_diff_trees)
1961
1978
 
1962
1979
        if (prefix is None) or (prefix == '0'):
1963
1980
            # diff -p0 format
1977
1994
            raise errors.BzrCommandError('bzr diff --revision takes exactly'
1978
1995
                                         ' one or two revision specifiers')
1979
1996
 
 
1997
        if using is not None and format is not None:
 
1998
            raise errors.BzrCommandError('--using and --format are mutually '
 
1999
                'exclusive.')
 
2000
 
1980
2001
        (old_tree, new_tree,
1981
2002
         old_branch, new_branch,
1982
 
         specific_files, extra_trees) = get_trees_and_branches_to_diff(
1983
 
            file_list, revision, old, new, apply_view=True)
 
2003
         specific_files, extra_trees) = get_trees_and_branches_to_diff_locked(
 
2004
            file_list, revision, old, new, self.add_cleanup, apply_view=True)
 
2005
        # GNU diff on Windows uses ANSI encoding for filenames
 
2006
        path_encoding = osutils.get_diff_header_encoding()
1984
2007
        return show_diff_trees(old_tree, new_tree, sys.stdout,
1985
2008
                               specific_files=specific_files,
1986
2009
                               external_diff_options=diff_options,
1987
2010
                               old_label=old_label, new_label=new_label,
1988
 
                               extra_trees=extra_trees, using=using)
 
2011
                               extra_trees=extra_trees,
 
2012
                               path_encoding=path_encoding,
 
2013
                               using=using,
 
2014
                               format_cls=format)
1989
2015
 
1990
2016
 
1991
2017
class cmd_deleted(Command):
1992
 
    """List files deleted in the working tree.
 
2018
    __doc__ = """List files deleted in the working tree.
1993
2019
    """
1994
2020
    # TODO: Show files deleted since a previous revision, or
1995
2021
    # between two revisions.
1998
2024
    # level of effort but possibly much less IO.  (Or possibly not,
1999
2025
    # if the directories are very large...)
2000
2026
    _see_also = ['status', 'ls']
2001
 
    takes_options = ['show-ids']
 
2027
    takes_options = ['directory', 'show-ids']
2002
2028
 
2003
2029
    @display_command
2004
 
    def run(self, show_ids=False):
2005
 
        tree = WorkingTree.open_containing(u'.')[0]
2006
 
        tree.lock_read()
2007
 
        self.add_cleanup(tree.unlock)
 
2030
    def run(self, show_ids=False, directory=u'.'):
 
2031
        tree = WorkingTree.open_containing(directory)[0]
 
2032
        self.add_cleanup(tree.lock_read().unlock)
2008
2033
        old = tree.basis_tree()
2009
 
        old.lock_read()
2010
 
        self.add_cleanup(old.unlock)
 
2034
        self.add_cleanup(old.lock_read().unlock)
2011
2035
        for path, ie in old.inventory.iter_entries():
2012
2036
            if not tree.has_id(ie.file_id):
2013
2037
                self.outf.write(path)
2018
2042
 
2019
2043
 
2020
2044
class cmd_modified(Command):
2021
 
    """List files modified in working tree.
 
2045
    __doc__ = """List files modified in working tree.
2022
2046
    """
2023
2047
 
2024
2048
    hidden = True
2025
2049
    _see_also = ['status', 'ls']
2026
 
    takes_options = [
2027
 
            Option('null',
2028
 
                   help='Write an ascii NUL (\\0) separator '
2029
 
                   'between files rather than a newline.')
2030
 
            ]
 
2050
    takes_options = ['directory', 'null']
2031
2051
 
2032
2052
    @display_command
2033
 
    def run(self, null=False):
2034
 
        tree = WorkingTree.open_containing(u'.')[0]
 
2053
    def run(self, null=False, directory=u'.'):
 
2054
        tree = WorkingTree.open_containing(directory)[0]
2035
2055
        td = tree.changes_from(tree.basis_tree())
2036
2056
        for path, id, kind, text_modified, meta_modified in td.modified:
2037
2057
            if null:
2041
2061
 
2042
2062
 
2043
2063
class cmd_added(Command):
2044
 
    """List files added in working tree.
 
2064
    __doc__ = """List files added in working tree.
2045
2065
    """
2046
2066
 
2047
2067
    hidden = True
2048
2068
    _see_also = ['status', 'ls']
2049
 
    takes_options = [
2050
 
            Option('null',
2051
 
                   help='Write an ascii NUL (\\0) separator '
2052
 
                   'between files rather than a newline.')
2053
 
            ]
 
2069
    takes_options = ['directory', 'null']
2054
2070
 
2055
2071
    @display_command
2056
 
    def run(self, null=False):
2057
 
        wt = WorkingTree.open_containing(u'.')[0]
2058
 
        wt.lock_read()
2059
 
        self.add_cleanup(wt.unlock)
 
2072
    def run(self, null=False, directory=u'.'):
 
2073
        wt = WorkingTree.open_containing(directory)[0]
 
2074
        self.add_cleanup(wt.lock_read().unlock)
2060
2075
        basis = wt.basis_tree()
2061
 
        basis.lock_read()
2062
 
        self.add_cleanup(basis.unlock)
 
2076
        self.add_cleanup(basis.lock_read().unlock)
2063
2077
        basis_inv = basis.inventory
2064
2078
        inv = wt.inventory
2065
2079
        for file_id in inv:
2068
2082
            if inv.is_root(file_id) and len(basis_inv) == 0:
2069
2083
                continue
2070
2084
            path = inv.id2path(file_id)
2071
 
            if not os.access(osutils.abspath(path), os.F_OK):
 
2085
            if not os.access(osutils.pathjoin(wt.basedir, path), os.F_OK):
2072
2086
                continue
2073
2087
            if null:
2074
2088
                self.outf.write(path + '\0')
2077
2091
 
2078
2092
 
2079
2093
class cmd_root(Command):
2080
 
    """Show the tree root directory.
 
2094
    __doc__ = """Show the tree root directory.
2081
2095
 
2082
2096
    The root is the nearest enclosing directory with a .bzr control
2083
2097
    directory."""
2107
2121
 
2108
2122
 
2109
2123
class cmd_log(Command):
2110
 
    """Show historical log for a branch or subset of a branch.
 
2124
    __doc__ = """Show historical log for a branch or subset of a branch.
2111
2125
 
2112
2126
    log is bzr's default tool for exploring the history of a branch.
2113
2127
    The branch to use is taken from the first parameter. If no parameters
2274
2288
                   help='Show just the specified revision.'
2275
2289
                   ' See also "help revisionspec".'),
2276
2290
            'log-format',
 
2291
            RegistryOption('authors',
 
2292
                'What names to list as authors - first, all or committer.',
 
2293
                title='Authors',
 
2294
                lazy_registry=('bzrlib.log', 'author_list_registry'),
 
2295
            ),
2277
2296
            Option('levels',
2278
2297
                   short_name='n',
2279
2298
                   help='Number of levels to display - 0 for all, 1 for flat.',
2294
2313
                   help='Show changes made in each revision as a patch.'),
2295
2314
            Option('include-merges',
2296
2315
                   help='Show merged revisions like --levels 0 does.'),
 
2316
            Option('exclude-common-ancestry',
 
2317
                   help='Display only the revisions that are not part'
 
2318
                   ' of both ancestries (require -rX..Y)'
 
2319
                   )
2297
2320
            ]
2298
2321
    encoding_type = 'replace'
2299
2322
 
2309
2332
            message=None,
2310
2333
            limit=None,
2311
2334
            show_diff=False,
2312
 
            include_merges=False):
 
2335
            include_merges=False,
 
2336
            authors=None,
 
2337
            exclude_common_ancestry=False,
 
2338
            ):
2313
2339
        from bzrlib.log import (
2314
2340
            Logger,
2315
2341
            make_log_request_dict,
2316
2342
            _get_info_for_log_files,
2317
2343
            )
2318
2344
        direction = (forward and 'forward') or 'reverse'
 
2345
        if (exclude_common_ancestry
 
2346
            and (revision is None or len(revision) != 2)):
 
2347
            raise errors.BzrCommandError(
 
2348
                '--exclude-common-ancestry requires -r with two revisions')
2319
2349
        if include_merges:
2320
2350
            if levels is None:
2321
2351
                levels = 0
2337
2367
        if file_list:
2338
2368
            # find the file ids to log and check for directory filtering
2339
2369
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(
2340
 
                revision, file_list)
2341
 
            self.add_cleanup(b.unlock)
 
2370
                revision, file_list, self.add_cleanup)
2342
2371
            for relpath, file_id, kind in file_info_list:
2343
2372
                if file_id is None:
2344
2373
                    raise errors.BzrCommandError(
2362
2391
                location = '.'
2363
2392
            dir, relpath = bzrdir.BzrDir.open_containing(location)
2364
2393
            b = dir.open_branch()
2365
 
            b.lock_read()
2366
 
            self.add_cleanup(b.unlock)
 
2394
            self.add_cleanup(b.lock_read().unlock)
2367
2395
            rev1, rev2 = _get_revision_range(revision, b, self.name())
2368
2396
 
2369
2397
        # Decide on the type of delta & diff filtering to use
2389
2417
                        show_timezone=timezone,
2390
2418
                        delta_format=get_verbosity_level(),
2391
2419
                        levels=levels,
2392
 
                        show_advice=levels is None)
 
2420
                        show_advice=levels is None,
 
2421
                        author_list_handler=authors)
2393
2422
 
2394
2423
        # Choose the algorithm for doing the logging. It's annoying
2395
2424
        # having multiple code paths like this but necessary until
2414
2443
            direction=direction, specific_fileids=file_ids,
2415
2444
            start_revision=rev1, end_revision=rev2, limit=limit,
2416
2445
            message_search=message, delta_type=delta_type,
2417
 
            diff_type=diff_type, _match_using_deltas=match_using_deltas)
 
2446
            diff_type=diff_type, _match_using_deltas=match_using_deltas,
 
2447
            exclude_common_ancestry=exclude_common_ancestry,
 
2448
            )
2418
2449
        Logger(b, rqst).show(lf)
2419
2450
 
2420
2451
 
2478
2509
 
2479
2510
 
2480
2511
class cmd_touching_revisions(Command):
2481
 
    """Return revision-ids which affected a particular file.
 
2512
    __doc__ = """Return revision-ids which affected a particular file.
2482
2513
 
2483
2514
    A more user-friendly interface is "bzr log FILE".
2484
2515
    """
2491
2522
        tree, relpath = WorkingTree.open_containing(filename)
2492
2523
        file_id = tree.path2id(relpath)
2493
2524
        b = tree.branch
2494
 
        b.lock_read()
2495
 
        self.add_cleanup(b.unlock)
 
2525
        self.add_cleanup(b.lock_read().unlock)
2496
2526
        touching_revs = log.find_touching_revisions(b, file_id)
2497
2527
        for revno, revision_id, what in touching_revs:
2498
2528
            self.outf.write("%6d %s\n" % (revno, what))
2499
2529
 
2500
2530
 
2501
2531
class cmd_ls(Command):
2502
 
    """List files in a tree.
 
2532
    __doc__ = """List files in a tree.
2503
2533
    """
2504
2534
 
2505
2535
    _see_also = ['status', 'cat']
2511
2541
                   help='Recurse into subdirectories.'),
2512
2542
            Option('from-root',
2513
2543
                   help='Print paths relative to the root of the branch.'),
2514
 
            Option('unknown', help='Print unknown files.'),
 
2544
            Option('unknown', short_name='u',
 
2545
                help='Print unknown files.'),
2515
2546
            Option('versioned', help='Print versioned files.',
2516
2547
                   short_name='V'),
2517
 
            Option('ignored', help='Print ignored files.'),
2518
 
            Option('null',
2519
 
                   help='Write an ascii NUL (\\0) separator '
2520
 
                   'between files rather than a newline.'),
2521
 
            Option('kind',
 
2548
            Option('ignored', short_name='i',
 
2549
                help='Print ignored files.'),
 
2550
            Option('kind', short_name='k',
2522
2551
                   help='List entries of a particular kind: file, directory, symlink.',
2523
2552
                   type=unicode),
 
2553
            'null',
2524
2554
            'show-ids',
 
2555
            'directory',
2525
2556
            ]
2526
2557
    @display_command
2527
2558
    def run(self, revision=None, verbose=False,
2528
2559
            recursive=False, from_root=False,
2529
2560
            unknown=False, versioned=False, ignored=False,
2530
 
            null=False, kind=None, show_ids=False, path=None):
 
2561
            null=False, kind=None, show_ids=False, path=None, directory=None):
2531
2562
 
2532
2563
        if kind and kind not in ('file', 'directory', 'symlink'):
2533
2564
            raise errors.BzrCommandError('invalid kind specified')
2545
2576
                raise errors.BzrCommandError('cannot specify both --from-root'
2546
2577
                                             ' and PATH')
2547
2578
            fs_path = path
2548
 
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
2549
 
            fs_path)
 
2579
        tree, branch, relpath = \
 
2580
            _open_directory_or_containing_tree_or_branch(fs_path, directory)
2550
2581
 
2551
2582
        # Calculate the prefix to use
2552
2583
        prefix = None
2567
2598
                view_str = views.view_display_str(view_files)
2568
2599
                note("Ignoring files outside view. View is %s" % view_str)
2569
2600
 
2570
 
        tree.lock_read()
2571
 
        self.add_cleanup(tree.unlock)
 
2601
        self.add_cleanup(tree.lock_read().unlock)
2572
2602
        for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
2573
2603
            from_dir=relpath, recursive=recursive):
2574
2604
            # Apply additional masking
2616
2646
 
2617
2647
 
2618
2648
class cmd_unknowns(Command):
2619
 
    """List unknown files.
 
2649
    __doc__ = """List unknown files.
2620
2650
    """
2621
2651
 
2622
2652
    hidden = True
2623
2653
    _see_also = ['ls']
 
2654
    takes_options = ['directory']
2624
2655
 
2625
2656
    @display_command
2626
 
    def run(self):
2627
 
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
 
2657
    def run(self, directory=u'.'):
 
2658
        for f in WorkingTree.open_containing(directory)[0].unknowns():
2628
2659
            self.outf.write(osutils.quotefn(f) + '\n')
2629
2660
 
2630
2661
 
2631
2662
class cmd_ignore(Command):
2632
 
    """Ignore specified files or patterns.
 
2663
    __doc__ = """Ignore specified files or patterns.
2633
2664
 
2634
2665
    See ``bzr help patterns`` for details on the syntax of patterns.
2635
2666
 
2644
2675
    using this command or directly by using an editor, be sure to commit
2645
2676
    it.
2646
2677
    
 
2678
    Bazaar also supports a global ignore file ~/.bazaar/ignore. On Windows
 
2679
    the global ignore file can be found in the application data directory as
 
2680
    C:\\Documents and Settings\\<user>\\Application Data\\Bazaar\\2.0\\ignore.
 
2681
    Global ignores are not touched by this command. The global ignore file
 
2682
    can be edited directly using an editor.
 
2683
 
2647
2684
    Patterns prefixed with '!' are exceptions to ignore patterns and take
2648
2685
    precedence over regular ignores.  Such exceptions are used to specify
2649
2686
    files that should be versioned which would otherwise be ignored.
2651
2688
    Patterns prefixed with '!!' act as regular ignore patterns, but have
2652
2689
    precedence over the '!' exception patterns.
2653
2690
 
2654
 
    Note: ignore patterns containing shell wildcards must be quoted from
2655
 
    the shell on Unix.
 
2691
    :Notes: 
 
2692
        
 
2693
    * Ignore patterns containing shell wildcards must be quoted from
 
2694
      the shell on Unix.
 
2695
 
 
2696
    * Ignore patterns starting with "#" act as comments in the ignore file.
 
2697
      To ignore patterns that begin with that character, use the "RE:" prefix.
2656
2698
 
2657
2699
    :Examples:
2658
2700
        Ignore the top level Makefile::
2667
2709
 
2668
2710
            bzr ignore "!special.class"
2669
2711
 
 
2712
        Ignore files whose name begins with the "#" character::
 
2713
 
 
2714
            bzr ignore "RE:^#"
 
2715
 
2670
2716
        Ignore .o files under the lib directory::
2671
2717
 
2672
2718
            bzr ignore "lib/**/*.o"
2689
2735
 
2690
2736
    _see_also = ['status', 'ignored', 'patterns']
2691
2737
    takes_args = ['name_pattern*']
2692
 
    takes_options = [
2693
 
        Option('old-default-rules',
2694
 
               help='Write out the ignore rules bzr < 0.9 always used.')
 
2738
    takes_options = ['directory',
 
2739
        Option('default-rules',
 
2740
               help='Display the default ignore rules that bzr uses.')
2695
2741
        ]
2696
2742
 
2697
 
    def run(self, name_pattern_list=None, old_default_rules=None):
 
2743
    def run(self, name_pattern_list=None, default_rules=None,
 
2744
            directory=u'.'):
2698
2745
        from bzrlib import ignores
2699
 
        if old_default_rules is not None:
2700
 
            # dump the rules and exit
2701
 
            for pattern in ignores.OLD_DEFAULTS:
 
2746
        if default_rules is not None:
 
2747
            # dump the default rules and exit
 
2748
            for pattern in ignores.USER_DEFAULTS:
2702
2749
                self.outf.write("%s\n" % pattern)
2703
2750
            return
2704
2751
        if not name_pattern_list:
2705
2752
            raise errors.BzrCommandError("ignore requires at least one "
2706
 
                                  "NAME_PATTERN or --old-default-rules")
 
2753
                "NAME_PATTERN or --default-rules.")
2707
2754
        name_pattern_list = [globbing.normalize_pattern(p)
2708
2755
                             for p in name_pattern_list]
 
2756
        bad_patterns = ''
 
2757
        for p in name_pattern_list:
 
2758
            if not globbing.Globster.is_pattern_valid(p):
 
2759
                bad_patterns += ('\n  %s' % p)
 
2760
        if bad_patterns:
 
2761
            msg = ('Invalid ignore pattern(s) found. %s' % bad_patterns)
 
2762
            ui.ui_factory.show_error(msg)
 
2763
            raise errors.InvalidPattern('')
2709
2764
        for name_pattern in name_pattern_list:
2710
2765
            if (name_pattern[0] == '/' or
2711
2766
                (len(name_pattern) > 1 and name_pattern[1] == ':')):
2712
2767
                raise errors.BzrCommandError(
2713
2768
                    "NAME_PATTERN should not be an absolute path")
2714
 
        tree, relpath = WorkingTree.open_containing(u'.')
 
2769
        tree, relpath = WorkingTree.open_containing(directory)
2715
2770
        ignores.tree_ignores_add_patterns(tree, name_pattern_list)
2716
2771
        ignored = globbing.Globster(name_pattern_list)
2717
2772
        matches = []
2718
 
        tree.lock_read()
 
2773
        self.add_cleanup(tree.lock_read().unlock)
2719
2774
        for entry in tree.list_files():
2720
2775
            id = entry[3]
2721
2776
            if id is not None:
2722
2777
                filename = entry[0]
2723
2778
                if ignored.match(filename):
2724
2779
                    matches.append(filename)
2725
 
        tree.unlock()
2726
2780
        if len(matches) > 0:
2727
2781
            self.outf.write("Warning: the following files are version controlled and"
2728
2782
                  " match your ignore pattern:\n%s"
2731
2785
 
2732
2786
 
2733
2787
class cmd_ignored(Command):
2734
 
    """List ignored files and the patterns that matched them.
 
2788
    __doc__ = """List ignored files and the patterns that matched them.
2735
2789
 
2736
2790
    List all the ignored files and the ignore pattern that caused the file to
2737
2791
    be ignored.
2743
2797
 
2744
2798
    encoding_type = 'replace'
2745
2799
    _see_also = ['ignore', 'ls']
 
2800
    takes_options = ['directory']
2746
2801
 
2747
2802
    @display_command
2748
 
    def run(self):
2749
 
        tree = WorkingTree.open_containing(u'.')[0]
2750
 
        tree.lock_read()
2751
 
        self.add_cleanup(tree.unlock)
 
2803
    def run(self, directory=u'.'):
 
2804
        tree = WorkingTree.open_containing(directory)[0]
 
2805
        self.add_cleanup(tree.lock_read().unlock)
2752
2806
        for path, file_class, kind, file_id, entry in tree.list_files():
2753
2807
            if file_class != 'I':
2754
2808
                continue
2758
2812
 
2759
2813
 
2760
2814
class cmd_lookup_revision(Command):
2761
 
    """Lookup the revision-id from a revision-number
 
2815
    __doc__ = """Lookup the revision-id from a revision-number
2762
2816
 
2763
2817
    :Examples:
2764
2818
        bzr lookup-revision 33
2765
2819
    """
2766
2820
    hidden = True
2767
2821
    takes_args = ['revno']
 
2822
    takes_options = ['directory']
2768
2823
 
2769
2824
    @display_command
2770
 
    def run(self, revno):
 
2825
    def run(self, revno, directory=u'.'):
2771
2826
        try:
2772
2827
            revno = int(revno)
2773
2828
        except ValueError:
2774
2829
            raise errors.BzrCommandError("not a valid revision-number: %r"
2775
2830
                                         % revno)
2776
 
        revid = WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
 
2831
        revid = WorkingTree.open_containing(directory)[0].branch.get_rev_id(revno)
2777
2832
        self.outf.write("%s\n" % revid)
2778
2833
 
2779
2834
 
2780
2835
class cmd_export(Command):
2781
 
    """Export current or past revision to a destination directory or archive.
 
2836
    __doc__ = """Export current or past revision to a destination directory or archive.
2782
2837
 
2783
2838
    If no revision is specified this exports the last committed revision.
2784
2839
 
2806
2861
      =================       =========================
2807
2862
    """
2808
2863
    takes_args = ['dest', 'branch_or_subdir?']
2809
 
    takes_options = [
 
2864
    takes_options = ['directory',
2810
2865
        Option('format',
2811
2866
               help="Type of file to export to.",
2812
2867
               type=unicode),
2821
2876
                    'revision in which it was changed.'),
2822
2877
        ]
2823
2878
    def run(self, dest, branch_or_subdir=None, revision=None, format=None,
2824
 
        root=None, filters=False, per_file_timestamps=False):
 
2879
        root=None, filters=False, per_file_timestamps=False, directory=u'.'):
2825
2880
        from bzrlib.export import export
2826
2881
 
2827
2882
        if branch_or_subdir is None:
2828
 
            tree = WorkingTree.open_containing(u'.')[0]
 
2883
            tree = WorkingTree.open_containing(directory)[0]
2829
2884
            b = tree.branch
2830
2885
            subdir = None
2831
2886
        else:
2841
2896
 
2842
2897
 
2843
2898
class cmd_cat(Command):
2844
 
    """Write the contents of a file as of a given revision to standard output.
 
2899
    __doc__ = """Write the contents of a file as of a given revision to standard output.
2845
2900
 
2846
2901
    If no revision is nominated, the last revision is used.
2847
2902
 
2850
2905
    """
2851
2906
 
2852
2907
    _see_also = ['ls']
2853
 
    takes_options = [
 
2908
    takes_options = ['directory',
2854
2909
        Option('name-from-revision', help='The path name in the old tree.'),
2855
2910
        Option('filters', help='Apply content filters to display the '
2856
2911
                'convenience form.'),
2861
2916
 
2862
2917
    @display_command
2863
2918
    def run(self, filename, revision=None, name_from_revision=False,
2864
 
            filters=False):
 
2919
            filters=False, directory=None):
2865
2920
        if revision is not None and len(revision) != 1:
2866
2921
            raise errors.BzrCommandError("bzr cat --revision takes exactly"
2867
2922
                                         " one revision specifier")
2868
2923
        tree, branch, relpath = \
2869
 
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2870
 
        branch.lock_read()
2871
 
        self.add_cleanup(branch.unlock)
 
2924
            _open_directory_or_containing_tree_or_branch(filename, directory)
 
2925
        self.add_cleanup(branch.lock_read().unlock)
2872
2926
        return self._run(tree, branch, relpath, filename, revision,
2873
2927
                         name_from_revision, filters)
2874
2928
 
2877
2931
        if tree is None:
2878
2932
            tree = b.basis_tree()
2879
2933
        rev_tree = _get_one_revision_tree('cat', revision, branch=b)
2880
 
        rev_tree.lock_read()
2881
 
        self.add_cleanup(rev_tree.unlock)
 
2934
        self.add_cleanup(rev_tree.lock_read().unlock)
2882
2935
 
2883
2936
        old_file_id = rev_tree.path2id(relpath)
2884
2937
 
2927
2980
 
2928
2981
 
2929
2982
class cmd_local_time_offset(Command):
2930
 
    """Show the offset in seconds from GMT to local time."""
 
2983
    __doc__ = """Show the offset in seconds from GMT to local time."""
2931
2984
    hidden = True
2932
2985
    @display_command
2933
2986
    def run(self):
2936
2989
 
2937
2990
 
2938
2991
class cmd_commit(Command):
2939
 
    """Commit changes into a new revision.
 
2992
    __doc__ = """Commit changes into a new revision.
2940
2993
 
2941
2994
    An explanatory message needs to be given for each commit. This is
2942
2995
    often done by using the --message option (getting the message from the
3050
3103
                         "the master branch until a normal commit "
3051
3104
                         "is performed."
3052
3105
                    ),
3053
 
             Option('show-diff',
 
3106
             Option('show-diff', short_name='p',
3054
3107
                    help='When no message is supplied, show the diff along'
3055
3108
                    ' with the status summary in the message editor.'),
3056
3109
             ]
3105
3158
 
3106
3159
        properties = {}
3107
3160
 
3108
 
        tree, selected_list = tree_files(selected_list)
 
3161
        tree, selected_list = WorkingTree.open_containing_paths(selected_list)
3109
3162
        if selected_list == ['']:
3110
3163
            # workaround - commit of root of tree should be exactly the same
3111
3164
            # as just default commit in that tree, and succeed even though
3136
3189
                    '(use --file "%(f)s" to take commit message from that file)'
3137
3190
                    % { 'f': message })
3138
3191
                ui.ui_factory.show_warning(warning_msg)
 
3192
            if '\r' in message:
 
3193
                message = message.replace('\r\n', '\n')
 
3194
                message = message.replace('\r', '\n')
 
3195
            if file:
 
3196
                raise errors.BzrCommandError(
 
3197
                    "please specify either --message or --file")
3139
3198
 
3140
3199
        def get_message(commit_obj):
3141
3200
            """Callback to get commit message"""
3142
 
            my_message = message
3143
 
            if my_message is not None and '\r' in my_message:
3144
 
                my_message = my_message.replace('\r\n', '\n')
3145
 
                my_message = my_message.replace('\r', '\n')
3146
 
            if my_message is None and not file:
3147
 
                t = make_commit_message_template_encoded(tree,
 
3201
            if file:
 
3202
                f = open(file)
 
3203
                try:
 
3204
                    my_message = f.read().decode(osutils.get_user_encoding())
 
3205
                finally:
 
3206
                    f.close()
 
3207
            elif message is not None:
 
3208
                my_message = message
 
3209
            else:
 
3210
                # No message supplied: make one up.
 
3211
                # text is the status of the tree
 
3212
                text = make_commit_message_template_encoded(tree,
3148
3213
                        selected_list, diff=show_diff,
3149
3214
                        output_encoding=osutils.get_user_encoding())
 
3215
                # start_message is the template generated from hooks
 
3216
                # XXX: Warning - looks like hooks return unicode,
 
3217
                # make_commit_message_template_encoded returns user encoding.
 
3218
                # We probably want to be using edit_commit_message instead to
 
3219
                # avoid this.
3150
3220
                start_message = generate_commit_message_template(commit_obj)
3151
 
                my_message = edit_commit_message_encoded(t,
 
3221
                my_message = edit_commit_message_encoded(text,
3152
3222
                    start_message=start_message)
3153
3223
                if my_message is None:
3154
3224
                    raise errors.BzrCommandError("please specify a commit"
3155
3225
                        " message with either --message or --file")
3156
 
            elif my_message and file:
3157
 
                raise errors.BzrCommandError(
3158
 
                    "please specify either --message or --file")
3159
 
            if file:
3160
 
                my_message = codecs.open(file, 'rt',
3161
 
                                         osutils.get_user_encoding()).read()
3162
3226
            if my_message == "":
3163
3227
                raise errors.BzrCommandError("empty commit message specified")
3164
3228
            return my_message
3174
3238
                        reporter=None, verbose=verbose, revprops=properties,
3175
3239
                        authors=author, timestamp=commit_stamp,
3176
3240
                        timezone=offset,
3177
 
                        exclude=safe_relpath_files(tree, exclude))
 
3241
                        exclude=tree.safe_relpath_files(exclude))
3178
3242
        except PointlessCommit:
3179
 
            # FIXME: This should really happen before the file is read in;
3180
 
            # perhaps prepare the commit; get the message; then actually commit
3181
3243
            raise errors.BzrCommandError("No changes to commit."
3182
3244
                              " Use --unchanged to commit anyhow.")
3183
3245
        except ConflictsInTree:
3196
3258
 
3197
3259
 
3198
3260
class cmd_check(Command):
3199
 
    """Validate working tree structure, branch consistency and repository history.
 
3261
    __doc__ = """Validate working tree structure, branch consistency and repository history.
3200
3262
 
3201
3263
    This command checks various invariants about branch and repository storage
3202
3264
    to detect data corruption or bzr bugs.
3266
3328
 
3267
3329
 
3268
3330
class cmd_upgrade(Command):
3269
 
    """Upgrade branch storage to current format.
 
3331
    __doc__ = """Upgrade branch storage to current format.
3270
3332
 
3271
3333
    The check command or bzr developers may sometimes advise you to run
3272
3334
    this command. When the default format has changed you may also be warned
3290
3352
 
3291
3353
 
3292
3354
class cmd_whoami(Command):
3293
 
    """Show or set bzr user id.
 
3355
    __doc__ = """Show or set bzr user id.
3294
3356
 
3295
3357
    :Examples:
3296
3358
        Show the email of the current user::
3301
3363
 
3302
3364
            bzr whoami "Frank Chu <fchu@example.com>"
3303
3365
    """
3304
 
    takes_options = [ Option('email',
 
3366
    takes_options = [ 'directory',
 
3367
                      Option('email',
3305
3368
                             help='Display email address only.'),
3306
3369
                      Option('branch',
3307
3370
                             help='Set identity for the current branch instead of '
3311
3374
    encoding_type = 'replace'
3312
3375
 
3313
3376
    @display_command
3314
 
    def run(self, email=False, branch=False, name=None):
 
3377
    def run(self, email=False, branch=False, name=None, directory=None):
3315
3378
        if name is None:
3316
 
            # use branch if we're inside one; otherwise global config
3317
 
            try:
3318
 
                c = Branch.open_containing('.')[0].get_config()
3319
 
            except errors.NotBranchError:
3320
 
                c = config.GlobalConfig()
 
3379
            if directory is None:
 
3380
                # use branch if we're inside one; otherwise global config
 
3381
                try:
 
3382
                    c = Branch.open_containing(u'.')[0].get_config()
 
3383
                except errors.NotBranchError:
 
3384
                    c = _mod_config.GlobalConfig()
 
3385
            else:
 
3386
                c = Branch.open(directory).get_config()
3321
3387
            if email:
3322
3388
                self.outf.write(c.user_email() + '\n')
3323
3389
            else:
3326
3392
 
3327
3393
        # display a warning if an email address isn't included in the given name.
3328
3394
        try:
3329
 
            config.extract_email_address(name)
 
3395
            _mod_config.extract_email_address(name)
3330
3396
        except errors.NoEmailInUsername, e:
3331
3397
            warning('"%s" does not seem to contain an email address.  '
3332
3398
                    'This is allowed, but not recommended.', name)
3333
3399
 
3334
3400
        # use global config unless --branch given
3335
3401
        if branch:
3336
 
            c = Branch.open_containing('.')[0].get_config()
 
3402
            if directory is None:
 
3403
                c = Branch.open_containing(u'.')[0].get_config()
 
3404
            else:
 
3405
                c = Branch.open(directory).get_config()
3337
3406
        else:
3338
 
            c = config.GlobalConfig()
 
3407
            c = _mod_config.GlobalConfig()
3339
3408
        c.set_user_option('email', name)
3340
3409
 
3341
3410
 
3342
3411
class cmd_nick(Command):
3343
 
    """Print or set the branch nickname.
 
3412
    __doc__ = """Print or set the branch nickname.
3344
3413
 
3345
3414
    If unset, the tree root directory name is used as the nickname.
3346
3415
    To print the current nickname, execute with no argument.
3351
3420
 
3352
3421
    _see_also = ['info']
3353
3422
    takes_args = ['nickname?']
3354
 
    def run(self, nickname=None):
3355
 
        branch = Branch.open_containing(u'.')[0]
 
3423
    takes_options = ['directory']
 
3424
    def run(self, nickname=None, directory=u'.'):
 
3425
        branch = Branch.open_containing(directory)[0]
3356
3426
        if nickname is None:
3357
3427
            self.printme(branch)
3358
3428
        else:
3364
3434
 
3365
3435
 
3366
3436
class cmd_alias(Command):
3367
 
    """Set/unset and display aliases.
 
3437
    __doc__ = """Set/unset and display aliases.
3368
3438
 
3369
3439
    :Examples:
3370
3440
        Show the current aliases::
3407
3477
                'bzr alias --remove expects an alias to remove.')
3408
3478
        # If alias is not found, print something like:
3409
3479
        # unalias: foo: not found
3410
 
        c = config.GlobalConfig()
 
3480
        c = _mod_config.GlobalConfig()
3411
3481
        c.unset_alias(alias_name)
3412
3482
 
3413
3483
    @display_command
3414
3484
    def print_aliases(self):
3415
3485
        """Print out the defined aliases in a similar format to bash."""
3416
 
        aliases = config.GlobalConfig().get_aliases()
 
3486
        aliases = _mod_config.GlobalConfig().get_aliases()
3417
3487
        for key, value in sorted(aliases.iteritems()):
3418
3488
            self.outf.write('bzr alias %s="%s"\n' % (key, value))
3419
3489
 
3429
3499
 
3430
3500
    def set_alias(self, alias_name, alias_command):
3431
3501
        """Save the alias in the global config."""
3432
 
        c = config.GlobalConfig()
 
3502
        c = _mod_config.GlobalConfig()
3433
3503
        c.set_alias(alias_name, alias_command)
3434
3504
 
3435
3505
 
3436
3506
class cmd_selftest(Command):
3437
 
    """Run internal test suite.
 
3507
    __doc__ = """Run internal test suite.
3438
3508
 
3439
3509
    If arguments are given, they are regular expressions that say which tests
3440
3510
    should run.  Tests matching any expression are run, and other tests are
3470
3540
    If you set BZR_TEST_PDB=1 when running selftest, failing tests will drop
3471
3541
    into a pdb postmortem session.
3472
3542
 
 
3543
    The --coverage=DIRNAME global option produces a report with covered code
 
3544
    indicated.
 
3545
 
3473
3546
    :Examples:
3474
3547
        Run only tests relating to 'ignore'::
3475
3548
 
3508
3581
                                 'throughout the test suite.',
3509
3582
                            type=get_transport_type),
3510
3583
                     Option('benchmark',
3511
 
                            help='Run the benchmarks rather than selftests.'),
 
3584
                            help='Run the benchmarks rather than selftests.',
 
3585
                            hidden=True),
3512
3586
                     Option('lsprof-timed',
3513
3587
                            help='Generate lsprof output for benchmarked'
3514
3588
                                 ' sections of code.'),
3515
3589
                     Option('lsprof-tests',
3516
3590
                            help='Generate lsprof output for each test.'),
3517
 
                     Option('cache-dir', type=str,
3518
 
                            help='Cache intermediate benchmark output in this '
3519
 
                                 'directory.'),
3520
3591
                     Option('first',
3521
3592
                            help='Run all tests, but run specified tests first.',
3522
3593
                            short_name='f',
3556
3627
 
3557
3628
    def run(self, testspecs_list=None, verbose=False, one=False,
3558
3629
            transport=None, benchmark=None,
3559
 
            lsprof_timed=None, cache_dir=None,
 
3630
            lsprof_timed=None,
3560
3631
            first=False, list_only=False,
3561
3632
            randomize=None, exclude=None, strict=False,
3562
3633
            load_list=None, debugflag=None, starting_with=None, subunit=False,
3563
3634
            parallel=None, lsprof_tests=False):
3564
 
        from bzrlib.tests import selftest
3565
 
        import bzrlib.benchmarks as benchmarks
3566
 
        from bzrlib.benchmarks import tree_creator
3567
 
 
3568
 
        # Make deprecation warnings visible, unless -Werror is set
3569
 
        symbol_versioning.activate_deprecation_warnings(override=False)
3570
 
 
3571
 
        if cache_dir is not None:
3572
 
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
 
3635
        from bzrlib import tests
 
3636
 
3573
3637
        if testspecs_list is not None:
3574
3638
            pattern = '|'.join(testspecs_list)
3575
3639
        else:
3581
3645
                raise errors.BzrCommandError("subunit not available. subunit "
3582
3646
                    "needs to be installed to use --subunit.")
3583
3647
            self.additional_selftest_args['runner_class'] = SubUnitBzrRunner
 
3648
            # On Windows, disable automatic conversion of '\n' to '\r\n' in
 
3649
            # stdout, which would corrupt the subunit stream. 
 
3650
            # FIXME: This has been fixed in subunit trunk (>0.0.5) so the
 
3651
            # following code can be deleted when it's sufficiently deployed
 
3652
            # -- vila/mgz 20100514
 
3653
            if (sys.platform == "win32"
 
3654
                and getattr(sys.stdout, 'fileno', None) is not None):
 
3655
                import msvcrt
 
3656
                msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
3584
3657
        if parallel:
3585
3658
            self.additional_selftest_args.setdefault(
3586
3659
                'suite_decorators', []).append(parallel)
3587
3660
        if benchmark:
3588
 
            test_suite_factory = benchmarks.test_suite
3589
 
            # Unless user explicitly asks for quiet, be verbose in benchmarks
3590
 
            verbose = not is_quiet()
3591
 
            # TODO: should possibly lock the history file...
3592
 
            benchfile = open(".perf_history", "at", buffering=1)
3593
 
            self.add_cleanup(benchfile.close)
3594
 
        else:
3595
 
            test_suite_factory = None
3596
 
            benchfile = None
 
3661
            raise errors.BzrCommandError(
 
3662
                "--benchmark is no longer supported from bzr 2.2; "
 
3663
                "use bzr-usertest instead")
 
3664
        test_suite_factory = None
3597
3665
        selftest_kwargs = {"verbose": verbose,
3598
3666
                          "pattern": pattern,
3599
3667
                          "stop_on_failure": one,
3601
3669
                          "test_suite_factory": test_suite_factory,
3602
3670
                          "lsprof_timed": lsprof_timed,
3603
3671
                          "lsprof_tests": lsprof_tests,
3604
 
                          "bench_history": benchfile,
3605
3672
                          "matching_tests_first": first,
3606
3673
                          "list_only": list_only,
3607
3674
                          "random_seed": randomize,
3612
3679
                          "starting_with": starting_with
3613
3680
                          }
3614
3681
        selftest_kwargs.update(self.additional_selftest_args)
3615
 
        result = selftest(**selftest_kwargs)
 
3682
 
 
3683
        # Make deprecation warnings visible, unless -Werror is set
 
3684
        cleanup = symbol_versioning.activate_deprecation_warnings(
 
3685
            override=False)
 
3686
        try:
 
3687
            result = tests.selftest(**selftest_kwargs)
 
3688
        finally:
 
3689
            cleanup()
3616
3690
        return int(not result)
3617
3691
 
3618
3692
 
3619
3693
class cmd_version(Command):
3620
 
    """Show version of bzr."""
 
3694
    __doc__ = """Show version of bzr."""
3621
3695
 
3622
3696
    encoding_type = 'replace'
3623
3697
    takes_options = [
3634
3708
 
3635
3709
 
3636
3710
class cmd_rocks(Command):
3637
 
    """Statement of optimism."""
 
3711
    __doc__ = """Statement of optimism."""
3638
3712
 
3639
3713
    hidden = True
3640
3714
 
3644
3718
 
3645
3719
 
3646
3720
class cmd_find_merge_base(Command):
3647
 
    """Find and print a base revision for merging two branches."""
 
3721
    __doc__ = """Find and print a base revision for merging two branches."""
3648
3722
    # TODO: Options to specify revisions on either side, as if
3649
3723
    #       merging only part of the history.
3650
3724
    takes_args = ['branch', 'other']
3656
3730
 
3657
3731
        branch1 = Branch.open_containing(branch)[0]
3658
3732
        branch2 = Branch.open_containing(other)[0]
3659
 
        branch1.lock_read()
3660
 
        self.add_cleanup(branch1.unlock)
3661
 
        branch2.lock_read()
3662
 
        self.add_cleanup(branch2.unlock)
 
3733
        self.add_cleanup(branch1.lock_read().unlock)
 
3734
        self.add_cleanup(branch2.lock_read().unlock)
3663
3735
        last1 = ensure_null(branch1.last_revision())
3664
3736
        last2 = ensure_null(branch2.last_revision())
3665
3737
 
3670
3742
 
3671
3743
 
3672
3744
class cmd_merge(Command):
3673
 
    """Perform a three-way merge.
 
3745
    __doc__ = """Perform a three-way merge.
3674
3746
 
3675
3747
    The source of the merge can be specified either in the form of a branch,
3676
3748
    or in the form of a path to a file containing a merge directive generated
3677
3749
    with bzr send. If neither is specified, the default is the upstream branch
3678
3750
    or the branch most recently merged using --remember.
3679
3751
 
3680
 
    When merging a branch, by default the tip will be merged. To pick a different
3681
 
    revision, pass --revision. If you specify two values, the first will be used as
3682
 
    BASE and the second one as OTHER. Merging individual revisions, or a subset of
3683
 
    available revisions, like this is commonly referred to as "cherrypicking".
3684
 
 
3685
 
    Revision numbers are always relative to the branch being merged.
3686
 
 
3687
 
    By default, bzr will try to merge in all new work from the other
3688
 
    branch, automatically determining an appropriate base.  If this
3689
 
    fails, you may need to give an explicit base.
 
3752
    When merging from a branch, by default bzr will try to merge in all new
 
3753
    work from the other branch, automatically determining an appropriate base
 
3754
    revision.  If this fails, you may need to give an explicit base.
 
3755
 
 
3756
    To pick a different ending revision, pass "--revision OTHER".  bzr will
 
3757
    try to merge in all new work up to and including revision OTHER.
 
3758
 
 
3759
    If you specify two values, "--revision BASE..OTHER", only revisions BASE
 
3760
    through OTHER, excluding BASE but including OTHER, will be merged.  If this
 
3761
    causes some revisions to be skipped, i.e. if the destination branch does
 
3762
    not already contain revision BASE, such a merge is commonly referred to as
 
3763
    a "cherrypick".
 
3764
 
 
3765
    Revision numbers are always relative to the source branch.
3690
3766
 
3691
3767
    Merge will do its best to combine the changes in two branches, but there
3692
3768
    are some kinds of problems only a human can fix.  When it encounters those,
3716
3792
    you to apply each diff hunk and file change, similar to "shelve".
3717
3793
 
3718
3794
    :Examples:
3719
 
        To merge the latest revision from bzr.dev::
 
3795
        To merge all new revisions from bzr.dev::
3720
3796
 
3721
3797
            bzr merge ../bzr.dev
3722
3798
 
3759
3835
                ' completely merged into the source, pull from the'
3760
3836
                ' source rather than merging.  When this happens,'
3761
3837
                ' you do not need to commit the result.'),
3762
 
        Option('directory',
 
3838
        custom_help('directory',
3763
3839
               help='Branch to merge into, '
3764
 
                    'rather than the one containing the working directory.',
3765
 
               short_name='d',
3766
 
               type=unicode,
3767
 
               ),
 
3840
                    'rather than the one containing the working directory.'),
3768
3841
        Option('preview', help='Instead of merging, show a diff of the'
3769
3842
               ' merge.'),
3770
3843
        Option('interactive', help='Select changes interactively.',
3803
3876
            unversioned_filter=tree.is_ignored, view_info=view_info)
3804
3877
        pb = ui.ui_factory.nested_progress_bar()
3805
3878
        self.add_cleanup(pb.finished)
3806
 
        tree.lock_write()
3807
 
        self.add_cleanup(tree.unlock)
 
3879
        self.add_cleanup(tree.lock_write().unlock)
3808
3880
        if location is not None:
3809
3881
            try:
3810
3882
                mergeable = bundle.read_mergeable_from_url(location,
3871
3943
    def _do_preview(self, merger):
3872
3944
        from bzrlib.diff import show_diff_trees
3873
3945
        result_tree = self._get_preview(merger)
 
3946
        path_encoding = osutils.get_diff_header_encoding()
3874
3947
        show_diff_trees(merger.this_tree, result_tree, self.outf,
3875
 
                        old_label='', new_label='')
 
3948
                        old_label='', new_label='',
 
3949
                        path_encoding=path_encoding)
3876
3950
 
3877
3951
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
3878
3952
        merger.change_reporter = change_reporter
3958
4032
        if ((remember or tree.branch.get_submit_branch() is None) and
3959
4033
             user_location is not None):
3960
4034
            tree.branch.set_submit_branch(other_branch.base)
3961
 
        _merge_tags_if_possible(other_branch, tree.branch)
 
4035
        # Merge tags (but don't set them in the master branch yet, the user
 
4036
        # might revert this merge).  Commit will propagate them.
 
4037
        _merge_tags_if_possible(other_branch, tree.branch, ignore_master=True)
3962
4038
        merger = _mod_merge.Merger.from_revision_ids(pb, tree,
3963
4039
            other_revision_id, base_revision_id, other_branch, base_branch)
3964
4040
        if other_path != '':
4031
4107
 
4032
4108
 
4033
4109
class cmd_remerge(Command):
4034
 
    """Redo a merge.
 
4110
    __doc__ = """Redo a merge.
4035
4111
 
4036
4112
    Use this if you want to try a different merge technique while resolving
4037
4113
    conflicts.  Some merge techniques are better than others, and remerge
4062
4138
 
4063
4139
    def run(self, file_list=None, merge_type=None, show_base=False,
4064
4140
            reprocess=False):
 
4141
        from bzrlib.conflicts import restore
4065
4142
        if merge_type is None:
4066
4143
            merge_type = _mod_merge.Merge3Merger
4067
 
        tree, file_list = tree_files(file_list)
4068
 
        tree.lock_write()
4069
 
        self.add_cleanup(tree.unlock)
 
4144
        tree, file_list = WorkingTree.open_containing_paths(file_list)
 
4145
        self.add_cleanup(tree.lock_write().unlock)
4070
4146
        parents = tree.get_parent_ids()
4071
4147
        if len(parents) != 2:
4072
4148
            raise errors.BzrCommandError("Sorry, remerge only works after normal"
4125
4201
 
4126
4202
 
4127
4203
class cmd_revert(Command):
4128
 
    """Revert files to a previous revision.
 
4204
    __doc__ = """Revert files to a previous revision.
4129
4205
 
4130
4206
    Giving a list of files will revert only those files.  Otherwise, all files
4131
4207
    will be reverted.  If the revision is not specified with '--revision', the
4181
4257
 
4182
4258
    def run(self, revision=None, no_backup=False, file_list=None,
4183
4259
            forget_merges=None):
4184
 
        tree, file_list = tree_files(file_list)
4185
 
        tree.lock_write()
4186
 
        self.add_cleanup(tree.unlock)
 
4260
        tree, file_list = WorkingTree.open_containing_paths(file_list)
 
4261
        self.add_cleanup(tree.lock_tree_write().unlock)
4187
4262
        if forget_merges:
4188
4263
            tree.set_parent_ids(tree.get_parent_ids()[:1])
4189
4264
        else:
4197
4272
 
4198
4273
 
4199
4274
class cmd_assert_fail(Command):
4200
 
    """Test reporting of assertion failures"""
 
4275
    __doc__ = """Test reporting of assertion failures"""
4201
4276
    # intended just for use in testing
4202
4277
 
4203
4278
    hidden = True
4207
4282
 
4208
4283
 
4209
4284
class cmd_help(Command):
4210
 
    """Show help on a command or other topic.
 
4285
    __doc__ = """Show help on a command or other topic.
4211
4286
    """
4212
4287
 
4213
4288
    _see_also = ['topics']
4226
4301
 
4227
4302
 
4228
4303
class cmd_shell_complete(Command):
4229
 
    """Show appropriate completions for context.
 
4304
    __doc__ = """Show appropriate completions for context.
4230
4305
 
4231
4306
    For a list of all available commands, say 'bzr shell-complete'.
4232
4307
    """
4241
4316
 
4242
4317
 
4243
4318
class cmd_missing(Command):
4244
 
    """Show unmerged/unpulled revisions between two branches.
 
4319
    __doc__ = """Show unmerged/unpulled revisions between two branches.
4245
4320
 
4246
4321
    OTHER_BRANCH may be local or remote.
4247
4322
 
4278
4353
    _see_also = ['merge', 'pull']
4279
4354
    takes_args = ['other_branch?']
4280
4355
    takes_options = [
 
4356
        'directory',
4281
4357
        Option('reverse', 'Reverse the order of revisions.'),
4282
4358
        Option('mine-only',
4283
4359
               'Display changes in the local branch only.'),
4305
4381
            theirs_only=False,
4306
4382
            log_format=None, long=False, short=False, line=False,
4307
4383
            show_ids=False, verbose=False, this=False, other=False,
4308
 
            include_merges=False, revision=None, my_revision=None):
 
4384
            include_merges=False, revision=None, my_revision=None,
 
4385
            directory=u'.'):
4309
4386
        from bzrlib.missing import find_unmerged, iter_log_revisions
4310
4387
        def message(s):
4311
4388
            if not is_quiet():
4324
4401
        elif theirs_only:
4325
4402
            restrict = 'remote'
4326
4403
 
4327
 
        local_branch = Branch.open_containing(u".")[0]
 
4404
        local_branch = Branch.open_containing(directory)[0]
 
4405
        self.add_cleanup(local_branch.lock_read().unlock)
 
4406
 
4328
4407
        parent = local_branch.get_parent()
4329
4408
        if other_branch is None:
4330
4409
            other_branch = parent
4339
4418
        remote_branch = Branch.open(other_branch)
4340
4419
        if remote_branch.base == local_branch.base:
4341
4420
            remote_branch = local_branch
 
4421
        else:
 
4422
            self.add_cleanup(remote_branch.lock_read().unlock)
4342
4423
 
4343
 
        local_branch.lock_read()
4344
 
        self.add_cleanup(local_branch.unlock)
4345
4424
        local_revid_range = _revision_range_to_revid_range(
4346
4425
            _get_revision_range(my_revision, local_branch,
4347
4426
                self.name()))
4348
4427
 
4349
 
        remote_branch.lock_read()
4350
 
        self.add_cleanup(remote_branch.unlock)
4351
4428
        remote_revid_range = _revision_range_to_revid_range(
4352
4429
            _get_revision_range(revision,
4353
4430
                remote_branch, self.name()))
4403
4480
            message("Branches are up to date.\n")
4404
4481
        self.cleanup_now()
4405
4482
        if not status_code and parent is None and other_branch is not None:
4406
 
            local_branch.lock_write()
4407
 
            self.add_cleanup(local_branch.unlock)
 
4483
            self.add_cleanup(local_branch.lock_write().unlock)
4408
4484
            # handle race conditions - a parent might be set while we run.
4409
4485
            if local_branch.get_parent() is None:
4410
4486
                local_branch.set_parent(remote_branch.base)
4412
4488
 
4413
4489
 
4414
4490
class cmd_pack(Command):
4415
 
    """Compress the data within a repository."""
 
4491
    __doc__ = """Compress the data within a repository.
 
4492
 
 
4493
    This operation compresses the data within a bazaar repository. As
 
4494
    bazaar supports automatic packing of repository, this operation is
 
4495
    normally not required to be done manually.
 
4496
 
 
4497
    During the pack operation, bazaar takes a backup of existing repository
 
4498
    data, i.e. pack files. This backup is eventually removed by bazaar
 
4499
    automatically when it is safe to do so. To save disk space by removing
 
4500
    the backed up pack files, the --clean-obsolete-packs option may be
 
4501
    used.
 
4502
 
 
4503
    Warning: If you use --clean-obsolete-packs and your machine crashes
 
4504
    during or immediately after repacking, you may be left with a state
 
4505
    where the deletion has been written to disk but the new packs have not
 
4506
    been. In this case the repository may be unusable.
 
4507
    """
4416
4508
 
4417
4509
    _see_also = ['repositories']
4418
4510
    takes_args = ['branch_or_repo?']
 
4511
    takes_options = [
 
4512
        Option('clean-obsolete-packs', 'Delete obsolete packs to save disk space.'),
 
4513
        ]
4419
4514
 
4420
 
    def run(self, branch_or_repo='.'):
 
4515
    def run(self, branch_or_repo='.', clean_obsolete_packs=False):
4421
4516
        dir = bzrdir.BzrDir.open_containing(branch_or_repo)[0]
4422
4517
        try:
4423
4518
            branch = dir.open_branch()
4424
4519
            repository = branch.repository
4425
4520
        except errors.NotBranchError:
4426
4521
            repository = dir.open_repository()
4427
 
        repository.pack()
 
4522
        repository.pack(clean_obsolete_packs=clean_obsolete_packs)
4428
4523
 
4429
4524
 
4430
4525
class cmd_plugins(Command):
4431
 
    """List the installed plugins.
 
4526
    __doc__ = """List the installed plugins.
4432
4527
 
4433
4528
    This command displays the list of installed plugins including
4434
4529
    version of plugin and a short description of each.
4473
4568
 
4474
4569
 
4475
4570
class cmd_testament(Command):
4476
 
    """Show testament (signing-form) of a revision."""
 
4571
    __doc__ = """Show testament (signing-form) of a revision."""
4477
4572
    takes_options = [
4478
4573
            'revision',
4479
4574
            Option('long', help='Produce long-format testament.'),
4491
4586
            b = Branch.open_containing(branch)[0]
4492
4587
        else:
4493
4588
            b = Branch.open(branch)
4494
 
        b.lock_read()
4495
 
        self.add_cleanup(b.unlock)
 
4589
        self.add_cleanup(b.lock_read().unlock)
4496
4590
        if revision is None:
4497
4591
            rev_id = b.last_revision()
4498
4592
        else:
4505
4599
 
4506
4600
 
4507
4601
class cmd_annotate(Command):
4508
 
    """Show the origin of each line in a file.
 
4602
    __doc__ = """Show the origin of each line in a file.
4509
4603
 
4510
4604
    This prints out the given file with an annotation on the left side
4511
4605
    indicating which revision, author and date introduced the change.
4522
4616
                     Option('long', help='Show commit date in annotations.'),
4523
4617
                     'revision',
4524
4618
                     'show-ids',
 
4619
                     'directory',
4525
4620
                     ]
4526
4621
    encoding_type = 'exact'
4527
4622
 
4528
4623
    @display_command
4529
4624
    def run(self, filename, all=False, long=False, revision=None,
4530
 
            show_ids=False):
 
4625
            show_ids=False, directory=None):
4531
4626
        from bzrlib.annotate import annotate_file, annotate_file_tree
4532
4627
        wt, branch, relpath = \
4533
 
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
 
4628
            _open_directory_or_containing_tree_or_branch(filename, directory)
4534
4629
        if wt is not None:
4535
 
            wt.lock_read()
4536
 
            self.add_cleanup(wt.unlock)
 
4630
            self.add_cleanup(wt.lock_read().unlock)
4537
4631
        else:
4538
 
            branch.lock_read()
4539
 
            self.add_cleanup(branch.unlock)
 
4632
            self.add_cleanup(branch.lock_read().unlock)
4540
4633
        tree = _get_one_revision_tree('annotate', revision, branch=branch)
4541
 
        tree.lock_read()
4542
 
        self.add_cleanup(tree.unlock)
 
4634
        self.add_cleanup(tree.lock_read().unlock)
4543
4635
        if wt is not None:
4544
4636
            file_id = wt.path2id(relpath)
4545
4637
        else:
4558
4650
 
4559
4651
 
4560
4652
class cmd_re_sign(Command):
4561
 
    """Create a digital signature for an existing revision."""
 
4653
    __doc__ = """Create a digital signature for an existing revision."""
4562
4654
    # TODO be able to replace existing ones.
4563
4655
 
4564
4656
    hidden = True # is this right ?
4565
4657
    takes_args = ['revision_id*']
4566
 
    takes_options = ['revision']
 
4658
    takes_options = ['directory', 'revision']
4567
4659
 
4568
 
    def run(self, revision_id_list=None, revision=None):
 
4660
    def run(self, revision_id_list=None, revision=None, directory=u'.'):
4569
4661
        if revision_id_list is not None and revision is not None:
4570
4662
            raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
4571
4663
        if revision_id_list is None and revision is None:
4572
4664
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
4573
 
        b = WorkingTree.open_containing(u'.')[0].branch
4574
 
        b.lock_write()
4575
 
        self.add_cleanup(b.unlock)
 
4665
        b = WorkingTree.open_containing(directory)[0].branch
 
4666
        self.add_cleanup(b.lock_write().unlock)
4576
4667
        return self._run(b, revision_id_list, revision)
4577
4668
 
4578
4669
    def _run(self, b, revision_id_list, revision):
4624
4715
 
4625
4716
 
4626
4717
class cmd_bind(Command):
4627
 
    """Convert the current branch into a checkout of the supplied branch.
 
4718
    __doc__ = """Convert the current branch into a checkout of the supplied branch.
 
4719
    If no branch is supplied, rebind to the last bound location.
4628
4720
 
4629
4721
    Once converted into a checkout, commits must succeed on the master branch
4630
4722
    before they will be applied to the local branch.
4636
4728
 
4637
4729
    _see_also = ['checkouts', 'unbind']
4638
4730
    takes_args = ['location?']
4639
 
    takes_options = []
 
4731
    takes_options = ['directory']
4640
4732
 
4641
 
    def run(self, location=None):
4642
 
        b, relpath = Branch.open_containing(u'.')
 
4733
    def run(self, location=None, directory=u'.'):
 
4734
        b, relpath = Branch.open_containing(directory)
4643
4735
        if location is None:
4644
4736
            try:
4645
4737
                location = b.get_old_bound_location()
4664
4756
 
4665
4757
 
4666
4758
class cmd_unbind(Command):
4667
 
    """Convert the current checkout into a regular branch.
 
4759
    __doc__ = """Convert the current checkout into a regular branch.
4668
4760
 
4669
4761
    After unbinding, the local branch is considered independent and subsequent
4670
4762
    commits will be local only.
4672
4764
 
4673
4765
    _see_also = ['checkouts', 'bind']
4674
4766
    takes_args = []
4675
 
    takes_options = []
 
4767
    takes_options = ['directory']
4676
4768
 
4677
 
    def run(self):
4678
 
        b, relpath = Branch.open_containing(u'.')
 
4769
    def run(self, directory=u'.'):
 
4770
        b, relpath = Branch.open_containing(directory)
4679
4771
        if not b.unbind():
4680
4772
            raise errors.BzrCommandError('Local branch is not bound')
4681
4773
 
4682
4774
 
4683
4775
class cmd_uncommit(Command):
4684
 
    """Remove the last committed revision.
 
4776
    __doc__ = """Remove the last committed revision.
4685
4777
 
4686
4778
    --verbose will print out what is being removed.
4687
4779
    --dry-run will go through all the motions, but not actually
4727
4819
            b = control.open_branch()
4728
4820
 
4729
4821
        if tree is not None:
4730
 
            tree.lock_write()
4731
 
            self.add_cleanup(tree.unlock)
 
4822
            self.add_cleanup(tree.lock_write().unlock)
4732
4823
        else:
4733
 
            b.lock_write()
4734
 
            self.add_cleanup(b.unlock)
 
4824
            self.add_cleanup(b.lock_write().unlock)
4735
4825
        return self._run(b, tree, dry_run, verbose, revision, force, local=local)
4736
4826
 
4737
4827
    def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
4776
4866
            self.outf.write('The above revision(s) will be removed.\n')
4777
4867
 
4778
4868
        if not force:
4779
 
            if not ui.ui_factory.get_boolean('Are you sure'):
4780
 
                self.outf.write('Canceled')
 
4869
            if not ui.ui_factory.confirm_action(
 
4870
                    'Uncommit these revisions',
 
4871
                    'bzrlib.builtins.uncommit',
 
4872
                    {}):
 
4873
                self.outf.write('Canceled\n')
4781
4874
                return 0
4782
4875
 
4783
4876
        mutter('Uncommitting from {%s} to {%s}',
4789
4882
 
4790
4883
 
4791
4884
class cmd_break_lock(Command):
4792
 
    """Break a dead lock on a repository, branch or working directory.
 
4885
    __doc__ = """Break a dead lock.
 
4886
 
 
4887
    This command breaks a lock on a repository, branch, working directory or
 
4888
    config file.
4793
4889
 
4794
4890
    CAUTION: Locks should only be broken when you are sure that the process
4795
4891
    holding the lock has been stopped.
4800
4896
    :Examples:
4801
4897
        bzr break-lock
4802
4898
        bzr break-lock bzr+ssh://example.com/bzr/foo
 
4899
        bzr break-lock --conf ~/.bazaar
4803
4900
    """
 
4901
 
4804
4902
    takes_args = ['location?']
 
4903
    takes_options = [
 
4904
        Option('config',
 
4905
               help='LOCATION is the directory where the config lock is.'),
 
4906
        Option('force',
 
4907
            help='Do not ask for confirmation before breaking the lock.'),
 
4908
        ]
4805
4909
 
4806
 
    def run(self, location=None, show=False):
 
4910
    def run(self, location=None, config=False, force=False):
4807
4911
        if location is None:
4808
4912
            location = u'.'
4809
 
        control, relpath = bzrdir.BzrDir.open_containing(location)
4810
 
        try:
4811
 
            control.break_lock()
4812
 
        except NotImplementedError:
4813
 
            pass
 
4913
        if force:
 
4914
            ui.ui_factory = ui.ConfirmationUserInterfacePolicy(ui.ui_factory,
 
4915
                None,
 
4916
                {'bzrlib.lockdir.break': True})
 
4917
        if config:
 
4918
            conf = _mod_config.LockableConfig(file_name=location)
 
4919
            conf.break_lock()
 
4920
        else:
 
4921
            control, relpath = bzrdir.BzrDir.open_containing(location)
 
4922
            try:
 
4923
                control.break_lock()
 
4924
            except NotImplementedError:
 
4925
                pass
4814
4926
 
4815
4927
 
4816
4928
class cmd_wait_until_signalled(Command):
4817
 
    """Test helper for test_start_and_stop_bzr_subprocess_send_signal.
 
4929
    __doc__ = """Test helper for test_start_and_stop_bzr_subprocess_send_signal.
4818
4930
 
4819
4931
    This just prints a line to signal when it is ready, then blocks on stdin.
4820
4932
    """
4828
4940
 
4829
4941
 
4830
4942
class cmd_serve(Command):
4831
 
    """Run the bzr server."""
 
4943
    __doc__ = """Run the bzr server."""
4832
4944
 
4833
4945
    aliases = ['server']
4834
4946
 
4845
4957
                    'result in a dynamically allocated port.  The default port '
4846
4958
                    'depends on the protocol.',
4847
4959
               type=str),
4848
 
        Option('directory',
4849
 
               help='Serve contents of this directory.',
4850
 
               type=unicode),
 
4960
        custom_help('directory',
 
4961
               help='Serve contents of this directory.'),
4851
4962
        Option('allow-writes',
4852
4963
               help='By default the server is a readonly server.  Supplying '
4853
4964
                    '--allow-writes enables write access to the contents of '
4880
4991
 
4881
4992
    def run(self, port=None, inet=False, directory=None, allow_writes=False,
4882
4993
            protocol=None):
4883
 
        from bzrlib.transport import get_transport, transport_server_registry
 
4994
        from bzrlib import transport
4884
4995
        if directory is None:
4885
4996
            directory = os.getcwd()
4886
4997
        if protocol is None:
4887
 
            protocol = transport_server_registry.get()
 
4998
            protocol = transport.transport_server_registry.get()
4888
4999
        host, port = self.get_host_and_port(port)
4889
5000
        url = urlutils.local_path_to_url(directory)
4890
5001
        if not allow_writes:
4891
5002
            url = 'readonly+' + url
4892
 
        transport = get_transport(url)
4893
 
        protocol(transport, host, port, inet)
 
5003
        t = transport.get_transport(url)
 
5004
        protocol(t, host, port, inet)
4894
5005
 
4895
5006
 
4896
5007
class cmd_join(Command):
4897
 
    """Combine a tree into its containing tree.
 
5008
    __doc__ = """Combine a tree into its containing tree.
4898
5009
 
4899
5010
    This command requires the target tree to be in a rich-root format.
4900
5011
 
4902
5013
    not part of it.  (Such trees can be produced by "bzr split", but also by
4903
5014
    running "bzr branch" with the target inside a tree.)
4904
5015
 
4905
 
    The result is a combined tree, with the subtree no longer an independant
 
5016
    The result is a combined tree, with the subtree no longer an independent
4906
5017
    part.  This is marked as a merge of the subtree into the containing tree,
4907
5018
    and all history is preserved.
4908
5019
    """
4940
5051
 
4941
5052
 
4942
5053
class cmd_split(Command):
4943
 
    """Split a subdirectory of a tree into a separate tree.
 
5054
    __doc__ = """Split a subdirectory of a tree into a separate tree.
4944
5055
 
4945
5056
    This command will produce a target tree in a format that supports
4946
5057
    rich roots, like 'rich-root' or 'rich-root-pack'.  These formats cannot be
4966
5077
 
4967
5078
 
4968
5079
class cmd_merge_directive(Command):
4969
 
    """Generate a merge directive for auto-merge tools.
 
5080
    __doc__ = """Generate a merge directive for auto-merge tools.
4970
5081
 
4971
5082
    A directive requests a merge to be performed, and also provides all the
4972
5083
    information necessary to do so.  This means it must either include a
4989
5100
    _see_also = ['send']
4990
5101
 
4991
5102
    takes_options = [
 
5103
        'directory',
4992
5104
        RegistryOption.from_kwargs('patch-type',
4993
5105
            'The type of patch to include in the directive.',
4994
5106
            title='Patch type',
5007
5119
    encoding_type = 'exact'
5008
5120
 
5009
5121
    def run(self, submit_branch=None, public_branch=None, patch_type='bundle',
5010
 
            sign=False, revision=None, mail_to=None, message=None):
 
5122
            sign=False, revision=None, mail_to=None, message=None,
 
5123
            directory=u'.'):
5011
5124
        from bzrlib.revision import ensure_null, NULL_REVISION
5012
5125
        include_patch, include_bundle = {
5013
5126
            'plain': (False, False),
5014
5127
            'diff': (True, False),
5015
5128
            'bundle': (True, True),
5016
5129
            }[patch_type]
5017
 
        branch = Branch.open('.')
 
5130
        branch = Branch.open(directory)
5018
5131
        stored_submit_branch = branch.get_submit_branch()
5019
5132
        if submit_branch is None:
5020
5133
            submit_branch = stored_submit_branch
5065
5178
 
5066
5179
 
5067
5180
class cmd_send(Command):
5068
 
    """Mail or create a merge-directive for submitting changes.
 
5181
    __doc__ = """Mail or create a merge-directive for submitting changes.
5069
5182
 
5070
5183
    A merge directive provides many things needed for requesting merges:
5071
5184
 
5105
5218
    given, in which case it is sent to a file.
5106
5219
 
5107
5220
    Mail is sent using your preferred mail program.  This should be transparent
5108
 
    on Windows (it uses MAPI).  On Linux, it requires the xdg-email utility.
 
5221
    on Windows (it uses MAPI).  On Unix, it requires the xdg-email utility.
5109
5222
    If the preferred client can't be found (or used), your editor will be used.
5110
5223
 
5111
5224
    To use a specific mail program, set the mail_client configuration option.
5182
5295
 
5183
5296
 
5184
5297
class cmd_bundle_revisions(cmd_send):
5185
 
    """Create a merge-directive for submitting changes.
 
5298
    __doc__ = """Create a merge-directive for submitting changes.
5186
5299
 
5187
5300
    A merge directive provides many things needed for requesting merges:
5188
5301
 
5255
5368
 
5256
5369
 
5257
5370
class cmd_tag(Command):
5258
 
    """Create, remove or modify a tag naming a revision.
 
5371
    __doc__ = """Create, remove or modify a tag naming a revision.
5259
5372
 
5260
5373
    Tags give human-meaningful names to revisions.  Commands that take a -r
5261
5374
    (--revision) option can be given -rtag:X, where X is any previously
5282
5395
        Option('delete',
5283
5396
            help='Delete this tag rather than placing it.',
5284
5397
            ),
5285
 
        Option('directory',
5286
 
            help='Branch in which to place the tag.',
5287
 
            short_name='d',
5288
 
            type=unicode,
5289
 
            ),
 
5398
        custom_help('directory',
 
5399
            help='Branch in which to place the tag.'),
5290
5400
        Option('force',
5291
5401
            help='Replace existing tags.',
5292
5402
            ),
5300
5410
            revision=None,
5301
5411
            ):
5302
5412
        branch, relpath = Branch.open_containing(directory)
5303
 
        branch.lock_write()
5304
 
        self.add_cleanup(branch.unlock)
 
5413
        self.add_cleanup(branch.lock_write().unlock)
5305
5414
        if delete:
5306
5415
            if tag_name is None:
5307
5416
                raise errors.BzrCommandError("No tag specified to delete.")
5308
5417
            branch.tags.delete_tag(tag_name)
5309
 
            self.outf.write('Deleted tag %s.\n' % tag_name)
 
5418
            note('Deleted tag %s.' % tag_name)
5310
5419
        else:
5311
5420
            if revision:
5312
5421
                if len(revision) != 1:
5324
5433
            if (not force) and branch.tags.has_tag(tag_name):
5325
5434
                raise errors.TagAlreadyExists(tag_name)
5326
5435
            branch.tags.set_tag(tag_name, revision_id)
5327
 
            self.outf.write('Created tag %s.\n' % tag_name)
 
5436
            note('Created tag %s.' % tag_name)
5328
5437
 
5329
5438
 
5330
5439
class cmd_tags(Command):
5331
 
    """List tags.
 
5440
    __doc__ = """List tags.
5332
5441
 
5333
5442
    This command shows a table of tag names and the revisions they reference.
5334
5443
    """
5335
5444
 
5336
5445
    _see_also = ['tag']
5337
5446
    takes_options = [
5338
 
        Option('directory',
5339
 
            help='Branch whose tags should be displayed.',
5340
 
            short_name='d',
5341
 
            type=unicode,
5342
 
            ),
 
5447
        custom_help('directory',
 
5448
            help='Branch whose tags should be displayed.'),
5343
5449
        RegistryOption.from_kwargs('sort',
5344
5450
            'Sort tags by different criteria.', title='Sorting',
5345
 
            alpha='Sort tags lexicographically (default).',
 
5451
            natural='Sort numeric substrings as numbers:'
 
5452
                    ' suitable for version numbers. (default)',
 
5453
            alpha='Sort tags lexicographically.',
5346
5454
            time='Sort tags chronologically.',
5347
5455
            ),
5348
5456
        'show-ids',
5352
5460
    @display_command
5353
5461
    def run(self,
5354
5462
            directory='.',
5355
 
            sort='alpha',
 
5463
            sort='natural',
5356
5464
            show_ids=False,
5357
5465
            revision=None,
5358
5466
            ):
5362
5470
        if not tags:
5363
5471
            return
5364
5472
 
5365
 
        branch.lock_read()
5366
 
        self.add_cleanup(branch.unlock)
 
5473
        self.add_cleanup(branch.lock_read().unlock)
5367
5474
        if revision:
5368
5475
            graph = branch.repository.get_graph()
5369
5476
            rev1, rev2 = _get_revision_range(revision, branch, self.name())
5371
5478
            # only show revisions between revid1 and revid2 (inclusive)
5372
5479
            tags = [(tag, revid) for tag, revid in tags if
5373
5480
                graph.is_between(revid, revid1, revid2)]
5374
 
        if sort == 'alpha':
 
5481
        if sort == 'natural':
 
5482
            def natural_sort_key(tag):
 
5483
                return [f(s) for f,s in 
 
5484
                        zip(itertools.cycle((unicode.lower,int)),
 
5485
                                            re.split('([0-9]+)', tag[0]))]
 
5486
            tags.sort(key=natural_sort_key)
 
5487
        elif sort == 'alpha':
5375
5488
            tags.sort()
5376
5489
        elif sort == 'time':
5377
5490
            timestamps = {}
5402
5515
 
5403
5516
 
5404
5517
class cmd_reconfigure(Command):
5405
 
    """Reconfigure the type of a bzr directory.
 
5518
    __doc__ = """Reconfigure the type of a bzr directory.
5406
5519
 
5407
5520
    A target configuration must be specified.
5408
5521
 
5493
5606
 
5494
5607
 
5495
5608
class cmd_switch(Command):
5496
 
    """Set the branch of a checkout and update.
 
5609
    __doc__ = """Set the branch of a checkout and update.
5497
5610
 
5498
5611
    For lightweight checkouts, this changes the branch being referenced.
5499
5612
    For heavyweight checkouts, this checks that there are no local commits
5516
5629
    """
5517
5630
 
5518
5631
    takes_args = ['to_location?']
5519
 
    takes_options = [Option('force',
 
5632
    takes_options = ['directory',
 
5633
                     Option('force',
5520
5634
                        help='Switch even if local commits will be lost.'),
5521
5635
                     'revision',
5522
5636
                     Option('create-branch', short_name='b',
5525
5639
                    ]
5526
5640
 
5527
5641
    def run(self, to_location=None, force=False, create_branch=False,
5528
 
            revision=None):
 
5642
            revision=None, directory=u'.'):
5529
5643
        from bzrlib import switch
5530
 
        tree_location = '.'
 
5644
        tree_location = directory
5531
5645
        revision = _get_one_revision('switch', revision)
5532
5646
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
5533
5647
        if to_location is None:
5534
5648
            if revision is None:
5535
5649
                raise errors.BzrCommandError('You must supply either a'
5536
5650
                                             ' revision or a location')
5537
 
            to_location = '.'
 
5651
            to_location = tree_location
5538
5652
        try:
5539
5653
            branch = control_dir.open_branch()
5540
5654
            had_explicit_nick = branch.get_config().has_explicit_nickname()
5589
5703
 
5590
5704
 
5591
5705
class cmd_view(Command):
5592
 
    """Manage filtered views.
 
5706
    __doc__ = """Manage filtered views.
5593
5707
 
5594
5708
    Views provide a mask over the tree so that users can focus on
5595
5709
    a subset of a tree when doing their work. After creating a view,
5675
5789
            name=None,
5676
5790
            switch=None,
5677
5791
            ):
5678
 
        tree, file_list = tree_files(file_list, apply_view=False)
 
5792
        tree, file_list = WorkingTree.open_containing_paths(file_list,
 
5793
            apply_view=False)
5679
5794
        current_view, view_dict = tree.views.get_view_info()
5680
5795
        if name is None:
5681
5796
            name = current_view
5743
5858
 
5744
5859
 
5745
5860
class cmd_hooks(Command):
5746
 
    """Show hooks."""
 
5861
    __doc__ = """Show hooks."""
5747
5862
 
5748
5863
    hidden = True
5749
5864
 
5763
5878
 
5764
5879
 
5765
5880
class cmd_remove_branch(Command):
5766
 
    """Remove a branch.
 
5881
    __doc__ = """Remove a branch.
5767
5882
 
5768
5883
    This will remove the branch from the specified location but 
5769
5884
    will keep any working tree or repository in place.
5785
5900
            location = "."
5786
5901
        branch = Branch.open_containing(location)[0]
5787
5902
        branch.bzrdir.destroy_branch()
5788
 
        
 
5903
 
5789
5904
 
5790
5905
class cmd_shelve(Command):
5791
 
    """Temporarily set aside some changes from the current tree.
 
5906
    __doc__ = """Temporarily set aside some changes from the current tree.
5792
5907
 
5793
5908
    Shelve allows you to temporarily put changes you've made "on the shelf",
5794
5909
    ie. out of the way, until a later time when you can bring them back from
5810
5925
 
5811
5926
    You can put multiple items on the shelf, and by default, 'unshelve' will
5812
5927
    restore the most recently shelved changes.
 
5928
 
 
5929
    For complicated changes, it is possible to edit the changes in a separate
 
5930
    editor program to decide what the file remaining in the working copy
 
5931
    should look like.  To do this, add the configuration option
 
5932
 
 
5933
        change_editor = PROGRAM @new_path @old_path
 
5934
 
 
5935
    where @new_path is replaced with the path of the new version of the 
 
5936
    file and @old_path is replaced with the path of the old version of 
 
5937
    the file.  The PROGRAM should save the new file with the desired 
 
5938
    contents of the file in the working tree.
 
5939
        
5813
5940
    """
5814
5941
 
5815
5942
    takes_args = ['file*']
5816
5943
 
5817
5944
    takes_options = [
 
5945
        'directory',
5818
5946
        'revision',
5819
5947
        Option('all', help='Shelve all changes.'),
5820
5948
        'message',
5826
5954
        Option('destroy',
5827
5955
               help='Destroy removed changes instead of shelving them.'),
5828
5956
    ]
5829
 
    _see_also = ['unshelve']
 
5957
    _see_also = ['unshelve', 'configuration']
5830
5958
 
5831
5959
    def run(self, revision=None, all=False, file_list=None, message=None,
5832
 
            writer=None, list=False, destroy=False):
 
5960
            writer=None, list=False, destroy=False, directory=None):
5833
5961
        if list:
5834
 
            return self.run_for_list()
 
5962
            return self.run_for_list(directory=directory)
5835
5963
        from bzrlib.shelf_ui import Shelver
5836
5964
        if writer is None:
5837
5965
            writer = bzrlib.option.diff_writer_registry.get()
5838
5966
        try:
5839
5967
            shelver = Shelver.from_args(writer(sys.stdout), revision, all,
5840
 
                file_list, message, destroy=destroy)
 
5968
                file_list, message, destroy=destroy, directory=directory)
5841
5969
            try:
5842
5970
                shelver.run()
5843
5971
            finally:
5845
5973
        except errors.UserAbort:
5846
5974
            return 0
5847
5975
 
5848
 
    def run_for_list(self):
5849
 
        tree = WorkingTree.open_containing('.')[0]
5850
 
        tree.lock_read()
5851
 
        self.add_cleanup(tree.unlock)
 
5976
    def run_for_list(self, directory=None):
 
5977
        if directory is None:
 
5978
            directory = u'.'
 
5979
        tree = WorkingTree.open_containing(directory)[0]
 
5980
        self.add_cleanup(tree.lock_read().unlock)
5852
5981
        manager = tree.get_shelf_manager()
5853
5982
        shelves = manager.active_shelves()
5854
5983
        if len(shelves) == 0:
5863
5992
 
5864
5993
 
5865
5994
class cmd_unshelve(Command):
5866
 
    """Restore shelved changes.
 
5995
    __doc__ = """Restore shelved changes.
5867
5996
 
5868
5997
    By default, the most recently shelved changes are restored. However if you
5869
5998
    specify a shelf by id those changes will be restored instead.  This works
5872
6001
 
5873
6002
    takes_args = ['shelf_id?']
5874
6003
    takes_options = [
 
6004
        'directory',
5875
6005
        RegistryOption.from_kwargs(
5876
6006
            'action', help="The action to perform.",
5877
6007
            enum_switch=False, value_switches=True,
5885
6015
    ]
5886
6016
    _see_also = ['shelve']
5887
6017
 
5888
 
    def run(self, shelf_id=None, action='apply'):
 
6018
    def run(self, shelf_id=None, action='apply', directory=u'.'):
5889
6019
        from bzrlib.shelf_ui import Unshelver
5890
 
        unshelver = Unshelver.from_args(shelf_id, action)
 
6020
        unshelver = Unshelver.from_args(shelf_id, action, directory=directory)
5891
6021
        try:
5892
6022
            unshelver.run()
5893
6023
        finally:
5895
6025
 
5896
6026
 
5897
6027
class cmd_clean_tree(Command):
5898
 
    """Remove unwanted files from working tree.
 
6028
    __doc__ = """Remove unwanted files from working tree.
5899
6029
 
5900
6030
    By default, only unknown files, not ignored files, are deleted.  Versioned
5901
6031
    files are never deleted.
5909
6039
 
5910
6040
    To check what clean-tree will do, use --dry-run.
5911
6041
    """
5912
 
    takes_options = [Option('ignored', help='Delete all ignored files.'),
 
6042
    takes_options = ['directory',
 
6043
                     Option('ignored', help='Delete all ignored files.'),
5913
6044
                     Option('detritus', help='Delete conflict files, merge'
5914
6045
                            ' backups, and failed selftest dirs.'),
5915
6046
                     Option('unknown',
5918
6049
                            ' deleting them.'),
5919
6050
                     Option('force', help='Do not prompt before deleting.')]
5920
6051
    def run(self, unknown=False, ignored=False, detritus=False, dry_run=False,
5921
 
            force=False):
 
6052
            force=False, directory=u'.'):
5922
6053
        from bzrlib.clean_tree import clean_tree
5923
6054
        if not (unknown or ignored or detritus):
5924
6055
            unknown = True
5925
6056
        if dry_run:
5926
6057
            force = True
5927
 
        clean_tree('.', unknown=unknown, ignored=ignored, detritus=detritus,
5928
 
                   dry_run=dry_run, no_prompt=force)
 
6058
        clean_tree(directory, unknown=unknown, ignored=ignored,
 
6059
                   detritus=detritus, dry_run=dry_run, no_prompt=force)
5929
6060
 
5930
6061
 
5931
6062
class cmd_reference(Command):
5932
 
    """list, view and set branch locations for nested trees.
 
6063
    __doc__ = """list, view and set branch locations for nested trees.
5933
6064
 
5934
6065
    If no arguments are provided, lists the branch locations for nested trees.
5935
6066
    If one argument is provided, display the branch location for that tree.
5975
6106
            self.outf.write('%s %s\n' % (path, location))
5976
6107
 
5977
6108
 
5978
 
from bzrlib.cmd_version_info import cmd_version_info
5979
 
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
5980
 
from bzrlib.foreign import cmd_dpush
5981
 
from bzrlib.sign_my_commits import cmd_sign_my_commits
 
6109
def _register_lazy_builtins():
 
6110
    # register lazy builtins from other modules; called at startup and should
 
6111
    # be only called once.
 
6112
    for (name, aliases, module_name) in [
 
6113
        ('cmd_bundle_info', [], 'bzrlib.bundle.commands'),
 
6114
        ('cmd_config', [], 'bzrlib.config'),
 
6115
        ('cmd_dpush', [], 'bzrlib.foreign'),
 
6116
        ('cmd_version_info', [], 'bzrlib.cmd_version_info'),
 
6117
        ('cmd_resolve', ['resolved'], 'bzrlib.conflicts'),
 
6118
        ('cmd_conflicts', [], 'bzrlib.conflicts'),
 
6119
        ('cmd_sign_my_commits', [], 'bzrlib.sign_my_commits'),
 
6120
        ('cmd_test_script', [], 'bzrlib.cmd_test_script'),
 
6121
        ]:
 
6122
        builtin_command_registry.register_lazy(name, aliases, module_name)