~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Martin Pool
  • Date: 2005-11-11 23:22:03 UTC
  • mto: (1185.33.43 bzr.dev)
  • mto: This revision was merged to the branch mainline in revision 1512.
  • Revision ID: mbp@sourcefrog.net-20051111232203-e1c6e4437f6fe9a7
Don't enable default logging twice

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
 
 
 
17
# DO NOT change this to cStringIO - it results in control files 
 
18
# written as UCS4
 
19
# FIXIT! (Only deal with byte streams OR unicode at any one layer.)
 
20
# RBC 20051018
 
21
from StringIO import StringIO
18
22
import sys
19
23
import os
20
24
 
21
25
import bzrlib
22
26
from bzrlib import BZRDIR
23
 
from bzrlib.commands import Command
 
27
from bzrlib.commands import Command, display_command
24
28
from bzrlib.branch import Branch
25
29
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
26
 
from bzrlib.errors import DivergedBranches
 
30
from bzrlib.errors import DivergedBranches, NoSuchFile, NoWorkingTree
27
31
from bzrlib.option import Option
28
32
from bzrlib.revisionspec import RevisionSpec
29
33
import bzrlib.trace
31
35
from bzrlib.workingtree import WorkingTree
32
36
 
33
37
 
 
38
def branch_files(file_list, default_branch='.'):
 
39
    """\
 
40
    Return a branch and list of branch-relative paths.
 
41
    If supplied file_list is empty or None, the branch default will be used,
 
42
    and returned file_list will match the original.
 
43
    """
 
44
    if file_list is None or len(file_list) == 0:
 
45
        return Branch.open_containing(default_branch)[0], file_list
 
46
    b = Branch.open_containing(file_list[0])[0]
 
47
    
 
48
    # note that if this is a remote branch, we would want
 
49
    # relpath against the transport. RBC 20051018
 
50
    # Most branch ops can't meaningfully operate on files in remote branches;
 
51
    # the above comment was in cmd_status.  ADHB 20051026
 
52
    tree = WorkingTree(b.base, b)
 
53
    new_list = []
 
54
    for filename in file_list:
 
55
        try:
 
56
            new_list.append(tree.relpath(filename))
 
57
        except NotBranchError:
 
58
            raise BzrCommandError("%s is not in the same branch as %s" % 
 
59
                                  (filename, file_list[0]))
 
60
    return b, new_list
 
61
 
 
62
 
 
63
# TODO: Make sure no commands unconditionally use the working directory as a
 
64
# branch.  If a filename argument is used, the first of them should be used to
 
65
# specify the branch.  (Perhaps this can be factored out into some kind of
 
66
# Argument class, representing a file in a branch, where the first occurrence
 
67
# opens the branch?)
 
68
 
34
69
class cmd_status(Command):
35
70
    """Display status summary.
36
71
 
71
106
    that revision, or between two revisions if two are provided.
72
107
    """
73
108
    
74
 
    # XXX: FIXME: bzr status should accept a -r option to show changes
75
 
    # relative to a revision, or between revisions
76
 
 
77
109
    # TODO: --no-recurse, --recurse options
78
110
    
79
111
    takes_args = ['file*']
80
 
    takes_options = ['all', 'show-ids']
 
112
    takes_options = ['all', 'show-ids', 'revision']
81
113
    aliases = ['st', 'stat']
82
114
    
 
115
    @display_command
83
116
    def run(self, all=False, show_ids=False, file_list=None, revision=None):
84
 
        if file_list:
85
 
            b, relpath = Branch.open_containing(file_list[0])
86
 
            if relpath == '' and len(file_list) == 1:
87
 
                file_list = None
88
 
            else:
89
 
                # generate relative paths.
90
 
                # note that if this is a remote branch, we would want
91
 
                # relpath against the transport. RBC 20051018
92
 
                tree = WorkingTree(b.base, b)
93
 
                file_list = [tree.relpath(x) for x in file_list]
94
 
        else:
95
 
            b = Branch.open_containing('.')[0]
 
117
        b, file_list = branch_files(file_list)
96
118
            
97
119
        from bzrlib.status import show_status
98
120
        show_status(b, show_unchanged=all, show_ids=show_ids,
110
132
    takes_args = ['revision_id?']
111
133
    takes_options = ['revision']
112
134
    
 
135
    @display_command
113
136
    def run(self, revision_id=None, revision=None):
114
137
 
115
138
        if revision_id is not None and revision is not None:
131
154
    """Show current revision number.
132
155
 
133
156
    This is equal to the number of revisions on this branch."""
 
157
    @display_command
134
158
    def run(self):
135
159
        print Branch.open_containing('.')[0].revno()
136
160
 
141
165
    hidden = True
142
166
    takes_args = ['revision_info*']
143
167
    takes_options = ['revision']
 
168
    @display_command
144
169
    def run(self, revision=None, revision_info_list=[]):
145
170
 
146
171
        revs = []
220
245
    takes_args = ['filename']
221
246
    hidden = True
222
247
    
 
248
    @display_command
223
249
    def run(self, filename):
224
250
        branch, relpath = Branch.open_containing(filename)
225
251
        print relpath
229
255
    """Show inventory of the current working copy or a revision."""
230
256
    takes_options = ['revision', 'show-ids']
231
257
    
 
258
    @display_command
232
259
    def run(self, revision=None, show_ids=False):
233
260
        b = Branch.open_containing('.')[0]
234
261
        if revision is None:
235
 
            inv = b.read_working_inventory()
 
262
            inv = b.working_tree().read_working_inventory()
236
263
        else:
237
264
            if len(revision) > 1:
238
265
                raise BzrCommandError('bzr inventory --revision takes'
256
283
    """
257
284
    takes_args = ['source$', 'dest']
258
285
    def run(self, source_list, dest):
259
 
        b = Branch.open_containing('.')[0]
 
286
        b, source_list = branch_files(source_list)
260
287
 
261
288
        # TODO: glob expansion on windows?
262
289
        tree = WorkingTree(b.base, b)
263
 
        b.move([tree.relpath(s) for s in source_list], tree.relpath(dest))
 
290
        b.move(source_list, tree.relpath(dest))
264
291
 
265
292
 
266
293
class cmd_rename(Command):
280
307
    takes_args = ['from_name', 'to_name']
281
308
    
282
309
    def run(self, from_name, to_name):
283
 
        b = Branch.open_containing('.')[0]
284
 
        tree = WorkingTree(b.base, b)
285
 
        b.rename_one(tree.relpath(from_name), tree.relpath(to_name))
 
310
        b, (from_name, to_name) = branch_files((from_name, to_name))
 
311
        b.rename_one(from_name, to_name)
286
312
 
287
313
 
288
314
class cmd_mv(Command):
302
328
    def run(self, names_list):
303
329
        if len(names_list) < 2:
304
330
            raise BzrCommandError("missing file argument")
305
 
        b = Branch.open_containing(names_list[0])[0]
306
 
        tree = WorkingTree(b.base, b)
307
 
        rel_names = [tree.relpath(x) for x in names_list]
 
331
        b, rel_names = branch_files(names_list)
308
332
        
309
333
        if os.path.isdir(names_list[-1]):
310
334
            # move into existing directory
318
342
            print "%s => %s" % (rel_names[0], rel_names[1])
319
343
            
320
344
    
321
 
 
322
 
 
323
345
class cmd_pull(Command):
324
346
    """Pull any changes from another branch into the current one.
325
347
 
326
 
    If the location is omitted, the last-used location will be used.
327
 
    Both the revision history and the working directory will be
328
 
    updated.
 
348
    If there is no default location set, the first pull will set it.  After
 
349
    that, you can omit the location to use the default.  To change the
 
350
    default, use --remember.
329
351
 
330
352
    This command only works on branches that have not diverged.  Branches are
331
353
    considered diverged if both branches have had commits without first
332
354
    pulling from the other.
333
355
 
334
356
    If branches have diverged, you can use 'bzr merge' to pull the text changes
335
 
    from one into the other.
 
357
    from one into the other.  Once one branch has merged, the other should
 
358
    be able to pull it again.
 
359
 
 
360
    If you want to forget your local changes and just update your branch to
 
361
    match the remote one, use --overwrite.
336
362
    """
337
 
    takes_options = ['remember', 'clobber']
 
363
    takes_options = ['remember', 'overwrite']
338
364
    takes_args = ['location?']
339
365
 
340
 
    def run(self, location=None, remember=False, clobber=False):
 
366
    def run(self, location=None, remember=False, overwrite=False):
341
367
        from bzrlib.merge import merge
342
 
        import tempfile
343
368
        from shutil import rmtree
344
369
        import errno
345
370
        
353
378
                location = stored_loc
354
379
        br_from = Branch.open(location)
355
380
        try:
356
 
            br_to.working_tree().pull(br_from, remember, clobber)
 
381
            br_to.working_tree().pull(br_from, overwrite)
357
382
        except DivergedBranches:
358
383
            raise BzrCommandError("These branches have diverged."
359
384
                                  "  Try merge.")
 
385
        if br_to.get_parent() is None or remember:
 
386
            br_to.set_parent(location)
 
387
 
 
388
 
 
389
class cmd_push(Command):
 
390
    """Push this branch into another branch.
 
391
    
 
392
    The remote branch will not have its working tree populated because this
 
393
    is both expensive, and may not be supported on the remote file system.
 
394
    
 
395
    Some smart servers or protocols *may* put the working tree in place.
 
396
 
 
397
    If there is no default push location set, the first push will set it.
 
398
    After that, you can omit the location to use the default.  To change the
 
399
    default, use --remember.
 
400
 
 
401
    This command only works on branches that have not diverged.  Branches are
 
402
    considered diverged if the branch being pushed to is not an older version
 
403
    of this branch.
 
404
 
 
405
    If branches have diverged, you can use 'bzr push --overwrite' to replace
 
406
    the other branch completely.
 
407
    
 
408
    If you want to ensure you have the different changes in the other branch,
 
409
    do a merge (see bzr help merge) from the other branch, and commit that
 
410
    before doing a 'push --overwrite'.
 
411
    """
 
412
    takes_options = ['remember', 'overwrite', 
 
413
                     Option('create-prefix', 
 
414
                            help='Create the path leading up to the branch '
 
415
                                 'if it does not already exist')]
 
416
    takes_args = ['location?']
 
417
 
 
418
    def run(self, location=None, remember=False, overwrite=False,
 
419
            create_prefix=False):
 
420
        import errno
 
421
        from shutil import rmtree
 
422
        from bzrlib.transport import get_transport
 
423
        
 
424
        br_from = Branch.open_containing('.')[0]
 
425
        stored_loc = br_from.get_push_location()
 
426
        if location is None:
 
427
            if stored_loc is None:
 
428
                raise BzrCommandError("No push location known or specified.")
 
429
            else:
 
430
                print "Using saved location: %s" % stored_loc
 
431
                location = stored_loc
 
432
        try:
 
433
            br_to = Branch.open(location)
 
434
        except NotBranchError:
 
435
            # create a branch.
 
436
            transport = get_transport(location).clone('..')
 
437
            if not create_prefix:
 
438
                try:
 
439
                    transport.mkdir(transport.relpath(location))
 
440
                except NoSuchFile:
 
441
                    raise BzrCommandError("Parent directory of %s "
 
442
                                          "does not exist." % location)
 
443
            else:
 
444
                current = transport.base
 
445
                needed = [(transport, transport.relpath(location))]
 
446
                while needed:
 
447
                    try:
 
448
                        transport, relpath = needed[-1]
 
449
                        transport.mkdir(relpath)
 
450
                        needed.pop()
 
451
                    except NoSuchFile:
 
452
                        new_transport = transport.clone('..')
 
453
                        needed.append((new_transport,
 
454
                                       new_transport.relpath(transport.base)))
 
455
                        if new_transport.base == transport.base:
 
456
                            raise BzrCommandError("Could not creeate "
 
457
                                                  "path prefix.")
 
458
                        
 
459
            NoSuchFile
 
460
            br_to = Branch.initialize(location)
 
461
        try:
 
462
            br_to.pull(br_from, overwrite)
 
463
        except DivergedBranches:
 
464
            raise BzrCommandError("These branches have diverged."
 
465
                                  "  Try a merge then push with overwrite.")
 
466
        if br_from.get_push_location() is None or remember:
 
467
            br_from.set_push_location(location)
360
468
 
361
469
 
362
470
class cmd_branch(Command):
378
486
 
379
487
    def run(self, from_location, to_location=None, revision=None, basis=None):
380
488
        from bzrlib.clone import copy_branch
381
 
        import tempfile
382
489
        import errno
383
490
        from shutil import rmtree
384
 
        cache_root = tempfile.mkdtemp()
385
491
        if revision is None:
386
492
            revision = [None]
387
493
        elif len(revision) > 1:
397
503
                raise
398
504
        br_from.lock_read()
399
505
        try:
400
 
            br_from.setup_caching(cache_root)
401
506
            if basis is not None:
402
507
                basis_branch = Branch.open_containing(basis)[0]
403
508
            else:
408
513
                revision_id = None
409
514
            if to_location is None:
410
515
                to_location = os.path.basename(from_location.rstrip("/\\"))
 
516
                name = None
 
517
            else:
 
518
                name = os.path.basename(to_location) + '\n'
411
519
            try:
412
520
                os.mkdir(to_location)
413
521
            except OSError, e:
426
534
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
427
535
                raise BzrCommandError(msg)
428
536
            except bzrlib.errors.UnlistableBranch:
 
537
                rmtree(to_location)
429
538
                msg = "The branch %s cannot be used as a --basis"
 
539
                raise BzrCommandError(msg)
 
540
            if name:
 
541
                branch = Branch.open(to_location)
 
542
                name = StringIO(name)
 
543
                branch.put_controlfile('branch-name', name)
430
544
        finally:
431
545
            br_from.unlock()
432
 
            rmtree(cache_root)
433
546
 
434
547
 
435
548
class cmd_renames(Command):
440
553
    # TODO: Only show renames under dir, rather than in the whole branch.
441
554
    takes_args = ['dir?']
442
555
 
 
556
    @display_command
443
557
    def run(self, dir='.'):
444
558
        b = Branch.open_containing(dir)[0]
445
559
        old_inv = b.basis_tree().inventory
446
 
        new_inv = b.read_working_inventory()
 
560
        new_inv = b.working_tree().read_working_inventory()
447
561
 
448
562
        renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
449
563
        renames.sort()
455
569
    """Show statistical information about a branch."""
456
570
    takes_args = ['branch?']
457
571
    
 
572
    @display_command
458
573
    def run(self, branch=None):
459
574
        import info
460
575
        b = Branch.open_containing(branch)[0]
472
587
    aliases = ['rm']
473
588
    
474
589
    def run(self, file_list, verbose=False):
475
 
        b = Branch.open_containing(file_list[0])[0]
476
 
        tree = WorkingTree(b.base, b)
477
 
        tree.remove([tree.relpath(f) for f in file_list], verbose=verbose)
 
590
        b, file_list = branch_files(file_list)
 
591
        tree = b.working_tree()
 
592
        tree.remove(file_list, verbose=verbose)
478
593
 
479
594
 
480
595
class cmd_file_id(Command):
486
601
    """
487
602
    hidden = True
488
603
    takes_args = ['filename']
 
604
    @display_command
489
605
    def run(self, filename):
490
606
        b, relpath = Branch.open_containing(filename)
491
607
        i = b.inventory.path2id(relpath)
502
618
    starting at the branch root."""
503
619
    hidden = True
504
620
    takes_args = ['filename']
 
621
    @display_command
505
622
    def run(self, filename):
506
623
        b, relpath = Branch.open_containing(filename)
507
624
        inv = b.inventory
515
632
class cmd_revision_history(Command):
516
633
    """Display list of revision ids on this branch."""
517
634
    hidden = True
 
635
    @display_command
518
636
    def run(self):
519
637
        for patchid in Branch.open_containing('.')[0].revision_history():
520
638
            print patchid
523
641
class cmd_ancestry(Command):
524
642
    """List all revisions merged into this branch."""
525
643
    hidden = True
 
644
    @display_command
526
645
    def run(self):
527
 
        b = find_branch('.')
 
646
        b = Branch.open_containing('.')[0]
528
647
        for revision_id in b.get_ancestry(b.last_revision()):
529
648
            print revision_id
530
649
 
531
650
 
532
651
class cmd_directories(Command):
533
652
    """Display list of versioned directories in this branch."""
 
653
    @display_command
534
654
    def run(self):
535
 
        for name, ie in Branch.open_containing('.')[0].read_working_inventory().directories():
 
655
        for name, ie in (Branch.open_containing('.')[0].working_tree().
 
656
                         read_working_inventory().directories()):
536
657
            if name == '':
537
658
                print '.'
538
659
            else:
548
669
    Recipe for importing a tree of files:
549
670
        cd ~/project
550
671
        bzr init
551
 
        bzr add -v .
 
672
        bzr add .
552
673
        bzr status
553
674
        bzr commit -m 'imported project'
554
675
    """
555
 
    def run(self):
556
 
        Branch.initialize('.')
 
676
    takes_args = ['location?']
 
677
    def run(self, location=None):
 
678
        from bzrlib.branch import Branch
 
679
        if location is None:
 
680
            location = '.'
 
681
        else:
 
682
            # The path has to exist to initialize a
 
683
            # branch inside of it.
 
684
            # Just using os.mkdir, since I don't
 
685
            # believe that we want to create a bunch of
 
686
            # locations if the user supplies an extended path
 
687
            if not os.path.exists(location):
 
688
                os.mkdir(location)
 
689
        Branch.initialize(location)
557
690
 
558
691
 
559
692
class cmd_diff(Command):
585
718
    takes_options = ['revision', 'diff-options']
586
719
    aliases = ['di', 'dif']
587
720
 
 
721
    @display_command
588
722
    def run(self, revision=None, file_list=None, diff_options=None):
589
723
        from bzrlib.diff import show_diff
590
 
 
591
 
        if file_list:
592
 
            b = Branch.open_containing(file_list[0])[0]
593
 
            tree = WorkingTree(b.base, b)
594
 
            file_list = [tree.relpath(f) for f in file_list]
595
 
            if file_list == ['']:
596
 
                # just pointing to top-of-tree
597
 
                file_list = None
598
 
        else:
599
 
            b = Branch.open_containing('.')[0]
600
 
 
 
724
        
 
725
        b, file_list = branch_files(file_list)
601
726
        if revision is not None:
602
727
            if len(revision) == 1:
603
 
                show_diff(b, revision[0], specific_files=file_list,
604
 
                          external_diff_options=diff_options)
 
728
                return show_diff(b, revision[0], specific_files=file_list,
 
729
                                 external_diff_options=diff_options)
605
730
            elif len(revision) == 2:
606
 
                show_diff(b, revision[0], specific_files=file_list,
607
 
                          external_diff_options=diff_options,
608
 
                          revision2=revision[1])
 
731
                return show_diff(b, revision[0], specific_files=file_list,
 
732
                                 external_diff_options=diff_options,
 
733
                                 revision2=revision[1])
609
734
            else:
610
735
                raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
611
736
        else:
612
 
            show_diff(b, None, specific_files=file_list,
613
 
                      external_diff_options=diff_options)
614
 
 
615
 
        
 
737
            return show_diff(b, None, specific_files=file_list,
 
738
                             external_diff_options=diff_options)
616
739
 
617
740
 
618
741
class cmd_deleted(Command):
624
747
    # directories with readdir, rather than stating each one.  Same
625
748
    # level of effort but possibly much less IO.  (Or possibly not,
626
749
    # if the directories are very large...)
 
750
    @display_command
627
751
    def run(self, show_ids=False):
628
752
        b = Branch.open_containing('.')[0]
629
753
        old = b.basis_tree()
639
763
class cmd_modified(Command):
640
764
    """List files modified in working tree."""
641
765
    hidden = True
 
766
    @display_command
642
767
    def run(self):
643
768
        from bzrlib.delta import compare_trees
644
769
 
653
778
class cmd_added(Command):
654
779
    """List files added in working tree."""
655
780
    hidden = True
 
781
    @display_command
656
782
    def run(self):
657
783
        b = Branch.open_containing('.')[0]
658
784
        wt = b.working_tree()
674
800
    The root is the nearest enclosing directory with a .bzr control
675
801
    directory."""
676
802
    takes_args = ['filename?']
 
803
    @display_command
677
804
    def run(self, filename=None):
678
805
        """Print the branch root."""
679
806
        b = Branch.open_containing(filename)[0]
683
810
class cmd_log(Command):
684
811
    """Show log of this branch.
685
812
 
686
 
    To request a range of logs, you can use the command -r begin:end
687
 
    -r revision requests a specific revision, -r :end or -r begin: are
 
813
    To request a range of logs, you can use the command -r begin..end
 
814
    -r revision requests a specific revision, -r ..end or -r begin.. are
688
815
    also valid.
689
816
    """
690
817
 
702
829
                            type=str),
703
830
                     Option('short', help='use moderately short format'),
704
831
                     ]
705
 
    
 
832
    @display_command
706
833
    def run(self, filename=None, timezone='original',
707
834
            verbose=False,
708
835
            show_ids=False,
721
848
        if filename:
722
849
            b, fp = Branch.open_containing(filename)
723
850
            if fp != '':
724
 
                file_id = b.read_working_inventory().path2id(fp)
 
851
                try:
 
852
                    inv = b.working_tree().read_working_inventory()
 
853
                except NoWorkingTree:
 
854
                    inv = b.get_inventory(b.last_revision())
 
855
                file_id = inv.path2id(fp)
725
856
            else:
726
857
                file_id = None  # points to branch root
727
858
        else:
777
908
    A more user-friendly interface is "bzr log FILE"."""
778
909
    hidden = True
779
910
    takes_args = ["filename"]
 
911
    @display_command
780
912
    def run(self, filename):
781
913
        b, relpath = Branch.open_containing(filename)[0]
782
 
        inv = b.read_working_inventory()
 
914
        inv = b.working_tree().read_working_inventory()
783
915
        file_id = inv.path2id(relpath)
784
916
        for revno, revision_id, what in bzrlib.log.find_touching_revisions(b, file_id):
785
917
            print "%6d %s" % (revno, what)
790
922
    """
791
923
    # TODO: Take a revision or remote path and list that tree instead.
792
924
    hidden = True
793
 
    def run(self, revision=None, verbose=False):
794
 
        b, relpath = Branch.open_containing('.')[0]
 
925
    takes_options = ['verbose', 'revision',
 
926
                     Option('non-recursive',
 
927
                            help='don\'t recurse into sub-directories'),
 
928
                     Option('from-root',
 
929
                            help='Print all paths from the root of the branch.'),
 
930
                     Option('unknown', help='Print unknown files'),
 
931
                     Option('versioned', help='Print versioned files'),
 
932
                     Option('ignored', help='Print ignored files'),
 
933
 
 
934
                     Option('null', help='Null separate the files'),
 
935
                    ]
 
936
    @display_command
 
937
    def run(self, revision=None, verbose=False, 
 
938
            non_recursive=False, from_root=False,
 
939
            unknown=False, versioned=False, ignored=False,
 
940
            null=False):
 
941
 
 
942
        if verbose and null:
 
943
            raise BzrCommandError('Cannot set both --verbose and --null')
 
944
        all = not (unknown or versioned or ignored)
 
945
 
 
946
        selection = {'I':ignored, '?':unknown, 'V':versioned}
 
947
 
 
948
        b, relpath = Branch.open_containing('.')
 
949
        if from_root:
 
950
            relpath = ''
 
951
        elif relpath:
 
952
            relpath += '/'
795
953
        if revision == None:
796
954
            tree = b.working_tree()
797
955
        else:
798
 
            tree = b.revision_tree(revision.in_history(b).rev_id)
 
956
            tree = b.revision_tree(revision[0].in_history(b).rev_id)
799
957
        for fp, fc, kind, fid, entry in tree.list_files():
800
 
            if verbose:
801
 
                kindch = entry.kind_character()
802
 
                print '%-8s %s%s' % (fc, fp, kindch)
803
 
            else:
804
 
                print fp
 
958
            if fp.startswith(relpath):
 
959
                fp = fp[len(relpath):]
 
960
                if non_recursive and '/' in fp:
 
961
                    continue
 
962
                if not all and not selection[fc]:
 
963
                    continue
 
964
                if verbose:
 
965
                    kindch = entry.kind_character()
 
966
                    print '%-8s %s%s' % (fc, fp, kindch)
 
967
                elif null:
 
968
                    sys.stdout.write(fp)
 
969
                    sys.stdout.write('\0')
 
970
                    sys.stdout.flush()
 
971
                else:
 
972
                    print fp
805
973
 
806
974
 
807
975
 
808
976
class cmd_unknowns(Command):
809
977
    """List unknown files."""
 
978
    @display_command
810
979
    def run(self):
811
980
        from bzrlib.osutils import quotefn
812
981
        for f in Branch.open_containing('.')[0].unknowns():
878
1047
    """List ignored files and the patterns that matched them.
879
1048
 
880
1049
    See also: bzr ignore"""
 
1050
    @display_command
881
1051
    def run(self):
882
1052
        tree = Branch.open_containing('.')[0].working_tree()
883
1053
        for path, file_class, kind, file_id, entry in tree.list_files():
897
1067
    hidden = True
898
1068
    takes_args = ['revno']
899
1069
    
 
1070
    @display_command
900
1071
    def run(self, revno):
901
1072
        try:
902
1073
            revno = int(revno)
956
1127
    takes_options = ['revision']
957
1128
    takes_args = ['filename']
958
1129
 
 
1130
    @display_command
959
1131
    def run(self, filename, revision=None):
960
1132
        if revision is None:
961
1133
            raise BzrCommandError("bzr cat requires a revision number")
968
1140
class cmd_local_time_offset(Command):
969
1141
    """Show the offset in seconds from GMT to local time."""
970
1142
    hidden = True    
 
1143
    @display_command
971
1144
    def run(self):
972
1145
        print bzrlib.osutils.local_time_offset()
973
1146
 
1016
1189
        from bzrlib.status import show_status
1017
1190
        from cStringIO import StringIO
1018
1191
 
1019
 
        b = Branch.open_containing('.')[0]
1020
 
        tree = WorkingTree(b.base, b)
1021
 
        if selected_list:
1022
 
            selected_list = [tree.relpath(s) for s in selected_list]
 
1192
        b, selected_list = branch_files(selected_list)
1023
1193
        if message is None and not file:
1024
1194
            catcher = StringIO()
1025
1195
            show_status(b, specific_files=selected_list,
1109
1279
    """Show bzr user id."""
1110
1280
    takes_options = ['email']
1111
1281
    
 
1282
    @display_command
1112
1283
    def run(self, email=False):
1113
1284
        try:
1114
1285
            b = bzrlib.branch.Branch.open_containing('.')[0]
1182
1353
 
1183
1354
class cmd_version(Command):
1184
1355
    """Show version of bzr."""
 
1356
    @display_command
1185
1357
    def run(self):
1186
1358
        show_version()
1187
1359
 
1188
1360
class cmd_rocks(Command):
1189
1361
    """Statement of optimism."""
1190
1362
    hidden = True
 
1363
    @display_command
1191
1364
    def run(self):
1192
1365
        print "it sure does!"
1193
1366
 
1200
1373
    takes_args = ['branch', 'other']
1201
1374
    hidden = True
1202
1375
    
 
1376
    @display_command
1203
1377
    def run(self, branch, other):
1204
1378
        from bzrlib.revision import common_ancestor, MultipleRevisionSources
1205
1379
        
1259
1433
    --force is given.
1260
1434
    """
1261
1435
    takes_args = ['branch?']
1262
 
    takes_options = ['revision', 'force', 'merge-type']
 
1436
    takes_options = ['revision', 'force', 'merge-type', 'reprocess',
 
1437
                     Option('show-base', help="Show base revision text in "
 
1438
                            "conflicts")]
1263
1439
 
1264
 
    def run(self, branch=None, revision=None, force=False, 
1265
 
            merge_type=None):
 
1440
    def run(self, branch=None, revision=None, force=False, merge_type=None,
 
1441
            show_base=False, reprocess=False):
1266
1442
        from bzrlib.merge import merge
1267
1443
        from bzrlib.merge_core import ApplyMerge3
1268
1444
        if merge_type is None:
1279
1455
        else:
1280
1456
            if len(revision) == 1:
1281
1457
                base = [None, None]
1282
 
                other = [branch, revision[0].in_history(branch).revno]
 
1458
                other_branch = Branch.open_containing(branch)[0]
 
1459
                revno = revision[0].in_history(other_branch).revno
 
1460
                other = [branch, revno]
1283
1461
            else:
1284
1462
                assert len(revision) == 2
1285
1463
                if None in revision:
1286
1464
                    raise BzrCommandError(
1287
1465
                        "Merge doesn't permit that revision specifier.")
1288
 
                b = Branch.open(branch)
 
1466
                b = Branch.open_containing(branch)[0]
1289
1467
 
1290
1468
                base = [branch, revision[0].in_history(b).revno]
1291
1469
                other = [branch, revision[1].in_history(b).revno]
1292
1470
 
1293
1471
        try:
1294
 
            merge(other, base, check_clean=(not force), merge_type=merge_type)
 
1472
            conflict_count = merge(other, base, check_clean=(not force),
 
1473
                                   merge_type=merge_type, reprocess=reprocess,
 
1474
                                   show_base=show_base)
 
1475
            if conflict_count != 0:
 
1476
                return 1
 
1477
            else:
 
1478
                return 0
1295
1479
        except bzrlib.errors.AmbiguousBase, e:
1296
1480
            m = ("sorry, bzr can't determine the right merge base yet\n"
1297
1481
                 "candidates are:\n  "
1325
1509
        elif len(revision) != 1:
1326
1510
            raise BzrCommandError('bzr revert --revision takes exactly 1 argument')
1327
1511
        else:
1328
 
            b = Branch.open_containing('.')[0]
 
1512
            b, file_list = branch_files(file_list)
1329
1513
            revno = revision[0].in_history(b).revno
1330
1514
        merge(('.', revno), parse_spec('.'),
1331
1515
              check_clean=False,
1351
1535
    takes_args = ['topic?']
1352
1536
    aliases = ['?']
1353
1537
    
 
1538
    @display_command
1354
1539
    def run(self, topic=None, long=False):
1355
1540
        import help
1356
1541
        if topic is None and long:
1366
1551
    aliases = ['s-c']
1367
1552
    hidden = True
1368
1553
    
 
1554
    @display_command
1369
1555
    def run(self, context=None):
1370
1556
        import shellcomplete
1371
1557
        shellcomplete.shellcomplete(context)
1380
1566
    def run(self, from_branch, to_branch):
1381
1567
        from bzrlib.fetch import Fetcher
1382
1568
        from bzrlib.branch import Branch
1383
 
        from_b = Branch(from_branch)
1384
 
        to_b = Branch(to_branch)
1385
 
        Fetcher(to_b, from_b)
1386
 
        
 
1569
        from_b = Branch.open(from_branch)
 
1570
        to_b = Branch.open(to_branch)
 
1571
        from_b.lock_read()
 
1572
        try:
 
1573
            to_b.lock_write()
 
1574
            try:
 
1575
                Fetcher(to_b, from_b)
 
1576
            finally:
 
1577
                to_b.unlock()
 
1578
        finally:
 
1579
            from_b.unlock()
1387
1580
 
1388
1581
 
1389
1582
class cmd_missing(Command):
1398
1591
    # unknown options are parsed as booleans
1399
1592
    takes_options = ['verbose', 'quiet']
1400
1593
 
 
1594
    @display_command
1401
1595
    def run(self, remote=None, verbose=False, quiet=False):
1402
1596
        from bzrlib.errors import BzrCommandError
1403
1597
        from bzrlib.missing import show_missing
1425
1619
class cmd_plugins(Command):
1426
1620
    """List plugins"""
1427
1621
    hidden = True
 
1622
    @display_command
1428
1623
    def run(self):
1429
1624
        import bzrlib.plugin
1430
1625
        from inspect import getdoc
1445
1640
    """Show testament (signing-form) of a revision."""
1446
1641
    takes_options = ['revision', 'long']
1447
1642
    takes_args = ['branch?']
 
1643
    @display_command
1448
1644
    def run(self, branch='.', revision=None, long=False):
1449
1645
        from bzrlib.testament import Testament
1450
1646
        b = Branch.open_containing(branch)[0]
1482
1678
                     Option('long', help='show date in annotations'),
1483
1679
                     ]
1484
1680
 
 
1681
    @display_command
1485
1682
    def run(self, filename, all=False, long=False):
1486
1683
        from bzrlib.annotate import annotate_file
1487
1684
        b, relpath = Branch.open_containing(filename)
1516
1713
        if revision_id is not None:
1517
1714
            b.sign_revision(revision_id, gpg_strategy)
1518
1715
        elif revision is not None:
1519
 
            for rev in revision:
1520
 
                if rev is None:
1521
 
                    raise BzrCommandError('You cannot specify a NULL revision.')
1522
 
                revno, rev_id = rev.in_history(b)
 
1716
            if len(revision) == 1:
 
1717
                revno, rev_id = revision[0].in_history(b)
1523
1718
                b.sign_revision(rev_id, gpg_strategy)
 
1719
            elif len(revision) == 2:
 
1720
                # are they both on rh- if so we can walk between them
 
1721
                # might be nice to have a range helper for arbitrary
 
1722
                # revision paths. hmm.
 
1723
                from_revno, from_revid = revision[0].in_history(b)
 
1724
                to_revno, to_revid = revision[1].in_history(b)
 
1725
                if to_revid is None:
 
1726
                    to_revno = b.revno()
 
1727
                if from_revno is None or to_revno is None:
 
1728
                    raise BzrCommandError('Cannot sign a range of non-revision-history revisions')
 
1729
                for revno in range(from_revno, to_revno + 1):
 
1730
                    b.sign_revision(b.get_rev_id(revno), gpg_strategy)
 
1731
            else:
 
1732
                raise BzrCommandError('Please supply either one revision, or a range.')
1524
1733
 
1525
1734
 
1526
1735
# these get imported and then picked up by the scan for cmd_*