~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

Merge from bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
"""builtin bzr commands"""
18
18
 
19
19
 
 
20
import codecs
20
21
import errno
21
22
import os
 
23
from shutil import rmtree
22
24
import sys
23
25
 
24
26
import bzrlib
32
34
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError, 
33
35
                           NotBranchError, DivergedBranches, NotConflicted,
34
36
                           NoSuchFile, NoWorkingTree, FileInWrongBranch,
35
 
                           NotVersionedError, BadBundle)
 
37
                           NotVersionedError, NotABundle)
36
38
from bzrlib.log import show_one_log
37
39
from bzrlib.merge import Merge3Merger
38
40
from bzrlib.option import Option
 
41
import bzrlib.osutils
39
42
from bzrlib.progress import DummyProgress, ProgressPhase
40
43
from bzrlib.revision import common_ancestor
41
44
from bzrlib.revisionspec import RevisionSpec
43
46
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
44
47
from bzrlib.transport.local import LocalTransport
45
48
import bzrlib.ui
 
49
import bzrlib.urlutils as urlutils
46
50
from bzrlib.workingtree import WorkingTree
47
51
 
48
52
 
152
156
    takes_args = ['file*']
153
157
    takes_options = ['all', 'show-ids', 'revision']
154
158
    aliases = ['st', 'stat']
 
159
 
 
160
    encoding_type = 'replace'
155
161
    
156
162
    @display_command
157
163
    def run(self, all=False, show_ids=False, file_list=None, revision=None):
158
 
        tree, file_list = tree_files(file_list)
159
 
            
160
164
        from bzrlib.status import show_tree_status
 
165
 
 
166
        tree, file_list = tree_files(file_list)
 
167
            
161
168
        show_tree_status(tree, show_unchanged=all, show_ids=show_ids,
162
 
                         specific_files=file_list, revision=revision)
 
169
                         specific_files=file_list, revision=revision,
 
170
                         to_file=self.outf)
163
171
 
164
172
 
165
173
class cmd_cat_revision(Command):
172
180
    hidden = True
173
181
    takes_args = ['revision_id?']
174
182
    takes_options = ['revision']
 
183
    # cat-revision is more for frontends so should be exact
 
184
    encoding = 'strict'
175
185
    
176
186
    @display_command
177
187
    def run(self, revision_id=None, revision=None):
181
191
        if revision_id is None and revision is None:
182
192
            raise BzrCommandError('You must supply either --revision or a revision_id')
183
193
        b = WorkingTree.open_containing(u'.')[0].branch
 
194
 
 
195
        # TODO: jam 20060112 should cat-revision always output utf-8?
184
196
        if revision_id is not None:
185
 
            sys.stdout.write(b.repository.get_revision_xml(revision_id))
 
197
            self.outf.write(b.repository.get_revision_xml(revision_id).decode('utf-8'))
186
198
        elif revision is not None:
187
199
            for rev in revision:
188
200
                if rev is None:
189
201
                    raise BzrCommandError('You cannot specify a NULL revision.')
190
202
                revno, rev_id = rev.in_history(b)
191
 
                sys.stdout.write(b.repository.get_revision_xml(rev_id))
 
203
                self.outf.write(b.repository.get_revision_xml(rev_id).decode('utf-8'))
192
204
    
193
205
 
194
206
class cmd_revno(Command):
195
207
    """Show current revision number.
196
208
 
197
 
    This is equal to the number of revisions on this branch."""
 
209
    This is equal to the number of revisions on this branch.
 
210
    """
 
211
 
198
212
    takes_args = ['location?']
 
213
 
199
214
    @display_command
200
215
    def run(self, location=u'.'):
201
 
        print Branch.open_containing(location)[0].revno()
 
216
        self.outf.write(str(Branch.open_containing(location)[0].revno()))
 
217
        self.outf.write('\n')
202
218
 
203
219
 
204
220
class cmd_revision_info(Command):
207
223
    hidden = True
208
224
    takes_args = ['revision_info*']
209
225
    takes_options = ['revision']
 
226
 
210
227
    @display_command
211
228
    def run(self, revision=None, revision_info_list=[]):
212
229
 
249
266
 
250
267
    Adding a file whose parent directory is not versioned will
251
268
    implicitly add the parent, and so on up to the root. This means
252
 
    you should never need to explictly add a directory, they'll just
 
269
    you should never need to explicitly add a directory, they'll just
253
270
    get added when you add a file in the directory.
254
271
 
255
272
    --dry-run will show which files would be added, but not actually 
257
274
    """
258
275
    takes_args = ['file*']
259
276
    takes_options = ['no-recurse', 'dry-run', 'verbose']
 
277
    encoding_type = 'replace'
260
278
 
261
279
    def run(self, file_list, no_recurse=False, dry_run=False, verbose=False):
262
280
        import bzrlib.add
263
281
 
264
 
        if dry_run:
265
 
            if is_quiet():
266
 
                # This is pointless, but I'd rather not raise an error
267
 
                action = bzrlib.add.add_action_null
268
 
            else:
269
 
                action = bzrlib.add.add_action_print
270
 
        elif is_quiet():
271
 
            action = bzrlib.add.add_action_add
272
 
        else:
273
 
            action = bzrlib.add.add_action_add_and_print
 
282
        action = bzrlib.add.AddAction(to_file=self.outf,
 
283
            should_print=(not is_quiet()))
274
284
 
275
285
        added, ignored = bzrlib.add.smart_add(file_list, not no_recurse, 
276
 
                                              action)
 
286
                                              action=action, save=not dry_run)
277
287
        if len(ignored) > 0:
278
288
            if verbose:
279
289
                for glob in sorted(ignored.keys()):
280
290
                    for path in ignored[glob]:
281
 
                        print "ignored %s matching \"%s\"" % (path, glob)
 
291
                        self.outf.write("ignored %s matching \"%s\"\n" 
 
292
                                        % (path, glob))
282
293
            else:
283
294
                match_len = 0
284
295
                for glob, paths in ignored.items():
285
296
                    match_len += len(paths)
286
 
                print "ignored %d file(s)." % match_len
287
 
            print "If you wish to add some of these files, please add them"\
288
 
                " by name."
 
297
                self.outf.write("ignored %d file(s).\n" % match_len)
 
298
            self.outf.write("If you wish to add some of these files,"
 
299
                            " please add them by name.\n")
289
300
 
290
301
 
291
302
class cmd_mkdir(Command):
293
304
 
294
305
    This is equivalent to creating the directory and then adding it.
295
306
    """
 
307
 
296
308
    takes_args = ['dir+']
 
309
    encoding_type = 'replace'
297
310
 
298
311
    def run(self, dir_list):
299
312
        for d in dir_list:
300
313
            os.mkdir(d)
301
314
            wt, dd = WorkingTree.open_containing(d)
302
315
            wt.add([dd])
303
 
            print 'added', d
 
316
            self.outf.write('added %s\n' % d)
304
317
 
305
318
 
306
319
class cmd_relpath(Command):
307
320
    """Show path of a file relative to root"""
 
321
 
308
322
    takes_args = ['filename']
309
323
    hidden = True
310
324
    
311
325
    @display_command
312
326
    def run(self, filename):
 
327
        # TODO: jam 20050106 Can relpath return a munged path if
 
328
        #       sys.stdout encoding cannot represent it?
313
329
        tree, relpath = WorkingTree.open_containing(filename)
314
 
        print relpath
 
330
        self.outf.write(relpath)
 
331
        self.outf.write('\n')
315
332
 
316
333
 
317
334
class cmd_inventory(Command):
320
337
    It is possible to limit the output to a particular entry
321
338
    type using the --kind option.  For example; --kind file.
322
339
    """
 
340
 
323
341
    takes_options = ['revision', 'show-ids', 'kind']
324
342
    
325
343
    @display_command
340
358
            if kind and kind != entry.kind:
341
359
                continue
342
360
            if show_ids:
343
 
                print '%-50s %s' % (path, entry.file_id)
 
361
                self.outf.write('%-50s %s\n' % (path, entry.file_id))
344
362
            else:
345
 
                print path
 
363
                self.outf.write(path)
 
364
                self.outf.write('\n')
346
365
 
347
366
 
348
367
class cmd_mv(Command):
358
377
 
359
378
    Files cannot be moved between branches.
360
379
    """
 
380
 
361
381
    takes_args = ['names*']
362
382
    aliases = ['move', 'rename']
 
383
    encoding_type = 'replace'
363
384
 
364
385
    def run(self, names_list):
365
386
        if len(names_list) < 2:
369
390
        if os.path.isdir(names_list[-1]):
370
391
            # move into existing directory
371
392
            for pair in tree.move(rel_names[:-1], rel_names[-1]):
372
 
                print "%s => %s" % pair
 
393
                self.outf.write("%s => %s\n" % pair)
373
394
        else:
374
395
            if len(names_list) != 2:
375
396
                raise BzrCommandError('to mv multiple files the destination '
376
397
                                      'must be a versioned directory')
377
398
            tree.rename_one(rel_names[0], rel_names[1])
378
 
            print "%s => %s" % (rel_names[0], rel_names[1])
 
399
            self.outf.write("%s => %s\n" % (rel_names[0], rel_names[1]))
379
400
            
380
401
    
381
402
class cmd_pull(Command):
400
421
    that, you can omit the location to use the default.  To change the
401
422
    default, use --remember.
402
423
    """
 
424
 
403
425
    takes_options = ['remember', 'overwrite', 'revision', 'verbose']
404
426
    takes_args = ['location?']
 
427
    encoding_type = 'replace'
405
428
 
406
429
    def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
407
430
        # FIXME: too much stuff is in the command class
410
433
            branch_to = tree_to.branch
411
434
        except NoWorkingTree:
412
435
            tree_to = None
413
 
            branch_to = Branch.open_containing(u'.')[0] 
 
436
            branch_to = Branch.open_containing(u'.')[0]
414
437
        stored_loc = branch_to.get_parent()
415
438
        if location is None:
416
439
            if stored_loc is None:
417
440
                raise BzrCommandError("No pull location known or specified.")
418
441
            else:
419
 
                print "Using saved location: %s" % stored_loc
 
442
                display_url = urlutils.unescape_for_display(stored_loc,
 
443
                        self.outf.encoding)
 
444
                self.outf.write("Using saved location: %s\n" % display_url)
420
445
                location = stored_loc
421
446
 
 
447
        branch_from = Branch.open(location)
 
448
 
422
449
        if branch_to.get_parent() is None or remember:
423
 
            branch_to.set_parent(location)
424
 
 
425
 
        branch_from = Branch.open(location)
 
450
            branch_to.set_parent(branch_from.base)
426
451
 
427
452
        if revision is None:
428
453
            rev_id = None
443
468
            if old_rh != new_rh:
444
469
                # Something changed
445
470
                from bzrlib.log import show_changed_revisions
446
 
                show_changed_revisions(branch_to, old_rh, new_rh)
 
471
                show_changed_revisions(branch_to, old_rh, new_rh,
 
472
                                       to_file=self.outf)
447
473
 
448
474
 
449
475
class cmd_push(Command):
470
496
    After that, you can omit the location to use the default.  To change the
471
497
    default, use --remember.
472
498
    """
473
 
    takes_options = ['remember', 'overwrite', 
 
499
 
 
500
    takes_options = ['remember', 'overwrite', 'verbose',
474
501
                     Option('create-prefix', 
475
502
                            help='Create the path leading up to the branch '
476
503
                                 'if it does not already exist')]
477
504
    takes_args = ['location?']
 
505
    encoding_type = 'replace'
478
506
 
479
507
    def run(self, location=None, remember=False, overwrite=False,
480
508
            create_prefix=False, verbose=False):
488
516
            if stored_loc is None:
489
517
                raise BzrCommandError("No push location known or specified.")
490
518
            else:
491
 
                print "Using saved location: %s" % stored_loc
 
519
                display_url = urlutils.unescape_for_display(stored_loc,
 
520
                        self.outf.encoding)
 
521
                self.outf.write("Using saved location: %s" % display_url)
492
522
                location = stored_loc
 
523
 
 
524
        transport = get_transport(location)
 
525
        location_url = transport.base
493
526
        if br_from.get_push_location() is None or remember:
494
 
            br_from.set_push_location(location)
 
527
            br_from.set_push_location(location_url)
 
528
 
 
529
        old_rh = []
495
530
        try:
496
 
            dir_to = bzrlib.bzrdir.BzrDir.open(location)
 
531
            dir_to = bzrlib.bzrdir.BzrDir.open(location_url)
497
532
            br_to = dir_to.open_branch()
498
533
        except NotBranchError:
499
534
            # create a branch.
500
 
            transport = get_transport(location).clone('..')
 
535
            transport = transport.clone('..')
501
536
            if not create_prefix:
502
537
                try:
503
 
                    transport.mkdir(transport.relpath(location))
 
538
                    relurl = transport.relpath(location_url)
 
539
                    mutter('creating directory %s => %s', location_url, relurl)
 
540
                    transport.mkdir(relurl)
504
541
                except NoSuchFile:
505
542
                    raise BzrCommandError("Parent directory of %s "
506
543
                                          "does not exist." % location)
507
544
            else:
508
545
                current = transport.base
509
 
                needed = [(transport, transport.relpath(location))]
 
546
                needed = [(transport, transport.relpath(location_url))]
510
547
                while needed:
511
548
                    try:
512
549
                        transport, relpath = needed[-1]
519
556
                        if new_transport.base == transport.base:
520
557
                            raise BzrCommandError("Could not create "
521
558
                                                  "path prefix.")
522
 
            dir_to = br_from.bzrdir.clone(location,
 
559
            dir_to = br_from.bzrdir.clone(location_url,
523
560
                revision_id=br_from.last_revision())
524
561
            br_to = dir_to.open_branch()
525
562
            count = len(br_to.revision_history())
546
583
            if old_rh != new_rh:
547
584
                # Something changed
548
585
                from bzrlib.log import show_changed_revisions
549
 
                show_changed_revisions(br_to, old_rh, new_rh)
 
586
                show_changed_revisions(br_to, old_rh, new_rh,
 
587
                                       to_file=self.outf)
550
588
 
551
589
 
552
590
class cmd_branch(Command):
567
605
    aliases = ['get', 'clone']
568
606
 
569
607
    def run(self, from_location, to_location=None, revision=None, basis=None):
 
608
        from bzrlib.transport import get_transport
570
609
        from bzrlib.osutils import rmtree
571
610
        if revision is None:
572
611
            revision = [None]
599
638
                name = None
600
639
            else:
601
640
                name = os.path.basename(to_location) + '\n'
 
641
 
 
642
            to_transport = get_transport(to_location)
602
643
            try:
603
 
                os.mkdir(to_location)
604
 
            except OSError, e:
605
 
                if e.errno == errno.EEXIST:
606
 
                    raise BzrCommandError('Target directory "%s" already'
607
 
                                          ' exists.' % to_location)
608
 
                if e.errno == errno.ENOENT:
609
 
                    raise BzrCommandError('Parent of "%s" does not exist.' %
610
 
                                          to_location)
611
 
                else:
612
 
                    raise
 
644
                to_transport.mkdir('.')
 
645
            except bzrlib.errors.FileExists:
 
646
                raise BzrCommandError('Target directory "%s" already'
 
647
                                      ' exists.' % to_location)
 
648
            except bzrlib.errors.NoSuchFile:
 
649
                raise BzrCommandError('Parent of "%s" does not exist.' %
 
650
                                      to_location)
613
651
            try:
614
652
                # preserve whatever source format we have.
615
 
                dir = br_from.bzrdir.sprout(to_location, revision_id, basis_dir)
 
653
                dir = br_from.bzrdir.sprout(to_transport.base,
 
654
                        revision_id, basis_dir)
616
655
                branch = dir.open_branch()
617
656
            except bzrlib.errors.NoSuchRevision:
618
 
                rmtree(to_location)
 
657
                to_transport.delete_tree('.')
619
658
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
620
659
                raise BzrCommandError(msg)
621
660
            except bzrlib.errors.UnlistableBranch:
624
663
                raise BzrCommandError(msg)
625
664
            if name:
626
665
                branch.control_files.put_utf8('branch-name', name)
627
 
 
628
666
            note('Branched %d revision(s).' % branch.revno())
629
667
        finally:
630
668
            br_from.unlock()
735
773
        renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
736
774
        renames.sort()
737
775
        for old_name, new_name in renames:
738
 
            print "%s => %s" % (old_name, new_name)        
 
776
            self.outf.write("%s => %s\n" % (old_name, new_name))
739
777
 
740
778
 
741
779
class cmd_update(Command):
804
842
    takes_args = ['file*']
805
843
    takes_options = ['verbose', Option('new', help='remove newly-added files')]
806
844
    aliases = ['rm']
 
845
    encoding_type = 'replace'
807
846
    
808
847
    def run(self, file_list, verbose=False, new=False):
809
848
        tree, file_list = tree_files(file_list)
818
857
            file_list = sorted([f[0] for f in added[0]], reverse=True)
819
858
            if len(file_list) == 0:
820
859
                raise BzrCommandError('No matching files.')
821
 
        tree.remove(file_list, verbose=verbose)
 
860
        tree.remove(file_list, verbose=verbose, to_file=self.outf)
822
861
 
823
862
 
824
863
class cmd_file_id(Command):
828
867
    same through all revisions where the file exists, even when it is
829
868
    moved or renamed.
830
869
    """
 
870
 
831
871
    hidden = True
832
872
    takes_args = ['filename']
 
873
 
833
874
    @display_command
834
875
    def run(self, filename):
835
876
        tree, relpath = WorkingTree.open_containing(filename)
837
878
        if i == None:
838
879
            raise BzrError("%r is not a versioned file" % filename)
839
880
        else:
840
 
            print i
 
881
            self.outf.write(i + '\n')
841
882
 
842
883
 
843
884
class cmd_file_path(Command):
844
885
    """Print path of file_ids to a file or directory.
845
886
 
846
887
    This prints one line for each directory down to the target,
847
 
    starting at the branch root."""
 
888
    starting at the branch root.
 
889
    """
 
890
 
848
891
    hidden = True
849
892
    takes_args = ['filename']
 
893
 
850
894
    @display_command
851
895
    def run(self, filename):
852
896
        tree, relpath = WorkingTree.open_containing(filename)
855
899
        if fid == None:
856
900
            raise BzrError("%r is not a versioned file" % filename)
857
901
        for fip in inv.get_idpath(fid):
858
 
            print fip
 
902
            self.outf.write(fip + '\n')
859
903
 
860
904
 
861
905
class cmd_reconcile(Command):
887
931
class cmd_revision_history(Command):
888
932
    """Display list of revision ids on this branch."""
889
933
    hidden = True
 
934
 
890
935
    @display_command
891
936
    def run(self):
892
937
        branch = WorkingTree.open_containing(u'.')[0].branch
893
938
        for patchid in branch.revision_history():
894
 
            print patchid
 
939
            self.outf.write(patchid)
 
940
            self.outf.write('\n')
895
941
 
896
942
 
897
943
class cmd_ancestry(Command):
898
944
    """List all revisions merged into this branch."""
899
945
    hidden = True
 
946
 
900
947
    @display_command
901
948
    def run(self):
902
949
        tree = WorkingTree.open_containing(u'.')[0]
906
953
        assert revision_ids[0] == None
907
954
        revision_ids.pop(0)
908
955
        for revision_id in revision_ids:
909
 
            print revision_id
 
956
            self.outf.write(revision_id + '\n')
910
957
 
911
958
 
912
959
class cmd_init(Command):
1037
1084
    takes_args = ['file*']
1038
1085
    takes_options = ['revision', 'diff-options', 'prefix']
1039
1086
    aliases = ['di', 'dif']
 
1087
    encoding_type = 'exact'
1040
1088
 
1041
1089
    @display_command
1042
1090
    def run(self, revision=None, file_list=None, diff_options=None,
1103
1151
    # directories with readdir, rather than stating each one.  Same
1104
1152
    # level of effort but possibly much less IO.  (Or possibly not,
1105
1153
    # if the directories are very large...)
 
1154
    takes_options = ['show-ids']
 
1155
 
1106
1156
    @display_command
1107
1157
    def run(self, show_ids=False):
1108
1158
        tree = WorkingTree.open_containing(u'.')[0]
1109
1159
        old = tree.basis_tree()
1110
1160
        for path, ie in old.inventory.iter_entries():
1111
1161
            if not tree.has_id(ie.file_id):
 
1162
                self.outf.write(path)
1112
1163
                if show_ids:
1113
 
                    print '%-50s %s' % (path, ie.file_id)
1114
 
                else:
1115
 
                    print path
 
1164
                    self.outf.write(' ')
 
1165
                    self.outf.write(ie.file_id)
 
1166
                self.outf.write('\n')
1116
1167
 
1117
1168
 
1118
1169
class cmd_modified(Command):
1126
1177
        td = compare_trees(tree.basis_tree(), tree)
1127
1178
 
1128
1179
        for path, id, kind, text_modified, meta_modified in td.modified:
1129
 
            print path
1130
 
 
 
1180
            self.outf.write(path + '\n')
1131
1181
 
1132
1182
 
1133
1183
class cmd_added(Command):
1144
1194
            path = inv.id2path(file_id)
1145
1195
            if not os.access(bzrlib.osutils.abspath(path), os.F_OK):
1146
1196
                continue
1147
 
            print path
1148
 
                
1149
 
        
 
1197
            self.outf.write(path + '\n')
 
1198
 
1150
1199
 
1151
1200
class cmd_root(Command):
1152
1201
    """Show the tree root directory.
1158
1207
    def run(self, filename=None):
1159
1208
        """Print the branch root."""
1160
1209
        tree = WorkingTree.open_containing(filename)[0]
1161
 
        print tree.basedir
 
1210
        self.outf.write(tree.basedir + '\n')
1162
1211
 
1163
1212
 
1164
1213
class cmd_log(Command):
1192
1241
                            type=str),
1193
1242
                     'short',
1194
1243
                     ]
 
1244
    encoding_type = 'replace'
 
1245
 
1195
1246
    @display_command
1196
1247
    def run(self, location=None, timezone='original',
1197
1248
            verbose=False,
1204
1255
            short=False,
1205
1256
            line=False):
1206
1257
        from bzrlib.log import log_formatter, show_log
1207
 
        import codecs
1208
1258
        assert message is None or isinstance(message, basestring), \
1209
1259
            "invalid message argument %r" % message
1210
1260
        direction = (forward and 'forward') or 'reverse'
1256
1306
        if rev1 > rev2:
1257
1307
            (rev2, rev1) = (rev1, rev2)
1258
1308
 
1259
 
        mutter('encoding log as %r', bzrlib.user_encoding)
1260
 
 
1261
 
        # use 'replace' so that we don't abort if trying to write out
1262
 
        # in e.g. the default C locale.
1263
 
        outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
1264
 
 
1265
1309
        if (log_format == None):
1266
1310
            default = bzrlib.config.BranchConfig(b).log_format()
1267
1311
            log_format = get_log_format(long=long, short=short, line=line, default=default)
1268
 
 
1269
1312
        lf = log_formatter(log_format,
1270
1313
                           show_ids=show_ids,
1271
 
                           to_file=outf,
 
1314
                           to_file=self.outf,
1272
1315
                           show_timezone=timezone)
1273
1316
 
1274
1317
        show_log(b,
1295
1338
class cmd_touching_revisions(Command):
1296
1339
    """Return revision-ids which affected a particular file.
1297
1340
 
1298
 
    A more user-friendly interface is "bzr log FILE"."""
 
1341
    A more user-friendly interface is "bzr log FILE".
 
1342
    """
 
1343
 
1299
1344
    hidden = True
1300
1345
    takes_args = ["filename"]
 
1346
 
1301
1347
    @display_command
1302
1348
    def run(self, filename):
1303
1349
        tree, relpath = WorkingTree.open_containing(filename)
1305
1351
        inv = tree.read_working_inventory()
1306
1352
        file_id = inv.path2id(relpath)
1307
1353
        for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
1308
 
            print "%6d %s" % (revno, what)
 
1354
            self.outf.write("%6d %s\n" % (revno, what))
1309
1355
 
1310
1356
 
1311
1357
class cmd_ls(Command):
1357
1403
                    continue
1358
1404
                if verbose:
1359
1405
                    kindch = entry.kind_character()
1360
 
                    print '%-8s %s%s' % (fc, fp, kindch)
 
1406
                    self.outf.write('%-8s %s%s\n' % (fc, fp, kindch))
1361
1407
                elif null:
1362
 
                    sys.stdout.write(fp)
1363
 
                    sys.stdout.write('\0')
1364
 
                    sys.stdout.flush()
 
1408
                    self.outf.write(fp + '\0')
 
1409
                    self.outf.flush()
1365
1410
                else:
1366
 
                    print fp
 
1411
                    self.outf.write(fp + '\n')
1367
1412
 
1368
1413
 
1369
1414
class cmd_unknowns(Command):
1372
1417
    def run(self):
1373
1418
        from bzrlib.osutils import quotefn
1374
1419
        for f in WorkingTree.open_containing(u'.')[0].unknowns():
1375
 
            print quotefn(f)
 
1420
            self.outf.write(quotefn(f) + '\n')
1376
1421
 
1377
1422
 
1378
1423
class cmd_ignore(Command):
1595
1640
        from bzrlib.msgeditor import edit_commit_message, \
1596
1641
                make_commit_message_template
1597
1642
        from tempfile import TemporaryFile
1598
 
        import codecs
1599
1643
 
1600
1644
        # TODO: Need a blackbox test for invoking the external editor; may be
1601
1645
        # slightly problematic to run this cross-platform.
1624
1668
            raise BzrCommandError("please specify either --message or --file")
1625
1669
        
1626
1670
        if file:
1627
 
            import codecs
1628
1671
            message = codecs.open(file, 'rt', bzrlib.user_encoding).read()
1629
1672
 
1630
1673
        if message == "":
2010
2053
        if merge_type is None:
2011
2054
            merge_type = Merge3Merger
2012
2055
 
2013
 
 
2014
2056
        tree = WorkingTree.open_containing(u'.')[0]
 
2057
 
2015
2058
        try:
2016
2059
            if branch is not None:
2017
2060
                reader = BundleReader(file(branch, 'rb'))
2021
2064
            if e.errno not in (errno.ENOENT, errno.EISDIR):
2022
2065
                raise
2023
2066
            reader = None
2024
 
        except BadBundle:
 
2067
        except NotABundle:
2025
2068
            reader = None
2026
2069
        if reader is not None:
2027
2070
            conflicts = merge_bundle(reader, tree, not force, merge_type,
2031
2074
            else:
2032
2075
                return 1
2033
2076
 
2034
 
        stored_loc = tree.branch.get_parent()
2035
 
        if branch is None:
2036
 
            if stored_loc is None:
2037
 
                raise BzrCommandError("No merge branch known or specified.")
2038
 
            else:
2039
 
                print "Using saved branch: %s" % stored_loc
2040
 
                branch = stored_loc
2041
 
 
2042
 
        if tree.branch.get_parent() is None or remember:
2043
 
            tree.branch.set_parent(branch)
 
2077
        branch = self._get_remembered_parent(tree, branch, 'Merging from')
2044
2078
 
2045
2079
        if revision is None or len(revision) < 1:
2046
2080
            base = [None, None]
2057
2091
                if None in revision:
2058
2092
                    raise BzrCommandError(
2059
2093
                        "Merge doesn't permit that revision specifier.")
2060
 
                b, path = Branch.open_containing(branch)
2061
 
 
2062
 
                base = [branch, revision[0].in_history(b).revno]
2063
 
                other = [branch, revision[1].in_history(b).revno]
 
2094
                other_branch, path = Branch.open_containing(branch)
 
2095
 
 
2096
                base = [branch, revision[0].in_history(other_branch).revno]
 
2097
                other = [branch, revision[1].in_history(other_branch).revno]
 
2098
 
 
2099
        if tree.branch.get_parent() is None or remember:
 
2100
            tree.branch.set_parent(other_branch.base)
 
2101
 
2064
2102
        if path != "":
2065
2103
            interesting_files = [path]
2066
2104
        else:
2069
2107
        try:
2070
2108
            try:
2071
2109
                conflict_count = merge(other, base, check_clean=(not force),
2072
 
                                       merge_type=merge_type, 
 
2110
                                       merge_type=merge_type,
2073
2111
                                       reprocess=reprocess,
2074
 
                                       show_base=show_base, 
 
2112
                                       show_base=show_base,
2075
2113
                                       pb=pb, file_list=interesting_files)
2076
2114
            finally:
2077
2115
                pb.finished()
2088
2126
                 "and (if you want) report this to the bzr developers\n")
2089
2127
            log_error(m)
2090
2128
 
 
2129
    # TODO: move up to common parent; this isn't merge-specific anymore. 
 
2130
    def _get_remembered_parent(self, tree, supplied_location, verb_string):
 
2131
        """Use tree.branch's parent if none was supplied.
 
2132
 
 
2133
        Report if the remembered location was used.
 
2134
        """
 
2135
        if supplied_location is not None:
 
2136
            return supplied_location
 
2137
        stored_location = tree.branch.get_parent()
 
2138
        mutter("%s", stored_location)
 
2139
        if stored_location is None:
 
2140
            raise BzrCommandError("No location specified or remembered")
 
2141
        display_url = urlutils.unescape_for_display(stored_location, self.outf.encoding)
 
2142
        self.outf.write("%s remembered location %s\n" % (verb_string, display_url))
 
2143
        return stored_location
 
2144
 
2091
2145
 
2092
2146
class cmd_remerge(Command):
2093
2147
    """Redo a merge.
2338
2392
            try:
2339
2393
                # handle race conditions - a parent might be set while we run.
2340
2394
                if local_branch.get_parent() is None:
2341
 
                    local_branch.set_parent(other_branch)
 
2395
                    local_branch.set_parent(remote_branch.base)
2342
2396
            finally:
2343
2397
                local_branch.unlock()
2344
2398
        return status_code
2516
2570
    """
2517
2571
 
2518
2572
    # TODO: jam 20060108 Add an option to allow uncommit to remove
2519
 
    # unreferenced information in 'branch-as-repostory' branches.
 
2573
    # unreferenced information in 'branch-as-repository' branches.
2520
2574
    # TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
2521
2575
    # information in shared branches as well.
2522
2576
    takes_options = ['verbose', 'revision',