launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #00152
[Merge] lp:~wgrant/launchpad/bug-598345-restrict-dep-contexts into lp:launchpad/devel
William Grant has proposed merging lp:~wgrant/launchpad/bug-598345-restrict-dep-contexts into lp:launchpad/devel.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
#52698 Auto-Dep retry algorithm doesn't check component
https://bugs.launchpad.net/bugs/52698
#598345 findDepCandidateByName does not restrict to available pockets
https://bugs.launchpad.net/bugs/598345
#606789 findDepCandidateByName blindly returns the first result
https://bugs.launchpad.net/bugs/606789
This branches fixes bug #52698 and bug #598345. At present some depwait builds are retried prematurely, as the candidate query in Archive.findDepCandidateByName constrains just the archive and distroarchseries context -- not the pocket or component, which are also included in the sources.list entries and restrict the available packages. A notable case is that of Hardy PPA packages dependent on debhelper 7: while a sufficient version is present in hardy-backports, most PPAs are not configured to use -backports. This results in such builds being retried every time the script runs, using vast amounts of buildd time to no effect.
A related (and also fixed here) issue is bug #606789: findDepCandidateByName() returned just the latest publication (by BPPH.id), and BinaryPackageBuild._isDependencySatisfied() checked the version constraint against that. But this ignores the fact that apt will look at *all* available versions across all archives and pockets, so _isDependencySatisfied needs to check that at least one of *any* of the available versions satisfies the version constraint.
I've fixed the first problem by refactoring the archive dependency expansion logic in lp.soyuz.adapters.archivedependencies, creating a new expand_dependencies() which returns a list of archives with the available pockets and components. The existing get_sources_list_for_building() wraps that, converting each dependency into a sources.list line, and adding any custom external dependencies as before. findDepCandidateByName() then uses expand_dependencies() to create the context restriction clause (archive, pocket and component). This is the same logic used to generate sources.list itself -- so it results in a completely accurate query.
For the second issue, findDepCandidateByName() has been replaced with findDepCandidates(), which returns a sequence of all matching binaries, latest first. _isDependencySatisfied() has been tweaked to look through all of them, returning True when a satisfying candidate is identified.
I've also removed some manual ogre-model logic from _isDependencySatisfied(), since that's now handled by findDepCandidates().
The findDepCandidateByName() doctests made me sad, so they've been replaced with expanded unit tests in test_archive. test_binarypackagebuild has two new tests: one checking that versioned dependencies work (a hole in the existing suite), and another verifying that more than just the latest binary is considered (new behaviour).
--
https://code.launchpad.net/~wgrant/launchpad/bug-598345-restrict-dep-contexts/+merge/30203
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/bug-598345-restrict-dep-contexts into lp:launchpad/devel.
=== modified file 'lib/lp/soyuz/adapters/archivedependencies.py'
--- lib/lp/soyuz/adapters/archivedependencies.py 2010-05-10 19:49:02 +0000
+++ lib/lp/soyuz/adapters/archivedependencies.py 2010-07-18 05:05:59 +0000
@@ -12,8 +12,9 @@
Auxiliary functions exposed for testing purposes:
- * get_components_for_building: return the corresponding component
- dependencies for a build, this result is known as 'ogre_components';
+ * get_components_for_context: return the corresponding component
+ dependencies for a component and pocket, this result is known as
+ 'ogre_components';
* get_primary_current_component: return the component name where the
building source is published in the primary archive.
@@ -30,7 +31,8 @@
'component_dependencies',
'default_component_dependency_name',
'default_pocket_dependency',
- 'get_components_for_building',
+ 'expand_dependencies',
+ 'get_components_for_context',
'get_primary_current_component',
'get_sources_list_for_building',
'pocket_dependencies',
@@ -86,19 +88,20 @@
default_component_dependency_name = 'multiverse'
-def get_components_for_building(build):
+def get_components_for_context(component, pocket):
"""Return the components allowed to be used in the build context.
- :param build: a context `IBuild`.
+ :param component: the context `IComponent`.
+ :param pocket: the context `IPocket`.
:return: a list of component names.
"""
# BACKPORTS should be able to fetch build dependencies from any
# component in order to cope with component changes occurring
- # accross distroseries. See bug #198936 for further information.
- if build.pocket == PackagePublishingPocket.BACKPORTS:
+ # across distroseries. See bug #198936 for further information.
+ if pocket == PackagePublishingPocket.BACKPORTS:
return component_dependencies['multiverse']
- return component_dependencies[build.current_component.name]
+ return component_dependencies[component.name]
def get_primary_current_component(archive, distroseries, sourcepackagename):
@@ -119,30 +122,73 @@
return 'universe'
+def expand_dependencies(archive, distro_series, pocket, component,
+ source_package_name):
+ """Return the set of dependency archives, pockets and components.
+
+ :param archive: the context `IArchive`.
+ :param distro_series: the context `IDistroSeries`.
+ :param pocket: the context `PackagePublishingPocket`.
+ :param component: the context `IComponent`.
+ :param source_package_name: A source package name (as text)
+ :return: a list of (archive, pocket, [component]), representing the
+ dependencies defined by the given build context.
+ """
+ deps = []
+
+ # Add implicit self-dependency for non-primary contexts.
+ if archive.purpose in ALLOW_RELEASE_BUILDS:
+ deps.append((
+ archive, PackagePublishingPocket.RELEASE,
+ get_components_for_context(component, pocket)))
+
+ primary_component = get_primary_current_component(
+ archive, distro_series, source_package_name)
+ # Consider user-selected archive dependencies.
+ for archive_dependency in archive.dependencies:
+ # When the dependency component is undefined, we should use
+ # the component where the source is published in the primary
+ # archive.
+ if archive_dependency.component is None:
+ components = component_dependencies[primary_component]
+ else:
+ components = component_dependencies[
+ archive_dependency.component.name]
+ # Follow pocket dependencies.
+ for pocket in pocket_dependencies[archive_dependency.pocket]:
+ deps.append(
+ (archive_dependency.dependency, pocket, components))
+
+ # Consider primary archive dependency override. Add the default
+ # primary archive dependencies if it's not present.
+ if archive.getArchiveDependency(
+ archive.distribution.main_archive) is None:
+ primary_dependencies = _get_default_primary_dependencies(
+ archive, component, pocket)
+ deps.extend(primary_dependencies)
+
+ return deps
+
+
def get_sources_list_for_building(build, distroarchseries, sourcepackagename):
"""Return the sources_list entries required to build the given item.
The entries are returned in the order that is most useful;
1. the context archive itself
- 2. external dependencies
- 3. user-selected archive dependencies
- 4. the default primary archive
+ 2. user-selected archive dependencies
+ 3. the default primary archive
+ 4. external dependencies
- :param build: a context `IBuild`.
- :param distroarchseries: A `IDistroArchSeries`
- :param sourcepackagename: A source package name (as text)
- :return: a deb sources_list entries (lines).
+ :param build: the context `IBuild`.
+ :param distroarchseries: the context `IDistroArchSeries`.
+ :param sourcepackagename: the source package name (as text).
+ :return: a list of sources.list entries.
"""
- deps = []
- sources_list_lines = []
-
- # Add implicit self-dependency for non-primary contexts.
- if build.archive.purpose in ALLOW_RELEASE_BUILDS:
- self_dep = [(
- build.archive, PackagePublishingPocket.RELEASE,
- get_components_for_building(build))]
- sources_list_lines = _get_sources_list_for_dependencies(
- self_dep, distroarchseries)
+ deps = expand_dependencies(
+ build.archive, distroarchseries.distroseries, build.pocket,
+ build.current_component, sourcepackagename)
+ sources_list_lines = \
+ _get_sources_list_for_dependencies(deps, distroarchseries)
# Append external sources_list lines for this archive if it's
# specified in the configuration.
@@ -166,35 +212,9 @@
if build.archive.enabled == True:
build.archive.disable()
- # Consider user-selected archive dependencies.
- primary_component = get_primary_current_component(
- build.archive, build.distro_series, sourcepackagename)
- for archive_dependency in build.archive.dependencies:
- # When the dependency component is undefined, we should use
- # the component where the source is published in the primary
- # archive.
- if archive_dependency.component is None:
- components = component_dependencies[primary_component]
- else:
- components = component_dependencies[
- archive_dependency.component.name]
- # Follow pocket dependencies.
- for pocket in pocket_dependencies[archive_dependency.pocket]:
- deps.append(
- (archive_dependency.dependency, pocket, components)
- )
-
- # Consider primary archive dependency override. Add the default
- # primary archive dependencies if it's not present.
- if build.archive.getArchiveDependency(
- build.archive.distribution.main_archive) is None:
- primary_dependencies = _get_default_primary_dependencies(build)
- deps.extend(primary_dependencies)
-
- sources_list_lines.extend(
- _get_sources_list_for_dependencies(deps, distroarchseries))
return sources_list_lines
+
def _has_published_binaries(archive, distroarchseries, pocket):
"""Whether or not the archive dependency has published binaries."""
# The primary archive dependencies are always relevant.
@@ -252,27 +272,29 @@
return sources_list_lines
-def _get_default_primary_dependencies(build):
- """Return the default primary dependencies for a given build.
+def _get_default_primary_dependencies(archive, component, pocket):
+ """Return the default primary dependencies for a given context.
- :param build: the `IBuild` context;
+ :param archive: the context `IArchive`.
+ :param component: the context `IComponent`.
+ :param pocket: the context `PackagePublishingPocket`.
:return: a list containing the default dependencies to primary
archive.
"""
- if build.archive.purpose in ALLOW_RELEASE_BUILDS:
+ if archive.purpose in ALLOW_RELEASE_BUILDS:
primary_pockets = pocket_dependencies[
default_pocket_dependency]
primary_components = component_dependencies[
default_component_dependency_name]
else:
- primary_pockets = pocket_dependencies[build.pocket]
- primary_components = get_components_for_building(build)
+ primary_pockets = pocket_dependencies[pocket]
+ primary_components = get_components_for_context(component, pocket)
primary_dependencies = []
for pocket in primary_pockets:
primary_dependencies.append(
- (build.distro_series.distribution.main_archive, pocket,
+ (archive.distribution.main_archive, pocket,
primary_components))
return primary_dependencies
=== modified file 'lib/lp/soyuz/doc/archive-dependencies.txt'
--- lib/lp/soyuz/doc/archive-dependencies.txt 2010-05-10 19:49:02 +0000
+++ lib/lp/soyuz/doc/archive-dependencies.txt 2010-07-18 05:05:59 +0000
@@ -97,7 +97,7 @@
... 'main', 'restricted', 'universe', 'multiverse', 'partner']
>>> from lp.soyuz.adapters.archivedependencies import (
- ... get_components_for_building)
+ ... get_components_for_context)
>>> ogre_pub = test_publisher.getPubSource(sourcename='ogre')
>>> [ogre_build] = ogre_pub.createMissingBuilds()
@@ -111,7 +111,8 @@
... syncUpdate(ogre_pub)
... flush_database_caches()
... components_term = " ".join(
- ... get_components_for_building(ogre_build))
+ ... get_components_for_context(
+ ... ogre_build.current_component, ogre_build.pocket))
... print '%10s | %s' % (ogre_build.current_component.name,
... components_term)
@@ -557,13 +558,12 @@
>>> print_building_sources_list(a_build)
deb http://ppa.launchpad.dev/cprov/ppa/ubuntu hoary main
+ deb http://ftpmaster.internal/ubuntu hoary
+ main restricted universe multiverse
+ deb http://ftpmaster.internal/ubuntu hoary-security
+ main restricted universe multiverse
+ deb http://ftpmaster.internal/ubuntu hoary-updates
+ main restricted universe multiverse
deb http://user:pass@repository zoing everything
deb http://user:pass@repository hoary public private
deb http://user:pass@repository hoary-extra public
- deb http://ftpmaster.internal/ubuntu hoary
- main restricted universe multiverse
- deb http://ftpmaster.internal/ubuntu hoary-security
- main restricted universe multiverse
- deb http://ftpmaster.internal/ubuntu hoary-updates
- main restricted universe multiverse
-
=== modified file 'lib/lp/soyuz/doc/archive.txt'
--- lib/lp/soyuz/doc/archive.txt 2010-07-02 21:25:36 +0000
+++ lib/lp/soyuz/doc/archive.txt 2010-07-18 05:05:59 +0000
@@ -1285,72 +1285,6 @@
...
AssertionError: This dependency does not exist.
-== Find binary package dependency candidates ==
-
-Archive allows a lookup on a single binary package dependency
-candidate by its name, via the `PublishedPackage` table:
-
- >>> warty_i386 = warty['i386']
-
- >>> candidate = ubuntu.main_archive.findDepCandidateByName(
- ... warty_i386, "pmount")
- >>> print candidate.binarypackagerelease.binarypackagename.name
- pmount
-
- >>> candidate = cprov.archive.findDepCandidateByName(
- ... warty_i386, "pmount")
- >>> print candidate.binarypackagerelease.binarypackagename.name
- pmount
-
-Since 'python2.4' isn't available in our sampledata (not even
-published), None is returned:
-
- >>> print ubuntu.main_archive.findDepCandidateByName(
- ... warty_i386, "python2.4")
- None
-
- >>> print cprov.archive.findDepCandidateByName(
- ... warty_i386, "python2.4")
- None
-
-This method is aware of the archive dependency tree. So, even when a
-package is not published on the context PPA but is available somewhere
-in the archive dependency domain it will be found.
-
-We also add another archive dependency here to exercise findDepCandidateByName
-a little more.
-
- >>> joe = factory.makePerson(email='joe@xxxxxxxxxxx')
- >>> second_ppa = factory.makeArchive(name="secondppa", owner=joe)
- >>> second_archive_dep = cprov.archive.addArchiveDependency(
- ... second_ppa, release_pocket, main_component)
-
-'at' binary package is not present in Celso's PPA.
-
- >>> cprov_archive.getAllPublishedBinaries(name='at').count()
- 0
-
-But it is available in PRIMARY ubuntu archive.
-
- >>> primary_candidate = ubuntu.main_archive.findDepCandidateByName(
- ... warty_i386, "at")
- >>> primary_candidate is not None
- True
-
-Then a lookup on Celso's PPA will find it.
-
- >>> ppa_candidate = cprov.archive.findDepCandidateByName(
- ... warty_i386, "at")
- >>> ppa_candidate is not None
- True
-
- >>> primary_candidate == ppa_candidate
- True
-
-And clean-up after ourselves:
-
- >>> ignore = cprov.archive.removeArchiveDependency(second_ppa)
-
== Creating a package copy request from an IArchive ==
The IArchive interface includes a convenience method for creating a
=== modified file 'lib/lp/soyuz/doc/binarypackagebuild.txt'
--- lib/lp/soyuz/doc/binarypackagebuild.txt 2010-06-10 22:12:08 +0000
+++ lib/lp/soyuz/doc/binarypackagebuild.txt 2010-07-18 05:05:59 +0000
@@ -987,8 +987,9 @@
main
>>> from lp.soyuz.adapters.archivedependencies import (
- ... get_components_for_building)
- >>> print get_components_for_building(depwait_build)
+ ... get_components_for_context)
+ >>> print get_components_for_context(
+ ... depwait_build.current_component, depwait_build.pocket)
['main']
Thus the 'pmount' dependency remains unsatisfied.
@@ -1036,7 +1037,8 @@
>>> flush_database_caches()
>>> login(ANONYMOUS)
- >>> print get_components_for_building(depwait_build)
+ >>> print get_components_for_context(
+ ... depwait_build.current_component, depwait_build.pocket)
['main']
>>> print pmount_pub.component.name
=== modified file 'lib/lp/soyuz/interfaces/archive.py'
--- lib/lp/soyuz/interfaces/archive.py 2010-07-12 08:45:32 +0000
+++ lib/lp/soyuz/interfaces/archive.py 2010-07-18 05:05:59 +0000
@@ -443,11 +443,24 @@
Person table indexes while searching.
"""
- def findDepCandidateByName(distroarchseries, name):
- """Return the last published binarypackage by given name.
-
- Return the `BinaryPackagePublishingHistory` record by distroarchseries
- and name, or None if not found.
+ def findDepCandidates(distro_arch_series, pocket, component,
+ source_package_name, dep_name):
+ """Return matching binaries in this archive and its dependencies.
+
+ Return all published `IBinaryPackagePublishingHistory` records with
+ the given name, in this archive and dependencies as specified by the
+ given build context, using the usual archive dependency rules.
+
+ We can't just use the first, since there may be other versions
+ published in other dependency archives.
+
+ :param distro_arch_series: the context `IDistroArchSeries`.
+ :param pocket: the context `PackagePublishingPocket`.
+ :param component: the context `IComponent`.
+ :param source_package_name: the context source package name (as text).
+ :param dep_name: the name of the binary package to look up.
+ :return: a sequence of matching `IBinaryPackagePublishingHistory`
+ records.
"""
def removeArchiveDependency(dependency):
=== modified file 'lib/lp/soyuz/model/archive.py'
--- lib/lp/soyuz/model/archive.py 2010-07-12 08:45:32 +0000
+++ lib/lp/soyuz/model/archive.py 2010-07-18 05:05:59 +0000
@@ -37,6 +37,7 @@
from lp.buildmaster.model.buildfarmjob import BuildFarmJob
from lp.buildmaster.model.packagebuild import PackageBuild
from lp.services.job.interfaces.job import JobStatus
+from lp.soyuz.adapters.archivedependencies import expand_dependencies
from lp.soyuz.adapters.packagelocation import PackageLocation
from canonical.launchpad.components.tokens import (
create_unique_token_for_table)
@@ -47,6 +48,7 @@
from lp.soyuz.model.binarypackagerelease import (
BinaryPackageReleaseDownloadCount)
from lp.soyuz.model.binarypackagebuild import BinaryPackageBuild
+from lp.soyuz.model.component import Component
from lp.soyuz.model.distributionsourcepackagecache import (
DistributionSourcePackageCache)
from lp.soyuz.model.distroseriespackagecache import DistroSeriesPackageCache
@@ -807,30 +809,32 @@
self.sources_cached = sources_cached.count()
self.binaries_cached = binaries_cached.count()
- def findDepCandidateByName(self, distroarchseries, name):
+ def findDepCandidates(self, distro_arch_series, pocket, component,
+ source_package_name, dep_name):
"""See `IArchive`."""
- archives = []
- if self.is_ppa:
- archives.append(self.distribution.main_archive.id)
- archives.append(self.id)
- archives.extend(
- IResultSet(self.dependencies).values(
- ArchiveDependency.dependencyID))
+ deps = expand_dependencies(
+ self, distro_arch_series.distroseries, pocket, component,
+ source_package_name)
+ archive_clause = Or([And(
+ BinaryPackagePublishingHistory.archiveID == archive.id,
+ BinaryPackagePublishingHistory.pocket == pocket,
+ Component.name.is_in(components))
+ for (archive, pocket, components) in deps])
store = ISlaveStore(BinaryPackagePublishingHistory)
- candidate = store.find(
+ return store.find(
BinaryPackagePublishingHistory,
- BinaryPackageName.name == name,
+ BinaryPackageName.name == dep_name,
BinaryPackageRelease.binarypackagename == BinaryPackageName.id,
BinaryPackagePublishingHistory.binarypackagerelease ==
BinaryPackageRelease.id,
BinaryPackagePublishingHistory.distroarchseries ==
- distroarchseries,
- In(BinaryPackagePublishingHistory.archiveID, archives),
+ distro_arch_series,
BinaryPackagePublishingHistory.status ==
- PackagePublishingStatus.PUBLISHED
- ).order_by(Desc(BinaryPackagePublishingHistory.id))
- return candidate.first()
+ PackagePublishingStatus.PUBLISHED,
+ BinaryPackagePublishingHistory.componentID == Component.id,
+ archive_clause).order_by(
+ Desc(BinaryPackagePublishingHistory.id))
def getArchiveDependency(self, dependency):
"""See `IArchive`."""
=== modified file 'lib/lp/soyuz/model/binarypackagebuild.py'
--- lib/lp/soyuz/model/binarypackagebuild.py 2010-06-15 11:11:27 +0000
+++ lib/lp/soyuz/model/binarypackagebuild.py 2010-07-18 05:05:59 +0000
@@ -50,7 +50,6 @@
from lp.buildmaster.model.packagebuild import (
PackageBuild, PackageBuildDerived)
from lp.services.job.model.job import Job
-from lp.soyuz.adapters.archivedependencies import get_components_for_building
from lp.soyuz.interfaces.archive import ArchivePurpose
from lp.soyuz.interfaces.binarypackagebuild import (
BuildSetStatus, CannotBeRescored, IBinaryPackageBuild,
@@ -387,33 +386,25 @@
def _isDependencySatisfied(self, token):
"""Check if the given dependency token is satisfied.
- Check if the dependency exists, if its version constraint is
- satisfied and if it is reachable in the build context.
+ Check if the dependency exists and that its version constraint is
+ satisfied.
"""
name, version, relation = self._parseDependencyToken(token)
- dep_candidate = self.archive.findDepCandidateByName(
- self.distro_arch_series, name)
-
- if not dep_candidate:
- return False
-
- if not self._checkDependencyVersion(
- dep_candidate.binarypackagerelease.version, version, relation):
- return False
-
- # Only PRIMARY archive build dependencies should be restricted
- # to the ogre_components. Both PARTNER and PPA can reach
- # dependencies from all components in the PRIMARY archive.
- # Moreover, PARTNER and PPA component domain is single, i.e,
- # PARTNER only contains packages in 'partner' component and PPAs
- # only contains packages in 'main' component.
- ogre_components = get_components_for_building(self)
- if (self.archive.purpose == ArchivePurpose.PRIMARY and
- dep_candidate.component.name not in ogre_components):
- return False
-
- return True
+ # There may be several published versions in the available
+ # archives and pockets. If any one of them satisifies our
+ # constraints, the dependency is satisfied.
+ dep_candidates = self.archive.findDepCandidates(
+ self.distro_arch_series, self.pocket, self.current_component,
+ self.source_package_release.sourcepackagename.name, name)
+
+ for dep_candidate in dep_candidates:
+ if self._checkDependencyVersion(
+ dep_candidate.binarypackagerelease.version, version,
+ relation):
+ return True
+
+ return False
def _toAptFormat(self, token):
"""Rebuild dependencies line in apt format."""
=== modified file 'lib/lp/soyuz/tests/test_archive.py'
--- lib/lp/soyuz/tests/test_archive.py 2010-07-12 13:32:53 +0000
+++ lib/lp/soyuz/tests/test_archive.py 2010-07-18 05:05:59 +0000
@@ -4,9 +4,10 @@
"""Test Archive features."""
from datetime import date, datetime, timedelta
+import unittest
+
import pytz
-import unittest
-
+import transaction
from zope.component import getUtility
from zope.security.interfaces import Unauthorized
from zope.security.proxy import removeSecurityProxy
@@ -1099,7 +1100,141 @@
login("commercial-member@xxxxxxxxxxxxx")
self.setCommercial(self.archive, True)
self.assertTrue(self.archive.commercial)
-
+
+
+class TestFindDepCandidates(TestCaseWithFactory):
+ """Tests for Archive.findDepCandidates."""
+
+ layer = LaunchpadZopelessLayer
+
+ def setUp(self):
+ super(TestFindDepCandidates, self).setUp()
+ self.archive = self.factory.makeArchive()
+ self.publisher = SoyuzTestPublisher()
+ login('admin@xxxxxxxxxxxxx')
+ self.publisher.prepareBreezyAutotest()
+
+ def assertDep(self, arch_tag, name, expected, archive=None,
+ pocket=PackagePublishingPocket.RELEASE, component=None,
+ source_package_name='something-new'):
+ """Helper to check that findDepCandidates works.
+
+ Searches for the given dependency name in the given architecture and
+ archive, and compares it to the given expected value.
+ The archive defaults to self.archive.
+
+ Also commits, since findDepCandidates uses the slave store.
+ """
+ transaction.commit()
+
+ if component is None:
+ component = getUtility(IComponentSet)['main']
+ if archive is None:
+ archive = self.archive
+
+ self.assertEquals(
+ list(
+ archive.findDepCandidates(
+ self.publisher.distroseries[arch_tag], pocket, component,
+ source_package_name, name)),
+ expected)
+
+ def test_finds_candidate_in_same_archive(self):
+ # A published candidate in the same archive should be found.
+ bins = self.publisher.getPubBinaries(
+ binaryname='foo', archive=self.archive,
+ status=PackagePublishingStatus.PUBLISHED)
+ self.assertDep('i386', 'foo', [bins[0]])
+ self.assertDep('hppa', 'foo', [bins[1]])
+
+ def test_does_not_find_pending_publication(self):
+ # A pending candidate in the same archive should not be found.
+ bins = self.publisher.getPubBinaries(
+ binaryname='foo', archive=self.archive)
+ self.assertDep('i386', 'foo', [])
+
+ def test_ppa_searches_primary_archive(self):
+ # PPA searches implicitly look in the primary archive too.
+ self.assertEquals(self.archive.purpose, ArchivePurpose.PPA)
+ self.assertDep('i386', 'foo', [])
+
+ bins = self.publisher.getPubBinaries(
+ binaryname='foo', archive=self.archive.distribution.main_archive,
+ status=PackagePublishingStatus.PUBLISHED)
+
+ self.assertDep('i386', 'foo', [bins[0]])
+
+ def test_searches_dependencies(self):
+ # Candidates from archives on which the target explicitly depends
+ # should be found.
+ bins = self.publisher.getPubBinaries(
+ binaryname='foo', archive=self.archive,
+ status=PackagePublishingStatus.PUBLISHED)
+ other_archive = self.factory.makeArchive()
+ self.assertDep('i386', 'foo', [], archive=other_archive)
+
+ other_archive.addArchiveDependency(
+ self.archive, PackagePublishingPocket.RELEASE)
+ self.assertDep('i386', 'foo', [bins[0]], archive=other_archive)
+
+ def test_obeys_dependency_pockets(self):
+ # Only packages published in a pocket matching the dependency should
+ # be found.
+ release_bins = self.publisher.getPubBinaries(
+ binaryname='foo-release', archive=self.archive,
+ status=PackagePublishingStatus.PUBLISHED)
+ updates_bins = self.publisher.getPubBinaries(
+ binaryname='foo-updates', archive=self.archive,
+ status=PackagePublishingStatus.PUBLISHED,
+ pocket=PackagePublishingPocket.UPDATES)
+ proposed_bins = self.publisher.getPubBinaries(
+ binaryname='foo-proposed', archive=self.archive,
+ status=PackagePublishingStatus.PUBLISHED,
+ pocket=PackagePublishingPocket.PROPOSED)
+
+ # Temporarily turn our test PPA into a copy archive, so we can
+ # add non-RELEASE dependencies on it.
+ removeSecurityProxy(self.archive).purpose = ArchivePurpose.COPY
+
+ other_archive = self.factory.makeArchive()
+ other_archive.addArchiveDependency(
+ self.archive, PackagePublishingPocket.UPDATES)
+ self.assertDep(
+ 'i386', 'foo-release', [release_bins[0]], archive=other_archive)
+ self.assertDep(
+ 'i386', 'foo-updates', [updates_bins[0]], archive=other_archive)
+ self.assertDep('i386', 'foo-proposed', [], archive=other_archive)
+
+ other_archive.removeArchiveDependency(self.archive)
+ other_archive.addArchiveDependency(
+ self.archive, PackagePublishingPocket.PROPOSED)
+ self.assertDep(
+ 'i386', 'foo-proposed', [proposed_bins[0]], archive=other_archive)
+
+ def test_obeys_dependency_components(self):
+ # Only packages published in a component matching the dependency
+ # should be found.
+ primary = self.archive.distribution.main_archive
+ main_bins = self.publisher.getPubBinaries(
+ binaryname='foo-main', archive=primary, component='main',
+ status=PackagePublishingStatus.PUBLISHED)
+ universe_bins = self.publisher.getPubBinaries(
+ binaryname='foo-universe', archive=primary,
+ component='universe',
+ status=PackagePublishingStatus.PUBLISHED)
+
+ self.archive.addArchiveDependency(
+ primary, PackagePublishingPocket.RELEASE,
+ component=getUtility(IComponentSet)['main'])
+ self.assertDep('i386', 'foo-main', [main_bins[0]])
+ self.assertDep('i386', 'foo-universe', [])
+
+ self.archive.removeArchiveDependency(primary)
+ self.archive.addArchiveDependency(
+ primary, PackagePublishingPocket.RELEASE,
+ component=getUtility(IComponentSet)['universe'])
+ self.assertDep('i386', 'foo-main', [main_bins[0]])
+ self.assertDep('i386', 'foo-universe', [universe_bins[0]])
def test_suite():
=== modified file 'lib/lp/soyuz/tests/test_binarypackagebuild.py'
--- lib/lp/soyuz/tests/test_binarypackagebuild.py 2010-06-21 07:26:51 +0000
+++ lib/lp/soyuz/tests/test_binarypackagebuild.py 2010-07-18 05:05:59 +0000
@@ -164,13 +164,13 @@
Return an `IBinaryPackageBuild` in MANUALDEWAIT state and depending on a
binary that exists and is reachable.
"""
- test_publisher = SoyuzTestPublisher()
- test_publisher.prepareBreezyAutotest()
+ self.publisher = SoyuzTestPublisher()
+ self.publisher.prepareBreezyAutotest()
- depwait_source = test_publisher.getPubSource(
+ depwait_source = self.publisher.getPubSource(
sourcename='depwait-source')
- test_publisher.getPubBinaries(
+ self.publisher.getPubBinaries(
binaryname='dep-bin',
status=PackagePublishingStatus.PUBLISHED)
@@ -273,6 +273,41 @@
depwait_build.updateDependencies()
self.assertEquals(depwait_build.dependencies, '')
+ def testVersionedDependencies(self):
+ # `IBinaryPackageBuild.updateDependencies` supports versioned
+ # dependencies. A build will not be retried unless the candidate
+ # complies with the version restriction.
+ # In this case, dep-bin 666 is available. >> 666 isn't
+ # satisified, but >= 666 is.
+ depwait_build = self._setupSimpleDepwaitContext()
+ self.layer.txn.commit()
+
+ depwait_build.dependencies = u'dep-bin (>> 666)'
+ depwait_build.updateDependencies()
+ self.assertEquals(depwait_build.dependencies, u'dep-bin (>> 666)')
+ depwait_build.dependencies = u'dep-bin (>= 666)'
+ depwait_build.updateDependencies()
+ self.assertEquals(depwait_build.dependencies, u'')
+
+ def testVersionedDependencyOnOldPublication(self):
+ # `IBinaryPackageBuild.updateDependencies` doesn't just consider
+ # the latest publication. There may be older publications which
+ # satisfy the version constraints (in other archives or pockets).
+ # In this case, dep-bin 666 and 999 are available, so both = 666
+ # and = 999 are satisfied.
+ depwait_build = self._setupSimpleDepwaitContext()
+ self.publisher.getPubBinaries(
+ binaryname='dep-bin', version='999',
+ status=PackagePublishingStatus.PUBLISHED)
+ self.layer.txn.commit()
+
+ depwait_build.dependencies = u'dep-bin (= 666)'
+ depwait_build.updateDependencies()
+ self.assertEquals(depwait_build.dependencies, u'')
+ depwait_build.dependencies = u'dep-bin (= 999)'
+ depwait_build.updateDependencies()
+ self.assertEquals(depwait_build.dependencies, u'')
+
class BaseTestCaseWithThreeBuilds(TestCaseWithFactory):
=== modified file 'lib/lp/soyuz/tests/test_publishing.py'
--- lib/lp/soyuz/tests/test_publishing.py 2010-07-15 14:19:40 +0000
+++ lib/lp/soyuz/tests/test_publishing.py 2010-07-18 05:05:59 +0000
@@ -267,7 +267,8 @@
pub_source=None,
version='666',
architecturespecific=False,
- builder=None):
+ builder=None,
+ component='main'):
"""Return a list of binary publishing records."""
if distroseries is None:
distroseries = self.distroseries
@@ -285,7 +286,8 @@
pub_source = self.getPubSource(
sourcename=sourcename, status=status, pocket=pocket,
archive=archive, distroseries=distroseries,
- version=version, architecturehintlist=architecturehintlist)
+ version=version, architecturehintlist=architecturehintlist,
+ component=component)
else:
archive = pub_source.archive