/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

Merge from bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
    delta,
34
34
    config,
35
35
    errors,
 
36
    globbing,
36
37
    ignores,
37
38
    log,
38
39
    merge as _mod_merge,
342
343
            file_ids_from=None):
343
344
        import bzrlib.add
344
345
 
 
346
        base_tree = None
345
347
        if file_ids_from is not None:
346
348
            try:
347
349
                base_tree, base_path = WorkingTree.open_containing(
357
359
            action = bzrlib.add.AddAction(to_file=self.outf,
358
360
                should_print=(not is_quiet()))
359
361
 
360
 
        added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
361
 
                                              action=action, save=not dry_run)
 
362
        if base_tree:
 
363
            base_tree.lock_read()
 
364
        try:
 
365
            added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
 
366
                action=action, save=not dry_run)
 
367
        finally:
 
368
            if base_tree is not None:
 
369
                base_tree.unlock()
362
370
        if len(ignored) > 0:
363
371
            if verbose:
364
372
                for glob in sorted(ignored.keys()):
430
438
            raise errors.BzrCommandError('invalid kind specified')
431
439
 
432
440
        work_tree, file_list = tree_files(file_list)
433
 
 
434
 
        if revision is not None:
435
 
            if len(revision) > 1:
436
 
                raise errors.BzrCommandError('bzr inventory --revision takes'
437
 
                                             ' exactly one revision identifier')
438
 
            revision_id = revision[0].in_history(work_tree.branch).rev_id
439
 
            tree = work_tree.branch.repository.revision_tree(revision_id)
440
 
                        
441
 
            # We include work_tree as well as 'tree' here
442
 
            # So that doing '-r 10 path/foo' will lookup whatever file
443
 
            # exists now at 'path/foo' even if it has been renamed, as
444
 
            # well as whatever files existed in revision 10 at path/foo
445
 
            trees = [tree, work_tree]
446
 
        else:
447
 
            tree = work_tree
448
 
            trees = [tree]
449
 
 
450
 
        if file_list is not None:
451
 
            file_ids = _mod_tree.find_ids_across_trees(file_list, trees,
452
 
                                                      require_versioned=True)
453
 
            # find_ids_across_trees may include some paths that don't
454
 
            # exist in 'tree'.
455
 
            entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
456
 
                             for file_id in file_ids if file_id in tree)
457
 
        else:
458
 
            entries = tree.inventory.entries()
 
441
        work_tree.lock_read()
 
442
        try:
 
443
            if revision is not None:
 
444
                if len(revision) > 1:
 
445
                    raise errors.BzrCommandError(
 
446
                        'bzr inventory --revision takes exactly one revision'
 
447
                        ' identifier')
 
448
                revision_id = revision[0].in_history(work_tree.branch).rev_id
 
449
                tree = work_tree.branch.repository.revision_tree(revision_id)
 
450
 
 
451
                extra_trees = [work_tree]
 
452
                tree.lock_read()
 
453
            else:
 
454
                tree = work_tree
 
455
                extra_trees = []
 
456
 
 
457
            if file_list is not None:
 
458
                file_ids = tree.paths2ids(file_list, trees=extra_trees,
 
459
                                          require_versioned=True)
 
460
                # find_ids_across_trees may include some paths that don't
 
461
                # exist in 'tree'.
 
462
                entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
 
463
                                 for file_id in file_ids if file_id in tree)
 
464
            else:
 
465
                entries = tree.inventory.entries()
 
466
        finally:
 
467
            tree.unlock()
 
468
            if tree is not work_tree:
 
469
                work_tree.unlock()
459
470
 
460
471
        for path, entry in entries:
461
472
            if kind and kind != entry.kind:
549
560
    def run(self, location=None, remember=False, overwrite=False,
550
561
            revision=None, verbose=False,
551
562
            directory=None):
 
563
        from bzrlib.tag import _merge_tags_if_possible
552
564
        # FIXME: too much stuff is in the command class
553
565
        if directory is None:
554
566
            directory = u'.'
597
609
 
598
610
        old_rh = branch_to.revision_history()
599
611
        if tree_to is not None:
600
 
            count = tree_to.pull(branch_from, overwrite, rev_id,
601
 
                delta.ChangeReporter(tree_to.inventory))
 
612
            result = tree_to.pull(branch_from, overwrite, rev_id,
 
613
                delta.ChangeReporter(unversioned_filter=tree_to.is_ignored))
602
614
        else:
603
 
            count = branch_to.pull(branch_from, overwrite, rev_id)
604
 
        note('%d revision(s) pulled.' % (count,))
 
615
            result = branch_to.pull(branch_from, overwrite, rev_id)
605
616
 
 
617
        result.report(self.outf)
606
618
        if verbose:
 
619
            from bzrlib.log import show_changed_revisions
607
620
            new_rh = branch_to.revision_history()
608
 
            if old_rh != new_rh:
609
 
                # Something changed
610
 
                from bzrlib.log import show_changed_revisions
611
 
                show_changed_revisions(branch_to, old_rh, new_rh,
612
 
                                       to_file=self.outf)
 
621
            show_changed_revisions(branch_to, old_rh, new_rh, to_file=self.outf)
613
622
 
614
623
 
615
624
class cmd_push(Command):
679
688
        to_transport = transport.get_transport(location)
680
689
        location_url = to_transport.base
681
690
 
682
 
        old_rh = []
683
 
        count = 0
684
 
 
685
691
        br_to = repository_to = dir_to = None
686
692
        try:
687
693
            dir_to = bzrdir.BzrDir.open_from_transport(to_transport)
701
707
            else:
702
708
                # Found a branch, so we must have found a repository
703
709
                repository_to = br_to.repository
704
 
 
 
710
        push_result = None
705
711
        old_rh = []
706
712
        if dir_to is None:
 
713
            # The destination doesn't exist; create it.
707
714
            # XXX: Refactor the create_prefix/no_create_prefix code into a
708
715
            #      common helper function
709
716
            try:
750
757
            dir_to = br_from.bzrdir.clone(location_url,
751
758
                revision_id=br_from.last_revision())
752
759
            br_to = dir_to.open_branch()
753
 
            count = br_to.last_revision_info()[0]
 
760
            # TODO: Some more useful message about what was copied
 
761
            note('Created new branch.')
754
762
            # We successfully created the target, remember it
755
763
            if br_from.get_push_location() is None or remember:
756
764
                br_from.set_push_location(br_to.base)
769
777
            repository_to.fetch(br_from.repository,
770
778
                                revision_id=last_revision_id)
771
779
            br_to = br_from.clone(dir_to, revision_id=last_revision_id)
772
 
            count = len(br_to.revision_history())
 
780
            note('Created new branch.')
773
781
            if br_from.get_push_location() is None or remember:
774
782
                br_from.set_push_location(br_to.base)
775
783
        else: # We have a valid to branch
784
792
                except errors.NotLocalUrl:
785
793
                    warning('This transport does not update the working '
786
794
                            'tree of: %s' % (br_to.base,))
787
 
                    count = br_from.push(br_to, overwrite)
 
795
                    push_result = br_from.push(br_to, overwrite)
788
796
                except errors.NoWorkingTree:
789
 
                    count = br_from.push(br_to, overwrite)
 
797
                    push_result = br_from.push(br_to, overwrite)
790
798
                else:
791
799
                    tree_to.lock_write()
792
800
                    try:
793
 
                        count = br_from.push(tree_to.branch, overwrite)
 
801
                        push_result = br_from.push(tree_to.branch, overwrite)
794
802
                        tree_to.update()
795
803
                    finally:
796
804
                        tree_to.unlock()
797
805
            except errors.DivergedBranches:
798
806
                raise errors.BzrCommandError('These branches have diverged.'
799
807
                                        '  Try using "merge" and then "push".')
800
 
        note('%d revision(s) pushed.' % (count,))
801
 
 
802
 
        if verbose:
 
808
        if push_result is not None:
 
809
            push_result.report(self.outf)
 
810
        elif verbose:
803
811
            new_rh = br_to.revision_history()
804
812
            if old_rh != new_rh:
805
813
                # Something changed
806
814
                from bzrlib.log import show_changed_revisions
807
815
                show_changed_revisions(br_to, old_rh, new_rh,
808
816
                                       to_file=self.outf)
 
817
        else:
 
818
            # we probably did a clone rather than a push, so a message was
 
819
            # emitted above
 
820
            pass
809
821
 
810
822
 
811
823
class cmd_branch(Command):
826
838
    aliases = ['get', 'clone']
827
839
 
828
840
    def run(self, from_location, to_location=None, revision=None, basis=None):
 
841
        from bzrlib.tag import _merge_tags_if_possible
829
842
        if revision is None:
830
843
            revision = [None]
831
844
        elif len(revision) > 1:
876
889
                raise errors.BzrCommandError(msg)
877
890
            if name:
878
891
                branch.control_files.put_utf8('branch-name', name)
 
892
            _merge_tags_if_possible(br_from, branch)
879
893
            note('Branched %d revision(s).' % branch.revno())
880
894
        finally:
881
895
            br_from.unlock()
967
981
    @display_command
968
982
    def run(self, dir=u'.'):
969
983
        tree = WorkingTree.open_containing(dir)[0]
970
 
        old_inv = tree.basis_tree().inventory
971
 
        new_inv = tree.read_working_inventory()
972
 
        renames = list(_mod_tree.find_renames(old_inv, new_inv))
973
 
        renames.sort()
974
 
        for old_name, new_name in renames:
975
 
            self.outf.write("%s => %s\n" % (old_name, new_name))
 
984
        tree.lock_read()
 
985
        try:
 
986
            new_inv = tree.inventory
 
987
            old_tree = tree.basis_tree()
 
988
            old_tree.lock_read()
 
989
            try:
 
990
                old_inv = old_tree.inventory
 
991
                renames = list(_mod_tree.find_renames(old_inv, new_inv))
 
992
                renames.sort()
 
993
                for old_name, new_name in renames:
 
994
                    self.outf.write("%s => %s\n" % (old_name, new_name))
 
995
            finally:
 
996
                old_tree.unlock()
 
997
        finally:
 
998
            tree.unlock()
976
999
 
977
1000
 
978
1001
class cmd_update(Command):
1083
1106
    @display_command
1084
1107
    def run(self, filename):
1085
1108
        tree, relpath = WorkingTree.open_containing(filename)
1086
 
        i = tree.inventory.path2id(relpath)
 
1109
        i = tree.path2id(relpath)
1087
1110
        if i is None:
1088
1111
            raise errors.NotVersionedError(filename)
1089
1112
        else:
1103
1126
    @display_command
1104
1127
    def run(self, filename):
1105
1128
        tree, relpath = WorkingTree.open_containing(filename)
1106
 
        inv = tree.inventory
1107
 
        fid = inv.path2id(relpath)
 
1129
        fid = tree.path2id(relpath)
1108
1130
        if fid is None:
1109
1131
            raise errors.NotVersionedError(filename)
1110
 
        for fip in inv.get_idpath(fid):
1111
 
            self.outf.write(fip + '\n')
 
1132
        segments = osutils.splitpath(relpath)
 
1133
        for pos in range(1, len(segments) + 1):
 
1134
            path = osutils.joinpath(segments[:pos])
 
1135
            self.outf.write("%s\n" % tree.path2id(path))
1112
1136
 
1113
1137
 
1114
1138
class cmd_reconcile(Command):
1233
1257
            existing_bzrdir = bzrdir.BzrDir.open(location)
1234
1258
        except errors.NotBranchError:
1235
1259
            # really a NotBzrDir error...
1236
 
            branch = bzrdir.BzrDir.create_branch_convenience(location,
 
1260
            branch = bzrdir.BzrDir.create_branch_convenience(to_transport.base,
1237
1261
                                                             format=format)
1238
1262
        else:
1239
1263
            from bzrlib.transport.local import LocalTransport
1419
1443
    @display_command
1420
1444
    def run(self, show_ids=False):
1421
1445
        tree = WorkingTree.open_containing(u'.')[0]
1422
 
        old = tree.basis_tree()
1423
 
        for path, ie in old.inventory.iter_entries():
1424
 
            if not tree.has_id(ie.file_id):
1425
 
                self.outf.write(path)
1426
 
                if show_ids:
1427
 
                    self.outf.write(' ')
1428
 
                    self.outf.write(ie.file_id)
1429
 
                self.outf.write('\n')
 
1446
        tree.lock_read()
 
1447
        try:
 
1448
            old = tree.basis_tree()
 
1449
            old.lock_read()
 
1450
            try:
 
1451
                for path, ie in old.inventory.iter_entries():
 
1452
                    if not tree.has_id(ie.file_id):
 
1453
                        self.outf.write(path)
 
1454
                        if show_ids:
 
1455
                            self.outf.write(' ')
 
1456
                            self.outf.write(ie.file_id)
 
1457
                        self.outf.write('\n')
 
1458
            finally:
 
1459
                old.unlock()
 
1460
        finally:
 
1461
            tree.unlock()
1430
1462
 
1431
1463
 
1432
1464
class cmd_modified(Command):
1456
1488
    @display_command
1457
1489
    def run(self):
1458
1490
        wt = WorkingTree.open_containing(u'.')[0]
1459
 
        basis_inv = wt.basis_tree().inventory
1460
 
        inv = wt.inventory
1461
 
        for file_id in inv:
1462
 
            if file_id in basis_inv:
1463
 
                continue
1464
 
            if inv.is_root(file_id) and len(basis_inv) == 0:
1465
 
                continue
1466
 
            path = inv.id2path(file_id)
1467
 
            if not os.access(osutils.abspath(path), os.F_OK):
1468
 
                continue
1469
 
            self.outf.write(path + '\n')
 
1491
        wt.lock_read()
 
1492
        try:
 
1493
            basis = wt.basis_tree()
 
1494
            basis.lock_read()
 
1495
            try:
 
1496
                basis_inv = basis.inventory
 
1497
                inv = wt.inventory
 
1498
                for file_id in inv:
 
1499
                    if file_id in basis_inv:
 
1500
                        continue
 
1501
                    if inv.is_root(file_id) and len(basis_inv) == 0:
 
1502
                        continue
 
1503
                    path = inv.id2path(file_id)
 
1504
                    if not os.access(osutils.abspath(path), os.F_OK):
 
1505
                        continue
 
1506
                    self.outf.write(path + '\n')
 
1507
            finally:
 
1508
                basis.unlock()
 
1509
        finally:
 
1510
            wt.unlock()
1470
1511
 
1471
1512
 
1472
1513
class cmd_root(Command):
1538
1579
            if fp != '':
1539
1580
                if tree is None:
1540
1581
                    tree = b.basis_tree()
1541
 
                inv = tree.inventory
1542
 
                file_id = inv.path2id(fp)
 
1582
                file_id = tree.path2id(fp)
1543
1583
                if file_id is None:
1544
1584
                    raise errors.BzrCommandError(
1545
1585
                        "Path does not have any revision history: %s" %
1633
1673
    def run(self, filename):
1634
1674
        tree, relpath = WorkingTree.open_containing(filename)
1635
1675
        b = tree.branch
1636
 
        inv = tree.read_working_inventory()
1637
 
        file_id = inv.path2id(relpath)
 
1676
        file_id = tree.path2id(relpath)
1638
1677
        for revno, revision_id, what in log.find_touching_revisions(b, file_id):
1639
1678
            self.outf.write("%6d %s\n" % (revno, what))
1640
1679
 
1693
1732
        elif tree is None:
1694
1733
            tree = branch.basis_tree()
1695
1734
 
1696
 
        for fp, fc, fkind, fid, entry in tree.list_files(include_root=False):
1697
 
            if fp.startswith(relpath):
1698
 
                fp = osutils.pathjoin(prefix, fp[len(relpath):])
1699
 
                if non_recursive and '/' in fp:
1700
 
                    continue
1701
 
                if not all and not selection[fc]:
1702
 
                    continue
1703
 
                if kind is not None and fkind != kind:
1704
 
                    continue
1705
 
                if verbose:
1706
 
                    kindch = entry.kind_character()
1707
 
                    outstring = '%-8s %s%s' % (fc, fp, kindch)
1708
 
                    if show_ids and fid is not None:
1709
 
                        outstring = "%-50s %s" % (outstring, fid)
1710
 
                    self.outf.write(outstring + '\n')
1711
 
                elif null:
1712
 
                    self.outf.write(fp + '\0')
1713
 
                    if show_ids:
 
1735
        tree.lock_read()
 
1736
        try:
 
1737
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False):
 
1738
                if fp.startswith(relpath):
 
1739
                    fp = osutils.pathjoin(prefix, fp[len(relpath):])
 
1740
                    if non_recursive and '/' in fp:
 
1741
                        continue
 
1742
                    if not all and not selection[fc]:
 
1743
                        continue
 
1744
                    if kind is not None and fkind != kind:
 
1745
                        continue
 
1746
                    if verbose:
 
1747
                        kindch = entry.kind_character()
 
1748
                        outstring = '%-8s %s%s' % (fc, fp, kindch)
 
1749
                        if show_ids and fid is not None:
 
1750
                            outstring = "%-50s %s" % (outstring, fid)
 
1751
                        self.outf.write(outstring + '\n')
 
1752
                    elif null:
 
1753
                        self.outf.write(fp + '\0')
 
1754
                        if show_ids:
 
1755
                            if fid is not None:
 
1756
                                self.outf.write(fid)
 
1757
                            self.outf.write('\0')
 
1758
                        self.outf.flush()
 
1759
                    else:
1714
1760
                        if fid is not None:
1715
 
                            self.outf.write(fid)
1716
 
                        self.outf.write('\0')
1717
 
                    self.outf.flush()
1718
 
                else:
1719
 
                    if fid is not None:
1720
 
                        my_id = fid
1721
 
                    else:
1722
 
                        my_id = ''
1723
 
                    if show_ids:
1724
 
                        self.outf.write('%-50s %s\n' % (fp, my_id))
1725
 
                    else:
1726
 
                        self.outf.write(fp + '\n')
 
1761
                            my_id = fid
 
1762
                        else:
 
1763
                            my_id = ''
 
1764
                        if show_ids:
 
1765
                            self.outf.write('%-50s %s\n' % (fp, my_id))
 
1766
                        else:
 
1767
                            self.outf.write(fp + '\n')
 
1768
        finally:
 
1769
            tree.unlock()
1727
1770
 
1728
1771
 
1729
1772
class cmd_unknowns(Command):
1789
1832
        if not name_pattern_list:
1790
1833
            raise errors.BzrCommandError("ignore requires at least one "
1791
1834
                                  "NAME_PATTERN or --old-default-rules")
 
1835
        name_pattern_list = [globbing.normalize_pattern(p) 
 
1836
                             for p in name_pattern_list]
1792
1837
        for name_pattern in name_pattern_list:
1793
 
            if name_pattern[0] == '/':
 
1838
            if (name_pattern[0] == '/' or 
 
1839
                (len(name_pattern) > 1 and name_pattern[1] == ':')):
1794
1840
                raise errors.BzrCommandError(
1795
1841
                    "NAME_PATTERN should not be an absolute path")
1796
1842
        tree, relpath = WorkingTree.open_containing(u'.')
1810
1856
        if igns and igns[-1] != '\n':
1811
1857
            igns += '\n'
1812
1858
        for name_pattern in name_pattern_list:
1813
 
            igns += name_pattern.rstrip('/') + '\n'
 
1859
            igns += name_pattern + '\n'
1814
1860
 
1815
1861
        f = AtomicFile(ifn, 'wb')
1816
1862
        try:
1819
1865
        finally:
1820
1866
            f.close()
1821
1867
 
1822
 
        inv = tree.inventory
1823
 
        if inv.path2id('.bzrignore'):
1824
 
            mutter('.bzrignore is already versioned')
1825
 
        else:
1826
 
            mutter('need to make new .bzrignore file versioned')
 
1868
        if not tree.path2id('.bzrignore'):
1827
1869
            tree.add(['.bzrignore'])
1828
1870
 
1829
1871
 
1834
1876
    @display_command
1835
1877
    def run(self):
1836
1878
        tree = WorkingTree.open_containing(u'.')[0]
1837
 
        for path, file_class, kind, file_id, entry in tree.list_files():
1838
 
            if file_class != 'I':
1839
 
                continue
1840
 
            ## XXX: Slightly inefficient since this was already calculated
1841
 
            pat = tree.is_ignored(path)
1842
 
            print '%-50s %s' % (path, pat)
 
1879
        tree.lock_read()
 
1880
        try:
 
1881
            for path, file_class, kind, file_id, entry in tree.list_files():
 
1882
                if file_class != 'I':
 
1883
                    continue
 
1884
                ## XXX: Slightly inefficient since this was already calculated
 
1885
                pat = tree.is_ignored(path)
 
1886
                print '%-50s %s' % (path, pat)
 
1887
        finally:
 
1888
            tree.unlock()
1843
1889
 
1844
1890
 
1845
1891
class cmd_lookup_revision(Command):
1925
1971
 
1926
1972
        tree = None
1927
1973
        try:
1928
 
            tree, relpath = WorkingTree.open_containing(filename)
1929
 
            b = tree.branch
1930
 
        except (errors.NotBranchError, errors.NotLocalUrl):
 
1974
            tree, b, relpath = \
 
1975
                    bzrdir.BzrDir.open_containing_tree_or_branch(filename)
 
1976
        except errors.NotBranchError:
1931
1977
            pass
1932
1978
 
1933
1979
        if revision is not None and revision[0].get_branch() is not None:
1934
1980
            b = Branch.open(revision[0].get_branch())
1935
1981
        if tree is None:
1936
 
            b, relpath = Branch.open_containing(filename)
1937
1982
            tree = b.basis_tree()
1938
1983
        if revision is None:
1939
1984
            revision_id = b.last_revision()
2117
2162
                        value_switches=True, title='Branch format'),
2118
2163
                    ]
2119
2164
 
2120
 
 
2121
2165
    def run(self, url='.', format=None):
2122
2166
        from bzrlib.upgrade import upgrade
2123
2167
        if format is None:
2215
2259
            run only tests relating to 'ignore'
2216
2260
        bzr --no-plugins selftest -v
2217
2261
            disable plugins and list tests as they're run
 
2262
 
 
2263
    For each test, that needs actual disk access, bzr create their own
 
2264
    subdirectory in the temporary testing directory (testXXXX.tmp).
 
2265
    By default the name of such subdirectory is based on the name of the test.
 
2266
    If option '--numbered-dirs' is given, bzr will use sequent numbers
 
2267
    of running tests to create such subdirectories. This is default behavior
 
2268
    on Windows because of path length limitation.
2218
2269
    """
2219
2270
    # TODO: --list should give a list of all available tests
2220
2271
 
2257
2308
                                 ' without running tests'),
2258
2309
                     Option('first',
2259
2310
                            help='run all tests, but run specified tests first',
2260
 
                            )
 
2311
                            ),
 
2312
                     Option('numbered-dirs',
 
2313
                            help='use numbered dirs for TestCaseInTempDir'),
2261
2314
                     ]
2262
2315
    encoding_type = 'replace'
2263
2316
 
2264
2317
    def run(self, testspecs_list=None, verbose=None, one=False,
2265
2318
            keep_output=False, transport=None, benchmark=None,
2266
2319
            lsprof_timed=None, cache_dir=None, clean_output=False,
2267
 
            first=False):
 
2320
            first=False, numbered_dirs=None):
2268
2321
        import bzrlib.ui
2269
2322
        from bzrlib.tests import selftest
2270
2323
        import bzrlib.benchmarks as benchmarks
2275
2328
            clean_selftest_output()
2276
2329
            return 0
2277
2330
 
 
2331
        if numbered_dirs is None and sys.platform == 'win32':
 
2332
            numbered_dirs = True
 
2333
 
2278
2334
        if cache_dir is not None:
2279
2335
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
2280
2336
        print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
2305
2361
                              lsprof_timed=lsprof_timed,
2306
2362
                              bench_history=benchfile,
2307
2363
                              matching_tests_first=first,
 
2364
                              numbered_dirs=numbered_dirs,
2308
2365
                              )
2309
2366
        finally:
2310
2367
            if benchfile is not None:
2332
2389
 
2333
2390
    @display_command
2334
2391
    def run(self):
2335
 
        print "it sure does!"
 
2392
        print "It sure does!"
2336
2393
 
2337
2394
 
2338
2395
class cmd_find_merge_base(Command):
2416
2473
                ' source rather than merging. When this happens,'
2417
2474
                ' you do not need to commit the result.'),
2418
2475
        Option('directory',
2419
 
            help='branch to merge into, '
 
2476
            help='Branch to merge into, '
2420
2477
                 'rather than the one containing the working directory',
2421
2478
            short_name='d',
2422
2479
            type=unicode,
2428
2485
            uncommitted=False, pull=False,
2429
2486
            directory=None,
2430
2487
            ):
 
2488
        from bzrlib.tag import _merge_tags_if_possible
2431
2489
        if merge_type is None:
2432
2490
            merge_type = _mod_merge.Merge3Merger
2433
2491
 
2434
2492
        if directory is None: directory = u'.'
 
2493
        # XXX: jam 20070225 WorkingTree should be locked before you extract its
 
2494
        #      inventory. Because merge is a mutating operation, it really
 
2495
        #      should be a lock_write() for the whole cmd_merge operation.
 
2496
        #      However, cmd_merge open's its own tree in _merge_helper, which
 
2497
        #      means if we lock here, the later lock_write() will always block.
 
2498
        #      Either the merge helper code should be updated to take a tree,
 
2499
        #      (What about tree.merge_from_branch?)
2435
2500
        tree = WorkingTree.open_containing(directory)[0]
2436
 
        change_reporter = delta.ChangeReporter(tree.inventory)
 
2501
        change_reporter = delta.ChangeReporter(
 
2502
            unversioned_filter=tree.is_ignored)
2437
2503
 
2438
2504
        if branch is not None:
2439
2505
            try:
2488
2554
        if tree.branch.get_parent() is None or remember:
2489
2555
            tree.branch.set_parent(other_branch.base)
2490
2556
 
 
2557
        # pull tags now... it's a bit inconsistent to do it ahead of copying
 
2558
        # the history but that's done inside the merge code
 
2559
        _merge_tags_if_possible(other_branch, tree.branch)
 
2560
 
2491
2561
        if path != "":
2492
2562
            interesting_files = [path]
2493
2563
        else:
2899
2969
                raise errors.BzrCommandError('bzr annotate --revision takes exactly 1 argument')
2900
2970
            else:
2901
2971
                revision_id = revision[0].in_history(branch).rev_id
2902
 
            file_id = tree.inventory.path2id(relpath)
 
2972
            file_id = tree.path2id(relpath)
2903
2973
            tree = branch.repository.revision_tree(revision_id)
2904
2974
            file_version = tree.inventory[file_id].revision
2905
2975
            annotate_file(branch, file_version, file_id, long, all, sys.stdout,
3128
3198
        Option('port',
3129
3199
               help='listen for connections on nominated port of the form '
3130
3200
                    '[hostname:]portnumber. Passing 0 as the port number will '
3131
 
                    'result in a dynamically allocated port.',
 
3201
                    'result in a dynamically allocated port. Default port is '
 
3202
                    '4155.',
3132
3203
               type=str),
3133
3204
        Option('directory',
3134
3205
               help='serve contents of directory',
3151
3222
        t = get_transport(url)
3152
3223
        if inet:
3153
3224
            server = smart.SmartServerPipeStreamMedium(sys.stdin, sys.stdout, t)
3154
 
        elif port is not None:
3155
 
            if ':' in port:
3156
 
                host, port = port.split(':')
3157
 
            else:
 
3225
        else:
 
3226
            if port is None:
 
3227
                port = smart.BZR_DEFAULT_PORT
3158
3228
                host = '127.0.0.1'
3159
 
            server = smart.SmartTCPServer(t, host=host, port=int(port))
 
3229
            else:
 
3230
                if ':' in port:
 
3231
                    host, port = port.split(':')
 
3232
                else:
 
3233
                    host = '127.0.0.1'
 
3234
                port = int(port)
 
3235
            server = smart.SmartTCPServer(t, host=host, port=port)
3160
3236
            print 'listening on port: ', server.port
3161
3237
            sys.stdout.flush()
3162
 
        else:
3163
 
            raise errors.BzrCommandError("bzr serve requires one of --inet or --port")
3164
3238
        server.serve()
3165
3239
 
 
3240
class cmd_join(Command):
 
3241
    """Combine a subtree into its containing tree.
 
3242
    
 
3243
    This is marked as a merge of the subtree into the containing tree, and all
 
3244
    history is preserved.
 
3245
    """
 
3246
 
 
3247
    takes_args = ['tree']
 
3248
    takes_options = [Option('reference', 'join by reference')]
 
3249
 
 
3250
    def run(self, tree, reference=False):
 
3251
        sub_tree = WorkingTree.open(tree)
 
3252
        parent_dir = osutils.dirname(sub_tree.basedir)
 
3253
        containing_tree = WorkingTree.open_containing(parent_dir)[0]
 
3254
        repo = containing_tree.branch.repository
 
3255
        if not repo.supports_rich_root():
 
3256
            raise errors.BzrCommandError(
 
3257
                "Can't join trees because %s doesn't support rich root data.\n"
 
3258
                "You can use bzr upgrade on the repository."
 
3259
                % (repo,))
 
3260
        if reference:
 
3261
            try:
 
3262
                containing_tree.add_reference(sub_tree)
 
3263
            except errors.BadReferenceTarget, e:
 
3264
                # XXX: Would be better to just raise a nicely printable
 
3265
                # exception from the real origin.  Also below.  mbp 20070306
 
3266
                raise errors.BzrCommandError("Cannot join %s.  %s" %
 
3267
                                             (tree, e.reason))
 
3268
        else:
 
3269
            try:
 
3270
                containing_tree.subsume(sub_tree)
 
3271
            except errors.BadSubsumeSource, e:
 
3272
                raise errors.BzrCommandError("Cannot join %s.  %s" % 
 
3273
                                             (tree, e.reason))
 
3274
 
 
3275
 
 
3276
class cmd_split(Command):
 
3277
    """Split a tree into two trees.
 
3278
    """
 
3279
 
 
3280
    takes_args = ['tree']
 
3281
 
 
3282
    def run(self, tree):
 
3283
        containing_tree, subdir = WorkingTree.open_containing(tree)
 
3284
        sub_id = containing_tree.path2id(subdir)
 
3285
        if sub_id is None:
 
3286
            raise errors.NotVersionedError(subdir)
 
3287
        try:
 
3288
            containing_tree.extract(sub_id)
 
3289
        except errors.RootNotRich:
 
3290
            raise errors.UpgradeRequired(containing_tree.branch.base)
 
3291
 
 
3292
 
 
3293
 
 
3294
class cmd_tag(Command):
 
3295
    """Create a tag naming a revision.
 
3296
    
 
3297
    Tags give human-meaningful names to revisions.  Commands that take a -r
 
3298
    (--revision) option can be given -rtag:X, where X is any previously
 
3299
    created tag.
 
3300
 
 
3301
    Tags are stored in the branch.  Tags are copied from one branch to another
 
3302
    along when you branch, push, pull or merge.
 
3303
 
 
3304
    It is an error to give a tag name that already exists unless you pass 
 
3305
    --force, in which case the tag is moved to point to the new revision.
 
3306
    """
 
3307
 
 
3308
    takes_args = ['tag_name']
 
3309
    takes_options = [
 
3310
        Option('delete',
 
3311
            help='Delete this tag rather than placing it.',
 
3312
            ),
 
3313
        Option('directory',
 
3314
            help='Branch in which to place the tag.',
 
3315
            short_name='d',
 
3316
            type=unicode,
 
3317
            ),
 
3318
        Option('force',
 
3319
            help='Replace existing tags',
 
3320
            ),
 
3321
        'revision',
 
3322
        ]
 
3323
 
 
3324
    def run(self, tag_name,
 
3325
            delete=None,
 
3326
            directory='.',
 
3327
            force=None,
 
3328
            revision=None,
 
3329
            ):
 
3330
        branch, relpath = Branch.open_containing(directory)
 
3331
        branch.lock_write()
 
3332
        try:
 
3333
            if delete:
 
3334
                branch.tags.delete_tag(tag_name)
 
3335
                self.outf.write('Deleted tag %s.\n' % tag_name)
 
3336
            else:
 
3337
                if revision:
 
3338
                    if len(revision) != 1:
 
3339
                        raise errors.BzrCommandError(
 
3340
                            "Tags can only be placed on a single revision, "
 
3341
                            "not on a range")
 
3342
                    revision_id = revision[0].in_history(branch).rev_id
 
3343
                else:
 
3344
                    revision_id = branch.last_revision()
 
3345
                if (not force) and branch.tags.has_tag(tag_name):
 
3346
                    raise errors.TagAlreadyExists(tag_name)
 
3347
                branch.tags.set_tag(tag_name, revision_id)
 
3348
                self.outf.write('Created tag %s.\n' % tag_name)
 
3349
        finally:
 
3350
            branch.unlock()
 
3351
 
 
3352
 
 
3353
class cmd_tags(Command):
 
3354
    """List tags.
 
3355
 
 
3356
    This tag shows a table of tag names and the revisions they reference.
 
3357
    """
 
3358
 
 
3359
    takes_options = [
 
3360
        Option('directory',
 
3361
            help='Branch whose tags should be displayed',
 
3362
            short_name='d',
 
3363
            type=unicode,
 
3364
            ),
 
3365
    ]
 
3366
 
 
3367
    @display_command
 
3368
    def run(self,
 
3369
            directory='.',
 
3370
            ):
 
3371
        branch, relpath = Branch.open_containing(directory)
 
3372
        for tag_name, target in sorted(branch.tags.get_tag_dict().items()):
 
3373
            self.outf.write('%-20s %s\n' % (tag_name, target))
 
3374
 
3166
3375
 
3167
3376
# command-line interpretation helper for merge-related commands
3168
3377
def _merge_helper(other_revision, base_revision,
3214
3423
                                     " type %s." % merge_type)
3215
3424
    if reprocess and show_base:
3216
3425
        raise errors.BzrCommandError("Cannot do conflict reduction and show base.")
 
3426
    # TODO: jam 20070226 We should really lock these trees earlier. However, we
 
3427
    #       only want to take out a lock_tree_write() if we don't have to pull
 
3428
    #       any ancestry. But merge might fetch ancestry in the middle, in
 
3429
    #       which case we would need a lock_write().
 
3430
    #       Because we cannot upgrade locks, for now we live with the fact that
 
3431
    #       the tree will be locked multiple times during a merge. (Maybe
 
3432
    #       read-only some of the time, but it means things will get read
 
3433
    #       multiple times.)
3217
3434
    try:
3218
3435
        merger = _mod_merge.Merger(this_tree.branch, this_tree=this_tree,
3219
3436
                                   pb=pb, change_reporter=change_reporter)
3228
3445
            return 0
3229
3446
        if file_list is None:
3230
3447
            if pull and merger.base_rev_id == merger.this_rev_id:
3231
 
                count = merger.this_tree.pull(merger.this_branch,
 
3448
                # FIXME: deduplicate with pull
 
3449
                result = merger.this_tree.pull(merger.this_branch,
3232
3450
                        False, merger.other_rev_id)
3233
 
                note('%d revision(s) pulled.' % (count,))
 
3451
                if result.old_revid == result.new_revid:
 
3452
                    note('No revisions to pull.')
 
3453
                else:
 
3454
                    note('Now on revision %d.' % result.new_revno)
3234
3455
                return 0
3235
3456
        merger.backup_files = backup_files
3236
3457
        merger.merge_type = merge_type