~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

[merge] robertc's integration, updated tests to check for retcode=3

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
from bzrlib import BZRDIR
27
27
from bzrlib.commands import Command, display_command
28
28
from bzrlib.branch import Branch
29
 
from bzrlib.errors import BzrError, BzrCheckError, BzrCommandError, NotBranchError
30
 
from bzrlib.errors import DivergedBranches, NoSuchFile, NoWorkingTree
 
29
from bzrlib.revision import common_ancestor
31
30
import bzrlib.errors as errors
 
31
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError, 
 
32
                           NotBranchError, DivergedBranches, NotConflicted,
 
33
                           NoSuchFile, NoWorkingTree)
32
34
from bzrlib.option import Option
33
35
from bzrlib.revisionspec import RevisionSpec
34
36
import bzrlib.trace
37
39
 
38
40
 
39
41
def branch_files(file_list, default_branch='.'):
 
42
    try:
 
43
        return inner_branch_files(file_list, default_branch)
 
44
    except NotBranchError:
 
45
        raise BzrCommandError("%s is not in the same branch as %s" %
 
46
                             (filename, file_list[0]))
 
47
 
 
48
def inner_branch_files(file_list, default_branch='.'):
40
49
    """\
41
50
    Return a branch and list of branch-relative paths.
42
51
    If supplied file_list is empty or None, the branch default will be used,
53
62
    tree = WorkingTree(b.base, b)
54
63
    new_list = []
55
64
    for filename in file_list:
56
 
        try:
57
 
            new_list.append(tree.relpath(filename))
58
 
        except NotBranchError:
59
 
            raise BzrCommandError("%s is not in the same branch as %s" % 
60
 
                                  (filename, file_list[0]))
 
65
        new_list.append(tree.relpath(filename))
61
66
    return b, new_list
62
67
 
63
68
 
107
112
    that revision, or between two revisions if two are provided.
108
113
    """
109
114
    
110
 
    # XXX: FIXME: bzr status should accept a -r option to show changes
111
 
    # relative to a revision, or between revisions
112
 
 
113
115
    # TODO: --no-recurse, --recurse options
114
116
    
115
117
    takes_args = ['file*']
116
 
    takes_options = ['all', 'show-ids']
 
118
    takes_options = ['all', 'show-ids', 'revision']
117
119
    aliases = ['st', 'stat']
118
120
    
119
121
    @display_command
238
240
        
239
241
        for d in dir_list:
240
242
            os.mkdir(d)
241
 
            if not b:
242
 
                b = Branch.open_containing(d)[0]
243
 
            b.add([d])
 
243
            b, dd = Branch.open_containing(d)
 
244
            b.add([dd])
244
245
            print 'added', d
245
246
 
246
247
 
364
365
    If you want to forget your local changes and just update your branch to
365
366
    match the remote one, use --overwrite.
366
367
    """
367
 
    takes_options = ['remember', 'overwrite']
 
368
    takes_options = ['remember', 'overwrite', 'verbose']
368
369
    takes_args = ['location?']
369
370
 
370
 
    def run(self, location=None, remember=False, overwrite=False):
 
371
    def run(self, location=None, remember=False, overwrite=False, verbose=False):
371
372
        from bzrlib.merge import merge
372
373
        from shutil import rmtree
373
374
        import errno
388
389
                location = stored_loc
389
390
        br_from = Branch.open(location)
390
391
        try:
 
392
            old_rh = br_to.revision_history()
391
393
            br_to.working_tree().pull(br_from, overwrite)
392
394
        except DivergedBranches:
393
395
            raise BzrCommandError("These branches have diverged."
395
397
        if br_to.get_parent() is None or remember:
396
398
            br_to.set_parent(location)
397
399
 
 
400
        if verbose:
 
401
            new_rh = br_to.revision_history()
 
402
            if old_rh != new_rh:
 
403
                # Something changed
 
404
                from bzrlib.log import show_changed_revisions
 
405
                show_changed_revisions(br_to, old_rh, new_rh)
 
406
 
398
407
 
399
408
class cmd_push(Command):
400
409
    """Push this branch into another branch.
426
435
    takes_args = ['location?']
427
436
 
428
437
    def run(self, location=None, remember=False, overwrite=False,
429
 
            create_prefix=False):
 
438
            create_prefix=False, verbose=False):
430
439
        import errno
431
440
        from shutil import rmtree
432
441
        from bzrlib.transport import get_transport
469
478
            NoSuchFile
470
479
            br_to = Branch.initialize(location)
471
480
        try:
 
481
            old_rh = br_to.revision_history()
472
482
            br_to.pull(br_from, overwrite)
473
483
        except DivergedBranches:
474
484
            raise BzrCommandError("These branches have diverged."
476
486
        if br_from.get_push_location() is None or remember:
477
487
            br_from.set_push_location(location)
478
488
 
 
489
        if verbose:
 
490
            new_rh = br_to.revision_history()
 
491
            if old_rh != new_rh:
 
492
                # Something changed
 
493
                from bzrlib.log import show_changed_revisions
 
494
                show_changed_revisions(br_to, old_rh, new_rh)
479
495
 
480
496
class cmd_branch(Command):
481
497
    """Create a new copy of a branch.
619
635
    @display_command
620
636
    def run(self, filename):
621
637
        b, relpath = Branch.open_containing(filename)
622
 
        i = b.inventory.path2id(relpath)
 
638
        i = b.working_tree().inventory.path2id(relpath)
623
639
        if i == None:
624
640
            raise BzrError("%r is not a versioned file" % filename)
625
641
        else:
736
752
    @display_command
737
753
    def run(self, revision=None, file_list=None, diff_options=None):
738
754
        from bzrlib.diff import show_diff
739
 
        
740
 
        b, file_list = branch_files(file_list)
 
755
        try:
 
756
            b, file_list = inner_branch_files(file_list)
 
757
            b2 = None
 
758
        except NotBranchError:
 
759
            if len(file_list) != 2:
 
760
                raise BzrCommandError("Files are in different branches")
 
761
 
 
762
            b, file1 = Branch.open_containing(file_list[0])
 
763
            b2, file2 = Branch.open_containing(file_list[1])
 
764
            if file1 != "" or file2 != "":
 
765
                raise BzrCommandError("Files are in different branches")
 
766
            file_list = None
741
767
        if revision is not None:
 
768
            if b2 is not None:
 
769
                raise BzrCommandError("Can't specify -r with two branches")
742
770
            if len(revision) == 1:
743
771
                return show_diff(b, revision[0], specific_files=file_list,
744
772
                                 external_diff_options=diff_options)
750
778
                raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
751
779
        else:
752
780
            return show_diff(b, None, specific_files=file_list,
753
 
                             external_diff_options=diff_options)
 
781
                             external_diff_options=diff_options, b2=b2)
754
782
 
755
783
 
756
784
class cmd_deleted(Command):
890
918
        if rev2 == 0:
891
919
            rev2 = None
892
920
 
893
 
        mutter('encoding log as %r' % bzrlib.user_encoding)
 
921
        mutter('encoding log as %r', bzrlib.user_encoding)
894
922
 
895
923
        # use 'replace' so that we don't abort if trying to write out
896
924
        # in e.g. the default C locale.
1102
1130
    is found exports to a directory (equivalent to --format=dir).
1103
1131
 
1104
1132
    Root may be the top directory for tar, tgz and tbz2 formats. If none
1105
 
    is given, the top directory will be the root name of the file."""
1106
 
    # TODO: list known exporters
 
1133
    is given, the top directory will be the root name of the file.
 
1134
 
 
1135
    Note: export of tree with non-ascii filenames to zip is not supported.
 
1136
 
 
1137
    Supported formats       Autodetected by extension
 
1138
    -----------------       -------------------------
 
1139
         dir                            -
 
1140
         tar                          .tar
 
1141
         tbz2                    .tar.bz2, .tbz2
 
1142
         tgz                      .tar.gz, .tgz
 
1143
         zip                          .zip
 
1144
    """
1107
1145
    takes_args = ['dest']
1108
1146
    takes_options = ['revision', 'format', 'root']
1109
1147
    def run(self, dest, revision=None, format=None, root=None):
1110
1148
        import os.path
 
1149
        from bzrlib.export import export
1111
1150
        b = Branch.open_containing('.')[0]
1112
1151
        if revision is None:
1113
1152
            rev_id = b.last_revision()
1116
1155
                raise BzrError('bzr export --revision takes exactly 1 argument')
1117
1156
            rev_id = revision[0].in_history(b).rev_id
1118
1157
        t = b.revision_tree(rev_id)
1119
 
        arg_root, ext = os.path.splitext(os.path.basename(dest))
1120
 
        if ext in ('.gz', '.bz2'):
1121
 
            new_root, new_ext = os.path.splitext(arg_root)
1122
 
            if new_ext == '.tar':
1123
 
                arg_root = new_root
1124
 
                ext = new_ext + ext
1125
 
        if root is None:
1126
 
            root = arg_root
1127
 
        if not format:
1128
 
            if ext in (".tar",):
1129
 
                format = "tar"
1130
 
            elif ext in (".tar.gz", ".tgz"):
1131
 
                format = "tgz"
1132
 
            elif ext in (".tar.bz2", ".tbz2"):
1133
 
                format = "tbz2"
1134
 
            else:
1135
 
                format = "dir"
1136
 
        t.export(dest, format, root)
 
1158
        try:
 
1159
            export(t, dest, format, root)
 
1160
        except errors.NoSuchExportFormat, e:
 
1161
            raise BzrCommandError('Unsupported export format: %s' % e.format)
1137
1162
 
1138
1163
 
1139
1164
class cmd_cat(Command):
1309
1334
        else:
1310
1335
            print config.username()
1311
1336
 
 
1337
class cmd_nick(Command):
 
1338
    """\
 
1339
    Print or set the branch nickname.  
 
1340
    If unset, the tree root directory name is used as the nickname
 
1341
    To print the current nickname, execute with no argument.  
 
1342
    """
 
1343
    takes_args = ['nickname?']
 
1344
    def run(self, nickname=None):
 
1345
        branch = Branch.open_containing('.')[0]
 
1346
        if nickname is None:
 
1347
            self.printme(branch)
 
1348
        else:
 
1349
            branch.nick = nickname
 
1350
 
 
1351
    @display_command
 
1352
    def printme(self, branch):
 
1353
        print branch.nick 
1312
1354
 
1313
1355
class cmd_selftest(Command):
1314
1356
    """Run internal test suite.
1316
1358
    This creates temporary test directories in the working directory,
1317
1359
    but not existing data is affected.  These directories are deleted
1318
1360
    if the tests pass, or left behind to help in debugging if they
1319
 
    fail.
 
1361
    fail and --keep-output is specified.
1320
1362
    
1321
1363
    If arguments are given, they are regular expressions that say
1322
1364
    which tests should run.
1326
1368
    takes_args = ['testspecs*']
1327
1369
    takes_options = ['verbose', 
1328
1370
                     Option('one', help='stop when one test fails'),
 
1371
                     Option('keep-output', 
 
1372
                            help='keep output directories when tests fail')
1329
1373
                    ]
1330
1374
 
1331
 
    def run(self, testspecs_list=None, verbose=False, one=False):
 
1375
    def run(self, testspecs_list=None, verbose=False, one=False,
 
1376
            keep_output=False):
1332
1377
        import bzrlib.ui
1333
1378
        from bzrlib.selftest import selftest
1334
1379
        # we don't want progress meters from the tests to go to the
1344
1389
                pattern = ".*"
1345
1390
            result = selftest(verbose=verbose, 
1346
1391
                              pattern=pattern,
1347
 
                              stop_on_failure=one)
 
1392
                              stop_on_failure=one, 
 
1393
                              keep_output=keep_output)
1348
1394
            if result:
1349
1395
                bzrlib.trace.info('tests passed')
1350
1396
            else:
1503
1549
            log_error(m)
1504
1550
 
1505
1551
 
 
1552
class cmd_remerge(Command):
 
1553
    """Redo a merge.
 
1554
    """
 
1555
    takes_args = ['file*']
 
1556
    takes_options = ['merge-type', 'reprocess',
 
1557
                     Option('show-base', help="Show base revision text in "
 
1558
                            "conflicts")]
 
1559
 
 
1560
    def run(self, file_list=None, merge_type=None, show_base=False,
 
1561
            reprocess=False):
 
1562
        from bzrlib.merge import merge_inner, transform_tree
 
1563
        from bzrlib.merge_core import ApplyMerge3
 
1564
        if merge_type is None:
 
1565
            merge_type = ApplyMerge3
 
1566
        b, file_list = branch_files(file_list)
 
1567
        b.lock_write()
 
1568
        try:
 
1569
            pending_merges = b.working_tree().pending_merges() 
 
1570
            if len(pending_merges) != 1:
 
1571
                raise BzrCommandError("Sorry, remerge only works after normal"
 
1572
                                      + " merges.  Not cherrypicking or"
 
1573
                                      + "multi-merges.")
 
1574
            this_tree = b.working_tree()
 
1575
            base_revision = common_ancestor(b.last_revision(), 
 
1576
                                            pending_merges[0], b)
 
1577
            base_tree = b.revision_tree(base_revision)
 
1578
            other_tree = b.revision_tree(pending_merges[0])
 
1579
            interesting_ids = None
 
1580
            if file_list is not None:
 
1581
                interesting_ids = set()
 
1582
                for filename in file_list:
 
1583
                    file_id = this_tree.path2id(filename)
 
1584
                    interesting_ids.add(file_id)
 
1585
                    if this_tree.kind(file_id) != "directory":
 
1586
                        continue
 
1587
                    
 
1588
                    for name, ie in this_tree.inventory.iter_entries(file_id):
 
1589
                        interesting_ids.add(ie.file_id)
 
1590
            transform_tree(this_tree, b.basis_tree(), interesting_ids)
 
1591
            if file_list is None:
 
1592
                restore_files = list(this_tree.iter_conflicts())
 
1593
            else:
 
1594
                restore_files = file_list
 
1595
            for filename in restore_files:
 
1596
                try:
 
1597
                    restore(this_tree.abspath(filename))
 
1598
                except NotConflicted:
 
1599
                    pass
 
1600
            conflicts =  merge_inner(b, other_tree, base_tree, 
 
1601
                                     interesting_ids = interesting_ids, 
 
1602
                                     other_rev_id=pending_merges[0], 
 
1603
                                     merge_type=merge_type, 
 
1604
                                     show_base=show_base,
 
1605
                                     reprocess=reprocess)
 
1606
        finally:
 
1607
            b.unlock()
 
1608
        if conflicts > 0:
 
1609
            return 1
 
1610
        else:
 
1611
            return 0
 
1612
 
1506
1613
class cmd_revert(Command):
1507
1614
    """Reverse all changes since the last commit.
1508
1615
 
1808
1915
# TODO: Some more consistent way to split command definitions across files;
1809
1916
# we do need to load at least some information about them to know of 
1810
1917
# aliases.
1811
 
from bzrlib.conflicts import cmd_resolve, cmd_conflicts
 
1918
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore