~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

Merge from integration.

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)
33
37
from bzrlib.option import Option
34
38
from bzrlib.revisionspec import RevisionSpec
35
39
import bzrlib.trace
36
 
from bzrlib.trace import mutter, note, log_error, warning
 
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
 
            sys.stdout.write(b.get_revision_xml_file(revision_id).read())
 
151
            sys.stdout.write(b.get_revision_xml(revision_id))
147
152
        elif revision is not None:
148
153
            for rev in revision:
149
154
                if rev is None:
150
155
                    raise BzrCommandError('You cannot specify a NULL revision.')
151
156
                revno, rev_id = rev.in_history(b)
152
 
                sys.stdout.write(b.get_revision_xml_file(rev_id).read())
 
157
                sys.stdout.write(b.get_revision_xml(rev_id))
153
158
    
154
159
 
155
160
class cmd_revno(Command):
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', 'quiet']
217
 
    
218
 
    def run(self, file_list, no_recurse=False, quiet=False):
219
 
        from bzrlib.add import smart_add, add_reporter_print, add_reporter_null
220
 
        if 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:
373
402
        from bzrlib.merge import merge
374
403
        from shutil import rmtree
375
404
        import errno
376
 
        
377
 
        tree_to = WorkingTree.open_containing('.')[0]
 
405
        # FIXME: too much stuff is in the command class        
 
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
 
        try:
387
 
            old_rh = tree_to.branch.revision_history()
388
 
            tree_to.pull(br_from, overwrite)
389
 
        except DivergedBranches:
390
 
            raise BzrCommandError("These branches have diverged."
391
 
                                  "  Try merge.")
392
 
        if tree_to.branch.get_parent() is None or remember:
393
 
            tree_to.branch.set_parent(location)
 
416
        br_to = tree_to.branch
 
417
 
 
418
        old_rh = br_to.revision_history()
 
419
        count = tree_to.pull(br_from, overwrite)
 
420
 
 
421
        if br_to.get_parent() is None or remember:
 
422
            br_to.set_parent(location)
 
423
        note('%d revision(s) pulled.' % (count,))
394
424
 
395
425
        if verbose:
396
426
            new_rh = tree_to.branch.revision_history()
431
461
 
432
462
    def run(self, location=None, remember=False, overwrite=False,
433
463
            create_prefix=False, verbose=False):
 
464
        # FIXME: Way too big!  Put this into a function called from the
 
465
        # command.
434
466
        import errno
435
467
        from shutil import rmtree
436
468
        from bzrlib.transport import get_transport
437
469
        
438
 
        tree_from = WorkingTree.open_containing('.')[0]
 
470
        tree_from = WorkingTree.open_containing(u'.')[0]
 
471
        br_from = tree_from.branch
439
472
        stored_loc = tree_from.branch.get_push_location()
440
473
        if location is None:
441
474
            if stored_loc is None:
469
502
                        if new_transport.base == transport.base:
470
503
                            raise BzrCommandError("Could not creeate "
471
504
                                                  "path prefix.")
472
 
                        
473
 
            NoSuchFile
474
505
            br_to = Branch.initialize(location)
 
506
        old_rh = br_to.revision_history()
475
507
        try:
476
 
            old_rh = br_to.revision_history()
477
 
            br_to.pull(tree_from.branch, 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)
478
518
        except DivergedBranches:
479
519
            raise BzrCommandError("These branches have diverged."
480
520
                                  "  Try a merge then push with overwrite.")
481
 
        if tree_from.branch.get_push_location() is None or remember:
482
 
            tree_from.branch.set_push_location(location)
 
521
        if br_from.get_push_location() is None or remember:
 
522
            br_from.set_push_location(location)
 
523
        note('%d revision(s) pushed.' % (count,))
483
524
 
484
525
        if verbose:
485
526
            new_rh = br_to.revision_history()
559
600
                rmtree(to_location)
560
601
                msg = "The branch %s cannot be used as a --basis"
561
602
                raise BzrCommandError(msg)
 
603
            branch = Branch.open(to_location)
562
604
            if name:
563
 
                branch = Branch.open(to_location)
564
605
                name = StringIO(name)
565
606
                branch.put_controlfile('branch-name', name)
 
607
            note('Branched %d revision(s).' % branch.revno())
566
608
        finally:
567
609
            br_from.unlock()
568
610
 
576
618
    takes_args = ['dir?']
577
619
 
578
620
    @display_command
579
 
    def run(self, dir='.'):
 
621
    def run(self, dir=u'.'):
580
622
        tree = WorkingTree.open_containing(dir)[0]
581
623
        old_inv = tree.branch.basis_tree().inventory
582
624
        new_inv = tree.read_working_inventory()
655
697
    hidden = True
656
698
    @display_command
657
699
    def run(self):
658
 
        branch = WorkingTree.open_containing('.')[0].branch
 
700
        branch = WorkingTree.open_containing(u'.')[0].branch
659
701
        for patchid in branch.revision_history():
660
702
            print patchid
661
703
 
665
707
    hidden = True
666
708
    @display_command
667
709
    def run(self):
668
 
        tree = WorkingTree.open_containing('.')[0]
 
710
        tree = WorkingTree.open_containing(u'.')[0]
669
711
        b = tree.branch
670
712
        # FIXME. should be tree.last_revision
671
713
        for revision_id in b.get_ancestry(b.last_revision()):
689
731
    def run(self, location=None):
690
732
        from bzrlib.branch import Branch
691
733
        if location is None:
692
 
            location = '.'
 
734
            location = u'.'
693
735
        else:
694
736
            # The path has to exist to initialize a
695
737
            # branch inside of it.
779
821
    # if the directories are very large...)
780
822
    @display_command
781
823
    def run(self, show_ids=False):
782
 
        tree = WorkingTree.open_containing('.')[0]
 
824
        tree = WorkingTree.open_containing(u'.')[0]
783
825
        old = tree.branch.basis_tree()
784
826
        for path, ie in old.inventory.iter_entries():
785
827
            if not tree.has_id(ie.file_id):
796
838
    def run(self):
797
839
        from bzrlib.delta import compare_trees
798
840
 
799
 
        tree = WorkingTree.open_containing('.')[0]
 
841
        tree = WorkingTree.open_containing(u'.')[0]
800
842
        td = compare_trees(tree.branch.basis_tree(), tree)
801
843
 
802
844
        for path, id, kind, text_modified, meta_modified in td.modified:
809
851
    hidden = True
810
852
    @display_command
811
853
    def run(self):
812
 
        wt = WorkingTree.open_containing('.')[0]
 
854
        wt = WorkingTree.open_containing(u'.')[0]
813
855
        basis_inv = wt.branch.basis_tree().inventory
814
856
        inv = wt.inventory
815
857
        for file_id in inv:
850
892
                            help='show from oldest to newest'),
851
893
                     'timezone', 'verbose', 
852
894
                     'show-ids', 'revision',
853
 
                     Option('line', help='format with one line per revision'),
854
 
                     'long', 
 
895
                     'line', 'long', 
855
896
                     Option('message',
856
897
                            help='show revisions whose message matches this regexp',
857
898
                            type=str),
858
 
                     Option('short', help='use moderately short format'),
 
899
                     'short',
859
900
                     ]
860
901
    @display_command
861
902
    def run(self, filename=None, timezone='original',
892
933
            else:
893
934
                file_id = None  # points to branch root
894
935
        else:
895
 
            tree, relpath = WorkingTree.open_containing('.')
 
936
            tree, relpath = WorkingTree.open_containing(u'.')
896
937
            b = tree.branch
897
938
            file_id = None
898
939
 
919
960
        # in e.g. the default C locale.
920
961
        outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
921
962
 
922
 
        log_format = 'long'
923
 
        if short:
924
 
            log_format = 'short'
925
 
        if line:
926
 
            log_format = 'line'
 
963
        log_format = get_log_format(long=long, short=short, line=line)
927
964
        lf = log_formatter(log_format,
928
965
                           show_ids=show_ids,
929
966
                           to_file=outf,
938
975
                 end_revision=rev2,
939
976
                 search=message)
940
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
941
987
 
942
988
 
943
989
class cmd_touching_revisions(Command):
984
1030
 
985
1031
        selection = {'I':ignored, '?':unknown, 'V':versioned}
986
1032
 
987
 
        tree, relpath = WorkingTree.open_containing('.')
 
1033
        tree, relpath = WorkingTree.open_containing(u'.')
988
1034
        if from_root:
989
 
            relpath = ''
 
1035
            relpath = u''
990
1036
        elif relpath:
991
1037
            relpath += '/'
992
1038
        if revision is not None:
1015
1061
    @display_command
1016
1062
    def run(self):
1017
1063
        from bzrlib.osutils import quotefn
1018
 
        for f in WorkingTree.open_containing('.')[0].unknowns():
 
1064
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
1019
1065
            print quotefn(f)
1020
1066
 
1021
1067
 
1044
1090
        from bzrlib.atomicfile import AtomicFile
1045
1091
        import os.path
1046
1092
 
1047
 
        tree, relpath = WorkingTree.open_containing('.')
 
1093
        tree, relpath = WorkingTree.open_containing(u'.')
1048
1094
        ifn = tree.abspath('.bzrignore')
1049
1095
 
1050
1096
        if os.path.exists(ifn):
1084
1130
    See also: bzr ignore"""
1085
1131
    @display_command
1086
1132
    def run(self):
1087
 
        tree = WorkingTree.open_containing('.')[0]
 
1133
        tree = WorkingTree.open_containing(u'.')[0]
1088
1134
        for path, file_class, kind, file_id, entry in tree.list_files():
1089
1135
            if file_class != 'I':
1090
1136
                continue
1109
1155
        except ValueError:
1110
1156
            raise BzrCommandError("not a valid revision-number: %r" % revno)
1111
1157
 
1112
 
        print WorkingTree.open_containing('.')[0].branch.get_rev_id(revno)
 
1158
        print WorkingTree.open_containing(u'.')[0].branch.get_rev_id(revno)
1113
1159
 
1114
1160
 
1115
1161
class cmd_export(Command):
1122
1168
    is found exports to a directory (equivalent to --format=dir).
1123
1169
 
1124
1170
    Root may be the top directory for tar, tgz and tbz2 formats. If none
1125
 
    is given, the top directory will be the root name of the file."""
1126
 
    # 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
    """
1127
1183
    takes_args = ['dest']
1128
1184
    takes_options = ['revision', 'format', 'root']
1129
1185
    def run(self, dest, revision=None, format=None, root=None):
1130
1186
        import os.path
1131
 
        tree = WorkingTree.open_containing('.')[0]
 
1187
        from bzrlib.export import export
 
1188
        tree = WorkingTree.open_containing(u'.')[0]
1132
1189
        b = tree.branch
1133
1190
        if revision is None:
1134
1191
            # should be tree.last_revision  FIXME
1135
 
            rev_id = tree.branch.last_revision()
 
1192
            rev_id = b.last_revision()
1136
1193
        else:
1137
1194
            if len(revision) != 1:
1138
1195
                raise BzrError('bzr export --revision takes exactly 1 argument')
1139
1196
            rev_id = revision[0].in_history(b).rev_id
1140
1197
        t = b.revision_tree(rev_id)
1141
 
        arg_root, ext = os.path.splitext(os.path.basename(dest))
1142
 
        if ext in ('.gz', '.bz2'):
1143
 
            new_root, new_ext = os.path.splitext(arg_root)
1144
 
            if new_ext == '.tar':
1145
 
                arg_root = new_root
1146
 
                ext = new_ext + ext
1147
 
        if root is None:
1148
 
            root = arg_root
1149
 
        if not format:
1150
 
            if ext in (".tar",):
1151
 
                format = "tar"
1152
 
            elif ext in (".tar.gz", ".tgz"):
1153
 
                format = "tgz"
1154
 
            elif ext in (".tar.bz2", ".tbz2"):
1155
 
                format = "tbz2"
1156
 
            else:
1157
 
                format = "dir"
1158
 
        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)
1159
1202
 
1160
1203
 
1161
1204
class cmd_cat(Command):
1166
1209
 
1167
1210
    @display_command
1168
1211
    def run(self, filename, revision=None):
1169
 
        if revision is None:
1170
 
            raise BzrCommandError("bzr cat requires a revision number")
1171
 
        elif len(revision) != 1:
 
1212
        if revision is not None and len(revision) != 1:
1172
1213
            raise BzrCommandError("bzr cat --revision takes exactly one number")
1173
1214
        tree = None
1174
1215
        try:
1176
1217
            b = tree.branch
1177
1218
        except NotBranchError:
1178
1219
            pass
 
1220
 
1179
1221
        if tree is None:
1180
1222
            b, relpath = Branch.open_containing(filename)
1181
 
        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)
1182
1228
 
1183
1229
 
1184
1230
class cmd_local_time_offset(Command):
1229
1275
            unchanged=False, strict=False):
1230
1276
        from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1231
1277
                StrictCommitFailed)
1232
 
        from bzrlib.msgeditor import edit_commit_message
 
1278
        from bzrlib.msgeditor import edit_commit_message, \
 
1279
                make_commit_message_template
1233
1280
        from bzrlib.status import show_status
1234
 
        from cStringIO import StringIO
1235
 
 
 
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
1236
1292
        tree, selected_list = tree_files(selected_list)
1237
1293
        if message is None and not file:
1238
 
            catcher = StringIO()
1239
 
            show_status(tree.branch, specific_files=selected_list,
1240
 
                        to_file=catcher)
1241
 
            message = edit_commit_message(catcher.getvalue())
1242
 
 
 
1294
            template = make_commit_message_template(tree, selected_list)
 
1295
            message = edit_commit_message(template)
1243
1296
            if message is None:
1244
1297
                raise BzrCommandError("please specify a commit message"
1245
1298
                                      " with either --message or --file")
1267
1320
        except StrictCommitFailed:
1268
1321
            raise BzrCommandError("Commit refused because there are unknown "
1269
1322
                                  "files in the working tree.")
 
1323
        note('Committed revision %d.' % (tree.branch.revno(),))
1270
1324
 
1271
1325
 
1272
1326
class cmd_check(Command):
1275
1329
    This command checks various invariants about the branch storage to
1276
1330
    detect data corruption or bzr bugs.
1277
1331
    """
1278
 
    takes_args = ['dir?']
 
1332
    takes_args = ['branch?']
1279
1333
    takes_options = ['verbose']
1280
1334
 
1281
 
    def run(self, dir='.', verbose=False):
 
1335
    def run(self, branch=None, verbose=False):
1282
1336
        from bzrlib.check import check
1283
 
        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)
1284
1343
 
1285
1344
 
1286
1345
class cmd_scan_cache(Command):
1288
1347
    def run(self):
1289
1348
        from bzrlib.hashcache import HashCache
1290
1349
 
1291
 
        c = HashCache('.')
 
1350
        c = HashCache(u'.')
1292
1351
        c.read()
1293
1352
        c.scan()
1294
1353
            
1314
1373
    """
1315
1374
    takes_args = ['dir?']
1316
1375
 
1317
 
    def run(self, dir='.'):
 
1376
    def run(self, dir=u'.'):
1318
1377
        from bzrlib.upgrade import upgrade
1319
1378
        upgrade(dir)
1320
1379
 
1326
1385
    @display_command
1327
1386
    def run(self, email=False):
1328
1387
        try:
1329
 
            b = WorkingTree.open_containing('.')[0].branch
 
1388
            b = WorkingTree.open_containing(u'.')[0].branch
1330
1389
            config = bzrlib.config.BranchConfig(b)
1331
1390
        except NotBranchError:
1332
1391
            config = bzrlib.config.GlobalConfig()
1344
1403
    """
1345
1404
    takes_args = ['nickname?']
1346
1405
    def run(self, nickname=None):
1347
 
        branch = Branch.open_containing('.')[0]
 
1406
        branch = Branch.open_containing(u'.')[0]
1348
1407
        if nickname is None:
1349
1408
            self.printme(branch)
1350
1409
        else:
1377
1436
    def run(self, testspecs_list=None, verbose=False, one=False,
1378
1437
            keep_output=False):
1379
1438
        import bzrlib.ui
1380
 
        from bzrlib.selftest import selftest
 
1439
        from bzrlib.tests import selftest
1381
1440
        # we don't want progress meters from the tests to go to the
1382
1441
        # real output; and we don't want log messages cluttering up
1383
1442
        # the real logs.
1402
1461
            bzrlib.ui.ui_factory = save_ui
1403
1462
 
1404
1463
 
 
1464
def _get_bzr_branch():
 
1465
    """If bzr is run from a branch, return Branch or None"""
 
1466
    import bzrlib.errors
 
1467
    from bzrlib.branch import Branch
 
1468
    from bzrlib.osutils import abspath
 
1469
    from os.path import dirname
 
1470
    
 
1471
    try:
 
1472
        branch = Branch.open(dirname(abspath(dirname(__file__))))
 
1473
        return branch
 
1474
    except bzrlib.errors.BzrError:
 
1475
        return None
 
1476
    
 
1477
 
1405
1478
def show_version():
1406
1479
    print "bzr (bazaar-ng) %s" % bzrlib.__version__
1407
1480
    # is bzrlib itself in a branch?
1408
 
    bzrrev = bzrlib.get_bzr_revision()
1409
 
    if bzrrev:
1410
 
        print "  (bzr checkout, revision %d {%s})" % bzrrev
 
1481
    branch = _get_bzr_branch()
 
1482
    if branch:
 
1483
        rh = branch.revision_history()
 
1484
        revno = len(rh)
 
1485
        print "  bzr checkout, revision %d" % (revno,)
 
1486
        print "  nick: %s" % (branch.nick,)
 
1487
        if rh:
 
1488
            print "  revid: %s" % (rh[-1],)
1411
1489
    print bzrlib.__copyright__
1412
1490
    print "http://bazaar-ng.org/"
1413
1491
    print
1509
1587
        if merge_type is None:
1510
1588
            merge_type = ApplyMerge3
1511
1589
        if branch is None:
1512
 
            branch = WorkingTree.open_containing('.')[0].branch.get_parent()
 
1590
            branch = WorkingTree.open_containing(u'.')[0].branch.get_parent()
1513
1591
            if branch is None:
1514
1592
                raise BzrCommandError("No merge location known or specified.")
1515
1593
            else:
1632
1710
            file_list = []
1633
1711
        if revision is None:
1634
1712
            revno = -1
1635
 
            tree = WorkingTree.open_containing('.')[0]
 
1713
            tree = WorkingTree.open_containing(u'.')[0]
1636
1714
            # FIXME should be tree.last_revision
1637
1715
            rev_id = tree.branch.last_revision()
1638
1716
        elif len(revision) != 1:
1704
1782
 
1705
1783
 
1706
1784
class cmd_missing(Command):
1707
 
    """What is missing in this branch relative to other branch.
1708
 
    """
1709
 
    # TODO: rewrite this in terms of ancestry so that it shows only
1710
 
    # unmerged things
1711
 
    
1712
 
    takes_args = ['remote?']
1713
 
    aliases = ['mis', 'miss']
1714
 
    # We don't have to add quiet to the list, because 
1715
 
    # unknown options are parsed as booleans
1716
 
    takes_options = ['verbose', 'quiet']
1717
 
 
1718
 
    @display_command
1719
 
    def run(self, remote=None, verbose=False, quiet=False):
1720
 
        from bzrlib.errors import BzrCommandError
1721
 
        from bzrlib.missing import show_missing
1722
 
 
1723
 
        if verbose and quiet:
1724
 
            raise BzrCommandError('Cannot pass both quiet and verbose')
1725
 
 
1726
 
        tree = WorkingTree.open_containing('.')[0]
1727
 
        parent = tree.branch.get_parent()
1728
 
        if remote is None:
1729
 
            if parent is None:
 
1785
    """Show unmerged/unpulled revisions between two branches.
 
1786
 
 
1787
    OTHER_BRANCH may be local or remote."""
 
1788
    takes_args = ['other_branch?']
 
1789
    takes_options = [Option('reverse', 'Reverse the order of revisions'),
 
1790
                     Option('mine-only', 
 
1791
                            'Display changes in the local branch only'),
 
1792
                     Option('theirs-only', 
 
1793
                            'Display changes in the remote branch only'), 
 
1794
                     'line',
 
1795
                     'long', 
 
1796
                     'short',
 
1797
                     'show-ids',
 
1798
                     'verbose'
 
1799
                     ]
 
1800
 
 
1801
    def run(self, other_branch=None, reverse=False, mine_only=False,
 
1802
            theirs_only=False, long=True, short=False, line=False, 
 
1803
            show_ids=False, verbose=False):
 
1804
        from bzrlib.missing import find_unmerged, iter_log_data
 
1805
        from bzrlib.log import log_formatter
 
1806
        local_branch = bzrlib.branch.Branch.open_containing(u".")[0]
 
1807
        parent = local_branch.get_parent()
 
1808
        if other_branch is None:
 
1809
            other_branch = parent
 
1810
            if other_branch is None:
1730
1811
                raise BzrCommandError("No missing location known or specified.")
1731
 
            else:
1732
 
                if not quiet:
1733
 
                    print "Using last location: %s" % parent
1734
 
                remote = parent
1735
 
        elif parent is None:
1736
 
            # We only update parent if it did not exist, missing
1737
 
            # should not change the parent
1738
 
            tree.branch.set_parent(remote)
1739
 
        br_remote = Branch.open_containing(remote)[0]
1740
 
        return show_missing(tree.branch, br_remote, verbose=verbose, quiet=quiet)
 
1812
            print "Using last location: " + local_branch.get_parent()
 
1813
        remote_branch = bzrlib.branch.Branch.open(other_branch)
 
1814
        local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
 
1815
        log_format = get_log_format(long=long, short=short, line=line)
 
1816
        lf = log_formatter(log_format, sys.stdout,
 
1817
                           show_ids=show_ids,
 
1818
                           show_timezone='original')
 
1819
        if reverse is False:
 
1820
            local_extra.reverse()
 
1821
            remote_extra.reverse()
 
1822
        if local_extra and not theirs_only:
 
1823
            print "You have %d extra revision(s):" % len(local_extra)
 
1824
            for data in iter_log_data(local_extra, local_branch, verbose):
 
1825
                lf.show(*data)
 
1826
            printed_local = True
 
1827
        else:
 
1828
            printed_local = False
 
1829
        if remote_extra and not mine_only:
 
1830
            if printed_local is True:
 
1831
                print "\n\n"
 
1832
            print "You are missing %d revision(s):" % len(remote_extra)
 
1833
            for data in iter_log_data(remote_extra, remote_branch, verbose):
 
1834
                lf.show(*data)
 
1835
        if not remote_extra and not local_extra:
 
1836
            status_code = 0
 
1837
            print "Branches are up to date."
 
1838
        else:
 
1839
            status_code = 1
 
1840
        if parent is None and other_branch is not None:
 
1841
            local_branch.set_parent(other_branch)
 
1842
        return status_code
1741
1843
 
1742
1844
 
1743
1845
class cmd_plugins(Command):
1747
1849
    def run(self):
1748
1850
        import bzrlib.plugin
1749
1851
        from inspect import getdoc
1750
 
        for plugin in bzrlib.plugin.all_plugins:
 
1852
        for name, plugin in bzrlib.plugin.all_plugins().items():
1751
1853
            if hasattr(plugin, '__path__'):
1752
1854
                print plugin.__path__[0]
1753
1855
            elif hasattr(plugin, '__file__'):
1765
1867
    takes_options = ['revision', 'long']
1766
1868
    takes_args = ['branch?']
1767
1869
    @display_command
1768
 
    def run(self, branch='.', revision=None, long=False):
 
1870
    def run(self, branch=u'.', revision=None, long=False):
1769
1871
        from bzrlib.testament import Testament
1770
1872
        b = WorkingTree.open_containing(branch)[0].branch
1771
1873
        b.lock_read()
1832
1934
            raise BzrCommandError('You can only supply one of revision_id or --revision')
1833
1935
        if revision_id is None and revision is None:
1834
1936
            raise BzrCommandError('You must supply either --revision or a revision_id')
1835
 
        b = WorkingTree.open_containing('.')[0].branch
 
1937
        b = WorkingTree.open_containing(u'.')[0].branch
1836
1938
        gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1837
1939
        if revision_id is not None:
1838
1940
            b.sign_revision(revision_id, gpg_strategy)
1856
1958
                raise BzrCommandError('Please supply either one revision, or a range.')
1857
1959
 
1858
1960
 
 
1961
class cmd_uncommit(bzrlib.commands.Command):
 
1962
    """Remove the last committed revision.
 
1963
 
 
1964
    By supplying the --all flag, it will not only remove the entry 
 
1965
    from revision_history, but also remove all of the entries in the
 
1966
    stores.
 
1967
 
 
1968
    --verbose will print out what is being removed.
 
1969
    --dry-run will go through all the motions, but not actually
 
1970
    remove anything.
 
1971
    
 
1972
    In the future, uncommit will create a changeset, which can then
 
1973
    be re-applied.
 
1974
    """
 
1975
    takes_options = ['all', 'verbose', 'revision',
 
1976
                    Option('dry-run', help='Don\'t actually make changes'),
 
1977
                    Option('force', help='Say yes to all questions.')]
 
1978
    takes_args = ['location?']
 
1979
    aliases = []
 
1980
 
 
1981
    def run(self, location=None, all=False,
 
1982
            dry_run=False, verbose=False,
 
1983
            revision=None, force=False):
 
1984
        from bzrlib.branch import Branch
 
1985
        from bzrlib.log import log_formatter
 
1986
        import sys
 
1987
        from bzrlib.uncommit import uncommit
 
1988
 
 
1989
        if location is None:
 
1990
            location = u'.'
 
1991
        b, relpath = Branch.open_containing(location)
 
1992
 
 
1993
        if revision is None:
 
1994
            revno = b.revno()
 
1995
            rev_id = b.last_revision()
 
1996
        else:
 
1997
            revno, rev_id = revision[0].in_history(b)
 
1998
        if rev_id is None:
 
1999
            print 'No revisions to uncommit.'
 
2000
 
 
2001
        for r in range(revno, b.revno()+1):
 
2002
            rev_id = b.get_rev_id(r)
 
2003
            lf = log_formatter('short', to_file=sys.stdout,show_timezone='original')
 
2004
            lf.show(r, b.get_revision(rev_id), None)
 
2005
 
 
2006
        if dry_run:
 
2007
            print 'Dry-run, pretending to remove the above revisions.'
 
2008
            if not force:
 
2009
                val = raw_input('Press <enter> to continue')
 
2010
        else:
 
2011
            print 'The above revision(s) will be removed.'
 
2012
            if not force:
 
2013
                val = raw_input('Are you sure [y/N]? ')
 
2014
                if val.lower() not in ('y', 'yes'):
 
2015
                    print 'Canceled'
 
2016
                    return 0
 
2017
 
 
2018
        uncommit(b, remove_files=all,
 
2019
                dry_run=dry_run, verbose=verbose,
 
2020
                revno=revno)
 
2021
 
 
2022
 
1859
2023
# these get imported and then picked up by the scan for cmd_*
1860
2024
# TODO: Some more consistent way to split command definitions across files;
1861
2025
# we do need to load at least some information about them to know of