~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/graph.py

  • Committer: John Arbash Meinel
  • Date: 2011-01-11 18:10:55 UTC
  • mto: This revision was merged to the branch mainline in revision 5596.
  • Revision ID: john@arbash-meinel.com-20110111181055-d79p02kioxcg4f7l
Change tuned_gzip.GzipFile to be deprecated

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007-2011 Canonical Ltd
 
1
# Copyright (C) 2007-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
23
23
    revision,
24
24
    trace,
25
25
    )
 
26
from bzrlib.symbol_versioning import deprecated_function, deprecated_in
26
27
 
27
28
STEP_UNIQUE_SEARCHER_EVERY = 5
28
29
 
63
64
        ancestry = self.ancestry
64
65
        return dict((k, ancestry[k]) for k in keys if k in ancestry)
65
66
 
 
67
@deprecated_function(deprecated_in((1, 16, 0)))
 
68
def _StackedParentsProvider(*args, **kwargs):
 
69
    return StackedParentsProvider(*args, **kwargs)
66
70
 
67
71
class StackedParentsProvider(object):
68
72
    """A parents provider which stacks (or unions) multiple providers.
1532
1536
            return revs, ghosts
1533
1537
 
1534
1538
 
1535
 
class AbstractSearchResult(object):
1536
 
    """The result of a search, describing a set of keys.
1537
 
    
1538
 
    Search results are typically used as the 'fetch_spec' parameter when
1539
 
    fetching revisions.
1540
 
 
1541
 
    :seealso: AbstractSearch
1542
 
    """
1543
 
 
1544
 
    def get_recipe(self):
1545
 
        """Return a recipe that can be used to replay this search.
1546
 
 
1547
 
        The recipe allows reconstruction of the same results at a later date.
1548
 
 
1549
 
        :return: A tuple of (search_kind_str, *details).  The details vary by
1550
 
            kind of search result.
1551
 
        """
1552
 
        raise NotImplementedError(self.get_recipe)
1553
 
 
1554
 
    def get_network_struct(self):
1555
 
        """Return a tuple that can be transmitted via the HPSS protocol."""
1556
 
        raise NotImplementedError(self.get_network_struct)
1557
 
 
1558
 
    def get_keys(self):
1559
 
        """Return the keys found in this search.
1560
 
 
1561
 
        :return: A set of keys.
1562
 
        """
1563
 
        raise NotImplementedError(self.get_keys)
1564
 
 
1565
 
    def is_empty(self):
1566
 
        """Return false if the search lists 1 or more revisions."""
1567
 
        raise NotImplementedError(self.is_empty)
1568
 
 
1569
 
    def refine(self, seen, referenced):
1570
 
        """Create a new search by refining this search.
1571
 
 
1572
 
        :param seen: Revisions that have been satisfied.
1573
 
        :param referenced: Revision references observed while satisfying some
1574
 
            of this search.
1575
 
        :return: A search result.
1576
 
        """
1577
 
        raise NotImplementedError(self.refine)
1578
 
 
1579
 
 
1580
 
class AbstractSearch(object):
1581
 
    """A search that can be executed, producing a search result.
1582
 
 
1583
 
    :seealso: AbstractSearchResult
1584
 
    """
1585
 
 
1586
 
    def execute(self):
1587
 
        """Construct a network-ready search result from this search description.
1588
 
 
1589
 
        This may take some time to search repositories, etc.
1590
 
 
1591
 
        :return: A search result (an object that implements
1592
 
            AbstractSearchResult's API).
1593
 
        """
1594
 
        raise NotImplementedError(self.execute)
1595
 
 
1596
 
 
1597
 
class SearchResult(AbstractSearchResult):
 
1539
class SearchResult(object):
1598
1540
    """The result of a breadth first search.
1599
1541
 
1600
1542
    A SearchResult provides the ability to reconstruct the search or access a
1615
1557
        self._recipe = ('search', start_keys, exclude_keys, key_count)
1616
1558
        self._keys = frozenset(keys)
1617
1559
 
1618
 
    def __repr__(self):
1619
 
        kind, start_keys, exclude_keys, key_count = self._recipe
1620
 
        if len(start_keys) > 5:
1621
 
            start_keys_repr = repr(list(start_keys)[:5])[:-1] + ', ...]'
1622
 
        else:
1623
 
            start_keys_repr = repr(start_keys)
1624
 
        if len(exclude_keys) > 5:
1625
 
            exclude_keys_repr = repr(list(exclude_keys)[:5])[:-1] + ', ...]'
1626
 
        else:
1627
 
            exclude_keys_repr = repr(exclude_keys)
1628
 
        return '<%s %s:(%s, %s, %d)>' % (self.__class__.__name__,
1629
 
            kind, start_keys_repr, exclude_keys_repr, key_count)
1630
 
 
1631
1560
    def get_recipe(self):
1632
1561
        """Return a recipe that can be used to replay this search.
1633
1562
 
1651
1580
        """
1652
1581
        return self._recipe
1653
1582
 
1654
 
    def get_network_struct(self):
1655
 
        start_keys = ' '.join(self._recipe[1])
1656
 
        stop_keys = ' '.join(self._recipe[2])
1657
 
        count = str(self._recipe[3])
1658
 
        return (self._recipe[0], '\n'.join((start_keys, stop_keys, count)))
1659
 
 
1660
1583
    def get_keys(self):
1661
1584
        """Return the keys found in this search.
1662
1585
 
1694
1617
        return SearchResult(pending_refs, exclude, count, keys)
1695
1618
 
1696
1619
 
1697
 
class PendingAncestryResult(AbstractSearchResult):
 
1620
class PendingAncestryResult(object):
1698
1621
    """A search result that will reconstruct the ancestry for some graph heads.
1699
1622
 
1700
1623
    Unlike SearchResult, this doesn't hold the complete search result in
1711
1634
        self.heads = frozenset(heads)
1712
1635
        self.repo = repo
1713
1636
 
1714
 
    def __repr__(self):
1715
 
        if len(self.heads) > 5:
1716
 
            heads_repr = repr(list(self.heads)[:5])[:-1]
1717
 
            heads_repr += ', <%d more>...]' % (len(self.heads) - 5,)
1718
 
        else:
1719
 
            heads_repr = repr(self.heads)
1720
 
        return '<%s heads:%s repo:%r>' % (
1721
 
            self.__class__.__name__, heads_repr, self.repo)
1722
 
 
1723
1637
    def get_recipe(self):
1724
1638
        """Return a recipe that can be used to replay this search.
1725
1639
 
1733
1647
        """
1734
1648
        return ('proxy-search', self.heads, set(), -1)
1735
1649
 
1736
 
    def get_network_struct(self):
1737
 
        parts = ['ancestry-of']
1738
 
        parts.extend(self.heads)
1739
 
        return parts
1740
 
 
1741
1650
    def get_keys(self):
1742
1651
        """See SearchResult.get_keys.
1743
1652
 
1770
1679
        return PendingAncestryResult(referenced - seen, self.repo)
1771
1680
 
1772
1681
 
1773
 
class EmptySearchResult(AbstractSearchResult):
1774
 
    """An empty search result."""
1775
 
 
1776
 
    def is_empty(self):
1777
 
        return True
1778
 
    
1779
 
 
1780
 
class EverythingResult(AbstractSearchResult):
1781
 
    """A search result that simply requests everything in the repository."""
1782
 
 
1783
 
    def __init__(self, repo):
1784
 
        self._repo = repo
1785
 
 
1786
 
    def __repr__(self):
1787
 
        return '%s(%r)' % (self.__class__.__name__, self._repo)
1788
 
 
1789
 
    def get_recipe(self):
1790
 
        raise NotImplementedError(self.get_recipe)
1791
 
 
1792
 
    def get_network_struct(self):
1793
 
        return ('everything',)
1794
 
 
1795
 
    def get_keys(self):
1796
 
        if 'evil' in debug.debug_flags:
1797
 
            from bzrlib import remote
1798
 
            if isinstance(self._repo, remote.RemoteRepository):
1799
 
                # warn developers (not users) not to do this
1800
 
                trace.mutter_callsite(
1801
 
                    2, "EverythingResult(RemoteRepository).get_keys() is slow.")
1802
 
        return self._repo.all_revision_ids()
1803
 
 
1804
 
    def is_empty(self):
1805
 
        # It's ok for this to wrongly return False: the worst that can happen
1806
 
        # is that RemoteStreamSource will initiate a get_stream on an empty
1807
 
        # repository.  And almost all repositories are non-empty.
1808
 
        return False
1809
 
 
1810
 
    def refine(self, seen, referenced):
1811
 
        heads = set(self._repo.all_revision_ids())
1812
 
        heads.difference_update(seen)
1813
 
        heads.update(referenced)
1814
 
        return PendingAncestryResult(heads, self._repo)
1815
 
 
1816
 
 
1817
 
class EverythingNotInOther(AbstractSearch):
1818
 
    """Find all revisions in that are in one repo but not the other."""
1819
 
 
1820
 
    def __init__(self, to_repo, from_repo, find_ghosts=False):
1821
 
        self.to_repo = to_repo
1822
 
        self.from_repo = from_repo
1823
 
        self.find_ghosts = find_ghosts
1824
 
 
1825
 
    def execute(self):
1826
 
        return self.to_repo.search_missing_revision_ids(
1827
 
            self.from_repo, find_ghosts=self.find_ghosts)
1828
 
 
1829
 
 
1830
 
class NotInOtherForRevs(AbstractSearch):
1831
 
    """Find all revisions missing in one repo for a some specific heads."""
1832
 
 
1833
 
    def __init__(self, to_repo, from_repo, required_ids, if_present_ids=None,
1834
 
            find_ghosts=False):
1835
 
        """Constructor.
1836
 
 
1837
 
        :param required_ids: revision IDs of heads that must be found, or else
1838
 
            the search will fail with NoSuchRevision.  All revisions in their
1839
 
            ancestry not already in the other repository will be included in
1840
 
            the search result.
1841
 
        :param if_present_ids: revision IDs of heads that may be absent in the
1842
 
            source repository.  If present, then their ancestry not already
1843
 
            found in other will be included in the search result.
1844
 
        """
1845
 
        self.to_repo = to_repo
1846
 
        self.from_repo = from_repo
1847
 
        self.find_ghosts = find_ghosts
1848
 
        self.required_ids = required_ids
1849
 
        self.if_present_ids = if_present_ids
1850
 
 
1851
 
    def __repr__(self):
1852
 
        if len(self.required_ids) > 5:
1853
 
            reqd_revs_repr = repr(list(self.required_ids)[:5])[:-1] + ', ...]'
1854
 
        else:
1855
 
            reqd_revs_repr = repr(self.required_ids)
1856
 
        if self.if_present_ids and len(self.if_present_ids) > 5:
1857
 
            ifp_revs_repr = repr(list(self.if_present_ids)[:5])[:-1] + ', ...]'
1858
 
        else:
1859
 
            ifp_revs_repr = repr(self.if_present_ids)
1860
 
 
1861
 
        return "<%s from:%r to:%r find_ghosts:%r req'd:%r if-present:%r>" % (
1862
 
            self.__class__.__name__, self.from_repo, self.to_repo,
1863
 
            self.find_ghosts, reqd_revs_repr, ifp_revs_repr)
1864
 
 
1865
 
    def execute(self):
1866
 
        return self.to_repo.search_missing_revision_ids(
1867
 
            self.from_repo, revision_ids=self.required_ids,
1868
 
            if_present_ids=self.if_present_ids, find_ghosts=self.find_ghosts)
1869
 
 
1870
 
 
1871
1682
def collapse_linear_regions(parent_map):
1872
1683
    """Collapse regions of the graph that are 'linear'.
1873
1684