/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: Parth Malwankar
  • Date: 2010-09-14 13:26:02 UTC
  • mto: This revision was merged to the branch mainline in revision 5444.
  • Revision ID: parth.malwankar@gmail.com-20100914132602-yuryma2apcrb501s
fixed NEWS entry

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
25
24
import sys
26
25
import time
33
32
    bzrdir,
34
33
    directory_service,
35
34
    delta,
36
 
    config,
 
35
    config as _mod_config,
37
36
    errors,
38
37
    globbing,
39
38
    hooks,
44
43
    reconfigure,
45
44
    rename_map,
46
45
    revision as _mod_revision,
 
46
    shelf,
47
47
    static_tuple,
48
48
    symbol_versioning,
49
49
    timestamp,
75
75
from bzrlib.trace import mutter, note, warning, is_quiet, get_verbosity_level
76
76
 
77
77
 
 
78
@symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
78
79
def tree_files(file_list, default_branch=u'.', canonicalize=True,
79
80
    apply_view=True):
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]))
 
81
    return internal_tree_files(file_list, default_branch, canonicalize,
 
82
        apply_view)
86
83
 
87
84
 
88
85
def tree_files_for_add(file_list):
152
149
 
153
150
# XXX: Bad function name; should possibly also be a class method of
154
151
# WorkingTree rather than a function.
 
152
@symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
155
153
def internal_tree_files(file_list, default_branch=u'.', canonicalize=True,
156
154
    apply_view=True):
157
155
    """Convert command-line paths to a WorkingTree and relative paths.
158
156
 
 
157
    Deprecated: use WorkingTree.open_containing_paths instead.
 
158
 
159
159
    This is typically used for command-line processors that take one or
160
160
    more filenames, and infer the workingtree that contains them.
161
161
 
171
171
 
172
172
    :return: workingtree, [relative_paths]
173
173
    """
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
 
174
    return WorkingTree.open_containing_paths(
 
175
        file_list, default_directory='.',
 
176
        canonicalize=True,
 
177
        apply_view=True)
221
178
 
222
179
 
223
180
def _get_view_info_for_change_reporter(tree):
232
189
    return view_info
233
190
 
234
191
 
 
192
def _open_directory_or_containing_tree_or_branch(filename, directory):
 
193
    """Open the tree or branch containing the specified file, unless
 
194
    the --directory option is used to specify a different branch."""
 
195
    if directory is not None:
 
196
        return (None, Branch.open(directory), filename)
 
197
    return bzrdir.BzrDir.open_containing_tree_or_branch(filename)
 
198
 
 
199
 
235
200
# TODO: Make sure no commands unconditionally use the working directory as a
236
201
# branch.  If a filename argument is used, the first of them should be used to
237
202
# specify the branch.  (Perhaps this can be factored out into some kind of
315
280
            raise errors.BzrCommandError('bzr status --revision takes exactly'
316
281
                                         ' one or two revision specifiers')
317
282
 
318
 
        tree, relfile_list = tree_files(file_list)
 
283
        tree, relfile_list = WorkingTree.open_containing_paths(file_list)
319
284
        # Avoid asking for specific files when that is not needed.
320
285
        if relfile_list == ['']:
321
286
            relfile_list = None
340
305
 
341
306
    hidden = True
342
307
    takes_args = ['revision_id?']
343
 
    takes_options = ['revision']
 
308
    takes_options = ['directory', 'revision']
344
309
    # cat-revision is more for frontends so should be exact
345
310
    encoding = 'strict'
346
311
 
353
318
        self.outf.write(revtext.decode('utf-8'))
354
319
 
355
320
    @display_command
356
 
    def run(self, revision_id=None, revision=None):
 
321
    def run(self, revision_id=None, revision=None, directory=u'.'):
357
322
        if revision_id is not None and revision is not None:
358
323
            raise errors.BzrCommandError('You can only supply one of'
359
324
                                         ' revision_id or --revision')
360
325
        if revision_id is None and revision is None:
361
326
            raise errors.BzrCommandError('You must supply either'
362
327
                                         ' --revision or a revision_id')
363
 
        b = WorkingTree.open_containing(u'.')[0].branch
 
328
        b = WorkingTree.open_containing(directory)[0].branch
364
329
 
365
330
        revisions = b.repository.revisions
366
331
        if revisions is None:
483
448
    takes_options = [
484
449
        Option('force',
485
450
               help='Remove the working tree even if it has '
486
 
                    'uncommitted changes.'),
 
451
                    'uncommitted or shelved changes.'),
487
452
        ]
488
453
 
489
454
    def run(self, location_list, force=False):
503
468
            if not force:
504
469
                if (working.has_changes()):
505
470
                    raise errors.UncommittedChanges(working)
 
471
                if working.get_shelf_manager().last_shelf() is not None:
 
472
                    raise errors.ShelvedChanges(working)
506
473
 
507
474
            if working.user_url != working.branch.user_url:
508
475
                raise errors.BzrCommandError("You cannot remove the working tree"
528
495
        if tree:
529
496
            try:
530
497
                wt = WorkingTree.open_containing(location)[0]
531
 
                wt.lock_read()
 
498
                self.add_cleanup(wt.lock_read().unlock)
532
499
            except (errors.NoWorkingTree, errors.NotLocalUrl):
533
500
                raise errors.NoWorkingTree(location)
534
 
            self.add_cleanup(wt.unlock)
535
501
            revid = wt.last_revision()
536
502
            try:
537
503
                revno_t = wt.branch.revision_id_to_dotted_revno(revid)
540
506
            revno = ".".join(str(n) for n in revno_t)
541
507
        else:
542
508
            b = Branch.open_containing(location)[0]
543
 
            b.lock_read()
544
 
            self.add_cleanup(b.unlock)
 
509
            self.add_cleanup(b.lock_read().unlock)
545
510
            revno = b.revno()
546
511
        self.cleanup_now()
547
512
        self.outf.write(str(revno) + '\n')
554
519
    takes_args = ['revision_info*']
555
520
    takes_options = [
556
521
        'revision',
557
 
        Option('directory',
 
522
        custom_help('directory',
558
523
            help='Branch to examine, '
559
 
                 'rather than the one containing the working directory.',
560
 
            short_name='d',
561
 
            type=unicode,
562
 
            ),
 
524
                 'rather than the one containing the working directory.'),
563
525
        Option('tree', help='Show revno of working tree'),
564
526
        ]
565
527
 
570
532
        try:
571
533
            wt = WorkingTree.open_containing(directory)[0]
572
534
            b = wt.branch
573
 
            wt.lock_read()
574
 
            self.add_cleanup(wt.unlock)
 
535
            self.add_cleanup(wt.lock_read().unlock)
575
536
        except (errors.NoWorkingTree, errors.NotLocalUrl):
576
537
            wt = None
577
538
            b = Branch.open_containing(directory)[0]
578
 
            b.lock_read()
579
 
            self.add_cleanup(b.unlock)
 
539
            self.add_cleanup(b.lock_read().unlock)
580
540
        revision_ids = []
581
541
        if revision is not None:
582
542
            revision_ids.extend(rev.as_revision_id(b) for rev in revision)
681
641
                should_print=(not is_quiet()))
682
642
 
683
643
        if base_tree:
684
 
            base_tree.lock_read()
685
 
            self.add_cleanup(base_tree.unlock)
 
644
            self.add_cleanup(base_tree.lock_read().unlock)
686
645
        tree, file_list = tree_files_for_add(file_list)
687
646
        added, ignored = tree.smart_add(file_list, not
688
647
            no_recurse, action=action, save=not dry_run)
759
718
            raise errors.BzrCommandError('invalid kind %r specified' % (kind,))
760
719
 
761
720
        revision = _get_one_revision('inventory', revision)
762
 
        work_tree, file_list = tree_files(file_list)
763
 
        work_tree.lock_read()
764
 
        self.add_cleanup(work_tree.unlock)
 
721
        work_tree, file_list = WorkingTree.open_containing_paths(file_list)
 
722
        self.add_cleanup(work_tree.lock_read().unlock)
765
723
        if revision is not None:
766
724
            tree = revision.as_tree(work_tree.branch)
767
725
 
768
726
            extra_trees = [work_tree]
769
 
            tree.lock_read()
770
 
            self.add_cleanup(tree.unlock)
 
727
            self.add_cleanup(tree.lock_read().unlock)
771
728
        else:
772
729
            tree = work_tree
773
730
            extra_trees = []
832
789
            names_list = []
833
790
        if len(names_list) < 2:
834
791
            raise errors.BzrCommandError("missing file argument")
835
 
        tree, rel_names = tree_files(names_list, canonicalize=False)
836
 
        tree.lock_tree_write()
837
 
        self.add_cleanup(tree.unlock)
 
792
        tree, rel_names = WorkingTree.open_containing_paths(names_list, canonicalize=False)
 
793
        self.add_cleanup(tree.lock_tree_write().unlock)
838
794
        self._run(tree, names_list, rel_names, after)
839
795
 
840
796
    def run_auto(self, names_list, after, dry_run):
844
800
        if after:
845
801
            raise errors.BzrCommandError('--after cannot be specified with'
846
802
                                         ' --auto.')
847
 
        work_tree, file_list = tree_files(names_list, default_branch='.')
848
 
        work_tree.lock_tree_write()
849
 
        self.add_cleanup(work_tree.unlock)
 
803
        work_tree, file_list = WorkingTree.open_containing_paths(
 
804
            names_list, default_directory='.')
 
805
        self.add_cleanup(work_tree.lock_tree_write().unlock)
850
806
        rename_map.RenameMap.guess_renames(work_tree, dry_run)
851
807
 
852
808
    def _run(self, tree, names_list, rel_names, after):
960
916
    takes_options = ['remember', 'overwrite', 'revision',
961
917
        custom_help('verbose',
962
918
            help='Show logs of pulled revisions.'),
963
 
        Option('directory',
 
919
        custom_help('directory',
964
920
            help='Branch to pull into, '
965
 
                 'rather than the one containing the working directory.',
966
 
            short_name='d',
967
 
            type=unicode,
968
 
            ),
 
921
                 'rather than the one containing the working directory.'),
969
922
        Option('local',
970
923
            help="Perform a local pull in a bound "
971
924
                 "branch.  Local pulls are not applied to "
986
939
        try:
987
940
            tree_to = WorkingTree.open_containing(directory)[0]
988
941
            branch_to = tree_to.branch
989
 
            tree_to.lock_write()
990
 
            self.add_cleanup(tree_to.unlock)
 
942
            self.add_cleanup(tree_to.lock_write().unlock)
991
943
        except errors.NoWorkingTree:
992
944
            tree_to = None
993
945
            branch_to = Branch.open_containing(directory)[0]
994
 
            branch_to.lock_write()
995
 
            self.add_cleanup(branch_to.unlock)
 
946
            self.add_cleanup(branch_to.lock_write().unlock)
996
947
 
997
948
        if local and not branch_to.get_bound_location():
998
949
            raise errors.LocalRequiresBoundBranch()
1029
980
        else:
1030
981
            branch_from = Branch.open(location,
1031
982
                possible_transports=possible_transports)
1032
 
            branch_from.lock_read()
1033
 
            self.add_cleanup(branch_from.unlock)
 
983
            self.add_cleanup(branch_from.lock_read().unlock)
1034
984
 
1035
985
            if branch_to.get_parent() is None or remember:
1036
986
                branch_to.set_parent(branch_from.base)
1088
1038
        Option('create-prefix',
1089
1039
               help='Create the path leading up to the branch '
1090
1040
                    'if it does not already exist.'),
1091
 
        Option('directory',
 
1041
        custom_help('directory',
1092
1042
            help='Branch to push from, '
1093
 
                 'rather than the one containing the working directory.',
1094
 
            short_name='d',
1095
 
            type=unicode,
1096
 
            ),
 
1043
                 'rather than the one containing the working directory.'),
1097
1044
        Option('use-existing-dir',
1098
1045
               help='By default push will fail if the target'
1099
1046
                    ' directory exists, but does not already'
1188
1135
 
1189
1136
    _see_also = ['checkout']
1190
1137
    takes_args = ['from_location', 'to_location?']
1191
 
    takes_options = ['revision', Option('hardlink',
1192
 
        help='Hard-link working tree files where possible.'),
 
1138
    takes_options = ['revision',
 
1139
        Option('hardlink', help='Hard-link working tree files where possible.'),
 
1140
        Option('files-from', type=str,
 
1141
               help="Get file contents from this tree."),
1193
1142
        Option('no-tree',
1194
1143
            help="Create a branch without a working-tree."),
1195
1144
        Option('switch',
1213
1162
 
1214
1163
    def run(self, from_location, to_location=None, revision=None,
1215
1164
            hardlink=False, stacked=False, standalone=False, no_tree=False,
1216
 
            use_existing_dir=False, switch=False, bind=False):
 
1165
            use_existing_dir=False, switch=False, bind=False,
 
1166
            files_from=None):
1217
1167
        from bzrlib import switch as _mod_switch
1218
1168
        from bzrlib.tag import _merge_tags_if_possible
1219
1169
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
1220
1170
            from_location)
 
1171
        if not (hardlink or files_from):
 
1172
            # accelerator_tree is usually slower because you have to read N
 
1173
            # files (no readahead, lots of seeks, etc), but allow the user to
 
1174
            # explicitly request it
 
1175
            accelerator_tree = None
 
1176
        if files_from is not None and files_from != from_location:
 
1177
            accelerator_tree = WorkingTree.open(files_from)
1221
1178
        revision = _get_one_revision('branch', revision)
1222
 
        br_from.lock_read()
1223
 
        self.add_cleanup(br_from.unlock)
 
1179
        self.add_cleanup(br_from.lock_read().unlock)
1224
1180
        if revision is not None:
1225
1181
            revision_id = revision.as_revision_id(br_from)
1226
1182
        else:
1331
1287
            to_location = branch_location
1332
1288
        accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch(
1333
1289
            branch_location)
 
1290
        if not (hardlink or files_from):
 
1291
            # accelerator_tree is usually slower because you have to read N
 
1292
            # files (no readahead, lots of seeks, etc), but allow the user to
 
1293
            # explicitly request it
 
1294
            accelerator_tree = None
1334
1295
        revision = _get_one_revision('checkout', revision)
1335
 
        if files_from is not None:
 
1296
        if files_from is not None and files_from != branch_location:
1336
1297
            accelerator_tree = WorkingTree.open(files_from)
1337
1298
        if revision is not None:
1338
1299
            revision_id = revision.as_revision_id(source)
1366
1327
    @display_command
1367
1328
    def run(self, dir=u'.'):
1368
1329
        tree = WorkingTree.open_containing(dir)[0]
1369
 
        tree.lock_read()
1370
 
        self.add_cleanup(tree.unlock)
 
1330
        self.add_cleanup(tree.lock_read().unlock)
1371
1331
        new_inv = tree.inventory
1372
1332
        old_tree = tree.basis_tree()
1373
 
        old_tree.lock_read()
1374
 
        self.add_cleanup(old_tree.unlock)
 
1333
        self.add_cleanup(old_tree.lock_read().unlock)
1375
1334
        old_inv = old_tree.inventory
1376
1335
        renames = []
1377
1336
        iterator = tree.iter_changes(old_tree, include_unchanged=True)
1415
1374
        master = branch.get_master_branch(
1416
1375
            possible_transports=possible_transports)
1417
1376
        if master is not None:
1418
 
            tree.lock_write()
1419
1377
            branch_location = master.base
 
1378
            tree.lock_write()
1420
1379
        else:
 
1380
            branch_location = tree.branch.base
1421
1381
            tree.lock_tree_write()
1422
 
            branch_location = tree.branch.base
1423
1382
        self.add_cleanup(tree.unlock)
1424
1383
        # get rid of the final '/' and be ready for display
1425
1384
        branch_location = urlutils.unescape_for_display(
1519
1478
class cmd_remove(Command):
1520
1479
    __doc__ = """Remove files or directories.
1521
1480
 
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.
 
1481
    This makes Bazaar stop tracking changes to the specified files. Bazaar will
 
1482
    delete them if they can easily be recovered using revert otherwise they
 
1483
    will be backed up (adding an extention of the form .~#~). If no options or
 
1484
    parameters are given Bazaar will scan for files that are being tracked by
 
1485
    Bazaar but missing in your tree and stop tracking them for you.
1526
1486
    """
1527
1487
    takes_args = ['file*']
1528
1488
    takes_options = ['verbose',
1530
1490
        RegistryOption.from_kwargs('file-deletion-strategy',
1531
1491
            'The file deletion mode to be used.',
1532
1492
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1533
 
            safe='Only delete files if they can be'
1534
 
                 ' safely recovered (default).',
 
1493
            safe='Backup changed files (default).',
1535
1494
            keep='Delete from bzr but leave the working copy.',
1536
1495
            force='Delete all the specified files, even if they can not be '
1537
1496
                'recovered and even if they are non-empty directories.')]
1540
1499
 
1541
1500
    def run(self, file_list, verbose=False, new=False,
1542
1501
        file_deletion_strategy='safe'):
1543
 
        tree, file_list = tree_files(file_list)
 
1502
        tree, file_list = WorkingTree.open_containing_paths(file_list)
1544
1503
 
1545
1504
        if file_list is not None:
1546
1505
            file_list = [f for f in file_list]
1547
1506
 
1548
 
        tree.lock_write()
1549
 
        self.add_cleanup(tree.unlock)
 
1507
        self.add_cleanup(tree.lock_write().unlock)
1550
1508
        # Heuristics should probably all move into tree.remove_smart or
1551
1509
        # some such?
1552
1510
        if new:
1635
1593
 
1636
1594
    _see_also = ['check']
1637
1595
    takes_args = ['branch?']
 
1596
    takes_options = [
 
1597
        Option('canonicalize-chks',
 
1598
               help='Make sure CHKs are in canonical form (repairs '
 
1599
                    'bug 522637).',
 
1600
               hidden=True),
 
1601
        ]
1638
1602
 
1639
 
    def run(self, branch="."):
 
1603
    def run(self, branch=".", canonicalize_chks=False):
1640
1604
        from bzrlib.reconcile import reconcile
1641
1605
        dir = bzrdir.BzrDir.open(branch)
1642
 
        reconcile(dir)
 
1606
        reconcile(dir, canonicalize_chks=canonicalize_chks)
1643
1607
 
1644
1608
 
1645
1609
class cmd_revision_history(Command):
1921
1885
        Same as 'bzr diff' but prefix paths with old/ and new/::
1922
1886
 
1923
1887
            bzr diff --prefix old/:new/
 
1888
            
 
1889
        Show the differences using a custom diff program with options::
 
1890
        
 
1891
            bzr diff --using /usr/bin/diff --diff-options -wu
1924
1892
    """
1925
1893
    _see_also = ['status']
1926
1894
    takes_args = ['file*']
1985
1953
         old_branch, new_branch,
1986
1954
         specific_files, extra_trees) = get_trees_and_branches_to_diff_locked(
1987
1955
            file_list, revision, old, new, self.add_cleanup, apply_view=True)
 
1956
        # GNU diff on Windows uses ANSI encoding for filenames
 
1957
        path_encoding = osutils.get_diff_header_encoding()
1988
1958
        return show_diff_trees(old_tree, new_tree, sys.stdout,
1989
1959
                               specific_files=specific_files,
1990
1960
                               external_diff_options=diff_options,
1991
1961
                               old_label=old_label, new_label=new_label,
1992
 
                               extra_trees=extra_trees, using=using,
 
1962
                               extra_trees=extra_trees,
 
1963
                               path_encoding=path_encoding,
 
1964
                               using=using,
1993
1965
                               format_cls=format)
1994
1966
 
1995
1967
 
2003
1975
    # level of effort but possibly much less IO.  (Or possibly not,
2004
1976
    # if the directories are very large...)
2005
1977
    _see_also = ['status', 'ls']
2006
 
    takes_options = ['show-ids']
 
1978
    takes_options = ['directory', 'show-ids']
2007
1979
 
2008
1980
    @display_command
2009
 
    def run(self, show_ids=False):
2010
 
        tree = WorkingTree.open_containing(u'.')[0]
2011
 
        tree.lock_read()
2012
 
        self.add_cleanup(tree.unlock)
 
1981
    def run(self, show_ids=False, directory=u'.'):
 
1982
        tree = WorkingTree.open_containing(directory)[0]
 
1983
        self.add_cleanup(tree.lock_read().unlock)
2013
1984
        old = tree.basis_tree()
2014
 
        old.lock_read()
2015
 
        self.add_cleanup(old.unlock)
 
1985
        self.add_cleanup(old.lock_read().unlock)
2016
1986
        for path, ie in old.inventory.iter_entries():
2017
1987
            if not tree.has_id(ie.file_id):
2018
1988
                self.outf.write(path)
2028
1998
 
2029
1999
    hidden = True
2030
2000
    _see_also = ['status', 'ls']
2031
 
    takes_options = [
2032
 
            Option('null',
2033
 
                   help='Write an ascii NUL (\\0) separator '
2034
 
                   'between files rather than a newline.')
2035
 
            ]
 
2001
    takes_options = ['directory', 'null']
2036
2002
 
2037
2003
    @display_command
2038
 
    def run(self, null=False):
2039
 
        tree = WorkingTree.open_containing(u'.')[0]
 
2004
    def run(self, null=False, directory=u'.'):
 
2005
        tree = WorkingTree.open_containing(directory)[0]
2040
2006
        td = tree.changes_from(tree.basis_tree())
2041
2007
        for path, id, kind, text_modified, meta_modified in td.modified:
2042
2008
            if null:
2051
2017
 
2052
2018
    hidden = True
2053
2019
    _see_also = ['status', 'ls']
2054
 
    takes_options = [
2055
 
            Option('null',
2056
 
                   help='Write an ascii NUL (\\0) separator '
2057
 
                   'between files rather than a newline.')
2058
 
            ]
 
2020
    takes_options = ['directory', 'null']
2059
2021
 
2060
2022
    @display_command
2061
 
    def run(self, null=False):
2062
 
        wt = WorkingTree.open_containing(u'.')[0]
2063
 
        wt.lock_read()
2064
 
        self.add_cleanup(wt.unlock)
 
2023
    def run(self, null=False, directory=u'.'):
 
2024
        wt = WorkingTree.open_containing(directory)[0]
 
2025
        self.add_cleanup(wt.lock_read().unlock)
2065
2026
        basis = wt.basis_tree()
2066
 
        basis.lock_read()
2067
 
        self.add_cleanup(basis.unlock)
 
2027
        self.add_cleanup(basis.lock_read().unlock)
2068
2028
        basis_inv = basis.inventory
2069
2029
        inv = wt.inventory
2070
2030
        for file_id in inv:
2073
2033
            if inv.is_root(file_id) and len(basis_inv) == 0:
2074
2034
                continue
2075
2035
            path = inv.id2path(file_id)
2076
 
            if not os.access(osutils.abspath(path), os.F_OK):
 
2036
            if not os.access(osutils.pathjoin(wt.basedir, path), os.F_OK):
2077
2037
                continue
2078
2038
            if null:
2079
2039
                self.outf.write(path + '\0')
2279
2239
                   help='Show just the specified revision.'
2280
2240
                   ' See also "help revisionspec".'),
2281
2241
            'log-format',
 
2242
            RegistryOption('authors',
 
2243
                'What names to list as authors - first, all or committer.',
 
2244
                title='Authors',
 
2245
                lazy_registry=('bzrlib.log', 'author_list_registry'),
 
2246
            ),
2282
2247
            Option('levels',
2283
2248
                   short_name='n',
2284
2249
                   help='Number of levels to display - 0 for all, 1 for flat.',
2319
2284
            limit=None,
2320
2285
            show_diff=False,
2321
2286
            include_merges=False,
 
2287
            authors=None,
2322
2288
            exclude_common_ancestry=False,
2323
2289
            ):
2324
2290
        from bzrlib.log import (
2352
2318
        if file_list:
2353
2319
            # find the file ids to log and check for directory filtering
2354
2320
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(
2355
 
                revision, file_list)
2356
 
            self.add_cleanup(b.unlock)
 
2321
                revision, file_list, self.add_cleanup)
2357
2322
            for relpath, file_id, kind in file_info_list:
2358
2323
                if file_id is None:
2359
2324
                    raise errors.BzrCommandError(
2377
2342
                location = '.'
2378
2343
            dir, relpath = bzrdir.BzrDir.open_containing(location)
2379
2344
            b = dir.open_branch()
2380
 
            b.lock_read()
2381
 
            self.add_cleanup(b.unlock)
 
2345
            self.add_cleanup(b.lock_read().unlock)
2382
2346
            rev1, rev2 = _get_revision_range(revision, b, self.name())
2383
2347
 
2384
2348
        # Decide on the type of delta & diff filtering to use
2404
2368
                        show_timezone=timezone,
2405
2369
                        delta_format=get_verbosity_level(),
2406
2370
                        levels=levels,
2407
 
                        show_advice=levels is None)
 
2371
                        show_advice=levels is None,
 
2372
                        author_list_handler=authors)
2408
2373
 
2409
2374
        # Choose the algorithm for doing the logging. It's annoying
2410
2375
        # having multiple code paths like this but necessary until
2508
2473
        tree, relpath = WorkingTree.open_containing(filename)
2509
2474
        file_id = tree.path2id(relpath)
2510
2475
        b = tree.branch
2511
 
        b.lock_read()
2512
 
        self.add_cleanup(b.unlock)
 
2476
        self.add_cleanup(b.lock_read().unlock)
2513
2477
        touching_revs = log.find_touching_revisions(b, file_id)
2514
2478
        for revno, revision_id, what in touching_revs:
2515
2479
            self.outf.write("%6d %s\n" % (revno, what))
2528
2492
                   help='Recurse into subdirectories.'),
2529
2493
            Option('from-root',
2530
2494
                   help='Print paths relative to the root of the branch.'),
2531
 
            Option('unknown', help='Print unknown files.'),
 
2495
            Option('unknown', short_name='u',
 
2496
                help='Print unknown files.'),
2532
2497
            Option('versioned', help='Print versioned files.',
2533
2498
                   short_name='V'),
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',
 
2499
            Option('ignored', short_name='i',
 
2500
                help='Print ignored files.'),
 
2501
            Option('kind', short_name='k',
2539
2502
                   help='List entries of a particular kind: file, directory, symlink.',
2540
2503
                   type=unicode),
 
2504
            'null',
2541
2505
            'show-ids',
 
2506
            'directory',
2542
2507
            ]
2543
2508
    @display_command
2544
2509
    def run(self, revision=None, verbose=False,
2545
2510
            recursive=False, from_root=False,
2546
2511
            unknown=False, versioned=False, ignored=False,
2547
 
            null=False, kind=None, show_ids=False, path=None):
 
2512
            null=False, kind=None, show_ids=False, path=None, directory=None):
2548
2513
 
2549
2514
        if kind and kind not in ('file', 'directory', 'symlink'):
2550
2515
            raise errors.BzrCommandError('invalid kind specified')
2562
2527
                raise errors.BzrCommandError('cannot specify both --from-root'
2563
2528
                                             ' and PATH')
2564
2529
            fs_path = path
2565
 
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
2566
 
            fs_path)
 
2530
        tree, branch, relpath = \
 
2531
            _open_directory_or_containing_tree_or_branch(fs_path, directory)
2567
2532
 
2568
2533
        # Calculate the prefix to use
2569
2534
        prefix = None
2584
2549
                view_str = views.view_display_str(view_files)
2585
2550
                note("Ignoring files outside view. View is %s" % view_str)
2586
2551
 
2587
 
        tree.lock_read()
2588
 
        self.add_cleanup(tree.unlock)
 
2552
        self.add_cleanup(tree.lock_read().unlock)
2589
2553
        for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
2590
2554
            from_dir=relpath, recursive=recursive):
2591
2555
            # Apply additional masking
2638
2602
 
2639
2603
    hidden = True
2640
2604
    _see_also = ['ls']
 
2605
    takes_options = ['directory']
2641
2606
 
2642
2607
    @display_command
2643
 
    def run(self):
2644
 
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
 
2608
    def run(self, directory=u'.'):
 
2609
        for f in WorkingTree.open_containing(directory)[0].unknowns():
2645
2610
            self.outf.write(osutils.quotefn(f) + '\n')
2646
2611
 
2647
2612
 
2712
2677
 
2713
2678
    _see_also = ['status', 'ignored', 'patterns']
2714
2679
    takes_args = ['name_pattern*']
2715
 
    takes_options = [
 
2680
    takes_options = ['directory',
2716
2681
        Option('default-rules',
2717
2682
               help='Display the default ignore rules that bzr uses.')
2718
2683
        ]
2719
2684
 
2720
 
    def run(self, name_pattern_list=None, default_rules=None):
 
2685
    def run(self, name_pattern_list=None, default_rules=None,
 
2686
            directory=u'.'):
2721
2687
        from bzrlib import ignores
2722
2688
        if default_rules is not None:
2723
2689
            # dump the default rules and exit
2729
2695
                "NAME_PATTERN or --default-rules.")
2730
2696
        name_pattern_list = [globbing.normalize_pattern(p)
2731
2697
                             for p in name_pattern_list]
 
2698
        bad_patterns = ''
 
2699
        for p in name_pattern_list:
 
2700
            if not globbing.Globster.is_pattern_valid(p):
 
2701
                bad_patterns += ('\n  %s' % p)
 
2702
        if bad_patterns:
 
2703
            msg = ('Invalid ignore pattern(s) found. %s' % bad_patterns)
 
2704
            ui.ui_factory.show_error(msg)
 
2705
            raise errors.InvalidPattern('')
2732
2706
        for name_pattern in name_pattern_list:
2733
2707
            if (name_pattern[0] == '/' or
2734
2708
                (len(name_pattern) > 1 and name_pattern[1] == ':')):
2735
2709
                raise errors.BzrCommandError(
2736
2710
                    "NAME_PATTERN should not be an absolute path")
2737
 
        tree, relpath = WorkingTree.open_containing(u'.')
 
2711
        tree, relpath = WorkingTree.open_containing(directory)
2738
2712
        ignores.tree_ignores_add_patterns(tree, name_pattern_list)
2739
2713
        ignored = globbing.Globster(name_pattern_list)
2740
2714
        matches = []
2741
 
        tree.lock_read()
 
2715
        self.add_cleanup(tree.lock_read().unlock)
2742
2716
        for entry in tree.list_files():
2743
2717
            id = entry[3]
2744
2718
            if id is not None:
2745
2719
                filename = entry[0]
2746
2720
                if ignored.match(filename):
2747
2721
                    matches.append(filename)
2748
 
        tree.unlock()
2749
2722
        if len(matches) > 0:
2750
2723
            self.outf.write("Warning: the following files are version controlled and"
2751
2724
                  " match your ignore pattern:\n%s"
2766
2739
 
2767
2740
    encoding_type = 'replace'
2768
2741
    _see_also = ['ignore', 'ls']
 
2742
    takes_options = ['directory']
2769
2743
 
2770
2744
    @display_command
2771
 
    def run(self):
2772
 
        tree = WorkingTree.open_containing(u'.')[0]
2773
 
        tree.lock_read()
2774
 
        self.add_cleanup(tree.unlock)
 
2745
    def run(self, directory=u'.'):
 
2746
        tree = WorkingTree.open_containing(directory)[0]
 
2747
        self.add_cleanup(tree.lock_read().unlock)
2775
2748
        for path, file_class, kind, file_id, entry in tree.list_files():
2776
2749
            if file_class != 'I':
2777
2750
                continue
2788
2761
    """
2789
2762
    hidden = True
2790
2763
    takes_args = ['revno']
 
2764
    takes_options = ['directory']
2791
2765
 
2792
2766
    @display_command
2793
 
    def run(self, revno):
 
2767
    def run(self, revno, directory=u'.'):
2794
2768
        try:
2795
2769
            revno = int(revno)
2796
2770
        except ValueError:
2797
2771
            raise errors.BzrCommandError("not a valid revision-number: %r"
2798
2772
                                         % revno)
2799
 
        revid = WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
 
2773
        revid = WorkingTree.open_containing(directory)[0].branch.get_rev_id(revno)
2800
2774
        self.outf.write("%s\n" % revid)
2801
2775
 
2802
2776
 
2829
2803
      =================       =========================
2830
2804
    """
2831
2805
    takes_args = ['dest', 'branch_or_subdir?']
2832
 
    takes_options = [
 
2806
    takes_options = ['directory',
2833
2807
        Option('format',
2834
2808
               help="Type of file to export to.",
2835
2809
               type=unicode),
2844
2818
                    'revision in which it was changed.'),
2845
2819
        ]
2846
2820
    def run(self, dest, branch_or_subdir=None, revision=None, format=None,
2847
 
        root=None, filters=False, per_file_timestamps=False):
 
2821
        root=None, filters=False, per_file_timestamps=False, directory=u'.'):
2848
2822
        from bzrlib.export import export
2849
2823
 
2850
2824
        if branch_or_subdir is None:
2851
 
            tree = WorkingTree.open_containing(u'.')[0]
 
2825
            tree = WorkingTree.open_containing(directory)[0]
2852
2826
            b = tree.branch
2853
2827
            subdir = None
2854
2828
        else:
2873
2847
    """
2874
2848
 
2875
2849
    _see_also = ['ls']
2876
 
    takes_options = [
 
2850
    takes_options = ['directory',
2877
2851
        Option('name-from-revision', help='The path name in the old tree.'),
2878
2852
        Option('filters', help='Apply content filters to display the '
2879
2853
                'convenience form.'),
2884
2858
 
2885
2859
    @display_command
2886
2860
    def run(self, filename, revision=None, name_from_revision=False,
2887
 
            filters=False):
 
2861
            filters=False, directory=None):
2888
2862
        if revision is not None and len(revision) != 1:
2889
2863
            raise errors.BzrCommandError("bzr cat --revision takes exactly"
2890
2864
                                         " one revision specifier")
2891
2865
        tree, branch, relpath = \
2892
 
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2893
 
        branch.lock_read()
2894
 
        self.add_cleanup(branch.unlock)
 
2866
            _open_directory_or_containing_tree_or_branch(filename, directory)
 
2867
        self.add_cleanup(branch.lock_read().unlock)
2895
2868
        return self._run(tree, branch, relpath, filename, revision,
2896
2869
                         name_from_revision, filters)
2897
2870
 
2900
2873
        if tree is None:
2901
2874
            tree = b.basis_tree()
2902
2875
        rev_tree = _get_one_revision_tree('cat', revision, branch=b)
2903
 
        rev_tree.lock_read()
2904
 
        self.add_cleanup(rev_tree.unlock)
 
2876
        self.add_cleanup(rev_tree.lock_read().unlock)
2905
2877
 
2906
2878
        old_file_id = rev_tree.path2id(relpath)
2907
2879
 
3128
3100
 
3129
3101
        properties = {}
3130
3102
 
3131
 
        tree, selected_list = tree_files(selected_list)
 
3103
        tree, selected_list = WorkingTree.open_containing_paths(selected_list)
3132
3104
        if selected_list == ['']:
3133
3105
            # workaround - commit of root of tree should be exactly the same
3134
3106
            # as just default commit in that tree, and succeed even though
3169
3141
        def get_message(commit_obj):
3170
3142
            """Callback to get commit message"""
3171
3143
            if file:
3172
 
                my_message = codecs.open(
3173
 
                    file, 'rt', osutils.get_user_encoding()).read()
 
3144
                f = open(file)
 
3145
                try:
 
3146
                    my_message = f.read().decode(osutils.get_user_encoding())
 
3147
                finally:
 
3148
                    f.close()
3174
3149
            elif message is not None:
3175
3150
                my_message = message
3176
3151
            else:
3205
3180
                        reporter=None, verbose=verbose, revprops=properties,
3206
3181
                        authors=author, timestamp=commit_stamp,
3207
3182
                        timezone=offset,
3208
 
                        exclude=safe_relpath_files(tree, exclude))
 
3183
                        exclude=tree.safe_relpath_files(exclude))
3209
3184
        except PointlessCommit:
3210
3185
            raise errors.BzrCommandError("No changes to commit."
3211
3186
                              " Use --unchanged to commit anyhow.")
3330
3305
 
3331
3306
            bzr whoami "Frank Chu <fchu@example.com>"
3332
3307
    """
3333
 
    takes_options = [ Option('email',
 
3308
    takes_options = [ 'directory',
 
3309
                      Option('email',
3334
3310
                             help='Display email address only.'),
3335
3311
                      Option('branch',
3336
3312
                             help='Set identity for the current branch instead of '
3340
3316
    encoding_type = 'replace'
3341
3317
 
3342
3318
    @display_command
3343
 
    def run(self, email=False, branch=False, name=None):
 
3319
    def run(self, email=False, branch=False, name=None, directory=None):
3344
3320
        if name is None:
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()
 
3321
            if directory is None:
 
3322
                # use branch if we're inside one; otherwise global config
 
3323
                try:
 
3324
                    c = Branch.open_containing(u'.')[0].get_config()
 
3325
                except errors.NotBranchError:
 
3326
                    c = _mod_config.GlobalConfig()
 
3327
            else:
 
3328
                c = Branch.open(directory).get_config()
3350
3329
            if email:
3351
3330
                self.outf.write(c.user_email() + '\n')
3352
3331
            else:
3355
3334
 
3356
3335
        # display a warning if an email address isn't included in the given name.
3357
3336
        try:
3358
 
            config.extract_email_address(name)
 
3337
            _mod_config.extract_email_address(name)
3359
3338
        except errors.NoEmailInUsername, e:
3360
3339
            warning('"%s" does not seem to contain an email address.  '
3361
3340
                    'This is allowed, but not recommended.', name)
3362
3341
 
3363
3342
        # use global config unless --branch given
3364
3343
        if branch:
3365
 
            c = Branch.open_containing('.')[0].get_config()
 
3344
            if directory is None:
 
3345
                c = Branch.open_containing(u'.')[0].get_config()
 
3346
            else:
 
3347
                c = Branch.open(directory).get_config()
3366
3348
        else:
3367
 
            c = config.GlobalConfig()
 
3349
            c = _mod_config.GlobalConfig()
3368
3350
        c.set_user_option('email', name)
3369
3351
 
3370
3352
 
3380
3362
 
3381
3363
    _see_also = ['info']
3382
3364
    takes_args = ['nickname?']
3383
 
    def run(self, nickname=None):
3384
 
        branch = Branch.open_containing(u'.')[0]
 
3365
    takes_options = ['directory']
 
3366
    def run(self, nickname=None, directory=u'.'):
 
3367
        branch = Branch.open_containing(directory)[0]
3385
3368
        if nickname is None:
3386
3369
            self.printme(branch)
3387
3370
        else:
3436
3419
                'bzr alias --remove expects an alias to remove.')
3437
3420
        # If alias is not found, print something like:
3438
3421
        # unalias: foo: not found
3439
 
        c = config.GlobalConfig()
 
3422
        c = _mod_config.GlobalConfig()
3440
3423
        c.unset_alias(alias_name)
3441
3424
 
3442
3425
    @display_command
3443
3426
    def print_aliases(self):
3444
3427
        """Print out the defined aliases in a similar format to bash."""
3445
 
        aliases = config.GlobalConfig().get_aliases()
 
3428
        aliases = _mod_config.GlobalConfig().get_aliases()
3446
3429
        for key, value in sorted(aliases.iteritems()):
3447
3430
            self.outf.write('bzr alias %s="%s"\n' % (key, value))
3448
3431
 
3458
3441
 
3459
3442
    def set_alias(self, alias_name, alias_command):
3460
3443
        """Save the alias in the global config."""
3461
 
        c = config.GlobalConfig()
 
3444
        c = _mod_config.GlobalConfig()
3462
3445
        c.set_alias(alias_name, alias_command)
3463
3446
 
3464
3447
 
3537
3520
                                 'throughout the test suite.',
3538
3521
                            type=get_transport_type),
3539
3522
                     Option('benchmark',
3540
 
                            help='Run the benchmarks rather than selftests.'),
 
3523
                            help='Run the benchmarks rather than selftests.',
 
3524
                            hidden=True),
3541
3525
                     Option('lsprof-timed',
3542
3526
                            help='Generate lsprof output for benchmarked'
3543
3527
                                 ' sections of code.'),
3544
3528
                     Option('lsprof-tests',
3545
3529
                            help='Generate lsprof output for each test.'),
3546
 
                     Option('cache-dir', type=str,
3547
 
                            help='Cache intermediate benchmark output in this '
3548
 
                                 'directory.'),
3549
3530
                     Option('first',
3550
3531
                            help='Run all tests, but run specified tests first.',
3551
3532
                            short_name='f',
3585
3566
 
3586
3567
    def run(self, testspecs_list=None, verbose=False, one=False,
3587
3568
            transport=None, benchmark=None,
3588
 
            lsprof_timed=None, cache_dir=None,
 
3569
            lsprof_timed=None,
3589
3570
            first=False, list_only=False,
3590
3571
            randomize=None, exclude=None, strict=False,
3591
3572
            load_list=None, debugflag=None, starting_with=None, subunit=False,
3592
3573
            parallel=None, lsprof_tests=False):
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)
 
3574
        from bzrlib import tests
 
3575
 
3602
3576
        if testspecs_list is not None:
3603
3577
            pattern = '|'.join(testspecs_list)
3604
3578
        else:
3612
3586
            self.additional_selftest_args['runner_class'] = SubUnitBzrRunner
3613
3587
            # On Windows, disable automatic conversion of '\n' to '\r\n' in
3614
3588
            # stdout, which would corrupt the subunit stream. 
3615
 
            if sys.platform == "win32" and sys.stdout.fileno() >= 0:
 
3589
            # FIXME: This has been fixed in subunit trunk (>0.0.5) so the
 
3590
            # following code can be deleted when it's sufficiently deployed
 
3591
            # -- vila/mgz 20100514
 
3592
            if (sys.platform == "win32"
 
3593
                and getattr(sys.stdout, 'fileno', None) is not None):
3616
3594
                import msvcrt
3617
3595
                msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
3618
3596
        if parallel:
3619
3597
            self.additional_selftest_args.setdefault(
3620
3598
                'suite_decorators', []).append(parallel)
3621
3599
        if benchmark:
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
 
3600
            raise errors.BzrCommandError(
 
3601
                "--benchmark is no longer supported from bzr 2.2; "
 
3602
                "use bzr-usertest instead")
 
3603
        test_suite_factory = None
3631
3604
        selftest_kwargs = {"verbose": verbose,
3632
3605
                          "pattern": pattern,
3633
3606
                          "stop_on_failure": one,
3635
3608
                          "test_suite_factory": test_suite_factory,
3636
3609
                          "lsprof_timed": lsprof_timed,
3637
3610
                          "lsprof_tests": lsprof_tests,
3638
 
                          "bench_history": benchfile,
3639
3611
                          "matching_tests_first": first,
3640
3612
                          "list_only": list_only,
3641
3613
                          "random_seed": randomize,
3646
3618
                          "starting_with": starting_with
3647
3619
                          }
3648
3620
        selftest_kwargs.update(self.additional_selftest_args)
3649
 
        result = selftest(**selftest_kwargs)
 
3621
 
 
3622
        # Make deprecation warnings visible, unless -Werror is set
 
3623
        cleanup = symbol_versioning.activate_deprecation_warnings(
 
3624
            override=False)
 
3625
        try:
 
3626
            result = tests.selftest(**selftest_kwargs)
 
3627
        finally:
 
3628
            cleanup()
3650
3629
        return int(not result)
3651
3630
 
3652
3631
 
3690
3669
 
3691
3670
        branch1 = Branch.open_containing(branch)[0]
3692
3671
        branch2 = Branch.open_containing(other)[0]
3693
 
        branch1.lock_read()
3694
 
        self.add_cleanup(branch1.unlock)
3695
 
        branch2.lock_read()
3696
 
        self.add_cleanup(branch2.unlock)
 
3672
        self.add_cleanup(branch1.lock_read().unlock)
 
3673
        self.add_cleanup(branch2.lock_read().unlock)
3697
3674
        last1 = ensure_null(branch1.last_revision())
3698
3675
        last2 = ensure_null(branch2.last_revision())
3699
3676
 
3793
3770
                ' completely merged into the source, pull from the'
3794
3771
                ' source rather than merging.  When this happens,'
3795
3772
                ' you do not need to commit the result.'),
3796
 
        Option('directory',
 
3773
        custom_help('directory',
3797
3774
               help='Branch to merge into, '
3798
 
                    'rather than the one containing the working directory.',
3799
 
               short_name='d',
3800
 
               type=unicode,
3801
 
               ),
 
3775
                    'rather than the one containing the working directory.'),
3802
3776
        Option('preview', help='Instead of merging, show a diff of the'
3803
3777
               ' merge.'),
3804
3778
        Option('interactive', help='Select changes interactively.',
3837
3811
            unversioned_filter=tree.is_ignored, view_info=view_info)
3838
3812
        pb = ui.ui_factory.nested_progress_bar()
3839
3813
        self.add_cleanup(pb.finished)
3840
 
        tree.lock_write()
3841
 
        self.add_cleanup(tree.unlock)
 
3814
        self.add_cleanup(tree.lock_write().unlock)
3842
3815
        if location is not None:
3843
3816
            try:
3844
3817
                mergeable = bundle.read_mergeable_from_url(location,
3905
3878
    def _do_preview(self, merger):
3906
3879
        from bzrlib.diff import show_diff_trees
3907
3880
        result_tree = self._get_preview(merger)
 
3881
        path_encoding = osutils.get_diff_header_encoding()
3908
3882
        show_diff_trees(merger.this_tree, result_tree, self.outf,
3909
 
                        old_label='', new_label='')
 
3883
                        old_label='', new_label='',
 
3884
                        path_encoding=path_encoding)
3910
3885
 
3911
3886
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
3912
3887
        merger.change_reporter = change_reporter
4099
4074
        from bzrlib.conflicts import restore
4100
4075
        if merge_type is None:
4101
4076
            merge_type = _mod_merge.Merge3Merger
4102
 
        tree, file_list = tree_files(file_list)
4103
 
        tree.lock_write()
4104
 
        self.add_cleanup(tree.unlock)
 
4077
        tree, file_list = WorkingTree.open_containing_paths(file_list)
 
4078
        self.add_cleanup(tree.lock_write().unlock)
4105
4079
        parents = tree.get_parent_ids()
4106
4080
        if len(parents) != 2:
4107
4081
            raise errors.BzrCommandError("Sorry, remerge only works after normal"
4216
4190
 
4217
4191
    def run(self, revision=None, no_backup=False, file_list=None,
4218
4192
            forget_merges=None):
4219
 
        tree, file_list = tree_files(file_list)
4220
 
        tree.lock_tree_write()
4221
 
        self.add_cleanup(tree.unlock)
 
4193
        tree, file_list = WorkingTree.open_containing_paths(file_list)
 
4194
        self.add_cleanup(tree.lock_tree_write().unlock)
4222
4195
        if forget_merges:
4223
4196
            tree.set_parent_ids(tree.get_parent_ids()[:1])
4224
4197
        else:
4313
4286
    _see_also = ['merge', 'pull']
4314
4287
    takes_args = ['other_branch?']
4315
4288
    takes_options = [
 
4289
        'directory',
4316
4290
        Option('reverse', 'Reverse the order of revisions.'),
4317
4291
        Option('mine-only',
4318
4292
               'Display changes in the local branch only.'),
4340
4314
            theirs_only=False,
4341
4315
            log_format=None, long=False, short=False, line=False,
4342
4316
            show_ids=False, verbose=False, this=False, other=False,
4343
 
            include_merges=False, revision=None, my_revision=None):
 
4317
            include_merges=False, revision=None, my_revision=None,
 
4318
            directory=u'.'):
4344
4319
        from bzrlib.missing import find_unmerged, iter_log_revisions
4345
4320
        def message(s):
4346
4321
            if not is_quiet():
4359
4334
        elif theirs_only:
4360
4335
            restrict = 'remote'
4361
4336
 
4362
 
        local_branch = Branch.open_containing(u".")[0]
4363
 
        local_branch.lock_read()
4364
 
        self.add_cleanup(local_branch.unlock)
 
4337
        local_branch = Branch.open_containing(directory)[0]
 
4338
        self.add_cleanup(local_branch.lock_read().unlock)
4365
4339
 
4366
4340
        parent = local_branch.get_parent()
4367
4341
        if other_branch is None:
4378
4352
        if remote_branch.base == local_branch.base:
4379
4353
            remote_branch = local_branch
4380
4354
        else:
4381
 
            remote_branch.lock_read()
4382
 
            self.add_cleanup(remote_branch.unlock)
 
4355
            self.add_cleanup(remote_branch.lock_read().unlock)
4383
4356
 
4384
4357
        local_revid_range = _revision_range_to_revid_range(
4385
4358
            _get_revision_range(my_revision, local_branch,
4440
4413
            message("Branches are up to date.\n")
4441
4414
        self.cleanup_now()
4442
4415
        if not status_code and parent is None and other_branch is not None:
4443
 
            local_branch.lock_write()
4444
 
            self.add_cleanup(local_branch.unlock)
 
4416
            self.add_cleanup(local_branch.lock_write().unlock)
4445
4417
            # handle race conditions - a parent might be set while we run.
4446
4418
            if local_branch.get_parent() is None:
4447
4419
                local_branch.set_parent(remote_branch.base)
4547
4519
            b = Branch.open_containing(branch)[0]
4548
4520
        else:
4549
4521
            b = Branch.open(branch)
4550
 
        b.lock_read()
4551
 
        self.add_cleanup(b.unlock)
 
4522
        self.add_cleanup(b.lock_read().unlock)
4552
4523
        if revision is None:
4553
4524
            rev_id = b.last_revision()
4554
4525
        else:
4578
4549
                     Option('long', help='Show commit date in annotations.'),
4579
4550
                     'revision',
4580
4551
                     'show-ids',
 
4552
                     'directory',
4581
4553
                     ]
4582
4554
    encoding_type = 'exact'
4583
4555
 
4584
4556
    @display_command
4585
4557
    def run(self, filename, all=False, long=False, revision=None,
4586
 
            show_ids=False):
 
4558
            show_ids=False, directory=None):
4587
4559
        from bzrlib.annotate import annotate_file, annotate_file_tree
4588
4560
        wt, branch, relpath = \
4589
 
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
 
4561
            _open_directory_or_containing_tree_or_branch(filename, directory)
4590
4562
        if wt is not None:
4591
 
            wt.lock_read()
4592
 
            self.add_cleanup(wt.unlock)
 
4563
            self.add_cleanup(wt.lock_read().unlock)
4593
4564
        else:
4594
 
            branch.lock_read()
4595
 
            self.add_cleanup(branch.unlock)
 
4565
            self.add_cleanup(branch.lock_read().unlock)
4596
4566
        tree = _get_one_revision_tree('annotate', revision, branch=branch)
4597
 
        tree.lock_read()
4598
 
        self.add_cleanup(tree.unlock)
 
4567
        self.add_cleanup(tree.lock_read().unlock)
4599
4568
        if wt is not None:
4600
4569
            file_id = wt.path2id(relpath)
4601
4570
        else:
4619
4588
 
4620
4589
    hidden = True # is this right ?
4621
4590
    takes_args = ['revision_id*']
4622
 
    takes_options = ['revision']
 
4591
    takes_options = ['directory', 'revision']
4623
4592
 
4624
 
    def run(self, revision_id_list=None, revision=None):
 
4593
    def run(self, revision_id_list=None, revision=None, directory=u'.'):
4625
4594
        if revision_id_list is not None and revision is not None:
4626
4595
            raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
4627
4596
        if revision_id_list is None and revision is None:
4628
4597
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
4629
 
        b = WorkingTree.open_containing(u'.')[0].branch
4630
 
        b.lock_write()
4631
 
        self.add_cleanup(b.unlock)
 
4598
        b = WorkingTree.open_containing(directory)[0].branch
 
4599
        self.add_cleanup(b.lock_write().unlock)
4632
4600
        return self._run(b, revision_id_list, revision)
4633
4601
 
4634
4602
    def _run(self, b, revision_id_list, revision):
4693
4661
 
4694
4662
    _see_also = ['checkouts', 'unbind']
4695
4663
    takes_args = ['location?']
4696
 
    takes_options = []
 
4664
    takes_options = ['directory']
4697
4665
 
4698
 
    def run(self, location=None):
4699
 
        b, relpath = Branch.open_containing(u'.')
 
4666
    def run(self, location=None, directory=u'.'):
 
4667
        b, relpath = Branch.open_containing(directory)
4700
4668
        if location is None:
4701
4669
            try:
4702
4670
                location = b.get_old_bound_location()
4729
4697
 
4730
4698
    _see_also = ['checkouts', 'bind']
4731
4699
    takes_args = []
4732
 
    takes_options = []
 
4700
    takes_options = ['directory']
4733
4701
 
4734
 
    def run(self):
4735
 
        b, relpath = Branch.open_containing(u'.')
 
4702
    def run(self, directory=u'.'):
 
4703
        b, relpath = Branch.open_containing(directory)
4736
4704
        if not b.unbind():
4737
4705
            raise errors.BzrCommandError('Local branch is not bound')
4738
4706
 
4784
4752
            b = control.open_branch()
4785
4753
 
4786
4754
        if tree is not None:
4787
 
            tree.lock_write()
4788
 
            self.add_cleanup(tree.unlock)
 
4755
            self.add_cleanup(tree.lock_write().unlock)
4789
4756
        else:
4790
 
            b.lock_write()
4791
 
            self.add_cleanup(b.unlock)
 
4757
            self.add_cleanup(b.lock_write().unlock)
4792
4758
        return self._run(b, tree, dry_run, verbose, revision, force, local=local)
4793
4759
 
4794
4760
    def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
4846
4812
 
4847
4813
 
4848
4814
class cmd_break_lock(Command):
4849
 
    __doc__ = """Break a dead lock on a repository, branch or working directory.
 
4815
    __doc__ = """Break a dead lock.
 
4816
 
 
4817
    This command breaks a lock on a repository, branch, working directory or
 
4818
    config file.
4850
4819
 
4851
4820
    CAUTION: Locks should only be broken when you are sure that the process
4852
4821
    holding the lock has been stopped.
4857
4826
    :Examples:
4858
4827
        bzr break-lock
4859
4828
        bzr break-lock bzr+ssh://example.com/bzr/foo
 
4829
        bzr break-lock --conf ~/.bazaar
4860
4830
    """
 
4831
 
4861
4832
    takes_args = ['location?']
 
4833
    takes_options = [
 
4834
        Option('config',
 
4835
               help='LOCATION is the directory where the config lock is.'),
 
4836
        ]
4862
4837
 
4863
 
    def run(self, location=None, show=False):
 
4838
    def run(self, location=None, config=False):
4864
4839
        if location is None:
4865
4840
            location = u'.'
4866
 
        control, relpath = bzrdir.BzrDir.open_containing(location)
4867
 
        try:
4868
 
            control.break_lock()
4869
 
        except NotImplementedError:
4870
 
            pass
 
4841
        if config:
 
4842
            conf = _mod_config.LockableConfig(file_name=location)
 
4843
            conf.break_lock()
 
4844
        else:
 
4845
            control, relpath = bzrdir.BzrDir.open_containing(location)
 
4846
            try:
 
4847
                control.break_lock()
 
4848
            except NotImplementedError:
 
4849
                pass
4871
4850
 
4872
4851
 
4873
4852
class cmd_wait_until_signalled(Command):
4902
4881
                    'result in a dynamically allocated port.  The default port '
4903
4882
                    'depends on the protocol.',
4904
4883
               type=str),
4905
 
        Option('directory',
4906
 
               help='Serve contents of this directory.',
4907
 
               type=unicode),
 
4884
        custom_help('directory',
 
4885
               help='Serve contents of this directory.'),
4908
4886
        Option('allow-writes',
4909
4887
               help='By default the server is a readonly server.  Supplying '
4910
4888
                    '--allow-writes enables write access to the contents of '
4937
4915
 
4938
4916
    def run(self, port=None, inet=False, directory=None, allow_writes=False,
4939
4917
            protocol=None):
4940
 
        from bzrlib.transport import get_transport, transport_server_registry
 
4918
        from bzrlib import transport
4941
4919
        if directory is None:
4942
4920
            directory = os.getcwd()
4943
4921
        if protocol is None:
4944
 
            protocol = transport_server_registry.get()
 
4922
            protocol = transport.transport_server_registry.get()
4945
4923
        host, port = self.get_host_and_port(port)
4946
4924
        url = urlutils.local_path_to_url(directory)
4947
4925
        if not allow_writes:
4948
4926
            url = 'readonly+' + url
4949
 
        transport = get_transport(url)
4950
 
        protocol(transport, host, port, inet)
 
4927
        t = transport.get_transport(url)
 
4928
        protocol(t, host, port, inet)
4951
4929
 
4952
4930
 
4953
4931
class cmd_join(Command):
5046
5024
    _see_also = ['send']
5047
5025
 
5048
5026
    takes_options = [
 
5027
        'directory',
5049
5028
        RegistryOption.from_kwargs('patch-type',
5050
5029
            'The type of patch to include in the directive.',
5051
5030
            title='Patch type',
5064
5043
    encoding_type = 'exact'
5065
5044
 
5066
5045
    def run(self, submit_branch=None, public_branch=None, patch_type='bundle',
5067
 
            sign=False, revision=None, mail_to=None, message=None):
 
5046
            sign=False, revision=None, mail_to=None, message=None,
 
5047
            directory=u'.'):
5068
5048
        from bzrlib.revision import ensure_null, NULL_REVISION
5069
5049
        include_patch, include_bundle = {
5070
5050
            'plain': (False, False),
5071
5051
            'diff': (True, False),
5072
5052
            'bundle': (True, True),
5073
5053
            }[patch_type]
5074
 
        branch = Branch.open('.')
 
5054
        branch = Branch.open(directory)
5075
5055
        stored_submit_branch = branch.get_submit_branch()
5076
5056
        if submit_branch is None:
5077
5057
            submit_branch = stored_submit_branch
5162
5142
    given, in which case it is sent to a file.
5163
5143
 
5164
5144
    Mail is sent using your preferred mail program.  This should be transparent
5165
 
    on Windows (it uses MAPI).  On Linux, it requires the xdg-email utility.
 
5145
    on Windows (it uses MAPI).  On Unix, it requires the xdg-email utility.
5166
5146
    If the preferred client can't be found (or used), your editor will be used.
5167
5147
 
5168
5148
    To use a specific mail program, set the mail_client configuration option.
5339
5319
        Option('delete',
5340
5320
            help='Delete this tag rather than placing it.',
5341
5321
            ),
5342
 
        Option('directory',
5343
 
            help='Branch in which to place the tag.',
5344
 
            short_name='d',
5345
 
            type=unicode,
5346
 
            ),
 
5322
        custom_help('directory',
 
5323
            help='Branch in which to place the tag.'),
5347
5324
        Option('force',
5348
5325
            help='Replace existing tags.',
5349
5326
            ),
5357
5334
            revision=None,
5358
5335
            ):
5359
5336
        branch, relpath = Branch.open_containing(directory)
5360
 
        branch.lock_write()
5361
 
        self.add_cleanup(branch.unlock)
 
5337
        self.add_cleanup(branch.lock_write().unlock)
5362
5338
        if delete:
5363
5339
            if tag_name is None:
5364
5340
                raise errors.BzrCommandError("No tag specified to delete.")
5392
5368
 
5393
5369
    _see_also = ['tag']
5394
5370
    takes_options = [
5395
 
        Option('directory',
5396
 
            help='Branch whose tags should be displayed.',
5397
 
            short_name='d',
5398
 
            type=unicode,
5399
 
            ),
 
5371
        custom_help('directory',
 
5372
            help='Branch whose tags should be displayed.'),
5400
5373
        RegistryOption.from_kwargs('sort',
5401
5374
            'Sort tags by different criteria.', title='Sorting',
5402
5375
            alpha='Sort tags lexicographically (default).',
5419
5392
        if not tags:
5420
5393
            return
5421
5394
 
5422
 
        branch.lock_read()
5423
 
        self.add_cleanup(branch.unlock)
 
5395
        self.add_cleanup(branch.lock_read().unlock)
5424
5396
        if revision:
5425
5397
            graph = branch.repository.get_graph()
5426
5398
            rev1, rev2 = _get_revision_range(revision, branch, self.name())
5573
5545
    """
5574
5546
 
5575
5547
    takes_args = ['to_location?']
5576
 
    takes_options = [Option('force',
 
5548
    takes_options = ['directory',
 
5549
                     Option('force',
5577
5550
                        help='Switch even if local commits will be lost.'),
5578
5551
                     'revision',
5579
5552
                     Option('create-branch', short_name='b',
5582
5555
                    ]
5583
5556
 
5584
5557
    def run(self, to_location=None, force=False, create_branch=False,
5585
 
            revision=None):
 
5558
            revision=None, directory=u'.'):
5586
5559
        from bzrlib import switch
5587
 
        tree_location = '.'
 
5560
        tree_location = directory
5588
5561
        revision = _get_one_revision('switch', revision)
5589
5562
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
5590
5563
        if to_location is None:
5591
5564
            if revision is None:
5592
5565
                raise errors.BzrCommandError('You must supply either a'
5593
5566
                                             ' revision or a location')
5594
 
            to_location = '.'
 
5567
            to_location = tree_location
5595
5568
        try:
5596
5569
            branch = control_dir.open_branch()
5597
5570
            had_explicit_nick = branch.get_config().has_explicit_nickname()
5732
5705
            name=None,
5733
5706
            switch=None,
5734
5707
            ):
5735
 
        tree, file_list = tree_files(file_list, apply_view=False)
 
5708
        tree, file_list = WorkingTree.open_containing_paths(file_list,
 
5709
            apply_view=False)
5736
5710
        current_view, view_dict = tree.views.get_view_info()
5737
5711
        if name is None:
5738
5712
            name = current_view
5872
5846
    takes_args = ['file*']
5873
5847
 
5874
5848
    takes_options = [
 
5849
        'directory',
5875
5850
        'revision',
5876
5851
        Option('all', help='Shelve all changes.'),
5877
5852
        'message',
5886
5861
    _see_also = ['unshelve']
5887
5862
 
5888
5863
    def run(self, revision=None, all=False, file_list=None, message=None,
5889
 
            writer=None, list=False, destroy=False):
 
5864
            writer=None, list=False, destroy=False, directory=u'.'):
5890
5865
        if list:
5891
5866
            return self.run_for_list()
5892
5867
        from bzrlib.shelf_ui import Shelver
5894
5869
            writer = bzrlib.option.diff_writer_registry.get()
5895
5870
        try:
5896
5871
            shelver = Shelver.from_args(writer(sys.stdout), revision, all,
5897
 
                file_list, message, destroy=destroy)
 
5872
                file_list, message, destroy=destroy, directory=directory)
5898
5873
            try:
5899
5874
                shelver.run()
5900
5875
            finally:
5904
5879
 
5905
5880
    def run_for_list(self):
5906
5881
        tree = WorkingTree.open_containing('.')[0]
5907
 
        tree.lock_read()
5908
 
        self.add_cleanup(tree.unlock)
 
5882
        self.add_cleanup(tree.lock_read().unlock)
5909
5883
        manager = tree.get_shelf_manager()
5910
 
        shelves = manager.active_shelves()
 
5884
        shelves = shelf.list_shelves(tree)
5911
5885
        if len(shelves) == 0:
5912
5886
            note('No shelved changes.')
5913
5887
            return 0
5914
 
        for shelf_id in reversed(shelves):
5915
 
            message = manager.get_metadata(shelf_id).get('message')
5916
 
            if message is None:
5917
 
                message = '<no message>'
 
5888
        for shelf_id, message in shelves:
5918
5889
            self.outf.write('%3d: %s\n' % (shelf_id, message))
5919
5890
        return 1
5920
5891
 
5929
5900
 
5930
5901
    takes_args = ['shelf_id?']
5931
5902
    takes_options = [
 
5903
        'directory',
5932
5904
        RegistryOption.from_kwargs(
5933
5905
            'action', help="The action to perform.",
5934
5906
            enum_switch=False, value_switches=True,
5942
5914
    ]
5943
5915
    _see_also = ['shelve']
5944
5916
 
5945
 
    def run(self, shelf_id=None, action='apply'):
 
5917
    def run(self, shelf_id=None, action='apply', directory=u'.'):
5946
5918
        from bzrlib.shelf_ui import Unshelver
5947
 
        unshelver = Unshelver.from_args(shelf_id, action)
 
5919
        unshelver = Unshelver.from_args(shelf_id, action, directory=directory)
5948
5920
        try:
5949
5921
            unshelver.run()
5950
5922
        finally:
5966
5938
 
5967
5939
    To check what clean-tree will do, use --dry-run.
5968
5940
    """
5969
 
    takes_options = [Option('ignored', help='Delete all ignored files.'),
 
5941
    takes_options = ['directory',
 
5942
                     Option('ignored', help='Delete all ignored files.'),
5970
5943
                     Option('detritus', help='Delete conflict files, merge'
5971
5944
                            ' backups, and failed selftest dirs.'),
5972
5945
                     Option('unknown',
5975
5948
                            ' deleting them.'),
5976
5949
                     Option('force', help='Do not prompt before deleting.')]
5977
5950
    def run(self, unknown=False, ignored=False, detritus=False, dry_run=False,
5978
 
            force=False):
 
5951
            force=False, directory=u'.'):
5979
5952
        from bzrlib.clean_tree import clean_tree
5980
5953
        if not (unknown or ignored or detritus):
5981
5954
            unknown = True
5982
5955
        if dry_run:
5983
5956
            force = True
5984
 
        clean_tree('.', unknown=unknown, ignored=ignored, detritus=detritus,
5985
 
                   dry_run=dry_run, no_prompt=force)
 
5957
        clean_tree(directory, unknown=unknown, ignored=ignored,
 
5958
                   detritus=detritus, dry_run=dry_run, no_prompt=force)
5986
5959
 
5987
5960
 
5988
5961
class cmd_reference(Command):