~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
36
36
    delta,
37
37
    config,
38
38
    errors,
 
39
    globbing,
39
40
    ignores,
40
41
    log,
41
42
    merge as _mod_merge,
347
348
            file_ids_from=None):
348
349
        import bzrlib.add
349
350
 
 
351
        base_tree = None
350
352
        if file_ids_from is not None:
351
353
            try:
352
354
                base_tree, base_path = WorkingTree.open_containing(
362
364
            action = bzrlib.add.AddAction(to_file=self.outf,
363
365
                should_print=(not is_quiet()))
364
366
 
365
 
        added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
366
 
                                              action=action, save=not dry_run)
 
367
        if base_tree:
 
368
            base_tree.lock_read()
 
369
        try:
 
370
            added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
 
371
                action=action, save=not dry_run)
 
372
        finally:
 
373
            if base_tree is not None:
 
374
                base_tree.unlock()
367
375
        if len(ignored) > 0:
368
376
            if verbose:
369
377
                for glob in sorted(ignored.keys()):
435
443
            raise errors.BzrCommandError('invalid kind specified')
436
444
 
437
445
        work_tree, file_list = tree_files(file_list)
438
 
 
439
 
        if revision is not None:
440
 
            if len(revision) > 1:
441
 
                raise errors.BzrCommandError('bzr inventory --revision takes'
442
 
                                             ' exactly one revision identifier')
443
 
            revision_id = revision[0].in_history(work_tree.branch).rev_id
444
 
            tree = work_tree.branch.repository.revision_tree(revision_id)
445
 
                        
446
 
            # We include work_tree as well as 'tree' here
447
 
            # So that doing '-r 10 path/foo' will lookup whatever file
448
 
            # exists now at 'path/foo' even if it has been renamed, as
449
 
            # well as whatever files existed in revision 10 at path/foo
450
 
            trees = [tree, work_tree]
451
 
        else:
452
 
            tree = work_tree
453
 
            trees = [tree]
454
 
 
455
 
        if file_list is not None:
456
 
            file_ids = _mod_tree.find_ids_across_trees(file_list, trees,
457
 
                                                      require_versioned=True)
458
 
            # find_ids_across_trees may include some paths that don't
459
 
            # exist in 'tree'.
460
 
            entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
461
 
                             for file_id in file_ids if file_id in tree)
462
 
        else:
463
 
            entries = tree.inventory.entries()
 
446
        work_tree.lock_read()
 
447
        try:
 
448
            if revision is not None:
 
449
                if len(revision) > 1:
 
450
                    raise errors.BzrCommandError(
 
451
                        'bzr inventory --revision takes exactly one revision'
 
452
                        ' identifier')
 
453
                revision_id = revision[0].in_history(work_tree.branch).rev_id
 
454
                tree = work_tree.branch.repository.revision_tree(revision_id)
 
455
 
 
456
                extra_trees = [work_tree]
 
457
                tree.lock_read()
 
458
            else:
 
459
                tree = work_tree
 
460
                extra_trees = []
 
461
 
 
462
            if file_list is not None:
 
463
                file_ids = tree.paths2ids(file_list, trees=extra_trees,
 
464
                                          require_versioned=True)
 
465
                # find_ids_across_trees may include some paths that don't
 
466
                # exist in 'tree'.
 
467
                entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
 
468
                                 for file_id in file_ids if file_id in tree)
 
469
            else:
 
470
                entries = tree.inventory.entries()
 
471
        finally:
 
472
            tree.unlock()
 
473
            if tree is not work_tree:
 
474
                work_tree.unlock()
464
475
 
465
476
        for path, entry in entries:
466
477
            if kind and kind != entry.kind:
604
615
        old_rh = branch_to.revision_history()
605
616
        if tree_to is not None:
606
617
            result = tree_to.pull(branch_from, overwrite, rev_id,
607
 
                delta.ChangeReporter(tree_to.inventory))
 
618
                delta.ChangeReporter(unversioned_filter=tree_to.is_ignored))
608
619
        else:
609
620
            result = branch_to.pull(branch_from, overwrite, rev_id)
610
621
 
975
986
    @display_command
976
987
    def run(self, dir=u'.'):
977
988
        tree = WorkingTree.open_containing(dir)[0]
978
 
        old_inv = tree.basis_tree().inventory
979
 
        new_inv = tree.read_working_inventory()
980
 
        renames = list(_mod_tree.find_renames(old_inv, new_inv))
981
 
        renames.sort()
982
 
        for old_name, new_name in renames:
983
 
            self.outf.write("%s => %s\n" % (old_name, new_name))
 
989
        tree.lock_read()
 
990
        try:
 
991
            new_inv = tree.inventory
 
992
            old_tree = tree.basis_tree()
 
993
            old_tree.lock_read()
 
994
            try:
 
995
                old_inv = old_tree.inventory
 
996
                renames = list(_mod_tree.find_renames(old_inv, new_inv))
 
997
                renames.sort()
 
998
                for old_name, new_name in renames:
 
999
                    self.outf.write("%s => %s\n" % (old_name, new_name))
 
1000
            finally:
 
1001
                old_tree.unlock()
 
1002
        finally:
 
1003
            tree.unlock()
984
1004
 
985
1005
 
986
1006
class cmd_update(Command):
1091
1111
    @display_command
1092
1112
    def run(self, filename):
1093
1113
        tree, relpath = WorkingTree.open_containing(filename)
1094
 
        i = tree.inventory.path2id(relpath)
 
1114
        i = tree.path2id(relpath)
1095
1115
        if i is None:
1096
1116
            raise errors.NotVersionedError(filename)
1097
1117
        else:
1111
1131
    @display_command
1112
1132
    def run(self, filename):
1113
1133
        tree, relpath = WorkingTree.open_containing(filename)
1114
 
        inv = tree.inventory
1115
 
        fid = inv.path2id(relpath)
 
1134
        fid = tree.path2id(relpath)
1116
1135
        if fid is None:
1117
1136
            raise errors.NotVersionedError(filename)
1118
 
        for fip in inv.get_idpath(fid):
1119
 
            self.outf.write(fip + '\n')
 
1137
        segments = osutils.splitpath(relpath)
 
1138
        for pos in range(1, len(segments) + 1):
 
1139
            path = osutils.joinpath(segments[:pos])
 
1140
            self.outf.write("%s\n" % tree.path2id(path))
1120
1141
 
1121
1142
 
1122
1143
class cmd_reconcile(Command):
1427
1448
    @display_command
1428
1449
    def run(self, show_ids=False):
1429
1450
        tree = WorkingTree.open_containing(u'.')[0]
1430
 
        old = tree.basis_tree()
1431
 
        for path, ie in old.inventory.iter_entries():
1432
 
            if not tree.has_id(ie.file_id):
1433
 
                self.outf.write(path)
1434
 
                if show_ids:
1435
 
                    self.outf.write(' ')
1436
 
                    self.outf.write(ie.file_id)
1437
 
                self.outf.write('\n')
 
1451
        tree.lock_read()
 
1452
        try:
 
1453
            old = tree.basis_tree()
 
1454
            old.lock_read()
 
1455
            try:
 
1456
                for path, ie in old.inventory.iter_entries():
 
1457
                    if not tree.has_id(ie.file_id):
 
1458
                        self.outf.write(path)
 
1459
                        if show_ids:
 
1460
                            self.outf.write(' ')
 
1461
                            self.outf.write(ie.file_id)
 
1462
                        self.outf.write('\n')
 
1463
            finally:
 
1464
                old.unlock()
 
1465
        finally:
 
1466
            tree.unlock()
1438
1467
 
1439
1468
 
1440
1469
class cmd_modified(Command):
1464
1493
    @display_command
1465
1494
    def run(self):
1466
1495
        wt = WorkingTree.open_containing(u'.')[0]
1467
 
        basis_inv = wt.basis_tree().inventory
1468
 
        inv = wt.inventory
1469
 
        for file_id in inv:
1470
 
            if file_id in basis_inv:
1471
 
                continue
1472
 
            if inv.is_root(file_id) and len(basis_inv) == 0:
1473
 
                continue
1474
 
            path = inv.id2path(file_id)
1475
 
            if not os.access(osutils.abspath(path), os.F_OK):
1476
 
                continue
1477
 
            self.outf.write(path + '\n')
 
1496
        wt.lock_read()
 
1497
        try:
 
1498
            basis = wt.basis_tree()
 
1499
            basis.lock_read()
 
1500
            try:
 
1501
                basis_inv = basis.inventory
 
1502
                inv = wt.inventory
 
1503
                for file_id in inv:
 
1504
                    if file_id in basis_inv:
 
1505
                        continue
 
1506
                    if inv.is_root(file_id) and len(basis_inv) == 0:
 
1507
                        continue
 
1508
                    path = inv.id2path(file_id)
 
1509
                    if not os.access(osutils.abspath(path), os.F_OK):
 
1510
                        continue
 
1511
                    self.outf.write(path + '\n')
 
1512
            finally:
 
1513
                basis.unlock()
 
1514
        finally:
 
1515
            wt.unlock()
1478
1516
 
1479
1517
 
1480
1518
class cmd_root(Command):
1546
1584
            if fp != '':
1547
1585
                if tree is None:
1548
1586
                    tree = b.basis_tree()
1549
 
                inv = tree.inventory
1550
 
                file_id = inv.path2id(fp)
 
1587
                file_id = tree.path2id(fp)
1551
1588
                if file_id is None:
1552
1589
                    raise errors.BzrCommandError(
1553
1590
                        "Path does not have any revision history: %s" %
1641
1678
    def run(self, filename):
1642
1679
        tree, relpath = WorkingTree.open_containing(filename)
1643
1680
        b = tree.branch
1644
 
        inv = tree.read_working_inventory()
1645
 
        file_id = inv.path2id(relpath)
 
1681
        file_id = tree.path2id(relpath)
1646
1682
        for revno, revision_id, what in log.find_touching_revisions(b, file_id):
1647
1683
            self.outf.write("%6d %s\n" % (revno, what))
1648
1684
 
1701
1737
        elif tree is None:
1702
1738
            tree = branch.basis_tree()
1703
1739
 
1704
 
        for fp, fc, fkind, fid, entry in tree.list_files(include_root=False):
1705
 
            if fp.startswith(relpath):
1706
 
                fp = osutils.pathjoin(prefix, fp[len(relpath):])
1707
 
                if non_recursive and '/' in fp:
1708
 
                    continue
1709
 
                if not all and not selection[fc]:
1710
 
                    continue
1711
 
                if kind is not None and fkind != kind:
1712
 
                    continue
1713
 
                if verbose:
1714
 
                    kindch = entry.kind_character()
1715
 
                    outstring = '%-8s %s%s' % (fc, fp, kindch)
1716
 
                    if show_ids and fid is not None:
1717
 
                        outstring = "%-50s %s" % (outstring, fid)
1718
 
                    self.outf.write(outstring + '\n')
1719
 
                elif null:
1720
 
                    self.outf.write(fp + '\0')
1721
 
                    if show_ids:
 
1740
        tree.lock_read()
 
1741
        try:
 
1742
            for fp, fc, fkind, fid, entry in tree.list_files(include_root=False):
 
1743
                if fp.startswith(relpath):
 
1744
                    fp = osutils.pathjoin(prefix, fp[len(relpath):])
 
1745
                    if non_recursive and '/' in fp:
 
1746
                        continue
 
1747
                    if not all and not selection[fc]:
 
1748
                        continue
 
1749
                    if kind is not None and fkind != kind:
 
1750
                        continue
 
1751
                    if verbose:
 
1752
                        kindch = entry.kind_character()
 
1753
                        outstring = '%-8s %s%s' % (fc, fp, kindch)
 
1754
                        if show_ids and fid is not None:
 
1755
                            outstring = "%-50s %s" % (outstring, fid)
 
1756
                        self.outf.write(outstring + '\n')
 
1757
                    elif null:
 
1758
                        self.outf.write(fp + '\0')
 
1759
                        if show_ids:
 
1760
                            if fid is not None:
 
1761
                                self.outf.write(fid)
 
1762
                            self.outf.write('\0')
 
1763
                        self.outf.flush()
 
1764
                    else:
1722
1765
                        if fid is not None:
1723
 
                            self.outf.write(fid)
1724
 
                        self.outf.write('\0')
1725
 
                    self.outf.flush()
1726
 
                else:
1727
 
                    if fid is not None:
1728
 
                        my_id = fid
1729
 
                    else:
1730
 
                        my_id = ''
1731
 
                    if show_ids:
1732
 
                        self.outf.write('%-50s %s\n' % (fp, my_id))
1733
 
                    else:
1734
 
                        self.outf.write(fp + '\n')
 
1766
                            my_id = fid
 
1767
                        else:
 
1768
                            my_id = ''
 
1769
                        if show_ids:
 
1770
                            self.outf.write('%-50s %s\n' % (fp, my_id))
 
1771
                        else:
 
1772
                            self.outf.write(fp + '\n')
 
1773
        finally:
 
1774
            tree.unlock()
1735
1775
 
1736
1776
 
1737
1777
class cmd_unknowns(Command):
1797
1837
        if not name_pattern_list:
1798
1838
            raise errors.BzrCommandError("ignore requires at least one "
1799
1839
                                  "NAME_PATTERN or --old-default-rules")
 
1840
        name_pattern_list = [globbing.normalize_pattern(p) 
 
1841
                             for p in name_pattern_list]
1800
1842
        for name_pattern in name_pattern_list:
1801
 
            if name_pattern[0] == '/':
 
1843
            if (name_pattern[0] == '/' or 
 
1844
                (len(name_pattern) > 1 and name_pattern[1] == ':')):
1802
1845
                raise errors.BzrCommandError(
1803
1846
                    "NAME_PATTERN should not be an absolute path")
1804
1847
        tree, relpath = WorkingTree.open_containing(u'.')
1818
1861
        if igns and igns[-1] != '\n':
1819
1862
            igns += '\n'
1820
1863
        for name_pattern in name_pattern_list:
1821
 
            igns += name_pattern.rstrip('/') + '\n'
 
1864
            igns += name_pattern + '\n'
1822
1865
 
1823
1866
        f = AtomicFile(ifn, 'wb')
1824
1867
        try:
1827
1870
        finally:
1828
1871
            f.close()
1829
1872
 
1830
 
        inv = tree.inventory
1831
 
        if inv.path2id('.bzrignore'):
1832
 
            mutter('.bzrignore is already versioned')
1833
 
        else:
1834
 
            mutter('need to make new .bzrignore file versioned')
 
1873
        if not tree.path2id('.bzrignore'):
1835
1874
            tree.add(['.bzrignore'])
1836
1875
 
1837
1876
 
1842
1881
    @display_command
1843
1882
    def run(self):
1844
1883
        tree = WorkingTree.open_containing(u'.')[0]
1845
 
        for path, file_class, kind, file_id, entry in tree.list_files():
1846
 
            if file_class != 'I':
1847
 
                continue
1848
 
            ## XXX: Slightly inefficient since this was already calculated
1849
 
            pat = tree.is_ignored(path)
1850
 
            print '%-50s %s' % (path, pat)
 
1884
        tree.lock_read()
 
1885
        try:
 
1886
            for path, file_class, kind, file_id, entry in tree.list_files():
 
1887
                if file_class != 'I':
 
1888
                    continue
 
1889
                ## XXX: Slightly inefficient since this was already calculated
 
1890
                pat = tree.is_ignored(path)
 
1891
                print '%-50s %s' % (path, pat)
 
1892
        finally:
 
1893
            tree.unlock()
1851
1894
 
1852
1895
 
1853
1896
class cmd_lookup_revision(Command):
2124
2167
                        value_switches=True, title='Branch format'),
2125
2168
                    ]
2126
2169
 
2127
 
 
2128
2170
    def run(self, url='.', format=None):
2129
2171
        from bzrlib.upgrade import upgrade
2130
2172
        if format is None:
2222
2264
            run only tests relating to 'ignore'
2223
2265
        bzr --no-plugins selftest -v
2224
2266
            disable plugins and list tests as they're run
 
2267
 
 
2268
    For each test, that needs actual disk access, bzr create their own
 
2269
    subdirectory in the temporary testing directory (testXXXX.tmp).
 
2270
    By default the name of such subdirectory is based on the name of the test.
 
2271
    If option '--numbered-dirs' is given, bzr will use sequent numbers
 
2272
    of running tests to create such subdirectories. This is default behavior
 
2273
    on Windows because of path length limitation.
2225
2274
    """
2226
2275
    # TODO: --list should give a list of all available tests
2227
2276
 
2264
2313
                                 ' without running tests'),
2265
2314
                     Option('first',
2266
2315
                            help='run all tests, but run specified tests first',
2267
 
                            )
 
2316
                            ),
 
2317
                     Option('numbered-dirs',
 
2318
                            help='use numbered dirs for TestCaseInTempDir'),
2268
2319
                     ]
2269
2320
    encoding_type = 'replace'
2270
2321
 
2271
2322
    def run(self, testspecs_list=None, verbose=None, one=False,
2272
2323
            keep_output=False, transport=None, benchmark=None,
2273
2324
            lsprof_timed=None, cache_dir=None, clean_output=False,
2274
 
            first=False):
 
2325
            first=False, numbered_dirs=None):
2275
2326
        import bzrlib.ui
2276
2327
        from bzrlib.tests import selftest
2277
2328
        import bzrlib.benchmarks as benchmarks
2282
2333
            clean_selftest_output()
2283
2334
            return 0
2284
2335
 
 
2336
        if numbered_dirs is None and sys.platform == 'win32':
 
2337
            numbered_dirs = True
 
2338
 
2285
2339
        if cache_dir is not None:
2286
2340
            tree_creator.TreeCreator.CACHE_ROOT = osutils.abspath(cache_dir)
2287
2341
        print '%10s: %s' % ('bzr', osutils.realpath(sys.argv[0]))
2312
2366
                              lsprof_timed=lsprof_timed,
2313
2367
                              bench_history=benchfile,
2314
2368
                              matching_tests_first=first,
 
2369
                              numbered_dirs=numbered_dirs,
2315
2370
                              )
2316
2371
        finally:
2317
2372
            if benchfile is not None:
2440
2495
            merge_type = _mod_merge.Merge3Merger
2441
2496
 
2442
2497
        if directory is None: directory = u'.'
 
2498
        # XXX: jam 20070225 WorkingTree should be locked before you extract its
 
2499
        #      inventory. Because merge is a mutating operation, it really
 
2500
        #      should be a lock_write() for the whole cmd_merge operation.
 
2501
        #      However, cmd_merge open's its own tree in _merge_helper, which
 
2502
        #      means if we lock here, the later lock_write() will always block.
 
2503
        #      Either the merge helper code should be updated to take a tree,
 
2504
        #      (What about tree.merge_from_branch?)
2443
2505
        tree = WorkingTree.open_containing(directory)[0]
2444
 
        change_reporter = delta.ChangeReporter(tree.inventory)
 
2506
        change_reporter = delta.ChangeReporter(
 
2507
            unversioned_filter=tree.is_ignored)
2445
2508
 
2446
2509
        if branch is not None:
2447
2510
            try:
2911
2974
                raise errors.BzrCommandError('bzr annotate --revision takes exactly 1 argument')
2912
2975
            else:
2913
2976
                revision_id = revision[0].in_history(branch).rev_id
2914
 
            file_id = tree.inventory.path2id(relpath)
 
2977
            file_id = tree.path2id(relpath)
2915
2978
            tree = branch.repository.revision_tree(revision_id)
2916
2979
            file_version = tree.inventory[file_id].revision
2917
2980
            annotate_file(branch, file_version, file_id, long, all, sys.stdout,
3179
3242
            sys.stdout.flush()
3180
3243
        server.serve()
3181
3244
 
 
3245
class cmd_join(Command):
 
3246
    """Combine a subtree into its containing tree.
 
3247
    
 
3248
    This is marked as a merge of the subtree into the containing tree, and all
 
3249
    history is preserved.
 
3250
    """
 
3251
 
 
3252
    takes_args = ['tree']
 
3253
    takes_options = [Option('reference', 'join by reference')]
 
3254
 
 
3255
    def run(self, tree, reference=False):
 
3256
        sub_tree = WorkingTree.open(tree)
 
3257
        parent_dir = osutils.dirname(sub_tree.basedir)
 
3258
        containing_tree = WorkingTree.open_containing(parent_dir)[0]
 
3259
        repo = containing_tree.branch.repository
 
3260
        if not repo.supports_rich_root():
 
3261
            raise errors.BzrCommandError(
 
3262
                "Can't join trees because %s doesn't support rich root data.\n"
 
3263
                "You can use bzr upgrade on the repository."
 
3264
                % (repo,))
 
3265
        if reference:
 
3266
            try:
 
3267
                containing_tree.add_reference(sub_tree)
 
3268
            except errors.BadReferenceTarget, e:
 
3269
                # XXX: Would be better to just raise a nicely printable
 
3270
                # exception from the real origin.  Also below.  mbp 20070306
 
3271
                raise errors.BzrCommandError("Cannot join %s.  %s" %
 
3272
                                             (tree, e.reason))
 
3273
        else:
 
3274
            try:
 
3275
                containing_tree.subsume(sub_tree)
 
3276
            except errors.BadSubsumeSource, e:
 
3277
                raise errors.BzrCommandError("Cannot join %s.  %s" % 
 
3278
                                             (tree, e.reason))
 
3279
 
 
3280
 
 
3281
class cmd_split(Command):
 
3282
    """Split a tree into two trees.
 
3283
    """
 
3284
 
 
3285
    takes_args = ['tree']
 
3286
 
 
3287
    def run(self, tree):
 
3288
        containing_tree, subdir = WorkingTree.open_containing(tree)
 
3289
        sub_id = containing_tree.path2id(subdir)
 
3290
        if sub_id is None:
 
3291
            raise errors.NotVersionedError(subdir)
 
3292
        try:
 
3293
            containing_tree.extract(sub_id)
 
3294
        except errors.RootNotRich:
 
3295
            raise errors.UpgradeRequired(containing_tree.branch.base)
 
3296
 
 
3297
 
3182
3298
 
3183
3299
class cmd_merge_directive(Command):
3184
3300
    """Generate a merge directive for auto-merge tools.
3395
3511
                                     " type %s." % merge_type)
3396
3512
    if reprocess and show_base:
3397
3513
        raise errors.BzrCommandError("Cannot do conflict reduction and show base.")
 
3514
    # TODO: jam 20070226 We should really lock these trees earlier. However, we
 
3515
    #       only want to take out a lock_tree_write() if we don't have to pull
 
3516
    #       any ancestry. But merge might fetch ancestry in the middle, in
 
3517
    #       which case we would need a lock_write().
 
3518
    #       Because we cannot upgrade locks, for now we live with the fact that
 
3519
    #       the tree will be locked multiple times during a merge. (Maybe
 
3520
    #       read-only some of the time, but it means things will get read
 
3521
    #       multiple times.)
3398
3522
    try:
3399
3523
        merger = _mod_merge.Merger(this_tree.branch, this_tree=this_tree,
3400
3524
                                   pb=pb, change_reporter=change_reporter)