~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2006-02-18 02:33:47 UTC
  • mfrom: (1534.1.24 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20060218023347-0952c65f668bfd68
Merge Robert Collins integration.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
26
import bzrlib.branch
 
27
from bzrlib.branch import Branch
 
28
import bzrlib.bzrdir as bzrdir
25
29
from bzrlib._merge_core import ApplyMerge3
26
30
from bzrlib.commands import Command, display_command
27
 
from bzrlib.branch import Branch
28
31
from bzrlib.revision import common_ancestor
29
32
import bzrlib.errors as errors
30
33
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError, 
392
395
    If you want to forget your local changes and just update your branch to
393
396
    match the remote one, use --overwrite.
394
397
    """
395
 
    takes_options = ['remember', 'overwrite', 'verbose']
 
398
    takes_options = ['remember', 'overwrite', 'revision', 'verbose']
396
399
    takes_args = ['location?']
397
400
 
398
 
    def run(self, location=None, remember=False, overwrite=False, verbose=False):
399
 
        from shutil import rmtree
400
 
        import errno
 
401
    def run(self, location=None, remember=False, overwrite=False, revision=None, verbose=False):
401
402
        # FIXME: too much stuff is in the command class        
402
403
        tree_to = WorkingTree.open_containing(u'.')[0]
403
404
        stored_loc = tree_to.branch.get_parent()
411
412
        br_from = Branch.open(location)
412
413
        br_to = tree_to.branch
413
414
 
 
415
        if revision is None:
 
416
            rev_id = None
 
417
        elif len(revision) == 1:
 
418
            rev_id = revision[0].in_history(br_from).rev_id
 
419
        else:
 
420
            raise BzrCommandError('bzr pull --revision takes one value.')
 
421
 
414
422
        old_rh = br_to.revision_history()
415
 
        count = tree_to.pull(br_from, overwrite)
 
423
        count = tree_to.pull(br_from, overwrite, rev_id)
416
424
 
417
425
        if br_to.get_parent() is None or remember:
418
426
            br_to.set_parent(location)
459
467
            create_prefix=False, verbose=False):
460
468
        # FIXME: Way too big!  Put this into a function called from the
461
469
        # command.
462
 
        import errno
463
 
        from shutil import rmtree
464
470
        from bzrlib.transport import get_transport
465
471
        
466
472
        tree_from = WorkingTree.open_containing(u'.')[0]
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
                dir = br_from.bzrdir.sprout(to_location, revision_id, basis_dir)
 
600
                branch = dir.open_branch()
593
601
            except bzrlib.errors.NoSuchRevision:
594
602
                rmtree(to_location)
595
603
                msg = "The branch %s has no revision %s." % (from_location, revision[0])
598
606
                rmtree(to_location)
599
607
                msg = "The branch %s cannot be used as a --basis"
600
608
                raise BzrCommandError(msg)
601
 
            branch = Branch.open(to_location)
602
609
            if name:
603
610
                branch.control_files.put_utf8('branch-name', name)
604
611
 
607
614
            br_from.unlock()
608
615
 
609
616
 
 
617
class cmd_checkout(Command):
 
618
    """Create a new checkout of an existing branch.
 
619
 
 
620
    If the TO_LOCATION is omitted, the last component of the BRANCH_LOCATION will
 
621
    be used.  In other words, "checkout ../foo/bar" will attempt to create ./bar.
 
622
 
 
623
    To retrieve the branch as of a particular revision, supply the --revision
 
624
    parameter, as in "checkout foo/bar -r 5". Note that this will be immediately
 
625
    out of date [so you cannot commit] but it may be useful (i.e. to examine old
 
626
    code.)
 
627
 
 
628
    --basis is to speed up checking out from remote branches.  When specified, it
 
629
    uses the inventory and file contents from the basis branch in preference to the
 
630
    branch being checked out. [Not implemented yet.]
 
631
    """
 
632
    takes_args = ['branch_location', 'to_location?']
 
633
    takes_options = ['revision'] # , 'basis']
 
634
 
 
635
    def run(self, branch_location, to_location=None, revision=None, basis=None):
 
636
        if revision is None:
 
637
            revision = [None]
 
638
        elif len(revision) > 1:
 
639
            raise BzrCommandError(
 
640
                'bzr checkout --revision takes exactly 1 revision value')
 
641
        source = Branch.open(branch_location)
 
642
        if len(revision) == 1 and revision[0] is not None:
 
643
            revision_id = revision[0].in_history(source)[1]
 
644
        else:
 
645
            revision_id = None
 
646
        if to_location is None:
 
647
            to_location = os.path.basename(branch_location.rstrip("/\\"))
 
648
        try:
 
649
            os.mkdir(to_location)
 
650
        except OSError, e:
 
651
            if e.errno == errno.EEXIST:
 
652
                raise BzrCommandError('Target directory "%s" already'
 
653
                                      ' exists.' % to_location)
 
654
            if e.errno == errno.ENOENT:
 
655
                raise BzrCommandError('Parent of "%s" does not exist.' %
 
656
                                      to_location)
 
657
            else:
 
658
                raise
 
659
        checkout = bzrdir.BzrDirMetaFormat1().initialize(to_location)
 
660
        bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
 
661
        checkout.create_workingtree(revision_id)
 
662
 
 
663
 
610
664
class cmd_renames(Command):
611
665
    """Show list of renamed files.
612
666
    """
618
672
    @display_command
619
673
    def run(self, dir=u'.'):
620
674
        tree = WorkingTree.open_containing(dir)[0]
621
 
        old_inv = tree.branch.basis_tree().inventory
 
675
        old_inv = tree.basis_tree().inventory
622
676
        new_inv = tree.read_working_inventory()
623
677
 
624
678
        renames = list(bzrlib.tree.find_renames(old_inv, new_inv))
627
681
            print "%s => %s" % (old_name, new_name)        
628
682
 
629
683
 
 
684
class cmd_update(Command):
 
685
    """Update a tree to have the latest code committed to its branch.
 
686
    
 
687
    This will perform a merge into the working tree, and may generate
 
688
    conflicts. If you have any uncommitted changes, you will still 
 
689
    need to commit them after the update.
 
690
    """
 
691
    takes_args = ['dir?']
 
692
 
 
693
    def run(self, dir='.'):
 
694
        tree = WorkingTree.open_containing(dir)[0]
 
695
        tree.lock_write()
 
696
        try:
 
697
            if tree.last_revision() == tree.branch.last_revision():
 
698
                note("Tree is up to date.")
 
699
                return
 
700
            conflicts = tree.update()
 
701
            note('Updated to revision %d.' %
 
702
                 (tree.branch.revision_id_to_revno(tree.last_revision()),))
 
703
            if conflicts != 0:
 
704
                return 1
 
705
            else:
 
706
                return 0
 
707
        finally:
 
708
            tree.unlock()
 
709
 
 
710
 
630
711
class cmd_info(Command):
631
712
    """Show statistical information about a branch."""
632
713
    takes_args = ['branch?']
633
714
    
634
715
    @display_command
635
716
    def run(self, branch=None):
636
 
        import info
637
 
        b = WorkingTree.open_containing(branch)[0].branch
638
 
        info.show_info(b)
 
717
        import bzrlib.info
 
718
        bzrlib.info.show_bzrdir_info(bzrdir.BzrDir.open_containing(branch)[0])
639
719
 
640
720
 
641
721
class cmd_remove(Command):
708
788
        tree = WorkingTree.open_containing(u'.')[0]
709
789
        b = tree.branch
710
790
        # FIXME. should be tree.last_revision
711
 
        for revision_id in b.get_ancestry(b.last_revision()):
 
791
        for revision_id in b.repository.get_ancestry(b.last_revision()):
712
792
            print revision_id
713
793
 
714
794
 
738
818
            # locations if the user supplies an extended path
739
819
            if not os.path.exists(location):
740
820
                os.mkdir(location)
741
 
        WorkingTree.create_standalone(location)
 
821
        bzrdir.BzrDir.create_standalone_workingtree(location)
742
822
 
743
823
 
744
824
class cmd_diff(Command):
820
900
    @display_command
821
901
    def run(self, show_ids=False):
822
902
        tree = WorkingTree.open_containing(u'.')[0]
823
 
        old = tree.branch.basis_tree()
 
903
        old = tree.basis_tree()
824
904
        for path, ie in old.inventory.iter_entries():
825
905
            if not tree.has_id(ie.file_id):
826
906
                if show_ids:
837
917
        from bzrlib.delta import compare_trees
838
918
 
839
919
        tree = WorkingTree.open_containing(u'.')[0]
840
 
        td = compare_trees(tree.branch.basis_tree(), tree)
 
920
        td = compare_trees(tree.basis_tree(), tree)
841
921
 
842
922
        for path, id, kind, text_modified, meta_modified in td.modified:
843
923
            print path
850
930
    @display_command
851
931
    def run(self):
852
932
        wt = WorkingTree.open_containing(u'.')[0]
853
 
        basis_inv = wt.branch.basis_tree().inventory
 
933
        basis_inv = wt.basis_tree().inventory
854
934
        inv = wt.inventory
855
935
        for file_id in inv:
856
936
            if file_id in basis_inv:
890
970
                            help='show from oldest to newest'),
891
971
                     'timezone', 'verbose', 
892
972
                     'show-ids', 'revision',
 
973
                     'log-format',
893
974
                     'line', 'long', 
894
975
                     Option('message',
895
976
                            help='show revisions whose message matches this regexp',
902
983
            show_ids=False,
903
984
            forward=False,
904
985
            revision=None,
 
986
            log_format=None,
905
987
            message=None,
906
988
            long=False,
907
989
            short=False,
912
994
            "invalid message argument %r" % message
913
995
        direction = (forward and 'forward') or 'reverse'
914
996
        
 
997
        # log everything
 
998
        file_id = None
915
999
        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())
 
1000
            # find the file id to log:
 
1001
 
 
1002
            dir, fp = bzrdir.BzrDir.open_containing(filename)
 
1003
            b = dir.open_branch()
929
1004
            if fp != '':
 
1005
                try:
 
1006
                    # might be a tree:
 
1007
                    inv = dir.open_workingtree().inventory
 
1008
                except (errors.NotBranchError, errors.NotLocalUrl):
 
1009
                    # either no tree, or is remote.
 
1010
                    inv = b.basis_tree().inventory
930
1011
                file_id = inv.path2id(fp)
931
 
            else:
932
 
                file_id = None  # points to branch root
933
1012
        else:
934
 
            tree, relpath = WorkingTree.open_containing(u'.')
935
 
            b = tree.branch
936
 
            file_id = None
 
1013
            # local dir only
 
1014
            # FIXME ? log the current subdir only RBC 20060203 
 
1015
            dir, relpath = bzrdir.BzrDir.open_containing('.')
 
1016
            b = dir.open_branch()
937
1017
 
938
1018
        if revision is None:
939
1019
            rev1 = None
941
1021
        elif len(revision) == 1:
942
1022
            rev1 = rev2 = revision[0].in_history(b).revno
943
1023
        elif len(revision) == 2:
944
 
            rev1 = revision[0].in_history(b).revno
945
 
            rev2 = revision[1].in_history(b).revno
 
1024
            if revision[0].spec is None:
 
1025
                # missing begin-range means first revision
 
1026
                rev1 = 1
 
1027
            else:
 
1028
                rev1 = revision[0].in_history(b).revno
 
1029
 
 
1030
            if revision[1].spec is None:
 
1031
                # missing end-range means last known revision
 
1032
                rev2 = b.revno()
 
1033
            else:
 
1034
                rev2 = revision[1].in_history(b).revno
946
1035
        else:
947
1036
            raise BzrCommandError('bzr log --revision takes one or two values.')
948
1037
 
958
1047
        # in e.g. the default C locale.
959
1048
        outf = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
960
1049
 
961
 
        log_format = get_log_format(long=long, short=short, line=line)
 
1050
        if (log_format == None):
 
1051
            default = bzrlib.config.BranchConfig(b).log_format()
 
1052
            log_format = get_log_format(long=long, short=short, line=line, default=default)
 
1053
 
962
1054
        lf = log_formatter(log_format,
963
1055
                           show_ids=show_ids,
964
1056
                           to_file=outf,
973
1065
                 end_revision=rev2,
974
1066
                 search=message)
975
1067
 
 
1068
 
976
1069
def get_log_format(long=False, short=False, line=False, default='long'):
977
1070
    log_format = default
978
1071
    if long:
1170
1263
 
1171
1264
    Note: export of tree with non-ascii filenames to zip is not supported.
1172
1265
 
1173
 
    Supported formats       Autodetected by extension
1174
 
    -----------------       -------------------------
 
1266
     Supported formats       Autodetected by extension
 
1267
     -----------------       -------------------------
1175
1268
         dir                            -
1176
1269
         tar                          .tar
1177
1270
         tbz2                    .tar.bz2, .tbz2
1357
1450
 
1358
1451
        if c.needs_write:
1359
1452
            c.write()
1360
 
            
 
1453
 
 
1454
 
 
1455
def get_format_type(typestring):
 
1456
    """Parse and return a format specifier."""
 
1457
    if typestring == "metadir":
 
1458
        return bzrdir.BzrDirMetaFormat1
 
1459
    msg = "No known bzr-dir format %s. Supported types are: metadir\n" %\
 
1460
        (typestring)
 
1461
    raise BzrCommandError(msg)
1361
1462
 
1362
1463
 
1363
1464
class cmd_upgrade(Command):
1368
1469
    during other operations to upgrade.
1369
1470
    """
1370
1471
    takes_args = ['url?']
1371
 
 
1372
 
    def run(self, url='.'):
 
1472
    takes_options = [
 
1473
                     Option('format', 
 
1474
                            help='Upgrade to a specific format rather than the'
 
1475
                                 ' current default format. Currently this '
 
1476
                                 ' option only accepts =metadir',
 
1477
                            type=get_format_type),
 
1478
                    ]
 
1479
 
 
1480
 
 
1481
    def run(self, url='.', format=None):
1373
1482
        from bzrlib.upgrade import upgrade
1374
 
        upgrade(url)
 
1483
        upgrade(url, format)
1375
1484
 
1376
1485
 
1377
1486
class cmd_whoami(Command):
1393
1502
 
1394
1503
 
1395
1504
class cmd_nick(Command):
1396
 
    """\
1397
 
    Print or set the branch nickname.  
 
1505
    """Print or set the branch nickname.  
 
1506
 
1398
1507
    If unset, the tree root directory name is used as the nickname
1399
1508
    To print the current nickname, execute with no argument.  
1400
1509
    """
1556
1665
        last1 = branch1.last_revision()
1557
1666
        last2 = branch2.last_revision()
1558
1667
 
1559
 
        source = MultipleRevisionSources(branch1, branch2)
 
1668
        source = MultipleRevisionSources(branch1.repository, 
 
1669
                                         branch2.repository)
1560
1670
        
1561
1671
        base_rev_id = common_ancestor(last1, last2, source)
1562
1672
 
1693
1803
                    
1694
1804
                    for name, ie in tree.inventory.iter_entries(file_id):
1695
1805
                        interesting_ids.add(ie.file_id)
1696
 
            transform_tree(tree, tree.branch.basis_tree(), interesting_ids)
 
1806
            transform_tree(tree, tree.basis_tree(), interesting_ids)
1697
1807
            if file_list is None:
1698
1808
                restore_files = list(tree.iter_conflicts())
1699
1809
            else:
1758
1868
    """Show help on a command or other topic.
1759
1869
 
1760
1870
    For a list of all available commands, say 'bzr help commands'."""
1761
 
    takes_options = ['long']
 
1871
    takes_options = [Option('long', 'show help on all commands')]
1762
1872
    takes_args = ['topic?']
1763
1873
    aliases = ['?']
1764
1874
    
1808
1918
                            'Display changes in the local branch only'),
1809
1919
                     Option('theirs-only', 
1810
1920
                            'Display changes in the remote branch only'), 
 
1921
                     'log-format',
1811
1922
                     'line',
1812
1923
                     'long', 
1813
1924
                     'short',
1816
1927
                     ]
1817
1928
 
1818
1929
    def run(self, other_branch=None, reverse=False, mine_only=False,
1819
 
            theirs_only=False, long=True, short=False, line=False, 
 
1930
            theirs_only=False, log_format=None, long=False, short=False, line=False, 
1820
1931
            show_ids=False, verbose=False):
1821
1932
        from bzrlib.missing import find_unmerged, iter_log_data
1822
1933
        from bzrlib.log import log_formatter
1829
1940
            print "Using last location: " + local_branch.get_parent()
1830
1941
        remote_branch = bzrlib.branch.Branch.open(other_branch)
1831
1942
        local_extra, remote_extra = find_unmerged(local_branch, remote_branch)
1832
 
        log_format = get_log_format(long=long, short=short, line=line)
 
1943
        if (log_format == None):
 
1944
            default = bzrlib.config.BranchConfig(local_branch).log_format()
 
1945
            log_format = get_log_format(long=long, short=short, line=line, default=default)
1833
1946
        lf = log_formatter(log_format, sys.stdout,
1834
1947
                           show_ids=show_ids,
1835
1948
                           show_timezone='original')
1943
2056
    # TODO be able to replace existing ones.
1944
2057
 
1945
2058
    hidden = True # is this right ?
1946
 
    takes_args = ['revision_id?']
 
2059
    takes_args = ['revision_id*']
1947
2060
    takes_options = ['revision']
1948
2061
    
1949
 
    def run(self, revision_id=None, revision=None):
 
2062
    def run(self, revision_id_list=None, revision=None):
1950
2063
        import bzrlib.config as config
1951
2064
        import bzrlib.gpg as gpg
1952
 
        if revision_id is not None and revision is not None:
 
2065
        if revision_id_list is not None and revision is not None:
1953
2066
            raise BzrCommandError('You can only supply one of revision_id or --revision')
1954
 
        if revision_id is None and revision is None:
 
2067
        if revision_id_list is None and revision is None:
1955
2068
            raise BzrCommandError('You must supply either --revision or a revision_id')
1956
2069
        b = WorkingTree.open_containing(u'.')[0].branch
1957
2070
        gpg_strategy = gpg.GPGStrategy(config.BranchConfig(b))
1958
 
        if revision_id is not None:
1959
 
            b.repository.sign_revision(revision_id, gpg_strategy)
 
2071
        if revision_id_list is not None:
 
2072
            for revision_id in revision_id_list:
 
2073
                b.repository.sign_revision(revision_id, gpg_strategy)
1960
2074
        elif revision is not None:
1961
2075
            if len(revision) == 1:
1962
2076
                revno, rev_id = revision[0].in_history(b)
2113
2227
# we do need to load at least some information about them to know of 
2114
2228
# aliases.
2115
2229
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore
 
2230
from bzrlib.sign_my_commits import cmd_sign_my_commits