/brz/remove-bazaar

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

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Ian Clatworthy
  • Date: 2009-05-18 07:48:02 UTC
  • mto: (4456.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 4457.
  • Revision ID: ian.clatworthy@canonical.com-20090518074802-dbx8ats78vl134y6
refactor ls command to use new APIs

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""builtin bzr commands"""
 
18
 
 
19
import os
 
20
 
 
21
from bzrlib.lazy_import import lazy_import
 
22
lazy_import(globals(), """
 
23
import codecs
 
24
import cStringIO
 
25
import sys
 
26
import time
 
27
 
 
28
import bzrlib
 
29
from bzrlib import (
 
30
    bugtracker,
 
31
    bundle,
 
32
    btree_index,
 
33
    bzrdir,
 
34
    delta,
 
35
    config,
 
36
    errors,
 
37
    globbing,
 
38
    hooks,
 
39
    log,
 
40
    merge as _mod_merge,
 
41
    merge_directive,
 
42
    osutils,
 
43
    reconfigure,
 
44
    rename_map,
 
45
    revision as _mod_revision,
 
46
    symbol_versioning,
 
47
    transport,
 
48
    tree as _mod_tree,
 
49
    ui,
 
50
    urlutils,
 
51
    views,
 
52
    )
 
53
from bzrlib.branch import Branch
 
54
from bzrlib.conflicts import ConflictList
 
55
from bzrlib.revisionspec import RevisionSpec, RevisionInfo
 
56
from bzrlib.smtp_connection import SMTPConnection
 
57
from bzrlib.workingtree import WorkingTree
 
58
""")
 
59
 
 
60
from bzrlib.commands import Command, display_command
 
61
from bzrlib.option import (
 
62
    ListOption,
 
63
    Option,
 
64
    RegistryOption,
 
65
    custom_help,
 
66
    _parse_revision_str,
 
67
    )
 
68
from bzrlib.trace import mutter, note, warning, is_quiet, get_verbosity_level
 
69
 
 
70
 
 
71
def tree_files(file_list, default_branch=u'.', canonicalize=True,
 
72
    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]))
 
79
 
 
80
 
 
81
def tree_files_for_add(file_list):
 
82
    """
 
83
    Return a tree and list of absolute paths from a file list.
 
84
 
 
85
    Similar to tree_files, but add handles files a bit differently, so it a
 
86
    custom implementation.  In particular, MutableTreeTree.smart_add expects
 
87
    absolute paths, which it immediately converts to relative paths.
 
88
    """
 
89
    # FIXME Would be nice to just return the relative paths like
 
90
    # internal_tree_files does, but there are a large number of unit tests
 
91
    # that assume the current interface to mutabletree.smart_add
 
92
    if file_list:
 
93
        tree, relpath = WorkingTree.open_containing(file_list[0])
 
94
        if tree.supports_views():
 
95
            view_files = tree.views.lookup_view()
 
96
            if view_files:
 
97
                for filename in file_list:
 
98
                    if not osutils.is_inside_any(view_files, filename):
 
99
                        raise errors.FileOutsideView(filename, view_files)
 
100
        file_list = file_list[:]
 
101
        file_list[0] = tree.abspath(relpath)
 
102
    else:
 
103
        tree = WorkingTree.open_containing(u'.')[0]
 
104
        if tree.supports_views():
 
105
            view_files = tree.views.lookup_view()
 
106
            if view_files:
 
107
                file_list = view_files
 
108
                view_str = views.view_display_str(view_files)
 
109
                note("Ignoring files outside view. View is %s" % view_str)
 
110
    return tree, file_list
 
111
 
 
112
 
 
113
def _get_one_revision(command_name, revisions):
 
114
    if revisions is None:
 
115
        return None
 
116
    if len(revisions) != 1:
 
117
        raise errors.BzrCommandError(
 
118
            'bzr %s --revision takes exactly one revision identifier' % (
 
119
                command_name,))
 
120
    return revisions[0]
 
121
 
 
122
 
 
123
def _get_one_revision_tree(command_name, revisions, branch=None, tree=None):
 
124
    if branch is None:
 
125
        branch = tree.branch
 
126
    if revisions is None:
 
127
        if tree is not None:
 
128
            rev_tree = tree.basis_tree()
 
129
        else:
 
130
            rev_tree = branch.basis_tree()
 
131
    else:
 
132
        revision = _get_one_revision(command_name, revisions)
 
133
        rev_tree = revision.as_tree(branch)
 
134
    return rev_tree
 
135
 
 
136
 
 
137
# XXX: Bad function name; should possibly also be a class method of
 
138
# WorkingTree rather than a function.
 
139
def internal_tree_files(file_list, default_branch=u'.', canonicalize=True,
 
140
    apply_view=True):
 
141
    """Convert command-line paths to a WorkingTree and relative paths.
 
142
 
 
143
    This is typically used for command-line processors that take one or
 
144
    more filenames, and infer the workingtree that contains them.
 
145
 
 
146
    The filenames given are not required to exist.
 
147
 
 
148
    :param file_list: Filenames to convert.
 
149
 
 
150
    :param default_branch: Fallback tree path to use if file_list is empty or
 
151
        None.
 
152
 
 
153
    :param apply_view: if True and a view is set, apply it or check that
 
154
        specified files are within it
 
155
 
 
156
    :return: workingtree, [relative_paths]
 
157
    """
 
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
 
205
 
 
206
 
 
207
def _get_view_info_for_change_reporter(tree):
 
208
    """Get the view information from a tree for change reporting."""
 
209
    view_info = None
 
210
    try:
 
211
        current_view = tree.views.get_view_info()[0]
 
212
        if current_view is not None:
 
213
            view_info = (current_view, tree.views.lookup_view())
 
214
    except errors.ViewsNotSupported:
 
215
        pass
 
216
    return view_info
 
217
 
 
218
 
 
219
# TODO: Make sure no commands unconditionally use the working directory as a
 
220
# branch.  If a filename argument is used, the first of them should be used to
 
221
# specify the branch.  (Perhaps this can be factored out into some kind of
 
222
# Argument class, representing a file in a branch, where the first occurrence
 
223
# opens the branch?)
 
224
 
 
225
class cmd_status(Command):
 
226
    """Display status summary.
 
227
 
 
228
    This reports on versioned and unknown files, reporting them
 
229
    grouped by state.  Possible states are:
 
230
 
 
231
    added
 
232
        Versioned in the working copy but not in the previous revision.
 
233
 
 
234
    removed
 
235
        Versioned in the previous revision but removed or deleted
 
236
        in the working copy.
 
237
 
 
238
    renamed
 
239
        Path of this file changed from the previous revision;
 
240
        the text may also have changed.  This includes files whose
 
241
        parent directory was renamed.
 
242
 
 
243
    modified
 
244
        Text has changed since the previous revision.
 
245
 
 
246
    kind changed
 
247
        File kind has been changed (e.g. from file to directory).
 
248
 
 
249
    unknown
 
250
        Not versioned and not matching an ignore pattern.
 
251
 
 
252
    To see ignored files use 'bzr ignored'.  For details on the
 
253
    changes to file texts, use 'bzr diff'.
 
254
 
 
255
    Note that --short or -S gives status flags for each item, similar
 
256
    to Subversion's status command. To get output similar to svn -q,
 
257
    use bzr status -SV.
 
258
 
 
259
    If no arguments are specified, the status of the entire working
 
260
    directory is shown.  Otherwise, only the status of the specified
 
261
    files or directories is reported.  If a directory is given, status
 
262
    is reported for everything inside that directory.
 
263
 
 
264
    Before merges are committed, the pending merge tip revisions are
 
265
    shown. To see all pending merge revisions, use the -v option.
 
266
    To skip the display of pending merge information altogether, use
 
267
    the no-pending option or specify a file/directory.
 
268
 
 
269
    If a revision argument is given, the status is calculated against
 
270
    that revision, or between two revisions if two are provided.
 
271
    """
 
272
 
 
273
    # TODO: --no-recurse, --recurse options
 
274
 
 
275
    takes_args = ['file*']
 
276
    takes_options = ['show-ids', 'revision', 'change', 'verbose',
 
277
                     Option('short', help='Use short status indicators.',
 
278
                            short_name='S'),
 
279
                     Option('versioned', help='Only show versioned files.',
 
280
                            short_name='V'),
 
281
                     Option('no-pending', help='Don\'t show pending merges.',
 
282
                           ),
 
283
                     ]
 
284
    aliases = ['st', 'stat']
 
285
 
 
286
    encoding_type = 'replace'
 
287
    _see_also = ['diff', 'revert', 'status-flags']
 
288
 
 
289
    @display_command
 
290
    def run(self, show_ids=False, file_list=None, revision=None, short=False,
 
291
            versioned=False, no_pending=False, verbose=False):
 
292
        from bzrlib.status import show_tree_status
 
293
 
 
294
        if revision and len(revision) > 2:
 
295
            raise errors.BzrCommandError('bzr status --revision takes exactly'
 
296
                                         ' one or two revision specifiers')
 
297
 
 
298
        tree, relfile_list = tree_files(file_list)
 
299
        # Avoid asking for specific files when that is not needed.
 
300
        if relfile_list == ['']:
 
301
            relfile_list = None
 
302
            # Don't disable pending merges for full trees other than '.'.
 
303
            if file_list == ['.']:
 
304
                no_pending = True
 
305
        # A specific path within a tree was given.
 
306
        elif relfile_list is not None:
 
307
            no_pending = True
 
308
        show_tree_status(tree, show_ids=show_ids,
 
309
                         specific_files=relfile_list, revision=revision,
 
310
                         to_file=self.outf, short=short, versioned=versioned,
 
311
                         show_pending=(not no_pending), verbose=verbose)
 
312
 
 
313
 
 
314
class cmd_cat_revision(Command):
 
315
    """Write out metadata for a revision.
 
316
 
 
317
    The revision to print can either be specified by a specific
 
318
    revision identifier, or you can use --revision.
 
319
    """
 
320
 
 
321
    hidden = True
 
322
    takes_args = ['revision_id?']
 
323
    takes_options = ['revision']
 
324
    # cat-revision is more for frontends so should be exact
 
325
    encoding = 'strict'
 
326
 
 
327
    @display_command
 
328
    def run(self, revision_id=None, revision=None):
 
329
        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')
 
332
        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
 
 
354
 
 
355
class cmd_dump_btree(Command):
 
356
    """Dump the contents of a btree index file to stdout.
 
357
 
 
358
    PATH is a btree index file, it can be any URL. This includes things like
 
359
    .bzr/repository/pack-names, or .bzr/repository/indices/a34b3a...ca4a4.iix
 
360
 
 
361
    By default, the tuples stored in the index file will be displayed. With
 
362
    --raw, we will uncompress the pages, but otherwise display the raw bytes
 
363
    stored in the index.
 
364
    """
 
365
 
 
366
    # TODO: Do we want to dump the internal nodes as well?
 
367
    # TODO: It would be nice to be able to dump the un-parsed information,
 
368
    #       rather than only going through iter_all_entries. However, this is
 
369
    #       good enough for a start
 
370
    hidden = True
 
371
    encoding_type = 'exact'
 
372
    takes_args = ['path']
 
373
    takes_options = [Option('raw', help='Write the uncompressed bytes out,'
 
374
                                        ' rather than the parsed tuples.'),
 
375
                    ]
 
376
 
 
377
    def run(self, path, raw=False):
 
378
        dirname, basename = osutils.split(path)
 
379
        t = transport.get_transport(dirname)
 
380
        if raw:
 
381
            self._dump_raw_bytes(t, basename)
 
382
        else:
 
383
            self._dump_entries(t, basename)
 
384
 
 
385
    def _get_index_and_bytes(self, trans, basename):
 
386
        """Create a BTreeGraphIndex and raw bytes."""
 
387
        bt = btree_index.BTreeGraphIndex(trans, basename, None)
 
388
        bytes = trans.get_bytes(basename)
 
389
        bt._file = cStringIO.StringIO(bytes)
 
390
        bt._size = len(bytes)
 
391
        return bt, bytes
 
392
 
 
393
    def _dump_raw_bytes(self, trans, basename):
 
394
        import zlib
 
395
 
 
396
        # We need to parse at least the root node.
 
397
        # This is because the first page of every row starts with an
 
398
        # uncompressed header.
 
399
        bt, bytes = self._get_index_and_bytes(trans, basename)
 
400
        for page_idx, page_start in enumerate(xrange(0, len(bytes),
 
401
                                                     btree_index._PAGE_SIZE)):
 
402
            page_end = min(page_start + btree_index._PAGE_SIZE, len(bytes))
 
403
            page_bytes = bytes[page_start:page_end]
 
404
            if page_idx == 0:
 
405
                self.outf.write('Root node:\n')
 
406
                header_end, data = bt._parse_header_from_bytes(page_bytes)
 
407
                self.outf.write(page_bytes[:header_end])
 
408
                page_bytes = data
 
409
            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')
 
413
 
 
414
    def _dump_entries(self, trans, basename):
 
415
        try:
 
416
            st = trans.stat(basename)
 
417
        except errors.TransportNotPossible:
 
418
            # We can't stat, so we'll fake it because we have to do the 'get()'
 
419
            # anyway.
 
420
            bt, _ = self._get_index_and_bytes(trans, basename)
 
421
        else:
 
422
            bt = btree_index.BTreeGraphIndex(trans, basename, st.st_size)
 
423
        for node in bt.iter_all_entries():
 
424
            # Node is made up of:
 
425
            # (index, key, value, [references])
 
426
            self.outf.write('%s\n' % (node[1:],))
 
427
 
 
428
 
 
429
class cmd_remove_tree(Command):
 
430
    """Remove the working tree from a given branch/checkout.
 
431
 
 
432
    Since a lightweight checkout is little more than a working tree
 
433
    this will refuse to run against one.
 
434
 
 
435
    To re-create the working tree, use "bzr checkout".
 
436
    """
 
437
    _see_also = ['checkout', 'working-trees']
 
438
    takes_args = ['location?']
 
439
    takes_options = [
 
440
        Option('force',
 
441
               help='Remove the working tree even if it has '
 
442
                    'uncommitted changes.'),
 
443
        ]
 
444
 
 
445
    def run(self, location='.', force=False):
 
446
        d = bzrdir.BzrDir.open(location)
 
447
 
 
448
        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()
 
467
 
 
468
 
 
469
class cmd_revno(Command):
 
470
    """Show current revision number.
 
471
 
 
472
    This is equal to the number of revisions on this branch.
 
473
    """
 
474
 
 
475
    _see_also = ['info']
 
476
    takes_args = ['location?']
 
477
 
 
478
    @display_command
 
479
    def run(self, location=u'.'):
 
480
        self.outf.write(str(Branch.open_containing(location)[0].revno()))
 
481
        self.outf.write('\n')
 
482
 
 
483
 
 
484
class cmd_revision_info(Command):
 
485
    """Show revision number and revision id for a given revision identifier.
 
486
    """
 
487
    hidden = True
 
488
    takes_args = ['revision_info*']
 
489
    takes_options = [
 
490
        'revision',
 
491
        Option('directory',
 
492
            help='Branch to examine, '
 
493
                 'rather than the one containing the working directory.',
 
494
            short_name='d',
 
495
            type=unicode,
 
496
            ),
 
497
        ]
 
498
 
 
499
    @display_command
 
500
    def run(self, revision=None, directory=u'.', revision_info_list=[]):
 
501
 
 
502
        revs = []
 
503
        if revision is not None:
 
504
            revs.extend(revision)
 
505
        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)
 
516
            try:
 
517
                revno = '%4d' % (b.revision_id_to_revno(revision_id))
 
518
            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)
 
522
 
 
523
 
 
524
class cmd_add(Command):
 
525
    """Add specified files or directories.
 
526
 
 
527
    In non-recursive mode, all the named items are added, regardless
 
528
    of whether they were previously ignored.  A warning is given if
 
529
    any of the named files are already versioned.
 
530
 
 
531
    In recursive mode (the default), files are treated the same way
 
532
    but the behaviour for directories is different.  Directories that
 
533
    are already versioned do not give a warning.  All directories,
 
534
    whether already versioned or not, are searched for files or
 
535
    subdirectories that are neither versioned or ignored, and these
 
536
    are added.  This search proceeds recursively into versioned
 
537
    directories.  If no names are given '.' is assumed.
 
538
 
 
539
    Therefore simply saying 'bzr add' will version all files that
 
540
    are currently unknown.
 
541
 
 
542
    Adding a file whose parent directory is not versioned will
 
543
    implicitly add the parent, and so on up to the root. This means
 
544
    you should never need to explicitly add a directory, they'll just
 
545
    get added when you add a file in the directory.
 
546
 
 
547
    --dry-run will show which files would be added, but not actually
 
548
    add them.
 
549
 
 
550
    --file-ids-from will try to use the file ids from the supplied path.
 
551
    It looks up ids trying to find a matching parent directory with the
 
552
    same filename, and then by pure path. This option is rarely needed
 
553
    but can be useful when adding the same logical file into two
 
554
    branches that will be merged later (without showing the two different
 
555
    adds as a conflict). It is also useful when merging another project
 
556
    into a subdirectory of this one.
 
557
    """
 
558
    takes_args = ['file*']
 
559
    takes_options = [
 
560
        Option('no-recurse',
 
561
               help="Don't recursively add the contents of directories."),
 
562
        Option('dry-run',
 
563
               help="Show what would be done, but don't actually do anything."),
 
564
        'verbose',
 
565
        Option('file-ids-from',
 
566
               type=unicode,
 
567
               help='Lookup file ids from this tree.'),
 
568
        ]
 
569
    encoding_type = 'replace'
 
570
    _see_also = ['remove']
 
571
 
 
572
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False,
 
573
            file_ids_from=None):
 
574
        import bzrlib.add
 
575
 
 
576
        base_tree = None
 
577
        if file_ids_from is not None:
 
578
            try:
 
579
                base_tree, base_path = WorkingTree.open_containing(
 
580
                                            file_ids_from)
 
581
            except errors.NoWorkingTree:
 
582
                base_branch, base_path = Branch.open_containing(
 
583
                                            file_ids_from)
 
584
                base_tree = base_branch.basis_tree()
 
585
 
 
586
            action = bzrlib.add.AddFromBaseAction(base_tree, base_path,
 
587
                          to_file=self.outf, should_print=(not is_quiet()))
 
588
        else:
 
589
            action = bzrlib.add.AddAction(to_file=self.outf,
 
590
                should_print=(not is_quiet()))
 
591
 
 
592
        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()
 
602
        if len(ignored) > 0:
 
603
            if verbose:
 
604
                for glob in sorted(ignored.keys()):
 
605
                    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 some of these files,"
 
614
                            " please add them by name.\n")
 
615
 
 
616
 
 
617
class cmd_mkdir(Command):
 
618
    """Create a new versioned directory.
 
619
 
 
620
    This is equivalent to creating the directory and then adding it.
 
621
    """
 
622
 
 
623
    takes_args = ['dir+']
 
624
    encoding_type = 'replace'
 
625
 
 
626
    def run(self, dir_list):
 
627
        for d in dir_list:
 
628
            os.mkdir(d)
 
629
            wt, dd = WorkingTree.open_containing(d)
 
630
            wt.add([dd])
 
631
            self.outf.write('added %s\n' % d)
 
632
 
 
633
 
 
634
class cmd_relpath(Command):
 
635
    """Show path of a file relative to root"""
 
636
 
 
637
    takes_args = ['filename']
 
638
    hidden = True
 
639
 
 
640
    @display_command
 
641
    def run(self, filename):
 
642
        # TODO: jam 20050106 Can relpath return a munged path if
 
643
        #       sys.stdout encoding cannot represent it?
 
644
        tree, relpath = WorkingTree.open_containing(filename)
 
645
        self.outf.write(relpath)
 
646
        self.outf.write('\n')
 
647
 
 
648
 
 
649
class cmd_inventory(Command):
 
650
    """Show inventory of the current working copy or a revision.
 
651
 
 
652
    It is possible to limit the output to a particular entry
 
653
    type using the --kind option.  For example: --kind file.
 
654
 
 
655
    It is also possible to restrict the list of files to a specific
 
656
    set. For example: bzr inventory --show-ids this/file
 
657
    """
 
658
 
 
659
    hidden = True
 
660
    _see_also = ['ls']
 
661
    takes_options = [
 
662
        'revision',
 
663
        'show-ids',
 
664
        Option('kind',
 
665
               help='List entries of a particular kind: file, directory, symlink.',
 
666
               type=unicode),
 
667
        ]
 
668
    takes_args = ['file*']
 
669
 
 
670
    @display_command
 
671
    def run(self, revision=None, show_ids=False, kind=None, file_list=None):
 
672
        if kind and kind not in ['file', 'directory', 'symlink']:
 
673
            raise errors.BzrCommandError('invalid kind %r specified' % (kind,))
 
674
 
 
675
        revision = _get_one_revision('inventory', revision)
 
676
        work_tree, file_list = tree_files(file_list)
 
677
        work_tree.lock_read()
 
678
        try:
 
679
            if revision is not None:
 
680
                tree = revision.as_tree(work_tree.branch)
 
681
 
 
682
                extra_trees = [work_tree]
 
683
                tree.lock_read()
 
684
            else:
 
685
                tree = work_tree
 
686
                extra_trees = []
 
687
 
 
688
            if file_list is not None:
 
689
                file_ids = tree.paths2ids(file_list, trees=extra_trees,
 
690
                                          require_versioned=True)
 
691
                # find_ids_across_trees may include some paths that don't
 
692
                # exist in 'tree'.
 
693
                entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
 
694
                                 for file_id in file_ids if file_id in tree)
 
695
            else:
 
696
                entries = tree.inventory.entries()
 
697
        finally:
 
698
            tree.unlock()
 
699
            if tree is not work_tree:
 
700
                work_tree.unlock()
 
701
 
 
702
        for path, entry in entries:
 
703
            if kind and kind != entry.kind:
 
704
                continue
 
705
            if show_ids:
 
706
                self.outf.write('%-50s %s\n' % (path, entry.file_id))
 
707
            else:
 
708
                self.outf.write(path)
 
709
                self.outf.write('\n')
 
710
 
 
711
 
 
712
class cmd_mv(Command):
 
713
    """Move or rename a file.
 
714
 
 
715
    :Usage:
 
716
        bzr mv OLDNAME NEWNAME
 
717
 
 
718
        bzr mv SOURCE... DESTINATION
 
719
 
 
720
    If the last argument is a versioned directory, all the other names
 
721
    are moved into it.  Otherwise, there must be exactly two arguments
 
722
    and the file is changed to a new name.
 
723
 
 
724
    If OLDNAME does not exist on the filesystem but is versioned and
 
725
    NEWNAME does exist on the filesystem but is not versioned, mv
 
726
    assumes that the file has been manually moved and only updates
 
727
    its internal inventory to reflect that change.
 
728
    The same is valid when moving many SOURCE files to a DESTINATION.
 
729
 
 
730
    Files cannot be moved between branches.
 
731
    """
 
732
 
 
733
    takes_args = ['names*']
 
734
    takes_options = [Option("after", help="Move only the bzr identifier"
 
735
        " of the file, because the file has already been moved."),
 
736
        Option('auto', help='Automatically guess renames.'),
 
737
        Option('dry-run', help='Avoid making changes when guessing renames.'),
 
738
        ]
 
739
    aliases = ['move', 'rename']
 
740
    encoding_type = 'replace'
 
741
 
 
742
    def run(self, names_list, after=False, auto=False, dry_run=False):
 
743
        if auto:
 
744
            return self.run_auto(names_list, after, dry_run)
 
745
        elif dry_run:
 
746
            raise errors.BzrCommandError('--dry-run requires --auto.')
 
747
        if names_list is None:
 
748
            names_list = []
 
749
        if len(names_list) < 2:
 
750
            raise errors.BzrCommandError("missing file argument")
 
751
        tree, rel_names = tree_files(names_list, canonicalize=False)
 
752
        tree.lock_write()
 
753
        try:
 
754
            self._run(tree, names_list, rel_names, after)
 
755
        finally:
 
756
            tree.unlock()
 
757
 
 
758
    def run_auto(self, names_list, after, dry_run):
 
759
        if names_list is not None and len(names_list) > 1:
 
760
            raise errors.BzrCommandError('Only one path may be specified to'
 
761
                                         ' --auto.')
 
762
        if after:
 
763
            raise errors.BzrCommandError('--after cannot be specified with'
 
764
                                         ' --auto.')
 
765
        work_tree, file_list = tree_files(names_list, default_branch='.')
 
766
        work_tree.lock_write()
 
767
        try:
 
768
            rename_map.RenameMap.guess_renames(work_tree, dry_run)
 
769
        finally:
 
770
            work_tree.unlock()
 
771
 
 
772
    def _run(self, tree, names_list, rel_names, after):
 
773
        into_existing = osutils.isdir(names_list[-1])
 
774
        if into_existing and len(names_list) == 2:
 
775
            # special cases:
 
776
            # a. case-insensitive filesystem and change case of dir
 
777
            # b. move directory after the fact (if the source used to be
 
778
            #    a directory, but now doesn't exist in the working tree
 
779
            #    and the target is an existing directory, just rename it)
 
780
            if (not tree.case_sensitive
 
781
                and rel_names[0].lower() == rel_names[1].lower()):
 
782
                into_existing = False
 
783
            else:
 
784
                inv = tree.inventory
 
785
                # 'fix' the case of a potential 'from'
 
786
                from_id = tree.path2id(
 
787
                            tree.get_canonical_inventory_path(rel_names[0]))
 
788
                if (not osutils.lexists(names_list[0]) and
 
789
                    from_id and inv.get_file_kind(from_id) == "directory"):
 
790
                    into_existing = False
 
791
        # move/rename
 
792
        if into_existing:
 
793
            # move into existing directory
 
794
            # All entries reference existing inventory items, so fix them up
 
795
            # for cicp file-systems.
 
796
            rel_names = tree.get_canonical_inventory_paths(rel_names)
 
797
            for pair in tree.move(rel_names[:-1], rel_names[-1], after=after):
 
798
                self.outf.write("%s => %s\n" % pair)
 
799
        else:
 
800
            if len(names_list) != 2:
 
801
                raise errors.BzrCommandError('to mv multiple files the'
 
802
                                             ' destination must be a versioned'
 
803
                                             ' directory')
 
804
 
 
805
            # for cicp file-systems: the src references an existing inventory
 
806
            # item:
 
807
            src = tree.get_canonical_inventory_path(rel_names[0])
 
808
            # Find the canonical version of the destination:  In all cases, the
 
809
            # parent of the target must be in the inventory, so we fetch the
 
810
            # canonical version from there (we do not always *use* the
 
811
            # canonicalized tail portion - we may be attempting to rename the
 
812
            # case of the tail)
 
813
            canon_dest = tree.get_canonical_inventory_path(rel_names[1])
 
814
            dest_parent = osutils.dirname(canon_dest)
 
815
            spec_tail = osutils.basename(rel_names[1])
 
816
            # For a CICP file-system, we need to avoid creating 2 inventory
 
817
            # entries that differ only by case.  So regardless of the case
 
818
            # we *want* to use (ie, specified by the user or the file-system),
 
819
            # we must always choose to use the case of any existing inventory
 
820
            # items.  The only exception to this is when we are attempting a
 
821
            # case-only rename (ie, canonical versions of src and dest are
 
822
            # the same)
 
823
            dest_id = tree.path2id(canon_dest)
 
824
            if dest_id is None or tree.path2id(src) == dest_id:
 
825
                # No existing item we care about, so work out what case we
 
826
                # are actually going to use.
 
827
                if after:
 
828
                    # If 'after' is specified, the tail must refer to a file on disk.
 
829
                    if dest_parent:
 
830
                        dest_parent_fq = osutils.pathjoin(tree.basedir, dest_parent)
 
831
                    else:
 
832
                        # pathjoin with an empty tail adds a slash, which breaks
 
833
                        # relpath :(
 
834
                        dest_parent_fq = tree.basedir
 
835
 
 
836
                    dest_tail = osutils.canonical_relpath(
 
837
                                    dest_parent_fq,
 
838
                                    osutils.pathjoin(dest_parent_fq, spec_tail))
 
839
                else:
 
840
                    # not 'after', so case as specified is used
 
841
                    dest_tail = spec_tail
 
842
            else:
 
843
                # Use the existing item so 'mv' fails with AlreadyVersioned.
 
844
                dest_tail = os.path.basename(canon_dest)
 
845
            dest = osutils.pathjoin(dest_parent, dest_tail)
 
846
            mutter("attempting to move %s => %s", src, dest)
 
847
            tree.rename_one(src, dest, after=after)
 
848
            self.outf.write("%s => %s\n" % (src, dest))
 
849
 
 
850
 
 
851
class cmd_pull(Command):
 
852
    """Turn this branch into a mirror of another branch.
 
853
 
 
854
    This command only works on branches that have not diverged.  Branches are
 
855
    considered diverged if the destination branch's most recent commit is one
 
856
    that has not been merged (directly or indirectly) into the parent.
 
857
 
 
858
    If branches have diverged, you can use 'bzr merge' to integrate the changes
 
859
    from one into the other.  Once one branch has merged, the other should
 
860
    be able to pull it again.
 
861
 
 
862
    If you want to forget your local changes and just update your branch to
 
863
    match the remote one, use pull --overwrite.
 
864
 
 
865
    If there is no default location set, the first pull will set it.  After
 
866
    that, you can omit the location to use the default.  To change the
 
867
    default, use --remember. The value will only be saved if the remote
 
868
    location can be accessed.
 
869
 
 
870
    Note: The location can be specified either in the form of a branch,
 
871
    or in the form of a path to a file containing a merge directive generated
 
872
    with bzr send.
 
873
    """
 
874
 
 
875
    _see_also = ['push', 'update', 'status-flags', 'send']
 
876
    takes_options = ['remember', 'overwrite', 'revision',
 
877
        custom_help('verbose',
 
878
            help='Show logs of pulled revisions.'),
 
879
        Option('directory',
 
880
            help='Branch to pull into, '
 
881
                 'rather than the one containing the working directory.',
 
882
            short_name='d',
 
883
            type=unicode,
 
884
            ),
 
885
        Option('local',
 
886
            help="Perform a local pull in a bound "
 
887
                 "branch.  Local pulls are not applied to "
 
888
                 "the master branch."
 
889
            ),
 
890
        ]
 
891
    takes_args = ['location?']
 
892
    encoding_type = 'replace'
 
893
 
 
894
    def run(self, location=None, remember=False, overwrite=False,
 
895
            revision=None, verbose=False,
 
896
            directory=None, local=False):
 
897
        # FIXME: too much stuff is in the command class
 
898
        revision_id = None
 
899
        mergeable = None
 
900
        if directory is None:
 
901
            directory = u'.'
 
902
        try:
 
903
            tree_to = WorkingTree.open_containing(directory)[0]
 
904
            branch_to = tree_to.branch
 
905
        except errors.NoWorkingTree:
 
906
            tree_to = None
 
907
            branch_to = Branch.open_containing(directory)[0]
 
908
        
 
909
        if local and not branch_to.get_bound_location():
 
910
            raise errors.LocalRequiresBoundBranch()
 
911
 
 
912
        possible_transports = []
 
913
        if location is not None:
 
914
            try:
 
915
                mergeable = bundle.read_mergeable_from_url(location,
 
916
                    possible_transports=possible_transports)
 
917
            except errors.NotABundle:
 
918
                mergeable = None
 
919
 
 
920
        stored_loc = branch_to.get_parent()
 
921
        if location is None:
 
922
            if stored_loc is None:
 
923
                raise errors.BzrCommandError("No pull location known or"
 
924
                                             " specified.")
 
925
            else:
 
926
                display_url = urlutils.unescape_for_display(stored_loc,
 
927
                        self.outf.encoding)
 
928
                if not is_quiet():
 
929
                    self.outf.write("Using saved parent location: %s\n" % display_url)
 
930
                location = stored_loc
 
931
 
 
932
        revision = _get_one_revision('pull', revision)
 
933
        if mergeable is not None:
 
934
            if revision is not None:
 
935
                raise errors.BzrCommandError(
 
936
                    'Cannot use -r with merge directives or bundles')
 
937
            mergeable.install_revisions(branch_to.repository)
 
938
            base_revision_id, revision_id, verified = \
 
939
                mergeable.get_merge_request(branch_to.repository)
 
940
            branch_from = branch_to
 
941
        else:
 
942
            branch_from = Branch.open(location,
 
943
                possible_transports=possible_transports)
 
944
 
 
945
            if branch_to.get_parent() is None or remember:
 
946
                branch_to.set_parent(branch_from.base)
 
947
 
 
948
        if revision is not None:
 
949
            revision_id = revision.as_revision_id(branch_from)
 
950
 
 
951
        branch_to.lock_write()
 
952
        try:
 
953
            if tree_to is not None:
 
954
                view_info = _get_view_info_for_change_reporter(tree_to)
 
955
                change_reporter = delta._ChangeReporter(
 
956
                    unversioned_filter=tree_to.is_ignored, view_info=view_info)
 
957
                result = tree_to.pull(branch_from, overwrite, revision_id,
 
958
                                      change_reporter,
 
959
                                      possible_transports=possible_transports,
 
960
                                      local=local)
 
961
            else:
 
962
                result = branch_to.pull(branch_from, overwrite, revision_id,
 
963
                                      local=local)
 
964
 
 
965
            result.report(self.outf)
 
966
            if verbose and result.old_revid != result.new_revid:
 
967
                log.show_branch_change(branch_to, self.outf, result.old_revno,
 
968
                                       result.old_revid)
 
969
        finally:
 
970
            branch_to.unlock()
 
971
 
 
972
 
 
973
class cmd_push(Command):
 
974
    """Update a mirror of this branch.
 
975
 
 
976
    The target branch will not have its working tree populated because this
 
977
    is both expensive, and is not supported on remote file systems.
 
978
 
 
979
    Some smart servers or protocols *may* put the working tree in place in
 
980
    the future.
 
981
 
 
982
    This command only works on branches that have not diverged.  Branches are
 
983
    considered diverged if the destination branch's most recent commit is one
 
984
    that has not been merged (directly or indirectly) by the source branch.
 
985
 
 
986
    If branches have diverged, you can use 'bzr push --overwrite' to replace
 
987
    the other branch completely, discarding its unmerged changes.
 
988
 
 
989
    If you want to ensure you have the different changes in the other branch,
 
990
    do a merge (see bzr help merge) from the other branch, and commit that.
 
991
    After that you will be able to do a push without '--overwrite'.
 
992
 
 
993
    If there is no default push location set, the first push will set it.
 
994
    After that, you can omit the location to use the default.  To change the
 
995
    default, use --remember. The value will only be saved if the remote
 
996
    location can be accessed.
 
997
    """
 
998
 
 
999
    _see_also = ['pull', 'update', 'working-trees']
 
1000
    takes_options = ['remember', 'overwrite', 'verbose', 'revision',
 
1001
        Option('create-prefix',
 
1002
               help='Create the path leading up to the branch '
 
1003
                    'if it does not already exist.'),
 
1004
        Option('directory',
 
1005
            help='Branch to push from, '
 
1006
                 'rather than the one containing the working directory.',
 
1007
            short_name='d',
 
1008
            type=unicode,
 
1009
            ),
 
1010
        Option('use-existing-dir',
 
1011
               help='By default push will fail if the target'
 
1012
                    ' directory exists, but does not already'
 
1013
                    ' have a control directory.  This flag will'
 
1014
                    ' allow push to proceed.'),
 
1015
        Option('stacked',
 
1016
            help='Create a stacked branch that references the public location '
 
1017
                'of the parent branch.'),
 
1018
        Option('stacked-on',
 
1019
            help='Create a stacked branch that refers to another branch '
 
1020
                'for the commit history. Only the work not present in the '
 
1021
                'referenced branch is included in the branch created.',
 
1022
            type=unicode),
 
1023
        ]
 
1024
    takes_args = ['location?']
 
1025
    encoding_type = 'replace'
 
1026
 
 
1027
    def run(self, location=None, remember=False, overwrite=False,
 
1028
        create_prefix=False, verbose=False, revision=None,
 
1029
        use_existing_dir=False, directory=None, stacked_on=None,
 
1030
        stacked=False):
 
1031
        from bzrlib.push import _show_push_branch
 
1032
 
 
1033
        # Get the source branch and revision_id
 
1034
        if directory is None:
 
1035
            directory = '.'
 
1036
        br_from = Branch.open_containing(directory)[0]
 
1037
        revision = _get_one_revision('push', revision)
 
1038
        if revision is not None:
 
1039
            revision_id = revision.in_history(br_from).rev_id
 
1040
        else:
 
1041
            revision_id = None
 
1042
 
 
1043
        # Get the stacked_on branch, if any
 
1044
        if stacked_on is not None:
 
1045
            stacked_on = urlutils.normalize_url(stacked_on)
 
1046
        elif stacked:
 
1047
            parent_url = br_from.get_parent()
 
1048
            if parent_url:
 
1049
                parent = Branch.open(parent_url)
 
1050
                stacked_on = parent.get_public_branch()
 
1051
                if not stacked_on:
 
1052
                    # I considered excluding non-http url's here, thus forcing
 
1053
                    # 'public' branches only, but that only works for some
 
1054
                    # users, so it's best to just depend on the user spotting an
 
1055
                    # error by the feedback given to them. RBC 20080227.
 
1056
                    stacked_on = parent_url
 
1057
            if not stacked_on:
 
1058
                raise errors.BzrCommandError(
 
1059
                    "Could not determine branch to refer to.")
 
1060
 
 
1061
        # Get the destination location
 
1062
        if location is None:
 
1063
            stored_loc = br_from.get_push_location()
 
1064
            if stored_loc is None:
 
1065
                raise errors.BzrCommandError(
 
1066
                    "No push location known or specified.")
 
1067
            else:
 
1068
                display_url = urlutils.unescape_for_display(stored_loc,
 
1069
                        self.outf.encoding)
 
1070
                self.outf.write("Using saved push location: %s\n" % display_url)
 
1071
                location = stored_loc
 
1072
 
 
1073
        _show_push_branch(br_from, revision_id, location, self.outf,
 
1074
            verbose=verbose, overwrite=overwrite, remember=remember,
 
1075
            stacked_on=stacked_on, create_prefix=create_prefix,
 
1076
            use_existing_dir=use_existing_dir)
 
1077
 
 
1078
 
 
1079
class cmd_branch(Command):
 
1080
    """Create a new copy of a branch.
 
1081
 
 
1082
    If the TO_LOCATION is omitted, the last component of the FROM_LOCATION will
 
1083
    be used.  In other words, "branch ../foo/bar" will attempt to create ./bar.
 
1084
    If the FROM_LOCATION has no / or path separator embedded, the TO_LOCATION
 
1085
    is derived from the FROM_LOCATION by stripping a leading scheme or drive
 
1086
    identifier, if any. For example, "branch lp:foo-bar" will attempt to
 
1087
    create ./foo-bar.
 
1088
 
 
1089
    To retrieve the branch as of a particular revision, supply the --revision
 
1090
    parameter, as in "branch foo/bar -r 5".
 
1091
    """
 
1092
 
 
1093
    _see_also = ['checkout']
 
1094
    takes_args = ['from_location', 'to_location?']
 
1095
    takes_options = ['revision', Option('hardlink',
 
1096
        help='Hard-link working tree files where possible.'),
 
1097
        Option('no-tree',
 
1098
            help="Create a branch without a working-tree."),
 
1099
        Option('stacked',
 
1100
            help='Create a stacked branch referring to the source branch. '
 
1101
                'The new branch will depend on the availability of the source '
 
1102
                'branch for all operations.'),
 
1103
        Option('standalone',
 
1104
               help='Do not use a shared repository, even if available.'),
 
1105
        ]
 
1106
    aliases = ['get', 'clone']
 
1107
 
 
1108
    def run(self, from_location, to_location=None, revision=None,
 
1109
            hardlink=False, stacked=False, standalone=False, no_tree=False):
 
1110
        from bzrlib.tag import _merge_tags_if_possible
 
1111
 
 
1112
        accelerator_tree, br_from = bzrdir.BzrDir.open_tree_or_branch(
 
1113
            from_location)
 
1114
        revision = _get_one_revision('branch', revision)
 
1115
        br_from.lock_read()
 
1116
        try:
 
1117
            if revision is not None:
 
1118
                revision_id = revision.as_revision_id(br_from)
 
1119
            else:
 
1120
                # FIXME - wt.last_revision, fallback to branch, fall back to
 
1121
                # None or perhaps NULL_REVISION to mean copy nothing
 
1122
                # RBC 20060209
 
1123
                revision_id = br_from.last_revision()
 
1124
            if to_location is None:
 
1125
                to_location = urlutils.derive_to_location(from_location)
 
1126
            to_transport = transport.get_transport(to_location)
 
1127
            try:
 
1128
                to_transport.mkdir('.')
 
1129
            except errors.FileExists:
 
1130
                raise errors.BzrCommandError('Target directory "%s" already'
 
1131
                                             ' exists.' % to_location)
 
1132
            except errors.NoSuchFile:
 
1133
                raise errors.BzrCommandError('Parent of "%s" does not exist.'
 
1134
                                             % to_location)
 
1135
            try:
 
1136
                # preserve whatever source format we have.
 
1137
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
 
1138
                                            possible_transports=[to_transport],
 
1139
                                            accelerator_tree=accelerator_tree,
 
1140
                                            hardlink=hardlink, stacked=stacked,
 
1141
                                            force_new_repo=standalone,
 
1142
                                            create_tree_if_local=not no_tree,
 
1143
                                            source_branch=br_from)
 
1144
                branch = dir.open_branch()
 
1145
            except errors.NoSuchRevision:
 
1146
                to_transport.delete_tree('.')
 
1147
                msg = "The branch %s has no revision %s." % (from_location,
 
1148
                    revision)
 
1149
                raise errors.BzrCommandError(msg)
 
1150
            _merge_tags_if_possible(br_from, branch)
 
1151
            # If the source branch is stacked, the new branch may
 
1152
            # be stacked whether we asked for that explicitly or not.
 
1153
            # We therefore need a try/except here and not just 'if stacked:'
 
1154
            try:
 
1155
                note('Created new stacked branch referring to %s.' %
 
1156
                    branch.get_stacked_on_url())
 
1157
            except (errors.NotStacked, errors.UnstackableBranchFormat,
 
1158
                errors.UnstackableRepositoryFormat), e:
 
1159
                note('Branched %d revision(s).' % branch.revno())
 
1160
        finally:
 
1161
            br_from.unlock()
 
1162
 
 
1163
 
 
1164
class cmd_checkout(Command):
 
1165
    """Create a new checkout of an existing branch.
 
1166
 
 
1167
    If BRANCH_LOCATION is omitted, checkout will reconstitute a working tree for
 
1168
    the branch found in '.'. This is useful if you have removed the working tree
 
1169
    or if it was never created - i.e. if you pushed the branch to its current
 
1170
    location using SFTP.
 
1171
 
 
1172
    If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
 
1173
    be used.  In other words, "checkout ../foo/bar" will attempt to create ./bar.
 
1174
    If the BRANCH_LOCATION has no / or path separator embedded, the TO_LOCATION
 
1175
    is derived from the BRANCH_LOCATION by stripping a leading scheme or drive
 
1176
    identifier, if any. For example, "checkout lp:foo-bar" will attempt to
 
1177
    create ./foo-bar.
 
1178
 
 
1179
    To retrieve the branch as of a particular revision, supply the --revision
 
1180
    parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
 
1181
    out of date [so you cannot commit] but it may be useful (i.e. to examine old
 
1182
    code.)
 
1183
    """
 
1184
 
 
1185
    _see_also = ['checkouts', 'branch']
 
1186
    takes_args = ['branch_location?', 'to_location?']
 
1187
    takes_options = ['revision',
 
1188
                     Option('lightweight',
 
1189
                            help="Perform a lightweight checkout.  Lightweight "
 
1190
                                 "checkouts depend on access to the branch for "
 
1191
                                 "every operation.  Normal checkouts can perform "
 
1192
                                 "common operations like diff and status without "
 
1193
                                 "such access, and also support local commits."
 
1194
                            ),
 
1195
                     Option('files-from', type=str,
 
1196
                            help="Get file contents from this tree."),
 
1197
                     Option('hardlink',
 
1198
                            help='Hard-link working tree files where possible.'
 
1199
                            ),
 
1200
                     ]
 
1201
    aliases = ['co']
 
1202
 
 
1203
    def run(self, branch_location=None, to_location=None, revision=None,
 
1204
            lightweight=False, files_from=None, hardlink=False):
 
1205
        if branch_location is None:
 
1206
            branch_location = osutils.getcwd()
 
1207
            to_location = branch_location
 
1208
        accelerator_tree, source = bzrdir.BzrDir.open_tree_or_branch(
 
1209
            branch_location)
 
1210
        revision = _get_one_revision('checkout', revision)
 
1211
        if files_from is not None:
 
1212
            accelerator_tree = WorkingTree.open(files_from)
 
1213
        if revision is not None:
 
1214
            revision_id = revision.as_revision_id(source)
 
1215
        else:
 
1216
            revision_id = None
 
1217
        if to_location is None:
 
1218
            to_location = urlutils.derive_to_location(branch_location)
 
1219
        # if the source and to_location are the same,
 
1220
        # and there is no working tree,
 
1221
        # then reconstitute a branch
 
1222
        if (osutils.abspath(to_location) ==
 
1223
            osutils.abspath(branch_location)):
 
1224
            try:
 
1225
                source.bzrdir.open_workingtree()
 
1226
            except errors.NoWorkingTree:
 
1227
                source.bzrdir.create_workingtree(revision_id)
 
1228
                return
 
1229
        source.create_checkout(to_location, revision_id, lightweight,
 
1230
                               accelerator_tree, hardlink)
 
1231
 
 
1232
 
 
1233
class cmd_renames(Command):
 
1234
    """Show list of renamed files.
 
1235
    """
 
1236
    # TODO: Option to show renames between two historical versions.
 
1237
 
 
1238
    # TODO: Only show renames under dir, rather than in the whole branch.
 
1239
    _see_also = ['status']
 
1240
    takes_args = ['dir?']
 
1241
 
 
1242
    @display_command
 
1243
    def run(self, dir=u'.'):
 
1244
        tree = WorkingTree.open_containing(dir)[0]
 
1245
        tree.lock_read()
 
1246
        try:
 
1247
            new_inv = tree.inventory
 
1248
            old_tree = tree.basis_tree()
 
1249
            old_tree.lock_read()
 
1250
            try:
 
1251
                old_inv = old_tree.inventory
 
1252
                renames = []
 
1253
                iterator = tree.iter_changes(old_tree, include_unchanged=True)
 
1254
                for f, paths, c, v, p, n, k, e in iterator:
 
1255
                    if paths[0] == paths[1]:
 
1256
                        continue
 
1257
                    if None in (paths):
 
1258
                        continue
 
1259
                    renames.append(paths)
 
1260
                renames.sort()
 
1261
                for old_name, new_name in renames:
 
1262
                    self.outf.write("%s => %s\n" % (old_name, new_name))
 
1263
            finally:
 
1264
                old_tree.unlock()
 
1265
        finally:
 
1266
            tree.unlock()
 
1267
 
 
1268
 
 
1269
class cmd_update(Command):
 
1270
    """Update a tree to have the latest code committed to its branch.
 
1271
 
 
1272
    This will perform a merge into the working tree, and may generate
 
1273
    conflicts. If you have any local changes, you will still
 
1274
    need to commit them after the update for the update to be complete.
 
1275
 
 
1276
    If you want to discard your local changes, you can just do a
 
1277
    'bzr revert' instead of 'bzr commit' after the update.
 
1278
    """
 
1279
 
 
1280
    _see_also = ['pull', 'working-trees', 'status-flags']
 
1281
    takes_args = ['dir?']
 
1282
    aliases = ['up']
 
1283
 
 
1284
    def run(self, dir='.'):
 
1285
        tree = WorkingTree.open_containing(dir)[0]
 
1286
        possible_transports = []
 
1287
        master = tree.branch.get_master_branch(
 
1288
            possible_transports=possible_transports)
 
1289
        if master is not None:
 
1290
            tree.lock_write()
 
1291
        else:
 
1292
            tree.lock_tree_write()
 
1293
        try:
 
1294
            existing_pending_merges = tree.get_parent_ids()[1:]
 
1295
            last_rev = _mod_revision.ensure_null(tree.last_revision())
 
1296
            if last_rev == _mod_revision.ensure_null(
 
1297
                tree.branch.last_revision()):
 
1298
                # may be up to date, check master too.
 
1299
                if master is None or last_rev == _mod_revision.ensure_null(
 
1300
                    master.last_revision()):
 
1301
                    revno = tree.branch.revision_id_to_revno(last_rev)
 
1302
                    note("Tree is up to date at revision %d." % (revno,))
 
1303
                    return 0
 
1304
            view_info = _get_view_info_for_change_reporter(tree)
 
1305
            conflicts = tree.update(
 
1306
                delta._ChangeReporter(unversioned_filter=tree.is_ignored,
 
1307
                view_info=view_info), possible_transports=possible_transports)
 
1308
            revno = tree.branch.revision_id_to_revno(
 
1309
                _mod_revision.ensure_null(tree.last_revision()))
 
1310
            note('Updated to revision %d.' % (revno,))
 
1311
            if tree.get_parent_ids()[1:] != existing_pending_merges:
 
1312
                note('Your local commits will now show as pending merges with '
 
1313
                     "'bzr status', and can be committed with 'bzr commit'.")
 
1314
            if conflicts != 0:
 
1315
                return 1
 
1316
            else:
 
1317
                return 0
 
1318
        finally:
 
1319
            tree.unlock()
 
1320
 
 
1321
 
 
1322
class cmd_info(Command):
 
1323
    """Show information about a working tree, branch or repository.
 
1324
 
 
1325
    This command will show all known locations and formats associated to the
 
1326
    tree, branch or repository.
 
1327
 
 
1328
    In verbose mode, statistical information is included with each report.
 
1329
    To see extended statistic information, use a verbosity level of 2 or
 
1330
    higher by specifying the verbose option multiple times, e.g. -vv.
 
1331
 
 
1332
    Branches and working trees will also report any missing revisions.
 
1333
 
 
1334
    :Examples:
 
1335
 
 
1336
      Display information on the format and related locations:
 
1337
 
 
1338
        bzr info
 
1339
 
 
1340
      Display the above together with extended format information and
 
1341
      basic statistics (like the number of files in the working tree and
 
1342
      number of revisions in the branch and repository):
 
1343
 
 
1344
        bzr info -v
 
1345
 
 
1346
      Display the above together with number of committers to the branch:
 
1347
 
 
1348
        bzr info -vv
 
1349
    """
 
1350
    _see_also = ['revno', 'working-trees', 'repositories']
 
1351
    takes_args = ['location?']
 
1352
    takes_options = ['verbose']
 
1353
    encoding_type = 'replace'
 
1354
 
 
1355
    @display_command
 
1356
    def run(self, location=None, verbose=False):
 
1357
        if verbose:
 
1358
            noise_level = get_verbosity_level()
 
1359
        else:
 
1360
            noise_level = 0
 
1361
        from bzrlib.info import show_bzrdir_info
 
1362
        show_bzrdir_info(bzrdir.BzrDir.open_containing(location)[0],
 
1363
                         verbose=noise_level, outfile=self.outf)
 
1364
 
 
1365
 
 
1366
class cmd_remove(Command):
 
1367
    """Remove files or directories.
 
1368
 
 
1369
    This makes bzr stop tracking changes to the specified files. bzr will delete
 
1370
    them if they can easily be recovered using revert. If no options or
 
1371
    parameters are given bzr will scan for files that are being tracked by bzr
 
1372
    but missing in your tree and stop tracking them for you.
 
1373
    """
 
1374
    takes_args = ['file*']
 
1375
    takes_options = ['verbose',
 
1376
        Option('new', help='Only remove files that have never been committed.'),
 
1377
        RegistryOption.from_kwargs('file-deletion-strategy',
 
1378
            'The file deletion mode to be used.',
 
1379
            title='Deletion Strategy', value_switches=True, enum_switch=False,
 
1380
            safe='Only delete files if they can be'
 
1381
                 ' safely recovered (default).',
 
1382
            keep="Don't delete any files.",
 
1383
            force='Delete all the specified files, even if they can not be '
 
1384
                'recovered and even if they are non-empty directories.')]
 
1385
    aliases = ['rm', 'del']
 
1386
    encoding_type = 'replace'
 
1387
 
 
1388
    def run(self, file_list, verbose=False, new=False,
 
1389
        file_deletion_strategy='safe'):
 
1390
        tree, file_list = tree_files(file_list)
 
1391
 
 
1392
        if file_list is not None:
 
1393
            file_list = [f for f in file_list]
 
1394
 
 
1395
        tree.lock_write()
 
1396
        try:
 
1397
            # Heuristics should probably all move into tree.remove_smart or
 
1398
            # some such?
 
1399
            if new:
 
1400
                added = tree.changes_from(tree.basis_tree(),
 
1401
                    specific_files=file_list).added
 
1402
                file_list = sorted([f[0] for f in added], reverse=True)
 
1403
                if len(file_list) == 0:
 
1404
                    raise errors.BzrCommandError('No matching files.')
 
1405
            elif file_list is None:
 
1406
                # missing files show up in iter_changes(basis) as
 
1407
                # versioned-with-no-kind.
 
1408
                missing = []
 
1409
                for change in tree.iter_changes(tree.basis_tree()):
 
1410
                    # Find paths in the working tree that have no kind:
 
1411
                    if change[1][1] is not None and change[6][1] is None:
 
1412
                        missing.append(change[1][1])
 
1413
                file_list = sorted(missing, reverse=True)
 
1414
                file_deletion_strategy = 'keep'
 
1415
            tree.remove(file_list, verbose=verbose, to_file=self.outf,
 
1416
                keep_files=file_deletion_strategy=='keep',
 
1417
                force=file_deletion_strategy=='force')
 
1418
        finally:
 
1419
            tree.unlock()
 
1420
 
 
1421
 
 
1422
class cmd_file_id(Command):
 
1423
    """Print file_id of a particular file or directory.
 
1424
 
 
1425
    The file_id is assigned when the file is first added and remains the
 
1426
    same through all revisions where the file exists, even when it is
 
1427
    moved or renamed.
 
1428
    """
 
1429
 
 
1430
    hidden = True
 
1431
    _see_also = ['inventory', 'ls']
 
1432
    takes_args = ['filename']
 
1433
 
 
1434
    @display_command
 
1435
    def run(self, filename):
 
1436
        tree, relpath = WorkingTree.open_containing(filename)
 
1437
        i = tree.path2id(relpath)
 
1438
        if i is None:
 
1439
            raise errors.NotVersionedError(filename)
 
1440
        else:
 
1441
            self.outf.write(i + '\n')
 
1442
 
 
1443
 
 
1444
class cmd_file_path(Command):
 
1445
    """Print path of file_ids to a file or directory.
 
1446
 
 
1447
    This prints one line for each directory down to the target,
 
1448
    starting at the branch root.
 
1449
    """
 
1450
 
 
1451
    hidden = True
 
1452
    takes_args = ['filename']
 
1453
 
 
1454
    @display_command
 
1455
    def run(self, filename):
 
1456
        tree, relpath = WorkingTree.open_containing(filename)
 
1457
        fid = tree.path2id(relpath)
 
1458
        if fid is None:
 
1459
            raise errors.NotVersionedError(filename)
 
1460
        segments = osutils.splitpath(relpath)
 
1461
        for pos in range(1, len(segments) + 1):
 
1462
            path = osutils.joinpath(segments[:pos])
 
1463
            self.outf.write("%s\n" % tree.path2id(path))
 
1464
 
 
1465
 
 
1466
class cmd_reconcile(Command):
 
1467
    """Reconcile bzr metadata in a branch.
 
1468
 
 
1469
    This can correct data mismatches that may have been caused by
 
1470
    previous ghost operations or bzr upgrades. You should only
 
1471
    need to run this command if 'bzr check' or a bzr developer
 
1472
    advises you to run it.
 
1473
 
 
1474
    If a second branch is provided, cross-branch reconciliation is
 
1475
    also attempted, which will check that data like the tree root
 
1476
    id which was not present in very early bzr versions is represented
 
1477
    correctly in both branches.
 
1478
 
 
1479
    At the same time it is run it may recompress data resulting in
 
1480
    a potential saving in disk space or performance gain.
 
1481
 
 
1482
    The branch *MUST* be on a listable system such as local disk or sftp.
 
1483
    """
 
1484
 
 
1485
    _see_also = ['check']
 
1486
    takes_args = ['branch?']
 
1487
 
 
1488
    def run(self, branch="."):
 
1489
        from bzrlib.reconcile import reconcile
 
1490
        dir = bzrdir.BzrDir.open(branch)
 
1491
        reconcile(dir)
 
1492
 
 
1493
 
 
1494
class cmd_revision_history(Command):
 
1495
    """Display the list of revision ids on a branch."""
 
1496
 
 
1497
    _see_also = ['log']
 
1498
    takes_args = ['location?']
 
1499
 
 
1500
    hidden = True
 
1501
 
 
1502
    @display_command
 
1503
    def run(self, location="."):
 
1504
        branch = Branch.open_containing(location)[0]
 
1505
        for revid in branch.revision_history():
 
1506
            self.outf.write(revid)
 
1507
            self.outf.write('\n')
 
1508
 
 
1509
 
 
1510
class cmd_ancestry(Command):
 
1511
    """List all revisions merged into this branch."""
 
1512
 
 
1513
    _see_also = ['log', 'revision-history']
 
1514
    takes_args = ['location?']
 
1515
 
 
1516
    hidden = True
 
1517
 
 
1518
    @display_command
 
1519
    def run(self, location="."):
 
1520
        try:
 
1521
            wt = WorkingTree.open_containing(location)[0]
 
1522
        except errors.NoWorkingTree:
 
1523
            b = Branch.open(location)
 
1524
            last_revision = b.last_revision()
 
1525
        else:
 
1526
            b = wt.branch
 
1527
            last_revision = wt.last_revision()
 
1528
 
 
1529
        revision_ids = b.repository.get_ancestry(last_revision)
 
1530
        revision_ids.pop(0)
 
1531
        for revision_id in revision_ids:
 
1532
            self.outf.write(revision_id + '\n')
 
1533
 
 
1534
 
 
1535
class cmd_init(Command):
 
1536
    """Make a directory into a versioned branch.
 
1537
 
 
1538
    Use this to create an empty branch, or before importing an
 
1539
    existing project.
 
1540
 
 
1541
    If there is a repository in a parent directory of the location, then
 
1542
    the history of the branch will be stored in the repository.  Otherwise
 
1543
    init creates a standalone branch which carries its own history
 
1544
    in the .bzr directory.
 
1545
 
 
1546
    If there is already a branch at the location but it has no working tree,
 
1547
    the tree can be populated with 'bzr checkout'.
 
1548
 
 
1549
    Recipe for importing a tree of files::
 
1550
 
 
1551
        cd ~/project
 
1552
        bzr init
 
1553
        bzr add .
 
1554
        bzr status
 
1555
        bzr commit -m "imported project"
 
1556
    """
 
1557
 
 
1558
    _see_also = ['init-repository', 'branch', 'checkout']
 
1559
    takes_args = ['location?']
 
1560
    takes_options = [
 
1561
        Option('create-prefix',
 
1562
               help='Create the path leading up to the branch '
 
1563
                    'if it does not already exist.'),
 
1564
         RegistryOption('format',
 
1565
                help='Specify a format for this branch. '
 
1566
                'See "help formats".',
 
1567
                lazy_registry=('bzrlib.bzrdir', 'format_registry'),
 
1568
                converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
 
1569
                value_switches=True,
 
1570
                title="Branch Format",
 
1571
                ),
 
1572
         Option('append-revisions-only',
 
1573
                help='Never change revnos or the existing log.'
 
1574
                '  Append revisions to it only.')
 
1575
         ]
 
1576
    def run(self, location=None, format=None, append_revisions_only=False,
 
1577
            create_prefix=False):
 
1578
        if format is None:
 
1579
            format = bzrdir.format_registry.make_bzrdir('default')
 
1580
        if location is None:
 
1581
            location = u'.'
 
1582
 
 
1583
        to_transport = transport.get_transport(location)
 
1584
 
 
1585
        # The path has to exist to initialize a
 
1586
        # branch inside of it.
 
1587
        # Just using os.mkdir, since I don't
 
1588
        # believe that we want to create a bunch of
 
1589
        # locations if the user supplies an extended path
 
1590
        try:
 
1591
            to_transport.ensure_base()
 
1592
        except errors.NoSuchFile:
 
1593
            if not create_prefix:
 
1594
                raise errors.BzrCommandError("Parent directory of %s"
 
1595
                    " does not exist."
 
1596
                    "\nYou may supply --create-prefix to create all"
 
1597
                    " leading parent directories."
 
1598
                    % location)
 
1599
            to_transport.create_prefix()
 
1600
 
 
1601
        try:
 
1602
            a_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport)
 
1603
        except errors.NotBranchError:
 
1604
            # really a NotBzrDir error...
 
1605
            create_branch = bzrdir.BzrDir.create_branch_convenience
 
1606
            branch = create_branch(to_transport.base, format=format,
 
1607
                                   possible_transports=[to_transport])
 
1608
            a_bzrdir = branch.bzrdir
 
1609
        else:
 
1610
            from bzrlib.transport.local import LocalTransport
 
1611
            if a_bzrdir.has_branch():
 
1612
                if (isinstance(to_transport, LocalTransport)
 
1613
                    and not a_bzrdir.has_workingtree()):
 
1614
                        raise errors.BranchExistsWithoutWorkingTree(location)
 
1615
                raise errors.AlreadyBranchError(location)
 
1616
            branch = a_bzrdir.create_branch()
 
1617
            a_bzrdir.create_workingtree()
 
1618
        if append_revisions_only:
 
1619
            try:
 
1620
                branch.set_append_revisions_only(True)
 
1621
            except errors.UpgradeRequired:
 
1622
                raise errors.BzrCommandError('This branch format cannot be set'
 
1623
                    ' to append-revisions-only.  Try --experimental-branch6')
 
1624
        if not is_quiet():
 
1625
            from bzrlib.info import describe_layout, describe_format
 
1626
            try:
 
1627
                tree = a_bzrdir.open_workingtree(recommend_upgrade=False)
 
1628
            except (errors.NoWorkingTree, errors.NotLocalUrl):
 
1629
                tree = None
 
1630
            repository = branch.repository
 
1631
            layout = describe_layout(repository, branch, tree).lower()
 
1632
            format = describe_format(a_bzrdir, repository, branch, tree)
 
1633
            self.outf.write("Created a %s (format: %s)\n" % (layout, format))
 
1634
            if repository.is_shared():
 
1635
                #XXX: maybe this can be refactored into transport.path_or_url()
 
1636
                url = repository.bzrdir.root_transport.external_url()
 
1637
                try:
 
1638
                    url = urlutils.local_path_from_url(url)
 
1639
                except errors.InvalidURL:
 
1640
                    pass
 
1641
                self.outf.write("Using shared repository: %s\n" % url)
 
1642
 
 
1643
 
 
1644
class cmd_init_repository(Command):
 
1645
    """Create a shared repository to hold branches.
 
1646
 
 
1647
    New branches created under the repository directory will store their
 
1648
    revisions in the repository, not in the branch directory.
 
1649
 
 
1650
    If the --no-trees option is used then the branches in the repository
 
1651
    will not have working trees by default.
 
1652
 
 
1653
    :Examples:
 
1654
        Create a shared repositories holding just branches::
 
1655
 
 
1656
            bzr init-repo --no-trees repo
 
1657
            bzr init repo/trunk
 
1658
 
 
1659
        Make a lightweight checkout elsewhere::
 
1660
 
 
1661
            bzr checkout --lightweight repo/trunk trunk-checkout
 
1662
            cd trunk-checkout
 
1663
            (add files here)
 
1664
    """
 
1665
 
 
1666
    _see_also = ['init', 'branch', 'checkout', 'repositories']
 
1667
    takes_args = ["location"]
 
1668
    takes_options = [RegistryOption('format',
 
1669
                            help='Specify a format for this repository. See'
 
1670
                                 ' "bzr help formats" for details.',
 
1671
                            lazy_registry=('bzrlib.bzrdir', 'format_registry'),
 
1672
                            converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
 
1673
                            value_switches=True, title='Repository format'),
 
1674
                     Option('no-trees',
 
1675
                             help='Branches in the repository will default to'
 
1676
                                  ' not having a working tree.'),
 
1677
                    ]
 
1678
    aliases = ["init-repo"]
 
1679
 
 
1680
    def run(self, location, format=None, no_trees=False):
 
1681
        if format is None:
 
1682
            format = bzrdir.format_registry.make_bzrdir('default')
 
1683
 
 
1684
        if location is None:
 
1685
            location = '.'
 
1686
 
 
1687
        to_transport = transport.get_transport(location)
 
1688
        to_transport.ensure_base()
 
1689
 
 
1690
        newdir = format.initialize_on_transport(to_transport)
 
1691
        repo = newdir.create_repository(shared=True)
 
1692
        repo.set_make_working_trees(not no_trees)
 
1693
        if not is_quiet():
 
1694
            from bzrlib.info import show_bzrdir_info
 
1695
            show_bzrdir_info(repo.bzrdir, verbose=0, outfile=self.outf)
 
1696
 
 
1697
 
 
1698
class cmd_diff(Command):
 
1699
    """Show differences in the working tree, between revisions or branches.
 
1700
 
 
1701
    If no arguments are given, all changes for the current tree are listed.
 
1702
    If files are given, only the changes in those files are listed.
 
1703
    Remote and multiple branches can be compared by using the --old and
 
1704
    --new options. If not provided, the default for both is derived from
 
1705
    the first argument, if any, or the current tree if no arguments are
 
1706
    given.
 
1707
 
 
1708
    "bzr diff -p1" is equivalent to "bzr diff --prefix old/:new/", and
 
1709
    produces patches suitable for "patch -p1".
 
1710
 
 
1711
    :Exit values:
 
1712
        1 - changed
 
1713
        2 - unrepresentable changes
 
1714
        3 - error
 
1715
        0 - no change
 
1716
 
 
1717
    :Examples:
 
1718
        Shows the difference in the working tree versus the last commit::
 
1719
 
 
1720
            bzr diff
 
1721
 
 
1722
        Difference between the working tree and revision 1::
 
1723
 
 
1724
            bzr diff -r1
 
1725
 
 
1726
        Difference between revision 2 and revision 1::
 
1727
 
 
1728
            bzr diff -r1..2
 
1729
 
 
1730
        Difference between revision 2 and revision 1 for branch xxx::
 
1731
 
 
1732
            bzr diff -r1..2 xxx
 
1733
 
 
1734
        Show just the differences for file NEWS::
 
1735
 
 
1736
            bzr diff NEWS
 
1737
 
 
1738
        Show the differences in working tree xxx for file NEWS::
 
1739
 
 
1740
            bzr diff xxx/NEWS
 
1741
 
 
1742
        Show the differences from branch xxx to this working tree:
 
1743
 
 
1744
            bzr diff --old xxx
 
1745
 
 
1746
        Show the differences between two branches for file NEWS::
 
1747
 
 
1748
            bzr diff --old xxx --new yyy NEWS
 
1749
 
 
1750
        Same as 'bzr diff' but prefix paths with old/ and new/::
 
1751
 
 
1752
            bzr diff --prefix old/:new/
 
1753
    """
 
1754
    _see_also = ['status']
 
1755
    takes_args = ['file*']
 
1756
    takes_options = [
 
1757
        Option('diff-options', type=str,
 
1758
               help='Pass these options to the external diff program.'),
 
1759
        Option('prefix', type=str,
 
1760
               short_name='p',
 
1761
               help='Set prefixes added to old and new filenames, as '
 
1762
                    'two values separated by a colon. (eg "old/:new/").'),
 
1763
        Option('old',
 
1764
            help='Branch/tree to compare from.',
 
1765
            type=unicode,
 
1766
            ),
 
1767
        Option('new',
 
1768
            help='Branch/tree to compare to.',
 
1769
            type=unicode,
 
1770
            ),
 
1771
        'revision',
 
1772
        'change',
 
1773
        Option('using',
 
1774
            help='Use this command to compare files.',
 
1775
            type=unicode,
 
1776
            ),
 
1777
        ]
 
1778
    aliases = ['di', 'dif']
 
1779
    encoding_type = 'exact'
 
1780
 
 
1781
    @display_command
 
1782
    def run(self, revision=None, file_list=None, diff_options=None,
 
1783
            prefix=None, old=None, new=None, using=None):
 
1784
        from bzrlib.diff import _get_trees_to_diff, show_diff_trees
 
1785
 
 
1786
        if (prefix is None) or (prefix == '0'):
 
1787
            # diff -p0 format
 
1788
            old_label = ''
 
1789
            new_label = ''
 
1790
        elif prefix == '1':
 
1791
            old_label = 'old/'
 
1792
            new_label = 'new/'
 
1793
        elif ':' in prefix:
 
1794
            old_label, new_label = prefix.split(":")
 
1795
        else:
 
1796
            raise errors.BzrCommandError(
 
1797
                '--prefix expects two values separated by a colon'
 
1798
                ' (eg "old/:new/")')
 
1799
 
 
1800
        if revision and len(revision) > 2:
 
1801
            raise errors.BzrCommandError('bzr diff --revision takes exactly'
 
1802
                                         ' one or two revision specifiers')
 
1803
 
 
1804
        old_tree, new_tree, specific_files, extra_trees = \
 
1805
                _get_trees_to_diff(file_list, revision, old, new,
 
1806
                apply_view=True)
 
1807
        return show_diff_trees(old_tree, new_tree, sys.stdout,
 
1808
                               specific_files=specific_files,
 
1809
                               external_diff_options=diff_options,
 
1810
                               old_label=old_label, new_label=new_label,
 
1811
                               extra_trees=extra_trees, using=using)
 
1812
 
 
1813
 
 
1814
class cmd_deleted(Command):
 
1815
    """List files deleted in the working tree.
 
1816
    """
 
1817
    # TODO: Show files deleted since a previous revision, or
 
1818
    # between two revisions.
 
1819
    # TODO: Much more efficient way to do this: read in new
 
1820
    # directories with readdir, rather than stating each one.  Same
 
1821
    # level of effort but possibly much less IO.  (Or possibly not,
 
1822
    # if the directories are very large...)
 
1823
    _see_also = ['status', 'ls']
 
1824
    takes_options = ['show-ids']
 
1825
 
 
1826
    @display_command
 
1827
    def run(self, show_ids=False):
 
1828
        tree = WorkingTree.open_containing(u'.')[0]
 
1829
        tree.lock_read()
 
1830
        try:
 
1831
            old = tree.basis_tree()
 
1832
            old.lock_read()
 
1833
            try:
 
1834
                for path, ie in old.inventory.iter_entries():
 
1835
                    if not tree.has_id(ie.file_id):
 
1836
                        self.outf.write(path)
 
1837
                        if show_ids:
 
1838
                            self.outf.write(' ')
 
1839
                            self.outf.write(ie.file_id)
 
1840
                        self.outf.write('\n')
 
1841
            finally:
 
1842
                old.unlock()
 
1843
        finally:
 
1844
            tree.unlock()
 
1845
 
 
1846
 
 
1847
class cmd_modified(Command):
 
1848
    """List files modified in working tree.
 
1849
    """
 
1850
 
 
1851
    hidden = True
 
1852
    _see_also = ['status', 'ls']
 
1853
    takes_options = [
 
1854
            Option('null',
 
1855
                   help='Write an ascii NUL (\\0) separator '
 
1856
                   'between files rather than a newline.')
 
1857
            ]
 
1858
 
 
1859
    @display_command
 
1860
    def run(self, null=False):
 
1861
        tree = WorkingTree.open_containing(u'.')[0]
 
1862
        td = tree.changes_from(tree.basis_tree())
 
1863
        for path, id, kind, text_modified, meta_modified in td.modified:
 
1864
            if null:
 
1865
                self.outf.write(path + '\0')
 
1866
            else:
 
1867
                self.outf.write(osutils.quotefn(path) + '\n')
 
1868
 
 
1869
 
 
1870
class cmd_added(Command):
 
1871
    """List files added in working tree.
 
1872
    """
 
1873
 
 
1874
    hidden = True
 
1875
    _see_also = ['status', 'ls']
 
1876
    takes_options = [
 
1877
            Option('null',
 
1878
                   help='Write an ascii NUL (\\0) separator '
 
1879
                   'between files rather than a newline.')
 
1880
            ]
 
1881
 
 
1882
    @display_command
 
1883
    def run(self, null=False):
 
1884
        wt = WorkingTree.open_containing(u'.')[0]
 
1885
        wt.lock_read()
 
1886
        try:
 
1887
            basis = wt.basis_tree()
 
1888
            basis.lock_read()
 
1889
            try:
 
1890
                basis_inv = basis.inventory
 
1891
                inv = wt.inventory
 
1892
                for file_id in inv:
 
1893
                    if file_id in basis_inv:
 
1894
                        continue
 
1895
                    if inv.is_root(file_id) and len(basis_inv) == 0:
 
1896
                        continue
 
1897
                    path = inv.id2path(file_id)
 
1898
                    if not os.access(osutils.abspath(path), os.F_OK):
 
1899
                        continue
 
1900
                    if null:
 
1901
                        self.outf.write(path + '\0')
 
1902
                    else:
 
1903
                        self.outf.write(osutils.quotefn(path) + '\n')
 
1904
            finally:
 
1905
                basis.unlock()
 
1906
        finally:
 
1907
            wt.unlock()
 
1908
 
 
1909
 
 
1910
class cmd_root(Command):
 
1911
    """Show the tree root directory.
 
1912
 
 
1913
    The root is the nearest enclosing directory with a .bzr control
 
1914
    directory."""
 
1915
 
 
1916
    takes_args = ['filename?']
 
1917
    @display_command
 
1918
    def run(self, filename=None):
 
1919
        """Print the branch root."""
 
1920
        tree = WorkingTree.open_containing(filename)[0]
 
1921
        self.outf.write(tree.basedir + '\n')
 
1922
 
 
1923
 
 
1924
def _parse_limit(limitstring):
 
1925
    try:
 
1926
        return int(limitstring)
 
1927
    except ValueError:
 
1928
        msg = "The limit argument must be an integer."
 
1929
        raise errors.BzrCommandError(msg)
 
1930
 
 
1931
 
 
1932
def _parse_levels(s):
 
1933
    try:
 
1934
        return int(s)
 
1935
    except ValueError:
 
1936
        msg = "The levels argument must be an integer."
 
1937
        raise errors.BzrCommandError(msg)
 
1938
 
 
1939
 
 
1940
class cmd_log(Command):
 
1941
    """Show historical log for a branch or subset of a branch.
 
1942
 
 
1943
    log is bzr's default tool for exploring the history of a branch.
 
1944
    The branch to use is taken from the first parameter. If no parameters
 
1945
    are given, the branch containing the working directory is logged.
 
1946
    Here are some simple examples::
 
1947
 
 
1948
      bzr log                       log the current branch
 
1949
      bzr log foo.py                log a file in its branch
 
1950
      bzr log http://server/branch  log a branch on a server
 
1951
 
 
1952
    The filtering, ordering and information shown for each revision can
 
1953
    be controlled as explained below. By default, all revisions are
 
1954
    shown sorted (topologically) so that newer revisions appear before
 
1955
    older ones and descendants always appear before ancestors. If displayed,
 
1956
    merged revisions are shown indented under the revision in which they
 
1957
    were merged.
 
1958
 
 
1959
    :Output control:
 
1960
 
 
1961
      The log format controls how information about each revision is
 
1962
      displayed. The standard log formats are called ``long``, ``short``
 
1963
      and ``line``. The default is long. See ``bzr help log-formats``
 
1964
      for more details on log formats.
 
1965
 
 
1966
      The following options can be used to control what information is
 
1967
      displayed::
 
1968
 
 
1969
        -l N        display a maximum of N revisions
 
1970
        -n N        display N levels of revisions (0 for all, 1 for collapsed)
 
1971
        -v          display a status summary (delta) for each revision
 
1972
        -p          display a diff (patch) for each revision
 
1973
        --show-ids  display revision-ids (and file-ids), not just revnos
 
1974
 
 
1975
      Note that the default number of levels to display is a function of the
 
1976
      log format. If the -n option is not used, the standard log formats show
 
1977
      just the top level (mainline).
 
1978
 
 
1979
      Status summaries are shown using status flags like A, M, etc. To see
 
1980
      the changes explained using words like ``added`` and ``modified``
 
1981
      instead, use the -vv option.
 
1982
 
 
1983
    :Ordering control:
 
1984
 
 
1985
      To display revisions from oldest to newest, use the --forward option.
 
1986
      In most cases, using this option will have little impact on the total
 
1987
      time taken to produce a log, though --forward does not incrementally
 
1988
      display revisions like --reverse does when it can.
 
1989
 
 
1990
    :Revision filtering:
 
1991
 
 
1992
      The -r option can be used to specify what revision or range of revisions
 
1993
      to filter against. The various forms are shown below::
 
1994
 
 
1995
        -rX      display revision X
 
1996
        -rX..    display revision X and later
 
1997
        -r..Y    display up to and including revision Y
 
1998
        -rX..Y   display from X to Y inclusive
 
1999
 
 
2000
      See ``bzr help revisionspec`` for details on how to specify X and Y.
 
2001
      Some common examples are given below::
 
2002
 
 
2003
        -r-1                show just the tip
 
2004
        -r-10..             show the last 10 mainline revisions
 
2005
        -rsubmit:..         show what's new on this branch
 
2006
        -rancestor:path..   show changes since the common ancestor of this
 
2007
                            branch and the one at location path
 
2008
        -rdate:yesterday..  show changes since yesterday
 
2009
 
 
2010
      When logging a range of revisions using -rX..Y, log starts at
 
2011
      revision Y and searches back in history through the primary
 
2012
      ("left-hand") parents until it finds X. When logging just the
 
2013
      top level (using -n1), an error is reported if X is not found
 
2014
      along the way. If multi-level logging is used (-n0), X may be
 
2015
      a nested merge revision and the log will be truncated accordingly.
 
2016
 
 
2017
    :Path filtering:
 
2018
 
 
2019
      If parameters are given and the first one is not a branch, the log
 
2020
      will be filtered to show only those revisions that changed the
 
2021
      nominated files or directories.
 
2022
 
 
2023
      Filenames are interpreted within their historical context. To log a
 
2024
      deleted file, specify a revision range so that the file existed at
 
2025
      the end or start of the range.
 
2026
 
 
2027
      Historical context is also important when interpreting pathnames of
 
2028
      renamed files/directories. Consider the following example:
 
2029
 
 
2030
      * revision 1: add tutorial.txt
 
2031
      * revision 2: modify tutorial.txt
 
2032
      * revision 3: rename tutorial.txt to guide.txt; add tutorial.txt
 
2033
 
 
2034
      In this case:
 
2035
 
 
2036
      * ``bzr log guide.txt`` will log the file added in revision 1
 
2037
 
 
2038
      * ``bzr log tutorial.txt`` will log the new file added in revision 3
 
2039
 
 
2040
      * ``bzr log -r2 -p tutorial.txt`` will show the changes made to
 
2041
        the original file in revision 2.
 
2042
 
 
2043
      * ``bzr log -r2 -p guide.txt`` will display an error message as there
 
2044
        was no file called guide.txt in revision 2.
 
2045
 
 
2046
      Renames are always followed by log. By design, there is no need to
 
2047
      explicitly ask for this (and no way to stop logging a file back
 
2048
      until it was last renamed).
 
2049
 
 
2050
    :Other filtering:
 
2051
 
 
2052
      The --message option can be used for finding revisions that match a
 
2053
      regular expression in a commit message.
 
2054
 
 
2055
    :Tips & tricks:
 
2056
 
 
2057
      GUI tools and IDEs are often better at exploring history than command
 
2058
      line tools. You may prefer qlog or glog from the QBzr and Bzr-Gtk packages
 
2059
      respectively for example. (TortoiseBzr uses qlog for displaying logs.) See
 
2060
      http://bazaar-vcs.org/BzrPlugins and http://bazaar-vcs.org/IDEIntegration.
 
2061
 
 
2062
      Web interfaces are often better at exploring history than command line
 
2063
      tools, particularly for branches on servers. You may prefer Loggerhead
 
2064
      or one of its alternatives. See http://bazaar-vcs.org/WebInterface.
 
2065
 
 
2066
      You may find it useful to add the aliases below to ``bazaar.conf``::
 
2067
 
 
2068
        [ALIASES]
 
2069
        tip = log -r-1
 
2070
        top = log -l10 --line
 
2071
        show = log -v -p
 
2072
 
 
2073
      ``bzr tip`` will then show the latest revision while ``bzr top``
 
2074
      will show the last 10 mainline revisions. To see the details of a
 
2075
      particular revision X,  ``bzr show -rX``.
 
2076
 
 
2077
      If you are interested in looking deeper into a particular merge X,
 
2078
      use ``bzr log -n0 -rX``.
 
2079
 
 
2080
      ``bzr log -v`` on a branch with lots of history is currently
 
2081
      very slow. A fix for this issue is currently under development.
 
2082
      With or without that fix, it is recommended that a revision range
 
2083
      be given when using the -v option.
 
2084
 
 
2085
      bzr has a generic full-text matching plugin, bzr-search, that can be
 
2086
      used to find revisions matching user names, commit messages, etc.
 
2087
      Among other features, this plugin can find all revisions containing
 
2088
      a list of words but not others.
 
2089
 
 
2090
      When exploring non-mainline history on large projects with deep
 
2091
      history, the performance of log can be greatly improved by installing
 
2092
      the historycache plugin. This plugin buffers historical information
 
2093
      trading disk space for faster speed.
 
2094
    """
 
2095
    takes_args = ['file*']
 
2096
    _see_also = ['log-formats', 'revisionspec']
 
2097
    takes_options = [
 
2098
            Option('forward',
 
2099
                   help='Show from oldest to newest.'),
 
2100
            'timezone',
 
2101
            custom_help('verbose',
 
2102
                   help='Show files changed in each revision.'),
 
2103
            'show-ids',
 
2104
            'revision',
 
2105
            Option('change',
 
2106
                   type=bzrlib.option._parse_revision_str,
 
2107
                   short_name='c',
 
2108
                   help='Show just the specified revision.'
 
2109
                   ' See also "help revisionspec".'),
 
2110
            'log-format',
 
2111
            Option('levels',
 
2112
                   short_name='n',
 
2113
                   help='Number of levels to display - 0 for all, 1 for flat.',
 
2114
                   argname='N',
 
2115
                   type=_parse_levels),
 
2116
            Option('message',
 
2117
                   short_name='m',
 
2118
                   help='Show revisions whose message matches this '
 
2119
                        'regular expression.',
 
2120
                   type=str),
 
2121
            Option('limit',
 
2122
                   short_name='l',
 
2123
                   help='Limit the output to the first N revisions.',
 
2124
                   argname='N',
 
2125
                   type=_parse_limit),
 
2126
            Option('show-diff',
 
2127
                   short_name='p',
 
2128
                   help='Show changes made in each revision as a patch.'),
 
2129
            Option('include-merges',
 
2130
                   help='Show merged revisions like --levels 0 does.'),
 
2131
            ]
 
2132
    encoding_type = 'replace'
 
2133
 
 
2134
    @display_command
 
2135
    def run(self, file_list=None, timezone='original',
 
2136
            verbose=False,
 
2137
            show_ids=False,
 
2138
            forward=False,
 
2139
            revision=None,
 
2140
            change=None,
 
2141
            log_format=None,
 
2142
            levels=None,
 
2143
            message=None,
 
2144
            limit=None,
 
2145
            show_diff=False,
 
2146
            include_merges=False):
 
2147
        from bzrlib.log import (
 
2148
            Logger,
 
2149
            make_log_request_dict,
 
2150
            _get_info_for_log_files,
 
2151
            )
 
2152
        direction = (forward and 'forward') or 'reverse'
 
2153
        if include_merges:
 
2154
            if levels is None:
 
2155
                levels = 0
 
2156
            else:
 
2157
                raise errors.BzrCommandError(
 
2158
                    '--levels and --include-merges are mutually exclusive')
 
2159
 
 
2160
        if change is not None:
 
2161
            if len(change) > 1:
 
2162
                raise errors.RangeInChangeOption()
 
2163
            if revision is not None:
 
2164
                raise errors.BzrCommandError(
 
2165
                    '--revision and --change are mutually exclusive')
 
2166
            else:
 
2167
                revision = change
 
2168
 
 
2169
        file_ids = []
 
2170
        filter_by_dir = False
 
2171
        if file_list:
 
2172
            # find the file ids to log and check for directory filtering
 
2173
            b, file_info_list, rev1, rev2 = _get_info_for_log_files(revision,
 
2174
                file_list)
 
2175
            for relpath, file_id, kind in file_info_list:
 
2176
                if file_id is None:
 
2177
                    raise errors.BzrCommandError(
 
2178
                        "Path unknown at end or start of revision range: %s" %
 
2179
                        relpath)
 
2180
                # If the relpath is the top of the tree, we log everything
 
2181
                if relpath == '':
 
2182
                    file_ids = []
 
2183
                    break
 
2184
                else:
 
2185
                    file_ids.append(file_id)
 
2186
                filter_by_dir = filter_by_dir or (
 
2187
                    kind in ['directory', 'tree-reference'])
 
2188
        else:
 
2189
            # log everything
 
2190
            # FIXME ? log the current subdir only RBC 20060203
 
2191
            if revision is not None \
 
2192
                    and len(revision) > 0 and revision[0].get_branch():
 
2193
                location = revision[0].get_branch()
 
2194
            else:
 
2195
                location = '.'
 
2196
            dir, relpath = bzrdir.BzrDir.open_containing(location)
 
2197
            b = dir.open_branch()
 
2198
            rev1, rev2 = _get_revision_range(revision, b, self.name())
 
2199
 
 
2200
        # Decide on the type of delta & diff filtering to use
 
2201
        # TODO: add an --all-files option to make this configurable & consistent
 
2202
        if not verbose:
 
2203
            delta_type = None
 
2204
        else:
 
2205
            delta_type = 'full'
 
2206
        if not show_diff:
 
2207
            diff_type = None
 
2208
        elif file_ids:
 
2209
            diff_type = 'partial'
 
2210
        else:
 
2211
            diff_type = 'full'
 
2212
 
 
2213
        b.lock_read()
 
2214
        try:
 
2215
            # Build the log formatter
 
2216
            if log_format is None:
 
2217
                log_format = log.log_formatter_registry.get_default(b)
 
2218
            lf = log_format(show_ids=show_ids, to_file=self.outf,
 
2219
                            show_timezone=timezone,
 
2220
                            delta_format=get_verbosity_level(),
 
2221
                            levels=levels,
 
2222
                            show_advice=levels is None)
 
2223
 
 
2224
            # Choose the algorithm for doing the logging. It's annoying
 
2225
            # having multiple code paths like this but necessary until
 
2226
            # the underlying repository format is faster at generating
 
2227
            # deltas or can provide everything we need from the indices.
 
2228
            # The default algorithm - match-using-deltas - works for
 
2229
            # multiple files and directories and is faster for small
 
2230
            # amounts of history (200 revisions say). However, it's too
 
2231
            # slow for logging a single file in a repository with deep
 
2232
            # history, i.e. > 10K revisions. In the spirit of "do no
 
2233
            # evil when adding features", we continue to use the
 
2234
            # original algorithm - per-file-graph - for the "single
 
2235
            # file that isn't a directory without showing a delta" case.
 
2236
            partial_history = revision and b.repository._format.supports_chks
 
2237
            match_using_deltas = (len(file_ids) != 1 or filter_by_dir
 
2238
                or delta_type or partial_history)
 
2239
 
 
2240
            # Build the LogRequest and execute it
 
2241
            if len(file_ids) == 0:
 
2242
                file_ids = None
 
2243
            rqst = make_log_request_dict(
 
2244
                direction=direction, specific_fileids=file_ids,
 
2245
                start_revision=rev1, end_revision=rev2, limit=limit,
 
2246
                message_search=message, delta_type=delta_type,
 
2247
                diff_type=diff_type, _match_using_deltas=match_using_deltas)
 
2248
            Logger(b, rqst).show(lf)
 
2249
        finally:
 
2250
            b.unlock()
 
2251
 
 
2252
 
 
2253
def _get_revision_range(revisionspec_list, branch, command_name):
 
2254
    """Take the input of a revision option and turn it into a revision range.
 
2255
 
 
2256
    It returns RevisionInfo objects which can be used to obtain the rev_id's
 
2257
    of the desired revisions. It does some user input validations.
 
2258
    """
 
2259
    if revisionspec_list is None:
 
2260
        rev1 = None
 
2261
        rev2 = None
 
2262
    elif len(revisionspec_list) == 1:
 
2263
        rev1 = rev2 = revisionspec_list[0].in_history(branch)
 
2264
    elif len(revisionspec_list) == 2:
 
2265
        start_spec = revisionspec_list[0]
 
2266
        end_spec = revisionspec_list[1]
 
2267
        if end_spec.get_branch() != start_spec.get_branch():
 
2268
            # b is taken from revision[0].get_branch(), and
 
2269
            # show_log will use its revision_history. Having
 
2270
            # different branches will lead to weird behaviors.
 
2271
            raise errors.BzrCommandError(
 
2272
                "bzr %s doesn't accept two revisions in different"
 
2273
                " branches." % command_name)
 
2274
        rev1 = start_spec.in_history(branch)
 
2275
        # Avoid loading all of history when we know a missing
 
2276
        # end of range means the last revision ...
 
2277
        if end_spec.spec is None:
 
2278
            last_revno, last_revision_id = branch.last_revision_info()
 
2279
            rev2 = RevisionInfo(branch, last_revno, last_revision_id)
 
2280
        else:
 
2281
            rev2 = end_spec.in_history(branch)
 
2282
    else:
 
2283
        raise errors.BzrCommandError(
 
2284
            'bzr %s --revision takes one or two values.' % command_name)
 
2285
    return rev1, rev2
 
2286
 
 
2287
 
 
2288
def _revision_range_to_revid_range(revision_range):
 
2289
    rev_id1 = None
 
2290
    rev_id2 = None
 
2291
    if revision_range[0] is not None:
 
2292
        rev_id1 = revision_range[0].rev_id
 
2293
    if revision_range[1] is not None:
 
2294
        rev_id2 = revision_range[1].rev_id
 
2295
    return rev_id1, rev_id2
 
2296
 
 
2297
def get_log_format(long=False, short=False, line=False, default='long'):
 
2298
    log_format = default
 
2299
    if long:
 
2300
        log_format = 'long'
 
2301
    if short:
 
2302
        log_format = 'short'
 
2303
    if line:
 
2304
        log_format = 'line'
 
2305
    return log_format
 
2306
 
 
2307
 
 
2308
class cmd_touching_revisions(Command):
 
2309
    """Return revision-ids which affected a particular file.
 
2310
 
 
2311
    A more user-friendly interface is "bzr log FILE".
 
2312
    """
 
2313
 
 
2314
    hidden = True
 
2315
    takes_args = ["filename"]
 
2316
 
 
2317
    @display_command
 
2318
    def run(self, filename):
 
2319
        tree, relpath = WorkingTree.open_containing(filename)
 
2320
        b = tree.branch
 
2321
        file_id = tree.path2id(relpath)
 
2322
        for revno, revision_id, what in log.find_touching_revisions(b, file_id):
 
2323
            self.outf.write("%6d %s\n" % (revno, what))
 
2324
 
 
2325
 
 
2326
class cmd_ls(Command):
 
2327
    """List files in a tree.
 
2328
    """
 
2329
 
 
2330
    _see_also = ['status', 'cat']
 
2331
    takes_args = ['path?']
 
2332
    takes_options = [
 
2333
            'verbose',
 
2334
            'revision',
 
2335
            Option('recursive', short_name='R',
 
2336
                   help='Recurse into subdirectories.'),
 
2337
            Option('from-root',
 
2338
                   help='Print paths relative to the root of the branch.'),
 
2339
            Option('unknown', help='Print unknown files.'),
 
2340
            Option('versioned', help='Print versioned files.',
 
2341
                   short_name='V'),
 
2342
            Option('ignored', help='Print ignored files.'),
 
2343
            Option('null',
 
2344
                   help='Write an ascii NUL (\\0) separator '
 
2345
                   'between files rather than a newline.'),
 
2346
            Option('kind',
 
2347
                   help='List entries of a particular kind: file, directory, symlink.',
 
2348
                   type=unicode),
 
2349
            'show-ids',
 
2350
            ]
 
2351
    @display_command
 
2352
    def run(self, revision=None, verbose=False,
 
2353
            recursive=False, from_root=False,
 
2354
            unknown=False, versioned=False, ignored=False,
 
2355
            null=False, kind=None, show_ids=False, path=None):
 
2356
        # Validate the command line options
 
2357
        if kind and kind not in ('file', 'directory', 'symlink'):
 
2358
            raise errors.BzrCommandError('invalid kind specified')
 
2359
        if verbose and null:
 
2360
            raise errors.BzrCommandError('Cannot set both --verbose and --null')
 
2361
        if path is None:
 
2362
            path = '.'
 
2363
        elif from_root:
 
2364
            raise errors.BzrCommandError('cannot specify both --from-root'
 
2365
                                         ' and PATH')
 
2366
 
 
2367
        # Get the tree
 
2368
        tree, branch, dir = bzrdir.BzrDir.open_containing_tree_or_branch(path)
 
2369
        mutter("ls dir is %s", dir)
 
2370
        if revision is not None or tree is None:
 
2371
            tree = _get_one_revision_tree('ls', revision, branch=branch)
 
2372
 
 
2373
        # Calculate the prefix to use
 
2374
        prefix = None
 
2375
        if from_root:
 
2376
            if dir:
 
2377
                prefix = dir + '/'
 
2378
        elif path != '.':
 
2379
            prefix = path + '/'
 
2380
 
 
2381
        # Display the files
 
2382
        from bzrlib import ls
 
2383
        ls.ls(tree, self.outf, from_dir=dir, recursive=recursive,
 
2384
            kind=kind, unknown=unknown, versioned=versioned, ignored=ignored,
 
2385
            verbose=verbose, null=null, show_ids=show_ids, prefix=prefix)
 
2386
 
 
2387
 
 
2388
class cmd_unknowns(Command):
 
2389
    """List unknown files.
 
2390
    """
 
2391
 
 
2392
    hidden = True
 
2393
    _see_also = ['ls']
 
2394
 
 
2395
    @display_command
 
2396
    def run(self):
 
2397
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
 
2398
            self.outf.write(osutils.quotefn(f) + '\n')
 
2399
 
 
2400
 
 
2401
class cmd_ignore(Command):
 
2402
    """Ignore specified files or patterns.
 
2403
 
 
2404
    See ``bzr help patterns`` for details on the syntax of patterns.
 
2405
 
 
2406
    To remove patterns from the ignore list, edit the .bzrignore file.
 
2407
    After adding, editing or deleting that file either indirectly by
 
2408
    using this command or directly by using an editor, be sure to commit
 
2409
    it.
 
2410
 
 
2411
    Note: ignore patterns containing shell wildcards must be quoted from
 
2412
    the shell on Unix.
 
2413
 
 
2414
    :Examples:
 
2415
        Ignore the top level Makefile::
 
2416
 
 
2417
            bzr ignore ./Makefile
 
2418
 
 
2419
        Ignore class files in all directories::
 
2420
 
 
2421
            bzr ignore "*.class"
 
2422
 
 
2423
        Ignore .o files under the lib directory::
 
2424
 
 
2425
            bzr ignore "lib/**/*.o"
 
2426
 
 
2427
        Ignore .o files under the lib directory::
 
2428
 
 
2429
            bzr ignore "RE:lib/.*\.o"
 
2430
 
 
2431
        Ignore everything but the "debian" toplevel directory::
 
2432
 
 
2433
            bzr ignore "RE:(?!debian/).*"
 
2434
    """
 
2435
 
 
2436
    _see_also = ['status', 'ignored', 'patterns']
 
2437
    takes_args = ['name_pattern*']
 
2438
    takes_options = [
 
2439
        Option('old-default-rules',
 
2440
               help='Write out the ignore rules bzr < 0.9 always used.')
 
2441
        ]
 
2442
 
 
2443
    def run(self, name_pattern_list=None, old_default_rules=None):
 
2444
        from bzrlib import ignores
 
2445
        if old_default_rules is not None:
 
2446
            # dump the rules and exit
 
2447
            for pattern in ignores.OLD_DEFAULTS:
 
2448
                print pattern
 
2449
            return
 
2450
        if not name_pattern_list:
 
2451
            raise errors.BzrCommandError("ignore requires at least one "
 
2452
                                  "NAME_PATTERN or --old-default-rules")
 
2453
        name_pattern_list = [globbing.normalize_pattern(p)
 
2454
                             for p in name_pattern_list]
 
2455
        for name_pattern in name_pattern_list:
 
2456
            if (name_pattern[0] == '/' or
 
2457
                (len(name_pattern) > 1 and name_pattern[1] == ':')):
 
2458
                raise errors.BzrCommandError(
 
2459
                    "NAME_PATTERN should not be an absolute path")
 
2460
        tree, relpath = WorkingTree.open_containing(u'.')
 
2461
        ignores.tree_ignores_add_patterns(tree, name_pattern_list)
 
2462
        ignored = globbing.Globster(name_pattern_list)
 
2463
        matches = []
 
2464
        tree.lock_read()
 
2465
        for entry in tree.list_files():
 
2466
            id = entry[3]
 
2467
            if id is not None:
 
2468
                filename = entry[0]
 
2469
                if ignored.match(filename):
 
2470
                    matches.append(filename.encode('utf-8'))
 
2471
        tree.unlock()
 
2472
        if len(matches) > 0:
 
2473
            print "Warning: the following files are version controlled and" \
 
2474
                  " match your ignore pattern:\n%s" \
 
2475
                  "\nThese files will continue to be version controlled" \
 
2476
                  " unless you 'bzr remove' them." % ("\n".join(matches),)
 
2477
 
 
2478
 
 
2479
class cmd_ignored(Command):
 
2480
    """List ignored files and the patterns that matched them.
 
2481
 
 
2482
    List all the ignored files and the ignore pattern that caused the file to
 
2483
    be ignored.
 
2484
 
 
2485
    Alternatively, to list just the files::
 
2486
 
 
2487
        bzr ls --ignored
 
2488
    """
 
2489
 
 
2490
    encoding_type = 'replace'
 
2491
    _see_also = ['ignore', 'ls']
 
2492
 
 
2493
    @display_command
 
2494
    def run(self):
 
2495
        tree = WorkingTree.open_containing(u'.')[0]
 
2496
        tree.lock_read()
 
2497
        try:
 
2498
            for path, file_class, kind, file_id, entry in tree.list_files():
 
2499
                if file_class != 'I':
 
2500
                    continue
 
2501
                ## XXX: Slightly inefficient since this was already calculated
 
2502
                pat = tree.is_ignored(path)
 
2503
                self.outf.write('%-50s %s\n' % (path, pat))
 
2504
        finally:
 
2505
            tree.unlock()
 
2506
 
 
2507
 
 
2508
class cmd_lookup_revision(Command):
 
2509
    """Lookup the revision-id from a revision-number
 
2510
 
 
2511
    :Examples:
 
2512
        bzr lookup-revision 33
 
2513
    """
 
2514
    hidden = True
 
2515
    takes_args = ['revno']
 
2516
 
 
2517
    @display_command
 
2518
    def run(self, revno):
 
2519
        try:
 
2520
            revno = int(revno)
 
2521
        except ValueError:
 
2522
            raise errors.BzrCommandError("not a valid revision-number: %r" % revno)
 
2523
 
 
2524
        print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
 
2525
 
 
2526
 
 
2527
class cmd_export(Command):
 
2528
    """Export current or past revision to a destination directory or archive.
 
2529
 
 
2530
    If no revision is specified this exports the last committed revision.
 
2531
 
 
2532
    Format may be an "exporter" name, such as tar, tgz, tbz2.  If none is
 
2533
    given, try to find the format with the extension. If no extension
 
2534
    is found exports to a directory (equivalent to --format=dir).
 
2535
 
 
2536
    If root is supplied, it will be used as the root directory inside
 
2537
    container formats (tar, zip, etc). If it is not supplied it will default
 
2538
    to the exported filename. The root option has no effect for 'dir' format.
 
2539
 
 
2540
    If branch is omitted then the branch containing the current working
 
2541
    directory will be used.
 
2542
 
 
2543
    Note: Export of tree with non-ASCII filenames to zip is not supported.
 
2544
 
 
2545
      =================       =========================
 
2546
      Supported formats       Autodetected by extension
 
2547
      =================       =========================
 
2548
         dir                         (none)
 
2549
         tar                          .tar
 
2550
         tbz2                    .tar.bz2, .tbz2
 
2551
         tgz                      .tar.gz, .tgz
 
2552
         zip                          .zip
 
2553
      =================       =========================
 
2554
    """
 
2555
    takes_args = ['dest', 'branch_or_subdir?']
 
2556
    takes_options = [
 
2557
        Option('format',
 
2558
               help="Type of file to export to.",
 
2559
               type=unicode),
 
2560
        'revision',
 
2561
        Option('filters', help='Apply content filters to export the '
 
2562
                'convenient form.'),
 
2563
        Option('root',
 
2564
               type=str,
 
2565
               help="Name of the root directory inside the exported file."),
 
2566
        ]
 
2567
    def run(self, dest, branch_or_subdir=None, revision=None, format=None,
 
2568
        root=None, filters=False):
 
2569
        from bzrlib.export import export
 
2570
 
 
2571
        if branch_or_subdir is None:
 
2572
            tree = WorkingTree.open_containing(u'.')[0]
 
2573
            b = tree.branch
 
2574
            subdir = None
 
2575
        else:
 
2576
            b, subdir = Branch.open_containing(branch_or_subdir)
 
2577
            tree = None
 
2578
 
 
2579
        rev_tree = _get_one_revision_tree('export', revision, branch=b, tree=tree)
 
2580
        try:
 
2581
            export(rev_tree, dest, format, root, subdir, filtered=filters)
 
2582
        except errors.NoSuchExportFormat, e:
 
2583
            raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
 
2584
 
 
2585
 
 
2586
class cmd_cat(Command):
 
2587
    """Write the contents of a file as of a given revision to standard output.
 
2588
 
 
2589
    If no revision is nominated, the last revision is used.
 
2590
 
 
2591
    Note: Take care to redirect standard output when using this command on a
 
2592
    binary file.
 
2593
    """
 
2594
 
 
2595
    _see_also = ['ls']
 
2596
    takes_options = [
 
2597
        Option('name-from-revision', help='The path name in the old tree.'),
 
2598
        Option('filters', help='Apply content filters to display the '
 
2599
                'convenience form.'),
 
2600
        'revision',
 
2601
        ]
 
2602
    takes_args = ['filename']
 
2603
    encoding_type = 'exact'
 
2604
 
 
2605
    @display_command
 
2606
    def run(self, filename, revision=None, name_from_revision=False,
 
2607
            filters=False):
 
2608
        if revision is not None and len(revision) != 1:
 
2609
            raise errors.BzrCommandError("bzr cat --revision takes exactly"
 
2610
                                         " one revision specifier")
 
2611
        tree, branch, relpath = \
 
2612
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
 
2613
        branch.lock_read()
 
2614
        try:
 
2615
            return self._run(tree, branch, relpath, filename, revision,
 
2616
                             name_from_revision, filters)
 
2617
        finally:
 
2618
            branch.unlock()
 
2619
 
 
2620
    def _run(self, tree, b, relpath, filename, revision, name_from_revision,
 
2621
        filtered):
 
2622
        if tree is None:
 
2623
            tree = b.basis_tree()
 
2624
        rev_tree = _get_one_revision_tree('cat', revision, branch=b)
 
2625
 
 
2626
        old_file_id = rev_tree.path2id(relpath)
 
2627
 
 
2628
        if name_from_revision:
 
2629
            # Try in revision if requested
 
2630
            if old_file_id is None:
 
2631
                raise errors.BzrCommandError(
 
2632
                    "%r is not present in revision %s" % (
 
2633
                        filename, rev_tree.get_revision_id()))
 
2634
            else:
 
2635
                content = rev_tree.get_file_text(old_file_id)
 
2636
        else:
 
2637
            cur_file_id = tree.path2id(relpath)
 
2638
            found = False
 
2639
            if cur_file_id is not None:
 
2640
                # Then try with the actual file id
 
2641
                try:
 
2642
                    content = rev_tree.get_file_text(cur_file_id)
 
2643
                    found = True
 
2644
                except errors.NoSuchId:
 
2645
                    # The actual file id didn't exist at that time
 
2646
                    pass
 
2647
            if not found and old_file_id is not None:
 
2648
                # Finally try with the old file id
 
2649
                content = rev_tree.get_file_text(old_file_id)
 
2650
                found = True
 
2651
            if not found:
 
2652
                # Can't be found anywhere
 
2653
                raise errors.BzrCommandError(
 
2654
                    "%r is not present in revision %s" % (
 
2655
                        filename, rev_tree.get_revision_id()))
 
2656
        if filtered:
 
2657
            from bzrlib.filters import (
 
2658
                ContentFilterContext,
 
2659
                filtered_output_bytes,
 
2660
                )
 
2661
            filters = rev_tree._content_filter_stack(relpath)
 
2662
            chunks = content.splitlines(True)
 
2663
            content = filtered_output_bytes(chunks, filters,
 
2664
                ContentFilterContext(relpath, rev_tree))
 
2665
            self.outf.writelines(content)
 
2666
        else:
 
2667
            self.outf.write(content)
 
2668
 
 
2669
 
 
2670
class cmd_local_time_offset(Command):
 
2671
    """Show the offset in seconds from GMT to local time."""
 
2672
    hidden = True
 
2673
    @display_command
 
2674
    def run(self):
 
2675
        print osutils.local_time_offset()
 
2676
 
 
2677
 
 
2678
 
 
2679
class cmd_commit(Command):
 
2680
    """Commit changes into a new revision.
 
2681
 
 
2682
    An explanatory message needs to be given for each commit. This is
 
2683
    often done by using the --message option (getting the message from the
 
2684
    command line) or by using the --file option (getting the message from
 
2685
    a file). If neither of these options is given, an editor is opened for
 
2686
    the user to enter the message. To see the changed files in the
 
2687
    boilerplate text loaded into the editor, use the --show-diff option.
 
2688
 
 
2689
    By default, the entire tree is committed and the person doing the
 
2690
    commit is assumed to be the author. These defaults can be overridden
 
2691
    as explained below.
 
2692
 
 
2693
    :Selective commits:
 
2694
 
 
2695
      If selected files are specified, only changes to those files are
 
2696
      committed.  If a directory is specified then the directory and
 
2697
      everything within it is committed.
 
2698
  
 
2699
      When excludes are given, they take precedence over selected files.
 
2700
      For example, to commit only changes within foo, but not changes
 
2701
      within foo/bar::
 
2702
  
 
2703
        bzr commit foo -x foo/bar
 
2704
  
 
2705
      A selective commit after a merge is not yet supported.
 
2706
 
 
2707
    :Custom authors:
 
2708
 
 
2709
      If the author of the change is not the same person as the committer,
 
2710
      you can specify the author's name using the --author option. The
 
2711
      name should be in the same format as a committer-id, e.g.
 
2712
      "John Doe <jdoe@example.com>". If there is more than one author of
 
2713
      the change you can specify the option multiple times, once for each
 
2714
      author.
 
2715
  
 
2716
    :Checks:
 
2717
 
 
2718
      A common mistake is to forget to add a new file or directory before
 
2719
      running the commit command. The --strict option checks for unknown
 
2720
      files and aborts the commit if any are found. More advanced pre-commit
 
2721
      checks can be implemented by defining hooks. See ``bzr help hooks``
 
2722
      for details.
 
2723
 
 
2724
    :Things to note:
 
2725
 
 
2726
      If you accidentially commit the wrong changes or make a spelling
 
2727
      mistake in the commit message say, you can use the uncommit command
 
2728
      to undo it. See ``bzr help uncommit`` for details.
 
2729
 
 
2730
      Hooks can also be configured to run after a commit. This allows you
 
2731
      to trigger updates to external systems like bug trackers. The --fixes
 
2732
      option can be used to record the association between a revision and
 
2733
      one or more bugs. See ``bzr help bugs`` for details.
 
2734
 
 
2735
      A selective commit may fail in some cases where the committed
 
2736
      tree would be invalid. Consider::
 
2737
  
 
2738
        bzr init foo
 
2739
        mkdir foo/bar
 
2740
        bzr add foo/bar
 
2741
        bzr commit foo -m "committing foo"
 
2742
        bzr mv foo/bar foo/baz
 
2743
        mkdir foo/bar
 
2744
        bzr add foo/bar
 
2745
        bzr commit foo/bar -m "committing bar but not baz"
 
2746
  
 
2747
      In the example above, the last commit will fail by design. This gives
 
2748
      the user the opportunity to decide whether they want to commit the
 
2749
      rename at the same time, separately first, or not at all. (As a general
 
2750
      rule, when in doubt, Bazaar has a policy of Doing the Safe Thing.)
 
2751
    """
 
2752
    # TODO: Run hooks on tree to-be-committed, and after commit.
 
2753
 
 
2754
    # TODO: Strict commit that fails if there are deleted files.
 
2755
    #       (what does "deleted files" mean ??)
 
2756
 
 
2757
    # TODO: Give better message for -s, --summary, used by tla people
 
2758
 
 
2759
    # XXX: verbose currently does nothing
 
2760
 
 
2761
    _see_also = ['add', 'bugs', 'hooks', 'uncommit']
 
2762
    takes_args = ['selected*']
 
2763
    takes_options = [
 
2764
            ListOption('exclude', type=str, short_name='x',
 
2765
                help="Do not consider changes made to a given path."),
 
2766
            Option('message', type=unicode,
 
2767
                   short_name='m',
 
2768
                   help="Description of the new revision."),
 
2769
            'verbose',
 
2770
             Option('unchanged',
 
2771
                    help='Commit even if nothing has changed.'),
 
2772
             Option('file', type=str,
 
2773
                    short_name='F',
 
2774
                    argname='msgfile',
 
2775
                    help='Take commit message from this file.'),
 
2776
             Option('strict',
 
2777
                    help="Refuse to commit if there are unknown "
 
2778
                    "files in the working tree."),
 
2779
             ListOption('fixes', type=str,
 
2780
                    help="Mark a bug as being fixed by this revision "
 
2781
                         "(see \"bzr help bugs\")."),
 
2782
             ListOption('author', type=unicode,
 
2783
                    help="Set the author's name, if it's different "
 
2784
                         "from the committer."),
 
2785
             Option('local',
 
2786
                    help="Perform a local commit in a bound "
 
2787
                         "branch.  Local commits are not pushed to "
 
2788
                         "the master branch until a normal commit "
 
2789
                         "is performed."
 
2790
                    ),
 
2791
              Option('show-diff',
 
2792
                     help='When no message is supplied, show the diff along'
 
2793
                     ' with the status summary in the message editor.'),
 
2794
             ]
 
2795
    aliases = ['ci', 'checkin']
 
2796
 
 
2797
    def _iter_bug_fix_urls(self, fixes, branch):
 
2798
        # Configure the properties for bug fixing attributes.
 
2799
        for fixed_bug in fixes:
 
2800
            tokens = fixed_bug.split(':')
 
2801
            if len(tokens) != 2:
 
2802
                raise errors.BzrCommandError(
 
2803
                    "Invalid bug %s. Must be in the form of 'tracker:id'. "
 
2804
                    "See \"bzr help bugs\" for more information on this "
 
2805
                    "feature.\nCommit refused." % fixed_bug)
 
2806
            tag, bug_id = tokens
 
2807
            try:
 
2808
                yield bugtracker.get_bug_url(tag, branch, bug_id)
 
2809
            except errors.UnknownBugTrackerAbbreviation:
 
2810
                raise errors.BzrCommandError(
 
2811
                    'Unrecognized bug %s. Commit refused.' % fixed_bug)
 
2812
            except errors.MalformedBugIdentifier, e:
 
2813
                raise errors.BzrCommandError(
 
2814
                    "%s\nCommit refused." % (str(e),))
 
2815
 
 
2816
    def run(self, message=None, file=None, verbose=False, selected_list=None,
 
2817
            unchanged=False, strict=False, local=False, fixes=None,
 
2818
            author=None, show_diff=False, exclude=None):
 
2819
        from bzrlib.errors import (
 
2820
            PointlessCommit,
 
2821
            ConflictsInTree,
 
2822
            StrictCommitFailed
 
2823
        )
 
2824
        from bzrlib.msgeditor import (
 
2825
            edit_commit_message_encoded,
 
2826
            generate_commit_message_template,
 
2827
            make_commit_message_template_encoded
 
2828
        )
 
2829
 
 
2830
        # TODO: Need a blackbox test for invoking the external editor; may be
 
2831
        # slightly problematic to run this cross-platform.
 
2832
 
 
2833
        # TODO: do more checks that the commit will succeed before
 
2834
        # spending the user's valuable time typing a commit message.
 
2835
 
 
2836
        properties = {}
 
2837
 
 
2838
        tree, selected_list = tree_files(selected_list)
 
2839
        if selected_list == ['']:
 
2840
            # workaround - commit of root of tree should be exactly the same
 
2841
            # as just default commit in that tree, and succeed even though
 
2842
            # selected-file merge commit is not done yet
 
2843
            selected_list = []
 
2844
 
 
2845
        if fixes is None:
 
2846
            fixes = []
 
2847
        bug_property = bugtracker.encode_fixes_bug_urls(
 
2848
            self._iter_bug_fix_urls(fixes, tree.branch))
 
2849
        if bug_property:
 
2850
            properties['bugs'] = bug_property
 
2851
 
 
2852
        if local and not tree.branch.get_bound_location():
 
2853
            raise errors.LocalRequiresBoundBranch()
 
2854
 
 
2855
        def get_message(commit_obj):
 
2856
            """Callback to get commit message"""
 
2857
            my_message = message
 
2858
            if my_message is None and not file:
 
2859
                t = make_commit_message_template_encoded(tree,
 
2860
                        selected_list, diff=show_diff,
 
2861
                        output_encoding=osutils.get_user_encoding())
 
2862
                start_message = generate_commit_message_template(commit_obj)
 
2863
                my_message = edit_commit_message_encoded(t,
 
2864
                    start_message=start_message)
 
2865
                if my_message is None:
 
2866
                    raise errors.BzrCommandError("please specify a commit"
 
2867
                        " message with either --message or --file")
 
2868
            elif my_message and file:
 
2869
                raise errors.BzrCommandError(
 
2870
                    "please specify either --message or --file")
 
2871
            if file:
 
2872
                my_message = codecs.open(file, 'rt',
 
2873
                                         osutils.get_user_encoding()).read()
 
2874
            if my_message == "":
 
2875
                raise errors.BzrCommandError("empty commit message specified")
 
2876
            return my_message
 
2877
 
 
2878
        try:
 
2879
            tree.commit(message_callback=get_message,
 
2880
                        specific_files=selected_list,
 
2881
                        allow_pointless=unchanged, strict=strict, local=local,
 
2882
                        reporter=None, verbose=verbose, revprops=properties,
 
2883
                        authors=author,
 
2884
                        exclude=safe_relpath_files(tree, exclude))
 
2885
        except PointlessCommit:
 
2886
            # FIXME: This should really happen before the file is read in;
 
2887
            # perhaps prepare the commit; get the message; then actually commit
 
2888
            raise errors.BzrCommandError("No changes to commit."
 
2889
                              " Use --unchanged to commit anyhow.")
 
2890
        except ConflictsInTree:
 
2891
            raise errors.BzrCommandError('Conflicts detected in working '
 
2892
                'tree.  Use "bzr conflicts" to list, "bzr resolve FILE" to'
 
2893
                ' resolve.')
 
2894
        except StrictCommitFailed:
 
2895
            raise errors.BzrCommandError("Commit refused because there are"
 
2896
                              " unknown files in the working tree.")
 
2897
        except errors.BoundBranchOutOfDate, e:
 
2898
            raise errors.BzrCommandError(str(e) + "\n"
 
2899
            'To commit to master branch, run update and then commit.\n'
 
2900
            'You can also pass --local to commit to continue working '
 
2901
            'disconnected.')
 
2902
 
 
2903
 
 
2904
class cmd_check(Command):
 
2905
    """Validate working tree structure, branch consistency and repository history.
 
2906
 
 
2907
    This command checks various invariants about branch and repository storage
 
2908
    to detect data corruption or bzr bugs.
 
2909
 
 
2910
    The working tree and branch checks will only give output if a problem is
 
2911
    detected. The output fields of the repository check are:
 
2912
 
 
2913
        revisions: This is just the number of revisions checked.  It doesn't
 
2914
            indicate a problem.
 
2915
        versionedfiles: This is just the number of versionedfiles checked.  It
 
2916
            doesn't indicate a problem.
 
2917
        unreferenced ancestors: Texts that are ancestors of other texts, but
 
2918
            are not properly referenced by the revision ancestry.  This is a
 
2919
            subtle problem that Bazaar can work around.
 
2920
        unique file texts: This is the total number of unique file contents
 
2921
            seen in the checked revisions.  It does not indicate a problem.
 
2922
        repeated file texts: This is the total number of repeated texts seen
 
2923
            in the checked revisions.  Texts can be repeated when their file
 
2924
            entries are modified, but the file contents are not.  It does not
 
2925
            indicate a problem.
 
2926
 
 
2927
    If no restrictions are specified, all Bazaar data that is found at the given
 
2928
    location will be checked.
 
2929
 
 
2930
    :Examples:
 
2931
 
 
2932
        Check the tree and branch at 'foo'::
 
2933
 
 
2934
            bzr check --tree --branch foo
 
2935
 
 
2936
        Check only the repository at 'bar'::
 
2937
 
 
2938
            bzr check --repo bar
 
2939
 
 
2940
        Check everything at 'baz'::
 
2941
 
 
2942
            bzr check baz
 
2943
    """
 
2944
 
 
2945
    _see_also = ['reconcile']
 
2946
    takes_args = ['path?']
 
2947
    takes_options = ['verbose',
 
2948
                     Option('branch', help="Check the branch related to the"
 
2949
                                           " current directory."),
 
2950
                     Option('repo', help="Check the repository related to the"
 
2951
                                         " current directory."),
 
2952
                     Option('tree', help="Check the working tree related to"
 
2953
                                         " the current directory.")]
 
2954
 
 
2955
    def run(self, path=None, verbose=False, branch=False, repo=False,
 
2956
            tree=False):
 
2957
        from bzrlib.check import check_dwim
 
2958
        if path is None:
 
2959
            path = '.'
 
2960
        if not branch and not repo and not tree:
 
2961
            branch = repo = tree = True
 
2962
        check_dwim(path, verbose, do_branch=branch, do_repo=repo, do_tree=tree)
 
2963
 
 
2964
 
 
2965
class cmd_upgrade(Command):
 
2966
    """Upgrade branch storage to current format.
 
2967
 
 
2968
    The check command or bzr developers may sometimes advise you to run
 
2969
    this command. When the default format has changed you may also be warned
 
2970
    during other operations to upgrade.
 
2971
    """
 
2972
 
 
2973
    _see_also = ['check']
 
2974
    takes_args = ['url?']
 
2975
    takes_options = [
 
2976
                    RegistryOption('format',
 
2977
                        help='Upgrade to a specific format.  See "bzr help'
 
2978
                             ' formats" for details.',
 
2979
                        lazy_registry=('bzrlib.bzrdir', 'format_registry'),
 
2980
                        converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
 
2981
                        value_switches=True, title='Branch format'),
 
2982
                    ]
 
2983
 
 
2984
    def run(self, url='.', format=None):
 
2985
        from bzrlib.upgrade import upgrade
 
2986
        upgrade(url, format)
 
2987
 
 
2988
 
 
2989
class cmd_whoami(Command):
 
2990
    """Show or set bzr user id.
 
2991
 
 
2992
    :Examples:
 
2993
        Show the email of the current user::
 
2994
 
 
2995
            bzr whoami --email
 
2996
 
 
2997
        Set the current user::
 
2998
 
 
2999
            bzr whoami "Frank Chu <fchu@example.com>"
 
3000
    """
 
3001
    takes_options = [ Option('email',
 
3002
                             help='Display email address only.'),
 
3003
                      Option('branch',
 
3004
                             help='Set identity for the current branch instead of '
 
3005
                                  'globally.'),
 
3006
                    ]
 
3007
    takes_args = ['name?']
 
3008
    encoding_type = 'replace'
 
3009
 
 
3010
    @display_command
 
3011
    def run(self, email=False, branch=False, name=None):
 
3012
        if name is None:
 
3013
            # use branch if we're inside one; otherwise global config
 
3014
            try:
 
3015
                c = Branch.open_containing('.')[0].get_config()
 
3016
            except errors.NotBranchError:
 
3017
                c = config.GlobalConfig()
 
3018
            if email:
 
3019
                self.outf.write(c.user_email() + '\n')
 
3020
            else:
 
3021
                self.outf.write(c.username() + '\n')
 
3022
            return
 
3023
 
 
3024
        # display a warning if an email address isn't included in the given name.
 
3025
        try:
 
3026
            config.extract_email_address(name)
 
3027
        except errors.NoEmailInUsername, e:
 
3028
            warning('"%s" does not seem to contain an email address.  '
 
3029
                    'This is allowed, but not recommended.', name)
 
3030
 
 
3031
        # use global config unless --branch given
 
3032
        if branch:
 
3033
            c = Branch.open_containing('.')[0].get_config()
 
3034
        else:
 
3035
            c = config.GlobalConfig()
 
3036
        c.set_user_option('email', name)
 
3037
 
 
3038
 
 
3039
class cmd_nick(Command):
 
3040
    """Print or set the branch nickname.
 
3041
 
 
3042
    If unset, the tree root directory name is used as the nickname.
 
3043
    To print the current nickname, execute with no argument.
 
3044
 
 
3045
    Bound branches use the nickname of its master branch unless it is set
 
3046
    locally.
 
3047
    """
 
3048
 
 
3049
    _see_also = ['info']
 
3050
    takes_args = ['nickname?']
 
3051
    def run(self, nickname=None):
 
3052
        branch = Branch.open_containing(u'.')[0]
 
3053
        if nickname is None:
 
3054
            self.printme(branch)
 
3055
        else:
 
3056
            branch.nick = nickname
 
3057
 
 
3058
    @display_command
 
3059
    def printme(self, branch):
 
3060
        print branch.nick
 
3061
 
 
3062
 
 
3063
class cmd_alias(Command):
 
3064
    """Set/unset and display aliases.
 
3065
 
 
3066
    :Examples:
 
3067
        Show the current aliases::
 
3068
 
 
3069
            bzr alias
 
3070
 
 
3071
        Show the alias specified for 'll'::
 
3072
 
 
3073
            bzr alias ll
 
3074
 
 
3075
        Set an alias for 'll'::
 
3076
 
 
3077
            bzr alias ll="log --line -r-10..-1"
 
3078
 
 
3079
        To remove an alias for 'll'::
 
3080
 
 
3081
            bzr alias --remove ll
 
3082
 
 
3083
    """
 
3084
    takes_args = ['name?']
 
3085
    takes_options = [
 
3086
        Option('remove', help='Remove the alias.'),
 
3087
        ]
 
3088
 
 
3089
    def run(self, name=None, remove=False):
 
3090
        if remove:
 
3091
            self.remove_alias(name)
 
3092
        elif name is None:
 
3093
            self.print_aliases()
 
3094
        else:
 
3095
            equal_pos = name.find('=')
 
3096
            if equal_pos == -1:
 
3097
                self.print_alias(name)
 
3098
            else:
 
3099
                self.set_alias(name[:equal_pos], name[equal_pos+1:])
 
3100
 
 
3101
    def remove_alias(self, alias_name):
 
3102
        if alias_name is None:
 
3103
            raise errors.BzrCommandError(
 
3104
                'bzr alias --remove expects an alias to remove.')
 
3105
        # If alias is not found, print something like:
 
3106
        # unalias: foo: not found
 
3107
        c = config.GlobalConfig()
 
3108
        c.unset_alias(alias_name)
 
3109
 
 
3110
    @display_command
 
3111
    def print_aliases(self):
 
3112
        """Print out the defined aliases in a similar format to bash."""
 
3113
        aliases = config.GlobalConfig().get_aliases()
 
3114
        for key, value in sorted(aliases.iteritems()):
 
3115
            self.outf.write('bzr alias %s="%s"\n' % (key, value))
 
3116
 
 
3117
    @display_command
 
3118
    def print_alias(self, alias_name):
 
3119
        from bzrlib.commands import get_alias
 
3120
        alias = get_alias(alias_name)
 
3121
        if alias is None:
 
3122
            self.outf.write("bzr alias: %s: not found\n" % alias_name)
 
3123
        else:
 
3124
            self.outf.write(
 
3125
                'bzr alias %s="%s"\n' % (alias_name, ' '.join(alias)))
 
3126
 
 
3127
    def set_alias(self, alias_name, alias_command):
 
3128
        """Save the alias in the global config."""
 
3129
        c = config.GlobalConfig()
 
3130
        c.set_alias(alias_name, alias_command)
 
3131
 
 
3132
 
 
3133
class cmd_selftest(Command):
 
3134
    """Run internal test suite.
 
3135
 
 
3136
    If arguments are given, they are regular expressions that say which tests
 
3137
    should run.  Tests matching any expression are run, and other tests are
 
3138
    not run.
 
3139
 
 
3140
    Alternatively if --first is given, matching tests are run first and then
 
3141
    all other tests are run.  This is useful if you have been working in a
 
3142
    particular area, but want to make sure nothing else was broken.
 
3143
 
 
3144
    If --exclude is given, tests that match that regular expression are
 
3145
    excluded, regardless of whether they match --first or not.
 
3146
 
 
3147
    To help catch accidential dependencies between tests, the --randomize
 
3148
    option is useful. In most cases, the argument used is the word 'now'.
 
3149
    Note that the seed used for the random number generator is displayed
 
3150
    when this option is used. The seed can be explicitly passed as the
 
3151
    argument to this option if required. This enables reproduction of the
 
3152
    actual ordering used if and when an order sensitive problem is encountered.
 
3153
 
 
3154
    If --list-only is given, the tests that would be run are listed. This is
 
3155
    useful when combined with --first, --exclude and/or --randomize to
 
3156
    understand their impact. The test harness reports "Listed nn tests in ..."
 
3157
    instead of "Ran nn tests in ..." when list mode is enabled.
 
3158
 
 
3159
    If the global option '--no-plugins' is given, plugins are not loaded
 
3160
    before running the selftests.  This has two effects: features provided or
 
3161
    modified by plugins will not be tested, and tests provided by plugins will
 
3162
    not be run.
 
3163
 
 
3164
    Tests that need working space on disk use a common temporary directory,
 
3165
    typically inside $TMPDIR or /tmp.
 
3166
 
 
3167
    :Examples:
 
3168
        Run only tests relating to 'ignore'::
 
3169
 
 
3170
            bzr selftest ignore
 
3171
 
 
3172
        Disable plugins and list tests as they're run::
 
3173
 
 
3174
            bzr --no-plugins selftest -v
 
3175
    """
 
3176
    # NB: this is used from the class without creating an instance, which is
 
3177
    # why it does not have a self parameter.
 
3178
    def get_transport_type(typestring):
 
3179
        """Parse and return a transport specifier."""
 
3180
        if typestring == "sftp":
 
3181
            from bzrlib.transport.sftp import SFTPAbsoluteServer
 
3182
            return SFTPAbsoluteServer
 
3183
        if typestring == "memory":
 
3184
            from bzrlib.transport.memory import MemoryServer
 
3185
            return MemoryServer
 
3186
        if typestring == "fakenfs":
 
3187
            from bzrlib.transport.fakenfs import FakeNFSServer
 
3188
            return FakeNFSServer
 
3189
        msg = "No known transport type %s. Supported types are: sftp\n" %\
 
3190
            (typestring)
 
3191
        raise errors.BzrCommandError(msg)
 
3192
 
 
3193
    hidden = True
 
3194
    takes_args = ['testspecs*']
 
3195
    takes_options = ['verbose',
 
3196
                     Option('one',
 
3197
                             help='Stop when one test fails.',
 
3198
                             short_name='1',
 
3199
                             ),
 
3200
                     Option('transport',
 
3201
                            help='Use a different transport by default '
 
3202
                                 'throughout the test suite.',
 
3203
                            type=get_transport_type),
 
3204
                     Option('benchmark',
 
3205
                            help='Run the benchmarks rather than selftests.'),
 
3206
                     Option('lsprof-timed',
 
3207
                            help='Generate lsprof output for benchmarked'
 
3208
                                 ' sections of code.'),
 
3209
                     Option('cache-dir', type=str,
 
3210
                            help='Cache intermediate benchmark output in this '
 
3211
                                 'directory.'),
 
3212
                     Option('first',
 
3213
                            help='Run all tests, but run specified tests first.',
 
3214
                            short_name='f',
 
3215
                            ),
 
3216
                     Option('list-only',
 
3217
                            help='List the tests instead of running them.'),
 
3218
                     RegistryOption('parallel',
 
3219
                        help="Run the test suite in parallel.",
 
3220
                        lazy_registry=('bzrlib.tests', 'parallel_registry'),
 
3221
                        value_switches=False,
 
3222
                        ),
 
3223
                     Option('randomize', type=str, argname="SEED",
 
3224
                            help='Randomize the order of tests using the given'
 
3225
                                 ' seed or "now" for the current time.'),
 
3226
                     Option('exclude', type=str, argname="PATTERN",
 
3227
                            short_name='x',
 
3228
                            help='Exclude tests that match this regular'
 
3229
                                 ' expression.'),
 
3230
                     Option('subunit',
 
3231
                        help='Output test progress via subunit.'),
 
3232
                     Option('strict', help='Fail on missing dependencies or '
 
3233
                            'known failures.'),
 
3234
                     Option('load-list', type=str, argname='TESTLISTFILE',
 
3235
                            help='Load a test id list from a text file.'),
 
3236
                     ListOption('debugflag', type=str, short_name='E',
 
3237
                                help='Turn on a selftest debug flag.'),
 
3238
                     ListOption('starting-with', type=str, argname='TESTID',
 
3239
                                param_name='starting_with', short_name='s',
 
3240
                                help=
 
3241
                                'Load only the tests starting with TESTID.'),
 
3242
                     ]
 
3243
    encoding_type = 'replace'
 
3244
 
 
3245
    def __init__(self):
 
3246
        Command.__init__(self)
 
3247
        self.additional_selftest_args = {}
 
3248
 
 
3249
    def run(self, testspecs_list=None, verbose=False, one=False,
 
3250
            transport=None, benchmark=None,
 
3251
            lsprof_timed=None, cache_dir=None,
 
3252
            first=False, list_only=False,
 
3253
            randomize=None, exclude=None, strict=False,
 
3254
            load_list=None, debugflag=None, starting_with=None, subunit=False,
 
3255
            parallel=None):
 
3256
        from bzrlib.tests import selftest
 
3257
        import bzrlib.benchmarks as benchmarks
 
3258
        from bzrlib.benchmarks import tree_creator
 
3259
 
 
3260
        # Make deprecation warnings visible, unless -Werror is set
 
3261
        symbol_versioning.activate_deprecation_warnings(override=False)
 
3262
 
 
3263
        if cache_dir is not None:
 
3264
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
 
3265
        if testspecs_list is not None:
 
3266
            pattern = '|'.join(testspecs_list)
 
3267
        else:
 
3268
            pattern = ".*"
 
3269
        if subunit:
 
3270
            try:
 
3271
                from bzrlib.tests import SubUnitBzrRunner
 
3272
            except ImportError:
 
3273
                raise errors.BzrCommandError("subunit not available. subunit "
 
3274
                    "needs to be installed to use --subunit.")
 
3275
            self.additional_selftest_args['runner_class'] = SubUnitBzrRunner
 
3276
        if parallel:
 
3277
            self.additional_selftest_args.setdefault(
 
3278
                'suite_decorators', []).append(parallel)
 
3279
        if benchmark:
 
3280
            test_suite_factory = benchmarks.test_suite
 
3281
            # Unless user explicitly asks for quiet, be verbose in benchmarks
 
3282
            verbose = not is_quiet()
 
3283
            # TODO: should possibly lock the history file...
 
3284
            benchfile = open(".perf_history", "at", buffering=1)
 
3285
        else:
 
3286
            test_suite_factory = None
 
3287
            benchfile = None
 
3288
        try:
 
3289
            selftest_kwargs = {"verbose": verbose,
 
3290
                              "pattern": pattern,
 
3291
                              "stop_on_failure": one,
 
3292
                              "transport": transport,
 
3293
                              "test_suite_factory": test_suite_factory,
 
3294
                              "lsprof_timed": lsprof_timed,
 
3295
                              "bench_history": benchfile,
 
3296
                              "matching_tests_first": first,
 
3297
                              "list_only": list_only,
 
3298
                              "random_seed": randomize,
 
3299
                              "exclude_pattern": exclude,
 
3300
                              "strict": strict,
 
3301
                              "load_list": load_list,
 
3302
                              "debug_flags": debugflag,
 
3303
                              "starting_with": starting_with
 
3304
                              }
 
3305
            selftest_kwargs.update(self.additional_selftest_args)
 
3306
            result = selftest(**selftest_kwargs)
 
3307
        finally:
 
3308
            if benchfile is not None:
 
3309
                benchfile.close()
 
3310
        return int(not result)
 
3311
 
 
3312
 
 
3313
class cmd_version(Command):
 
3314
    """Show version of bzr."""
 
3315
 
 
3316
    encoding_type = 'replace'
 
3317
    takes_options = [
 
3318
        Option("short", help="Print just the version number."),
 
3319
        ]
 
3320
 
 
3321
    @display_command
 
3322
    def run(self, short=False):
 
3323
        from bzrlib.version import show_version
 
3324
        if short:
 
3325
            self.outf.write(bzrlib.version_string + '\n')
 
3326
        else:
 
3327
            show_version(to_file=self.outf)
 
3328
 
 
3329
 
 
3330
class cmd_rocks(Command):
 
3331
    """Statement of optimism."""
 
3332
 
 
3333
    hidden = True
 
3334
 
 
3335
    @display_command
 
3336
    def run(self):
 
3337
        print "It sure does!"
 
3338
 
 
3339
 
 
3340
class cmd_find_merge_base(Command):
 
3341
    """Find and print a base revision for merging two branches."""
 
3342
    # TODO: Options to specify revisions on either side, as if
 
3343
    #       merging only part of the history.
 
3344
    takes_args = ['branch', 'other']
 
3345
    hidden = True
 
3346
 
 
3347
    @display_command
 
3348
    def run(self, branch, other):
 
3349
        from bzrlib.revision import ensure_null
 
3350
 
 
3351
        branch1 = Branch.open_containing(branch)[0]
 
3352
        branch2 = Branch.open_containing(other)[0]
 
3353
        branch1.lock_read()
 
3354
        try:
 
3355
            branch2.lock_read()
 
3356
            try:
 
3357
                last1 = ensure_null(branch1.last_revision())
 
3358
                last2 = ensure_null(branch2.last_revision())
 
3359
 
 
3360
                graph = branch1.repository.get_graph(branch2.repository)
 
3361
                base_rev_id = graph.find_unique_lca(last1, last2)
 
3362
 
 
3363
                print 'merge base is revision %s' % base_rev_id
 
3364
            finally:
 
3365
                branch2.unlock()
 
3366
        finally:
 
3367
            branch1.unlock()
 
3368
 
 
3369
 
 
3370
class cmd_merge(Command):
 
3371
    """Perform a three-way merge.
 
3372
 
 
3373
    The source of the merge can be specified either in the form of a branch,
 
3374
    or in the form of a path to a file containing a merge directive generated
 
3375
    with bzr send. If neither is specified, the default is the upstream branch
 
3376
    or the branch most recently merged using --remember.
 
3377
 
 
3378
    When merging a branch, by default the tip will be merged. To pick a different
 
3379
    revision, pass --revision. If you specify two values, the first will be used as
 
3380
    BASE and the second one as OTHER. Merging individual revisions, or a subset of
 
3381
    available revisions, like this is commonly referred to as "cherrypicking".
 
3382
 
 
3383
    Revision numbers are always relative to the branch being merged.
 
3384
 
 
3385
    By default, bzr will try to merge in all new work from the other
 
3386
    branch, automatically determining an appropriate base.  If this
 
3387
    fails, you may need to give an explicit base.
 
3388
 
 
3389
    Merge will do its best to combine the changes in two branches, but there
 
3390
    are some kinds of problems only a human can fix.  When it encounters those,
 
3391
    it will mark a conflict.  A conflict means that you need to fix something,
 
3392
    before you should commit.
 
3393
 
 
3394
    Use bzr resolve when you have fixed a problem.  See also bzr conflicts.
 
3395
 
 
3396
    If there is no default branch set, the first merge will set it. After
 
3397
    that, you can omit the branch to use the default.  To change the
 
3398
    default, use --remember. The value will only be saved if the remote
 
3399
    location can be accessed.
 
3400
 
 
3401
    The results of the merge are placed into the destination working
 
3402
    directory, where they can be reviewed (with bzr diff), tested, and then
 
3403
    committed to record the result of the merge.
 
3404
 
 
3405
    merge refuses to run if there are any uncommitted changes, unless
 
3406
    --force is given.
 
3407
 
 
3408
    :Examples:
 
3409
        To merge the latest revision from bzr.dev::
 
3410
 
 
3411
            bzr merge ../bzr.dev
 
3412
 
 
3413
        To merge changes up to and including revision 82 from bzr.dev::
 
3414
 
 
3415
            bzr merge -r 82 ../bzr.dev
 
3416
 
 
3417
        To merge the changes introduced by 82, without previous changes::
 
3418
 
 
3419
            bzr merge -r 81..82 ../bzr.dev
 
3420
 
 
3421
        To apply a merge directive contained in /tmp/merge:
 
3422
 
 
3423
            bzr merge /tmp/merge
 
3424
    """
 
3425
 
 
3426
    encoding_type = 'exact'
 
3427
    _see_also = ['update', 'remerge', 'status-flags', 'send']
 
3428
    takes_args = ['location?']
 
3429
    takes_options = [
 
3430
        'change',
 
3431
        'revision',
 
3432
        Option('force',
 
3433
               help='Merge even if the destination tree has uncommitted changes.'),
 
3434
        'merge-type',
 
3435
        'reprocess',
 
3436
        'remember',
 
3437
        Option('show-base', help="Show base revision text in "
 
3438
               "conflicts."),
 
3439
        Option('uncommitted', help='Apply uncommitted changes'
 
3440
               ' from a working copy, instead of branch changes.'),
 
3441
        Option('pull', help='If the destination is already'
 
3442
                ' completely merged into the source, pull from the'
 
3443
                ' source rather than merging.  When this happens,'
 
3444
                ' you do not need to commit the result.'),
 
3445
        Option('directory',
 
3446
               help='Branch to merge into, '
 
3447
                    'rather than the one containing the working directory.',
 
3448
               short_name='d',
 
3449
               type=unicode,
 
3450
               ),
 
3451
        Option('preview', help='Instead of merging, show a diff of the merge.')
 
3452
    ]
 
3453
 
 
3454
    def run(self, location=None, revision=None, force=False,
 
3455
            merge_type=None, show_base=False, reprocess=None, remember=False,
 
3456
            uncommitted=False, pull=False,
 
3457
            directory=None,
 
3458
            preview=False,
 
3459
            ):
 
3460
        if merge_type is None:
 
3461
            merge_type = _mod_merge.Merge3Merger
 
3462
 
 
3463
        if directory is None: directory = u'.'
 
3464
        possible_transports = []
 
3465
        merger = None
 
3466
        allow_pending = True
 
3467
        verified = 'inapplicable'
 
3468
        tree = WorkingTree.open_containing(directory)[0]
 
3469
 
 
3470
        # die as quickly as possible if there are uncommitted changes
 
3471
        try:
 
3472
            basis_tree = tree.revision_tree(tree.last_revision())
 
3473
        except errors.NoSuchRevision:
 
3474
            basis_tree = tree.basis_tree()
 
3475
        if not force:
 
3476
            changes = tree.changes_from(basis_tree)
 
3477
            if changes.has_changed():
 
3478
                raise errors.UncommittedChanges(tree)
 
3479
 
 
3480
        view_info = _get_view_info_for_change_reporter(tree)
 
3481
        change_reporter = delta._ChangeReporter(
 
3482
            unversioned_filter=tree.is_ignored, view_info=view_info)
 
3483
        cleanups = []
 
3484
        try:
 
3485
            pb = ui.ui_factory.nested_progress_bar()
 
3486
            cleanups.append(pb.finished)
 
3487
            tree.lock_write()
 
3488
            cleanups.append(tree.unlock)
 
3489
            if location is not None:
 
3490
                try:
 
3491
                    mergeable = bundle.read_mergeable_from_url(location,
 
3492
                        possible_transports=possible_transports)
 
3493
                except errors.NotABundle:
 
3494
                    mergeable = None
 
3495
                else:
 
3496
                    if uncommitted:
 
3497
                        raise errors.BzrCommandError('Cannot use --uncommitted'
 
3498
                            ' with bundles or merge directives.')
 
3499
 
 
3500
                    if revision is not None:
 
3501
                        raise errors.BzrCommandError(
 
3502
                            'Cannot use -r with merge directives or bundles')
 
3503
                    merger, verified = _mod_merge.Merger.from_mergeable(tree,
 
3504
                       mergeable, pb)
 
3505
 
 
3506
            if merger is None and uncommitted:
 
3507
                if revision is not None and len(revision) > 0:
 
3508
                    raise errors.BzrCommandError('Cannot use --uncommitted and'
 
3509
                        ' --revision at the same time.')
 
3510
                location = self._select_branch_location(tree, location)[0]
 
3511
                other_tree, other_path = WorkingTree.open_containing(location)
 
3512
                merger = _mod_merge.Merger.from_uncommitted(tree, other_tree,
 
3513
                    pb)
 
3514
                allow_pending = False
 
3515
                if other_path != '':
 
3516
                    merger.interesting_files = [other_path]
 
3517
 
 
3518
            if merger is None:
 
3519
                merger, allow_pending = self._get_merger_from_branch(tree,
 
3520
                    location, revision, remember, possible_transports, pb)
 
3521
 
 
3522
            merger.merge_type = merge_type
 
3523
            merger.reprocess = reprocess
 
3524
            merger.show_base = show_base
 
3525
            self.sanity_check_merger(merger)
 
3526
            if (merger.base_rev_id == merger.other_rev_id and
 
3527
                merger.other_rev_id is not None):
 
3528
                note('Nothing to do.')
 
3529
                return 0
 
3530
            if pull:
 
3531
                if merger.interesting_files is not None:
 
3532
                    raise errors.BzrCommandError('Cannot pull individual files')
 
3533
                if (merger.base_rev_id == tree.last_revision()):
 
3534
                    result = tree.pull(merger.other_branch, False,
 
3535
                                       merger.other_rev_id)
 
3536
                    result.report(self.outf)
 
3537
                    return 0
 
3538
            merger.check_basis(False)
 
3539
            if preview:
 
3540
                return self._do_preview(merger)
 
3541
            else:
 
3542
                return self._do_merge(merger, change_reporter, allow_pending,
 
3543
                                      verified)
 
3544
        finally:
 
3545
            for cleanup in reversed(cleanups):
 
3546
                cleanup()
 
3547
 
 
3548
    def _do_preview(self, merger):
 
3549
        from bzrlib.diff import show_diff_trees
 
3550
        tree_merger = merger.make_merger()
 
3551
        tt = tree_merger.make_preview_transform()
 
3552
        try:
 
3553
            result_tree = tt.get_preview_tree()
 
3554
            show_diff_trees(merger.this_tree, result_tree, self.outf,
 
3555
                            old_label='', new_label='')
 
3556
        finally:
 
3557
            tt.finalize()
 
3558
 
 
3559
    def _do_merge(self, merger, change_reporter, allow_pending, verified):
 
3560
        merger.change_reporter = change_reporter
 
3561
        conflict_count = merger.do_merge()
 
3562
        if allow_pending:
 
3563
            merger.set_pending()
 
3564
        if verified == 'failed':
 
3565
            warning('Preview patch does not match changes')
 
3566
        if conflict_count != 0:
 
3567
            return 1
 
3568
        else:
 
3569
            return 0
 
3570
 
 
3571
    def sanity_check_merger(self, merger):
 
3572
        if (merger.show_base and
 
3573
            not merger.merge_type is _mod_merge.Merge3Merger):
 
3574
            raise errors.BzrCommandError("Show-base is not supported for this"
 
3575
                                         " merge type. %s" % merger.merge_type)
 
3576
        if merger.reprocess is None:
 
3577
            if merger.show_base:
 
3578
                merger.reprocess = False
 
3579
            else:
 
3580
                # Use reprocess if the merger supports it
 
3581
                merger.reprocess = merger.merge_type.supports_reprocess
 
3582
        if merger.reprocess and not merger.merge_type.supports_reprocess:
 
3583
            raise errors.BzrCommandError("Conflict reduction is not supported"
 
3584
                                         " for merge type %s." %
 
3585
                                         merger.merge_type)
 
3586
        if merger.reprocess and merger.show_base:
 
3587
            raise errors.BzrCommandError("Cannot do conflict reduction and"
 
3588
                                         " show base.")
 
3589
 
 
3590
    def _get_merger_from_branch(self, tree, location, revision, remember,
 
3591
                                possible_transports, pb):
 
3592
        """Produce a merger from a location, assuming it refers to a branch."""
 
3593
        from bzrlib.tag import _merge_tags_if_possible
 
3594
        # find the branch locations
 
3595
        other_loc, user_location = self._select_branch_location(tree, location,
 
3596
            revision, -1)
 
3597
        if revision is not None and len(revision) == 2:
 
3598
            base_loc, _unused = self._select_branch_location(tree,
 
3599
                location, revision, 0)
 
3600
        else:
 
3601
            base_loc = other_loc
 
3602
        # Open the branches
 
3603
        other_branch, other_path = Branch.open_containing(other_loc,
 
3604
            possible_transports)
 
3605
        if base_loc == other_loc:
 
3606
            base_branch = other_branch
 
3607
        else:
 
3608
            base_branch, base_path = Branch.open_containing(base_loc,
 
3609
                possible_transports)
 
3610
        # Find the revision ids
 
3611
        if revision is None or len(revision) < 1 or revision[-1] is None:
 
3612
            other_revision_id = _mod_revision.ensure_null(
 
3613
                other_branch.last_revision())
 
3614
        else:
 
3615
            other_revision_id = revision[-1].as_revision_id(other_branch)
 
3616
        if (revision is not None and len(revision) == 2
 
3617
            and revision[0] is not None):
 
3618
            base_revision_id = revision[0].as_revision_id(base_branch)
 
3619
        else:
 
3620
            base_revision_id = None
 
3621
        # Remember where we merge from
 
3622
        if ((remember or tree.branch.get_submit_branch() is None) and
 
3623
             user_location is not None):
 
3624
            tree.branch.set_submit_branch(other_branch.base)
 
3625
        _merge_tags_if_possible(other_branch, tree.branch)
 
3626
        merger = _mod_merge.Merger.from_revision_ids(pb, tree,
 
3627
            other_revision_id, base_revision_id, other_branch, base_branch)
 
3628
        if other_path != '':
 
3629
            allow_pending = False
 
3630
            merger.interesting_files = [other_path]
 
3631
        else:
 
3632
            allow_pending = True
 
3633
        return merger, allow_pending
 
3634
 
 
3635
    def _select_branch_location(self, tree, user_location, revision=None,
 
3636
                                index=None):
 
3637
        """Select a branch location, according to possible inputs.
 
3638
 
 
3639
        If provided, branches from ``revision`` are preferred.  (Both
 
3640
        ``revision`` and ``index`` must be supplied.)
 
3641
 
 
3642
        Otherwise, the ``location`` parameter is used.  If it is None, then the
 
3643
        ``submit`` or ``parent`` location is used, and a note is printed.
 
3644
 
 
3645
        :param tree: The working tree to select a branch for merging into
 
3646
        :param location: The location entered by the user
 
3647
        :param revision: The revision parameter to the command
 
3648
        :param index: The index to use for the revision parameter.  Negative
 
3649
            indices are permitted.
 
3650
        :return: (selected_location, user_location).  The default location
 
3651
            will be the user-entered location.
 
3652
        """
 
3653
        if (revision is not None and index is not None
 
3654
            and revision[index] is not None):
 
3655
            branch = revision[index].get_branch()
 
3656
            if branch is not None:
 
3657
                return branch, branch
 
3658
        if user_location is None:
 
3659
            location = self._get_remembered(tree, 'Merging from')
 
3660
        else:
 
3661
            location = user_location
 
3662
        return location, user_location
 
3663
 
 
3664
    def _get_remembered(self, tree, verb_string):
 
3665
        """Use tree.branch's parent if none was supplied.
 
3666
 
 
3667
        Report if the remembered location was used.
 
3668
        """
 
3669
        stored_location = tree.branch.get_submit_branch()
 
3670
        stored_location_type = "submit"
 
3671
        if stored_location is None:
 
3672
            stored_location = tree.branch.get_parent()
 
3673
            stored_location_type = "parent"
 
3674
        mutter("%s", stored_location)
 
3675
        if stored_location is None:
 
3676
            raise errors.BzrCommandError("No location specified or remembered")
 
3677
        display_url = urlutils.unescape_for_display(stored_location, 'utf-8')
 
3678
        note(u"%s remembered %s location %s", verb_string,
 
3679
                stored_location_type, display_url)
 
3680
        return stored_location
 
3681
 
 
3682
 
 
3683
class cmd_remerge(Command):
 
3684
    """Redo a merge.
 
3685
 
 
3686
    Use this if you want to try a different merge technique while resolving
 
3687
    conflicts.  Some merge techniques are better than others, and remerge
 
3688
    lets you try different ones on different files.
 
3689
 
 
3690
    The options for remerge have the same meaning and defaults as the ones for
 
3691
    merge.  The difference is that remerge can (only) be run when there is a
 
3692
    pending merge, and it lets you specify particular files.
 
3693
 
 
3694
    :Examples:
 
3695
        Re-do the merge of all conflicted files, and show the base text in
 
3696
        conflict regions, in addition to the usual THIS and OTHER texts::
 
3697
 
 
3698
            bzr remerge --show-base
 
3699
 
 
3700
        Re-do the merge of "foobar", using the weave merge algorithm, with
 
3701
        additional processing to reduce the size of conflict regions::
 
3702
 
 
3703
            bzr remerge --merge-type weave --reprocess foobar
 
3704
    """
 
3705
    takes_args = ['file*']
 
3706
    takes_options = [
 
3707
            'merge-type',
 
3708
            'reprocess',
 
3709
            Option('show-base',
 
3710
                   help="Show base revision text in conflicts."),
 
3711
            ]
 
3712
 
 
3713
    def run(self, file_list=None, merge_type=None, show_base=False,
 
3714
            reprocess=False):
 
3715
        if merge_type is None:
 
3716
            merge_type = _mod_merge.Merge3Merger
 
3717
        tree, file_list = tree_files(file_list)
 
3718
        tree.lock_write()
 
3719
        try:
 
3720
            parents = tree.get_parent_ids()
 
3721
            if len(parents) != 2:
 
3722
                raise errors.BzrCommandError("Sorry, remerge only works after normal"
 
3723
                                             " merges.  Not cherrypicking or"
 
3724
                                             " multi-merges.")
 
3725
            repository = tree.branch.repository
 
3726
            interesting_ids = None
 
3727
            new_conflicts = []
 
3728
            conflicts = tree.conflicts()
 
3729
            if file_list is not None:
 
3730
                interesting_ids = set()
 
3731
                for filename in file_list:
 
3732
                    file_id = tree.path2id(filename)
 
3733
                    if file_id is None:
 
3734
                        raise errors.NotVersionedError(filename)
 
3735
                    interesting_ids.add(file_id)
 
3736
                    if tree.kind(file_id) != "directory":
 
3737
                        continue
 
3738
 
 
3739
                    for name, ie in tree.inventory.iter_entries(file_id):
 
3740
                        interesting_ids.add(ie.file_id)
 
3741
                new_conflicts = conflicts.select_conflicts(tree, file_list)[0]
 
3742
            else:
 
3743
                # Remerge only supports resolving contents conflicts
 
3744
                allowed_conflicts = ('text conflict', 'contents conflict')
 
3745
                restore_files = [c.path for c in conflicts
 
3746
                                 if c.typestring in allowed_conflicts]
 
3747
            _mod_merge.transform_tree(tree, tree.basis_tree(), interesting_ids)
 
3748
            tree.set_conflicts(ConflictList(new_conflicts))
 
3749
            if file_list is not None:
 
3750
                restore_files = file_list
 
3751
            for filename in restore_files:
 
3752
                try:
 
3753
                    restore(tree.abspath(filename))
 
3754
                except errors.NotConflicted:
 
3755
                    pass
 
3756
            # Disable pending merges, because the file texts we are remerging
 
3757
            # have not had those merges performed.  If we use the wrong parents
 
3758
            # list, we imply that the working tree text has seen and rejected
 
3759
            # all the changes from the other tree, when in fact those changes
 
3760
            # have not yet been seen.
 
3761
            pb = ui.ui_factory.nested_progress_bar()
 
3762
            tree.set_parent_ids(parents[:1])
 
3763
            try:
 
3764
                merger = _mod_merge.Merger.from_revision_ids(pb,
 
3765
                                                             tree, parents[1])
 
3766
                merger.interesting_ids = interesting_ids
 
3767
                merger.merge_type = merge_type
 
3768
                merger.show_base = show_base
 
3769
                merger.reprocess = reprocess
 
3770
                conflicts = merger.do_merge()
 
3771
            finally:
 
3772
                tree.set_parent_ids(parents)
 
3773
                pb.finished()
 
3774
        finally:
 
3775
            tree.unlock()
 
3776
        if conflicts > 0:
 
3777
            return 1
 
3778
        else:
 
3779
            return 0
 
3780
 
 
3781
 
 
3782
class cmd_revert(Command):
 
3783
    """Revert files to a previous revision.
 
3784
 
 
3785
    Giving a list of files will revert only those files.  Otherwise, all files
 
3786
    will be reverted.  If the revision is not specified with '--revision', the
 
3787
    last committed revision is used.
 
3788
 
 
3789
    To remove only some changes, without reverting to a prior version, use
 
3790
    merge instead.  For example, "merge . --revision -2..-3" will remove the
 
3791
    changes introduced by -2, without affecting the changes introduced by -1.
 
3792
    Or to remove certain changes on a hunk-by-hunk basis, see the Shelf plugin.
 
3793
 
 
3794
    By default, any files that have been manually changed will be backed up
 
3795
    first.  (Files changed only by merge are not backed up.)  Backup files have
 
3796
    '.~#~' appended to their name, where # is a number.
 
3797
 
 
3798
    When you provide files, you can use their current pathname or the pathname
 
3799
    from the target revision.  So you can use revert to "undelete" a file by
 
3800
    name.  If you name a directory, all the contents of that directory will be
 
3801
    reverted.
 
3802
 
 
3803
    Any files that have been newly added since that revision will be deleted,
 
3804
    with a backup kept if appropriate.  Directories containing unknown files
 
3805
    will not be deleted.
 
3806
 
 
3807
    The working tree contains a list of pending merged revisions, which will
 
3808
    be included as parents in the next commit.  Normally, revert clears that
 
3809
    list as well as reverting the files.  If any files are specified, revert
 
3810
    leaves the pending merge list alone and reverts only the files.  Use "bzr
 
3811
    revert ." in the tree root to revert all files but keep the merge record,
 
3812
    and "bzr revert --forget-merges" to clear the pending merge list without
 
3813
    reverting any files.
 
3814
    """
 
3815
 
 
3816
    _see_also = ['cat', 'export']
 
3817
    takes_options = [
 
3818
        'revision',
 
3819
        Option('no-backup', "Do not save backups of reverted files."),
 
3820
        Option('forget-merges',
 
3821
               'Remove pending merge marker, without changing any files.'),
 
3822
        ]
 
3823
    takes_args = ['file*']
 
3824
 
 
3825
    def run(self, revision=None, no_backup=False, file_list=None,
 
3826
            forget_merges=None):
 
3827
        tree, file_list = tree_files(file_list)
 
3828
        tree.lock_write()
 
3829
        try:
 
3830
            if forget_merges:
 
3831
                tree.set_parent_ids(tree.get_parent_ids()[:1])
 
3832
            else:
 
3833
                self._revert_tree_to_revision(tree, revision, file_list, no_backup)
 
3834
        finally:
 
3835
            tree.unlock()
 
3836
 
 
3837
    @staticmethod
 
3838
    def _revert_tree_to_revision(tree, revision, file_list, no_backup):
 
3839
        rev_tree = _get_one_revision_tree('revert', revision, tree=tree)
 
3840
        pb = ui.ui_factory.nested_progress_bar()
 
3841
        try:
 
3842
            tree.revert(file_list, rev_tree, not no_backup, pb,
 
3843
                report_changes=True)
 
3844
        finally:
 
3845
            pb.finished()
 
3846
 
 
3847
 
 
3848
class cmd_assert_fail(Command):
 
3849
    """Test reporting of assertion failures"""
 
3850
    # intended just for use in testing
 
3851
 
 
3852
    hidden = True
 
3853
 
 
3854
    def run(self):
 
3855
        raise AssertionError("always fails")
 
3856
 
 
3857
 
 
3858
class cmd_help(Command):
 
3859
    """Show help on a command or other topic.
 
3860
    """
 
3861
 
 
3862
    _see_also = ['topics']
 
3863
    takes_options = [
 
3864
            Option('long', 'Show help on all commands.'),
 
3865
            ]
 
3866
    takes_args = ['topic?']
 
3867
    aliases = ['?', '--help', '-?', '-h']
 
3868
 
 
3869
    @display_command
 
3870
    def run(self, topic=None, long=False):
 
3871
        import bzrlib.help
 
3872
        if topic is None and long:
 
3873
            topic = "commands"
 
3874
        bzrlib.help.help(topic)
 
3875
 
 
3876
 
 
3877
class cmd_shell_complete(Command):
 
3878
    """Show appropriate completions for context.
 
3879
 
 
3880
    For a list of all available commands, say 'bzr shell-complete'.
 
3881
    """
 
3882
    takes_args = ['context?']
 
3883
    aliases = ['s-c']
 
3884
    hidden = True
 
3885
 
 
3886
    @display_command
 
3887
    def run(self, context=None):
 
3888
        import shellcomplete
 
3889
        shellcomplete.shellcomplete(context)
 
3890
 
 
3891
 
 
3892
class cmd_missing(Command):
 
3893
    """Show unmerged/unpulled revisions between two branches.
 
3894
 
 
3895
    OTHER_BRANCH may be local or remote.
 
3896
 
 
3897
    To filter on a range of revisions, you can use the command -r begin..end
 
3898
    -r revision requests a specific revision, -r ..end or -r begin.. are
 
3899
    also valid.
 
3900
 
 
3901
    :Examples:
 
3902
 
 
3903
        Determine the missing revisions between this and the branch at the
 
3904
        remembered pull location::
 
3905
 
 
3906
            bzr missing
 
3907
 
 
3908
        Determine the missing revisions between this and another branch::
 
3909
 
 
3910
            bzr missing http://server/branch
 
3911
 
 
3912
        Determine the missing revisions up to a specific revision on the other
 
3913
        branch::
 
3914
 
 
3915
            bzr missing -r ..-10
 
3916
 
 
3917
        Determine the missing revisions up to a specific revision on this
 
3918
        branch::
 
3919
 
 
3920
            bzr missing --my-revision ..-10
 
3921
    """
 
3922
 
 
3923
    _see_also = ['merge', 'pull']
 
3924
    takes_args = ['other_branch?']
 
3925
    takes_options = [
 
3926
        Option('reverse', 'Reverse the order of revisions.'),
 
3927
        Option('mine-only',
 
3928
               'Display changes in the local branch only.'),
 
3929
        Option('this' , 'Same as --mine-only.'),
 
3930
        Option('theirs-only',
 
3931
               'Display changes in the remote branch only.'),
 
3932
        Option('other', 'Same as --theirs-only.'),
 
3933
        'log-format',
 
3934
        'show-ids',
 
3935
        'verbose',
 
3936
        custom_help('revision',
 
3937
             help='Filter on other branch revisions (inclusive). '
 
3938
                'See "help revisionspec" for details.'),
 
3939
        Option('my-revision',
 
3940
            type=_parse_revision_str,
 
3941
            help='Filter on local branch revisions (inclusive). '
 
3942
                'See "help revisionspec" for details.'),
 
3943
        Option('include-merges',
 
3944
               'Show all revisions in addition to the mainline ones.'),
 
3945
        ]
 
3946
    encoding_type = 'replace'
 
3947
 
 
3948
    @display_command
 
3949
    def run(self, other_branch=None, reverse=False, mine_only=False,
 
3950
            theirs_only=False,
 
3951
            log_format=None, long=False, short=False, line=False,
 
3952
            show_ids=False, verbose=False, this=False, other=False,
 
3953
            include_merges=False, revision=None, my_revision=None):
 
3954
        from bzrlib.missing import find_unmerged, iter_log_revisions
 
3955
        def message(s):
 
3956
            if not is_quiet():
 
3957
                self.outf.write(s)
 
3958
 
 
3959
        if this:
 
3960
            mine_only = this
 
3961
        if other:
 
3962
            theirs_only = other
 
3963
        # TODO: We should probably check that we don't have mine-only and
 
3964
        #       theirs-only set, but it gets complicated because we also have
 
3965
        #       this and other which could be used.
 
3966
        restrict = 'all'
 
3967
        if mine_only:
 
3968
            restrict = 'local'
 
3969
        elif theirs_only:
 
3970
            restrict = 'remote'
 
3971
 
 
3972
        local_branch = Branch.open_containing(u".")[0]
 
3973
        parent = local_branch.get_parent()
 
3974
        if other_branch is None:
 
3975
            other_branch = parent
 
3976
            if other_branch is None:
 
3977
                raise errors.BzrCommandError("No peer location known"
 
3978
                                             " or specified.")
 
3979
            display_url = urlutils.unescape_for_display(parent,
 
3980
                                                        self.outf.encoding)
 
3981
            message("Using saved parent location: "
 
3982
                    + display_url + "\n")
 
3983
 
 
3984
        remote_branch = Branch.open(other_branch)
 
3985
        if remote_branch.base == local_branch.base:
 
3986
            remote_branch = local_branch
 
3987
 
 
3988
        local_revid_range = _revision_range_to_revid_range(
 
3989
            _get_revision_range(my_revision, local_branch,
 
3990
                self.name()))
 
3991
 
 
3992
        remote_revid_range = _revision_range_to_revid_range(
 
3993
            _get_revision_range(revision,
 
3994
                remote_branch, self.name()))
 
3995
 
 
3996
        local_branch.lock_read()
 
3997
        try:
 
3998
            remote_branch.lock_read()
 
3999
            try:
 
4000
                local_extra, remote_extra = find_unmerged(
 
4001
                    local_branch, remote_branch, restrict,
 
4002
                    backward=not reverse,
 
4003
                    include_merges=include_merges,
 
4004
                    local_revid_range=local_revid_range,
 
4005
                    remote_revid_range=remote_revid_range)
 
4006
 
 
4007
                if log_format is None:
 
4008
                    registry = log.log_formatter_registry
 
4009
                    log_format = registry.get_default(local_branch)
 
4010
                lf = log_format(to_file=self.outf,
 
4011
                                show_ids=show_ids,
 
4012
                                show_timezone='original')
 
4013
 
 
4014
                status_code = 0
 
4015
                if local_extra and not theirs_only:
 
4016
                    message("You have %d extra revision(s):\n" %
 
4017
                        len(local_extra))
 
4018
                    for revision in iter_log_revisions(local_extra,
 
4019
                                        local_branch.repository,
 
4020
                                        verbose):
 
4021
                        lf.log_revision(revision)
 
4022
                    printed_local = True
 
4023
                    status_code = 1
 
4024
                else:
 
4025
                    printed_local = False
 
4026
 
 
4027
                if remote_extra and not mine_only:
 
4028
                    if printed_local is True:
 
4029
                        message("\n\n\n")
 
4030
                    message("You are missing %d revision(s):\n" %
 
4031
                        len(remote_extra))
 
4032
                    for revision in iter_log_revisions(remote_extra,
 
4033
                                        remote_branch.repository,
 
4034
                                        verbose):
 
4035
                        lf.log_revision(revision)
 
4036
                    status_code = 1
 
4037
 
 
4038
                if mine_only and not local_extra:
 
4039
                    # We checked local, and found nothing extra
 
4040
                    message('This branch is up to date.\n')
 
4041
                elif theirs_only and not remote_extra:
 
4042
                    # We checked remote, and found nothing extra
 
4043
                    message('Other branch is up to date.\n')
 
4044
                elif not (mine_only or theirs_only or local_extra or
 
4045
                          remote_extra):
 
4046
                    # We checked both branches, and neither one had extra
 
4047
                    # revisions
 
4048
                    message("Branches are up to date.\n")
 
4049
            finally:
 
4050
                remote_branch.unlock()
 
4051
        finally:
 
4052
            local_branch.unlock()
 
4053
        if not status_code and parent is None and other_branch is not None:
 
4054
            local_branch.lock_write()
 
4055
            try:
 
4056
                # handle race conditions - a parent might be set while we run.
 
4057
                if local_branch.get_parent() is None:
 
4058
                    local_branch.set_parent(remote_branch.base)
 
4059
            finally:
 
4060
                local_branch.unlock()
 
4061
        return status_code
 
4062
 
 
4063
 
 
4064
class cmd_pack(Command):
 
4065
    """Compress the data within a repository."""
 
4066
 
 
4067
    _see_also = ['repositories']
 
4068
    takes_args = ['branch_or_repo?']
 
4069
 
 
4070
    def run(self, branch_or_repo='.'):
 
4071
        dir = bzrdir.BzrDir.open_containing(branch_or_repo)[0]
 
4072
        try:
 
4073
            branch = dir.open_branch()
 
4074
            repository = branch.repository
 
4075
        except errors.NotBranchError:
 
4076
            repository = dir.open_repository()
 
4077
        repository.pack()
 
4078
 
 
4079
 
 
4080
class cmd_plugins(Command):
 
4081
    """List the installed plugins.
 
4082
 
 
4083
    This command displays the list of installed plugins including
 
4084
    version of plugin and a short description of each.
 
4085
 
 
4086
    --verbose shows the path where each plugin is located.
 
4087
 
 
4088
    A plugin is an external component for Bazaar that extends the
 
4089
    revision control system, by adding or replacing code in Bazaar.
 
4090
    Plugins can do a variety of things, including overriding commands,
 
4091
    adding new commands, providing additional network transports and
 
4092
    customizing log output.
 
4093
 
 
4094
    See the Bazaar web site, http://bazaar-vcs.org, for further
 
4095
    information on plugins including where to find them and how to
 
4096
    install them. Instructions are also provided there on how to
 
4097
    write new plugins using the Python programming language.
 
4098
    """
 
4099
    takes_options = ['verbose']
 
4100
 
 
4101
    @display_command
 
4102
    def run(self, verbose=False):
 
4103
        import bzrlib.plugin
 
4104
        from inspect import getdoc
 
4105
        result = []
 
4106
        for name, plugin in bzrlib.plugin.plugins().items():
 
4107
            version = plugin.__version__
 
4108
            if version == 'unknown':
 
4109
                version = ''
 
4110
            name_ver = '%s %s' % (name, version)
 
4111
            d = getdoc(plugin.module)
 
4112
            if d:
 
4113
                doc = d.split('\n')[0]
 
4114
            else:
 
4115
                doc = '(no description)'
 
4116
            result.append((name_ver, doc, plugin.path()))
 
4117
        for name_ver, doc, path in sorted(result):
 
4118
            print name_ver
 
4119
            print '   ', doc
 
4120
            if verbose:
 
4121
                print '   ', path
 
4122
            print
 
4123
 
 
4124
 
 
4125
class cmd_testament(Command):
 
4126
    """Show testament (signing-form) of a revision."""
 
4127
    takes_options = [
 
4128
            'revision',
 
4129
            Option('long', help='Produce long-format testament.'),
 
4130
            Option('strict',
 
4131
                   help='Produce a strict-format testament.')]
 
4132
    takes_args = ['branch?']
 
4133
    @display_command
 
4134
    def run(self, branch=u'.', revision=None, long=False, strict=False):
 
4135
        from bzrlib.testament import Testament, StrictTestament
 
4136
        if strict is True:
 
4137
            testament_class = StrictTestament
 
4138
        else:
 
4139
            testament_class = Testament
 
4140
        if branch == '.':
 
4141
            b = Branch.open_containing(branch)[0]
 
4142
        else:
 
4143
            b = Branch.open(branch)
 
4144
        b.lock_read()
 
4145
        try:
 
4146
            if revision is None:
 
4147
                rev_id = b.last_revision()
 
4148
            else:
 
4149
                rev_id = revision[0].as_revision_id(b)
 
4150
            t = testament_class.from_revision(b.repository, rev_id)
 
4151
            if long:
 
4152
                sys.stdout.writelines(t.as_text_lines())
 
4153
            else:
 
4154
                sys.stdout.write(t.as_short_text())
 
4155
        finally:
 
4156
            b.unlock()
 
4157
 
 
4158
 
 
4159
class cmd_annotate(Command):
 
4160
    """Show the origin of each line in a file.
 
4161
 
 
4162
    This prints out the given file with an annotation on the left side
 
4163
    indicating which revision, author and date introduced the change.
 
4164
 
 
4165
    If the origin is the same for a run of consecutive lines, it is
 
4166
    shown only at the top, unless the --all option is given.
 
4167
    """
 
4168
    # TODO: annotate directories; showing when each file was last changed
 
4169
    # TODO: if the working copy is modified, show annotations on that
 
4170
    #       with new uncommitted lines marked
 
4171
    aliases = ['ann', 'blame', 'praise']
 
4172
    takes_args = ['filename']
 
4173
    takes_options = [Option('all', help='Show annotations on all lines.'),
 
4174
                     Option('long', help='Show commit date in annotations.'),
 
4175
                     'revision',
 
4176
                     'show-ids',
 
4177
                     ]
 
4178
    encoding_type = 'exact'
 
4179
 
 
4180
    @display_command
 
4181
    def run(self, filename, all=False, long=False, revision=None,
 
4182
            show_ids=False):
 
4183
        from bzrlib.annotate import annotate_file, annotate_file_tree
 
4184
        wt, branch, relpath = \
 
4185
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
 
4186
        if wt is not None:
 
4187
            wt.lock_read()
 
4188
        else:
 
4189
            branch.lock_read()
 
4190
        try:
 
4191
            tree = _get_one_revision_tree('annotate', revision, branch=branch)
 
4192
            if wt is not None:
 
4193
                file_id = wt.path2id(relpath)
 
4194
            else:
 
4195
                file_id = tree.path2id(relpath)
 
4196
            if file_id is None:
 
4197
                raise errors.NotVersionedError(filename)
 
4198
            file_version = tree.inventory[file_id].revision
 
4199
            if wt is not None and revision is None:
 
4200
                # If there is a tree and we're not annotating historical
 
4201
                # versions, annotate the working tree's content.
 
4202
                annotate_file_tree(wt, file_id, self.outf, long, all,
 
4203
                    show_ids=show_ids)
 
4204
            else:
 
4205
                annotate_file(branch, file_version, file_id, long, all, self.outf,
 
4206
                              show_ids=show_ids)
 
4207
        finally:
 
4208
            if wt is not None:
 
4209
                wt.unlock()
 
4210
            else:
 
4211
                branch.unlock()
 
4212
 
 
4213
 
 
4214
class cmd_re_sign(Command):
 
4215
    """Create a digital signature for an existing revision."""
 
4216
    # TODO be able to replace existing ones.
 
4217
 
 
4218
    hidden = True # is this right ?
 
4219
    takes_args = ['revision_id*']
 
4220
    takes_options = ['revision']
 
4221
 
 
4222
    def run(self, revision_id_list=None, revision=None):
 
4223
        if revision_id_list is not None and revision is not None:
 
4224
            raise errors.BzrCommandError('You can only supply one of revision_id or --revision')
 
4225
        if revision_id_list is None and revision is None:
 
4226
            raise errors.BzrCommandError('You must supply either --revision or a revision_id')
 
4227
        b = WorkingTree.open_containing(u'.')[0].branch
 
4228
        b.lock_write()
 
4229
        try:
 
4230
            return self._run(b, revision_id_list, revision)
 
4231
        finally:
 
4232
            b.unlock()
 
4233
 
 
4234
    def _run(self, b, revision_id_list, revision):
 
4235
        import bzrlib.gpg as gpg
 
4236
        gpg_strategy = gpg.GPGStrategy(b.get_config())
 
4237
        if revision_id_list is not None:
 
4238
            b.repository.start_write_group()
 
4239
            try:
 
4240
                for revision_id in revision_id_list:
 
4241
                    b.repository.sign_revision(revision_id, gpg_strategy)
 
4242
            except:
 
4243
                b.repository.abort_write_group()
 
4244
                raise
 
4245
            else:
 
4246
                b.repository.commit_write_group()
 
4247
        elif revision is not None:
 
4248
            if len(revision) == 1:
 
4249
                revno, rev_id = revision[0].in_history(b)
 
4250
                b.repository.start_write_group()
 
4251
                try:
 
4252
                    b.repository.sign_revision(rev_id, gpg_strategy)
 
4253
                except:
 
4254
                    b.repository.abort_write_group()
 
4255
                    raise
 
4256
                else:
 
4257
                    b.repository.commit_write_group()
 
4258
            elif len(revision) == 2:
 
4259
                # are they both on rh- if so we can walk between them
 
4260
                # might be nice to have a range helper for arbitrary
 
4261
                # revision paths. hmm.
 
4262
                from_revno, from_revid = revision[0].in_history(b)
 
4263
                to_revno, to_revid = revision[1].in_history(b)
 
4264
                if to_revid is None:
 
4265
                    to_revno = b.revno()
 
4266
                if from_revno is None or to_revno is None:
 
4267
                    raise errors.BzrCommandError('Cannot sign a range of non-revision-history revisions')
 
4268
                b.repository.start_write_group()
 
4269
                try:
 
4270
                    for revno in range(from_revno, to_revno + 1):
 
4271
                        b.repository.sign_revision(b.get_rev_id(revno),
 
4272
                                                   gpg_strategy)
 
4273
                except:
 
4274
                    b.repository.abort_write_group()
 
4275
                    raise
 
4276
                else:
 
4277
                    b.repository.commit_write_group()
 
4278
            else:
 
4279
                raise errors.BzrCommandError('Please supply either one revision, or a range.')
 
4280
 
 
4281
 
 
4282
class cmd_bind(Command):
 
4283
    """Convert the current branch into a checkout of the supplied branch.
 
4284
 
 
4285
    Once converted into a checkout, commits must succeed on the master branch
 
4286
    before they will be applied to the local branch.
 
4287
 
 
4288
    Bound branches use the nickname of its master branch unless it is set
 
4289
    locally, in which case binding will update the the local nickname to be
 
4290
    that of the master.
 
4291
    """
 
4292
 
 
4293
    _see_also = ['checkouts', 'unbind']
 
4294
    takes_args = ['location?']
 
4295
    takes_options = []
 
4296
 
 
4297
    def run(self, location=None):
 
4298
        b, relpath = Branch.open_containing(u'.')
 
4299
        if location is None:
 
4300
            try:
 
4301
                location = b.get_old_bound_location()
 
4302
            except errors.UpgradeRequired:
 
4303
                raise errors.BzrCommandError('No location supplied.  '
 
4304
                    'This format does not remember old locations.')
 
4305
            else:
 
4306
                if location is None:
 
4307
                    raise errors.BzrCommandError('No location supplied and no '
 
4308
                        'previous location known')
 
4309
        b_other = Branch.open(location)
 
4310
        try:
 
4311
            b.bind(b_other)
 
4312
        except errors.DivergedBranches:
 
4313
            raise errors.BzrCommandError('These branches have diverged.'
 
4314
                                         ' Try merging, and then bind again.')
 
4315
        if b.get_config().has_explicit_nickname():
 
4316
            b.nick = b_other.nick
 
4317
 
 
4318
 
 
4319
class cmd_unbind(Command):
 
4320
    """Convert the current checkout into a regular branch.
 
4321
 
 
4322
    After unbinding, the local branch is considered independent and subsequent
 
4323
    commits will be local only.
 
4324
    """
 
4325
 
 
4326
    _see_also = ['checkouts', 'bind']
 
4327
    takes_args = []
 
4328
    takes_options = []
 
4329
 
 
4330
    def run(self):
 
4331
        b, relpath = Branch.open_containing(u'.')
 
4332
        if not b.unbind():
 
4333
            raise errors.BzrCommandError('Local branch is not bound')
 
4334
 
 
4335
 
 
4336
class cmd_uncommit(Command):
 
4337
    """Remove the last committed revision.
 
4338
 
 
4339
    --verbose will print out what is being removed.
 
4340
    --dry-run will go through all the motions, but not actually
 
4341
    remove anything.
 
4342
 
 
4343
    If --revision is specified, uncommit revisions to leave the branch at the
 
4344
    specified revision.  For example, "bzr uncommit -r 15" will leave the
 
4345
    branch at revision 15.
 
4346
 
 
4347
    Uncommit leaves the working tree ready for a new commit.  The only change
 
4348
    it may make is to restore any pending merges that were present before
 
4349
    the commit.
 
4350
    """
 
4351
 
 
4352
    # TODO: jam 20060108 Add an option to allow uncommit to remove
 
4353
    # unreferenced information in 'branch-as-repository' branches.
 
4354
    # TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
 
4355
    # information in shared branches as well.
 
4356
    _see_also = ['commit']
 
4357
    takes_options = ['verbose', 'revision',
 
4358
                    Option('dry-run', help='Don\'t actually make changes.'),
 
4359
                    Option('force', help='Say yes to all questions.'),
 
4360
                    Option('local',
 
4361
                           help="Only remove the commits from the local branch"
 
4362
                                " when in a checkout."
 
4363
                           ),
 
4364
                    ]
 
4365
    takes_args = ['location?']
 
4366
    aliases = []
 
4367
    encoding_type = 'replace'
 
4368
 
 
4369
    def run(self, location=None,
 
4370
            dry_run=False, verbose=False,
 
4371
            revision=None, force=False, local=False):
 
4372
        if location is None:
 
4373
            location = u'.'
 
4374
        control, relpath = bzrdir.BzrDir.open_containing(location)
 
4375
        try:
 
4376
            tree = control.open_workingtree()
 
4377
            b = tree.branch
 
4378
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
4379
            tree = None
 
4380
            b = control.open_branch()
 
4381
 
 
4382
        if tree is not None:
 
4383
            tree.lock_write()
 
4384
        else:
 
4385
            b.lock_write()
 
4386
        try:
 
4387
            return self._run(b, tree, dry_run, verbose, revision, force,
 
4388
                             local=local)
 
4389
        finally:
 
4390
            if tree is not None:
 
4391
                tree.unlock()
 
4392
            else:
 
4393
                b.unlock()
 
4394
 
 
4395
    def _run(self, b, tree, dry_run, verbose, revision, force, local=False):
 
4396
        from bzrlib.log import log_formatter, show_log
 
4397
        from bzrlib.uncommit import uncommit
 
4398
 
 
4399
        last_revno, last_rev_id = b.last_revision_info()
 
4400
 
 
4401
        rev_id = None
 
4402
        if revision is None:
 
4403
            revno = last_revno
 
4404
            rev_id = last_rev_id
 
4405
        else:
 
4406
            # 'bzr uncommit -r 10' actually means uncommit
 
4407
            # so that the final tree is at revno 10.
 
4408
            # but bzrlib.uncommit.uncommit() actually uncommits
 
4409
            # the revisions that are supplied.
 
4410
            # So we need to offset it by one
 
4411
            revno = revision[0].in_history(b).revno + 1
 
4412
            if revno <= last_revno:
 
4413
                rev_id = b.get_rev_id(revno)
 
4414
 
 
4415
        if rev_id is None or _mod_revision.is_null(rev_id):
 
4416
            self.outf.write('No revisions to uncommit.\n')
 
4417
            return 1
 
4418
 
 
4419
        lf = log_formatter('short',
 
4420
                           to_file=self.outf,
 
4421
                           show_timezone='original')
 
4422
 
 
4423
        show_log(b,
 
4424
                 lf,
 
4425
                 verbose=False,
 
4426
                 direction='forward',
 
4427
                 start_revision=revno,
 
4428
                 end_revision=last_revno)
 
4429
 
 
4430
        if dry_run:
 
4431
            print 'Dry-run, pretending to remove the above revisions.'
 
4432
            if not force:
 
4433
                val = raw_input('Press <enter> to continue')
 
4434
        else:
 
4435
            print 'The above revision(s) will be removed.'
 
4436
            if not force:
 
4437
                val = raw_input('Are you sure [y/N]? ')
 
4438
                if val.lower() not in ('y', 'yes'):
 
4439
                    print 'Canceled'
 
4440
                    return 0
 
4441
 
 
4442
        mutter('Uncommitting from {%s} to {%s}',
 
4443
               last_rev_id, rev_id)
 
4444
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
 
4445
                 revno=revno, local=local)
 
4446
        note('You can restore the old tip by running:\n'
 
4447
             '  bzr pull . -r revid:%s', last_rev_id)
 
4448
 
 
4449
 
 
4450
class cmd_break_lock(Command):
 
4451
    """Break a dead lock on a repository, branch or working directory.
 
4452
 
 
4453
    CAUTION: Locks should only be broken when you are sure that the process
 
4454
    holding the lock has been stopped.
 
4455
 
 
4456
    You can get information on what locks are open via the 'bzr info' command.
 
4457
 
 
4458
    :Examples:
 
4459
        bzr break-lock
 
4460
    """
 
4461
    takes_args = ['location?']
 
4462
 
 
4463
    def run(self, location=None, show=False):
 
4464
        if location is None:
 
4465
            location = u'.'
 
4466
        control, relpath = bzrdir.BzrDir.open_containing(location)
 
4467
        try:
 
4468
            control.break_lock()
 
4469
        except NotImplementedError:
 
4470
            pass
 
4471
 
 
4472
 
 
4473
class cmd_wait_until_signalled(Command):
 
4474
    """Test helper for test_start_and_stop_bzr_subprocess_send_signal.
 
4475
 
 
4476
    This just prints a line to signal when it is ready, then blocks on stdin.
 
4477
    """
 
4478
 
 
4479
    hidden = True
 
4480
 
 
4481
    def run(self):
 
4482
        sys.stdout.write("running\n")
 
4483
        sys.stdout.flush()
 
4484
        sys.stdin.readline()
 
4485
 
 
4486
 
 
4487
class cmd_serve(Command):
 
4488
    """Run the bzr server."""
 
4489
 
 
4490
    aliases = ['server']
 
4491
 
 
4492
    takes_options = [
 
4493
        Option('inet',
 
4494
               help='Serve on stdin/out for use from inetd or sshd.'),
 
4495
        Option('port',
 
4496
               help='Listen for connections on nominated port of the form '
 
4497
                    '[hostname:]portnumber.  Passing 0 as the port number will '
 
4498
                    'result in a dynamically allocated port.  The default port is '
 
4499
                    '4155.',
 
4500
               type=str),
 
4501
        Option('directory',
 
4502
               help='Serve contents of this directory.',
 
4503
               type=unicode),
 
4504
        Option('allow-writes',
 
4505
               help='By default the server is a readonly server.  Supplying '
 
4506
                    '--allow-writes enables write access to the contents of '
 
4507
                    'the served directory and below.'
 
4508
                ),
 
4509
        ]
 
4510
 
 
4511
    def run_smart_server(self, smart_server):
 
4512
        """Run 'smart_server' forever, with no UI output at all."""
 
4513
        # For the duration of this server, no UI output is permitted. note
 
4514
        # that this may cause problems with blackbox tests. This should be
 
4515
        # changed with care though, as we dont want to use bandwidth sending
 
4516
        # progress over stderr to smart server clients!
 
4517
        from bzrlib import lockdir
 
4518
        old_factory = ui.ui_factory
 
4519
        old_lockdir_timeout = lockdir._DEFAULT_TIMEOUT_SECONDS
 
4520
        try:
 
4521
            ui.ui_factory = ui.SilentUIFactory()
 
4522
            lockdir._DEFAULT_TIMEOUT_SECONDS = 0
 
4523
            smart_server.serve()
 
4524
        finally:
 
4525
            ui.ui_factory = old_factory
 
4526
            lockdir._DEFAULT_TIMEOUT_SECONDS = old_lockdir_timeout
 
4527
 
 
4528
    def get_host_and_port(self, port):
 
4529
        """Return the host and port to run the smart server on.
 
4530
 
 
4531
        If 'port' is None, the default host (`medium.BZR_DEFAULT_INTERFACE`)
 
4532
        and port (`medium.BZR_DEFAULT_PORT`) will be used.
 
4533
 
 
4534
        If 'port' has a colon in it, the string before the colon will be
 
4535
        interpreted as the host.
 
4536
 
 
4537
        :param port: A string of the port to run the server on.
 
4538
        :return: A tuple of (host, port), where 'host' is a host name or IP,
 
4539
            and port is an integer TCP/IP port.
 
4540
        """
 
4541
        from bzrlib.smart import medium
 
4542
        host = medium.BZR_DEFAULT_INTERFACE
 
4543
        if port is None:
 
4544
            port = medium.BZR_DEFAULT_PORT
 
4545
        else:
 
4546
            if ':' in port:
 
4547
                host, port = port.split(':')
 
4548
            port = int(port)
 
4549
        return host, port
 
4550
 
 
4551
    def get_smart_server(self, transport, inet, port):
 
4552
        """Construct a smart server.
 
4553
 
 
4554
        :param transport: The base transport from which branches will be
 
4555
            served.
 
4556
        :param inet: If True, serve over stdin and stdout. Used for running
 
4557
            from inet.
 
4558
        :param port: The port to listen on. By default, it's `
 
4559
            medium.BZR_DEFAULT_PORT`. See `get_host_and_port` for more
 
4560
            information.
 
4561
        :return: A smart server.
 
4562
        """
 
4563
        from bzrlib.smart import medium, server
 
4564
        if inet:
 
4565
            smart_server = medium.SmartServerPipeStreamMedium(
 
4566
                sys.stdin, sys.stdout, transport)
 
4567
        else:
 
4568
            host, port = self.get_host_and_port(port)
 
4569
            smart_server = server.SmartTCPServer(
 
4570
                transport, host=host, port=port)
 
4571
            note('listening on port: %s' % smart_server.port)
 
4572
        return smart_server
 
4573
 
 
4574
    def run(self, port=None, inet=False, directory=None, allow_writes=False):
 
4575
        from bzrlib.transport import get_transport
 
4576
        from bzrlib.transport.chroot import ChrootServer
 
4577
        if directory is None:
 
4578
            directory = os.getcwd()
 
4579
        url = urlutils.local_path_to_url(directory)
 
4580
        if not allow_writes:
 
4581
            url = 'readonly+' + url
 
4582
        chroot_server = ChrootServer(get_transport(url))
 
4583
        chroot_server.setUp()
 
4584
        t = get_transport(chroot_server.get_url())
 
4585
        smart_server = self.get_smart_server(t, inet, port)
 
4586
        self.run_smart_server(smart_server)
 
4587
 
 
4588
 
 
4589
class cmd_join(Command):
 
4590
    """Combine a tree into its containing tree.
 
4591
 
 
4592
    This command requires the target tree to be in a rich-root format.
 
4593
 
 
4594
    The TREE argument should be an independent tree, inside another tree, but
 
4595
    not part of it.  (Such trees can be produced by "bzr split", but also by
 
4596
    running "bzr branch" with the target inside a tree.)
 
4597
 
 
4598
    The result is a combined tree, with the subtree no longer an independant
 
4599
    part.  This is marked as a merge of the subtree into the containing tree,
 
4600
    and all history is preserved.
 
4601
    """
 
4602
 
 
4603
    _see_also = ['split']
 
4604
    takes_args = ['tree']
 
4605
    takes_options = [
 
4606
            Option('reference', help='Join by reference.', hidden=True),
 
4607
            ]
 
4608
 
 
4609
    def run(self, tree, reference=False):
 
4610
        sub_tree = WorkingTree.open(tree)
 
4611
        parent_dir = osutils.dirname(sub_tree.basedir)
 
4612
        containing_tree = WorkingTree.open_containing(parent_dir)[0]
 
4613
        repo = containing_tree.branch.repository
 
4614
        if not repo.supports_rich_root():
 
4615
            raise errors.BzrCommandError(
 
4616
                "Can't join trees because %s doesn't support rich root data.\n"
 
4617
                "You can use bzr upgrade on the repository."
 
4618
                % (repo,))
 
4619
        if reference:
 
4620
            try:
 
4621
                containing_tree.add_reference(sub_tree)
 
4622
            except errors.BadReferenceTarget, e:
 
4623
                # XXX: Would be better to just raise a nicely printable
 
4624
                # exception from the real origin.  Also below.  mbp 20070306
 
4625
                raise errors.BzrCommandError("Cannot join %s.  %s" %
 
4626
                                             (tree, e.reason))
 
4627
        else:
 
4628
            try:
 
4629
                containing_tree.subsume(sub_tree)
 
4630
            except errors.BadSubsumeSource, e:
 
4631
                raise errors.BzrCommandError("Cannot join %s.  %s" %
 
4632
                                             (tree, e.reason))
 
4633
 
 
4634
 
 
4635
class cmd_split(Command):
 
4636
    """Split a subdirectory of a tree into a separate tree.
 
4637
 
 
4638
    This command will produce a target tree in a format that supports
 
4639
    rich roots, like 'rich-root' or 'rich-root-pack'.  These formats cannot be
 
4640
    converted into earlier formats like 'dirstate-tags'.
 
4641
 
 
4642
    The TREE argument should be a subdirectory of a working tree.  That
 
4643
    subdirectory will be converted into an independent tree, with its own
 
4644
    branch.  Commits in the top-level tree will not apply to the new subtree.
 
4645
    """
 
4646
 
 
4647
    _see_also = ['join']
 
4648
    takes_args = ['tree']
 
4649
 
 
4650
    def run(self, tree):
 
4651
        containing_tree, subdir = WorkingTree.open_containing(tree)
 
4652
        sub_id = containing_tree.path2id(subdir)
 
4653
        if sub_id is None:
 
4654
            raise errors.NotVersionedError(subdir)
 
4655
        try:
 
4656
            containing_tree.extract(sub_id)
 
4657
        except errors.RootNotRich:
 
4658
            raise errors.UpgradeRequired(containing_tree.branch.base)
 
4659
 
 
4660
 
 
4661
class cmd_merge_directive(Command):
 
4662
    """Generate a merge directive for auto-merge tools.
 
4663
 
 
4664
    A directive requests a merge to be performed, and also provides all the
 
4665
    information necessary to do so.  This means it must either include a
 
4666
    revision bundle, or the location of a branch containing the desired
 
4667
    revision.
 
4668
 
 
4669
    A submit branch (the location to merge into) must be supplied the first
 
4670
    time the command is issued.  After it has been supplied once, it will
 
4671
    be remembered as the default.
 
4672
 
 
4673
    A public branch is optional if a revision bundle is supplied, but required
 
4674
    if --diff or --plain is specified.  It will be remembered as the default
 
4675
    after the first use.
 
4676
    """
 
4677
 
 
4678
    takes_args = ['submit_branch?', 'public_branch?']
 
4679
 
 
4680
    hidden = True
 
4681
 
 
4682
    _see_also = ['send']
 
4683
 
 
4684
    takes_options = [
 
4685
        RegistryOption.from_kwargs('patch-type',
 
4686
            'The type of patch to include in the directive.',
 
4687
            title='Patch type',
 
4688
            value_switches=True,
 
4689
            enum_switch=False,
 
4690
            bundle='Bazaar revision bundle (default).',
 
4691
            diff='Normal unified diff.',
 
4692
            plain='No patch, just directive.'),
 
4693
        Option('sign', help='GPG-sign the directive.'), 'revision',
 
4694
        Option('mail-to', type=str,
 
4695
            help='Instead of printing the directive, email to this address.'),
 
4696
        Option('message', type=str, short_name='m',
 
4697
            help='Message to use when committing this merge.')
 
4698
        ]
 
4699
 
 
4700
    encoding_type = 'exact'
 
4701
 
 
4702
    def run(self, submit_branch=None, public_branch=None, patch_type='bundle',
 
4703
            sign=False, revision=None, mail_to=None, message=None):
 
4704
        from bzrlib.revision import ensure_null, NULL_REVISION
 
4705
        include_patch, include_bundle = {
 
4706
            'plain': (False, False),
 
4707
            'diff': (True, False),
 
4708
            'bundle': (True, True),
 
4709
            }[patch_type]
 
4710
        branch = Branch.open('.')
 
4711
        stored_submit_branch = branch.get_submit_branch()
 
4712
        if submit_branch is None:
 
4713
            submit_branch = stored_submit_branch
 
4714
        else:
 
4715
            if stored_submit_branch is None:
 
4716
                branch.set_submit_branch(submit_branch)
 
4717
        if submit_branch is None:
 
4718
            submit_branch = branch.get_parent()
 
4719
        if submit_branch is None:
 
4720
            raise errors.BzrCommandError('No submit branch specified or known')
 
4721
 
 
4722
        stored_public_branch = branch.get_public_branch()
 
4723
        if public_branch is None:
 
4724
            public_branch = stored_public_branch
 
4725
        elif stored_public_branch is None:
 
4726
            branch.set_public_branch(public_branch)
 
4727
        if not include_bundle and public_branch is None:
 
4728
            raise errors.BzrCommandError('No public branch specified or'
 
4729
                                         ' known')
 
4730
        base_revision_id = None
 
4731
        if revision is not None:
 
4732
            if len(revision) > 2:
 
4733
                raise errors.BzrCommandError('bzr merge-directive takes '
 
4734
                    'at most two one revision identifiers')
 
4735
            revision_id = revision[-1].as_revision_id(branch)
 
4736
            if len(revision) == 2:
 
4737
                base_revision_id = revision[0].as_revision_id(branch)
 
4738
        else:
 
4739
            revision_id = branch.last_revision()
 
4740
        revision_id = ensure_null(revision_id)
 
4741
        if revision_id == NULL_REVISION:
 
4742
            raise errors.BzrCommandError('No revisions to bundle.')
 
4743
        directive = merge_directive.MergeDirective2.from_objects(
 
4744
            branch.repository, revision_id, time.time(),
 
4745
            osutils.local_time_offset(), submit_branch,
 
4746
            public_branch=public_branch, include_patch=include_patch,
 
4747
            include_bundle=include_bundle, message=message,
 
4748
            base_revision_id=base_revision_id)
 
4749
        if mail_to is None:
 
4750
            if sign:
 
4751
                self.outf.write(directive.to_signed(branch))
 
4752
            else:
 
4753
                self.outf.writelines(directive.to_lines())
 
4754
        else:
 
4755
            message = directive.to_email(mail_to, branch, sign)
 
4756
            s = SMTPConnection(branch.get_config())
 
4757
            s.send_email(message)
 
4758
 
 
4759
 
 
4760
class cmd_send(Command):
 
4761
    """Mail or create a merge-directive for submitting changes.
 
4762
 
 
4763
    A merge directive provides many things needed for requesting merges:
 
4764
 
 
4765
    * A machine-readable description of the merge to perform
 
4766
 
 
4767
    * An optional patch that is a preview of the changes requested
 
4768
 
 
4769
    * An optional bundle of revision data, so that the changes can be applied
 
4770
      directly from the merge directive, without retrieving data from a
 
4771
      branch.
 
4772
 
 
4773
    If --no-bundle is specified, then public_branch is needed (and must be
 
4774
    up-to-date), so that the receiver can perform the merge using the
 
4775
    public_branch.  The public_branch is always included if known, so that
 
4776
    people can check it later.
 
4777
 
 
4778
    The submit branch defaults to the parent, but can be overridden.  Both
 
4779
    submit branch and public branch will be remembered if supplied.
 
4780
 
 
4781
    If a public_branch is known for the submit_branch, that public submit
 
4782
    branch is used in the merge instructions.  This means that a local mirror
 
4783
    can be used as your actual submit branch, once you have set public_branch
 
4784
    for that mirror.
 
4785
 
 
4786
    Mail is sent using your preferred mail program.  This should be transparent
 
4787
    on Windows (it uses MAPI).  On Linux, it requires the xdg-email utility.
 
4788
    If the preferred client can't be found (or used), your editor will be used.
 
4789
 
 
4790
    To use a specific mail program, set the mail_client configuration option.
 
4791
    (For Thunderbird 1.5, this works around some bugs.)  Supported values for
 
4792
    specific clients are "claws", "evolution", "kmail", "mutt", and
 
4793
    "thunderbird"; generic options are "default", "editor", "emacsclient",
 
4794
    "mapi", and "xdg-email".  Plugins may also add supported clients.
 
4795
 
 
4796
    If mail is being sent, a to address is required.  This can be supplied
 
4797
    either on the commandline, by setting the submit_to configuration
 
4798
    option in the branch itself or the child_submit_to configuration option
 
4799
    in the submit branch.
 
4800
 
 
4801
    Two formats are currently supported: "4" uses revision bundle format 4 and
 
4802
    merge directive format 2.  It is significantly faster and smaller than
 
4803
    older formats.  It is compatible with Bazaar 0.19 and later.  It is the
 
4804
    default.  "0.9" uses revision bundle format 0.9 and merge directive
 
4805
    format 1.  It is compatible with Bazaar 0.12 - 0.18.
 
4806
 
 
4807
    The merge directives created by bzr send may be applied using bzr merge or
 
4808
    bzr pull by specifying a file containing a merge directive as the location.
 
4809
    """
 
4810
 
 
4811
    encoding_type = 'exact'
 
4812
 
 
4813
    _see_also = ['merge', 'pull']
 
4814
 
 
4815
    takes_args = ['submit_branch?', 'public_branch?']
 
4816
 
 
4817
    takes_options = [
 
4818
        Option('no-bundle',
 
4819
               help='Do not include a bundle in the merge directive.'),
 
4820
        Option('no-patch', help='Do not include a preview patch in the merge'
 
4821
               ' directive.'),
 
4822
        Option('remember',
 
4823
               help='Remember submit and public branch.'),
 
4824
        Option('from',
 
4825
               help='Branch to generate the submission from, '
 
4826
               'rather than the one containing the working directory.',
 
4827
               short_name='f',
 
4828
               type=unicode),
 
4829
        Option('output', short_name='o',
 
4830
               help='Write merge directive to this file; '
 
4831
                    'use - for stdout.',
 
4832
               type=unicode),
 
4833
        Option('mail-to', help='Mail the request to this address.',
 
4834
               type=unicode),
 
4835
        'revision',
 
4836
        'message',
 
4837
        Option('body', help='Body for the email.', type=unicode),
 
4838
        RegistryOption.from_kwargs('format',
 
4839
        'Use the specified output format.',
 
4840
        **{'4': 'Bundle format 4, Merge Directive 2 (default)',
 
4841
           '0.9': 'Bundle format 0.9, Merge Directive 1',})
 
4842
        ]
 
4843
 
 
4844
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
 
4845
            no_patch=False, revision=None, remember=False, output=None,
 
4846
            format='4', mail_to=None, message=None, body=None, **kwargs):
 
4847
        return self._run(submit_branch, revision, public_branch, remember,
 
4848
                         format, no_bundle, no_patch, output,
 
4849
                         kwargs.get('from', '.'), mail_to, message, body)
 
4850
 
 
4851
    def _run(self, submit_branch, revision, public_branch, remember, format,
 
4852
             no_bundle, no_patch, output, from_, mail_to, message, body):
 
4853
        from bzrlib.revision import NULL_REVISION
 
4854
        tree, branch = bzrdir.BzrDir.open_containing_tree_or_branch(from_)[:2]
 
4855
        # we may need to write data into branch's repository to calculate
 
4856
        # the data to send.
 
4857
        branch.lock_write()
 
4858
        try:
 
4859
            if output is None:
 
4860
                config = branch.get_config()
 
4861
                if mail_to is None:
 
4862
                    mail_to = config.get_user_option('submit_to')
 
4863
                mail_client = config.get_mail_client()
 
4864
                if (not getattr(mail_client, 'supports_body', False)
 
4865
                    and body is not None):
 
4866
                    raise errors.BzrCommandError(
 
4867
                        'Mail client "%s" does not support specifying body' %
 
4868
                        mail_client.__class__.__name__)
 
4869
            if remember and submit_branch is None:
 
4870
                raise errors.BzrCommandError(
 
4871
                    '--remember requires a branch to be specified.')
 
4872
            stored_submit_branch = branch.get_submit_branch()
 
4873
            remembered_submit_branch = None
 
4874
            if submit_branch is None:
 
4875
                submit_branch = stored_submit_branch
 
4876
                remembered_submit_branch = "submit"
 
4877
            else:
 
4878
                if stored_submit_branch is None or remember:
 
4879
                    branch.set_submit_branch(submit_branch)
 
4880
            if submit_branch is None:
 
4881
                submit_branch = branch.get_parent()
 
4882
                remembered_submit_branch = "parent"
 
4883
            if submit_branch is None:
 
4884
                raise errors.BzrCommandError('No submit branch known or'
 
4885
                                             ' specified')
 
4886
            if remembered_submit_branch is not None:
 
4887
                note('Using saved %s location "%s" to determine what '
 
4888
                        'changes to submit.', remembered_submit_branch,
 
4889
                        submit_branch)
 
4890
 
 
4891
            if mail_to is None:
 
4892
                submit_config = Branch.open(submit_branch).get_config()
 
4893
                mail_to = submit_config.get_user_option("child_submit_to")
 
4894
 
 
4895
            stored_public_branch = branch.get_public_branch()
 
4896
            if public_branch is None:
 
4897
                public_branch = stored_public_branch
 
4898
            elif stored_public_branch is None or remember:
 
4899
                branch.set_public_branch(public_branch)
 
4900
            if no_bundle and public_branch is None:
 
4901
                raise errors.BzrCommandError('No public branch specified or'
 
4902
                                             ' known')
 
4903
            base_revision_id = None
 
4904
            revision_id = None
 
4905
            if revision is not None:
 
4906
                if len(revision) > 2:
 
4907
                    raise errors.BzrCommandError('bzr send takes '
 
4908
                        'at most two one revision identifiers')
 
4909
                revision_id = revision[-1].as_revision_id(branch)
 
4910
                if len(revision) == 2:
 
4911
                    base_revision_id = revision[0].as_revision_id(branch)
 
4912
            if revision_id is None:
 
4913
                revision_id = branch.last_revision()
 
4914
            if revision_id == NULL_REVISION:
 
4915
                raise errors.BzrCommandError('No revisions to submit.')
 
4916
            if format == '4':
 
4917
                directive = merge_directive.MergeDirective2.from_objects(
 
4918
                    branch.repository, revision_id, time.time(),
 
4919
                    osutils.local_time_offset(), submit_branch,
 
4920
                    public_branch=public_branch, include_patch=not no_patch,
 
4921
                    include_bundle=not no_bundle, message=message,
 
4922
                    base_revision_id=base_revision_id)
 
4923
            elif format == '0.9':
 
4924
                if not no_bundle:
 
4925
                    if not no_patch:
 
4926
                        patch_type = 'bundle'
 
4927
                    else:
 
4928
                        raise errors.BzrCommandError('Format 0.9 does not'
 
4929
                            ' permit bundle with no patch')
 
4930
                else:
 
4931
                    if not no_patch:
 
4932
                        patch_type = 'diff'
 
4933
                    else:
 
4934
                        patch_type = None
 
4935
                directive = merge_directive.MergeDirective.from_objects(
 
4936
                    branch.repository, revision_id, time.time(),
 
4937
                    osutils.local_time_offset(), submit_branch,
 
4938
                    public_branch=public_branch, patch_type=patch_type,
 
4939
                    message=message)
 
4940
 
 
4941
            if output is None:
 
4942
                directive.compose_merge_request(mail_client, mail_to, body,
 
4943
                                                branch, tree)
 
4944
            else:
 
4945
                if output == '-':
 
4946
                    outfile = self.outf
 
4947
                else:
 
4948
                    outfile = open(output, 'wb')
 
4949
                try:
 
4950
                    outfile.writelines(directive.to_lines())
 
4951
                finally:
 
4952
                    if outfile is not self.outf:
 
4953
                        outfile.close()
 
4954
        finally:
 
4955
            branch.unlock()
 
4956
 
 
4957
 
 
4958
class cmd_bundle_revisions(cmd_send):
 
4959
 
 
4960
    """Create a merge-directive for submitting changes.
 
4961
 
 
4962
    A merge directive provides many things needed for requesting merges:
 
4963
 
 
4964
    * A machine-readable description of the merge to perform
 
4965
 
 
4966
    * An optional patch that is a preview of the changes requested
 
4967
 
 
4968
    * An optional bundle of revision data, so that the changes can be applied
 
4969
      directly from the merge directive, without retrieving data from a
 
4970
      branch.
 
4971
 
 
4972
    If --no-bundle is specified, then public_branch is needed (and must be
 
4973
    up-to-date), so that the receiver can perform the merge using the
 
4974
    public_branch.  The public_branch is always included if known, so that
 
4975
    people can check it later.
 
4976
 
 
4977
    The submit branch defaults to the parent, but can be overridden.  Both
 
4978
    submit branch and public branch will be remembered if supplied.
 
4979
 
 
4980
    If a public_branch is known for the submit_branch, that public submit
 
4981
    branch is used in the merge instructions.  This means that a local mirror
 
4982
    can be used as your actual submit branch, once you have set public_branch
 
4983
    for that mirror.
 
4984
 
 
4985
    Two formats are currently supported: "4" uses revision bundle format 4 and
 
4986
    merge directive format 2.  It is significantly faster and smaller than
 
4987
    older formats.  It is compatible with Bazaar 0.19 and later.  It is the
 
4988
    default.  "0.9" uses revision bundle format 0.9 and merge directive
 
4989
    format 1.  It is compatible with Bazaar 0.12 - 0.18.
 
4990
    """
 
4991
 
 
4992
    takes_options = [
 
4993
        Option('no-bundle',
 
4994
               help='Do not include a bundle in the merge directive.'),
 
4995
        Option('no-patch', help='Do not include a preview patch in the merge'
 
4996
               ' directive.'),
 
4997
        Option('remember',
 
4998
               help='Remember submit and public branch.'),
 
4999
        Option('from',
 
5000
               help='Branch to generate the submission from, '
 
5001
               'rather than the one containing the working directory.',
 
5002
               short_name='f',
 
5003
               type=unicode),
 
5004
        Option('output', short_name='o', help='Write directive to this file.',
 
5005
               type=unicode),
 
5006
        'revision',
 
5007
        RegistryOption.from_kwargs('format',
 
5008
        'Use the specified output format.',
 
5009
        **{'4': 'Bundle format 4, Merge Directive 2 (default)',
 
5010
           '0.9': 'Bundle format 0.9, Merge Directive 1',})
 
5011
        ]
 
5012
    aliases = ['bundle']
 
5013
 
 
5014
    _see_also = ['send', 'merge']
 
5015
 
 
5016
    hidden = True
 
5017
 
 
5018
    def run(self, submit_branch=None, public_branch=None, no_bundle=False,
 
5019
            no_patch=False, revision=None, remember=False, output=None,
 
5020
            format='4', **kwargs):
 
5021
        if output is None:
 
5022
            output = '-'
 
5023
        return self._run(submit_branch, revision, public_branch, remember,
 
5024
                         format, no_bundle, no_patch, output,
 
5025
                         kwargs.get('from', '.'), None, None, None)
 
5026
 
 
5027
 
 
5028
class cmd_tag(Command):
 
5029
    """Create, remove or modify a tag naming a revision.
 
5030
 
 
5031
    Tags give human-meaningful names to revisions.  Commands that take a -r
 
5032
    (--revision) option can be given -rtag:X, where X is any previously
 
5033
    created tag.
 
5034
 
 
5035
    Tags are stored in the branch.  Tags are copied from one branch to another
 
5036
    along when you branch, push, pull or merge.
 
5037
 
 
5038
    It is an error to give a tag name that already exists unless you pass
 
5039
    --force, in which case the tag is moved to point to the new revision.
 
5040
 
 
5041
    To rename a tag (change the name but keep it on the same revsion), run ``bzr
 
5042
    tag new-name -r tag:old-name`` and then ``bzr tag --delete oldname``.
 
5043
    """
 
5044
 
 
5045
    _see_also = ['commit', 'tags']
 
5046
    takes_args = ['tag_name']
 
5047
    takes_options = [
 
5048
        Option('delete',
 
5049
            help='Delete this tag rather than placing it.',
 
5050
            ),
 
5051
        Option('directory',
 
5052
            help='Branch in which to place the tag.',
 
5053
            short_name='d',
 
5054
            type=unicode,
 
5055
            ),
 
5056
        Option('force',
 
5057
            help='Replace existing tags.',
 
5058
            ),
 
5059
        'revision',
 
5060
        ]
 
5061
 
 
5062
    def run(self, tag_name,
 
5063
            delete=None,
 
5064
            directory='.',
 
5065
            force=None,
 
5066
            revision=None,
 
5067
            ):
 
5068
        branch, relpath = Branch.open_containing(directory)
 
5069
        branch.lock_write()
 
5070
        try:
 
5071
            if delete:
 
5072
                branch.tags.delete_tag(tag_name)
 
5073
                self.outf.write('Deleted tag %s.\n' % tag_name)
 
5074
            else:
 
5075
                if revision:
 
5076
                    if len(revision) != 1:
 
5077
                        raise errors.BzrCommandError(
 
5078
                            "Tags can only be placed on a single revision, "
 
5079
                            "not on a range")
 
5080
                    revision_id = revision[0].as_revision_id(branch)
 
5081
                else:
 
5082
                    revision_id = branch.last_revision()
 
5083
                if (not force) and branch.tags.has_tag(tag_name):
 
5084
                    raise errors.TagAlreadyExists(tag_name)
 
5085
                branch.tags.set_tag(tag_name, revision_id)
 
5086
                self.outf.write('Created tag %s.\n' % tag_name)
 
5087
        finally:
 
5088
            branch.unlock()
 
5089
 
 
5090
 
 
5091
class cmd_tags(Command):
 
5092
    """List tags.
 
5093
 
 
5094
    This command shows a table of tag names and the revisions they reference.
 
5095
    """
 
5096
 
 
5097
    _see_also = ['tag']
 
5098
    takes_options = [
 
5099
        Option('directory',
 
5100
            help='Branch whose tags should be displayed.',
 
5101
            short_name='d',
 
5102
            type=unicode,
 
5103
            ),
 
5104
        RegistryOption.from_kwargs('sort',
 
5105
            'Sort tags by different criteria.', title='Sorting',
 
5106
            alpha='Sort tags lexicographically (default).',
 
5107
            time='Sort tags chronologically.',
 
5108
            ),
 
5109
        'show-ids',
 
5110
        'revision',
 
5111
    ]
 
5112
 
 
5113
    @display_command
 
5114
    def run(self,
 
5115
            directory='.',
 
5116
            sort='alpha',
 
5117
            show_ids=False,
 
5118
            revision=None,
 
5119
            ):
 
5120
        branch, relpath = Branch.open_containing(directory)
 
5121
 
 
5122
        tags = branch.tags.get_tag_dict().items()
 
5123
        if not tags:
 
5124
            return
 
5125
 
 
5126
        if revision:
 
5127
            branch.lock_read()
 
5128
            try:
 
5129
                graph = branch.repository.get_graph()
 
5130
                rev1, rev2 = _get_revision_range(revision, branch, self.name())
 
5131
                revid1, revid2 = rev1.rev_id, rev2.rev_id
 
5132
                # only show revisions between revid1 and revid2 (inclusive)
 
5133
                tags = [(tag, revid) for tag, revid in tags if
 
5134
                    graph.is_between(revid, revid1, revid2)]
 
5135
            finally:
 
5136
                branch.unlock()
 
5137
        if sort == 'alpha':
 
5138
            tags.sort()
 
5139
        elif sort == 'time':
 
5140
            timestamps = {}
 
5141
            for tag, revid in tags:
 
5142
                try:
 
5143
                    revobj = branch.repository.get_revision(revid)
 
5144
                except errors.NoSuchRevision:
 
5145
                    timestamp = sys.maxint # place them at the end
 
5146
                else:
 
5147
                    timestamp = revobj.timestamp
 
5148
                timestamps[revid] = timestamp
 
5149
            tags.sort(key=lambda x: timestamps[x[1]])
 
5150
        if not show_ids:
 
5151
            # [ (tag, revid), ... ] -> [ (tag, dotted_revno), ... ]
 
5152
            revno_map = branch.get_revision_id_to_revno_map()
 
5153
            tags = [ (tag, '.'.join(map(str, revno_map.get(revid, ('?',)))))
 
5154
                        for tag, revid in tags ]
 
5155
        for tag, revspec in tags:
 
5156
            self.outf.write('%-20s %s\n' % (tag, revspec))
 
5157
 
 
5158
 
 
5159
class cmd_reconfigure(Command):
 
5160
    """Reconfigure the type of a bzr directory.
 
5161
 
 
5162
    A target configuration must be specified.
 
5163
 
 
5164
    For checkouts, the bind-to location will be auto-detected if not specified.
 
5165
    The order of preference is
 
5166
    1. For a lightweight checkout, the current bound location.
 
5167
    2. For branches that used to be checkouts, the previously-bound location.
 
5168
    3. The push location.
 
5169
    4. The parent location.
 
5170
    If none of these is available, --bind-to must be specified.
 
5171
    """
 
5172
 
 
5173
    _see_also = ['branches', 'checkouts', 'standalone-trees', 'working-trees']
 
5174
    takes_args = ['location?']
 
5175
    takes_options = [
 
5176
        RegistryOption.from_kwargs(
 
5177
            'target_type',
 
5178
            title='Target type',
 
5179
            help='The type to reconfigure the directory to.',
 
5180
            value_switches=True, enum_switch=False,
 
5181
            branch='Reconfigure to be an unbound branch with no working tree.',
 
5182
            tree='Reconfigure to be an unbound branch with a working tree.',
 
5183
            checkout='Reconfigure to be a bound branch with a working tree.',
 
5184
            lightweight_checkout='Reconfigure to be a lightweight'
 
5185
                ' checkout (with no local history).',
 
5186
            standalone='Reconfigure to be a standalone branch '
 
5187
                '(i.e. stop using shared repository).',
 
5188
            use_shared='Reconfigure to use a shared repository.',
 
5189
            with_trees='Reconfigure repository to create '
 
5190
                'working trees on branches by default.',
 
5191
            with_no_trees='Reconfigure repository to not create '
 
5192
                'working trees on branches by default.'
 
5193
            ),
 
5194
        Option('bind-to', help='Branch to bind checkout to.', type=str),
 
5195
        Option('force',
 
5196
               help='Perform reconfiguration even if local changes'
 
5197
               ' will be lost.')
 
5198
        ]
 
5199
 
 
5200
    def run(self, location=None, target_type=None, bind_to=None, force=False):
 
5201
        directory = bzrdir.BzrDir.open(location)
 
5202
        if target_type is None:
 
5203
            raise errors.BzrCommandError('No target configuration specified')
 
5204
        elif target_type == 'branch':
 
5205
            reconfiguration = reconfigure.Reconfigure.to_branch(directory)
 
5206
        elif target_type == 'tree':
 
5207
            reconfiguration = reconfigure.Reconfigure.to_tree(directory)
 
5208
        elif target_type == 'checkout':
 
5209
            reconfiguration = reconfigure.Reconfigure.to_checkout(
 
5210
                directory, bind_to)
 
5211
        elif target_type == 'lightweight-checkout':
 
5212
            reconfiguration = reconfigure.Reconfigure.to_lightweight_checkout(
 
5213
                directory, bind_to)
 
5214
        elif target_type == 'use-shared':
 
5215
            reconfiguration = reconfigure.Reconfigure.to_use_shared(directory)
 
5216
        elif target_type == 'standalone':
 
5217
            reconfiguration = reconfigure.Reconfigure.to_standalone(directory)
 
5218
        elif target_type == 'with-trees':
 
5219
            reconfiguration = reconfigure.Reconfigure.set_repository_trees(
 
5220
                directory, True)
 
5221
        elif target_type == 'with-no-trees':
 
5222
            reconfiguration = reconfigure.Reconfigure.set_repository_trees(
 
5223
                directory, False)
 
5224
        reconfiguration.apply(force)
 
5225
 
 
5226
 
 
5227
class cmd_switch(Command):
 
5228
    """Set the branch of a checkout and update.
 
5229
 
 
5230
    For lightweight checkouts, this changes the branch being referenced.
 
5231
    For heavyweight checkouts, this checks that there are no local commits
 
5232
    versus the current bound branch, then it makes the local branch a mirror
 
5233
    of the new location and binds to it.
 
5234
 
 
5235
    In both cases, the working tree is updated and uncommitted changes
 
5236
    are merged. The user can commit or revert these as they desire.
 
5237
 
 
5238
    Pending merges need to be committed or reverted before using switch.
 
5239
 
 
5240
    The path to the branch to switch to can be specified relative to the parent
 
5241
    directory of the current branch. For example, if you are currently in a
 
5242
    checkout of /path/to/branch, specifying 'newbranch' will find a branch at
 
5243
    /path/to/newbranch.
 
5244
 
 
5245
    Bound branches use the nickname of its master branch unless it is set
 
5246
    locally, in which case switching will update the the local nickname to be
 
5247
    that of the master.
 
5248
    """
 
5249
 
 
5250
    takes_args = ['to_location']
 
5251
    takes_options = [Option('force',
 
5252
                        help='Switch even if local commits will be lost.')
 
5253
                     ]
 
5254
 
 
5255
    def run(self, to_location, force=False):
 
5256
        from bzrlib import switch
 
5257
        tree_location = '.'
 
5258
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
 
5259
        try:
 
5260
            branch = control_dir.open_branch()
 
5261
            had_explicit_nick = branch.get_config().has_explicit_nickname()
 
5262
        except errors.NotBranchError:
 
5263
            had_explicit_nick = False
 
5264
        try:
 
5265
            to_branch = Branch.open(to_location)
 
5266
        except errors.NotBranchError:
 
5267
            this_url = self._get_branch_location(control_dir)
 
5268
            to_branch = Branch.open(
 
5269
                urlutils.join(this_url, '..', to_location))
 
5270
        switch.switch(control_dir, to_branch, force)
 
5271
        if had_explicit_nick:
 
5272
            branch = control_dir.open_branch() #get the new branch!
 
5273
            branch.nick = to_branch.nick
 
5274
        note('Switched to branch: %s',
 
5275
            urlutils.unescape_for_display(to_branch.base, 'utf-8'))
 
5276
 
 
5277
    def _get_branch_location(self, control_dir):
 
5278
        """Return location of branch for this control dir."""
 
5279
        try:
 
5280
            this_branch = control_dir.open_branch()
 
5281
            # This may be a heavy checkout, where we want the master branch
 
5282
            master_location = this_branch.get_bound_location()
 
5283
            if master_location is not None:
 
5284
                return master_location
 
5285
            # If not, use a local sibling
 
5286
            return this_branch.base
 
5287
        except errors.NotBranchError:
 
5288
            format = control_dir.find_branch_format()
 
5289
            if getattr(format, 'get_reference', None) is not None:
 
5290
                return format.get_reference(control_dir)
 
5291
            else:
 
5292
                return control_dir.root_transport.base
 
5293
 
 
5294
 
 
5295
class cmd_view(Command):
 
5296
    """Manage filtered views.
 
5297
 
 
5298
    Views provide a mask over the tree so that users can focus on
 
5299
    a subset of a tree when doing their work. After creating a view,
 
5300
    commands that support a list of files - status, diff, commit, etc -
 
5301
    effectively have that list of files implicitly given each time.
 
5302
    An explicit list of files can still be given but those files
 
5303
    must be within the current view.
 
5304
 
 
5305
    In most cases, a view has a short life-span: it is created to make
 
5306
    a selected change and is deleted once that change is committed.
 
5307
    At other times, you may wish to create one or more named views
 
5308
    and switch between them.
 
5309
 
 
5310
    To disable the current view without deleting it, you can switch to
 
5311
    the pseudo view called ``off``. This can be useful when you need
 
5312
    to see the whole tree for an operation or two (e.g. merge) but
 
5313
    want to switch back to your view after that.
 
5314
 
 
5315
    :Examples:
 
5316
      To define the current view::
 
5317
 
 
5318
        bzr view file1 dir1 ...
 
5319
 
 
5320
      To list the current view::
 
5321
 
 
5322
        bzr view
 
5323
 
 
5324
      To delete the current view::
 
5325
 
 
5326
        bzr view --delete
 
5327
 
 
5328
      To disable the current view without deleting it::
 
5329
 
 
5330
        bzr view --switch off
 
5331
 
 
5332
      To define a named view and switch to it::
 
5333
 
 
5334
        bzr view --name view-name file1 dir1 ...
 
5335
 
 
5336
      To list a named view::
 
5337
 
 
5338
        bzr view --name view-name
 
5339
 
 
5340
      To delete a named view::
 
5341
 
 
5342
        bzr view --name view-name --delete
 
5343
 
 
5344
      To switch to a named view::
 
5345
 
 
5346
        bzr view --switch view-name
 
5347
 
 
5348
      To list all views defined::
 
5349
 
 
5350
        bzr view --all
 
5351
 
 
5352
      To delete all views::
 
5353
 
 
5354
        bzr view --delete --all
 
5355
    """
 
5356
 
 
5357
    _see_also = []
 
5358
    takes_args = ['file*']
 
5359
    takes_options = [
 
5360
        Option('all',
 
5361
            help='Apply list or delete action to all views.',
 
5362
            ),
 
5363
        Option('delete',
 
5364
            help='Delete the view.',
 
5365
            ),
 
5366
        Option('name',
 
5367
            help='Name of the view to define, list or delete.',
 
5368
            type=unicode,
 
5369
            ),
 
5370
        Option('switch',
 
5371
            help='Name of the view to switch to.',
 
5372
            type=unicode,
 
5373
            ),
 
5374
        ]
 
5375
 
 
5376
    def run(self, file_list,
 
5377
            all=False,
 
5378
            delete=False,
 
5379
            name=None,
 
5380
            switch=None,
 
5381
            ):
 
5382
        tree, file_list = tree_files(file_list, apply_view=False)
 
5383
        current_view, view_dict = tree.views.get_view_info()
 
5384
        if name is None:
 
5385
            name = current_view
 
5386
        if delete:
 
5387
            if file_list:
 
5388
                raise errors.BzrCommandError(
 
5389
                    "Both --delete and a file list specified")
 
5390
            elif switch:
 
5391
                raise errors.BzrCommandError(
 
5392
                    "Both --delete and --switch specified")
 
5393
            elif all:
 
5394
                tree.views.set_view_info(None, {})
 
5395
                self.outf.write("Deleted all views.\n")
 
5396
            elif name is None:
 
5397
                raise errors.BzrCommandError("No current view to delete")
 
5398
            else:
 
5399
                tree.views.delete_view(name)
 
5400
                self.outf.write("Deleted '%s' view.\n" % name)
 
5401
        elif switch:
 
5402
            if file_list:
 
5403
                raise errors.BzrCommandError(
 
5404
                    "Both --switch and a file list specified")
 
5405
            elif all:
 
5406
                raise errors.BzrCommandError(
 
5407
                    "Both --switch and --all specified")
 
5408
            elif switch == 'off':
 
5409
                if current_view is None:
 
5410
                    raise errors.BzrCommandError("No current view to disable")
 
5411
                tree.views.set_view_info(None, view_dict)
 
5412
                self.outf.write("Disabled '%s' view.\n" % (current_view))
 
5413
            else:
 
5414
                tree.views.set_view_info(switch, view_dict)
 
5415
                view_str = views.view_display_str(tree.views.lookup_view())
 
5416
                self.outf.write("Using '%s' view: %s\n" % (switch, view_str))
 
5417
        elif all:
 
5418
            if view_dict:
 
5419
                self.outf.write('Views defined:\n')
 
5420
                for view in sorted(view_dict):
 
5421
                    if view == current_view:
 
5422
                        active = "=>"
 
5423
                    else:
 
5424
                        active = "  "
 
5425
                    view_str = views.view_display_str(view_dict[view])
 
5426
                    self.outf.write('%s %-20s %s\n' % (active, view, view_str))
 
5427
            else:
 
5428
                self.outf.write('No views defined.\n')
 
5429
        elif file_list:
 
5430
            if name is None:
 
5431
                # No name given and no current view set
 
5432
                name = 'my'
 
5433
            elif name == 'off':
 
5434
                raise errors.BzrCommandError(
 
5435
                    "Cannot change the 'off' pseudo view")
 
5436
            tree.views.set_view(name, sorted(file_list))
 
5437
            view_str = views.view_display_str(tree.views.lookup_view())
 
5438
            self.outf.write("Using '%s' view: %s\n" % (name, view_str))
 
5439
        else:
 
5440
            # list the files
 
5441
            if name is None:
 
5442
                # No name given and no current view set
 
5443
                self.outf.write('No current view.\n')
 
5444
            else:
 
5445
                view_str = views.view_display_str(tree.views.lookup_view(name))
 
5446
                self.outf.write("'%s' view is: %s\n" % (name, view_str))
 
5447
 
 
5448
 
 
5449
class cmd_hooks(Command):
 
5450
    """Show hooks."""
 
5451
 
 
5452
    hidden = True
 
5453
 
 
5454
    def run(self):
 
5455
        for hook_key in sorted(hooks.known_hooks.keys()):
 
5456
            some_hooks = hooks.known_hooks_key_to_object(hook_key)
 
5457
            self.outf.write("%s:\n" % type(some_hooks).__name__)
 
5458
            for hook_name, hook_point in sorted(some_hooks.items()):
 
5459
                self.outf.write("  %s:\n" % (hook_name,))
 
5460
                found_hooks = list(hook_point)
 
5461
                if found_hooks:
 
5462
                    for hook in found_hooks:
 
5463
                        self.outf.write("    %s\n" %
 
5464
                                        (some_hooks.get_hook_name(hook),))
 
5465
                else:
 
5466
                    self.outf.write("    <no hooks installed>\n")
 
5467
 
 
5468
 
 
5469
class cmd_shelve(Command):
 
5470
    """Temporarily set aside some changes from the current tree.
 
5471
 
 
5472
    Shelve allows you to temporarily put changes you've made "on the shelf",
 
5473
    ie. out of the way, until a later time when you can bring them back from
 
5474
    the shelf with the 'unshelve' command.  The changes are stored alongside
 
5475
    your working tree, and so they aren't propagated along with your branch nor
 
5476
    will they survive its deletion.
 
5477
 
 
5478
    If shelve --list is specified, previously-shelved changes are listed.
 
5479
 
 
5480
    Shelve is intended to help separate several sets of changes that have
 
5481
    been inappropriately mingled.  If you just want to get rid of all changes
 
5482
    and you don't need to restore them later, use revert.  If you want to
 
5483
    shelve all text changes at once, use shelve --all.
 
5484
 
 
5485
    If filenames are specified, only the changes to those files will be
 
5486
    shelved. Other files will be left untouched.
 
5487
 
 
5488
    If a revision is specified, changes since that revision will be shelved.
 
5489
 
 
5490
    You can put multiple items on the shelf, and by default, 'unshelve' will
 
5491
    restore the most recently shelved changes.
 
5492
    """
 
5493
 
 
5494
    takes_args = ['file*']
 
5495
 
 
5496
    takes_options = [
 
5497
        'revision',
 
5498
        Option('all', help='Shelve all changes.'),
 
5499
        'message',
 
5500
        RegistryOption('writer', 'Method to use for writing diffs.',
 
5501
                       bzrlib.option.diff_writer_registry,
 
5502
                       value_switches=True, enum_switch=False),
 
5503
 
 
5504
        Option('list', help='List shelved changes.'),
 
5505
        Option('destroy',
 
5506
               help='Destroy removed changes instead of shelving them.'),
 
5507
    ]
 
5508
    _see_also = ['unshelve']
 
5509
 
 
5510
    def run(self, revision=None, all=False, file_list=None, message=None,
 
5511
            writer=None, list=False, destroy=False):
 
5512
        if list:
 
5513
            return self.run_for_list()
 
5514
        from bzrlib.shelf_ui import Shelver
 
5515
        if writer is None:
 
5516
            writer = bzrlib.option.diff_writer_registry.get()
 
5517
        try:
 
5518
            Shelver.from_args(writer(sys.stdout), revision, all, file_list,
 
5519
                              message, destroy=destroy).run()
 
5520
        except errors.UserAbort:
 
5521
            return 0
 
5522
 
 
5523
    def run_for_list(self):
 
5524
        tree = WorkingTree.open_containing('.')[0]
 
5525
        tree.lock_read()
 
5526
        try:
 
5527
            manager = tree.get_shelf_manager()
 
5528
            shelves = manager.active_shelves()
 
5529
            if len(shelves) == 0:
 
5530
                note('No shelved changes.')
 
5531
                return 0
 
5532
            for shelf_id in reversed(shelves):
 
5533
                message = manager.get_metadata(shelf_id).get('message')
 
5534
                if message is None:
 
5535
                    message = '<no message>'
 
5536
                self.outf.write('%3d: %s\n' % (shelf_id, message))
 
5537
            return 1
 
5538
        finally:
 
5539
            tree.unlock()
 
5540
 
 
5541
 
 
5542
class cmd_unshelve(Command):
 
5543
    """Restore shelved changes.
 
5544
 
 
5545
    By default, the most recently shelved changes are restored. However if you
 
5546
    specify a shelf by id those changes will be restored instead.  This works
 
5547
    best when the changes don't depend on each other.
 
5548
    """
 
5549
 
 
5550
    takes_args = ['shelf_id?']
 
5551
    takes_options = [
 
5552
        RegistryOption.from_kwargs(
 
5553
            'action', help="The action to perform.",
 
5554
            enum_switch=False, value_switches=True,
 
5555
            apply="Apply changes and remove from the shelf.",
 
5556
            dry_run="Show changes, but do not apply or remove them.",
 
5557
            delete_only="Delete changes without applying them."
 
5558
        )
 
5559
    ]
 
5560
    _see_also = ['shelve']
 
5561
 
 
5562
    def run(self, shelf_id=None, action='apply'):
 
5563
        from bzrlib.shelf_ui import Unshelver
 
5564
        Unshelver.from_args(shelf_id, action).run()
 
5565
 
 
5566
 
 
5567
class cmd_clean_tree(Command):
 
5568
    """Remove unwanted files from working tree.
 
5569
 
 
5570
    By default, only unknown files, not ignored files, are deleted.  Versioned
 
5571
    files are never deleted.
 
5572
 
 
5573
    Another class is 'detritus', which includes files emitted by bzr during
 
5574
    normal operations and selftests.  (The value of these files decreases with
 
5575
    time.)
 
5576
 
 
5577
    If no options are specified, unknown files are deleted.  Otherwise, option
 
5578
    flags are respected, and may be combined.
 
5579
 
 
5580
    To check what clean-tree will do, use --dry-run.
 
5581
    """
 
5582
    takes_options = [Option('ignored', help='Delete all ignored files.'),
 
5583
                     Option('detritus', help='Delete conflict files, merge'
 
5584
                            ' backups, and failed selftest dirs.'),
 
5585
                     Option('unknown',
 
5586
                            help='Delete files unknown to bzr (default).'),
 
5587
                     Option('dry-run', help='Show files to delete instead of'
 
5588
                            ' deleting them.'),
 
5589
                     Option('force', help='Do not prompt before deleting.')]
 
5590
    def run(self, unknown=False, ignored=False, detritus=False, dry_run=False,
 
5591
            force=False):
 
5592
        from bzrlib.clean_tree import clean_tree
 
5593
        if not (unknown or ignored or detritus):
 
5594
            unknown = True
 
5595
        if dry_run:
 
5596
            force = True
 
5597
        clean_tree('.', unknown=unknown, ignored=ignored, detritus=detritus,
 
5598
                   dry_run=dry_run, no_prompt=force)
 
5599
 
 
5600
 
 
5601
class cmd_reference(Command):
 
5602
    """list, view and set branch locations for nested trees.
 
5603
 
 
5604
    If no arguments are provided, lists the branch locations for nested trees.
 
5605
    If one argument is provided, display the branch location for that tree.
 
5606
    If two arguments are provided, set the branch location for that tree.
 
5607
    """
 
5608
 
 
5609
    hidden = True
 
5610
 
 
5611
    takes_args = ['path?', 'location?']
 
5612
 
 
5613
    def run(self, path=None, location=None):
 
5614
        branchdir = '.'
 
5615
        if path is not None:
 
5616
            branchdir = path
 
5617
        tree, branch, relpath =(
 
5618
            bzrdir.BzrDir.open_containing_tree_or_branch(branchdir))
 
5619
        if path is not None:
 
5620
            path = relpath
 
5621
        if tree is None:
 
5622
            tree = branch.basis_tree()
 
5623
        if path is None:
 
5624
            info = branch._get_all_reference_info().iteritems()
 
5625
            self._display_reference_info(tree, branch, info)
 
5626
        else:
 
5627
            file_id = tree.path2id(path)
 
5628
            if file_id is None:
 
5629
                raise errors.NotVersionedError(path)
 
5630
            if location is None:
 
5631
                info = [(file_id, branch.get_reference_info(file_id))]
 
5632
                self._display_reference_info(tree, branch, info)
 
5633
            else:
 
5634
                branch.set_reference_info(file_id, path, location)
 
5635
 
 
5636
    def _display_reference_info(self, tree, branch, info):
 
5637
        ref_list = []
 
5638
        for file_id, (path, location) in info:
 
5639
            try:
 
5640
                path = tree.id2path(file_id)
 
5641
            except errors.NoSuchId:
 
5642
                pass
 
5643
            ref_list.append((path, location))
 
5644
        for path, location in sorted(ref_list):
 
5645
            self.outf.write('%s %s\n' % (path, location))
 
5646
 
 
5647
 
 
5648
# these get imported and then picked up by the scan for cmd_*
 
5649
# TODO: Some more consistent way to split command definitions across files;
 
5650
# we do need to load at least some information about them to know of
 
5651
# aliases.  ideally we would avoid loading the implementation until the
 
5652
# details were needed.
 
5653
from bzrlib.cmd_version_info import cmd_version_info
 
5654
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
 
5655
from bzrlib.bundle.commands import (
 
5656
    cmd_bundle_info,
 
5657
    )
 
5658
from bzrlib.foreign import cmd_dpush
 
5659
from bzrlib.sign_my_commits import cmd_sign_my_commits
 
5660
from bzrlib.weave_commands import cmd_versionedfile_list, \
 
5661
        cmd_weave_plan_merge, cmd_weave_merge_text