~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

 * bzr add now lists how many files were ignored per glob.  add --verbose
   lists the specific files.  (Aaron Bentley)

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
 
17
"""builtin bzr commands"""
 
18
 
17
19
# DO NOT change this to cStringIO - it results in control files 
18
20
# written as UCS4
19
21
# FIXIT! (Only deal with byte streams OR unicode at any one layer.)
20
22
# RBC 20051018
 
23
 
21
24
from StringIO import StringIO
22
25
import sys
23
26
import os
27
30
from bzrlib.commands import Command, display_command
28
31
from bzrlib.branch import Branch
29
32
from bzrlib.revision import common_ancestor
 
33
import bzrlib.errors as errors
30
34
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError, 
31
35
                           NotBranchError, DivergedBranches, NotConflicted,
32
36
                           NoSuchFile, NoWorkingTree, FileInWrongBranch)
35
39
import bzrlib.trace
36
40
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
37
41
from bzrlib.workingtree import WorkingTree
38
 
 
39
 
 
40
 
def tree_files(file_list, default_branch='.'):
 
42
from bzrlib.log import show_one_log
 
43
 
 
44
 
 
45
def tree_files(file_list, default_branch=u'.'):
41
46
    try:
42
47
        return internal_tree_files(file_list, default_branch)
43
48
    except FileInWrongBranch, e:
44
49
        raise BzrCommandError("%s is not in the same branch as %s" %
45
50
                             (e.path, file_list[0]))
46
51
 
47
 
def internal_tree_files(file_list, default_branch='.'):
 
52
def internal_tree_files(file_list, default_branch=u'.'):
48
53
    """\
49
54
    Return a branch and list of branch-relative paths.
50
55
    If supplied file_list is empty or None, the branch default will be used,
57
62
    for filename in file_list:
58
63
        try:
59
64
            new_list.append(tree.relpath(filename))
60
 
        except NotBranchError:
 
65
        except errors.PathNotChild:
61
66
            raise FileInWrongBranch(tree.branch, filename)
62
67
    return tree, new_list
63
68
 
141
146
            raise BzrCommandError('You can only supply one of revision_id or --revision')
142
147
        if revision_id is None and revision is None:
143
148
            raise BzrCommandError('You must supply either --revision or a revision_id')
144
 
        b = WorkingTree.open_containing('.')[0].branch
 
149
        b = WorkingTree.open_containing(u'.')[0].branch
145
150
        if revision_id is not None:
146
151
            sys.stdout.write(b.get_revision_xml(revision_id))
147
152
        elif revision is not None:
156
161
    """Show current revision number.
157
162
 
158
163
    This is equal to the number of revisions on this branch."""
 
164
    takes_args = ['location?']
159
165
    @display_command
160
 
    def run(self):
161
 
        print Branch.open_containing('.')[0].revno()
 
166
    def run(self, location=u'.'):
 
167
        print Branch.open_containing(location)[0].revno()
162
168
 
163
169
 
164
170
class cmd_revision_info(Command):
179
185
        if len(revs) == 0:
180
186
            raise BzrCommandError('You must supply a revision identifier')
181
187
 
182
 
        b = WorkingTree.open_containing('.')[0].branch
 
188
        b = WorkingTree.open_containing(u'.')[0].branch
183
189
 
184
190
        for rev in revs:
185
191
            revinfo = rev.in_history(b)
211
217
    implicitly add the parent, and so on up to the root. This means
212
218
    you should never need to explictly add a directory, they'll just
213
219
    get added when you add a file in the directory.
 
220
 
 
221
    --dry-run will show which files would be added, but not actually 
 
222
    add them.
214
223
    """
215
224
    takes_args = ['file*']
216
 
    takes_options = ['no-recurse']
217
 
    
218
 
    def run(self, file_list, no_recurse=False):
219
 
        from bzrlib.add import smart_add, add_reporter_print, add_reporter_null
220
 
        if is_quiet():
221
 
            reporter = add_reporter_null
 
225
    takes_options = ['no-recurse', 'dry-run', 'verbose']
 
226
 
 
227
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False):
 
228
        import bzrlib.add
 
229
 
 
230
        if dry_run:
 
231
            if is_quiet():
 
232
                # This is pointless, but I'd rather not raise an error
 
233
                action = bzrlib.add.add_action_null
 
234
            else:
 
235
                action = bzrlib.add.add_action_print
 
236
        elif is_quiet():
 
237
            action = bzrlib.add.add_action_add
222
238
        else:
223
 
            reporter = add_reporter_print
224
 
        smart_add(file_list, not no_recurse, reporter)
 
239
            action = bzrlib.add.add_action_add_and_print
 
240
 
 
241
        added, ignored = bzrlib.add.smart_add(file_list, not no_recurse, 
 
242
                                              action)
 
243
        if len(ignored) > 0:
 
244
            for glob in sorted(ignored.keys()):
 
245
                match_len = len(ignored[glob])
 
246
                if verbose:
 
247
                    for path in ignored[glob]:
 
248
                        print "ignored %s matching \"%s\"" % (path, glob)
 
249
                else:
 
250
                    print "ignored %d file(s) matching \"%s\"" % (match_len,
 
251
                                                              glob)
 
252
            print "If you wish to add some of these files, please add them"\
 
253
                " by name."
225
254
 
226
255
 
227
256
class cmd_mkdir(Command):
262
291
    def run(self, revision=None, show_ids=False, kind=None):
263
292
        if kind and kind not in ['file', 'directory', 'symlink']:
264
293
            raise BzrCommandError('invalid kind specified')
265
 
        tree = WorkingTree.open_containing('.')[0]
 
294
        tree = WorkingTree.open_containing(u'.')[0]
266
295
        if revision is None:
267
296
            inv = tree.read_working_inventory()
268
297
        else:
374
403
        from shutil import rmtree
375
404
        import errno
376
405
        # FIXME: too much stuff is in the command class        
377
 
        tree_to = WorkingTree.open_containing('.')[0]
 
406
        tree_to = WorkingTree.open_containing(u'.')[0]
378
407
        stored_loc = tree_to.branch.get_parent()
379
408
        if location is None:
380
409
            if stored_loc is None:
382
411
            else:
383
412
                print "Using saved location: %s" % stored_loc
384
413
                location = stored_loc
 
414
 
385
415
        br_from = Branch.open(location)
386
416
        br_to = tree_to.branch
387
 
        try:
388
 
            old_rh = br_to.revision_history()
389
 
            count = tree_to.pull(br_from, overwrite)
390
 
        except DivergedBranches:
391
 
            # FIXME: Just make DivergedBranches display the right message
392
 
            # itself.
393
 
            raise BzrCommandError("These branches have diverged."
394
 
                                  "  Try merge.")
 
417
 
 
418
        old_rh = br_to.revision_history()
 
419
        count = tree_to.pull(br_from, overwrite)
 
420
 
395
421
        if br_to.get_parent() is None or remember:
396
422
            br_to.set_parent(location)
397
 
        note('%d revision(s) pulled.', count)
 
423
        note('%d revision(s) pulled.' % (count,))
 
424
 
398
425
        if verbose:
399
426
            new_rh = tree_to.branch.revision_history()
400
427
            if old_rh != new_rh:
440
467
        from shutil import rmtree
441
468
        from bzrlib.transport import get_transport
442
469
        
443
 
        tree_from = WorkingTree.open_containing('.')[0]
 
470
        tree_from = WorkingTree.open_containing(u'.')[0]
444
471
        br_from = tree_from.branch
445
472
        stored_loc = tree_from.branch.get_push_location()
446
473
        if location is None:
476
503
                            raise BzrCommandError("Could not creeate "
477
504
                                                  "path prefix.")
478
505
            br_to = Branch.initialize(location)
 
506
        old_rh = br_to.revision_history()
479
507
        try:
480
 
            old_rh = br_to.revision_history()
481
 
            count = br_to.pull(br_from, overwrite)
 
508
            try:
 
509
                tree_to = br_to.working_tree()
 
510
            except NoWorkingTree:
 
511
                # TODO: This should be updated for branches which don't have a
 
512
                # working tree, as opposed to ones where we just couldn't 
 
513
                # update the tree.
 
514
                warning('Unable to update the working tree of: %s' % (br_to.base,))
 
515
                count = br_to.pull(br_from, overwrite)
 
516
            else:
 
517
                count = tree_to.pull(br_from, overwrite)
482
518
        except DivergedBranches:
483
519
            raise BzrCommandError("These branches have diverged."
484
520
                                  "  Try a merge then push with overwrite.")
485
521
        if br_from.get_push_location() is None or remember:
486
522
            br_from.set_push_location(location)
487
523
        note('%d revision(s) pushed.' % (count,))
 
524
 
488
525
        if verbose:
489
526
            new_rh = br_to.revision_history()
490
527
            if old_rh != new_rh:
581
618
    takes_args = ['dir?']
582
619
 
583
620
    @display_command
584
 
    def run(self, dir='.'):
 
621
    def run(self, dir=u'.'):
585
622
        tree = WorkingTree.open_containing(dir)[0]
586
623
        old_inv = tree.branch.basis_tree().inventory
587
624
        new_inv = tree.read_working_inventory()
660
697
    hidden = True
661
698
    @display_command
662
699
    def run(self):
663
 
        branch = WorkingTree.open_containing('.')[0].branch
 
700
        branch = WorkingTree.open_containing(u'.')[0].branch
664
701
        for patchid in branch.revision_history():
665
702
            print patchid
666
703
 
670
707
    hidden = True
671
708
    @display_command
672
709
    def run(self):
673
 
        tree = WorkingTree.open_containing('.')[0]
 
710
        tree = WorkingTree.open_containing(u'.')[0]
674
711
        b = tree.branch
675
712
        # FIXME. should be tree.last_revision
676
713
        for revision_id in b.get_ancestry(b.last_revision()):
694
731
    def run(self, location=None):
695
732
        from bzrlib.branch import Branch
696
733
        if location is None:
697
 
            location = '.'
 
734
            location = u'.'
698
735
        else:
699
736
            # The path has to exist to initialize a
700
737
            # branch inside of it.
784
821
    # if the directories are very large...)
785
822
    @display_command
786
823
    def run(self, show_ids=False):
787
 
        tree = WorkingTree.open_containing('.')[0]
 
824
        tree = WorkingTree.open_containing(u'.')[0]
788
825
        old = tree.branch.basis_tree()
789
826
        for path, ie in old.inventory.iter_entries():
790
827
            if not tree.has_id(ie.file_id):
801
838
    def run(self):
802
839
        from bzrlib.delta import compare_trees
803
840
 
804
 
        tree = WorkingTree.open_containing('.')[0]
 
841
        tree = WorkingTree.open_containing(u'.')[0]
805
842
        td = compare_trees(tree.branch.basis_tree(), tree)
806
843
 
807
844
        for path, id, kind, text_modified, meta_modified in td.modified:
814
851
    hidden = True
815
852
    @display_command
816
853
    def run(self):
817
 
        wt = WorkingTree.open_containing('.')[0]
 
854
        wt = WorkingTree.open_containing(u'.')[0]
818
855
        basis_inv = wt.branch.basis_tree().inventory
819
856
        inv = wt.inventory
820
857
        for file_id in inv:
855
892
                            help='show from oldest to newest'),
856
893
                     'timezone', 'verbose', 
857
894
                     'show-ids', 'revision',
858
 
                     Option('line', help='format with one line per revision'),
859
 
                     'long', 
 
895
                     'line', 'long', 
860
896
                     Option('message',
861
897
                            help='show revisions whose message matches this regexp',
862
898
                            type=str),
863
 
                     Option('short', help='use moderately short format'),
 
899
                     'short',
864
900
                     ]
865
901
    @display_command
866
902
    def run(self, filename=None, timezone='original',
897
933
            else:
898
934
                file_id = None  # points to branch root
899
935
        else:
900
 
            tree, relpath = WorkingTree.open_containing('.')
 
936
            tree, relpath = WorkingTree.open_containing(u'.')
901
937
            b = tree.branch
902
938
            file_id = None
903
939
 
924
960
        # in e.g. the default C locale.
925
961
        outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
926
962
 
927
 
        log_format = 'long'
928
 
        if short:
929
 
            log_format = 'short'
930
 
        if line:
931
 
            log_format = 'line'
 
963
        log_format = get_log_format(long=long, short=short, line=line)
932
964
        lf = log_formatter(log_format,
933
965
                           show_ids=show_ids,
934
966
                           to_file=outf,
943
975
                 end_revision=rev2,
944
976
                 search=message)
945
977
 
 
978
def get_log_format(long=False, short=False, line=False, default='long'):
 
979
    log_format = default
 
980
    if long:
 
981
        log_format = 'long'
 
982
    if short:
 
983
        log_format = 'short'
 
984
    if line:
 
985
        log_format = 'line'
 
986
    return log_format
946
987
 
947
988
 
948
989
class cmd_touching_revisions(Command):
989
1030
 
990
1031
        selection = {'I':ignored, '?':unknown, 'V':versioned}
991
1032
 
992
 
        tree, relpath = WorkingTree.open_containing('.')
 
1033
        tree, relpath = WorkingTree.open_containing(u'.')
993
1034
        if from_root:
994
 
            relpath = ''
 
1035
            relpath = u''
995
1036
        elif relpath:
996
1037
            relpath += '/'
997
1038
        if revision is not None:
1020
1061
    @display_command
1021
1062
    def run(self):
1022
1063
        from bzrlib.osutils import quotefn
1023
 
        for f in WorkingTree.open_containing('.')[0].unknowns():
 
1064
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
1024
1065
            print quotefn(f)
1025
1066
 
1026
1067
 
1049
1090
        from bzrlib.atomicfile import AtomicFile
1050
1091
        import os.path
1051
1092
 
1052
 
        tree, relpath = WorkingTree.open_containing('.')
 
1093
        tree, relpath = WorkingTree.open_containing(u'.')
1053
1094
        ifn = tree.abspath('.bzrignore')
1054
1095
 
1055
1096
        if os.path.exists(ifn):
1089
1130
    See also: bzr ignore"""
1090
1131
    @display_command
1091
1132
    def run(self):
1092
 
        tree = WorkingTree.open_containing('.')[0]
 
1133
        tree = WorkingTree.open_containing(u'.')[0]
1093
1134
        for path, file_class, kind, file_id, entry in tree.list_files():
1094
1135
            if file_class != 'I':
1095
1136
                continue
1114
1155
        except ValueError:
1115
1156
            raise BzrCommandError("not a valid revision-number: %r" % revno)
1116
1157
 
1117
 
        print WorkingTree.open_containing('.')[0].branch.get_rev_id(revno)
 
1158
        print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
1118
1159
 
1119
1160
 
1120
1161
class cmd_export(Command):
1127
1168
    is found exports to a directory (equivalent to --format=dir).
1128
1169
 
1129
1170
    Root may be the top directory for tar, tgz and tbz2 formats. If none
1130
 
    is given, the top directory will be the root name of the file."""
1131
 
    # TODO: list known exporters
 
1171
    is given, the top directory will be the root name of the file.
 
1172
 
 
1173
    Note: export of tree with non-ascii filenames to zip is not supported.
 
1174
 
 
1175
    Supported formats       Autodetected by extension
 
1176
    -----------------       -------------------------
 
1177
         dir                            -
 
1178
         tar                          .tar
 
1179
         tbz2                    .tar.bz2, .tbz2
 
1180
         tgz                      .tar.gz, .tgz
 
1181
         zip                          .zip
 
1182
    """
1132
1183
    takes_args = ['dest']
1133
1184
    takes_options = ['revision', 'format', 'root']
1134
1185
    def run(self, dest, revision=None, format=None, root=None):
1135
1186
        import os.path
1136
 
        tree = WorkingTree.open_containing('.')[0]
 
1187
        from bzrlib.export import export
 
1188
        tree = WorkingTree.open_containing(u'.')[0]
1137
1189
        b = tree.branch
1138
1190
        if revision is None:
1139
1191
            # should be tree.last_revision  FIXME
1140
 
            rev_id = tree.branch.last_revision()
 
1192
            rev_id = b.last_revision()
1141
1193
        else:
1142
1194
            if len(revision) != 1:
1143
1195
                raise BzrError('bzr export --revision takes exactly 1 argument')
1144
1196
            rev_id = revision[0].in_history(b).rev_id
1145
1197
        t = b.revision_tree(rev_id)
1146
 
        arg_root, ext = os.path.splitext(os.path.basename(dest))
1147
 
        if ext in ('.gz', '.bz2'):
1148
 
            new_root, new_ext = os.path.splitext(arg_root)
1149
 
            if new_ext == '.tar':
1150
 
                arg_root = new_root
1151
 
                ext = new_ext + ext
1152
 
        if root is None:
1153
 
            root = arg_root
1154
 
        if not format:
1155
 
            if ext in (".tar",):
1156
 
                format = "tar"
1157
 
            elif ext in (".tar.gz", ".tgz"):
1158
 
                format = "tgz"
1159
 
            elif ext in (".tar.bz2", ".tbz2"):
1160
 
                format = "tbz2"
1161
 
            else:
1162
 
                format = "dir"
1163
 
        t.export(dest, format, root)
 
1198
        try:
 
1199
            export(t, dest, format, root)
 
1200
        except errors.NoSuchExportFormat, e:
 
1201
            raise BzrCommandError('Unsupported export format: %s' % e.format)
1164
1202
 
1165
1203
 
1166
1204
class cmd_cat(Command):
1171
1209
 
1172
1210
    @display_command
1173
1211
    def run(self, filename, revision=None):
1174
 
        if revision is None:
1175
 
            raise BzrCommandError("bzr cat requires a revision number")
1176
 
        elif len(revision) != 1:
 
1212
        if revision is not None and len(revision) != 1:
1177
1213
            raise BzrCommandError("bzr cat --revision takes exactly one number")
1178
1214
        tree = None
1179
1215
        try:
1181
1217
            b = tree.branch
1182
1218
        except NotBranchError:
1183
1219
            pass
 
1220
 
1184
1221
        if tree is None:
1185
1222
            b, relpath = Branch.open_containing(filename)
1186
 
        b.print_file(relpath, revision[0].in_history(b).revno)
 
1223
        if revision is None:
 
1224
            revision_id = b.last_revision()
 
1225
        else:
 
1226
            revision_id = revision[0].in_history(b).rev_id
 
1227
        b.print_file(relpath, revision_id)
1187
1228
 
1188
1229
 
1189
1230
class cmd_local_time_offset(Command):
1234
1275
            unchanged=False, strict=False):
1235
1276
        from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1236
1277
                StrictCommitFailed)
1237
 
        from bzrlib.msgeditor import edit_commit_message
 
1278
        from bzrlib.msgeditor import edit_commit_message, \
 
1279
                make_commit_message_template
1238
1280
        from bzrlib.status import show_status
1239
 
        from cStringIO import StringIO
1240
 
 
 
1281
        from tempfile import TemporaryFile
 
1282
        import codecs
 
1283
 
 
1284
        # TODO: Need a blackbox test for invoking the external editor; may be
 
1285
        # slightly problematic to run this cross-platform.
 
1286
 
 
1287
        # TODO: do more checks that the commit will succeed before 
 
1288
        # spending the user's valuable time typing a commit message.
 
1289
        #
 
1290
        # TODO: if the commit *does* happen to fail, then save the commit 
 
1291
        # message to a temporary file where it can be recovered
1241
1292
        tree, selected_list = tree_files(selected_list)
1242
1293
        if message is None and not file:
1243
 
            catcher = StringIO()
1244
 
            show_status(tree.branch, specific_files=selected_list,
1245
 
                        to_file=catcher)
1246
 
            message = edit_commit_message(catcher.getvalue())
1247
 
 
 
1294
            template = make_commit_message_template(tree, selected_list)
 
1295
            message = edit_commit_message(template)
1248
1296
            if message is None:
1249
1297
                raise BzrCommandError("please specify a commit message"
1250
1298
                                      " with either --message or --file")
1273
1321
            raise BzrCommandError("Commit refused because there are unknown "
1274
1322
                                  "files in the working tree.")
1275
1323
        note('Committed revision %d.' % (tree.branch.revno(),))
1276
 
        
 
1324
 
1277
1325
 
1278
1326
class cmd_check(Command):
1279
1327
    """Validate consistency of branch history.
1281
1329
    This command checks various invariants about the branch storage to
1282
1330
    detect data corruption or bzr bugs.
1283
1331
    """
1284
 
    takes_args = ['dir?']
 
1332
    takes_args = ['branch?']
1285
1333
    takes_options = ['verbose']
1286
1334
 
1287
 
    def run(self, dir='.', verbose=False):
 
1335
    def run(self, branch=None, verbose=False):
1288
1336
        from bzrlib.check import check
1289
 
        check(WorkingTree.open_containing(dir)[0].branch, verbose)
 
1337
        if branch is None:
 
1338
            tree = WorkingTree.open_containing()[0]
 
1339
            branch = tree.branch
 
1340
        else:
 
1341
            branch = Branch.open(branch)
 
1342
        check(branch, verbose)
1290
1343
 
1291
1344
 
1292
1345
class cmd_scan_cache(Command):
1294
1347
    def run(self):
1295
1348
        from bzrlib.hashcache import HashCache
1296
1349
 
1297
 
        c = HashCache('.')
 
1350
        c = HashCache(u'.')
1298
1351
        c.read()
1299
1352
        c.scan()
1300
1353
            
1320
1373
    """
1321
1374
    takes_args = ['dir?']
1322
1375
 
1323
 
    def run(self, dir='.'):
 
1376
    def run(self, dir=u'.'):
1324
1377
        from bzrlib.upgrade import upgrade
1325
1378
        upgrade(dir)
1326
1379
 
1332
1385
    @display_command
1333
1386
    def run(self, email=False):
1334
1387
        try:
1335
 
            b = WorkingTree.open_containing('.')[0].branch
 
1388
            b = WorkingTree.open_containing(u'.')[0].branch
1336
1389
            config = bzrlib.config.BranchConfig(b)
1337
1390
        except NotBranchError:
1338
1391
            config = bzrlib.config.GlobalConfig()
1350
1403
    """
1351
1404
    takes_args = ['nickname?']
1352
1405
    def run(self, nickname=None):
1353
 
        branch = Branch.open_containing('.')[0]
 
1406
        branch = Branch.open_containing(u'.')[0]
1354
1407
        if nickname is None:
1355
1408
            self.printme(branch)
1356
1409
        else:
1383
1436
    def run(self, testspecs_list=None, verbose=False, one=False,
1384
1437
            keep_output=False):
1385
1438
        import bzrlib.ui
1386
 
        from bzrlib.selftest import selftest
 
1439
        from bzrlib.tests import selftest
1387
1440
        # we don't want progress meters from the tests to go to the
1388
1441
        # real output; and we don't want log messages cluttering up
1389
1442
        # the real logs.
1515
1568
        if merge_type is None:
1516
1569
            merge_type = ApplyMerge3
1517
1570
        if branch is None:
1518
 
            branch = WorkingTree.open_containing('.')[0].branch.get_parent()
 
1571
            branch = WorkingTree.open_containing(u'.')[0].branch.get_parent()
1519
1572
            if branch is None:
1520
1573
                raise BzrCommandError("No merge location known or specified.")
1521
1574
            else:
1638
1691
            file_list = []
1639
1692
        if revision is None:
1640
1693
            revno = -1
1641
 
            tree = WorkingTree.open_containing('.')[0]
 
1694
            tree = WorkingTree.open_containing(u'.')[0]
1642
1695
            # FIXME should be tree.last_revision
1643
1696
            rev_id = tree.branch.last_revision()
1644
1697
        elif len(revision) != 1:
1710
1763
 
1711
1764
 
1712
1765
class cmd_missing(Command):
1713
 
    """What is missing in this branch relative to other branch.
1714
 
    """
1715
 
    # TODO: rewrite this in terms of ancestry so that it shows only
1716
 
    # unmerged things
1717
 
    
1718
 
    takes_args = ['remote?']
1719
 
    aliases = ['mis', 'miss']
1720
 
    takes_options = ['verbose']
1721
 
 
1722
 
    @display_command
1723
 
    def run(self, remote=None, verbose=False):
1724
 
        from bzrlib.errors import BzrCommandError
1725
 
        from bzrlib.missing import show_missing
1726
 
 
1727
 
        if verbose and is_quiet():
1728
 
            raise BzrCommandError('Cannot pass both quiet and verbose')
1729
 
 
1730
 
        tree = WorkingTree.open_containing('.')[0]
1731
 
        parent = tree.branch.get_parent()
1732
 
        if remote is None:
1733
 
            if parent is None:
 
1766
    """Show unmerged/unpulled revisions between two branches.
 
1767
 
 
1768
    OTHER_BRANCH may be local or remote."""
 
1769
    takes_args = ['other_branch?']
 
1770
    takes_options = [Option('reverse', 'Reverse the order of revisions'),
 
1771
                     Option('mine-only', 
 
1772
                            'Display changes in the local branch only'),
 
1773
                     Option('theirs-only', 
 
1774
                            'Display changes in the remote branch only'), 
 
1775
                     'line',
 
1776
                     'long', 
 
1777
                     'short',
 
1778
                     'show-ids',
 
1779
                     'verbose'
 
1780
                     ]
 
1781
 
 
1782
    def run(self, other_branch=None, reverse=False, mine_only=False,
 
1783
            theirs_only=False, long=True, short=False, line=False, 
 
1784
            show_ids=False, verbose=False):
 
1785
        from bzrlib.missing import find_unmerged, iter_log_data
 
1786
        from bzrlib.log import log_formatter
 
1787
        local_branch = bzrlib.branch.Branch.open_containing(u".")[0]
 
1788
        parent = local_branch.get_parent()
 
1789
        if other_branch is None:
 
1790
            other_branch = parent
 
1791
            if other_branch is None:
1734
1792
                raise BzrCommandError("No missing location known or specified.")
1735
 
            else:
1736
 
                if not is_quiet():
1737
 
                    print "Using last location: %s" % parent
1738
 
                remote = parent
1739
 
        elif parent is None:
1740
 
            # We only update parent if it did not exist, missing
1741
 
            # should not change the parent
1742
 
            tree.branch.set_parent(remote)
1743
 
        br_remote = Branch.open_containing(remote)[0]
1744
 
        return show_missing(tree.branch, br_remote, verbose=verbose, 
1745
 
                            quiet=is_quiet())
 
1793
            print "Using last location: " + local_branch.get_parent()
 
1794
        remote_branch = bzrlib.branch.Branch.open(other_branch)
 
1795
        local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
 
1796
        log_format = get_log_format(long=long, short=short, line=line)
 
1797
        lf = log_formatter(log_format, sys.stdout,
 
1798
                           show_ids=show_ids,
 
1799
                           show_timezone='original')
 
1800
        if reverse is False:
 
1801
            local_extra.reverse()
 
1802
            remote_extra.reverse()
 
1803
        if local_extra and not theirs_only:
 
1804
            print "You have %d extra revision(s):" % len(local_extra)
 
1805
            for data in iter_log_data(local_extra, local_branch, verbose):
 
1806
                lf.show(*data)
 
1807
            printed_local = True
 
1808
        else:
 
1809
            printed_local = False
 
1810
        if remote_extra and not mine_only:
 
1811
            if printed_local is True:
 
1812
                print "\n\n"
 
1813
            print "You are missing %d revision(s):" % len(remote_extra)
 
1814
            for data in iter_log_data(remote_extra, remote_branch, verbose):
 
1815
                lf.show(*data)
 
1816
        if not remote_extra and not local_extra:
 
1817
            status_code = 0
 
1818
            print "Branches are up to date."
 
1819
        else:
 
1820
            status_code = 1
 
1821
        if parent is None and other_branch is not None:
 
1822
            local_branch.set_parent(other_branch)
 
1823
        return status_code
1746
1824
 
1747
1825
 
1748
1826
class cmd_plugins(Command):
1752
1830
    def run(self):
1753
1831
        import bzrlib.plugin
1754
1832
        from inspect import getdoc
1755
 
        for plugin in bzrlib.plugin.all_plugins:
 
1833
        for name, plugin in bzrlib.plugin.all_plugins().items():
1756
1834
            if hasattr(plugin, '__path__'):
1757
1835
                print plugin.__path__[0]
1758
1836
            elif hasattr(plugin, '__file__'):
1770
1848
    takes_options = ['revision', 'long']
1771
1849
    takes_args = ['branch?']
1772
1850
    @display_command
1773
 
    def run(self, branch='.', revision=None, long=False):
 
1851
    def run(self, branch=u'.', revision=None, long=False):
1774
1852
        from bzrlib.testament import Testament
1775
1853
        b = WorkingTree.open_containing(branch)[0].branch
1776
1854
        b.lock_read()
1837
1915
            raise BzrCommandError('You can only supply one of revision_id or --revision')
1838
1916
        if revision_id is None and revision is None:
1839
1917
            raise BzrCommandError('You must supply either --revision or a revision_id')
1840
 
        b = WorkingTree.open_containing('.')[0].branch
 
1918
        b = WorkingTree.open_containing(u'.')[0].branch
1841
1919
        gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1842
1920
        if revision_id is not None:
1843
1921
            b.sign_revision(revision_id, gpg_strategy)
1861
1939
                raise BzrCommandError('Please supply either one revision, or a range.')
1862
1940
 
1863
1941
 
 
1942
class cmd_uncommit(bzrlib.commands.Command):
 
1943
    """Remove the last committed revision.
 
1944
 
 
1945
    By supplying the --all flag, it will not only remove the entry 
 
1946
    from revision_history, but also remove all of the entries in the
 
1947
    stores.
 
1948
 
 
1949
    --verbose will print out what is being removed.
 
1950
    --dry-run will go through all the motions, but not actually
 
1951
    remove anything.
 
1952
    
 
1953
    In the future, uncommit will create a changeset, which can then
 
1954
    be re-applied.
 
1955
    """
 
1956
    takes_options = ['all', 'verbose', 'revision',
 
1957
                    Option('dry-run', help='Don\'t actually make changes'),
 
1958
                    Option('force', help='Say yes to all questions.')]
 
1959
    takes_args = ['location?']
 
1960
    aliases = []
 
1961
 
 
1962
    def run(self, location=None, all=False,
 
1963
            dry_run=False, verbose=False,
 
1964
            revision=None, force=False):
 
1965
        from bzrlib.branch import Branch
 
1966
        from bzrlib.log import log_formatter
 
1967
        import sys
 
1968
        from bzrlib.uncommit import uncommit
 
1969
 
 
1970
        if location is None:
 
1971
            location = u'.'
 
1972
        b, relpath = Branch.open_containing(location)
 
1973
 
 
1974
        if revision is None:
 
1975
            revno = b.revno()
 
1976
            rev_id = b.last_revision()
 
1977
        else:
 
1978
            revno, rev_id = revision[0].in_history(b)
 
1979
        if rev_id is None:
 
1980
            print 'No revisions to uncommit.'
 
1981
 
 
1982
        for r in range(revno, b.revno()+1):
 
1983
            rev_id = b.get_rev_id(r)
 
1984
            lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
 
1985
            lf.show(r, b.get_revision(rev_id), None)
 
1986
 
 
1987
        if dry_run:
 
1988
            print 'Dry-run, pretending to remove the above revisions.'
 
1989
            if not force:
 
1990
                val = raw_input('Press <enter> to continue')
 
1991
        else:
 
1992
            print 'The above revision(s) will be removed.'
 
1993
            if not force:
 
1994
                val = raw_input('Are you sure [y/N]? ')
 
1995
                if val.lower() not in ('y', 'yes'):
 
1996
                    print 'Canceled'
 
1997
                    return 0
 
1998
 
 
1999
        uncommit(b, remove_files=all,
 
2000
                dry_run=dry_run, verbose=verbose,
 
2001
                revno=revno)
 
2002
 
 
2003
 
1864
2004
# these get imported and then picked up by the scan for cmd_*
1865
2005
# TODO: Some more consistent way to split command definitions across files;
1866
2006
# we do need to load at least some information about them to know of