~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/builtins.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-03-07 10:45:44 UTC
  • mfrom: (2321.1.2 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20070307104544-59e3e6358e4bdb29
(robertc) Merge dirstate and subtrees. (Robert Collins, Martin Pool, Aaaron Bentley, John A Meinel, James Westby)

Show diffs side-by-side

added added

removed removed

Lines of Context:
343
343
            file_ids_from=None):
344
344
        import bzrlib.add
345
345
 
 
346
        base_tree = None
346
347
        if file_ids_from is not None:
347
348
            try:
348
349
                base_tree, base_path = WorkingTree.open_containing(
358
359
            action = bzrlib.add.AddAction(to_file=self.outf,
359
360
                should_print=(not is_quiet()))
360
361
 
361
 
        added, ignored = bzrlib.add.smart_add(file_list, not no_recurse,
362
 
                                              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()
363
370
        if len(ignored) > 0:
364
371
            if verbose:
365
372
                for glob in sorted(ignored.keys()):
431
438
            raise errors.BzrCommandError('invalid kind specified')
432
439
 
433
440
        work_tree, file_list = tree_files(file_list)
434
 
 
435
 
        if revision is not None:
436
 
            if len(revision) > 1:
437
 
                raise errors.BzrCommandError('bzr inventory --revision takes'
438
 
                                             ' exactly one revision identifier')
439
 
            revision_id = revision[0].in_history(work_tree.branch).rev_id
440
 
            tree = work_tree.branch.repository.revision_tree(revision_id)
441
 
                        
442
 
            # We include work_tree as well as 'tree' here
443
 
            # So that doing '-r 10 path/foo' will lookup whatever file
444
 
            # exists now at 'path/foo' even if it has been renamed, as
445
 
            # well as whatever files existed in revision 10 at path/foo
446
 
            trees = [tree, work_tree]
447
 
        else:
448
 
            tree = work_tree
449
 
            trees = [tree]
450
 
 
451
 
        if file_list is not None:
452
 
            file_ids = _mod_tree.find_ids_across_trees(file_list, trees,
453
 
                                                      require_versioned=True)
454
 
            # find_ids_across_trees may include some paths that don't
455
 
            # exist in 'tree'.
456
 
            entries = sorted((tree.id2path(file_id), tree.inventory[file_id])
457
 
                             for file_id in file_ids if file_id in tree)
458
 
        else:
459
 
            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()
460
470
 
461
471
        for path, entry in entries:
462
472
            if kind and kind != entry.kind:
600
610
        old_rh = branch_to.revision_history()
601
611
        if tree_to is not None:
602
612
            result = tree_to.pull(branch_from, overwrite, rev_id,
603
 
                delta.ChangeReporter(tree_to.inventory))
 
613
                delta.ChangeReporter(unversioned_filter=tree_to.is_ignored))
604
614
        else:
605
615
            result = branch_to.pull(branch_from, overwrite, rev_id)
606
616
 
971
981
    @display_command
972
982
    def run(self, dir=u'.'):
973
983
        tree = WorkingTree.open_containing(dir)[0]
974
 
        old_inv = tree.basis_tree().inventory
975
 
        new_inv = tree.read_working_inventory()
976
 
        renames = list(_mod_tree.find_renames(old_inv, new_inv))
977
 
        renames.sort()
978
 
        for old_name, new_name in renames:
979
 
            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()
980
999
 
981
1000
 
982
1001
class cmd_update(Command):
1087
1106
    @display_command
1088
1107
    def run(self, filename):
1089
1108
        tree, relpath = WorkingTree.open_containing(filename)
1090
 
        i = tree.inventory.path2id(relpath)
 
1109
        i = tree.path2id(relpath)
1091
1110
        if i is None:
1092
1111
            raise errors.NotVersionedError(filename)
1093
1112
        else:
1107
1126
    @display_command
1108
1127
    def run(self, filename):
1109
1128
        tree, relpath = WorkingTree.open_containing(filename)
1110
 
        inv = tree.inventory
1111
 
        fid = inv.path2id(relpath)
 
1129
        fid = tree.path2id(relpath)
1112
1130
        if fid is None:
1113
1131
            raise errors.NotVersionedError(filename)
1114
 
        for fip in inv.get_idpath(fid):
1115
 
            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))
1116
1136
 
1117
1137
 
1118
1138
class cmd_reconcile(Command):
1423
1443
    @display_command
1424
1444
    def run(self, show_ids=False):
1425
1445
        tree = WorkingTree.open_containing(u'.')[0]
1426
 
        old = tree.basis_tree()
1427
 
        for path, ie in old.inventory.iter_entries():
1428
 
            if not tree.has_id(ie.file_id):
1429
 
                self.outf.write(path)
1430
 
                if show_ids:
1431
 
                    self.outf.write(' ')
1432
 
                    self.outf.write(ie.file_id)
1433
 
                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()
1434
1462
 
1435
1463
 
1436
1464
class cmd_modified(Command):
1460
1488
    @display_command
1461
1489
    def run(self):
1462
1490
        wt = WorkingTree.open_containing(u'.')[0]
1463
 
        basis_inv = wt.basis_tree().inventory
1464
 
        inv = wt.inventory
1465
 
        for file_id in inv:
1466
 
            if file_id in basis_inv:
1467
 
                continue
1468
 
            if inv.is_root(file_id) and len(basis_inv) == 0:
1469
 
                continue
1470
 
            path = inv.id2path(file_id)
1471
 
            if not os.access(osutils.abspath(path), os.F_OK):
1472
 
                continue
1473
 
            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()
1474
1511
 
1475
1512
 
1476
1513
class cmd_root(Command):
1542
1579
            if fp != '':
1543
1580
                if tree is None:
1544
1581
                    tree = b.basis_tree()
1545
 
                inv = tree.inventory
1546
 
                file_id = inv.path2id(fp)
 
1582
                file_id = tree.path2id(fp)
1547
1583
                if file_id is None:
1548
1584
                    raise errors.BzrCommandError(
1549
1585
                        "Path does not have any revision history: %s" %
1637
1673
    def run(self, filename):
1638
1674
        tree, relpath = WorkingTree.open_containing(filename)
1639
1675
        b = tree.branch
1640
 
        inv = tree.read_working_inventory()
1641
 
        file_id = inv.path2id(relpath)
 
1676
        file_id = tree.path2id(relpath)
1642
1677
        for revno, revision_id, what in log.find_touching_revisions(b, file_id):
1643
1678
            self.outf.write("%6d %s\n" % (revno, what))
1644
1679
 
1697
1732
        elif tree is None:
1698
1733
            tree = branch.basis_tree()
1699
1734
 
1700
 
        for fp, fc, fkind, fid, entry in tree.list_files(include_root=False):
1701
 
            if fp.startswith(relpath):
1702
 
                fp = osutils.pathjoin(prefix, fp[len(relpath):])
1703
 
                if non_recursive and '/' in fp:
1704
 
                    continue
1705
 
                if not all and not selection[fc]:
1706
 
                    continue
1707
 
                if kind is not None and fkind != kind:
1708
 
                    continue
1709
 
                if verbose:
1710
 
                    kindch = entry.kind_character()
1711
 
                    outstring = '%-8s %s%s' % (fc, fp, kindch)
1712
 
                    if show_ids and fid is not None:
1713
 
                        outstring = "%-50s %s" % (outstring, fid)
1714
 
                    self.outf.write(outstring + '\n')
1715
 
                elif null:
1716
 
                    self.outf.write(fp + '\0')
1717
 
                    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:
1718
1760
                        if fid is not None:
1719
 
                            self.outf.write(fid)
1720
 
                        self.outf.write('\0')
1721
 
                    self.outf.flush()
1722
 
                else:
1723
 
                    if fid is not None:
1724
 
                        my_id = fid
1725
 
                    else:
1726
 
                        my_id = ''
1727
 
                    if show_ids:
1728
 
                        self.outf.write('%-50s %s\n' % (fp, my_id))
1729
 
                    else:
1730
 
                        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()
1731
1770
 
1732
1771
 
1733
1772
class cmd_unknowns(Command):
1826
1865
        finally:
1827
1866
            f.close()
1828
1867
 
1829
 
        inv = tree.inventory
1830
 
        if inv.path2id('.bzrignore'):
1831
 
            mutter('.bzrignore is already versioned')
1832
 
        else:
1833
 
            mutter('need to make new .bzrignore file versioned')
 
1868
        if not tree.path2id('.bzrignore'):
1834
1869
            tree.add(['.bzrignore'])
1835
1870
 
1836
1871
 
1841
1876
    @display_command
1842
1877
    def run(self):
1843
1878
        tree = WorkingTree.open_containing(u'.')[0]
1844
 
        for path, file_class, kind, file_id, entry in tree.list_files():
1845
 
            if file_class != 'I':
1846
 
                continue
1847
 
            ## XXX: Slightly inefficient since this was already calculated
1848
 
            pat = tree.is_ignored(path)
1849
 
            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()
1850
1889
 
1851
1890
 
1852
1891
class cmd_lookup_revision(Command):
2123
2162
                        value_switches=True, title='Branch format'),
2124
2163
                    ]
2125
2164
 
2126
 
 
2127
2165
    def run(self, url='.', format=None):
2128
2166
        from bzrlib.upgrade import upgrade
2129
2167
        if format is None:
2439
2477
            merge_type = _mod_merge.Merge3Merger
2440
2478
 
2441
2479
        if directory is None: directory = u'.'
 
2480
        # XXX: jam 20070225 WorkingTree should be locked before you extract its
 
2481
        #      inventory. Because merge is a mutating operation, it really
 
2482
        #      should be a lock_write() for the whole cmd_merge operation.
 
2483
        #      However, cmd_merge open's its own tree in _merge_helper, which
 
2484
        #      means if we lock here, the later lock_write() will always block.
 
2485
        #      Either the merge helper code should be updated to take a tree,
 
2486
        #      (What about tree.merge_from_branch?)
2442
2487
        tree = WorkingTree.open_containing(directory)[0]
2443
 
        change_reporter = delta.ChangeReporter(tree.inventory)
 
2488
        change_reporter = delta.ChangeReporter(
 
2489
            unversioned_filter=tree.is_ignored)
2444
2490
 
2445
2491
        if branch is not None:
2446
2492
            try:
2910
2956
                raise errors.BzrCommandError('bzr annotate --revision takes exactly 1 argument')
2911
2957
            else:
2912
2958
                revision_id = revision[0].in_history(branch).rev_id
2913
 
            file_id = tree.inventory.path2id(relpath)
 
2959
            file_id = tree.path2id(relpath)
2914
2960
            tree = branch.repository.revision_tree(revision_id)
2915
2961
            file_version = tree.inventory[file_id].revision
2916
2962
            annotate_file(branch, file_version, file_id, long, all, sys.stdout,
3178
3224
            sys.stdout.flush()
3179
3225
        server.serve()
3180
3226
 
 
3227
class cmd_join(Command):
 
3228
    """Combine a subtree into its containing tree.
 
3229
    
 
3230
    This is marked as a merge of the subtree into the containing tree, and all
 
3231
    history is preserved.
 
3232
    """
 
3233
 
 
3234
    takes_args = ['tree']
 
3235
    takes_options = [Option('reference', 'join by reference')]
 
3236
 
 
3237
    def run(self, tree, reference=False):
 
3238
        sub_tree = WorkingTree.open(tree)
 
3239
        parent_dir = osutils.dirname(sub_tree.basedir)
 
3240
        containing_tree = WorkingTree.open_containing(parent_dir)[0]
 
3241
        repo = containing_tree.branch.repository
 
3242
        if not repo.supports_rich_root():
 
3243
            raise errors.BzrCommandError(
 
3244
                "Can't join trees because %s doesn't support rich root data.\n"
 
3245
                "You can use bzr upgrade on the repository."
 
3246
                % (repo,))
 
3247
        if reference:
 
3248
            try:
 
3249
                containing_tree.add_reference(sub_tree)
 
3250
            except errors.BadReferenceTarget, e:
 
3251
                # XXX: Would be better to just raise a nicely printable
 
3252
                # exception from the real origin.  Also below.  mbp 20070306
 
3253
                raise errors.BzrCommandError("Cannot join %s.  %s" %
 
3254
                                             (tree, e.reason))
 
3255
        else:
 
3256
            try:
 
3257
                containing_tree.subsume(sub_tree)
 
3258
            except errors.BadSubsumeSource, e:
 
3259
                raise errors.BzrCommandError("Cannot join %s.  %s" % 
 
3260
                                             (tree, e.reason))
 
3261
 
 
3262
 
 
3263
class cmd_split(Command):
 
3264
    """Split a tree into two trees.
 
3265
    """
 
3266
 
 
3267
    takes_args = ['tree']
 
3268
 
 
3269
    def run(self, tree):
 
3270
        containing_tree, subdir = WorkingTree.open_containing(tree)
 
3271
        sub_id = containing_tree.path2id(subdir)
 
3272
        if sub_id is None:
 
3273
            raise errors.NotVersionedError(subdir)
 
3274
        try:
 
3275
            containing_tree.extract(sub_id)
 
3276
        except errors.RootNotRich:
 
3277
            raise errors.UpgradeRequired(containing_tree.branch.base)
 
3278
 
 
3279
 
3181
3280
 
3182
3281
class cmd_tag(Command):
3183
3282
    """Create a tag naming a revision.
3311
3410
                                     " type %s." % merge_type)
3312
3411
    if reprocess and show_base:
3313
3412
        raise errors.BzrCommandError("Cannot do conflict reduction and show base.")
 
3413
    # TODO: jam 20070226 We should really lock these trees earlier. However, we
 
3414
    #       only want to take out a lock_tree_write() if we don't have to pull
 
3415
    #       any ancestry. But merge might fetch ancestry in the middle, in
 
3416
    #       which case we would need a lock_write().
 
3417
    #       Because we cannot upgrade locks, for now we live with the fact that
 
3418
    #       the tree will be locked multiple times during a merge. (Maybe
 
3419
    #       read-only some of the time, but it means things will get read
 
3420
    #       multiple times.)
3314
3421
    try:
3315
3422
        merger = _mod_merge.Merger(this_tree.branch, this_tree=this_tree,
3316
3423
                                   pb=pb, change_reporter=change_reporter)