~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Jelmer Vernooij
  • Date: 2010-12-20 11:57:14 UTC
  • mto: This revision was merged to the branch mainline in revision 5577.
  • Revision ID: jelmer@samba.org-20101220115714-2ru3hfappjweeg7q
Don't use no-plugins.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
20
20
 
21
21
from bzrlib.lazy_import import lazy_import
22
22
lazy_import(globals(), """
23
 
import codecs
24
23
import cStringIO
 
24
import itertools
 
25
import re
25
26
import sys
26
27
import time
27
28
 
31
32
    bundle,
32
33
    btree_index,
33
34
    bzrdir,
 
35
    directory_service,
34
36
    delta,
35
 
    config,
 
37
    config as _mod_config,
36
38
    errors,
37
39
    globbing,
38
40
    hooks,
43
45
    reconfigure,
44
46
    rename_map,
45
47
    revision as _mod_revision,
 
48
    static_tuple,
46
49
    symbol_versioning,
 
50
    timestamp,
47
51
    transport,
48
52
    ui,
49
53
    urlutils,
51
55
    )
52
56
from bzrlib.branch import Branch
53
57
from bzrlib.conflicts import ConflictList
 
58
from bzrlib.transport import memory
54
59
from bzrlib.revisionspec import RevisionSpec, RevisionInfo
55
60
from bzrlib.smtp_connection import SMTPConnection
56
61
from bzrlib.workingtree import WorkingTree
57
62
""")
58
63
 
59
 
from bzrlib.commands import Command, display_command
 
64
from bzrlib.commands import (
 
65
    Command,
 
66
    builtin_command_registry,
 
67
    display_command,
 
68
    )
60
69
from bzrlib.option import (
61
70
    ListOption,
62
71
    Option,
67
76
from bzrlib.trace import mutter, note, warning, is_quiet, get_verbosity_level
68
77
 
69
78
 
 
79
@symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
70
80
def tree_files(file_list, default_branch=u'.', canonicalize=True,
71
81
    apply_view=True):
72
 
    try:
73
 
        return internal_tree_files(file_list, default_branch, canonicalize,
74
 
            apply_view)
75
 
    except errors.FileInWrongBranch, e:
76
 
        raise errors.BzrCommandError("%s is not in the same branch as %s" %
77
 
                                     (e.path, file_list[0]))
 
82
    return internal_tree_files(file_list, default_branch, canonicalize,
 
83
        apply_view)
78
84
 
79
85
 
80
86
def tree_files_for_add(file_list):
144
150
 
145
151
# XXX: Bad function name; should possibly also be a class method of
146
152
# WorkingTree rather than a function.
 
153
@symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
147
154
def internal_tree_files(file_list, default_branch=u'.', canonicalize=True,
148
155
    apply_view=True):
149
156
    """Convert command-line paths to a WorkingTree and relative paths.
150
157
 
 
158
    Deprecated: use WorkingTree.open_containing_paths instead.
 
159
 
151
160
    This is typically used for command-line processors that take one or
152
161
    more filenames, and infer the workingtree that contains them.
153
162
 
163
172
 
164
173
    :return: workingtree, [relative_paths]
165
174
    """
166
 
    if file_list is None or len(file_list) == 0:
167
 
        tree = WorkingTree.open_containing(default_branch)[0]
168
 
        if tree.supports_views() and apply_view:
169
 
            view_files = tree.views.lookup_view()
170
 
            if view_files:
171
 
                file_list = view_files
172
 
                view_str = views.view_display_str(view_files)
173
 
                note("Ignoring files outside view. View is %s" % view_str)
174
 
        return tree, file_list
175
 
    tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
176
 
    return tree, safe_relpath_files(tree, file_list, canonicalize,
177
 
        apply_view=apply_view)
178
 
 
179
 
 
180
 
def safe_relpath_files(tree, file_list, canonicalize=True, apply_view=True):
181
 
    """Convert file_list into a list of relpaths in tree.
182
 
 
183
 
    :param tree: A tree to operate on.
184
 
    :param file_list: A list of user provided paths or None.
185
 
    :param apply_view: if True and a view is set, apply it or check that
186
 
        specified files are within it
187
 
    :return: A list of relative paths.
188
 
    :raises errors.PathNotChild: When a provided path is in a different tree
189
 
        than tree.
190
 
    """
191
 
    if file_list is None:
192
 
        return None
193
 
    if tree.supports_views() and apply_view:
194
 
        view_files = tree.views.lookup_view()
195
 
    else:
196
 
        view_files = []
197
 
    new_list = []
198
 
    # tree.relpath exists as a "thunk" to osutils, but canonical_relpath
199
 
    # doesn't - fix that up here before we enter the loop.
200
 
    if canonicalize:
201
 
        fixer = lambda p: osutils.canonical_relpath(tree.basedir, p)
202
 
    else:
203
 
        fixer = tree.relpath
204
 
    for filename in file_list:
205
 
        try:
206
 
            relpath = fixer(osutils.dereference_path(filename))
207
 
            if  view_files and not osutils.is_inside_any(view_files, relpath):
208
 
                raise errors.FileOutsideView(filename, view_files)
209
 
            new_list.append(relpath)
210
 
        except errors.PathNotChild:
211
 
            raise errors.FileInWrongBranch(tree.branch, filename)
212
 
    return new_list
 
175
    return WorkingTree.open_containing_paths(
 
176
        file_list, default_directory='.',
 
177
        canonicalize=True,
 
178
        apply_view=True)
213
179
 
214
180
 
215
181
def _get_view_info_for_change_reporter(tree):
224
190
    return view_info
225
191
 
226
192
 
 
193
def _open_directory_or_containing_tree_or_branch(filename, directory):
 
194
    """Open the tree or branch containing the specified file, unless
 
195
    the --directory option is used to specify a different branch."""
 
196
    if directory is not None:
 
197
        return (None, Branch.open(directory), filename)
 
198
    return bzrdir.BzrDir.open_containing_tree_or_branch(filename)
 
199
 
 
200
 
227
201
# TODO: Make sure no commands unconditionally use the working directory as a
228
202
# branch.  If a filename argument is used, the first of them should be used to
229
203
# specify the branch.  (Perhaps this can be factored out into some kind of
231
205
# opens the branch?)
232
206
 
233
207
class cmd_status(Command):
234
 
    """Display status summary.
 
208
    __doc__ = """Display status summary.
235
209
 
236
210
    This reports on versioned and unknown files, reporting them
237
211
    grouped by state.  Possible states are:
257
231
    unknown
258
232
        Not versioned and not matching an ignore pattern.
259
233
 
 
234
    Additionally for directories, symlinks and files with an executable
 
235
    bit, Bazaar indicates their type using a trailing character: '/', '@'
 
236
    or '*' respectively.
 
237
 
260
238
    To see ignored files use 'bzr ignored'.  For details on the
261
239
    changes to file texts, use 'bzr diff'.
262
240
 
274
252
    To skip the display of pending merge information altogether, use
275
253
    the no-pending option or specify a file/directory.
276
254
 
277
 
    If a revision argument is given, the status is calculated against
278
 
    that revision, or between two revisions if two are provided.
 
255
    To compare the working directory to a specific revision, pass a
 
256
    single revision to the revision argument.
 
257
 
 
258
    To see which files have changed in a specific revision, or between
 
259
    two revisions, pass a revision range to the revision argument.
 
260
    This will produce the same results as calling 'bzr diff --summarize'.
279
261
    """
280
262
 
281
263
    # TODO: --no-recurse, --recurse options
303
285
            raise errors.BzrCommandError('bzr status --revision takes exactly'
304
286
                                         ' one or two revision specifiers')
305
287
 
306
 
        tree, relfile_list = tree_files(file_list)
 
288
        tree, relfile_list = WorkingTree.open_containing_paths(file_list)
307
289
        # Avoid asking for specific files when that is not needed.
308
290
        if relfile_list == ['']:
309
291
            relfile_list = None
320
302
 
321
303
 
322
304
class cmd_cat_revision(Command):
323
 
    """Write out metadata for a revision.
 
305
    __doc__ = """Write out metadata for a revision.
324
306
 
325
307
    The revision to print can either be specified by a specific
326
308
    revision identifier, or you can use --revision.
328
310
 
329
311
    hidden = True
330
312
    takes_args = ['revision_id?']
331
 
    takes_options = ['revision']
 
313
    takes_options = ['directory', 'revision']
332
314
    # cat-revision is more for frontends so should be exact
333
315
    encoding = 'strict'
334
316
 
 
317
    def print_revision(self, revisions, revid):
 
318
        stream = revisions.get_record_stream([(revid,)], 'unordered', True)
 
319
        record = stream.next()
 
320
        if record.storage_kind == 'absent':
 
321
            raise errors.NoSuchRevision(revisions, revid)
 
322
        revtext = record.get_bytes_as('fulltext')
 
323
        self.outf.write(revtext.decode('utf-8'))
 
324
 
335
325
    @display_command
336
 
    def run(self, revision_id=None, revision=None):
 
326
    def run(self, revision_id=None, revision=None, directory=u'.'):
337
327
        if revision_id is not None and revision is not None:
338
328
            raise errors.BzrCommandError('You can only supply one of'
339
329
                                         ' revision_id or --revision')
340
330
        if revision_id is None and revision is None:
341
331
            raise errors.BzrCommandError('You must supply either'
342
332
                                         ' --revision or a revision_id')
343
 
        b = WorkingTree.open_containing(u'.')[0].branch
344
 
 
345
 
        # TODO: jam 20060112 should cat-revision always output utf-8?
346
 
        if revision_id is not None:
347
 
            revision_id = osutils.safe_revision_id(revision_id, warn=False)
348
 
            try:
349
 
                self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
350
 
            except errors.NoSuchRevision:
351
 
                msg = "The repository %s contains no revision %s." % (b.repository.base,
352
 
                    revision_id)
353
 
                raise errors.BzrCommandError(msg)
354
 
        elif revision is not None:
355
 
            for rev in revision:
356
 
                if rev is None:
357
 
                    raise errors.BzrCommandError('You cannot specify a NULL'
358
 
                                                 ' revision.')
359
 
                rev_id = rev.as_revision_id(b)
360
 
                self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
361
 
 
 
333
        b = WorkingTree.open_containing(directory)[0].branch
 
334
 
 
335
        revisions = b.repository.revisions
 
336
        if revisions is None:
 
337
            raise errors.BzrCommandError('Repository %r does not support '
 
338
                'access to raw revision texts')
 
339
 
 
340
        b.repository.lock_read()
 
341
        try:
 
342
            # TODO: jam 20060112 should cat-revision always output utf-8?
 
343
            if revision_id is not None:
 
344
                revision_id = osutils.safe_revision_id(revision_id, warn=False)
 
345
                try:
 
346
                    self.print_revision(revisions, revision_id)
 
347
                except errors.NoSuchRevision:
 
348
                    msg = "The repository %s contains no revision %s." % (
 
349
                        b.repository.base, revision_id)
 
350
                    raise errors.BzrCommandError(msg)
 
351
            elif revision is not None:
 
352
                for rev in revision:
 
353
                    if rev is None:
 
354
                        raise errors.BzrCommandError(
 
355
                            'You cannot specify a NULL revision.')
 
356
                    rev_id = rev.as_revision_id(b)
 
357
                    self.print_revision(revisions, rev_id)
 
358
        finally:
 
359
            b.repository.unlock()
 
360
        
362
361
 
363
362
class cmd_dump_btree(Command):
364
 
    """Dump the contents of a btree index file to stdout.
 
363
    __doc__ = """Dump the contents of a btree index file to stdout.
365
364
 
366
365
    PATH is a btree index file, it can be any URL. This includes things like
367
366
    .bzr/repository/pack-names, or .bzr/repository/indices/a34b3a...ca4a4.iix
431
430
        for node in bt.iter_all_entries():
432
431
            # Node is made up of:
433
432
            # (index, key, value, [references])
434
 
            self.outf.write('%s\n' % (node[1:],))
 
433
            try:
 
434
                refs = node[3]
 
435
            except IndexError:
 
436
                refs_as_tuples = None
 
437
            else:
 
438
                refs_as_tuples = static_tuple.as_tuples(refs)
 
439
            as_tuple = (tuple(node[1]), node[2], refs_as_tuples)
 
440
            self.outf.write('%s\n' % (as_tuple,))
435
441
 
436
442
 
437
443
class cmd_remove_tree(Command):
438
 
    """Remove the working tree from a given branch/checkout.
 
444
    __doc__ = """Remove the working tree from a given branch/checkout.
439
445
 
440
446
    Since a lightweight checkout is little more than a working tree
441
447
    this will refuse to run against one.
443
449
    To re-create the working tree, use "bzr checkout".
444
450
    """
445
451
    _see_also = ['checkout', 'working-trees']
446
 
    takes_args = ['location?']
 
452
    takes_args = ['location*']
447
453
    takes_options = [
448
454
        Option('force',
449
455
               help='Remove the working tree even if it has '
450
 
                    'uncommitted changes.'),
 
456
                    'uncommitted or shelved changes.'),
451
457
        ]
452
458
 
453
 
    def run(self, location='.', force=False):
454
 
        d = bzrdir.BzrDir.open(location)
455
 
 
456
 
        try:
457
 
            working = d.open_workingtree()
458
 
        except errors.NoWorkingTree:
459
 
            raise errors.BzrCommandError("No working tree to remove")
460
 
        except errors.NotLocalUrl:
461
 
            raise errors.BzrCommandError("You cannot remove the working tree"
462
 
                                         " of a remote path")
463
 
        if not force:
464
 
            # XXX: What about pending merges ? -- vila 20090629
465
 
            if working.has_changes(working.basis_tree()):
466
 
                raise errors.UncommittedChanges(working)
467
 
 
468
 
        working_path = working.bzrdir.root_transport.base
469
 
        branch_path = working.branch.bzrdir.root_transport.base
470
 
        if working_path != branch_path:
471
 
            raise errors.BzrCommandError("You cannot remove the working tree"
472
 
                                         " from a lightweight checkout")
473
 
 
474
 
        d.destroy_workingtree()
 
459
    def run(self, location_list, force=False):
 
460
        if not location_list:
 
461
            location_list=['.']
 
462
 
 
463
        for location in location_list:
 
464
            d = bzrdir.BzrDir.open(location)
 
465
            
 
466
            try:
 
467
                working = d.open_workingtree()
 
468
            except errors.NoWorkingTree:
 
469
                raise errors.BzrCommandError("No working tree to remove")
 
470
            except errors.NotLocalUrl:
 
471
                raise errors.BzrCommandError("You cannot remove the working tree"
 
472
                                             " of a remote path")
 
473
            if not force:
 
474
                if (working.has_changes()):
 
475
                    raise errors.UncommittedChanges(working)
 
476
                if working.get_shelf_manager().last_shelf() is not None:
 
477
                    raise errors.ShelvedChanges(working)
 
478
 
 
479
            if working.user_url != working.branch.user_url:
 
480
                raise errors.BzrCommandError("You cannot remove the working tree"
 
481
                                             " from a lightweight checkout")
 
482
 
 
483
            d.destroy_workingtree()
475
484
 
476
485
 
477
486
class cmd_revno(Command):
478
 
    """Show current revision number.
 
487
    __doc__ = """Show current revision number.
479
488
 
480
489
    This is equal to the number of revisions on this branch.
481
490
    """
491
500
        if tree:
492
501
            try:
493
502
                wt = WorkingTree.open_containing(location)[0]
494
 
                wt.lock_read()
 
503
                self.add_cleanup(wt.lock_read().unlock)
495
504
            except (errors.NoWorkingTree, errors.NotLocalUrl):
496
505
                raise errors.NoWorkingTree(location)
 
506
            revid = wt.last_revision()
497
507
            try:
498
 
                revid = wt.last_revision()
499
 
                try:
500
 
                    revno_t = wt.branch.revision_id_to_dotted_revno(revid)
501
 
                except errors.NoSuchRevision:
502
 
                    revno_t = ('???',)
503
 
                revno = ".".join(str(n) for n in revno_t)
504
 
            finally:
505
 
                wt.unlock()
 
508
                revno_t = wt.branch.revision_id_to_dotted_revno(revid)
 
509
            except errors.NoSuchRevision:
 
510
                revno_t = ('???',)
 
511
            revno = ".".join(str(n) for n in revno_t)
506
512
        else:
507
513
            b = Branch.open_containing(location)[0]
508
 
            b.lock_read()
509
 
            try:
510
 
                revno = b.revno()
511
 
            finally:
512
 
                b.unlock()
513
 
 
 
514
            self.add_cleanup(b.lock_read().unlock)
 
515
            revno = b.revno()
 
516
        self.cleanup_now()
514
517
        self.outf.write(str(revno) + '\n')
515
518
 
516
519
 
517
520
class cmd_revision_info(Command):
518
 
    """Show revision number and revision id for a given revision identifier.
 
521
    __doc__ = """Show revision number and revision id for a given revision identifier.
519
522
    """
520
523
    hidden = True
521
524
    takes_args = ['revision_info*']
522
525
    takes_options = [
523
526
        'revision',
524
 
        Option('directory',
 
527
        custom_help('directory',
525
528
            help='Branch to examine, '
526
 
                 'rather than the one containing the working directory.',
527
 
            short_name='d',
528
 
            type=unicode,
529
 
            ),
 
529
                 'rather than the one containing the working directory.'),
530
530
        Option('tree', help='Show revno of working tree'),
531
531
        ]
532
532
 
537
537
        try:
538
538
            wt = WorkingTree.open_containing(directory)[0]
539
539
            b = wt.branch
540
 
            wt.lock_read()
 
540
            self.add_cleanup(wt.lock_read().unlock)
541
541
        except (errors.NoWorkingTree, errors.NotLocalUrl):
542
542
            wt = None
543
543
            b = Branch.open_containing(directory)[0]
544
 
            b.lock_read()
545
 
        try:
546
 
            revision_ids = []
547
 
            if revision is not None:
548
 
                revision_ids.extend(rev.as_revision_id(b) for rev in revision)
549
 
            if revision_info_list is not None:
550
 
                for rev_str in revision_info_list:
551
 
                    rev_spec = RevisionSpec.from_string(rev_str)
552
 
                    revision_ids.append(rev_spec.as_revision_id(b))
553
 
            # No arguments supplied, default to the last revision
554
 
            if len(revision_ids) == 0:
555
 
                if tree:
556
 
                    if wt is None:
557
 
                        raise errors.NoWorkingTree(directory)
558
 
                    revision_ids.append(wt.last_revision())
559
 
                else:
560
 
                    revision_ids.append(b.last_revision())
561
 
 
562
 
            revinfos = []
563
 
            maxlen = 0
564
 
            for revision_id in revision_ids:
565
 
                try:
566
 
                    dotted_revno = b.revision_id_to_dotted_revno(revision_id)
567
 
                    revno = '.'.join(str(i) for i in dotted_revno)
568
 
                except errors.NoSuchRevision:
569
 
                    revno = '???'
570
 
                maxlen = max(maxlen, len(revno))
571
 
                revinfos.append([revno, revision_id])
572
 
        finally:
573
 
            if wt is None:
574
 
                b.unlock()
 
544
            self.add_cleanup(b.lock_read().unlock)
 
545
        revision_ids = []
 
546
        if revision is not None:
 
547
            revision_ids.extend(rev.as_revision_id(b) for rev in revision)
 
548
        if revision_info_list is not None:
 
549
            for rev_str in revision_info_list:
 
550
                rev_spec = RevisionSpec.from_string(rev_str)
 
551
                revision_ids.append(rev_spec.as_revision_id(b))
 
552
        # No arguments supplied, default to the last revision
 
553
        if len(revision_ids) == 0:
 
554
            if tree:
 
555
                if wt is None:
 
556
                    raise errors.NoWorkingTree(directory)
 
557
                revision_ids.append(wt.last_revision())
575
558
            else:
576
 
                wt.unlock()
577
 
 
 
559
                revision_ids.append(b.last_revision())
 
560
 
 
561
        revinfos = []
 
562
        maxlen = 0
 
563
        for revision_id in revision_ids:
 
564
            try:
 
565
                dotted_revno = b.revision_id_to_dotted_revno(revision_id)
 
566
                revno = '.'.join(str(i) for i in dotted_revno)
 
567
            except errors.NoSuchRevision:
 
568
                revno = '???'
 
569
            maxlen = max(maxlen, len(revno))
 
570
            revinfos.append([revno, revision_id])
 
571
 
 
572
        self.cleanup_now()
578
573
        for ri in revinfos:
579
574
            self.outf.write('%*s %s\n' % (maxlen, ri[0], ri[1]))
580
575
 
581
576
 
582
577
class cmd_add(Command):
583
 
    """Add specified files or directories.
 
578
    __doc__ = """Add specified files or directories.
584
579
 
585
580
    In non-recursive mode, all the named items are added, regardless
586
581
    of whether they were previously ignored.  A warning is given if
651
646
                should_print=(not is_quiet()))
652
647
 
653
648
        if base_tree:
654
 
            base_tree.lock_read()
655
 
        try:
656
 
            file_list = self._maybe_expand_globs(file_list)
657
 
            tree, file_list = tree_files_for_add(file_list)
658
 
            added, ignored = tree.smart_add(file_list, not
659
 
                no_recurse, action=action, save=not dry_run)
660
 
        finally:
661
 
            if base_tree is not None:
662
 
                base_tree.unlock()
 
649
            self.add_cleanup(base_tree.lock_read().unlock)
 
650
        tree, file_list = tree_files_for_add(file_list)
 
651
        added, ignored = tree.smart_add(file_list, not
 
652
            no_recurse, action=action, save=not dry_run)
 
653
        self.cleanup_now()
663
654
        if len(ignored) > 0:
664
655
            if verbose:
665
656
                for glob in sorted(ignored.keys()):
669
660
 
670
661
 
671
662
class cmd_mkdir(Command):
672
 
    """Create a new versioned directory.
 
663
    __doc__ = """Create a new versioned directory.
673
664
 
674
665
    This is equivalent to creating the directory and then adding it.
675
666
    """
679
670
 
680
671
    def run(self, dir_list):
681
672
        for d in dir_list:
682
 
            os.mkdir(d)
683
673
            wt, dd = WorkingTree.open_containing(d)
684
 
            wt.add([dd])
685
 
            self.outf.write('added %s\n' % d)
 
674
            base = os.path.dirname(dd)
 
675
            id = wt.path2id(base)
 
676
            if id != None:
 
677
                os.mkdir(d)
 
678
                wt.add([dd])
 
679
                self.outf.write('added %s\n' % d)
 
680
            else:
 
681
                raise errors.NotVersionedError(path=base)
686
682
 
687
683
 
688
684
class cmd_relpath(Command):
689
 
    """Show path of a file relative to root"""
 
685
    __doc__ = """Show path of a file relative to root"""
690
686
 
691
687
    takes_args = ['filename']
692
688
    hidden = True
701
697
 
702
698
 
703
699
class cmd_inventory(Command):
704
 
    """Show inventory of the current working copy or a revision.
 
700
    __doc__ = """Show inventory of the current working copy or a revision.
705
701
 
706
702
    It is possible to limit the output to a particular entry
707
703
    type using the --kind option.  For example: --kind file.
727
723
            raise errors.BzrCommandError('invalid kind %r specified' % (kind,))
728
724
 
729
725
        revision = _get_one_revision('inventory', revision)
730
 
        work_tree, file_list = tree_files(file_list)
731
 
        work_tree.lock_read()
732
 
        try:
733
 
            if revision is not None:
734
 
                tree = revision.as_tree(work_tree.branch)
735
 
 
736
 
                extra_trees = [work_tree]
737
 
                tree.lock_read()
738
 
            else:
739
 
                tree = work_tree
740
 
                extra_trees = []
741
 
 
742
 
            if file_list is not None:
743
 
                file_ids = tree.paths2ids(file_list, trees=extra_trees,
744
 
                                          require_versioned=True)
745
 
                # find_ids_across_trees may include some paths that don't
746
 
                # exist in 'tree'.
747
 
                entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
748
 
                                 for file_id in file_ids if file_id in tree)
749
 
            else:
750
 
                entries = tree.inventory.entries()
751
 
        finally:
752
 
            tree.unlock()
753
 
            if tree is not work_tree:
754
 
                work_tree.unlock()
755
 
 
 
726
        work_tree, file_list = WorkingTree.open_containing_paths(file_list)
 
727
        self.add_cleanup(work_tree.lock_read().unlock)
 
728
        if revision is not None:
 
729
            tree = revision.as_tree(work_tree.branch)
 
730
 
 
731
            extra_trees = [work_tree]
 
732
            self.add_cleanup(tree.lock_read().unlock)
 
733
        else:
 
734
            tree = work_tree
 
735
            extra_trees = []
 
736
 
 
737
        if file_list is not None:
 
738
            file_ids = tree.paths2ids(file_list, trees=extra_trees,
 
739
                                      require_versioned=True)
 
740
            # find_ids_across_trees may include some paths that don't
 
741
            # exist in 'tree'.
 
742
            entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
 
743
                             for file_id in file_ids if file_id in tree)
 
744
        else:
 
745
            entries = tree.inventory.entries()
 
746
 
 
747
        self.cleanup_now()
756
748
        for path, entry in entries:
757
749
            if kind and kind != entry.kind:
758
750
                continue
764
756
 
765
757
 
766
758
class cmd_mv(Command):
767
 
    """Move or rename a file.
 
759
    __doc__ = """Move or rename a file.
768
760
 
769
761
    :Usage:
770
762
        bzr mv OLDNAME NEWNAME
802
794
            names_list = []
803
795
        if len(names_list) < 2:
804
796
            raise errors.BzrCommandError("missing file argument")
805
 
        tree, rel_names = tree_files(names_list, canonicalize=False)
806
 
        tree.lock_tree_write()
807
 
        try:
808
 
            self._run(tree, names_list, rel_names, after)
809
 
        finally:
810
 
            tree.unlock()
 
797
        tree, rel_names = WorkingTree.open_containing_paths(names_list, canonicalize=False)
 
798
        self.add_cleanup(tree.lock_tree_write().unlock)
 
799
        self._run(tree, names_list, rel_names, after)
811
800
 
812
801
    def run_auto(self, names_list, after, dry_run):
813
802
        if names_list is not None and len(names_list) > 1:
816
805
        if after:
817
806
            raise errors.BzrCommandError('--after cannot be specified with'
818
807
                                         ' --auto.')
819
 
        work_tree, file_list = tree_files(names_list, default_branch='.')
820
 
        work_tree.lock_tree_write()
821
 
        try:
822
 
            rename_map.RenameMap.guess_renames(work_tree, dry_run)
823
 
        finally:
824
 
            work_tree.unlock()
 
808
        work_tree, file_list = WorkingTree.open_containing_paths(
 
809
            names_list, default_directory='.')
 
810
        self.add_cleanup(work_tree.lock_tree_write().unlock)
 
811
        rename_map.RenameMap.guess_renames(work_tree, dry_run)
825
812
 
826
813
    def _run(self, tree, names_list, rel_names, after):
827
814
        into_existing = osutils.isdir(names_list[-1])
848
835
            # All entries reference existing inventory items, so fix them up
849
836
            # for cicp file-systems.
850
837
            rel_names = tree.get_canonical_inventory_paths(rel_names)
851
 
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
852
 
                self.outf.write("%s => %s\n" % pair)
 
838
            for src, dest in tree.move(rel_names[:-1], rel_names[-1], after=after):
 
839
                if not is_quiet():
 
840
                    self.outf.write("%s => %s\n" % (src, dest))
853
841
        else:
854
842
            if len(names_list) != 2:
855
843
                raise errors.BzrCommandError('to mv multiple files the'
899
887
            dest = osutils.pathjoin(dest_parent, dest_tail)
900
888
            mutter("attempting to move %s => %s", src, dest)
901
889
            tree.rename_one(src, dest, after=after)
902
 
            self.outf.write("%s => %s\n" % (src, dest))
 
890
            if not is_quiet():
 
891
                self.outf.write("%s => %s\n" % (src, dest))
903
892
 
904
893
 
905
894
class cmd_pull(Command):
906
 
    """Turn this branch into a mirror of another branch.
 
895
    __doc__ = """Turn this branch into a mirror of another branch.
907
896
 
908
 
    This command only works on branches that have not diverged.  Branches are
909
 
    considered diverged if the destination branch's most recent commit is one
910
 
    that has not been merged (directly or indirectly) into the parent.
 
897
    By default, this command only works on branches that have not diverged.
 
898
    Branches are considered diverged if the destination branch's most recent 
 
899
    commit is one that has not been merged (directly or indirectly) into the 
 
900
    parent.
911
901
 
912
902
    If branches have diverged, you can use 'bzr merge' to integrate the changes
913
903
    from one into the other.  Once one branch has merged, the other should
914
904
    be able to pull it again.
915
905
 
916
 
    If you want to forget your local changes and just update your branch to
917
 
    match the remote one, use pull --overwrite.
 
906
    If you want to replace your local changes and just want your branch to
 
907
    match the remote one, use pull --overwrite. This will work even if the two
 
908
    branches have diverged.
918
909
 
919
910
    If there is no default location set, the first pull will set it.  After
920
911
    that, you can omit the location to use the default.  To change the
930
921
    takes_options = ['remember', 'overwrite', 'revision',
931
922
        custom_help('verbose',
932
923
            help='Show logs of pulled revisions.'),
933
 
        Option('directory',
 
924
        custom_help('directory',
934
925
            help='Branch to pull into, '
935
 
                 'rather than the one containing the working directory.',
936
 
            short_name='d',
937
 
            type=unicode,
938
 
            ),
 
926
                 'rather than the one containing the working directory.'),
939
927
        Option('local',
940
928
            help="Perform a local pull in a bound "
941
929
                 "branch.  Local pulls are not applied to "
942
930
                 "the master branch."
943
931
            ),
 
932
        Option('show-base',
 
933
            help="Show base revision text in conflicts.")
944
934
        ]
945
935
    takes_args = ['location?']
946
936
    encoding_type = 'replace'
947
937
 
948
938
    def run(self, location=None, remember=False, overwrite=False,
949
939
            revision=None, verbose=False,
950
 
            directory=None, local=False):
 
940
            directory=None, local=False,
 
941
            show_base=False):
951
942
        # FIXME: too much stuff is in the command class
952
943
        revision_id = None
953
944
        mergeable = None
956
947
        try:
957
948
            tree_to = WorkingTree.open_containing(directory)[0]
958
949
            branch_to = tree_to.branch
 
950
            self.add_cleanup(tree_to.lock_write().unlock)
959
951
        except errors.NoWorkingTree:
960
952
            tree_to = None
961
953
            branch_to = Branch.open_containing(directory)[0]
962
 
        
 
954
            self.add_cleanup(branch_to.lock_write().unlock)
 
955
 
 
956
        if tree_to is None and show_base:
 
957
            raise errors.BzrCommandError("Need working tree for --show-base.")
 
958
 
963
959
        if local and not branch_to.get_bound_location():
964
960
            raise errors.LocalRequiresBoundBranch()
965
961
 
995
991
        else:
996
992
            branch_from = Branch.open(location,
997
993
                possible_transports=possible_transports)
 
994
            self.add_cleanup(branch_from.lock_read().unlock)
998
995
 
999
996
            if branch_to.get_parent() is None or remember:
1000
997
                branch_to.set_parent(branch_from.base)
1001
998
 
1002
 
        if branch_from is not branch_to:
1003
 
            branch_from.lock_read()
1004
 
        try:
1005
 
            if revision is not None:
1006
 
                revision_id = revision.as_revision_id(branch_from)
1007
 
 
1008
 
            branch_to.lock_write()
1009
 
            try:
1010
 
                if tree_to is not None:
1011
 
                    view_info = _get_view_info_for_change_reporter(tree_to)
1012
 
                    change_reporter = delta._ChangeReporter(
1013
 
                        unversioned_filter=tree_to.is_ignored,
1014
 
                        view_info=view_info)
1015
 
                    result = tree_to.pull(
1016
 
                        branch_from, overwrite, revision_id, change_reporter,
1017
 
                        possible_transports=possible_transports, local=local)
1018
 
                else:
1019
 
                    result = branch_to.pull(
1020
 
                        branch_from, overwrite, revision_id, local=local)
1021
 
 
1022
 
                result.report(self.outf)
1023
 
                if verbose and result.old_revid != result.new_revid:
1024
 
                    log.show_branch_change(
1025
 
                        branch_to, self.outf, result.old_revno,
1026
 
                        result.old_revid)
1027
 
            finally:
1028
 
                branch_to.unlock()
1029
 
        finally:
1030
 
            if branch_from is not branch_to:
1031
 
                branch_from.unlock()
 
999
        if revision is not None:
 
1000
            revision_id = revision.as_revision_id(branch_from)
 
1001
 
 
1002
        if tree_to is not None:
 
1003
            view_info = _get_view_info_for_change_reporter(tree_to)
 
1004
            change_reporter = delta._ChangeReporter(
 
1005
                unversioned_filter=tree_to.is_ignored,
 
1006
                view_info=view_info)
 
1007
            result = tree_to.pull(
 
1008
                branch_from, overwrite, revision_id, change_reporter,
 
1009
                possible_transports=possible_transports, local=local,
 
1010
                show_base=show_base)
 
1011
        else:
 
1012
            result = branch_to.pull(
 
1013
                branch_from, overwrite, revision_id, local=local)
 
1014
 
 
1015
        result.report(self.outf)
 
1016
        if verbose and result.old_revid != result.new_revid:
 
1017
            log.show_branch_change(
 
1018
                branch_to, self.outf, result.old_revno,
 
1019
                result.old_revid)
1032
1020
 
1033
1021
 
1034
1022
class cmd_push(Command):
1035
 
    """Update a mirror of this branch.
 
1023
    __doc__ = """Update a mirror of this branch.
1036
1024
 
1037
1025
    The target branch will not have its working tree populated because this
1038
1026
    is both expensive, and is not supported on remote file systems.
1062
1050
        Option('create-prefix',
1063
1051
               help='Create the path leading up to the branch '
1064
1052
                    'if it does not already exist.'),
1065
 
        Option('directory',
 
1053
        custom_help('directory',
1066
1054
            help='Branch to push from, '
1067
 
                 'rather than the one containing the working directory.',
1068
 
            short_name='d',
1069
 
            type=unicode,
1070
 
            ),
 
1055
                 'rather than the one containing the working directory.'),
1071
1056
        Option('use-existing-dir',
1072
1057
               help='By default push will fail if the target'
1073
1058
                    ' directory exists, but does not already'
1084
1069
        Option('strict',
1085
1070
               help='Refuse to push if there are uncommitted changes in'
1086
1071
               ' the working tree, --no-strict disables the check.'),
 
1072
        Option('no-tree',
 
1073
               help="Don't populate the working tree, even for protocols"
 
1074
               " that support it."),
1087
1075
        ]
1088
1076
    takes_args = ['location?']
1089
1077
    encoding_type = 'replace'
1091
1079
    def run(self, location=None, remember=False, overwrite=False,
1092
1080
        create_prefix=False, verbose=False, revision=None,
1093
1081
        use_existing_dir=False, directory=None, stacked_on=None,
1094
 
        stacked=False, strict=None):
 
1082
        stacked=False, strict=None, no_tree=False):
1095
1083
        from bzrlib.push import _show_push_branch
1096
1084
 
1097
1085
        if directory is None:
1099
1087
        # Get the source branch
1100
1088
        (tree, br_from,
1101
1089
         _unused) = bzrdir.BzrDir.open_containing_tree_or_branch(directory)
1102
 
        if strict is None:
1103
 
            strict = br_from.get_config().get_user_option_as_bool('push_strict')
1104
 
        if strict is None: strict = True # default value
1105
1090
        # Get the tip's revision_id
1106
1091
        revision = _get_one_revision('push', revision)
1107
1092
        if revision is not None:
1108
1093
            revision_id = revision.in_history(br_from).rev_id
1109
1094
        else:
1110
1095
            revision_id = None
1111
 
        if strict and tree is not None and revision_id is None:
1112
 
            if (tree.has_changes(tree.basis_tree())
1113
 
                or len(tree.get_parent_ids()) > 1):
1114
 
                raise errors.UncommittedChanges(
1115
 
                    tree, more='Use --no-strict to force the push.')
1116
 
            if tree.last_revision() != tree.branch.last_revision():
1117
 
                # The tree has lost sync with its branch, there is little
1118
 
                # chance that the user is aware of it but he can still force
1119
 
                # the push with --no-strict
1120
 
                raise errors.OutOfDateTree(
1121
 
                    tree, more='Use --no-strict to force the push.')
1122
 
 
 
1096
        if tree is not None and revision_id is None:
 
1097
            tree.check_changed_or_out_of_date(
 
1098
                strict, 'push_strict',
 
1099
                more_error='Use --no-strict to force the push.',
 
1100
                more_warning='Uncommitted changes will not be pushed.')
1123
1101
        # Get the stacked_on branch, if any
1124
1102
        if stacked_on is not None:
1125
1103
            stacked_on = urlutils.normalize_url(stacked_on)
1153
1131
        _show_push_branch(br_from, revision_id, location, self.outf,
1154
1132
            verbose=verbose, overwrite=overwrite, remember=remember,
1155
1133
            stacked_on=stacked_on, create_prefix=create_prefix,
1156
 
            use_existing_dir=use_existing_dir)
 
1134
            use_existing_dir=use_existing_dir, no_tree=no_tree)
1157
1135
 
1158
1136
 
1159
1137
class cmd_branch(Command):
1160
 
    """Create a new branch that is a copy of an existing branch.
 
1138
    __doc__ = """Create a new branch that is a copy of an existing branch.
1161
1139
 
1162
1140
    If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
1163
1141
    be used.  In other words, "branch ../foo/bar" will attempt to create ./bar.
1172
1150
 
1173
1151
    _see_also = ['checkout']
1174
1152
    takes_args = ['from_location', 'to_location?']
1175
 
    takes_options = ['revision', Option('hardlink',
1176
 
        help='Hard-link working tree files where possible.'),
 
1153
    takes_options = ['revision',
 
1154
        Option('hardlink', help='Hard-link working tree files where possible.'),
 
1155
        Option('files-from', type=str,
 
1156
               help="Get file contents from this tree."),
1177
1157
        Option('no-tree',
1178
1158
            help="Create a branch without a working-tree."),
1179
1159
        Option('switch',
1190
1170
                    ' directory exists, but does not already'
1191
1171
                    ' have a control directory.  This flag will'
1192
1172
                    ' allow branch to proceed.'),
 
1173
        Option('bind',
 
1174
            help="Bind new branch to from location."),
1193
1175
        ]
1194
1176
    aliases = ['get', 'clone']
1195
1177
 
1196
1178
    def run(self, from_location, to_location=None, revision=None,
1197
1179
            hardlink=False, stacked=False, standalone=False, no_tree=False,
1198
 
            use_existing_dir=False, switch=False):
 
1180
            use_existing_dir=False, switch=False, bind=False,
 
1181
            files_from=None):
1199
1182
        from bzrlib import switch as _mod_switch
1200
1183
        from bzrlib.tag import _merge_tags_if_possible
1201
1184
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
1202
1185
            from_location)
1203
 
        if (accelerator_tree is not None and
1204
 
            accelerator_tree.supports_content_filtering()):
 
1186
        if not (hardlink or files_from):
 
1187
            # accelerator_tree is usually slower because you have to read N
 
1188
            # files (no readahead, lots of seeks, etc), but allow the user to
 
1189
            # explicitly request it
1205
1190
            accelerator_tree = None
 
1191
        if files_from is not None and files_from != from_location:
 
1192
            accelerator_tree = WorkingTree.open(files_from)
1206
1193
        revision = _get_one_revision('branch', revision)
1207
 
        br_from.lock_read()
 
1194
        self.add_cleanup(br_from.lock_read().unlock)
 
1195
        if revision is not None:
 
1196
            revision_id = revision.as_revision_id(br_from)
 
1197
        else:
 
1198
            # FIXME - wt.last_revision, fallback to branch, fall back to
 
1199
            # None or perhaps NULL_REVISION to mean copy nothing
 
1200
            # RBC 20060209
 
1201
            revision_id = br_from.last_revision()
 
1202
        if to_location is None:
 
1203
            to_location = urlutils.derive_to_location(from_location)
 
1204
        to_transport = transport.get_transport(to_location)
1208
1205
        try:
1209
 
            if revision is not None:
1210
 
                revision_id = revision.as_revision_id(br_from)
 
1206
            to_transport.mkdir('.')
 
1207
        except errors.FileExists:
 
1208
            if not use_existing_dir:
 
1209
                raise errors.BzrCommandError('Target directory "%s" '
 
1210
                    'already exists.' % to_location)
1211
1211
            else:
1212
 
                # FIXME - wt.last_revision, fallback to branch, fall back to
1213
 
                # None or perhaps NULL_REVISION to mean copy nothing
1214
 
                # RBC 20060209
1215
 
                revision_id = br_from.last_revision()
1216
 
            if to_location is None:
1217
 
                to_location = urlutils.derive_to_location(from_location)
1218
 
            to_transport = transport.get_transport(to_location)
1219
 
            try:
1220
 
                to_transport.mkdir('.')
1221
 
            except errors.FileExists:
1222
 
                if not use_existing_dir:
1223
 
                    raise errors.BzrCommandError('Target directory "%s" '
1224
 
                        'already exists.' % to_location)
 
1212
                try:
 
1213
                    bzrdir.BzrDir.open_from_transport(to_transport)
 
1214
                except errors.NotBranchError:
 
1215
                    pass
1225
1216
                else:
1226
 
                    try:
1227
 
                        bzrdir.BzrDir.open_from_transport(to_transport)
1228
 
                    except errors.NotBranchError:
1229
 
                        pass
1230
 
                    else:
1231
 
                        raise errors.AlreadyBranchError(to_location)
1232
 
            except errors.NoSuchFile:
1233
 
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
1234
 
                                             % to_location)
1235
 
            try:
1236
 
                # preserve whatever source format we have.
1237
 
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
1238
 
                                            possible_transports=[to_transport],
1239
 
                                            accelerator_tree=accelerator_tree,
1240
 
                                            hardlink=hardlink, stacked=stacked,
1241
 
                                            force_new_repo=standalone,
1242
 
                                            create_tree_if_local=not no_tree,
1243
 
                                            source_branch=br_from)
1244
 
                branch = dir.open_branch()
1245
 
            except errors.NoSuchRevision:
1246
 
                to_transport.delete_tree('.')
1247
 
                msg = "The branch %s has no revision %s." % (from_location,
1248
 
                    revision)
1249
 
                raise errors.BzrCommandError(msg)
1250
 
            _merge_tags_if_possible(br_from, branch)
1251
 
            # If the source branch is stacked, the new branch may
1252
 
            # be stacked whether we asked for that explicitly or not.
1253
 
            # We therefore need a try/except here and not just 'if stacked:'
1254
 
            try:
1255
 
                note('Created new stacked branch referring to %s.' %
1256
 
                    branch.get_stacked_on_url())
1257
 
            except (errors.NotStacked, errors.UnstackableBranchFormat,
1258
 
                errors.UnstackableRepositoryFormat), e:
1259
 
                note('Branched %d revision(s).' % branch.revno())
1260
 
            if switch:
1261
 
                # Switch to the new branch
1262
 
                wt, _ = WorkingTree.open_containing('.')
1263
 
                _mod_switch.switch(wt.bzrdir, branch)
1264
 
                note('Switched to branch: %s',
1265
 
                    urlutils.unescape_for_display(branch.base, 'utf-8'))
1266
 
        finally:
1267
 
            br_from.unlock()
 
1217
                    raise errors.AlreadyBranchError(to_location)
 
1218
        except errors.NoSuchFile:
 
1219
            raise errors.BzrCommandError('Parent of "%s" does not exist.'
 
1220
                                         % to_location)
 
1221
        try:
 
1222
            # preserve whatever source format we have.
 
1223
            dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
 
1224
                                        possible_transports=[to_transport],
 
1225
                                        accelerator_tree=accelerator_tree,
 
1226
                                        hardlink=hardlink, stacked=stacked,
 
1227
                                        force_new_repo=standalone,
 
1228
                                        create_tree_if_local=not no_tree,
 
1229
                                        source_branch=br_from)
 
1230
            branch = dir.open_branch()
 
1231
        except errors.NoSuchRevision:
 
1232
            to_transport.delete_tree('.')
 
1233
            msg = "The branch %s has no revision %s." % (from_location,
 
1234
                revision)
 
1235
            raise errors.BzrCommandError(msg)
 
1236
        _merge_tags_if_possible(br_from, branch)
 
1237
        # If the source branch is stacked, the new branch may
 
1238
        # be stacked whether we asked for that explicitly or not.
 
1239
        # We therefore need a try/except here and not just 'if stacked:'
 
1240
        try:
 
1241
            note('Created new stacked branch referring to %s.' %
 
1242
                branch.get_stacked_on_url())
 
1243
        except (errors.NotStacked, errors.UnstackableBranchFormat,
 
1244
            errors.UnstackableRepositoryFormat), e:
 
1245
            note('Branched %d revision(s).' % branch.revno())
 
1246
        if bind:
 
1247
            # Bind to the parent
 
1248
            parent_branch = Branch.open(from_location)
 
1249
            branch.bind(parent_branch)
 
1250
            note('New branch bound to %s' % from_location)
 
1251
        if switch:
 
1252
            # Switch to the new branch
 
1253
            wt, _ = WorkingTree.open_containing('.')
 
1254
            _mod_switch.switch(wt.bzrdir, branch)
 
1255
            note('Switched to branch: %s',
 
1256
                urlutils.unescape_for_display(branch.base, 'utf-8'))
1268
1257
 
1269
1258
 
1270
1259
class cmd_checkout(Command):
1271
 
    """Create a new checkout of an existing branch.
 
1260
    __doc__ = """Create a new checkout of an existing branch.
1272
1261
 
1273
1262
    If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree for
1274
1263
    the branch found in '.'. This is useful if you have removed the working tree
1313
1302
            to_location = branch_location
1314
1303
        accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch(
1315
1304
            branch_location)
 
1305
        if not (hardlink or files_from):
 
1306
            # accelerator_tree is usually slower because you have to read N
 
1307
            # files (no readahead, lots of seeks, etc), but allow the user to
 
1308
            # explicitly request it
 
1309
            accelerator_tree = None
1316
1310
        revision = _get_one_revision('checkout', revision)
1317
 
        if files_from is not None:
 
1311
        if files_from is not None and files_from != branch_location:
1318
1312
            accelerator_tree = WorkingTree.open(files_from)
1319
1313
        if revision is not None:
1320
1314
            revision_id = revision.as_revision_id(source)
1337
1331
 
1338
1332
 
1339
1333
class cmd_renames(Command):
1340
 
    """Show list of renamed files.
 
1334
    __doc__ = """Show list of renamed files.
1341
1335
    """
1342
1336
    # TODO: Option to show renames between two historical versions.
1343
1337
 
1348
1342
    @display_command
1349
1343
    def run(self, dir=u'.'):
1350
1344
        tree = WorkingTree.open_containing(dir)[0]
1351
 
        tree.lock_read()
1352
 
        try:
1353
 
            new_inv = tree.inventory
1354
 
            old_tree = tree.basis_tree()
1355
 
            old_tree.lock_read()
1356
 
            try:
1357
 
                old_inv = old_tree.inventory
1358
 
                renames = []
1359
 
                iterator = tree.iter_changes(old_tree, include_unchanged=True)
1360
 
                for f, paths, c, v, p, n, k, e in iterator:
1361
 
                    if paths[0] == paths[1]:
1362
 
                        continue
1363
 
                    if None in (paths):
1364
 
                        continue
1365
 
                    renames.append(paths)
1366
 
                renames.sort()
1367
 
                for old_name, new_name in renames:
1368
 
                    self.outf.write("%s => %s\n" % (old_name, new_name))
1369
 
            finally:
1370
 
                old_tree.unlock()
1371
 
        finally:
1372
 
            tree.unlock()
 
1345
        self.add_cleanup(tree.lock_read().unlock)
 
1346
        new_inv = tree.inventory
 
1347
        old_tree = tree.basis_tree()
 
1348
        self.add_cleanup(old_tree.lock_read().unlock)
 
1349
        old_inv = old_tree.inventory
 
1350
        renames = []
 
1351
        iterator = tree.iter_changes(old_tree, include_unchanged=True)
 
1352
        for f, paths, c, v, p, n, k, e in iterator:
 
1353
            if paths[0] == paths[1]:
 
1354
                continue
 
1355
            if None in (paths):
 
1356
                continue
 
1357
            renames.append(paths)
 
1358
        renames.sort()
 
1359
        for old_name, new_name in renames:
 
1360
            self.outf.write("%s => %s\n" % (old_name, new_name))
1373
1361
 
1374
1362
 
1375
1363
class cmd_update(Command):
1376
 
    """Update a tree to have the latest code committed to its branch.
 
1364
    __doc__ = """Update a tree to have the latest code committed to its branch.
1377
1365
 
1378
1366
    This will perform a merge into the working tree, and may generate
1379
1367
    conflicts. If you have any local changes, you will still
1381
1369
 
1382
1370
    If you want to discard your local changes, you can just do a
1383
1371
    'bzr revert' instead of 'bzr commit' after the update.
 
1372
 
 
1373
    If you want to restore a file that has been removed locally, use
 
1374
    'bzr revert' instead of 'bzr update'.
 
1375
 
 
1376
    If the tree's branch is bound to a master branch, it will also update
 
1377
    the branch from the master.
1384
1378
    """
1385
1379
 
1386
1380
    _see_also = ['pull', 'working-trees', 'status-flags']
1387
1381
    takes_args = ['dir?']
 
1382
    takes_options = ['revision',
 
1383
                     Option('show-base',
 
1384
                            help="Show base revision text in conflicts."),
 
1385
                     ]
1388
1386
    aliases = ['up']
1389
1387
 
1390
 
    def run(self, dir='.'):
 
1388
    def run(self, dir='.', revision=None, show_base=None):
 
1389
        if revision is not None and len(revision) != 1:
 
1390
            raise errors.BzrCommandError(
 
1391
                        "bzr update --revision takes exactly one revision")
1391
1392
        tree = WorkingTree.open_containing(dir)[0]
 
1393
        branch = tree.branch
1392
1394
        possible_transports = []
1393
 
        master = tree.branch.get_master_branch(
 
1395
        master = branch.get_master_branch(
1394
1396
            possible_transports=possible_transports)
1395
1397
        if master is not None:
 
1398
            branch_location = master.base
1396
1399
            tree.lock_write()
1397
1400
        else:
 
1401
            branch_location = tree.branch.base
1398
1402
            tree.lock_tree_write()
 
1403
        self.add_cleanup(tree.unlock)
 
1404
        # get rid of the final '/' and be ready for display
 
1405
        branch_location = urlutils.unescape_for_display(
 
1406
            branch_location.rstrip('/'),
 
1407
            self.outf.encoding)
 
1408
        existing_pending_merges = tree.get_parent_ids()[1:]
 
1409
        if master is None:
 
1410
            old_tip = None
 
1411
        else:
 
1412
            # may need to fetch data into a heavyweight checkout
 
1413
            # XXX: this may take some time, maybe we should display a
 
1414
            # message
 
1415
            old_tip = branch.update(possible_transports)
 
1416
        if revision is not None:
 
1417
            revision_id = revision[0].as_revision_id(branch)
 
1418
        else:
 
1419
            revision_id = branch.last_revision()
 
1420
        if revision_id == _mod_revision.ensure_null(tree.last_revision()):
 
1421
            revno = branch.revision_id_to_dotted_revno(revision_id)
 
1422
            note("Tree is up to date at revision %s of branch %s" %
 
1423
                ('.'.join(map(str, revno)), branch_location))
 
1424
            return 0
 
1425
        view_info = _get_view_info_for_change_reporter(tree)
 
1426
        change_reporter = delta._ChangeReporter(
 
1427
            unversioned_filter=tree.is_ignored,
 
1428
            view_info=view_info)
1399
1429
        try:
1400
 
            existing_pending_merges = tree.get_parent_ids()[1:]
1401
 
            last_rev = _mod_revision.ensure_null(tree.last_revision())
1402
 
            if last_rev == _mod_revision.ensure_null(
1403
 
                tree.branch.last_revision()):
1404
 
                # may be up to date, check master too.
1405
 
                if master is None or last_rev == _mod_revision.ensure_null(
1406
 
                    master.last_revision()):
1407
 
                    revno = tree.branch.revision_id_to_revno(last_rev)
1408
 
                    note("Tree is up to date at revision %d." % (revno,))
1409
 
                    return 0
1410
 
            view_info = _get_view_info_for_change_reporter(tree)
1411
1430
            conflicts = tree.update(
1412
 
                delta._ChangeReporter(unversioned_filter=tree.is_ignored,
1413
 
                view_info=view_info), possible_transports=possible_transports)
1414
 
            revno = tree.branch.revision_id_to_revno(
1415
 
                _mod_revision.ensure_null(tree.last_revision()))
1416
 
            note('Updated to revision %d.' % (revno,))
1417
 
            if tree.get_parent_ids()[1:] != existing_pending_merges:
1418
 
                note('Your local commits will now show as pending merges with '
1419
 
                     "'bzr status', and can be committed with 'bzr commit'.")
1420
 
            if conflicts != 0:
1421
 
                return 1
1422
 
            else:
1423
 
                return 0
1424
 
        finally:
1425
 
            tree.unlock()
 
1431
                change_reporter,
 
1432
                possible_transports=possible_transports,
 
1433
                revision=revision_id,
 
1434
                old_tip=old_tip,
 
1435
                show_base=show_base)
 
1436
        except errors.NoSuchRevision, e:
 
1437
            raise errors.BzrCommandError(
 
1438
                                  "branch has no revision %s\n"
 
1439
                                  "bzr update --revision only works"
 
1440
                                  " for a revision in the branch history"
 
1441
                                  % (e.revision))
 
1442
        revno = tree.branch.revision_id_to_dotted_revno(
 
1443
            _mod_revision.ensure_null(tree.last_revision()))
 
1444
        note('Updated to revision %s of branch %s' %
 
1445
             ('.'.join(map(str, revno)), branch_location))
 
1446
        parent_ids = tree.get_parent_ids()
 
1447
        if parent_ids[1:] and parent_ids[1:] != existing_pending_merges:
 
1448
            note('Your local commits will now show as pending merges with '
 
1449
                 "'bzr status', and can be committed with 'bzr commit'.")
 
1450
        if conflicts != 0:
 
1451
            return 1
 
1452
        else:
 
1453
            return 0
1426
1454
 
1427
1455
 
1428
1456
class cmd_info(Command):
1429
 
    """Show information about a working tree, branch or repository.
 
1457
    __doc__ = """Show information about a working tree, branch or repository.
1430
1458
 
1431
1459
    This command will show all known locations and formats associated to the
1432
1460
    tree, branch or repository.
1470
1498
 
1471
1499
 
1472
1500
class cmd_remove(Command):
1473
 
    """Remove files or directories.
 
1501
    __doc__ = """Remove files or directories.
1474
1502
 
1475
 
    This makes bzr stop tracking changes to the specified files. bzr will delete
1476
 
    them if they can easily be recovered using revert. If no options or
1477
 
    parameters are given bzr will scan for files that are being tracked by bzr
1478
 
    but missing in your tree and stop tracking them for you.
 
1503
    This makes Bazaar stop tracking changes to the specified files. Bazaar will
 
1504
    delete them if they can easily be recovered using revert otherwise they
 
1505
    will be backed up (adding an extention of the form .~#~). If no options or
 
1506
    parameters are given Bazaar will scan for files that are being tracked by
 
1507
    Bazaar but missing in your tree and stop tracking them for you.
1479
1508
    """
1480
1509
    takes_args = ['file*']
1481
1510
    takes_options = ['verbose',
1483
1512
        RegistryOption.from_kwargs('file-deletion-strategy',
1484
1513
            'The file deletion mode to be used.',
1485
1514
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1486
 
            safe='Only delete files if they can be'
1487
 
                 ' safely recovered (default).',
 
1515
            safe='Backup changed files (default).',
1488
1516
            keep='Delete from bzr but leave the working copy.',
 
1517
            no_backup='Don\'t backup changed files.',
1489
1518
            force='Delete all the specified files, even if they can not be '
1490
 
                'recovered and even if they are non-empty directories.')]
 
1519
                'recovered and even if they are non-empty directories. '
 
1520
                '(deprecated, use no-backup)')]
1491
1521
    aliases = ['rm', 'del']
1492
1522
    encoding_type = 'replace'
1493
1523
 
1494
1524
    def run(self, file_list, verbose=False, new=False,
1495
1525
        file_deletion_strategy='safe'):
1496
 
        tree, file_list = tree_files(file_list)
 
1526
        if file_deletion_strategy == 'force':
 
1527
            note("(The --force option is deprecated, rather use --no-backup "
 
1528
                "in future.)")
 
1529
            file_deletion_strategy = 'no-backup'
 
1530
 
 
1531
        tree, file_list = WorkingTree.open_containing_paths(file_list)
1497
1532
 
1498
1533
        if file_list is not None:
1499
1534
            file_list = [f for f in file_list]
1500
1535
 
1501
 
        tree.lock_write()
1502
 
        try:
1503
 
            # Heuristics should probably all move into tree.remove_smart or
1504
 
            # some such?
1505
 
            if new:
1506
 
                added = tree.changes_from(tree.basis_tree(),
1507
 
                    specific_files=file_list).added
1508
 
                file_list = sorted([f[0] for f in added], reverse=True)
1509
 
                if len(file_list) == 0:
1510
 
                    raise errors.BzrCommandError('No matching files.')
1511
 
            elif file_list is None:
1512
 
                # missing files show up in iter_changes(basis) as
1513
 
                # versioned-with-no-kind.
1514
 
                missing = []
1515
 
                for change in tree.iter_changes(tree.basis_tree()):
1516
 
                    # Find paths in the working tree that have no kind:
1517
 
                    if change[1][1] is not None and change[6][1] is None:
1518
 
                        missing.append(change[1][1])
1519
 
                file_list = sorted(missing, reverse=True)
1520
 
                file_deletion_strategy = 'keep'
1521
 
            tree.remove(file_list, verbose=verbose, to_file=self.outf,
1522
 
                keep_files=file_deletion_strategy=='keep',
1523
 
                force=file_deletion_strategy=='force')
1524
 
        finally:
1525
 
            tree.unlock()
 
1536
        self.add_cleanup(tree.lock_write().unlock)
 
1537
        # Heuristics should probably all move into tree.remove_smart or
 
1538
        # some such?
 
1539
        if new:
 
1540
            added = tree.changes_from(tree.basis_tree(),
 
1541
                specific_files=file_list).added
 
1542
            file_list = sorted([f[0] for f in added], reverse=True)
 
1543
            if len(file_list) == 0:
 
1544
                raise errors.BzrCommandError('No matching files.')
 
1545
        elif file_list is None:
 
1546
            # missing files show up in iter_changes(basis) as
 
1547
            # versioned-with-no-kind.
 
1548
            missing = []
 
1549
            for change in tree.iter_changes(tree.basis_tree()):
 
1550
                # Find paths in the working tree that have no kind:
 
1551
                if change[1][1] is not None and change[6][1] is None:
 
1552
                    missing.append(change[1][1])
 
1553
            file_list = sorted(missing, reverse=True)
 
1554
            file_deletion_strategy = 'keep'
 
1555
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
 
1556
            keep_files=file_deletion_strategy=='keep',
 
1557
            force=(file_deletion_strategy=='no-backup'))
1526
1558
 
1527
1559
 
1528
1560
class cmd_file_id(Command):
1529
 
    """Print file_id of a particular file or directory.
 
1561
    __doc__ = """Print file_id of a particular file or directory.
1530
1562
 
1531
1563
    The file_id is assigned when the file is first added and remains the
1532
1564
    same through all revisions where the file exists, even when it is
1548
1580
 
1549
1581
 
1550
1582
class cmd_file_path(Command):
1551
 
    """Print path of file_ids to a file or directory.
 
1583
    __doc__ = """Print path of file_ids to a file or directory.
1552
1584
 
1553
1585
    This prints one line for each directory down to the target,
1554
1586
    starting at the branch root.
1570
1602
 
1571
1603
 
1572
1604
class cmd_reconcile(Command):
1573
 
    """Reconcile bzr metadata in a branch.
 
1605
    __doc__ = """Reconcile bzr metadata in a branch.
1574
1606
 
1575
1607
    This can correct data mismatches that may have been caused by
1576
1608
    previous ghost operations or bzr upgrades. You should only
1590
1622
 
1591
1623
    _see_also = ['check']
1592
1624
    takes_args = ['branch?']
 
1625
    takes_options = [
 
1626
        Option('canonicalize-chks',
 
1627
               help='Make sure CHKs are in canonical form (repairs '
 
1628
                    'bug 522637).',
 
1629
               hidden=True),
 
1630
        ]
1593
1631
 
1594
 
    def run(self, branch="."):
 
1632
    def run(self, branch=".", canonicalize_chks=False):
1595
1633
        from bzrlib.reconcile import reconcile
1596
1634
        dir = bzrdir.BzrDir.open(branch)
1597
 
        reconcile(dir)
 
1635
        reconcile(dir, canonicalize_chks=canonicalize_chks)
1598
1636
 
1599
1637
 
1600
1638
class cmd_revision_history(Command):
1601
 
    """Display the list of revision ids on a branch."""
 
1639
    __doc__ = """Display the list of revision ids on a branch."""
1602
1640
 
1603
1641
    _see_also = ['log']
1604
1642
    takes_args = ['location?']
1614
1652
 
1615
1653
 
1616
1654
class cmd_ancestry(Command):
1617
 
    """List all revisions merged into this branch."""
 
1655
    __doc__ = """List all revisions merged into this branch."""
1618
1656
 
1619
1657
    _see_also = ['log', 'revision-history']
1620
1658
    takes_args = ['location?']
1639
1677
 
1640
1678
 
1641
1679
class cmd_init(Command):
1642
 
    """Make a directory into a versioned branch.
 
1680
    __doc__ = """Make a directory into a versioned branch.
1643
1681
 
1644
1682
    Use this to create an empty branch, or before importing an
1645
1683
    existing project.
1677
1715
                ),
1678
1716
         Option('append-revisions-only',
1679
1717
                help='Never change revnos or the existing log.'
1680
 
                '  Append revisions to it only.')
 
1718
                '  Append revisions to it only.'),
 
1719
         Option('no-tree',
 
1720
                'Create a branch without a working tree.')
1681
1721
         ]
1682
1722
    def run(self, location=None, format=None, append_revisions_only=False,
1683
 
            create_prefix=False):
 
1723
            create_prefix=False, no_tree=False):
1684
1724
        if format is None:
1685
1725
            format = bzrdir.format_registry.make_bzrdir('default')
1686
1726
        if location is None:
1709
1749
        except errors.NotBranchError:
1710
1750
            # really a NotBzrDir error...
1711
1751
            create_branch = bzrdir.BzrDir.create_branch_convenience
 
1752
            if no_tree:
 
1753
                force_new_tree = False
 
1754
            else:
 
1755
                force_new_tree = None
1712
1756
            branch = create_branch(to_transport.base, format=format,
1713
 
                                   possible_transports=[to_transport])
 
1757
                                   possible_transports=[to_transport],
 
1758
                                   force_new_tree=force_new_tree)
1714
1759
            a_bzrdir = branch.bzrdir
1715
1760
        else:
1716
1761
            from bzrlib.transport.local import LocalTransport
1720
1765
                        raise errors.BranchExistsWithoutWorkingTree(location)
1721
1766
                raise errors.AlreadyBranchError(location)
1722
1767
            branch = a_bzrdir.create_branch()
1723
 
            a_bzrdir.create_workingtree()
 
1768
            if not no_tree:
 
1769
                a_bzrdir.create_workingtree()
1724
1770
        if append_revisions_only:
1725
1771
            try:
1726
1772
                branch.set_append_revisions_only(True)
1748
1794
 
1749
1795
 
1750
1796
class cmd_init_repository(Command):
1751
 
    """Create a shared repository to hold branches.
 
1797
    __doc__ = """Create a shared repository for branches to share storage space.
1752
1798
 
1753
1799
    New branches created under the repository directory will store their
1754
 
    revisions in the repository, not in the branch directory.
 
1800
    revisions in the repository, not in the branch directory.  For branches
 
1801
    with shared history, this reduces the amount of storage needed and 
 
1802
    speeds up the creation of new branches.
1755
1803
 
1756
 
    If the --no-trees option is used then the branches in the repository
1757
 
    will not have working trees by default.
 
1804
    If the --no-trees option is given then the branches in the repository
 
1805
    will not have working trees by default.  They will still exist as 
 
1806
    directories on disk, but they will not have separate copies of the 
 
1807
    files at a certain revision.  This can be useful for repositories that
 
1808
    store branches which are interacted with through checkouts or remote
 
1809
    branches, such as on a server.
1758
1810
 
1759
1811
    :Examples:
1760
 
        Create a shared repositories holding just branches::
 
1812
        Create a shared repository holding just branches::
1761
1813
 
1762
1814
            bzr init-repo --no-trees repo
1763
1815
            bzr init repo/trunk
1802
1854
 
1803
1855
 
1804
1856
class cmd_diff(Command):
1805
 
    """Show differences in the working tree, between revisions or branches.
 
1857
    __doc__ = """Show differences in the working tree, between revisions or branches.
1806
1858
 
1807
1859
    If no arguments are given, all changes for the current tree are listed.
1808
1860
    If files are given, only the changes in those files are listed.
1814
1866
    "bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1815
1867
    produces patches suitable for "patch -p1".
1816
1868
 
 
1869
    Note that when using the -r argument with a range of revisions, the
 
1870
    differences are computed between the two specified revisions.  That
 
1871
    is, the command does not show the changes introduced by the first 
 
1872
    revision in the range.  This differs from the interpretation of 
 
1873
    revision ranges used by "bzr log" which includes the first revision
 
1874
    in the range.
 
1875
 
1817
1876
    :Exit values:
1818
1877
        1 - changed
1819
1878
        2 - unrepresentable changes
1829
1888
 
1830
1889
            bzr diff -r1
1831
1890
 
1832
 
        Difference between revision 2 and revision 1::
1833
 
 
1834
 
            bzr diff -r1..2
1835
 
 
1836
 
        Difference between revision 2 and revision 1 for branch xxx::
1837
 
 
1838
 
            bzr diff -r1..2 xxx
 
1891
        Difference between revision 3 and revision 1::
 
1892
 
 
1893
            bzr diff -r1..3
 
1894
 
 
1895
        Difference between revision 3 and revision 1 for branch xxx::
 
1896
 
 
1897
            bzr diff -r1..3 xxx
 
1898
 
 
1899
        The changes introduced by revision 2 (equivalent to -r1..2)::
 
1900
 
 
1901
            bzr diff -c2
 
1902
 
 
1903
        To see the changes introduced by revision X::
 
1904
        
 
1905
            bzr diff -cX
 
1906
 
 
1907
        Note that in the case of a merge, the -c option shows the changes
 
1908
        compared to the left hand parent. To see the changes against
 
1909
        another parent, use::
 
1910
 
 
1911
            bzr diff -r<chosen_parent>..X
 
1912
 
 
1913
        The changes between the current revision and the previous revision
 
1914
        (equivalent to -c-1 and -r-2..-1)
 
1915
 
 
1916
            bzr diff -r-2..
1839
1917
 
1840
1918
        Show just the differences for file NEWS::
1841
1919
 
1856
1934
        Same as 'bzr diff' but prefix paths with old/ and new/::
1857
1935
 
1858
1936
            bzr diff --prefix old/:new/
 
1937
            
 
1938
        Show the differences using a custom diff program with options::
 
1939
        
 
1940
            bzr diff --using /usr/bin/diff --diff-options -wu
1859
1941
    """
1860
1942
    _see_also = ['status']
1861
1943
    takes_args = ['file*']
1880
1962
            help='Use this command to compare files.',
1881
1963
            type=unicode,
1882
1964
            ),
 
1965
        RegistryOption('format',
 
1966
            help='Diff format to use.',
 
1967
            lazy_registry=('bzrlib.diff', 'format_registry'),
 
1968
            value_switches=False, title='Diff format'),
1883
1969
        ]
1884
1970
    aliases = ['di', 'dif']
1885
1971
    encoding_type = 'exact'
1886
1972
 
1887
1973
    @display_command
1888
1974
    def run(self, revision=None, file_list=None, diff_options=None,
1889
 
            prefix=None, old=None, new=None, using=None):
1890
 
        from bzrlib.diff import _get_trees_to_diff, show_diff_trees
 
1975
            prefix=None, old=None, new=None, using=None, format=None):
 
1976
        from bzrlib.diff import (get_trees_and_branches_to_diff_locked,
 
1977
            show_diff_trees)
1891
1978
 
1892
1979
        if (prefix is None) or (prefix == '0'):
1893
1980
            # diff -p0 format
1907
1994
            raise errors.BzrCommandError('bzr diff --revision takes exactly'
1908
1995
                                         ' one or two revision specifiers')
1909
1996
 
1910
 
        old_tree, new_tree, specific_files, extra_trees = \
1911
 
                _get_trees_to_diff(file_list, revision, old, new,
1912
 
                apply_view=True)
 
1997
        if using is not None and format is not None:
 
1998
            raise errors.BzrCommandError('--using and --format are mutually '
 
1999
                'exclusive.')
 
2000
 
 
2001
        (old_tree, new_tree,
 
2002
         old_branch, new_branch,
 
2003
         specific_files, extra_trees) = get_trees_and_branches_to_diff_locked(
 
2004
            file_list, revision, old, new, self.add_cleanup, apply_view=True)
 
2005
        # GNU diff on Windows uses ANSI encoding for filenames
 
2006
        path_encoding = osutils.get_diff_header_encoding()
1913
2007
        return show_diff_trees(old_tree, new_tree, sys.stdout,
1914
2008
                               specific_files=specific_files,
1915
2009
                               external_diff_options=diff_options,
1916
2010
                               old_label=old_label, new_label=new_label,
1917
 
                               extra_trees=extra_trees, using=using)
 
2011
                               extra_trees=extra_trees,
 
2012
                               path_encoding=path_encoding,
 
2013
                               using=using,
 
2014
                               format_cls=format)
1918
2015
 
1919
2016
 
1920
2017
class cmd_deleted(Command):
1921
 
    """List files deleted in the working tree.
 
2018
    __doc__ = """List files deleted in the working tree.
1922
2019
    """
1923
2020
    # TODO: Show files deleted since a previous revision, or
1924
2021
    # between two revisions.
1927
2024
    # level of effort but possibly much less IO.  (Or possibly not,
1928
2025
    # if the directories are very large...)
1929
2026
    _see_also = ['status', 'ls']
1930
 
    takes_options = ['show-ids']
 
2027
    takes_options = ['directory', 'show-ids']
1931
2028
 
1932
2029
    @display_command
1933
 
    def run(self, show_ids=False):
1934
 
        tree = WorkingTree.open_containing(u'.')[0]
1935
 
        tree.lock_read()
1936
 
        try:
1937
 
            old = tree.basis_tree()
1938
 
            old.lock_read()
1939
 
            try:
1940
 
                for path, ie in old.inventory.iter_entries():
1941
 
                    if not tree.has_id(ie.file_id):
1942
 
                        self.outf.write(path)
1943
 
                        if show_ids:
1944
 
                            self.outf.write(' ')
1945
 
                            self.outf.write(ie.file_id)
1946
 
                        self.outf.write('\n')
1947
 
            finally:
1948
 
                old.unlock()
1949
 
        finally:
1950
 
            tree.unlock()
 
2030
    def run(self, show_ids=False, directory=u'.'):
 
2031
        tree = WorkingTree.open_containing(directory)[0]
 
2032
        self.add_cleanup(tree.lock_read().unlock)
 
2033
        old = tree.basis_tree()
 
2034
        self.add_cleanup(old.lock_read().unlock)
 
2035
        for path, ie in old.inventory.iter_entries():
 
2036
            if not tree.has_id(ie.file_id):
 
2037
                self.outf.write(path)
 
2038
                if show_ids:
 
2039
                    self.outf.write(' ')
 
2040
                    self.outf.write(ie.file_id)
 
2041
                self.outf.write('\n')
1951
2042
 
1952
2043
 
1953
2044
class cmd_modified(Command):
1954
 
    """List files modified in working tree.
 
2045
    __doc__ = """List files modified in working tree.
1955
2046
    """
1956
2047
 
1957
2048
    hidden = True
1958
2049
    _see_also = ['status', 'ls']
1959
 
    takes_options = [
1960
 
            Option('null',
1961
 
                   help='Write an ascii NUL (\\0) separator '
1962
 
                   'between files rather than a newline.')
1963
 
            ]
 
2050
    takes_options = ['directory', 'null']
1964
2051
 
1965
2052
    @display_command
1966
 
    def run(self, null=False):
1967
 
        tree = WorkingTree.open_containing(u'.')[0]
 
2053
    def run(self, null=False, directory=u'.'):
 
2054
        tree = WorkingTree.open_containing(directory)[0]
1968
2055
        td = tree.changes_from(tree.basis_tree())
1969
2056
        for path, id, kind, text_modified, meta_modified in td.modified:
1970
2057
            if null:
1974
2061
 
1975
2062
 
1976
2063
class cmd_added(Command):
1977
 
    """List files added in working tree.
 
2064
    __doc__ = """List files added in working tree.
1978
2065
    """
1979
2066
 
1980
2067
    hidden = True
1981
2068
    _see_also = ['status', 'ls']
1982
 
    takes_options = [
1983
 
            Option('null',
1984
 
                   help='Write an ascii NUL (\\0) separator '
1985
 
                   'between files rather than a newline.')
1986
 
            ]
 
2069
    takes_options = ['directory', 'null']
1987
2070
 
1988
2071
    @display_command
1989
 
    def run(self, null=False):
1990
 
        wt = WorkingTree.open_containing(u'.')[0]
1991
 
        wt.lock_read()
1992
 
        try:
1993
 
            basis = wt.basis_tree()
1994
 
            basis.lock_read()
1995
 
            try:
1996
 
                basis_inv = basis.inventory
1997
 
                inv = wt.inventory
1998
 
                for file_id in inv:
1999
 
                    if file_id in basis_inv:
2000
 
                        continue
2001
 
                    if inv.is_root(file_id) and len(basis_inv) == 0:
2002
 
                        continue
2003
 
                    path = inv.id2path(file_id)
2004
 
                    if not os.access(osutils.abspath(path), os.F_OK):
2005
 
                        continue
2006
 
                    if null:
2007
 
                        self.outf.write(path + '\0')
2008
 
                    else:
2009
 
                        self.outf.write(osutils.quotefn(path) + '\n')
2010
 
            finally:
2011
 
                basis.unlock()
2012
 
        finally:
2013
 
            wt.unlock()
 
2072
    def run(self, null=False, directory=u'.'):
 
2073
        wt = WorkingTree.open_containing(directory)[0]
 
2074
        self.add_cleanup(wt.lock_read().unlock)
 
2075
        basis = wt.basis_tree()
 
2076
        self.add_cleanup(basis.lock_read().unlock)
 
2077
        basis_inv = basis.inventory
 
2078
        inv = wt.inventory
 
2079
        for file_id in inv:
 
2080
            if file_id in basis_inv:
 
2081
                continue
 
2082
            if inv.is_root(file_id) and len(basis_inv) == 0:
 
2083
                continue
 
2084
            path = inv.id2path(file_id)
 
2085
            if not os.access(osutils.pathjoin(wt.basedir, path), os.F_OK):
 
2086
                continue
 
2087
            if null:
 
2088
                self.outf.write(path + '\0')
 
2089
            else:
 
2090
                self.outf.write(osutils.quotefn(path) + '\n')
2014
2091
 
2015
2092
 
2016
2093
class cmd_root(Command):
2017
 
    """Show the tree root directory.
 
2094
    __doc__ = """Show the tree root directory.
2018
2095
 
2019
2096
    The root is the nearest enclosing directory with a .bzr control
2020
2097
    directory."""
2044
2121
 
2045
2122
 
2046
2123
class cmd_log(Command):
2047
 
    """Show historical log for a branch or subset of a branch.
 
2124
    __doc__ = """Show historical log for a branch or subset of a branch.
2048
2125
 
2049
2126
    log is bzr's default tool for exploring the history of a branch.
2050
2127
    The branch to use is taken from the first parameter. If no parameters
2161
2238
    :Tips & tricks:
2162
2239
 
2163
2240
      GUI tools and IDEs are often better at exploring history than command
2164
 
      line tools. You may prefer qlog or glog from the QBzr and Bzr-Gtk packages
2165
 
      respectively for example. (TortoiseBzr uses qlog for displaying logs.) See
2166
 
      http://bazaar-vcs.org/BzrPlugins and http://bazaar-vcs.org/IDEIntegration.
2167
 
 
2168
 
      Web interfaces are often better at exploring history than command line
2169
 
      tools, particularly for branches on servers. You may prefer Loggerhead
2170
 
      or one of its alternatives. See http://bazaar-vcs.org/WebInterface.
 
2241
      line tools: you may prefer qlog or viz from qbzr or bzr-gtk, the
 
2242
      bzr-explorer shell, or the Loggerhead web interface.  See the Plugin
 
2243
      Guide <http://doc.bazaar.canonical.com/plugins/en/> and
 
2244
      <http://wiki.bazaar.canonical.com/IDEIntegration>.  
2171
2245
 
2172
2246
      You may find it useful to add the aliases below to ``bazaar.conf``::
2173
2247
 
2214
2288
                   help='Show just the specified revision.'
2215
2289
                   ' See also "help revisionspec".'),
2216
2290
            'log-format',
 
2291
            RegistryOption('authors',
 
2292
                'What names to list as authors - first, all or committer.',
 
2293
                title='Authors',
 
2294
                lazy_registry=('bzrlib.log', 'author_list_registry'),
 
2295
            ),
2217
2296
            Option('levels',
2218
2297
                   short_name='n',
2219
2298
                   help='Number of levels to display - 0 for all, 1 for flat.',
2234
2313
                   help='Show changes made in each revision as a patch.'),
2235
2314
            Option('include-merges',
2236
2315
                   help='Show merged revisions like --levels 0 does.'),
 
2316
            Option('exclude-common-ancestry',
 
2317
                   help='Display only the revisions that are not part'
 
2318
                   ' of both ancestries (require -rX..Y)'
 
2319
                   )
2237
2320
            ]
2238
2321
    encoding_type = 'replace'
2239
2322
 
2249
2332
            message=None,
2250
2333
            limit=None,
2251
2334
            show_diff=False,
2252
 
            include_merges=False):
 
2335
            include_merges=False,
 
2336
            authors=None,
 
2337
            exclude_common_ancestry=False,
 
2338
            ):
2253
2339
        from bzrlib.log import (
2254
2340
            Logger,
2255
2341
            make_log_request_dict,
2256
2342
            _get_info_for_log_files,
2257
2343
            )
2258
2344
        direction = (forward and 'forward') or 'reverse'
 
2345
        if (exclude_common_ancestry
 
2346
            and (revision is None or len(revision) != 2)):
 
2347
            raise errors.BzrCommandError(
 
2348
                '--exclude-common-ancestry requires -r with two revisions')
2259
2349
        if include_merges:
2260
2350
            if levels is None:
2261
2351
                levels = 0
2276
2366
        filter_by_dir = False
2277
2367
        if file_list:
2278
2368
            # find the file ids to log and check for directory filtering
2279
 
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(revision,
2280
 
                file_list)
 
2369
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(
 
2370
                revision, file_list, self.add_cleanup)
2281
2371
            for relpath, file_id, kind in file_info_list:
2282
2372
                if file_id is None:
2283
2373
                    raise errors.BzrCommandError(
2301
2391
                location = '.'
2302
2392
            dir, relpath = bzrdir.BzrDir.open_containing(location)
2303
2393
            b = dir.open_branch()
 
2394
            self.add_cleanup(b.lock_read().unlock)
2304
2395
            rev1, rev2 = _get_revision_range(revision, b, self.name())
2305
2396
 
2306
2397
        # Decide on the type of delta & diff filtering to use
2316
2407
        else:
2317
2408
            diff_type = 'full'
2318
2409
 
2319
 
        b.lock_read()
2320
 
        try:
2321
 
            # Build the log formatter
2322
 
            if log_format is None:
2323
 
                log_format = log.log_formatter_registry.get_default(b)
2324
 
            lf = log_format(show_ids=show_ids, to_file=self.outf,
2325
 
                            show_timezone=timezone,
2326
 
                            delta_format=get_verbosity_level(),
2327
 
                            levels=levels,
2328
 
                            show_advice=levels is None)
2329
 
 
2330
 
            # Choose the algorithm for doing the logging. It's annoying
2331
 
            # having multiple code paths like this but necessary until
2332
 
            # the underlying repository format is faster at generating
2333
 
            # deltas or can provide everything we need from the indices.
2334
 
            # The default algorithm - match-using-deltas - works for
2335
 
            # multiple files and directories and is faster for small
2336
 
            # amounts of history (200 revisions say). However, it's too
2337
 
            # slow for logging a single file in a repository with deep
2338
 
            # history, i.e. > 10K revisions. In the spirit of "do no
2339
 
            # evil when adding features", we continue to use the
2340
 
            # original algorithm - per-file-graph - for the "single
2341
 
            # file that isn't a directory without showing a delta" case.
2342
 
            partial_history = revision and b.repository._format.supports_chks
2343
 
            match_using_deltas = (len(file_ids) != 1 or filter_by_dir
2344
 
                or delta_type or partial_history)
2345
 
 
2346
 
            # Build the LogRequest and execute it
2347
 
            if len(file_ids) == 0:
2348
 
                file_ids = None
2349
 
            rqst = make_log_request_dict(
2350
 
                direction=direction, specific_fileids=file_ids,
2351
 
                start_revision=rev1, end_revision=rev2, limit=limit,
2352
 
                message_search=message, delta_type=delta_type,
2353
 
                diff_type=diff_type, _match_using_deltas=match_using_deltas)
2354
 
            Logger(b, rqst).show(lf)
2355
 
        finally:
2356
 
            b.unlock()
 
2410
        # Build the log formatter
 
2411
        if log_format is None:
 
2412
            log_format = log.log_formatter_registry.get_default(b)
 
2413
        # Make a non-encoding output to include the diffs - bug 328007
 
2414
        unencoded_output = ui.ui_factory.make_output_stream(encoding_type='exact')
 
2415
        lf = log_format(show_ids=show_ids, to_file=self.outf,
 
2416
                        to_exact_file=unencoded_output,
 
2417
                        show_timezone=timezone,
 
2418
                        delta_format=get_verbosity_level(),
 
2419
                        levels=levels,
 
2420
                        show_advice=levels is None,
 
2421
                        author_list_handler=authors)
 
2422
 
 
2423
        # Choose the algorithm for doing the logging. It's annoying
 
2424
        # having multiple code paths like this but necessary until
 
2425
        # the underlying repository format is faster at generating
 
2426
        # deltas or can provide everything we need from the indices.
 
2427
        # The default algorithm - match-using-deltas - works for
 
2428
        # multiple files and directories and is faster for small
 
2429
        # amounts of history (200 revisions say). However, it's too
 
2430
        # slow for logging a single file in a repository with deep
 
2431
        # history, i.e. > 10K revisions. In the spirit of "do no
 
2432
        # evil when adding features", we continue to use the
 
2433
        # original algorithm - per-file-graph - for the "single
 
2434
        # file that isn't a directory without showing a delta" case.
 
2435
        partial_history = revision and b.repository._format.supports_chks
 
2436
        match_using_deltas = (len(file_ids) != 1 or filter_by_dir
 
2437
            or delta_type or partial_history)
 
2438
 
 
2439
        # Build the LogRequest and execute it
 
2440
        if len(file_ids) == 0:
 
2441
            file_ids = None
 
2442
        rqst = make_log_request_dict(
 
2443
            direction=direction, specific_fileids=file_ids,
 
2444
            start_revision=rev1, end_revision=rev2, limit=limit,
 
2445
            message_search=message, delta_type=delta_type,
 
2446
            diff_type=diff_type, _match_using_deltas=match_using_deltas,
 
2447
            exclude_common_ancestry=exclude_common_ancestry,
 
2448
            )
 
2449
        Logger(b, rqst).show(lf)
2357
2450
 
2358
2451
 
2359
2452
def _get_revision_range(revisionspec_list, branch, command_name):
2377
2470
            raise errors.BzrCommandError(
2378
2471
                "bzr %s doesn't accept two revisions in different"
2379
2472
                " branches." % command_name)
2380
 
        rev1 = start_spec.in_history(branch)
 
2473
        if start_spec.spec is None:
 
2474
            # Avoid loading all the history.
 
2475
            rev1 = RevisionInfo(branch, None, None)
 
2476
        else:
 
2477
            rev1 = start_spec.in_history(branch)
2381
2478
        # Avoid loading all of history when we know a missing
2382
2479
        # end of range means the last revision ...
2383
2480
        if end_spec.spec is None:
2412
2509
 
2413
2510
 
2414
2511
class cmd_touching_revisions(Command):
2415
 
    """Return revision-ids which affected a particular file.
 
2512
    __doc__ = """Return revision-ids which affected a particular file.
2416
2513
 
2417
2514
    A more user-friendly interface is "bzr log FILE".
2418
2515
    """
2423
2520
    @display_command
2424
2521
    def run(self, filename):
2425
2522
        tree, relpath = WorkingTree.open_containing(filename)
 
2523
        file_id = tree.path2id(relpath)
2426
2524
        b = tree.branch
2427
 
        file_id = tree.path2id(relpath)
2428
 
        for revno, revision_id, what in log.find_touching_revisions(b, file_id):
 
2525
        self.add_cleanup(b.lock_read().unlock)
 
2526
        touching_revs = log.find_touching_revisions(b, file_id)
 
2527
        for revno, revision_id, what in touching_revs:
2429
2528
            self.outf.write("%6d %s\n" % (revno, what))
2430
2529
 
2431
2530
 
2432
2531
class cmd_ls(Command):
2433
 
    """List files in a tree.
 
2532
    __doc__ = """List files in a tree.
2434
2533
    """
2435
2534
 
2436
2535
    _see_also = ['status', 'cat']
2442
2541
                   help='Recurse into subdirectories.'),
2443
2542
            Option('from-root',
2444
2543
                   help='Print paths relative to the root of the branch.'),
2445
 
            Option('unknown', help='Print unknown files.'),
 
2544
            Option('unknown', short_name='u',
 
2545
                help='Print unknown files.'),
2446
2546
            Option('versioned', help='Print versioned files.',
2447
2547
                   short_name='V'),
2448
 
            Option('ignored', help='Print ignored files.'),
2449
 
            Option('null',
2450
 
                   help='Write an ascii NUL (\\0) separator '
2451
 
                   'between files rather than a newline.'),
2452
 
            Option('kind',
 
2548
            Option('ignored', short_name='i',
 
2549
                help='Print ignored files.'),
 
2550
            Option('kind', short_name='k',
2453
2551
                   help='List entries of a particular kind: file, directory, symlink.',
2454
2552
                   type=unicode),
 
2553
            'null',
2455
2554
            'show-ids',
 
2555
            'directory',
2456
2556
            ]
2457
2557
    @display_command
2458
2558
    def run(self, revision=None, verbose=False,
2459
2559
            recursive=False, from_root=False,
2460
2560
            unknown=False, versioned=False, ignored=False,
2461
 
            null=False, kind=None, show_ids=False, path=None):
 
2561
            null=False, kind=None, show_ids=False, path=None, directory=None):
2462
2562
 
2463
2563
        if kind and kind not in ('file', 'directory', 'symlink'):
2464
2564
            raise errors.BzrCommandError('invalid kind specified')
2476
2576
                raise errors.BzrCommandError('cannot specify both --from-root'
2477
2577
                                             ' and PATH')
2478
2578
            fs_path = path
2479
 
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
2480
 
            fs_path)
 
2579
        tree, branch, relpath = \
 
2580
            _open_directory_or_containing_tree_or_branch(fs_path, directory)
2481
2581
 
2482
2582
        # Calculate the prefix to use
2483
2583
        prefix = None
2484
2584
        if from_root:
2485
2585
            if relpath:
2486
2586
                prefix = relpath + '/'
2487
 
        elif fs_path != '.':
 
2587
        elif fs_path != '.' and not fs_path.endswith('/'):
2488
2588
            prefix = fs_path + '/'
2489
2589
 
2490
2590
        if revision is not None or tree is None:
2498
2598
                view_str = views.view_display_str(view_files)
2499
2599
                note("Ignoring files outside view. View is %s" % view_str)
2500
2600
 
2501
 
        tree.lock_read()
2502
 
        try:
2503
 
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
2504
 
                from_dir=relpath, recursive=recursive):
2505
 
                # Apply additional masking
2506
 
                if not all and not selection[fc]:
2507
 
                    continue
2508
 
                if kind is not None and fkind != kind:
2509
 
                    continue
2510
 
                if apply_view:
2511
 
                    try:
2512
 
                        if relpath:
2513
 
                            fullpath = osutils.pathjoin(relpath, fp)
2514
 
                        else:
2515
 
                            fullpath = fp
2516
 
                        views.check_path_in_view(tree, fullpath)
2517
 
                    except errors.FileOutsideView:
2518
 
                        continue
 
2601
        self.add_cleanup(tree.lock_read().unlock)
 
2602
        for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
 
2603
            from_dir=relpath, recursive=recursive):
 
2604
            # Apply additional masking
 
2605
            if not all and not selection[fc]:
 
2606
                continue
 
2607
            if kind is not None and fkind != kind:
 
2608
                continue
 
2609
            if apply_view:
 
2610
                try:
 
2611
                    if relpath:
 
2612
                        fullpath = osutils.pathjoin(relpath, fp)
 
2613
                    else:
 
2614
                        fullpath = fp
 
2615
                    views.check_path_in_view(tree, fullpath)
 
2616
                except errors.FileOutsideView:
 
2617
                    continue
2519
2618
 
2520
 
                # Output the entry
2521
 
                if prefix:
2522
 
                    fp = osutils.pathjoin(prefix, fp)
2523
 
                kindch = entry.kind_character()
2524
 
                outstring = fp + kindch
2525
 
                ui.ui_factory.clear_term()
2526
 
                if verbose:
2527
 
                    outstring = '%-8s %s' % (fc, outstring)
2528
 
                    if show_ids and fid is not None:
2529
 
                        outstring = "%-50s %s" % (outstring, fid)
 
2619
            # Output the entry
 
2620
            if prefix:
 
2621
                fp = osutils.pathjoin(prefix, fp)
 
2622
            kindch = entry.kind_character()
 
2623
            outstring = fp + kindch
 
2624
            ui.ui_factory.clear_term()
 
2625
            if verbose:
 
2626
                outstring = '%-8s %s' % (fc, outstring)
 
2627
                if show_ids and fid is not None:
 
2628
                    outstring = "%-50s %s" % (outstring, fid)
 
2629
                self.outf.write(outstring + '\n')
 
2630
            elif null:
 
2631
                self.outf.write(fp + '\0')
 
2632
                if show_ids:
 
2633
                    if fid is not None:
 
2634
                        self.outf.write(fid)
 
2635
                    self.outf.write('\0')
 
2636
                self.outf.flush()
 
2637
            else:
 
2638
                if show_ids:
 
2639
                    if fid is not None:
 
2640
                        my_id = fid
 
2641
                    else:
 
2642
                        my_id = ''
 
2643
                    self.outf.write('%-50s %s\n' % (outstring, my_id))
 
2644
                else:
2530
2645
                    self.outf.write(outstring + '\n')
2531
 
                elif null:
2532
 
                    self.outf.write(fp + '\0')
2533
 
                    if show_ids:
2534
 
                        if fid is not None:
2535
 
                            self.outf.write(fid)
2536
 
                        self.outf.write('\0')
2537
 
                    self.outf.flush()
2538
 
                else:
2539
 
                    if show_ids:
2540
 
                        if fid is not None:
2541
 
                            my_id = fid
2542
 
                        else:
2543
 
                            my_id = ''
2544
 
                        self.outf.write('%-50s %s\n' % (outstring, my_id))
2545
 
                    else:
2546
 
                        self.outf.write(outstring + '\n')
2547
 
        finally:
2548
 
            tree.unlock()
2549
2646
 
2550
2647
 
2551
2648
class cmd_unknowns(Command):
2552
 
    """List unknown files.
 
2649
    __doc__ = """List unknown files.
2553
2650
    """
2554
2651
 
2555
2652
    hidden = True
2556
2653
    _see_also = ['ls']
 
2654
    takes_options = ['directory']
2557
2655
 
2558
2656
    @display_command
2559
 
    def run(self):
2560
 
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
 
2657
    def run(self, directory=u'.'):
 
2658
        for f in WorkingTree.open_containing(directory)[0].unknowns():
2561
2659
            self.outf.write(osutils.quotefn(f) + '\n')
2562
2660
 
2563
2661
 
2564
2662
class cmd_ignore(Command):
2565
 
    """Ignore specified files or patterns.
 
2663
    __doc__ = """Ignore specified files or patterns.
2566
2664
 
2567
2665
    See ``bzr help patterns`` for details on the syntax of patterns.
2568
2666
 
 
2667
    If a .bzrignore file does not exist, the ignore command
 
2668
    will create one and add the specified files or patterns to the newly
 
2669
    created file. The ignore command will also automatically add the 
 
2670
    .bzrignore file to be versioned. Creating a .bzrignore file without
 
2671
    the use of the ignore command will require an explicit add command.
 
2672
 
2569
2673
    To remove patterns from the ignore list, edit the .bzrignore file.
2570
2674
    After adding, editing or deleting that file either indirectly by
2571
2675
    using this command or directly by using an editor, be sure to commit
2572
2676
    it.
2573
 
 
2574
 
    Note: ignore patterns containing shell wildcards must be quoted from
2575
 
    the shell on Unix.
 
2677
    
 
2678
    Bazaar also supports a global ignore file ~/.bazaar/ignore. On Windows
 
2679
    the global ignore file can be found in the application data directory as
 
2680
    C:\\Documents and Settings\\<user>\\Application Data\\Bazaar\\2.0\\ignore.
 
2681
    Global ignores are not touched by this command. The global ignore file
 
2682
    can be edited directly using an editor.
 
2683
 
 
2684
    Patterns prefixed with '!' are exceptions to ignore patterns and take
 
2685
    precedence over regular ignores.  Such exceptions are used to specify
 
2686
    files that should be versioned which would otherwise be ignored.
 
2687
    
 
2688
    Patterns prefixed with '!!' act as regular ignore patterns, but have
 
2689
    precedence over the '!' exception patterns.
 
2690
 
 
2691
    :Notes: 
 
2692
        
 
2693
    * Ignore patterns containing shell wildcards must be quoted from
 
2694
      the shell on Unix.
 
2695
 
 
2696
    * Ignore patterns starting with "#" act as comments in the ignore file.
 
2697
      To ignore patterns that begin with that character, use the "RE:" prefix.
2576
2698
 
2577
2699
    :Examples:
2578
2700
        Ignore the top level Makefile::
2579
2701
 
2580
2702
            bzr ignore ./Makefile
2581
2703
 
2582
 
        Ignore class files in all directories::
 
2704
        Ignore .class files in all directories...::
2583
2705
 
2584
2706
            bzr ignore "*.class"
2585
2707
 
 
2708
        ...but do not ignore "special.class"::
 
2709
 
 
2710
            bzr ignore "!special.class"
 
2711
 
 
2712
        Ignore files whose name begins with the "#" character::
 
2713
 
 
2714
            bzr ignore "RE:^#"
 
2715
 
2586
2716
        Ignore .o files under the lib directory::
2587
2717
 
2588
2718
            bzr ignore "lib/**/*.o"
2594
2724
        Ignore everything but the "debian" toplevel directory::
2595
2725
 
2596
2726
            bzr ignore "RE:(?!debian/).*"
 
2727
        
 
2728
        Ignore everything except the "local" toplevel directory,
 
2729
        but always ignore "*~" autosave files, even under local/::
 
2730
        
 
2731
            bzr ignore "*"
 
2732
            bzr ignore "!./local"
 
2733
            bzr ignore "!!*~"
2597
2734
    """
2598
2735
 
2599
2736
    _see_also = ['status', 'ignored', 'patterns']
2600
2737
    takes_args = ['name_pattern*']
2601
 
    takes_options = [
2602
 
        Option('old-default-rules',
2603
 
               help='Write out the ignore rules bzr < 0.9 always used.')
 
2738
    takes_options = ['directory',
 
2739
        Option('default-rules',
 
2740
               help='Display the default ignore rules that bzr uses.')
2604
2741
        ]
2605
2742
 
2606
 
    def run(self, name_pattern_list=None, old_default_rules=None):
 
2743
    def run(self, name_pattern_list=None, default_rules=None,
 
2744
            directory=u'.'):
2607
2745
        from bzrlib import ignores
2608
 
        if old_default_rules is not None:
2609
 
            # dump the rules and exit
2610
 
            for pattern in ignores.OLD_DEFAULTS:
2611
 
                print pattern
 
2746
        if default_rules is not None:
 
2747
            # dump the default rules and exit
 
2748
            for pattern in ignores.USER_DEFAULTS:
 
2749
                self.outf.write("%s\n" % pattern)
2612
2750
            return
2613
2751
        if not name_pattern_list:
2614
2752
            raise errors.BzrCommandError("ignore requires at least one "
2615
 
                                  "NAME_PATTERN or --old-default-rules")
 
2753
                "NAME_PATTERN or --default-rules.")
2616
2754
        name_pattern_list = [globbing.normalize_pattern(p)
2617
2755
                             for p in name_pattern_list]
 
2756
        bad_patterns = ''
 
2757
        for p in name_pattern_list:
 
2758
            if not globbing.Globster.is_pattern_valid(p):
 
2759
                bad_patterns += ('\n  %s' % p)
 
2760
        if bad_patterns:
 
2761
            msg = ('Invalid ignore pattern(s) found. %s' % bad_patterns)
 
2762
            ui.ui_factory.show_error(msg)
 
2763
            raise errors.InvalidPattern('')
2618
2764
        for name_pattern in name_pattern_list:
2619
2765
            if (name_pattern[0] == '/' or
2620
2766
                (len(name_pattern) > 1 and name_pattern[1] == ':')):
2621
2767
                raise errors.BzrCommandError(
2622
2768
                    "NAME_PATTERN should not be an absolute path")
2623
 
        tree, relpath = WorkingTree.open_containing(u'.')
 
2769
        tree, relpath = WorkingTree.open_containing(directory)
2624
2770
        ignores.tree_ignores_add_patterns(tree, name_pattern_list)
2625
2771
        ignored = globbing.Globster(name_pattern_list)
2626
2772
        matches = []
2627
 
        tree.lock_read()
 
2773
        self.add_cleanup(tree.lock_read().unlock)
2628
2774
        for entry in tree.list_files():
2629
2775
            id = entry[3]
2630
2776
            if id is not None:
2631
2777
                filename = entry[0]
2632
2778
                if ignored.match(filename):
2633
 
                    matches.append(filename.encode('utf-8'))
2634
 
        tree.unlock()
 
2779
                    matches.append(filename)
2635
2780
        if len(matches) > 0:
2636
 
            print "Warning: the following files are version controlled and" \
2637
 
                  " match your ignore pattern:\n%s" \
2638
 
                  "\nThese files will continue to be version controlled" \
2639
 
                  " unless you 'bzr remove' them." % ("\n".join(matches),)
 
2781
            self.outf.write("Warning: the following files are version controlled and"
 
2782
                  " match your ignore pattern:\n%s"
 
2783
                  "\nThese files will continue to be version controlled"
 
2784
                  " unless you 'bzr remove' them.\n" % ("\n".join(matches),))
2640
2785
 
2641
2786
 
2642
2787
class cmd_ignored(Command):
2643
 
    """List ignored files and the patterns that matched them.
 
2788
    __doc__ = """List ignored files and the patterns that matched them.
2644
2789
 
2645
2790
    List all the ignored files and the ignore pattern that caused the file to
2646
2791
    be ignored.
2652
2797
 
2653
2798
    encoding_type = 'replace'
2654
2799
    _see_also = ['ignore', 'ls']
 
2800
    takes_options = ['directory']
2655
2801
 
2656
2802
    @display_command
2657
 
    def run(self):
2658
 
        tree = WorkingTree.open_containing(u'.')[0]
2659
 
        tree.lock_read()
2660
 
        try:
2661
 
            for path, file_class, kind, file_id, entry in tree.list_files():
2662
 
                if file_class != 'I':
2663
 
                    continue
2664
 
                ## XXX: Slightly inefficient since this was already calculated
2665
 
                pat = tree.is_ignored(path)
2666
 
                self.outf.write('%-50s %s\n' % (path, pat))
2667
 
        finally:
2668
 
            tree.unlock()
 
2803
    def run(self, directory=u'.'):
 
2804
        tree = WorkingTree.open_containing(directory)[0]
 
2805
        self.add_cleanup(tree.lock_read().unlock)
 
2806
        for path, file_class, kind, file_id, entry in tree.list_files():
 
2807
            if file_class != 'I':
 
2808
                continue
 
2809
            ## XXX: Slightly inefficient since this was already calculated
 
2810
            pat = tree.is_ignored(path)
 
2811
            self.outf.write('%-50s %s\n' % (path, pat))
2669
2812
 
2670
2813
 
2671
2814
class cmd_lookup_revision(Command):
2672
 
    """Lookup the revision-id from a revision-number
 
2815
    __doc__ = """Lookup the revision-id from a revision-number
2673
2816
 
2674
2817
    :Examples:
2675
2818
        bzr lookup-revision 33
2676
2819
    """
2677
2820
    hidden = True
2678
2821
    takes_args = ['revno']
 
2822
    takes_options = ['directory']
2679
2823
 
2680
2824
    @display_command
2681
 
    def run(self, revno):
 
2825
    def run(self, revno, directory=u'.'):
2682
2826
        try:
2683
2827
            revno = int(revno)
2684
2828
        except ValueError:
2685
 
            raise errors.BzrCommandError("not a valid revision-number: %r" % revno)
2686
 
 
2687
 
        print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
 
2829
            raise errors.BzrCommandError("not a valid revision-number: %r"
 
2830
                                         % revno)
 
2831
        revid = WorkingTree.open_containing(directory)[0].branch.get_rev_id(revno)
 
2832
        self.outf.write("%s\n" % revid)
2688
2833
 
2689
2834
 
2690
2835
class cmd_export(Command):
2691
 
    """Export current or past revision to a destination directory or archive.
 
2836
    __doc__ = """Export current or past revision to a destination directory or archive.
2692
2837
 
2693
2838
    If no revision is specified this exports the last committed revision.
2694
2839
 
2716
2861
      =================       =========================
2717
2862
    """
2718
2863
    takes_args = ['dest', 'branch_or_subdir?']
2719
 
    takes_options = [
 
2864
    takes_options = ['directory',
2720
2865
        Option('format',
2721
2866
               help="Type of file to export to.",
2722
2867
               type=unicode),
2726
2871
        Option('root',
2727
2872
               type=str,
2728
2873
               help="Name of the root directory inside the exported file."),
 
2874
        Option('per-file-timestamps',
 
2875
               help='Set modification time of files to that of the last '
 
2876
                    'revision in which it was changed.'),
2729
2877
        ]
2730
2878
    def run(self, dest, branch_or_subdir=None, revision=None, format=None,
2731
 
        root=None, filters=False):
 
2879
        root=None, filters=False, per_file_timestamps=False, directory=u'.'):
2732
2880
        from bzrlib.export import export
2733
2881
 
2734
2882
        if branch_or_subdir is None:
2735
 
            tree = WorkingTree.open_containing(u'.')[0]
 
2883
            tree = WorkingTree.open_containing(directory)[0]
2736
2884
            b = tree.branch
2737
2885
            subdir = None
2738
2886
        else:
2741
2889
 
2742
2890
        rev_tree = _get_one_revision_tree('export', revision, branch=b, tree=tree)
2743
2891
        try:
2744
 
            export(rev_tree, dest, format, root, subdir, filtered=filters)
 
2892
            export(rev_tree, dest, format, root, subdir, filtered=filters,
 
2893
                   per_file_timestamps=per_file_timestamps)
2745
2894
        except errors.NoSuchExportFormat, e:
2746
2895
            raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
2747
2896
 
2748
2897
 
2749
2898
class cmd_cat(Command):
2750
 
    """Write the contents of a file as of a given revision to standard output.
 
2899
    __doc__ = """Write the contents of a file as of a given revision to standard output.
2751
2900
 
2752
2901
    If no revision is nominated, the last revision is used.
2753
2902
 
2756
2905
    """
2757
2906
 
2758
2907
    _see_also = ['ls']
2759
 
    takes_options = [
 
2908
    takes_options = ['directory',
2760
2909
        Option('name-from-revision', help='The path name in the old tree.'),
2761
2910
        Option('filters', help='Apply content filters to display the '
2762
2911
                'convenience form.'),
2767
2916
 
2768
2917
    @display_command
2769
2918
    def run(self, filename, revision=None, name_from_revision=False,
2770
 
            filters=False):
 
2919
            filters=False, directory=None):
2771
2920
        if revision is not None and len(revision) != 1:
2772
2921
            raise errors.BzrCommandError("bzr cat --revision takes exactly"
2773
2922
                                         " one revision specifier")
2774
2923
        tree, branch, relpath = \
2775
 
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2776
 
        branch.lock_read()
2777
 
        try:
2778
 
            return self._run(tree, branch, relpath, filename, revision,
2779
 
                             name_from_revision, filters)
2780
 
        finally:
2781
 
            branch.unlock()
 
2924
            _open_directory_or_containing_tree_or_branch(filename, directory)
 
2925
        self.add_cleanup(branch.lock_read().unlock)
 
2926
        return self._run(tree, branch, relpath, filename, revision,
 
2927
                         name_from_revision, filters)
2782
2928
 
2783
2929
    def _run(self, tree, b, relpath, filename, revision, name_from_revision,
2784
2930
        filtered):
2785
2931
        if tree is None:
2786
2932
            tree = b.basis_tree()
2787
2933
        rev_tree = _get_one_revision_tree('cat', revision, branch=b)
 
2934
        self.add_cleanup(rev_tree.lock_read().unlock)
2788
2935
 
2789
2936
        old_file_id = rev_tree.path2id(relpath)
2790
2937
 
2825
2972
            chunks = content.splitlines(True)
2826
2973
            content = filtered_output_bytes(chunks, filters,
2827
2974
                ContentFilterContext(relpath, rev_tree))
 
2975
            self.cleanup_now()
2828
2976
            self.outf.writelines(content)
2829
2977
        else:
 
2978
            self.cleanup_now()
2830
2979
            self.outf.write(content)
2831
2980
 
2832
2981
 
2833
2982
class cmd_local_time_offset(Command):
2834
 
    """Show the offset in seconds from GMT to local time."""
 
2983
    __doc__ = """Show the offset in seconds from GMT to local time."""
2835
2984
    hidden = True
2836
2985
    @display_command
2837
2986
    def run(self):
2838
 
        print osutils.local_time_offset()
 
2987
        self.outf.write("%s\n" % osutils.local_time_offset())
2839
2988
 
2840
2989
 
2841
2990
 
2842
2991
class cmd_commit(Command):
2843
 
    """Commit changes into a new revision.
 
2992
    __doc__ = """Commit changes into a new revision.
2844
2993
 
2845
2994
    An explanatory message needs to be given for each commit. This is
2846
2995
    often done by using the --message option (getting the message from the
2939
3088
             Option('strict',
2940
3089
                    help="Refuse to commit if there are unknown "
2941
3090
                    "files in the working tree."),
 
3091
             Option('commit-time', type=str,
 
3092
                    help="Manually set a commit time using commit date "
 
3093
                    "format, e.g. '2009-10-10 08:00:00 +0100'."),
2942
3094
             ListOption('fixes', type=str,
2943
3095
                    help="Mark a bug as being fixed by this revision "
2944
3096
                         "(see \"bzr help bugs\")."),
2951
3103
                         "the master branch until a normal commit "
2952
3104
                         "is performed."
2953
3105
                    ),
2954
 
              Option('show-diff',
2955
 
                     help='When no message is supplied, show the diff along'
2956
 
                     ' with the status summary in the message editor.'),
 
3106
             Option('show-diff', short_name='p',
 
3107
                    help='When no message is supplied, show the diff along'
 
3108
                    ' with the status summary in the message editor.'),
2957
3109
             ]
2958
3110
    aliases = ['ci', 'checkin']
2959
3111
 
2978
3130
 
2979
3131
    def run(self, message=None, file=None, verbose=False, selected_list=None,
2980
3132
            unchanged=False, strict=False, local=False, fixes=None,
2981
 
            author=None, show_diff=False, exclude=None):
 
3133
            author=None, show_diff=False, exclude=None, commit_time=None):
2982
3134
        from bzrlib.errors import (
2983
3135
            PointlessCommit,
2984
3136
            ConflictsInTree,
2990
3142
            make_commit_message_template_encoded
2991
3143
        )
2992
3144
 
 
3145
        commit_stamp = offset = None
 
3146
        if commit_time is not None:
 
3147
            try:
 
3148
                commit_stamp, offset = timestamp.parse_patch_date(commit_time)
 
3149
            except ValueError, e:
 
3150
                raise errors.BzrCommandError(
 
3151
                    "Could not parse --commit-time: " + str(e))
 
3152
 
2993
3153
        # TODO: Need a blackbox test for invoking the external editor; may be
2994
3154
        # slightly problematic to run this cross-platform.
2995
3155
 
2998
3158
 
2999
3159
        properties = {}
3000
3160
 
3001
 
        tree, selected_list = tree_files(selected_list)
 
3161
        tree, selected_list = WorkingTree.open_containing_paths(selected_list)
3002
3162
        if selected_list == ['']:
3003
3163
            # workaround - commit of root of tree should be exactly the same
3004
3164
            # as just default commit in that tree, and succeed even though
3015
3175
        if local and not tree.branch.get_bound_location():
3016
3176
            raise errors.LocalRequiresBoundBranch()
3017
3177
 
 
3178
        if message is not None:
 
3179
            try:
 
3180
                file_exists = osutils.lexists(message)
 
3181
            except UnicodeError:
 
3182
                # The commit message contains unicode characters that can't be
 
3183
                # represented in the filesystem encoding, so that can't be a
 
3184
                # file.
 
3185
                file_exists = False
 
3186
            if file_exists:
 
3187
                warning_msg = (
 
3188
                    'The commit message is a file name: "%(f)s".\n'
 
3189
                    '(use --file "%(f)s" to take commit message from that file)'
 
3190
                    % { 'f': message })
 
3191
                ui.ui_factory.show_warning(warning_msg)
 
3192
            if '\r' in message:
 
3193
                message = message.replace('\r\n', '\n')
 
3194
                message = message.replace('\r', '\n')
 
3195
            if file:
 
3196
                raise errors.BzrCommandError(
 
3197
                    "please specify either --message or --file")
 
3198
 
3018
3199
        def get_message(commit_obj):
3019
3200
            """Callback to get commit message"""
3020
 
            my_message = message
3021
 
            if my_message is None and not file:
3022
 
                t = make_commit_message_template_encoded(tree,
 
3201
            if file:
 
3202
                f = open(file)
 
3203
                try:
 
3204
                    my_message = f.read().decode(osutils.get_user_encoding())
 
3205
                finally:
 
3206
                    f.close()
 
3207
            elif message is not None:
 
3208
                my_message = message
 
3209
            else:
 
3210
                # No message supplied: make one up.
 
3211
                # text is the status of the tree
 
3212
                text = make_commit_message_template_encoded(tree,
3023
3213
                        selected_list, diff=show_diff,
3024
3214
                        output_encoding=osutils.get_user_encoding())
 
3215
                # start_message is the template generated from hooks
 
3216
                # XXX: Warning - looks like hooks return unicode,
 
3217
                # make_commit_message_template_encoded returns user encoding.
 
3218
                # We probably want to be using edit_commit_message instead to
 
3219
                # avoid this.
3025
3220
                start_message = generate_commit_message_template(commit_obj)
3026
 
                my_message = edit_commit_message_encoded(t,
 
3221
                my_message = edit_commit_message_encoded(text,
3027
3222
                    start_message=start_message)
3028
3223
                if my_message is None:
3029
3224
                    raise errors.BzrCommandError("please specify a commit"
3030
3225
                        " message with either --message or --file")
3031
 
            elif my_message and file:
3032
 
                raise errors.BzrCommandError(
3033
 
                    "please specify either --message or --file")
3034
 
            if file:
3035
 
                my_message = codecs.open(file, 'rt',
3036
 
                                         osutils.get_user_encoding()).read()
3037
3226
            if my_message == "":
3038
3227
                raise errors.BzrCommandError("empty commit message specified")
3039
3228
            return my_message
3047
3236
                        specific_files=selected_list,
3048
3237
                        allow_pointless=unchanged, strict=strict, local=local,
3049
3238
                        reporter=None, verbose=verbose, revprops=properties,
3050
 
                        authors=author,
3051
 
                        exclude=safe_relpath_files(tree, exclude))
 
3239
                        authors=author, timestamp=commit_stamp,
 
3240
                        timezone=offset,
 
3241
                        exclude=tree.safe_relpath_files(exclude))
3052
3242
        except PointlessCommit:
3053
 
            # FIXME: This should really happen before the file is read in;
3054
 
            # perhaps prepare the commit; get the message; then actually commit
3055
3243
            raise errors.BzrCommandError("No changes to commit."
3056
3244
                              " Use --unchanged to commit anyhow.")
3057
3245
        except ConflictsInTree:
3062
3250
            raise errors.BzrCommandError("Commit refused because there are"
3063
3251
                              " unknown files in the working tree.")
3064
3252
        except errors.BoundBranchOutOfDate, e:
3065
 
            raise errors.BzrCommandError(str(e) + "\n"
3066
 
            'To commit to master branch, run update and then commit.\n'
3067
 
            'You can also pass --local to commit to continue working '
3068
 
            'disconnected.')
 
3253
            e.extra_help = ("\n"
 
3254
                'To commit to master branch, run update and then commit.\n'
 
3255
                'You can also pass --local to commit to continue working '
 
3256
                'disconnected.')
 
3257
            raise
3069
3258
 
3070
3259
 
3071
3260
class cmd_check(Command):
3072
 
    """Validate working tree structure, branch consistency and repository history.
 
3261
    __doc__ = """Validate working tree structure, branch consistency and repository history.
3073
3262
 
3074
3263
    This command checks various invariants about branch and repository storage
3075
3264
    to detect data corruption or bzr bugs.
3139
3328
 
3140
3329
 
3141
3330
class cmd_upgrade(Command):
3142
 
    """Upgrade branch storage to current format.
 
3331
    __doc__ = """Upgrade branch storage to current format.
3143
3332
 
3144
3333
    The check command or bzr developers may sometimes advise you to run
3145
3334
    this command. When the default format has changed you may also be warned
3163
3352
 
3164
3353
 
3165
3354
class cmd_whoami(Command):
3166
 
    """Show or set bzr user id.
 
3355
    __doc__ = """Show or set bzr user id.
3167
3356
 
3168
3357
    :Examples:
3169
3358
        Show the email of the current user::
3174
3363
 
3175
3364
            bzr whoami "Frank Chu <fchu@example.com>"
3176
3365
    """
3177
 
    takes_options = [ Option('email',
 
3366
    takes_options = [ 'directory',
 
3367
                      Option('email',
3178
3368
                             help='Display email address only.'),
3179
3369
                      Option('branch',
3180
3370
                             help='Set identity for the current branch instead of '
3184
3374
    encoding_type = 'replace'
3185
3375
 
3186
3376
    @display_command
3187
 
    def run(self, email=False, branch=False, name=None):
 
3377
    def run(self, email=False, branch=False, name=None, directory=None):
3188
3378
        if name is None:
3189
 
            # use branch if we're inside one; otherwise global config
3190
 
            try:
3191
 
                c = Branch.open_containing('.')[0].get_config()
3192
 
            except errors.NotBranchError:
3193
 
                c = config.GlobalConfig()
 
3379
            if directory is None:
 
3380
                # use branch if we're inside one; otherwise global config
 
3381
                try:
 
3382
                    c = Branch.open_containing(u'.')[0].get_config()
 
3383
                except errors.NotBranchError:
 
3384
                    c = _mod_config.GlobalConfig()
 
3385
            else:
 
3386
                c = Branch.open(directory).get_config()
3194
3387
            if email:
3195
3388
                self.outf.write(c.user_email() + '\n')
3196
3389
            else:
3199
3392
 
3200
3393
        # display a warning if an email address isn't included in the given name.
3201
3394
        try:
3202
 
            config.extract_email_address(name)
 
3395
            _mod_config.extract_email_address(name)
3203
3396
        except errors.NoEmailInUsername, e:
3204
3397
            warning('"%s" does not seem to contain an email address.  '
3205
3398
                    'This is allowed, but not recommended.', name)
3206
3399
 
3207
3400
        # use global config unless --branch given
3208
3401
        if branch:
3209
 
            c = Branch.open_containing('.')[0].get_config()
 
3402
            if directory is None:
 
3403
                c = Branch.open_containing(u'.')[0].get_config()
 
3404
            else:
 
3405
                c = Branch.open(directory).get_config()
3210
3406
        else:
3211
 
            c = config.GlobalConfig()
 
3407
            c = _mod_config.GlobalConfig()
3212
3408
        c.set_user_option('email', name)
3213
3409
 
3214
3410
 
3215
3411
class cmd_nick(Command):
3216
 
    """Print or set the branch nickname.
 
3412
    __doc__ = """Print or set the branch nickname.
3217
3413
 
3218
3414
    If unset, the tree root directory name is used as the nickname.
3219
3415
    To print the current nickname, execute with no argument.
3224
3420
 
3225
3421
    _see_also = ['info']
3226
3422
    takes_args = ['nickname?']
3227
 
    def run(self, nickname=None):
3228
 
        branch = Branch.open_containing(u'.')[0]
 
3423
    takes_options = ['directory']
 
3424
    def run(self, nickname=None, directory=u'.'):
 
3425
        branch = Branch.open_containing(directory)[0]
3229
3426
        if nickname is None:
3230
3427
            self.printme(branch)
3231
3428
        else:
3233
3430
 
3234
3431
    @display_command
3235
3432
    def printme(self, branch):
3236
 
        print branch.nick
 
3433
        self.outf.write('%s\n' % branch.nick)
3237
3434
 
3238
3435
 
3239
3436
class cmd_alias(Command):
3240
 
    """Set/unset and display aliases.
 
3437
    __doc__ = """Set/unset and display aliases.
3241
3438
 
3242
3439
    :Examples:
3243
3440
        Show the current aliases::
3280
3477
                'bzr alias --remove expects an alias to remove.')
3281
3478
        # If alias is not found, print something like:
3282
3479
        # unalias: foo: not found
3283
 
        c = config.GlobalConfig()
 
3480
        c = _mod_config.GlobalConfig()
3284
3481
        c.unset_alias(alias_name)
3285
3482
 
3286
3483
    @display_command
3287
3484
    def print_aliases(self):
3288
3485
        """Print out the defined aliases in a similar format to bash."""
3289
 
        aliases = config.GlobalConfig().get_aliases()
 
3486
        aliases = _mod_config.GlobalConfig().get_aliases()
3290
3487
        for key, value in sorted(aliases.iteritems()):
3291
3488
            self.outf.write('bzr alias %s="%s"\n' % (key, value))
3292
3489
 
3302
3499
 
3303
3500
    def set_alias(self, alias_name, alias_command):
3304
3501
        """Save the alias in the global config."""
3305
 
        c = config.GlobalConfig()
 
3502
        c = _mod_config.GlobalConfig()
3306
3503
        c.set_alias(alias_name, alias_command)
3307
3504
 
3308
3505
 
3309
3506
class cmd_selftest(Command):
3310
 
    """Run internal test suite.
 
3507
    __doc__ = """Run internal test suite.
3311
3508
 
3312
3509
    If arguments are given, they are regular expressions that say which tests
3313
3510
    should run.  Tests matching any expression are run, and other tests are
3340
3537
    Tests that need working space on disk use a common temporary directory,
3341
3538
    typically inside $TMPDIR or /tmp.
3342
3539
 
 
3540
    If you set BZR_TEST_PDB=1 when running selftest, failing tests will drop
 
3541
    into a pdb postmortem session.
 
3542
 
 
3543
    The --coverage=DIRNAME global option produces a report with covered code
 
3544
    indicated.
 
3545
 
3343
3546
    :Examples:
3344
3547
        Run only tests relating to 'ignore'::
3345
3548
 
3354
3557
    def get_transport_type(typestring):
3355
3558
        """Parse and return a transport specifier."""
3356
3559
        if typestring == "sftp":
3357
 
            from bzrlib.transport.sftp import SFTPAbsoluteServer
3358
 
            return SFTPAbsoluteServer
 
3560
            from bzrlib.tests import stub_sftp
 
3561
            return stub_sftp.SFTPAbsoluteServer
3359
3562
        if typestring == "memory":
3360
 
            from bzrlib.transport.memory import MemoryServer
3361
 
            return MemoryServer
 
3563
            from bzrlib.tests import test_server
 
3564
            return memory.MemoryServer
3362
3565
        if typestring == "fakenfs":
3363
 
            from bzrlib.transport.fakenfs import FakeNFSServer
3364
 
            return FakeNFSServer
 
3566
            from bzrlib.tests import test_server
 
3567
            return test_server.FakeNFSServer
3365
3568
        msg = "No known transport type %s. Supported types are: sftp\n" %\
3366
3569
            (typestring)
3367
3570
        raise errors.BzrCommandError(msg)
3378
3581
                                 'throughout the test suite.',
3379
3582
                            type=get_transport_type),
3380
3583
                     Option('benchmark',
3381
 
                            help='Run the benchmarks rather than selftests.'),
 
3584
                            help='Run the benchmarks rather than selftests.',
 
3585
                            hidden=True),
3382
3586
                     Option('lsprof-timed',
3383
3587
                            help='Generate lsprof output for benchmarked'
3384
3588
                                 ' sections of code.'),
3385
 
                     Option('cache-dir', type=str,
3386
 
                            help='Cache intermediate benchmark output in this '
3387
 
                                 'directory.'),
 
3589
                     Option('lsprof-tests',
 
3590
                            help='Generate lsprof output for each test.'),
3388
3591
                     Option('first',
3389
3592
                            help='Run all tests, but run specified tests first.',
3390
3593
                            short_name='f',
3424
3627
 
3425
3628
    def run(self, testspecs_list=None, verbose=False, one=False,
3426
3629
            transport=None, benchmark=None,
3427
 
            lsprof_timed=None, cache_dir=None,
 
3630
            lsprof_timed=None,
3428
3631
            first=False, list_only=False,
3429
3632
            randomize=None, exclude=None, strict=False,
3430
3633
            load_list=None, debugflag=None, starting_with=None, subunit=False,
3431
 
            parallel=None):
3432
 
        from bzrlib.tests import selftest
3433
 
        import bzrlib.benchmarks as benchmarks
3434
 
        from bzrlib.benchmarks import tree_creator
3435
 
 
3436
 
        # Make deprecation warnings visible, unless -Werror is set
3437
 
        symbol_versioning.activate_deprecation_warnings(override=False)
3438
 
 
3439
 
        if cache_dir is not None:
3440
 
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
 
3634
            parallel=None, lsprof_tests=False):
 
3635
        from bzrlib import tests
 
3636
 
3441
3637
        if testspecs_list is not None:
3442
3638
            pattern = '|'.join(testspecs_list)
3443
3639
        else:
3449
3645
                raise errors.BzrCommandError("subunit not available. subunit "
3450
3646
                    "needs to be installed to use --subunit.")
3451
3647
            self.additional_selftest_args['runner_class'] = SubUnitBzrRunner
 
3648
            # On Windows, disable automatic conversion of '\n' to '\r\n' in
 
3649
            # stdout, which would corrupt the subunit stream. 
 
3650
            # FIXME: This has been fixed in subunit trunk (>0.0.5) so the
 
3651
            # following code can be deleted when it's sufficiently deployed
 
3652
            # -- vila/mgz 20100514
 
3653
            if (sys.platform == "win32"
 
3654
                and getattr(sys.stdout, 'fileno', None) is not None):
 
3655
                import msvcrt
 
3656
                msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
3452
3657
        if parallel:
3453
3658
            self.additional_selftest_args.setdefault(
3454
3659
                'suite_decorators', []).append(parallel)
3455
3660
        if benchmark:
3456
 
            test_suite_factory = benchmarks.test_suite
3457
 
            # Unless user explicitly asks for quiet, be verbose in benchmarks
3458
 
            verbose = not is_quiet()
3459
 
            # TODO: should possibly lock the history file...
3460
 
            benchfile = open(".perf_history", "at", buffering=1)
3461
 
        else:
3462
 
            test_suite_factory = None
3463
 
            benchfile = None
 
3661
            raise errors.BzrCommandError(
 
3662
                "--benchmark is no longer supported from bzr 2.2; "
 
3663
                "use bzr-usertest instead")
 
3664
        test_suite_factory = None
 
3665
        selftest_kwargs = {"verbose": verbose,
 
3666
                          "pattern": pattern,
 
3667
                          "stop_on_failure": one,
 
3668
                          "transport": transport,
 
3669
                          "test_suite_factory": test_suite_factory,
 
3670
                          "lsprof_timed": lsprof_timed,
 
3671
                          "lsprof_tests": lsprof_tests,
 
3672
                          "matching_tests_first": first,
 
3673
                          "list_only": list_only,
 
3674
                          "random_seed": randomize,
 
3675
                          "exclude_pattern": exclude,
 
3676
                          "strict": strict,
 
3677
                          "load_list": load_list,
 
3678
                          "debug_flags": debugflag,
 
3679
                          "starting_with": starting_with
 
3680
                          }
 
3681
        selftest_kwargs.update(self.additional_selftest_args)
 
3682
 
 
3683
        # Make deprecation warnings visible, unless -Werror is set
 
3684
        cleanup = symbol_versioning.activate_deprecation_warnings(
 
3685
            override=False)
3464
3686
        try:
3465
 
            selftest_kwargs = {"verbose": verbose,
3466
 
                              "pattern": pattern,
3467
 
                              "stop_on_failure": one,
3468
 
                              "transport": transport,
3469
 
                              "test_suite_factory": test_suite_factory,
3470
 
                              "lsprof_timed": lsprof_timed,
3471
 
                              "bench_history": benchfile,
3472
 
                              "matching_tests_first": first,
3473
 
                              "list_only": list_only,
3474
 
                              "random_seed": randomize,
3475
 
                              "exclude_pattern": exclude,
3476
 
                              "strict": strict,
3477
 
                              "load_list": load_list,
3478
 
                              "debug_flags": debugflag,
3479
 
                              "starting_with": starting_with
3480
 
                              }
3481
 
            selftest_kwargs.update(self.additional_selftest_args)
3482
 
            result = selftest(**selftest_kwargs)
 
3687
            result = tests.selftest(**selftest_kwargs)
3483
3688
        finally:
3484
 
            if benchfile is not None:
3485
 
                benchfile.close()
 
3689
            cleanup()
3486
3690
        return int(not result)
3487
3691
 
3488
3692
 
3489
3693
class cmd_version(Command):
3490
 
    """Show version of bzr."""
 
3694
    __doc__ = """Show version of bzr."""
3491
3695
 
3492
3696
    encoding_type = 'replace'
3493
3697
    takes_options = [
3504
3708
 
3505
3709
 
3506
3710
class cmd_rocks(Command):
3507
 
    """Statement of optimism."""
 
3711
    __doc__ = """Statement of optimism."""
3508
3712
 
3509
3713
    hidden = True
3510
3714
 
3511
3715
    @display_command
3512
3716
    def run(self):
3513
 
        print "It sure does!"
 
3717
        self.outf.write("It sure does!\n")
3514
3718
 
3515
3719
 
3516
3720
class cmd_find_merge_base(Command):
3517
 
    """Find and print a base revision for merging two branches."""
 
3721
    __doc__ = """Find and print a base revision for merging two branches."""
3518
3722
    # TODO: Options to specify revisions on either side, as if
3519
3723
    #       merging only part of the history.
3520
3724
    takes_args = ['branch', 'other']
3526
3730
 
3527
3731
        branch1 = Branch.open_containing(branch)[0]
3528
3732
        branch2 = Branch.open_containing(other)[0]
3529
 
        branch1.lock_read()
3530
 
        try:
3531
 
            branch2.lock_read()
3532
 
            try:
3533
 
                last1 = ensure_null(branch1.last_revision())
3534
 
                last2 = ensure_null(branch2.last_revision())
3535
 
 
3536
 
                graph = branch1.repository.get_graph(branch2.repository)
3537
 
                base_rev_id = graph.find_unique_lca(last1, last2)
3538
 
 
3539
 
                print 'merge base is revision %s' % base_rev_id
3540
 
            finally:
3541
 
                branch2.unlock()
3542
 
        finally:
3543
 
            branch1.unlock()
 
3733
        self.add_cleanup(branch1.lock_read().unlock)
 
3734
        self.add_cleanup(branch2.lock_read().unlock)
 
3735
        last1 = ensure_null(branch1.last_revision())
 
3736
        last2 = ensure_null(branch2.last_revision())
 
3737
 
 
3738
        graph = branch1.repository.get_graph(branch2.repository)
 
3739
        base_rev_id = graph.find_unique_lca(last1, last2)
 
3740
 
 
3741
        self.outf.write('merge base is revision %s\n' % base_rev_id)
3544
3742
 
3545
3743
 
3546
3744
class cmd_merge(Command):
3547
 
    """Perform a three-way merge.
 
3745
    __doc__ = """Perform a three-way merge.
3548
3746
 
3549
3747
    The source of the merge can be specified either in the form of a branch,
3550
3748
    or in the form of a path to a file containing a merge directive generated
3551
3749
    with bzr send. If neither is specified, the default is the upstream branch
3552
3750
    or the branch most recently merged using --remember.
3553
3751
 
3554
 
    When merging a branch, by default the tip will be merged. To pick a different
3555
 
    revision, pass --revision. If you specify two values, the first will be used as
3556
 
    BASE and the second one as OTHER. Merging individual revisions, or a subset of
3557
 
    available revisions, like this is commonly referred to as "cherrypicking".
3558
 
 
3559
 
    Revision numbers are always relative to the branch being merged.
3560
 
 
3561
 
    By default, bzr will try to merge in all new work from the other
3562
 
    branch, automatically determining an appropriate base.  If this
3563
 
    fails, you may need to give an explicit base.
 
3752
    When merging from a branch, by default bzr will try to merge in all new
 
3753
    work from the other branch, automatically determining an appropriate base
 
3754
    revision.  If this fails, you may need to give an explicit base.
 
3755
 
 
3756
    To pick a different ending revision, pass "--revision OTHER".  bzr will
 
3757
    try to merge in all new work up to and including revision OTHER.
 
3758
 
 
3759
    If you specify two values, "--revision BASE..OTHER", only revisions BASE
 
3760
    through OTHER, excluding BASE but including OTHER, will be merged.  If this
 
3761
    causes some revisions to be skipped, i.e. if the destination branch does
 
3762
    not already contain revision BASE, such a merge is commonly referred to as
 
3763
    a "cherrypick".
 
3764
 
 
3765
    Revision numbers are always relative to the source branch.
3564
3766
 
3565
3767
    Merge will do its best to combine the changes in two branches, but there
3566
3768
    are some kinds of problems only a human can fix.  When it encounters those,
3579
3781
    committed to record the result of the merge.
3580
3782
 
3581
3783
    merge refuses to run if there are any uncommitted changes, unless
3582
 
    --force is given.
 
3784
    --force is given. The --force option can also be used to create a
 
3785
    merge revision which has more than two parents.
 
3786
 
 
3787
    If one would like to merge changes from the working tree of the other
 
3788
    branch without merging any committed revisions, the --uncommitted option
 
3789
    can be given.
3583
3790
 
3584
3791
    To select only some changes to merge, use "merge -i", which will prompt
3585
3792
    you to apply each diff hunk and file change, similar to "shelve".
3586
3793
 
3587
3794
    :Examples:
3588
 
        To merge the latest revision from bzr.dev::
 
3795
        To merge all new revisions from bzr.dev::
3589
3796
 
3590
3797
            bzr merge ../bzr.dev
3591
3798
 
3597
3804
 
3598
3805
            bzr merge -r 81..82 ../bzr.dev
3599
3806
 
3600
 
        To apply a merge directive contained in /tmp/merge:
 
3807
        To apply a merge directive contained in /tmp/merge::
3601
3808
 
3602
3809
            bzr merge /tmp/merge
 
3810
 
 
3811
        To create a merge revision with three parents from two branches
 
3812
        feature1a and feature1b:
 
3813
 
 
3814
            bzr merge ../feature1a
 
3815
            bzr merge ../feature1b --force
 
3816
            bzr commit -m 'revision with three parents'
3603
3817
    """
3604
3818
 
3605
3819
    encoding_type = 'exact'
3621
3835
                ' completely merged into the source, pull from the'
3622
3836
                ' source rather than merging.  When this happens,'
3623
3837
                ' you do not need to commit the result.'),
3624
 
        Option('directory',
 
3838
        custom_help('directory',
3625
3839
               help='Branch to merge into, '
3626
 
                    'rather than the one containing the working directory.',
3627
 
               short_name='d',
3628
 
               type=unicode,
3629
 
               ),
 
3840
                    'rather than the one containing the working directory.'),
3630
3841
        Option('preview', help='Instead of merging, show a diff of the'
3631
3842
               ' merge.'),
3632
3843
        Option('interactive', help='Select changes interactively.',
3650
3861
        verified = 'inapplicable'
3651
3862
        tree = WorkingTree.open_containing(directory)[0]
3652
3863
 
3653
 
        # die as quickly as possible if there are uncommitted changes
3654
3864
        try:
3655
3865
            basis_tree = tree.revision_tree(tree.last_revision())
3656
3866
        except errors.NoSuchRevision:
3657
3867
            basis_tree = tree.basis_tree()
 
3868
 
 
3869
        # die as quickly as possible if there are uncommitted changes
3658
3870
        if not force:
3659
 
            if tree.has_changes(basis_tree):
 
3871
            if tree.has_changes():
3660
3872
                raise errors.UncommittedChanges(tree)
3661
3873
 
3662
3874
        view_info = _get_view_info_for_change_reporter(tree)
3663
3875
        change_reporter = delta._ChangeReporter(
3664
3876
            unversioned_filter=tree.is_ignored, view_info=view_info)
3665
 
        cleanups = []
3666
 
        try:
3667
 
            pb = ui.ui_factory.nested_progress_bar()
3668
 
            cleanups.append(pb.finished)
3669
 
            tree.lock_write()
3670
 
            cleanups.append(tree.unlock)
3671
 
            if location is not None:
3672
 
                try:
3673
 
                    mergeable = bundle.read_mergeable_from_url(location,
3674
 
                        possible_transports=possible_transports)
3675
 
                except errors.NotABundle:
3676
 
                    mergeable = None
3677
 
                else:
3678
 
                    if uncommitted:
3679
 
                        raise errors.BzrCommandError('Cannot use --uncommitted'
3680
 
                            ' with bundles or merge directives.')
3681
 
 
3682
 
                    if revision is not None:
3683
 
                        raise errors.BzrCommandError(
3684
 
                            'Cannot use -r with merge directives or bundles')
3685
 
                    merger, verified = _mod_merge.Merger.from_mergeable(tree,
3686
 
                       mergeable, pb)
3687
 
 
3688
 
            if merger is None and uncommitted:
3689
 
                if revision is not None and len(revision) > 0:
3690
 
                    raise errors.BzrCommandError('Cannot use --uncommitted and'
3691
 
                        ' --revision at the same time.')
3692
 
                merger = self.get_merger_from_uncommitted(tree, location, pb,
3693
 
                                                          cleanups)
3694
 
                allow_pending = False
3695
 
 
3696
 
            if merger is None:
3697
 
                merger, allow_pending = self._get_merger_from_branch(tree,
3698
 
                    location, revision, remember, possible_transports, pb)
3699
 
 
3700
 
            merger.merge_type = merge_type
3701
 
            merger.reprocess = reprocess
3702
 
            merger.show_base = show_base
3703
 
            self.sanity_check_merger(merger)
3704
 
            if (merger.base_rev_id == merger.other_rev_id and
3705
 
                merger.other_rev_id is not None):
3706
 
                note('Nothing to do.')
 
3877
        pb = ui.ui_factory.nested_progress_bar()
 
3878
        self.add_cleanup(pb.finished)
 
3879
        self.add_cleanup(tree.lock_write().unlock)
 
3880
        if location is not None:
 
3881
            try:
 
3882
                mergeable = bundle.read_mergeable_from_url(location,
 
3883
                    possible_transports=possible_transports)
 
3884
            except errors.NotABundle:
 
3885
                mergeable = None
 
3886
            else:
 
3887
                if uncommitted:
 
3888
                    raise errors.BzrCommandError('Cannot use --uncommitted'
 
3889
                        ' with bundles or merge directives.')
 
3890
 
 
3891
                if revision is not None:
 
3892
                    raise errors.BzrCommandError(
 
3893
                        'Cannot use -r with merge directives or bundles')
 
3894
                merger, verified = _mod_merge.Merger.from_mergeable(tree,
 
3895
                   mergeable, None)
 
3896
 
 
3897
        if merger is None and uncommitted:
 
3898
            if revision is not None and len(revision) > 0:
 
3899
                raise errors.BzrCommandError('Cannot use --uncommitted and'
 
3900
                    ' --revision at the same time.')
 
3901
            merger = self.get_merger_from_uncommitted(tree, location, None)
 
3902
            allow_pending = False
 
3903
 
 
3904
        if merger is None:
 
3905
            merger, allow_pending = self._get_merger_from_branch(tree,
 
3906
                location, revision, remember, possible_transports, None)
 
3907
 
 
3908
        merger.merge_type = merge_type
 
3909
        merger.reprocess = reprocess
 
3910
        merger.show_base = show_base
 
3911
        self.sanity_check_merger(merger)
 
3912
        if (merger.base_rev_id == merger.other_rev_id and
 
3913
            merger.other_rev_id is not None):
 
3914
            note('Nothing to do.')
 
3915
            return 0
 
3916
        if pull:
 
3917
            if merger.interesting_files is not None:
 
3918
                raise errors.BzrCommandError('Cannot pull individual files')
 
3919
            if (merger.base_rev_id == tree.last_revision()):
 
3920
                result = tree.pull(merger.other_branch, False,
 
3921
                                   merger.other_rev_id)
 
3922
                result.report(self.outf)
3707
3923
                return 0
3708
 
            if pull:
3709
 
                if merger.interesting_files is not None:
3710
 
                    raise errors.BzrCommandError('Cannot pull individual files')
3711
 
                if (merger.base_rev_id == tree.last_revision()):
3712
 
                    result = tree.pull(merger.other_branch, False,
3713
 
                                       merger.other_rev_id)
3714
 
                    result.report(self.outf)
3715
 
                    return 0
3716
 
            merger.check_basis(False)
3717
 
            if preview:
3718
 
                return self._do_preview(merger, cleanups)
3719
 
            elif interactive:
3720
 
                return self._do_interactive(merger, cleanups)
3721
 
            else:
3722
 
                return self._do_merge(merger, change_reporter, allow_pending,
3723
 
                                      verified)
3724
 
        finally:
3725
 
            for cleanup in reversed(cleanups):
3726
 
                cleanup()
 
3924
        if merger.this_basis is None:
 
3925
            raise errors.BzrCommandError(
 
3926
                "This branch has no commits."
 
3927
                " (perhaps you would prefer 'bzr pull')")
 
3928
        if preview:
 
3929
            return self._do_preview(merger)
 
3930
        elif interactive:
 
3931
            return self._do_interactive(merger)
 
3932
        else:
 
3933
            return self._do_merge(merger, change_reporter, allow_pending,
 
3934
                                  verified)
3727
3935
 
3728
 
    def _get_preview(self, merger, cleanups):
 
3936
    def _get_preview(self, merger):
3729
3937
        tree_merger = merger.make_merger()
3730
3938
        tt = tree_merger.make_preview_transform()
3731
 
        cleanups.append(tt.finalize)
 
3939
        self.add_cleanup(tt.finalize)
3732
3940
        result_tree = tt.get_preview_tree()
3733
3941
        return result_tree
3734
3942
 
3735
 
    def _do_preview(self, merger, cleanups):
 
3943
    def _do_preview(self, merger):
3736
3944
        from bzrlib.diff import show_diff_trees
3737
 
        result_tree = self._get_preview(merger, cleanups)
 
3945
        result_tree = self._get_preview(merger)
 
3946
        path_encoding = osutils.get_diff_header_encoding()
3738
3947
        show_diff_trees(merger.this_tree, result_tree, self.outf,
3739
 
                        old_label='', new_label='')
 
3948
                        old_label='', new_label='',
 
3949
                        path_encoding=path_encoding)
3740
3950
 
3741
3951
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
3742
3952
        merger.change_reporter = change_reporter
3750
3960
        else:
3751
3961
            return 0
3752
3962
 
3753
 
    def _do_interactive(self, merger, cleanups):
 
3963
    def _do_interactive(self, merger):
3754
3964
        """Perform an interactive merge.
3755
3965
 
3756
3966
        This works by generating a preview tree of the merge, then using
3758
3968
        and the preview tree.
3759
3969
        """
3760
3970
        from bzrlib import shelf_ui
3761
 
        result_tree = self._get_preview(merger, cleanups)
 
3971
        result_tree = self._get_preview(merger)
3762
3972
        writer = bzrlib.option.diff_writer_registry.get()
3763
3973
        shelver = shelf_ui.Shelver(merger.this_tree, result_tree, destroy=True,
3764
3974
                                   reporter=shelf_ui.ApplyReporter(),
3765
3975
                                   diff_writer=writer(sys.stdout))
3766
 
        shelver.run()
 
3976
        try:
 
3977
            shelver.run()
 
3978
        finally:
 
3979
            shelver.finalize()
3767
3980
 
3768
3981
    def sanity_check_merger(self, merger):
3769
3982
        if (merger.show_base and
3819
4032
        if ((remember or tree.branch.get_submit_branch() is None) and
3820
4033
             user_location is not None):
3821
4034
            tree.branch.set_submit_branch(other_branch.base)
3822
 
        _merge_tags_if_possible(other_branch, tree.branch)
 
4035
        # Merge tags (but don't set them in the master branch yet, the user
 
4036
        # might revert this merge).  Commit will propagate them.
 
4037
        _merge_tags_if_possible(other_branch, tree.branch, ignore_master=True)
3823
4038
        merger = _mod_merge.Merger.from_revision_ids(pb, tree,
3824
4039
            other_revision_id, base_revision_id, other_branch, base_branch)
3825
4040
        if other_path != '':
3829
4044
            allow_pending = True
3830
4045
        return merger, allow_pending
3831
4046
 
3832
 
    def get_merger_from_uncommitted(self, tree, location, pb, cleanups):
 
4047
    def get_merger_from_uncommitted(self, tree, location, pb):
3833
4048
        """Get a merger for uncommitted changes.
3834
4049
 
3835
4050
        :param tree: The tree the merger should apply to.
3836
4051
        :param location: The location containing uncommitted changes.
3837
4052
        :param pb: The progress bar to use for showing progress.
3838
 
        :param cleanups: A list of operations to perform to clean up the
3839
 
            temporary directories, unfinalized objects, etc.
3840
4053
        """
3841
4054
        location = self._select_branch_location(tree, location)[0]
3842
4055
        other_tree, other_path = WorkingTree.open_containing(location)
3894
4107
 
3895
4108
 
3896
4109
class cmd_remerge(Command):
3897
 
    """Redo a merge.
 
4110
    __doc__ = """Redo a merge.
3898
4111
 
3899
4112
    Use this if you want to try a different merge technique while resolving
3900
4113
    conflicts.  Some merge techniques are better than others, and remerge
3925
4138
 
3926
4139
    def run(self, file_list=None, merge_type=None, show_base=False,
3927
4140
            reprocess=False):
 
4141
        from bzrlib.conflicts import restore
3928
4142
        if merge_type is None:
3929
4143
            merge_type = _mod_merge.Merge3Merger
3930
 
        tree, file_list = tree_files(file_list)
3931
 
        tree.lock_write()
3932
 
        try:
3933
 
            parents = tree.get_parent_ids()
3934
 
            if len(parents) != 2:
3935
 
                raise errors.BzrCommandError("Sorry, remerge only works after normal"
3936
 
                                             " merges.  Not cherrypicking or"
3937
 
                                             " multi-merges.")
3938
 
            repository = tree.branch.repository
3939
 
            interesting_ids = None
3940
 
            new_conflicts = []
3941
 
            conflicts = tree.conflicts()
3942
 
            if file_list is not None:
3943
 
                interesting_ids = set()
3944
 
                for filename in file_list:
3945
 
                    file_id = tree.path2id(filename)
3946
 
                    if file_id is None:
3947
 
                        raise errors.NotVersionedError(filename)
3948
 
                    interesting_ids.add(file_id)
3949
 
                    if tree.kind(file_id) != "directory":
3950
 
                        continue
 
4144
        tree, file_list = WorkingTree.open_containing_paths(file_list)
 
4145
        self.add_cleanup(tree.lock_write().unlock)
 
4146
        parents = tree.get_parent_ids()
 
4147
        if len(parents) != 2:
 
4148
            raise errors.BzrCommandError("Sorry, remerge only works after normal"
 
4149
                                         " merges.  Not cherrypicking or"
 
4150
                                         " multi-merges.")
 
4151
        repository = tree.branch.repository
 
4152
        interesting_ids = None
 
4153
        new_conflicts = []
 
4154
        conflicts = tree.conflicts()
 
4155
        if file_list is not None:
 
4156
            interesting_ids = set()
 
4157
            for filename in file_list:
 
4158
                file_id = tree.path2id(filename)
 
4159
                if file_id is None:
 
4160
                    raise errors.NotVersionedError(filename)
 
4161
                interesting_ids.add(file_id)
 
4162
                if tree.kind(file_id) != "directory":
 
4163
                    continue
3951
4164
 
3952
 
                    for name, ie in tree.inventory.iter_entries(file_id):
3953
 
                        interesting_ids.add(ie.file_id)
3954
 
                new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
3955
 
            else:
3956
 
                # Remerge only supports resolving contents conflicts
3957
 
                allowed_conflicts = ('text conflict', 'contents conflict')
3958
 
                restore_files = [c.path for c in conflicts
3959
 
                                 if c.typestring in allowed_conflicts]
3960
 
            _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
3961
 
            tree.set_conflicts(ConflictList(new_conflicts))
3962
 
            if file_list is not None:
3963
 
                restore_files = file_list
3964
 
            for filename in restore_files:
3965
 
                try:
3966
 
                    restore(tree.abspath(filename))
3967
 
                except errors.NotConflicted:
3968
 
                    pass
3969
 
            # Disable pending merges, because the file texts we are remerging
3970
 
            # have not had those merges performed.  If we use the wrong parents
3971
 
            # list, we imply that the working tree text has seen and rejected
3972
 
            # all the changes from the other tree, when in fact those changes
3973
 
            # have not yet been seen.
3974
 
            pb = ui.ui_factory.nested_progress_bar()
3975
 
            tree.set_parent_ids(parents[:1])
 
4165
                for name, ie in tree.inventory.iter_entries(file_id):
 
4166
                    interesting_ids.add(ie.file_id)
 
4167
            new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
 
4168
        else:
 
4169
            # Remerge only supports resolving contents conflicts
 
4170
            allowed_conflicts = ('text conflict', 'contents conflict')
 
4171
            restore_files = [c.path for c in conflicts
 
4172
                             if c.typestring in allowed_conflicts]
 
4173
        _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
 
4174
        tree.set_conflicts(ConflictList(new_conflicts))
 
4175
        if file_list is not None:
 
4176
            restore_files = file_list
 
4177
        for filename in restore_files:
3976
4178
            try:
3977
 
                merger = _mod_merge.Merger.from_revision_ids(pb,
3978
 
                                                             tree, parents[1])
3979
 
                merger.interesting_ids = interesting_ids
3980
 
                merger.merge_type = merge_type
3981
 
                merger.show_base = show_base
3982
 
                merger.reprocess = reprocess
3983
 
                conflicts = merger.do_merge()
3984
 
            finally:
3985
 
                tree.set_parent_ids(parents)
3986
 
                pb.finished()
 
4179
                restore(tree.abspath(filename))
 
4180
            except errors.NotConflicted:
 
4181
                pass
 
4182
        # Disable pending merges, because the file texts we are remerging
 
4183
        # have not had those merges performed.  If we use the wrong parents
 
4184
        # list, we imply that the working tree text has seen and rejected
 
4185
        # all the changes from the other tree, when in fact those changes
 
4186
        # have not yet been seen.
 
4187
        tree.set_parent_ids(parents[:1])
 
4188
        try:
 
4189
            merger = _mod_merge.Merger.from_revision_ids(None, tree, parents[1])
 
4190
            merger.interesting_ids = interesting_ids
 
4191
            merger.merge_type = merge_type
 
4192
            merger.show_base = show_base
 
4193
            merger.reprocess = reprocess
 
4194
            conflicts = merger.do_merge()
3987
4195
        finally:
3988
 
            tree.unlock()
 
4196
            tree.set_parent_ids(parents)
3989
4197
        if conflicts > 0:
3990
4198
            return 1
3991
4199
        else:
3993
4201
 
3994
4202
 
3995
4203
class cmd_revert(Command):
3996
 
    """Revert files to a previous revision.
 
4204
    __doc__ = """Revert files to a previous revision.
3997
4205
 
3998
4206
    Giving a list of files will revert only those files.  Otherwise, all files
3999
4207
    will be reverted.  If the revision is not specified with '--revision', the
4000
4208
    last committed revision is used.
4001
4209
 
4002
4210
    To remove only some changes, without reverting to a prior version, use
4003
 
    merge instead.  For example, "merge . --revision -2..-3" will remove the
4004
 
    changes introduced by -2, without affecting the changes introduced by -1.
4005
 
    Or to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
 
4211
    merge instead.  For example, "merge . -r -2..-3" (don't forget the ".")
 
4212
    will remove the changes introduced by the second last commit (-2), without
 
4213
    affecting the changes introduced by the last commit (-1).  To remove
 
4214
    certain changes on a hunk-by-hunk basis, see the shelve command.
4006
4215
 
4007
4216
    By default, any files that have been manually changed will be backed up
4008
4217
    first.  (Files changed only by merge are not backed up.)  Backup files have
4013
4222
    name.  If you name a directory, all the contents of that directory will be
4014
4223
    reverted.
4015
4224
 
4016
 
    Any files that have been newly added since that revision will be deleted,
4017
 
    with a backup kept if appropriate.  Directories containing unknown files
4018
 
    will not be deleted.
 
4225
    If you have newly added files since the target revision, they will be
 
4226
    removed.  If the files to be removed have been changed, backups will be
 
4227
    created as above.  Directories containing unknown files will not be
 
4228
    deleted.
4019
4229
 
4020
 
    The working tree contains a list of pending merged revisions, which will
4021
 
    be included as parents in the next commit.  Normally, revert clears that
4022
 
    list as well as reverting the files.  If any files are specified, revert
4023
 
    leaves the pending merge list alone and reverts only the files.  Use "bzr
4024
 
    revert ." in the tree root to revert all files but keep the merge record,
4025
 
    and "bzr revert --forget-merges" to clear the pending merge list without
 
4230
    The working tree contains a list of revisions that have been merged but
 
4231
    not yet committed. These revisions will be included as additional parents
 
4232
    of the next commit.  Normally, using revert clears that list as well as
 
4233
    reverting the files.  If any files are specified, revert leaves the list
 
4234
    of uncommitted merges alone and reverts only the files.  Use ``bzr revert
 
4235
    .`` in the tree root to revert all files but keep the recorded merges,
 
4236
    and ``bzr revert --forget-merges`` to clear the pending merge list without
4026
4237
    reverting any files.
 
4238
 
 
4239
    Using "bzr revert --forget-merges", it is possible to apply all of the
 
4240
    changes from a branch in a single revision.  To do this, perform the merge
 
4241
    as desired.  Then doing revert with the "--forget-merges" option will keep
 
4242
    the content of the tree as it was, but it will clear the list of pending
 
4243
    merges.  The next commit will then contain all of the changes that are
 
4244
    present in the other branch, but without any other parent revisions.
 
4245
    Because this technique forgets where these changes originated, it may
 
4246
    cause additional conflicts on later merges involving the same source and
 
4247
    target branches.
4027
4248
    """
4028
4249
 
4029
 
    _see_also = ['cat', 'export']
 
4250
    _see_also = ['cat', 'export', 'merge', 'shelve']
4030
4251
    takes_options = [
4031
4252
        'revision',
4032
4253
        Option('no-backup', "Do not save backups of reverted files."),
4037
4258
 
4038
4259
    def run(self, revision=None, no_backup=False, file_list=None,
4039
4260
            forget_merges=None):
4040
 
        tree, file_list = tree_files(file_list)
4041
 
        tree.lock_write()
4042
 
        try:
4043
 
            if forget_merges:
4044
 
                tree.set_parent_ids(tree.get_parent_ids()[:1])
4045
 
            else:
4046
 
                self._revert_tree_to_revision(tree, revision, file_list, no_backup)
4047
 
        finally:
4048
 
            tree.unlock()
 
4261
        tree, file_list = WorkingTree.open_containing_paths(file_list)
 
4262
        self.add_cleanup(tree.lock_tree_write().unlock)
 
4263
        if forget_merges:
 
4264
            tree.set_parent_ids(tree.get_parent_ids()[:1])
 
4265
        else:
 
4266
            self._revert_tree_to_revision(tree, revision, file_list, no_backup)
4049
4267
 
4050
4268
    @staticmethod
4051
4269
    def _revert_tree_to_revision(tree, revision, file_list, no_backup):
4052
4270
        rev_tree = _get_one_revision_tree('revert', revision, tree=tree)
4053
 
        pb = ui.ui_factory.nested_progress_bar()
4054
 
        try:
4055
 
            tree.revert(file_list, rev_tree, not no_backup, pb,
4056
 
                report_changes=True)
4057
 
        finally:
4058
 
            pb.finished()
 
4271
        tree.revert(file_list, rev_tree, not no_backup, None,
 
4272
            report_changes=True)
4059
4273
 
4060
4274
 
4061
4275
class cmd_assert_fail(Command):
4062
 
    """Test reporting of assertion failures"""
 
4276
    __doc__ = """Test reporting of assertion failures"""
4063
4277
    # intended just for use in testing
4064
4278
 
4065
4279
    hidden = True
4069
4283
 
4070
4284
 
4071
4285
class cmd_help(Command):
4072
 
    """Show help on a command or other topic.
 
4286
    __doc__ = """Show help on a command or other topic.
4073
4287
    """
4074
4288
 
4075
4289
    _see_also = ['topics']
4088
4302
 
4089
4303
 
4090
4304
class cmd_shell_complete(Command):
4091
 
    """Show appropriate completions for context.
 
4305
    __doc__ = """Show appropriate completions for context.
4092
4306
 
4093
4307
    For a list of all available commands, say 'bzr shell-complete'.
4094
4308
    """
4103
4317
 
4104
4318
 
4105
4319
class cmd_missing(Command):
4106
 
    """Show unmerged/unpulled revisions between two branches.
 
4320
    __doc__ = """Show unmerged/unpulled revisions between two branches.
4107
4321
 
4108
4322
    OTHER_BRANCH may be local or remote.
4109
4323
 
4110
4324
    To filter on a range of revisions, you can use the command -r begin..end
4111
4325
    -r revision requests a specific revision, -r ..end or -r begin.. are
4112
4326
    also valid.
 
4327
            
 
4328
    :Exit values:
 
4329
        1 - some missing revisions
 
4330
        0 - no missing revisions
4113
4331
 
4114
4332
    :Examples:
4115
4333
 
4136
4354
    _see_also = ['merge', 'pull']
4137
4355
    takes_args = ['other_branch?']
4138
4356
    takes_options = [
 
4357
        'directory',
4139
4358
        Option('reverse', 'Reverse the order of revisions.'),
4140
4359
        Option('mine-only',
4141
4360
               'Display changes in the local branch only.'),
4163
4382
            theirs_only=False,
4164
4383
            log_format=None, long=False, short=False, line=False,
4165
4384
            show_ids=False, verbose=False, this=False, other=False,
4166
 
            include_merges=False, revision=None, my_revision=None):
 
4385
            include_merges=False, revision=None, my_revision=None,
 
4386
            directory=u'.'):
4167
4387
        from bzrlib.missing import find_unmerged, iter_log_revisions
4168
4388
        def message(s):
4169
4389
            if not is_quiet():
4182
4402
        elif theirs_only:
4183
4403
            restrict = 'remote'
4184
4404
 
4185
 
        local_branch = Branch.open_containing(u".")[0]
 
4405
        local_branch = Branch.open_containing(directory)[0]
 
4406
        self.add_cleanup(local_branch.lock_read().unlock)
 
4407
 
4186
4408
        parent = local_branch.get_parent()
4187
4409
        if other_branch is None:
4188
4410
            other_branch = parent
4197
4419
        remote_branch = Branch.open(other_branch)
4198
4420
        if remote_branch.base == local_branch.base:
4199
4421
            remote_branch = local_branch
 
4422
        else:
 
4423
            self.add_cleanup(remote_branch.lock_read().unlock)
4200
4424
 
4201
4425
        local_revid_range = _revision_range_to_revid_range(
4202
4426
            _get_revision_range(my_revision, local_branch,
4206
4430
            _get_revision_range(revision,
4207
4431
                remote_branch, self.name()))
4208
4432
 
4209
 
        local_branch.lock_read()
4210
 
        try:
4211
 
            remote_branch.lock_read()
4212
 
            try:
4213
 
                local_extra, remote_extra = find_unmerged(
4214
 
                    local_branch, remote_branch, restrict,
4215
 
                    backward=not reverse,
4216
 
                    include_merges=include_merges,
4217
 
                    local_revid_range=local_revid_range,
4218
 
                    remote_revid_range=remote_revid_range)
4219
 
 
4220
 
                if log_format is None:
4221
 
                    registry = log.log_formatter_registry
4222
 
                    log_format = registry.get_default(local_branch)
4223
 
                lf = log_format(to_file=self.outf,
4224
 
                                show_ids=show_ids,
4225
 
                                show_timezone='original')
4226
 
 
4227
 
                status_code = 0
4228
 
                if local_extra and not theirs_only:
4229
 
                    message("You have %d extra revision(s):\n" %
4230
 
                        len(local_extra))
4231
 
                    for revision in iter_log_revisions(local_extra,
4232
 
                                        local_branch.repository,
4233
 
                                        verbose):
4234
 
                        lf.log_revision(revision)
4235
 
                    printed_local = True
4236
 
                    status_code = 1
4237
 
                else:
4238
 
                    printed_local = False
4239
 
 
4240
 
                if remote_extra and not mine_only:
4241
 
                    if printed_local is True:
4242
 
                        message("\n\n\n")
4243
 
                    message("You are missing %d revision(s):\n" %
4244
 
                        len(remote_extra))
4245
 
                    for revision in iter_log_revisions(remote_extra,
4246
 
                                        remote_branch.repository,
4247
 
                                        verbose):
4248
 
                        lf.log_revision(revision)
4249
 
                    status_code = 1
4250
 
 
4251
 
                if mine_only and not local_extra:
4252
 
                    # We checked local, and found nothing extra
4253
 
                    message('This branch is up to date.\n')
4254
 
                elif theirs_only and not remote_extra:
4255
 
                    # We checked remote, and found nothing extra
4256
 
                    message('Other branch is up to date.\n')
4257
 
                elif not (mine_only or theirs_only or local_extra or
4258
 
                          remote_extra):
4259
 
                    # We checked both branches, and neither one had extra
4260
 
                    # revisions
4261
 
                    message("Branches are up to date.\n")
4262
 
            finally:
4263
 
                remote_branch.unlock()
4264
 
        finally:
4265
 
            local_branch.unlock()
 
4433
        local_extra, remote_extra = find_unmerged(
 
4434
            local_branch, remote_branch, restrict,
 
4435
            backward=not reverse,
 
4436
            include_merges=include_merges,
 
4437
            local_revid_range=local_revid_range,
 
4438
            remote_revid_range=remote_revid_range)
 
4439
 
 
4440
        if log_format is None:
 
4441
            registry = log.log_formatter_registry
 
4442
            log_format = registry.get_default(local_branch)
 
4443
        lf = log_format(to_file=self.outf,
 
4444
                        show_ids=show_ids,
 
4445
                        show_timezone='original')
 
4446
 
 
4447
        status_code = 0
 
4448
        if local_extra and not theirs_only:
 
4449
            message("You have %d extra revision(s):\n" %
 
4450
                len(local_extra))
 
4451
            for revision in iter_log_revisions(local_extra,
 
4452
                                local_branch.repository,
 
4453
                                verbose):
 
4454
                lf.log_revision(revision)
 
4455
            printed_local = True
 
4456
            status_code = 1
 
4457
        else:
 
4458
            printed_local = False
 
4459
 
 
4460
        if remote_extra and not mine_only:
 
4461
            if printed_local is True:
 
4462
                message("\n\n\n")
 
4463
            message("You are missing %d revision(s):\n" %
 
4464
                len(remote_extra))
 
4465
            for revision in iter_log_revisions(remote_extra,
 
4466
                                remote_branch.repository,
 
4467
                                verbose):
 
4468
                lf.log_revision(revision)
 
4469
            status_code = 1
 
4470
 
 
4471
        if mine_only and not local_extra:
 
4472
            # We checked local, and found nothing extra
 
4473
            message('This branch is up to date.\n')
 
4474
        elif theirs_only and not remote_extra:
 
4475
            # We checked remote, and found nothing extra
 
4476
            message('Other branch is up to date.\n')
 
4477
        elif not (mine_only or theirs_only or local_extra or
 
4478
                  remote_extra):
 
4479
            # We checked both branches, and neither one had extra
 
4480
            # revisions
 
4481
            message("Branches are up to date.\n")
 
4482
        self.cleanup_now()
4266
4483
        if not status_code and parent is None and other_branch is not None:
4267
 
            local_branch.lock_write()
4268
 
            try:
4269
 
                # handle race conditions - a parent might be set while we run.
4270
 
                if local_branch.get_parent() is None:
4271
 
                    local_branch.set_parent(remote_branch.base)
4272
 
            finally:
4273
 
                local_branch.unlock()
 
4484
            self.add_cleanup(local_branch.lock_write().unlock)
 
4485
            # handle race conditions - a parent might be set while we run.
 
4486
            if local_branch.get_parent() is None:
 
4487
                local_branch.set_parent(remote_branch.base)
4274
4488
        return status_code
4275
4489
 
4276
4490
 
4277
4491
class cmd_pack(Command):
4278
 
    """Compress the data within a repository."""
 
4492
    __doc__ = """Compress the data within a repository.
 
4493
 
 
4494
    This operation compresses the data within a bazaar repository. As
 
4495
    bazaar supports automatic packing of repository, this operation is
 
4496
    normally not required to be done manually.
 
4497
 
 
4498
    During the pack operation, bazaar takes a backup of existing repository
 
4499
    data, i.e. pack files. This backup is eventually removed by bazaar
 
4500
    automatically when it is safe to do so. To save disk space by removing
 
4501
    the backed up pack files, the --clean-obsolete-packs option may be
 
4502
    used.
 
4503
 
 
4504
    Warning: If you use --clean-obsolete-packs and your machine crashes
 
4505
    during or immediately after repacking, you may be left with a state
 
4506
    where the deletion has been written to disk but the new packs have not
 
4507
    been. In this case the repository may be unusable.
 
4508
    """
4279
4509
 
4280
4510
    _see_also = ['repositories']
4281
4511
    takes_args = ['branch_or_repo?']
 
4512
    takes_options = [
 
4513
        Option('clean-obsolete-packs', 'Delete obsolete packs to save disk space.'),
 
4514
        ]
4282
4515
 
4283
 
    def run(self, branch_or_repo='.'):
 
4516
    def run(self, branch_or_repo='.', clean_obsolete_packs=False):
4284
4517
        dir = bzrdir.BzrDir.open_containing(branch_or_repo)[0]
4285
4518
        try:
4286
4519
            branch = dir.open_branch()
4287
4520
            repository = branch.repository
4288
4521
        except errors.NotBranchError:
4289
4522
            repository = dir.open_repository()
4290
 
        repository.pack()
 
4523
        repository.pack(clean_obsolete_packs=clean_obsolete_packs)
4291
4524
 
4292
4525
 
4293
4526
class cmd_plugins(Command):
4294
 
    """List the installed plugins.
 
4527
    __doc__ = """List the installed plugins.
4295
4528
 
4296
4529
    This command displays the list of installed plugins including
4297
4530
    version of plugin and a short description of each.
4304
4537
    adding new commands, providing additional network transports and
4305
4538
    customizing log output.
4306
4539
 
4307
 
    See the Bazaar web site, http://bazaar-vcs.org, for further
4308
 
    information on plugins including where to find them and how to
4309
 
    install them. Instructions are also provided there on how to
4310
 
    write new plugins using the Python programming language.
 
4540
    See the Bazaar Plugin Guide <http://doc.bazaar.canonical.com/plugins/en/>
 
4541
    for further information on plugins including where to find them and how to
 
4542
    install them. Instructions are also provided there on how to write new
 
4543
    plugins using the Python programming language.
4311
4544
    """
4312
4545
    takes_options = ['verbose']
4313
4546
 
4328
4561
                doc = '(no description)'
4329
4562
            result.append((name_ver, doc, plugin.path()))
4330
4563
        for name_ver, doc, path in sorted(result):
4331
 
            print name_ver
4332
 
            print '   ', doc
 
4564
            self.outf.write("%s\n" % name_ver)
 
4565
            self.outf.write("   %s\n" % doc)
4333
4566
            if verbose:
4334
 
                print '   ', path
4335
 
            print
 
4567
                self.outf.write("   %s\n" % path)
 
4568
            self.outf.write("\n")
4336
4569
 
4337
4570
 
4338
4571
class cmd_testament(Command):
4339
 
    """Show testament (signing-form) of a revision."""
 
4572
    __doc__ = """Show testament (signing-form) of a revision."""
4340
4573
    takes_options = [
4341
4574
            'revision',
4342
4575
            Option('long', help='Produce long-format testament.'),
4354
4587
            b = Branch.open_containing(branch)[0]
4355
4588
        else:
4356
4589
            b = Branch.open(branch)
4357
 
        b.lock_read()
4358
 
        try:
4359
 
            if revision is None:
4360
 
                rev_id = b.last_revision()
4361
 
            else:
4362
 
                rev_id = revision[0].as_revision_id(b)
4363
 
            t = testament_class.from_revision(b.repository, rev_id)
4364
 
            if long:
4365
 
                sys.stdout.writelines(t.as_text_lines())
4366
 
            else:
4367
 
                sys.stdout.write(t.as_short_text())
4368
 
        finally:
4369
 
            b.unlock()
 
4590
        self.add_cleanup(b.lock_read().unlock)
 
4591
        if revision is None:
 
4592
            rev_id = b.last_revision()
 
4593
        else:
 
4594
            rev_id = revision[0].as_revision_id(b)
 
4595
        t = testament_class.from_revision(b.repository, rev_id)
 
4596
        if long:
 
4597
            sys.stdout.writelines(t.as_text_lines())
 
4598
        else:
 
4599
            sys.stdout.write(t.as_short_text())
4370
4600
 
4371
4601
 
4372
4602
class cmd_annotate(Command):
4373
 
    """Show the origin of each line in a file.
 
4603
    __doc__ = """Show the origin of each line in a file.
4374
4604
 
4375
4605
    This prints out the given file with an annotation on the left side
4376
4606
    indicating which revision, author and date introduced the change.
4387
4617
                     Option('long', help='Show commit date in annotations.'),
4388
4618
                     'revision',
4389
4619
                     'show-ids',
 
4620
                     'directory',
4390
4621
                     ]
4391
4622
    encoding_type = 'exact'
4392
4623
 
4393
4624
    @display_command
4394
4625
    def run(self, filename, all=False, long=False, revision=None,
4395
 
            show_ids=False):
 
4626
            show_ids=False, directory=None):
4396
4627
        from bzrlib.annotate import annotate_file, annotate_file_tree
4397
4628
        wt, branch, relpath = \
4398
 
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
4399
 
        if wt is not None:
4400
 
            wt.lock_read()
4401
 
        else:
4402
 
            branch.lock_read()
4403
 
        try:
4404
 
            tree = _get_one_revision_tree('annotate', revision, branch=branch)
4405
 
            if wt is not None:
4406
 
                file_id = wt.path2id(relpath)
4407
 
            else:
4408
 
                file_id = tree.path2id(relpath)
4409
 
            if file_id is None:
4410
 
                raise errors.NotVersionedError(filename)
4411
 
            file_version = tree.inventory[file_id].revision
4412
 
            if wt is not None and revision is None:
4413
 
                # If there is a tree and we're not annotating historical
4414
 
                # versions, annotate the working tree's content.
4415
 
                annotate_file_tree(wt, file_id, self.outf, long, all,
4416
 
                    show_ids=show_ids)
4417
 
            else:
4418
 
                annotate_file(branch, file_version, file_id, long, all, self.outf,
4419
 
                              show_ids=show_ids)
4420
 
        finally:
4421
 
            if wt is not None:
4422
 
                wt.unlock()
4423
 
            else:
4424
 
                branch.unlock()
 
4629
            _open_directory_or_containing_tree_or_branch(filename, directory)
 
4630
        if wt is not None:
 
4631
            self.add_cleanup(wt.lock_read().unlock)
 
4632
        else:
 
4633
            self.add_cleanup(branch.lock_read().unlock)
 
4634
        tree = _get_one_revision_tree('annotate', revision, branch=branch)
 
4635
        self.add_cleanup(tree.lock_read().unlock)
 
4636
        if wt is not None:
 
4637
            file_id = wt.path2id(relpath)
 
4638
        else:
 
4639
            file_id = tree.path2id(relpath)
 
4640
        if file_id is None:
 
4641
            raise errors.NotVersionedError(filename)
 
4642
        file_version = tree.inventory[file_id].revision
 
4643
        if wt is not None and revision is None:
 
4644
            # If there is a tree and we're not annotating historical
 
4645
            # versions, annotate the working tree's content.
 
4646
            annotate_file_tree(wt, file_id, self.outf, long, all,
 
4647
                show_ids=show_ids)
 
4648
        else:
 
4649
            annotate_file(branch, file_version, file_id, long, all, self.outf,
 
4650
                          show_ids=show_ids)
4425
4651
 
4426
4652
 
4427
4653
class cmd_re_sign(Command):
4428
 
    """Create a digital signature for an existing revision."""
 
4654
    __doc__ = """Create a digital signature for an existing revision."""
4429
4655
    # TODO be able to replace existing ones.
4430
4656
 
4431
4657
    hidden = True # is this right ?
4432
4658
    takes_args = ['revision_id*']
4433
 
    takes_options = ['revision']
 
4659
    takes_options = ['directory', 'revision']
4434
4660
 
4435
 
    def run(self, revision_id_list=None, revision=None):
 
4661
    def run(self, revision_id_list=None, revision=None, directory=u'.'):
4436
4662
        if revision_id_list is not None and revision is not None:
4437
4663
            raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
4438
4664
        if revision_id_list is None and revision is None:
4439
4665
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
4440
 
        b = WorkingTree.open_containing(u'.')[0].branch
4441
 
        b.lock_write()
4442
 
        try:
4443
 
            return self._run(b, revision_id_list, revision)
4444
 
        finally:
4445
 
            b.unlock()
 
4666
        b = WorkingTree.open_containing(directory)[0].branch
 
4667
        self.add_cleanup(b.lock_write().unlock)
 
4668
        return self._run(b, revision_id_list, revision)
4446
4669
 
4447
4670
    def _run(self, b, revision_id_list, revision):
4448
4671
        import bzrlib.gpg as gpg
4493
4716
 
4494
4717
 
4495
4718
class cmd_bind(Command):
4496
 
    """Convert the current branch into a checkout of the supplied branch.
 
4719
    __doc__ = """Convert the current branch into a checkout of the supplied branch.
 
4720
    If no branch is supplied, rebind to the last bound location.
4497
4721
 
4498
4722
    Once converted into a checkout, commits must succeed on the master branch
4499
4723
    before they will be applied to the local branch.
4500
4724
 
4501
4725
    Bound branches use the nickname of its master branch unless it is set
4502
 
    locally, in which case binding will update the the local nickname to be
 
4726
    locally, in which case binding will update the local nickname to be
4503
4727
    that of the master.
4504
4728
    """
4505
4729
 
4506
4730
    _see_also = ['checkouts', 'unbind']
4507
4731
    takes_args = ['location?']
4508
 
    takes_options = []
 
4732
    takes_options = ['directory']
4509
4733
 
4510
 
    def run(self, location=None):
4511
 
        b, relpath = Branch.open_containing(u'.')
 
4734
    def run(self, location=None, directory=u'.'):
 
4735
        b, relpath = Branch.open_containing(directory)
4512
4736
        if location is None:
4513
4737
            try:
4514
4738
                location = b.get_old_bound_location()
4517
4741
                    'This format does not remember old locations.')
4518
4742
            else:
4519
4743
                if location is None:
4520
 
                    raise errors.BzrCommandError('No location supplied and no '
4521
 
                        'previous location known')
 
4744
                    if b.get_bound_location() is not None:
 
4745
                        raise errors.BzrCommandError('Branch is already bound')
 
4746
                    else:
 
4747
                        raise errors.BzrCommandError('No location supplied '
 
4748
                            'and no previous location known')
4522
4749
        b_other = Branch.open(location)
4523
4750
        try:
4524
4751
            b.bind(b_other)
4530
4757
 
4531
4758
 
4532
4759
class cmd_unbind(Command):
4533
 
    """Convert the current checkout into a regular branch.
 
4760
    __doc__ = """Convert the current checkout into a regular branch.
4534
4761
 
4535
4762
    After unbinding, the local branch is considered independent and subsequent
4536
4763
    commits will be local only.
4538
4765
 
4539
4766
    _see_also = ['checkouts', 'bind']
4540
4767
    takes_args = []
4541
 
    takes_options = []
 
4768
    takes_options = ['directory']
4542
4769
 
4543
 
    def run(self):
4544
 
        b, relpath = Branch.open_containing(u'.')
 
4770
    def run(self, directory=u'.'):
 
4771
        b, relpath = Branch.open_containing(directory)
4545
4772
        if not b.unbind():
4546
4773
            raise errors.BzrCommandError('Local branch is not bound')
4547
4774
 
4548
4775
 
4549
4776
class cmd_uncommit(Command):
4550
 
    """Remove the last committed revision.
 
4777
    __doc__ = """Remove the last committed revision.
4551
4778
 
4552
4779
    --verbose will print out what is being removed.
4553
4780
    --dry-run will go through all the motions, but not actually
4593
4820
            b = control.open_branch()
4594
4821
 
4595
4822
        if tree is not None:
4596
 
            tree.lock_write()
 
4823
            self.add_cleanup(tree.lock_write().unlock)
4597
4824
        else:
4598
 
            b.lock_write()
4599
 
        try:
4600
 
            return self._run(b, tree, dry_run, verbose, revision, force,
4601
 
                             local=local)
4602
 
        finally:
4603
 
            if tree is not None:
4604
 
                tree.unlock()
4605
 
            else:
4606
 
                b.unlock()
 
4825
            self.add_cleanup(b.lock_write().unlock)
 
4826
        return self._run(b, tree, dry_run, verbose, revision, force, local=local)
4607
4827
 
4608
4828
    def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
4609
4829
        from bzrlib.log import log_formatter, show_log
4641
4861
                 end_revision=last_revno)
4642
4862
 
4643
4863
        if dry_run:
4644
 
            print 'Dry-run, pretending to remove the above revisions.'
4645
 
            if not force:
4646
 
                val = raw_input('Press <enter> to continue')
 
4864
            self.outf.write('Dry-run, pretending to remove'
 
4865
                            ' the above revisions.\n')
4647
4866
        else:
4648
 
            print 'The above revision(s) will be removed.'
4649
 
            if not force:
4650
 
                val = raw_input('Are you sure [y/N]? ')
4651
 
                if val.lower() not in ('y', 'yes'):
4652
 
                    print 'Canceled'
4653
 
                    return 0
 
4867
            self.outf.write('The above revision(s) will be removed.\n')
 
4868
 
 
4869
        if not force:
 
4870
            if not ui.ui_factory.confirm_action(
 
4871
                    'Uncommit these revisions',
 
4872
                    'bzrlib.builtins.uncommit',
 
4873
                    {}):
 
4874
                self.outf.write('Canceled\n')
 
4875
                return 0
4654
4876
 
4655
4877
        mutter('Uncommitting from {%s} to {%s}',
4656
4878
               last_rev_id, rev_id)
4657
4879
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
4658
4880
                 revno=revno, local=local)
4659
 
        note('You can restore the old tip by running:\n'
4660
 
             '  bzr pull . -r revid:%s', last_rev_id)
 
4881
        self.outf.write('You can restore the old tip by running:\n'
 
4882
             '  bzr pull . -r revid:%s\n' % last_rev_id)
4661
4883
 
4662
4884
 
4663
4885
class cmd_break_lock(Command):
4664
 
    """Break a dead lock on a repository, branch or working directory.
 
4886
    __doc__ = """Break a dead lock.
 
4887
 
 
4888
    This command breaks a lock on a repository, branch, working directory or
 
4889
    config file.
4665
4890
 
4666
4891
    CAUTION: Locks should only be broken when you are sure that the process
4667
4892
    holding the lock has been stopped.
4668
4893
 
4669
 
    You can get information on what locks are open via the 'bzr info' command.
 
4894
    You can get information on what locks are open via the 'bzr info
 
4895
    [location]' command.
4670
4896
 
4671
4897
    :Examples:
4672
4898
        bzr break-lock
 
4899
        bzr break-lock bzr+ssh://example.com/bzr/foo
 
4900
        bzr break-lock --conf ~/.bazaar
4673
4901
    """
 
4902
 
4674
4903
    takes_args = ['location?']
 
4904
    takes_options = [
 
4905
        Option('config',
 
4906
               help='LOCATION is the directory where the config lock is.'),
 
4907
        Option('force',
 
4908
            help='Do not ask for confirmation before breaking the lock.'),
 
4909
        ]
4675
4910
 
4676
 
    def run(self, location=None, show=False):
 
4911
    def run(self, location=None, config=False, force=False):
4677
4912
        if location is None:
4678
4913
            location = u'.'
4679
 
        control, relpath = bzrdir.BzrDir.open_containing(location)
4680
 
        try:
4681
 
            control.break_lock()
4682
 
        except NotImplementedError:
4683
 
            pass
 
4914
        if force:
 
4915
            ui.ui_factory = ui.ConfirmationUserInterfacePolicy(ui.ui_factory,
 
4916
                None,
 
4917
                {'bzrlib.lockdir.break': True})
 
4918
        if config:
 
4919
            conf = _mod_config.LockableConfig(file_name=location)
 
4920
            conf.break_lock()
 
4921
        else:
 
4922
            control, relpath = bzrdir.BzrDir.open_containing(location)
 
4923
            try:
 
4924
                control.break_lock()
 
4925
            except NotImplementedError:
 
4926
                pass
4684
4927
 
4685
4928
 
4686
4929
class cmd_wait_until_signalled(Command):
4687
 
    """Test helper for test_start_and_stop_bzr_subprocess_send_signal.
 
4930
    __doc__ = """Test helper for test_start_and_stop_bzr_subprocess_send_signal.
4688
4931
 
4689
4932
    This just prints a line to signal when it is ready, then blocks on stdin.
4690
4933
    """
4698
4941
 
4699
4942
 
4700
4943
class cmd_serve(Command):
4701
 
    """Run the bzr server."""
 
4944
    __doc__ = """Run the bzr server."""
4702
4945
 
4703
4946
    aliases = ['server']
4704
4947
 
4705
4948
    takes_options = [
4706
4949
        Option('inet',
4707
4950
               help='Serve on stdin/out for use from inetd or sshd.'),
4708
 
        RegistryOption('protocol', 
4709
 
               help="Protocol to serve.", 
 
4951
        RegistryOption('protocol',
 
4952
               help="Protocol to serve.",
4710
4953
               lazy_registry=('bzrlib.transport', 'transport_server_registry'),
4711
4954
               value_switches=True),
4712
4955
        Option('port',
4715
4958
                    'result in a dynamically allocated port.  The default port '
4716
4959
                    'depends on the protocol.',
4717
4960
               type=str),
4718
 
        Option('directory',
4719
 
               help='Serve contents of this directory.',
4720
 
               type=unicode),
 
4961
        custom_help('directory',
 
4962
               help='Serve contents of this directory.'),
4721
4963
        Option('allow-writes',
4722
4964
               help='By default the server is a readonly server.  Supplying '
4723
4965
                    '--allow-writes enables write access to the contents of '
4724
 
                    'the served directory and below.'
 
4966
                    'the served directory and below.  Note that ``bzr serve`` '
 
4967
                    'does not perform authentication, so unless some form of '
 
4968
                    'external authentication is arranged supplying this '
 
4969
                    'option leads to global uncontrolled write access to your '
 
4970
                    'file system.'
4725
4971
                ),
4726
4972
        ]
4727
4973
 
4746
4992
 
4747
4993
    def run(self, port=None, inet=False, directory=None, allow_writes=False,
4748
4994
            protocol=None):
4749
 
        from bzrlib.transport import get_transport, transport_server_registry
 
4995
        from bzrlib import transport
4750
4996
        if directory is None:
4751
4997
            directory = os.getcwd()
4752
4998
        if protocol is None:
4753
 
            protocol = transport_server_registry.get()
 
4999
            protocol = transport.transport_server_registry.get()
4754
5000
        host, port = self.get_host_and_port(port)
4755
5001
        url = urlutils.local_path_to_url(directory)
4756
5002
        if not allow_writes:
4757
5003
            url = 'readonly+' + url
4758
 
        transport = get_transport(url)
4759
 
        protocol(transport, host, port, inet)
 
5004
        t = transport.get_transport(url)
 
5005
        protocol(t, host, port, inet)
4760
5006
 
4761
5007
 
4762
5008
class cmd_join(Command):
4763
 
    """Combine a tree into its containing tree.
 
5009
    __doc__ = """Combine a tree into its containing tree.
4764
5010
 
4765
5011
    This command requires the target tree to be in a rich-root format.
4766
5012
 
4768
5014
    not part of it.  (Such trees can be produced by "bzr split", but also by
4769
5015
    running "bzr branch" with the target inside a tree.)
4770
5016
 
4771
 
    The result is a combined tree, with the subtree no longer an independant
 
5017
    The result is a combined tree, with the subtree no longer an independent
4772
5018
    part.  This is marked as a merge of the subtree into the containing tree,
4773
5019
    and all history is preserved.
4774
5020
    """
4806
5052
 
4807
5053
 
4808
5054
class cmd_split(Command):
4809
 
    """Split a subdirectory of a tree into a separate tree.
 
5055
    __doc__ = """Split a subdirectory of a tree into a separate tree.
4810
5056
 
4811
5057
    This command will produce a target tree in a format that supports
4812
5058
    rich roots, like 'rich-root' or 'rich-root-pack'.  These formats cannot be
4832
5078
 
4833
5079
 
4834
5080
class cmd_merge_directive(Command):
4835
 
    """Generate a merge directive for auto-merge tools.
 
5081
    __doc__ = """Generate a merge directive for auto-merge tools.
4836
5082
 
4837
5083
    A directive requests a merge to be performed, and also provides all the
4838
5084
    information necessary to do so.  This means it must either include a
4855
5101
    _see_also = ['send']
4856
5102
 
4857
5103
    takes_options = [
 
5104
        'directory',
4858
5105
        RegistryOption.from_kwargs('patch-type',
4859
5106
            'The type of patch to include in the directive.',
4860
5107
            title='Patch type',
4873
5120
    encoding_type = 'exact'
4874
5121
 
4875
5122
    def run(self, submit_branch=None, public_branch=None, patch_type='bundle',
4876
 
            sign=False, revision=None, mail_to=None, message=None):
 
5123
            sign=False, revision=None, mail_to=None, message=None,
 
5124
            directory=u'.'):
4877
5125
        from bzrlib.revision import ensure_null, NULL_REVISION
4878
5126
        include_patch, include_bundle = {
4879
5127
            'plain': (False, False),
4880
5128
            'diff': (True, False),
4881
5129
            'bundle': (True, True),
4882
5130
            }[patch_type]
4883
 
        branch = Branch.open('.')
 
5131
        branch = Branch.open(directory)
4884
5132
        stored_submit_branch = branch.get_submit_branch()
4885
5133
        if submit_branch is None:
4886
5134
            submit_branch = stored_submit_branch
4931
5179
 
4932
5180
 
4933
5181
class cmd_send(Command):
4934
 
    """Mail or create a merge-directive for submitting changes.
 
5182
    __doc__ = """Mail or create a merge-directive for submitting changes.
4935
5183
 
4936
5184
    A merge directive provides many things needed for requesting merges:
4937
5185
 
4943
5191
      directly from the merge directive, without retrieving data from a
4944
5192
      branch.
4945
5193
 
4946
 
    If --no-bundle is specified, then public_branch is needed (and must be
4947
 
    up-to-date), so that the receiver can perform the merge using the
4948
 
    public_branch.  The public_branch is always included if known, so that
4949
 
    people can check it later.
4950
 
 
4951
 
    The submit branch defaults to the parent, but can be overridden.  Both
4952
 
    submit branch and public branch will be remembered if supplied.
4953
 
 
4954
 
    If a public_branch is known for the submit_branch, that public submit
4955
 
    branch is used in the merge instructions.  This means that a local mirror
4956
 
    can be used as your actual submit branch, once you have set public_branch
4957
 
    for that mirror.
 
5194
    `bzr send` creates a compact data set that, when applied using bzr
 
5195
    merge, has the same effect as merging from the source branch.  
 
5196
    
 
5197
    By default the merge directive is self-contained and can be applied to any
 
5198
    branch containing submit_branch in its ancestory without needing access to
 
5199
    the source branch.
 
5200
    
 
5201
    If --no-bundle is specified, then Bazaar doesn't send the contents of the
 
5202
    revisions, but only a structured request to merge from the
 
5203
    public_location.  In that case the public_branch is needed and it must be
 
5204
    up-to-date and accessible to the recipient.  The public_branch is always
 
5205
    included if known, so that people can check it later.
 
5206
 
 
5207
    The submit branch defaults to the parent of the source branch, but can be
 
5208
    overridden.  Both submit branch and public branch will be remembered in
 
5209
    branch.conf the first time they are used for a particular branch.  The
 
5210
    source branch defaults to that containing the working directory, but can
 
5211
    be changed using --from.
 
5212
 
 
5213
    In order to calculate those changes, bzr must analyse the submit branch.
 
5214
    Therefore it is most efficient for the submit branch to be a local mirror.
 
5215
    If a public location is known for the submit_branch, that location is used
 
5216
    in the merge directive.
 
5217
 
 
5218
    The default behaviour is to send the merge directive by mail, unless -o is
 
5219
    given, in which case it is sent to a file.
4958
5220
 
4959
5221
    Mail is sent using your preferred mail program.  This should be transparent
4960
 
    on Windows (it uses MAPI).  On Linux, it requires the xdg-email utility.
 
5222
    on Windows (it uses MAPI).  On Unix, it requires the xdg-email utility.
4961
5223
    If the preferred client can't be found (or used), your editor will be used.
4962
5224
 
4963
5225
    To use a specific mail program, set the mail_client configuration option.
4964
5226
    (For Thunderbird 1.5, this works around some bugs.)  Supported values for
4965
 
    specific clients are "claws", "evolution", "kmail", "mutt", and
4966
 
    "thunderbird"; generic options are "default", "editor", "emacsclient",
4967
 
    "mapi", and "xdg-email".  Plugins may also add supported clients.
 
5227
    specific clients are "claws", "evolution", "kmail", "mail.app" (MacOS X's
 
5228
    Mail.app), "mutt", and "thunderbird"; generic options are "default",
 
5229
    "editor", "emacsclient", "mapi", and "xdg-email".  Plugins may also add
 
5230
    supported clients.
4968
5231
 
4969
5232
    If mail is being sent, a to address is required.  This can be supplied
4970
5233
    either on the commandline, by setting the submit_to configuration
4979
5242
 
4980
5243
    The merge directives created by bzr send may be applied using bzr merge or
4981
5244
    bzr pull by specifying a file containing a merge directive as the location.
 
5245
 
 
5246
    bzr send makes extensive use of public locations to map local locations into
 
5247
    URLs that can be used by other people.  See `bzr help configuration` to
 
5248
    set them, and use `bzr info` to display them.
4982
5249
    """
4983
5250
 
4984
5251
    encoding_type = 'exact'
5000
5267
               short_name='f',
5001
5268
               type=unicode),
5002
5269
        Option('output', short_name='o',
5003
 
               help='Write merge directive to this file; '
 
5270
               help='Write merge directive to this file or directory; '
5004
5271
                    'use - for stdout.',
5005
5272
               type=unicode),
5006
5273
        Option('strict',
5029
5296
 
5030
5297
 
5031
5298
class cmd_bundle_revisions(cmd_send):
5032
 
    """Create a merge-directive for submitting changes.
 
5299
    __doc__ = """Create a merge-directive for submitting changes.
5033
5300
 
5034
5301
    A merge directive provides many things needed for requesting merges:
5035
5302
 
5102
5369
 
5103
5370
 
5104
5371
class cmd_tag(Command):
5105
 
    """Create, remove or modify a tag naming a revision.
 
5372
    __doc__ = """Create, remove or modify a tag naming a revision.
5106
5373
 
5107
5374
    Tags give human-meaningful names to revisions.  Commands that take a -r
5108
5375
    (--revision) option can be given -rtag:X, where X is any previously
5116
5383
 
5117
5384
    To rename a tag (change the name but keep it on the same revsion), run ``bzr
5118
5385
    tag new-name -r tag:old-name`` and then ``bzr tag --delete oldname``.
 
5386
 
 
5387
    If no tag name is specified it will be determined through the 
 
5388
    'automatic_tag_name' hook. This can e.g. be used to automatically tag
 
5389
    upstream releases by reading configure.ac. See ``bzr help hooks`` for
 
5390
    details.
5119
5391
    """
5120
5392
 
5121
5393
    _see_also = ['commit', 'tags']
5122
 
    takes_args = ['tag_name']
 
5394
    takes_args = ['tag_name?']
5123
5395
    takes_options = [
5124
5396
        Option('delete',
5125
5397
            help='Delete this tag rather than placing it.',
5126
5398
            ),
5127
 
        Option('directory',
5128
 
            help='Branch in which to place the tag.',
5129
 
            short_name='d',
5130
 
            type=unicode,
5131
 
            ),
 
5399
        custom_help('directory',
 
5400
            help='Branch in which to place the tag.'),
5132
5401
        Option('force',
5133
5402
            help='Replace existing tags.',
5134
5403
            ),
5135
5404
        'revision',
5136
5405
        ]
5137
5406
 
5138
 
    def run(self, tag_name,
 
5407
    def run(self, tag_name=None,
5139
5408
            delete=None,
5140
5409
            directory='.',
5141
5410
            force=None,
5142
5411
            revision=None,
5143
5412
            ):
5144
5413
        branch, relpath = Branch.open_containing(directory)
5145
 
        branch.lock_write()
5146
 
        try:
5147
 
            if delete:
5148
 
                branch.tags.delete_tag(tag_name)
5149
 
                self.outf.write('Deleted tag %s.\n' % tag_name)
 
5414
        self.add_cleanup(branch.lock_write().unlock)
 
5415
        if delete:
 
5416
            if tag_name is None:
 
5417
                raise errors.BzrCommandError("No tag specified to delete.")
 
5418
            branch.tags.delete_tag(tag_name)
 
5419
            note('Deleted tag %s.' % tag_name)
 
5420
        else:
 
5421
            if revision:
 
5422
                if len(revision) != 1:
 
5423
                    raise errors.BzrCommandError(
 
5424
                        "Tags can only be placed on a single revision, "
 
5425
                        "not on a range")
 
5426
                revision_id = revision[0].as_revision_id(branch)
5150
5427
            else:
5151
 
                if revision:
5152
 
                    if len(revision) != 1:
5153
 
                        raise errors.BzrCommandError(
5154
 
                            "Tags can only be placed on a single revision, "
5155
 
                            "not on a range")
5156
 
                    revision_id = revision[0].as_revision_id(branch)
5157
 
                else:
5158
 
                    revision_id = branch.last_revision()
5159
 
                if (not force) and branch.tags.has_tag(tag_name):
5160
 
                    raise errors.TagAlreadyExists(tag_name)
5161
 
                branch.tags.set_tag(tag_name, revision_id)
5162
 
                self.outf.write('Created tag %s.\n' % tag_name)
5163
 
        finally:
5164
 
            branch.unlock()
 
5428
                revision_id = branch.last_revision()
 
5429
            if tag_name is None:
 
5430
                tag_name = branch.automatic_tag_name(revision_id)
 
5431
                if tag_name is None:
 
5432
                    raise errors.BzrCommandError(
 
5433
                        "Please specify a tag name.")
 
5434
            if (not force) and branch.tags.has_tag(tag_name):
 
5435
                raise errors.TagAlreadyExists(tag_name)
 
5436
            branch.tags.set_tag(tag_name, revision_id)
 
5437
            note('Created tag %s.' % tag_name)
5165
5438
 
5166
5439
 
5167
5440
class cmd_tags(Command):
5168
 
    """List tags.
 
5441
    __doc__ = """List tags.
5169
5442
 
5170
5443
    This command shows a table of tag names and the revisions they reference.
5171
5444
    """
5172
5445
 
5173
5446
    _see_also = ['tag']
5174
5447
    takes_options = [
5175
 
        Option('directory',
5176
 
            help='Branch whose tags should be displayed.',
5177
 
            short_name='d',
5178
 
            type=unicode,
5179
 
            ),
 
5448
        custom_help('directory',
 
5449
            help='Branch whose tags should be displayed.'),
5180
5450
        RegistryOption.from_kwargs('sort',
5181
5451
            'Sort tags by different criteria.', title='Sorting',
5182
 
            alpha='Sort tags lexicographically (default).',
 
5452
            natural='Sort numeric substrings as numbers:'
 
5453
                    ' suitable for version numbers. (default)',
 
5454
            alpha='Sort tags lexicographically.',
5183
5455
            time='Sort tags chronologically.',
5184
5456
            ),
5185
5457
        'show-ids',
5189
5461
    @display_command
5190
5462
    def run(self,
5191
5463
            directory='.',
5192
 
            sort='alpha',
 
5464
            sort='natural',
5193
5465
            show_ids=False,
5194
5466
            revision=None,
5195
5467
            ):
5199
5471
        if not tags:
5200
5472
            return
5201
5473
 
5202
 
        branch.lock_read()
5203
 
        try:
5204
 
            if revision:
5205
 
                graph = branch.repository.get_graph()
5206
 
                rev1, rev2 = _get_revision_range(revision, branch, self.name())
5207
 
                revid1, revid2 = rev1.rev_id, rev2.rev_id
5208
 
                # only show revisions between revid1 and revid2 (inclusive)
5209
 
                tags = [(tag, revid) for tag, revid in tags if
5210
 
                    graph.is_between(revid, revid1, revid2)]
5211
 
            if sort == 'alpha':
5212
 
                tags.sort()
5213
 
            elif sort == 'time':
5214
 
                timestamps = {}
5215
 
                for tag, revid in tags:
5216
 
                    try:
5217
 
                        revobj = branch.repository.get_revision(revid)
5218
 
                    except errors.NoSuchRevision:
5219
 
                        timestamp = sys.maxint # place them at the end
5220
 
                    else:
5221
 
                        timestamp = revobj.timestamp
5222
 
                    timestamps[revid] = timestamp
5223
 
                tags.sort(key=lambda x: timestamps[x[1]])
5224
 
            if not show_ids:
5225
 
                # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
5226
 
                for index, (tag, revid) in enumerate(tags):
5227
 
                    try:
5228
 
                        revno = branch.revision_id_to_dotted_revno(revid)
5229
 
                        if isinstance(revno, tuple):
5230
 
                            revno = '.'.join(map(str, revno))
5231
 
                    except errors.NoSuchRevision:
5232
 
                        # Bad tag data/merges can lead to tagged revisions
5233
 
                        # which are not in this branch. Fail gracefully ...
5234
 
                        revno = '?'
5235
 
                    tags[index] = (tag, revno)
5236
 
        finally:
5237
 
            branch.unlock()
 
5474
        self.add_cleanup(branch.lock_read().unlock)
 
5475
        if revision:
 
5476
            graph = branch.repository.get_graph()
 
5477
            rev1, rev2 = _get_revision_range(revision, branch, self.name())
 
5478
            revid1, revid2 = rev1.rev_id, rev2.rev_id
 
5479
            # only show revisions between revid1 and revid2 (inclusive)
 
5480
            tags = [(tag, revid) for tag, revid in tags if
 
5481
                graph.is_between(revid, revid1, revid2)]
 
5482
        if sort == 'natural':
 
5483
            def natural_sort_key(tag):
 
5484
                return [f(s) for f,s in 
 
5485
                        zip(itertools.cycle((unicode.lower,int)),
 
5486
                                            re.split('([0-9]+)', tag[0]))]
 
5487
            tags.sort(key=natural_sort_key)
 
5488
        elif sort == 'alpha':
 
5489
            tags.sort()
 
5490
        elif sort == 'time':
 
5491
            timestamps = {}
 
5492
            for tag, revid in tags:
 
5493
                try:
 
5494
                    revobj = branch.repository.get_revision(revid)
 
5495
                except errors.NoSuchRevision:
 
5496
                    timestamp = sys.maxint # place them at the end
 
5497
                else:
 
5498
                    timestamp = revobj.timestamp
 
5499
                timestamps[revid] = timestamp
 
5500
            tags.sort(key=lambda x: timestamps[x[1]])
 
5501
        if not show_ids:
 
5502
            # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
 
5503
            for index, (tag, revid) in enumerate(tags):
 
5504
                try:
 
5505
                    revno = branch.revision_id_to_dotted_revno(revid)
 
5506
                    if isinstance(revno, tuple):
 
5507
                        revno = '.'.join(map(str, revno))
 
5508
                except errors.NoSuchRevision:
 
5509
                    # Bad tag data/merges can lead to tagged revisions
 
5510
                    # which are not in this branch. Fail gracefully ...
 
5511
                    revno = '?'
 
5512
                tags[index] = (tag, revno)
 
5513
        self.cleanup_now()
5238
5514
        for tag, revspec in tags:
5239
5515
            self.outf.write('%-20s %s\n' % (tag, revspec))
5240
5516
 
5241
5517
 
5242
5518
class cmd_reconfigure(Command):
5243
 
    """Reconfigure the type of a bzr directory.
 
5519
    __doc__ = """Reconfigure the type of a bzr directory.
5244
5520
 
5245
5521
    A target configuration must be specified.
5246
5522
 
5331
5607
 
5332
5608
 
5333
5609
class cmd_switch(Command):
5334
 
    """Set the branch of a checkout and update.
 
5610
    __doc__ = """Set the branch of a checkout and update.
5335
5611
 
5336
5612
    For lightweight checkouts, this changes the branch being referenced.
5337
5613
    For heavyweight checkouts, this checks that there are no local commits
5349
5625
    /path/to/newbranch.
5350
5626
 
5351
5627
    Bound branches use the nickname of its master branch unless it is set
5352
 
    locally, in which case switching will update the the local nickname to be
 
5628
    locally, in which case switching will update the local nickname to be
5353
5629
    that of the master.
5354
5630
    """
5355
5631
 
5356
 
    takes_args = ['to_location']
5357
 
    takes_options = [Option('force',
 
5632
    takes_args = ['to_location?']
 
5633
    takes_options = ['directory',
 
5634
                     Option('force',
5358
5635
                        help='Switch even if local commits will be lost.'),
 
5636
                     'revision',
5359
5637
                     Option('create-branch', short_name='b',
5360
5638
                        help='Create the target branch from this one before'
5361
5639
                             ' switching to it.'),
5362
 
                     ]
 
5640
                    ]
5363
5641
 
5364
 
    def run(self, to_location, force=False, create_branch=False):
 
5642
    def run(self, to_location=None, force=False, create_branch=False,
 
5643
            revision=None, directory=u'.'):
5365
5644
        from bzrlib import switch
5366
 
        tree_location = '.'
 
5645
        tree_location = directory
 
5646
        revision = _get_one_revision('switch', revision)
5367
5647
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
 
5648
        if to_location is None:
 
5649
            if revision is None:
 
5650
                raise errors.BzrCommandError('You must supply either a'
 
5651
                                             ' revision or a location')
 
5652
            to_location = tree_location
5368
5653
        try:
5369
5654
            branch = control_dir.open_branch()
5370
5655
            had_explicit_nick = branch.get_config().has_explicit_nickname()
5375
5660
            if branch is None:
5376
5661
                raise errors.BzrCommandError('cannot create branch without'
5377
5662
                                             ' source branch')
 
5663
            to_location = directory_service.directories.dereference(
 
5664
                              to_location)
5378
5665
            if '/' not in to_location and '\\' not in to_location:
5379
5666
                # This path is meant to be relative to the existing branch
5380
5667
                this_url = self._get_branch_location(control_dir)
5382
5669
            to_branch = branch.bzrdir.sprout(to_location,
5383
5670
                                 possible_transports=[branch.bzrdir.root_transport],
5384
5671
                                 source_branch=branch).open_branch()
5385
 
            # try:
5386
 
            #     from_branch = control_dir.open_branch()
5387
 
            # except errors.NotBranchError:
5388
 
            #     raise BzrCommandError('Cannot create a branch from this'
5389
 
            #         ' location when we cannot open this branch')
5390
 
            # from_branch.bzrdir.sprout(
5391
 
            pass
5392
5672
        else:
5393
5673
            try:
5394
5674
                to_branch = Branch.open(to_location)
5396
5676
                this_url = self._get_branch_location(control_dir)
5397
5677
                to_branch = Branch.open(
5398
5678
                    urlutils.join(this_url, '..', to_location))
5399
 
        switch.switch(control_dir, to_branch, force)
 
5679
        if revision is not None:
 
5680
            revision = revision.as_revision_id(to_branch)
 
5681
        switch.switch(control_dir, to_branch, force, revision_id=revision)
5400
5682
        if had_explicit_nick:
5401
5683
            branch = control_dir.open_branch() #get the new branch!
5402
5684
            branch.nick = to_branch.nick
5422
5704
 
5423
5705
 
5424
5706
class cmd_view(Command):
5425
 
    """Manage filtered views.
 
5707
    __doc__ = """Manage filtered views.
5426
5708
 
5427
5709
    Views provide a mask over the tree so that users can focus on
5428
5710
    a subset of a tree when doing their work. After creating a view,
5508
5790
            name=None,
5509
5791
            switch=None,
5510
5792
            ):
5511
 
        tree, file_list = tree_files(file_list, apply_view=False)
 
5793
        tree, file_list = WorkingTree.open_containing_paths(file_list,
 
5794
            apply_view=False)
5512
5795
        current_view, view_dict = tree.views.get_view_info()
5513
5796
        if name is None:
5514
5797
            name = current_view
5576
5859
 
5577
5860
 
5578
5861
class cmd_hooks(Command):
5579
 
    """Show hooks."""
 
5862
    __doc__ = """Show hooks."""
5580
5863
 
5581
5864
    hidden = True
5582
5865
 
5595
5878
                    self.outf.write("    <no hooks installed>\n")
5596
5879
 
5597
5880
 
 
5881
class cmd_remove_branch(Command):
 
5882
    __doc__ = """Remove a branch.
 
5883
 
 
5884
    This will remove the branch from the specified location but 
 
5885
    will keep any working tree or repository in place.
 
5886
 
 
5887
    :Examples:
 
5888
 
 
5889
      Remove the branch at repo/trunk::
 
5890
 
 
5891
        bzr remove-branch repo/trunk
 
5892
 
 
5893
    """
 
5894
 
 
5895
    takes_args = ["location?"]
 
5896
 
 
5897
    aliases = ["rmbranch"]
 
5898
 
 
5899
    def run(self, location=None):
 
5900
        if location is None:
 
5901
            location = "."
 
5902
        branch = Branch.open_containing(location)[0]
 
5903
        branch.bzrdir.destroy_branch()
 
5904
 
 
5905
 
5598
5906
class cmd_shelve(Command):
5599
 
    """Temporarily set aside some changes from the current tree.
 
5907
    __doc__ = """Temporarily set aside some changes from the current tree.
5600
5908
 
5601
5909
    Shelve allows you to temporarily put changes you've made "on the shelf",
5602
5910
    ie. out of the way, until a later time when you can bring them back from
5618
5926
 
5619
5927
    You can put multiple items on the shelf, and by default, 'unshelve' will
5620
5928
    restore the most recently shelved changes.
 
5929
 
 
5930
    For complicated changes, it is possible to edit the changes in a separate
 
5931
    editor program to decide what the file remaining in the working copy
 
5932
    should look like.  To do this, add the configuration option
 
5933
 
 
5934
        change_editor = PROGRAM @new_path @old_path
 
5935
 
 
5936
    where @new_path is replaced with the path of the new version of the 
 
5937
    file and @old_path is replaced with the path of the old version of 
 
5938
    the file.  The PROGRAM should save the new file with the desired 
 
5939
    contents of the file in the working tree.
 
5940
        
5621
5941
    """
5622
5942
 
5623
5943
    takes_args = ['file*']
5624
5944
 
5625
5945
    takes_options = [
 
5946
        'directory',
5626
5947
        'revision',
5627
5948
        Option('all', help='Shelve all changes.'),
5628
5949
        'message',
5634
5955
        Option('destroy',
5635
5956
               help='Destroy removed changes instead of shelving them.'),
5636
5957
    ]
5637
 
    _see_also = ['unshelve']
 
5958
    _see_also = ['unshelve', 'configuration']
5638
5959
 
5639
5960
    def run(self, revision=None, all=False, file_list=None, message=None,
5640
 
            writer=None, list=False, destroy=False):
 
5961
            writer=None, list=False, destroy=False, directory=None):
5641
5962
        if list:
5642
 
            return self.run_for_list()
 
5963
            return self.run_for_list(directory=directory)
5643
5964
        from bzrlib.shelf_ui import Shelver
5644
5965
        if writer is None:
5645
5966
            writer = bzrlib.option.diff_writer_registry.get()
5646
5967
        try:
5647
5968
            shelver = Shelver.from_args(writer(sys.stdout), revision, all,
5648
 
                file_list, message, destroy=destroy)
 
5969
                file_list, message, destroy=destroy, directory=directory)
5649
5970
            try:
5650
5971
                shelver.run()
5651
5972
            finally:
5652
 
                shelver.work_tree.unlock()
 
5973
                shelver.finalize()
5653
5974
        except errors.UserAbort:
5654
5975
            return 0
5655
5976
 
5656
 
    def run_for_list(self):
5657
 
        tree = WorkingTree.open_containing('.')[0]
5658
 
        tree.lock_read()
5659
 
        try:
5660
 
            manager = tree.get_shelf_manager()
5661
 
            shelves = manager.active_shelves()
5662
 
            if len(shelves) == 0:
5663
 
                note('No shelved changes.')
5664
 
                return 0
5665
 
            for shelf_id in reversed(shelves):
5666
 
                message = manager.get_metadata(shelf_id).get('message')
5667
 
                if message is None:
5668
 
                    message = '<no message>'
5669
 
                self.outf.write('%3d: %s\n' % (shelf_id, message))
5670
 
            return 1
5671
 
        finally:
5672
 
            tree.unlock()
 
5977
    def run_for_list(self, directory=None):
 
5978
        if directory is None:
 
5979
            directory = u'.'
 
5980
        tree = WorkingTree.open_containing(directory)[0]
 
5981
        self.add_cleanup(tree.lock_read().unlock)
 
5982
        manager = tree.get_shelf_manager()
 
5983
        shelves = manager.active_shelves()
 
5984
        if len(shelves) == 0:
 
5985
            note('No shelved changes.')
 
5986
            return 0
 
5987
        for shelf_id in reversed(shelves):
 
5988
            message = manager.get_metadata(shelf_id).get('message')
 
5989
            if message is None:
 
5990
                message = '<no message>'
 
5991
            self.outf.write('%3d: %s\n' % (shelf_id, message))
 
5992
        return 1
5673
5993
 
5674
5994
 
5675
5995
class cmd_unshelve(Command):
5676
 
    """Restore shelved changes.
 
5996
    __doc__ = """Restore shelved changes.
5677
5997
 
5678
5998
    By default, the most recently shelved changes are restored. However if you
5679
5999
    specify a shelf by id those changes will be restored instead.  This works
5682
6002
 
5683
6003
    takes_args = ['shelf_id?']
5684
6004
    takes_options = [
 
6005
        'directory',
5685
6006
        RegistryOption.from_kwargs(
5686
6007
            'action', help="The action to perform.",
5687
6008
            enum_switch=False, value_switches=True,
5688
6009
            apply="Apply changes and remove from the shelf.",
5689
6010
            dry_run="Show changes, but do not apply or remove them.",
5690
 
            delete_only="Delete changes without applying them."
 
6011
            preview="Instead of unshelving the changes, show the diff that "
 
6012
                    "would result from unshelving.",
 
6013
            delete_only="Delete changes without applying them.",
 
6014
            keep="Apply changes but don't delete them.",
5691
6015
        )
5692
6016
    ]
5693
6017
    _see_also = ['shelve']
5694
6018
 
5695
 
    def run(self, shelf_id=None, action='apply'):
 
6019
    def run(self, shelf_id=None, action='apply', directory=u'.'):
5696
6020
        from bzrlib.shelf_ui import Unshelver
5697
 
        unshelver = Unshelver.from_args(shelf_id, action)
 
6021
        unshelver = Unshelver.from_args(shelf_id, action, directory=directory)
5698
6022
        try:
5699
6023
            unshelver.run()
5700
6024
        finally:
5702
6026
 
5703
6027
 
5704
6028
class cmd_clean_tree(Command):
5705
 
    """Remove unwanted files from working tree.
 
6029
    __doc__ = """Remove unwanted files from working tree.
5706
6030
 
5707
6031
    By default, only unknown files, not ignored files, are deleted.  Versioned
5708
6032
    files are never deleted.
5716
6040
 
5717
6041
    To check what clean-tree will do, use --dry-run.
5718
6042
    """
5719
 
    takes_options = [Option('ignored', help='Delete all ignored files.'),
 
6043
    takes_options = ['directory',
 
6044
                     Option('ignored', help='Delete all ignored files.'),
5720
6045
                     Option('detritus', help='Delete conflict files, merge'
5721
6046
                            ' backups, and failed selftest dirs.'),
5722
6047
                     Option('unknown',
5725
6050
                            ' deleting them.'),
5726
6051
                     Option('force', help='Do not prompt before deleting.')]
5727
6052
    def run(self, unknown=False, ignored=False, detritus=False, dry_run=False,
5728
 
            force=False):
 
6053
            force=False, directory=u'.'):
5729
6054
        from bzrlib.clean_tree import clean_tree
5730
6055
        if not (unknown or ignored or detritus):
5731
6056
            unknown = True
5732
6057
        if dry_run:
5733
6058
            force = True
5734
 
        clean_tree('.', unknown=unknown, ignored=ignored, detritus=detritus,
5735
 
                   dry_run=dry_run, no_prompt=force)
 
6059
        clean_tree(directory, unknown=unknown, ignored=ignored,
 
6060
                   detritus=detritus, dry_run=dry_run, no_prompt=force)
5736
6061
 
5737
6062
 
5738
6063
class cmd_reference(Command):
5739
 
    """list, view and set branch locations for nested trees.
 
6064
    __doc__ = """list, view and set branch locations for nested trees.
5740
6065
 
5741
6066
    If no arguments are provided, lists the branch locations for nested trees.
5742
6067
    If one argument is provided, display the branch location for that tree.
5782
6107
            self.outf.write('%s %s\n' % (path, location))
5783
6108
 
5784
6109
 
5785
 
# these get imported and then picked up by the scan for cmd_*
5786
 
# TODO: Some more consistent way to split command definitions across files;
5787
 
# we do need to load at least some information about them to know of
5788
 
# aliases.  ideally we would avoid loading the implementation until the
5789
 
# details were needed.
5790
 
from bzrlib.cmd_version_info import cmd_version_info
5791
 
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
5792
 
from bzrlib.bundle.commands import (
5793
 
    cmd_bundle_info,
5794
 
    )
5795
 
from bzrlib.foreign import cmd_dpush
5796
 
from bzrlib.sign_my_commits import cmd_sign_my_commits
5797
 
from bzrlib.weave_commands import cmd_versionedfile_list, \
5798
 
        cmd_weave_plan_merge, cmd_weave_merge_text
 
6110
def _register_lazy_builtins():
 
6111
    # register lazy builtins from other modules; called at startup and should
 
6112
    # be only called once.
 
6113
    for (name, aliases, module_name) in [
 
6114
        ('cmd_bundle_info', [], 'bzrlib.bundle.commands'),
 
6115
        ('cmd_config', [], 'bzrlib.config'),
 
6116
        ('cmd_dpush', [], 'bzrlib.foreign'),
 
6117
        ('cmd_version_info', [], 'bzrlib.cmd_version_info'),
 
6118
        ('cmd_resolve', ['resolved'], 'bzrlib.conflicts'),
 
6119
        ('cmd_conflicts', [], 'bzrlib.conflicts'),
 
6120
        ('cmd_sign_my_commits', [], 'bzrlib.sign_my_commits'),
 
6121
        ('cmd_test_script', [], 'bzrlib.cmd_test_script'),
 
6122
        ]:
 
6123
        builtin_command_registry.register_lazy(name, aliases, module_name)