~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

Merge from mpool.

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
 
30
from bzrlib.errors import (BzrError, BzrCheckError, BzrCommandError, 
 
31
                           NotBranchError, DivergedBranches, NotConflicted,
 
32
                           NoSuchFile, NoWorkingTree, FileInWrongBranch)
31
33
from bzrlib.option import Option
32
34
from bzrlib.revisionspec import RevisionSpec
33
35
import bzrlib.trace
36
38
 
37
39
 
38
40
def tree_files(file_list, default_branch='.'):
 
41
    try:
 
42
        return internal_tree_files(file_list, default_branch)
 
43
    except FileInWrongBranch, e:
 
44
        raise BzrCommandError("%s is not in the same branch as %s" %
 
45
                             (e.path, file_list[0]))
 
46
 
 
47
def internal_tree_files(file_list, default_branch='.'):
39
48
    """\
40
49
    Return a branch and list of branch-relative paths.
41
50
    If supplied file_list is empty or None, the branch default will be used,
49
58
        try:
50
59
            new_list.append(tree.relpath(filename))
51
60
        except NotBranchError:
52
 
            raise BzrCommandError("%s is not in the same tree as %s" % 
53
 
                                  (filename, file_list[0]))
 
61
            raise FileInWrongBranch(tree.branch, filename)
54
62
    return tree, new_list
55
63
 
56
64
 
100
108
    that revision, or between two revisions if two are provided.
101
109
    """
102
110
    
103
 
    # XXX: FIXME: bzr status should accept a -r option to show changes
104
 
    # relative to a revision, or between revisions
105
 
 
106
111
    # TODO: --no-recurse, --recurse options
107
112
    
108
113
    takes_args = ['file*']
109
 
    takes_options = ['all', 'show-ids']
 
114
    takes_options = ['all', 'show-ids', 'revision']
110
115
    aliases = ['st', 'stat']
111
116
    
112
117
    @display_command
246
251
 
247
252
 
248
253
class cmd_inventory(Command):
249
 
    """Show inventory of the current working copy or a revision."""
250
 
    takes_options = ['revision', 'show-ids']
 
254
    """Show inventory of the current working copy or a revision.
 
255
 
 
256
    It is possible to limit the output to a particular entry
 
257
    type using the --kind option.  For example; --kind file.
 
258
    """
 
259
    takes_options = ['revision', 'show-ids', 'kind']
251
260
    
252
261
    @display_command
253
 
    def run(self, revision=None, show_ids=False):
 
262
    def run(self, revision=None, show_ids=False, kind=None):
 
263
        if kind and kind not in ['file', 'directory', 'symlink']:
 
264
            raise BzrCommandError('invalid kind specified')
254
265
        tree = WorkingTree.open_containing('.')[0]
255
266
        if revision is None:
256
267
            inv = tree.read_working_inventory()
262
273
                revision[0].in_history(tree.branch).rev_id)
263
274
 
264
275
        for path, entry in inv.entries():
 
276
            if kind and kind != entry.kind:
 
277
                continue
265
278
            if show_ids:
266
279
                print '%-50s %s' % (path, entry.file_id)
267
280
            else:
659
672
            print revision_id
660
673
 
661
674
 
662
 
class cmd_directories(Command):
663
 
    """Display list of versioned directories in this tree."""
664
 
    @display_command
665
 
    def run(self):
666
 
        for name, ie in (WorkingTree.open_containing('.')[0].
667
 
                         read_working_inventory().directories()):
668
 
            if name == '':
669
 
                print '.'
670
 
            else:
671
 
                print name
672
 
 
673
 
 
674
675
class cmd_init(Command):
675
676
    """Make a directory into a versioned branch.
676
677
 
732
733
    @display_command
733
734
    def run(self, revision=None, file_list=None, diff_options=None):
734
735
        from bzrlib.diff import show_diff
735
 
        
736
 
        tree, file_list = tree_files(file_list)
 
736
        try:
 
737
            tree, file_list = internal_tree_files(file_list)
 
738
            b = None
 
739
            b2 = None
 
740
        except FileInWrongBranch:
 
741
            if len(file_list) != 2:
 
742
                raise BzrCommandError("Files are in different branches")
 
743
 
 
744
            b, file1 = Branch.open_containing(file_list[0])
 
745
            b2, file2 = Branch.open_containing(file_list[1])
 
746
            if file1 != "" or file2 != "":
 
747
                # FIXME diff those two files. rbc 20051123
 
748
                raise BzrCommandError("Files are in different branches")
 
749
            file_list = None
737
750
        if revision is not None:
 
751
            if b2 is not None:
 
752
                raise BzrCommandError("Can't specify -r with two branches")
738
753
            if len(revision) == 1:
739
754
                return show_diff(tree.branch, revision[0], specific_files=file_list,
740
755
                                 external_diff_options=diff_options)
745
760
            else:
746
761
                raise BzrCommandError('bzr diff --revision takes exactly one or two revision identifiers')
747
762
        else:
748
 
            return show_diff(tree.branch, None, specific_files=file_list,
749
 
                             external_diff_options=diff_options)
 
763
            if b is not None:
 
764
                return show_diff(b, None, specific_files=file_list,
 
765
                                 external_diff_options=diff_options, b2=b2)
 
766
            else:
 
767
                return show_diff(tree.branch, None, specific_files=file_list,
 
768
                                 external_diff_options=diff_options)
750
769
 
751
770
 
752
771
class cmd_deleted(Command):
888
907
        else:
889
908
            raise BzrCommandError('bzr log --revision takes one or two values.')
890
909
 
891
 
        if rev1 == 0:
892
 
            rev1 = None
893
 
        if rev2 == 0:
894
 
            rev2 = None
 
910
        # By this point, the revision numbers are converted to the +ve
 
911
        # form if they were supplied in the -ve form, so we can do
 
912
        # this comparison in relative safety
 
913
        if rev1 > rev2:
 
914
            (rev2, rev1) = (rev1, rev2)
895
915
 
896
916
        mutter('encoding log as %r', bzrlib.user_encoding)
897
917
 
1316
1336
        else:
1317
1337
            print config.username()
1318
1338
 
 
1339
class cmd_nick(Command):
 
1340
    """\
 
1341
    Print or set the branch nickname.  
 
1342
    If unset, the tree root directory name is used as the nickname
 
1343
    To print the current nickname, execute with no argument.  
 
1344
    """
 
1345
    takes_args = ['nickname?']
 
1346
    def run(self, nickname=None):
 
1347
        branch = Branch.open_containing('.')[0]
 
1348
        if nickname is None:
 
1349
            self.printme(branch)
 
1350
        else:
 
1351
            branch.nick = nickname
 
1352
 
 
1353
    @display_command
 
1354
    def printme(self, branch):
 
1355
        print branch.nick 
1319
1356
 
1320
1357
class cmd_selftest(Command):
1321
1358
    """Run internal test suite.
1323
1360
    This creates temporary test directories in the working directory,
1324
1361
    but not existing data is affected.  These directories are deleted
1325
1362
    if the tests pass, or left behind to help in debugging if they
1326
 
    fail.
 
1363
    fail and --keep-output is specified.
1327
1364
    
1328
1365
    If arguments are given, they are regular expressions that say
1329
1366
    which tests should run.
1333
1370
    takes_args = ['testspecs*']
1334
1371
    takes_options = ['verbose', 
1335
1372
                     Option('one', help='stop when one test fails'),
 
1373
                     Option('keep-output', 
 
1374
                            help='keep output directories when tests fail')
1336
1375
                    ]
1337
1376
 
1338
 
    def run(self, testspecs_list=None, verbose=False, one=False):
 
1377
    def run(self, testspecs_list=None, verbose=False, one=False,
 
1378
            keep_output=False):
1339
1379
        import bzrlib.ui
1340
1380
        from bzrlib.selftest import selftest
1341
1381
        # we don't want progress meters from the tests to go to the
1351
1391
                pattern = ".*"
1352
1392
            result = selftest(verbose=verbose, 
1353
1393
                              pattern=pattern,
1354
 
                              stop_on_failure=one)
 
1394
                              stop_on_failure=one, 
 
1395
                              keep_output=keep_output)
1355
1396
            if result:
1356
1397
                bzrlib.trace.info('tests passed')
1357
1398
            else:
1510
1551
            log_error(m)
1511
1552
 
1512
1553
 
 
1554
class cmd_remerge(Command):
 
1555
    """Redo a merge.
 
1556
    """
 
1557
    takes_args = ['file*']
 
1558
    takes_options = ['merge-type', 'reprocess',
 
1559
                     Option('show-base', help="Show base revision text in "
 
1560
                            "conflicts")]
 
1561
 
 
1562
    def run(self, file_list=None, merge_type=None, show_base=False,
 
1563
            reprocess=False):
 
1564
        from bzrlib.merge import merge_inner, transform_tree
 
1565
        from bzrlib.merge_core import ApplyMerge3
 
1566
        if merge_type is None:
 
1567
            merge_type = ApplyMerge3
 
1568
        tree, file_list = tree_files(file_list)
 
1569
        tree.lock_write()
 
1570
        try:
 
1571
            pending_merges = tree.pending_merges() 
 
1572
            if len(pending_merges) != 1:
 
1573
                raise BzrCommandError("Sorry, remerge only works after normal"
 
1574
                                      + " merges.  Not cherrypicking or"
 
1575
                                      + "multi-merges.")
 
1576
            base_revision = common_ancestor(tree.branch.last_revision(), 
 
1577
                                            pending_merges[0], tree.branch)
 
1578
            base_tree = tree.branch.revision_tree(base_revision)
 
1579
            other_tree = tree.branch.revision_tree(pending_merges[0])
 
1580
            interesting_ids = None
 
1581
            if file_list is not None:
 
1582
                interesting_ids = set()
 
1583
                for filename in file_list:
 
1584
                    file_id = tree.path2id(filename)
 
1585
                    interesting_ids.add(file_id)
 
1586
                    if tree.kind(file_id) != "directory":
 
1587
                        continue
 
1588
                    
 
1589
                    for name, ie in tree.inventory.iter_entries(file_id):
 
1590
                        interesting_ids.add(ie.file_id)
 
1591
            transform_tree(tree, tree.branch.basis_tree(), interesting_ids)
 
1592
            if file_list is None:
 
1593
                restore_files = list(tree.iter_conflicts())
 
1594
            else:
 
1595
                restore_files = file_list
 
1596
            for filename in restore_files:
 
1597
                try:
 
1598
                    restore(tree.abspath(filename))
 
1599
                except NotConflicted:
 
1600
                    pass
 
1601
            conflicts =  merge_inner(tree.branch, other_tree, base_tree, 
 
1602
                                     interesting_ids = interesting_ids, 
 
1603
                                     other_rev_id=pending_merges[0], 
 
1604
                                     merge_type=merge_type, 
 
1605
                                     show_base=show_base,
 
1606
                                     reprocess=reprocess)
 
1607
        finally:
 
1608
            tree.unlock()
 
1609
        if conflicts > 0:
 
1610
            return 1
 
1611
        else:
 
1612
            return 0
 
1613
 
1513
1614
class cmd_revert(Command):
1514
1615
    """Reverse all changes since the last commit.
1515
1616
 
1759
1860
# TODO: Some more consistent way to split command definitions across files;
1760
1861
# we do need to load at least some information about them to know of 
1761
1862
# aliases.
1762
 
from bzrlib.conflicts import cmd_resolve, cmd_conflicts
 
1863
from bzrlib.conflicts import cmd_resolve, cmd_conflicts, restore