~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transform.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2008-07-02 19:51:05 UTC
  • mfrom: (3363.2.39 is_executable)
  • Revision ID: pqm@pqm.ubuntu.com-20080702195105-5gqthymygmtjrwaf
Make PreviewTree behavior more correct when changes are present

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
import os
18
18
import errno
19
 
from stat import S_ISREG
 
19
from stat import S_ISREG, S_IEXEC
20
20
import tempfile
21
21
 
22
22
from bzrlib.lazy_import import lazy_import
23
23
lazy_import(globals(), """
24
24
from bzrlib import (
 
25
    annotate,
25
26
    bzrdir,
26
27
    delta,
27
28
    errors,
34
35
                           ExistingLimbo, ImmortalLimbo, NoFinalPath,
35
36
                           UnableCreateSymlink)
36
37
from bzrlib.inventory import InventoryEntry
37
 
from bzrlib.osutils import (file_kind, supports_executable, pathjoin, lexists,
38
 
                            delete_any, has_symlinks)
 
38
from bzrlib.osutils import (
 
39
    delete_any,
 
40
    file_kind,
 
41
    has_symlinks,
 
42
    lexists,
 
43
    pathjoin,
 
44
    splitpath,
 
45
    supports_executable,
 
46
)
39
47
from bzrlib.progress import DummyProgress, ProgressPhase
40
48
from bzrlib.symbol_versioning import (
41
49
        deprecated_function,
1383
1391
        except KeyError:
1384
1392
            return
1385
1393
        file_id = self.tree_file_id(parent_id)
1386
 
        for child in self._tree.inventory[file_id].children.iterkeys():
 
1394
        if file_id is None:
 
1395
            return
 
1396
        children = getattr(self._tree.inventory[file_id], 'children', {})
 
1397
        for child in children:
1387
1398
            childpath = joinpath(path, child)
1388
1399
            yield self.trans_id_tree_path(childpath)
1389
1400
 
1394
1405
    def __init__(self, transform):
1395
1406
        self._transform = transform
1396
1407
        self._final_paths = FinalPaths(transform)
 
1408
        self.__by_parent = None
1397
1409
 
1398
1410
    def _changes(self, file_id):
1399
1411
        for changes in self._transform.iter_changes():
1416
1428
        name = self._transform._limbo_name(trans_id)
1417
1429
        return os.lstat(name)
1418
1430
 
 
1431
    @property
 
1432
    def _by_parent(self):
 
1433
        if self.__by_parent is None:
 
1434
            self.__by_parent = self._transform.by_parent()
 
1435
        return self.__by_parent
 
1436
 
1419
1437
    def lock_read(self):
1420
1438
        # Perhaps in theory, this should lock the TreeTransform?
1421
1439
        pass
1432
1450
        return self._transform.final_file_id(self._transform.root)
1433
1451
 
1434
1452
    def all_file_ids(self):
1435
 
        return self._transform._tree.all_file_ids()
 
1453
        tree_ids = set(self._transform._tree.all_file_ids())
 
1454
        tree_ids.difference_update(self._transform.tree_file_id(t)
 
1455
                                   for t in self._transform._removed_id)
 
1456
        tree_ids.update(self._transform._new_id.values())
 
1457
        return tree_ids
1436
1458
 
1437
1459
    def __iter__(self):
1438
1460
        return iter(self.all_file_ids())
1450
1472
                      trees=[], require_versioned=require_versioned))
1451
1473
        return result
1452
1474
 
 
1475
    def _path2trans_id(self, path):
 
1476
        segments = splitpath(path)
 
1477
        cur_parent = self._transform.root
 
1478
        for cur_segment in segments:
 
1479
            for child in self._all_children(cur_parent):
 
1480
                if self._transform.final_name(child) == cur_segment:
 
1481
                    cur_parent = child
 
1482
                    break
 
1483
            else:
 
1484
                return None
 
1485
        return cur_parent
 
1486
 
1453
1487
    def path2id(self, path):
1454
 
        return self._transform._tree.path2id(path)
 
1488
        return self._transform.final_file_id(self._path2trans_id(path))
1455
1489
 
1456
1490
    def id2path(self, file_id):
1457
1491
        trans_id = self._transform.trans_id_file_id(file_id)
1460
1494
        except NoFinalPath:
1461
1495
            raise errors.NoSuchId(self, file_id)
1462
1496
 
 
1497
    def _all_children(self, trans_id):
 
1498
        children = set(self._transform.iter_tree_children(trans_id))
 
1499
        # children in the _new_parent set are provided by _by_parent.
 
1500
        children.difference_update(self._transform._new_parent.keys())
 
1501
        children.update(self._by_parent.get(trans_id, []))
 
1502
        return children
 
1503
 
 
1504
    def _make_inv_entries(self, ordered_entries, specific_file_ids):
 
1505
        for trans_id, parent_file_id in ordered_entries:
 
1506
            file_id = self._transform.final_file_id(trans_id)
 
1507
            if file_id is None:
 
1508
                continue
 
1509
            if (specific_file_ids is not None
 
1510
                and file_id not in specific_file_ids):
 
1511
                continue
 
1512
            try:
 
1513
                kind = self._transform.final_kind(trans_id)
 
1514
            except NoSuchFile:
 
1515
                kind = self._transform._tree.stored_kind(file_id)
 
1516
            new_entry = inventory.make_entry(
 
1517
                kind,
 
1518
                self._transform.final_name(trans_id),
 
1519
                parent_file_id, file_id)
 
1520
            yield new_entry, trans_id
 
1521
 
1463
1522
    def iter_entries_by_dir(self, specific_file_ids=None):
1464
 
        return self._transform._tree.iter_entries_by_dir(specific_file_ids)
 
1523
        # This may not be a maximally efficient implementation, but it is
 
1524
        # reasonably straightforward.  An implementation that grafts the
 
1525
        # TreeTransform changes onto the tree's iter_entries_by_dir results
 
1526
        # might be more efficient, but requires tricky inferences about stack
 
1527
        # position.
 
1528
        todo = [ROOT_PARENT]
 
1529
        ordered_ids = []
 
1530
        while len(todo) > 0:
 
1531
            parent = todo.pop()
 
1532
            parent_file_id = self._transform.final_file_id(parent)
 
1533
            children = list(self._all_children(parent))
 
1534
            paths = dict(zip(children, self._final_paths.get_paths(children)))
 
1535
            children.sort(key=paths.get)
 
1536
            todo.extend(reversed(children))
 
1537
            for trans_id in children:
 
1538
                ordered_ids.append((trans_id, parent_file_id))
 
1539
        for entry, trans_id in self._make_inv_entries(ordered_ids,
 
1540
                                                      specific_file_ids):
 
1541
            yield unicode(self._final_paths.get_path(trans_id)), entry
1465
1542
 
1466
1543
    def kind(self, file_id):
1467
1544
        trans_id = self._transform.trans_id_file_id(file_id)
1468
1545
        return self._transform.final_kind(trans_id)
1469
1546
 
1470
1547
    def stored_kind(self, file_id):
1471
 
        return self._transform._tree.stored_kind(file_id)
 
1548
        trans_id = self._transform.trans_id_file_id(file_id)
 
1549
        try:
 
1550
            return self._transform._new_contents[trans_id]
 
1551
        except KeyError:
 
1552
            return self._transform._tree.stored_kind(file_id)
1472
1553
 
1473
1554
    def get_file_mtime(self, file_id, path=None):
1474
1555
        """See Tree.get_file_mtime"""
1487
1568
        return self._transform._tree.get_file_sha1(file_id)
1488
1569
 
1489
1570
    def is_executable(self, file_id, path=None):
1490
 
        return self._transform._tree.is_executable(file_id, path)
 
1571
        trans_id = self._transform.trans_id_file_id(file_id)
 
1572
        try:
 
1573
            return self._transform._new_executability[trans_id]
 
1574
        except KeyError:
 
1575
            return self._transform._tree.is_executable(file_id, path)
1491
1576
 
1492
1577
    def path_content_summary(self, path):
1493
 
        return self._transform._tree.path_content_summary(path)
 
1578
        trans_id = self._path2trans_id(path)
 
1579
        tt = self._transform
 
1580
        tree_path = tt._tree_id_paths.get(trans_id)
 
1581
        kind = tt._new_contents.get(trans_id)
 
1582
        if kind is None:
 
1583
            if tree_path is None or trans_id in tt._removed_contents:
 
1584
                return 'missing', None, None, None
 
1585
            summary = tt._tree.path_content_summary(tree_path)
 
1586
            kind, size, executable, link_or_sha1 = summary
 
1587
        else:
 
1588
            link_or_sha1 = None
 
1589
            limbo_name = tt._limbo_name(trans_id)
 
1590
            if trans_id in tt._new_reference_revision:
 
1591
                kind = 'tree-reference'
 
1592
            if kind == 'file':
 
1593
                statval = os.lstat(limbo_name)
 
1594
                size = statval.st_size
 
1595
                if not supports_executable():
 
1596
                    executable = None
 
1597
                else:
 
1598
                    executable = statval.st_mode & S_IEXEC
 
1599
            else:
 
1600
                size = None
 
1601
                executable = None
 
1602
            if kind == 'symlink':
 
1603
                link_or_sha1 = os.readlink(limbo_name)
 
1604
        if supports_executable():
 
1605
            executable = tt._new_executability.get(trans_id, executable)
 
1606
        return kind, size, executable, link_or_sha1
1494
1607
 
1495
1608
    def iter_changes(self, from_tree, include_unchanged=False,
1496
1609
                      specific_files=None, pb=None, extra_trees=None,
1528
1641
 
1529
1642
    def annotate_iter(self, file_id,
1530
1643
                      default_revision=_mod_revision.CURRENT_REVISION):
1531
 
        return self._transform._tree.annotate_iter(file_id,
1532
 
            default_revision=default_revision)
 
1644
        changes = self._changes(file_id)
 
1645
        if changes is None:
 
1646
            get_old = True
 
1647
        else:
 
1648
            changed_content, versioned, kind = (changes[2], changes[3],
 
1649
                                                changes[6])
 
1650
            if kind[1] is None:
 
1651
                return None
 
1652
            get_old = (kind[0] == 'file' and versioned[0])
 
1653
        if get_old:
 
1654
            old_annotation = self._transform._tree.annotate_iter(file_id,
 
1655
                default_revision=default_revision)
 
1656
        else:
 
1657
            old_annotation = []
 
1658
        if changes is None:
 
1659
            return old_annotation
 
1660
        if not changed_content:
 
1661
            return old_annotation
 
1662
        return annotate.reannotate([old_annotation],
 
1663
                                   self.get_file(file_id).readlines(),
 
1664
                                   default_revision)
1533
1665
 
1534
1666
    def get_symlink_target(self, file_id):
1535
1667
        """See Tree.get_symlink_target"""