~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-10-07 12:45:51 UTC
  • mfrom: (5459.4.1 561061-ssh-protocol)
  • Revision ID: pqm@pqm.ubuntu.com-20101007124551-zfqhlkqdegiy7otp
(vila) Don't force openssh to use protocol=2 (Neil Martinsen-Burrell)

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:
311
281
            raise errors.BzrCommandError('bzr status --revision takes exactly'
312
282
                                         ' one or two revision specifiers')
313
283
 
314
 
        tree, relfile_list = tree_files(file_list)
 
284
        tree, relfile_list = WorkingTree.open_containing_paths(file_list)
315
285
        # Avoid asking for specific files when that is not needed.
316
286
        if relfile_list == ['']:
317
287
            relfile_list = None
328
298
 
329
299
 
330
300
class cmd_cat_revision(Command):
331
 
    """Write out metadata for a revision.
 
301
    __doc__ = """Write out metadata for a revision.
332
302
 
333
303
    The revision to print can either be specified by a specific
334
304
    revision identifier, or you can use --revision.
336
306
 
337
307
    hidden = True
338
308
    takes_args = ['revision_id?']
339
 
    takes_options = ['revision']
 
309
    takes_options = ['directory', 'revision']
340
310
    # cat-revision is more for frontends so should be exact
341
311
    encoding = 'strict'
342
312
 
 
313
    def print_revision(self, revisions, revid):
 
314
        stream = revisions.get_record_stream([(revid,)], 'unordered', True)
 
315
        record = stream.next()
 
316
        if record.storage_kind == 'absent':
 
317
            raise errors.NoSuchRevision(revisions, revid)
 
318
        revtext = record.get_bytes_as('fulltext')
 
319
        self.outf.write(revtext.decode('utf-8'))
 
320
 
343
321
    @display_command
344
 
    def run(self, revision_id=None, revision=None):
 
322
    def run(self, revision_id=None, revision=None, directory=u'.'):
345
323
        if revision_id is not None and revision is not None:
346
324
            raise errors.BzrCommandError('You can only supply one of'
347
325
                                         ' revision_id or --revision')
348
326
        if revision_id is None and revision is None:
349
327
            raise errors.BzrCommandError('You must supply either'
350
328
                                         ' --revision or a revision_id')
351
 
        b = WorkingTree.open_containing(u'.')[0].branch
352
 
 
353
 
        # TODO: jam 20060112 should cat-revision always output utf-8?
354
 
        if revision_id is not None:
355
 
            revision_id = osutils.safe_revision_id(revision_id, warn=False)
356
 
            try:
357
 
                self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
358
 
            except errors.NoSuchRevision:
359
 
                msg = "The repository %s contains no revision %s." % (b.repository.base,
360
 
                    revision_id)
361
 
                raise errors.BzrCommandError(msg)
362
 
        elif revision is not None:
363
 
            for rev in revision:
364
 
                if rev is None:
365
 
                    raise errors.BzrCommandError('You cannot specify a NULL'
366
 
                                                 ' revision.')
367
 
                rev_id = rev.as_revision_id(b)
368
 
                self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
369
 
 
 
329
        b = WorkingTree.open_containing(directory)[0].branch
 
330
 
 
331
        revisions = b.repository.revisions
 
332
        if revisions is None:
 
333
            raise errors.BzrCommandError('Repository %r does not support '
 
334
                'access to raw revision texts')
 
335
 
 
336
        b.repository.lock_read()
 
337
        try:
 
338
            # TODO: jam 20060112 should cat-revision always output utf-8?
 
339
            if revision_id is not None:
 
340
                revision_id = osutils.safe_revision_id(revision_id, warn=False)
 
341
                try:
 
342
                    self.print_revision(revisions, revision_id)
 
343
                except errors.NoSuchRevision:
 
344
                    msg = "The repository %s contains no revision %s." % (
 
345
                        b.repository.base, revision_id)
 
346
                    raise errors.BzrCommandError(msg)
 
347
            elif revision is not None:
 
348
                for rev in revision:
 
349
                    if rev is None:
 
350
                        raise errors.BzrCommandError(
 
351
                            'You cannot specify a NULL revision.')
 
352
                    rev_id = rev.as_revision_id(b)
 
353
                    self.print_revision(revisions, rev_id)
 
354
        finally:
 
355
            b.repository.unlock()
 
356
        
370
357
 
371
358
class cmd_dump_btree(Command):
372
 
    """Dump the contents of a btree index file to stdout.
 
359
    __doc__ = """Dump the contents of a btree index file to stdout.
373
360
 
374
361
    PATH is a btree index file, it can be any URL. This includes things like
375
362
    .bzr/repository/pack-names, or .bzr/repository/indices/a34b3a...ca4a4.iix
439
426
        for node in bt.iter_all_entries():
440
427
            # Node is made up of:
441
428
            # (index, key, value, [references])
442
 
            refs_as_tuples = static_tuple.as_tuples(node[3])
 
429
            try:
 
430
                refs = node[3]
 
431
            except IndexError:
 
432
                refs_as_tuples = None
 
433
            else:
 
434
                refs_as_tuples = static_tuple.as_tuples(refs)
443
435
            as_tuple = (tuple(node[1]), node[2], refs_as_tuples)
444
436
            self.outf.write('%s\n' % (as_tuple,))
445
437
 
446
438
 
447
439
class cmd_remove_tree(Command):
448
 
    """Remove the working tree from a given branch/checkout.
 
440
    __doc__ = """Remove the working tree from a given branch/checkout.
449
441
 
450
442
    Since a lightweight checkout is little more than a working tree
451
443
    this will refuse to run against one.
457
449
    takes_options = [
458
450
        Option('force',
459
451
               help='Remove the working tree even if it has '
460
 
                    'uncommitted changes.'),
 
452
                    'uncommitted or shelved changes.'),
461
453
        ]
462
454
 
463
455
    def run(self, location_list, force=False):
477
469
            if not force:
478
470
                if (working.has_changes()):
479
471
                    raise errors.UncommittedChanges(working)
 
472
                if working.get_shelf_manager().last_shelf() is not None:
 
473
                    raise errors.ShelvedChanges(working)
480
474
 
481
 
            working_path = working.bzrdir.root_transport.base
482
 
            branch_path = working.branch.bzrdir.root_transport.base
483
 
            if working_path != branch_path:
 
475
            if working.user_url != working.branch.user_url:
484
476
                raise errors.BzrCommandError("You cannot remove the working tree"
485
477
                                             " from a lightweight checkout")
486
478
 
488
480
 
489
481
 
490
482
class cmd_revno(Command):
491
 
    """Show current revision number.
 
483
    __doc__ = """Show current revision number.
492
484
 
493
485
    This is equal to the number of revisions on this branch.
494
486
    """
504
496
        if tree:
505
497
            try:
506
498
                wt = WorkingTree.open_containing(location)[0]
507
 
                wt.lock_read()
 
499
                self.add_cleanup(wt.lock_read().unlock)
508
500
            except (errors.NoWorkingTree, errors.NotLocalUrl):
509
501
                raise errors.NoWorkingTree(location)
510
 
            self.add_cleanup(wt.unlock)
511
502
            revid = wt.last_revision()
512
503
            try:
513
504
                revno_t = wt.branch.revision_id_to_dotted_revno(revid)
516
507
            revno = ".".join(str(n) for n in revno_t)
517
508
        else:
518
509
            b = Branch.open_containing(location)[0]
519
 
            b.lock_read()
520
 
            self.add_cleanup(b.unlock)
 
510
            self.add_cleanup(b.lock_read().unlock)
521
511
            revno = b.revno()
522
512
        self.cleanup_now()
523
513
        self.outf.write(str(revno) + '\n')
524
514
 
525
515
 
526
516
class cmd_revision_info(Command):
527
 
    """Show revision number and revision id for a given revision identifier.
 
517
    __doc__ = """Show revision number and revision id for a given revision identifier.
528
518
    """
529
519
    hidden = True
530
520
    takes_args = ['revision_info*']
531
521
    takes_options = [
532
522
        'revision',
533
 
        Option('directory',
 
523
        custom_help('directory',
534
524
            help='Branch to examine, '
535
 
                 'rather than the one containing the working directory.',
536
 
            short_name='d',
537
 
            type=unicode,
538
 
            ),
 
525
                 'rather than the one containing the working directory.'),
539
526
        Option('tree', help='Show revno of working tree'),
540
527
        ]
541
528
 
546
533
        try:
547
534
            wt = WorkingTree.open_containing(directory)[0]
548
535
            b = wt.branch
549
 
            wt.lock_read()
550
 
            self.add_cleanup(wt.unlock)
 
536
            self.add_cleanup(wt.lock_read().unlock)
551
537
        except (errors.NoWorkingTree, errors.NotLocalUrl):
552
538
            wt = None
553
539
            b = Branch.open_containing(directory)[0]
554
 
            b.lock_read()
555
 
            self.add_cleanup(b.unlock)
 
540
            self.add_cleanup(b.lock_read().unlock)
556
541
        revision_ids = []
557
542
        if revision is not None:
558
543
            revision_ids.extend(rev.as_revision_id(b) for rev in revision)
586
571
 
587
572
 
588
573
class cmd_add(Command):
589
 
    """Add specified files or directories.
 
574
    __doc__ = """Add specified files or directories.
590
575
 
591
576
    In non-recursive mode, all the named items are added, regardless
592
577
    of whether they were previously ignored.  A warning is given if
657
642
                should_print=(not is_quiet()))
658
643
 
659
644
        if base_tree:
660
 
            base_tree.lock_read()
661
 
            self.add_cleanup(base_tree.unlock)
 
645
            self.add_cleanup(base_tree.lock_read().unlock)
662
646
        tree, file_list = tree_files_for_add(file_list)
663
647
        added, ignored = tree.smart_add(file_list, not
664
648
            no_recurse, action=action, save=not dry_run)
672
656
 
673
657
 
674
658
class cmd_mkdir(Command):
675
 
    """Create a new versioned directory.
 
659
    __doc__ = """Create a new versioned directory.
676
660
 
677
661
    This is equivalent to creating the directory and then adding it.
678
662
    """
682
666
 
683
667
    def run(self, dir_list):
684
668
        for d in dir_list:
685
 
            os.mkdir(d)
686
669
            wt, dd = WorkingTree.open_containing(d)
687
 
            wt.add([dd])
688
 
            self.outf.write('added %s\n' % d)
 
670
            base = os.path.dirname(dd)
 
671
            id = wt.path2id(base)
 
672
            if id != None:
 
673
                os.mkdir(d)
 
674
                wt.add([dd])
 
675
                self.outf.write('added %s\n' % d)
 
676
            else:
 
677
                raise errors.NotVersionedError(path=base)
689
678
 
690
679
 
691
680
class cmd_relpath(Command):
692
 
    """Show path of a file relative to root"""
 
681
    __doc__ = """Show path of a file relative to root"""
693
682
 
694
683
    takes_args = ['filename']
695
684
    hidden = True
704
693
 
705
694
 
706
695
class cmd_inventory(Command):
707
 
    """Show inventory of the current working copy or a revision.
 
696
    __doc__ = """Show inventory of the current working copy or a revision.
708
697
 
709
698
    It is possible to limit the output to a particular entry
710
699
    type using the --kind option.  For example: --kind file.
730
719
            raise errors.BzrCommandError('invalid kind %r specified' % (kind,))
731
720
 
732
721
        revision = _get_one_revision('inventory', revision)
733
 
        work_tree, file_list = tree_files(file_list)
734
 
        work_tree.lock_read()
735
 
        self.add_cleanup(work_tree.unlock)
 
722
        work_tree, file_list = WorkingTree.open_containing_paths(file_list)
 
723
        self.add_cleanup(work_tree.lock_read().unlock)
736
724
        if revision is not None:
737
725
            tree = revision.as_tree(work_tree.branch)
738
726
 
739
727
            extra_trees = [work_tree]
740
 
            tree.lock_read()
741
 
            self.add_cleanup(tree.unlock)
 
728
            self.add_cleanup(tree.lock_read().unlock)
742
729
        else:
743
730
            tree = work_tree
744
731
            extra_trees = []
765
752
 
766
753
 
767
754
class cmd_mv(Command):
768
 
    """Move or rename a file.
 
755
    __doc__ = """Move or rename a file.
769
756
 
770
757
    :Usage:
771
758
        bzr mv OLDNAME NEWNAME
803
790
            names_list = []
804
791
        if len(names_list) < 2:
805
792
            raise errors.BzrCommandError("missing file argument")
806
 
        tree, rel_names = tree_files(names_list, canonicalize=False)
807
 
        tree.lock_tree_write()
808
 
        self.add_cleanup(tree.unlock)
 
793
        tree, rel_names = WorkingTree.open_containing_paths(names_list, canonicalize=False)
 
794
        self.add_cleanup(tree.lock_tree_write().unlock)
809
795
        self._run(tree, names_list, rel_names, after)
810
796
 
811
797
    def run_auto(self, names_list, after, dry_run):
815
801
        if after:
816
802
            raise errors.BzrCommandError('--after cannot be specified with'
817
803
                                         ' --auto.')
818
 
        work_tree, file_list = tree_files(names_list, default_branch='.')
819
 
        work_tree.lock_tree_write()
820
 
        self.add_cleanup(work_tree.unlock)
 
804
        work_tree, file_list = WorkingTree.open_containing_paths(
 
805
            names_list, default_directory='.')
 
806
        self.add_cleanup(work_tree.lock_tree_write().unlock)
821
807
        rename_map.RenameMap.guess_renames(work_tree, dry_run)
822
808
 
823
809
    def _run(self, tree, names_list, rel_names, after):
902
888
 
903
889
 
904
890
class cmd_pull(Command):
905
 
    """Turn this branch into a mirror of another branch.
 
891
    __doc__ = """Turn this branch into a mirror of another branch.
906
892
 
907
893
    By default, this command only works on branches that have not diverged.
908
894
    Branches are considered diverged if the destination branch's most recent 
931
917
    takes_options = ['remember', 'overwrite', 'revision',
932
918
        custom_help('verbose',
933
919
            help='Show logs of pulled revisions.'),
934
 
        Option('directory',
 
920
        custom_help('directory',
935
921
            help='Branch to pull into, '
936
 
                 'rather than the one containing the working directory.',
937
 
            short_name='d',
938
 
            type=unicode,
939
 
            ),
 
922
                 'rather than the one containing the working directory.'),
940
923
        Option('local',
941
924
            help="Perform a local pull in a bound "
942
925
                 "branch.  Local pulls are not applied to "
943
926
                 "the master branch."
944
927
            ),
 
928
        Option('show-base',
 
929
            help="Show base revision text in conflicts.")
945
930
        ]
946
931
    takes_args = ['location?']
947
932
    encoding_type = 'replace'
948
933
 
949
934
    def run(self, location=None, remember=False, overwrite=False,
950
935
            revision=None, verbose=False,
951
 
            directory=None, local=False):
 
936
            directory=None, local=False,
 
937
            show_base=False):
952
938
        # FIXME: too much stuff is in the command class
953
939
        revision_id = None
954
940
        mergeable = None
957
943
        try:
958
944
            tree_to = WorkingTree.open_containing(directory)[0]
959
945
            branch_to = tree_to.branch
 
946
            self.add_cleanup(tree_to.lock_write().unlock)
960
947
        except errors.NoWorkingTree:
961
948
            tree_to = None
962
949
            branch_to = Branch.open_containing(directory)[0]
963
 
        
 
950
            self.add_cleanup(branch_to.lock_write().unlock)
 
951
 
 
952
        if tree_to is None and show_base:
 
953
            raise errors.BzrCommandError("Need working tree for --show-base.")
 
954
 
964
955
        if local and not branch_to.get_bound_location():
965
956
            raise errors.LocalRequiresBoundBranch()
966
957
 
996
987
        else:
997
988
            branch_from = Branch.open(location,
998
989
                possible_transports=possible_transports)
 
990
            self.add_cleanup(branch_from.lock_read().unlock)
999
991
 
1000
992
            if branch_to.get_parent() is None or remember:
1001
993
                branch_to.set_parent(branch_from.base)
1002
994
 
1003
 
        if branch_from is not branch_to:
1004
 
            branch_from.lock_read()
1005
 
            self.add_cleanup(branch_from.unlock)
1006
995
        if revision is not None:
1007
996
            revision_id = revision.as_revision_id(branch_from)
1008
997
 
1009
 
        branch_to.lock_write()
1010
 
        self.add_cleanup(branch_to.unlock)
1011
998
        if tree_to is not None:
1012
999
            view_info = _get_view_info_for_change_reporter(tree_to)
1013
1000
            change_reporter = delta._ChangeReporter(
1015
1002
                view_info=view_info)
1016
1003
            result = tree_to.pull(
1017
1004
                branch_from, overwrite, revision_id, change_reporter,
1018
 
                possible_transports=possible_transports, local=local)
 
1005
                possible_transports=possible_transports, local=local,
 
1006
                show_base=show_base)
1019
1007
        else:
1020
1008
            result = branch_to.pull(
1021
1009
                branch_from, overwrite, revision_id, local=local)
1028
1016
 
1029
1017
 
1030
1018
class cmd_push(Command):
1031
 
    """Update a mirror of this branch.
 
1019
    __doc__ = """Update a mirror of this branch.
1032
1020
 
1033
1021
    The target branch will not have its working tree populated because this
1034
1022
    is both expensive, and is not supported on remote file systems.
1058
1046
        Option('create-prefix',
1059
1047
               help='Create the path leading up to the branch '
1060
1048
                    'if it does not already exist.'),
1061
 
        Option('directory',
 
1049
        custom_help('directory',
1062
1050
            help='Branch to push from, '
1063
 
                 'rather than the one containing the working directory.',
1064
 
            short_name='d',
1065
 
            type=unicode,
1066
 
            ),
 
1051
                 'rather than the one containing the working directory.'),
1067
1052
        Option('use-existing-dir',
1068
1053
               help='By default push will fail if the target'
1069
1054
                    ' directory exists, but does not already'
1095
1080
        # Get the source branch
1096
1081
        (tree, br_from,
1097
1082
         _unused) = bzrdir.BzrDir.open_containing_tree_or_branch(directory)
1098
 
        if strict is None:
1099
 
            strict = br_from.get_config().get_user_option_as_bool('push_strict')
1100
 
        if strict is None: strict = True # default value
1101
1083
        # Get the tip's revision_id
1102
1084
        revision = _get_one_revision('push', revision)
1103
1085
        if revision is not None:
1104
1086
            revision_id = revision.in_history(br_from).rev_id
1105
1087
        else:
1106
1088
            revision_id = None
1107
 
        if strict and tree is not None and revision_id is None:
1108
 
            if (tree.has_changes()):
1109
 
                raise errors.UncommittedChanges(
1110
 
                    tree, more='Use --no-strict to force the push.')
1111
 
            if tree.last_revision() != tree.branch.last_revision():
1112
 
                # The tree has lost sync with its branch, there is little
1113
 
                # chance that the user is aware of it but he can still force
1114
 
                # the push with --no-strict
1115
 
                raise errors.OutOfDateTree(
1116
 
                    tree, more='Use --no-strict to force the push.')
1117
 
 
 
1089
        if tree is not None and revision_id is None:
 
1090
            tree.check_changed_or_out_of_date(
 
1091
                strict, 'push_strict',
 
1092
                more_error='Use --no-strict to force the push.',
 
1093
                more_warning='Uncommitted changes will not be pushed.')
1118
1094
        # Get the stacked_on branch, if any
1119
1095
        if stacked_on is not None:
1120
1096
            stacked_on = urlutils.normalize_url(stacked_on)
1152
1128
 
1153
1129
 
1154
1130
class cmd_branch(Command):
1155
 
    """Create a new branch that is a copy of an existing branch.
 
1131
    __doc__ = """Create a new branch that is a copy of an existing branch.
1156
1132
 
1157
1133
    If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
1158
1134
    be used.  In other words, "branch ../foo/bar" will attempt to create ./bar.
1167
1143
 
1168
1144
    _see_also = ['checkout']
1169
1145
    takes_args = ['from_location', 'to_location?']
1170
 
    takes_options = ['revision', Option('hardlink',
1171
 
        help='Hard-link working tree files where possible.'),
 
1146
    takes_options = ['revision',
 
1147
        Option('hardlink', help='Hard-link working tree files where possible.'),
 
1148
        Option('files-from', type=str,
 
1149
               help="Get file contents from this tree."),
1172
1150
        Option('no-tree',
1173
1151
            help="Create a branch without a working-tree."),
1174
1152
        Option('switch',
1192
1170
 
1193
1171
    def run(self, from_location, to_location=None, revision=None,
1194
1172
            hardlink=False, stacked=False, standalone=False, no_tree=False,
1195
 
            use_existing_dir=False, switch=False, bind=False):
 
1173
            use_existing_dir=False, switch=False, bind=False,
 
1174
            files_from=None):
1196
1175
        from bzrlib import switch as _mod_switch
1197
1176
        from bzrlib.tag import _merge_tags_if_possible
1198
1177
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
1199
1178
            from_location)
 
1179
        if not (hardlink or files_from):
 
1180
            # accelerator_tree is usually slower because you have to read N
 
1181
            # files (no readahead, lots of seeks, etc), but allow the user to
 
1182
            # explicitly request it
 
1183
            accelerator_tree = None
 
1184
        if files_from is not None and files_from != from_location:
 
1185
            accelerator_tree = WorkingTree.open(files_from)
1200
1186
        revision = _get_one_revision('branch', revision)
1201
 
        br_from.lock_read()
1202
 
        self.add_cleanup(br_from.unlock)
 
1187
        self.add_cleanup(br_from.lock_read().unlock)
1203
1188
        if revision is not None:
1204
1189
            revision_id = revision.as_revision_id(br_from)
1205
1190
        else:
1265
1250
 
1266
1251
 
1267
1252
class cmd_checkout(Command):
1268
 
    """Create a new checkout of an existing branch.
 
1253
    __doc__ = """Create a new checkout of an existing branch.
1269
1254
 
1270
1255
    If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree for
1271
1256
    the branch found in '.'. This is useful if you have removed the working tree
1310
1295
            to_location = branch_location
1311
1296
        accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch(
1312
1297
            branch_location)
 
1298
        if not (hardlink or files_from):
 
1299
            # accelerator_tree is usually slower because you have to read N
 
1300
            # files (no readahead, lots of seeks, etc), but allow the user to
 
1301
            # explicitly request it
 
1302
            accelerator_tree = None
1313
1303
        revision = _get_one_revision('checkout', revision)
1314
 
        if files_from is not None:
 
1304
        if files_from is not None and files_from != branch_location:
1315
1305
            accelerator_tree = WorkingTree.open(files_from)
1316
1306
        if revision is not None:
1317
1307
            revision_id = revision.as_revision_id(source)
1334
1324
 
1335
1325
 
1336
1326
class cmd_renames(Command):
1337
 
    """Show list of renamed files.
 
1327
    __doc__ = """Show list of renamed files.
1338
1328
    """
1339
1329
    # TODO: Option to show renames between two historical versions.
1340
1330
 
1345
1335
    @display_command
1346
1336
    def run(self, dir=u'.'):
1347
1337
        tree = WorkingTree.open_containing(dir)[0]
1348
 
        tree.lock_read()
1349
 
        self.add_cleanup(tree.unlock)
 
1338
        self.add_cleanup(tree.lock_read().unlock)
1350
1339
        new_inv = tree.inventory
1351
1340
        old_tree = tree.basis_tree()
1352
 
        old_tree.lock_read()
1353
 
        self.add_cleanup(old_tree.unlock)
 
1341
        self.add_cleanup(old_tree.lock_read().unlock)
1354
1342
        old_inv = old_tree.inventory
1355
1343
        renames = []
1356
1344
        iterator = tree.iter_changes(old_tree, include_unchanged=True)
1366
1354
 
1367
1355
 
1368
1356
class cmd_update(Command):
1369
 
    """Update a tree to have the latest code committed to its branch.
 
1357
    __doc__ = """Update a tree to have the latest code committed to its branch.
1370
1358
 
1371
1359
    This will perform a merge into the working tree, and may generate
1372
1360
    conflicts. If you have any local changes, you will still
1375
1363
    If you want to discard your local changes, you can just do a
1376
1364
    'bzr revert' instead of 'bzr commit' after the update.
1377
1365
 
 
1366
    If you want to restore a file that has been removed locally, use
 
1367
    'bzr revert' instead of 'bzr update'.
 
1368
 
1378
1369
    If the tree's branch is bound to a master branch, it will also update
1379
1370
    the branch from the master.
1380
1371
    """
1381
1372
 
1382
1373
    _see_also = ['pull', 'working-trees', 'status-flags']
1383
1374
    takes_args = ['dir?']
1384
 
    takes_options = ['revision']
 
1375
    takes_options = ['revision',
 
1376
                     Option('show-base',
 
1377
                            help="Show base revision text in conflicts."),
 
1378
                     ]
1385
1379
    aliases = ['up']
1386
1380
 
1387
 
    def run(self, dir='.', revision=None):
 
1381
    def run(self, dir='.', revision=None, show_base=None):
1388
1382
        if revision is not None and len(revision) != 1:
1389
1383
            raise errors.BzrCommandError(
1390
1384
                        "bzr update --revision takes exactly one revision")
1394
1388
        master = branch.get_master_branch(
1395
1389
            possible_transports=possible_transports)
1396
1390
        if master is not None:
1397
 
            tree.lock_write()
1398
1391
            branch_location = master.base
 
1392
            tree.lock_write()
1399
1393
        else:
 
1394
            branch_location = tree.branch.base
1400
1395
            tree.lock_tree_write()
1401
 
            branch_location = tree.branch.base
1402
1396
        self.add_cleanup(tree.unlock)
1403
1397
        # get rid of the final '/' and be ready for display
1404
 
        branch_location = urlutils.unescape_for_display(branch_location[:-1],
1405
 
                                                        self.outf.encoding)
 
1398
        branch_location = urlutils.unescape_for_display(
 
1399
            branch_location.rstrip('/'),
 
1400
            self.outf.encoding)
1406
1401
        existing_pending_merges = tree.get_parent_ids()[1:]
1407
1402
        if master is None:
1408
1403
            old_tip = None
1416
1411
        else:
1417
1412
            revision_id = branch.last_revision()
1418
1413
        if revision_id == _mod_revision.ensure_null(tree.last_revision()):
1419
 
            revno = branch.revision_id_to_revno(revision_id)
1420
 
            note("Tree is up to date at revision %d of branch %s" %
1421
 
                (revno, branch_location))
 
1414
            revno = branch.revision_id_to_dotted_revno(revision_id)
 
1415
            note("Tree is up to date at revision %s of branch %s" %
 
1416
                ('.'.join(map(str, revno)), branch_location))
1422
1417
            return 0
1423
1418
        view_info = _get_view_info_for_change_reporter(tree)
1424
1419
        change_reporter = delta._ChangeReporter(
1429
1424
                change_reporter,
1430
1425
                possible_transports=possible_transports,
1431
1426
                revision=revision_id,
1432
 
                old_tip=old_tip)
 
1427
                old_tip=old_tip,
 
1428
                show_base=show_base)
1433
1429
        except errors.NoSuchRevision, e:
1434
1430
            raise errors.BzrCommandError(
1435
1431
                                  "branch has no revision %s\n"
1436
1432
                                  "bzr update --revision only works"
1437
1433
                                  " for a revision in the branch history"
1438
1434
                                  % (e.revision))
1439
 
        revno = tree.branch.revision_id_to_revno(
 
1435
        revno = tree.branch.revision_id_to_dotted_revno(
1440
1436
            _mod_revision.ensure_null(tree.last_revision()))
1441
 
        note('Updated to revision %d of branch %s' %
1442
 
             (revno, branch_location))
1443
 
        if tree.get_parent_ids()[1:] != existing_pending_merges:
 
1437
        note('Updated to revision %s of branch %s' %
 
1438
             ('.'.join(map(str, revno)), branch_location))
 
1439
        parent_ids = tree.get_parent_ids()
 
1440
        if parent_ids[1:] and parent_ids[1:] != existing_pending_merges:
1444
1441
            note('Your local commits will now show as pending merges with '
1445
1442
                 "'bzr status', and can be committed with 'bzr commit'.")
1446
1443
        if conflicts != 0:
1450
1447
 
1451
1448
 
1452
1449
class cmd_info(Command):
1453
 
    """Show information about a working tree, branch or repository.
 
1450
    __doc__ = """Show information about a working tree, branch or repository.
1454
1451
 
1455
1452
    This command will show all known locations and formats associated to the
1456
1453
    tree, branch or repository.
1494
1491
 
1495
1492
 
1496
1493
class cmd_remove(Command):
1497
 
    """Remove files or directories.
 
1494
    __doc__ = """Remove files or directories.
1498
1495
 
1499
 
    This makes bzr stop tracking changes to the specified files. bzr will delete
1500
 
    them if they can easily be recovered using revert. If no options or
1501
 
    parameters are given bzr will scan for files that are being tracked by bzr
1502
 
    but missing in your tree and stop tracking them for you.
 
1496
    This makes Bazaar stop tracking changes to the specified files. Bazaar will
 
1497
    delete them if they can easily be recovered using revert otherwise they
 
1498
    will be backed up (adding an extention of the form .~#~). If no options or
 
1499
    parameters are given Bazaar will scan for files that are being tracked by
 
1500
    Bazaar but missing in your tree and stop tracking them for you.
1503
1501
    """
1504
1502
    takes_args = ['file*']
1505
1503
    takes_options = ['verbose',
1507
1505
        RegistryOption.from_kwargs('file-deletion-strategy',
1508
1506
            'The file deletion mode to be used.',
1509
1507
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1510
 
            safe='Only delete files if they can be'
1511
 
                 ' safely recovered (default).',
 
1508
            safe='Backup changed files (default).',
1512
1509
            keep='Delete from bzr but leave the working copy.',
 
1510
            no_backup='Don\'t backup changed files.',
1513
1511
            force='Delete all the specified files, even if they can not be '
1514
 
                'recovered and even if they are non-empty directories.')]
 
1512
                'recovered and even if they are non-empty directories. '
 
1513
                '(deprecated, use no-backup)')]
1515
1514
    aliases = ['rm', 'del']
1516
1515
    encoding_type = 'replace'
1517
1516
 
1518
1517
    def run(self, file_list, verbose=False, new=False,
1519
1518
        file_deletion_strategy='safe'):
1520
 
        tree, file_list = tree_files(file_list)
 
1519
        if file_deletion_strategy == 'force':
 
1520
            note("(The --force option is deprecated, rather use --no-backup "
 
1521
                "in future.)")
 
1522
            file_deletion_strategy = 'no-backup'
 
1523
 
 
1524
        tree, file_list = WorkingTree.open_containing_paths(file_list)
1521
1525
 
1522
1526
        if file_list is not None:
1523
1527
            file_list = [f for f in file_list]
1524
1528
 
1525
 
        tree.lock_write()
1526
 
        self.add_cleanup(tree.unlock)
 
1529
        self.add_cleanup(tree.lock_write().unlock)
1527
1530
        # Heuristics should probably all move into tree.remove_smart or
1528
1531
        # some such?
1529
1532
        if new:
1544
1547
            file_deletion_strategy = 'keep'
1545
1548
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
1546
1549
            keep_files=file_deletion_strategy=='keep',
1547
 
            force=file_deletion_strategy=='force')
 
1550
            force=(file_deletion_strategy=='no-backup'))
1548
1551
 
1549
1552
 
1550
1553
class cmd_file_id(Command):
1551
 
    """Print file_id of a particular file or directory.
 
1554
    __doc__ = """Print file_id of a particular file or directory.
1552
1555
 
1553
1556
    The file_id is assigned when the file is first added and remains the
1554
1557
    same through all revisions where the file exists, even when it is
1570
1573
 
1571
1574
 
1572
1575
class cmd_file_path(Command):
1573
 
    """Print path of file_ids to a file or directory.
 
1576
    __doc__ = """Print path of file_ids to a file or directory.
1574
1577
 
1575
1578
    This prints one line for each directory down to the target,
1576
1579
    starting at the branch root.
1592
1595
 
1593
1596
 
1594
1597
class cmd_reconcile(Command):
1595
 
    """Reconcile bzr metadata in a branch.
 
1598
    __doc__ = """Reconcile bzr metadata in a branch.
1596
1599
 
1597
1600
    This can correct data mismatches that may have been caused by
1598
1601
    previous ghost operations or bzr upgrades. You should only
1612
1615
 
1613
1616
    _see_also = ['check']
1614
1617
    takes_args = ['branch?']
 
1618
    takes_options = [
 
1619
        Option('canonicalize-chks',
 
1620
               help='Make sure CHKs are in canonical form (repairs '
 
1621
                    'bug 522637).',
 
1622
               hidden=True),
 
1623
        ]
1615
1624
 
1616
 
    def run(self, branch="."):
 
1625
    def run(self, branch=".", canonicalize_chks=False):
1617
1626
        from bzrlib.reconcile import reconcile
1618
1627
        dir = bzrdir.BzrDir.open(branch)
1619
 
        reconcile(dir)
 
1628
        reconcile(dir, canonicalize_chks=canonicalize_chks)
1620
1629
 
1621
1630
 
1622
1631
class cmd_revision_history(Command):
1623
 
    """Display the list of revision ids on a branch."""
 
1632
    __doc__ = """Display the list of revision ids on a branch."""
1624
1633
 
1625
1634
    _see_also = ['log']
1626
1635
    takes_args = ['location?']
1636
1645
 
1637
1646
 
1638
1647
class cmd_ancestry(Command):
1639
 
    """List all revisions merged into this branch."""
 
1648
    __doc__ = """List all revisions merged into this branch."""
1640
1649
 
1641
1650
    _see_also = ['log', 'revision-history']
1642
1651
    takes_args = ['location?']
1661
1670
 
1662
1671
 
1663
1672
class cmd_init(Command):
1664
 
    """Make a directory into a versioned branch.
 
1673
    __doc__ = """Make a directory into a versioned branch.
1665
1674
 
1666
1675
    Use this to create an empty branch, or before importing an
1667
1676
    existing project.
1770
1779
 
1771
1780
 
1772
1781
class cmd_init_repository(Command):
1773
 
    """Create a shared repository for branches to share storage space.
 
1782
    __doc__ = """Create a shared repository for branches to share storage space.
1774
1783
 
1775
1784
    New branches created under the repository directory will store their
1776
1785
    revisions in the repository, not in the branch directory.  For branches
1830
1839
 
1831
1840
 
1832
1841
class cmd_diff(Command):
1833
 
    """Show differences in the working tree, between revisions or branches.
 
1842
    __doc__ = """Show differences in the working tree, between revisions or branches.
1834
1843
 
1835
1844
    If no arguments are given, all changes for the current tree are listed.
1836
1845
    If files are given, only the changes in those files are listed.
1898
1907
        Same as 'bzr diff' but prefix paths with old/ and new/::
1899
1908
 
1900
1909
            bzr diff --prefix old/:new/
 
1910
            
 
1911
        Show the differences using a custom diff program with options::
 
1912
        
 
1913
            bzr diff --using /usr/bin/diff --diff-options -wu
1901
1914
    """
1902
1915
    _see_also = ['status']
1903
1916
    takes_args = ['file*']
1922
1935
            help='Use this command to compare files.',
1923
1936
            type=unicode,
1924
1937
            ),
 
1938
        RegistryOption('format',
 
1939
            help='Diff format to use.',
 
1940
            lazy_registry=('bzrlib.diff', 'format_registry'),
 
1941
            value_switches=False, title='Diff format'),
1925
1942
        ]
1926
1943
    aliases = ['di', 'dif']
1927
1944
    encoding_type = 'exact'
1928
1945
 
1929
1946
    @display_command
1930
1947
    def run(self, revision=None, file_list=None, diff_options=None,
1931
 
            prefix=None, old=None, new=None, using=None):
1932
 
        from bzrlib.diff import get_trees_and_branches_to_diff, show_diff_trees
 
1948
            prefix=None, old=None, new=None, using=None, format=None):
 
1949
        from bzrlib.diff import (get_trees_and_branches_to_diff_locked,
 
1950
            show_diff_trees)
1933
1951
 
1934
1952
        if (prefix is None) or (prefix == '0'):
1935
1953
            # diff -p0 format
1949
1967
            raise errors.BzrCommandError('bzr diff --revision takes exactly'
1950
1968
                                         ' one or two revision specifiers')
1951
1969
 
 
1970
        if using is not None and format is not None:
 
1971
            raise errors.BzrCommandError('--using and --format are mutually '
 
1972
                'exclusive.')
 
1973
 
1952
1974
        (old_tree, new_tree,
1953
1975
         old_branch, new_branch,
1954
 
         specific_files, extra_trees) = get_trees_and_branches_to_diff(
1955
 
            file_list, revision, old, new, apply_view=True)
 
1976
         specific_files, extra_trees) = get_trees_and_branches_to_diff_locked(
 
1977
            file_list, revision, old, new, self.add_cleanup, apply_view=True)
 
1978
        # GNU diff on Windows uses ANSI encoding for filenames
 
1979
        path_encoding = osutils.get_diff_header_encoding()
1956
1980
        return show_diff_trees(old_tree, new_tree, sys.stdout,
1957
1981
                               specific_files=specific_files,
1958
1982
                               external_diff_options=diff_options,
1959
1983
                               old_label=old_label, new_label=new_label,
1960
 
                               extra_trees=extra_trees, using=using)
 
1984
                               extra_trees=extra_trees,
 
1985
                               path_encoding=path_encoding,
 
1986
                               using=using,
 
1987
                               format_cls=format)
1961
1988
 
1962
1989
 
1963
1990
class cmd_deleted(Command):
1964
 
    """List files deleted in the working tree.
 
1991
    __doc__ = """List files deleted in the working tree.
1965
1992
    """
1966
1993
    # TODO: Show files deleted since a previous revision, or
1967
1994
    # between two revisions.
1970
1997
    # level of effort but possibly much less IO.  (Or possibly not,
1971
1998
    # if the directories are very large...)
1972
1999
    _see_also = ['status', 'ls']
1973
 
    takes_options = ['show-ids']
 
2000
    takes_options = ['directory', 'show-ids']
1974
2001
 
1975
2002
    @display_command
1976
 
    def run(self, show_ids=False):
1977
 
        tree = WorkingTree.open_containing(u'.')[0]
1978
 
        tree.lock_read()
1979
 
        self.add_cleanup(tree.unlock)
 
2003
    def run(self, show_ids=False, directory=u'.'):
 
2004
        tree = WorkingTree.open_containing(directory)[0]
 
2005
        self.add_cleanup(tree.lock_read().unlock)
1980
2006
        old = tree.basis_tree()
1981
 
        old.lock_read()
1982
 
        self.add_cleanup(old.unlock)
 
2007
        self.add_cleanup(old.lock_read().unlock)
1983
2008
        for path, ie in old.inventory.iter_entries():
1984
2009
            if not tree.has_id(ie.file_id):
1985
2010
                self.outf.write(path)
1990
2015
 
1991
2016
 
1992
2017
class cmd_modified(Command):
1993
 
    """List files modified in working tree.
 
2018
    __doc__ = """List files modified in working tree.
1994
2019
    """
1995
2020
 
1996
2021
    hidden = True
1997
2022
    _see_also = ['status', 'ls']
1998
 
    takes_options = [
1999
 
            Option('null',
2000
 
                   help='Write an ascii NUL (\\0) separator '
2001
 
                   'between files rather than a newline.')
2002
 
            ]
 
2023
    takes_options = ['directory', 'null']
2003
2024
 
2004
2025
    @display_command
2005
 
    def run(self, null=False):
2006
 
        tree = WorkingTree.open_containing(u'.')[0]
 
2026
    def run(self, null=False, directory=u'.'):
 
2027
        tree = WorkingTree.open_containing(directory)[0]
2007
2028
        td = tree.changes_from(tree.basis_tree())
2008
2029
        for path, id, kind, text_modified, meta_modified in td.modified:
2009
2030
            if null:
2013
2034
 
2014
2035
 
2015
2036
class cmd_added(Command):
2016
 
    """List files added in working tree.
 
2037
    __doc__ = """List files added in working tree.
2017
2038
    """
2018
2039
 
2019
2040
    hidden = True
2020
2041
    _see_also = ['status', 'ls']
2021
 
    takes_options = [
2022
 
            Option('null',
2023
 
                   help='Write an ascii NUL (\\0) separator '
2024
 
                   'between files rather than a newline.')
2025
 
            ]
 
2042
    takes_options = ['directory', 'null']
2026
2043
 
2027
2044
    @display_command
2028
 
    def run(self, null=False):
2029
 
        wt = WorkingTree.open_containing(u'.')[0]
2030
 
        wt.lock_read()
2031
 
        self.add_cleanup(wt.unlock)
 
2045
    def run(self, null=False, directory=u'.'):
 
2046
        wt = WorkingTree.open_containing(directory)[0]
 
2047
        self.add_cleanup(wt.lock_read().unlock)
2032
2048
        basis = wt.basis_tree()
2033
 
        basis.lock_read()
2034
 
        self.add_cleanup(basis.unlock)
 
2049
        self.add_cleanup(basis.lock_read().unlock)
2035
2050
        basis_inv = basis.inventory
2036
2051
        inv = wt.inventory
2037
2052
        for file_id in inv:
2040
2055
            if inv.is_root(file_id) and len(basis_inv) == 0:
2041
2056
                continue
2042
2057
            path = inv.id2path(file_id)
2043
 
            if not os.access(osutils.abspath(path), os.F_OK):
 
2058
            if not os.access(osutils.pathjoin(wt.basedir, path), os.F_OK):
2044
2059
                continue
2045
2060
            if null:
2046
2061
                self.outf.write(path + '\0')
2049
2064
 
2050
2065
 
2051
2066
class cmd_root(Command):
2052
 
    """Show the tree root directory.
 
2067
    __doc__ = """Show the tree root directory.
2053
2068
 
2054
2069
    The root is the nearest enclosing directory with a .bzr control
2055
2070
    directory."""
2079
2094
 
2080
2095
 
2081
2096
class cmd_log(Command):
2082
 
    """Show historical log for a branch or subset of a branch.
 
2097
    __doc__ = """Show historical log for a branch or subset of a branch.
2083
2098
 
2084
2099
    log is bzr's default tool for exploring the history of a branch.
2085
2100
    The branch to use is taken from the first parameter. If no parameters
2246
2261
                   help='Show just the specified revision.'
2247
2262
                   ' See also "help revisionspec".'),
2248
2263
            'log-format',
 
2264
            RegistryOption('authors',
 
2265
                'What names to list as authors - first, all or committer.',
 
2266
                title='Authors',
 
2267
                lazy_registry=('bzrlib.log', 'author_list_registry'),
 
2268
            ),
2249
2269
            Option('levels',
2250
2270
                   short_name='n',
2251
2271
                   help='Number of levels to display - 0 for all, 1 for flat.',
2266
2286
                   help='Show changes made in each revision as a patch.'),
2267
2287
            Option('include-merges',
2268
2288
                   help='Show merged revisions like --levels 0 does.'),
 
2289
            Option('exclude-common-ancestry',
 
2290
                   help='Display only the revisions that are not part'
 
2291
                   ' of both ancestries (require -rX..Y)'
 
2292
                   )
2269
2293
            ]
2270
2294
    encoding_type = 'replace'
2271
2295
 
2281
2305
            message=None,
2282
2306
            limit=None,
2283
2307
            show_diff=False,
2284
 
            include_merges=False):
 
2308
            include_merges=False,
 
2309
            authors=None,
 
2310
            exclude_common_ancestry=False,
 
2311
            ):
2285
2312
        from bzrlib.log import (
2286
2313
            Logger,
2287
2314
            make_log_request_dict,
2288
2315
            _get_info_for_log_files,
2289
2316
            )
2290
2317
        direction = (forward and 'forward') or 'reverse'
 
2318
        if (exclude_common_ancestry
 
2319
            and (revision is None or len(revision) != 2)):
 
2320
            raise errors.BzrCommandError(
 
2321
                '--exclude-common-ancestry requires -r with two revisions')
2291
2322
        if include_merges:
2292
2323
            if levels is None:
2293
2324
                levels = 0
2309
2340
        if file_list:
2310
2341
            # find the file ids to log and check for directory filtering
2311
2342
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(
2312
 
                revision, file_list)
2313
 
            self.add_cleanup(b.unlock)
 
2343
                revision, file_list, self.add_cleanup)
2314
2344
            for relpath, file_id, kind in file_info_list:
2315
2345
                if file_id is None:
2316
2346
                    raise errors.BzrCommandError(
2334
2364
                location = '.'
2335
2365
            dir, relpath = bzrdir.BzrDir.open_containing(location)
2336
2366
            b = dir.open_branch()
2337
 
            b.lock_read()
2338
 
            self.add_cleanup(b.unlock)
 
2367
            self.add_cleanup(b.lock_read().unlock)
2339
2368
            rev1, rev2 = _get_revision_range(revision, b, self.name())
2340
2369
 
2341
2370
        # Decide on the type of delta & diff filtering to use
2361
2390
                        show_timezone=timezone,
2362
2391
                        delta_format=get_verbosity_level(),
2363
2392
                        levels=levels,
2364
 
                        show_advice=levels is None)
 
2393
                        show_advice=levels is None,
 
2394
                        author_list_handler=authors)
2365
2395
 
2366
2396
        # Choose the algorithm for doing the logging. It's annoying
2367
2397
        # having multiple code paths like this but necessary until
2386
2416
            direction=direction, specific_fileids=file_ids,
2387
2417
            start_revision=rev1, end_revision=rev2, limit=limit,
2388
2418
            message_search=message, delta_type=delta_type,
2389
 
            diff_type=diff_type, _match_using_deltas=match_using_deltas)
 
2419
            diff_type=diff_type, _match_using_deltas=match_using_deltas,
 
2420
            exclude_common_ancestry=exclude_common_ancestry,
 
2421
            )
2390
2422
        Logger(b, rqst).show(lf)
2391
2423
 
2392
2424
 
2411
2443
            raise errors.BzrCommandError(
2412
2444
                "bzr %s doesn't accept two revisions in different"
2413
2445
                " branches." % command_name)
2414
 
        rev1 = start_spec.in_history(branch)
 
2446
        if start_spec.spec is None:
 
2447
            # Avoid loading all the history.
 
2448
            rev1 = RevisionInfo(branch, None, None)
 
2449
        else:
 
2450
            rev1 = start_spec.in_history(branch)
2415
2451
        # Avoid loading all of history when we know a missing
2416
2452
        # end of range means the last revision ...
2417
2453
        if end_spec.spec is None:
2446
2482
 
2447
2483
 
2448
2484
class cmd_touching_revisions(Command):
2449
 
    """Return revision-ids which affected a particular file.
 
2485
    __doc__ = """Return revision-ids which affected a particular file.
2450
2486
 
2451
2487
    A more user-friendly interface is "bzr log FILE".
2452
2488
    """
2459
2495
        tree, relpath = WorkingTree.open_containing(filename)
2460
2496
        file_id = tree.path2id(relpath)
2461
2497
        b = tree.branch
2462
 
        b.lock_read()
2463
 
        self.add_cleanup(b.unlock)
 
2498
        self.add_cleanup(b.lock_read().unlock)
2464
2499
        touching_revs = log.find_touching_revisions(b, file_id)
2465
2500
        for revno, revision_id, what in touching_revs:
2466
2501
            self.outf.write("%6d %s\n" % (revno, what))
2467
2502
 
2468
2503
 
2469
2504
class cmd_ls(Command):
2470
 
    """List files in a tree.
 
2505
    __doc__ = """List files in a tree.
2471
2506
    """
2472
2507
 
2473
2508
    _see_also = ['status', 'cat']
2479
2514
                   help='Recurse into subdirectories.'),
2480
2515
            Option('from-root',
2481
2516
                   help='Print paths relative to the root of the branch.'),
2482
 
            Option('unknown', help='Print unknown files.'),
 
2517
            Option('unknown', short_name='u',
 
2518
                help='Print unknown files.'),
2483
2519
            Option('versioned', help='Print versioned files.',
2484
2520
                   short_name='V'),
2485
 
            Option('ignored', help='Print ignored files.'),
2486
 
            Option('null',
2487
 
                   help='Write an ascii NUL (\\0) separator '
2488
 
                   'between files rather than a newline.'),
2489
 
            Option('kind',
 
2521
            Option('ignored', short_name='i',
 
2522
                help='Print ignored files.'),
 
2523
            Option('kind', short_name='k',
2490
2524
                   help='List entries of a particular kind: file, directory, symlink.',
2491
2525
                   type=unicode),
 
2526
            'null',
2492
2527
            'show-ids',
 
2528
            'directory',
2493
2529
            ]
2494
2530
    @display_command
2495
2531
    def run(self, revision=None, verbose=False,
2496
2532
            recursive=False, from_root=False,
2497
2533
            unknown=False, versioned=False, ignored=False,
2498
 
            null=False, kind=None, show_ids=False, path=None):
 
2534
            null=False, kind=None, show_ids=False, path=None, directory=None):
2499
2535
 
2500
2536
        if kind and kind not in ('file', 'directory', 'symlink'):
2501
2537
            raise errors.BzrCommandError('invalid kind specified')
2513
2549
                raise errors.BzrCommandError('cannot specify both --from-root'
2514
2550
                                             ' and PATH')
2515
2551
            fs_path = path
2516
 
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
2517
 
            fs_path)
 
2552
        tree, branch, relpath = \
 
2553
            _open_directory_or_containing_tree_or_branch(fs_path, directory)
2518
2554
 
2519
2555
        # Calculate the prefix to use
2520
2556
        prefix = None
2535
2571
                view_str = views.view_display_str(view_files)
2536
2572
                note("Ignoring files outside view. View is %s" % view_str)
2537
2573
 
2538
 
        tree.lock_read()
2539
 
        self.add_cleanup(tree.unlock)
 
2574
        self.add_cleanup(tree.lock_read().unlock)
2540
2575
        for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
2541
2576
            from_dir=relpath, recursive=recursive):
2542
2577
            # Apply additional masking
2584
2619
 
2585
2620
 
2586
2621
class cmd_unknowns(Command):
2587
 
    """List unknown files.
 
2622
    __doc__ = """List unknown files.
2588
2623
    """
2589
2624
 
2590
2625
    hidden = True
2591
2626
    _see_also = ['ls']
 
2627
    takes_options = ['directory']
2592
2628
 
2593
2629
    @display_command
2594
 
    def run(self):
2595
 
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
 
2630
    def run(self, directory=u'.'):
 
2631
        for f in WorkingTree.open_containing(directory)[0].unknowns():
2596
2632
            self.outf.write(osutils.quotefn(f) + '\n')
2597
2633
 
2598
2634
 
2599
2635
class cmd_ignore(Command):
2600
 
    """Ignore specified files or patterns.
 
2636
    __doc__ = """Ignore specified files or patterns.
2601
2637
 
2602
2638
    See ``bzr help patterns`` for details on the syntax of patterns.
2603
2639
 
2612
2648
    using this command or directly by using an editor, be sure to commit
2613
2649
    it.
2614
2650
    
 
2651
    Bazaar also supports a global ignore file ~/.bazaar/ignore. On Windows
 
2652
    the global ignore file can be found in the application data directory as
 
2653
    C:\\Documents and Settings\\<user>\\Application Data\\Bazaar\\2.0\\ignore.
 
2654
    Global ignores are not touched by this command. The global ignore file
 
2655
    can be edited directly using an editor.
 
2656
 
2615
2657
    Patterns prefixed with '!' are exceptions to ignore patterns and take
2616
2658
    precedence over regular ignores.  Such exceptions are used to specify
2617
2659
    files that should be versioned which would otherwise be ignored.
2657
2699
 
2658
2700
    _see_also = ['status', 'ignored', 'patterns']
2659
2701
    takes_args = ['name_pattern*']
2660
 
    takes_options = [
2661
 
        Option('old-default-rules',
2662
 
               help='Write out the ignore rules bzr < 0.9 always used.')
 
2702
    takes_options = ['directory',
 
2703
        Option('default-rules',
 
2704
               help='Display the default ignore rules that bzr uses.')
2663
2705
        ]
2664
2706
 
2665
 
    def run(self, name_pattern_list=None, old_default_rules=None):
 
2707
    def run(self, name_pattern_list=None, default_rules=None,
 
2708
            directory=u'.'):
2666
2709
        from bzrlib import ignores
2667
 
        if old_default_rules is not None:
2668
 
            # dump the rules and exit
2669
 
            for pattern in ignores.OLD_DEFAULTS:
2670
 
                print pattern
 
2710
        if default_rules is not None:
 
2711
            # dump the default rules and exit
 
2712
            for pattern in ignores.USER_DEFAULTS:
 
2713
                self.outf.write("%s\n" % pattern)
2671
2714
            return
2672
2715
        if not name_pattern_list:
2673
2716
            raise errors.BzrCommandError("ignore requires at least one "
2674
 
                                  "NAME_PATTERN or --old-default-rules")
 
2717
                "NAME_PATTERN or --default-rules.")
2675
2718
        name_pattern_list = [globbing.normalize_pattern(p)
2676
2719
                             for p in name_pattern_list]
 
2720
        bad_patterns = ''
 
2721
        for p in name_pattern_list:
 
2722
            if not globbing.Globster.is_pattern_valid(p):
 
2723
                bad_patterns += ('\n  %s' % p)
 
2724
        if bad_patterns:
 
2725
            msg = ('Invalid ignore pattern(s) found. %s' % bad_patterns)
 
2726
            ui.ui_factory.show_error(msg)
 
2727
            raise errors.InvalidPattern('')
2677
2728
        for name_pattern in name_pattern_list:
2678
2729
            if (name_pattern[0] == '/' or
2679
2730
                (len(name_pattern) > 1 and name_pattern[1] == ':')):
2680
2731
                raise errors.BzrCommandError(
2681
2732
                    "NAME_PATTERN should not be an absolute path")
2682
 
        tree, relpath = WorkingTree.open_containing(u'.')
 
2733
        tree, relpath = WorkingTree.open_containing(directory)
2683
2734
        ignores.tree_ignores_add_patterns(tree, name_pattern_list)
2684
2735
        ignored = globbing.Globster(name_pattern_list)
2685
2736
        matches = []
2686
 
        tree.lock_read()
 
2737
        self.add_cleanup(tree.lock_read().unlock)
2687
2738
        for entry in tree.list_files():
2688
2739
            id = entry[3]
2689
2740
            if id is not None:
2690
2741
                filename = entry[0]
2691
2742
                if ignored.match(filename):
2692
 
                    matches.append(filename.encode('utf-8'))
2693
 
        tree.unlock()
 
2743
                    matches.append(filename)
2694
2744
        if len(matches) > 0:
2695
 
            print "Warning: the following files are version controlled and" \
2696
 
                  " match your ignore pattern:\n%s" \
2697
 
                  "\nThese files will continue to be version controlled" \
2698
 
                  " unless you 'bzr remove' them." % ("\n".join(matches),)
 
2745
            self.outf.write("Warning: the following files are version controlled and"
 
2746
                  " match your ignore pattern:\n%s"
 
2747
                  "\nThese files will continue to be version controlled"
 
2748
                  " unless you 'bzr remove' them.\n" % ("\n".join(matches),))
2699
2749
 
2700
2750
 
2701
2751
class cmd_ignored(Command):
2702
 
    """List ignored files and the patterns that matched them.
 
2752
    __doc__ = """List ignored files and the patterns that matched them.
2703
2753
 
2704
2754
    List all the ignored files and the ignore pattern that caused the file to
2705
2755
    be ignored.
2711
2761
 
2712
2762
    encoding_type = 'replace'
2713
2763
    _see_also = ['ignore', 'ls']
 
2764
    takes_options = ['directory']
2714
2765
 
2715
2766
    @display_command
2716
 
    def run(self):
2717
 
        tree = WorkingTree.open_containing(u'.')[0]
2718
 
        tree.lock_read()
2719
 
        self.add_cleanup(tree.unlock)
 
2767
    def run(self, directory=u'.'):
 
2768
        tree = WorkingTree.open_containing(directory)[0]
 
2769
        self.add_cleanup(tree.lock_read().unlock)
2720
2770
        for path, file_class, kind, file_id, entry in tree.list_files():
2721
2771
            if file_class != 'I':
2722
2772
                continue
2726
2776
 
2727
2777
 
2728
2778
class cmd_lookup_revision(Command):
2729
 
    """Lookup the revision-id from a revision-number
 
2779
    __doc__ = """Lookup the revision-id from a revision-number
2730
2780
 
2731
2781
    :Examples:
2732
2782
        bzr lookup-revision 33
2733
2783
    """
2734
2784
    hidden = True
2735
2785
    takes_args = ['revno']
 
2786
    takes_options = ['directory']
2736
2787
 
2737
2788
    @display_command
2738
 
    def run(self, revno):
 
2789
    def run(self, revno, directory=u'.'):
2739
2790
        try:
2740
2791
            revno = int(revno)
2741
2792
        except ValueError:
2742
 
            raise errors.BzrCommandError("not a valid revision-number: %r" % revno)
2743
 
 
2744
 
        print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
 
2793
            raise errors.BzrCommandError("not a valid revision-number: %r"
 
2794
                                         % revno)
 
2795
        revid = WorkingTree.open_containing(directory)[0].branch.get_rev_id(revno)
 
2796
        self.outf.write("%s\n" % revid)
2745
2797
 
2746
2798
 
2747
2799
class cmd_export(Command):
2748
 
    """Export current or past revision to a destination directory or archive.
 
2800
    __doc__ = """Export current or past revision to a destination directory or archive.
2749
2801
 
2750
2802
    If no revision is specified this exports the last committed revision.
2751
2803
 
2773
2825
      =================       =========================
2774
2826
    """
2775
2827
    takes_args = ['dest', 'branch_or_subdir?']
2776
 
    takes_options = [
 
2828
    takes_options = ['directory',
2777
2829
        Option('format',
2778
2830
               help="Type of file to export to.",
2779
2831
               type=unicode),
2783
2835
        Option('root',
2784
2836
               type=str,
2785
2837
               help="Name of the root directory inside the exported file."),
 
2838
        Option('per-file-timestamps',
 
2839
               help='Set modification time of files to that of the last '
 
2840
                    'revision in which it was changed.'),
2786
2841
        ]
2787
2842
    def run(self, dest, branch_or_subdir=None, revision=None, format=None,
2788
 
        root=None, filters=False):
 
2843
        root=None, filters=False, per_file_timestamps=False, directory=u'.'):
2789
2844
        from bzrlib.export import export
2790
2845
 
2791
2846
        if branch_or_subdir is None:
2792
 
            tree = WorkingTree.open_containing(u'.')[0]
 
2847
            tree = WorkingTree.open_containing(directory)[0]
2793
2848
            b = tree.branch
2794
2849
            subdir = None
2795
2850
        else:
2798
2853
 
2799
2854
        rev_tree = _get_one_revision_tree('export', revision, branch=b, tree=tree)
2800
2855
        try:
2801
 
            export(rev_tree, dest, format, root, subdir, filtered=filters)
 
2856
            export(rev_tree, dest, format, root, subdir, filtered=filters,
 
2857
                   per_file_timestamps=per_file_timestamps)
2802
2858
        except errors.NoSuchExportFormat, e:
2803
2859
            raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
2804
2860
 
2805
2861
 
2806
2862
class cmd_cat(Command):
2807
 
    """Write the contents of a file as of a given revision to standard output.
 
2863
    __doc__ = """Write the contents of a file as of a given revision to standard output.
2808
2864
 
2809
2865
    If no revision is nominated, the last revision is used.
2810
2866
 
2813
2869
    """
2814
2870
 
2815
2871
    _see_also = ['ls']
2816
 
    takes_options = [
 
2872
    takes_options = ['directory',
2817
2873
        Option('name-from-revision', help='The path name in the old tree.'),
2818
2874
        Option('filters', help='Apply content filters to display the '
2819
2875
                'convenience form.'),
2824
2880
 
2825
2881
    @display_command
2826
2882
    def run(self, filename, revision=None, name_from_revision=False,
2827
 
            filters=False):
 
2883
            filters=False, directory=None):
2828
2884
        if revision is not None and len(revision) != 1:
2829
2885
            raise errors.BzrCommandError("bzr cat --revision takes exactly"
2830
2886
                                         " one revision specifier")
2831
2887
        tree, branch, relpath = \
2832
 
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2833
 
        branch.lock_read()
2834
 
        self.add_cleanup(branch.unlock)
 
2888
            _open_directory_or_containing_tree_or_branch(filename, directory)
 
2889
        self.add_cleanup(branch.lock_read().unlock)
2835
2890
        return self._run(tree, branch, relpath, filename, revision,
2836
2891
                         name_from_revision, filters)
2837
2892
 
2840
2895
        if tree is None:
2841
2896
            tree = b.basis_tree()
2842
2897
        rev_tree = _get_one_revision_tree('cat', revision, branch=b)
2843
 
        rev_tree.lock_read()
2844
 
        self.add_cleanup(rev_tree.unlock)
 
2898
        self.add_cleanup(rev_tree.lock_read().unlock)
2845
2899
 
2846
2900
        old_file_id = rev_tree.path2id(relpath)
2847
2901
 
2890
2944
 
2891
2945
 
2892
2946
class cmd_local_time_offset(Command):
2893
 
    """Show the offset in seconds from GMT to local time."""
 
2947
    __doc__ = """Show the offset in seconds from GMT to local time."""
2894
2948
    hidden = True
2895
2949
    @display_command
2896
2950
    def run(self):
2897
 
        print osutils.local_time_offset()
 
2951
        self.outf.write("%s\n" % osutils.local_time_offset())
2898
2952
 
2899
2953
 
2900
2954
 
2901
2955
class cmd_commit(Command):
2902
 
    """Commit changes into a new revision.
 
2956
    __doc__ = """Commit changes into a new revision.
2903
2957
 
2904
2958
    An explanatory message needs to be given for each commit. This is
2905
2959
    often done by using the --message option (getting the message from the
3013
3067
                         "the master branch until a normal commit "
3014
3068
                         "is performed."
3015
3069
                    ),
3016
 
             Option('show-diff',
 
3070
             Option('show-diff', short_name='p',
3017
3071
                    help='When no message is supplied, show the diff along'
3018
3072
                    ' with the status summary in the message editor.'),
3019
3073
             ]
3068
3122
 
3069
3123
        properties = {}
3070
3124
 
3071
 
        tree, selected_list = tree_files(selected_list)
 
3125
        tree, selected_list = WorkingTree.open_containing_paths(selected_list)
3072
3126
        if selected_list == ['']:
3073
3127
            # workaround - commit of root of tree should be exactly the same
3074
3128
            # as just default commit in that tree, and succeed even though
3099
3153
                    '(use --file "%(f)s" to take commit message from that file)'
3100
3154
                    % { 'f': message })
3101
3155
                ui.ui_factory.show_warning(warning_msg)
 
3156
            if '\r' in message:
 
3157
                message = message.replace('\r\n', '\n')
 
3158
                message = message.replace('\r', '\n')
 
3159
            if file:
 
3160
                raise errors.BzrCommandError(
 
3161
                    "please specify either --message or --file")
3102
3162
 
3103
3163
        def get_message(commit_obj):
3104
3164
            """Callback to get commit message"""
3105
 
            my_message = message
3106
 
            if my_message is not None and '\r' in my_message:
3107
 
                my_message = my_message.replace('\r\n', '\n')
3108
 
                my_message = my_message.replace('\r', '\n')
3109
 
            if my_message is None and not file:
3110
 
                t = make_commit_message_template_encoded(tree,
 
3165
            if file:
 
3166
                f = open(file)
 
3167
                try:
 
3168
                    my_message = f.read().decode(osutils.get_user_encoding())
 
3169
                finally:
 
3170
                    f.close()
 
3171
            elif message is not None:
 
3172
                my_message = message
 
3173
            else:
 
3174
                # No message supplied: make one up.
 
3175
                # text is the status of the tree
 
3176
                text = make_commit_message_template_encoded(tree,
3111
3177
                        selected_list, diff=show_diff,
3112
3178
                        output_encoding=osutils.get_user_encoding())
 
3179
                # start_message is the template generated from hooks
 
3180
                # XXX: Warning - looks like hooks return unicode,
 
3181
                # make_commit_message_template_encoded returns user encoding.
 
3182
                # We probably want to be using edit_commit_message instead to
 
3183
                # avoid this.
3113
3184
                start_message = generate_commit_message_template(commit_obj)
3114
 
                my_message = edit_commit_message_encoded(t,
 
3185
                my_message = edit_commit_message_encoded(text,
3115
3186
                    start_message=start_message)
3116
3187
                if my_message is None:
3117
3188
                    raise errors.BzrCommandError("please specify a commit"
3118
3189
                        " message with either --message or --file")
3119
 
            elif my_message and file:
3120
 
                raise errors.BzrCommandError(
3121
 
                    "please specify either --message or --file")
3122
 
            if file:
3123
 
                my_message = codecs.open(file, 'rt',
3124
 
                                         osutils.get_user_encoding()).read()
3125
3190
            if my_message == "":
3126
3191
                raise errors.BzrCommandError("empty commit message specified")
3127
3192
            return my_message
3137
3202
                        reporter=None, verbose=verbose, revprops=properties,
3138
3203
                        authors=author, timestamp=commit_stamp,
3139
3204
                        timezone=offset,
3140
 
                        exclude=safe_relpath_files(tree, exclude))
 
3205
                        exclude=tree.safe_relpath_files(exclude))
3141
3206
        except PointlessCommit:
3142
 
            # FIXME: This should really happen before the file is read in;
3143
 
            # perhaps prepare the commit; get the message; then actually commit
3144
3207
            raise errors.BzrCommandError("No changes to commit."
3145
3208
                              " Use --unchanged to commit anyhow.")
3146
3209
        except ConflictsInTree:
3151
3214
            raise errors.BzrCommandError("Commit refused because there are"
3152
3215
                              " unknown files in the working tree.")
3153
3216
        except errors.BoundBranchOutOfDate, e:
3154
 
            raise errors.BzrCommandError(str(e) + "\n"
3155
 
            'To commit to master branch, run update and then commit.\n'
3156
 
            'You can also pass --local to commit to continue working '
3157
 
            'disconnected.')
 
3217
            e.extra_help = ("\n"
 
3218
                'To commit to master branch, run update and then commit.\n'
 
3219
                'You can also pass --local to commit to continue working '
 
3220
                'disconnected.')
 
3221
            raise
3158
3222
 
3159
3223
 
3160
3224
class cmd_check(Command):
3161
 
    """Validate working tree structure, branch consistency and repository history.
 
3225
    __doc__ = """Validate working tree structure, branch consistency and repository history.
3162
3226
 
3163
3227
    This command checks various invariants about branch and repository storage
3164
3228
    to detect data corruption or bzr bugs.
3228
3292
 
3229
3293
 
3230
3294
class cmd_upgrade(Command):
3231
 
    """Upgrade branch storage to current format.
 
3295
    __doc__ = """Upgrade branch storage to current format.
3232
3296
 
3233
3297
    The check command or bzr developers may sometimes advise you to run
3234
3298
    this command. When the default format has changed you may also be warned
3252
3316
 
3253
3317
 
3254
3318
class cmd_whoami(Command):
3255
 
    """Show or set bzr user id.
 
3319
    __doc__ = """Show or set bzr user id.
3256
3320
 
3257
3321
    :Examples:
3258
3322
        Show the email of the current user::
3263
3327
 
3264
3328
            bzr whoami "Frank Chu <fchu@example.com>"
3265
3329
    """
3266
 
    takes_options = [ Option('email',
 
3330
    takes_options = [ 'directory',
 
3331
                      Option('email',
3267
3332
                             help='Display email address only.'),
3268
3333
                      Option('branch',
3269
3334
                             help='Set identity for the current branch instead of '
3273
3338
    encoding_type = 'replace'
3274
3339
 
3275
3340
    @display_command
3276
 
    def run(self, email=False, branch=False, name=None):
 
3341
    def run(self, email=False, branch=False, name=None, directory=None):
3277
3342
        if name is None:
3278
 
            # use branch if we're inside one; otherwise global config
3279
 
            try:
3280
 
                c = Branch.open_containing('.')[0].get_config()
3281
 
            except errors.NotBranchError:
3282
 
                c = config.GlobalConfig()
 
3343
            if directory is None:
 
3344
                # use branch if we're inside one; otherwise global config
 
3345
                try:
 
3346
                    c = Branch.open_containing(u'.')[0].get_config()
 
3347
                except errors.NotBranchError:
 
3348
                    c = _mod_config.GlobalConfig()
 
3349
            else:
 
3350
                c = Branch.open(directory).get_config()
3283
3351
            if email:
3284
3352
                self.outf.write(c.user_email() + '\n')
3285
3353
            else:
3288
3356
 
3289
3357
        # display a warning if an email address isn't included in the given name.
3290
3358
        try:
3291
 
            config.extract_email_address(name)
 
3359
            _mod_config.extract_email_address(name)
3292
3360
        except errors.NoEmailInUsername, e:
3293
3361
            warning('"%s" does not seem to contain an email address.  '
3294
3362
                    'This is allowed, but not recommended.', name)
3295
3363
 
3296
3364
        # use global config unless --branch given
3297
3365
        if branch:
3298
 
            c = Branch.open_containing('.')[0].get_config()
 
3366
            if directory is None:
 
3367
                c = Branch.open_containing(u'.')[0].get_config()
 
3368
            else:
 
3369
                c = Branch.open(directory).get_config()
3299
3370
        else:
3300
 
            c = config.GlobalConfig()
 
3371
            c = _mod_config.GlobalConfig()
3301
3372
        c.set_user_option('email', name)
3302
3373
 
3303
3374
 
3304
3375
class cmd_nick(Command):
3305
 
    """Print or set the branch nickname.
 
3376
    __doc__ = """Print or set the branch nickname.
3306
3377
 
3307
3378
    If unset, the tree root directory name is used as the nickname.
3308
3379
    To print the current nickname, execute with no argument.
3313
3384
 
3314
3385
    _see_also = ['info']
3315
3386
    takes_args = ['nickname?']
3316
 
    def run(self, nickname=None):
3317
 
        branch = Branch.open_containing(u'.')[0]
 
3387
    takes_options = ['directory']
 
3388
    def run(self, nickname=None, directory=u'.'):
 
3389
        branch = Branch.open_containing(directory)[0]
3318
3390
        if nickname is None:
3319
3391
            self.printme(branch)
3320
3392
        else:
3322
3394
 
3323
3395
    @display_command
3324
3396
    def printme(self, branch):
3325
 
        print branch.nick
 
3397
        self.outf.write('%s\n' % branch.nick)
3326
3398
 
3327
3399
 
3328
3400
class cmd_alias(Command):
3329
 
    """Set/unset and display aliases.
 
3401
    __doc__ = """Set/unset and display aliases.
3330
3402
 
3331
3403
    :Examples:
3332
3404
        Show the current aliases::
3369
3441
                'bzr alias --remove expects an alias to remove.')
3370
3442
        # If alias is not found, print something like:
3371
3443
        # unalias: foo: not found
3372
 
        c = config.GlobalConfig()
 
3444
        c = _mod_config.GlobalConfig()
3373
3445
        c.unset_alias(alias_name)
3374
3446
 
3375
3447
    @display_command
3376
3448
    def print_aliases(self):
3377
3449
        """Print out the defined aliases in a similar format to bash."""
3378
 
        aliases = config.GlobalConfig().get_aliases()
 
3450
        aliases = _mod_config.GlobalConfig().get_aliases()
3379
3451
        for key, value in sorted(aliases.iteritems()):
3380
3452
            self.outf.write('bzr alias %s="%s"\n' % (key, value))
3381
3453
 
3391
3463
 
3392
3464
    def set_alias(self, alias_name, alias_command):
3393
3465
        """Save the alias in the global config."""
3394
 
        c = config.GlobalConfig()
 
3466
        c = _mod_config.GlobalConfig()
3395
3467
        c.set_alias(alias_name, alias_command)
3396
3468
 
3397
3469
 
3398
3470
class cmd_selftest(Command):
3399
 
    """Run internal test suite.
 
3471
    __doc__ = """Run internal test suite.
3400
3472
 
3401
3473
    If arguments are given, they are regular expressions that say which tests
3402
3474
    should run.  Tests matching any expression are run, and other tests are
3432
3504
    If you set BZR_TEST_PDB=1 when running selftest, failing tests will drop
3433
3505
    into a pdb postmortem session.
3434
3506
 
 
3507
    The --coverage=DIRNAME global option produces a report with covered code
 
3508
    indicated.
 
3509
 
3435
3510
    :Examples:
3436
3511
        Run only tests relating to 'ignore'::
3437
3512
 
3470
3545
                                 'throughout the test suite.',
3471
3546
                            type=get_transport_type),
3472
3547
                     Option('benchmark',
3473
 
                            help='Run the benchmarks rather than selftests.'),
 
3548
                            help='Run the benchmarks rather than selftests.',
 
3549
                            hidden=True),
3474
3550
                     Option('lsprof-timed',
3475
3551
                            help='Generate lsprof output for benchmarked'
3476
3552
                                 ' sections of code.'),
3477
3553
                     Option('lsprof-tests',
3478
3554
                            help='Generate lsprof output for each test.'),
3479
 
                     Option('cache-dir', type=str,
3480
 
                            help='Cache intermediate benchmark output in this '
3481
 
                                 'directory.'),
3482
3555
                     Option('first',
3483
3556
                            help='Run all tests, but run specified tests first.',
3484
3557
                            short_name='f',
3518
3591
 
3519
3592
    def run(self, testspecs_list=None, verbose=False, one=False,
3520
3593
            transport=None, benchmark=None,
3521
 
            lsprof_timed=None, cache_dir=None,
 
3594
            lsprof_timed=None,
3522
3595
            first=False, list_only=False,
3523
3596
            randomize=None, exclude=None, strict=False,
3524
3597
            load_list=None, debugflag=None, starting_with=None, subunit=False,
3525
3598
            parallel=None, lsprof_tests=False):
3526
 
        from bzrlib.tests import selftest
3527
 
        import bzrlib.benchmarks as benchmarks
3528
 
        from bzrlib.benchmarks import tree_creator
3529
 
 
3530
 
        # Make deprecation warnings visible, unless -Werror is set
3531
 
        symbol_versioning.activate_deprecation_warnings(override=False)
3532
 
 
3533
 
        if cache_dir is not None:
3534
 
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
 
3599
        from bzrlib import tests
 
3600
 
3535
3601
        if testspecs_list is not None:
3536
3602
            pattern = '|'.join(testspecs_list)
3537
3603
        else:
3543
3609
                raise errors.BzrCommandError("subunit not available. subunit "
3544
3610
                    "needs to be installed to use --subunit.")
3545
3611
            self.additional_selftest_args['runner_class'] = SubUnitBzrRunner
 
3612
            # On Windows, disable automatic conversion of '\n' to '\r\n' in
 
3613
            # stdout, which would corrupt the subunit stream. 
 
3614
            # FIXME: This has been fixed in subunit trunk (>0.0.5) so the
 
3615
            # following code can be deleted when it's sufficiently deployed
 
3616
            # -- vila/mgz 20100514
 
3617
            if (sys.platform == "win32"
 
3618
                and getattr(sys.stdout, 'fileno', None) is not None):
 
3619
                import msvcrt
 
3620
                msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
3546
3621
        if parallel:
3547
3622
            self.additional_selftest_args.setdefault(
3548
3623
                'suite_decorators', []).append(parallel)
3549
3624
        if benchmark:
3550
 
            test_suite_factory = benchmarks.test_suite
3551
 
            # Unless user explicitly asks for quiet, be verbose in benchmarks
3552
 
            verbose = not is_quiet()
3553
 
            # TODO: should possibly lock the history file...
3554
 
            benchfile = open(".perf_history", "at", buffering=1)
3555
 
            self.add_cleanup(benchfile.close)
3556
 
        else:
3557
 
            test_suite_factory = None
3558
 
            benchfile = None
 
3625
            raise errors.BzrCommandError(
 
3626
                "--benchmark is no longer supported from bzr 2.2; "
 
3627
                "use bzr-usertest instead")
 
3628
        test_suite_factory = None
3559
3629
        selftest_kwargs = {"verbose": verbose,
3560
3630
                          "pattern": pattern,
3561
3631
                          "stop_on_failure": one,
3563
3633
                          "test_suite_factory": test_suite_factory,
3564
3634
                          "lsprof_timed": lsprof_timed,
3565
3635
                          "lsprof_tests": lsprof_tests,
3566
 
                          "bench_history": benchfile,
3567
3636
                          "matching_tests_first": first,
3568
3637
                          "list_only": list_only,
3569
3638
                          "random_seed": randomize,
3574
3643
                          "starting_with": starting_with
3575
3644
                          }
3576
3645
        selftest_kwargs.update(self.additional_selftest_args)
3577
 
        result = selftest(**selftest_kwargs)
 
3646
 
 
3647
        # Make deprecation warnings visible, unless -Werror is set
 
3648
        cleanup = symbol_versioning.activate_deprecation_warnings(
 
3649
            override=False)
 
3650
        try:
 
3651
            result = tests.selftest(**selftest_kwargs)
 
3652
        finally:
 
3653
            cleanup()
3578
3654
        return int(not result)
3579
3655
 
3580
3656
 
3581
3657
class cmd_version(Command):
3582
 
    """Show version of bzr."""
 
3658
    __doc__ = """Show version of bzr."""
3583
3659
 
3584
3660
    encoding_type = 'replace'
3585
3661
    takes_options = [
3596
3672
 
3597
3673
 
3598
3674
class cmd_rocks(Command):
3599
 
    """Statement of optimism."""
 
3675
    __doc__ = """Statement of optimism."""
3600
3676
 
3601
3677
    hidden = True
3602
3678
 
3603
3679
    @display_command
3604
3680
    def run(self):
3605
 
        print "It sure does!"
 
3681
        self.outf.write("It sure does!\n")
3606
3682
 
3607
3683
 
3608
3684
class cmd_find_merge_base(Command):
3609
 
    """Find and print a base revision for merging two branches."""
 
3685
    __doc__ = """Find and print a base revision for merging two branches."""
3610
3686
    # TODO: Options to specify revisions on either side, as if
3611
3687
    #       merging only part of the history.
3612
3688
    takes_args = ['branch', 'other']
3618
3694
 
3619
3695
        branch1 = Branch.open_containing(branch)[0]
3620
3696
        branch2 = Branch.open_containing(other)[0]
3621
 
        branch1.lock_read()
3622
 
        self.add_cleanup(branch1.unlock)
3623
 
        branch2.lock_read()
3624
 
        self.add_cleanup(branch2.unlock)
 
3697
        self.add_cleanup(branch1.lock_read().unlock)
 
3698
        self.add_cleanup(branch2.lock_read().unlock)
3625
3699
        last1 = ensure_null(branch1.last_revision())
3626
3700
        last2 = ensure_null(branch2.last_revision())
3627
3701
 
3628
3702
        graph = branch1.repository.get_graph(branch2.repository)
3629
3703
        base_rev_id = graph.find_unique_lca(last1, last2)
3630
3704
 
3631
 
        print 'merge base is revision %s' % base_rev_id
 
3705
        self.outf.write('merge base is revision %s\n' % base_rev_id)
3632
3706
 
3633
3707
 
3634
3708
class cmd_merge(Command):
3635
 
    """Perform a three-way merge.
 
3709
    __doc__ = """Perform a three-way merge.
3636
3710
 
3637
3711
    The source of the merge can be specified either in the form of a branch,
3638
3712
    or in the form of a path to a file containing a merge directive generated
3721
3795
                ' completely merged into the source, pull from the'
3722
3796
                ' source rather than merging.  When this happens,'
3723
3797
                ' you do not need to commit the result.'),
3724
 
        Option('directory',
 
3798
        custom_help('directory',
3725
3799
               help='Branch to merge into, '
3726
 
                    'rather than the one containing the working directory.',
3727
 
               short_name='d',
3728
 
               type=unicode,
3729
 
               ),
 
3800
                    'rather than the one containing the working directory.'),
3730
3801
        Option('preview', help='Instead of merging, show a diff of the'
3731
3802
               ' merge.'),
3732
3803
        Option('interactive', help='Select changes interactively.',
3765
3836
            unversioned_filter=tree.is_ignored, view_info=view_info)
3766
3837
        pb = ui.ui_factory.nested_progress_bar()
3767
3838
        self.add_cleanup(pb.finished)
3768
 
        tree.lock_write()
3769
 
        self.add_cleanup(tree.unlock)
 
3839
        self.add_cleanup(tree.lock_write().unlock)
3770
3840
        if location is not None:
3771
3841
            try:
3772
3842
                mergeable = bundle.read_mergeable_from_url(location,
3833
3903
    def _do_preview(self, merger):
3834
3904
        from bzrlib.diff import show_diff_trees
3835
3905
        result_tree = self._get_preview(merger)
 
3906
        path_encoding = osutils.get_diff_header_encoding()
3836
3907
        show_diff_trees(merger.this_tree, result_tree, self.outf,
3837
 
                        old_label='', new_label='')
 
3908
                        old_label='', new_label='',
 
3909
                        path_encoding=path_encoding)
3838
3910
 
3839
3911
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
3840
3912
        merger.change_reporter = change_reporter
3993
4065
 
3994
4066
 
3995
4067
class cmd_remerge(Command):
3996
 
    """Redo a merge.
 
4068
    __doc__ = """Redo a merge.
3997
4069
 
3998
4070
    Use this if you want to try a different merge technique while resolving
3999
4071
    conflicts.  Some merge techniques are better than others, and remerge
4024
4096
 
4025
4097
    def run(self, file_list=None, merge_type=None, show_base=False,
4026
4098
            reprocess=False):
 
4099
        from bzrlib.conflicts import restore
4027
4100
        if merge_type is None:
4028
4101
            merge_type = _mod_merge.Merge3Merger
4029
 
        tree, file_list = tree_files(file_list)
4030
 
        tree.lock_write()
4031
 
        self.add_cleanup(tree.unlock)
 
4102
        tree, file_list = WorkingTree.open_containing_paths(file_list)
 
4103
        self.add_cleanup(tree.lock_write().unlock)
4032
4104
        parents = tree.get_parent_ids()
4033
4105
        if len(parents) != 2:
4034
4106
            raise errors.BzrCommandError("Sorry, remerge only works after normal"
4087
4159
 
4088
4160
 
4089
4161
class cmd_revert(Command):
4090
 
    """Revert files to a previous revision.
 
4162
    __doc__ = """Revert files to a previous revision.
4091
4163
 
4092
4164
    Giving a list of files will revert only those files.  Otherwise, all files
4093
4165
    will be reverted.  If the revision is not specified with '--revision', the
4143
4215
 
4144
4216
    def run(self, revision=None, no_backup=False, file_list=None,
4145
4217
            forget_merges=None):
4146
 
        tree, file_list = tree_files(file_list)
4147
 
        tree.lock_write()
4148
 
        self.add_cleanup(tree.unlock)
 
4218
        tree, file_list = WorkingTree.open_containing_paths(file_list)
 
4219
        self.add_cleanup(tree.lock_tree_write().unlock)
4149
4220
        if forget_merges:
4150
4221
            tree.set_parent_ids(tree.get_parent_ids()[:1])
4151
4222
        else:
4159
4230
 
4160
4231
 
4161
4232
class cmd_assert_fail(Command):
4162
 
    """Test reporting of assertion failures"""
 
4233
    __doc__ = """Test reporting of assertion failures"""
4163
4234
    # intended just for use in testing
4164
4235
 
4165
4236
    hidden = True
4169
4240
 
4170
4241
 
4171
4242
class cmd_help(Command):
4172
 
    """Show help on a command or other topic.
 
4243
    __doc__ = """Show help on a command or other topic.
4173
4244
    """
4174
4245
 
4175
4246
    _see_also = ['topics']
4188
4259
 
4189
4260
 
4190
4261
class cmd_shell_complete(Command):
4191
 
    """Show appropriate completions for context.
 
4262
    __doc__ = """Show appropriate completions for context.
4192
4263
 
4193
4264
    For a list of all available commands, say 'bzr shell-complete'.
4194
4265
    """
4203
4274
 
4204
4275
 
4205
4276
class cmd_missing(Command):
4206
 
    """Show unmerged/unpulled revisions between two branches.
 
4277
    __doc__ = """Show unmerged/unpulled revisions between two branches.
4207
4278
 
4208
4279
    OTHER_BRANCH may be local or remote.
4209
4280
 
4240
4311
    _see_also = ['merge', 'pull']
4241
4312
    takes_args = ['other_branch?']
4242
4313
    takes_options = [
 
4314
        'directory',
4243
4315
        Option('reverse', 'Reverse the order of revisions.'),
4244
4316
        Option('mine-only',
4245
4317
               'Display changes in the local branch only.'),
4267
4339
            theirs_only=False,
4268
4340
            log_format=None, long=False, short=False, line=False,
4269
4341
            show_ids=False, verbose=False, this=False, other=False,
4270
 
            include_merges=False, revision=None, my_revision=None):
 
4342
            include_merges=False, revision=None, my_revision=None,
 
4343
            directory=u'.'):
4271
4344
        from bzrlib.missing import find_unmerged, iter_log_revisions
4272
4345
        def message(s):
4273
4346
            if not is_quiet():
4286
4359
        elif theirs_only:
4287
4360
            restrict = 'remote'
4288
4361
 
4289
 
        local_branch = Branch.open_containing(u".")[0]
 
4362
        local_branch = Branch.open_containing(directory)[0]
 
4363
        self.add_cleanup(local_branch.lock_read().unlock)
 
4364
 
4290
4365
        parent = local_branch.get_parent()
4291
4366
        if other_branch is None:
4292
4367
            other_branch = parent
4301
4376
        remote_branch = Branch.open(other_branch)
4302
4377
        if remote_branch.base == local_branch.base:
4303
4378
            remote_branch = local_branch
 
4379
        else:
 
4380
            self.add_cleanup(remote_branch.lock_read().unlock)
4304
4381
 
4305
 
        local_branch.lock_read()
4306
 
        self.add_cleanup(local_branch.unlock)
4307
4382
        local_revid_range = _revision_range_to_revid_range(
4308
4383
            _get_revision_range(my_revision, local_branch,
4309
4384
                self.name()))
4310
4385
 
4311
 
        remote_branch.lock_read()
4312
 
        self.add_cleanup(remote_branch.unlock)
4313
4386
        remote_revid_range = _revision_range_to_revid_range(
4314
4387
            _get_revision_range(revision,
4315
4388
                remote_branch, self.name()))
4365
4438
            message("Branches are up to date.\n")
4366
4439
        self.cleanup_now()
4367
4440
        if not status_code and parent is None and other_branch is not None:
4368
 
            local_branch.lock_write()
4369
 
            self.add_cleanup(local_branch.unlock)
 
4441
            self.add_cleanup(local_branch.lock_write().unlock)
4370
4442
            # handle race conditions - a parent might be set while we run.
4371
4443
            if local_branch.get_parent() is None:
4372
4444
                local_branch.set_parent(remote_branch.base)
4374
4446
 
4375
4447
 
4376
4448
class cmd_pack(Command):
4377
 
    """Compress the data within a repository."""
 
4449
    __doc__ = """Compress the data within a repository.
 
4450
 
 
4451
    This operation compresses the data within a bazaar repository. As
 
4452
    bazaar supports automatic packing of repository, this operation is
 
4453
    normally not required to be done manually.
 
4454
 
 
4455
    During the pack operation, bazaar takes a backup of existing repository
 
4456
    data, i.e. pack files. This backup is eventually removed by bazaar
 
4457
    automatically when it is safe to do so. To save disk space by removing
 
4458
    the backed up pack files, the --clean-obsolete-packs option may be
 
4459
    used.
 
4460
 
 
4461
    Warning: If you use --clean-obsolete-packs and your machine crashes
 
4462
    during or immediately after repacking, you may be left with a state
 
4463
    where the deletion has been written to disk but the new packs have not
 
4464
    been. In this case the repository may be unusable.
 
4465
    """
4378
4466
 
4379
4467
    _see_also = ['repositories']
4380
4468
    takes_args = ['branch_or_repo?']
 
4469
    takes_options = [
 
4470
        Option('clean-obsolete-packs', 'Delete obsolete packs to save disk space.'),
 
4471
        ]
4381
4472
 
4382
 
    def run(self, branch_or_repo='.'):
 
4473
    def run(self, branch_or_repo='.', clean_obsolete_packs=False):
4383
4474
        dir = bzrdir.BzrDir.open_containing(branch_or_repo)[0]
4384
4475
        try:
4385
4476
            branch = dir.open_branch()
4386
4477
            repository = branch.repository
4387
4478
        except errors.NotBranchError:
4388
4479
            repository = dir.open_repository()
4389
 
        repository.pack()
 
4480
        repository.pack(clean_obsolete_packs=clean_obsolete_packs)
4390
4481
 
4391
4482
 
4392
4483
class cmd_plugins(Command):
4393
 
    """List the installed plugins.
 
4484
    __doc__ = """List the installed plugins.
4394
4485
 
4395
4486
    This command displays the list of installed plugins including
4396
4487
    version of plugin and a short description of each.
4427
4518
                doc = '(no description)'
4428
4519
            result.append((name_ver, doc, plugin.path()))
4429
4520
        for name_ver, doc, path in sorted(result):
4430
 
            print name_ver
4431
 
            print '   ', doc
 
4521
            self.outf.write("%s\n" % name_ver)
 
4522
            self.outf.write("   %s\n" % doc)
4432
4523
            if verbose:
4433
 
                print '   ', path
4434
 
            print
 
4524
                self.outf.write("   %s\n" % path)
 
4525
            self.outf.write("\n")
4435
4526
 
4436
4527
 
4437
4528
class cmd_testament(Command):
4438
 
    """Show testament (signing-form) of a revision."""
 
4529
    __doc__ = """Show testament (signing-form) of a revision."""
4439
4530
    takes_options = [
4440
4531
            'revision',
4441
4532
            Option('long', help='Produce long-format testament.'),
4453
4544
            b = Branch.open_containing(branch)[0]
4454
4545
        else:
4455
4546
            b = Branch.open(branch)
4456
 
        b.lock_read()
4457
 
        self.add_cleanup(b.unlock)
 
4547
        self.add_cleanup(b.lock_read().unlock)
4458
4548
        if revision is None:
4459
4549
            rev_id = b.last_revision()
4460
4550
        else:
4467
4557
 
4468
4558
 
4469
4559
class cmd_annotate(Command):
4470
 
    """Show the origin of each line in a file.
 
4560
    __doc__ = """Show the origin of each line in a file.
4471
4561
 
4472
4562
    This prints out the given file with an annotation on the left side
4473
4563
    indicating which revision, author and date introduced the change.
4484
4574
                     Option('long', help='Show commit date in annotations.'),
4485
4575
                     'revision',
4486
4576
                     'show-ids',
 
4577
                     'directory',
4487
4578
                     ]
4488
4579
    encoding_type = 'exact'
4489
4580
 
4490
4581
    @display_command
4491
4582
    def run(self, filename, all=False, long=False, revision=None,
4492
 
            show_ids=False):
 
4583
            show_ids=False, directory=None):
4493
4584
        from bzrlib.annotate import annotate_file, annotate_file_tree
4494
4585
        wt, branch, relpath = \
4495
 
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
 
4586
            _open_directory_or_containing_tree_or_branch(filename, directory)
4496
4587
        if wt is not None:
4497
 
            wt.lock_read()
4498
 
            self.add_cleanup(wt.unlock)
 
4588
            self.add_cleanup(wt.lock_read().unlock)
4499
4589
        else:
4500
 
            branch.lock_read()
4501
 
            self.add_cleanup(branch.unlock)
 
4590
            self.add_cleanup(branch.lock_read().unlock)
4502
4591
        tree = _get_one_revision_tree('annotate', revision, branch=branch)
4503
 
        tree.lock_read()
4504
 
        self.add_cleanup(tree.unlock)
 
4592
        self.add_cleanup(tree.lock_read().unlock)
4505
4593
        if wt is not None:
4506
4594
            file_id = wt.path2id(relpath)
4507
4595
        else:
4520
4608
 
4521
4609
 
4522
4610
class cmd_re_sign(Command):
4523
 
    """Create a digital signature for an existing revision."""
 
4611
    __doc__ = """Create a digital signature for an existing revision."""
4524
4612
    # TODO be able to replace existing ones.
4525
4613
 
4526
4614
    hidden = True # is this right ?
4527
4615
    takes_args = ['revision_id*']
4528
 
    takes_options = ['revision']
 
4616
    takes_options = ['directory', 'revision']
4529
4617
 
4530
 
    def run(self, revision_id_list=None, revision=None):
 
4618
    def run(self, revision_id_list=None, revision=None, directory=u'.'):
4531
4619
        if revision_id_list is not None and revision is not None:
4532
4620
            raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
4533
4621
        if revision_id_list is None and revision is None:
4534
4622
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
4535
 
        b = WorkingTree.open_containing(u'.')[0].branch
4536
 
        b.lock_write()
4537
 
        self.add_cleanup(b.unlock)
 
4623
        b = WorkingTree.open_containing(directory)[0].branch
 
4624
        self.add_cleanup(b.lock_write().unlock)
4538
4625
        return self._run(b, revision_id_list, revision)
4539
4626
 
4540
4627
    def _run(self, b, revision_id_list, revision):
4586
4673
 
4587
4674
 
4588
4675
class cmd_bind(Command):
4589
 
    """Convert the current branch into a checkout of the supplied branch.
 
4676
    __doc__ = """Convert the current branch into a checkout of the supplied branch.
 
4677
    If no branch is supplied, rebind to the last bound location.
4590
4678
 
4591
4679
    Once converted into a checkout, commits must succeed on the master branch
4592
4680
    before they will be applied to the local branch.
4598
4686
 
4599
4687
    _see_also = ['checkouts', 'unbind']
4600
4688
    takes_args = ['location?']
4601
 
    takes_options = []
 
4689
    takes_options = ['directory']
4602
4690
 
4603
 
    def run(self, location=None):
4604
 
        b, relpath = Branch.open_containing(u'.')
 
4691
    def run(self, location=None, directory=u'.'):
 
4692
        b, relpath = Branch.open_containing(directory)
4605
4693
        if location is None:
4606
4694
            try:
4607
4695
                location = b.get_old_bound_location()
4626
4714
 
4627
4715
 
4628
4716
class cmd_unbind(Command):
4629
 
    """Convert the current checkout into a regular branch.
 
4717
    __doc__ = """Convert the current checkout into a regular branch.
4630
4718
 
4631
4719
    After unbinding, the local branch is considered independent and subsequent
4632
4720
    commits will be local only.
4634
4722
 
4635
4723
    _see_also = ['checkouts', 'bind']
4636
4724
    takes_args = []
4637
 
    takes_options = []
 
4725
    takes_options = ['directory']
4638
4726
 
4639
 
    def run(self):
4640
 
        b, relpath = Branch.open_containing(u'.')
 
4727
    def run(self, directory=u'.'):
 
4728
        b, relpath = Branch.open_containing(directory)
4641
4729
        if not b.unbind():
4642
4730
            raise errors.BzrCommandError('Local branch is not bound')
4643
4731
 
4644
4732
 
4645
4733
class cmd_uncommit(Command):
4646
 
    """Remove the last committed revision.
 
4734
    __doc__ = """Remove the last committed revision.
4647
4735
 
4648
4736
    --verbose will print out what is being removed.
4649
4737
    --dry-run will go through all the motions, but not actually
4689
4777
            b = control.open_branch()
4690
4778
 
4691
4779
        if tree is not None:
4692
 
            tree.lock_write()
4693
 
            self.add_cleanup(tree.unlock)
 
4780
            self.add_cleanup(tree.lock_write().unlock)
4694
4781
        else:
4695
 
            b.lock_write()
4696
 
            self.add_cleanup(b.unlock)
 
4782
            self.add_cleanup(b.lock_write().unlock)
4697
4783
        return self._run(b, tree, dry_run, verbose, revision, force, local=local)
4698
4784
 
4699
4785
    def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
4717
4803
                rev_id = b.get_rev_id(revno)
4718
4804
 
4719
4805
        if rev_id is None or _mod_revision.is_null(rev_id):
4720
 
            ui.ui_factory.note('No revisions to uncommit.')
 
4806
            self.outf.write('No revisions to uncommit.\n')
4721
4807
            return 1
4722
4808
 
4723
 
        log_collector = ui.ui_factory.make_output_stream()
4724
4809
        lf = log_formatter('short',
4725
 
                           to_file=log_collector,
 
4810
                           to_file=self.outf,
4726
4811
                           show_timezone='original')
4727
4812
 
4728
4813
        show_log(b,
4733
4818
                 end_revision=last_revno)
4734
4819
 
4735
4820
        if dry_run:
4736
 
            ui.ui_factory.note('Dry-run, pretending to remove the above revisions.')
 
4821
            self.outf.write('Dry-run, pretending to remove'
 
4822
                            ' the above revisions.\n')
4737
4823
        else:
4738
 
            ui.ui_factory.note('The above revision(s) will be removed.')
 
4824
            self.outf.write('The above revision(s) will be removed.\n')
4739
4825
 
4740
4826
        if not force:
4741
 
            if not ui.ui_factory.get_boolean('Are you sure [y/N]? '):
4742
 
                ui.ui_factory.note('Canceled')
 
4827
            if not ui.ui_factory.confirm_action(
 
4828
                    'Uncommit these revisions',
 
4829
                    'bzrlib.builtins.uncommit',
 
4830
                    {}):
 
4831
                self.outf.write('Canceled\n')
4743
4832
                return 0
4744
4833
 
4745
4834
        mutter('Uncommitting from {%s} to {%s}',
4746
4835
               last_rev_id, rev_id)
4747
4836
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
4748
4837
                 revno=revno, local=local)
4749
 
        ui.ui_factory.note('You can restore the old tip by running:\n'
4750
 
             '  bzr pull . -r revid:%s' % last_rev_id)
 
4838
        self.outf.write('You can restore the old tip by running:\n'
 
4839
             '  bzr pull . -r revid:%s\n' % last_rev_id)
4751
4840
 
4752
4841
 
4753
4842
class cmd_break_lock(Command):
4754
 
    """Break a dead lock on a repository, branch or working directory.
 
4843
    __doc__ = """Break a dead lock.
 
4844
 
 
4845
    This command breaks a lock on a repository, branch, working directory or
 
4846
    config file.
4755
4847
 
4756
4848
    CAUTION: Locks should only be broken when you are sure that the process
4757
4849
    holding the lock has been stopped.
4762
4854
    :Examples:
4763
4855
        bzr break-lock
4764
4856
        bzr break-lock bzr+ssh://example.com/bzr/foo
 
4857
        bzr break-lock --conf ~/.bazaar
4765
4858
    """
 
4859
 
4766
4860
    takes_args = ['location?']
 
4861
    takes_options = [
 
4862
        Option('config',
 
4863
               help='LOCATION is the directory where the config lock is.'),
 
4864
        Option('force',
 
4865
            help='Do not ask for confirmation before breaking the lock.'),
 
4866
        ]
4767
4867
 
4768
 
    def run(self, location=None, show=False):
 
4868
    def run(self, location=None, config=False, force=False):
4769
4869
        if location is None:
4770
4870
            location = u'.'
4771
 
        control, relpath = bzrdir.BzrDir.open_containing(location)
4772
 
        try:
4773
 
            control.break_lock()
4774
 
        except NotImplementedError:
4775
 
            pass
 
4871
        if force:
 
4872
            ui.ui_factory = ui.ConfirmationUserInterfacePolicy(ui.ui_factory,
 
4873
                None,
 
4874
                {'bzrlib.lockdir.break': True})
 
4875
        if config:
 
4876
            conf = _mod_config.LockableConfig(file_name=location)
 
4877
            conf.break_lock()
 
4878
        else:
 
4879
            control, relpath = bzrdir.BzrDir.open_containing(location)
 
4880
            try:
 
4881
                control.break_lock()
 
4882
            except NotImplementedError:
 
4883
                pass
4776
4884
 
4777
4885
 
4778
4886
class cmd_wait_until_signalled(Command):
4779
 
    """Test helper for test_start_and_stop_bzr_subprocess_send_signal.
 
4887
    __doc__ = """Test helper for test_start_and_stop_bzr_subprocess_send_signal.
4780
4888
 
4781
4889
    This just prints a line to signal when it is ready, then blocks on stdin.
4782
4890
    """
4790
4898
 
4791
4899
 
4792
4900
class cmd_serve(Command):
4793
 
    """Run the bzr server."""
 
4901
    __doc__ = """Run the bzr server."""
4794
4902
 
4795
4903
    aliases = ['server']
4796
4904
 
4807
4915
                    'result in a dynamically allocated port.  The default port '
4808
4916
                    'depends on the protocol.',
4809
4917
               type=str),
4810
 
        Option('directory',
4811
 
               help='Serve contents of this directory.',
4812
 
               type=unicode),
 
4918
        custom_help('directory',
 
4919
               help='Serve contents of this directory.'),
4813
4920
        Option('allow-writes',
4814
4921
               help='By default the server is a readonly server.  Supplying '
4815
4922
                    '--allow-writes enables write access to the contents of '
4842
4949
 
4843
4950
    def run(self, port=None, inet=False, directory=None, allow_writes=False,
4844
4951
            protocol=None):
4845
 
        from bzrlib.transport import get_transport, transport_server_registry
 
4952
        from bzrlib import transport
4846
4953
        if directory is None:
4847
4954
            directory = os.getcwd()
4848
4955
        if protocol is None:
4849
 
            protocol = transport_server_registry.get()
 
4956
            protocol = transport.transport_server_registry.get()
4850
4957
        host, port = self.get_host_and_port(port)
4851
4958
        url = urlutils.local_path_to_url(directory)
4852
4959
        if not allow_writes:
4853
4960
            url = 'readonly+' + url
4854
 
        transport = get_transport(url)
4855
 
        protocol(transport, host, port, inet)
 
4961
        t = transport.get_transport(url)
 
4962
        protocol(t, host, port, inet)
4856
4963
 
4857
4964
 
4858
4965
class cmd_join(Command):
4859
 
    """Combine a tree into its containing tree.
 
4966
    __doc__ = """Combine a tree into its containing tree.
4860
4967
 
4861
4968
    This command requires the target tree to be in a rich-root format.
4862
4969
 
4864
4971
    not part of it.  (Such trees can be produced by "bzr split", but also by
4865
4972
    running "bzr branch" with the target inside a tree.)
4866
4973
 
4867
 
    The result is a combined tree, with the subtree no longer an independant
 
4974
    The result is a combined tree, with the subtree no longer an independent
4868
4975
    part.  This is marked as a merge of the subtree into the containing tree,
4869
4976
    and all history is preserved.
4870
4977
    """
4902
5009
 
4903
5010
 
4904
5011
class cmd_split(Command):
4905
 
    """Split a subdirectory of a tree into a separate tree.
 
5012
    __doc__ = """Split a subdirectory of a tree into a separate tree.
4906
5013
 
4907
5014
    This command will produce a target tree in a format that supports
4908
5015
    rich roots, like 'rich-root' or 'rich-root-pack'.  These formats cannot be
4928
5035
 
4929
5036
 
4930
5037
class cmd_merge_directive(Command):
4931
 
    """Generate a merge directive for auto-merge tools.
 
5038
    __doc__ = """Generate a merge directive for auto-merge tools.
4932
5039
 
4933
5040
    A directive requests a merge to be performed, and also provides all the
4934
5041
    information necessary to do so.  This means it must either include a
4951
5058
    _see_also = ['send']
4952
5059
 
4953
5060
    takes_options = [
 
5061
        'directory',
4954
5062
        RegistryOption.from_kwargs('patch-type',
4955
5063
            'The type of patch to include in the directive.',
4956
5064
            title='Patch type',
4969
5077
    encoding_type = 'exact'
4970
5078
 
4971
5079
    def run(self, submit_branch=None, public_branch=None, patch_type='bundle',
4972
 
            sign=False, revision=None, mail_to=None, message=None):
 
5080
            sign=False, revision=None, mail_to=None, message=None,
 
5081
            directory=u'.'):
4973
5082
        from bzrlib.revision import ensure_null, NULL_REVISION
4974
5083
        include_patch, include_bundle = {
4975
5084
            'plain': (False, False),
4976
5085
            'diff': (True, False),
4977
5086
            'bundle': (True, True),
4978
5087
            }[patch_type]
4979
 
        branch = Branch.open('.')
 
5088
        branch = Branch.open(directory)
4980
5089
        stored_submit_branch = branch.get_submit_branch()
4981
5090
        if submit_branch is None:
4982
5091
            submit_branch = stored_submit_branch
5027
5136
 
5028
5137
 
5029
5138
class cmd_send(Command):
5030
 
    """Mail or create a merge-directive for submitting changes.
 
5139
    __doc__ = """Mail or create a merge-directive for submitting changes.
5031
5140
 
5032
5141
    A merge directive provides many things needed for requesting merges:
5033
5142
 
5067
5176
    given, in which case it is sent to a file.
5068
5177
 
5069
5178
    Mail is sent using your preferred mail program.  This should be transparent
5070
 
    on Windows (it uses MAPI).  On Linux, it requires the xdg-email utility.
 
5179
    on Windows (it uses MAPI).  On Unix, it requires the xdg-email utility.
5071
5180
    If the preferred client can't be found (or used), your editor will be used.
5072
5181
 
5073
5182
    To use a specific mail program, set the mail_client configuration option.
5115
5224
               short_name='f',
5116
5225
               type=unicode),
5117
5226
        Option('output', short_name='o',
5118
 
               help='Write merge directive to this file; '
 
5227
               help='Write merge directive to this file or directory; '
5119
5228
                    'use - for stdout.',
5120
5229
               type=unicode),
5121
5230
        Option('strict',
5144
5253
 
5145
5254
 
5146
5255
class cmd_bundle_revisions(cmd_send):
5147
 
    """Create a merge-directive for submitting changes.
 
5256
    __doc__ = """Create a merge-directive for submitting changes.
5148
5257
 
5149
5258
    A merge directive provides many things needed for requesting merges:
5150
5259
 
5217
5326
 
5218
5327
 
5219
5328
class cmd_tag(Command):
5220
 
    """Create, remove or modify a tag naming a revision.
 
5329
    __doc__ = """Create, remove or modify a tag naming a revision.
5221
5330
 
5222
5331
    Tags give human-meaningful names to revisions.  Commands that take a -r
5223
5332
    (--revision) option can be given -rtag:X, where X is any previously
5231
5340
 
5232
5341
    To rename a tag (change the name but keep it on the same revsion), run ``bzr
5233
5342
    tag new-name -r tag:old-name`` and then ``bzr tag --delete oldname``.
 
5343
 
 
5344
    If no tag name is specified it will be determined through the 
 
5345
    'automatic_tag_name' hook. This can e.g. be used to automatically tag
 
5346
    upstream releases by reading configure.ac. See ``bzr help hooks`` for
 
5347
    details.
5234
5348
    """
5235
5349
 
5236
5350
    _see_also = ['commit', 'tags']
5237
 
    takes_args = ['tag_name']
 
5351
    takes_args = ['tag_name?']
5238
5352
    takes_options = [
5239
5353
        Option('delete',
5240
5354
            help='Delete this tag rather than placing it.',
5241
5355
            ),
5242
 
        Option('directory',
5243
 
            help='Branch in which to place the tag.',
5244
 
            short_name='d',
5245
 
            type=unicode,
5246
 
            ),
 
5356
        custom_help('directory',
 
5357
            help='Branch in which to place the tag.'),
5247
5358
        Option('force',
5248
5359
            help='Replace existing tags.',
5249
5360
            ),
5250
5361
        'revision',
5251
5362
        ]
5252
5363
 
5253
 
    def run(self, tag_name,
 
5364
    def run(self, tag_name=None,
5254
5365
            delete=None,
5255
5366
            directory='.',
5256
5367
            force=None,
5257
5368
            revision=None,
5258
5369
            ):
5259
5370
        branch, relpath = Branch.open_containing(directory)
5260
 
        branch.lock_write()
5261
 
        self.add_cleanup(branch.unlock)
 
5371
        self.add_cleanup(branch.lock_write().unlock)
5262
5372
        if delete:
 
5373
            if tag_name is None:
 
5374
                raise errors.BzrCommandError("No tag specified to delete.")
5263
5375
            branch.tags.delete_tag(tag_name)
5264
5376
            self.outf.write('Deleted tag %s.\n' % tag_name)
5265
5377
        else:
5271
5383
                revision_id = revision[0].as_revision_id(branch)
5272
5384
            else:
5273
5385
                revision_id = branch.last_revision()
 
5386
            if tag_name is None:
 
5387
                tag_name = branch.automatic_tag_name(revision_id)
 
5388
                if tag_name is None:
 
5389
                    raise errors.BzrCommandError(
 
5390
                        "Please specify a tag name.")
5274
5391
            if (not force) and branch.tags.has_tag(tag_name):
5275
5392
                raise errors.TagAlreadyExists(tag_name)
5276
5393
            branch.tags.set_tag(tag_name, revision_id)
5278
5395
 
5279
5396
 
5280
5397
class cmd_tags(Command):
5281
 
    """List tags.
 
5398
    __doc__ = """List tags.
5282
5399
 
5283
5400
    This command shows a table of tag names and the revisions they reference.
5284
5401
    """
5285
5402
 
5286
5403
    _see_also = ['tag']
5287
5404
    takes_options = [
5288
 
        Option('directory',
5289
 
            help='Branch whose tags should be displayed.',
5290
 
            short_name='d',
5291
 
            type=unicode,
5292
 
            ),
 
5405
        custom_help('directory',
 
5406
            help='Branch whose tags should be displayed.'),
5293
5407
        RegistryOption.from_kwargs('sort',
5294
5408
            'Sort tags by different criteria.', title='Sorting',
5295
 
            alpha='Sort tags lexicographically (default).',
 
5409
            natural='Sort numeric substrings as numbers:'
 
5410
                    ' suitable for version numbers. (default)',
 
5411
            alpha='Sort tags lexicographically.',
5296
5412
            time='Sort tags chronologically.',
5297
5413
            ),
5298
5414
        'show-ids',
5302
5418
    @display_command
5303
5419
    def run(self,
5304
5420
            directory='.',
5305
 
            sort='alpha',
 
5421
            sort='natural',
5306
5422
            show_ids=False,
5307
5423
            revision=None,
5308
5424
            ):
5312
5428
        if not tags:
5313
5429
            return
5314
5430
 
5315
 
        branch.lock_read()
5316
 
        self.add_cleanup(branch.unlock)
 
5431
        self.add_cleanup(branch.lock_read().unlock)
5317
5432
        if revision:
5318
5433
            graph = branch.repository.get_graph()
5319
5434
            rev1, rev2 = _get_revision_range(revision, branch, self.name())
5321
5436
            # only show revisions between revid1 and revid2 (inclusive)
5322
5437
            tags = [(tag, revid) for tag, revid in tags if
5323
5438
                graph.is_between(revid, revid1, revid2)]
5324
 
        if sort == 'alpha':
 
5439
        if sort == 'natural':
 
5440
            def natural_sort_key(tag):
 
5441
                return [f(s) for f,s in 
 
5442
                        zip(itertools.cycle((unicode.lower,int)),
 
5443
                                            re.split('([0-9]+)', tag[0]))]
 
5444
            tags.sort(key=natural_sort_key)
 
5445
        elif sort == 'alpha':
5325
5446
            tags.sort()
5326
5447
        elif sort == 'time':
5327
5448
            timestamps = {}
5352
5473
 
5353
5474
 
5354
5475
class cmd_reconfigure(Command):
5355
 
    """Reconfigure the type of a bzr directory.
 
5476
    __doc__ = """Reconfigure the type of a bzr directory.
5356
5477
 
5357
5478
    A target configuration must be specified.
5358
5479
 
5443
5564
 
5444
5565
 
5445
5566
class cmd_switch(Command):
5446
 
    """Set the branch of a checkout and update.
 
5567
    __doc__ = """Set the branch of a checkout and update.
5447
5568
 
5448
5569
    For lightweight checkouts, this changes the branch being referenced.
5449
5570
    For heavyweight checkouts, this checks that there are no local commits
5466
5587
    """
5467
5588
 
5468
5589
    takes_args = ['to_location?']
5469
 
    takes_options = [Option('force',
 
5590
    takes_options = ['directory',
 
5591
                     Option('force',
5470
5592
                        help='Switch even if local commits will be lost.'),
5471
5593
                     'revision',
5472
5594
                     Option('create-branch', short_name='b',
5475
5597
                    ]
5476
5598
 
5477
5599
    def run(self, to_location=None, force=False, create_branch=False,
5478
 
            revision=None):
 
5600
            revision=None, directory=u'.'):
5479
5601
        from bzrlib import switch
5480
 
        tree_location = '.'
 
5602
        tree_location = directory
5481
5603
        revision = _get_one_revision('switch', revision)
5482
5604
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
5483
5605
        if to_location is None:
5484
5606
            if revision is None:
5485
5607
                raise errors.BzrCommandError('You must supply either a'
5486
5608
                                             ' revision or a location')
5487
 
            to_location = '.'
 
5609
            to_location = tree_location
5488
5610
        try:
5489
5611
            branch = control_dir.open_branch()
5490
5612
            had_explicit_nick = branch.get_config().has_explicit_nickname()
5539
5661
 
5540
5662
 
5541
5663
class cmd_view(Command):
5542
 
    """Manage filtered views.
 
5664
    __doc__ = """Manage filtered views.
5543
5665
 
5544
5666
    Views provide a mask over the tree so that users can focus on
5545
5667
    a subset of a tree when doing their work. After creating a view,
5625
5747
            name=None,
5626
5748
            switch=None,
5627
5749
            ):
5628
 
        tree, file_list = tree_files(file_list, apply_view=False)
 
5750
        tree, file_list = WorkingTree.open_containing_paths(file_list,
 
5751
            apply_view=False)
5629
5752
        current_view, view_dict = tree.views.get_view_info()
5630
5753
        if name is None:
5631
5754
            name = current_view
5693
5816
 
5694
5817
 
5695
5818
class cmd_hooks(Command):
5696
 
    """Show hooks."""
 
5819
    __doc__ = """Show hooks."""
5697
5820
 
5698
5821
    hidden = True
5699
5822
 
5712
5835
                    self.outf.write("    <no hooks installed>\n")
5713
5836
 
5714
5837
 
 
5838
class cmd_remove_branch(Command):
 
5839
    __doc__ = """Remove a branch.
 
5840
 
 
5841
    This will remove the branch from the specified location but 
 
5842
    will keep any working tree or repository in place.
 
5843
 
 
5844
    :Examples:
 
5845
 
 
5846
      Remove the branch at repo/trunk::
 
5847
 
 
5848
        bzr remove-branch repo/trunk
 
5849
 
 
5850
    """
 
5851
 
 
5852
    takes_args = ["location?"]
 
5853
 
 
5854
    aliases = ["rmbranch"]
 
5855
 
 
5856
    def run(self, location=None):
 
5857
        if location is None:
 
5858
            location = "."
 
5859
        branch = Branch.open_containing(location)[0]
 
5860
        branch.bzrdir.destroy_branch()
 
5861
        
 
5862
 
5715
5863
class cmd_shelve(Command):
5716
 
    """Temporarily set aside some changes from the current tree.
 
5864
    __doc__ = """Temporarily set aside some changes from the current tree.
5717
5865
 
5718
5866
    Shelve allows you to temporarily put changes you've made "on the shelf",
5719
5867
    ie. out of the way, until a later time when you can bring them back from
5740
5888
    takes_args = ['file*']
5741
5889
 
5742
5890
    takes_options = [
 
5891
        'directory',
5743
5892
        'revision',
5744
5893
        Option('all', help='Shelve all changes.'),
5745
5894
        'message',
5754
5903
    _see_also = ['unshelve']
5755
5904
 
5756
5905
    def run(self, revision=None, all=False, file_list=None, message=None,
5757
 
            writer=None, list=False, destroy=False):
 
5906
            writer=None, list=False, destroy=False, directory=u'.'):
5758
5907
        if list:
5759
5908
            return self.run_for_list()
5760
5909
        from bzrlib.shelf_ui import Shelver
5762
5911
            writer = bzrlib.option.diff_writer_registry.get()
5763
5912
        try:
5764
5913
            shelver = Shelver.from_args(writer(sys.stdout), revision, all,
5765
 
                file_list, message, destroy=destroy)
 
5914
                file_list, message, destroy=destroy, directory=directory)
5766
5915
            try:
5767
5916
                shelver.run()
5768
5917
            finally:
5772
5921
 
5773
5922
    def run_for_list(self):
5774
5923
        tree = WorkingTree.open_containing('.')[0]
5775
 
        tree.lock_read()
5776
 
        self.add_cleanup(tree.unlock)
 
5924
        self.add_cleanup(tree.lock_read().unlock)
5777
5925
        manager = tree.get_shelf_manager()
5778
5926
        shelves = manager.active_shelves()
5779
5927
        if len(shelves) == 0:
5788
5936
 
5789
5937
 
5790
5938
class cmd_unshelve(Command):
5791
 
    """Restore shelved changes.
 
5939
    __doc__ = """Restore shelved changes.
5792
5940
 
5793
5941
    By default, the most recently shelved changes are restored. However if you
5794
5942
    specify a shelf by id those changes will be restored instead.  This works
5797
5945
 
5798
5946
    takes_args = ['shelf_id?']
5799
5947
    takes_options = [
 
5948
        'directory',
5800
5949
        RegistryOption.from_kwargs(
5801
5950
            'action', help="The action to perform.",
5802
5951
            enum_switch=False, value_switches=True,
5810
5959
    ]
5811
5960
    _see_also = ['shelve']
5812
5961
 
5813
 
    def run(self, shelf_id=None, action='apply'):
 
5962
    def run(self, shelf_id=None, action='apply', directory=u'.'):
5814
5963
        from bzrlib.shelf_ui import Unshelver
5815
 
        unshelver = Unshelver.from_args(shelf_id, action)
 
5964
        unshelver = Unshelver.from_args(shelf_id, action, directory=directory)
5816
5965
        try:
5817
5966
            unshelver.run()
5818
5967
        finally:
5820
5969
 
5821
5970
 
5822
5971
class cmd_clean_tree(Command):
5823
 
    """Remove unwanted files from working tree.
 
5972
    __doc__ = """Remove unwanted files from working tree.
5824
5973
 
5825
5974
    By default, only unknown files, not ignored files, are deleted.  Versioned
5826
5975
    files are never deleted.
5834
5983
 
5835
5984
    To check what clean-tree will do, use --dry-run.
5836
5985
    """
5837
 
    takes_options = [Option('ignored', help='Delete all ignored files.'),
 
5986
    takes_options = ['directory',
 
5987
                     Option('ignored', help='Delete all ignored files.'),
5838
5988
                     Option('detritus', help='Delete conflict files, merge'
5839
5989
                            ' backups, and failed selftest dirs.'),
5840
5990
                     Option('unknown',
5843
5993
                            ' deleting them.'),
5844
5994
                     Option('force', help='Do not prompt before deleting.')]
5845
5995
    def run(self, unknown=False, ignored=False, detritus=False, dry_run=False,
5846
 
            force=False):
 
5996
            force=False, directory=u'.'):
5847
5997
        from bzrlib.clean_tree import clean_tree
5848
5998
        if not (unknown or ignored or detritus):
5849
5999
            unknown = True
5850
6000
        if dry_run:
5851
6001
            force = True
5852
 
        clean_tree('.', unknown=unknown, ignored=ignored, detritus=detritus,
5853
 
                   dry_run=dry_run, no_prompt=force)
 
6002
        clean_tree(directory, unknown=unknown, ignored=ignored,
 
6003
                   detritus=detritus, dry_run=dry_run, no_prompt=force)
5854
6004
 
5855
6005
 
5856
6006
class cmd_reference(Command):
5857
 
    """list, view and set branch locations for nested trees.
 
6007
    __doc__ = """list, view and set branch locations for nested trees.
5858
6008
 
5859
6009
    If no arguments are provided, lists the branch locations for nested trees.
5860
6010
    If one argument is provided, display the branch location for that tree.
5900
6050
            self.outf.write('%s %s\n' % (path, location))
5901
6051
 
5902
6052
 
5903
 
# these get imported and then picked up by the scan for cmd_*
5904
 
# TODO: Some more consistent way to split command definitions across files;
5905
 
# we do need to load at least some information about them to know of
5906
 
# aliases.  ideally we would avoid loading the implementation until the
5907
 
# details were needed.
5908
 
from bzrlib.cmd_version_info import cmd_version_info
5909
 
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
5910
 
from bzrlib.bundle.commands import (
5911
 
    cmd_bundle_info,
5912
 
    )
5913
 
from bzrlib.foreign import cmd_dpush
5914
 
from bzrlib.sign_my_commits import cmd_sign_my_commits
 
6053
def _register_lazy_builtins():
 
6054
    # register lazy builtins from other modules; called at startup and should
 
6055
    # be only called once.
 
6056
    for (name, aliases, module_name) in [
 
6057
        ('cmd_bundle_info', [], 'bzrlib.bundle.commands'),
 
6058
        ('cmd_dpush', [], 'bzrlib.foreign'),
 
6059
        ('cmd_version_info', [], 'bzrlib.cmd_version_info'),
 
6060
        ('cmd_resolve', ['resolved'], 'bzrlib.conflicts'),
 
6061
        ('cmd_conflicts', [], 'bzrlib.conflicts'),
 
6062
        ('cmd_sign_my_commits', [], 'bzrlib.sign_my_commits'),
 
6063
        ]:
 
6064
        builtin_command_registry.register_lazy(name, aliases, module_name)