~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Jelmer Vernooij
  • Date: 2012-01-19 00:55:26 UTC
  • mto: (6437.3.23 2.5)
  • mto: This revision was merged to the branch mainline in revision 6451.
  • Revision ID: jelmer@samba.org-20120119005526-q2gst8d3v8qtqpot
Avoid the word safe.

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-2011 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
16
16
 
17
17
"""builtin bzr commands"""
18
18
 
 
19
from __future__ import absolute_import
 
20
 
19
21
import os
20
22
 
21
 
from bzrlib.lazy_import import lazy_import
22
 
lazy_import(globals(), """
23
 
import codecs
 
23
import bzrlib.bzrdir
 
24
 
 
25
from bzrlib import lazy_import
 
26
lazy_import.lazy_import(globals(), """
24
27
import cStringIO
 
28
import errno
25
29
import sys
26
30
import time
27
31
 
30
34
    bugtracker,
31
35
    bundle,
32
36
    btree_index,
33
 
    bzrdir,
 
37
    controldir,
 
38
    directory_service,
34
39
    delta,
35
 
    config,
 
40
    config as _mod_config,
36
41
    errors,
37
42
    globbing,
38
43
    hooks,
43
48
    reconfigure,
44
49
    rename_map,
45
50
    revision as _mod_revision,
46
 
    symbol_versioning,
 
51
    static_tuple,
 
52
    timestamp,
47
53
    transport,
48
 
    tree as _mod_tree,
49
54
    ui,
50
55
    urlutils,
51
56
    views,
 
57
    gpg,
52
58
    )
53
59
from bzrlib.branch import Branch
54
60
from bzrlib.conflicts import ConflictList
 
61
from bzrlib.transport import memory
55
62
from bzrlib.revisionspec import RevisionSpec, RevisionInfo
56
63
from bzrlib.smtp_connection import SMTPConnection
57
64
from bzrlib.workingtree import WorkingTree
 
65
from bzrlib.i18n import gettext, ngettext
58
66
""")
59
67
 
60
 
from bzrlib.commands import Command, display_command
 
68
from bzrlib.commands import (
 
69
    Command,
 
70
    builtin_command_registry,
 
71
    display_command,
 
72
    )
61
73
from bzrlib.option import (
62
74
    ListOption,
63
75
    Option,
66
78
    _parse_revision_str,
67
79
    )
68
80
from bzrlib.trace import mutter, note, warning, is_quiet, get_verbosity_level
69
 
 
70
 
 
 
81
from bzrlib import (
 
82
    symbol_versioning,
 
83
    )
 
84
 
 
85
 
 
86
@symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
71
87
def tree_files(file_list, default_branch=u'.', canonicalize=True,
72
88
    apply_view=True):
73
 
    try:
74
 
        return internal_tree_files(file_list, default_branch, canonicalize,
75
 
            apply_view)
76
 
    except errors.FileInWrongBranch, e:
77
 
        raise errors.BzrCommandError("%s is not in the same branch as %s" %
78
 
                                     (e.path, file_list[0]))
 
89
    return internal_tree_files(file_list, default_branch, canonicalize,
 
90
        apply_view)
79
91
 
80
92
 
81
93
def tree_files_for_add(file_list):
106
118
            if view_files:
107
119
                file_list = view_files
108
120
                view_str = views.view_display_str(view_files)
109
 
                note("Ignoring files outside view. View is %s" % view_str)
 
121
                note(gettext("Ignoring files outside view. View is %s") % view_str)
110
122
    return tree, file_list
111
123
 
112
124
 
114
126
    if revisions is None:
115
127
        return None
116
128
    if len(revisions) != 1:
117
 
        raise errors.BzrCommandError(
118
 
            'bzr %s --revision takes exactly one revision identifier' % (
 
129
        raise errors.BzrCommandError(gettext(
 
130
            'bzr %s --revision takes exactly one revision identifier') % (
119
131
                command_name,))
120
132
    return revisions[0]
121
133
 
122
134
 
123
135
def _get_one_revision_tree(command_name, revisions, branch=None, tree=None):
 
136
    """Get a revision tree. Not suitable for commands that change the tree.
 
137
    
 
138
    Specifically, the basis tree in dirstate trees is coupled to the dirstate
 
139
    and doing a commit/uncommit/pull will at best fail due to changing the
 
140
    basis revision data.
 
141
 
 
142
    If tree is passed in, it should be already locked, for lifetime management
 
143
    of the trees internal cached state.
 
144
    """
124
145
    if branch is None:
125
146
        branch = tree.branch
126
147
    if revisions is None:
136
157
 
137
158
# XXX: Bad function name; should possibly also be a class method of
138
159
# WorkingTree rather than a function.
 
160
@symbol_versioning.deprecated_function(symbol_versioning.deprecated_in((2, 3, 0)))
139
161
def internal_tree_files(file_list, default_branch=u'.', canonicalize=True,
140
162
    apply_view=True):
141
163
    """Convert command-line paths to a WorkingTree and relative paths.
142
164
 
 
165
    Deprecated: use WorkingTree.open_containing_paths instead.
 
166
 
143
167
    This is typically used for command-line processors that take one or
144
168
    more filenames, and infer the workingtree that contains them.
145
169
 
155
179
 
156
180
    :return: workingtree, [relative_paths]
157
181
    """
158
 
    if file_list is None or len(file_list) == 0:
159
 
        tree = WorkingTree.open_containing(default_branch)[0]
160
 
        if tree.supports_views() and apply_view:
161
 
            view_files = tree.views.lookup_view()
162
 
            if view_files:
163
 
                file_list = view_files
164
 
                view_str = views.view_display_str(view_files)
165
 
                note("Ignoring files outside view. View is %s" % view_str)
166
 
        return tree, file_list
167
 
    tree = WorkingTree.open_containing(osutils.realpath(file_list[0]))[0]
168
 
    return tree, safe_relpath_files(tree, file_list, canonicalize,
169
 
        apply_view=apply_view)
170
 
 
171
 
 
172
 
def safe_relpath_files(tree, file_list, canonicalize=True, apply_view=True):
173
 
    """Convert file_list into a list of relpaths in tree.
174
 
 
175
 
    :param tree: A tree to operate on.
176
 
    :param file_list: A list of user provided paths or None.
177
 
    :param apply_view: if True and a view is set, apply it or check that
178
 
        specified files are within it
179
 
    :return: A list of relative paths.
180
 
    :raises errors.PathNotChild: When a provided path is in a different tree
181
 
        than tree.
182
 
    """
183
 
    if file_list is None:
184
 
        return None
185
 
    if tree.supports_views() and apply_view:
186
 
        view_files = tree.views.lookup_view()
187
 
    else:
188
 
        view_files = []
189
 
    new_list = []
190
 
    # tree.relpath exists as a "thunk" to osutils, but canonical_relpath
191
 
    # doesn't - fix that up here before we enter the loop.
192
 
    if canonicalize:
193
 
        fixer = lambda p: osutils.canonical_relpath(tree.basedir, p)
194
 
    else:
195
 
        fixer = tree.relpath
196
 
    for filename in file_list:
197
 
        try:
198
 
            relpath = fixer(osutils.dereference_path(filename))
199
 
            if  view_files and not osutils.is_inside_any(view_files, relpath):
200
 
                raise errors.FileOutsideView(filename, view_files)
201
 
            new_list.append(relpath)
202
 
        except errors.PathNotChild:
203
 
            raise errors.FileInWrongBranch(tree.branch, filename)
204
 
    return new_list
 
182
    return WorkingTree.open_containing_paths(
 
183
        file_list, default_directory='.',
 
184
        canonicalize=True,
 
185
        apply_view=True)
205
186
 
206
187
 
207
188
def _get_view_info_for_change_reporter(tree):
216
197
    return view_info
217
198
 
218
199
 
 
200
def _open_directory_or_containing_tree_or_branch(filename, directory):
 
201
    """Open the tree or branch containing the specified file, unless
 
202
    the --directory option is used to specify a different branch."""
 
203
    if directory is not None:
 
204
        return (None, Branch.open(directory), filename)
 
205
    return controldir.ControlDir.open_containing_tree_or_branch(filename)
 
206
 
 
207
 
219
208
# TODO: Make sure no commands unconditionally use the working directory as a
220
209
# branch.  If a filename argument is used, the first of them should be used to
221
210
# specify the branch.  (Perhaps this can be factored out into some kind of
223
212
# opens the branch?)
224
213
 
225
214
class cmd_status(Command):
226
 
    """Display status summary.
 
215
    __doc__ = """Display status summary.
227
216
 
228
217
    This reports on versioned and unknown files, reporting them
229
218
    grouped by state.  Possible states are:
249
238
    unknown
250
239
        Not versioned and not matching an ignore pattern.
251
240
 
 
241
    Additionally for directories, symlinks and files with a changed
 
242
    executable bit, Bazaar indicates their type using a trailing
 
243
    character: '/', '@' or '*' respectively. These decorations can be
 
244
    disabled using the '--no-classify' option.
 
245
 
252
246
    To see ignored files use 'bzr ignored'.  For details on the
253
247
    changes to file texts, use 'bzr diff'.
254
248
 
266
260
    To skip the display of pending merge information altogether, use
267
261
    the no-pending option or specify a file/directory.
268
262
 
269
 
    If a revision argument is given, the status is calculated against
270
 
    that revision, or between two revisions if two are provided.
 
263
    To compare the working directory to a specific revision, pass a
 
264
    single revision to the revision argument.
 
265
 
 
266
    To see which files have changed in a specific revision, or between
 
267
    two revisions, pass a revision range to the revision argument.
 
268
    This will produce the same results as calling 'bzr diff --summarize'.
271
269
    """
272
270
 
273
271
    # TODO: --no-recurse, --recurse options
280
278
                            short_name='V'),
281
279
                     Option('no-pending', help='Don\'t show pending merges.',
282
280
                           ),
 
281
                     Option('no-classify',
 
282
                            help='Do not mark object type using indicator.',
 
283
                           ),
283
284
                     ]
284
285
    aliases = ['st', 'stat']
285
286
 
288
289
 
289
290
    @display_command
290
291
    def run(self, show_ids=False, file_list=None, revision=None, short=False,
291
 
            versioned=False, no_pending=False, verbose=False):
 
292
            versioned=False, no_pending=False, verbose=False,
 
293
            no_classify=False):
292
294
        from bzrlib.status import show_tree_status
293
295
 
294
296
        if revision and len(revision) > 2:
295
 
            raise errors.BzrCommandError('bzr status --revision takes exactly'
296
 
                                         ' one or two revision specifiers')
 
297
            raise errors.BzrCommandError(gettext('bzr status --revision takes exactly'
 
298
                                         ' one or two revision specifiers'))
297
299
 
298
 
        tree, relfile_list = tree_files(file_list)
 
300
        tree, relfile_list = WorkingTree.open_containing_paths(file_list)
299
301
        # Avoid asking for specific files when that is not needed.
300
302
        if relfile_list == ['']:
301
303
            relfile_list = None
308
310
        show_tree_status(tree, show_ids=show_ids,
309
311
                         specific_files=relfile_list, revision=revision,
310
312
                         to_file=self.outf, short=short, versioned=versioned,
311
 
                         show_pending=(not no_pending), verbose=verbose)
 
313
                         show_pending=(not no_pending), verbose=verbose,
 
314
                         classify=not no_classify)
312
315
 
313
316
 
314
317
class cmd_cat_revision(Command):
315
 
    """Write out metadata for a revision.
 
318
    __doc__ = """Write out metadata for a revision.
316
319
 
317
320
    The revision to print can either be specified by a specific
318
321
    revision identifier, or you can use --revision.
320
323
 
321
324
    hidden = True
322
325
    takes_args = ['revision_id?']
323
 
    takes_options = ['revision']
 
326
    takes_options = ['directory', 'revision']
324
327
    # cat-revision is more for frontends so should be exact
325
328
    encoding = 'strict'
326
329
 
 
330
    def print_revision(self, revisions, revid):
 
331
        stream = revisions.get_record_stream([(revid,)], 'unordered', True)
 
332
        record = stream.next()
 
333
        if record.storage_kind == 'absent':
 
334
            raise errors.NoSuchRevision(revisions, revid)
 
335
        revtext = record.get_bytes_as('fulltext')
 
336
        self.outf.write(revtext.decode('utf-8'))
 
337
 
327
338
    @display_command
328
 
    def run(self, revision_id=None, revision=None):
 
339
    def run(self, revision_id=None, revision=None, directory=u'.'):
329
340
        if revision_id is not None and revision is not None:
330
 
            raise errors.BzrCommandError('You can only supply one of'
331
 
                                         ' revision_id or --revision')
 
341
            raise errors.BzrCommandError(gettext('You can only supply one of'
 
342
                                         ' revision_id or --revision'))
332
343
        if revision_id is None and revision is None:
333
 
            raise errors.BzrCommandError('You must supply either'
334
 
                                         ' --revision or a revision_id')
335
 
        b = WorkingTree.open_containing(u'.')[0].branch
336
 
 
337
 
        # TODO: jam 20060112 should cat-revision always output utf-8?
338
 
        if revision_id is not None:
339
 
            revision_id = osutils.safe_revision_id(revision_id, warn=False)
340
 
            try:
341
 
                self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
342
 
            except errors.NoSuchRevision:
343
 
                msg = "The repository %s contains no revision %s." % (b.repository.base,
344
 
                    revision_id)
345
 
                raise errors.BzrCommandError(msg)
346
 
        elif revision is not None:
347
 
            for rev in revision:
348
 
                if rev is None:
349
 
                    raise errors.BzrCommandError('You cannot specify a NULL'
350
 
                                                 ' revision.')
351
 
                rev_id = rev.as_revision_id(b)
352
 
                self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
353
 
 
 
344
            raise errors.BzrCommandError(gettext('You must supply either'
 
345
                                         ' --revision or a revision_id'))
 
346
 
 
347
        b = controldir.ControlDir.open_containing_tree_or_branch(directory)[1]
 
348
 
 
349
        revisions = b.repository.revisions
 
350
        if revisions is None:
 
351
            raise errors.BzrCommandError(gettext('Repository %r does not support '
 
352
                'access to raw revision texts'))
 
353
 
 
354
        b.repository.lock_read()
 
355
        try:
 
356
            # TODO: jam 20060112 should cat-revision always output utf-8?
 
357
            if revision_id is not None:
 
358
                revision_id = osutils.safe_revision_id(revision_id, warn=False)
 
359
                try:
 
360
                    self.print_revision(revisions, revision_id)
 
361
                except errors.NoSuchRevision:
 
362
                    msg = gettext("The repository {0} contains no revision {1}.").format(
 
363
                        b.repository.base, revision_id)
 
364
                    raise errors.BzrCommandError(msg)
 
365
            elif revision is not None:
 
366
                for rev in revision:
 
367
                    if rev is None:
 
368
                        raise errors.BzrCommandError(
 
369
                            gettext('You cannot specify a NULL revision.'))
 
370
                    rev_id = rev.as_revision_id(b)
 
371
                    self.print_revision(revisions, rev_id)
 
372
        finally:
 
373
            b.repository.unlock()
 
374
        
354
375
 
355
376
class cmd_dump_btree(Command):
356
 
    """Dump the contents of a btree index file to stdout.
 
377
    __doc__ = """Dump the contents of a btree index file to stdout.
357
378
 
358
379
    PATH is a btree index file, it can be any URL. This includes things like
359
380
    .bzr/repository/pack-names, or .bzr/repository/indices/a34b3a...ca4a4.iix
407
428
                self.outf.write(page_bytes[:header_end])
408
429
                page_bytes = data
409
430
            self.outf.write('\nPage %d\n' % (page_idx,))
410
 
            decomp_bytes = zlib.decompress(page_bytes)
411
 
            self.outf.write(decomp_bytes)
412
 
            self.outf.write('\n')
 
431
            if len(page_bytes) == 0:
 
432
                self.outf.write('(empty)\n');
 
433
            else:
 
434
                decomp_bytes = zlib.decompress(page_bytes)
 
435
                self.outf.write(decomp_bytes)
 
436
                self.outf.write('\n')
413
437
 
414
438
    def _dump_entries(self, trans, basename):
415
439
        try:
423
447
        for node in bt.iter_all_entries():
424
448
            # Node is made up of:
425
449
            # (index, key, value, [references])
426
 
            self.outf.write('%s\n' % (node[1:],))
 
450
            try:
 
451
                refs = node[3]
 
452
            except IndexError:
 
453
                refs_as_tuples = None
 
454
            else:
 
455
                refs_as_tuples = static_tuple.as_tuples(refs)
 
456
            as_tuple = (tuple(node[1]), node[2], refs_as_tuples)
 
457
            self.outf.write('%s\n' % (as_tuple,))
427
458
 
428
459
 
429
460
class cmd_remove_tree(Command):
430
 
    """Remove the working tree from a given branch/checkout.
 
461
    __doc__ = """Remove the working tree from a given branch/checkout.
431
462
 
432
463
    Since a lightweight checkout is little more than a working tree
433
464
    this will refuse to run against one.
435
466
    To re-create the working tree, use "bzr checkout".
436
467
    """
437
468
    _see_also = ['checkout', 'working-trees']
438
 
    takes_args = ['location?']
 
469
    takes_args = ['location*']
439
470
    takes_options = [
440
471
        Option('force',
441
472
               help='Remove the working tree even if it has '
442
 
                    'uncommitted changes.'),
 
473
                    'uncommitted or shelved changes.'),
443
474
        ]
444
475
 
445
 
    def run(self, location='.', force=False):
446
 
        d = bzrdir.BzrDir.open(location)
447
 
 
 
476
    def run(self, location_list, force=False):
 
477
        if not location_list:
 
478
            location_list=['.']
 
479
 
 
480
        for location in location_list:
 
481
            d = controldir.ControlDir.open(location)
 
482
 
 
483
            try:
 
484
                working = d.open_workingtree()
 
485
            except errors.NoWorkingTree:
 
486
                raise errors.BzrCommandError(gettext("No working tree to remove"))
 
487
            except errors.NotLocalUrl:
 
488
                raise errors.BzrCommandError(gettext("You cannot remove the working tree"
 
489
                                             " of a remote path"))
 
490
            if not force:
 
491
                if (working.has_changes()):
 
492
                    raise errors.UncommittedChanges(working)
 
493
                if working.get_shelf_manager().last_shelf() is not None:
 
494
                    raise errors.ShelvedChanges(working)
 
495
 
 
496
            if working.user_url != working.branch.user_url:
 
497
                raise errors.BzrCommandError(gettext("You cannot remove the working tree"
 
498
                                             " from a lightweight checkout"))
 
499
 
 
500
            d.destroy_workingtree()
 
501
 
 
502
 
 
503
class cmd_repair_workingtree(Command):
 
504
    __doc__ = """Reset the working tree state file.
 
505
 
 
506
    This is not meant to be used normally, but more as a way to recover from
 
507
    filesystem corruption, etc. This rebuilds the working inventory back to a
 
508
    'known good' state. Any new modifications (adding a file, renaming, etc)
 
509
    will be lost, though modified files will still be detected as such.
 
510
 
 
511
    Most users will want something more like "bzr revert" or "bzr update"
 
512
    unless the state file has become corrupted.
 
513
 
 
514
    By default this attempts to recover the current state by looking at the
 
515
    headers of the state file. If the state file is too corrupted to even do
 
516
    that, you can supply --revision to force the state of the tree.
 
517
    """
 
518
 
 
519
    takes_options = ['revision', 'directory',
 
520
        Option('force',
 
521
               help='Reset the tree even if it doesn\'t appear to be'
 
522
                    ' corrupted.'),
 
523
    ]
 
524
    hidden = True
 
525
 
 
526
    def run(self, revision=None, directory='.', force=False):
 
527
        tree, _ = WorkingTree.open_containing(directory)
 
528
        self.add_cleanup(tree.lock_tree_write().unlock)
 
529
        if not force:
 
530
            try:
 
531
                tree.check_state()
 
532
            except errors.BzrError:
 
533
                pass # There seems to be a real error here, so we'll reset
 
534
            else:
 
535
                # Refuse
 
536
                raise errors.BzrCommandError(gettext(
 
537
                    'The tree does not appear to be corrupt. You probably'
 
538
                    ' want "bzr revert" instead. Use "--force" if you are'
 
539
                    ' sure you want to reset the working tree.'))
 
540
        if revision is None:
 
541
            revision_ids = None
 
542
        else:
 
543
            revision_ids = [r.as_revision_id(tree.branch) for r in revision]
448
544
        try:
449
 
            working = d.open_workingtree()
450
 
        except errors.NoWorkingTree:
451
 
            raise errors.BzrCommandError("No working tree to remove")
452
 
        except errors.NotLocalUrl:
453
 
            raise errors.BzrCommandError("You cannot remove the working tree of a "
454
 
                                         "remote path")
455
 
        if not force:
456
 
            changes = working.changes_from(working.basis_tree())
457
 
            if changes.has_changed():
458
 
                raise errors.UncommittedChanges(working)
459
 
 
460
 
        working_path = working.bzrdir.root_transport.base
461
 
        branch_path = working.branch.bzrdir.root_transport.base
462
 
        if working_path != branch_path:
463
 
            raise errors.BzrCommandError("You cannot remove the working tree from "
464
 
                                         "a lightweight checkout")
465
 
 
466
 
        d.destroy_workingtree()
 
545
            tree.reset_state(revision_ids)
 
546
        except errors.BzrError, e:
 
547
            if revision_ids is None:
 
548
                extra = (gettext(', the header appears corrupt, try passing -r -1'
 
549
                         ' to set the state to the last commit'))
 
550
            else:
 
551
                extra = ''
 
552
            raise errors.BzrCommandError(gettext('failed to reset the tree state{0}').format(extra))
467
553
 
468
554
 
469
555
class cmd_revno(Command):
470
 
    """Show current revision number.
 
556
    __doc__ = """Show current revision number.
471
557
 
472
558
    This is equal to the number of revisions on this branch.
473
559
    """
474
560
 
475
561
    _see_also = ['info']
476
562
    takes_args = ['location?']
 
563
    takes_options = [
 
564
        Option('tree', help='Show revno of working tree.'),
 
565
        'revision',
 
566
        ]
477
567
 
478
568
    @display_command
479
 
    def run(self, location=u'.'):
480
 
        self.outf.write(str(Branch.open_containing(location)[0].revno()))
481
 
        self.outf.write('\n')
 
569
    def run(self, tree=False, location=u'.', revision=None):
 
570
        if revision is not None and tree:
 
571
            raise errors.BzrCommandError(gettext("--tree and --revision can "
 
572
                "not be used together"))
 
573
 
 
574
        if tree:
 
575
            try:
 
576
                wt = WorkingTree.open_containing(location)[0]
 
577
                self.add_cleanup(wt.lock_read().unlock)
 
578
            except (errors.NoWorkingTree, errors.NotLocalUrl):
 
579
                raise errors.NoWorkingTree(location)
 
580
            b = wt.branch
 
581
            revid = wt.last_revision()
 
582
        else:
 
583
            b = Branch.open_containing(location)[0]
 
584
            self.add_cleanup(b.lock_read().unlock)
 
585
            if revision:
 
586
                if len(revision) != 1:
 
587
                    raise errors.BzrCommandError(gettext(
 
588
                        "Tags can only be placed on a single revision, "
 
589
                        "not on a range"))
 
590
                revid = revision[0].as_revision_id(b)
 
591
            else:
 
592
                revid = b.last_revision()
 
593
        try:
 
594
            revno_t = b.revision_id_to_dotted_revno(revid)
 
595
        except errors.NoSuchRevision:
 
596
            revno_t = ('???',)
 
597
        revno = ".".join(str(n) for n in revno_t)
 
598
        self.cleanup_now()
 
599
        self.outf.write(revno + '\n')
482
600
 
483
601
 
484
602
class cmd_revision_info(Command):
485
 
    """Show revision number and revision id for a given revision identifier.
 
603
    __doc__ = """Show revision number and revision id for a given revision identifier.
486
604
    """
487
605
    hidden = True
488
606
    takes_args = ['revision_info*']
489
607
    takes_options = [
490
608
        'revision',
491
 
        Option('directory',
 
609
        custom_help('directory',
492
610
            help='Branch to examine, '
493
 
                 'rather than the one containing the working directory.',
494
 
            short_name='d',
495
 
            type=unicode,
496
 
            ),
 
611
                 'rather than the one containing the working directory.'),
 
612
        Option('tree', help='Show revno of working tree.'),
497
613
        ]
498
614
 
499
615
    @display_command
500
 
    def run(self, revision=None, directory=u'.', revision_info_list=[]):
 
616
    def run(self, revision=None, directory=u'.', tree=False,
 
617
            revision_info_list=[]):
501
618
 
502
 
        revs = []
 
619
        try:
 
620
            wt = WorkingTree.open_containing(directory)[0]
 
621
            b = wt.branch
 
622
            self.add_cleanup(wt.lock_read().unlock)
 
623
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
624
            wt = None
 
625
            b = Branch.open_containing(directory)[0]
 
626
            self.add_cleanup(b.lock_read().unlock)
 
627
        revision_ids = []
503
628
        if revision is not None:
504
 
            revs.extend(revision)
 
629
            revision_ids.extend(rev.as_revision_id(b) for rev in revision)
505
630
        if revision_info_list is not None:
506
 
            for rev in revision_info_list:
507
 
                revs.append(RevisionSpec.from_string(rev))
508
 
 
509
 
        b = Branch.open_containing(directory)[0]
510
 
 
511
 
        if len(revs) == 0:
512
 
            revs.append(RevisionSpec.from_string('-1'))
513
 
 
514
 
        for rev in revs:
515
 
            revision_id = rev.as_revision_id(b)
 
631
            for rev_str in revision_info_list:
 
632
                rev_spec = RevisionSpec.from_string(rev_str)
 
633
                revision_ids.append(rev_spec.as_revision_id(b))
 
634
        # No arguments supplied, default to the last revision
 
635
        if len(revision_ids) == 0:
 
636
            if tree:
 
637
                if wt is None:
 
638
                    raise errors.NoWorkingTree(directory)
 
639
                revision_ids.append(wt.last_revision())
 
640
            else:
 
641
                revision_ids.append(b.last_revision())
 
642
 
 
643
        revinfos = []
 
644
        maxlen = 0
 
645
        for revision_id in revision_ids:
516
646
            try:
517
 
                revno = '%4d' % (b.revision_id_to_revno(revision_id))
 
647
                dotted_revno = b.revision_id_to_dotted_revno(revision_id)
 
648
                revno = '.'.join(str(i) for i in dotted_revno)
518
649
            except errors.NoSuchRevision:
519
 
                dotted_map = b.get_revision_id_to_revno_map()
520
 
                revno = '.'.join(str(i) for i in dotted_map[revision_id])
521
 
            print '%s %s' % (revno, revision_id)
 
650
                revno = '???'
 
651
            maxlen = max(maxlen, len(revno))
 
652
            revinfos.append([revno, revision_id])
 
653
 
 
654
        self.cleanup_now()
 
655
        for ri in revinfos:
 
656
            self.outf.write('%*s %s\n' % (maxlen, ri[0], ri[1]))
522
657
 
523
658
 
524
659
class cmd_add(Command):
525
 
    """Add specified files or directories.
 
660
    __doc__ = """Add specified files or directories.
526
661
 
527
662
    In non-recursive mode, all the named items are added, regardless
528
663
    of whether they were previously ignored.  A warning is given if
536
671
    are added.  This search proceeds recursively into versioned
537
672
    directories.  If no names are given '.' is assumed.
538
673
 
 
674
    A warning will be printed when nested trees are encountered,
 
675
    unless they are explicitly ignored.
 
676
 
539
677
    Therefore simply saying 'bzr add' will version all files that
540
678
    are currently unknown.
541
679
 
554
692
    branches that will be merged later (without showing the two different
555
693
    adds as a conflict). It is also useful when merging another project
556
694
    into a subdirectory of this one.
 
695
    
 
696
    Any files matching patterns in the ignore list will not be added
 
697
    unless they are explicitly mentioned.
 
698
    
 
699
    In recursive mode, files larger than the configuration option 
 
700
    add.maximum_file_size will be skipped. Named items are never skipped due
 
701
    to file size.
557
702
    """
558
703
    takes_args = ['file*']
559
704
    takes_options = [
567
712
               help='Lookup file ids from this tree.'),
568
713
        ]
569
714
    encoding_type = 'replace'
570
 
    _see_also = ['remove']
 
715
    _see_also = ['remove', 'ignore']
571
716
 
572
717
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
573
718
            file_ids_from=None):
586
731
            action = bzrlib.add.AddFromBaseAction(base_tree, base_path,
587
732
                          to_file=self.outf, should_print=(not is_quiet()))
588
733
        else:
589
 
            action = bzrlib.add.AddAction(to_file=self.outf,
 
734
            action = bzrlib.add.AddWithSkipLargeAction(to_file=self.outf,
590
735
                should_print=(not is_quiet()))
591
736
 
592
737
        if base_tree:
593
 
            base_tree.lock_read()
594
 
        try:
595
 
            file_list = self._maybe_expand_globs(file_list)
596
 
            tree, file_list = tree_files_for_add(file_list)
597
 
            added, ignored = tree.smart_add(file_list, not
598
 
                no_recurse, action=action, save=not dry_run)
599
 
        finally:
600
 
            if base_tree is not None:
601
 
                base_tree.unlock()
 
738
            self.add_cleanup(base_tree.lock_read().unlock)
 
739
        tree, file_list = tree_files_for_add(file_list)
 
740
        added, ignored = tree.smart_add(file_list, not
 
741
            no_recurse, action=action, save=not dry_run)
 
742
        self.cleanup_now()
602
743
        if len(ignored) > 0:
603
744
            if verbose:
604
745
                for glob in sorted(ignored.keys()):
605
746
                    for path in ignored[glob]:
606
 
                        self.outf.write("ignored %s matching \"%s\"\n"
607
 
                                        % (path, glob))
608
 
            else:
609
 
                match_len = 0
610
 
                for glob, paths in ignored.items():
611
 
                    match_len += len(paths)
612
 
                self.outf.write("ignored %d file(s).\n" % match_len)
613
 
            self.outf.write("If you wish to add ignored files, "
614
 
                            "please add them explicitly by name. "
615
 
                            "(\"bzr ignored\" gives a list)\n")
 
747
                        self.outf.write(
 
748
                         gettext("ignored {0} matching \"{1}\"\n").format(
 
749
                         path, glob))
616
750
 
617
751
 
618
752
class cmd_mkdir(Command):
619
 
    """Create a new versioned directory.
 
753
    __doc__ = """Create a new versioned directory.
620
754
 
621
755
    This is equivalent to creating the directory and then adding it.
622
756
    """
623
757
 
624
758
    takes_args = ['dir+']
 
759
    takes_options = [
 
760
        Option(
 
761
            'parents',
 
762
            help='No error if existing, make parent directories as needed.',
 
763
            short_name='p'
 
764
            )
 
765
        ]
625
766
    encoding_type = 'replace'
626
767
 
627
 
    def run(self, dir_list):
628
 
        for d in dir_list:
629
 
            os.mkdir(d)
630
 
            wt, dd = WorkingTree.open_containing(d)
631
 
            wt.add([dd])
632
 
            self.outf.write('added %s\n' % d)
 
768
    @classmethod
 
769
    def add_file_with_parents(cls, wt, relpath):
 
770
        if wt.path2id(relpath) is not None:
 
771
            return
 
772
        cls.add_file_with_parents(wt, osutils.dirname(relpath))
 
773
        wt.add([relpath])
 
774
 
 
775
    @classmethod
 
776
    def add_file_single(cls, wt, relpath):
 
777
        wt.add([relpath])
 
778
 
 
779
    def run(self, dir_list, parents=False):
 
780
        if parents:
 
781
            add_file = self.add_file_with_parents
 
782
        else:
 
783
            add_file = self.add_file_single
 
784
        for dir in dir_list:
 
785
            wt, relpath = WorkingTree.open_containing(dir)
 
786
            if parents:
 
787
                try:
 
788
                    os.makedirs(dir)
 
789
                except OSError, e:
 
790
                    if e.errno != errno.EEXIST:
 
791
                        raise
 
792
            else:
 
793
                os.mkdir(dir)
 
794
            add_file(wt, relpath)
 
795
            if not is_quiet():
 
796
                self.outf.write(gettext('added %s\n') % dir)
633
797
 
634
798
 
635
799
class cmd_relpath(Command):
636
 
    """Show path of a file relative to root"""
 
800
    __doc__ = """Show path of a file relative to root"""
637
801
 
638
802
    takes_args = ['filename']
639
803
    hidden = True
648
812
 
649
813
 
650
814
class cmd_inventory(Command):
651
 
    """Show inventory of the current working copy or a revision.
 
815
    __doc__ = """Show inventory of the current working copy or a revision.
652
816
 
653
817
    It is possible to limit the output to a particular entry
654
818
    type using the --kind option.  For example: --kind file.
671
835
    @display_command
672
836
    def run(self, revision=None, show_ids=False, kind=None, file_list=None):
673
837
        if kind and kind not in ['file', 'directory', 'symlink']:
674
 
            raise errors.BzrCommandError('invalid kind %r specified' % (kind,))
 
838
            raise errors.BzrCommandError(gettext('invalid kind %r specified') % (kind,))
675
839
 
676
840
        revision = _get_one_revision('inventory', revision)
677
 
        work_tree, file_list = tree_files(file_list)
678
 
        work_tree.lock_read()
679
 
        try:
680
 
            if revision is not None:
681
 
                tree = revision.as_tree(work_tree.branch)
682
 
 
683
 
                extra_trees = [work_tree]
684
 
                tree.lock_read()
685
 
            else:
686
 
                tree = work_tree
687
 
                extra_trees = []
688
 
 
689
 
            if file_list is not None:
690
 
                file_ids = tree.paths2ids(file_list, trees=extra_trees,
691
 
                                          require_versioned=True)
692
 
                # find_ids_across_trees may include some paths that don't
693
 
                # exist in 'tree'.
694
 
                entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
695
 
                                 for file_id in file_ids if file_id in tree)
696
 
            else:
697
 
                entries = tree.inventory.entries()
698
 
        finally:
699
 
            tree.unlock()
700
 
            if tree is not work_tree:
701
 
                work_tree.unlock()
702
 
 
 
841
        work_tree, file_list = WorkingTree.open_containing_paths(file_list)
 
842
        self.add_cleanup(work_tree.lock_read().unlock)
 
843
        if revision is not None:
 
844
            tree = revision.as_tree(work_tree.branch)
 
845
 
 
846
            extra_trees = [work_tree]
 
847
            self.add_cleanup(tree.lock_read().unlock)
 
848
        else:
 
849
            tree = work_tree
 
850
            extra_trees = []
 
851
 
 
852
        if file_list is not None:
 
853
            file_ids = tree.paths2ids(file_list, trees=extra_trees,
 
854
                                      require_versioned=True)
 
855
            # find_ids_across_trees may include some paths that don't
 
856
            # exist in 'tree'.
 
857
            entries = sorted(
 
858
                (tree.id2path(file_id), tree.inventory[file_id])
 
859
                for file_id in file_ids if tree.has_id(file_id))
 
860
        else:
 
861
            entries = tree.inventory.entries()
 
862
 
 
863
        self.cleanup_now()
703
864
        for path, entry in entries:
704
865
            if kind and kind != entry.kind:
705
866
                continue
711
872
 
712
873
 
713
874
class cmd_mv(Command):
714
 
    """Move or rename a file.
 
875
    __doc__ = """Move or rename a file.
715
876
 
716
877
    :Usage:
717
878
        bzr mv OLDNAME NEWNAME
744
905
        if auto:
745
906
            return self.run_auto(names_list, after, dry_run)
746
907
        elif dry_run:
747
 
            raise errors.BzrCommandError('--dry-run requires --auto.')
 
908
            raise errors.BzrCommandError(gettext('--dry-run requires --auto.'))
748
909
        if names_list is None:
749
910
            names_list = []
750
911
        if len(names_list) < 2:
751
 
            raise errors.BzrCommandError("missing file argument")
752
 
        tree, rel_names = tree_files(names_list, canonicalize=False)
753
 
        tree.lock_write()
754
 
        try:
755
 
            self._run(tree, names_list, rel_names, after)
756
 
        finally:
757
 
            tree.unlock()
 
912
            raise errors.BzrCommandError(gettext("missing file argument"))
 
913
        tree, rel_names = WorkingTree.open_containing_paths(names_list, canonicalize=False)
 
914
        for file_name in rel_names[0:-1]:
 
915
            if file_name == '':
 
916
                raise errors.BzrCommandError(gettext("can not move root of branch"))
 
917
        self.add_cleanup(tree.lock_tree_write().unlock)
 
918
        self._run(tree, names_list, rel_names, after)
758
919
 
759
920
    def run_auto(self, names_list, after, dry_run):
760
921
        if names_list is not None and len(names_list) > 1:
761
 
            raise errors.BzrCommandError('Only one path may be specified to'
762
 
                                         ' --auto.')
 
922
            raise errors.BzrCommandError(gettext('Only one path may be specified to'
 
923
                                         ' --auto.'))
763
924
        if after:
764
 
            raise errors.BzrCommandError('--after cannot be specified with'
765
 
                                         ' --auto.')
766
 
        work_tree, file_list = tree_files(names_list, default_branch='.')
767
 
        work_tree.lock_write()
768
 
        try:
769
 
            rename_map.RenameMap.guess_renames(work_tree, dry_run)
770
 
        finally:
771
 
            work_tree.unlock()
 
925
            raise errors.BzrCommandError(gettext('--after cannot be specified with'
 
926
                                         ' --auto.'))
 
927
        work_tree, file_list = WorkingTree.open_containing_paths(
 
928
            names_list, default_directory='.')
 
929
        self.add_cleanup(work_tree.lock_tree_write().unlock)
 
930
        rename_map.RenameMap.guess_renames(work_tree, dry_run)
772
931
 
773
932
    def _run(self, tree, names_list, rel_names, after):
774
933
        into_existing = osutils.isdir(names_list[-1])
795
954
            # All entries reference existing inventory items, so fix them up
796
955
            # for cicp file-systems.
797
956
            rel_names = tree.get_canonical_inventory_paths(rel_names)
798
 
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
799
 
                self.outf.write("%s => %s\n" % pair)
 
957
            for src, dest in tree.move(rel_names[:-1], rel_names[-1], after=after):
 
958
                if not is_quiet():
 
959
                    self.outf.write("%s => %s\n" % (src, dest))
800
960
        else:
801
961
            if len(names_list) != 2:
802
 
                raise errors.BzrCommandError('to mv multiple files the'
 
962
                raise errors.BzrCommandError(gettext('to mv multiple files the'
803
963
                                             ' destination must be a versioned'
804
 
                                             ' directory')
 
964
                                             ' directory'))
805
965
 
806
966
            # for cicp file-systems: the src references an existing inventory
807
967
            # item:
846
1006
            dest = osutils.pathjoin(dest_parent, dest_tail)
847
1007
            mutter("attempting to move %s => %s", src, dest)
848
1008
            tree.rename_one(src, dest, after=after)
849
 
            self.outf.write("%s => %s\n" % (src, dest))
 
1009
            if not is_quiet():
 
1010
                self.outf.write("%s => %s\n" % (src, dest))
850
1011
 
851
1012
 
852
1013
class cmd_pull(Command):
853
 
    """Turn this branch into a mirror of another branch.
 
1014
    __doc__ = """Turn this branch into a mirror of another branch.
854
1015
 
855
 
    This command only works on branches that have not diverged.  Branches are
856
 
    considered diverged if the destination branch's most recent commit is one
857
 
    that has not been merged (directly or indirectly) into the parent.
 
1016
    By default, this command only works on branches that have not diverged.
 
1017
    Branches are considered diverged if the destination branch's most recent 
 
1018
    commit is one that has not been merged (directly or indirectly) into the 
 
1019
    parent.
858
1020
 
859
1021
    If branches have diverged, you can use 'bzr merge' to integrate the changes
860
1022
    from one into the other.  Once one branch has merged, the other should
861
1023
    be able to pull it again.
862
1024
 
863
 
    If you want to forget your local changes and just update your branch to
864
 
    match the remote one, use pull --overwrite.
865
 
 
866
 
    If there is no default location set, the first pull will set it.  After
867
 
    that, you can omit the location to use the default.  To change the
868
 
    default, use --remember. The value will only be saved if the remote
869
 
    location can be accessed.
 
1025
    If you want to replace your local changes and just want your branch to
 
1026
    match the remote one, use pull --overwrite. This will work even if the two
 
1027
    branches have diverged.
 
1028
 
 
1029
    If there is no default location set, the first pull will set it (use
 
1030
    --no-remember to avoid setting it). After that, you can omit the
 
1031
    location to use the default.  To change the default, use --remember. The
 
1032
    value will only be saved if the remote location can be accessed.
 
1033
 
 
1034
    The --verbose option will display the revisions pulled using the log_format
 
1035
    configuration option. You can use a different format by overriding it with
 
1036
    -Olog_format=<other_format>.
870
1037
 
871
1038
    Note: The location can be specified either in the form of a branch,
872
1039
    or in the form of a path to a file containing a merge directive generated
877
1044
    takes_options = ['remember', 'overwrite', 'revision',
878
1045
        custom_help('verbose',
879
1046
            help='Show logs of pulled revisions.'),
880
 
        Option('directory',
 
1047
        custom_help('directory',
881
1048
            help='Branch to pull into, '
882
 
                 'rather than the one containing the working directory.',
883
 
            short_name='d',
884
 
            type=unicode,
885
 
            ),
 
1049
                 'rather than the one containing the working directory.'),
886
1050
        Option('local',
887
1051
            help="Perform a local pull in a bound "
888
1052
                 "branch.  Local pulls are not applied to "
889
1053
                 "the master branch."
890
1054
            ),
 
1055
        Option('show-base',
 
1056
            help="Show base revision text in conflicts.")
891
1057
        ]
892
1058
    takes_args = ['location?']
893
1059
    encoding_type = 'replace'
894
1060
 
895
 
    def run(self, location=None, remember=False, overwrite=False,
 
1061
    def run(self, location=None, remember=None, overwrite=False,
896
1062
            revision=None, verbose=False,
897
 
            directory=None, local=False):
 
1063
            directory=None, local=False,
 
1064
            show_base=False):
898
1065
        # FIXME: too much stuff is in the command class
899
1066
        revision_id = None
900
1067
        mergeable = None
903
1070
        try:
904
1071
            tree_to = WorkingTree.open_containing(directory)[0]
905
1072
            branch_to = tree_to.branch
 
1073
            self.add_cleanup(tree_to.lock_write().unlock)
906
1074
        except errors.NoWorkingTree:
907
1075
            tree_to = None
908
1076
            branch_to = Branch.open_containing(directory)[0]
909
 
        
 
1077
            self.add_cleanup(branch_to.lock_write().unlock)
 
1078
 
 
1079
        if tree_to is None and show_base:
 
1080
            raise errors.BzrCommandError(gettext("Need working tree for --show-base."))
 
1081
 
910
1082
        if local and not branch_to.get_bound_location():
911
1083
            raise errors.LocalRequiresBoundBranch()
912
1084
 
921
1093
        stored_loc = branch_to.get_parent()
922
1094
        if location is None:
923
1095
            if stored_loc is None:
924
 
                raise errors.BzrCommandError("No pull location known or"
925
 
                                             " specified.")
 
1096
                raise errors.BzrCommandError(gettext("No pull location known or"
 
1097
                                             " specified."))
926
1098
            else:
927
1099
                display_url = urlutils.unescape_for_display(stored_loc,
928
1100
                        self.outf.encoding)
929
1101
                if not is_quiet():
930
 
                    self.outf.write("Using saved parent location: %s\n" % display_url)
 
1102
                    self.outf.write(gettext("Using saved parent location: %s\n") % display_url)
931
1103
                location = stored_loc
932
1104
 
933
1105
        revision = _get_one_revision('pull', revision)
934
1106
        if mergeable is not None:
935
1107
            if revision is not None:
936
 
                raise errors.BzrCommandError(
937
 
                    'Cannot use -r with merge directives or bundles')
 
1108
                raise errors.BzrCommandError(gettext(
 
1109
                    'Cannot use -r with merge directives or bundles'))
938
1110
            mergeable.install_revisions(branch_to.repository)
939
1111
            base_revision_id, revision_id, verified = \
940
1112
                mergeable.get_merge_request(branch_to.repository)
942
1114
        else:
943
1115
            branch_from = Branch.open(location,
944
1116
                possible_transports=possible_transports)
945
 
 
946
 
            if branch_to.get_parent() is None or remember:
 
1117
            self.add_cleanup(branch_from.lock_read().unlock)
 
1118
            # Remembers if asked explicitly or no previous location is set
 
1119
            if (remember
 
1120
                or (remember is None and branch_to.get_parent() is None)):
947
1121
                branch_to.set_parent(branch_from.base)
948
1122
 
949
 
        if branch_from is not branch_to:
950
 
            branch_from.lock_read()
951
 
        try:
952
 
            if revision is not None:
953
 
                revision_id = revision.as_revision_id(branch_from)
954
 
 
955
 
            branch_to.lock_write()
956
 
            try:
957
 
                if tree_to is not None:
958
 
                    view_info = _get_view_info_for_change_reporter(tree_to)
959
 
                    change_reporter = delta._ChangeReporter(
960
 
                        unversioned_filter=tree_to.is_ignored,
961
 
                        view_info=view_info)
962
 
                    result = tree_to.pull(
963
 
                        branch_from, overwrite, revision_id, change_reporter,
964
 
                        possible_transports=possible_transports, local=local)
965
 
                else:
966
 
                    result = branch_to.pull(
967
 
                        branch_from, overwrite, revision_id, local=local)
968
 
 
969
 
                result.report(self.outf)
970
 
                if verbose and result.old_revid != result.new_revid:
971
 
                    log.show_branch_change(
972
 
                        branch_to, self.outf, result.old_revno,
973
 
                        result.old_revid)
974
 
            finally:
975
 
                branch_to.unlock()
976
 
        finally:
977
 
            if branch_from is not branch_to:
978
 
                branch_from.unlock()
 
1123
        if revision is not None:
 
1124
            revision_id = revision.as_revision_id(branch_from)
 
1125
 
 
1126
        if tree_to is not None:
 
1127
            view_info = _get_view_info_for_change_reporter(tree_to)
 
1128
            change_reporter = delta._ChangeReporter(
 
1129
                unversioned_filter=tree_to.is_ignored,
 
1130
                view_info=view_info)
 
1131
            result = tree_to.pull(
 
1132
                branch_from, overwrite, revision_id, change_reporter,
 
1133
                local=local, show_base=show_base)
 
1134
        else:
 
1135
            result = branch_to.pull(
 
1136
                branch_from, overwrite, revision_id, local=local)
 
1137
 
 
1138
        result.report(self.outf)
 
1139
        if verbose and result.old_revid != result.new_revid:
 
1140
            log.show_branch_change(
 
1141
                branch_to, self.outf, result.old_revno,
 
1142
                result.old_revid)
 
1143
        if getattr(result, 'tag_conflicts', None):
 
1144
            return 1
 
1145
        else:
 
1146
            return 0
979
1147
 
980
1148
 
981
1149
class cmd_push(Command):
982
 
    """Update a mirror of this branch.
 
1150
    __doc__ = """Update a mirror of this branch.
983
1151
 
984
1152
    The target branch will not have its working tree populated because this
985
1153
    is both expensive, and is not supported on remote file systems.
998
1166
    do a merge (see bzr help merge) from the other branch, and commit that.
999
1167
    After that you will be able to do a push without '--overwrite'.
1000
1168
 
1001
 
    If there is no default push location set, the first push will set it.
1002
 
    After that, you can omit the location to use the default.  To change the
1003
 
    default, use --remember. The value will only be saved if the remote
1004
 
    location can be accessed.
 
1169
    If there is no default push location set, the first push will set it (use
 
1170
    --no-remember to avoid setting it).  After that, you can omit the
 
1171
    location to use the default.  To change the default, use --remember. The
 
1172
    value will only be saved if the remote location can be accessed.
 
1173
 
 
1174
    The --verbose option will display the revisions pushed using the log_format
 
1175
    configuration option. You can use a different format by overriding it with
 
1176
    -Olog_format=<other_format>.
1005
1177
    """
1006
1178
 
1007
1179
    _see_also = ['pull', 'update', 'working-trees']
1009
1181
        Option('create-prefix',
1010
1182
               help='Create the path leading up to the branch '
1011
1183
                    'if it does not already exist.'),
1012
 
        Option('directory',
 
1184
        custom_help('directory',
1013
1185
            help='Branch to push from, '
1014
 
                 'rather than the one containing the working directory.',
1015
 
            short_name='d',
1016
 
            type=unicode,
1017
 
            ),
 
1186
                 'rather than the one containing the working directory.'),
1018
1187
        Option('use-existing-dir',
1019
1188
               help='By default push will fail if the target'
1020
1189
                    ' directory exists, but does not already'
1030
1199
            type=unicode),
1031
1200
        Option('strict',
1032
1201
               help='Refuse to push if there are uncommitted changes in'
1033
 
               ' the working tree.'),
 
1202
               ' the working tree, --no-strict disables the check.'),
 
1203
        Option('no-tree',
 
1204
               help="Don't populate the working tree, even for protocols"
 
1205
               " that support it."),
1034
1206
        ]
1035
1207
    takes_args = ['location?']
1036
1208
    encoding_type = 'replace'
1037
1209
 
1038
 
    def run(self, location=None, remember=False, overwrite=False,
 
1210
    def run(self, location=None, remember=None, overwrite=False,
1039
1211
        create_prefix=False, verbose=False, revision=None,
1040
1212
        use_existing_dir=False, directory=None, stacked_on=None,
1041
 
        stacked=False, strict=None):
 
1213
        stacked=False, strict=None, no_tree=False):
1042
1214
        from bzrlib.push import _show_push_branch
1043
1215
 
1044
1216
        if directory is None:
1045
1217
            directory = '.'
1046
1218
        # Get the source branch
1047
 
        tree, br_from = bzrdir.BzrDir.open_tree_or_branch(directory)
1048
 
        if strict is None:
1049
 
            strict = br_from.get_config().get_user_option('push_strict')
1050
 
            if strict is not None:
1051
 
                # FIXME: This should be better supported by config
1052
 
                # -- vila 20090611
1053
 
                bools = dict(yes=True, no=False, on=True, off=False,
1054
 
                             true=True, false=False)
1055
 
                try:
1056
 
                    strict = bools[strict.lower()]
1057
 
                except KeyError:
1058
 
                    strict = None
1059
 
        if strict:
1060
 
            changes = tree.changes_from(tree.basis_tree())
1061
 
            if changes.has_changed():
1062
 
                raise errors.UncommittedChanges(tree)
 
1219
        (tree, br_from,
 
1220
         _unused) = controldir.ControlDir.open_containing_tree_or_branch(directory)
1063
1221
        # Get the tip's revision_id
1064
1222
        revision = _get_one_revision('push', revision)
1065
1223
        if revision is not None:
1066
1224
            revision_id = revision.in_history(br_from).rev_id
1067
1225
        else:
1068
1226
            revision_id = None
1069
 
 
 
1227
        if tree is not None and revision_id is None:
 
1228
            tree.check_changed_or_out_of_date(
 
1229
                strict, 'push_strict',
 
1230
                more_error='Use --no-strict to force the push.',
 
1231
                more_warning='Uncommitted changes will not be pushed.')
1070
1232
        # Get the stacked_on branch, if any
1071
1233
        if stacked_on is not None:
1072
1234
            stacked_on = urlutils.normalize_url(stacked_on)
1082
1244
                    # error by the feedback given to them. RBC 20080227.
1083
1245
                    stacked_on = parent_url
1084
1246
            if not stacked_on:
1085
 
                raise errors.BzrCommandError(
1086
 
                    "Could not determine branch to refer to.")
 
1247
                raise errors.BzrCommandError(gettext(
 
1248
                    "Could not determine branch to refer to."))
1087
1249
 
1088
1250
        # Get the destination location
1089
1251
        if location is None:
1090
1252
            stored_loc = br_from.get_push_location()
1091
1253
            if stored_loc is None:
1092
 
                raise errors.BzrCommandError(
1093
 
                    "No push location known or specified.")
 
1254
                parent_loc = br_from.get_parent()
 
1255
                if parent_loc:
 
1256
                    raise errors.BzrCommandError(gettext(
 
1257
                        "No push location known or specified. To push to the "
 
1258
                        "parent branch (at %s), use 'bzr push :parent'." %
 
1259
                        urlutils.unescape_for_display(parent_loc,
 
1260
                            self.outf.encoding)))
 
1261
                else:
 
1262
                    raise errors.BzrCommandError(gettext(
 
1263
                        "No push location known or specified."))
1094
1264
            else:
1095
1265
                display_url = urlutils.unescape_for_display(stored_loc,
1096
1266
                        self.outf.encoding)
1097
 
                self.outf.write("Using saved push location: %s\n" % display_url)
 
1267
                note(gettext("Using saved push location: %s") % display_url)
1098
1268
                location = stored_loc
1099
1269
 
1100
1270
        _show_push_branch(br_from, revision_id, location, self.outf,
1101
1271
            verbose=verbose, overwrite=overwrite, remember=remember,
1102
1272
            stacked_on=stacked_on, create_prefix=create_prefix,
1103
 
            use_existing_dir=use_existing_dir)
 
1273
            use_existing_dir=use_existing_dir, no_tree=no_tree)
1104
1274
 
1105
1275
 
1106
1276
class cmd_branch(Command):
1107
 
    """Create a new branch that is a copy of an existing branch.
 
1277
    __doc__ = """Create a new branch that is a copy of an existing branch.
1108
1278
 
1109
1279
    If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
1110
1280
    be used.  In other words, "branch ../foo/bar" will attempt to create ./bar.
1115
1285
 
1116
1286
    To retrieve the branch as of a particular revision, supply the --revision
1117
1287
    parameter, as in "branch foo/bar -r 5".
 
1288
 
 
1289
    The synonyms 'clone' and 'get' for this command are deprecated.
1118
1290
    """
1119
1291
 
1120
1292
    _see_also = ['checkout']
1121
1293
    takes_args = ['from_location', 'to_location?']
1122
 
    takes_options = ['revision', Option('hardlink',
1123
 
        help='Hard-link working tree files where possible.'),
 
1294
    takes_options = ['revision',
 
1295
        Option('hardlink', help='Hard-link working tree files where possible.'),
 
1296
        Option('files-from', type=str,
 
1297
               help="Get file contents from this tree."),
1124
1298
        Option('no-tree',
1125
1299
            help="Create a branch without a working-tree."),
 
1300
        Option('switch',
 
1301
            help="Switch the checkout in the current directory "
 
1302
                 "to the new branch."),
1126
1303
        Option('stacked',
1127
1304
            help='Create a stacked branch referring to the source branch. '
1128
1305
                'The new branch will depend on the availability of the source '
1129
1306
                'branch for all operations.'),
1130
1307
        Option('standalone',
1131
1308
               help='Do not use a shared repository, even if available.'),
 
1309
        Option('use-existing-dir',
 
1310
               help='By default branch will fail if the target'
 
1311
                    ' directory exists, but does not already'
 
1312
                    ' have a control directory.  This flag will'
 
1313
                    ' allow branch to proceed.'),
 
1314
        Option('bind',
 
1315
            help="Bind new branch to from location."),
1132
1316
        ]
1133
1317
    aliases = ['get', 'clone']
1134
1318
 
1135
1319
    def run(self, from_location, to_location=None, revision=None,
1136
 
            hardlink=False, stacked=False, standalone=False, no_tree=False):
 
1320
            hardlink=False, stacked=False, standalone=False, no_tree=False,
 
1321
            use_existing_dir=False, switch=False, bind=False,
 
1322
            files_from=None):
 
1323
        from bzrlib import switch as _mod_switch
1137
1324
        from bzrlib.tag import _merge_tags_if_possible
1138
 
 
1139
 
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
 
1325
        if self.invoked_as in ['get', 'clone']:
 
1326
            ui.ui_factory.show_user_warning(
 
1327
                'deprecated_command',
 
1328
                deprecated_name=self.invoked_as,
 
1329
                recommended_name='branch',
 
1330
                deprecated_in_version='2.4')
 
1331
        accelerator_tree, br_from = controldir.ControlDir.open_tree_or_branch(
1140
1332
            from_location)
1141
 
        if (accelerator_tree is not None and
1142
 
            accelerator_tree.supports_content_filtering()):
 
1333
        if not (hardlink or files_from):
 
1334
            # accelerator_tree is usually slower because you have to read N
 
1335
            # files (no readahead, lots of seeks, etc), but allow the user to
 
1336
            # explicitly request it
1143
1337
            accelerator_tree = None
 
1338
        if files_from is not None and files_from != from_location:
 
1339
            accelerator_tree = WorkingTree.open(files_from)
1144
1340
        revision = _get_one_revision('branch', revision)
1145
 
        br_from.lock_read()
1146
 
        try:
1147
 
            if revision is not None:
1148
 
                revision_id = revision.as_revision_id(br_from)
1149
 
            else:
1150
 
                # FIXME - wt.last_revision, fallback to branch, fall back to
1151
 
                # None or perhaps NULL_REVISION to mean copy nothing
1152
 
                # RBC 20060209
1153
 
                revision_id = br_from.last_revision()
 
1341
        self.add_cleanup(br_from.lock_read().unlock)
 
1342
        if revision is not None:
 
1343
            revision_id = revision.as_revision_id(br_from)
 
1344
        else:
 
1345
            # FIXME - wt.last_revision, fallback to branch, fall back to
 
1346
            # None or perhaps NULL_REVISION to mean copy nothing
 
1347
            # RBC 20060209
 
1348
            revision_id = br_from.last_revision()
 
1349
        if to_location is None:
 
1350
            to_location = getattr(br_from, "name", None)
1154
1351
            if to_location is None:
1155
1352
                to_location = urlutils.derive_to_location(from_location)
1156
 
            to_transport = transport.get_transport(to_location)
 
1353
        to_transport = transport.get_transport(to_location)
 
1354
        try:
 
1355
            to_transport.mkdir('.')
 
1356
        except errors.FileExists:
1157
1357
            try:
1158
 
                to_transport.mkdir('.')
1159
 
            except errors.FileExists:
1160
 
                raise errors.BzrCommandError('Target directory "%s" already'
1161
 
                                             ' exists.' % to_location)
1162
 
            except errors.NoSuchFile:
1163
 
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
1164
 
                                             % to_location)
 
1358
                to_dir = controldir.ControlDir.open_from_transport(
 
1359
                    to_transport)
 
1360
            except errors.NotBranchError:
 
1361
                if not use_existing_dir:
 
1362
                    raise errors.BzrCommandError(gettext('Target directory "%s" '
 
1363
                        'already exists.') % to_location)
 
1364
                else:
 
1365
                    to_dir = None
 
1366
            else:
 
1367
                try:
 
1368
                    to_dir.open_branch()
 
1369
                except errors.NotBranchError:
 
1370
                    pass
 
1371
                else:
 
1372
                    raise errors.AlreadyBranchError(to_location)
 
1373
        except errors.NoSuchFile:
 
1374
            raise errors.BzrCommandError(gettext('Parent of "%s" does not exist.')
 
1375
                                         % to_location)
 
1376
        else:
 
1377
            to_dir = None
 
1378
        if to_dir is None:
1165
1379
            try:
1166
1380
                # preserve whatever source format we have.
1167
 
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
 
1381
                to_dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
1168
1382
                                            possible_transports=[to_transport],
1169
1383
                                            accelerator_tree=accelerator_tree,
1170
1384
                                            hardlink=hardlink, stacked=stacked,
1171
1385
                                            force_new_repo=standalone,
1172
1386
                                            create_tree_if_local=not no_tree,
1173
1387
                                            source_branch=br_from)
1174
 
                branch = dir.open_branch()
 
1388
                branch = to_dir.open_branch(
 
1389
                    possible_transports=[
 
1390
                        br_from.bzrdir.root_transport, to_transport])
1175
1391
            except errors.NoSuchRevision:
1176
1392
                to_transport.delete_tree('.')
1177
 
                msg = "The branch %s has no revision %s." % (from_location,
1178
 
                    revision)
 
1393
                msg = gettext("The branch {0} has no revision {1}.").format(
 
1394
                    from_location, revision)
1179
1395
                raise errors.BzrCommandError(msg)
1180
 
            _merge_tags_if_possible(br_from, branch)
1181
 
            # If the source branch is stacked, the new branch may
1182
 
            # be stacked whether we asked for that explicitly or not.
1183
 
            # We therefore need a try/except here and not just 'if stacked:'
 
1396
        else:
 
1397
            branch = br_from.sprout(to_dir, revision_id=revision_id)
 
1398
        _merge_tags_if_possible(br_from, branch)
 
1399
        # If the source branch is stacked, the new branch may
 
1400
        # be stacked whether we asked for that explicitly or not.
 
1401
        # We therefore need a try/except here and not just 'if stacked:'
 
1402
        try:
 
1403
            note(gettext('Created new stacked branch referring to %s.') %
 
1404
                branch.get_stacked_on_url())
 
1405
        except (errors.NotStacked, errors.UnstackableBranchFormat,
 
1406
            errors.UnstackableRepositoryFormat), e:
 
1407
            note(ngettext('Branched %d revision.', 'Branched %d revisions.', branch.revno()) % branch.revno())
 
1408
        if bind:
 
1409
            # Bind to the parent
 
1410
            parent_branch = Branch.open(from_location)
 
1411
            branch.bind(parent_branch)
 
1412
            note(gettext('New branch bound to %s') % from_location)
 
1413
        if switch:
 
1414
            # Switch to the new branch
 
1415
            wt, _ = WorkingTree.open_containing('.')
 
1416
            _mod_switch.switch(wt.bzrdir, branch)
 
1417
            note(gettext('Switched to branch: %s'),
 
1418
                urlutils.unescape_for_display(branch.base, 'utf-8'))
 
1419
 
 
1420
 
 
1421
class cmd_branches(Command):
 
1422
    __doc__ = """List the branches available at the current location.
 
1423
 
 
1424
    This command will print the names of all the branches at the current
 
1425
    location.
 
1426
    """
 
1427
 
 
1428
    takes_args = ['location?']
 
1429
    takes_options = [
 
1430
                  Option('recursive', short_name='R',
 
1431
                         help='Recursively scan for branches rather than '
 
1432
                              'just looking in the specified location.')]
 
1433
 
 
1434
    def run(self, location=".", recursive=False):
 
1435
        if recursive:
 
1436
            t = transport.get_transport(location)
 
1437
            if not t.listable():
 
1438
                raise errors.BzrCommandError(
 
1439
                    "Can't scan this type of location.")
 
1440
            for b in controldir.ControlDir.find_branches(t):
 
1441
                self.outf.write("%s\n" % urlutils.unescape_for_display(
 
1442
                    urlutils.relative_url(t.base, b.base),
 
1443
                    self.outf.encoding).rstrip("/"))
 
1444
        else:
 
1445
            dir = controldir.ControlDir.open_containing(location)[0]
1184
1446
            try:
1185
 
                note('Created new stacked branch referring to %s.' %
1186
 
                    branch.get_stacked_on_url())
1187
 
            except (errors.NotStacked, errors.UnstackableBranchFormat,
1188
 
                errors.UnstackableRepositoryFormat), e:
1189
 
                note('Branched %d revision(s).' % branch.revno())
1190
 
        finally:
1191
 
            br_from.unlock()
 
1447
                active_branch = dir.open_branch(name="")
 
1448
            except errors.NotBranchError:
 
1449
                active_branch = None
 
1450
            branches = dir.get_branches()
 
1451
            names = {}
 
1452
            for name, branch in branches.iteritems():
 
1453
                if name == "":
 
1454
                    continue
 
1455
                active = (active_branch is not None and
 
1456
                          active_branch.base == branch.base)
 
1457
                names[name] = active
 
1458
            # Only mention the current branch explicitly if it's not
 
1459
            # one of the colocated branches
 
1460
            if not any(names.values()) and active_branch is not None:
 
1461
                self.outf.write("* %s\n" % gettext("(default)"))
 
1462
            for name in sorted(names.keys()):
 
1463
                active = names[name]
 
1464
                if active:
 
1465
                    prefix = "*"
 
1466
                else:
 
1467
                    prefix = " "
 
1468
                self.outf.write("%s %s\n" % (
 
1469
                    prefix, name.encode(self.outf.encoding)))
1192
1470
 
1193
1471
 
1194
1472
class cmd_checkout(Command):
1195
 
    """Create a new checkout of an existing branch.
 
1473
    __doc__ = """Create a new checkout of an existing branch.
1196
1474
 
1197
1475
    If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree for
1198
1476
    the branch found in '.'. This is useful if you have removed the working tree
1235
1513
        if branch_location is None:
1236
1514
            branch_location = osutils.getcwd()
1237
1515
            to_location = branch_location
1238
 
        accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch(
 
1516
        accelerator_tree, source = controldir.ControlDir.open_tree_or_branch(
1239
1517
            branch_location)
 
1518
        if not (hardlink or files_from):
 
1519
            # accelerator_tree is usually slower because you have to read N
 
1520
            # files (no readahead, lots of seeks, etc), but allow the user to
 
1521
            # explicitly request it
 
1522
            accelerator_tree = None
1240
1523
        revision = _get_one_revision('checkout', revision)
1241
 
        if files_from is not None:
 
1524
        if files_from is not None and files_from != branch_location:
1242
1525
            accelerator_tree = WorkingTree.open(files_from)
1243
1526
        if revision is not None:
1244
1527
            revision_id = revision.as_revision_id(source)
1261
1544
 
1262
1545
 
1263
1546
class cmd_renames(Command):
1264
 
    """Show list of renamed files.
 
1547
    __doc__ = """Show list of renamed files.
1265
1548
    """
1266
1549
    # TODO: Option to show renames between two historical versions.
1267
1550
 
1272
1555
    @display_command
1273
1556
    def run(self, dir=u'.'):
1274
1557
        tree = WorkingTree.open_containing(dir)[0]
1275
 
        tree.lock_read()
1276
 
        try:
1277
 
            new_inv = tree.inventory
1278
 
            old_tree = tree.basis_tree()
1279
 
            old_tree.lock_read()
1280
 
            try:
1281
 
                old_inv = old_tree.inventory
1282
 
                renames = []
1283
 
                iterator = tree.iter_changes(old_tree, include_unchanged=True)
1284
 
                for f, paths, c, v, p, n, k, e in iterator:
1285
 
                    if paths[0] == paths[1]:
1286
 
                        continue
1287
 
                    if None in (paths):
1288
 
                        continue
1289
 
                    renames.append(paths)
1290
 
                renames.sort()
1291
 
                for old_name, new_name in renames:
1292
 
                    self.outf.write("%s => %s\n" % (old_name, new_name))
1293
 
            finally:
1294
 
                old_tree.unlock()
1295
 
        finally:
1296
 
            tree.unlock()
 
1558
        self.add_cleanup(tree.lock_read().unlock)
 
1559
        new_inv = tree.inventory
 
1560
        old_tree = tree.basis_tree()
 
1561
        self.add_cleanup(old_tree.lock_read().unlock)
 
1562
        old_inv = old_tree.inventory
 
1563
        renames = []
 
1564
        iterator = tree.iter_changes(old_tree, include_unchanged=True)
 
1565
        for f, paths, c, v, p, n, k, e in iterator:
 
1566
            if paths[0] == paths[1]:
 
1567
                continue
 
1568
            if None in (paths):
 
1569
                continue
 
1570
            renames.append(paths)
 
1571
        renames.sort()
 
1572
        for old_name, new_name in renames:
 
1573
            self.outf.write("%s => %s\n" % (old_name, new_name))
1297
1574
 
1298
1575
 
1299
1576
class cmd_update(Command):
1300
 
    """Update a tree to have the latest code committed to its branch.
1301
 
 
1302
 
    This will perform a merge into the working tree, and may generate
1303
 
    conflicts. If you have any local changes, you will still
1304
 
    need to commit them after the update for the update to be complete.
1305
 
 
1306
 
    If you want to discard your local changes, you can just do a
1307
 
    'bzr revert' instead of 'bzr commit' after the update.
 
1577
    __doc__ = """Update a working tree to a new revision.
 
1578
 
 
1579
    This will perform a merge of the destination revision (the tip of the
 
1580
    branch, or the specified revision) into the working tree, and then make
 
1581
    that revision the basis revision for the working tree.  
 
1582
 
 
1583
    You can use this to visit an older revision, or to update a working tree
 
1584
    that is out of date from its branch.
 
1585
    
 
1586
    If there are any uncommitted changes in the tree, they will be carried
 
1587
    across and remain as uncommitted changes after the update.  To discard
 
1588
    these changes, use 'bzr revert'.  The uncommitted changes may conflict
 
1589
    with the changes brought in by the change in basis revision.
 
1590
 
 
1591
    If the tree's branch is bound to a master branch, bzr will also update
 
1592
    the branch from the master.
 
1593
 
 
1594
    You cannot update just a single file or directory, because each Bazaar
 
1595
    working tree has just a single basis revision.  If you want to restore a
 
1596
    file that has been removed locally, use 'bzr revert' instead of 'bzr
 
1597
    update'.  If you want to restore a file to its state in a previous
 
1598
    revision, use 'bzr revert' with a '-r' option, or use 'bzr cat' to write
 
1599
    out the old content of that file to a new location.
 
1600
 
 
1601
    The 'dir' argument, if given, must be the location of the root of a
 
1602
    working tree to update.  By default, the working tree that contains the 
 
1603
    current working directory is used.
1308
1604
    """
1309
1605
 
1310
1606
    _see_also = ['pull', 'working-trees', 'status-flags']
1311
1607
    takes_args = ['dir?']
 
1608
    takes_options = ['revision',
 
1609
                     Option('show-base',
 
1610
                            help="Show base revision text in conflicts."),
 
1611
                     ]
1312
1612
    aliases = ['up']
1313
1613
 
1314
 
    def run(self, dir='.'):
1315
 
        tree = WorkingTree.open_containing(dir)[0]
 
1614
    def run(self, dir=None, revision=None, show_base=None):
 
1615
        if revision is not None and len(revision) != 1:
 
1616
            raise errors.BzrCommandError(gettext(
 
1617
                "bzr update --revision takes exactly one revision"))
 
1618
        if dir is None:
 
1619
            tree = WorkingTree.open_containing('.')[0]
 
1620
        else:
 
1621
            tree, relpath = WorkingTree.open_containing(dir)
 
1622
            if relpath:
 
1623
                # See bug 557886.
 
1624
                raise errors.BzrCommandError(gettext(
 
1625
                    "bzr update can only update a whole tree, "
 
1626
                    "not a file or subdirectory"))
 
1627
        branch = tree.branch
1316
1628
        possible_transports = []
1317
 
        master = tree.branch.get_master_branch(
 
1629
        master = branch.get_master_branch(
1318
1630
            possible_transports=possible_transports)
1319
1631
        if master is not None:
 
1632
            branch_location = master.base
1320
1633
            tree.lock_write()
1321
1634
        else:
 
1635
            branch_location = tree.branch.base
1322
1636
            tree.lock_tree_write()
 
1637
        self.add_cleanup(tree.unlock)
 
1638
        # get rid of the final '/' and be ready for display
 
1639
        branch_location = urlutils.unescape_for_display(
 
1640
            branch_location.rstrip('/'),
 
1641
            self.outf.encoding)
 
1642
        existing_pending_merges = tree.get_parent_ids()[1:]
 
1643
        if master is None:
 
1644
            old_tip = None
 
1645
        else:
 
1646
            # may need to fetch data into a heavyweight checkout
 
1647
            # XXX: this may take some time, maybe we should display a
 
1648
            # message
 
1649
            old_tip = branch.update(possible_transports)
 
1650
        if revision is not None:
 
1651
            revision_id = revision[0].as_revision_id(branch)
 
1652
        else:
 
1653
            revision_id = branch.last_revision()
 
1654
        if revision_id == _mod_revision.ensure_null(tree.last_revision()):
 
1655
            revno = branch.revision_id_to_dotted_revno(revision_id)
 
1656
            note(gettext("Tree is up to date at revision {0} of branch {1}"
 
1657
                        ).format('.'.join(map(str, revno)), branch_location))
 
1658
            return 0
 
1659
        view_info = _get_view_info_for_change_reporter(tree)
 
1660
        change_reporter = delta._ChangeReporter(
 
1661
            unversioned_filter=tree.is_ignored,
 
1662
            view_info=view_info)
1323
1663
        try:
1324
 
            existing_pending_merges = tree.get_parent_ids()[1:]
1325
 
            last_rev = _mod_revision.ensure_null(tree.last_revision())
1326
 
            if last_rev == _mod_revision.ensure_null(
1327
 
                tree.branch.last_revision()):
1328
 
                # may be up to date, check master too.
1329
 
                if master is None or last_rev == _mod_revision.ensure_null(
1330
 
                    master.last_revision()):
1331
 
                    revno = tree.branch.revision_id_to_revno(last_rev)
1332
 
                    note("Tree is up to date at revision %d." % (revno,))
1333
 
                    return 0
1334
 
            view_info = _get_view_info_for_change_reporter(tree)
1335
1664
            conflicts = tree.update(
1336
 
                delta._ChangeReporter(unversioned_filter=tree.is_ignored,
1337
 
                view_info=view_info), possible_transports=possible_transports)
1338
 
            revno = tree.branch.revision_id_to_revno(
1339
 
                _mod_revision.ensure_null(tree.last_revision()))
1340
 
            note('Updated to revision %d.' % (revno,))
1341
 
            if tree.get_parent_ids()[1:] != existing_pending_merges:
1342
 
                note('Your local commits will now show as pending merges with '
1343
 
                     "'bzr status', and can be committed with 'bzr commit'.")
1344
 
            if conflicts != 0:
1345
 
                return 1
1346
 
            else:
1347
 
                return 0
1348
 
        finally:
1349
 
            tree.unlock()
 
1665
                change_reporter,
 
1666
                possible_transports=possible_transports,
 
1667
                revision=revision_id,
 
1668
                old_tip=old_tip,
 
1669
                show_base=show_base)
 
1670
        except errors.NoSuchRevision, e:
 
1671
            raise errors.BzrCommandError(gettext(
 
1672
                                  "branch has no revision %s\n"
 
1673
                                  "bzr update --revision only works"
 
1674
                                  " for a revision in the branch history")
 
1675
                                  % (e.revision))
 
1676
        revno = tree.branch.revision_id_to_dotted_revno(
 
1677
            _mod_revision.ensure_null(tree.last_revision()))
 
1678
        note(gettext('Updated to revision {0} of branch {1}').format(
 
1679
             '.'.join(map(str, revno)), branch_location))
 
1680
        parent_ids = tree.get_parent_ids()
 
1681
        if parent_ids[1:] and parent_ids[1:] != existing_pending_merges:
 
1682
            note(gettext('Your local commits will now show as pending merges with '
 
1683
                 "'bzr status', and can be committed with 'bzr commit'."))
 
1684
        if conflicts != 0:
 
1685
            return 1
 
1686
        else:
 
1687
            return 0
1350
1688
 
1351
1689
 
1352
1690
class cmd_info(Command):
1353
 
    """Show information about a working tree, branch or repository.
 
1691
    __doc__ = """Show information about a working tree, branch or repository.
1354
1692
 
1355
1693
    This command will show all known locations and formats associated to the
1356
1694
    tree, branch or repository.
1389
1727
        else:
1390
1728
            noise_level = 0
1391
1729
        from bzrlib.info import show_bzrdir_info
1392
 
        show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
 
1730
        show_bzrdir_info(controldir.ControlDir.open_containing(location)[0],
1393
1731
                         verbose=noise_level, outfile=self.outf)
1394
1732
 
1395
1733
 
1396
1734
class cmd_remove(Command):
1397
 
    """Remove files or directories.
 
1735
    __doc__ = """Remove files or directories.
1398
1736
 
1399
 
    This makes bzr stop tracking changes to the specified files. bzr will delete
1400
 
    them if they can easily be recovered using revert. If no options or
1401
 
    parameters are given bzr will scan for files that are being tracked by bzr
1402
 
    but missing in your tree and stop tracking them for you.
 
1737
    This makes Bazaar stop tracking changes to the specified files. Bazaar will
 
1738
    delete them if they can easily be recovered using revert otherwise they
 
1739
    will be backed up (adding an extention of the form .~#~). If no options or
 
1740
    parameters are given Bazaar will scan for files that are being tracked by
 
1741
    Bazaar but missing in your tree and stop tracking them for you.
1403
1742
    """
1404
1743
    takes_args = ['file*']
1405
1744
    takes_options = ['verbose',
1407
1746
        RegistryOption.from_kwargs('file-deletion-strategy',
1408
1747
            'The file deletion mode to be used.',
1409
1748
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1410
 
            safe='Only delete files if they can be'
1411
 
                 ' safely recovered (default).',
1412
 
            keep="Don't delete any files.",
 
1749
            safe='Backup changed files (default).',
 
1750
            keep='Delete from bzr but leave the working copy.',
 
1751
            no_backup='Don\'t backup changed files.',
1413
1752
            force='Delete all the specified files, even if they can not be '
1414
 
                'recovered and even if they are non-empty directories.')]
 
1753
                'recovered and even if they are non-empty directories. '
 
1754
                '(deprecated, use no-backup)')]
1415
1755
    aliases = ['rm', 'del']
1416
1756
    encoding_type = 'replace'
1417
1757
 
1418
1758
    def run(self, file_list, verbose=False, new=False,
1419
1759
        file_deletion_strategy='safe'):
1420
 
        tree, file_list = tree_files(file_list)
 
1760
        if file_deletion_strategy == 'force':
 
1761
            note(gettext("(The --force option is deprecated, rather use --no-backup "
 
1762
                "in future.)"))
 
1763
            file_deletion_strategy = 'no-backup'
 
1764
 
 
1765
        tree, file_list = WorkingTree.open_containing_paths(file_list)
1421
1766
 
1422
1767
        if file_list is not None:
1423
1768
            file_list = [f for f in file_list]
1424
1769
 
1425
 
        tree.lock_write()
1426
 
        try:
1427
 
            # Heuristics should probably all move into tree.remove_smart or
1428
 
            # some such?
1429
 
            if new:
1430
 
                added = tree.changes_from(tree.basis_tree(),
1431
 
                    specific_files=file_list).added
1432
 
                file_list = sorted([f[0] for f in added], reverse=True)
1433
 
                if len(file_list) == 0:
1434
 
                    raise errors.BzrCommandError('No matching files.')
1435
 
            elif file_list is None:
1436
 
                # missing files show up in iter_changes(basis) as
1437
 
                # versioned-with-no-kind.
1438
 
                missing = []
1439
 
                for change in tree.iter_changes(tree.basis_tree()):
1440
 
                    # Find paths in the working tree that have no kind:
1441
 
                    if change[1][1] is not None and change[6][1] is None:
1442
 
                        missing.append(change[1][1])
1443
 
                file_list = sorted(missing, reverse=True)
1444
 
                file_deletion_strategy = 'keep'
1445
 
            tree.remove(file_list, verbose=verbose, to_file=self.outf,
1446
 
                keep_files=file_deletion_strategy=='keep',
1447
 
                force=file_deletion_strategy=='force')
1448
 
        finally:
1449
 
            tree.unlock()
 
1770
        self.add_cleanup(tree.lock_write().unlock)
 
1771
        # Heuristics should probably all move into tree.remove_smart or
 
1772
        # some such?
 
1773
        if new:
 
1774
            added = tree.changes_from(tree.basis_tree(),
 
1775
                specific_files=file_list).added
 
1776
            file_list = sorted([f[0] for f in added], reverse=True)
 
1777
            if len(file_list) == 0:
 
1778
                raise errors.BzrCommandError(gettext('No matching files.'))
 
1779
        elif file_list is None:
 
1780
            # missing files show up in iter_changes(basis) as
 
1781
            # versioned-with-no-kind.
 
1782
            missing = []
 
1783
            for change in tree.iter_changes(tree.basis_tree()):
 
1784
                # Find paths in the working tree that have no kind:
 
1785
                if change[1][1] is not None and change[6][1] is None:
 
1786
                    missing.append(change[1][1])
 
1787
            file_list = sorted(missing, reverse=True)
 
1788
            file_deletion_strategy = 'keep'
 
1789
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
 
1790
            keep_files=file_deletion_strategy=='keep',
 
1791
            force=(file_deletion_strategy=='no-backup'))
1450
1792
 
1451
1793
 
1452
1794
class cmd_file_id(Command):
1453
 
    """Print file_id of a particular file or directory.
 
1795
    __doc__ = """Print file_id of a particular file or directory.
1454
1796
 
1455
1797
    The file_id is assigned when the file is first added and remains the
1456
1798
    same through all revisions where the file exists, even when it is
1472
1814
 
1473
1815
 
1474
1816
class cmd_file_path(Command):
1475
 
    """Print path of file_ids to a file or directory.
 
1817
    __doc__ = """Print path of file_ids to a file or directory.
1476
1818
 
1477
1819
    This prints one line for each directory down to the target,
1478
1820
    starting at the branch root.
1494
1836
 
1495
1837
 
1496
1838
class cmd_reconcile(Command):
1497
 
    """Reconcile bzr metadata in a branch.
 
1839
    __doc__ = """Reconcile bzr metadata in a branch.
1498
1840
 
1499
1841
    This can correct data mismatches that may have been caused by
1500
1842
    previous ghost operations or bzr upgrades. You should only
1514
1856
 
1515
1857
    _see_also = ['check']
1516
1858
    takes_args = ['branch?']
 
1859
    takes_options = [
 
1860
        Option('canonicalize-chks',
 
1861
               help='Make sure CHKs are in canonical form (repairs '
 
1862
                    'bug 522637).',
 
1863
               hidden=True),
 
1864
        ]
1517
1865
 
1518
 
    def run(self, branch="."):
 
1866
    def run(self, branch=".", canonicalize_chks=False):
1519
1867
        from bzrlib.reconcile import reconcile
1520
 
        dir = bzrdir.BzrDir.open(branch)
1521
 
        reconcile(dir)
 
1868
        dir = controldir.ControlDir.open(branch)
 
1869
        reconcile(dir, canonicalize_chks=canonicalize_chks)
1522
1870
 
1523
1871
 
1524
1872
class cmd_revision_history(Command):
1525
 
    """Display the list of revision ids on a branch."""
 
1873
    __doc__ = """Display the list of revision ids on a branch."""
1526
1874
 
1527
1875
    _see_also = ['log']
1528
1876
    takes_args = ['location?']
1532
1880
    @display_command
1533
1881
    def run(self, location="."):
1534
1882
        branch = Branch.open_containing(location)[0]
1535
 
        for revid in branch.revision_history():
 
1883
        self.add_cleanup(branch.lock_read().unlock)
 
1884
        graph = branch.repository.get_graph()
 
1885
        history = list(graph.iter_lefthand_ancestry(branch.last_revision(),
 
1886
            [_mod_revision.NULL_REVISION]))
 
1887
        for revid in reversed(history):
1536
1888
            self.outf.write(revid)
1537
1889
            self.outf.write('\n')
1538
1890
 
1539
1891
 
1540
1892
class cmd_ancestry(Command):
1541
 
    """List all revisions merged into this branch."""
 
1893
    __doc__ = """List all revisions merged into this branch."""
1542
1894
 
1543
1895
    _see_also = ['log', 'revision-history']
1544
1896
    takes_args = ['location?']
1556
1908
            b = wt.branch
1557
1909
            last_revision = wt.last_revision()
1558
1910
 
1559
 
        revision_ids = b.repository.get_ancestry(last_revision)
1560
 
        revision_ids.pop(0)
1561
 
        for revision_id in revision_ids:
 
1911
        self.add_cleanup(b.repository.lock_read().unlock)
 
1912
        graph = b.repository.get_graph()
 
1913
        revisions = [revid for revid, parents in
 
1914
            graph.iter_ancestry([last_revision])]
 
1915
        for revision_id in reversed(revisions):
 
1916
            if _mod_revision.is_null(revision_id):
 
1917
                continue
1562
1918
            self.outf.write(revision_id + '\n')
1563
1919
 
1564
1920
 
1565
1921
class cmd_init(Command):
1566
 
    """Make a directory into a versioned branch.
 
1922
    __doc__ = """Make a directory into a versioned branch.
1567
1923
 
1568
1924
    Use this to create an empty branch, or before importing an
1569
1925
    existing project.
1595
1951
                help='Specify a format for this branch. '
1596
1952
                'See "help formats".',
1597
1953
                lazy_registry=('bzrlib.bzrdir', 'format_registry'),
1598
 
                converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
 
1954
                converter=lambda name: controldir.format_registry.make_bzrdir(name),
1599
1955
                value_switches=True,
1600
 
                title="Branch Format",
 
1956
                title="Branch format",
1601
1957
                ),
1602
1958
         Option('append-revisions-only',
1603
1959
                help='Never change revnos or the existing log.'
1604
 
                '  Append revisions to it only.')
 
1960
                '  Append revisions to it only.'),
 
1961
         Option('no-tree',
 
1962
                'Create a branch without a working tree.')
1605
1963
         ]
1606
1964
    def run(self, location=None, format=None, append_revisions_only=False,
1607
 
            create_prefix=False):
 
1965
            create_prefix=False, no_tree=False):
1608
1966
        if format is None:
1609
 
            format = bzrdir.format_registry.make_bzrdir('default')
 
1967
            format = controldir.format_registry.make_bzrdir('default')
1610
1968
        if location is None:
1611
1969
            location = u'.'
1612
1970
 
1621
1979
            to_transport.ensure_base()
1622
1980
        except errors.NoSuchFile:
1623
1981
            if not create_prefix:
1624
 
                raise errors.BzrCommandError("Parent directory of %s"
 
1982
                raise errors.BzrCommandError(gettext("Parent directory of %s"
1625
1983
                    " does not exist."
1626
1984
                    "\nYou may supply --create-prefix to create all"
1627
 
                    " leading parent directories."
 
1985
                    " leading parent directories.")
1628
1986
                    % location)
1629
1987
            to_transport.create_prefix()
1630
1988
 
1631
1989
        try:
1632
 
            a_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport)
 
1990
            a_bzrdir = controldir.ControlDir.open_from_transport(to_transport)
1633
1991
        except errors.NotBranchError:
1634
1992
            # really a NotBzrDir error...
1635
 
            create_branch = bzrdir.BzrDir.create_branch_convenience
 
1993
            create_branch = controldir.ControlDir.create_branch_convenience
 
1994
            if no_tree:
 
1995
                force_new_tree = False
 
1996
            else:
 
1997
                force_new_tree = None
1636
1998
            branch = create_branch(to_transport.base, format=format,
1637
 
                                   possible_transports=[to_transport])
 
1999
                                   possible_transports=[to_transport],
 
2000
                                   force_new_tree=force_new_tree)
1638
2001
            a_bzrdir = branch.bzrdir
1639
2002
        else:
1640
2003
            from bzrlib.transport.local import LocalTransport
1644
2007
                        raise errors.BranchExistsWithoutWorkingTree(location)
1645
2008
                raise errors.AlreadyBranchError(location)
1646
2009
            branch = a_bzrdir.create_branch()
1647
 
            a_bzrdir.create_workingtree()
 
2010
            if not no_tree and not a_bzrdir.has_workingtree():
 
2011
                a_bzrdir.create_workingtree()
1648
2012
        if append_revisions_only:
1649
2013
            try:
1650
2014
                branch.set_append_revisions_only(True)
1651
2015
            except errors.UpgradeRequired:
1652
 
                raise errors.BzrCommandError('This branch format cannot be set'
1653
 
                    ' to append-revisions-only.  Try --default.')
 
2016
                raise errors.BzrCommandError(gettext('This branch format cannot be set'
 
2017
                    ' to append-revisions-only.  Try --default.'))
1654
2018
        if not is_quiet():
1655
2019
            from bzrlib.info import describe_layout, describe_format
1656
2020
            try:
1660
2024
            repository = branch.repository
1661
2025
            layout = describe_layout(repository, branch, tree).lower()
1662
2026
            format = describe_format(a_bzrdir, repository, branch, tree)
1663
 
            self.outf.write("Created a %s (format: %s)\n" % (layout, format))
 
2027
            self.outf.write(gettext("Created a {0} (format: {1})\n").format(
 
2028
                  layout, format))
1664
2029
            if repository.is_shared():
1665
2030
                #XXX: maybe this can be refactored into transport.path_or_url()
1666
2031
                url = repository.bzrdir.root_transport.external_url()
1668
2033
                    url = urlutils.local_path_from_url(url)
1669
2034
                except errors.InvalidURL:
1670
2035
                    pass
1671
 
                self.outf.write("Using shared repository: %s\n" % url)
 
2036
                self.outf.write(gettext("Using shared repository: %s\n") % url)
1672
2037
 
1673
2038
 
1674
2039
class cmd_init_repository(Command):
1675
 
    """Create a shared repository to hold branches.
 
2040
    __doc__ = """Create a shared repository for branches to share storage space.
1676
2041
 
1677
2042
    New branches created under the repository directory will store their
1678
 
    revisions in the repository, not in the branch directory.
 
2043
    revisions in the repository, not in the branch directory.  For branches
 
2044
    with shared history, this reduces the amount of storage needed and 
 
2045
    speeds up the creation of new branches.
1679
2046
 
1680
 
    If the --no-trees option is used then the branches in the repository
1681
 
    will not have working trees by default.
 
2047
    If the --no-trees option is given then the branches in the repository
 
2048
    will not have working trees by default.  They will still exist as 
 
2049
    directories on disk, but they will not have separate copies of the 
 
2050
    files at a certain revision.  This can be useful for repositories that
 
2051
    store branches which are interacted with through checkouts or remote
 
2052
    branches, such as on a server.
1682
2053
 
1683
2054
    :Examples:
1684
 
        Create a shared repositories holding just branches::
 
2055
        Create a shared repository holding just branches::
1685
2056
 
1686
2057
            bzr init-repo --no-trees repo
1687
2058
            bzr init repo/trunk
1698
2069
    takes_options = [RegistryOption('format',
1699
2070
                            help='Specify a format for this repository. See'
1700
2071
                                 ' "bzr help formats" for details.',
1701
 
                            lazy_registry=('bzrlib.bzrdir', 'format_registry'),
1702
 
                            converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
 
2072
                            lazy_registry=('bzrlib.controldir', 'format_registry'),
 
2073
                            converter=lambda name: controldir.format_registry.make_bzrdir(name),
1703
2074
                            value_switches=True, title='Repository format'),
1704
2075
                     Option('no-trees',
1705
2076
                             help='Branches in the repository will default to'
1709
2080
 
1710
2081
    def run(self, location, format=None, no_trees=False):
1711
2082
        if format is None:
1712
 
            format = bzrdir.format_registry.make_bzrdir('default')
 
2083
            format = controldir.format_registry.make_bzrdir('default')
1713
2084
 
1714
2085
        if location is None:
1715
2086
            location = '.'
1716
2087
 
1717
2088
        to_transport = transport.get_transport(location)
1718
 
        to_transport.ensure_base()
1719
2089
 
1720
 
        newdir = format.initialize_on_transport(to_transport)
1721
 
        repo = newdir.create_repository(shared=True)
1722
 
        repo.set_make_working_trees(not no_trees)
 
2090
        (repo, newdir, require_stacking, repository_policy) = (
 
2091
            format.initialize_on_transport_ex(to_transport,
 
2092
            create_prefix=True, make_working_trees=not no_trees,
 
2093
            shared_repo=True, force_new_repo=True,
 
2094
            use_existing_dir=True,
 
2095
            repo_format_name=format.repository_format.get_format_string()))
1723
2096
        if not is_quiet():
1724
2097
            from bzrlib.info import show_bzrdir_info
1725
 
            show_bzrdir_info(repo.bzrdir, verbose=0, outfile=self.outf)
 
2098
            show_bzrdir_info(newdir, verbose=0, outfile=self.outf)
1726
2099
 
1727
2100
 
1728
2101
class cmd_diff(Command):
1729
 
    """Show differences in the working tree, between revisions or branches.
 
2102
    __doc__ = """Show differences in the working tree, between revisions or branches.
1730
2103
 
1731
2104
    If no arguments are given, all changes for the current tree are listed.
1732
2105
    If files are given, only the changes in those files are listed.
1738
2111
    "bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
1739
2112
    produces patches suitable for "patch -p1".
1740
2113
 
 
2114
    Note that when using the -r argument with a range of revisions, the
 
2115
    differences are computed between the two specified revisions.  That
 
2116
    is, the command does not show the changes introduced by the first 
 
2117
    revision in the range.  This differs from the interpretation of 
 
2118
    revision ranges used by "bzr log" which includes the first revision
 
2119
    in the range.
 
2120
 
1741
2121
    :Exit values:
1742
2122
        1 - changed
1743
2123
        2 - unrepresentable changes
1753
2133
 
1754
2134
            bzr diff -r1
1755
2135
 
1756
 
        Difference between revision 2 and revision 1::
1757
 
 
1758
 
            bzr diff -r1..2
1759
 
 
1760
 
        Difference between revision 2 and revision 1 for branch xxx::
1761
 
 
1762
 
            bzr diff -r1..2 xxx
 
2136
        Difference between revision 3 and revision 1::
 
2137
 
 
2138
            bzr diff -r1..3
 
2139
 
 
2140
        Difference between revision 3 and revision 1 for branch xxx::
 
2141
 
 
2142
            bzr diff -r1..3 xxx
 
2143
 
 
2144
        The changes introduced by revision 2 (equivalent to -r1..2)::
 
2145
 
 
2146
            bzr diff -c2
 
2147
 
 
2148
        To see the changes introduced by revision X::
 
2149
        
 
2150
            bzr diff -cX
 
2151
 
 
2152
        Note that in the case of a merge, the -c option shows the changes
 
2153
        compared to the left hand parent. To see the changes against
 
2154
        another parent, use::
 
2155
 
 
2156
            bzr diff -r<chosen_parent>..X
 
2157
 
 
2158
        The changes between the current revision and the previous revision
 
2159
        (equivalent to -c-1 and -r-2..-1)
 
2160
 
 
2161
            bzr diff -r-2..
1763
2162
 
1764
2163
        Show just the differences for file NEWS::
1765
2164
 
1780
2179
        Same as 'bzr diff' but prefix paths with old/ and new/::
1781
2180
 
1782
2181
            bzr diff --prefix old/:new/
 
2182
            
 
2183
        Show the differences using a custom diff program with options::
 
2184
        
 
2185
            bzr diff --using /usr/bin/diff --diff-options -wu
1783
2186
    """
1784
2187
    _see_also = ['status']
1785
2188
    takes_args = ['file*']
1804
2207
            help='Use this command to compare files.',
1805
2208
            type=unicode,
1806
2209
            ),
 
2210
        RegistryOption('format',
 
2211
            short_name='F',
 
2212
            help='Diff format to use.',
 
2213
            lazy_registry=('bzrlib.diff', 'format_registry'),
 
2214
            title='Diff format'),
1807
2215
        ]
1808
2216
    aliases = ['di', 'dif']
1809
2217
    encoding_type = 'exact'
1810
2218
 
1811
2219
    @display_command
1812
2220
    def run(self, revision=None, file_list=None, diff_options=None,
1813
 
            prefix=None, old=None, new=None, using=None):
1814
 
        from bzrlib.diff import _get_trees_to_diff, show_diff_trees
 
2221
            prefix=None, old=None, new=None, using=None, format=None):
 
2222
        from bzrlib.diff import (get_trees_and_branches_to_diff_locked,
 
2223
            show_diff_trees)
1815
2224
 
1816
2225
        if (prefix is None) or (prefix == '0'):
1817
2226
            # diff -p0 format
1823
2232
        elif ':' in prefix:
1824
2233
            old_label, new_label = prefix.split(":")
1825
2234
        else:
1826
 
            raise errors.BzrCommandError(
 
2235
            raise errors.BzrCommandError(gettext(
1827
2236
                '--prefix expects two values separated by a colon'
1828
 
                ' (eg "old/:new/")')
 
2237
                ' (eg "old/:new/")'))
1829
2238
 
1830
2239
        if revision and len(revision) > 2:
1831
 
            raise errors.BzrCommandError('bzr diff --revision takes exactly'
1832
 
                                         ' one or two revision specifiers')
1833
 
 
1834
 
        old_tree, new_tree, specific_files, extra_trees = \
1835
 
                _get_trees_to_diff(file_list, revision, old, new,
1836
 
                apply_view=True)
 
2240
            raise errors.BzrCommandError(gettext('bzr diff --revision takes exactly'
 
2241
                                         ' one or two revision specifiers'))
 
2242
 
 
2243
        if using is not None and format is not None:
 
2244
            raise errors.BzrCommandError(gettext(
 
2245
                '{0} and {1} are mutually exclusive').format(
 
2246
                '--using', '--format'))
 
2247
 
 
2248
        (old_tree, new_tree,
 
2249
         old_branch, new_branch,
 
2250
         specific_files, extra_trees) = get_trees_and_branches_to_diff_locked(
 
2251
            file_list, revision, old, new, self.add_cleanup, apply_view=True)
 
2252
        # GNU diff on Windows uses ANSI encoding for filenames
 
2253
        path_encoding = osutils.get_diff_header_encoding()
1837
2254
        return show_diff_trees(old_tree, new_tree, sys.stdout,
1838
2255
                               specific_files=specific_files,
1839
2256
                               external_diff_options=diff_options,
1840
2257
                               old_label=old_label, new_label=new_label,
1841
 
                               extra_trees=extra_trees, using=using)
 
2258
                               extra_trees=extra_trees,
 
2259
                               path_encoding=path_encoding,
 
2260
                               using=using,
 
2261
                               format_cls=format)
1842
2262
 
1843
2263
 
1844
2264
class cmd_deleted(Command):
1845
 
    """List files deleted in the working tree.
 
2265
    __doc__ = """List files deleted in the working tree.
1846
2266
    """
1847
2267
    # TODO: Show files deleted since a previous revision, or
1848
2268
    # between two revisions.
1851
2271
    # level of effort but possibly much less IO.  (Or possibly not,
1852
2272
    # if the directories are very large...)
1853
2273
    _see_also = ['status', 'ls']
1854
 
    takes_options = ['show-ids']
 
2274
    takes_options = ['directory', 'show-ids']
1855
2275
 
1856
2276
    @display_command
1857
 
    def run(self, show_ids=False):
1858
 
        tree = WorkingTree.open_containing(u'.')[0]
1859
 
        tree.lock_read()
1860
 
        try:
1861
 
            old = tree.basis_tree()
1862
 
            old.lock_read()
1863
 
            try:
1864
 
                for path, ie in old.inventory.iter_entries():
1865
 
                    if not tree.has_id(ie.file_id):
1866
 
                        self.outf.write(path)
1867
 
                        if show_ids:
1868
 
                            self.outf.write(' ')
1869
 
                            self.outf.write(ie.file_id)
1870
 
                        self.outf.write('\n')
1871
 
            finally:
1872
 
                old.unlock()
1873
 
        finally:
1874
 
            tree.unlock()
 
2277
    def run(self, show_ids=False, directory=u'.'):
 
2278
        tree = WorkingTree.open_containing(directory)[0]
 
2279
        self.add_cleanup(tree.lock_read().unlock)
 
2280
        old = tree.basis_tree()
 
2281
        self.add_cleanup(old.lock_read().unlock)
 
2282
        for path, ie in old.inventory.iter_entries():
 
2283
            if not tree.has_id(ie.file_id):
 
2284
                self.outf.write(path)
 
2285
                if show_ids:
 
2286
                    self.outf.write(' ')
 
2287
                    self.outf.write(ie.file_id)
 
2288
                self.outf.write('\n')
1875
2289
 
1876
2290
 
1877
2291
class cmd_modified(Command):
1878
 
    """List files modified in working tree.
 
2292
    __doc__ = """List files modified in working tree.
1879
2293
    """
1880
2294
 
1881
2295
    hidden = True
1882
2296
    _see_also = ['status', 'ls']
1883
 
    takes_options = [
1884
 
            Option('null',
1885
 
                   help='Write an ascii NUL (\\0) separator '
1886
 
                   'between files rather than a newline.')
1887
 
            ]
 
2297
    takes_options = ['directory', 'null']
1888
2298
 
1889
2299
    @display_command
1890
 
    def run(self, null=False):
1891
 
        tree = WorkingTree.open_containing(u'.')[0]
 
2300
    def run(self, null=False, directory=u'.'):
 
2301
        tree = WorkingTree.open_containing(directory)[0]
 
2302
        self.add_cleanup(tree.lock_read().unlock)
1892
2303
        td = tree.changes_from(tree.basis_tree())
 
2304
        self.cleanup_now()
1893
2305
        for path, id, kind, text_modified, meta_modified in td.modified:
1894
2306
            if null:
1895
2307
                self.outf.write(path + '\0')
1898
2310
 
1899
2311
 
1900
2312
class cmd_added(Command):
1901
 
    """List files added in working tree.
 
2313
    __doc__ = """List files added in working tree.
1902
2314
    """
1903
2315
 
1904
2316
    hidden = True
1905
2317
    _see_also = ['status', 'ls']
1906
 
    takes_options = [
1907
 
            Option('null',
1908
 
                   help='Write an ascii NUL (\\0) separator '
1909
 
                   'between files rather than a newline.')
1910
 
            ]
 
2318
    takes_options = ['directory', 'null']
1911
2319
 
1912
2320
    @display_command
1913
 
    def run(self, null=False):
1914
 
        wt = WorkingTree.open_containing(u'.')[0]
1915
 
        wt.lock_read()
1916
 
        try:
1917
 
            basis = wt.basis_tree()
1918
 
            basis.lock_read()
1919
 
            try:
1920
 
                basis_inv = basis.inventory
1921
 
                inv = wt.inventory
1922
 
                for file_id in inv:
1923
 
                    if file_id in basis_inv:
1924
 
                        continue
1925
 
                    if inv.is_root(file_id) and len(basis_inv) == 0:
1926
 
                        continue
1927
 
                    path = inv.id2path(file_id)
1928
 
                    if not os.access(osutils.abspath(path), os.F_OK):
1929
 
                        continue
1930
 
                    if null:
1931
 
                        self.outf.write(path + '\0')
1932
 
                    else:
1933
 
                        self.outf.write(osutils.quotefn(path) + '\n')
1934
 
            finally:
1935
 
                basis.unlock()
1936
 
        finally:
1937
 
            wt.unlock()
 
2321
    def run(self, null=False, directory=u'.'):
 
2322
        wt = WorkingTree.open_containing(directory)[0]
 
2323
        self.add_cleanup(wt.lock_read().unlock)
 
2324
        basis = wt.basis_tree()
 
2325
        self.add_cleanup(basis.lock_read().unlock)
 
2326
        basis_inv = basis.inventory
 
2327
        inv = wt.inventory
 
2328
        for file_id in inv:
 
2329
            if basis_inv.has_id(file_id):
 
2330
                continue
 
2331
            if inv.is_root(file_id) and len(basis_inv) == 0:
 
2332
                continue
 
2333
            path = inv.id2path(file_id)
 
2334
            if not os.access(osutils.pathjoin(wt.basedir, path), os.F_OK):
 
2335
                continue
 
2336
            if null:
 
2337
                self.outf.write(path + '\0')
 
2338
            else:
 
2339
                self.outf.write(osutils.quotefn(path) + '\n')
1938
2340
 
1939
2341
 
1940
2342
class cmd_root(Command):
1941
 
    """Show the tree root directory.
 
2343
    __doc__ = """Show the tree root directory.
1942
2344
 
1943
2345
    The root is the nearest enclosing directory with a .bzr control
1944
2346
    directory."""
1955
2357
    try:
1956
2358
        return int(limitstring)
1957
2359
    except ValueError:
1958
 
        msg = "The limit argument must be an integer."
 
2360
        msg = gettext("The limit argument must be an integer.")
1959
2361
        raise errors.BzrCommandError(msg)
1960
2362
 
1961
2363
 
1963
2365
    try:
1964
2366
        return int(s)
1965
2367
    except ValueError:
1966
 
        msg = "The levels argument must be an integer."
 
2368
        msg = gettext("The levels argument must be an integer.")
1967
2369
        raise errors.BzrCommandError(msg)
1968
2370
 
1969
2371
 
1970
2372
class cmd_log(Command):
1971
 
    """Show historical log for a branch or subset of a branch.
 
2373
    __doc__ = """Show historical log for a branch or subset of a branch.
1972
2374
 
1973
2375
    log is bzr's default tool for exploring the history of a branch.
1974
2376
    The branch to use is taken from the first parameter. If no parameters
2079
2481
 
2080
2482
    :Other filtering:
2081
2483
 
2082
 
      The --message option can be used for finding revisions that match a
2083
 
      regular expression in a commit message.
 
2484
      The --match option can be used for finding revisions that match a
 
2485
      regular expression in a commit message, committer, author or bug.
 
2486
      Specifying the option several times will match any of the supplied
 
2487
      expressions. --match-author, --match-bugs, --match-committer and
 
2488
      --match-message can be used to only match a specific field.
2084
2489
 
2085
2490
    :Tips & tricks:
2086
2491
 
2087
2492
      GUI tools and IDEs are often better at exploring history than command
2088
 
      line tools. You may prefer qlog or glog from the QBzr and Bzr-Gtk packages
2089
 
      respectively for example. (TortoiseBzr uses qlog for displaying logs.) See
2090
 
      http://bazaar-vcs.org/BzrPlugins and http://bazaar-vcs.org/IDEIntegration.
2091
 
 
2092
 
      Web interfaces are often better at exploring history than command line
2093
 
      tools, particularly for branches on servers. You may prefer Loggerhead
2094
 
      or one of its alternatives. See http://bazaar-vcs.org/WebInterface.
 
2493
      line tools: you may prefer qlog or viz from qbzr or bzr-gtk, the
 
2494
      bzr-explorer shell, or the Loggerhead web interface.  See the Plugin
 
2495
      Guide <http://doc.bazaar.canonical.com/plugins/en/> and
 
2496
      <http://wiki.bazaar.canonical.com/IDEIntegration>.  
2095
2497
 
2096
2498
      You may find it useful to add the aliases below to ``bazaar.conf``::
2097
2499
 
2138
2540
                   help='Show just the specified revision.'
2139
2541
                   ' See also "help revisionspec".'),
2140
2542
            'log-format',
 
2543
            RegistryOption('authors',
 
2544
                'What names to list as authors - first, all or committer.',
 
2545
                title='Authors',
 
2546
                lazy_registry=('bzrlib.log', 'author_list_registry'),
 
2547
            ),
2141
2548
            Option('levels',
2142
2549
                   short_name='n',
2143
2550
                   help='Number of levels to display - 0 for all, 1 for flat.',
2144
2551
                   argname='N',
2145
2552
                   type=_parse_levels),
2146
2553
            Option('message',
2147
 
                   short_name='m',
2148
2554
                   help='Show revisions whose message matches this '
2149
2555
                        'regular expression.',
2150
 
                   type=str),
 
2556
                   type=str,
 
2557
                   hidden=True),
2151
2558
            Option('limit',
2152
2559
                   short_name='l',
2153
2560
                   help='Limit the output to the first N revisions.',
2156
2563
            Option('show-diff',
2157
2564
                   short_name='p',
2158
2565
                   help='Show changes made in each revision as a patch.'),
2159
 
            Option('include-merges',
 
2566
            Option('include-merged',
2160
2567
                   help='Show merged revisions like --levels 0 does.'),
 
2568
            Option('include-merges', hidden=True,
 
2569
                   help='Historical alias for --include-merged.'),
 
2570
            Option('omit-merges',
 
2571
                   help='Do not report commits with more than one parent.'),
 
2572
            Option('exclude-common-ancestry',
 
2573
                   help='Display only the revisions that are not part'
 
2574
                   ' of both ancestries (require -rX..Y).'
 
2575
                   ),
 
2576
            Option('signatures',
 
2577
                   help='Show digital signature validity.'),
 
2578
            ListOption('match',
 
2579
                short_name='m',
 
2580
                help='Show revisions whose properties match this '
 
2581
                'expression.',
 
2582
                type=str),
 
2583
            ListOption('match-message',
 
2584
                   help='Show revisions whose message matches this '
 
2585
                   'expression.',
 
2586
                type=str),
 
2587
            ListOption('match-committer',
 
2588
                   help='Show revisions whose committer matches this '
 
2589
                   'expression.',
 
2590
                type=str),
 
2591
            ListOption('match-author',
 
2592
                   help='Show revisions whose authors match this '
 
2593
                   'expression.',
 
2594
                type=str),
 
2595
            ListOption('match-bugs',
 
2596
                   help='Show revisions whose bugs match this '
 
2597
                   'expression.',
 
2598
                type=str)
2161
2599
            ]
2162
2600
    encoding_type = 'replace'
2163
2601
 
2173
2611
            message=None,
2174
2612
            limit=None,
2175
2613
            show_diff=False,
2176
 
            include_merges=False):
 
2614
            include_merged=None,
 
2615
            authors=None,
 
2616
            exclude_common_ancestry=False,
 
2617
            signatures=False,
 
2618
            match=None,
 
2619
            match_message=None,
 
2620
            match_committer=None,
 
2621
            match_author=None,
 
2622
            match_bugs=None,
 
2623
            omit_merges=False,
 
2624
            include_merges=symbol_versioning.DEPRECATED_PARAMETER,
 
2625
            ):
2177
2626
        from bzrlib.log import (
2178
2627
            Logger,
2179
2628
            make_log_request_dict,
2180
2629
            _get_info_for_log_files,
2181
2630
            )
2182
2631
        direction = (forward and 'forward') or 'reverse'
2183
 
        if include_merges:
 
2632
        if symbol_versioning.deprecated_passed(include_merges):
 
2633
            ui.ui_factory.show_user_warning(
 
2634
                'deprecated_command_option',
 
2635
                deprecated_name='--include-merges',
 
2636
                recommended_name='--include-merged',
 
2637
                deprecated_in_version='2.5',
 
2638
                command=self.invoked_as)
 
2639
            if include_merged is None:
 
2640
                include_merged = include_merges
 
2641
            else:
 
2642
                raise errors.BzrCommandError(gettext(
 
2643
                    '{0} and {1} are mutually exclusive').format(
 
2644
                    '--include-merges', '--include-merged'))
 
2645
        if include_merged is None:
 
2646
            include_merged = False
 
2647
        if (exclude_common_ancestry
 
2648
            and (revision is None or len(revision) != 2)):
 
2649
            raise errors.BzrCommandError(gettext(
 
2650
                '--exclude-common-ancestry requires -r with two revisions'))
 
2651
        if include_merged:
2184
2652
            if levels is None:
2185
2653
                levels = 0
2186
2654
            else:
2187
 
                raise errors.BzrCommandError(
2188
 
                    '--levels and --include-merges are mutually exclusive')
 
2655
                raise errors.BzrCommandError(gettext(
 
2656
                    '{0} and {1} are mutually exclusive').format(
 
2657
                    '--levels', '--include-merged'))
2189
2658
 
2190
2659
        if change is not None:
2191
2660
            if len(change) > 1:
2192
2661
                raise errors.RangeInChangeOption()
2193
2662
            if revision is not None:
2194
 
                raise errors.BzrCommandError(
2195
 
                    '--revision and --change are mutually exclusive')
 
2663
                raise errors.BzrCommandError(gettext(
 
2664
                    '{0} and {1} are mutually exclusive').format(
 
2665
                    '--revision', '--change'))
2196
2666
            else:
2197
2667
                revision = change
2198
2668
 
2200
2670
        filter_by_dir = False
2201
2671
        if file_list:
2202
2672
            # find the file ids to log and check for directory filtering
2203
 
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(revision,
2204
 
                file_list)
 
2673
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(
 
2674
                revision, file_list, self.add_cleanup)
2205
2675
            for relpath, file_id, kind in file_info_list:
2206
2676
                if file_id is None:
2207
 
                    raise errors.BzrCommandError(
2208
 
                        "Path unknown at end or start of revision range: %s" %
 
2677
                    raise errors.BzrCommandError(gettext(
 
2678
                        "Path unknown at end or start of revision range: %s") %
2209
2679
                        relpath)
2210
2680
                # If the relpath is the top of the tree, we log everything
2211
2681
                if relpath == '':
2223
2693
                location = revision[0].get_branch()
2224
2694
            else:
2225
2695
                location = '.'
2226
 
            dir, relpath = bzrdir.BzrDir.open_containing(location)
 
2696
            dir, relpath = controldir.ControlDir.open_containing(location)
2227
2697
            b = dir.open_branch()
 
2698
            self.add_cleanup(b.lock_read().unlock)
2228
2699
            rev1, rev2 = _get_revision_range(revision, b, self.name())
2229
2700
 
 
2701
        if b.get_config().validate_signatures_in_log():
 
2702
            signatures = True
 
2703
 
 
2704
        if signatures:
 
2705
            if not gpg.GPGStrategy.verify_signatures_available():
 
2706
                raise errors.GpgmeNotInstalled(None)
 
2707
 
2230
2708
        # Decide on the type of delta & diff filtering to use
2231
2709
        # TODO: add an --all-files option to make this configurable & consistent
2232
2710
        if not verbose:
2240
2718
        else:
2241
2719
            diff_type = 'full'
2242
2720
 
2243
 
        b.lock_read()
2244
 
        try:
2245
 
            # Build the log formatter
2246
 
            if log_format is None:
2247
 
                log_format = log.log_formatter_registry.get_default(b)
2248
 
            lf = log_format(show_ids=show_ids, to_file=self.outf,
2249
 
                            show_timezone=timezone,
2250
 
                            delta_format=get_verbosity_level(),
2251
 
                            levels=levels,
2252
 
                            show_advice=levels is None)
2253
 
 
2254
 
            # Choose the algorithm for doing the logging. It's annoying
2255
 
            # having multiple code paths like this but necessary until
2256
 
            # the underlying repository format is faster at generating
2257
 
            # deltas or can provide everything we need from the indices.
2258
 
            # The default algorithm - match-using-deltas - works for
2259
 
            # multiple files and directories and is faster for small
2260
 
            # amounts of history (200 revisions say). However, it's too
2261
 
            # slow for logging a single file in a repository with deep
2262
 
            # history, i.e. > 10K revisions. In the spirit of "do no
2263
 
            # evil when adding features", we continue to use the
2264
 
            # original algorithm - per-file-graph - for the "single
2265
 
            # file that isn't a directory without showing a delta" case.
2266
 
            partial_history = revision and b.repository._format.supports_chks
2267
 
            match_using_deltas = (len(file_ids) != 1 or filter_by_dir
2268
 
                or delta_type or partial_history)
2269
 
 
2270
 
            # Build the LogRequest and execute it
2271
 
            if len(file_ids) == 0:
2272
 
                file_ids = None
2273
 
            rqst = make_log_request_dict(
2274
 
                direction=direction, specific_fileids=file_ids,
2275
 
                start_revision=rev1, end_revision=rev2, limit=limit,
2276
 
                message_search=message, delta_type=delta_type,
2277
 
                diff_type=diff_type, _match_using_deltas=match_using_deltas)
2278
 
            Logger(b, rqst).show(lf)
2279
 
        finally:
2280
 
            b.unlock()
 
2721
        # Build the log formatter
 
2722
        if log_format is None:
 
2723
            log_format = log.log_formatter_registry.get_default(b)
 
2724
        # Make a non-encoding output to include the diffs - bug 328007
 
2725
        unencoded_output = ui.ui_factory.make_output_stream(encoding_type='exact')
 
2726
        lf = log_format(show_ids=show_ids, to_file=self.outf,
 
2727
                        to_exact_file=unencoded_output,
 
2728
                        show_timezone=timezone,
 
2729
                        delta_format=get_verbosity_level(),
 
2730
                        levels=levels,
 
2731
                        show_advice=levels is None,
 
2732
                        author_list_handler=authors)
 
2733
 
 
2734
        # Choose the algorithm for doing the logging. It's annoying
 
2735
        # having multiple code paths like this but necessary until
 
2736
        # the underlying repository format is faster at generating
 
2737
        # deltas or can provide everything we need from the indices.
 
2738
        # The default algorithm - match-using-deltas - works for
 
2739
        # multiple files and directories and is faster for small
 
2740
        # amounts of history (200 revisions say). However, it's too
 
2741
        # slow for logging a single file in a repository with deep
 
2742
        # history, i.e. > 10K revisions. In the spirit of "do no
 
2743
        # evil when adding features", we continue to use the
 
2744
        # original algorithm - per-file-graph - for the "single
 
2745
        # file that isn't a directory without showing a delta" case.
 
2746
        partial_history = revision and b.repository._format.supports_chks
 
2747
        match_using_deltas = (len(file_ids) != 1 or filter_by_dir
 
2748
            or delta_type or partial_history)
 
2749
 
 
2750
        match_dict = {}
 
2751
        if match:
 
2752
            match_dict[''] = match
 
2753
        if match_message:
 
2754
            match_dict['message'] = match_message
 
2755
        if match_committer:
 
2756
            match_dict['committer'] = match_committer
 
2757
        if match_author:
 
2758
            match_dict['author'] = match_author
 
2759
        if match_bugs:
 
2760
            match_dict['bugs'] = match_bugs
 
2761
 
 
2762
        # Build the LogRequest and execute it
 
2763
        if len(file_ids) == 0:
 
2764
            file_ids = None
 
2765
        rqst = make_log_request_dict(
 
2766
            direction=direction, specific_fileids=file_ids,
 
2767
            start_revision=rev1, end_revision=rev2, limit=limit,
 
2768
            message_search=message, delta_type=delta_type,
 
2769
            diff_type=diff_type, _match_using_deltas=match_using_deltas,
 
2770
            exclude_common_ancestry=exclude_common_ancestry, match=match_dict,
 
2771
            signature=signatures, omit_merges=omit_merges,
 
2772
            )
 
2773
        Logger(b, rqst).show(lf)
2281
2774
 
2282
2775
 
2283
2776
def _get_revision_range(revisionspec_list, branch, command_name):
2298
2791
            # b is taken from revision[0].get_branch(), and
2299
2792
            # show_log will use its revision_history. Having
2300
2793
            # different branches will lead to weird behaviors.
2301
 
            raise errors.BzrCommandError(
 
2794
            raise errors.BzrCommandError(gettext(
2302
2795
                "bzr %s doesn't accept two revisions in different"
2303
 
                " branches." % command_name)
2304
 
        rev1 = start_spec.in_history(branch)
 
2796
                " branches.") % command_name)
 
2797
        if start_spec.spec is None:
 
2798
            # Avoid loading all the history.
 
2799
            rev1 = RevisionInfo(branch, None, None)
 
2800
        else:
 
2801
            rev1 = start_spec.in_history(branch)
2305
2802
        # Avoid loading all of history when we know a missing
2306
2803
        # end of range means the last revision ...
2307
2804
        if end_spec.spec is None:
2310
2807
        else:
2311
2808
            rev2 = end_spec.in_history(branch)
2312
2809
    else:
2313
 
        raise errors.BzrCommandError(
2314
 
            'bzr %s --revision takes one or two values.' % command_name)
 
2810
        raise errors.BzrCommandError(gettext(
 
2811
            'bzr %s --revision takes one or two values.') % command_name)
2315
2812
    return rev1, rev2
2316
2813
 
2317
2814
 
2336
2833
 
2337
2834
 
2338
2835
class cmd_touching_revisions(Command):
2339
 
    """Return revision-ids which affected a particular file.
 
2836
    __doc__ = """Return revision-ids which affected a particular file.
2340
2837
 
2341
2838
    A more user-friendly interface is "bzr log FILE".
2342
2839
    """
2347
2844
    @display_command
2348
2845
    def run(self, filename):
2349
2846
        tree, relpath = WorkingTree.open_containing(filename)
 
2847
        file_id = tree.path2id(relpath)
2350
2848
        b = tree.branch
2351
 
        file_id = tree.path2id(relpath)
2352
 
        for revno, revision_id, what in log.find_touching_revisions(b, file_id):
 
2849
        self.add_cleanup(b.lock_read().unlock)
 
2850
        touching_revs = log.find_touching_revisions(b, file_id)
 
2851
        for revno, revision_id, what in touching_revs:
2353
2852
            self.outf.write("%6d %s\n" % (revno, what))
2354
2853
 
2355
2854
 
2356
2855
class cmd_ls(Command):
2357
 
    """List files in a tree.
 
2856
    __doc__ = """List files in a tree.
2358
2857
    """
2359
2858
 
2360
2859
    _see_also = ['status', 'cat']
2366
2865
                   help='Recurse into subdirectories.'),
2367
2866
            Option('from-root',
2368
2867
                   help='Print paths relative to the root of the branch.'),
2369
 
            Option('unknown', help='Print unknown files.'),
 
2868
            Option('unknown', short_name='u',
 
2869
                help='Print unknown files.'),
2370
2870
            Option('versioned', help='Print versioned files.',
2371
2871
                   short_name='V'),
2372
 
            Option('ignored', help='Print ignored files.'),
2373
 
            Option('null',
2374
 
                   help='Write an ascii NUL (\\0) separator '
2375
 
                   'between files rather than a newline.'),
2376
 
            Option('kind',
 
2872
            Option('ignored', short_name='i',
 
2873
                help='Print ignored files.'),
 
2874
            Option('kind', short_name='k',
2377
2875
                   help='List entries of a particular kind: file, directory, symlink.',
2378
2876
                   type=unicode),
 
2877
            'null',
2379
2878
            'show-ids',
 
2879
            'directory',
2380
2880
            ]
2381
2881
    @display_command
2382
2882
    def run(self, revision=None, verbose=False,
2383
2883
            recursive=False, from_root=False,
2384
2884
            unknown=False, versioned=False, ignored=False,
2385
 
            null=False, kind=None, show_ids=False, path=None):
 
2885
            null=False, kind=None, show_ids=False, path=None, directory=None):
2386
2886
 
2387
2887
        if kind and kind not in ('file', 'directory', 'symlink'):
2388
 
            raise errors.BzrCommandError('invalid kind specified')
 
2888
            raise errors.BzrCommandError(gettext('invalid kind specified'))
2389
2889
 
2390
2890
        if verbose and null:
2391
 
            raise errors.BzrCommandError('Cannot set both --verbose and --null')
 
2891
            raise errors.BzrCommandError(gettext('Cannot set both --verbose and --null'))
2392
2892
        all = not (unknown or versioned or ignored)
2393
2893
 
2394
2894
        selection = {'I':ignored, '?':unknown, 'V':versioned}
2395
2895
 
2396
2896
        if path is None:
2397
2897
            fs_path = '.'
2398
 
            prefix = ''
2399
2898
        else:
2400
2899
            if from_root:
2401
 
                raise errors.BzrCommandError('cannot specify both --from-root'
2402
 
                                             ' and PATH')
 
2900
                raise errors.BzrCommandError(gettext('cannot specify both --from-root'
 
2901
                                             ' and PATH'))
2403
2902
            fs_path = path
2404
 
            prefix = path
2405
 
        tree, branch, relpath = bzrdir.BzrDir.open_containing_tree_or_branch(
2406
 
            fs_path)
 
2903
        tree, branch, relpath = \
 
2904
            _open_directory_or_containing_tree_or_branch(fs_path, directory)
 
2905
 
 
2906
        # Calculate the prefix to use
 
2907
        prefix = None
2407
2908
        if from_root:
2408
 
            relpath = u''
2409
 
        elif relpath:
2410
 
            relpath += '/'
 
2909
            if relpath:
 
2910
                prefix = relpath + '/'
 
2911
        elif fs_path != '.' and not fs_path.endswith('/'):
 
2912
            prefix = fs_path + '/'
 
2913
 
2411
2914
        if revision is not None or tree is None:
2412
2915
            tree = _get_one_revision_tree('ls', revision, branch=branch)
2413
2916
 
2417
2920
            if view_files:
2418
2921
                apply_view = True
2419
2922
                view_str = views.view_display_str(view_files)
2420
 
                note("Ignoring files outside view. View is %s" % view_str)
2421
 
 
2422
 
        tree.lock_read()
2423
 
        try:
2424
 
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False):
2425
 
                if fp.startswith(relpath):
2426
 
                    rp = fp[len(relpath):]
2427
 
                    fp = osutils.pathjoin(prefix, rp)
2428
 
                    if not recursive and '/' in rp:
2429
 
                        continue
2430
 
                    if not all and not selection[fc]:
2431
 
                        continue
2432
 
                    if kind is not None and fkind != kind:
2433
 
                        continue
2434
 
                    if apply_view:
2435
 
                        try:
2436
 
                            views.check_path_in_view(tree, fp)
2437
 
                        except errors.FileOutsideView:
2438
 
                            continue
2439
 
                    kindch = entry.kind_character()
2440
 
                    outstring = fp + kindch
2441
 
                    ui.ui_factory.clear_term()
2442
 
                    if verbose:
2443
 
                        outstring = '%-8s %s' % (fc, outstring)
2444
 
                        if show_ids and fid is not None:
2445
 
                            outstring = "%-50s %s" % (outstring, fid)
2446
 
                        self.outf.write(outstring + '\n')
2447
 
                    elif null:
2448
 
                        self.outf.write(fp + '\0')
2449
 
                        if show_ids:
2450
 
                            if fid is not None:
2451
 
                                self.outf.write(fid)
2452
 
                            self.outf.write('\0')
2453
 
                        self.outf.flush()
2454
 
                    else:
2455
 
                        if fid is not None:
2456
 
                            my_id = fid
2457
 
                        else:
2458
 
                            my_id = ''
2459
 
                        if show_ids:
2460
 
                            self.outf.write('%-50s %s\n' % (outstring, my_id))
2461
 
                        else:
2462
 
                            self.outf.write(outstring + '\n')
2463
 
        finally:
2464
 
            tree.unlock()
 
2923
                note(gettext("Ignoring files outside view. View is %s") % view_str)
 
2924
 
 
2925
        self.add_cleanup(tree.lock_read().unlock)
 
2926
        for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
 
2927
            from_dir=relpath, recursive=recursive):
 
2928
            # Apply additional masking
 
2929
            if not all and not selection[fc]:
 
2930
                continue
 
2931
            if kind is not None and fkind != kind:
 
2932
                continue
 
2933
            if apply_view:
 
2934
                try:
 
2935
                    if relpath:
 
2936
                        fullpath = osutils.pathjoin(relpath, fp)
 
2937
                    else:
 
2938
                        fullpath = fp
 
2939
                    views.check_path_in_view(tree, fullpath)
 
2940
                except errors.FileOutsideView:
 
2941
                    continue
 
2942
 
 
2943
            # Output the entry
 
2944
            if prefix:
 
2945
                fp = osutils.pathjoin(prefix, fp)
 
2946
            kindch = entry.kind_character()
 
2947
            outstring = fp + kindch
 
2948
            ui.ui_factory.clear_term()
 
2949
            if verbose:
 
2950
                outstring = '%-8s %s' % (fc, outstring)
 
2951
                if show_ids and fid is not None:
 
2952
                    outstring = "%-50s %s" % (outstring, fid)
 
2953
                self.outf.write(outstring + '\n')
 
2954
            elif null:
 
2955
                self.outf.write(fp + '\0')
 
2956
                if show_ids:
 
2957
                    if fid is not None:
 
2958
                        self.outf.write(fid)
 
2959
                    self.outf.write('\0')
 
2960
                self.outf.flush()
 
2961
            else:
 
2962
                if show_ids:
 
2963
                    if fid is not None:
 
2964
                        my_id = fid
 
2965
                    else:
 
2966
                        my_id = ''
 
2967
                    self.outf.write('%-50s %s\n' % (outstring, my_id))
 
2968
                else:
 
2969
                    self.outf.write(outstring + '\n')
2465
2970
 
2466
2971
 
2467
2972
class cmd_unknowns(Command):
2468
 
    """List unknown files.
 
2973
    __doc__ = """List unknown files.
2469
2974
    """
2470
2975
 
2471
2976
    hidden = True
2472
2977
    _see_also = ['ls']
 
2978
    takes_options = ['directory']
2473
2979
 
2474
2980
    @display_command
2475
 
    def run(self):
2476
 
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
 
2981
    def run(self, directory=u'.'):
 
2982
        for f in WorkingTree.open_containing(directory)[0].unknowns():
2477
2983
            self.outf.write(osutils.quotefn(f) + '\n')
2478
2984
 
2479
2985
 
2480
2986
class cmd_ignore(Command):
2481
 
    """Ignore specified files or patterns.
 
2987
    __doc__ = """Ignore specified files or patterns.
2482
2988
 
2483
2989
    See ``bzr help patterns`` for details on the syntax of patterns.
2484
2990
 
 
2991
    If a .bzrignore file does not exist, the ignore command
 
2992
    will create one and add the specified files or patterns to the newly
 
2993
    created file. The ignore command will also automatically add the 
 
2994
    .bzrignore file to be versioned. Creating a .bzrignore file without
 
2995
    the use of the ignore command will require an explicit add command.
 
2996
 
2485
2997
    To remove patterns from the ignore list, edit the .bzrignore file.
2486
2998
    After adding, editing or deleting that file either indirectly by
2487
2999
    using this command or directly by using an editor, be sure to commit
2488
3000
    it.
2489
 
 
2490
 
    Note: ignore patterns containing shell wildcards must be quoted from
2491
 
    the shell on Unix.
 
3001
    
 
3002
    Bazaar also supports a global ignore file ~/.bazaar/ignore. On Windows
 
3003
    the global ignore file can be found in the application data directory as
 
3004
    C:\\Documents and Settings\\<user>\\Application Data\\Bazaar\\2.0\\ignore.
 
3005
    Global ignores are not touched by this command. The global ignore file
 
3006
    can be edited directly using an editor.
 
3007
 
 
3008
    Patterns prefixed with '!' are exceptions to ignore patterns and take
 
3009
    precedence over regular ignores.  Such exceptions are used to specify
 
3010
    files that should be versioned which would otherwise be ignored.
 
3011
    
 
3012
    Patterns prefixed with '!!' act as regular ignore patterns, but have
 
3013
    precedence over the '!' exception patterns.
 
3014
 
 
3015
    :Notes: 
 
3016
        
 
3017
    * Ignore patterns containing shell wildcards must be quoted from
 
3018
      the shell on Unix.
 
3019
 
 
3020
    * Ignore patterns starting with "#" act as comments in the ignore file.
 
3021
      To ignore patterns that begin with that character, use the "RE:" prefix.
2492
3022
 
2493
3023
    :Examples:
2494
3024
        Ignore the top level Makefile::
2495
3025
 
2496
3026
            bzr ignore ./Makefile
2497
3027
 
2498
 
        Ignore class files in all directories::
 
3028
        Ignore .class files in all directories...::
2499
3029
 
2500
3030
            bzr ignore "*.class"
2501
3031
 
 
3032
        ...but do not ignore "special.class"::
 
3033
 
 
3034
            bzr ignore "!special.class"
 
3035
 
 
3036
        Ignore files whose name begins with the "#" character::
 
3037
 
 
3038
            bzr ignore "RE:^#"
 
3039
 
2502
3040
        Ignore .o files under the lib directory::
2503
3041
 
2504
3042
            bzr ignore "lib/**/*.o"
2510
3048
        Ignore everything but the "debian" toplevel directory::
2511
3049
 
2512
3050
            bzr ignore "RE:(?!debian/).*"
 
3051
        
 
3052
        Ignore everything except the "local" toplevel directory,
 
3053
        but always ignore autosave files ending in ~, even under local/::
 
3054
        
 
3055
            bzr ignore "*"
 
3056
            bzr ignore "!./local"
 
3057
            bzr ignore "!!*~"
2513
3058
    """
2514
3059
 
2515
3060
    _see_also = ['status', 'ignored', 'patterns']
2516
3061
    takes_args = ['name_pattern*']
2517
 
    takes_options = [
2518
 
        Option('old-default-rules',
2519
 
               help='Write out the ignore rules bzr < 0.9 always used.')
 
3062
    takes_options = ['directory',
 
3063
        Option('default-rules',
 
3064
               help='Display the default ignore rules that bzr uses.')
2520
3065
        ]
2521
3066
 
2522
 
    def run(self, name_pattern_list=None, old_default_rules=None):
 
3067
    def run(self, name_pattern_list=None, default_rules=None,
 
3068
            directory=u'.'):
2523
3069
        from bzrlib import ignores
2524
 
        if old_default_rules is not None:
2525
 
            # dump the rules and exit
2526
 
            for pattern in ignores.OLD_DEFAULTS:
2527
 
                print pattern
 
3070
        if default_rules is not None:
 
3071
            # dump the default rules and exit
 
3072
            for pattern in ignores.USER_DEFAULTS:
 
3073
                self.outf.write("%s\n" % pattern)
2528
3074
            return
2529
3075
        if not name_pattern_list:
2530
 
            raise errors.BzrCommandError("ignore requires at least one "
2531
 
                                  "NAME_PATTERN or --old-default-rules")
 
3076
            raise errors.BzrCommandError(gettext("ignore requires at least one "
 
3077
                "NAME_PATTERN or --default-rules."))
2532
3078
        name_pattern_list = [globbing.normalize_pattern(p)
2533
3079
                             for p in name_pattern_list]
 
3080
        bad_patterns = ''
 
3081
        bad_patterns_count = 0
 
3082
        for p in name_pattern_list:
 
3083
            if not globbing.Globster.is_pattern_valid(p):
 
3084
                bad_patterns_count += 1
 
3085
                bad_patterns += ('\n  %s' % p)
 
3086
        if bad_patterns:
 
3087
            msg = (ngettext('Invalid ignore pattern found. %s', 
 
3088
                            'Invalid ignore patterns found. %s',
 
3089
                            bad_patterns_count) % bad_patterns)
 
3090
            ui.ui_factory.show_error(msg)
 
3091
            raise errors.InvalidPattern('')
2534
3092
        for name_pattern in name_pattern_list:
2535
3093
            if (name_pattern[0] == '/' or
2536
3094
                (len(name_pattern) > 1 and name_pattern[1] == ':')):
2537
 
                raise errors.BzrCommandError(
2538
 
                    "NAME_PATTERN should not be an absolute path")
2539
 
        tree, relpath = WorkingTree.open_containing(u'.')
 
3095
                raise errors.BzrCommandError(gettext(
 
3096
                    "NAME_PATTERN should not be an absolute path"))
 
3097
        tree, relpath = WorkingTree.open_containing(directory)
2540
3098
        ignores.tree_ignores_add_patterns(tree, name_pattern_list)
2541
3099
        ignored = globbing.Globster(name_pattern_list)
2542
3100
        matches = []
2543
 
        tree.lock_read()
 
3101
        self.add_cleanup(tree.lock_read().unlock)
2544
3102
        for entry in tree.list_files():
2545
3103
            id = entry[3]
2546
3104
            if id is not None:
2547
3105
                filename = entry[0]
2548
3106
                if ignored.match(filename):
2549
 
                    matches.append(filename.encode('utf-8'))
2550
 
        tree.unlock()
 
3107
                    matches.append(filename)
2551
3108
        if len(matches) > 0:
2552
 
            print "Warning: the following files are version controlled and" \
2553
 
                  " match your ignore pattern:\n%s" \
2554
 
                  "\nThese files will continue to be version controlled" \
2555
 
                  " unless you 'bzr remove' them." % ("\n".join(matches),)
 
3109
            self.outf.write(gettext("Warning: the following files are version "
 
3110
                  "controlled and match your ignore pattern:\n%s"
 
3111
                  "\nThese files will continue to be version controlled"
 
3112
                  " unless you 'bzr remove' them.\n") % ("\n".join(matches),))
2556
3113
 
2557
3114
 
2558
3115
class cmd_ignored(Command):
2559
 
    """List ignored files and the patterns that matched them.
 
3116
    __doc__ = """List ignored files and the patterns that matched them.
2560
3117
 
2561
3118
    List all the ignored files and the ignore pattern that caused the file to
2562
3119
    be ignored.
2568
3125
 
2569
3126
    encoding_type = 'replace'
2570
3127
    _see_also = ['ignore', 'ls']
 
3128
    takes_options = ['directory']
2571
3129
 
2572
3130
    @display_command
2573
 
    def run(self):
2574
 
        tree = WorkingTree.open_containing(u'.')[0]
2575
 
        tree.lock_read()
2576
 
        try:
2577
 
            for path, file_class, kind, file_id, entry in tree.list_files():
2578
 
                if file_class != 'I':
2579
 
                    continue
2580
 
                ## XXX: Slightly inefficient since this was already calculated
2581
 
                pat = tree.is_ignored(path)
2582
 
                self.outf.write('%-50s %s\n' % (path, pat))
2583
 
        finally:
2584
 
            tree.unlock()
 
3131
    def run(self, directory=u'.'):
 
3132
        tree = WorkingTree.open_containing(directory)[0]
 
3133
        self.add_cleanup(tree.lock_read().unlock)
 
3134
        for path, file_class, kind, file_id, entry in tree.list_files():
 
3135
            if file_class != 'I':
 
3136
                continue
 
3137
            ## XXX: Slightly inefficient since this was already calculated
 
3138
            pat = tree.is_ignored(path)
 
3139
            self.outf.write('%-50s %s\n' % (path, pat))
2585
3140
 
2586
3141
 
2587
3142
class cmd_lookup_revision(Command):
2588
 
    """Lookup the revision-id from a revision-number
 
3143
    __doc__ = """Lookup the revision-id from a revision-number
2589
3144
 
2590
3145
    :Examples:
2591
3146
        bzr lookup-revision 33
2592
3147
    """
2593
3148
    hidden = True
2594
3149
    takes_args = ['revno']
 
3150
    takes_options = ['directory']
2595
3151
 
2596
3152
    @display_command
2597
 
    def run(self, revno):
 
3153
    def run(self, revno, directory=u'.'):
2598
3154
        try:
2599
3155
            revno = int(revno)
2600
3156
        except ValueError:
2601
 
            raise errors.BzrCommandError("not a valid revision-number: %r" % revno)
2602
 
 
2603
 
        print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
 
3157
            raise errors.BzrCommandError(gettext("not a valid revision-number: %r")
 
3158
                                         % revno)
 
3159
        revid = WorkingTree.open_containing(directory)[0].branch.get_rev_id(revno)
 
3160
        self.outf.write("%s\n" % revid)
2604
3161
 
2605
3162
 
2606
3163
class cmd_export(Command):
2607
 
    """Export current or past revision to a destination directory or archive.
 
3164
    __doc__ = """Export current or past revision to a destination directory or archive.
2608
3165
 
2609
3166
    If no revision is specified this exports the last committed revision.
2610
3167
 
2631
3188
         zip                          .zip
2632
3189
      =================       =========================
2633
3190
    """
 
3191
    encoding = 'exact'
2634
3192
    takes_args = ['dest', 'branch_or_subdir?']
2635
 
    takes_options = [
 
3193
    takes_options = ['directory',
2636
3194
        Option('format',
2637
3195
               help="Type of file to export to.",
2638
3196
               type=unicode),
2642
3200
        Option('root',
2643
3201
               type=str,
2644
3202
               help="Name of the root directory inside the exported file."),
 
3203
        Option('per-file-timestamps',
 
3204
               help='Set modification time of files to that of the last '
 
3205
                    'revision in which it was changed.'),
 
3206
        Option('uncommitted',
 
3207
               help='Export the working tree contents rather than that of the '
 
3208
                    'last revision.'),
2645
3209
        ]
2646
3210
    def run(self, dest, branch_or_subdir=None, revision=None, format=None,
2647
 
        root=None, filters=False):
 
3211
        root=None, filters=False, per_file_timestamps=False, uncommitted=False,
 
3212
        directory=u'.'):
2648
3213
        from bzrlib.export import export
2649
3214
 
2650
3215
        if branch_or_subdir is None:
2651
 
            tree = WorkingTree.open_containing(u'.')[0]
2652
 
            b = tree.branch
2653
 
            subdir = None
 
3216
            branch_or_subdir = directory
 
3217
 
 
3218
        (tree, b, subdir) = controldir.ControlDir.open_containing_tree_or_branch(
 
3219
            branch_or_subdir)
 
3220
        if tree is not None:
 
3221
            self.add_cleanup(tree.lock_read().unlock)
 
3222
 
 
3223
        if uncommitted:
 
3224
            if tree is None:
 
3225
                raise errors.BzrCommandError(
 
3226
                    gettext("--uncommitted requires a working tree"))
 
3227
            export_tree = tree
2654
3228
        else:
2655
 
            b, subdir = Branch.open_containing(branch_or_subdir)
2656
 
            tree = None
2657
 
 
2658
 
        rev_tree = _get_one_revision_tree('export', revision, branch=b, tree=tree)
 
3229
            export_tree = _get_one_revision_tree('export', revision, branch=b, tree=tree)
2659
3230
        try:
2660
 
            export(rev_tree, dest, format, root, subdir, filtered=filters)
 
3231
            export(export_tree, dest, format, root, subdir, filtered=filters,
 
3232
                   per_file_timestamps=per_file_timestamps)
2661
3233
        except errors.NoSuchExportFormat, e:
2662
 
            raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
 
3234
            raise errors.BzrCommandError(
 
3235
                gettext('Unsupported export format: %s') % e.format)
2663
3236
 
2664
3237
 
2665
3238
class cmd_cat(Command):
2666
 
    """Write the contents of a file as of a given revision to standard output.
 
3239
    __doc__ = """Write the contents of a file as of a given revision to standard output.
2667
3240
 
2668
3241
    If no revision is nominated, the last revision is used.
2669
3242
 
2672
3245
    """
2673
3246
 
2674
3247
    _see_also = ['ls']
2675
 
    takes_options = [
 
3248
    takes_options = ['directory',
2676
3249
        Option('name-from-revision', help='The path name in the old tree.'),
2677
3250
        Option('filters', help='Apply content filters to display the '
2678
3251
                'convenience form.'),
2683
3256
 
2684
3257
    @display_command
2685
3258
    def run(self, filename, revision=None, name_from_revision=False,
2686
 
            filters=False):
 
3259
            filters=False, directory=None):
2687
3260
        if revision is not None and len(revision) != 1:
2688
 
            raise errors.BzrCommandError("bzr cat --revision takes exactly"
2689
 
                                         " one revision specifier")
 
3261
            raise errors.BzrCommandError(gettext("bzr cat --revision takes exactly"
 
3262
                                         " one revision specifier"))
2690
3263
        tree, branch, relpath = \
2691
 
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
2692
 
        branch.lock_read()
2693
 
        try:
2694
 
            return self._run(tree, branch, relpath, filename, revision,
2695
 
                             name_from_revision, filters)
2696
 
        finally:
2697
 
            branch.unlock()
 
3264
            _open_directory_or_containing_tree_or_branch(filename, directory)
 
3265
        self.add_cleanup(branch.lock_read().unlock)
 
3266
        return self._run(tree, branch, relpath, filename, revision,
 
3267
                         name_from_revision, filters)
2698
3268
 
2699
3269
    def _run(self, tree, b, relpath, filename, revision, name_from_revision,
2700
3270
        filtered):
2701
3271
        if tree is None:
2702
3272
            tree = b.basis_tree()
2703
3273
        rev_tree = _get_one_revision_tree('cat', revision, branch=b)
 
3274
        self.add_cleanup(rev_tree.lock_read().unlock)
2704
3275
 
2705
3276
        old_file_id = rev_tree.path2id(relpath)
2706
3277
 
 
3278
        # TODO: Split out this code to something that generically finds the
 
3279
        # best id for a path across one or more trees; it's like
 
3280
        # find_ids_across_trees but restricted to find just one. -- mbp
 
3281
        # 20110705.
2707
3282
        if name_from_revision:
2708
3283
            # Try in revision if requested
2709
3284
            if old_file_id is None:
2710
 
                raise errors.BzrCommandError(
2711
 
                    "%r is not present in revision %s" % (
 
3285
                raise errors.BzrCommandError(gettext(
 
3286
                    "{0!r} is not present in revision {1}").format(
2712
3287
                        filename, rev_tree.get_revision_id()))
2713
3288
            else:
2714
 
                content = rev_tree.get_file_text(old_file_id)
 
3289
                actual_file_id = old_file_id
2715
3290
        else:
2716
3291
            cur_file_id = tree.path2id(relpath)
2717
 
            found = False
2718
 
            if cur_file_id is not None:
2719
 
                # Then try with the actual file id
2720
 
                try:
2721
 
                    content = rev_tree.get_file_text(cur_file_id)
2722
 
                    found = True
2723
 
                except errors.NoSuchId:
2724
 
                    # The actual file id didn't exist at that time
2725
 
                    pass
2726
 
            if not found and old_file_id is not None:
2727
 
                # Finally try with the old file id
2728
 
                content = rev_tree.get_file_text(old_file_id)
2729
 
                found = True
2730
 
            if not found:
2731
 
                # Can't be found anywhere
2732
 
                raise errors.BzrCommandError(
2733
 
                    "%r is not present in revision %s" % (
 
3292
            if cur_file_id is not None and rev_tree.has_id(cur_file_id):
 
3293
                actual_file_id = cur_file_id
 
3294
            elif old_file_id is not None:
 
3295
                actual_file_id = old_file_id
 
3296
            else:
 
3297
                raise errors.BzrCommandError(gettext(
 
3298
                    "{0!r} is not present in revision {1}").format(
2734
3299
                        filename, rev_tree.get_revision_id()))
2735
3300
        if filtered:
2736
 
            from bzrlib.filters import (
2737
 
                ContentFilterContext,
2738
 
                filtered_output_bytes,
2739
 
                )
2740
 
            filters = rev_tree._content_filter_stack(relpath)
2741
 
            chunks = content.splitlines(True)
2742
 
            content = filtered_output_bytes(chunks, filters,
2743
 
                ContentFilterContext(relpath, rev_tree))
2744
 
            self.outf.writelines(content)
 
3301
            from bzrlib.filter_tree import ContentFilterTree
 
3302
            filter_tree = ContentFilterTree(rev_tree,
 
3303
                rev_tree._content_filter_stack)
 
3304
            content = filter_tree.get_file_text(actual_file_id)
2745
3305
        else:
2746
 
            self.outf.write(content)
 
3306
            content = rev_tree.get_file_text(actual_file_id)
 
3307
        self.cleanup_now()
 
3308
        self.outf.write(content)
2747
3309
 
2748
3310
 
2749
3311
class cmd_local_time_offset(Command):
2750
 
    """Show the offset in seconds from GMT to local time."""
 
3312
    __doc__ = """Show the offset in seconds from GMT to local time."""
2751
3313
    hidden = True
2752
3314
    @display_command
2753
3315
    def run(self):
2754
 
        print osutils.local_time_offset()
 
3316
        self.outf.write("%s\n" % osutils.local_time_offset())
2755
3317
 
2756
3318
 
2757
3319
 
2758
3320
class cmd_commit(Command):
2759
 
    """Commit changes into a new revision.
 
3321
    __doc__ = """Commit changes into a new revision.
2760
3322
 
2761
3323
    An explanatory message needs to be given for each commit. This is
2762
3324
    often done by using the --message option (getting the message from the
2810
3372
      to trigger updates to external systems like bug trackers. The --fixes
2811
3373
      option can be used to record the association between a revision and
2812
3374
      one or more bugs. See ``bzr help bugs`` for details.
2813
 
 
2814
 
      A selective commit may fail in some cases where the committed
2815
 
      tree would be invalid. Consider::
2816
 
  
2817
 
        bzr init foo
2818
 
        mkdir foo/bar
2819
 
        bzr add foo/bar
2820
 
        bzr commit foo -m "committing foo"
2821
 
        bzr mv foo/bar foo/baz
2822
 
        mkdir foo/bar
2823
 
        bzr add foo/bar
2824
 
        bzr commit foo/bar -m "committing bar but not baz"
2825
 
  
2826
 
      In the example above, the last commit will fail by design. This gives
2827
 
      the user the opportunity to decide whether they want to commit the
2828
 
      rename at the same time, separately first, or not at all. (As a general
2829
 
      rule, when in doubt, Bazaar has a policy of Doing the Safe Thing.)
2830
3375
    """
2831
 
    # TODO: Run hooks on tree to-be-committed, and after commit.
2832
 
 
2833
 
    # TODO: Strict commit that fails if there are deleted files.
2834
 
    #       (what does "deleted files" mean ??)
2835
 
 
2836
 
    # TODO: Give better message for -s, --summary, used by tla people
2837
 
 
2838
 
    # XXX: verbose currently does nothing
2839
3376
 
2840
3377
    _see_also = ['add', 'bugs', 'hooks', 'uncommit']
2841
3378
    takes_args = ['selected*']
2855
3392
             Option('strict',
2856
3393
                    help="Refuse to commit if there are unknown "
2857
3394
                    "files in the working tree."),
 
3395
             Option('commit-time', type=str,
 
3396
                    help="Manually set a commit time using commit date "
 
3397
                    "format, e.g. '2009-10-10 08:00:00 +0100'."),
2858
3398
             ListOption('fixes', type=str,
2859
3399
                    help="Mark a bug as being fixed by this revision "
2860
3400
                         "(see \"bzr help bugs\")."),
2867
3407
                         "the master branch until a normal commit "
2868
3408
                         "is performed."
2869
3409
                    ),
2870
 
              Option('show-diff',
2871
 
                     help='When no message is supplied, show the diff along'
2872
 
                     ' with the status summary in the message editor.'),
 
3410
             Option('show-diff', short_name='p',
 
3411
                    help='When no message is supplied, show the diff along'
 
3412
                    ' with the status summary in the message editor.'),
 
3413
             Option('lossy', 
 
3414
                    help='When committing to a foreign version control '
 
3415
                    'system do not push data that can not be natively '
 
3416
                    'represented.'),
2873
3417
             ]
2874
3418
    aliases = ['ci', 'checkin']
2875
3419
 
2876
3420
    def _iter_bug_fix_urls(self, fixes, branch):
 
3421
        default_bugtracker  = None
2877
3422
        # Configure the properties for bug fixing attributes.
2878
3423
        for fixed_bug in fixes:
2879
3424
            tokens = fixed_bug.split(':')
2880
 
            if len(tokens) != 2:
2881
 
                raise errors.BzrCommandError(
 
3425
            if len(tokens) == 1:
 
3426
                if default_bugtracker is None:
 
3427
                    branch_config = branch.get_config()
 
3428
                    default_bugtracker = branch_config.get_user_option(
 
3429
                        "bugtracker")
 
3430
                if default_bugtracker is None:
 
3431
                    raise errors.BzrCommandError(gettext(
 
3432
                        "No tracker specified for bug %s. Use the form "
 
3433
                        "'tracker:id' or specify a default bug tracker "
 
3434
                        "using the `bugtracker` option.\nSee "
 
3435
                        "\"bzr help bugs\" for more information on this "
 
3436
                        "feature. Commit refused.") % fixed_bug)
 
3437
                tag = default_bugtracker
 
3438
                bug_id = tokens[0]
 
3439
            elif len(tokens) != 2:
 
3440
                raise errors.BzrCommandError(gettext(
2882
3441
                    "Invalid bug %s. Must be in the form of 'tracker:id'. "
2883
3442
                    "See \"bzr help bugs\" for more information on this "
2884
 
                    "feature.\nCommit refused." % fixed_bug)
2885
 
            tag, bug_id = tokens
 
3443
                    "feature.\nCommit refused.") % fixed_bug)
 
3444
            else:
 
3445
                tag, bug_id = tokens
2886
3446
            try:
2887
3447
                yield bugtracker.get_bug_url(tag, branch, bug_id)
2888
3448
            except errors.UnknownBugTrackerAbbreviation:
2889
 
                raise errors.BzrCommandError(
2890
 
                    'Unrecognized bug %s. Commit refused.' % fixed_bug)
 
3449
                raise errors.BzrCommandError(gettext(
 
3450
                    'Unrecognized bug %s. Commit refused.') % fixed_bug)
2891
3451
            except errors.MalformedBugIdentifier, e:
2892
 
                raise errors.BzrCommandError(
2893
 
                    "%s\nCommit refused." % (str(e),))
 
3452
                raise errors.BzrCommandError(gettext(
 
3453
                    "%s\nCommit refused.") % (str(e),))
2894
3454
 
2895
3455
    def run(self, message=None, file=None, verbose=False, selected_list=None,
2896
3456
            unchanged=False, strict=False, local=False, fixes=None,
2897
 
            author=None, show_diff=False, exclude=None):
 
3457
            author=None, show_diff=False, exclude=None, commit_time=None,
 
3458
            lossy=False):
2898
3459
        from bzrlib.errors import (
2899
3460
            PointlessCommit,
2900
3461
            ConflictsInTree,
2903
3464
        from bzrlib.msgeditor import (
2904
3465
            edit_commit_message_encoded,
2905
3466
            generate_commit_message_template,
2906
 
            make_commit_message_template_encoded
 
3467
            make_commit_message_template_encoded,
 
3468
            set_commit_message,
2907
3469
        )
2908
3470
 
2909
 
        # TODO: Need a blackbox test for invoking the external editor; may be
2910
 
        # slightly problematic to run this cross-platform.
2911
 
 
2912
 
        # TODO: do more checks that the commit will succeed before
2913
 
        # spending the user's valuable time typing a commit message.
 
3471
        commit_stamp = offset = None
 
3472
        if commit_time is not None:
 
3473
            try:
 
3474
                commit_stamp, offset = timestamp.parse_patch_date(commit_time)
 
3475
            except ValueError, e:
 
3476
                raise errors.BzrCommandError(gettext(
 
3477
                    "Could not parse --commit-time: " + str(e)))
2914
3478
 
2915
3479
        properties = {}
2916
3480
 
2917
 
        tree, selected_list = tree_files(selected_list)
 
3481
        tree, selected_list = WorkingTree.open_containing_paths(selected_list)
2918
3482
        if selected_list == ['']:
2919
3483
            # workaround - commit of root of tree should be exactly the same
2920
3484
            # as just default commit in that tree, and succeed even though
2931
3495
        if local and not tree.branch.get_bound_location():
2932
3496
            raise errors.LocalRequiresBoundBranch()
2933
3497
 
 
3498
        if message is not None:
 
3499
            try:
 
3500
                file_exists = osutils.lexists(message)
 
3501
            except UnicodeError:
 
3502
                # The commit message contains unicode characters that can't be
 
3503
                # represented in the filesystem encoding, so that can't be a
 
3504
                # file.
 
3505
                file_exists = False
 
3506
            if file_exists:
 
3507
                warning_msg = (
 
3508
                    'The commit message is a file name: "%(f)s".\n'
 
3509
                    '(use --file "%(f)s" to take commit message from that file)'
 
3510
                    % { 'f': message })
 
3511
                ui.ui_factory.show_warning(warning_msg)
 
3512
            if '\r' in message:
 
3513
                message = message.replace('\r\n', '\n')
 
3514
                message = message.replace('\r', '\n')
 
3515
            if file:
 
3516
                raise errors.BzrCommandError(gettext(
 
3517
                    "please specify either --message or --file"))
 
3518
 
2934
3519
        def get_message(commit_obj):
2935
3520
            """Callback to get commit message"""
2936
 
            my_message = message
2937
 
            if my_message is None and not file:
2938
 
                t = make_commit_message_template_encoded(tree,
 
3521
            if file:
 
3522
                f = open(file)
 
3523
                try:
 
3524
                    my_message = f.read().decode(osutils.get_user_encoding())
 
3525
                finally:
 
3526
                    f.close()
 
3527
            elif message is not None:
 
3528
                my_message = message
 
3529
            else:
 
3530
                # No message supplied: make one up.
 
3531
                # text is the status of the tree
 
3532
                text = make_commit_message_template_encoded(tree,
2939
3533
                        selected_list, diff=show_diff,
2940
3534
                        output_encoding=osutils.get_user_encoding())
2941
 
                start_message = generate_commit_message_template(commit_obj)
2942
 
                my_message = edit_commit_message_encoded(t,
2943
 
                    start_message=start_message)
2944
 
                if my_message is None:
2945
 
                    raise errors.BzrCommandError("please specify a commit"
2946
 
                        " message with either --message or --file")
2947
 
            elif my_message and file:
2948
 
                raise errors.BzrCommandError(
2949
 
                    "please specify either --message or --file")
2950
 
            if file:
2951
 
                my_message = codecs.open(file, 'rt',
2952
 
                                         osutils.get_user_encoding()).read()
2953
 
            if my_message == "":
2954
 
                raise errors.BzrCommandError("empty commit message specified")
 
3535
                # start_message is the template generated from hooks
 
3536
                # XXX: Warning - looks like hooks return unicode,
 
3537
                # make_commit_message_template_encoded returns user encoding.
 
3538
                # We probably want to be using edit_commit_message instead to
 
3539
                # avoid this.
 
3540
                my_message = set_commit_message(commit_obj)
 
3541
                if my_message is None:
 
3542
                    start_message = generate_commit_message_template(commit_obj)
 
3543
                    my_message = edit_commit_message_encoded(text,
 
3544
                        start_message=start_message)
 
3545
                if my_message is None:
 
3546
                    raise errors.BzrCommandError(gettext("please specify a commit"
 
3547
                        " message with either --message or --file"))
 
3548
                if my_message == "":
 
3549
                    raise errors.BzrCommandError(gettext("Empty commit message specified."
 
3550
                            " Please specify a commit message with either"
 
3551
                            " --message or --file or leave a blank message"
 
3552
                            " with --message \"\"."))
2955
3553
            return my_message
2956
3554
 
 
3555
        # The API permits a commit with a filter of [] to mean 'select nothing'
 
3556
        # but the command line should not do that.
 
3557
        if not selected_list:
 
3558
            selected_list = None
2957
3559
        try:
2958
3560
            tree.commit(message_callback=get_message,
2959
3561
                        specific_files=selected_list,
2960
3562
                        allow_pointless=unchanged, strict=strict, local=local,
2961
3563
                        reporter=None, verbose=verbose, revprops=properties,
2962
 
                        authors=author,
2963
 
                        exclude=safe_relpath_files(tree, exclude))
 
3564
                        authors=author, timestamp=commit_stamp,
 
3565
                        timezone=offset,
 
3566
                        exclude=tree.safe_relpath_files(exclude),
 
3567
                        lossy=lossy)
2964
3568
        except PointlessCommit:
2965
 
            # FIXME: This should really happen before the file is read in;
2966
 
            # perhaps prepare the commit; get the message; then actually commit
2967
 
            raise errors.BzrCommandError("No changes to commit."
2968
 
                              " Use --unchanged to commit anyhow.")
 
3569
            raise errors.BzrCommandError(gettext("No changes to commit."
 
3570
                " Please 'bzr add' the files you want to commit, or use"
 
3571
                " --unchanged to force an empty commit."))
2969
3572
        except ConflictsInTree:
2970
 
            raise errors.BzrCommandError('Conflicts detected in working '
 
3573
            raise errors.BzrCommandError(gettext('Conflicts detected in working '
2971
3574
                'tree.  Use "bzr conflicts" to list, "bzr resolve FILE" to'
2972
 
                ' resolve.')
 
3575
                ' resolve.'))
2973
3576
        except StrictCommitFailed:
2974
 
            raise errors.BzrCommandError("Commit refused because there are"
2975
 
                              " unknown files in the working tree.")
 
3577
            raise errors.BzrCommandError(gettext("Commit refused because there are"
 
3578
                              " unknown files in the working tree."))
2976
3579
        except errors.BoundBranchOutOfDate, e:
2977
 
            raise errors.BzrCommandError(str(e) + "\n"
2978
 
            'To commit to master branch, run update and then commit.\n'
2979
 
            'You can also pass --local to commit to continue working '
2980
 
            'disconnected.')
 
3580
            e.extra_help = (gettext("\n"
 
3581
                'To commit to master branch, run update and then commit.\n'
 
3582
                'You can also pass --local to commit to continue working '
 
3583
                'disconnected.'))
 
3584
            raise
2981
3585
 
2982
3586
 
2983
3587
class cmd_check(Command):
2984
 
    """Validate working tree structure, branch consistency and repository history.
 
3588
    __doc__ = """Validate working tree structure, branch consistency and repository history.
2985
3589
 
2986
3590
    This command checks various invariants about branch and repository storage
2987
3591
    to detect data corruption or bzr bugs.
2989
3593
    The working tree and branch checks will only give output if a problem is
2990
3594
    detected. The output fields of the repository check are:
2991
3595
 
2992
 
        revisions: This is just the number of revisions checked.  It doesn't
2993
 
            indicate a problem.
2994
 
        versionedfiles: This is just the number of versionedfiles checked.  It
2995
 
            doesn't indicate a problem.
2996
 
        unreferenced ancestors: Texts that are ancestors of other texts, but
2997
 
            are not properly referenced by the revision ancestry.  This is a
2998
 
            subtle problem that Bazaar can work around.
2999
 
        unique file texts: This is the total number of unique file contents
3000
 
            seen in the checked revisions.  It does not indicate a problem.
3001
 
        repeated file texts: This is the total number of repeated texts seen
3002
 
            in the checked revisions.  Texts can be repeated when their file
3003
 
            entries are modified, but the file contents are not.  It does not
3004
 
            indicate a problem.
 
3596
    revisions
 
3597
        This is just the number of revisions checked.  It doesn't
 
3598
        indicate a problem.
 
3599
 
 
3600
    versionedfiles
 
3601
        This is just the number of versionedfiles checked.  It
 
3602
        doesn't indicate a problem.
 
3603
 
 
3604
    unreferenced ancestors
 
3605
        Texts that are ancestors of other texts, but
 
3606
        are not properly referenced by the revision ancestry.  This is a
 
3607
        subtle problem that Bazaar can work around.
 
3608
 
 
3609
    unique file texts
 
3610
        This is the total number of unique file contents
 
3611
        seen in the checked revisions.  It does not indicate a problem.
 
3612
 
 
3613
    repeated file texts
 
3614
        This is the total number of repeated texts seen
 
3615
        in the checked revisions.  Texts can be repeated when their file
 
3616
        entries are modified, but the file contents are not.  It does not
 
3617
        indicate a problem.
3005
3618
 
3006
3619
    If no restrictions are specified, all Bazaar data that is found at the given
3007
3620
    location will be checked.
3042
3655
 
3043
3656
 
3044
3657
class cmd_upgrade(Command):
3045
 
    """Upgrade branch storage to current format.
3046
 
 
3047
 
    The check command or bzr developers may sometimes advise you to run
3048
 
    this command. When the default format has changed you may also be warned
3049
 
    during other operations to upgrade.
 
3658
    __doc__ = """Upgrade a repository, branch or working tree to a newer format.
 
3659
 
 
3660
    When the default format has changed after a major new release of
 
3661
    Bazaar, you may be informed during certain operations that you
 
3662
    should upgrade. Upgrading to a newer format may improve performance
 
3663
    or make new features available. It may however limit interoperability
 
3664
    with older repositories or with older versions of Bazaar.
 
3665
 
 
3666
    If you wish to upgrade to a particular format rather than the
 
3667
    current default, that can be specified using the --format option.
 
3668
    As a consequence, you can use the upgrade command this way to
 
3669
    "downgrade" to an earlier format, though some conversions are
 
3670
    a one way process (e.g. changing from the 1.x default to the
 
3671
    2.x default) so downgrading is not always possible.
 
3672
 
 
3673
    A backup.bzr.~#~ directory is created at the start of the conversion
 
3674
    process (where # is a number). By default, this is left there on
 
3675
    completion. If the conversion fails, delete the new .bzr directory
 
3676
    and rename this one back in its place. Use the --clean option to ask
 
3677
    for the backup.bzr directory to be removed on successful conversion.
 
3678
    Alternatively, you can delete it by hand if everything looks good
 
3679
    afterwards.
 
3680
 
 
3681
    If the location given is a shared repository, dependent branches
 
3682
    are also converted provided the repository converts successfully.
 
3683
    If the conversion of a branch fails, remaining branches are still
 
3684
    tried.
 
3685
 
 
3686
    For more information on upgrades, see the Bazaar Upgrade Guide,
 
3687
    http://doc.bazaar.canonical.com/latest/en/upgrade-guide/.
3050
3688
    """
3051
3689
 
3052
 
    _see_also = ['check']
 
3690
    _see_also = ['check', 'reconcile', 'formats']
3053
3691
    takes_args = ['url?']
3054
3692
    takes_options = [
3055
 
                    RegistryOption('format',
3056
 
                        help='Upgrade to a specific format.  See "bzr help'
3057
 
                             ' formats" for details.',
3058
 
                        lazy_registry=('bzrlib.bzrdir', 'format_registry'),
3059
 
                        converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
3060
 
                        value_switches=True, title='Branch format'),
3061
 
                    ]
 
3693
        RegistryOption('format',
 
3694
            help='Upgrade to a specific format.  See "bzr help'
 
3695
                 ' formats" for details.',
 
3696
            lazy_registry=('bzrlib.controldir', 'format_registry'),
 
3697
            converter=lambda name: controldir.format_registry.make_bzrdir(name),
 
3698
            value_switches=True, title='Branch format'),
 
3699
        Option('clean',
 
3700
            help='Remove the backup.bzr directory if successful.'),
 
3701
        Option('dry-run',
 
3702
            help="Show what would be done, but don't actually do anything."),
 
3703
    ]
3062
3704
 
3063
 
    def run(self, url='.', format=None):
 
3705
    def run(self, url='.', format=None, clean=False, dry_run=False):
3064
3706
        from bzrlib.upgrade import upgrade
3065
 
        upgrade(url, format)
 
3707
        exceptions = upgrade(url, format, clean_up=clean, dry_run=dry_run)
 
3708
        if exceptions:
 
3709
            if len(exceptions) == 1:
 
3710
                # Compatibility with historical behavior
 
3711
                raise exceptions[0]
 
3712
            else:
 
3713
                return 3
3066
3714
 
3067
3715
 
3068
3716
class cmd_whoami(Command):
3069
 
    """Show or set bzr user id.
 
3717
    __doc__ = """Show or set bzr user id.
3070
3718
 
3071
3719
    :Examples:
3072
3720
        Show the email of the current user::
3077
3725
 
3078
3726
            bzr whoami "Frank Chu <fchu@example.com>"
3079
3727
    """
3080
 
    takes_options = [ Option('email',
 
3728
    takes_options = [ 'directory',
 
3729
                      Option('email',
3081
3730
                             help='Display email address only.'),
3082
3731
                      Option('branch',
3083
3732
                             help='Set identity for the current branch instead of '
3087
3736
    encoding_type = 'replace'
3088
3737
 
3089
3738
    @display_command
3090
 
    def run(self, email=False, branch=False, name=None):
 
3739
    def run(self, email=False, branch=False, name=None, directory=None):
3091
3740
        if name is None:
3092
 
            # use branch if we're inside one; otherwise global config
3093
 
            try:
3094
 
                c = Branch.open_containing('.')[0].get_config()
3095
 
            except errors.NotBranchError:
3096
 
                c = config.GlobalConfig()
 
3741
            if directory is None:
 
3742
                # use branch if we're inside one; otherwise global config
 
3743
                try:
 
3744
                    c = Branch.open_containing(u'.')[0].get_config_stack()
 
3745
                except errors.NotBranchError:
 
3746
                    c = _mod_config.GlobalStack()
 
3747
            else:
 
3748
                c = Branch.open(directory).get_config_stack()
 
3749
            identity = c.get('email')
3097
3750
            if email:
3098
 
                self.outf.write(c.user_email() + '\n')
 
3751
                self.outf.write(_mod_config.extract_email_address(identity)
 
3752
                                + '\n')
3099
3753
            else:
3100
 
                self.outf.write(c.username() + '\n')
 
3754
                self.outf.write(identity + '\n')
3101
3755
            return
3102
3756
 
 
3757
        if email:
 
3758
            raise errors.BzrCommandError(gettext("--email can only be used to display existing "
 
3759
                                         "identity"))
 
3760
 
3103
3761
        # display a warning if an email address isn't included in the given name.
3104
3762
        try:
3105
 
            config.extract_email_address(name)
 
3763
            _mod_config.extract_email_address(name)
3106
3764
        except errors.NoEmailInUsername, e:
3107
3765
            warning('"%s" does not seem to contain an email address.  '
3108
3766
                    'This is allowed, but not recommended.', name)
3109
3767
 
3110
3768
        # use global config unless --branch given
3111
3769
        if branch:
3112
 
            c = Branch.open_containing('.')[0].get_config()
 
3770
            if directory is None:
 
3771
                c = Branch.open_containing(u'.')[0].get_config_stack()
 
3772
            else:
 
3773
                c = Branch.open(directory).get_config_stack()
3113
3774
        else:
3114
 
            c = config.GlobalConfig()
3115
 
        c.set_user_option('email', name)
 
3775
            c = _mod_config.GlobalStack()
 
3776
        c.set('email', name)
3116
3777
 
3117
3778
 
3118
3779
class cmd_nick(Command):
3119
 
    """Print or set the branch nickname.
 
3780
    __doc__ = """Print or set the branch nickname.
3120
3781
 
3121
3782
    If unset, the tree root directory name is used as the nickname.
3122
3783
    To print the current nickname, execute with no argument.
3127
3788
 
3128
3789
    _see_also = ['info']
3129
3790
    takes_args = ['nickname?']
3130
 
    def run(self, nickname=None):
3131
 
        branch = Branch.open_containing(u'.')[0]
 
3791
    takes_options = ['directory']
 
3792
    def run(self, nickname=None, directory=u'.'):
 
3793
        branch = Branch.open_containing(directory)[0]
3132
3794
        if nickname is None:
3133
3795
            self.printme(branch)
3134
3796
        else:
3136
3798
 
3137
3799
    @display_command
3138
3800
    def printme(self, branch):
3139
 
        print branch.nick
 
3801
        self.outf.write('%s\n' % branch.nick)
3140
3802
 
3141
3803
 
3142
3804
class cmd_alias(Command):
3143
 
    """Set/unset and display aliases.
 
3805
    __doc__ = """Set/unset and display aliases.
3144
3806
 
3145
3807
    :Examples:
3146
3808
        Show the current aliases::
3179
3841
 
3180
3842
    def remove_alias(self, alias_name):
3181
3843
        if alias_name is None:
3182
 
            raise errors.BzrCommandError(
3183
 
                'bzr alias --remove expects an alias to remove.')
 
3844
            raise errors.BzrCommandError(gettext(
 
3845
                'bzr alias --remove expects an alias to remove.'))
3184
3846
        # If alias is not found, print something like:
3185
3847
        # unalias: foo: not found
3186
 
        c = config.GlobalConfig()
 
3848
        c = _mod_config.GlobalConfig()
3187
3849
        c.unset_alias(alias_name)
3188
3850
 
3189
3851
    @display_command
3190
3852
    def print_aliases(self):
3191
3853
        """Print out the defined aliases in a similar format to bash."""
3192
 
        aliases = config.GlobalConfig().get_aliases()
 
3854
        aliases = _mod_config.GlobalConfig().get_aliases()
3193
3855
        for key, value in sorted(aliases.iteritems()):
3194
3856
            self.outf.write('bzr alias %s="%s"\n' % (key, value))
3195
3857
 
3205
3867
 
3206
3868
    def set_alias(self, alias_name, alias_command):
3207
3869
        """Save the alias in the global config."""
3208
 
        c = config.GlobalConfig()
 
3870
        c = _mod_config.GlobalConfig()
3209
3871
        c.set_alias(alias_name, alias_command)
3210
3872
 
3211
3873
 
3212
3874
class cmd_selftest(Command):
3213
 
    """Run internal test suite.
 
3875
    __doc__ = """Run internal test suite.
3214
3876
 
3215
3877
    If arguments are given, they are regular expressions that say which tests
3216
3878
    should run.  Tests matching any expression are run, and other tests are
3243
3905
    Tests that need working space on disk use a common temporary directory,
3244
3906
    typically inside $TMPDIR or /tmp.
3245
3907
 
 
3908
    If you set BZR_TEST_PDB=1 when running selftest, failing tests will drop
 
3909
    into a pdb postmortem session.
 
3910
 
 
3911
    The --coverage=DIRNAME global option produces a report with covered code
 
3912
    indicated.
 
3913
 
3246
3914
    :Examples:
3247
3915
        Run only tests relating to 'ignore'::
3248
3916
 
3257
3925
    def get_transport_type(typestring):
3258
3926
        """Parse and return a transport specifier."""
3259
3927
        if typestring == "sftp":
3260
 
            from bzrlib.transport.sftp import SFTPAbsoluteServer
3261
 
            return SFTPAbsoluteServer
3262
 
        if typestring == "memory":
3263
 
            from bzrlib.transport.memory import MemoryServer
3264
 
            return MemoryServer
3265
 
        if typestring == "fakenfs":
3266
 
            from bzrlib.transport.fakenfs import FakeNFSServer
3267
 
            return FakeNFSServer
 
3928
            from bzrlib.tests import stub_sftp
 
3929
            return stub_sftp.SFTPAbsoluteServer
 
3930
        elif typestring == "memory":
 
3931
            from bzrlib.tests import test_server
 
3932
            return memory.MemoryServer
 
3933
        elif typestring == "fakenfs":
 
3934
            from bzrlib.tests import test_server
 
3935
            return test_server.FakeNFSServer
3268
3936
        msg = "No known transport type %s. Supported types are: sftp\n" %\
3269
3937
            (typestring)
3270
3938
        raise errors.BzrCommandError(msg)
3281
3949
                                 'throughout the test suite.',
3282
3950
                            type=get_transport_type),
3283
3951
                     Option('benchmark',
3284
 
                            help='Run the benchmarks rather than selftests.'),
 
3952
                            help='Run the benchmarks rather than selftests.',
 
3953
                            hidden=True),
3285
3954
                     Option('lsprof-timed',
3286
3955
                            help='Generate lsprof output for benchmarked'
3287
3956
                                 ' sections of code.'),
3288
 
                     Option('cache-dir', type=str,
3289
 
                            help='Cache intermediate benchmark output in this '
3290
 
                                 'directory.'),
 
3957
                     Option('lsprof-tests',
 
3958
                            help='Generate lsprof output for each test.'),
3291
3959
                     Option('first',
3292
3960
                            help='Run all tests, but run specified tests first.',
3293
3961
                            short_name='f',
3302
3970
                     Option('randomize', type=str, argname="SEED",
3303
3971
                            help='Randomize the order of tests using the given'
3304
3972
                                 ' seed or "now" for the current time.'),
3305
 
                     Option('exclude', type=str, argname="PATTERN",
3306
 
                            short_name='x',
3307
 
                            help='Exclude tests that match this regular'
3308
 
                                 ' expression.'),
 
3973
                     ListOption('exclude', type=str, argname="PATTERN",
 
3974
                                short_name='x',
 
3975
                                help='Exclude tests that match this regular'
 
3976
                                ' expression.'),
3309
3977
                     Option('subunit',
3310
3978
                        help='Output test progress via subunit.'),
3311
3979
                     Option('strict', help='Fail on missing dependencies or '
3318
3986
                                param_name='starting_with', short_name='s',
3319
3987
                                help=
3320
3988
                                'Load only the tests starting with TESTID.'),
 
3989
                     Option('sync',
 
3990
                            help="By default we disable fsync and fdatasync"
 
3991
                                 " while running the test suite.")
3321
3992
                     ]
3322
3993
    encoding_type = 'replace'
3323
3994
 
3327
3998
 
3328
3999
    def run(self, testspecs_list=None, verbose=False, one=False,
3329
4000
            transport=None, benchmark=None,
3330
 
            lsprof_timed=None, cache_dir=None,
 
4001
            lsprof_timed=None,
3331
4002
            first=False, list_only=False,
3332
4003
            randomize=None, exclude=None, strict=False,
3333
4004
            load_list=None, debugflag=None, starting_with=None, subunit=False,
3334
 
            parallel=None):
3335
 
        from bzrlib.tests import selftest
3336
 
        import bzrlib.benchmarks as benchmarks
3337
 
        from bzrlib.benchmarks import tree_creator
3338
 
 
3339
 
        # Make deprecation warnings visible, unless -Werror is set
3340
 
        symbol_versioning.activate_deprecation_warnings(override=False)
3341
 
 
3342
 
        if cache_dir is not None:
3343
 
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
 
4005
            parallel=None, lsprof_tests=False,
 
4006
            sync=False):
 
4007
 
 
4008
        # During selftest, disallow proxying, as it can cause severe
 
4009
        # performance penalties and is only needed for thread
 
4010
        # safety. The selftest command is assumed to not use threads
 
4011
        # too heavily. The call should be as early as possible, as
 
4012
        # error reporting for past duplicate imports won't have useful
 
4013
        # backtraces.
 
4014
        lazy_import.disallow_proxying()
 
4015
 
 
4016
        from bzrlib import tests
 
4017
 
3344
4018
        if testspecs_list is not None:
3345
4019
            pattern = '|'.join(testspecs_list)
3346
4020
        else:
3349
4023
            try:
3350
4024
                from bzrlib.tests import SubUnitBzrRunner
3351
4025
            except ImportError:
3352
 
                raise errors.BzrCommandError("subunit not available. subunit "
3353
 
                    "needs to be installed to use --subunit.")
 
4026
                raise errors.BzrCommandError(gettext("subunit not available. subunit "
 
4027
                    "needs to be installed to use --subunit."))
3354
4028
            self.additional_selftest_args['runner_class'] = SubUnitBzrRunner
 
4029
            # On Windows, disable automatic conversion of '\n' to '\r\n' in
 
4030
            # stdout, which would corrupt the subunit stream. 
 
4031
            # FIXME: This has been fixed in subunit trunk (>0.0.5) so the
 
4032
            # following code can be deleted when it's sufficiently deployed
 
4033
            # -- vila/mgz 20100514
 
4034
            if (sys.platform == "win32"
 
4035
                and getattr(sys.stdout, 'fileno', None) is not None):
 
4036
                import msvcrt
 
4037
                msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
3355
4038
        if parallel:
3356
4039
            self.additional_selftest_args.setdefault(
3357
4040
                'suite_decorators', []).append(parallel)
3358
4041
        if benchmark:
3359
 
            test_suite_factory = benchmarks.test_suite
3360
 
            # Unless user explicitly asks for quiet, be verbose in benchmarks
3361
 
            verbose = not is_quiet()
3362
 
            # TODO: should possibly lock the history file...
3363
 
            benchfile = open(".perf_history", "at", buffering=1)
 
4042
            raise errors.BzrCommandError(gettext(
 
4043
                "--benchmark is no longer supported from bzr 2.2; "
 
4044
                "use bzr-usertest instead"))
 
4045
        test_suite_factory = None
 
4046
        if not exclude:
 
4047
            exclude_pattern = None
3364
4048
        else:
3365
 
            test_suite_factory = None
3366
 
            benchfile = None
 
4049
            exclude_pattern = '(' + '|'.join(exclude) + ')'
 
4050
        if not sync:
 
4051
            self._disable_fsync()
 
4052
        selftest_kwargs = {"verbose": verbose,
 
4053
                          "pattern": pattern,
 
4054
                          "stop_on_failure": one,
 
4055
                          "transport": transport,
 
4056
                          "test_suite_factory": test_suite_factory,
 
4057
                          "lsprof_timed": lsprof_timed,
 
4058
                          "lsprof_tests": lsprof_tests,
 
4059
                          "matching_tests_first": first,
 
4060
                          "list_only": list_only,
 
4061
                          "random_seed": randomize,
 
4062
                          "exclude_pattern": exclude_pattern,
 
4063
                          "strict": strict,
 
4064
                          "load_list": load_list,
 
4065
                          "debug_flags": debugflag,
 
4066
                          "starting_with": starting_with
 
4067
                          }
 
4068
        selftest_kwargs.update(self.additional_selftest_args)
 
4069
 
 
4070
        # Make deprecation warnings visible, unless -Werror is set
 
4071
        cleanup = symbol_versioning.activate_deprecation_warnings(
 
4072
            override=False)
3367
4073
        try:
3368
 
            selftest_kwargs = {"verbose": verbose,
3369
 
                              "pattern": pattern,
3370
 
                              "stop_on_failure": one,
3371
 
                              "transport": transport,
3372
 
                              "test_suite_factory": test_suite_factory,
3373
 
                              "lsprof_timed": lsprof_timed,
3374
 
                              "bench_history": benchfile,
3375
 
                              "matching_tests_first": first,
3376
 
                              "list_only": list_only,
3377
 
                              "random_seed": randomize,
3378
 
                              "exclude_pattern": exclude,
3379
 
                              "strict": strict,
3380
 
                              "load_list": load_list,
3381
 
                              "debug_flags": debugflag,
3382
 
                              "starting_with": starting_with
3383
 
                              }
3384
 
            selftest_kwargs.update(self.additional_selftest_args)
3385
 
            result = selftest(**selftest_kwargs)
 
4074
            result = tests.selftest(**selftest_kwargs)
3386
4075
        finally:
3387
 
            if benchfile is not None:
3388
 
                benchfile.close()
 
4076
            cleanup()
3389
4077
        return int(not result)
3390
4078
 
 
4079
    def _disable_fsync(self):
 
4080
        """Change the 'os' functionality to not synchronize."""
 
4081
        self._orig_fsync = getattr(os, 'fsync', None)
 
4082
        if self._orig_fsync is not None:
 
4083
            os.fsync = lambda filedes: None
 
4084
        self._orig_fdatasync = getattr(os, 'fdatasync', None)
 
4085
        if self._orig_fdatasync is not None:
 
4086
            os.fdatasync = lambda filedes: None
 
4087
 
3391
4088
 
3392
4089
class cmd_version(Command):
3393
 
    """Show version of bzr."""
 
4090
    __doc__ = """Show version of bzr."""
3394
4091
 
3395
4092
    encoding_type = 'replace'
3396
4093
    takes_options = [
3407
4104
 
3408
4105
 
3409
4106
class cmd_rocks(Command):
3410
 
    """Statement of optimism."""
 
4107
    __doc__ = """Statement of optimism."""
3411
4108
 
3412
4109
    hidden = True
3413
4110
 
3414
4111
    @display_command
3415
4112
    def run(self):
3416
 
        print "It sure does!"
 
4113
        self.outf.write(gettext("It sure does!\n"))
3417
4114
 
3418
4115
 
3419
4116
class cmd_find_merge_base(Command):
3420
 
    """Find and print a base revision for merging two branches."""
 
4117
    __doc__ = """Find and print a base revision for merging two branches."""
3421
4118
    # TODO: Options to specify revisions on either side, as if
3422
4119
    #       merging only part of the history.
3423
4120
    takes_args = ['branch', 'other']
3429
4126
 
3430
4127
        branch1 = Branch.open_containing(branch)[0]
3431
4128
        branch2 = Branch.open_containing(other)[0]
3432
 
        branch1.lock_read()
3433
 
        try:
3434
 
            branch2.lock_read()
3435
 
            try:
3436
 
                last1 = ensure_null(branch1.last_revision())
3437
 
                last2 = ensure_null(branch2.last_revision())
3438
 
 
3439
 
                graph = branch1.repository.get_graph(branch2.repository)
3440
 
                base_rev_id = graph.find_unique_lca(last1, last2)
3441
 
 
3442
 
                print 'merge base is revision %s' % base_rev_id
3443
 
            finally:
3444
 
                branch2.unlock()
3445
 
        finally:
3446
 
            branch1.unlock()
 
4129
        self.add_cleanup(branch1.lock_read().unlock)
 
4130
        self.add_cleanup(branch2.lock_read().unlock)
 
4131
        last1 = ensure_null(branch1.last_revision())
 
4132
        last2 = ensure_null(branch2.last_revision())
 
4133
 
 
4134
        graph = branch1.repository.get_graph(branch2.repository)
 
4135
        base_rev_id = graph.find_unique_lca(last1, last2)
 
4136
 
 
4137
        self.outf.write(gettext('merge base is revision %s\n') % base_rev_id)
3447
4138
 
3448
4139
 
3449
4140
class cmd_merge(Command):
3450
 
    """Perform a three-way merge.
 
4141
    __doc__ = """Perform a three-way merge.
3451
4142
 
3452
4143
    The source of the merge can be specified either in the form of a branch,
3453
4144
    or in the form of a path to a file containing a merge directive generated
3454
4145
    with bzr send. If neither is specified, the default is the upstream branch
3455
 
    or the branch most recently merged using --remember.
3456
 
 
3457
 
    When merging a branch, by default the tip will be merged. To pick a different
3458
 
    revision, pass --revision. If you specify two values, the first will be used as
3459
 
    BASE and the second one as OTHER. Merging individual revisions, or a subset of
3460
 
    available revisions, like this is commonly referred to as "cherrypicking".
3461
 
 
3462
 
    Revision numbers are always relative to the branch being merged.
3463
 
 
3464
 
    By default, bzr will try to merge in all new work from the other
3465
 
    branch, automatically determining an appropriate base.  If this
3466
 
    fails, you may need to give an explicit base.
 
4146
    or the branch most recently merged using --remember.  The source of the
 
4147
    merge may also be specified in the form of a path to a file in another
 
4148
    branch:  in this case, only the modifications to that file are merged into
 
4149
    the current working tree.
 
4150
 
 
4151
    When merging from a branch, by default bzr will try to merge in all new
 
4152
    work from the other branch, automatically determining an appropriate base
 
4153
    revision.  If this fails, you may need to give an explicit base.
 
4154
 
 
4155
    To pick a different ending revision, pass "--revision OTHER".  bzr will
 
4156
    try to merge in all new work up to and including revision OTHER.
 
4157
 
 
4158
    If you specify two values, "--revision BASE..OTHER", only revisions BASE
 
4159
    through OTHER, excluding BASE but including OTHER, will be merged.  If this
 
4160
    causes some revisions to be skipped, i.e. if the destination branch does
 
4161
    not already contain revision BASE, such a merge is commonly referred to as
 
4162
    a "cherrypick". Unlike a normal merge, Bazaar does not currently track
 
4163
    cherrypicks. The changes look like a normal commit, and the history of the
 
4164
    changes from the other branch is not stored in the commit.
 
4165
 
 
4166
    Revision numbers are always relative to the source branch.
3467
4167
 
3468
4168
    Merge will do its best to combine the changes in two branches, but there
3469
4169
    are some kinds of problems only a human can fix.  When it encounters those,
3470
4170
    it will mark a conflict.  A conflict means that you need to fix something,
3471
 
    before you should commit.
 
4171
    before you can commit.
3472
4172
 
3473
4173
    Use bzr resolve when you have fixed a problem.  See also bzr conflicts.
3474
4174
 
3475
 
    If there is no default branch set, the first merge will set it. After
3476
 
    that, you can omit the branch to use the default.  To change the
3477
 
    default, use --remember. The value will only be saved if the remote
3478
 
    location can be accessed.
 
4175
    If there is no default branch set, the first merge will set it (use
 
4176
    --no-remember to avoid setting it). After that, you can omit the branch
 
4177
    to use the default.  To change the default, use --remember. The value will
 
4178
    only be saved if the remote location can be accessed.
3479
4179
 
3480
4180
    The results of the merge are placed into the destination working
3481
4181
    directory, where they can be reviewed (with bzr diff), tested, and then
3482
4182
    committed to record the result of the merge.
3483
4183
 
3484
4184
    merge refuses to run if there are any uncommitted changes, unless
3485
 
    --force is given.
 
4185
    --force is given.  If --force is given, then the changes from the source 
 
4186
    will be merged with the current working tree, including any uncommitted
 
4187
    changes in the tree.  The --force option can also be used to create a
 
4188
    merge revision which has more than two parents.
 
4189
 
 
4190
    If one would like to merge changes from the working tree of the other
 
4191
    branch without merging any committed revisions, the --uncommitted option
 
4192
    can be given.
 
4193
 
 
4194
    To select only some changes to merge, use "merge -i", which will prompt
 
4195
    you to apply each diff hunk and file change, similar to "shelve".
3486
4196
 
3487
4197
    :Examples:
3488
 
        To merge the latest revision from bzr.dev::
 
4198
        To merge all new revisions from bzr.dev::
3489
4199
 
3490
4200
            bzr merge ../bzr.dev
3491
4201
 
3497
4207
 
3498
4208
            bzr merge -r 81..82 ../bzr.dev
3499
4209
 
3500
 
        To apply a merge directive contained in /tmp/merge:
 
4210
        To apply a merge directive contained in /tmp/merge::
3501
4211
 
3502
4212
            bzr merge /tmp/merge
 
4213
 
 
4214
        To create a merge revision with three parents from two branches
 
4215
        feature1a and feature1b:
 
4216
 
 
4217
            bzr merge ../feature1a
 
4218
            bzr merge ../feature1b --force
 
4219
            bzr commit -m 'revision with three parents'
3503
4220
    """
3504
4221
 
3505
4222
    encoding_type = 'exact'
3521
4238
                ' completely merged into the source, pull from the'
3522
4239
                ' source rather than merging.  When this happens,'
3523
4240
                ' you do not need to commit the result.'),
3524
 
        Option('directory',
 
4241
        custom_help('directory',
3525
4242
               help='Branch to merge into, '
3526
 
                    'rather than the one containing the working directory.',
3527
 
               short_name='d',
3528
 
               type=unicode,
3529
 
               ),
3530
 
        Option('preview', help='Instead of merging, show a diff of the merge.')
 
4243
                    'rather than the one containing the working directory.'),
 
4244
        Option('preview', help='Instead of merging, show a diff of the'
 
4245
               ' merge.'),
 
4246
        Option('interactive', help='Select changes interactively.',
 
4247
            short_name='i')
3531
4248
    ]
3532
4249
 
3533
4250
    def run(self, location=None, revision=None, force=False,
3534
 
            merge_type=None, show_base=False, reprocess=None, remember=False,
 
4251
            merge_type=None, show_base=False, reprocess=None, remember=None,
3535
4252
            uncommitted=False, pull=False,
3536
4253
            directory=None,
3537
4254
            preview=False,
 
4255
            interactive=False,
3538
4256
            ):
3539
4257
        if merge_type is None:
3540
4258
            merge_type = _mod_merge.Merge3Merger
3544
4262
        merger = None
3545
4263
        allow_pending = True
3546
4264
        verified = 'inapplicable'
 
4265
 
3547
4266
        tree = WorkingTree.open_containing(directory)[0]
 
4267
        if tree.branch.revno() == 0:
 
4268
            raise errors.BzrCommandError(gettext('Merging into empty branches not currently supported, '
 
4269
                                         'https://bugs.launchpad.net/bzr/+bug/308562'))
3548
4270
 
3549
 
        # die as quickly as possible if there are uncommitted changes
3550
4271
        try:
3551
4272
            basis_tree = tree.revision_tree(tree.last_revision())
3552
4273
        except errors.NoSuchRevision:
3553
4274
            basis_tree = tree.basis_tree()
 
4275
 
 
4276
        # die as quickly as possible if there are uncommitted changes
3554
4277
        if not force:
3555
 
            changes = tree.changes_from(basis_tree)
3556
 
            if changes.has_changed():
 
4278
            if tree.has_changes():
3557
4279
                raise errors.UncommittedChanges(tree)
3558
4280
 
3559
4281
        view_info = _get_view_info_for_change_reporter(tree)
3560
4282
        change_reporter = delta._ChangeReporter(
3561
4283
            unversioned_filter=tree.is_ignored, view_info=view_info)
3562
 
        cleanups = []
3563
 
        try:
3564
 
            pb = ui.ui_factory.nested_progress_bar()
3565
 
            cleanups.append(pb.finished)
3566
 
            tree.lock_write()
3567
 
            cleanups.append(tree.unlock)
3568
 
            if location is not None:
3569
 
                try:
3570
 
                    mergeable = bundle.read_mergeable_from_url(location,
3571
 
                        possible_transports=possible_transports)
3572
 
                except errors.NotABundle:
3573
 
                    mergeable = None
3574
 
                else:
3575
 
                    if uncommitted:
3576
 
                        raise errors.BzrCommandError('Cannot use --uncommitted'
3577
 
                            ' with bundles or merge directives.')
3578
 
 
3579
 
                    if revision is not None:
3580
 
                        raise errors.BzrCommandError(
3581
 
                            'Cannot use -r with merge directives or bundles')
3582
 
                    merger, verified = _mod_merge.Merger.from_mergeable(tree,
3583
 
                       mergeable, pb)
3584
 
 
3585
 
            if merger is None and uncommitted:
3586
 
                if revision is not None and len(revision) > 0:
3587
 
                    raise errors.BzrCommandError('Cannot use --uncommitted and'
3588
 
                        ' --revision at the same time.')
3589
 
                location = self._select_branch_location(tree, location)[0]
3590
 
                other_tree, other_path = WorkingTree.open_containing(location)
3591
 
                merger = _mod_merge.Merger.from_uncommitted(tree, other_tree,
3592
 
                    pb)
3593
 
                allow_pending = False
3594
 
                if other_path != '':
3595
 
                    merger.interesting_files = [other_path]
3596
 
 
3597
 
            if merger is None:
3598
 
                merger, allow_pending = self._get_merger_from_branch(tree,
3599
 
                    location, revision, remember, possible_transports, pb)
3600
 
 
3601
 
            merger.merge_type = merge_type
3602
 
            merger.reprocess = reprocess
3603
 
            merger.show_base = show_base
3604
 
            self.sanity_check_merger(merger)
3605
 
            if (merger.base_rev_id == merger.other_rev_id and
3606
 
                merger.other_rev_id is not None):
3607
 
                note('Nothing to do.')
 
4284
        pb = ui.ui_factory.nested_progress_bar()
 
4285
        self.add_cleanup(pb.finished)
 
4286
        self.add_cleanup(tree.lock_write().unlock)
 
4287
        if location is not None:
 
4288
            try:
 
4289
                mergeable = bundle.read_mergeable_from_url(location,
 
4290
                    possible_transports=possible_transports)
 
4291
            except errors.NotABundle:
 
4292
                mergeable = None
 
4293
            else:
 
4294
                if uncommitted:
 
4295
                    raise errors.BzrCommandError(gettext('Cannot use --uncommitted'
 
4296
                        ' with bundles or merge directives.'))
 
4297
 
 
4298
                if revision is not None:
 
4299
                    raise errors.BzrCommandError(gettext(
 
4300
                        'Cannot use -r with merge directives or bundles'))
 
4301
                merger, verified = _mod_merge.Merger.from_mergeable(tree,
 
4302
                   mergeable, None)
 
4303
 
 
4304
        if merger is None and uncommitted:
 
4305
            if revision is not None and len(revision) > 0:
 
4306
                raise errors.BzrCommandError(gettext('Cannot use --uncommitted and'
 
4307
                    ' --revision at the same time.'))
 
4308
            merger = self.get_merger_from_uncommitted(tree, location, None)
 
4309
            allow_pending = False
 
4310
 
 
4311
        if merger is None:
 
4312
            merger, allow_pending = self._get_merger_from_branch(tree,
 
4313
                location, revision, remember, possible_transports, None)
 
4314
 
 
4315
        merger.merge_type = merge_type
 
4316
        merger.reprocess = reprocess
 
4317
        merger.show_base = show_base
 
4318
        self.sanity_check_merger(merger)
 
4319
        if (merger.base_rev_id == merger.other_rev_id and
 
4320
            merger.other_rev_id is not None):
 
4321
            # check if location is a nonexistent file (and not a branch) to
 
4322
            # disambiguate the 'Nothing to do'
 
4323
            if merger.interesting_files:
 
4324
                if not merger.other_tree.has_filename(
 
4325
                    merger.interesting_files[0]):
 
4326
                    note(gettext("merger: ") + str(merger))
 
4327
                    raise errors.PathsDoNotExist([location])
 
4328
            note(gettext('Nothing to do.'))
 
4329
            return 0
 
4330
        if pull and not preview:
 
4331
            if merger.interesting_files is not None:
 
4332
                raise errors.BzrCommandError(gettext('Cannot pull individual files'))
 
4333
            if (merger.base_rev_id == tree.last_revision()):
 
4334
                result = tree.pull(merger.other_branch, False,
 
4335
                                   merger.other_rev_id)
 
4336
                result.report(self.outf)
3608
4337
                return 0
3609
 
            if pull:
3610
 
                if merger.interesting_files is not None:
3611
 
                    raise errors.BzrCommandError('Cannot pull individual files')
3612
 
                if (merger.base_rev_id == tree.last_revision()):
3613
 
                    result = tree.pull(merger.other_branch, False,
3614
 
                                       merger.other_rev_id)
3615
 
                    result.report(self.outf)
3616
 
                    return 0
3617
 
            merger.check_basis(False)
3618
 
            if preview:
3619
 
                return self._do_preview(merger)
3620
 
            else:
3621
 
                return self._do_merge(merger, change_reporter, allow_pending,
3622
 
                                      verified)
3623
 
        finally:
3624
 
            for cleanup in reversed(cleanups):
3625
 
                cleanup()
 
4338
        if merger.this_basis is None:
 
4339
            raise errors.BzrCommandError(gettext(
 
4340
                "This branch has no commits."
 
4341
                " (perhaps you would prefer 'bzr pull')"))
 
4342
        if preview:
 
4343
            return self._do_preview(merger)
 
4344
        elif interactive:
 
4345
            return self._do_interactive(merger)
 
4346
        else:
 
4347
            return self._do_merge(merger, change_reporter, allow_pending,
 
4348
                                  verified)
 
4349
 
 
4350
    def _get_preview(self, merger):
 
4351
        tree_merger = merger.make_merger()
 
4352
        tt = tree_merger.make_preview_transform()
 
4353
        self.add_cleanup(tt.finalize)
 
4354
        result_tree = tt.get_preview_tree()
 
4355
        return result_tree
3626
4356
 
3627
4357
    def _do_preview(self, merger):
3628
4358
        from bzrlib.diff import show_diff_trees
3629
 
        tree_merger = merger.make_merger()
3630
 
        tt = tree_merger.make_preview_transform()
3631
 
        try:
3632
 
            result_tree = tt.get_preview_tree()
3633
 
            show_diff_trees(merger.this_tree, result_tree, self.outf,
3634
 
                            old_label='', new_label='')
3635
 
        finally:
3636
 
            tt.finalize()
 
4359
        result_tree = self._get_preview(merger)
 
4360
        path_encoding = osutils.get_diff_header_encoding()
 
4361
        show_diff_trees(merger.this_tree, result_tree, self.outf,
 
4362
                        old_label='', new_label='',
 
4363
                        path_encoding=path_encoding)
3637
4364
 
3638
4365
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
3639
4366
        merger.change_reporter = change_reporter
3647
4374
        else:
3648
4375
            return 0
3649
4376
 
 
4377
    def _do_interactive(self, merger):
 
4378
        """Perform an interactive merge.
 
4379
 
 
4380
        This works by generating a preview tree of the merge, then using
 
4381
        Shelver to selectively remove the differences between the working tree
 
4382
        and the preview tree.
 
4383
        """
 
4384
        from bzrlib import shelf_ui
 
4385
        result_tree = self._get_preview(merger)
 
4386
        writer = bzrlib.option.diff_writer_registry.get()
 
4387
        shelver = shelf_ui.Shelver(merger.this_tree, result_tree, destroy=True,
 
4388
                                   reporter=shelf_ui.ApplyReporter(),
 
4389
                                   diff_writer=writer(sys.stdout))
 
4390
        try:
 
4391
            shelver.run()
 
4392
        finally:
 
4393
            shelver.finalize()
 
4394
 
3650
4395
    def sanity_check_merger(self, merger):
3651
4396
        if (merger.show_base and
3652
4397
            not merger.merge_type is _mod_merge.Merge3Merger):
3653
 
            raise errors.BzrCommandError("Show-base is not supported for this"
3654
 
                                         " merge type. %s" % merger.merge_type)
 
4398
            raise errors.BzrCommandError(gettext("Show-base is not supported for this"
 
4399
                                         " merge type. %s") % merger.merge_type)
3655
4400
        if merger.reprocess is None:
3656
4401
            if merger.show_base:
3657
4402
                merger.reprocess = False
3659
4404
                # Use reprocess if the merger supports it
3660
4405
                merger.reprocess = merger.merge_type.supports_reprocess
3661
4406
        if merger.reprocess and not merger.merge_type.supports_reprocess:
3662
 
            raise errors.BzrCommandError("Conflict reduction is not supported"
3663
 
                                         " for merge type %s." %
 
4407
            raise errors.BzrCommandError(gettext("Conflict reduction is not supported"
 
4408
                                         " for merge type %s.") %
3664
4409
                                         merger.merge_type)
3665
4410
        if merger.reprocess and merger.show_base:
3666
 
            raise errors.BzrCommandError("Cannot do conflict reduction and"
3667
 
                                         " show base.")
 
4411
            raise errors.BzrCommandError(gettext("Cannot do conflict reduction and"
 
4412
                                         " show base."))
3668
4413
 
3669
4414
    def _get_merger_from_branch(self, tree, location, revision, remember,
3670
4415
                                possible_transports, pb):
3687
4432
            base_branch, base_path = Branch.open_containing(base_loc,
3688
4433
                possible_transports)
3689
4434
        # Find the revision ids
3690
 
        if revision is None or len(revision) < 1 or revision[-1] is None:
 
4435
        other_revision_id = None
 
4436
        base_revision_id = None
 
4437
        if revision is not None:
 
4438
            if len(revision) >= 1:
 
4439
                other_revision_id = revision[-1].as_revision_id(other_branch)
 
4440
            if len(revision) == 2:
 
4441
                base_revision_id = revision[0].as_revision_id(base_branch)
 
4442
        if other_revision_id is None:
3691
4443
            other_revision_id = _mod_revision.ensure_null(
3692
4444
                other_branch.last_revision())
3693
 
        else:
3694
 
            other_revision_id = revision[-1].as_revision_id(other_branch)
3695
 
        if (revision is not None and len(revision) == 2
3696
 
            and revision[0] is not None):
3697
 
            base_revision_id = revision[0].as_revision_id(base_branch)
3698
 
        else:
3699
 
            base_revision_id = None
3700
 
        # Remember where we merge from
3701
 
        if ((remember or tree.branch.get_submit_branch() is None) and
3702
 
             user_location is not None):
 
4445
        # Remember where we merge from. We need to remember if:
 
4446
        # - user specify a location (and we don't merge from the parent
 
4447
        #   branch)
 
4448
        # - user ask to remember or there is no previous location set to merge
 
4449
        #   from and user didn't ask to *not* remember
 
4450
        if (user_location is not None
 
4451
            and ((remember
 
4452
                  or (remember is None
 
4453
                      and tree.branch.get_submit_branch() is None)))):
3703
4454
            tree.branch.set_submit_branch(other_branch.base)
3704
 
        _merge_tags_if_possible(other_branch, tree.branch)
 
4455
        # Merge tags (but don't set them in the master branch yet, the user
 
4456
        # might revert this merge).  Commit will propagate them.
 
4457
        _merge_tags_if_possible(other_branch, tree.branch, ignore_master=True)
3705
4458
        merger = _mod_merge.Merger.from_revision_ids(pb, tree,
3706
4459
            other_revision_id, base_revision_id, other_branch, base_branch)
3707
4460
        if other_path != '':
3711
4464
            allow_pending = True
3712
4465
        return merger, allow_pending
3713
4466
 
 
4467
    def get_merger_from_uncommitted(self, tree, location, pb):
 
4468
        """Get a merger for uncommitted changes.
 
4469
 
 
4470
        :param tree: The tree the merger should apply to.
 
4471
        :param location: The location containing uncommitted changes.
 
4472
        :param pb: The progress bar to use for showing progress.
 
4473
        """
 
4474
        location = self._select_branch_location(tree, location)[0]
 
4475
        other_tree, other_path = WorkingTree.open_containing(location)
 
4476
        merger = _mod_merge.Merger.from_uncommitted(tree, other_tree, pb)
 
4477
        if other_path != '':
 
4478
            merger.interesting_files = [other_path]
 
4479
        return merger
 
4480
 
3714
4481
    def _select_branch_location(self, tree, user_location, revision=None,
3715
4482
                                index=None):
3716
4483
        """Select a branch location, according to possible inputs.
3752
4519
            stored_location_type = "parent"
3753
4520
        mutter("%s", stored_location)
3754
4521
        if stored_location is None:
3755
 
            raise errors.BzrCommandError("No location specified or remembered")
 
4522
            raise errors.BzrCommandError(gettext("No location specified or remembered"))
3756
4523
        display_url = urlutils.unescape_for_display(stored_location, 'utf-8')
3757
 
        note(u"%s remembered %s location %s", verb_string,
3758
 
                stored_location_type, display_url)
 
4524
        note(gettext("{0} remembered {1} location {2}").format(verb_string,
 
4525
                stored_location_type, display_url))
3759
4526
        return stored_location
3760
4527
 
3761
4528
 
3762
4529
class cmd_remerge(Command):
3763
 
    """Redo a merge.
 
4530
    __doc__ = """Redo a merge.
3764
4531
 
3765
4532
    Use this if you want to try a different merge technique while resolving
3766
4533
    conflicts.  Some merge techniques are better than others, and remerge
3791
4558
 
3792
4559
    def run(self, file_list=None, merge_type=None, show_base=False,
3793
4560
            reprocess=False):
 
4561
        from bzrlib.conflicts import restore
3794
4562
        if merge_type is None:
3795
4563
            merge_type = _mod_merge.Merge3Merger
3796
 
        tree, file_list = tree_files(file_list)
3797
 
        tree.lock_write()
3798
 
        try:
3799
 
            parents = tree.get_parent_ids()
3800
 
            if len(parents) != 2:
3801
 
                raise errors.BzrCommandError("Sorry, remerge only works after normal"
3802
 
                                             " merges.  Not cherrypicking or"
3803
 
                                             " multi-merges.")
3804
 
            repository = tree.branch.repository
3805
 
            interesting_ids = None
3806
 
            new_conflicts = []
3807
 
            conflicts = tree.conflicts()
3808
 
            if file_list is not None:
3809
 
                interesting_ids = set()
3810
 
                for filename in file_list:
3811
 
                    file_id = tree.path2id(filename)
3812
 
                    if file_id is None:
3813
 
                        raise errors.NotVersionedError(filename)
3814
 
                    interesting_ids.add(file_id)
3815
 
                    if tree.kind(file_id) != "directory":
3816
 
                        continue
 
4564
        tree, file_list = WorkingTree.open_containing_paths(file_list)
 
4565
        self.add_cleanup(tree.lock_write().unlock)
 
4566
        parents = tree.get_parent_ids()
 
4567
        if len(parents) != 2:
 
4568
            raise errors.BzrCommandError(gettext("Sorry, remerge only works after normal"
 
4569
                                         " merges.  Not cherrypicking or"
 
4570
                                         " multi-merges."))
 
4571
        repository = tree.branch.repository
 
4572
        interesting_ids = None
 
4573
        new_conflicts = []
 
4574
        conflicts = tree.conflicts()
 
4575
        if file_list is not None:
 
4576
            interesting_ids = set()
 
4577
            for filename in file_list:
 
4578
                file_id = tree.path2id(filename)
 
4579
                if file_id is None:
 
4580
                    raise errors.NotVersionedError(filename)
 
4581
                interesting_ids.add(file_id)
 
4582
                if tree.kind(file_id) != "directory":
 
4583
                    continue
3817
4584
 
3818
 
                    for name, ie in tree.inventory.iter_entries(file_id):
3819
 
                        interesting_ids.add(ie.file_id)
3820
 
                new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
3821
 
            else:
3822
 
                # Remerge only supports resolving contents conflicts
3823
 
                allowed_conflicts = ('text conflict', 'contents conflict')
3824
 
                restore_files = [c.path for c in conflicts
3825
 
                                 if c.typestring in allowed_conflicts]
3826
 
            _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
3827
 
            tree.set_conflicts(ConflictList(new_conflicts))
3828
 
            if file_list is not None:
3829
 
                restore_files = file_list
3830
 
            for filename in restore_files:
3831
 
                try:
3832
 
                    restore(tree.abspath(filename))
3833
 
                except errors.NotConflicted:
3834
 
                    pass
3835
 
            # Disable pending merges, because the file texts we are remerging
3836
 
            # have not had those merges performed.  If we use the wrong parents
3837
 
            # list, we imply that the working tree text has seen and rejected
3838
 
            # all the changes from the other tree, when in fact those changes
3839
 
            # have not yet been seen.
3840
 
            pb = ui.ui_factory.nested_progress_bar()
3841
 
            tree.set_parent_ids(parents[:1])
 
4585
                for name, ie in tree.inventory.iter_entries(file_id):
 
4586
                    interesting_ids.add(ie.file_id)
 
4587
            new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
 
4588
        else:
 
4589
            # Remerge only supports resolving contents conflicts
 
4590
            allowed_conflicts = ('text conflict', 'contents conflict')
 
4591
            restore_files = [c.path for c in conflicts
 
4592
                             if c.typestring in allowed_conflicts]
 
4593
        _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
 
4594
        tree.set_conflicts(ConflictList(new_conflicts))
 
4595
        if file_list is not None:
 
4596
            restore_files = file_list
 
4597
        for filename in restore_files:
3842
4598
            try:
3843
 
                merger = _mod_merge.Merger.from_revision_ids(pb,
3844
 
                                                             tree, parents[1])
3845
 
                merger.interesting_ids = interesting_ids
3846
 
                merger.merge_type = merge_type
3847
 
                merger.show_base = show_base
3848
 
                merger.reprocess = reprocess
3849
 
                conflicts = merger.do_merge()
3850
 
            finally:
3851
 
                tree.set_parent_ids(parents)
3852
 
                pb.finished()
 
4599
                restore(tree.abspath(filename))
 
4600
            except errors.NotConflicted:
 
4601
                pass
 
4602
        # Disable pending merges, because the file texts we are remerging
 
4603
        # have not had those merges performed.  If we use the wrong parents
 
4604
        # list, we imply that the working tree text has seen and rejected
 
4605
        # all the changes from the other tree, when in fact those changes
 
4606
        # have not yet been seen.
 
4607
        tree.set_parent_ids(parents[:1])
 
4608
        try:
 
4609
            merger = _mod_merge.Merger.from_revision_ids(None, tree, parents[1])
 
4610
            merger.interesting_ids = interesting_ids
 
4611
            merger.merge_type = merge_type
 
4612
            merger.show_base = show_base
 
4613
            merger.reprocess = reprocess
 
4614
            conflicts = merger.do_merge()
3853
4615
        finally:
3854
 
            tree.unlock()
 
4616
            tree.set_parent_ids(parents)
3855
4617
        if conflicts > 0:
3856
4618
            return 1
3857
4619
        else:
3859
4621
 
3860
4622
 
3861
4623
class cmd_revert(Command):
3862
 
    """Revert files to a previous revision.
 
4624
    __doc__ = """Revert files to a previous revision.
3863
4625
 
3864
4626
    Giving a list of files will revert only those files.  Otherwise, all files
3865
4627
    will be reverted.  If the revision is not specified with '--revision', the
3866
4628
    last committed revision is used.
3867
4629
 
3868
4630
    To remove only some changes, without reverting to a prior version, use
3869
 
    merge instead.  For example, "merge . --revision -2..-3" will remove the
3870
 
    changes introduced by -2, without affecting the changes introduced by -1.
3871
 
    Or to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
 
4631
    merge instead.  For example, "merge . -r -2..-3" (don't forget the ".")
 
4632
    will remove the changes introduced by the second last commit (-2), without
 
4633
    affecting the changes introduced by the last commit (-1).  To remove
 
4634
    certain changes on a hunk-by-hunk basis, see the shelve command.
3872
4635
 
3873
4636
    By default, any files that have been manually changed will be backed up
3874
4637
    first.  (Files changed only by merge are not backed up.)  Backup files have
3879
4642
    name.  If you name a directory, all the contents of that directory will be
3880
4643
    reverted.
3881
4644
 
3882
 
    Any files that have been newly added since that revision will be deleted,
3883
 
    with a backup kept if appropriate.  Directories containing unknown files
3884
 
    will not be deleted.
 
4645
    If you have newly added files since the target revision, they will be
 
4646
    removed.  If the files to be removed have been changed, backups will be
 
4647
    created as above.  Directories containing unknown files will not be
 
4648
    deleted.
3885
4649
 
3886
 
    The working tree contains a list of pending merged revisions, which will
3887
 
    be included as parents in the next commit.  Normally, revert clears that
3888
 
    list as well as reverting the files.  If any files are specified, revert
3889
 
    leaves the pending merge list alone and reverts only the files.  Use "bzr
3890
 
    revert ." in the tree root to revert all files but keep the merge record,
3891
 
    and "bzr revert --forget-merges" to clear the pending merge list without
 
4650
    The working tree contains a list of revisions that have been merged but
 
4651
    not yet committed. These revisions will be included as additional parents
 
4652
    of the next commit.  Normally, using revert clears that list as well as
 
4653
    reverting the files.  If any files are specified, revert leaves the list
 
4654
    of uncommitted merges alone and reverts only the files.  Use ``bzr revert
 
4655
    .`` in the tree root to revert all files but keep the recorded merges,
 
4656
    and ``bzr revert --forget-merges`` to clear the pending merge list without
3892
4657
    reverting any files.
 
4658
 
 
4659
    Using "bzr revert --forget-merges", it is possible to apply all of the
 
4660
    changes from a branch in a single revision.  To do this, perform the merge
 
4661
    as desired.  Then doing revert with the "--forget-merges" option will keep
 
4662
    the content of the tree as it was, but it will clear the list of pending
 
4663
    merges.  The next commit will then contain all of the changes that are
 
4664
    present in the other branch, but without any other parent revisions.
 
4665
    Because this technique forgets where these changes originated, it may
 
4666
    cause additional conflicts on later merges involving the same source and
 
4667
    target branches.
3893
4668
    """
3894
4669
 
3895
 
    _see_also = ['cat', 'export']
 
4670
    _see_also = ['cat', 'export', 'merge', 'shelve']
3896
4671
    takes_options = [
3897
4672
        'revision',
3898
4673
        Option('no-backup', "Do not save backups of reverted files."),
3903
4678
 
3904
4679
    def run(self, revision=None, no_backup=False, file_list=None,
3905
4680
            forget_merges=None):
3906
 
        tree, file_list = tree_files(file_list)
3907
 
        tree.lock_write()
3908
 
        try:
3909
 
            if forget_merges:
3910
 
                tree.set_parent_ids(tree.get_parent_ids()[:1])
3911
 
            else:
3912
 
                self._revert_tree_to_revision(tree, revision, file_list, no_backup)
3913
 
        finally:
3914
 
            tree.unlock()
 
4681
        tree, file_list = WorkingTree.open_containing_paths(file_list)
 
4682
        self.add_cleanup(tree.lock_tree_write().unlock)
 
4683
        if forget_merges:
 
4684
            tree.set_parent_ids(tree.get_parent_ids()[:1])
 
4685
        else:
 
4686
            self._revert_tree_to_revision(tree, revision, file_list, no_backup)
3915
4687
 
3916
4688
    @staticmethod
3917
4689
    def _revert_tree_to_revision(tree, revision, file_list, no_backup):
3918
4690
        rev_tree = _get_one_revision_tree('revert', revision, tree=tree)
3919
 
        pb = ui.ui_factory.nested_progress_bar()
3920
 
        try:
3921
 
            tree.revert(file_list, rev_tree, not no_backup, pb,
3922
 
                report_changes=True)
3923
 
        finally:
3924
 
            pb.finished()
 
4691
        tree.revert(file_list, rev_tree, not no_backup, None,
 
4692
            report_changes=True)
3925
4693
 
3926
4694
 
3927
4695
class cmd_assert_fail(Command):
3928
 
    """Test reporting of assertion failures"""
 
4696
    __doc__ = """Test reporting of assertion failures"""
3929
4697
    # intended just for use in testing
3930
4698
 
3931
4699
    hidden = True
3935
4703
 
3936
4704
 
3937
4705
class cmd_help(Command):
3938
 
    """Show help on a command or other topic.
 
4706
    __doc__ = """Show help on a command or other topic.
3939
4707
    """
3940
4708
 
3941
4709
    _see_also = ['topics']
3954
4722
 
3955
4723
 
3956
4724
class cmd_shell_complete(Command):
3957
 
    """Show appropriate completions for context.
 
4725
    __doc__ = """Show appropriate completions for context.
3958
4726
 
3959
4727
    For a list of all available commands, say 'bzr shell-complete'.
3960
4728
    """
3964
4732
 
3965
4733
    @display_command
3966
4734
    def run(self, context=None):
3967
 
        import shellcomplete
 
4735
        from bzrlib import shellcomplete
3968
4736
        shellcomplete.shellcomplete(context)
3969
4737
 
3970
4738
 
3971
4739
class cmd_missing(Command):
3972
 
    """Show unmerged/unpulled revisions between two branches.
 
4740
    __doc__ = """Show unmerged/unpulled revisions between two branches.
3973
4741
 
3974
4742
    OTHER_BRANCH may be local or remote.
3975
4743
 
3976
4744
    To filter on a range of revisions, you can use the command -r begin..end
3977
4745
    -r revision requests a specific revision, -r ..end or -r begin.. are
3978
4746
    also valid.
 
4747
            
 
4748
    :Exit values:
 
4749
        1 - some missing revisions
 
4750
        0 - no missing revisions
3979
4751
 
3980
4752
    :Examples:
3981
4753
 
4002
4774
    _see_also = ['merge', 'pull']
4003
4775
    takes_args = ['other_branch?']
4004
4776
    takes_options = [
 
4777
        'directory',
4005
4778
        Option('reverse', 'Reverse the order of revisions.'),
4006
4779
        Option('mine-only',
4007
4780
               'Display changes in the local branch only.'),
4019
4792
            type=_parse_revision_str,
4020
4793
            help='Filter on local branch revisions (inclusive). '
4021
4794
                'See "help revisionspec" for details.'),
4022
 
        Option('include-merges',
 
4795
        Option('include-merged',
4023
4796
               'Show all revisions in addition to the mainline ones.'),
 
4797
        Option('include-merges', hidden=True,
 
4798
               help='Historical alias for --include-merged.'),
4024
4799
        ]
4025
4800
    encoding_type = 'replace'
4026
4801
 
4029
4804
            theirs_only=False,
4030
4805
            log_format=None, long=False, short=False, line=False,
4031
4806
            show_ids=False, verbose=False, this=False, other=False,
4032
 
            include_merges=False, revision=None, my_revision=None):
 
4807
            include_merged=None, revision=None, my_revision=None,
 
4808
            directory=u'.',
 
4809
            include_merges=symbol_versioning.DEPRECATED_PARAMETER):
4033
4810
        from bzrlib.missing import find_unmerged, iter_log_revisions
4034
4811
        def message(s):
4035
4812
            if not is_quiet():
4036
4813
                self.outf.write(s)
4037
4814
 
 
4815
        if symbol_versioning.deprecated_passed(include_merges):
 
4816
            ui.ui_factory.show_user_warning(
 
4817
                'deprecated_command_option',
 
4818
                deprecated_name='--include-merges',
 
4819
                recommended_name='--include-merged',
 
4820
                deprecated_in_version='2.5',
 
4821
                command=self.invoked_as)
 
4822
            if include_merged is None:
 
4823
                include_merged = include_merges
 
4824
            else:
 
4825
                raise errors.BzrCommandError(gettext(
 
4826
                    '{0} and {1} are mutually exclusive').format(
 
4827
                    '--include-merges', '--include-merged'))
 
4828
        if include_merged is None:
 
4829
            include_merged = False
4038
4830
        if this:
4039
4831
            mine_only = this
4040
4832
        if other:
4048
4840
        elif theirs_only:
4049
4841
            restrict = 'remote'
4050
4842
 
4051
 
        local_branch = Branch.open_containing(u".")[0]
 
4843
        local_branch = Branch.open_containing(directory)[0]
 
4844
        self.add_cleanup(local_branch.lock_read().unlock)
 
4845
 
4052
4846
        parent = local_branch.get_parent()
4053
4847
        if other_branch is None:
4054
4848
            other_branch = parent
4055
4849
            if other_branch is None:
4056
 
                raise errors.BzrCommandError("No peer location known"
4057
 
                                             " or specified.")
 
4850
                raise errors.BzrCommandError(gettext("No peer location known"
 
4851
                                             " or specified."))
4058
4852
            display_url = urlutils.unescape_for_display(parent,
4059
4853
                                                        self.outf.encoding)
4060
 
            message("Using saved parent location: "
4061
 
                    + display_url + "\n")
 
4854
            message(gettext("Using saved parent location: {0}\n").format(
 
4855
                    display_url))
4062
4856
 
4063
4857
        remote_branch = Branch.open(other_branch)
4064
4858
        if remote_branch.base == local_branch.base:
4065
4859
            remote_branch = local_branch
 
4860
        else:
 
4861
            self.add_cleanup(remote_branch.lock_read().unlock)
4066
4862
 
4067
4863
        local_revid_range = _revision_range_to_revid_range(
4068
4864
            _get_revision_range(my_revision, local_branch,
4072
4868
            _get_revision_range(revision,
4073
4869
                remote_branch, self.name()))
4074
4870
 
4075
 
        local_branch.lock_read()
4076
 
        try:
4077
 
            remote_branch.lock_read()
4078
 
            try:
4079
 
                local_extra, remote_extra = find_unmerged(
4080
 
                    local_branch, remote_branch, restrict,
4081
 
                    backward=not reverse,
4082
 
                    include_merges=include_merges,
4083
 
                    local_revid_range=local_revid_range,
4084
 
                    remote_revid_range=remote_revid_range)
4085
 
 
4086
 
                if log_format is None:
4087
 
                    registry = log.log_formatter_registry
4088
 
                    log_format = registry.get_default(local_branch)
4089
 
                lf = log_format(to_file=self.outf,
4090
 
                                show_ids=show_ids,
4091
 
                                show_timezone='original')
4092
 
 
4093
 
                status_code = 0
4094
 
                if local_extra and not theirs_only:
4095
 
                    message("You have %d extra revision(s):\n" %
4096
 
                        len(local_extra))
4097
 
                    for revision in iter_log_revisions(local_extra,
4098
 
                                        local_branch.repository,
4099
 
                                        verbose):
4100
 
                        lf.log_revision(revision)
4101
 
                    printed_local = True
4102
 
                    status_code = 1
4103
 
                else:
4104
 
                    printed_local = False
4105
 
 
4106
 
                if remote_extra and not mine_only:
4107
 
                    if printed_local is True:
4108
 
                        message("\n\n\n")
4109
 
                    message("You are missing %d revision(s):\n" %
4110
 
                        len(remote_extra))
4111
 
                    for revision in iter_log_revisions(remote_extra,
4112
 
                                        remote_branch.repository,
4113
 
                                        verbose):
4114
 
                        lf.log_revision(revision)
4115
 
                    status_code = 1
4116
 
 
4117
 
                if mine_only and not local_extra:
4118
 
                    # We checked local, and found nothing extra
4119
 
                    message('This branch is up to date.\n')
4120
 
                elif theirs_only and not remote_extra:
4121
 
                    # We checked remote, and found nothing extra
4122
 
                    message('Other branch is up to date.\n')
4123
 
                elif not (mine_only or theirs_only or local_extra or
4124
 
                          remote_extra):
4125
 
                    # We checked both branches, and neither one had extra
4126
 
                    # revisions
4127
 
                    message("Branches are up to date.\n")
4128
 
            finally:
4129
 
                remote_branch.unlock()
4130
 
        finally:
4131
 
            local_branch.unlock()
 
4871
        local_extra, remote_extra = find_unmerged(
 
4872
            local_branch, remote_branch, restrict,
 
4873
            backward=not reverse,
 
4874
            include_merged=include_merged,
 
4875
            local_revid_range=local_revid_range,
 
4876
            remote_revid_range=remote_revid_range)
 
4877
 
 
4878
        if log_format is None:
 
4879
            registry = log.log_formatter_registry
 
4880
            log_format = registry.get_default(local_branch)
 
4881
        lf = log_format(to_file=self.outf,
 
4882
                        show_ids=show_ids,
 
4883
                        show_timezone='original')
 
4884
 
 
4885
        status_code = 0
 
4886
        if local_extra and not theirs_only:
 
4887
            message(ngettext("You have %d extra revision:\n",
 
4888
                             "You have %d extra revisions:\n", 
 
4889
                             len(local_extra)) %
 
4890
                len(local_extra))
 
4891
            for revision in iter_log_revisions(local_extra,
 
4892
                                local_branch.repository,
 
4893
                                verbose):
 
4894
                lf.log_revision(revision)
 
4895
            printed_local = True
 
4896
            status_code = 1
 
4897
        else:
 
4898
            printed_local = False
 
4899
 
 
4900
        if remote_extra and not mine_only:
 
4901
            if printed_local is True:
 
4902
                message("\n\n\n")
 
4903
            message(ngettext("You are missing %d revision:\n",
 
4904
                             "You are missing %d revisions:\n",
 
4905
                             len(remote_extra)) %
 
4906
                len(remote_extra))
 
4907
            for revision in iter_log_revisions(remote_extra,
 
4908
                                remote_branch.repository,
 
4909
                                verbose):
 
4910
                lf.log_revision(revision)
 
4911
            status_code = 1
 
4912
 
 
4913
        if mine_only and not local_extra:
 
4914
            # We checked local, and found nothing extra
 
4915
            message(gettext('This branch has no new revisions.\n'))
 
4916
        elif theirs_only and not remote_extra:
 
4917
            # We checked remote, and found nothing extra
 
4918
            message(gettext('Other branch has no new revisions.\n'))
 
4919
        elif not (mine_only or theirs_only or local_extra or
 
4920
                  remote_extra):
 
4921
            # We checked both branches, and neither one had extra
 
4922
            # revisions
 
4923
            message(gettext("Branches are up to date.\n"))
 
4924
        self.cleanup_now()
4132
4925
        if not status_code and parent is None and other_branch is not None:
4133
 
            local_branch.lock_write()
4134
 
            try:
4135
 
                # handle race conditions - a parent might be set while we run.
4136
 
                if local_branch.get_parent() is None:
4137
 
                    local_branch.set_parent(remote_branch.base)
4138
 
            finally:
4139
 
                local_branch.unlock()
 
4926
            self.add_cleanup(local_branch.lock_write().unlock)
 
4927
            # handle race conditions - a parent might be set while we run.
 
4928
            if local_branch.get_parent() is None:
 
4929
                local_branch.set_parent(remote_branch.base)
4140
4930
        return status_code
4141
4931
 
4142
4932
 
4143
4933
class cmd_pack(Command):
4144
 
    """Compress the data within a repository."""
 
4934
    __doc__ = """Compress the data within a repository.
 
4935
 
 
4936
    This operation compresses the data within a bazaar repository. As
 
4937
    bazaar supports automatic packing of repository, this operation is
 
4938
    normally not required to be done manually.
 
4939
 
 
4940
    During the pack operation, bazaar takes a backup of existing repository
 
4941
    data, i.e. pack files. This backup is eventually removed by bazaar
 
4942
    automatically when it is safe to do so. To save disk space by removing
 
4943
    the backed up pack files, the --clean-obsolete-packs option may be
 
4944
    used.
 
4945
 
 
4946
    Warning: If you use --clean-obsolete-packs and your machine crashes
 
4947
    during or immediately after repacking, you may be left with a state
 
4948
    where the deletion has been written to disk but the new packs have not
 
4949
    been. In this case the repository may be unusable.
 
4950
    """
4145
4951
 
4146
4952
    _see_also = ['repositories']
4147
4953
    takes_args = ['branch_or_repo?']
 
4954
    takes_options = [
 
4955
        Option('clean-obsolete-packs', 'Delete obsolete packs to save disk space.'),
 
4956
        ]
4148
4957
 
4149
 
    def run(self, branch_or_repo='.'):
4150
 
        dir = bzrdir.BzrDir.open_containing(branch_or_repo)[0]
 
4958
    def run(self, branch_or_repo='.', clean_obsolete_packs=False):
 
4959
        dir = controldir.ControlDir.open_containing(branch_or_repo)[0]
4151
4960
        try:
4152
4961
            branch = dir.open_branch()
4153
4962
            repository = branch.repository
4154
4963
        except errors.NotBranchError:
4155
4964
            repository = dir.open_repository()
4156
 
        repository.pack()
 
4965
        repository.pack(clean_obsolete_packs=clean_obsolete_packs)
4157
4966
 
4158
4967
 
4159
4968
class cmd_plugins(Command):
4160
 
    """List the installed plugins.
 
4969
    __doc__ = """List the installed plugins.
4161
4970
 
4162
4971
    This command displays the list of installed plugins including
4163
4972
    version of plugin and a short description of each.
4170
4979
    adding new commands, providing additional network transports and
4171
4980
    customizing log output.
4172
4981
 
4173
 
    See the Bazaar web site, http://bazaar-vcs.org, for further
4174
 
    information on plugins including where to find them and how to
4175
 
    install them. Instructions are also provided there on how to
4176
 
    write new plugins using the Python programming language.
 
4982
    See the Bazaar Plugin Guide <http://doc.bazaar.canonical.com/plugins/en/>
 
4983
    for further information on plugins including where to find them and how to
 
4984
    install them. Instructions are also provided there on how to write new
 
4985
    plugins using the Python programming language.
4177
4986
    """
4178
4987
    takes_options = ['verbose']
4179
4988
 
4180
4989
    @display_command
4181
4990
    def run(self, verbose=False):
4182
 
        import bzrlib.plugin
4183
 
        from inspect import getdoc
4184
 
        result = []
4185
 
        for name, plugin in bzrlib.plugin.plugins().items():
4186
 
            version = plugin.__version__
4187
 
            if version == 'unknown':
4188
 
                version = ''
4189
 
            name_ver = '%s %s' % (name, version)
4190
 
            d = getdoc(plugin.module)
4191
 
            if d:
4192
 
                doc = d.split('\n')[0]
4193
 
            else:
4194
 
                doc = '(no description)'
4195
 
            result.append((name_ver, doc, plugin.path()))
4196
 
        for name_ver, doc, path in sorted(result):
4197
 
            print name_ver
4198
 
            print '   ', doc
4199
 
            if verbose:
4200
 
                print '   ', path
4201
 
            print
 
4991
        from bzrlib import plugin
 
4992
        # Don't give writelines a generator as some codecs don't like that
 
4993
        self.outf.writelines(
 
4994
            list(plugin.describe_plugins(show_paths=verbose)))
4202
4995
 
4203
4996
 
4204
4997
class cmd_testament(Command):
4205
 
    """Show testament (signing-form) of a revision."""
 
4998
    __doc__ = """Show testament (signing-form) of a revision."""
4206
4999
    takes_options = [
4207
5000
            'revision',
4208
5001
            Option('long', help='Produce long-format testament.'),
4220
5013
            b = Branch.open_containing(branch)[0]
4221
5014
        else:
4222
5015
            b = Branch.open(branch)
4223
 
        b.lock_read()
4224
 
        try:
4225
 
            if revision is None:
4226
 
                rev_id = b.last_revision()
4227
 
            else:
4228
 
                rev_id = revision[0].as_revision_id(b)
4229
 
            t = testament_class.from_revision(b.repository, rev_id)
4230
 
            if long:
4231
 
                sys.stdout.writelines(t.as_text_lines())
4232
 
            else:
4233
 
                sys.stdout.write(t.as_short_text())
4234
 
        finally:
4235
 
            b.unlock()
 
5016
        self.add_cleanup(b.lock_read().unlock)
 
5017
        if revision is None:
 
5018
            rev_id = b.last_revision()
 
5019
        else:
 
5020
            rev_id = revision[0].as_revision_id(b)
 
5021
        t = testament_class.from_revision(b.repository, rev_id)
 
5022
        if long:
 
5023
            sys.stdout.writelines(t.as_text_lines())
 
5024
        else:
 
5025
            sys.stdout.write(t.as_short_text())
4236
5026
 
4237
5027
 
4238
5028
class cmd_annotate(Command):
4239
 
    """Show the origin of each line in a file.
 
5029
    __doc__ = """Show the origin of each line in a file.
4240
5030
 
4241
5031
    This prints out the given file with an annotation on the left side
4242
5032
    indicating which revision, author and date introduced the change.
4253
5043
                     Option('long', help='Show commit date in annotations.'),
4254
5044
                     'revision',
4255
5045
                     'show-ids',
 
5046
                     'directory',
4256
5047
                     ]
4257
5048
    encoding_type = 'exact'
4258
5049
 
4259
5050
    @display_command
4260
5051
    def run(self, filename, all=False, long=False, revision=None,
4261
 
            show_ids=False):
4262
 
        from bzrlib.annotate import annotate_file, annotate_file_tree
 
5052
            show_ids=False, directory=None):
 
5053
        from bzrlib.annotate import (
 
5054
            annotate_file_tree,
 
5055
            )
4263
5056
        wt, branch, relpath = \
4264
 
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
 
5057
            _open_directory_or_containing_tree_or_branch(filename, directory)
4265
5058
        if wt is not None:
4266
 
            wt.lock_read()
4267
 
        else:
4268
 
            branch.lock_read()
4269
 
        try:
4270
 
            tree = _get_one_revision_tree('annotate', revision, branch=branch)
4271
 
            if wt is not None:
4272
 
                file_id = wt.path2id(relpath)
4273
 
            else:
4274
 
                file_id = tree.path2id(relpath)
4275
 
            if file_id is None:
4276
 
                raise errors.NotVersionedError(filename)
4277
 
            file_version = tree.inventory[file_id].revision
4278
 
            if wt is not None and revision is None:
4279
 
                # If there is a tree and we're not annotating historical
4280
 
                # versions, annotate the working tree's content.
4281
 
                annotate_file_tree(wt, file_id, self.outf, long, all,
4282
 
                    show_ids=show_ids)
4283
 
            else:
4284
 
                annotate_file(branch, file_version, file_id, long, all, self.outf,
4285
 
                              show_ids=show_ids)
4286
 
        finally:
4287
 
            if wt is not None:
4288
 
                wt.unlock()
4289
 
            else:
4290
 
                branch.unlock()
 
5059
            self.add_cleanup(wt.lock_read().unlock)
 
5060
        else:
 
5061
            self.add_cleanup(branch.lock_read().unlock)
 
5062
        tree = _get_one_revision_tree('annotate', revision, branch=branch)
 
5063
        self.add_cleanup(tree.lock_read().unlock)
 
5064
        if wt is not None and revision is None:
 
5065
            file_id = wt.path2id(relpath)
 
5066
        else:
 
5067
            file_id = tree.path2id(relpath)
 
5068
        if file_id is None:
 
5069
            raise errors.NotVersionedError(filename)
 
5070
        if wt is not None and revision is None:
 
5071
            # If there is a tree and we're not annotating historical
 
5072
            # versions, annotate the working tree's content.
 
5073
            annotate_file_tree(wt, file_id, self.outf, long, all,
 
5074
                show_ids=show_ids)
 
5075
        else:
 
5076
            annotate_file_tree(tree, file_id, self.outf, long, all,
 
5077
                show_ids=show_ids, branch=branch)
4291
5078
 
4292
5079
 
4293
5080
class cmd_re_sign(Command):
4294
 
    """Create a digital signature for an existing revision."""
 
5081
    __doc__ = """Create a digital signature for an existing revision."""
4295
5082
    # TODO be able to replace existing ones.
4296
5083
 
4297
5084
    hidden = True # is this right ?
4298
5085
    takes_args = ['revision_id*']
4299
 
    takes_options = ['revision']
 
5086
    takes_options = ['directory', 'revision']
4300
5087
 
4301
 
    def run(self, revision_id_list=None, revision=None):
 
5088
    def run(self, revision_id_list=None, revision=None, directory=u'.'):
4302
5089
        if revision_id_list is not None and revision is not None:
4303
 
            raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
 
5090
            raise errors.BzrCommandError(gettext('You can only supply one of revision_id or --revision'))
4304
5091
        if revision_id_list is None and revision is None:
4305
 
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
4306
 
        b = WorkingTree.open_containing(u'.')[0].branch
4307
 
        b.lock_write()
4308
 
        try:
4309
 
            return self._run(b, revision_id_list, revision)
4310
 
        finally:
4311
 
            b.unlock()
 
5092
            raise errors.BzrCommandError(gettext('You must supply either --revision or a revision_id'))
 
5093
        b = WorkingTree.open_containing(directory)[0].branch
 
5094
        self.add_cleanup(b.lock_write().unlock)
 
5095
        return self._run(b, revision_id_list, revision)
4312
5096
 
4313
5097
    def _run(self, b, revision_id_list, revision):
4314
5098
        import bzrlib.gpg as gpg
4315
 
        gpg_strategy = gpg.GPGStrategy(b.get_config())
 
5099
        gpg_strategy = gpg.GPGStrategy(b.get_config_stack())
4316
5100
        if revision_id_list is not None:
4317
5101
            b.repository.start_write_group()
4318
5102
            try:
4343
5127
                if to_revid is None:
4344
5128
                    to_revno = b.revno()
4345
5129
                if from_revno is None or to_revno is None:
4346
 
                    raise errors.BzrCommandError('Cannot sign a range of non-revision-history revisions')
 
5130
                    raise errors.BzrCommandError(gettext('Cannot sign a range of non-revision-history revisions'))
4347
5131
                b.repository.start_write_group()
4348
5132
                try:
4349
5133
                    for revno in range(from_revno, to_revno + 1):
4355
5139
                else:
4356
5140
                    b.repository.commit_write_group()
4357
5141
            else:
4358
 
                raise errors.BzrCommandError('Please supply either one revision, or a range.')
 
5142
                raise errors.BzrCommandError(gettext('Please supply either one revision, or a range.'))
4359
5143
 
4360
5144
 
4361
5145
class cmd_bind(Command):
4362
 
    """Convert the current branch into a checkout of the supplied branch.
 
5146
    __doc__ = """Convert the current branch into a checkout of the supplied branch.
 
5147
    If no branch is supplied, rebind to the last bound location.
4363
5148
 
4364
5149
    Once converted into a checkout, commits must succeed on the master branch
4365
5150
    before they will be applied to the local branch.
4366
5151
 
4367
5152
    Bound branches use the nickname of its master branch unless it is set
4368
 
    locally, in which case binding will update the the local nickname to be
 
5153
    locally, in which case binding will update the local nickname to be
4369
5154
    that of the master.
4370
5155
    """
4371
5156
 
4372
5157
    _see_also = ['checkouts', 'unbind']
4373
5158
    takes_args = ['location?']
4374
 
    takes_options = []
 
5159
    takes_options = ['directory']
4375
5160
 
4376
 
    def run(self, location=None):
4377
 
        b, relpath = Branch.open_containing(u'.')
 
5161
    def run(self, location=None, directory=u'.'):
 
5162
        b, relpath = Branch.open_containing(directory)
4378
5163
        if location is None:
4379
5164
            try:
4380
5165
                location = b.get_old_bound_location()
4381
5166
            except errors.UpgradeRequired:
4382
 
                raise errors.BzrCommandError('No location supplied.  '
4383
 
                    'This format does not remember old locations.')
 
5167
                raise errors.BzrCommandError(gettext('No location supplied.  '
 
5168
                    'This format does not remember old locations.'))
4384
5169
            else:
4385
5170
                if location is None:
4386
 
                    raise errors.BzrCommandError('No location supplied and no '
4387
 
                        'previous location known')
 
5171
                    if b.get_bound_location() is not None:
 
5172
                        raise errors.BzrCommandError(gettext('Branch is already bound'))
 
5173
                    else:
 
5174
                        raise errors.BzrCommandError(gettext('No location supplied '
 
5175
                            'and no previous location known'))
4388
5176
        b_other = Branch.open(location)
4389
5177
        try:
4390
5178
            b.bind(b_other)
4391
5179
        except errors.DivergedBranches:
4392
 
            raise errors.BzrCommandError('These branches have diverged.'
4393
 
                                         ' Try merging, and then bind again.')
 
5180
            raise errors.BzrCommandError(gettext('These branches have diverged.'
 
5181
                                         ' Try merging, and then bind again.'))
4394
5182
        if b.get_config().has_explicit_nickname():
4395
5183
            b.nick = b_other.nick
4396
5184
 
4397
5185
 
4398
5186
class cmd_unbind(Command):
4399
 
    """Convert the current checkout into a regular branch.
 
5187
    __doc__ = """Convert the current checkout into a regular branch.
4400
5188
 
4401
5189
    After unbinding, the local branch is considered independent and subsequent
4402
5190
    commits will be local only.
4404
5192
 
4405
5193
    _see_also = ['checkouts', 'bind']
4406
5194
    takes_args = []
4407
 
    takes_options = []
 
5195
    takes_options = ['directory']
4408
5196
 
4409
 
    def run(self):
4410
 
        b, relpath = Branch.open_containing(u'.')
 
5197
    def run(self, directory=u'.'):
 
5198
        b, relpath = Branch.open_containing(directory)
4411
5199
        if not b.unbind():
4412
 
            raise errors.BzrCommandError('Local branch is not bound')
 
5200
            raise errors.BzrCommandError(gettext('Local branch is not bound'))
4413
5201
 
4414
5202
 
4415
5203
class cmd_uncommit(Command):
4416
 
    """Remove the last committed revision.
 
5204
    __doc__ = """Remove the last committed revision.
4417
5205
 
4418
5206
    --verbose will print out what is being removed.
4419
5207
    --dry-run will go through all the motions, but not actually
4436
5224
    takes_options = ['verbose', 'revision',
4437
5225
                    Option('dry-run', help='Don\'t actually make changes.'),
4438
5226
                    Option('force', help='Say yes to all questions.'),
 
5227
                    Option('keep-tags',
 
5228
                           help='Keep tags that point to removed revisions.'),
4439
5229
                    Option('local',
4440
5230
                           help="Only remove the commits from the local branch"
4441
5231
                                " when in a checkout."
4445
5235
    aliases = []
4446
5236
    encoding_type = 'replace'
4447
5237
 
4448
 
    def run(self, location=None,
4449
 
            dry_run=False, verbose=False,
4450
 
            revision=None, force=False, local=False):
 
5238
    def run(self, location=None, dry_run=False, verbose=False,
 
5239
            revision=None, force=False, local=False, keep_tags=False):
4451
5240
        if location is None:
4452
5241
            location = u'.'
4453
 
        control, relpath = bzrdir.BzrDir.open_containing(location)
 
5242
        control, relpath = controldir.ControlDir.open_containing(location)
4454
5243
        try:
4455
5244
            tree = control.open_workingtree()
4456
5245
            b = tree.branch
4459
5248
            b = control.open_branch()
4460
5249
 
4461
5250
        if tree is not None:
4462
 
            tree.lock_write()
 
5251
            self.add_cleanup(tree.lock_write().unlock)
4463
5252
        else:
4464
 
            b.lock_write()
4465
 
        try:
4466
 
            return self._run(b, tree, dry_run, verbose, revision, force,
4467
 
                             local=local)
4468
 
        finally:
4469
 
            if tree is not None:
4470
 
                tree.unlock()
4471
 
            else:
4472
 
                b.unlock()
 
5253
            self.add_cleanup(b.lock_write().unlock)
 
5254
        return self._run(b, tree, dry_run, verbose, revision, force,
 
5255
                         local, keep_tags)
4473
5256
 
4474
 
    def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
 
5257
    def _run(self, b, tree, dry_run, verbose, revision, force, local,
 
5258
             keep_tags):
4475
5259
        from bzrlib.log import log_formatter, show_log
4476
5260
        from bzrlib.uncommit import uncommit
4477
5261
 
4492
5276
                rev_id = b.get_rev_id(revno)
4493
5277
 
4494
5278
        if rev_id is None or _mod_revision.is_null(rev_id):
4495
 
            self.outf.write('No revisions to uncommit.\n')
 
5279
            self.outf.write(gettext('No revisions to uncommit.\n'))
4496
5280
            return 1
4497
5281
 
4498
5282
        lf = log_formatter('short',
4507
5291
                 end_revision=last_revno)
4508
5292
 
4509
5293
        if dry_run:
4510
 
            print 'Dry-run, pretending to remove the above revisions.'
4511
 
            if not force:
4512
 
                val = raw_input('Press <enter> to continue')
 
5294
            self.outf.write(gettext('Dry-run, pretending to remove'
 
5295
                            ' the above revisions.\n'))
4513
5296
        else:
4514
 
            print 'The above revision(s) will be removed.'
4515
 
            if not force:
4516
 
                val = raw_input('Are you sure [y/N]? ')
4517
 
                if val.lower() not in ('y', 'yes'):
4518
 
                    print 'Canceled'
4519
 
                    return 0
 
5297
            self.outf.write(gettext('The above revision(s) will be removed.\n'))
 
5298
 
 
5299
        if not force:
 
5300
            if not ui.ui_factory.confirm_action(
 
5301
                    gettext(u'Uncommit these revisions'),
 
5302
                    'bzrlib.builtins.uncommit',
 
5303
                    {}):
 
5304
                self.outf.write(gettext('Canceled\n'))
 
5305
                return 0
4520
5306
 
4521
5307
        mutter('Uncommitting from {%s} to {%s}',
4522
5308
               last_rev_id, rev_id)
4523
5309
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
4524
 
                 revno=revno, local=local)
4525
 
        note('You can restore the old tip by running:\n'
4526
 
             '  bzr pull . -r revid:%s', last_rev_id)
 
5310
                 revno=revno, local=local, keep_tags=keep_tags)
 
5311
        self.outf.write(gettext('You can restore the old tip by running:\n'
 
5312
             '  bzr pull . -r revid:%s\n') % last_rev_id)
4527
5313
 
4528
5314
 
4529
5315
class cmd_break_lock(Command):
4530
 
    """Break a dead lock on a repository, branch or working directory.
 
5316
    __doc__ = """Break a dead lock.
 
5317
 
 
5318
    This command breaks a lock on a repository, branch, working directory or
 
5319
    config file.
4531
5320
 
4532
5321
    CAUTION: Locks should only be broken when you are sure that the process
4533
5322
    holding the lock has been stopped.
4534
5323
 
4535
 
    You can get information on what locks are open via the 'bzr info' command.
 
5324
    You can get information on what locks are open via the 'bzr info
 
5325
    [location]' command.
4536
5326
 
4537
5327
    :Examples:
4538
5328
        bzr break-lock
 
5329
        bzr break-lock bzr+ssh://example.com/bzr/foo
 
5330
        bzr break-lock --conf ~/.bazaar
4539
5331
    """
 
5332
 
4540
5333
    takes_args = ['location?']
 
5334
    takes_options = [
 
5335
        Option('config',
 
5336
               help='LOCATION is the directory where the config lock is.'),
 
5337
        Option('force',
 
5338
            help='Do not ask for confirmation before breaking the lock.'),
 
5339
        ]
4541
5340
 
4542
 
    def run(self, location=None, show=False):
 
5341
    def run(self, location=None, config=False, force=False):
4543
5342
        if location is None:
4544
5343
            location = u'.'
4545
 
        control, relpath = bzrdir.BzrDir.open_containing(location)
4546
 
        try:
4547
 
            control.break_lock()
4548
 
        except NotImplementedError:
4549
 
            pass
 
5344
        if force:
 
5345
            ui.ui_factory = ui.ConfirmationUserInterfacePolicy(ui.ui_factory,
 
5346
                None,
 
5347
                {'bzrlib.lockdir.break': True})
 
5348
        if config:
 
5349
            conf = _mod_config.LockableConfig(file_name=location)
 
5350
            conf.break_lock()
 
5351
        else:
 
5352
            control, relpath = controldir.ControlDir.open_containing(location)
 
5353
            try:
 
5354
                control.break_lock()
 
5355
            except NotImplementedError:
 
5356
                pass
4550
5357
 
4551
5358
 
4552
5359
class cmd_wait_until_signalled(Command):
4553
 
    """Test helper for test_start_and_stop_bzr_subprocess_send_signal.
 
5360
    __doc__ = """Test helper for test_start_and_stop_bzr_subprocess_send_signal.
4554
5361
 
4555
5362
    This just prints a line to signal when it is ready, then blocks on stdin.
4556
5363
    """
4564
5371
 
4565
5372
 
4566
5373
class cmd_serve(Command):
4567
 
    """Run the bzr server."""
 
5374
    __doc__ = """Run the bzr server."""
4568
5375
 
4569
5376
    aliases = ['server']
4570
5377
 
4571
5378
    takes_options = [
4572
5379
        Option('inet',
4573
5380
               help='Serve on stdin/out for use from inetd or sshd.'),
4574
 
        RegistryOption('protocol', 
4575
 
               help="Protocol to serve.", 
 
5381
        RegistryOption('protocol',
 
5382
               help="Protocol to serve.",
4576
5383
               lazy_registry=('bzrlib.transport', 'transport_server_registry'),
4577
5384
               value_switches=True),
4578
5385
        Option('port',
4581
5388
                    'result in a dynamically allocated port.  The default port '
4582
5389
                    'depends on the protocol.',
4583
5390
               type=str),
4584
 
        Option('directory',
4585
 
               help='Serve contents of this directory.',
4586
 
               type=unicode),
 
5391
        custom_help('directory',
 
5392
               help='Serve contents of this directory.'),
4587
5393
        Option('allow-writes',
4588
5394
               help='By default the server is a readonly server.  Supplying '
4589
5395
                    '--allow-writes enables write access to the contents of '
4590
 
                    'the served directory and below.'
 
5396
                    'the served directory and below.  Note that ``bzr serve`` '
 
5397
                    'does not perform authentication, so unless some form of '
 
5398
                    'external authentication is arranged supplying this '
 
5399
                    'option leads to global uncontrolled write access to your '
 
5400
                    'file system.'
4591
5401
                ),
 
5402
        Option('client-timeout', type=float,
 
5403
               help='Override the default idle client timeout (5min).'),
4592
5404
        ]
4593
5405
 
4594
5406
    def get_host_and_port(self, port):
4611
5423
        return host, port
4612
5424
 
4613
5425
    def run(self, port=None, inet=False, directory=None, allow_writes=False,
4614
 
            protocol=None):
4615
 
        from bzrlib.transport import get_transport, transport_server_registry
 
5426
            protocol=None, client_timeout=None):
 
5427
        from bzrlib import transport
4616
5428
        if directory is None:
4617
5429
            directory = os.getcwd()
4618
5430
        if protocol is None:
4619
 
            protocol = transport_server_registry.get()
 
5431
            protocol = transport.transport_server_registry.get()
4620
5432
        host, port = self.get_host_and_port(port)
4621
 
        url = urlutils.local_path_to_url(directory)
 
5433
        url = transport.location_to_url(directory)
4622
5434
        if not allow_writes:
4623
5435
            url = 'readonly+' + url
4624
 
        transport = get_transport(url)
4625
 
        protocol(transport, host, port, inet)
 
5436
        t = transport.get_transport_from_url(url)
 
5437
        try:
 
5438
            protocol(t, host, port, inet, client_timeout)
 
5439
        except TypeError, e:
 
5440
            # We use symbol_versioning.deprecated_in just so that people
 
5441
            # grepping can find it here.
 
5442
            # symbol_versioning.deprecated_in((2, 5, 0))
 
5443
            symbol_versioning.warn(
 
5444
                'Got TypeError(%s)\ntrying to call protocol: %s.%s\n'
 
5445
                'Most likely it needs to be updated to support a'
 
5446
                ' "timeout" parameter (added in bzr 2.5.0)'
 
5447
                % (e, protocol.__module__, protocol),
 
5448
                DeprecationWarning)
 
5449
            protocol(t, host, port, inet)
4626
5450
 
4627
5451
 
4628
5452
class cmd_join(Command):
4629
 
    """Combine a tree into its containing tree.
 
5453
    __doc__ = """Combine a tree into its containing tree.
4630
5454
 
4631
5455
    This command requires the target tree to be in a rich-root format.
4632
5456
 
4634
5458
    not part of it.  (Such trees can be produced by "bzr split", but also by
4635
5459
    running "bzr branch" with the target inside a tree.)
4636
5460
 
4637
 
    The result is a combined tree, with the subtree no longer an independant
 
5461
    The result is a combined tree, with the subtree no longer an independent
4638
5462
    part.  This is marked as a merge of the subtree into the containing tree,
4639
5463
    and all history is preserved.
4640
5464
    """
4651
5475
        containing_tree = WorkingTree.open_containing(parent_dir)[0]
4652
5476
        repo = containing_tree.branch.repository
4653
5477
        if not repo.supports_rich_root():
4654
 
            raise errors.BzrCommandError(
 
5478
            raise errors.BzrCommandError(gettext(
4655
5479
                "Can't join trees because %s doesn't support rich root data.\n"
4656
 
                "You can use bzr upgrade on the repository."
 
5480
                "You can use bzr upgrade on the repository.")
4657
5481
                % (repo,))
4658
5482
        if reference:
4659
5483
            try:
4661
5485
            except errors.BadReferenceTarget, e:
4662
5486
                # XXX: Would be better to just raise a nicely printable
4663
5487
                # exception from the real origin.  Also below.  mbp 20070306
4664
 
                raise errors.BzrCommandError("Cannot join %s.  %s" %
4665
 
                                             (tree, e.reason))
 
5488
                raise errors.BzrCommandError(
 
5489
                       gettext("Cannot join {0}.  {1}").format(tree, e.reason))
4666
5490
        else:
4667
5491
            try:
4668
5492
                containing_tree.subsume(sub_tree)
4669
5493
            except errors.BadSubsumeSource, e:
4670
 
                raise errors.BzrCommandError("Cannot join %s.  %s" %
4671
 
                                             (tree, e.reason))
 
5494
                raise errors.BzrCommandError(
 
5495
                       gettext("Cannot join {0}.  {1}").format(tree, e.reason))
4672
5496
 
4673
5497
 
4674
5498
class cmd_split(Command):
4675
 
    """Split a subdirectory of a tree into a separate tree.
 
5499
    __doc__ = """Split a subdirectory of a tree into a separate tree.
4676
5500
 
4677
5501
    This command will produce a target tree in a format that supports
4678
5502
    rich roots, like 'rich-root' or 'rich-root-pack'.  These formats cannot be
4698
5522
 
4699
5523
 
4700
5524
class cmd_merge_directive(Command):
4701
 
    """Generate a merge directive for auto-merge tools.
 
5525
    __doc__ = """Generate a merge directive for auto-merge tools.
4702
5526
 
4703
5527
    A directive requests a merge to be performed, and also provides all the
4704
5528
    information necessary to do so.  This means it must either include a
4721
5545
    _see_also = ['send']
4722
5546
 
4723
5547
    takes_options = [
 
5548
        'directory',
4724
5549
        RegistryOption.from_kwargs('patch-type',
4725
5550
            'The type of patch to include in the directive.',
4726
5551
            title='Patch type',
4739
5564
    encoding_type = 'exact'
4740
5565
 
4741
5566
    def run(self, submit_branch=None, public_branch=None, patch_type='bundle',
4742
 
            sign=False, revision=None, mail_to=None, message=None):
 
5567
            sign=False, revision=None, mail_to=None, message=None,
 
5568
            directory=u'.'):
4743
5569
        from bzrlib.revision import ensure_null, NULL_REVISION
4744
5570
        include_patch, include_bundle = {
4745
5571
            'plain': (False, False),
4746
5572
            'diff': (True, False),
4747
5573
            'bundle': (True, True),
4748
5574
            }[patch_type]
4749
 
        branch = Branch.open('.')
 
5575
        branch = Branch.open(directory)
4750
5576
        stored_submit_branch = branch.get_submit_branch()
4751
5577
        if submit_branch is None:
4752
5578
            submit_branch = stored_submit_branch
4756
5582
        if submit_branch is None:
4757
5583
            submit_branch = branch.get_parent()
4758
5584
        if submit_branch is None:
4759
 
            raise errors.BzrCommandError('No submit branch specified or known')
 
5585
            raise errors.BzrCommandError(gettext('No submit branch specified or known'))
4760
5586
 
4761
5587
        stored_public_branch = branch.get_public_branch()
4762
5588
        if public_branch is None:
4764
5590
        elif stored_public_branch is None:
4765
5591
            branch.set_public_branch(public_branch)
4766
5592
        if not include_bundle and public_branch is None:
4767
 
            raise errors.BzrCommandError('No public branch specified or'
4768
 
                                         ' known')
 
5593
            raise errors.BzrCommandError(gettext('No public branch specified or'
 
5594
                                         ' known'))
4769
5595
        base_revision_id = None
4770
5596
        if revision is not None:
4771
5597
            if len(revision) > 2:
4772
 
                raise errors.BzrCommandError('bzr merge-directive takes '
4773
 
                    'at most two one revision identifiers')
 
5598
                raise errors.BzrCommandError(gettext('bzr merge-directive takes '
 
5599
                    'at most two one revision identifiers'))
4774
5600
            revision_id = revision[-1].as_revision_id(branch)
4775
5601
            if len(revision) == 2:
4776
5602
                base_revision_id = revision[0].as_revision_id(branch)
4778
5604
            revision_id = branch.last_revision()
4779
5605
        revision_id = ensure_null(revision_id)
4780
5606
        if revision_id == NULL_REVISION:
4781
 
            raise errors.BzrCommandError('No revisions to bundle.')
 
5607
            raise errors.BzrCommandError(gettext('No revisions to bundle.'))
4782
5608
        directive = merge_directive.MergeDirective2.from_objects(
4783
5609
            branch.repository, revision_id, time.time(),
4784
5610
            osutils.local_time_offset(), submit_branch,
4792
5618
                self.outf.writelines(directive.to_lines())
4793
5619
        else:
4794
5620
            message = directive.to_email(mail_to, branch, sign)
4795
 
            s = SMTPConnection(branch.get_config())
 
5621
            s = SMTPConnection(branch.get_config_stack())
4796
5622
            s.send_email(message)
4797
5623
 
4798
5624
 
4799
5625
class cmd_send(Command):
4800
 
    """Mail or create a merge-directive for submitting changes.
 
5626
    __doc__ = """Mail or create a merge-directive for submitting changes.
4801
5627
 
4802
5628
    A merge directive provides many things needed for requesting merges:
4803
5629
 
4809
5635
      directly from the merge directive, without retrieving data from a
4810
5636
      branch.
4811
5637
 
4812
 
    If --no-bundle is specified, then public_branch is needed (and must be
4813
 
    up-to-date), so that the receiver can perform the merge using the
4814
 
    public_branch.  The public_branch is always included if known, so that
4815
 
    people can check it later.
4816
 
 
4817
 
    The submit branch defaults to the parent, but can be overridden.  Both
4818
 
    submit branch and public branch will be remembered if supplied.
4819
 
 
4820
 
    If a public_branch is known for the submit_branch, that public submit
4821
 
    branch is used in the merge instructions.  This means that a local mirror
4822
 
    can be used as your actual submit branch, once you have set public_branch
4823
 
    for that mirror.
 
5638
    `bzr send` creates a compact data set that, when applied using bzr
 
5639
    merge, has the same effect as merging from the source branch.  
 
5640
    
 
5641
    By default the merge directive is self-contained and can be applied to any
 
5642
    branch containing submit_branch in its ancestory without needing access to
 
5643
    the source branch.
 
5644
    
 
5645
    If --no-bundle is specified, then Bazaar doesn't send the contents of the
 
5646
    revisions, but only a structured request to merge from the
 
5647
    public_location.  In that case the public_branch is needed and it must be
 
5648
    up-to-date and accessible to the recipient.  The public_branch is always
 
5649
    included if known, so that people can check it later.
 
5650
 
 
5651
    The submit branch defaults to the parent of the source branch, but can be
 
5652
    overridden.  Both submit branch and public branch will be remembered in
 
5653
    branch.conf the first time they are used for a particular branch.  The
 
5654
    source branch defaults to that containing the working directory, but can
 
5655
    be changed using --from.
 
5656
 
 
5657
    Both the submit branch and the public branch follow the usual behavior with
 
5658
    respect to --remember: If there is no default location set, the first send
 
5659
    will set it (use --no-remember to avoid setting it). After that, you can
 
5660
    omit the location to use the default.  To change the default, use
 
5661
    --remember. The value will only be saved if the location can be accessed.
 
5662
 
 
5663
    In order to calculate those changes, bzr must analyse the submit branch.
 
5664
    Therefore it is most efficient for the submit branch to be a local mirror.
 
5665
    If a public location is known for the submit_branch, that location is used
 
5666
    in the merge directive.
 
5667
 
 
5668
    The default behaviour is to send the merge directive by mail, unless -o is
 
5669
    given, in which case it is sent to a file.
4824
5670
 
4825
5671
    Mail is sent using your preferred mail program.  This should be transparent
4826
 
    on Windows (it uses MAPI).  On Linux, it requires the xdg-email utility.
 
5672
    on Windows (it uses MAPI).  On Unix, it requires the xdg-email utility.
4827
5673
    If the preferred client can't be found (or used), your editor will be used.
4828
5674
 
4829
5675
    To use a specific mail program, set the mail_client configuration option.
4830
5676
    (For Thunderbird 1.5, this works around some bugs.)  Supported values for
4831
 
    specific clients are "claws", "evolution", "kmail", "mutt", and
4832
 
    "thunderbird"; generic options are "default", "editor", "emacsclient",
4833
 
    "mapi", and "xdg-email".  Plugins may also add supported clients.
 
5677
    specific clients are "claws", "evolution", "kmail", "mail.app" (MacOS X's
 
5678
    Mail.app), "mutt", and "thunderbird"; generic options are "default",
 
5679
    "editor", "emacsclient", "mapi", and "xdg-email".  Plugins may also add
 
5680
    supported clients.
4834
5681
 
4835
5682
    If mail is being sent, a to address is required.  This can be supplied
4836
5683
    either on the commandline, by setting the submit_to configuration
4845
5692
 
4846
5693
    The merge directives created by bzr send may be applied using bzr merge or
4847
5694
    bzr pull by specifying a file containing a merge directive as the location.
 
5695
 
 
5696
    bzr send makes extensive use of public locations to map local locations into
 
5697
    URLs that can be used by other people.  See `bzr help configuration` to
 
5698
    set them, and use `bzr info` to display them.
4848
5699
    """
4849
5700
 
4850
5701
    encoding_type = 'exact'
4866
5717
               short_name='f',
4867
5718
               type=unicode),
4868
5719
        Option('output', short_name='o',
4869
 
               help='Write merge directive to this file; '
 
5720
               help='Write merge directive to this file or directory; '
4870
5721
                    'use - for stdout.',
4871
5722
               type=unicode),
 
5723
        Option('strict',
 
5724
               help='Refuse to send if there are uncommitted changes in'
 
5725
               ' the working tree, --no-strict disables the check.'),
4872
5726
        Option('mail-to', help='Mail the request to this address.',
4873
5727
               type=unicode),
4874
5728
        'revision',
4875
5729
        'message',
4876
5730
        Option('body', help='Body for the email.', type=unicode),
4877
5731
        RegistryOption('format',
4878
 
                       help='Use the specified output format.', 
4879
 
                       lazy_registry=('bzrlib.send', 'format_registry'))
 
5732
                       help='Use the specified output format.',
 
5733
                       lazy_registry=('bzrlib.send', 'format_registry')),
4880
5734
        ]
4881
5735
 
4882
5736
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4883
 
            no_patch=False, revision=None, remember=False, output=None,
4884
 
            format=None, mail_to=None, message=None, body=None, **kwargs):
 
5737
            no_patch=False, revision=None, remember=None, output=None,
 
5738
            format=None, mail_to=None, message=None, body=None,
 
5739
            strict=None, **kwargs):
4885
5740
        from bzrlib.send import send
4886
5741
        return send(submit_branch, revision, public_branch, remember,
4887
 
                         format, no_bundle, no_patch, output,
4888
 
                         kwargs.get('from', '.'), mail_to, message, body,
4889
 
                         self.outf)
 
5742
                    format, no_bundle, no_patch, output,
 
5743
                    kwargs.get('from', '.'), mail_to, message, body,
 
5744
                    self.outf,
 
5745
                    strict=strict)
4890
5746
 
4891
5747
 
4892
5748
class cmd_bundle_revisions(cmd_send):
4893
 
    """Create a merge-directive for submitting changes.
 
5749
    __doc__ = """Create a merge-directive for submitting changes.
4894
5750
 
4895
5751
    A merge directive provides many things needed for requesting merges:
4896
5752
 
4936
5792
               type=unicode),
4937
5793
        Option('output', short_name='o', help='Write directive to this file.',
4938
5794
               type=unicode),
 
5795
        Option('strict',
 
5796
               help='Refuse to bundle revisions if there are uncommitted'
 
5797
               ' changes in the working tree, --no-strict disables the check.'),
4939
5798
        'revision',
4940
5799
        RegistryOption('format',
4941
5800
                       help='Use the specified output format.',
4949
5808
 
4950
5809
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
4951
5810
            no_patch=False, revision=None, remember=False, output=None,
4952
 
            format=None, **kwargs):
 
5811
            format=None, strict=None, **kwargs):
4953
5812
        if output is None:
4954
5813
            output = '-'
4955
5814
        from bzrlib.send import send
4956
5815
        return send(submit_branch, revision, public_branch, remember,
4957
5816
                         format, no_bundle, no_patch, output,
4958
5817
                         kwargs.get('from', '.'), None, None, None,
4959
 
                         self.outf)
 
5818
                         self.outf, strict=strict)
4960
5819
 
4961
5820
 
4962
5821
class cmd_tag(Command):
4963
 
    """Create, remove or modify a tag naming a revision.
 
5822
    __doc__ = """Create, remove or modify a tag naming a revision.
4964
5823
 
4965
5824
    Tags give human-meaningful names to revisions.  Commands that take a -r
4966
5825
    (--revision) option can be given -rtag:X, where X is any previously
4974
5833
 
4975
5834
    To rename a tag (change the name but keep it on the same revsion), run ``bzr
4976
5835
    tag new-name -r tag:old-name`` and then ``bzr tag --delete oldname``.
 
5836
 
 
5837
    If no tag name is specified it will be determined through the 
 
5838
    'automatic_tag_name' hook. This can e.g. be used to automatically tag
 
5839
    upstream releases by reading configure.ac. See ``bzr help hooks`` for
 
5840
    details.
4977
5841
    """
4978
5842
 
4979
5843
    _see_also = ['commit', 'tags']
4980
 
    takes_args = ['tag_name']
 
5844
    takes_args = ['tag_name?']
4981
5845
    takes_options = [
4982
5846
        Option('delete',
4983
5847
            help='Delete this tag rather than placing it.',
4984
5848
            ),
4985
 
        Option('directory',
4986
 
            help='Branch in which to place the tag.',
4987
 
            short_name='d',
4988
 
            type=unicode,
4989
 
            ),
 
5849
        custom_help('directory',
 
5850
            help='Branch in which to place the tag.'),
4990
5851
        Option('force',
4991
5852
            help='Replace existing tags.',
4992
5853
            ),
4993
5854
        'revision',
4994
5855
        ]
4995
5856
 
4996
 
    def run(self, tag_name,
 
5857
    def run(self, tag_name=None,
4997
5858
            delete=None,
4998
5859
            directory='.',
4999
5860
            force=None,
5000
5861
            revision=None,
5001
5862
            ):
5002
5863
        branch, relpath = Branch.open_containing(directory)
5003
 
        branch.lock_write()
5004
 
        try:
5005
 
            if delete:
5006
 
                branch.tags.delete_tag(tag_name)
5007
 
                self.outf.write('Deleted tag %s.\n' % tag_name)
5008
 
            else:
5009
 
                if revision:
5010
 
                    if len(revision) != 1:
5011
 
                        raise errors.BzrCommandError(
5012
 
                            "Tags can only be placed on a single revision, "
5013
 
                            "not on a range")
5014
 
                    revision_id = revision[0].as_revision_id(branch)
5015
 
                else:
5016
 
                    revision_id = branch.last_revision()
5017
 
                if (not force) and branch.tags.has_tag(tag_name):
5018
 
                    raise errors.TagAlreadyExists(tag_name)
 
5864
        self.add_cleanup(branch.lock_write().unlock)
 
5865
        if delete:
 
5866
            if tag_name is None:
 
5867
                raise errors.BzrCommandError(gettext("No tag specified to delete."))
 
5868
            branch.tags.delete_tag(tag_name)
 
5869
            note(gettext('Deleted tag %s.') % tag_name)
 
5870
        else:
 
5871
            if revision:
 
5872
                if len(revision) != 1:
 
5873
                    raise errors.BzrCommandError(gettext(
 
5874
                        "Tags can only be placed on a single revision, "
 
5875
                        "not on a range"))
 
5876
                revision_id = revision[0].as_revision_id(branch)
 
5877
            else:
 
5878
                revision_id = branch.last_revision()
 
5879
            if tag_name is None:
 
5880
                tag_name = branch.automatic_tag_name(revision_id)
 
5881
                if tag_name is None:
 
5882
                    raise errors.BzrCommandError(gettext(
 
5883
                        "Please specify a tag name."))
 
5884
            try:
 
5885
                existing_target = branch.tags.lookup_tag(tag_name)
 
5886
            except errors.NoSuchTag:
 
5887
                existing_target = None
 
5888
            if not force and existing_target not in (None, revision_id):
 
5889
                raise errors.TagAlreadyExists(tag_name)
 
5890
            if existing_target == revision_id:
 
5891
                note(gettext('Tag %s already exists for that revision.') % tag_name)
 
5892
            else:
5019
5893
                branch.tags.set_tag(tag_name, revision_id)
5020
 
                self.outf.write('Created tag %s.\n' % tag_name)
5021
 
        finally:
5022
 
            branch.unlock()
 
5894
                if existing_target is None:
 
5895
                    note(gettext('Created tag %s.') % tag_name)
 
5896
                else:
 
5897
                    note(gettext('Updated tag %s.') % tag_name)
5023
5898
 
5024
5899
 
5025
5900
class cmd_tags(Command):
5026
 
    """List tags.
 
5901
    __doc__ = """List tags.
5027
5902
 
5028
5903
    This command shows a table of tag names and the revisions they reference.
5029
5904
    """
5030
5905
 
5031
5906
    _see_also = ['tag']
5032
5907
    takes_options = [
5033
 
        Option('directory',
5034
 
            help='Branch whose tags should be displayed.',
5035
 
            short_name='d',
5036
 
            type=unicode,
5037
 
            ),
5038
 
        RegistryOption.from_kwargs('sort',
 
5908
        custom_help('directory',
 
5909
            help='Branch whose tags should be displayed.'),
 
5910
        RegistryOption('sort',
5039
5911
            'Sort tags by different criteria.', title='Sorting',
5040
 
            alpha='Sort tags lexicographically (default).',
5041
 
            time='Sort tags chronologically.',
 
5912
            lazy_registry=('bzrlib.tag', 'tag_sort_methods')
5042
5913
            ),
5043
5914
        'show-ids',
5044
5915
        'revision',
5045
5916
    ]
5046
5917
 
5047
5918
    @display_command
5048
 
    def run(self,
5049
 
            directory='.',
5050
 
            sort='alpha',
5051
 
            show_ids=False,
5052
 
            revision=None,
5053
 
            ):
 
5919
    def run(self, directory='.', sort=None, show_ids=False, revision=None):
 
5920
        from bzrlib.tag import tag_sort_methods
5054
5921
        branch, relpath = Branch.open_containing(directory)
5055
5922
 
5056
5923
        tags = branch.tags.get_tag_dict().items()
5057
5924
        if not tags:
5058
5925
            return
5059
5926
 
5060
 
        branch.lock_read()
5061
 
        try:
5062
 
            if revision:
5063
 
                graph = branch.repository.get_graph()
5064
 
                rev1, rev2 = _get_revision_range(revision, branch, self.name())
5065
 
                revid1, revid2 = rev1.rev_id, rev2.rev_id
5066
 
                # only show revisions between revid1 and revid2 (inclusive)
5067
 
                tags = [(tag, revid) for tag, revid in tags if
5068
 
                    graph.is_between(revid, revid1, revid2)]
5069
 
            if sort == 'alpha':
5070
 
                tags.sort()
5071
 
            elif sort == 'time':
5072
 
                timestamps = {}
5073
 
                for tag, revid in tags:
5074
 
                    try:
5075
 
                        revobj = branch.repository.get_revision(revid)
5076
 
                    except errors.NoSuchRevision:
5077
 
                        timestamp = sys.maxint # place them at the end
5078
 
                    else:
5079
 
                        timestamp = revobj.timestamp
5080
 
                    timestamps[revid] = timestamp
5081
 
                tags.sort(key=lambda x: timestamps[x[1]])
5082
 
            if not show_ids:
5083
 
                # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
5084
 
                for index, (tag, revid) in enumerate(tags):
5085
 
                    try:
5086
 
                        revno = branch.revision_id_to_dotted_revno(revid)
5087
 
                        if isinstance(revno, tuple):
5088
 
                            revno = '.'.join(map(str, revno))
5089
 
                    except errors.NoSuchRevision:
5090
 
                        # Bad tag data/merges can lead to tagged revisions
5091
 
                        # which are not in this branch. Fail gracefully ...
5092
 
                        revno = '?'
5093
 
                    tags[index] = (tag, revno)
5094
 
        finally:
5095
 
            branch.unlock()
 
5927
        self.add_cleanup(branch.lock_read().unlock)
 
5928
        if revision:
 
5929
            # Restrict to the specified range
 
5930
            tags = self._tags_for_range(branch, revision)
 
5931
        if sort is None:
 
5932
            sort = tag_sort_methods.get()
 
5933
        sort(branch, tags)
 
5934
        if not show_ids:
 
5935
            # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
 
5936
            for index, (tag, revid) in enumerate(tags):
 
5937
                try:
 
5938
                    revno = branch.revision_id_to_dotted_revno(revid)
 
5939
                    if isinstance(revno, tuple):
 
5940
                        revno = '.'.join(map(str, revno))
 
5941
                except (errors.NoSuchRevision,
 
5942
                        errors.GhostRevisionsHaveNoRevno,
 
5943
                        errors.UnsupportedOperation):
 
5944
                    # Bad tag data/merges can lead to tagged revisions
 
5945
                    # which are not in this branch. Fail gracefully ...
 
5946
                    revno = '?'
 
5947
                tags[index] = (tag, revno)
 
5948
        self.cleanup_now()
5096
5949
        for tag, revspec in tags:
5097
5950
            self.outf.write('%-20s %s\n' % (tag, revspec))
5098
5951
 
 
5952
    def _tags_for_range(self, branch, revision):
 
5953
        range_valid = True
 
5954
        rev1, rev2 = _get_revision_range(revision, branch, self.name())
 
5955
        revid1, revid2 = rev1.rev_id, rev2.rev_id
 
5956
        # _get_revision_range will always set revid2 if it's not specified.
 
5957
        # If revid1 is None, it means we want to start from the branch
 
5958
        # origin which is always a valid ancestor. If revid1 == revid2, the
 
5959
        # ancestry check is useless.
 
5960
        if revid1 and revid1 != revid2:
 
5961
            # FIXME: We really want to use the same graph than
 
5962
            # branch.iter_merge_sorted_revisions below, but this is not
 
5963
            # easily available -- vila 2011-09-23
 
5964
            if branch.repository.get_graph().is_ancestor(revid2, revid1):
 
5965
                # We don't want to output anything in this case...
 
5966
                return []
 
5967
        # only show revisions between revid1 and revid2 (inclusive)
 
5968
        tagged_revids = branch.tags.get_reverse_tag_dict()
 
5969
        found = []
 
5970
        for r in branch.iter_merge_sorted_revisions(
 
5971
            start_revision_id=revid2, stop_revision_id=revid1,
 
5972
            stop_rule='include'):
 
5973
            revid_tags = tagged_revids.get(r[0], None)
 
5974
            if revid_tags:
 
5975
                found.extend([(tag, r[0]) for tag in revid_tags])
 
5976
        return found
 
5977
 
5099
5978
 
5100
5979
class cmd_reconfigure(Command):
5101
 
    """Reconfigure the type of a bzr directory.
 
5980
    __doc__ = """Reconfigure the type of a bzr directory.
5102
5981
 
5103
5982
    A target configuration must be specified.
5104
5983
 
5115
5994
    takes_args = ['location?']
5116
5995
    takes_options = [
5117
5996
        RegistryOption.from_kwargs(
5118
 
            'target_type',
5119
 
            title='Target type',
5120
 
            help='The type to reconfigure the directory to.',
 
5997
            'tree_type',
 
5998
            title='Tree type',
 
5999
            help='The relation between branch and tree.',
5121
6000
            value_switches=True, enum_switch=False,
5122
6001
            branch='Reconfigure to be an unbound branch with no working tree.',
5123
6002
            tree='Reconfigure to be an unbound branch with a working tree.',
5124
6003
            checkout='Reconfigure to be a bound branch with a working tree.',
5125
6004
            lightweight_checkout='Reconfigure to be a lightweight'
5126
6005
                ' checkout (with no local history).',
 
6006
            ),
 
6007
        RegistryOption.from_kwargs(
 
6008
            'repository_type',
 
6009
            title='Repository type',
 
6010
            help='Location fo the repository.',
 
6011
            value_switches=True, enum_switch=False,
5127
6012
            standalone='Reconfigure to be a standalone branch '
5128
6013
                '(i.e. stop using shared repository).',
5129
6014
            use_shared='Reconfigure to use a shared repository.',
 
6015
            ),
 
6016
        RegistryOption.from_kwargs(
 
6017
            'repository_trees',
 
6018
            title='Trees in Repository',
 
6019
            help='Whether new branches in the repository have trees.',
 
6020
            value_switches=True, enum_switch=False,
5130
6021
            with_trees='Reconfigure repository to create '
5131
6022
                'working trees on branches by default.',
5132
6023
            with_no_trees='Reconfigure repository to not create '
5134
6025
            ),
5135
6026
        Option('bind-to', help='Branch to bind checkout to.', type=str),
5136
6027
        Option('force',
5137
 
               help='Perform reconfiguration even if local changes'
5138
 
               ' will be lost.')
 
6028
            help='Perform reconfiguration even if local changes'
 
6029
            ' will be lost.'),
 
6030
        Option('stacked-on',
 
6031
            help='Reconfigure a branch to be stacked on another branch.',
 
6032
            type=unicode,
 
6033
            ),
 
6034
        Option('unstacked',
 
6035
            help='Reconfigure a branch to be unstacked.  This '
 
6036
                'may require copying substantial data into it.',
 
6037
            ),
5139
6038
        ]
5140
6039
 
5141
 
    def run(self, location=None, target_type=None, bind_to=None, force=False):
5142
 
        directory = bzrdir.BzrDir.open(location)
5143
 
        if target_type is None:
5144
 
            raise errors.BzrCommandError('No target configuration specified')
5145
 
        elif target_type == 'branch':
 
6040
    def run(self, location=None, bind_to=None, force=False,
 
6041
            tree_type=None, repository_type=None, repository_trees=None,
 
6042
            stacked_on=None, unstacked=None):
 
6043
        directory = controldir.ControlDir.open(location)
 
6044
        if stacked_on and unstacked:
 
6045
            raise errors.BzrCommandError(gettext("Can't use both --stacked-on and --unstacked"))
 
6046
        elif stacked_on is not None:
 
6047
            reconfigure.ReconfigureStackedOn().apply(directory, stacked_on)
 
6048
        elif unstacked:
 
6049
            reconfigure.ReconfigureUnstacked().apply(directory)
 
6050
        # At the moment you can use --stacked-on and a different
 
6051
        # reconfiguration shape at the same time; there seems no good reason
 
6052
        # to ban it.
 
6053
        if (tree_type is None and
 
6054
            repository_type is None and
 
6055
            repository_trees is None):
 
6056
            if stacked_on or unstacked:
 
6057
                return
 
6058
            else:
 
6059
                raise errors.BzrCommandError(gettext('No target configuration '
 
6060
                    'specified'))
 
6061
        reconfiguration = None
 
6062
        if tree_type == 'branch':
5146
6063
            reconfiguration = reconfigure.Reconfigure.to_branch(directory)
5147
 
        elif target_type == 'tree':
 
6064
        elif tree_type == 'tree':
5148
6065
            reconfiguration = reconfigure.Reconfigure.to_tree(directory)
5149
 
        elif target_type == 'checkout':
 
6066
        elif tree_type == 'checkout':
5150
6067
            reconfiguration = reconfigure.Reconfigure.to_checkout(
5151
6068
                directory, bind_to)
5152
 
        elif target_type == 'lightweight-checkout':
 
6069
        elif tree_type == 'lightweight-checkout':
5153
6070
            reconfiguration = reconfigure.Reconfigure.to_lightweight_checkout(
5154
6071
                directory, bind_to)
5155
 
        elif target_type == 'use-shared':
 
6072
        if reconfiguration:
 
6073
            reconfiguration.apply(force)
 
6074
            reconfiguration = None
 
6075
        if repository_type == 'use-shared':
5156
6076
            reconfiguration = reconfigure.Reconfigure.to_use_shared(directory)
5157
 
        elif target_type == 'standalone':
 
6077
        elif repository_type == 'standalone':
5158
6078
            reconfiguration = reconfigure.Reconfigure.to_standalone(directory)
5159
 
        elif target_type == 'with-trees':
 
6079
        if reconfiguration:
 
6080
            reconfiguration.apply(force)
 
6081
            reconfiguration = None
 
6082
        if repository_trees == 'with-trees':
5160
6083
            reconfiguration = reconfigure.Reconfigure.set_repository_trees(
5161
6084
                directory, True)
5162
 
        elif target_type == 'with-no-trees':
 
6085
        elif repository_trees == 'with-no-trees':
5163
6086
            reconfiguration = reconfigure.Reconfigure.set_repository_trees(
5164
6087
                directory, False)
5165
 
        reconfiguration.apply(force)
 
6088
        if reconfiguration:
 
6089
            reconfiguration.apply(force)
 
6090
            reconfiguration = None
5166
6091
 
5167
6092
 
5168
6093
class cmd_switch(Command):
5169
 
    """Set the branch of a checkout and update.
 
6094
    __doc__ = """Set the branch of a checkout and update.
5170
6095
 
5171
6096
    For lightweight checkouts, this changes the branch being referenced.
5172
6097
    For heavyweight checkouts, this checks that there are no local commits
5184
6109
    /path/to/newbranch.
5185
6110
 
5186
6111
    Bound branches use the nickname of its master branch unless it is set
5187
 
    locally, in which case switching will update the the local nickname to be
 
6112
    locally, in which case switching will update the local nickname to be
5188
6113
    that of the master.
5189
6114
    """
5190
6115
 
5191
 
    takes_args = ['to_location']
5192
 
    takes_options = [Option('force',
5193
 
                        help='Switch even if local commits will be lost.')
5194
 
                     ]
 
6116
    takes_args = ['to_location?']
 
6117
    takes_options = ['directory',
 
6118
                     Option('force',
 
6119
                        help='Switch even if local commits will be lost.'),
 
6120
                     'revision',
 
6121
                     Option('create-branch', short_name='b',
 
6122
                        help='Create the target branch from this one before'
 
6123
                             ' switching to it.'),
 
6124
                    ]
5195
6125
 
5196
 
    def run(self, to_location, force=False):
 
6126
    def run(self, to_location=None, force=False, create_branch=False,
 
6127
            revision=None, directory=u'.'):
5197
6128
        from bzrlib import switch
5198
 
        tree_location = '.'
5199
 
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
 
6129
        tree_location = directory
 
6130
        revision = _get_one_revision('switch', revision)
 
6131
        control_dir = controldir.ControlDir.open_containing(tree_location)[0]
 
6132
        if to_location is None:
 
6133
            if revision is None:
 
6134
                raise errors.BzrCommandError(gettext('You must supply either a'
 
6135
                                             ' revision or a location'))
 
6136
            to_location = tree_location
5200
6137
        try:
5201
6138
            branch = control_dir.open_branch()
5202
6139
            had_explicit_nick = branch.get_config().has_explicit_nickname()
5203
6140
        except errors.NotBranchError:
 
6141
            branch = None
5204
6142
            had_explicit_nick = False
5205
 
        try:
5206
 
            to_branch = Branch.open(to_location)
5207
 
        except errors.NotBranchError:
5208
 
            this_url = self._get_branch_location(control_dir)
5209
 
            to_branch = Branch.open(
5210
 
                urlutils.join(this_url, '..', to_location))
5211
 
        switch.switch(control_dir, to_branch, force)
 
6143
        if create_branch:
 
6144
            if branch is None:
 
6145
                raise errors.BzrCommandError(gettext('cannot create branch without'
 
6146
                                             ' source branch'))
 
6147
            to_location = directory_service.directories.dereference(
 
6148
                              to_location)
 
6149
            if '/' not in to_location and '\\' not in to_location:
 
6150
                # This path is meant to be relative to the existing branch
 
6151
                this_url = self._get_branch_location(control_dir)
 
6152
                # Perhaps the target control dir supports colocated branches?
 
6153
                try:
 
6154
                    root = controldir.ControlDir.open(this_url,
 
6155
                        possible_transports=[control_dir.user_transport])
 
6156
                except errors.NotBranchError:
 
6157
                    colocated = False
 
6158
                else:
 
6159
                    colocated = root._format.colocated_branches
 
6160
                if colocated:
 
6161
                    to_location = urlutils.join_segment_parameters(this_url,
 
6162
                        {"branch": urlutils.escape(to_location)})
 
6163
                else:
 
6164
                    to_location = urlutils.join(
 
6165
                        this_url, '..', urlutils.escape(to_location))
 
6166
            to_branch = branch.bzrdir.sprout(to_location,
 
6167
                                 possible_transports=[branch.bzrdir.root_transport],
 
6168
                                 source_branch=branch).open_branch()
 
6169
        else:
 
6170
            # Perhaps it's a colocated branch?
 
6171
            try:
 
6172
                to_branch = control_dir.open_branch(to_location)
 
6173
            except (errors.NotBranchError, errors.NoColocatedBranchSupport):
 
6174
                try:
 
6175
                    to_branch = Branch.open(to_location)
 
6176
                except errors.NotBranchError:
 
6177
                    this_url = self._get_branch_location(control_dir)
 
6178
                    to_branch = Branch.open(
 
6179
                        urlutils.join(
 
6180
                            this_url, '..', urlutils.escape(to_location)))
 
6181
        if revision is not None:
 
6182
            revision = revision.as_revision_id(to_branch)
 
6183
        switch.switch(control_dir, to_branch, force, revision_id=revision)
5212
6184
        if had_explicit_nick:
5213
6185
            branch = control_dir.open_branch() #get the new branch!
5214
6186
            branch.nick = to_branch.nick
5215
 
        note('Switched to branch: %s',
 
6187
        note(gettext('Switched to branch: %s'),
5216
6188
            urlutils.unescape_for_display(to_branch.base, 'utf-8'))
5217
6189
 
5218
6190
    def _get_branch_location(self, control_dir):
5234
6206
 
5235
6207
 
5236
6208
class cmd_view(Command):
5237
 
    """Manage filtered views.
 
6209
    __doc__ = """Manage filtered views.
5238
6210
 
5239
6211
    Views provide a mask over the tree so that users can focus on
5240
6212
    a subset of a tree when doing their work. After creating a view,
5320
6292
            name=None,
5321
6293
            switch=None,
5322
6294
            ):
5323
 
        tree, file_list = tree_files(file_list, apply_view=False)
 
6295
        tree, file_list = WorkingTree.open_containing_paths(file_list,
 
6296
            apply_view=False)
5324
6297
        current_view, view_dict = tree.views.get_view_info()
5325
6298
        if name is None:
5326
6299
            name = current_view
5327
6300
        if delete:
5328
6301
            if file_list:
5329
 
                raise errors.BzrCommandError(
5330
 
                    "Both --delete and a file list specified")
 
6302
                raise errors.BzrCommandError(gettext(
 
6303
                    "Both --delete and a file list specified"))
5331
6304
            elif switch:
5332
 
                raise errors.BzrCommandError(
5333
 
                    "Both --delete and --switch specified")
 
6305
                raise errors.BzrCommandError(gettext(
 
6306
                    "Both --delete and --switch specified"))
5334
6307
            elif all:
5335
6308
                tree.views.set_view_info(None, {})
5336
 
                self.outf.write("Deleted all views.\n")
 
6309
                self.outf.write(gettext("Deleted all views.\n"))
5337
6310
            elif name is None:
5338
 
                raise errors.BzrCommandError("No current view to delete")
 
6311
                raise errors.BzrCommandError(gettext("No current view to delete"))
5339
6312
            else:
5340
6313
                tree.views.delete_view(name)
5341
 
                self.outf.write("Deleted '%s' view.\n" % name)
 
6314
                self.outf.write(gettext("Deleted '%s' view.\n") % name)
5342
6315
        elif switch:
5343
6316
            if file_list:
5344
 
                raise errors.BzrCommandError(
5345
 
                    "Both --switch and a file list specified")
 
6317
                raise errors.BzrCommandError(gettext(
 
6318
                    "Both --switch and a file list specified"))
5346
6319
            elif all:
5347
 
                raise errors.BzrCommandError(
5348
 
                    "Both --switch and --all specified")
 
6320
                raise errors.BzrCommandError(gettext(
 
6321
                    "Both --switch and --all specified"))
5349
6322
            elif switch == 'off':
5350
6323
                if current_view is None:
5351
 
                    raise errors.BzrCommandError("No current view to disable")
 
6324
                    raise errors.BzrCommandError(gettext("No current view to disable"))
5352
6325
                tree.views.set_view_info(None, view_dict)
5353
 
                self.outf.write("Disabled '%s' view.\n" % (current_view))
 
6326
                self.outf.write(gettext("Disabled '%s' view.\n") % (current_view))
5354
6327
            else:
5355
6328
                tree.views.set_view_info(switch, view_dict)
5356
6329
                view_str = views.view_display_str(tree.views.lookup_view())
5357
 
                self.outf.write("Using '%s' view: %s\n" % (switch, view_str))
 
6330
                self.outf.write(gettext("Using '{0}' view: {1}\n").format(switch, view_str))
5358
6331
        elif all:
5359
6332
            if view_dict:
5360
 
                self.outf.write('Views defined:\n')
 
6333
                self.outf.write(gettext('Views defined:\n'))
5361
6334
                for view in sorted(view_dict):
5362
6335
                    if view == current_view:
5363
6336
                        active = "=>"
5366
6339
                    view_str = views.view_display_str(view_dict[view])
5367
6340
                    self.outf.write('%s %-20s %s\n' % (active, view, view_str))
5368
6341
            else:
5369
 
                self.outf.write('No views defined.\n')
 
6342
                self.outf.write(gettext('No views defined.\n'))
5370
6343
        elif file_list:
5371
6344
            if name is None:
5372
6345
                # No name given and no current view set
5373
6346
                name = 'my'
5374
6347
            elif name == 'off':
5375
 
                raise errors.BzrCommandError(
5376
 
                    "Cannot change the 'off' pseudo view")
 
6348
                raise errors.BzrCommandError(gettext(
 
6349
                    "Cannot change the 'off' pseudo view"))
5377
6350
            tree.views.set_view(name, sorted(file_list))
5378
6351
            view_str = views.view_display_str(tree.views.lookup_view())
5379
 
            self.outf.write("Using '%s' view: %s\n" % (name, view_str))
 
6352
            self.outf.write(gettext("Using '{0}' view: {1}\n").format(name, view_str))
5380
6353
        else:
5381
6354
            # list the files
5382
6355
            if name is None:
5383
6356
                # No name given and no current view set
5384
 
                self.outf.write('No current view.\n')
 
6357
                self.outf.write(gettext('No current view.\n'))
5385
6358
            else:
5386
6359
                view_str = views.view_display_str(tree.views.lookup_view(name))
5387
 
                self.outf.write("'%s' view is: %s\n" % (name, view_str))
 
6360
                self.outf.write(gettext("'{0}' view is: {1}\n").format(name, view_str))
5388
6361
 
5389
6362
 
5390
6363
class cmd_hooks(Command):
5391
 
    """Show hooks."""
 
6364
    __doc__ = """Show hooks."""
5392
6365
 
5393
6366
    hidden = True
5394
6367
 
5404
6377
                        self.outf.write("    %s\n" %
5405
6378
                                        (some_hooks.get_hook_name(hook),))
5406
6379
                else:
5407
 
                    self.outf.write("    <no hooks installed>\n")
 
6380
                    self.outf.write(gettext("    <no hooks installed>\n"))
 
6381
 
 
6382
 
 
6383
class cmd_remove_branch(Command):
 
6384
    __doc__ = """Remove a branch.
 
6385
 
 
6386
    This will remove the branch from the specified location but 
 
6387
    will keep any working tree or repository in place.
 
6388
 
 
6389
    :Examples:
 
6390
 
 
6391
      Remove the branch at repo/trunk::
 
6392
 
 
6393
        bzr remove-branch repo/trunk
 
6394
 
 
6395
    """
 
6396
 
 
6397
    takes_args = ["location?"]
 
6398
 
 
6399
    aliases = ["rmbranch"]
 
6400
 
 
6401
    def run(self, location=None):
 
6402
        if location is None:
 
6403
            location = "."
 
6404
        branch = Branch.open_containing(location)[0]
 
6405
        branch.bzrdir.destroy_branch()
5408
6406
 
5409
6407
 
5410
6408
class cmd_shelve(Command):
5411
 
    """Temporarily set aside some changes from the current tree.
 
6409
    __doc__ = """Temporarily set aside some changes from the current tree.
5412
6410
 
5413
6411
    Shelve allows you to temporarily put changes you've made "on the shelf",
5414
6412
    ie. out of the way, until a later time when you can bring them back from
5430
6428
 
5431
6429
    You can put multiple items on the shelf, and by default, 'unshelve' will
5432
6430
    restore the most recently shelved changes.
 
6431
 
 
6432
    For complicated changes, it is possible to edit the changes in a separate
 
6433
    editor program to decide what the file remaining in the working copy
 
6434
    should look like.  To do this, add the configuration option
 
6435
 
 
6436
        change_editor = PROGRAM @new_path @old_path
 
6437
 
 
6438
    where @new_path is replaced with the path of the new version of the 
 
6439
    file and @old_path is replaced with the path of the old version of 
 
6440
    the file.  The PROGRAM should save the new file with the desired 
 
6441
    contents of the file in the working tree.
 
6442
        
5433
6443
    """
5434
6444
 
5435
6445
    takes_args = ['file*']
5436
6446
 
5437
6447
    takes_options = [
 
6448
        'directory',
5438
6449
        'revision',
5439
6450
        Option('all', help='Shelve all changes.'),
5440
6451
        'message',
5446
6457
        Option('destroy',
5447
6458
               help='Destroy removed changes instead of shelving them.'),
5448
6459
    ]
5449
 
    _see_also = ['unshelve']
 
6460
    _see_also = ['unshelve', 'configuration']
5450
6461
 
5451
6462
    def run(self, revision=None, all=False, file_list=None, message=None,
5452
 
            writer=None, list=False, destroy=False):
 
6463
            writer=None, list=False, destroy=False, directory=None):
5453
6464
        if list:
5454
 
            return self.run_for_list()
 
6465
            return self.run_for_list(directory=directory)
5455
6466
        from bzrlib.shelf_ui import Shelver
5456
6467
        if writer is None:
5457
6468
            writer = bzrlib.option.diff_writer_registry.get()
5458
6469
        try:
5459
 
            Shelver.from_args(writer(sys.stdout), revision, all, file_list,
5460
 
                              message, destroy=destroy).run()
 
6470
            shelver = Shelver.from_args(writer(sys.stdout), revision, all,
 
6471
                file_list, message, destroy=destroy, directory=directory)
 
6472
            try:
 
6473
                shelver.run()
 
6474
            finally:
 
6475
                shelver.finalize()
5461
6476
        except errors.UserAbort:
5462
6477
            return 0
5463
6478
 
5464
 
    def run_for_list(self):
5465
 
        tree = WorkingTree.open_containing('.')[0]
5466
 
        tree.lock_read()
5467
 
        try:
5468
 
            manager = tree.get_shelf_manager()
5469
 
            shelves = manager.active_shelves()
5470
 
            if len(shelves) == 0:
5471
 
                note('No shelved changes.')
5472
 
                return 0
5473
 
            for shelf_id in reversed(shelves):
5474
 
                message = manager.get_metadata(shelf_id).get('message')
5475
 
                if message is None:
5476
 
                    message = '<no message>'
5477
 
                self.outf.write('%3d: %s\n' % (shelf_id, message))
5478
 
            return 1
5479
 
        finally:
5480
 
            tree.unlock()
 
6479
    def run_for_list(self, directory=None):
 
6480
        if directory is None:
 
6481
            directory = u'.'
 
6482
        tree = WorkingTree.open_containing(directory)[0]
 
6483
        self.add_cleanup(tree.lock_read().unlock)
 
6484
        manager = tree.get_shelf_manager()
 
6485
        shelves = manager.active_shelves()
 
6486
        if len(shelves) == 0:
 
6487
            note(gettext('No shelved changes.'))
 
6488
            return 0
 
6489
        for shelf_id in reversed(shelves):
 
6490
            message = manager.get_metadata(shelf_id).get('message')
 
6491
            if message is None:
 
6492
                message = '<no message>'
 
6493
            self.outf.write('%3d: %s\n' % (shelf_id, message))
 
6494
        return 1
5481
6495
 
5482
6496
 
5483
6497
class cmd_unshelve(Command):
5484
 
    """Restore shelved changes.
 
6498
    __doc__ = """Restore shelved changes.
5485
6499
 
5486
6500
    By default, the most recently shelved changes are restored. However if you
5487
6501
    specify a shelf by id those changes will be restored instead.  This works
5490
6504
 
5491
6505
    takes_args = ['shelf_id?']
5492
6506
    takes_options = [
 
6507
        'directory',
5493
6508
        RegistryOption.from_kwargs(
5494
6509
            'action', help="The action to perform.",
5495
6510
            enum_switch=False, value_switches=True,
5496
6511
            apply="Apply changes and remove from the shelf.",
5497
6512
            dry_run="Show changes, but do not apply or remove them.",
5498
 
            delete_only="Delete changes without applying them."
 
6513
            preview="Instead of unshelving the changes, show the diff that "
 
6514
                    "would result from unshelving.",
 
6515
            delete_only="Delete changes without applying them.",
 
6516
            keep="Apply changes but don't delete them.",
5499
6517
        )
5500
6518
    ]
5501
6519
    _see_also = ['shelve']
5502
6520
 
5503
 
    def run(self, shelf_id=None, action='apply'):
 
6521
    def run(self, shelf_id=None, action='apply', directory=u'.'):
5504
6522
        from bzrlib.shelf_ui import Unshelver
5505
 
        Unshelver.from_args(shelf_id, action).run()
 
6523
        unshelver = Unshelver.from_args(shelf_id, action, directory=directory)
 
6524
        try:
 
6525
            unshelver.run()
 
6526
        finally:
 
6527
            unshelver.tree.unlock()
5506
6528
 
5507
6529
 
5508
6530
class cmd_clean_tree(Command):
5509
 
    """Remove unwanted files from working tree.
 
6531
    __doc__ = """Remove unwanted files from working tree.
5510
6532
 
5511
6533
    By default, only unknown files, not ignored files, are deleted.  Versioned
5512
6534
    files are never deleted.
5520
6542
 
5521
6543
    To check what clean-tree will do, use --dry-run.
5522
6544
    """
5523
 
    takes_options = [Option('ignored', help='Delete all ignored files.'),
5524
 
                     Option('detritus', help='Delete conflict files, merge'
 
6545
    takes_options = ['directory',
 
6546
                     Option('ignored', help='Delete all ignored files.'),
 
6547
                     Option('detritus', help='Delete conflict files, merge and revert'
5525
6548
                            ' backups, and failed selftest dirs.'),
5526
6549
                     Option('unknown',
5527
6550
                            help='Delete files unknown to bzr (default).'),
5529
6552
                            ' deleting them.'),
5530
6553
                     Option('force', help='Do not prompt before deleting.')]
5531
6554
    def run(self, unknown=False, ignored=False, detritus=False, dry_run=False,
5532
 
            force=False):
 
6555
            force=False, directory=u'.'):
5533
6556
        from bzrlib.clean_tree import clean_tree
5534
6557
        if not (unknown or ignored or detritus):
5535
6558
            unknown = True
5536
6559
        if dry_run:
5537
6560
            force = True
5538
 
        clean_tree('.', unknown=unknown, ignored=ignored, detritus=detritus,
5539
 
                   dry_run=dry_run, no_prompt=force)
 
6561
        clean_tree(directory, unknown=unknown, ignored=ignored,
 
6562
                   detritus=detritus, dry_run=dry_run, no_prompt=force)
5540
6563
 
5541
6564
 
5542
6565
class cmd_reference(Command):
5543
 
    """list, view and set branch locations for nested trees.
 
6566
    __doc__ = """list, view and set branch locations for nested trees.
5544
6567
 
5545
6568
    If no arguments are provided, lists the branch locations for nested trees.
5546
6569
    If one argument is provided, display the branch location for that tree.
5556
6579
        if path is not None:
5557
6580
            branchdir = path
5558
6581
        tree, branch, relpath =(
5559
 
            bzrdir.BzrDir.open_containing_tree_or_branch(branchdir))
 
6582
            controldir.ControlDir.open_containing_tree_or_branch(branchdir))
5560
6583
        if path is not None:
5561
6584
            path = relpath
5562
6585
        if tree is None:
5586
6609
            self.outf.write('%s %s\n' % (path, location))
5587
6610
 
5588
6611
 
5589
 
# these get imported and then picked up by the scan for cmd_*
5590
 
# TODO: Some more consistent way to split command definitions across files;
5591
 
# we do need to load at least some information about them to know of
5592
 
# aliases.  ideally we would avoid loading the implementation until the
5593
 
# details were needed.
5594
 
from bzrlib.cmd_version_info import cmd_version_info
5595
 
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
5596
 
from bzrlib.bundle.commands import (
5597
 
    cmd_bundle_info,
5598
 
    )
5599
 
from bzrlib.foreign import cmd_dpush
5600
 
from bzrlib.sign_my_commits import cmd_sign_my_commits
5601
 
from bzrlib.weave_commands import cmd_versionedfile_list, \
5602
 
        cmd_weave_plan_merge, cmd_weave_merge_text
 
6612
class cmd_export_pot(Command):
 
6613
    __doc__ = """Export command helps and error messages in po format."""
 
6614
 
 
6615
    hidden = True
 
6616
    takes_options = [Option('plugin', 
 
6617
                            help='Export help text from named command '\
 
6618
                                 '(defaults to all built in commands).',
 
6619
                            type=str),
 
6620
                     Option('include-duplicates',
 
6621
                            help='Output multiple copies of the same msgid '
 
6622
                                 'string if it appears more than once.'),
 
6623
                            ]
 
6624
 
 
6625
    def run(self, plugin=None, include_duplicates=False):
 
6626
        from bzrlib.export_pot import export_pot
 
6627
        export_pot(self.outf, plugin, include_duplicates)
 
6628
 
 
6629
 
 
6630
def _register_lazy_builtins():
 
6631
    # register lazy builtins from other modules; called at startup and should
 
6632
    # be only called once.
 
6633
    for (name, aliases, module_name) in [
 
6634
        ('cmd_bundle_info', [], 'bzrlib.bundle.commands'),
 
6635
        ('cmd_config', [], 'bzrlib.config'),
 
6636
        ('cmd_dpush', [], 'bzrlib.foreign'),
 
6637
        ('cmd_version_info', [], 'bzrlib.cmd_version_info'),
 
6638
        ('cmd_resolve', ['resolved'], 'bzrlib.conflicts'),
 
6639
        ('cmd_conflicts', [], 'bzrlib.conflicts'),
 
6640
        ('cmd_sign_my_commits', [], 'bzrlib.commit_signature_commands'),
 
6641
        ('cmd_verify_signatures', [],
 
6642
                                        'bzrlib.commit_signature_commands'),
 
6643
        ('cmd_test_script', [], 'bzrlib.cmd_test_script'),
 
6644
        ]:
 
6645
        builtin_command_registry.register_lazy(name, aliases, module_name)