~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transform.py

Merge up bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
    bzrdir,
26
26
    delta,
27
27
    errors,
28
 
    inventory
 
28
    inventory,
 
29
    revision as _mod_revision,
29
30
    )
30
31
""")
31
32
from bzrlib.errors import (DuplicateKey, MalformedTransform, NoSuchFile,
38
39
from bzrlib.progress import DummyProgress, ProgressPhase
39
40
from bzrlib.symbol_versioning import (
40
41
        deprecated_function,
41
 
        zero_fifteen,
42
 
        zero_ninety,
43
42
        )
44
43
from bzrlib.trace import mutter, warning
45
44
from bzrlib import tree
440
439
 
441
440
    def version_file(self, file_id, trans_id):
442
441
        """Schedule a file to become versioned."""
443
 
        assert file_id is not None
 
442
        if file_id is None:
 
443
            raise ValueError()
444
444
        unique_add(self._new_id, trans_id, file_id)
445
445
        unique_add(self._r_new_id, file_id, trans_id)
446
446
 
510
510
        applied.
511
511
        """
512
512
        try:
513
 
            # there is a new id for this file
514
 
            assert self._new_id[trans_id] is not None
515
513
            return self._new_id[trans_id]
516
514
        except KeyError:
517
515
            if trans_id in self._removed_id:
1242
1240
                        file_id = self._tree.get_root_id()
1243
1241
                    else:
1244
1242
                        file_id = self.tree_file_id(trans_id)
1245
 
                    assert file_id is not None
1246
1243
                    # File-id isn't really being deleted, just moved
1247
1244
                    if file_id in self._r_new_id:
1248
1245
                        continue
1359
1356
            yield self.trans_id_tree_path(childpath)
1360
1357
 
1361
1358
 
1362
 
class _PreviewTree(object):
 
1359
class _PreviewTree(tree.Tree):
1363
1360
    """Partial implementation of Tree to support show_diff_trees"""
1364
1361
 
1365
1362
    def __init__(self, transform):
1366
1363
        self._transform = transform
 
1364
        self._final_paths = FinalPaths(transform)
 
1365
 
 
1366
    def _changes(self, file_id):
 
1367
        for changes in self._transform.iter_changes():
 
1368
            if changes[0] == file_id:
 
1369
                return changes
 
1370
 
 
1371
    def _content_change(self, file_id):
 
1372
        """Return True if the content of this file changed"""
 
1373
        changes = self._changes(file_id)
 
1374
        # changes[2] is true if the file content changed.  See
 
1375
        # InterTree.iter_changes.
 
1376
        return (changes is not None and changes[2])
 
1377
 
 
1378
    def _get_file_revision(self, file_id, vf, tree_revision):
 
1379
        return self._transform._tree._get_file_revision(file_id, vf,
 
1380
                                                        tree_revision)
 
1381
 
 
1382
    def _stat_limbo_file(self, file_id):
 
1383
        trans_id = self._transform.trans_id_file_id(file_id)
 
1384
        name = self._transform._limbo_name(trans_id)
 
1385
        return os.lstat(name)
1367
1386
 
1368
1387
    def lock_read(self):
1369
1388
        # Perhaps in theory, this should lock the TreeTransform?
1372
1391
    def unlock(self):
1373
1392
        pass
1374
1393
 
 
1394
    @property
 
1395
    def inventory(self):
 
1396
        """This Tree does not use inventory as its backing data."""
 
1397
        raise NotImplementedError(_PreviewTree.inventory)
 
1398
 
 
1399
    def get_root_id(self):
 
1400
        return self._transform.final_file_id(self._transform.root)
 
1401
 
 
1402
    def all_file_ids(self):
 
1403
        return self._transform._tree.all_file_ids()
 
1404
 
 
1405
    def __iter__(self):
 
1406
        return iter(self.all_file_ids())
 
1407
 
 
1408
    def paths2ids(self, specific_files, trees=None, require_versioned=False):
 
1409
        """See Tree.paths2ids"""
 
1410
        to_find = set(specific_files)
 
1411
        result = set()
 
1412
        for (file_id, paths, changed, versioned, parent, name, kind,
 
1413
             executable) in self._transform.iter_changes():
 
1414
            if paths[1] in to_find:
 
1415
                result.append(file_id)
 
1416
                to_find.remove(paths[1])
 
1417
        result.update(self._transform._tree.paths2ids(to_find,
 
1418
                      trees=[], require_versioned=require_versioned))
 
1419
        return result
 
1420
 
 
1421
    def path2id(self, path):
 
1422
        return self._transform._tree.path2id(path)
 
1423
 
 
1424
    def id2path(self, file_id):
 
1425
        trans_id = self._transform.trans_id_file_id(file_id)
 
1426
        try:
 
1427
            return self._final_paths._determine_path(trans_id)
 
1428
        except NoFinalPath:
 
1429
            raise errors.NoSuchId(self, file_id)
 
1430
 
 
1431
    def iter_entries_by_dir(self, specific_file_ids=None):
 
1432
        return self._transform._tree.iter_entries_by_dir(specific_file_ids)
 
1433
 
 
1434
    def kind(self, file_id):
 
1435
        trans_id = self._transform.trans_id_file_id(file_id)
 
1436
        return self._transform.final_kind(trans_id)
 
1437
 
 
1438
    def stored_kind(self, file_id):
 
1439
        return self._transform._tree.stored_kind(file_id)
 
1440
 
 
1441
    def get_file_mtime(self, file_id, path=None):
 
1442
        """See Tree.get_file_mtime"""
 
1443
        if not self._content_change(file_id):
 
1444
            return self._transform._tree.get_file_mtime(file_id, path)
 
1445
        return self._stat_limbo_file(file_id).st_mtime
 
1446
 
 
1447
    def get_file_size(self, file_id):
 
1448
        """See Tree.get_file_size"""
 
1449
        if self.kind(file_id) == 'file':
 
1450
            return self._transform._tree.get_file_size(file_id)
 
1451
        else:
 
1452
            return None
 
1453
 
 
1454
    def get_file_sha1(self, file_id, path=None, stat_value=None):
 
1455
        return self._transform._tree.get_file_sha1(file_id)
 
1456
 
 
1457
    def is_executable(self, file_id, path=None):
 
1458
        return self._transform._tree.is_executable(file_id, path)
 
1459
 
 
1460
    def path_content_summary(self, path):
 
1461
        return self._transform._tree.path_content_summary(path)
 
1462
 
1375
1463
    def iter_changes(self, from_tree, include_unchanged=False,
1376
1464
                      specific_files=None, pb=None, extra_trees=None,
1377
1465
                      require_versioned=True, want_unversioned=False):
1391
1479
            raise ValueError('want_unversioned is not supported')
1392
1480
        return self._transform.iter_changes()
1393
1481
 
1394
 
    def kind(self, file_id):
1395
 
        trans_id = self._transform.trans_id_file_id(file_id)
1396
 
        return self._transform.final_kind(trans_id)
1397
 
 
1398
 
    def get_file_mtime(self, file_id, path=None):
1399
 
        """See Tree.get_file_mtime"""
1400
 
        trans_id = self._transform.trans_id_file_id(file_id)
1401
 
        name = self._transform._limbo_name(trans_id)
1402
 
        return os.stat(name).st_mtime
1403
 
 
1404
 
    def get_file(self, file_id):
 
1482
    def get_file(self, file_id, path=None):
1405
1483
        """See Tree.get_file"""
 
1484
        if not self._content_change(file_id):
 
1485
            return self._transform._tree.get_file(file_id, path)
1406
1486
        trans_id = self._transform.trans_id_file_id(file_id)
1407
1487
        name = self._transform._limbo_name(trans_id)
1408
1488
        return open(name, 'rb')
1409
1489
 
 
1490
    def get_file_text(self, file_id):
 
1491
        text_file = self.get_file(file_id)
 
1492
        try:
 
1493
            return text_file.read()
 
1494
        finally:
 
1495
            text_file.close()
 
1496
 
 
1497
    def annotate_iter(self, file_id,
 
1498
                      default_revision=_mod_revision.CURRENT_REVISION):
 
1499
        return self._transform._tree.annotate_iter(file_id,
 
1500
            default_revision=default_revision)
 
1501
 
1410
1502
    def get_symlink_target(self, file_id):
1411
1503
        """See Tree.get_symlink_target"""
 
1504
        if not self._content_change(file_id):
 
1505
            return self._transform._tree.get_symlink_target(file_id)
1412
1506
        trans_id = self._transform.trans_id_file_id(file_id)
1413
1507
        name = self._transform._limbo_name(trans_id)
1414
1508
        return os.readlink(name)
1415
1509
 
1416
 
    def paths2ids(self, specific_files, trees=None, require_versioned=False):
1417
 
        """See Tree.paths2ids"""
1418
 
        return 'not_empty'
 
1510
    def list_files(self, include_root=False):
 
1511
        return self._transform._tree.list_files(include_root)
 
1512
 
 
1513
    def walkdirs(self, prefix=""):
 
1514
        return self._transform._tree.walkdirs(prefix)
 
1515
 
 
1516
    def get_parent_ids(self):
 
1517
        return self._transform._tree.get_parent_ids()
 
1518
 
 
1519
    def get_revision_tree(self, revision_id):
 
1520
        return self._transform._tree.get_revision_tree(revision_id)
1419
1521
 
1420
1522
 
1421
1523
def joinpath(parent, child):
1664
1766
    new_conflicts = set()
1665
1767
    for c_type, conflict in ((c[0], c) for c in conflicts):
1666
1768
        # Anything but a 'duplicate' would indicate programmer error
1667
 
        assert c_type == 'duplicate', c_type
 
1769
        if c_type != 'duplicate':
 
1770
            raise AssertionError(c_type)
1668
1771
        # Now figure out which is new and which is old
1669
1772
        if tt.new_contents(conflict[1]):
1670
1773
            new_file = conflict[1]
1728
1831
        tt.set_executability(entry.executable, trans_id)
1729
1832
 
1730
1833
 
1731
 
@deprecated_function(zero_fifteen)
1732
 
def find_interesting(working_tree, target_tree, filenames):
1733
 
    """Find the ids corresponding to specified filenames.
1734
 
    
1735
 
    Deprecated: Please use tree1.paths2ids(filenames, [tree2]).
1736
 
    """
1737
 
    working_tree.lock_read()
1738
 
    try:
1739
 
        target_tree.lock_read()
1740
 
        try:
1741
 
            return working_tree.paths2ids(filenames, [target_tree])
1742
 
        finally:
1743
 
            target_tree.unlock()
1744
 
    finally:
1745
 
        working_tree.unlock()
1746
 
 
1747
 
 
1748
 
@deprecated_function(zero_ninety)
1749
 
def change_entry(tt, file_id, working_tree, target_tree, 
1750
 
                 trans_id_file_id, backups, trans_id, by_parent):
1751
 
    """Replace a file_id's contents with those from a target tree."""
1752
 
    if file_id is None and target_tree is None:
1753
 
        # skip the logic altogether in the deprecation test
1754
 
        return
1755
 
    e_trans_id = trans_id_file_id(file_id)
1756
 
    entry = target_tree.inventory[file_id]
1757
 
    has_contents, contents_mod, meta_mod, = _entry_changes(file_id, entry, 
1758
 
                                                           working_tree)
1759
 
    if contents_mod:
1760
 
        mode_id = e_trans_id
1761
 
        if has_contents:
1762
 
            if not backups:
1763
 
                tt.delete_contents(e_trans_id)
1764
 
            else:
1765
 
                parent_trans_id = trans_id_file_id(entry.parent_id)
1766
 
                backup_name = get_backup_name(entry, by_parent,
1767
 
                                              parent_trans_id, tt)
1768
 
                tt.adjust_path(backup_name, parent_trans_id, e_trans_id)
1769
 
                tt.unversion_file(e_trans_id)
1770
 
                e_trans_id = tt.create_path(entry.name, parent_trans_id)
1771
 
                tt.version_file(file_id, e_trans_id)
1772
 
                trans_id[file_id] = e_trans_id
1773
 
        create_by_entry(tt, entry, target_tree, e_trans_id, mode_id=mode_id)
1774
 
        create_entry_executability(tt, entry, e_trans_id)
1775
 
 
1776
 
    elif meta_mod:
1777
 
        tt.set_executability(entry.executable, e_trans_id)
1778
 
    if tt.final_name(e_trans_id) != entry.name:
1779
 
        adjust_path  = True
1780
 
    else:
1781
 
        parent_id = tt.final_parent(e_trans_id)
1782
 
        parent_file_id = tt.final_file_id(parent_id)
1783
 
        if parent_file_id != entry.parent_id:
1784
 
            adjust_path = True
1785
 
        else:
1786
 
            adjust_path = False
1787
 
    if adjust_path:
1788
 
        parent_trans_id = trans_id_file_id(entry.parent_id)
1789
 
        tt.adjust_path(entry.name, parent_trans_id, e_trans_id)
1790
 
 
1791
 
 
1792
1834
def get_backup_name(entry, by_parent, parent_trans_id, tt):
1793
1835
    return _get_backup_name(entry.name, by_parent, parent_trans_id, tt)
1794
1836
 
1942
1984
                    # preserve the execute bit when backing up
1943
1985
                    if keep_content and executable[0] == executable[1]:
1944
1986
                        tt.set_executability(executable[1], trans_id)
1945
 
                else:
1946
 
                    assert kind[1] is None
 
1987
                elif kind[1] is not None:
 
1988
                    raise AssertionError(kind[1])
1947
1989
            if versioned == (False, True):
1948
1990
                tt.version_file(file_id, trans_id)
1949
1991
            if versioned == (True, False):