~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

1st cut merge of bzr.dev r3907

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
"""builtin bzr commands"""
18
18
 
19
19
import os
20
 
from StringIO import StringIO
21
20
 
22
21
from bzrlib.lazy_import import lazy_import
23
22
lazy_import(globals(), """
24
23
import codecs
 
24
import cStringIO
25
25
import sys
26
26
import time
27
27
 
29
29
from bzrlib import (
30
30
    bugtracker,
31
31
    bundle,
 
32
    btree_index,
32
33
    bzrdir,
33
34
    delta,
34
35
    config,
35
36
    errors,
36
37
    globbing,
37
 
    ignores,
38
38
    log,
39
39
    merge as _mod_merge,
40
40
    merge_directive,
56
56
 
57
57
from bzrlib.commands import Command, display_command
58
58
from bzrlib.option import ListOption, Option, RegistryOption, custom_help
59
 
from bzrlib.trace import mutter, note, warning, is_quiet, info
 
59
from bzrlib.trace import mutter, note, warning, is_quiet, get_verbosity_level
60
60
 
61
61
 
62
62
def tree_files(file_list, default_branch=u'.'):
67
67
                                     (e.path, file_list[0]))
68
68
 
69
69
 
 
70
def _get_one_revision_tree(command_name, revisions, branch=None, tree=None):
 
71
    if branch is None:
 
72
        branch = tree.branch
 
73
    if revisions is None:
 
74
        if tree is not None:
 
75
            rev_tree = tree.basis_tree()
 
76
        else:
 
77
            rev_tree = branch.basis_tree()
 
78
    else:
 
79
        if len(revisions) != 1:
 
80
            raise errors.BzrCommandError(
 
81
                'bzr %s --revision takes exactly one revision identifier' % (
 
82
                    command_name,))
 
83
        rev_tree = revisions[0].as_tree(branch)
 
84
    return rev_tree
 
85
 
 
86
 
70
87
# XXX: Bad function name; should possibly also be a class method of
71
88
# WorkingTree rather than a function.
72
89
def internal_tree_files(file_list, default_branch=u'.'):
184
201
            raise errors.BzrCommandError('bzr status --revision takes exactly'
185
202
                                         ' one or two revision specifiers')
186
203
 
187
 
        tree, file_list = tree_files(file_list)
188
 
            
 
204
        tree, relfile_list = tree_files(file_list)
 
205
        # Avoid asking for specific files when that is not needed.
 
206
        if relfile_list == ['']:
 
207
            relfile_list = None
 
208
            # Don't disable pending merges for full trees other than '.'.
 
209
            if file_list == ['.']:
 
210
                no_pending = True
 
211
        # A specific path within a tree was given.
 
212
        elif relfile_list is not None:
 
213
            no_pending = True
189
214
        show_tree_status(tree, show_ids=show_ids,
190
 
                         specific_files=file_list, revision=revision,
 
215
                         specific_files=relfile_list, revision=revision,
191
216
                         to_file=self.outf, short=short, versioned=versioned,
192
 
                         show_pending=not no_pending)
 
217
                         show_pending=(not no_pending))
193
218
 
194
219
 
195
220
class cmd_cat_revision(Command):
218
243
        # TODO: jam 20060112 should cat-revision always output utf-8?
219
244
        if revision_id is not None:
220
245
            revision_id = osutils.safe_revision_id(revision_id, warn=False)
221
 
            self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
 
246
            try:
 
247
                self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
 
248
            except errors.NoSuchRevision:
 
249
                msg = "The repository %s contains no revision %s." % (b.repository.base,
 
250
                    revision_id)
 
251
                raise errors.BzrCommandError(msg)
222
252
        elif revision is not None:
223
253
            for rev in revision:
224
254
                if rev is None:
226
256
                                                 ' revision.')
227
257
                rev_id = rev.as_revision_id(b)
228
258
                self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
229
 
    
 
259
 
 
260
 
 
261
class cmd_dump_btree(Command):
 
262
    """Dump the contents of a btree index file to stdout.
 
263
 
 
264
    PATH is a btree index file, it can be any URL. This includes things like
 
265
    .bzr/repository/pack-names, or .bzr/repository/indices/a34b3a...ca4a4.iix
 
266
 
 
267
    By default, the tuples stored in the index file will be displayed. With
 
268
    --raw, we will uncompress the pages, but otherwise display the raw bytes
 
269
    stored in the index.
 
270
    """
 
271
 
 
272
    # TODO: Do we want to dump the internal nodes as well?
 
273
    # TODO: It would be nice to be able to dump the un-parsed information,
 
274
    #       rather than only going through iter_all_entries. However, this is
 
275
    #       good enough for a start
 
276
    hidden = True
 
277
    encoding_type = 'exact'
 
278
    takes_args = ['path']
 
279
    takes_options = [Option('raw', help='Write the uncompressed bytes out,'
 
280
                                        ' rather than the parsed tuples.'),
 
281
                    ]
 
282
 
 
283
    def run(self, path, raw=False):
 
284
        dirname, basename = osutils.split(path)
 
285
        t = transport.get_transport(dirname)
 
286
        if raw:
 
287
            self._dump_raw_bytes(t, basename)
 
288
        else:
 
289
            self._dump_entries(t, basename)
 
290
 
 
291
    def _get_index_and_bytes(self, trans, basename):
 
292
        """Create a BTreeGraphIndex and raw bytes."""
 
293
        bt = btree_index.BTreeGraphIndex(trans, basename, None)
 
294
        bytes = trans.get_bytes(basename)
 
295
        bt._file = cStringIO.StringIO(bytes)
 
296
        bt._size = len(bytes)
 
297
        return bt, bytes
 
298
 
 
299
    def _dump_raw_bytes(self, trans, basename):
 
300
        import zlib
 
301
 
 
302
        # We need to parse at least the root node.
 
303
        # This is because the first page of every row starts with an
 
304
        # uncompressed header.
 
305
        bt, bytes = self._get_index_and_bytes(trans, basename)
 
306
        for page_idx, page_start in enumerate(xrange(0, len(bytes),
 
307
                                                     btree_index._PAGE_SIZE)):
 
308
            page_end = min(page_start + btree_index._PAGE_SIZE, len(bytes))
 
309
            page_bytes = bytes[page_start:page_end]
 
310
            if page_idx == 0:
 
311
                self.outf.write('Root node:\n')
 
312
                header_end, data = bt._parse_header_from_bytes(page_bytes)
 
313
                self.outf.write(page_bytes[:header_end])
 
314
                page_bytes = data
 
315
            self.outf.write('\nPage %d\n' % (page_idx,))
 
316
            decomp_bytes = zlib.decompress(page_bytes)
 
317
            self.outf.write(decomp_bytes)
 
318
            self.outf.write('\n')
 
319
 
 
320
    def _dump_entries(self, trans, basename):
 
321
        try:
 
322
            st = trans.stat(basename)
 
323
        except errors.TransportNotPossible:
 
324
            # We can't stat, so we'll fake it because we have to do the 'get()'
 
325
            # anyway.
 
326
            bt, _ = self._get_index_and_bytes(trans, basename)
 
327
        else:
 
328
            bt = btree_index.BTreeGraphIndex(trans, basename, st.st_size)
 
329
        for node in bt.iter_all_entries():
 
330
            # Node is made up of:
 
331
            # (index, key, value, [references])
 
332
            self.outf.write('%s\n' % (node[1:],))
 
333
 
230
334
 
231
335
class cmd_remove_tree(Command):
232
336
    """Remove the working tree from a given branch/checkout.
237
341
    To re-create the working tree, use "bzr checkout".
238
342
    """
239
343
    _see_also = ['checkout', 'working-trees']
240
 
 
241
344
    takes_args = ['location?']
 
345
    takes_options = [
 
346
        Option('force',
 
347
               help='Remove the working tree even if it has '
 
348
                    'uncommitted changes.'),
 
349
        ]
242
350
 
243
 
    def run(self, location='.'):
 
351
    def run(self, location='.', force=False):
244
352
        d = bzrdir.BzrDir.open(location)
245
353
        
246
354
        try:
250
358
        except errors.NotLocalUrl:
251
359
            raise errors.BzrCommandError("You cannot remove the working tree of a "
252
360
                                         "remote path")
253
 
        
 
361
        if not force:
 
362
            changes = working.changes_from(working.basis_tree())
 
363
            if changes.has_changed():
 
364
                raise errors.UncommittedChanges(working)
 
365
 
254
366
        working_path = working.bzrdir.root_transport.base
255
367
        branch_path = working.branch.bzrdir.root_transport.base
256
368
        if working_path != branch_path:
280
392
    """
281
393
    hidden = True
282
394
    takes_args = ['revision_info*']
283
 
    takes_options = ['revision']
 
395
    takes_options = [
 
396
        'revision',
 
397
        Option('directory',
 
398
            help='Branch to examine, '
 
399
                 'rather than the one containing the working directory.',
 
400
            short_name='d',
 
401
            type=unicode,
 
402
            ),
 
403
        ]
284
404
 
285
405
    @display_command
286
 
    def run(self, revision=None, revision_info_list=[]):
 
406
    def run(self, revision=None, directory=u'.', revision_info_list=[]):
287
407
 
288
408
        revs = []
289
409
        if revision is not None:
292
412
            for rev in revision_info_list:
293
413
                revs.append(RevisionSpec.from_string(rev))
294
414
 
295
 
        b = Branch.open_containing(u'.')[0]
 
415
        b = Branch.open_containing(directory)[0]
296
416
 
297
417
        if len(revs) == 0:
298
418
            revs.append(RevisionSpec.from_string('-1'))
469
589
                    raise errors.BzrCommandError(
470
590
                        'bzr inventory --revision takes exactly one revision'
471
591
                        ' identifier')
472
 
                revision_id = revision[0].as_revision_id(work_tree.branch)
473
 
                tree = work_tree.branch.repository.revision_tree(revision_id)
 
592
                tree = revision[0].as_tree(work_tree.branch)
474
593
 
475
594
                extra_trees = [work_tree]
476
595
                tree.lock_read()
644
763
                display_url = urlutils.unescape_for_display(stored_loc,
645
764
                        self.outf.encoding)
646
765
                if not is_quiet():
647
 
                    self.outf.write("Using saved location: %s\n" % display_url)
 
766
                    self.outf.write("Using saved parent location: %s\n" % display_url)
648
767
                location = stored_loc
649
768
 
650
769
        if mergeable is not None:
687
806
                    result.old_revid))
688
807
                old_rh.reverse()
689
808
                new_rh = branch_to.revision_history()
 
809
                log_format = branch_to.get_config().log_format()
690
810
                log.show_changed_revisions(branch_to, old_rh, new_rh,
691
 
                                           to_file=self.outf)
 
811
                                           to_file=self.outf,
 
812
                                           log_format=log_format)
692
813
        finally:
693
814
            branch_to.unlock()
694
815
 
793
914
            else:
794
915
                display_url = urlutils.unescape_for_display(stored_loc,
795
916
                        self.outf.encoding)
796
 
                self.outf.write("Using saved location: %s\n" % display_url)
 
917
                self.outf.write("Using saved push location: %s\n" % display_url)
797
918
                location = stored_loc
798
919
 
799
920
        _show_push_branch(br_from, revision_id, location, self.outf,
824
945
            help='Create a stacked branch referring to the source branch. '
825
946
                'The new branch will depend on the availability of the source '
826
947
                'branch for all operations.'),
 
948
        Option('standalone',
 
949
               help='Do not use a shared repository, even if available.'),
827
950
        ]
828
951
    aliases = ['get', 'clone']
829
952
 
830
953
    def run(self, from_location, to_location=None, revision=None,
831
 
            hardlink=False, stacked=False):
 
954
            hardlink=False, stacked=False, standalone=False):
832
955
        from bzrlib.tag import _merge_tags_if_possible
833
956
        if revision is None:
834
957
            revision = [None]
863
986
                dir = br_from.bzrdir.sprout(to_transport.base, revision_id,
864
987
                                            possible_transports=[to_transport],
865
988
                                            accelerator_tree=accelerator_tree,
866
 
                                            hardlink=hardlink, stacked=stacked)
 
989
                                            hardlink=hardlink, stacked=stacked,
 
990
                                            force_new_repo=standalone,
 
991
                                            source_branch=br_from)
867
992
                branch = dir.open_branch()
868
993
            except errors.NoSuchRevision:
869
994
                to_transport.delete_tree('.')
976
1101
            old_tree.lock_read()
977
1102
            try:
978
1103
                old_inv = old_tree.inventory
979
 
                renames = list(_mod_tree.find_renames(old_inv, new_inv))
 
1104
                renames = []
 
1105
                iterator = tree.iter_changes(old_tree, include_unchanged=True)
 
1106
                for f, paths, c, v, p, n, k, e in iterator:
 
1107
                    if paths[0] == paths[1]:
 
1108
                        continue
 
1109
                    if None in (paths):
 
1110
                        continue
 
1111
                    renames.append(paths)
980
1112
                renames.sort()
981
1113
                for old_name, new_name in renames:
982
1114
                    self.outf.write("%s => %s\n" % (old_name, new_name))
1066
1198
class cmd_remove(Command):
1067
1199
    """Remove files or directories.
1068
1200
 
1069
 
    This makes bzr stop tracking changes to the specified files and
1070
 
    delete them if they can easily be recovered using revert.
1071
 
 
1072
 
    You can specify one or more files, and/or --new.  If you specify --new,
1073
 
    only 'added' files will be removed.  If you specify both, then new files
1074
 
    in the specified directories will be removed.  If the directories are
1075
 
    also new, they will also be removed.
 
1201
    This makes bzr stop tracking changes to the specified files. bzr will delete
 
1202
    them if they can easily be recovered using revert. If no options or
 
1203
    parameters are given bzr will scan for files that are being tracked by bzr
 
1204
    but missing in your tree and stop tracking them for you.
1076
1205
    """
1077
1206
    takes_args = ['file*']
1078
1207
    takes_options = ['verbose',
1079
 
        Option('new', help='Remove newly-added files.'),
 
1208
        Option('new', help='Only remove files that have never been committed.'),
1080
1209
        RegistryOption.from_kwargs('file-deletion-strategy',
1081
1210
            'The file deletion mode to be used.',
1082
1211
            title='Deletion Strategy', value_switches=True, enum_switch=False,
1085
1214
            keep="Don't delete any files.",
1086
1215
            force='Delete all the specified files, even if they can not be '
1087
1216
                'recovered and even if they are non-empty directories.')]
1088
 
    aliases = ['rm']
 
1217
    aliases = ['rm', 'del']
1089
1218
    encoding_type = 'replace'
1090
1219
 
1091
1220
    def run(self, file_list, verbose=False, new=False,
1094
1223
 
1095
1224
        if file_list is not None:
1096
1225
            file_list = [f for f in file_list]
1097
 
        elif not new:
1098
 
            raise errors.BzrCommandError('Specify one or more files to'
1099
 
            ' remove, or use --new.')
1100
1226
 
1101
 
        if new:
1102
 
            added = tree.changes_from(tree.basis_tree(),
1103
 
                specific_files=file_list).added
1104
 
            file_list = sorted([f[0] for f in added], reverse=True)
1105
 
            if len(file_list) == 0:
1106
 
                raise errors.BzrCommandError('No matching files.')
1107
 
        tree.remove(file_list, verbose=verbose, to_file=self.outf,
1108
 
            keep_files=file_deletion_strategy=='keep',
1109
 
            force=file_deletion_strategy=='force')
 
1227
        tree.lock_write()
 
1228
        try:
 
1229
            # Heuristics should probably all move into tree.remove_smart or
 
1230
            # some such?
 
1231
            if new:
 
1232
                added = tree.changes_from(tree.basis_tree(),
 
1233
                    specific_files=file_list).added
 
1234
                file_list = sorted([f[0] for f in added], reverse=True)
 
1235
                if len(file_list) == 0:
 
1236
                    raise errors.BzrCommandError('No matching files.')
 
1237
            elif file_list is None:
 
1238
                # missing files show up in iter_changes(basis) as
 
1239
                # versioned-with-no-kind.
 
1240
                missing = []
 
1241
                for change in tree.iter_changes(tree.basis_tree()):
 
1242
                    # Find paths in the working tree that have no kind:
 
1243
                    if change[1][1] is not None and change[6][1] is None:
 
1244
                        missing.append(change[1][1])
 
1245
                file_list = sorted(missing, reverse=True)
 
1246
                file_deletion_strategy = 'keep'
 
1247
            tree.remove(file_list, verbose=verbose, to_file=self.outf,
 
1248
                keep_files=file_deletion_strategy=='keep',
 
1249
                force=file_deletion_strategy=='force')
 
1250
        finally:
 
1251
            tree.unlock()
1110
1252
 
1111
1253
 
1112
1254
class cmd_file_id(Command):
1254
1396
         RegistryOption('format',
1255
1397
                help='Specify a format for this branch. '
1256
1398
                'See "help formats".',
1257
 
                registry=bzrdir.format_registry,
1258
 
                converter=bzrdir.format_registry.make_bzrdir,
 
1399
                lazy_registry=('bzrlib.bzrdir', 'format_registry'),
 
1400
                converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
1259
1401
                value_switches=True,
1260
1402
                title="Branch Format",
1261
1403
                ),
1289
1431
            _create_prefix(to_transport)
1290
1432
 
1291
1433
        try:
1292
 
            existing_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport)
 
1434
            a_bzrdir = bzrdir.BzrDir.open_from_transport(to_transport)
1293
1435
        except errors.NotBranchError:
1294
1436
            # really a NotBzrDir error...
1295
1437
            create_branch = bzrdir.BzrDir.create_branch_convenience
1296
1438
            branch = create_branch(to_transport.base, format=format,
1297
1439
                                   possible_transports=[to_transport])
 
1440
            a_bzrdir = branch.bzrdir
1298
1441
        else:
1299
1442
            from bzrlib.transport.local import LocalTransport
1300
 
            if existing_bzrdir.has_branch():
 
1443
            if a_bzrdir.has_branch():
1301
1444
                if (isinstance(to_transport, LocalTransport)
1302
 
                    and not existing_bzrdir.has_workingtree()):
 
1445
                    and not a_bzrdir.has_workingtree()):
1303
1446
                        raise errors.BranchExistsWithoutWorkingTree(location)
1304
1447
                raise errors.AlreadyBranchError(location)
1305
 
            else:
1306
 
                branch = existing_bzrdir.create_branch()
1307
 
                existing_bzrdir.create_workingtree()
 
1448
            branch = a_bzrdir.create_branch()
 
1449
            a_bzrdir.create_workingtree()
1308
1450
        if append_revisions_only:
1309
1451
            try:
1310
1452
                branch.set_append_revisions_only(True)
1311
1453
            except errors.UpgradeRequired:
1312
1454
                raise errors.BzrCommandError('This branch format cannot be set'
1313
1455
                    ' to append-revisions-only.  Try --experimental-branch6')
 
1456
        if not is_quiet():
 
1457
            from bzrlib.info import show_bzrdir_info
 
1458
            show_bzrdir_info(a_bzrdir, verbose=0, outfile=self.outf)
1314
1459
 
1315
1460
 
1316
1461
class cmd_init_repository(Command):
1340
1485
    takes_options = [RegistryOption('format',
1341
1486
                            help='Specify a format for this repository. See'
1342
1487
                                 ' "bzr help formats" for details.',
1343
 
                            registry=bzrdir.format_registry,
1344
 
                            converter=bzrdir.format_registry.make_bzrdir,
 
1488
                            lazy_registry=('bzrlib.bzrdir', 'format_registry'),
 
1489
                            converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
1345
1490
                            value_switches=True, title='Repository format'),
1346
1491
                     Option('no-trees',
1347
1492
                             help='Branches in the repository will default to'
1362
1507
        newdir = format.initialize_on_transport(to_transport)
1363
1508
        repo = newdir.create_repository(shared=True)
1364
1509
        repo.set_make_working_trees(not no_trees)
 
1510
        if not is_quiet():
 
1511
            from bzrlib.info import show_bzrdir_info
 
1512
            show_bzrdir_info(repo.bzrdir, verbose=0, outfile=self.outf)
1365
1513
 
1366
1514
 
1367
1515
class cmd_diff(Command):
1626
1774
    takes_options = [
1627
1775
            Option('forward',
1628
1776
                   help='Show from oldest to newest.'),
1629
 
            Option('timezone',
1630
 
                   type=str,
1631
 
                   help='Display timezone as local, original, or utc.'),
 
1777
            'timezone',
1632
1778
            custom_help('verbose',
1633
1779
                   help='Show files changed in each revision.'),
1634
1780
            'show-ids',
1635
1781
            'revision',
 
1782
            Option('change',
 
1783
                   type=bzrlib.option._parse_revision_str,
 
1784
                   short_name='c',
 
1785
                   help='Show just the specified revision.'
 
1786
                   ' See also "help revisionspec".'),
1636
1787
            'log-format',
1637
1788
            Option('message',
1638
1789
                   short_name='m',
1653
1804
            show_ids=False,
1654
1805
            forward=False,
1655
1806
            revision=None,
 
1807
            change=None,
1656
1808
            log_format=None,
1657
1809
            message=None,
1658
1810
            limit=None):
1659
1811
        from bzrlib.log import show_log
1660
1812
        direction = (forward and 'forward') or 'reverse'
1661
 
        
 
1813
 
 
1814
        if change is not None:
 
1815
            if len(change) > 1:
 
1816
                raise errors.RangeInChangeOption()
 
1817
            if revision is not None:
 
1818
                raise errors.BzrCommandError(
 
1819
                    '--revision and --change are mutually exclusive')
 
1820
            else:
 
1821
                revision = change
 
1822
 
1662
1823
        # log everything
1663
1824
        file_id = None
1664
1825
        if location:
1710
1871
                log_format = log.log_formatter_registry.get_default(b)
1711
1872
 
1712
1873
            lf = log_format(show_ids=show_ids, to_file=self.outf,
1713
 
                            show_timezone=timezone)
 
1874
                            show_timezone=timezone,
 
1875
                            delta_format=get_verbosity_level())
1714
1876
 
1715
1877
            show_log(b,
1716
1878
                     lf,
1810
1972
            relpath = u''
1811
1973
        elif relpath:
1812
1974
            relpath += '/'
1813
 
        if revision is not None:
1814
 
            tree = branch.repository.revision_tree(
1815
 
                revision[0].as_revision_id(branch))
1816
 
        elif tree is None:
1817
 
            tree = branch.basis_tree()
 
1975
        if revision is not None or tree is None:
 
1976
            tree = _get_one_revision_tree('ls', revision, branch=branch)
1818
1977
 
1819
1978
        tree.lock_read()
1820
1979
        try:
1827
1986
                        continue
1828
1987
                    if kind is not None and fkind != kind:
1829
1988
                        continue
 
1989
                    kindch = entry.kind_character()
 
1990
                    outstring = fp + kindch
1830
1991
                    if verbose:
1831
 
                        kindch = entry.kind_character()
1832
 
                        outstring = '%-8s %s%s' % (fc, fp, kindch)
 
1992
                        outstring = '%-8s %s' % (fc, outstring)
1833
1993
                        if show_ids and fid is not None:
1834
1994
                            outstring = "%-50s %s" % (outstring, fid)
1835
1995
                        self.outf.write(outstring + '\n')
1846
2006
                        else:
1847
2007
                            my_id = ''
1848
2008
                        if show_ids:
1849
 
                            self.outf.write('%-50s %s\n' % (fp, my_id))
 
2009
                            self.outf.write('%-50s %s\n' % (outstring, my_id))
1850
2010
                        else:
1851
 
                            self.outf.write(fp + '\n')
 
2011
                            self.outf.write(outstring + '\n')
1852
2012
        finally:
1853
2013
            tree.unlock()
1854
2014
 
1941
2101
            print "Warning: the following files are version controlled and" \
1942
2102
                  " match your ignore pattern:\n%s" % ("\n".join(matches),)
1943
2103
 
 
2104
 
1944
2105
class cmd_ignored(Command):
1945
2106
    """List ignored files and the patterns that matched them.
 
2107
 
 
2108
    List all the ignored files and the ignore pattern that caused the file to
 
2109
    be ignored.
 
2110
 
 
2111
    Alternatively, to list just the files::
 
2112
 
 
2113
        bzr ls --ignored
1946
2114
    """
1947
2115
 
1948
2116
    encoding_type = 'replace'
1949
 
    _see_also = ['ignore']
 
2117
    _see_also = ['ignore', 'ls']
1950
2118
 
1951
2119
    @display_command
1952
2120
    def run(self):
2010
2178
         zip                          .zip
2011
2179
      =================       =========================
2012
2180
    """
2013
 
    takes_args = ['dest', 'branch?']
 
2181
    takes_args = ['dest', 'branch_or_subdir?']
2014
2182
    takes_options = [
2015
2183
        Option('format',
2016
2184
               help="Type of file to export to.",
2021
2189
               type=str,
2022
2190
               help="Name of the root directory inside the exported file."),
2023
2191
        ]
2024
 
    def run(self, dest, branch=None, revision=None, format=None, root=None,
2025
 
        filters=False):
 
2192
    def run(self, dest, branch_or_subdir=None, revision=None, format=None,
 
2193
        root=None, filters=False):
2026
2194
        from bzrlib.export import export
2027
2195
 
2028
 
        if branch is None:
 
2196
        if branch_or_subdir is None:
2029
2197
            tree = WorkingTree.open_containing(u'.')[0]
2030
2198
            b = tree.branch
2031
 
        else:
2032
 
            b = Branch.open(branch)
2033
 
            
2034
 
        if revision is None:
2035
 
            # should be tree.last_revision  FIXME
2036
 
            rev_id = b.last_revision()
2037
 
        else:
2038
 
            if len(revision) != 1:
2039
 
                raise errors.BzrCommandError('bzr export --revision takes exactly 1 argument')
2040
 
            rev_id = revision[0].as_revision_id(b)
2041
 
        t = b.repository.revision_tree(rev_id)
 
2199
            subdir = None
 
2200
        else:
 
2201
            b, subdir = Branch.open_containing(branch_or_subdir)
 
2202
            tree = None
 
2203
 
 
2204
        rev_tree = _get_one_revision_tree('export', revision, branch=b, tree=tree)
2042
2205
        try:
2043
 
            export(t, dest, format, root, filtered=filters)
 
2206
            export(rev_tree, dest, format, root, subdir, filtered=filters)
2044
2207
        except errors.NoSuchExportFormat, e:
2045
2208
            raise errors.BzrCommandError('Unsupported export format: %s' % e.format)
2046
2209
 
2082
2245
        filtered):
2083
2246
        if tree is None:
2084
2247
            tree = b.basis_tree()
2085
 
        if revision is None:
2086
 
            revision_id = b.last_revision()
2087
 
        else:
2088
 
            revision_id = revision[0].as_revision_id(b)
 
2248
        rev_tree = _get_one_revision_tree('cat', revision, branch=b)
2089
2249
 
2090
2250
        cur_file_id = tree.path2id(relpath)
2091
 
        rev_tree = b.repository.revision_tree(revision_id)
2092
2251
        old_file_id = rev_tree.path2id(relpath)
2093
 
        
 
2252
 
2094
2253
        if name_from_revision:
2095
2254
            if old_file_id is None:
2096
 
                raise errors.BzrCommandError("%r is not present in revision %s"
2097
 
                                                % (filename, revision_id))
 
2255
                raise errors.BzrCommandError(
 
2256
                    "%r is not present in revision %s" % (
 
2257
                        filename, rev_tree.get_revision_id()))
2098
2258
            else:
2099
2259
                content = rev_tree.get_file_text(old_file_id)
2100
2260
        elif cur_file_id is not None:
2102
2262
        elif old_file_id is not None:
2103
2263
            content = rev_tree.get_file_text(old_file_id)
2104
2264
        else:
2105
 
            raise errors.BzrCommandError("%r is not present in revision %s" %
2106
 
                                         (filename, revision_id))
 
2265
            raise errors.BzrCommandError(
 
2266
                "%r is not present in revision %s" % (
 
2267
                    filename, rev_tree.get_revision_id()))
2107
2268
        if filtered:
2108
2269
            from bzrlib.filters import (
2109
2270
                ContentFilterContext,
2240
2401
        )
2241
2402
        from bzrlib.msgeditor import (
2242
2403
            edit_commit_message_encoded,
 
2404
            generate_commit_message_template,
2243
2405
            make_commit_message_template_encoded
2244
2406
        )
2245
2407
 
2273
2435
            if my_message is None and not file:
2274
2436
                t = make_commit_message_template_encoded(tree,
2275
2437
                        selected_list, diff=show_diff,
2276
 
                        output_encoding=bzrlib.user_encoding)
2277
 
                my_message = edit_commit_message_encoded(t)
 
2438
                        output_encoding=osutils.get_user_encoding())
 
2439
                start_message = generate_commit_message_template(commit_obj)
 
2440
                my_message = edit_commit_message_encoded(t, 
 
2441
                    start_message=start_message)
2278
2442
                if my_message is None:
2279
2443
                    raise errors.BzrCommandError("please specify a commit"
2280
2444
                        " message with either --message or --file")
2283
2447
                    "please specify either --message or --file")
2284
2448
            if file:
2285
2449
                my_message = codecs.open(file, 'rt',
2286
 
                                         bzrlib.user_encoding).read()
 
2450
                                         osutils.get_user_encoding()).read()
2287
2451
            if my_message == "":
2288
2452
                raise errors.BzrCommandError("empty commit message specified")
2289
2453
            return my_message
2389
2553
                    RegistryOption('format',
2390
2554
                        help='Upgrade to a specific format.  See "bzr help'
2391
2555
                             ' formats" for details.',
2392
 
                        registry=bzrdir.format_registry,
2393
 
                        converter=bzrdir.format_registry.make_bzrdir,
 
2556
                        lazy_registry=('bzrlib.bzrdir', 'format_registry'),
 
2557
                        converter=lambda name: bzrdir.format_registry.make_bzrdir(name),
2394
2558
                        value_switches=True, title='Branch format'),
2395
2559
                    ]
2396
2560
 
2452
2616
 
2453
2617
 
2454
2618
class cmd_nick(Command):
2455
 
    """Print or set the branch nickname.  
2456
 
 
2457
 
    If unset, the tree root directory name is used as the nickname
2458
 
    To print the current nickname, execute with no argument.  
 
2619
    """Print or set the branch nickname.
 
2620
 
 
2621
    If unset, the tree root directory name is used as the nickname.
 
2622
    To print the current nickname, execute with no argument.
 
2623
 
 
2624
    Bound branches use the nickname of its master branch unless it is set
 
2625
    locally.
2459
2626
    """
2460
2627
 
2461
2628
    _see_also = ['info']
2640
2807
                            help='Load a test id list from a text file.'),
2641
2808
                     ListOption('debugflag', type=str, short_name='E',
2642
2809
                                help='Turn on a selftest debug flag.'),
2643
 
                     Option('starting-with', type=str, argname='TESTID',
2644
 
                            short_name='s',
2645
 
                            help='Load only the tests starting with TESTID.'),
 
2810
                     ListOption('starting-with', type=str, argname='TESTID',
 
2811
                                param_name='starting_with', short_name='s',
 
2812
                                help=
 
2813
                                'Load only the tests starting with TESTID.'),
2646
2814
                     ]
2647
2815
    encoding_type = 'replace'
2648
2816
 
2652
2820
            first=False, list_only=False,
2653
2821
            randomize=None, exclude=None, strict=False,
2654
2822
            load_list=None, debugflag=None, starting_with=None):
2655
 
        import bzrlib.ui
2656
2823
        from bzrlib.tests import selftest
2657
2824
        import bzrlib.benchmarks as benchmarks
2658
2825
        from bzrlib.benchmarks import tree_creator
2852
3019
    ]
2853
3020
 
2854
3021
    def run(self, location=None, revision=None, force=False,
2855
 
            merge_type=None, show_base=False, reprocess=False, remember=False,
 
3022
            merge_type=None, show_base=False, reprocess=None, remember=False,
2856
3023
            uncommitted=False, pull=False,
2857
3024
            directory=None,
2858
3025
            preview=False,
2961
3128
            not merger.merge_type is _mod_merge.Merge3Merger):
2962
3129
            raise errors.BzrCommandError("Show-base is not supported for this"
2963
3130
                                         " merge type. %s" % merger.merge_type)
 
3131
        if merger.reprocess is None:
 
3132
            if merger.show_base:
 
3133
                merger.reprocess = False
 
3134
            else:
 
3135
                # Use reprocess if the merger supports it
 
3136
                merger.reprocess = merger.merge_type.supports_reprocess
2964
3137
        if merger.reprocess and not merger.merge_type.supports_reprocess:
2965
3138
            raise errors.BzrCommandError("Conflict reduction is not supported"
2966
3139
                                         " for merge type %s." %
3049
3222
        Report if the remembered location was used.
3050
3223
        """
3051
3224
        stored_location = tree.branch.get_submit_branch()
 
3225
        stored_location_type = "submit"
3052
3226
        if stored_location is None:
3053
3227
            stored_location = tree.branch.get_parent()
 
3228
            stored_location_type = "parent"
3054
3229
        mutter("%s", stored_location)
3055
3230
        if stored_location is None:
3056
3231
            raise errors.BzrCommandError("No location specified or remembered")
3057
3232
        display_url = urlutils.unescape_for_display(stored_location, 'utf-8')
3058
 
        note(u"%s remembered location %s", verb_string, display_url)
 
3233
        note(u"%s remembered %s location %s", verb_string,
 
3234
                stored_location_type, display_url)
3059
3235
        return stored_location
3060
3236
 
3061
3237
 
3204
3380
    def run(self, revision=None, no_backup=False, file_list=None,
3205
3381
            forget_merges=None):
3206
3382
        tree, file_list = tree_files(file_list)
3207
 
        if forget_merges:
3208
 
            tree.set_parent_ids(tree.get_parent_ids()[:1])
3209
 
        else:
3210
 
            self._revert_tree_to_revision(tree, revision, file_list, no_backup)
 
3383
        tree.lock_write()
 
3384
        try:
 
3385
            if forget_merges:
 
3386
                tree.set_parent_ids(tree.get_parent_ids()[:1])
 
3387
            else:
 
3388
                self._revert_tree_to_revision(tree, revision, file_list, no_backup)
 
3389
        finally:
 
3390
            tree.unlock()
3211
3391
 
3212
3392
    @staticmethod
3213
3393
    def _revert_tree_to_revision(tree, revision, file_list, no_backup):
3214
 
        if revision is None:
3215
 
            rev_id = tree.last_revision()
3216
 
        elif len(revision) != 1:
3217
 
            raise errors.BzrCommandError('bzr revert --revision takes exactly 1 argument')
3218
 
        else:
3219
 
            rev_id = revision[0].as_revision_id(tree.branch)
 
3394
        rev_tree = _get_one_revision_tree('revert', revision, tree=tree)
3220
3395
        pb = ui.ui_factory.nested_progress_bar()
3221
3396
        try:
3222
 
            tree.revert(file_list,
3223
 
                        tree.branch.repository.revision_tree(rev_id),
3224
 
                        not no_backup, pb, report_changes=True)
 
3397
            tree.revert(file_list, rev_tree, not no_backup, pb,
 
3398
                report_changes=True)
3225
3399
        finally:
3226
3400
            pb.finished()
3227
3401
 
3288
3462
            Option('other', 'Same as --theirs-only.'),
3289
3463
            'log-format',
3290
3464
            'show-ids',
3291
 
            'verbose'
 
3465
            'verbose',
 
3466
            Option('include-merges', 'Show merged revisions.'),
3292
3467
            ]
3293
3468
    encoding_type = 'replace'
3294
3469
 
3295
3470
    @display_command
3296
3471
    def run(self, other_branch=None, reverse=False, mine_only=False,
3297
 
            theirs_only=False, log_format=None, long=False, short=False, line=False, 
3298
 
            show_ids=False, verbose=False, this=False, other=False):
 
3472
            theirs_only=False,
 
3473
            log_format=None, long=False, short=False, line=False,
 
3474
            show_ids=False, verbose=False, this=False, other=False,
 
3475
            include_merges=False):
3299
3476
        from bzrlib.missing import find_unmerged, iter_log_revisions
 
3477
        def message(s):
 
3478
            if not is_quiet():
 
3479
                self.outf.write(s)
3300
3480
 
3301
3481
        if this:
3302
3482
            mine_only = this
3320
3500
                                             " or specified.")
3321
3501
            display_url = urlutils.unescape_for_display(parent,
3322
3502
                                                        self.outf.encoding)
3323
 
            self.outf.write("Using last location: " + display_url + "\n")
 
3503
            message("Using saved parent location: "
 
3504
                    + display_url + "\n")
3324
3505
 
3325
3506
        remote_branch = Branch.open(other_branch)
3326
3507
        if remote_branch.base == local_branch.base:
3330
3511
            remote_branch.lock_read()
3331
3512
            try:
3332
3513
                local_extra, remote_extra = find_unmerged(
3333
 
                    local_branch, remote_branch, restrict)
 
3514
                    local_branch, remote_branch, restrict,
 
3515
                    backward=not reverse,
 
3516
                    include_merges=include_merges)
3334
3517
 
3335
3518
                if log_format is None:
3336
3519
                    registry = log.log_formatter_registry
3338
3521
                lf = log_format(to_file=self.outf,
3339
3522
                                show_ids=show_ids,
3340
3523
                                show_timezone='original')
3341
 
                if reverse is False:
3342
 
                    if local_extra is not None:
3343
 
                        local_extra.reverse()
3344
 
                    if remote_extra is not None:
3345
 
                        remote_extra.reverse()
3346
3524
 
3347
3525
                status_code = 0
3348
3526
                if local_extra and not theirs_only:
3349
 
                    self.outf.write("You have %d extra revision(s):\n" %
3350
 
                                    len(local_extra))
 
3527
                    message("You have %d extra revision(s):\n" %
 
3528
                        len(local_extra))
3351
3529
                    for revision in iter_log_revisions(local_extra,
3352
3530
                                        local_branch.repository,
3353
3531
                                        verbose):
3359
3537
 
3360
3538
                if remote_extra and not mine_only:
3361
3539
                    if printed_local is True:
3362
 
                        self.outf.write("\n\n\n")
3363
 
                    self.outf.write("You are missing %d revision(s):\n" %
3364
 
                                    len(remote_extra))
 
3540
                        message("\n\n\n")
 
3541
                    message("You are missing %d revision(s):\n" %
 
3542
                        len(remote_extra))
3365
3543
                    for revision in iter_log_revisions(remote_extra,
3366
3544
                                        remote_branch.repository,
3367
3545
                                        verbose):
3370
3548
 
3371
3549
                if mine_only and not local_extra:
3372
3550
                    # We checked local, and found nothing extra
3373
 
                    self.outf.write('This branch is up to date.\n')
 
3551
                    message('This branch is up to date.\n')
3374
3552
                elif theirs_only and not remote_extra:
3375
3553
                    # We checked remote, and found nothing extra
3376
 
                    self.outf.write('Other branch is up to date.\n')
 
3554
                    message('Other branch is up to date.\n')
3377
3555
                elif not (mine_only or theirs_only or local_extra or
3378
3556
                          remote_extra):
3379
3557
                    # We checked both branches, and neither one had extra
3380
3558
                    # revisions
3381
 
                    self.outf.write("Branches are up to date.\n")
 
3559
                    message("Branches are up to date.\n")
3382
3560
            finally:
3383
3561
                remote_branch.unlock()
3384
3562
        finally:
3513
3691
    @display_command
3514
3692
    def run(self, filename, all=False, long=False, revision=None,
3515
3693
            show_ids=False):
3516
 
        from bzrlib.annotate import annotate_file
 
3694
        from bzrlib.annotate import annotate_file, annotate_file_tree
3517
3695
        wt, branch, relpath = \
3518
3696
            bzrdir.BzrDir.open_containing_tree_or_branch(filename)
3519
3697
        if wt is not None:
3521
3699
        else:
3522
3700
            branch.lock_read()
3523
3701
        try:
3524
 
            if revision is None:
3525
 
                revision_id = branch.last_revision()
3526
 
            elif len(revision) != 1:
3527
 
                raise errors.BzrCommandError('bzr annotate --revision takes exactly 1 argument')
3528
 
            else:
3529
 
                revision_id = revision[0].as_revision_id(branch)
3530
 
            tree = branch.repository.revision_tree(revision_id)
 
3702
            tree = _get_one_revision_tree('annotate', revision, branch=branch)
3531
3703
            if wt is not None:
3532
3704
                file_id = wt.path2id(relpath)
3533
3705
            else:
3535
3707
            if file_id is None:
3536
3708
                raise errors.NotVersionedError(filename)
3537
3709
            file_version = tree.inventory[file_id].revision
3538
 
            annotate_file(branch, file_version, file_id, long, all, self.outf,
3539
 
                          show_ids=show_ids)
 
3710
            if wt is not None and revision is None:
 
3711
                # If there is a tree and we're not annotating historical
 
3712
                # versions, annotate the working tree's content.
 
3713
                annotate_file_tree(wt, file_id, self.outf, long, all,
 
3714
                    show_ids=show_ids)
 
3715
            else:
 
3716
                annotate_file(branch, file_version, file_id, long, all, self.outf,
 
3717
                              show_ids=show_ids)
3540
3718
        finally:
3541
3719
            if wt is not None:
3542
3720
                wt.unlock()
3617
3795
 
3618
3796
    Once converted into a checkout, commits must succeed on the master branch
3619
3797
    before they will be applied to the local branch.
 
3798
 
 
3799
    Bound branches use the nickname of its master branch unless it is set
 
3800
    locally, in which case binding will update the the local nickname to be
 
3801
    that of the master.
3620
3802
    """
3621
3803
 
3622
3804
    _see_also = ['checkouts', 'unbind']
3641
3823
        except errors.DivergedBranches:
3642
3824
            raise errors.BzrCommandError('These branches have diverged.'
3643
3825
                                         ' Try merging, and then bind again.')
 
3826
        if b.get_config().has_explicit_nickname():
 
3827
            b.nick = b_other.nick
3644
3828
 
3645
3829
 
3646
3830
class cmd_unbind(Command):
3766
3950
                    print 'Canceled'
3767
3951
                    return 0
3768
3952
 
 
3953
        mutter('Uncommitting from {%s} to {%s}',
 
3954
               last_rev_id, rev_id)
3769
3955
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
3770
3956
                 revno=revno, local=local)
 
3957
        note('You can restore the old tip by running:\n'
 
3958
             '  bzr pull . -r revid:%s', last_rev_id)
3771
3959
 
3772
3960
 
3773
3961
class cmd_break_lock(Command):
4087
4275
    (For Thunderbird 1.5, this works around some bugs.)  Supported values for
4088
4276
    specific clients are "evolution", "kmail", "mutt", and "thunderbird";
4089
4277
    generic options are "default", "editor", "emacsclient", "mapi", and
4090
 
    "xdg-email".
 
4278
    "xdg-email".  Plugins may also add supported clients.
4091
4279
 
4092
4280
    If mail is being sent, a to address is required.  This can be supplied
4093
4281
    either on the commandline, by setting the submit_to configuration
4147
4335
        from bzrlib.revision import NULL_REVISION
4148
4336
        branch = Branch.open_containing(from_)[0]
4149
4337
        if output is None:
4150
 
            outfile = StringIO()
 
4338
            outfile = cStringIO.StringIO()
4151
4339
        elif output == '-':
4152
4340
            outfile = self.outf
4153
4341
        else:
4165
4353
                raise errors.BzrCommandError(
4166
4354
                    '--remember requires a branch to be specified.')
4167
4355
            stored_submit_branch = branch.get_submit_branch()
4168
 
            remembered_submit_branch = False
 
4356
            remembered_submit_branch = None
4169
4357
            if submit_branch is None:
4170
4358
                submit_branch = stored_submit_branch
4171
 
                remembered_submit_branch = True
 
4359
                remembered_submit_branch = "submit"
4172
4360
            else:
4173
4361
                if stored_submit_branch is None or remember:
4174
4362
                    branch.set_submit_branch(submit_branch)
4175
4363
            if submit_branch is None:
4176
4364
                submit_branch = branch.get_parent()
4177
 
                remembered_submit_branch = True
 
4365
                remembered_submit_branch = "parent"
4178
4366
            if submit_branch is None:
4179
4367
                raise errors.BzrCommandError('No submit branch known or'
4180
4368
                                             ' specified')
4181
 
            if remembered_submit_branch:
4182
 
                note('Using saved location "%s" to determine what changes to submit.', submit_branch)
 
4369
            if remembered_submit_branch is not None:
 
4370
                note('Using saved %s location "%s" to determine what '
 
4371
                        'changes to submit.', remembered_submit_branch,
 
4372
                        submit_branch)
4183
4373
 
4184
4374
            if mail_to is None:
4185
4375
                submit_config = Branch.open(submit_branch).get_config()
4330
4520
 
4331
4521
    It is an error to give a tag name that already exists unless you pass 
4332
4522
    --force, in which case the tag is moved to point to the new revision.
 
4523
 
 
4524
    To rename a tag (change the name but keep it on the same revsion), run ``bzr
 
4525
    tag new-name -r tag:old-name`` and then ``bzr tag --delete oldname``.
4333
4526
    """
4334
4527
 
4335
4528
    _see_also = ['commit', 'tags']
4497
4690
    For heavyweight checkouts, this checks that there are no local commits
4498
4691
    versus the current bound branch, then it makes the local branch a mirror
4499
4692
    of the new location and binds to it.
4500
 
    
 
4693
 
4501
4694
    In both cases, the working tree is updated and uncommitted changes
4502
4695
    are merged. The user can commit or revert these as they desire.
4503
4696
 
4507
4700
    directory of the current branch. For example, if you are currently in a
4508
4701
    checkout of /path/to/branch, specifying 'newbranch' will find a branch at
4509
4702
    /path/to/newbranch.
 
4703
 
 
4704
    Bound branches use the nickname of its master branch unless it is set
 
4705
    locally, in which case switching will update the the local nickname to be
 
4706
    that of the master.
4510
4707
    """
4511
4708
 
4512
4709
    takes_args = ['to_location']
4518
4715
        from bzrlib import switch
4519
4716
        tree_location = '.'
4520
4717
        control_dir = bzrdir.BzrDir.open_containing(tree_location)[0]
 
4718
        branch = control_dir.open_branch()
4521
4719
        try:
4522
4720
            to_branch = Branch.open(to_location)
4523
4721
        except errors.NotBranchError:
 
4722
            this_branch = control_dir.open_branch()
 
4723
            # This may be a heavy checkout, where we want the master branch
 
4724
            this_url = this_branch.get_bound_location()
 
4725
            # If not, use a local sibling
 
4726
            if this_url is None:
 
4727
                this_url = this_branch.base
4524
4728
            to_branch = Branch.open(
4525
 
                control_dir.open_branch().base + '../' + to_location)
 
4729
                urlutils.join(this_url, '..', to_location))
4526
4730
        switch.switch(control_dir, to_branch, force)
 
4731
        if branch.get_config().has_explicit_nickname():
 
4732
            branch = control_dir.open_branch() #get the new branch!
 
4733
            branch.nick = to_branch.nick
4527
4734
        note('Switched to branch: %s',
4528
4735
            urlutils.unescape_for_display(to_branch.base, 'utf-8'))
4529
4736
 
4550
4757
                self.outf.write("  <no hooks installed>\n")
4551
4758
 
4552
4759
 
 
4760
class cmd_shelve(Command):
 
4761
    """Temporarily set aside some changes from the current tree.
 
4762
 
 
4763
    Shelve allows you to temporarily put changes you've made "on the shelf",
 
4764
    ie. out of the way, until a later time when you can bring them back from
 
4765
    the shelf with the 'unshelve' command.
 
4766
 
 
4767
    If shelve --list is specified, previously-shelved changes are listed.
 
4768
 
 
4769
    Shelve is intended to help separate several sets of changes that have
 
4770
    been inappropriately mingled.  If you just want to get rid of all changes
 
4771
    and you don't need to restore them later, use revert.  If you want to
 
4772
    shelve all text changes at once, use shelve --all.
 
4773
 
 
4774
    If filenames are specified, only the changes to those files will be
 
4775
    shelved. Other files will be left untouched.
 
4776
 
 
4777
    If a revision is specified, changes since that revision will be shelved.
 
4778
 
 
4779
    You can put multiple items on the shelf, and by default, 'unshelve' will
 
4780
    restore the most recently shelved changes.
 
4781
    """
 
4782
 
 
4783
    takes_args = ['file*']
 
4784
 
 
4785
    takes_options = [
 
4786
        'revision',
 
4787
        Option('all', help='Shelve all changes.'),
 
4788
        'message',
 
4789
        RegistryOption('writer', 'Method to use for writing diffs.',
 
4790
                       bzrlib.option.diff_writer_registry,
 
4791
                       value_switches=True, enum_switch=False),
 
4792
 
 
4793
        Option('list', help='List shelved changes.'),
 
4794
    ]
 
4795
    _see_also = ['unshelve']
 
4796
 
 
4797
    def run(self, revision=None, all=False, file_list=None, message=None,
 
4798
            writer=None, list=False):
 
4799
        if list:
 
4800
            return self.run_for_list()
 
4801
        from bzrlib.shelf_ui import Shelver
 
4802
        if writer is None:
 
4803
            writer = bzrlib.option.diff_writer_registry.get()
 
4804
        try:
 
4805
            Shelver.from_args(writer(sys.stdout), revision, all, file_list,
 
4806
                              message).run()
 
4807
        except errors.UserAbort:
 
4808
            return 0
 
4809
 
 
4810
    def run_for_list(self):
 
4811
        tree = WorkingTree.open_containing('.')[0]
 
4812
        tree.lock_read()
 
4813
        try:
 
4814
            manager = tree.get_shelf_manager()
 
4815
            shelves = manager.active_shelves()
 
4816
            if len(shelves) == 0:
 
4817
                note('No shelved changes.')
 
4818
                return 0
 
4819
            for shelf_id in reversed(shelves):
 
4820
                message = manager.get_metadata(shelf_id).get('message')
 
4821
                if message is None:
 
4822
                    message = '<no message>'
 
4823
                self.outf.write('%3d: %s\n' % (shelf_id, message))
 
4824
            return 1
 
4825
        finally:
 
4826
            tree.unlock()
 
4827
 
 
4828
 
 
4829
class cmd_unshelve(Command):
 
4830
    """Restore shelved changes.
 
4831
 
 
4832
    By default, the most recently shelved changes are restored. However if you
 
4833
    specify a patch by name those changes will be restored instead.  This
 
4834
    works best when the changes don't depend on each other.
 
4835
    """
 
4836
 
 
4837
    takes_args = ['shelf_id?']
 
4838
    takes_options = [
 
4839
        RegistryOption.from_kwargs(
 
4840
            'action', help="The action to perform.",
 
4841
            enum_switch=False, value_switches=True,
 
4842
            apply="Apply changes and remove from the shelf.",
 
4843
            dry_run="Show changes, but do not apply or remove them.",
 
4844
            delete_only="Delete changes without applying them."
 
4845
        )
 
4846
    ]
 
4847
    _see_also = ['shelve']
 
4848
 
 
4849
    def run(self, shelf_id=None, action='apply'):
 
4850
        from bzrlib.shelf_ui import Unshelver
 
4851
        Unshelver.from_args(shelf_id, action).run()
 
4852
 
 
4853
 
4553
4854
def _create_prefix(cur_transport):
4554
4855
    needed = [cur_transport]
4555
4856
    # Recurse upwards until we can create a directory successfully