/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

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
23
24
import cStringIO
24
25
import sys
25
26
import time
32
33
    bzrdir,
33
34
    directory_service,
34
35
    delta,
35
 
    config as _mod_config,
 
36
    config,
36
37
    errors,
37
38
    globbing,
38
39
    hooks,
74
75
from bzrlib.trace import mutter, note, warning, is_quiet, get_verbosity_level
75
76
 
76
77
 
77
 
@symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
78
78
def tree_files(file_list, default_branch=u'.', canonicalize=True,
79
79
    apply_view=True):
80
 
    return internal_tree_files(file_list, default_branch, canonicalize,
81
 
        apply_view)
 
80
    try:
 
81
        return internal_tree_files(file_list, default_branch, canonicalize,
 
82
            apply_view)
 
83
    except errors.FileInWrongBranch, e:
 
84
        raise errors.BzrCommandError("%s is not in the same branch as %s" %
 
85
                                     (e.path, file_list[0]))
82
86
 
83
87
 
84
88
def tree_files_for_add(file_list):
148
152
 
149
153
# XXX: Bad function name; should possibly also be a class method of
150
154
# WorkingTree rather than a function.
151
 
@symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
152
155
def internal_tree_files(file_list, default_branch=u'.', canonicalize=True,
153
156
    apply_view=True):
154
157
    """Convert command-line paths to a WorkingTree and relative paths.
155
158
 
156
 
    Deprecated: use WorkingTree.open_containing_paths instead.
157
 
 
158
159
    This is typically used for command-line processors that take one or
159
160
    more filenames, and infer the workingtree that contains them.
160
161
 
170
171
 
171
172
    :return: workingtree, [relative_paths]
172
173
    """
173
 
    return WorkingTree.open_containing_paths(
174
 
        file_list, default_directory='.',
175
 
        canonicalize=True,
176
 
        apply_view=True)
 
174
    if file_list is None or len(file_list) == 0:
 
175
        tree = WorkingTree.open_containing(default_branch)[0]
 
176
        if tree.supports_views() and apply_view:
 
177
            view_files = tree.views.lookup_view()
 
178
            if view_files:
 
179
                file_list = view_files
 
180
                view_str = views.view_display_str(view_files)
 
181
                note("Ignoring files outside view. View is %s" % view_str)
 
182
        return tree, file_list
 
183
    tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
 
184
    return tree, safe_relpath_files(tree, file_list, canonicalize,
 
185
        apply_view=apply_view)
 
186
 
 
187
 
 
188
def safe_relpath_files(tree, file_list, canonicalize=True, apply_view=True):
 
189
    """Convert file_list into a list of relpaths in tree.
 
190
 
 
191
    :param tree: A tree to operate on.
 
192
    :param file_list: A list of user provided paths or None.
 
193
    :param apply_view: if True and a view is set, apply it or check that
 
194
        specified files are within it
 
195
    :return: A list of relative paths.
 
196
    :raises errors.PathNotChild: When a provided path is in a different tree
 
197
        than tree.
 
198
    """
 
199
    if file_list is None:
 
200
        return None
 
201
    if tree.supports_views() and apply_view:
 
202
        view_files = tree.views.lookup_view()
 
203
    else:
 
204
        view_files = []
 
205
    new_list = []
 
206
    # tree.relpath exists as a "thunk" to osutils, but canonical_relpath
 
207
    # doesn't - fix that up here before we enter the loop.
 
208
    if canonicalize:
 
209
        fixer = lambda p: osutils.canonical_relpath(tree.basedir, p)
 
210
    else:
 
211
        fixer = tree.relpath
 
212
    for filename in file_list:
 
213
        try:
 
214
            relpath = fixer(osutils.dereference_path(filename))
 
215
            if  view_files and not osutils.is_inside_any(view_files, relpath):
 
216
                raise errors.FileOutsideView(filename, view_files)
 
217
            new_list.append(relpath)
 
218
        except errors.PathNotChild:
 
219
            raise errors.FileInWrongBranch(tree.branch, filename)
 
220
    return new_list
177
221
 
178
222
 
179
223
def _get_view_info_for_change_reporter(tree):
188
232
    return view_info
189
233
 
190
234
 
191
 
def _open_directory_or_containing_tree_or_branch(filename, directory):
192
 
    """Open the tree or branch containing the specified file, unless
193
 
    the --directory option is used to specify a different branch."""
194
 
    if directory is not None:
195
 
        return (None, Branch.open(directory), filename)
196
 
    return bzrdir.BzrDir.open_containing_tree_or_branch(filename)
197
 
 
198
 
 
199
235
# TODO: Make sure no commands unconditionally use the working directory as a
200
236
# branch.  If a filename argument is used, the first of them should be used to
201
237
# specify the branch.  (Perhaps this can be factored out into some kind of
279
315
            raise errors.BzrCommandError('bzr status --revision takes exactly'
280
316
                                         ' one or two revision specifiers')
281
317
 
282
 
        tree, relfile_list = WorkingTree.open_containing_paths(file_list)
 
318
        tree, relfile_list = tree_files(file_list)
283
319
        # Avoid asking for specific files when that is not needed.
284
320
        if relfile_list == ['']:
285
321
            relfile_list = None
304
340
 
305
341
    hidden = True
306
342
    takes_args = ['revision_id?']
307
 
    takes_options = ['directory', 'revision']
 
343
    takes_options = ['revision']
308
344
    # cat-revision is more for frontends so should be exact
309
345
    encoding = 'strict'
310
346
 
317
353
        self.outf.write(revtext.decode('utf-8'))
318
354
 
319
355
    @display_command
320
 
    def run(self, revision_id=None, revision=None, directory=u'.'):
 
356
    def run(self, revision_id=None, revision=None):
321
357
        if revision_id is not None and revision is not None:
322
358
            raise errors.BzrCommandError('You can only supply one of'
323
359
                                         ' revision_id or --revision')
324
360
        if revision_id is None and revision is None:
325
361
            raise errors.BzrCommandError('You must supply either'
326
362
                                         ' --revision or a revision_id')
327
 
        b = WorkingTree.open_containing(directory)[0].branch
 
363
        b = WorkingTree.open_containing(u'.')[0].branch
328
364
 
329
365
        revisions = b.repository.revisions
330
366
        if revisions is None:
447
483
    takes_options = [
448
484
        Option('force',
449
485
               help='Remove the working tree even if it has '
450
 
                    'uncommitted or shelved changes.'),
 
486
                    'uncommitted changes.'),
451
487
        ]
452
488
 
453
489
    def run(self, location_list, force=False):
467
503
            if not force:
468
504
                if (working.has_changes()):
469
505
                    raise errors.UncommittedChanges(working)
470
 
                if working.get_shelf_manager().last_shelf() is not None:
471
 
                    raise errors.ShelvedChanges(working)
472
506
 
473
507
            if working.user_url != working.branch.user_url:
474
508
                raise errors.BzrCommandError("You cannot remove the working tree"
494
528
        if tree:
495
529
            try:
496
530
                wt = WorkingTree.open_containing(location)[0]
497
 
                self.add_cleanup(wt.lock_read().unlock)
 
531
                wt.lock_read()
498
532
            except (errors.NoWorkingTree, errors.NotLocalUrl):
499
533
                raise errors.NoWorkingTree(location)
 
534
            self.add_cleanup(wt.unlock)
500
535
            revid = wt.last_revision()
501
536
            try:
502
537
                revno_t = wt.branch.revision_id_to_dotted_revno(revid)
505
540
            revno = ".".join(str(n) for n in revno_t)
506
541
        else:
507
542
            b = Branch.open_containing(location)[0]
508
 
            self.add_cleanup(b.lock_read().unlock)
 
543
            b.lock_read()
 
544
            self.add_cleanup(b.unlock)
509
545
            revno = b.revno()
510
546
        self.cleanup_now()
511
547
        self.outf.write(str(revno) + '\n')
518
554
    takes_args = ['revision_info*']
519
555
    takes_options = [
520
556
        'revision',
521
 
        custom_help('directory',
 
557
        Option('directory',
522
558
            help='Branch to examine, '
523
 
                 'rather than the one containing the working directory.'),
 
559
                 'rather than the one containing the working directory.',
 
560
            short_name='d',
 
561
            type=unicode,
 
562
            ),
524
563
        Option('tree', help='Show revno of working tree'),
525
564
        ]
526
565
 
531
570
        try:
532
571
            wt = WorkingTree.open_containing(directory)[0]
533
572
            b = wt.branch
534
 
            self.add_cleanup(wt.lock_read().unlock)
 
573
            wt.lock_read()
 
574
            self.add_cleanup(wt.unlock)
535
575
        except (errors.NoWorkingTree, errors.NotLocalUrl):
536
576
            wt = None
537
577
            b = Branch.open_containing(directory)[0]
538
 
            self.add_cleanup(b.lock_read().unlock)
 
578
            b.lock_read()
 
579
            self.add_cleanup(b.unlock)
539
580
        revision_ids = []
540
581
        if revision is not None:
541
582
            revision_ids.extend(rev.as_revision_id(b) for rev in revision)
640
681
                should_print=(not is_quiet()))
641
682
 
642
683
        if base_tree:
643
 
            self.add_cleanup(base_tree.lock_read().unlock)
 
684
            base_tree.lock_read()
 
685
            self.add_cleanup(base_tree.unlock)
644
686
        tree, file_list = tree_files_for_add(file_list)
645
687
        added, ignored = tree.smart_add(file_list, not
646
688
            no_recurse, action=action, save=not dry_run)
717
759
            raise errors.BzrCommandError('invalid kind %r specified' % (kind,))
718
760
 
719
761
        revision = _get_one_revision('inventory', revision)
720
 
        work_tree, file_list = WorkingTree.open_containing_paths(file_list)
721
 
        self.add_cleanup(work_tree.lock_read().unlock)
 
762
        work_tree, file_list = tree_files(file_list)
 
763
        work_tree.lock_read()
 
764
        self.add_cleanup(work_tree.unlock)
722
765
        if revision is not None:
723
766
            tree = revision.as_tree(work_tree.branch)
724
767
 
725
768
            extra_trees = [work_tree]
726
 
            self.add_cleanup(tree.lock_read().unlock)
 
769
            tree.lock_read()
 
770
            self.add_cleanup(tree.unlock)
727
771
        else:
728
772
            tree = work_tree
729
773
            extra_trees = []
788
832
            names_list = []
789
833
        if len(names_list) < 2:
790
834
            raise errors.BzrCommandError("missing file argument")
791
 
        tree, rel_names = WorkingTree.open_containing_paths(names_list, canonicalize=False)
792
 
        self.add_cleanup(tree.lock_tree_write().unlock)
 
835
        tree, rel_names = tree_files(names_list, canonicalize=False)
 
836
        tree.lock_tree_write()
 
837
        self.add_cleanup(tree.unlock)
793
838
        self._run(tree, names_list, rel_names, after)
794
839
 
795
840
    def run_auto(self, names_list, after, dry_run):
799
844
        if after:
800
845
            raise errors.BzrCommandError('--after cannot be specified with'
801
846
                                         ' --auto.')
802
 
        work_tree, file_list = WorkingTree.open_containing_paths(
803
 
            names_list, default_directory='.')
804
 
        self.add_cleanup(work_tree.lock_tree_write().unlock)
 
847
        work_tree, file_list = tree_files(names_list, default_branch='.')
 
848
        work_tree.lock_tree_write()
 
849
        self.add_cleanup(work_tree.unlock)
805
850
        rename_map.RenameMap.guess_renames(work_tree, dry_run)
806
851
 
807
852
    def _run(self, tree, names_list, rel_names, after):
915
960
    takes_options = ['remember', 'overwrite', 'revision',
916
961
        custom_help('verbose',
917
962
            help='Show logs of pulled revisions.'),
918
 
        custom_help('directory',
 
963
        Option('directory',
919
964
            help='Branch to pull into, '
920
 
                 'rather than the one containing the working directory.'),
 
965
                 'rather than the one containing the working directory.',
 
966
            short_name='d',
 
967
            type=unicode,
 
968
            ),
921
969
        Option('local',
922
970
            help="Perform a local pull in a bound "
923
971
                 "branch.  Local pulls are not applied to "
924
972
                 "the master branch."
925
973
            ),
926
 
        Option('show-base',
927
 
            help="Show base revision text in conflicts.")
928
974
        ]
929
975
    takes_args = ['location?']
930
976
    encoding_type = 'replace'
931
977
 
932
978
    def run(self, location=None, remember=False, overwrite=False,
933
979
            revision=None, verbose=False,
934
 
            directory=None, local=False,
935
 
            show_base=False):
 
980
            directory=None, local=False):
936
981
        # FIXME: too much stuff is in the command class
937
982
        revision_id = None
938
983
        mergeable = None
941
986
        try:
942
987
            tree_to = WorkingTree.open_containing(directory)[0]
943
988
            branch_to = tree_to.branch
944
 
            self.add_cleanup(tree_to.lock_write().unlock)
 
989
            tree_to.lock_write()
 
990
            self.add_cleanup(tree_to.unlock)
945
991
        except errors.NoWorkingTree:
946
992
            tree_to = None
947
993
            branch_to = Branch.open_containing(directory)[0]
948
 
            self.add_cleanup(branch_to.lock_write().unlock)
949
 
 
950
 
        if tree_to is None and show_base:
951
 
            raise errors.BzrCommandError("Need working tree for --show-base.")
 
994
            branch_to.lock_write()
 
995
            self.add_cleanup(branch_to.unlock)
952
996
 
953
997
        if local and not branch_to.get_bound_location():
954
998
            raise errors.LocalRequiresBoundBranch()
985
1029
        else:
986
1030
            branch_from = Branch.open(location,
987
1031
                possible_transports=possible_transports)
988
 
            self.add_cleanup(branch_from.lock_read().unlock)
 
1032
            branch_from.lock_read()
 
1033
            self.add_cleanup(branch_from.unlock)
989
1034
 
990
1035
            if branch_to.get_parent() is None or remember:
991
1036
                branch_to.set_parent(branch_from.base)
1000
1045
                view_info=view_info)
1001
1046
            result = tree_to.pull(
1002
1047
                branch_from, overwrite, revision_id, change_reporter,
1003
 
                possible_transports=possible_transports, local=local,
1004
 
                show_base=show_base)
 
1048
                possible_transports=possible_transports, local=local)
1005
1049
        else:
1006
1050
            result = branch_to.pull(
1007
1051
                branch_from, overwrite, revision_id, local=local)
1044
1088
        Option('create-prefix',
1045
1089
               help='Create the path leading up to the branch '
1046
1090
                    'if it does not already exist.'),
1047
 
        custom_help('directory',
 
1091
        Option('directory',
1048
1092
            help='Branch to push from, '
1049
 
                 'rather than the one containing the working directory.'),
 
1093
                 'rather than the one containing the working directory.',
 
1094
            short_name='d',
 
1095
            type=unicode,
 
1096
            ),
1050
1097
        Option('use-existing-dir',
1051
1098
               help='By default push will fail if the target'
1052
1099
                    ' directory exists, but does not already'
1141
1188
 
1142
1189
    _see_also = ['checkout']
1143
1190
    takes_args = ['from_location', 'to_location?']
1144
 
    takes_options = ['revision',
1145
 
        Option('hardlink', help='Hard-link working tree files where possible.'),
1146
 
        Option('files-from', type=str,
1147
 
               help="Get file contents from this tree."),
 
1191
    takes_options = ['revision', Option('hardlink',
 
1192
        help='Hard-link working tree files where possible.'),
1148
1193
        Option('no-tree',
1149
1194
            help="Create a branch without a working-tree."),
1150
1195
        Option('switch',
1168
1213
 
1169
1214
    def run(self, from_location, to_location=None, revision=None,
1170
1215
            hardlink=False, stacked=False, standalone=False, no_tree=False,
1171
 
            use_existing_dir=False, switch=False, bind=False,
1172
 
            files_from=None):
 
1216
            use_existing_dir=False, switch=False, bind=False):
1173
1217
        from bzrlib import switch as _mod_switch
1174
1218
        from bzrlib.tag import _merge_tags_if_possible
1175
1219
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
1176
1220
            from_location)
1177
 
        if not (hardlink or files_from):
1178
 
            # accelerator_tree is usually slower because you have to read N
1179
 
            # files (no readahead, lots of seeks, etc), but allow the user to
1180
 
            # explicitly request it
1181
 
            accelerator_tree = None
1182
 
        if files_from is not None and files_from != from_location:
1183
 
            accelerator_tree = WorkingTree.open(files_from)
1184
1221
        revision = _get_one_revision('branch', revision)
1185
 
        self.add_cleanup(br_from.lock_read().unlock)
 
1222
        br_from.lock_read()
 
1223
        self.add_cleanup(br_from.unlock)
1186
1224
        if revision is not None:
1187
1225
            revision_id = revision.as_revision_id(br_from)
1188
1226
        else:
1293
1331
            to_location = branch_location
1294
1332
        accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch(
1295
1333
            branch_location)
1296
 
        if not (hardlink or files_from):
1297
 
            # accelerator_tree is usually slower because you have to read N
1298
 
            # files (no readahead, lots of seeks, etc), but allow the user to
1299
 
            # explicitly request it
1300
 
            accelerator_tree = None
1301
1334
        revision = _get_one_revision('checkout', revision)
1302
 
        if files_from is not None and files_from != branch_location:
 
1335
        if files_from is not None:
1303
1336
            accelerator_tree = WorkingTree.open(files_from)
1304
1337
        if revision is not None:
1305
1338
            revision_id = revision.as_revision_id(source)
1333
1366
    @display_command
1334
1367
    def run(self, dir=u'.'):
1335
1368
        tree = WorkingTree.open_containing(dir)[0]
1336
 
        self.add_cleanup(tree.lock_read().unlock)
 
1369
        tree.lock_read()
 
1370
        self.add_cleanup(tree.unlock)
1337
1371
        new_inv = tree.inventory
1338
1372
        old_tree = tree.basis_tree()
1339
 
        self.add_cleanup(old_tree.lock_read().unlock)
 
1373
        old_tree.lock_read()
 
1374
        self.add_cleanup(old_tree.unlock)
1340
1375
        old_inv = old_tree.inventory
1341
1376
        renames = []
1342
1377
        iterator = tree.iter_changes(old_tree, include_unchanged=True)
1367
1402
 
1368
1403
    _see_also = ['pull', 'working-trees', 'status-flags']
1369
1404
    takes_args = ['dir?']
1370
 
    takes_options = ['revision',
1371
 
                     Option('show-base',
1372
 
                            help="Show base revision text in conflicts."),
1373
 
                     ]
 
1405
    takes_options = ['revision']
1374
1406
    aliases = ['up']
1375
1407
 
1376
 
    def run(self, dir='.', revision=None,show_base=None):
 
1408
    def run(self, dir='.', revision=None):
1377
1409
        if revision is not None and len(revision) != 1:
1378
1410
            raise errors.BzrCommandError(
1379
1411
                        "bzr update --revision takes exactly one revision")
1383
1415
        master = branch.get_master_branch(
1384
1416
            possible_transports=possible_transports)
1385
1417
        if master is not None:
 
1418
            tree.lock_write()
1386
1419
            branch_location = master.base
1387
 
            tree.lock_write()
1388
1420
        else:
 
1421
            tree.lock_tree_write()
1389
1422
            branch_location = tree.branch.base
1390
 
            tree.lock_tree_write()
1391
1423
        self.add_cleanup(tree.unlock)
1392
1424
        # get rid of the final '/' and be ready for display
1393
1425
        branch_location = urlutils.unescape_for_display(
1419
1451
                change_reporter,
1420
1452
                possible_transports=possible_transports,
1421
1453
                revision=revision_id,
1422
 
                old_tip=old_tip,
1423
 
                show_base=show_base)
 
1454
                old_tip=old_tip)
1424
1455
        except errors.NoSuchRevision, e:
1425
1456
            raise errors.BzrCommandError(
1426
1457
                                  "branch has no revision %s\n"
1488
1519
class cmd_remove(Command):
1489
1520
    __doc__ = """Remove files or directories.
1490
1521
 
1491
 
    This makes Bazaar stop tracking changes to the specified files. Bazaar will
1492
 
    delete them if they can easily be recovered using revert otherwise they
1493
 
    will be backed up (adding an extention of the form .~#~). If no options or
1494
 
    parameters are given Bazaar will scan for files that are being tracked by
1495
 
    Bazaar but missing in your tree and stop tracking them for you.
 
1522
    This makes bzr stop tracking changes to the specified files. bzr will delete
 
1523
    them if they can easily be recovered using revert. If no options or
 
1524
    parameters are given bzr will scan for files that are being tracked by bzr
 
1525
    but missing in your tree and stop tracking them for you.
1496
1526
    """
1497
1527
    takes_args = ['file*']
1498
1528
    takes_options = ['verbose',
1500
1530
        RegistryOption.from_kwargs('file-deletion-strategy',
1501
1531
            'The file deletion mode to be used.',
1502
1532
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1503
 
            safe='Backup changed files (default).',
 
1533
            safe='Only delete files if they can be'
 
1534
                 ' safely recovered (default).',
1504
1535
            keep='Delete from bzr but leave the working copy.',
1505
1536
            force='Delete all the specified files, even if they can not be '
1506
1537
                'recovered and even if they are non-empty directories.')]
1509
1540
 
1510
1541
    def run(self, file_list, verbose=False, new=False,
1511
1542
        file_deletion_strategy='safe'):
1512
 
        tree, file_list = WorkingTree.open_containing_paths(file_list)
 
1543
        tree, file_list = tree_files(file_list)
1513
1544
 
1514
1545
        if file_list is not None:
1515
1546
            file_list = [f for f in file_list]
1516
1547
 
1517
 
        self.add_cleanup(tree.lock_write().unlock)
 
1548
        tree.lock_write()
 
1549
        self.add_cleanup(tree.unlock)
1518
1550
        # Heuristics should probably all move into tree.remove_smart or
1519
1551
        # some such?
1520
1552
        if new:
1603
1635
 
1604
1636
    _see_also = ['check']
1605
1637
    takes_args = ['branch?']
1606
 
    takes_options = [
1607
 
        Option('canonicalize-chks',
1608
 
               help='Make sure CHKs are in canonical form (repairs '
1609
 
                    'bug 522637).',
1610
 
               hidden=True),
1611
 
        ]
1612
1638
 
1613
 
    def run(self, branch=".", canonicalize_chks=False):
 
1639
    def run(self, branch="."):
1614
1640
        from bzrlib.reconcile import reconcile
1615
1641
        dir = bzrdir.BzrDir.open(branch)
1616
 
        reconcile(dir, canonicalize_chks=canonicalize_chks)
 
1642
        reconcile(dir)
1617
1643
 
1618
1644
 
1619
1645
class cmd_revision_history(Command):
1895
1921
        Same as 'bzr diff' but prefix paths with old/ and new/::
1896
1922
 
1897
1923
            bzr diff --prefix old/:new/
1898
 
            
1899
 
        Show the differences using a custom diff program with options::
1900
 
        
1901
 
            bzr diff --using /usr/bin/diff --diff-options -wu
1902
1924
    """
1903
1925
    _see_also = ['status']
1904
1926
    takes_args = ['file*']
1963
1985
         old_branch, new_branch,
1964
1986
         specific_files, extra_trees) = get_trees_and_branches_to_diff_locked(
1965
1987
            file_list, revision, old, new, self.add_cleanup, apply_view=True)
1966
 
        # GNU diff on Windows uses ANSI encoding for filenames
1967
 
        path_encoding = osutils.get_diff_header_encoding()
1968
1988
        return show_diff_trees(old_tree, new_tree, sys.stdout,
1969
1989
                               specific_files=specific_files,
1970
1990
                               external_diff_options=diff_options,
1971
1991
                               old_label=old_label, new_label=new_label,
1972
 
                               extra_trees=extra_trees,
1973
 
                               path_encoding=path_encoding,
1974
 
                               using=using,
 
1992
                               extra_trees=extra_trees, using=using,
1975
1993
                               format_cls=format)
1976
1994
 
1977
1995
 
1985
2003
    # level of effort but possibly much less IO.  (Or possibly not,
1986
2004
    # if the directories are very large...)
1987
2005
    _see_also = ['status', 'ls']
1988
 
    takes_options = ['directory', 'show-ids']
 
2006
    takes_options = ['show-ids']
1989
2007
 
1990
2008
    @display_command
1991
 
    def run(self, show_ids=False, directory=u'.'):
1992
 
        tree = WorkingTree.open_containing(directory)[0]
1993
 
        self.add_cleanup(tree.lock_read().unlock)
 
2009
    def run(self, show_ids=False):
 
2010
        tree = WorkingTree.open_containing(u'.')[0]
 
2011
        tree.lock_read()
 
2012
        self.add_cleanup(tree.unlock)
1994
2013
        old = tree.basis_tree()
1995
 
        self.add_cleanup(old.lock_read().unlock)
 
2014
        old.lock_read()
 
2015
        self.add_cleanup(old.unlock)
1996
2016
        for path, ie in old.inventory.iter_entries():
1997
2017
            if not tree.has_id(ie.file_id):
1998
2018
                self.outf.write(path)
2008
2028
 
2009
2029
    hidden = True
2010
2030
    _see_also = ['status', 'ls']
2011
 
    takes_options = ['directory', 'null']
 
2031
    takes_options = [
 
2032
            Option('null',
 
2033
                   help='Write an ascii NUL (\\0) separator '
 
2034
                   'between files rather than a newline.')
 
2035
            ]
2012
2036
 
2013
2037
    @display_command
2014
 
    def run(self, null=False, directory=u'.'):
2015
 
        tree = WorkingTree.open_containing(directory)[0]
 
2038
    def run(self, null=False):
 
2039
        tree = WorkingTree.open_containing(u'.')[0]
2016
2040
        td = tree.changes_from(tree.basis_tree())
2017
2041
        for path, id, kind, text_modified, meta_modified in td.modified:
2018
2042
            if null:
2027
2051
 
2028
2052
    hidden = True
2029
2053
    _see_also = ['status', 'ls']
2030
 
    takes_options = ['directory', 'null']
 
2054
    takes_options = [
 
2055
            Option('null',
 
2056
                   help='Write an ascii NUL (\\0) separator '
 
2057
                   'between files rather than a newline.')
 
2058
            ]
2031
2059
 
2032
2060
    @display_command
2033
 
    def run(self, null=False, directory=u'.'):
2034
 
        wt = WorkingTree.open_containing(directory)[0]
2035
 
        self.add_cleanup(wt.lock_read().unlock)
 
2061
    def run(self, null=False):
 
2062
        wt = WorkingTree.open_containing(u'.')[0]
 
2063
        wt.lock_read()
 
2064
        self.add_cleanup(wt.unlock)
2036
2065
        basis = wt.basis_tree()
2037
 
        self.add_cleanup(basis.lock_read().unlock)
 
2066
        basis.lock_read()
 
2067
        self.add_cleanup(basis.unlock)
2038
2068
        basis_inv = basis.inventory
2039
2069
        inv = wt.inventory
2040
2070
        for file_id in inv:
2043
2073
            if inv.is_root(file_id) and len(basis_inv) == 0:
2044
2074
                continue
2045
2075
            path = inv.id2path(file_id)
2046
 
            if not os.access(osutils.pathjoin(wt.basedir, path), os.F_OK):
 
2076
            if not os.access(osutils.abspath(path), os.F_OK):
2047
2077
                continue
2048
2078
            if null:
2049
2079
                self.outf.write(path + '\0')
2249
2279
                   help='Show just the specified revision.'
2250
2280
                   ' See also "help revisionspec".'),
2251
2281
            'log-format',
2252
 
            RegistryOption('authors',
2253
 
                'What names to list as authors - first, all or committer.',
2254
 
                title='Authors',
2255
 
                lazy_registry=('bzrlib.log', 'author_list_registry'),
2256
 
            ),
2257
2282
            Option('levels',
2258
2283
                   short_name='n',
2259
2284
                   help='Number of levels to display - 0 for all, 1 for flat.',
2294
2319
            limit=None,
2295
2320
            show_diff=False,
2296
2321
            include_merges=False,
2297
 
            authors=None,
2298
2322
            exclude_common_ancestry=False,
2299
2323
            ):
2300
2324
        from bzrlib.log import (
2328
2352
        if file_list:
2329
2353
            # find the file ids to log and check for directory filtering
2330
2354
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(
2331
 
                revision, file_list, self.add_cleanup)
 
2355
                revision, file_list)
 
2356
            self.add_cleanup(b.unlock)
2332
2357
            for relpath, file_id, kind in file_info_list:
2333
2358
                if file_id is None:
2334
2359
                    raise errors.BzrCommandError(
2352
2377
                location = '.'
2353
2378
            dir, relpath = bzrdir.BzrDir.open_containing(location)
2354
2379
            b = dir.open_branch()
2355
 
            self.add_cleanup(b.lock_read().unlock)
 
2380
            b.lock_read()
 
2381
            self.add_cleanup(b.unlock)
2356
2382
            rev1, rev2 = _get_revision_range(revision, b, self.name())
2357
2383
 
2358
2384
        # Decide on the type of delta & diff filtering to use
2378
2404
                        show_timezone=timezone,
2379
2405
                        delta_format=get_verbosity_level(),
2380
2406
                        levels=levels,
2381
 
                        show_advice=levels is None,
2382
 
                        author_list_handler=authors)
 
2407
                        show_advice=levels is None)
2383
2408
 
2384
2409
        # Choose the algorithm for doing the logging. It's annoying
2385
2410
        # having multiple code paths like this but necessary until
2483
2508
        tree, relpath = WorkingTree.open_containing(filename)
2484
2509
        file_id = tree.path2id(relpath)
2485
2510
        b = tree.branch
2486
 
        self.add_cleanup(b.lock_read().unlock)
 
2511
        b.lock_read()
 
2512
        self.add_cleanup(b.unlock)
2487
2513
        touching_revs = log.find_touching_revisions(b, file_id)
2488
2514
        for revno, revision_id, what in touching_revs:
2489
2515
            self.outf.write("%6d %s\n" % (revno, what))
2502
2528
                   help='Recurse into subdirectories.'),
2503
2529
            Option('from-root',
2504
2530
                   help='Print paths relative to the root of the branch.'),
2505
 
            Option('unknown', short_name='u',
2506
 
                help='Print unknown files.'),
 
2531
            Option('unknown', help='Print unknown files.'),
2507
2532
            Option('versioned', help='Print versioned files.',
2508
2533
                   short_name='V'),
2509
 
            Option('ignored', short_name='i',
2510
 
                help='Print ignored files.'),
2511
 
            Option('kind', short_name='k',
 
2534
            Option('ignored', help='Print ignored files.'),
 
2535
            Option('null',
 
2536
                   help='Write an ascii NUL (\\0) separator '
 
2537
                   'between files rather than a newline.'),
 
2538
            Option('kind',
2512
2539
                   help='List entries of a particular kind: file, directory, symlink.',
2513
2540
                   type=unicode),
2514
 
            'null',
2515
2541
            'show-ids',
2516
 
            'directory',
2517
2542
            ]
2518
2543
    @display_command
2519
2544
    def run(self, revision=None, verbose=False,
2520
2545
            recursive=False, from_root=False,
2521
2546
            unknown=False, versioned=False, ignored=False,
2522
 
            null=False, kind=None, show_ids=False, path=None, directory=None):
 
2547
            null=False, kind=None, show_ids=False, path=None):
2523
2548
 
2524
2549
        if kind and kind not in ('file', 'directory', 'symlink'):
2525
2550
            raise errors.BzrCommandError('invalid kind specified')
2537
2562
                raise errors.BzrCommandError('cannot specify both --from-root'
2538
2563
                                             ' and PATH')
2539
2564
            fs_path = path
2540
 
        tree, branch, relpath = \
2541
 
            _open_directory_or_containing_tree_or_branch(fs_path, directory)
 
2565
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
 
2566
            fs_path)
2542
2567
 
2543
2568
        # Calculate the prefix to use
2544
2569
        prefix = None
2559
2584
                view_str = views.view_display_str(view_files)
2560
2585
                note("Ignoring files outside view. View is %s" % view_str)
2561
2586
 
2562
 
        self.add_cleanup(tree.lock_read().unlock)
 
2587
        tree.lock_read()
 
2588
        self.add_cleanup(tree.unlock)
2563
2589
        for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
2564
2590
            from_dir=relpath, recursive=recursive):
2565
2591
            # Apply additional masking
2612
2638
 
2613
2639
    hidden = True
2614
2640
    _see_also = ['ls']
2615
 
    takes_options = ['directory']
2616
2641
 
2617
2642
    @display_command
2618
 
    def run(self, directory=u'.'):
2619
 
        for f in WorkingTree.open_containing(directory)[0].unknowns():
 
2643
    def run(self):
 
2644
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
2620
2645
            self.outf.write(osutils.quotefn(f) + '\n')
2621
2646
 
2622
2647
 
2687
2712
 
2688
2713
    _see_also = ['status', 'ignored', 'patterns']
2689
2714
    takes_args = ['name_pattern*']
2690
 
    takes_options = ['directory',
 
2715
    takes_options = [
2691
2716
        Option('default-rules',
2692
2717
               help='Display the default ignore rules that bzr uses.')
2693
2718
        ]
2694
2719
 
2695
 
    def run(self, name_pattern_list=None, default_rules=None,
2696
 
            directory=u'.'):
 
2720
    def run(self, name_pattern_list=None, default_rules=None):
2697
2721
        from bzrlib import ignores
2698
2722
        if default_rules is not None:
2699
2723
            # dump the default rules and exit
2705
2729
                "NAME_PATTERN or --default-rules.")
2706
2730
        name_pattern_list = [globbing.normalize_pattern(p)
2707
2731
                             for p in name_pattern_list]
2708
 
        bad_patterns = ''
2709
 
        for p in name_pattern_list:
2710
 
            if not globbing.Globster.is_pattern_valid(p):
2711
 
                bad_patterns += ('\n  %s' % p)
2712
 
        if bad_patterns:
2713
 
            msg = ('Invalid ignore pattern(s) found. %s' % bad_patterns)
2714
 
            ui.ui_factory.show_error(msg)
2715
 
            raise errors.InvalidPattern('')
2716
2732
        for name_pattern in name_pattern_list:
2717
2733
            if (name_pattern[0] == '/' or
2718
2734
                (len(name_pattern) > 1 and name_pattern[1] == ':')):
2719
2735
                raise errors.BzrCommandError(
2720
2736
                    "NAME_PATTERN should not be an absolute path")
2721
 
        tree, relpath = WorkingTree.open_containing(directory)
 
2737
        tree, relpath = WorkingTree.open_containing(u'.')
2722
2738
        ignores.tree_ignores_add_patterns(tree, name_pattern_list)
2723
2739
        ignored = globbing.Globster(name_pattern_list)
2724
2740
        matches = []
2725
 
        self.add_cleanup(tree.lock_read().unlock)
 
2741
        tree.lock_read()
2726
2742
        for entry in tree.list_files():
2727
2743
            id = entry[3]
2728
2744
            if id is not None:
2729
2745
                filename = entry[0]
2730
2746
                if ignored.match(filename):
2731
2747
                    matches.append(filename)
 
2748
        tree.unlock()
2732
2749
        if len(matches) > 0:
2733
2750
            self.outf.write("Warning: the following files are version controlled and"
2734
2751
                  " match your ignore pattern:\n%s"
2749
2766
 
2750
2767
    encoding_type = 'replace'
2751
2768
    _see_also = ['ignore', 'ls']
2752
 
    takes_options = ['directory']
2753
2769
 
2754
2770
    @display_command
2755
 
    def run(self, directory=u'.'):
2756
 
        tree = WorkingTree.open_containing(directory)[0]
2757
 
        self.add_cleanup(tree.lock_read().unlock)
 
2771
    def run(self):
 
2772
        tree = WorkingTree.open_containing(u'.')[0]
 
2773
        tree.lock_read()
 
2774
        self.add_cleanup(tree.unlock)
2758
2775
        for path, file_class, kind, file_id, entry in tree.list_files():
2759
2776
            if file_class != 'I':
2760
2777
                continue
2771
2788
    """
2772
2789
    hidden = True
2773
2790
    takes_args = ['revno']
2774
 
    takes_options = ['directory']
2775
2791
 
2776
2792
    @display_command
2777
 
    def run(self, revno, directory=u'.'):
 
2793
    def run(self, revno):
2778
2794
        try:
2779
2795
            revno = int(revno)
2780
2796
        except ValueError:
2781
2797
            raise errors.BzrCommandError("not a valid revision-number: %r"
2782
2798
                                         % revno)
2783
 
        revid = WorkingTree.open_containing(directory)[0].branch.get_rev_id(revno)
 
2799
        revid = WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
2784
2800
        self.outf.write("%s\n" % revid)
2785
2801
 
2786
2802
 
2813
2829
      =================       =========================
2814
2830
    """
2815
2831
    takes_args = ['dest', 'branch_or_subdir?']
2816
 
    takes_options = ['directory',
 
2832
    takes_options = [
2817
2833
        Option('format',
2818
2834
               help="Type of file to export to.",
2819
2835
               type=unicode),
2828
2844
                    'revision in which it was changed.'),
2829
2845
        ]
2830
2846
    def run(self, dest, branch_or_subdir=None, revision=None, format=None,
2831
 
        root=None, filters=False, per_file_timestamps=False, directory=u'.'):
 
2847
        root=None, filters=False, per_file_timestamps=False):
2832
2848
        from bzrlib.export import export
2833
2849
 
2834
2850
        if branch_or_subdir is None:
2835
 
            tree = WorkingTree.open_containing(directory)[0]
 
2851
            tree = WorkingTree.open_containing(u'.')[0]
2836
2852
            b = tree.branch
2837
2853
            subdir = None
2838
2854
        else:
2857
2873
    """
2858
2874
 
2859
2875
    _see_also = ['ls']
2860
 
    takes_options = ['directory',
 
2876
    takes_options = [
2861
2877
        Option('name-from-revision', help='The path name in the old tree.'),
2862
2878
        Option('filters', help='Apply content filters to display the '
2863
2879
                'convenience form.'),
2868
2884
 
2869
2885
    @display_command
2870
2886
    def run(self, filename, revision=None, name_from_revision=False,
2871
 
            filters=False, directory=None):
 
2887
            filters=False):
2872
2888
        if revision is not None and len(revision) != 1:
2873
2889
            raise errors.BzrCommandError("bzr cat --revision takes exactly"
2874
2890
                                         " one revision specifier")
2875
2891
        tree, branch, relpath = \
2876
 
            _open_directory_or_containing_tree_or_branch(filename, directory)
2877
 
        self.add_cleanup(branch.lock_read().unlock)
 
2892
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
 
2893
        branch.lock_read()
 
2894
        self.add_cleanup(branch.unlock)
2878
2895
        return self._run(tree, branch, relpath, filename, revision,
2879
2896
                         name_from_revision, filters)
2880
2897
 
2883
2900
        if tree is None:
2884
2901
            tree = b.basis_tree()
2885
2902
        rev_tree = _get_one_revision_tree('cat', revision, branch=b)
2886
 
        self.add_cleanup(rev_tree.lock_read().unlock)
 
2903
        rev_tree.lock_read()
 
2904
        self.add_cleanup(rev_tree.unlock)
2887
2905
 
2888
2906
        old_file_id = rev_tree.path2id(relpath)
2889
2907
 
3110
3128
 
3111
3129
        properties = {}
3112
3130
 
3113
 
        tree, selected_list = WorkingTree.open_containing_paths(selected_list)
 
3131
        tree, selected_list = tree_files(selected_list)
3114
3132
        if selected_list == ['']:
3115
3133
            # workaround - commit of root of tree should be exactly the same
3116
3134
            # as just default commit in that tree, and succeed even though
3151
3169
        def get_message(commit_obj):
3152
3170
            """Callback to get commit message"""
3153
3171
            if file:
3154
 
                f = open(file)
3155
 
                try:
3156
 
                    my_message = f.read().decode(osutils.get_user_encoding())
3157
 
                finally:
3158
 
                    f.close()
 
3172
                my_message = codecs.open(
 
3173
                    file, 'rt', osutils.get_user_encoding()).read()
3159
3174
            elif message is not None:
3160
3175
                my_message = message
3161
3176
            else:
3190
3205
                        reporter=None, verbose=verbose, revprops=properties,
3191
3206
                        authors=author, timestamp=commit_stamp,
3192
3207
                        timezone=offset,
3193
 
                        exclude=tree.safe_relpath_files(exclude))
 
3208
                        exclude=safe_relpath_files(tree, exclude))
3194
3209
        except PointlessCommit:
3195
3210
            raise errors.BzrCommandError("No changes to commit."
3196
3211
                              " Use --unchanged to commit anyhow.")
3315
3330
 
3316
3331
            bzr whoami "Frank Chu <fchu@example.com>"
3317
3332
    """
3318
 
    takes_options = [ 'directory',
3319
 
                      Option('email',
 
3333
    takes_options = [ Option('email',
3320
3334
                             help='Display email address only.'),
3321
3335
                      Option('branch',
3322
3336
                             help='Set identity for the current branch instead of '
3326
3340
    encoding_type = 'replace'
3327
3341
 
3328
3342
    @display_command
3329
 
    def run(self, email=False, branch=False, name=None, directory=None):
 
3343
    def run(self, email=False, branch=False, name=None):
3330
3344
        if name is None:
3331
 
            if directory is None:
3332
 
                # use branch if we're inside one; otherwise global config
3333
 
                try:
3334
 
                    c = Branch.open_containing(u'.')[0].get_config()
3335
 
                except errors.NotBranchError:
3336
 
                    c = _mod_config.GlobalConfig()
3337
 
            else:
3338
 
                c = Branch.open(directory).get_config()
 
3345
            # use branch if we're inside one; otherwise global config
 
3346
            try:
 
3347
                c = Branch.open_containing('.')[0].get_config()
 
3348
            except errors.NotBranchError:
 
3349
                c = config.GlobalConfig()
3339
3350
            if email:
3340
3351
                self.outf.write(c.user_email() + '\n')
3341
3352
            else:
3344
3355
 
3345
3356
        # display a warning if an email address isn't included in the given name.
3346
3357
        try:
3347
 
            _mod_config.extract_email_address(name)
 
3358
            config.extract_email_address(name)
3348
3359
        except errors.NoEmailInUsername, e:
3349
3360
            warning('"%s" does not seem to contain an email address.  '
3350
3361
                    'This is allowed, but not recommended.', name)
3351
3362
 
3352
3363
        # use global config unless --branch given
3353
3364
        if branch:
3354
 
            if directory is None:
3355
 
                c = Branch.open_containing(u'.')[0].get_config()
3356
 
            else:
3357
 
                c = Branch.open(directory).get_config()
 
3365
            c = Branch.open_containing('.')[0].get_config()
3358
3366
        else:
3359
 
            c = _mod_config.GlobalConfig()
 
3367
            c = config.GlobalConfig()
3360
3368
        c.set_user_option('email', name)
3361
3369
 
3362
3370
 
3372
3380
 
3373
3381
    _see_also = ['info']
3374
3382
    takes_args = ['nickname?']
3375
 
    takes_options = ['directory']
3376
 
    def run(self, nickname=None, directory=u'.'):
3377
 
        branch = Branch.open_containing(directory)[0]
 
3383
    def run(self, nickname=None):
 
3384
        branch = Branch.open_containing(u'.')[0]
3378
3385
        if nickname is None:
3379
3386
            self.printme(branch)
3380
3387
        else:
3429
3436
                'bzr alias --remove expects an alias to remove.')
3430
3437
        # If alias is not found, print something like:
3431
3438
        # unalias: foo: not found
3432
 
        c = _mod_config.GlobalConfig()
 
3439
        c = config.GlobalConfig()
3433
3440
        c.unset_alias(alias_name)
3434
3441
 
3435
3442
    @display_command
3436
3443
    def print_aliases(self):
3437
3444
        """Print out the defined aliases in a similar format to bash."""
3438
 
        aliases = _mod_config.GlobalConfig().get_aliases()
 
3445
        aliases = config.GlobalConfig().get_aliases()
3439
3446
        for key, value in sorted(aliases.iteritems()):
3440
3447
            self.outf.write('bzr alias %s="%s"\n' % (key, value))
3441
3448
 
3451
3458
 
3452
3459
    def set_alias(self, alias_name, alias_command):
3453
3460
        """Save the alias in the global config."""
3454
 
        c = _mod_config.GlobalConfig()
 
3461
        c = config.GlobalConfig()
3455
3462
        c.set_alias(alias_name, alias_command)
3456
3463
 
3457
3464
 
3492
3499
    If you set BZR_TEST_PDB=1 when running selftest, failing tests will drop
3493
3500
    into a pdb postmortem session.
3494
3501
 
3495
 
    The --coverage=DIRNAME global option produces a report with covered code
3496
 
    indicated.
3497
 
 
3498
3502
    :Examples:
3499
3503
        Run only tests relating to 'ignore'::
3500
3504
 
3533
3537
                                 'throughout the test suite.',
3534
3538
                            type=get_transport_type),
3535
3539
                     Option('benchmark',
3536
 
                            help='Run the benchmarks rather than selftests.',
3537
 
                            hidden=True),
 
3540
                            help='Run the benchmarks rather than selftests.'),
3538
3541
                     Option('lsprof-timed',
3539
3542
                            help='Generate lsprof output for benchmarked'
3540
3543
                                 ' sections of code.'),
3541
3544
                     Option('lsprof-tests',
3542
3545
                            help='Generate lsprof output for each test.'),
 
3546
                     Option('cache-dir', type=str,
 
3547
                            help='Cache intermediate benchmark output in this '
 
3548
                                 'directory.'),
3543
3549
                     Option('first',
3544
3550
                            help='Run all tests, but run specified tests first.',
3545
3551
                            short_name='f',
3579
3585
 
3580
3586
    def run(self, testspecs_list=None, verbose=False, one=False,
3581
3587
            transport=None, benchmark=None,
3582
 
            lsprof_timed=None,
 
3588
            lsprof_timed=None, cache_dir=None,
3583
3589
            first=False, list_only=False,
3584
3590
            randomize=None, exclude=None, strict=False,
3585
3591
            load_list=None, debugflag=None, starting_with=None, subunit=False,
3586
3592
            parallel=None, lsprof_tests=False):
3587
 
        from bzrlib import tests
3588
 
 
 
3593
        from bzrlib.tests import selftest
 
3594
        import bzrlib.benchmarks as benchmarks
 
3595
        from bzrlib.benchmarks import tree_creator
 
3596
 
 
3597
        # Make deprecation warnings visible, unless -Werror is set
 
3598
        symbol_versioning.activate_deprecation_warnings(override=False)
 
3599
 
 
3600
        if cache_dir is not None:
 
3601
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
3589
3602
        if testspecs_list is not None:
3590
3603
            pattern = '|'.join(testspecs_list)
3591
3604
        else:
3599
3612
            self.additional_selftest_args['runner_class'] = SubUnitBzrRunner
3600
3613
            # On Windows, disable automatic conversion of '\n' to '\r\n' in
3601
3614
            # stdout, which would corrupt the subunit stream. 
3602
 
            # FIXME: This has been fixed in subunit trunk (>0.0.5) so the
3603
 
            # following code can be deleted when it's sufficiently deployed
3604
 
            # -- vila/mgz 20100514
3605
 
            if (sys.platform == "win32"
3606
 
                and getattr(sys.stdout, 'fileno', None) is not None):
 
3615
            if sys.platform == "win32" and sys.stdout.fileno() >= 0:
3607
3616
                import msvcrt
3608
3617
                msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
3609
3618
        if parallel:
3610
3619
            self.additional_selftest_args.setdefault(
3611
3620
                'suite_decorators', []).append(parallel)
3612
3621
        if benchmark:
3613
 
            raise errors.BzrCommandError(
3614
 
                "--benchmark is no longer supported from bzr 2.2; "
3615
 
                "use bzr-usertest instead")
3616
 
        test_suite_factory = None
 
3622
            test_suite_factory = benchmarks.test_suite
 
3623
            # Unless user explicitly asks for quiet, be verbose in benchmarks
 
3624
            verbose = not is_quiet()
 
3625
            # TODO: should possibly lock the history file...
 
3626
            benchfile = open(".perf_history", "at", buffering=1)
 
3627
            self.add_cleanup(benchfile.close)
 
3628
        else:
 
3629
            test_suite_factory = None
 
3630
            benchfile = None
3617
3631
        selftest_kwargs = {"verbose": verbose,
3618
3632
                          "pattern": pattern,
3619
3633
                          "stop_on_failure": one,
3621
3635
                          "test_suite_factory": test_suite_factory,
3622
3636
                          "lsprof_timed": lsprof_timed,
3623
3637
                          "lsprof_tests": lsprof_tests,
 
3638
                          "bench_history": benchfile,
3624
3639
                          "matching_tests_first": first,
3625
3640
                          "list_only": list_only,
3626
3641
                          "random_seed": randomize,
3631
3646
                          "starting_with": starting_with
3632
3647
                          }
3633
3648
        selftest_kwargs.update(self.additional_selftest_args)
3634
 
 
3635
 
        # Make deprecation warnings visible, unless -Werror is set
3636
 
        cleanup = symbol_versioning.activate_deprecation_warnings(
3637
 
            override=False)
3638
 
        try:
3639
 
            result = tests.selftest(**selftest_kwargs)
3640
 
        finally:
3641
 
            cleanup()
 
3649
        result = selftest(**selftest_kwargs)
3642
3650
        return int(not result)
3643
3651
 
3644
3652
 
3682
3690
 
3683
3691
        branch1 = Branch.open_containing(branch)[0]
3684
3692
        branch2 = Branch.open_containing(other)[0]
3685
 
        self.add_cleanup(branch1.lock_read().unlock)
3686
 
        self.add_cleanup(branch2.lock_read().unlock)
 
3693
        branch1.lock_read()
 
3694
        self.add_cleanup(branch1.unlock)
 
3695
        branch2.lock_read()
 
3696
        self.add_cleanup(branch2.unlock)
3687
3697
        last1 = ensure_null(branch1.last_revision())
3688
3698
        last2 = ensure_null(branch2.last_revision())
3689
3699
 
3783
3793
                ' completely merged into the source, pull from the'
3784
3794
                ' source rather than merging.  When this happens,'
3785
3795
                ' you do not need to commit the result.'),
3786
 
        custom_help('directory',
 
3796
        Option('directory',
3787
3797
               help='Branch to merge into, '
3788
 
                    'rather than the one containing the working directory.'),
 
3798
                    'rather than the one containing the working directory.',
 
3799
               short_name='d',
 
3800
               type=unicode,
 
3801
               ),
3789
3802
        Option('preview', help='Instead of merging, show a diff of the'
3790
3803
               ' merge.'),
3791
3804
        Option('interactive', help='Select changes interactively.',
3824
3837
            unversioned_filter=tree.is_ignored, view_info=view_info)
3825
3838
        pb = ui.ui_factory.nested_progress_bar()
3826
3839
        self.add_cleanup(pb.finished)
3827
 
        self.add_cleanup(tree.lock_write().unlock)
 
3840
        tree.lock_write()
 
3841
        self.add_cleanup(tree.unlock)
3828
3842
        if location is not None:
3829
3843
            try:
3830
3844
                mergeable = bundle.read_mergeable_from_url(location,
3891
3905
    def _do_preview(self, merger):
3892
3906
        from bzrlib.diff import show_diff_trees
3893
3907
        result_tree = self._get_preview(merger)
3894
 
        path_encoding = osutils.get_diff_header_encoding()
3895
3908
        show_diff_trees(merger.this_tree, result_tree, self.outf,
3896
 
                        old_label='', new_label='',
3897
 
                        path_encoding=path_encoding)
 
3909
                        old_label='', new_label='')
3898
3910
 
3899
3911
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
3900
3912
        merger.change_reporter = change_reporter
4087
4099
        from bzrlib.conflicts import restore
4088
4100
        if merge_type is None:
4089
4101
            merge_type = _mod_merge.Merge3Merger
4090
 
        tree, file_list = WorkingTree.open_containing_paths(file_list)
4091
 
        self.add_cleanup(tree.lock_write().unlock)
 
4102
        tree, file_list = tree_files(file_list)
 
4103
        tree.lock_write()
 
4104
        self.add_cleanup(tree.unlock)
4092
4105
        parents = tree.get_parent_ids()
4093
4106
        if len(parents) != 2:
4094
4107
            raise errors.BzrCommandError("Sorry, remerge only works after normal"
4203
4216
 
4204
4217
    def run(self, revision=None, no_backup=False, file_list=None,
4205
4218
            forget_merges=None):
4206
 
        tree, file_list = WorkingTree.open_containing_paths(file_list)
4207
 
        self.add_cleanup(tree.lock_tree_write().unlock)
 
4219
        tree, file_list = tree_files(file_list)
 
4220
        tree.lock_tree_write()
 
4221
        self.add_cleanup(tree.unlock)
4208
4222
        if forget_merges:
4209
4223
            tree.set_parent_ids(tree.get_parent_ids()[:1])
4210
4224
        else:
4299
4313
    _see_also = ['merge', 'pull']
4300
4314
    takes_args = ['other_branch?']
4301
4315
    takes_options = [
4302
 
        'directory',
4303
4316
        Option('reverse', 'Reverse the order of revisions.'),
4304
4317
        Option('mine-only',
4305
4318
               'Display changes in the local branch only.'),
4327
4340
            theirs_only=False,
4328
4341
            log_format=None, long=False, short=False, line=False,
4329
4342
            show_ids=False, verbose=False, this=False, other=False,
4330
 
            include_merges=False, revision=None, my_revision=None,
4331
 
            directory=u'.'):
 
4343
            include_merges=False, revision=None, my_revision=None):
4332
4344
        from bzrlib.missing import find_unmerged, iter_log_revisions
4333
4345
        def message(s):
4334
4346
            if not is_quiet():
4347
4359
        elif theirs_only:
4348
4360
            restrict = 'remote'
4349
4361
 
4350
 
        local_branch = Branch.open_containing(directory)[0]
4351
 
        self.add_cleanup(local_branch.lock_read().unlock)
 
4362
        local_branch = Branch.open_containing(u".")[0]
 
4363
        local_branch.lock_read()
 
4364
        self.add_cleanup(local_branch.unlock)
4352
4365
 
4353
4366
        parent = local_branch.get_parent()
4354
4367
        if other_branch is None:
4365
4378
        if remote_branch.base == local_branch.base:
4366
4379
            remote_branch = local_branch
4367
4380
        else:
4368
 
            self.add_cleanup(remote_branch.lock_read().unlock)
 
4381
            remote_branch.lock_read()
 
4382
            self.add_cleanup(remote_branch.unlock)
4369
4383
 
4370
4384
        local_revid_range = _revision_range_to_revid_range(
4371
4385
            _get_revision_range(my_revision, local_branch,
4426
4440
            message("Branches are up to date.\n")
4427
4441
        self.cleanup_now()
4428
4442
        if not status_code and parent is None and other_branch is not None:
4429
 
            self.add_cleanup(local_branch.lock_write().unlock)
 
4443
            local_branch.lock_write()
 
4444
            self.add_cleanup(local_branch.unlock)
4430
4445
            # handle race conditions - a parent might be set while we run.
4431
4446
            if local_branch.get_parent() is None:
4432
4447
                local_branch.set_parent(remote_branch.base)
4532
4547
            b = Branch.open_containing(branch)[0]
4533
4548
        else:
4534
4549
            b = Branch.open(branch)
4535
 
        self.add_cleanup(b.lock_read().unlock)
 
4550
        b.lock_read()
 
4551
        self.add_cleanup(b.unlock)
4536
4552
        if revision is None:
4537
4553
            rev_id = b.last_revision()
4538
4554
        else:
4562
4578
                     Option('long', help='Show commit date in annotations.'),
4563
4579
                     'revision',
4564
4580
                     'show-ids',
4565
 
                     'directory',
4566
4581
                     ]
4567
4582
    encoding_type = 'exact'
4568
4583
 
4569
4584
    @display_command
4570
4585
    def run(self, filename, all=False, long=False, revision=None,
4571
 
            show_ids=False, directory=None):
 
4586
            show_ids=False):
4572
4587
        from bzrlib.annotate import annotate_file, annotate_file_tree
4573
4588
        wt, branch, relpath = \
4574
 
            _open_directory_or_containing_tree_or_branch(filename, directory)
 
4589
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
4575
4590
        if wt is not None:
4576
 
            self.add_cleanup(wt.lock_read().unlock)
 
4591
            wt.lock_read()
 
4592
            self.add_cleanup(wt.unlock)
4577
4593
        else:
4578
 
            self.add_cleanup(branch.lock_read().unlock)
 
4594
            branch.lock_read()
 
4595
            self.add_cleanup(branch.unlock)
4579
4596
        tree = _get_one_revision_tree('annotate', revision, branch=branch)
4580
 
        self.add_cleanup(tree.lock_read().unlock)
 
4597
        tree.lock_read()
 
4598
        self.add_cleanup(tree.unlock)
4581
4599
        if wt is not None:
4582
4600
            file_id = wt.path2id(relpath)
4583
4601
        else:
4601
4619
 
4602
4620
    hidden = True # is this right ?
4603
4621
    takes_args = ['revision_id*']
4604
 
    takes_options = ['directory', 'revision']
 
4622
    takes_options = ['revision']
4605
4623
 
4606
 
    def run(self, revision_id_list=None, revision=None, directory=u'.'):
 
4624
    def run(self, revision_id_list=None, revision=None):
4607
4625
        if revision_id_list is not None and revision is not None:
4608
4626
            raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
4609
4627
        if revision_id_list is None and revision is None:
4610
4628
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
4611
 
        b = WorkingTree.open_containing(directory)[0].branch
4612
 
        self.add_cleanup(b.lock_write().unlock)
 
4629
        b = WorkingTree.open_containing(u'.')[0].branch
 
4630
        b.lock_write()
 
4631
        self.add_cleanup(b.unlock)
4613
4632
        return self._run(b, revision_id_list, revision)
4614
4633
 
4615
4634
    def _run(self, b, revision_id_list, revision):
4674
4693
 
4675
4694
    _see_also = ['checkouts', 'unbind']
4676
4695
    takes_args = ['location?']
4677
 
    takes_options = ['directory']
 
4696
    takes_options = []
4678
4697
 
4679
 
    def run(self, location=None, directory=u'.'):
4680
 
        b, relpath = Branch.open_containing(directory)
 
4698
    def run(self, location=None):
 
4699
        b, relpath = Branch.open_containing(u'.')
4681
4700
        if location is None:
4682
4701
            try:
4683
4702
                location = b.get_old_bound_location()
4710
4729
 
4711
4730
    _see_also = ['checkouts', 'bind']
4712
4731
    takes_args = []
4713
 
    takes_options = ['directory']
 
4732
    takes_options = []
4714
4733
 
4715
 
    def run(self, directory=u'.'):
4716
 
        b, relpath = Branch.open_containing(directory)
 
4734
    def run(self):
 
4735
        b, relpath = Branch.open_containing(u'.')
4717
4736
        if not b.unbind():
4718
4737
            raise errors.BzrCommandError('Local branch is not bound')
4719
4738
 
4765
4784
            b = control.open_branch()
4766
4785
 
4767
4786
        if tree is not None:
4768
 
            self.add_cleanup(tree.lock_write().unlock)
 
4787
            tree.lock_write()
 
4788
            self.add_cleanup(tree.unlock)
4769
4789
        else:
4770
 
            self.add_cleanup(b.lock_write().unlock)
 
4790
            b.lock_write()
 
4791
            self.add_cleanup(b.unlock)
4771
4792
        return self._run(b, tree, dry_run, verbose, revision, force, local=local)
4772
4793
 
4773
4794
    def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
4812
4833
            self.outf.write('The above revision(s) will be removed.\n')
4813
4834
 
4814
4835
        if not force:
4815
 
            if not ui.ui_factory.confirm_action(
4816
 
                    'Uncommit these revisions',
4817
 
                    'bzrlib.builtins.uncommit',
4818
 
                    {}):
4819
 
                self.outf.write('Canceled\n')
 
4836
            if not ui.ui_factory.get_boolean('Are you sure'):
 
4837
                self.outf.write('Canceled')
4820
4838
                return 0
4821
4839
 
4822
4840
        mutter('Uncommitting from {%s} to {%s}',
4828
4846
 
4829
4847
 
4830
4848
class cmd_break_lock(Command):
4831
 
    __doc__ = """Break a dead lock.
4832
 
 
4833
 
    This command breaks a lock on a repository, branch, working directory or
4834
 
    config file.
 
4849
    __doc__ = """Break a dead lock on a repository, branch or working directory.
4835
4850
 
4836
4851
    CAUTION: Locks should only be broken when you are sure that the process
4837
4852
    holding the lock has been stopped.
4842
4857
    :Examples:
4843
4858
        bzr break-lock
4844
4859
        bzr break-lock bzr+ssh://example.com/bzr/foo
4845
 
        bzr break-lock --conf ~/.bazaar
4846
4860
    """
4847
 
 
4848
4861
    takes_args = ['location?']
4849
 
    takes_options = [
4850
 
        Option('config',
4851
 
               help='LOCATION is the directory where the config lock is.'),
4852
 
        ]
4853
4862
 
4854
 
    def run(self, location=None, config=False):
 
4863
    def run(self, location=None, show=False):
4855
4864
        if location is None:
4856
4865
            location = u'.'
4857
 
        if config:
4858
 
            conf = _mod_config.LockableConfig(file_name=location)
4859
 
            conf.break_lock()
4860
 
        else:
4861
 
            control, relpath = bzrdir.BzrDir.open_containing(location)
4862
 
            try:
4863
 
                control.break_lock()
4864
 
            except NotImplementedError:
4865
 
                pass
 
4866
        control, relpath = bzrdir.BzrDir.open_containing(location)
 
4867
        try:
 
4868
            control.break_lock()
 
4869
        except NotImplementedError:
 
4870
            pass
4866
4871
 
4867
4872
 
4868
4873
class cmd_wait_until_signalled(Command):
4897
4902
                    'result in a dynamically allocated port.  The default port '
4898
4903
                    'depends on the protocol.',
4899
4904
               type=str),
4900
 
        custom_help('directory',
4901
 
               help='Serve contents of this directory.'),
 
4905
        Option('directory',
 
4906
               help='Serve contents of this directory.',
 
4907
               type=unicode),
4902
4908
        Option('allow-writes',
4903
4909
               help='By default the server is a readonly server.  Supplying '
4904
4910
                    '--allow-writes enables write access to the contents of '
4931
4937
 
4932
4938
    def run(self, port=None, inet=False, directory=None, allow_writes=False,
4933
4939
            protocol=None):
4934
 
        from bzrlib import transport
 
4940
        from bzrlib.transport import get_transport, transport_server_registry
4935
4941
        if directory is None:
4936
4942
            directory = os.getcwd()
4937
4943
        if protocol is None:
4938
 
            protocol = transport.transport_server_registry.get()
 
4944
            protocol = transport_server_registry.get()
4939
4945
        host, port = self.get_host_and_port(port)
4940
4946
        url = urlutils.local_path_to_url(directory)
4941
4947
        if not allow_writes:
4942
4948
            url = 'readonly+' + url
4943
 
        t = transport.get_transport(url)
4944
 
        protocol(t, host, port, inet)
 
4949
        transport = get_transport(url)
 
4950
        protocol(transport, host, port, inet)
4945
4951
 
4946
4952
 
4947
4953
class cmd_join(Command):
5040
5046
    _see_also = ['send']
5041
5047
 
5042
5048
    takes_options = [
5043
 
        'directory',
5044
5049
        RegistryOption.from_kwargs('patch-type',
5045
5050
            'The type of patch to include in the directive.',
5046
5051
            title='Patch type',
5059
5064
    encoding_type = 'exact'
5060
5065
 
5061
5066
    def run(self, submit_branch=None, public_branch=None, patch_type='bundle',
5062
 
            sign=False, revision=None, mail_to=None, message=None,
5063
 
            directory=u'.'):
 
5067
            sign=False, revision=None, mail_to=None, message=None):
5064
5068
        from bzrlib.revision import ensure_null, NULL_REVISION
5065
5069
        include_patch, include_bundle = {
5066
5070
            'plain': (False, False),
5067
5071
            'diff': (True, False),
5068
5072
            'bundle': (True, True),
5069
5073
            }[patch_type]
5070
 
        branch = Branch.open(directory)
 
5074
        branch = Branch.open('.')
5071
5075
        stored_submit_branch = branch.get_submit_branch()
5072
5076
        if submit_branch is None:
5073
5077
            submit_branch = stored_submit_branch
5158
5162
    given, in which case it is sent to a file.
5159
5163
 
5160
5164
    Mail is sent using your preferred mail program.  This should be transparent
5161
 
    on Windows (it uses MAPI).  On Unix, it requires the xdg-email utility.
 
5165
    on Windows (it uses MAPI).  On Linux, it requires the xdg-email utility.
5162
5166
    If the preferred client can't be found (or used), your editor will be used.
5163
5167
 
5164
5168
    To use a specific mail program, set the mail_client configuration option.
5335
5339
        Option('delete',
5336
5340
            help='Delete this tag rather than placing it.',
5337
5341
            ),
5338
 
        custom_help('directory',
5339
 
            help='Branch in which to place the tag.'),
 
5342
        Option('directory',
 
5343
            help='Branch in which to place the tag.',
 
5344
            short_name='d',
 
5345
            type=unicode,
 
5346
            ),
5340
5347
        Option('force',
5341
5348
            help='Replace existing tags.',
5342
5349
            ),
5350
5357
            revision=None,
5351
5358
            ):
5352
5359
        branch, relpath = Branch.open_containing(directory)
5353
 
        self.add_cleanup(branch.lock_write().unlock)
 
5360
        branch.lock_write()
 
5361
        self.add_cleanup(branch.unlock)
5354
5362
        if delete:
5355
5363
            if tag_name is None:
5356
5364
                raise errors.BzrCommandError("No tag specified to delete.")
5384
5392
 
5385
5393
    _see_also = ['tag']
5386
5394
    takes_options = [
5387
 
        custom_help('directory',
5388
 
            help='Branch whose tags should be displayed.'),
 
5395
        Option('directory',
 
5396
            help='Branch whose tags should be displayed.',
 
5397
            short_name='d',
 
5398
            type=unicode,
 
5399
            ),
5389
5400
        RegistryOption.from_kwargs('sort',
5390
5401
            'Sort tags by different criteria.', title='Sorting',
5391
5402
            alpha='Sort tags lexicographically (default).',
5408
5419
        if not tags:
5409
5420
            return
5410
5421
 
5411
 
        self.add_cleanup(branch.lock_read().unlock)
 
5422
        branch.lock_read()
 
5423
        self.add_cleanup(branch.unlock)
5412
5424
        if revision:
5413
5425
            graph = branch.repository.get_graph()
5414
5426
            rev1, rev2 = _get_revision_range(revision, branch, self.name())
5561
5573
    """
5562
5574
 
5563
5575
    takes_args = ['to_location?']
5564
 
    takes_options = ['directory',
5565
 
                     Option('force',
 
5576
    takes_options = [Option('force',
5566
5577
                        help='Switch even if local commits will be lost.'),
5567
5578
                     'revision',
5568
5579
                     Option('create-branch', short_name='b',
5571
5582
                    ]
5572
5583
 
5573
5584
    def run(self, to_location=None, force=False, create_branch=False,
5574
 
            revision=None, directory=u'.'):
 
5585
            revision=None):
5575
5586
        from bzrlib import switch
5576
 
        tree_location = directory
 
5587
        tree_location = '.'
5577
5588
        revision = _get_one_revision('switch', revision)
5578
5589
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
5579
5590
        if to_location is None:
5580
5591
            if revision is None:
5581
5592
                raise errors.BzrCommandError('You must supply either a'
5582
5593
                                             ' revision or a location')
5583
 
            to_location = tree_location
 
5594
            to_location = '.'
5584
5595
        try:
5585
5596
            branch = control_dir.open_branch()
5586
5597
            had_explicit_nick = branch.get_config().has_explicit_nickname()
5721
5732
            name=None,
5722
5733
            switch=None,
5723
5734
            ):
5724
 
        tree, file_list = WorkingTree.open_containing_paths(file_list,
5725
 
            apply_view=False)
 
5735
        tree, file_list = tree_files(file_list, apply_view=False)
5726
5736
        current_view, view_dict = tree.views.get_view_info()
5727
5737
        if name is None:
5728
5738
            name = current_view
5862
5872
    takes_args = ['file*']
5863
5873
 
5864
5874
    takes_options = [
5865
 
        'directory',
5866
5875
        'revision',
5867
5876
        Option('all', help='Shelve all changes.'),
5868
5877
        'message',
5877
5886
    _see_also = ['unshelve']
5878
5887
 
5879
5888
    def run(self, revision=None, all=False, file_list=None, message=None,
5880
 
            writer=None, list=False, destroy=False, directory=u'.'):
 
5889
            writer=None, list=False, destroy=False):
5881
5890
        if list:
5882
5891
            return self.run_for_list()
5883
5892
        from bzrlib.shelf_ui import Shelver
5885
5894
            writer = bzrlib.option.diff_writer_registry.get()
5886
5895
        try:
5887
5896
            shelver = Shelver.from_args(writer(sys.stdout), revision, all,
5888
 
                file_list, message, destroy=destroy, directory=directory)
 
5897
                file_list, message, destroy=destroy)
5889
5898
            try:
5890
5899
                shelver.run()
5891
5900
            finally:
5895
5904
 
5896
5905
    def run_for_list(self):
5897
5906
        tree = WorkingTree.open_containing('.')[0]
5898
 
        self.add_cleanup(tree.lock_read().unlock)
 
5907
        tree.lock_read()
 
5908
        self.add_cleanup(tree.unlock)
5899
5909
        manager = tree.get_shelf_manager()
5900
5910
        shelves = manager.active_shelves()
5901
5911
        if len(shelves) == 0:
5919
5929
 
5920
5930
    takes_args = ['shelf_id?']
5921
5931
    takes_options = [
5922
 
        'directory',
5923
5932
        RegistryOption.from_kwargs(
5924
5933
            'action', help="The action to perform.",
5925
5934
            enum_switch=False, value_switches=True,
5933
5942
    ]
5934
5943
    _see_also = ['shelve']
5935
5944
 
5936
 
    def run(self, shelf_id=None, action='apply', directory=u'.'):
 
5945
    def run(self, shelf_id=None, action='apply'):
5937
5946
        from bzrlib.shelf_ui import Unshelver
5938
 
        unshelver = Unshelver.from_args(shelf_id, action, directory=directory)
 
5947
        unshelver = Unshelver.from_args(shelf_id, action)
5939
5948
        try:
5940
5949
            unshelver.run()
5941
5950
        finally:
5957
5966
 
5958
5967
    To check what clean-tree will do, use --dry-run.
5959
5968
    """
5960
 
    takes_options = ['directory',
5961
 
                     Option('ignored', help='Delete all ignored files.'),
 
5969
    takes_options = [Option('ignored', help='Delete all ignored files.'),
5962
5970
                     Option('detritus', help='Delete conflict files, merge'
5963
5971
                            ' backups, and failed selftest dirs.'),
5964
5972
                     Option('unknown',
5967
5975
                            ' deleting them.'),
5968
5976
                     Option('force', help='Do not prompt before deleting.')]
5969
5977
    def run(self, unknown=False, ignored=False, detritus=False, dry_run=False,
5970
 
            force=False, directory=u'.'):
 
5978
            force=False):
5971
5979
        from bzrlib.clean_tree import clean_tree
5972
5980
        if not (unknown or ignored or detritus):
5973
5981
            unknown = True
5974
5982
        if dry_run:
5975
5983
            force = True
5976
 
        clean_tree(directory, unknown=unknown, ignored=ignored,
5977
 
                   detritus=detritus, dry_run=dry_run, no_prompt=force)
 
5984
        clean_tree('.', unknown=unknown, ignored=ignored, detritus=detritus,
 
5985
                   dry_run=dry_run, no_prompt=force)
5978
5986
 
5979
5987
 
5980
5988
class cmd_reference(Command):