/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

merge bzr.dev r3998

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