~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Martin Pool
  • Date: 2006-03-06 11:20:10 UTC
  • mfrom: (1593 +trunk)
  • mto: This revision was merged to the branch mainline in revision 1611.
  • Revision ID: mbp@sourcefrog.net-20060306112010-17c0170dde5d1eea
[merge] large merge to sync with bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005 by Canonical Ltd
 
1
# Copyright (C) 2004, 2005, 2006 by Canonical Ltd
2
2
 
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
17
17
"""builtin bzr commands"""
18
18
 
19
19
 
 
20
import errno
20
21
import os
 
22
from shutil import rmtree
21
23
import sys
22
24
 
23
25
import bzrlib
24
 
from bzrlib import BZRDIR
25
 
from bzrlib._merge_core import ApplyMerge3
 
26
import bzrlib.branch
 
27
from bzrlib.branch import Branch
 
28
import bzrlib.bzrdir as bzrdir
26
29
from bzrlib.commands import Command, display_command
27
 
from bzrlib.branch import Branch
28
30
from bzrlib.revision import common_ancestor
29
31
import bzrlib.errors as errors
30
32
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError, 
31
33
                           NotBranchError, DivergedBranches, NotConflicted,
32
 
                           NoSuchFile, NoWorkingTree, FileInWrongBranch)
 
34
                           NoSuchFile, NoWorkingTree, FileInWrongBranch,
 
35
                           NotVersionedError)
33
36
from bzrlib.log import show_one_log
 
37
from bzrlib.merge import Merge3Merger
34
38
from bzrlib.option import Option
 
39
from bzrlib.progress import DummyProgress
35
40
from bzrlib.revisionspec import RevisionSpec
36
41
import bzrlib.trace
37
42
from bzrlib.trace import mutter, note, log_error, warning, is_quiet
38
43
from bzrlib.transport.local import LocalTransport
 
44
import bzrlib.ui
39
45
from bzrlib.workingtree import WorkingTree
40
46
 
41
47
 
120
126
    def run(self, all=False, show_ids=False, file_list=None, revision=None):
121
127
        tree, file_list = tree_files(file_list)
122
128
            
123
 
        from bzrlib.status import show_status
124
 
        show_status(tree.branch, show_unchanged=all, show_ids=show_ids,
125
 
                    specific_files=file_list, revision=revision)
 
129
        from bzrlib.status import show_tree_status
 
130
        show_tree_status(tree, show_unchanged=all, show_ids=show_ids,
 
131
                         specific_files=file_list, revision=revision)
126
132
 
127
133
 
128
134
class cmd_cat_revision(Command):
392
398
    If you want to forget your local changes and just update your branch to
393
399
    match the remote one, use --overwrite.
394
400
    """
395
 
    takes_options = ['remember', 'overwrite', 'verbose']
 
401
    takes_options = ['remember', 'overwrite', 'revision', 'verbose']
396
402
    takes_args = ['location?']
397
403
 
398
 
    def run(self, location=None, remember=False, overwrite=False, verbose=False):
399
 
        from shutil import rmtree
400
 
        import errno
 
404
    def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
401
405
        # FIXME: too much stuff is in the command class        
402
406
        tree_to = WorkingTree.open_containing(u'.')[0]
403
407
        stored_loc = tree_to.branch.get_parent()
411
415
        br_from = Branch.open(location)
412
416
        br_to = tree_to.branch
413
417
 
 
418
        if revision is None:
 
419
            rev_id = None
 
420
        elif len(revision) == 1:
 
421
            rev_id = revision[0].in_history(br_from).rev_id
 
422
        else:
 
423
            raise BzrCommandError('bzr pull --revision takes one value.')
 
424
 
414
425
        old_rh = br_to.revision_history()
415
 
        count = tree_to.pull(br_from, overwrite)
 
426
        count = tree_to.pull(br_from, overwrite, rev_id)
416
427
 
417
428
        if br_to.get_parent() is None or remember:
418
429
            br_to.set_parent(location)
459
470
            create_prefix=False, verbose=False):
460
471
        # FIXME: Way too big!  Put this into a function called from the
461
472
        # command.
462
 
        import errno
463
 
        from shutil import rmtree
464
473
        from bzrlib.transport import get_transport
465
474
        
466
475
        tree_from = WorkingTree.open_containing(u'.')[0]
498
507
                        if new_transport.base == transport.base:
499
508
                            raise BzrCommandError("Could not creeate "
500
509
                                                  "path prefix.")
501
 
            if isinstance(transport, LocalTransport):
502
 
                br_to = WorkingTree.create_standalone(location).branch
503
 
            else:
504
 
                br_to = Branch.create(location)
 
510
            br_to = bzrlib.bzrdir.BzrDir.create_branch_convenience(location)
505
511
        old_rh = br_to.revision_history()
506
512
        try:
507
513
            try:
547
553
    aliases = ['get', 'clone']
548
554
 
549
555
    def run(self, from_location, to_location=None, revision=None, basis=None):
550
 
        import errno
551
 
        from shutil import rmtree
552
556
        if revision is None:
553
557
            revision = [None]
554
558
        elif len(revision) > 1:
565
569
        br_from.lock_read()
566
570
        try:
567
571
            if basis is not None:
568
 
                basis_branch = WorkingTree.open_containing(basis)[0].branch
 
572
                basis_dir = bzrdir.BzrDir.open_containing(basis)[0]
569
573
            else:
570
 
                basis_branch = None
 
574
                basis_dir = None
571
575
            if len(revision) == 1 and revision[0] is not None:
572
576
                revision_id = revision[0].in_history(br_from)[1]
573
577
            else:
574
 
                revision_id = None
 
578
                # FIXME - wt.last_revision, fallback to branch, fall back to
 
579
                # None or perhaps NULL_REVISION to mean copy nothing
 
580
                # RBC 20060209
 
581
                revision_id = br_from.last_revision()
575
582
            if to_location is None:
576
583
                to_location = os.path.basename(from_location.rstrip("/\\"))
577
584
                name = None
589
596
                else:
590
597
                    raise
591
598
            try:
592
 
                br_from.clone(to_location, revision_id, basis_branch)
 
599
                # preserve whatever source format we have.
 
600
                dir = br_from.bzrdir.sprout(to_location, revision_id, basis_dir)
 
601
                branch = dir.open_branch()
593
602
            except bzrlib.errors.NoSuchRevision:
594
603
                rmtree(to_location)
595
604
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
596
605
                raise BzrCommandError(msg)
597
606
            except bzrlib.errors.UnlistableBranch:
598
607
                rmtree(to_location)
599
 
                msg = "The branch %s cannot be used as a --basis"
 
608
                msg = "The branch %s cannot be used as a --basis" % (basis,)
600
609
                raise BzrCommandError(msg)
601
 
            branch = Branch.open(to_location)
602
610
            if name:
603
611
                branch.control_files.put_utf8('branch-name', name)
604
612
 
607
615
            br_from.unlock()
608
616
 
609
617
 
 
618
class cmd_checkout(Command):
 
619
    """Create a new checkout of an existing branch.
 
620
 
 
621
    If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
 
622
    be used.  In other words, "checkout ../foo/bar" will attempt to create ./bar.
 
623
 
 
624
    To retrieve the branch as of a particular revision, supply the --revision
 
625
    parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
 
626
    out of date [so you cannot commit] but it may be useful (i.e. to examine old
 
627
    code.)
 
628
 
 
629
    --basis is to speed up checking out from remote branches.  When specified, it
 
630
    uses the inventory and file contents from the basis branch in preference to the
 
631
    branch being checked out. [Not implemented yet.]
 
632
    """
 
633
    takes_args = ['branch_location', 'to_location?']
 
634
    takes_options = ['revision', # , 'basis']
 
635
                     Option('lightweight',
 
636
                            help="perform a lightweight checkout. Lightweight "
 
637
                                 "checkouts depend on access to the branch for "
 
638
                                 "every operation. Normal checkouts can perform "
 
639
                                 "common operations like diff and status without "
 
640
                                 "such access, and also support local commits."
 
641
                            ),
 
642
                     ]
 
643
 
 
644
    def run(self, branch_location, to_location=None, revision=None, basis=None,
 
645
            lightweight=False):
 
646
        if revision is None:
 
647
            revision = [None]
 
648
        elif len(revision) > 1:
 
649
            raise BzrCommandError(
 
650
                'bzr checkout --revision takes exactly 1 revision value')
 
651
        source = Branch.open(branch_location)
 
652
        if len(revision) == 1 and revision[0] is not None:
 
653
            revision_id = revision[0].in_history(source)[1]
 
654
        else:
 
655
            revision_id = None
 
656
        if to_location is None:
 
657
            to_location = os.path.basename(branch_location.rstrip("/\\"))
 
658
        try:
 
659
            os.mkdir(to_location)
 
660
        except OSError, e:
 
661
            if e.errno == errno.EEXIST:
 
662
                raise BzrCommandError('Target directory "%s" already'
 
663
                                      ' exists.' % to_location)
 
664
            if e.errno == errno.ENOENT:
 
665
                raise BzrCommandError('Parent of "%s" does not exist.' %
 
666
                                      to_location)
 
667
            else:
 
668
                raise
 
669
        old_format = bzrlib.bzrdir.BzrDirFormat.get_default_format()
 
670
        bzrlib.bzrdir.BzrDirFormat.set_default_format(bzrdir.BzrDirMetaFormat1())
 
671
        try:
 
672
            if lightweight:
 
673
                checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
 
674
                bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
 
675
            else:
 
676
                checkout_branch =  bzrlib.bzrdir.BzrDir.create_branch_convenience(
 
677
                    to_location, force_new_tree=False)
 
678
                checkout = checkout_branch.bzrdir
 
679
                checkout_branch.bind(source)
 
680
                if revision_id is not None:
 
681
                    rh = checkout_branch.revision_history()
 
682
                    checkout_branch.set_revision_history(rh[:rh.index(revision_id) + 1])
 
683
            checkout.create_workingtree(revision_id)
 
684
        finally:
 
685
            bzrlib.bzrdir.BzrDirFormat.set_default_format(old_format)
 
686
 
 
687
 
610
688
class cmd_renames(Command):
611
689
    """Show list of renamed files.
612
690
    """
618
696
    @display_command
619
697
    def run(self, dir=u'.'):
620
698
        tree = WorkingTree.open_containing(dir)[0]
621
 
        old_inv = tree.branch.basis_tree().inventory
 
699
        old_inv = tree.basis_tree().inventory
622
700
        new_inv = tree.read_working_inventory()
623
701
 
624
702
        renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
627
705
            print "%s => %s" % (old_name, new_name)        
628
706
 
629
707
 
 
708
class cmd_update(Command):
 
709
    """Update a tree to have the latest code committed to its branch.
 
710
    
 
711
    This will perform a merge into the working tree, and may generate
 
712
    conflicts. If you have any local changes, you will still 
 
713
    need to commit them after the update for the update to be complete.
 
714
    
 
715
    If you want to discard your local changes, you can just do a 
 
716
    'bzr revert' instead of 'bzr commit' after the update.
 
717
    """
 
718
    takes_args = ['dir?']
 
719
 
 
720
    def run(self, dir='.'):
 
721
        tree = WorkingTree.open_containing(dir)[0]
 
722
        tree.lock_write()
 
723
        try:
 
724
            if tree.last_revision() == tree.branch.last_revision():
 
725
                # may be up to date, check master too.
 
726
                master = tree.branch.get_master_branch()
 
727
                if master is None or master.last_revision == tree.last_revision():
 
728
                    note("Tree is up to date.")
 
729
                    return
 
730
            conflicts = tree.update()
 
731
            note('Updated to revision %d.' %
 
732
                 (tree.branch.revision_id_to_revno(tree.last_revision()),))
 
733
            if conflicts != 0:
 
734
                return 1
 
735
            else:
 
736
                return 0
 
737
        finally:
 
738
            tree.unlock()
 
739
 
 
740
 
630
741
class cmd_info(Command):
631
742
    """Show statistical information about a branch."""
632
743
    takes_args = ['branch?']
633
744
    
634
745
    @display_command
635
746
    def run(self, branch=None):
636
 
        import info
637
 
        b = WorkingTree.open_containing(branch)[0].branch
638
 
        info.show_info(b)
 
747
        import bzrlib.info
 
748
        bzrlib.info.show_bzrdir_info(bzrdir.BzrDir.open_containing(branch)[0])
639
749
 
640
750
 
641
751
class cmd_remove(Command):
690
800
            print fip
691
801
 
692
802
 
 
803
class cmd_reconcile(Command):
 
804
    """Reconcile bzr metadata in a branch.
 
805
 
 
806
    This can correct data mismatches that may have been caused by
 
807
    previous ghost operations or bzr upgrades. You should only
 
808
    need to run this command if 'bzr check' or a bzr developer 
 
809
    advises you to run it.
 
810
 
 
811
    If a second branch is provided, cross-branch reconciliation is
 
812
    also attempted, which will check that data like the tree root
 
813
    id which was not present in very early bzr versions is represented
 
814
    correctly in both branches.
 
815
 
 
816
    At the same time it is run it may recompress data resulting in 
 
817
    a potential saving in disk space or performance gain.
 
818
 
 
819
    The branch *MUST* be on a listable system such as local disk or sftp.
 
820
    """
 
821
    takes_args = ['branch?']
 
822
 
 
823
    def run(self, branch="."):
 
824
        from bzrlib.reconcile import reconcile
 
825
        dir = bzrlib.bzrdir.BzrDir.open(branch)
 
826
        reconcile(dir)
 
827
 
 
828
 
693
829
class cmd_revision_history(Command):
694
830
    """Display list of revision ids on this branch."""
695
831
    hidden = True
738
874
            # locations if the user supplies an extended path
739
875
            if not os.path.exists(location):
740
876
                os.mkdir(location)
741
 
        WorkingTree.create_standalone(location)
 
877
        bzrdir.BzrDir.create_standalone_workingtree(location)
742
878
 
743
879
 
744
880
class cmd_diff(Command):
772
908
 
773
909
    @display_command
774
910
    def run(self, revision=None, file_list=None, diff_options=None):
775
 
        from bzrlib.diff import show_diff
 
911
        from bzrlib.diff import diff_cmd_helper, show_diff_trees
776
912
        try:
777
 
            tree, file_list = internal_tree_files(file_list)
 
913
            tree1, file_list = internal_tree_files(file_list)
 
914
            tree2 = None
778
915
            b = None
779
916
            b2 = None
780
917
        except FileInWrongBranch:
781
918
            if len(file_list) != 2:
782
919
                raise BzrCommandError("Files are in different branches")
783
920
 
784
 
            b, file1 = Branch.open_containing(file_list[0])
785
 
            b2, file2 = Branch.open_containing(file_list[1])
 
921
            tree1, file1 = WorkingTree.open_containing(file_list[0])
 
922
            tree2, file2 = WorkingTree.open_containing(file_list[1])
786
923
            if file1 != "" or file2 != "":
787
924
                # FIXME diff those two files. rbc 20051123
788
925
                raise BzrCommandError("Files are in different branches")
789
926
            file_list = None
790
927
        if revision is not None:
791
 
            if b2 is not None:
 
928
            if tree2 is not None:
792
929
                raise BzrCommandError("Can't specify -r with two branches")
793
930
            if (len(revision) == 1) or (revision[1].spec is None):
794
 
                return show_diff(tree.branch, revision[0], specific_files=file_list,
795
 
                                 external_diff_options=diff_options)
 
931
                return diff_cmd_helper(tree1, file_list, diff_options,
 
932
                                       revision[0])
796
933
            elif len(revision) == 2:
797
 
                return show_diff(tree.branch, revision[0], specific_files=file_list,
798
 
                                 external_diff_options=diff_options,
799
 
                                 revision2=revision[1])
 
934
                return diff_cmd_helper(tree1, file_list, diff_options,
 
935
                                       revision[0], revision[1])
800
936
            else:
801
937
                raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
802
938
        else:
803
 
            if b is not None:
804
 
                return show_diff(b, None, specific_files=file_list,
805
 
                                 external_diff_options=diff_options, b2=b2)
 
939
            if tree2 is not None:
 
940
                return show_diff_trees(tree1, tree2, sys.stdout, 
 
941
                                       specific_files=file_list,
 
942
                                       external_diff_options=diff_options)
806
943
            else:
807
 
                return show_diff(tree.branch, None, specific_files=file_list,
808
 
                                 external_diff_options=diff_options)
 
944
                return diff_cmd_helper(tree1, file_list, diff_options)
809
945
 
810
946
 
811
947
class cmd_deleted(Command):
820
956
    @display_command
821
957
    def run(self, show_ids=False):
822
958
        tree = WorkingTree.open_containing(u'.')[0]
823
 
        old = tree.branch.basis_tree()
 
959
        old = tree.basis_tree()
824
960
        for path, ie in old.inventory.iter_entries():
825
961
            if not tree.has_id(ie.file_id):
826
962
                if show_ids:
837
973
        from bzrlib.delta import compare_trees
838
974
 
839
975
        tree = WorkingTree.open_containing(u'.')[0]
840
 
        td = compare_trees(tree.branch.basis_tree(), tree)
 
976
        td = compare_trees(tree.basis_tree(), tree)
841
977
 
842
978
        for path, id, kind, text_modified, meta_modified in td.modified:
843
979
            print path
850
986
    @display_command
851
987
    def run(self):
852
988
        wt = WorkingTree.open_containing(u'.')[0]
853
 
        basis_inv = wt.branch.basis_tree().inventory
 
989
        basis_inv = wt.basis_tree().inventory
854
990
        inv = wt.inventory
855
991
        for file_id in inv:
856
992
            if file_id in basis_inv:
890
1026
                            help='show from oldest to newest'),
891
1027
                     'timezone', 'verbose', 
892
1028
                     'show-ids', 'revision',
 
1029
                     'log-format',
893
1030
                     'line', 'long', 
894
1031
                     Option('message',
895
1032
                            help='show revisions whose message matches this regexp',
902
1039
            show_ids=False,
903
1040
            forward=False,
904
1041
            revision=None,
 
1042
            log_format=None,
905
1043
            message=None,
906
1044
            long=False,
907
1045
            short=False,
912
1050
            "invalid message argument %r" % message
913
1051
        direction = (forward and 'forward') or 'reverse'
914
1052
        
 
1053
        # log everything
 
1054
        file_id = None
915
1055
        if filename:
916
 
            # might be a tree:
917
 
            tree = None
918
 
            try:
919
 
                tree, fp = WorkingTree.open_containing(filename)
920
 
                b = tree.branch
921
 
                if fp != '':
922
 
                    inv = tree.read_working_inventory()
923
 
            except NotBranchError:
924
 
                pass
925
 
            if tree is None:
926
 
                b, fp = Branch.open_containing(filename)
927
 
                if fp != '':
928
 
                    inv = b.repository.get_inventory(b.last_revision())
 
1056
            # find the file id to log:
 
1057
 
 
1058
            dir, fp = bzrdir.BzrDir.open_containing(filename)
 
1059
            b = dir.open_branch()
929
1060
            if fp != '':
 
1061
                try:
 
1062
                    # might be a tree:
 
1063
                    inv = dir.open_workingtree().inventory
 
1064
                except (errors.NotBranchError, errors.NotLocalUrl):
 
1065
                    # either no tree, or is remote.
 
1066
                    inv = b.basis_tree().inventory
930
1067
                file_id = inv.path2id(fp)
931
 
            else:
932
 
                file_id = None  # points to branch root
933
1068
        else:
934
 
            tree, relpath = WorkingTree.open_containing(u'.')
935
 
            b = tree.branch
936
 
            file_id = None
 
1069
            # local dir only
 
1070
            # FIXME ? log the current subdir only RBC 20060203 
 
1071
            dir, relpath = bzrdir.BzrDir.open_containing('.')
 
1072
            b = dir.open_branch()
937
1073
 
938
1074
        if revision is None:
939
1075
            rev1 = None
941
1077
        elif len(revision) == 1:
942
1078
            rev1 = rev2 = revision[0].in_history(b).revno
943
1079
        elif len(revision) == 2:
944
 
            rev1 = revision[0].in_history(b).revno
945
 
            rev2 = revision[1].in_history(b).revno
 
1080
            if revision[0].spec is None:
 
1081
                # missing begin-range means first revision
 
1082
                rev1 = 1
 
1083
            else:
 
1084
                rev1 = revision[0].in_history(b).revno
 
1085
 
 
1086
            if revision[1].spec is None:
 
1087
                # missing end-range means last known revision
 
1088
                rev2 = b.revno()
 
1089
            else:
 
1090
                rev2 = revision[1].in_history(b).revno
946
1091
        else:
947
1092
            raise BzrCommandError('bzr log --revision takes one or two values.')
948
1093
 
958
1103
        # in e.g. the default C locale.
959
1104
        outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
960
1105
 
961
 
        log_format = get_log_format(long=long, short=short, line=line)
 
1106
        if (log_format == None):
 
1107
            default = bzrlib.config.BranchConfig(b).log_format()
 
1108
            log_format = get_log_format(long=long, short=short, line=line, default=default)
 
1109
 
962
1110
        lf = log_formatter(log_format,
963
1111
                           show_ids=show_ids,
964
1112
                           to_file=outf,
973
1121
                 end_revision=rev2,
974
1122
                 search=message)
975
1123
 
 
1124
 
976
1125
def get_log_format(long=False, short=False, line=False, default='long'):
977
1126
    log_format = default
978
1127
    if long:
1266
1415
                     Option('strict',
1267
1416
                            help="refuse to commit if there are unknown "
1268
1417
                            "files in the working tree."),
 
1418
                     Option('local',
 
1419
                            help="perform a local only commit in a bound "
 
1420
                                 "branch. Such commits are not pushed to "
 
1421
                                 "the master branch until a normal commit "
 
1422
                                 "is performed."
 
1423
                            ),
1269
1424
                     ]
1270
1425
    aliases = ['ci', 'checkin']
1271
1426
 
1272
1427
    def run(self, message=None, file=None, verbose=True, selected_list=None,
1273
 
            unchanged=False, strict=False):
 
1428
            unchanged=False, strict=False, local=False):
1274
1429
        from bzrlib.errors import (PointlessCommit, ConflictsInTree,
1275
1430
                StrictCommitFailed)
1276
1431
        from bzrlib.msgeditor import edit_commit_message, \
1277
1432
                make_commit_message_template
1278
 
        from bzrlib.status import show_status
1279
1433
        from tempfile import TemporaryFile
1280
1434
        import codecs
1281
1435
 
1288
1442
        # TODO: if the commit *does* happen to fail, then save the commit 
1289
1443
        # message to a temporary file where it can be recovered
1290
1444
        tree, selected_list = tree_files(selected_list)
 
1445
        if local and not tree.branch.get_bound_location():
 
1446
            raise errors.LocalRequiresBoundBranch()
1291
1447
        if message is None and not file:
1292
1448
            template = make_commit_message_template(tree, selected_list)
1293
1449
            message = edit_commit_message(template)
1306
1462
            
1307
1463
        try:
1308
1464
            tree.commit(message, specific_files=selected_list,
1309
 
                        allow_pointless=unchanged, strict=strict)
 
1465
                        allow_pointless=unchanged, strict=strict, local=local)
1310
1466
        except PointlessCommit:
1311
1467
            # FIXME: This should really happen before the file is read in;
1312
1468
            # perhaps prepare the commit; get the message; then actually commit
1318
1474
        except StrictCommitFailed:
1319
1475
            raise BzrCommandError("Commit refused because there are unknown "
1320
1476
                                  "files in the working tree.")
 
1477
        except errors.BoundBranchOutOfDate, e:
 
1478
            raise BzrCommandError(str(e)
 
1479
                                  + ' Either unbind, update, or'
 
1480
                                    ' pass --local to commit.')
 
1481
 
1321
1482
        note('Committed revision %d.' % (tree.branch.revno(),))
1322
1483
 
1323
1484
 
1357
1518
 
1358
1519
        if c.needs_write:
1359
1520
            c.write()
1360
 
            
 
1521
 
 
1522
 
 
1523
def get_format_type(typestring):
 
1524
    """Parse and return a format specifier."""
 
1525
    if typestring == "metadir":
 
1526
        return bzrdir.BzrDirMetaFormat1()
 
1527
    if typestring == "knit":
 
1528
        format = bzrdir.BzrDirMetaFormat1()
 
1529
        format.repository_format = bzrlib.repository.RepositoryFormatKnit1()
 
1530
        return format
 
1531
    msg = "No known bzr-dir format %s. Supported types are: metadir\n" %\
 
1532
        (typestring)
 
1533
    raise BzrCommandError(msg)
1361
1534
 
1362
1535
 
1363
1536
class cmd_upgrade(Command):
1368
1541
    during other operations to upgrade.
1369
1542
    """
1370
1543
    takes_args = ['url?']
1371
 
 
1372
 
    def run(self, url='.'):
 
1544
    takes_options = [
 
1545
                     Option('format', 
 
1546
                            help='Upgrade to a specific format rather than the'
 
1547
                                 ' current default format. Currently this '
 
1548
                                 ' option only accepts =metadir',
 
1549
                            type=get_format_type),
 
1550
                    ]
 
1551
 
 
1552
 
 
1553
    def run(self, url='.', format=None):
1373
1554
        from bzrlib.upgrade import upgrade
1374
 
        upgrade(url)
 
1555
        upgrade(url, format)
1375
1556
 
1376
1557
 
1377
1558
class cmd_whoami(Command):
1610
1791
 
1611
1792
    def run(self, branch=None, revision=None, force=False, merge_type=None,
1612
1793
            show_base=False, reprocess=False):
1613
 
        from bzrlib._merge_core import ApplyMerge3
1614
1794
        if merge_type is None:
1615
 
            merge_type = ApplyMerge3
 
1795
            merge_type = Merge3Merger
1616
1796
        if branch is None:
1617
1797
            branch = WorkingTree.open_containing(u'.')[0].branch.get_parent()
1618
1798
            if branch is None:
1641
1821
        try:
1642
1822
            conflict_count = merge(other, base, check_clean=(not force),
1643
1823
                                   merge_type=merge_type, reprocess=reprocess,
1644
 
                                   show_base=show_base)
 
1824
                                   show_base=show_base, 
 
1825
                                   pb=bzrlib.ui.ui_factory.progress_bar())
1645
1826
            if conflict_count != 0:
1646
1827
                return 1
1647
1828
            else:
1667
1848
    def run(self, file_list=None, merge_type=None, show_base=False,
1668
1849
            reprocess=False):
1669
1850
        from bzrlib.merge import merge_inner, transform_tree
1670
 
        from bzrlib._merge_core import ApplyMerge3
1671
1851
        if merge_type is None:
1672
 
            merge_type = ApplyMerge3
 
1852
            merge_type = Merge3Merger
1673
1853
        tree, file_list = tree_files(file_list)
1674
1854
        tree.lock_write()
1675
1855
        try:
1688
1868
                interesting_ids = set()
1689
1869
                for filename in file_list:
1690
1870
                    file_id = tree.path2id(filename)
 
1871
                    if file_id is None:
 
1872
                        raise NotVersionedError(filename)
1691
1873
                    interesting_ids.add(file_id)
1692
1874
                    if tree.kind(file_id) != "directory":
1693
1875
                        continue
1694
1876
                    
1695
1877
                    for name, ie in tree.inventory.iter_entries(file_id):
1696
1878
                        interesting_ids.add(ie.file_id)
1697
 
            transform_tree(tree, tree.branch.basis_tree(), interesting_ids)
 
1879
            transform_tree(tree, tree.basis_tree(), interesting_ids)
1698
1880
            if file_list is None:
1699
1881
                restore_files = list(tree.iter_conflicts())
1700
1882
            else:
1745
1927
        else:
1746
1928
            rev_id = revision[0].in_history(tree.branch).rev_id
1747
1929
        tree.revert(file_list, tree.branch.repository.revision_tree(rev_id),
1748
 
                    not no_backup)
 
1930
                    not no_backup, bzrlib.ui.ui_factory.progress_bar())
1749
1931
 
1750
1932
 
1751
1933
class cmd_assert_fail(Command):
1759
1941
    """Show help on a command or other topic.
1760
1942
 
1761
1943
    For a list of all available commands, say 'bzr help commands'."""
1762
 
    takes_options = ['long']
 
1944
    takes_options = [Option('long', 'show help on all commands')]
1763
1945
    takes_args = ['topic?']
1764
1946
    aliases = ['?']
1765
1947
    
1809
1991
                            'Display changes in the local branch only'),
1810
1992
                     Option('theirs-only', 
1811
1993
                            'Display changes in the remote branch only'), 
 
1994
                     'log-format',
1812
1995
                     'line',
1813
1996
                     'long', 
1814
1997
                     'short',
1817
2000
                     ]
1818
2001
 
1819
2002
    def run(self, other_branch=None, reverse=False, mine_only=False,
1820
 
            theirs_only=False, long=True, short=False, line=False, 
 
2003
            theirs_only=False, log_format=None, long=False, short=False, line=False, 
1821
2004
            show_ids=False, verbose=False):
1822
2005
        from bzrlib.missing import find_unmerged, iter_log_data
1823
2006
        from bzrlib.log import log_formatter
1830
2013
            print "Using last location: " + local_branch.get_parent()
1831
2014
        remote_branch = bzrlib.branch.Branch.open(other_branch)
1832
2015
        local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
1833
 
        log_format = get_log_format(long=long, short=short, line=line)
 
2016
        if (log_format == None):
 
2017
            default = bzrlib.config.BranchConfig(local_branch).log_format()
 
2018
            log_format = get_log_format(long=long, short=short, line=line, default=default)
1834
2019
        lf = log_formatter(log_format, sys.stdout,
1835
2020
                           show_ids=show_ids,
1836
2021
                           show_timezone='original')
1944
2129
    # TODO be able to replace existing ones.
1945
2130
 
1946
2131
    hidden = True # is this right ?
1947
 
    takes_args = ['revision_id?']
 
2132
    takes_args = ['revision_id*']
1948
2133
    takes_options = ['revision']
1949
2134
    
1950
 
    def run(self, revision_id=None, revision=None):
 
2135
    def run(self, revision_id_list=None, revision=None):
1951
2136
        import bzrlib.config as config
1952
2137
        import bzrlib.gpg as gpg
1953
 
        if revision_id is not None and revision is not None:
 
2138
        if revision_id_list is not None and revision is not None:
1954
2139
            raise BzrCommandError('You can only supply one of revision_id or --revision')
1955
 
        if revision_id is None and revision is None:
 
2140
        if revision_id_list is None and revision is None:
1956
2141
            raise BzrCommandError('You must supply either --revision or a revision_id')
1957
2142
        b = WorkingTree.open_containing(u'.')[0].branch
1958
2143
        gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1959
 
        if revision_id is not None:
1960
 
            b.repository.sign_revision(revision_id, gpg_strategy)
 
2144
        if revision_id_list is not None:
 
2145
            for revision_id in revision_id_list:
 
2146
                b.repository.sign_revision(revision_id, gpg_strategy)
1961
2147
        elif revision is not None:
1962
2148
            if len(revision) == 1:
1963
2149
                revno, rev_id = revision[0].in_history(b)
1979
2165
                raise BzrCommandError('Please supply either one revision, or a range.')
1980
2166
 
1981
2167
 
 
2168
class cmd_bind(Command):
 
2169
    """Bind the current branch to a master branch.
 
2170
 
 
2171
    After binding, commits must succeed on the master branch
 
2172
    before they are executed on the local one.
 
2173
    """
 
2174
 
 
2175
    takes_args = ['location']
 
2176
    takes_options = []
 
2177
 
 
2178
    def run(self, location=None):
 
2179
        b, relpath = Branch.open_containing(u'.')
 
2180
        b_other = Branch.open(location)
 
2181
        try:
 
2182
            b.bind(b_other)
 
2183
        except DivergedBranches:
 
2184
            raise BzrCommandError('These branches have diverged.'
 
2185
                                  ' Try merging, and then bind again.')
 
2186
 
 
2187
 
 
2188
class cmd_unbind(Command):
 
2189
    """Bind the current branch to its parent.
 
2190
 
 
2191
    After unbinding, the local branch is considered independent.
 
2192
    """
 
2193
 
 
2194
    takes_args = []
 
2195
    takes_options = []
 
2196
 
 
2197
    def run(self):
 
2198
        b, relpath = Branch.open_containing(u'.')
 
2199
        if not b.unbind():
 
2200
            raise BzrCommandError('Local branch is not bound')
 
2201
 
 
2202
 
1982
2203
class cmd_uncommit(bzrlib.commands.Command):
1983
2204
    """Remove the last committed revision.
1984
2205
 
1992
2213
    
1993
2214
    In the future, uncommit will create a changeset, which can then
1994
2215
    be re-applied.
 
2216
    """
1995
2217
 
1996
 
    TODO: jam 20060108 Add an option to allow uncommit to remove unreferenced
1997
 
              information in 'branch-as-repostory' branches.
1998
 
    TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
1999
 
              information in shared branches as well.
2000
 
    """
 
2218
    # TODO: jam 20060108 Add an option to allow uncommit to remove
 
2219
    # unreferenced information in 'branch-as-repostory' branches.
 
2220
    # TODO: jam 20060108 Add the ability for uncommit to remove unreferenced
 
2221
    # information in shared branches as well.
2001
2222
    takes_options = ['verbose', 'revision',
2002
2223
                    Option('dry-run', help='Don\'t actually make changes'),
2003
2224
                    Option('force', help='Say yes to all questions.')]
2014
2235
 
2015
2236
        if location is None:
2016
2237
            location = u'.'
2017
 
        b, relpath = Branch.open_containing(location)
 
2238
        control, relpath = bzrdir.BzrDir.open_containing(location)
 
2239
        b = control.open_branch()
 
2240
        try:
 
2241
            tree = control.open_workingtree()
 
2242
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
2243
            tree = None
2018
2244
 
2019
2245
        if revision is None:
2020
2246
            revno = b.revno()
2041
2267
                    print 'Canceled'
2042
2268
                    return 0
2043
2269
 
2044
 
        uncommit(b, dry_run=dry_run, verbose=verbose,
 
2270
        uncommit(b, tree=tree, dry_run=dry_run, verbose=verbose,
2045
2271
                revno=revno)
2046
2272
 
2047
2273
 
 
2274
class cmd_break_lock(Command):
 
2275
    """Break a dead lock on a repository, branch or working directory.
 
2276
 
 
2277
    CAUTION: Locks should only be broken when you are sure that the process
 
2278
    holding the lock has been stopped.
 
2279
    
 
2280
    example:
 
2281
        bzr break-lock .
 
2282
    """
 
2283
    takes_args = ['location']
 
2284
    takes_options = [Option('show',
 
2285
                            help="just show information on the lock, " \
 
2286
                                 "don't break it"),
 
2287
                    ]
 
2288
    def run(self, location, show=False):
 
2289
        d = bzrdir.BzrDir.open(location)
 
2290
        repo = d.open_repository()
 
2291
        if not repo.is_locked():
 
2292
            raise errors.ObjectNotLocked(repo)
 
2293
 
 
2294
 
 
2295
# command-line interpretation helper for merge-related commands
2048
2296
def merge(other_revision, base_revision,
2049
2297
          check_clean=True, ignore_zero=False,
2050
 
          this_dir=None, backup_files=False, merge_type=ApplyMerge3,
2051
 
          file_list=None, show_base=False, reprocess=False):
 
2298
          this_dir=None, backup_files=False, merge_type=Merge3Merger,
 
2299
          file_list=None, show_base=False, reprocess=False,
 
2300
          pb=DummyProgress()):
2052
2301
    """Merge changes into a tree.
2053
2302
 
2054
2303
    base_revision
2076
2325
    clients might prefer to call merge.merge_inner(), which has less magic 
2077
2326
    behavior.
2078
2327
    """
2079
 
    from bzrlib.merge import Merger, _MergeConflictHandler
 
2328
    from bzrlib.merge import Merger
2080
2329
    if this_dir is None:
2081
2330
        this_dir = u'.'
2082
2331
    this_tree = WorkingTree.open_containing(this_dir)[0]
2083
 
    if show_base and not merge_type is ApplyMerge3:
 
2332
    if show_base and not merge_type is Merge3Merger:
2084
2333
        raise BzrCommandError("Show-base is not supported for this merge"
2085
2334
                              " type. %s" % merge_type)
2086
 
    if reprocess and not merge_type is ApplyMerge3:
 
2335
    if reprocess and not merge_type is Merge3Merger:
2087
2336
        raise BzrCommandError("Reprocess is not supported for this merge"
2088
2337
                              " type. %s" % merge_type)
2089
2338
    if reprocess and show_base:
2090
2339
        raise BzrCommandError("Cannot reprocess and show base.")
2091
 
    merger = Merger(this_tree.branch, this_tree=this_tree)
 
2340
    merger = Merger(this_tree.branch, this_tree=this_tree, pb=pb)
2092
2341
    merger.check_basis(check_clean)
2093
2342
    merger.set_other(other_revision)
2094
2343
    merger.set_base(base_revision)
2100
2349
    merger.set_interesting_files(file_list)
2101
2350
    merger.show_base = show_base 
2102
2351
    merger.reprocess = reprocess
2103
 
    merger.conflict_handler = _MergeConflictHandler(merger.this_tree, 
2104
 
                                                    merger.base_tree, 
2105
 
                                                    merger.other_tree,
2106
 
                                                    ignore_zero=ignore_zero)
2107
2352
    conflicts = merger.do_merge()
2108
2353
    merger.set_pending()
2109
2354
    return conflicts
2114
2359
# we do need to load at least some information about them to know of 
2115
2360
# aliases.
2116
2361
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
 
2362
from bzrlib.sign_my_commits import cmd_sign_my_commits