Merge lp:~wgrant/launchpad/simplify-getRelevantToSourceAndArchive into lp:launchpad

Proposed by William Grant
Status: Merged
Merged at revision: 17229
Proposed branch: lp:~wgrant/launchpad/simplify-getRelevantToSourceAndArchive
Merge into: lp:launchpad
Diff against target: 725 lines (+140/-496)
6 files modified
lib/lp/soyuz/doc/sourcepackagerelease-build-lookup.txt (+0/-349)
lib/lp/soyuz/interfaces/binarypackagebuild.py (+9/-8)
lib/lp/soyuz/model/binarypackagebuild.py (+38/-87)
lib/lp/soyuz/scripts/tests/test_initialize_distroseries.py (+2/-2)
lib/lp/soyuz/tests/test_build_set.py (+91/-46)
lib/lp/soyuz/tests/test_doc.py (+0/-4)
To merge this branch: bzr merge lp:~wgrant/launchpad/simplify-getRelevantToSourceAndArchive
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+240805@code.launchpad.net

Commit message

BinaryPackageBuildSet.getRelevantToSourceAndLocation is replaced by a much simpler findBuiltOrPublishedBySourceAndArchive. Only successful builds are interesting, the series is uninteresting, and there's always at most one per archtag.

Description of the change

BinaryPackageBuildSet.getRelevantToSourceAndLocation is replaced by a much simpler findBuiltOrPublishedBySourceAndArchive.

The horrifying complexity arose over the 9 year history of the method (originally SourcePackageRelease.getBuildByArch), persisting through ArchiveRework and NativeSourceSyncing which both fundamentally changed its functionality. SPR.getBuildByArch's purpose is now served by two new methods: a tiny BPBS.getBySourceAndLocation which looks any build up by its natural key (SourcePackageRelease, Archive, DistroArchSeries), and a little-used BPBS.findBuiltOrPublishedBySourceAndArchive which finds all successfully builds that either built in or were copied into the archive, split by architecturetag.

findBuiltOrPublishedBySourceAndArchive is much simpler and faster than the old getBuildByArch, as its callsites only care about successful builds, and the series is irrelevant to filtering.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== removed file 'lib/lp/soyuz/doc/sourcepackagerelease-build-lookup.txt'
2--- lib/lp/soyuz/doc/sourcepackagerelease-build-lookup.txt 2014-11-05 09:09:21 +0000
3+++ lib/lp/soyuz/doc/sourcepackagerelease-build-lookup.txt 1970-01-01 00:00:00 +0000
4@@ -1,349 +0,0 @@
5- DOCTESTS SUCK! PLEASE DO NOT ADD TO THIS DOCTEST, SEE
6- lib/lp/soyuz/tests/test_sourcepackagerelease.py instead and consider
7- migrating tests from here to there.
8-
9-
10-= Creating & Looking for Build records =
11-
12-IBinaryPackageBuildSet can create and look up build records.
13-
14-It provides a 'getRelevantToSourceAndLocation' method which allows the
15-application to lookup for BinaryPackageBuild records for
16-SourcePackageRelease in a given DistroArchSeries and Archive.
17-
18-To demonstrate this we need to define some variables.
19-
20- >>> from zope.component import getUtility
21- >>> from lp.registry.interfaces.distribution import IDistributionSet
22- >>> from lp.services.librarian.interfaces import ILibraryFileAliasSet
23- >>> from lp.soyuz.interfaces.binarypackagebuild import (
24- ... IBinaryPackageBuildSet)
25-
26- >>> ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
27- >>> hoary = ubuntu.getSeries('hoary')
28-
29-Retrieve hoary/i386 and hoary/hppa `DistroArchSeries.
30-
31- >>> hoary_i386 = hoary['i386']
32- >>> hoary_hppa = hoary['hppa']
33-
34- >>> fake_chroot = getUtility(ILibraryFileAliasSet)[1]
35- >>> trash = hoary_i386.addOrUpdateChroot(fake_chroot)
36- >>> trash = hoary_hppa.addOrUpdateChroot(fake_chroot)
37-
38- >>> from lp.registry.interfaces.person import IPersonSet
39- >>> cprov = getUtility(IPersonSet).getByName('cprov')
40-
41- >>> from lp.registry.interfaces.pocket import (
42- ... PackagePublishingPocket)
43- >>> pocket_release = PackagePublishingPocket.RELEASE
44-
45-The base method BinaryPackageBuildSet.new() is able to create a build to
46-a given distro_arch_series, pocket and archive.
47-
48-Build.status, by default is set to NEEDSBUILD, but you can
49-optionally provide another status.
50-
51- >>> hoary_evo_source = hoary.getSourcePackage('evolution')
52- >>> evo_release = hoary_evo_source['1.0'].sourcepackagerelease
53-
54- >>> from lp.buildmaster.enums import BuildStatus
55- >>> evo_build_i386 = getUtility(IBinaryPackageBuildSet).new(
56- ... evo_release, ubuntu.main_archive, hoary_i386, pocket_release,
57- ... status=BuildStatus.FULLYBUILT)
58-
59- >>> print evo_build_i386.status.name
60- FULLYBUILT
61-
62- >>> evo_build_i386.distro_arch_series.architecturetag
63- u'i386'
64-
65- >>> print evo_build_i386.archive.displayname
66- Primary Archive for Ubuntu Linux
67-
68-The build record can be retrieved on hoary/i386 architecture.
69-
70- >>> bpbs = getUtility(IBinaryPackageBuildSet)
71- >>> test_build_i386 = bpbs.getRelevantToSourceAndLocation(
72- ... evo_release, ubuntu.main_archive, hoary_i386)
73- >>> test_build_i386 == evo_build_i386
74- True
75-
76-However a hoary/hppa build is not available.
77-
78- >>> test_build_hppa = bpbs.getRelevantToSourceAndLocation(
79- ... evo_release, ubuntu.main_archive, hoary_hppa)
80- >>> print test_build_hppa
81- None
82-
83-
84-== Sources inherited during distroseries initialization ==
85-
86-We will copy the evolution source to ubuntu/breezy-autotest as if it
87-was inherited in the initialization.
88-
89- >>> breezy_autotest = ubuntu.getSeries('breezy-autotest')
90- >>> breezy_autotest_i386 = breezy_autotest['i386']
91-
92- >>> print breezy_autotest.previous_series.title
93- The Hoary Hedgehog Release
94-
95- >>> evo_pub = hoary.getPublishedSources('evolution', version='1.0')[0]
96- >>> copied_pub = evo_pub.copyTo(
97- ... breezy_autotest, pocket_release, breezy_autotest.main_archive)
98-
99- >>> breezy_autotest_evo_source = breezy_autotest.getSourcePackage(
100- ... 'evolution')
101- >>> breezy_autotest_evo_release = breezy_autotest_evo_source['1.0']
102- >>> evo_release == breezy_autotest_evo_release.sourcepackagerelease
103- True
104-
105-Since evolution source was already built on ubuntu/hoary/i386, the
106-parent series, it should be found by a build lookup happening on
107-ubuntu/breezy-autotest/i386.
108-
109-In practical terms it means that another build is not necessary in
110-this context.
111-
112- >>> breezy_autotest_build = bpbs.getRelevantToSourceAndLocation(
113- ... evo_release, ubuntu.main_archive, breezy_autotest_i386)
114- >>> print breezy_autotest_build.title
115- i386 build of evolution 1.0 in ubuntu hoary RELEASE
116-
117-
118-== Sources with architecture-independent and specific binaries ==
119-
120-Even if the source package builds an architecture-independent package,
121-no Build record will be returned by getRelevantToSourceAndLocation() if
122-arch-specific binary packages were not built (see bug #65712 for further
123-information).
124-
125-In order to be independent of the sampledata we will use the
126-SoyuzTestPublisher helper to create fake but complete publication for
127-this test.
128-
129- >>> from lp.soyuz.enums import (
130- ... PackagePublishingStatus)
131- >>> from lp.soyuz.tests.test_publishing import (
132- ... SoyuzTestPublisher)
133-
134- >>> test_publisher = SoyuzTestPublisher()
135-
136- >>> name16 = getUtility(IPersonSet).getByName('name16')
137- >>> test_publisher.person = name16
138-
139-Let's create and publish a source which produces an
140-architecture-independent binary.
141-
142- >>> foo_pub_src = test_publisher.getPubSource(
143- ... version="1.0", architecturehintlist='all',
144- ... distroseries=hoary, archive=ubuntu.main_archive,
145- ... status=PackagePublishingStatus.PUBLISHED)
146-
147- >>> foo_pub_binaries = test_publisher.getPubBinaries(
148- ... distroseries=hoary, pub_source=foo_pub_src,
149- ... status=PackagePublishingStatus.PUBLISHED)
150-
151-The build record for foo in hoary/i386 was created.
152-
153- >>> test_build_i386 = bpbs.getRelevantToSourceAndLocation(
154- ... foo_pub_src.sourcepackagerelease, ubuntu.main_archive, hoary_i386)
155- >>> print test_build_i386.title
156- i386 build of foo 1.0 in ubuntu hoary RELEASE
157-
158-And despite of having a architecture-independent binary published in
159-hoary hppa, the build lookup in this architecture returns None, i.e,
160-the build doesn't exist.
161-
162- >>> for pub in foo_pub_binaries:
163- ... print pub.displayname
164- foo-bin 1.0 in hoary i386
165- foo-bin 1.0 in hoary hppa
166-
167- >>> test_build_hppa = bpbs.getRelevantToSourceAndLocation(
168- ... foo_pub_src.sourcepackagerelease, ubuntu.main_archive, hoary_hppa)
169- >>> print test_build_hppa
170- None
171-
172-
173-== Sources copied from PRIMARY to PPAs ==
174-
175-Sources published (uploaded or copied) to the PPA do not share builds
176-with the distribution main archive (PRIMARY/PARTNER). They should have
177-a build record representing the building context for the specific PPA
178-where they are published.
179-
180-Let's start by copying a PRIMARY archive source to Celso's PPA.
181-
182- >>> copy = evo_pub.copyTo(hoary, pocket_release, cprov.archive)
183-
184-No suitable build will be found for it.
185-
186- >>> test_build_i386_ppa = bpbs.getRelevantToSourceAndLocation(
187- ... copy.sourcepackagerelease, cprov.archive, hoary_i386)
188- >>> print test_build_i386_ppa
189- None
190-
191-Then we can create a build record representing the intent to build
192-the copied source using the current PPA context. The PPA build context
193-is a merge between the PRIMARY archive context and the differences
194-introduced by the PPA itself, like new package or new dependency
195-versions, so the resulted binary will be influenced by the PPA
196-contents at the time it was built.
197-
198- >>> evo_build_i386_ppa = getUtility(IBinaryPackageBuildSet).new(
199- ... copy.sourcepackagerelease, cprov.archive, hoary_i386,
200- ... pocket_release)
201-
202- >>> evo_build_i386_ppa.status.name
203- 'NEEDSBUILD'
204-
205- >>> print evo_build_i386_ppa.archive.displayname
206- PPA for Celso Providelo
207-
208-The copied source build lookup in the PPA returns the build created in
209-the PPA context, not the PRIMARY archive one.
210-
211- >>> test_build_i386_ppa = bpbs.getRelevantToSourceAndLocation(
212- ... copy.sourcepackagerelease, cprov.archive, hoary_i386)
213- >>> test_build_i386_ppa == evo_build_i386_ppa
214- True
215-
216-As expected, the hoary/hppa build is still missing in both archives.
217-
218- >>> test_build_hppa_ppa = bpbs.getRelevantToSourceAndLocation(
219- ... copy.sourcepackagerelease, cprov.archive, hoary_hppa)
220- >>> print test_build_hppa_ppa
221- None
222-
223-When we create a hoary/hppa build in the PPA context, it will continue
224-to be missing in the PRIMARY archive context.
225-
226- >>> evo_build_hppa_ppa = getUtility(IBinaryPackageBuildSet).new(
227- ... copy.sourcepackagerelease, cprov.archive, hoary_hppa,
228- ... pocket_release)
229-
230- >>> test_build_hppa_ppa = bpbs.getRelevantToSourceAndLocation(
231- ... copy.sourcepackagerelease, cprov.archive, hoary_hppa)
232- >>> print test_build_hppa_ppa.title
233- hppa build of evolution 1.0 in ubuntu hoary RELEASE
234-
235- >>> test_build_hppa = bpbs.getRelevantToSourceAndLocation(
236- ... evo_release, ubuntu.main_archive, hoary_hppa)
237- >>> print test_build_hppa
238- None
239-
240-
241-== Build lookup for sources & binaries copied across PPAs ==
242-
243-Launchpad also allows copies from published sources including
244-corresponding binaries from PRIMARY archive to PPA or from one PPA to
245-another.
246-
247-We will create a foo_1.0 source, build and i386 binary published in
248-hoary PRIMARY archive.
249-
250- >>> foo_pub_src = test_publisher.getPubSource(
251- ... version="0.1", architecturehintlist='i386',
252- ... distroseries=hoary, archive=ubuntu.main_archive,
253- ... status=PackagePublishingStatus.PUBLISHED)
254-
255- >>> foo_pub_binaries = test_publisher.getPubBinaries(
256- ... distroseries=hoary, pub_source=foo_pub_src,
257- ... status=PackagePublishingStatus.PUBLISHED)
258-
259- >>> foo_source_release = foo_pub_src.sourcepackagerelease
260- >>> build_primary = bpbs.getRelevantToSourceAndLocation(
261- ... foo_source_release, ubuntu.main_archive, hoary_i386)
262-
263- >>> print build_primary.title
264- i386 build of foo 0.1 in ubuntu hoary RELEASE
265-
266- >>> print build_primary.archive.displayname
267- Primary Archive for Ubuntu Linux
268-
269-Then we can copy source and binary from PRIMARY archive to Celso's PPA:
270-
271- >>> cprov_src = foo_pub_src.copyTo(
272- ... hoary, pocket_release, cprov.archive)
273- >>> [cprov_bin] = foo_pub_binaries[0].copyTo(
274- ... hoary, pocket_release, cprov.archive)
275- >>> cprov_src.status = PackagePublishingStatus.PUBLISHED
276- >>> cprov_bin.status = PackagePublishingStatus.PUBLISHED
277- >>> from lp.services.database.sqlbase import flush_database_updates
278- >>> flush_database_updates()
279-
280-A build record is clearly not required here, since both, source and
281-binary got copied from PRIMARY archive, thus the system is able to
282-identify this situation and locate the original build. See the
283-bug #181736 report for previous mistakes in this area.
284-
285- >>> cprov_spr = cprov_src.sourcepackagerelease
286- >>> cprov_build = bpbs.getRelevantToSourceAndLocation(
287- ... cprov_spr, cprov.archive, hoary_i386)
288-
289- >>> print cprov_build.title
290- i386 build of foo 0.1 in ubuntu hoary RELEASE
291-
292- >>> print cprov_build.archive.displayname
293- Primary Archive for Ubuntu Linux
294-
295-It's even possible to copy source and binaries from hoary to warty
296-suite in Celso's PPA.
297-
298- >>> cprov_foo_src = cprov.archive.getPublishedSources(
299- ... name=u'foo', distroseries=hoary).first()
300- >>> cprov_foo_bin = cprov_foo_src.getPublishedBinaries()[0]
301-
302- >>> warty = ubuntu.getSeries('warty')
303- >>> copied_source = cprov_foo_src.copyTo(
304- ... warty, pocket_release, cprov.archive)
305- >>> [copied_binary] = cprov_foo_bin.copyTo(
306- ... warty, pocket_release, cprov.archive)
307- >>> copied_source.status = PackagePublishingStatus.PUBLISHED
308- >>> copied_binary.status = PackagePublishingStatus.PUBLISHED
309- >>> flush_database_updates()
310-
311-In this case the system is also able to locate the original build by
312-following the build path of the corresponding published binaries.
313-
314- >>> copied_source_release = copied_source.sourcepackagerelease
315- >>> warty_i386 = warty['i386']
316- >>> copied_build_candidate = bpbs.getRelevantToSourceAndLocation(
317- ... copied_source_release, cprov.archive, warty_i386)
318-
319- >>> print copied_build_candidate.title
320- i386 build of foo 0.1 in ubuntu hoary RELEASE
321-
322- >>> print copied_build_candidate.archive.displayname
323- Primary Archive for Ubuntu Linux
324-
325-Now we can also copy the hoary source and its binary from Celso's PPA
326-to Mark Shuttleworth's PPA.
327-
328- >>> cprov_foo_src = cprov.archive.getPublishedSources(
329- ... name=u'foo', distroseries=hoary).first()
330- >>> cprov_foo_bin = cprov_foo_src.getPublishedBinaries()[0]
331-
332- >>> mark = getUtility(IPersonSet).getByName('mark')
333- >>> mark_src = cprov_foo_src.copyTo(
334- ... hoary, pocket_release, mark.archive)
335- >>> [mark_bin] = cprov_foo_bin.copyTo(
336- ... hoary, pocket_release, mark.archive)
337- >>> mark_src.status = PackagePublishingStatus.PUBLISHED
338- >>> mark_bin.status = PackagePublishingStatus.PUBLISHED
339- >>> flush_database_updates()
340-
341-The published binaries build path is followed again to find the
342-original build that happened in the primary archive.
343-
344- >>> mark_spr = mark_src.sourcepackagerelease
345- >>> mark_build = bpbs.getRelevantToSourceAndLocation(
346- ... mark_spr, mark.archive, hoary_i386)
347-
348- >>> print mark_build.title
349- i386 build of foo 0.1 in ubuntu hoary RELEASE
350-
351- >>> print mark_build.archive.displayname
352- Primary Archive for Ubuntu Linux
353-
354
355=== modified file 'lib/lp/soyuz/interfaces/binarypackagebuild.py'
356--- lib/lp/soyuz/interfaces/binarypackagebuild.py 2014-11-05 11:20:23 +0000
357+++ lib/lp/soyuz/interfaces/binarypackagebuild.py 2014-11-06 02:44:46 +0000
358@@ -380,14 +380,15 @@
359 :return: a list of `IBuild` records not target to PPA archives.
360 """
361
362- def getRelevantToSourceAndLocation(sourcepackagerelease, archive,
363- distroarchseries):
364- """Return build for the given source, archive and distroarchseries.
365-
366- It looks for a build in any state registered *directly* for the
367- given distroarchseries and archive.
368-
369- Returns None if a suitable build could not be found.
370+ def findBuiltOrPublishedBySourceAndArchive(sourcepackagerelease, archive):
371+ """Find all successful builds for source relevant to an Archive.
372+
373+ This includes all successful builds for the source directly in
374+ this archive, and any that had their binaries copied into this
375+ archive.
376+
377+ :return: A dict mapping architecture tags (in string form,
378+ e.g. 'i386') to `BinaryPackageBuild`s for that build.
379 """
380
381 def getStatusSummaryForBuilds(builds):
382
383=== modified file 'lib/lp/soyuz/model/binarypackagebuild.py'
384--- lib/lp/soyuz/model/binarypackagebuild.py 2014-11-05 11:25:28 +0000
385+++ lib/lp/soyuz/model/binarypackagebuild.py 2014-11-06 02:44:46 +0000
386@@ -19,12 +19,14 @@
387 import pytz
388 from sqlobject import SQLObjectNotFound
389 from storm.expr import (
390+ And,
391 Desc,
392+ Exists,
393 Join,
394 LeftJoin,
395 Or,
396+ Select,
397 )
398-from storm.info import ClassAlias
399 from storm.locals import (
400 Bool,
401 DateTime,
402@@ -1163,89 +1165,38 @@
403 Desc(BinaryPackageBuild.date_created), BinaryPackageBuild.id)
404 return resultset
405
406- def _findBySourceAndLocation(self, sourcepackagerelease, archive,
407- distroseries):
408- """Find builds for a SourcePackageRelease by series and archive.
409-
410- Looks for `BinaryPackageBuild` records for this source package
411- release, with publication records in the given distroseries.
412- There should be at most one of these per architecture.
413-
414- :param distroseries: `DistroSeries` to look for.
415- :return: A dict mapping architecture tags (in string form,
416- e.g. 'i386') to `BinaryPackageBuild`s for that build.
417- """
418- # Avoid circular imports.
419- from lp.soyuz.model.distroarchseries import DistroArchSeries
420+ def findBuiltOrPublishedBySourceAndArchive(self, sourcepackagerelease,
421+ archive):
422+ """See `IBinaryPackageBuildSet`."""
423 from lp.soyuz.model.publishing import BinaryPackagePublishingHistory
424
425- BuildDAS = ClassAlias(DistroArchSeries, 'BuildDAS')
426- PublishDAS = ClassAlias(DistroArchSeries, 'PublishDAS')
427-
428- query = IStore(BinaryPackageBuild).find(
429- (BuildDAS.architecturetag, BinaryPackageBuild),
430+ published_query = Select(
431+ 1,
432+ tables=(
433+ BinaryPackagePublishingHistory,
434+ Join(
435+ BinaryPackageRelease,
436+ BinaryPackageRelease.id ==
437+ BinaryPackagePublishingHistory.binarypackagereleaseID)
438+ ),
439+ where=And(
440+ BinaryPackagePublishingHistory.archive == archive,
441+ BinaryPackageRelease.build == BinaryPackageBuild.id))
442+ builds = list(IStore(BinaryPackageBuild).find(
443+ BinaryPackageBuild,
444+ BinaryPackageBuild.status == BuildStatus.FULLYBUILT,
445 BinaryPackageBuild.source_package_release == sourcepackagerelease,
446- BinaryPackageRelease.buildID == BinaryPackageBuild.id,
447- BuildDAS.id == BinaryPackageBuild.distro_arch_series_id,
448- BinaryPackagePublishingHistory.binarypackagereleaseID ==
449- BinaryPackageRelease.id,
450- BinaryPackagePublishingHistory.archiveID == archive.id,
451- PublishDAS.id ==
452- BinaryPackagePublishingHistory.distroarchseriesID,
453- PublishDAS.distroseriesID == distroseries.id,
454- # Architecture-independent binary package releases are built
455- # in the nominated arch-indep architecture but published in
456- # all architectures. This condition makes sure we consider
457- # only builds that have been published in their own
458- # architecture.
459- PublishDAS.architecturetag == BuildDAS.architecturetag)
460- results = list(query.config(distinct=True))
461- mapped_results = dict(results)
462- assert len(mapped_results) == len(results), (
463- "Found multiple build candidates per architecture: %s. "
464- "This may mean that we have a serious problem in our DB model. "
465- "Further investigation is required."
466- % [(tag, build.id) for tag, build in results])
467- return mapped_results
468-
469- def getRelevantToSourceAndLocation(self, sourcepackagerelease, archive,
470- distroarchseries):
471- """See IBinaryPackageBuildSet."""
472- # First we try to follow any binaries built from the given source
473- # in a distroarchseries with the given architecturetag and published
474- # in the given (distroarchseries, archive) location.
475- # (Querying all architectures and then picking the right one out
476- # of the result turns out to be much faster than querying for
477- # just the architecture we want).
478- builds_by_arch = self._findBySourceAndLocation(
479- sourcepackagerelease, archive, distroarchseries.distroseries)
480- build = builds_by_arch.get(distroarchseries.architecturetag)
481- if build is not None:
482- # If there was any published binary we can use its original build.
483- # This case covers the situations when both source and binaries
484- # got copied from another location.
485- return build
486-
487- # If there was no published binary we have to try to find a
488- # suitable build in all possible location across the distroseries
489- # inheritance tree. See below.
490- clause_tables = ['DistroArchSeries']
491- queries = [
492- "DistroArchSeries.id = BinaryPackageBuild.distro_arch_series AND "
493- "BinaryPackageBuild.archive = %s AND "
494- "DistroArchSeries.architecturetag = %s AND "
495- "BinaryPackageBuild.source_package_release = %s" % (
496- sqlvalues(
497- archive.id, distroarchseries.architecturetag,
498- sourcepackagerelease))]
499-
500- # Query only the last build record for this sourcerelease
501- # across all possible locations.
502- query = " AND ".join(queries)
503-
504- return BinaryPackageBuild.selectFirst(
505- query, clauseTables=clause_tables,
506- orderBy=['-date_created'])
507+ Or(
508+ BinaryPackageBuild.archive == archive,
509+ Exists(published_query))))
510+ arch_map = {
511+ build.distro_arch_series.architecturetag: build
512+ for build in builds}
513+ if len(arch_map) != len(builds):
514+ raise AssertionError(
515+ "Multiple successful builds for a single archtag. "
516+ "Something is probably corrupt.")
517+ return arch_map
518
519 def getStatusSummaryForBuilds(self, builds):
520 """See `IBinaryPackageBuildSet`."""
521@@ -1440,14 +1391,14 @@
522 Return the just-created `IBinaryPackageBuild` record already
523 scored or None if a suitable build is already present.
524 """
525- build_candidate = self.getRelevantToSourceAndLocation(
526+ exact_build = self.getBySourceAndLocation(
527 sourcepackagerelease, archive, arch)
528+ if exact_build is not None:
529+ return None
530
531- # Check DistroArchSeries database IDs because the object belongs
532- # to different transactions (architecture_available is cached).
533- if (build_candidate is not None and
534- (build_candidate.distro_arch_series.id == arch.id or
535- build_candidate.status == BuildStatus.FULLYBUILT)):
536+ build_candidate = self.findBuiltOrPublishedBySourceAndArchive(
537+ sourcepackagerelease, archive).get(arch.architecturetag)
538+ if build_candidate is not None:
539 return None
540
541 build = self.new(
542
543=== modified file 'lib/lp/soyuz/scripts/tests/test_initialize_distroseries.py'
544--- lib/lp/soyuz/scripts/tests/test_initialize_distroseries.py 2014-11-05 12:10:10 +0000
545+++ lib/lp/soyuz/scripts/tests/test_initialize_distroseries.py 2014-11-06 02:44:46 +0000
546@@ -598,8 +598,8 @@
547 self.assertEqual(udev_src.title, u'udev - 0.1-1')
548 # The build of udev 0.1-1 has been copied across.
549 bpbs = getUtility(IBinaryPackageBuildSet)
550- child_udev = bpbs.getRelevantToSourceAndLocation(
551- udev_src, child.main_archive, child[parent_das.architecturetag])
552+ child_udev = bpbs.findBuiltOrPublishedBySourceAndArchive(
553+ udev_src, child.main_archive).get(parent_das.architecturetag)
554 parent_udev = bpbs.getBySourceAndLocation(
555 udev_src, parent.main_archive, parent[parent_das.architecturetag])
556 self.assertEqual(parent_udev.id, child_udev.id)
557
558=== modified file 'lib/lp/soyuz/tests/test_build_set.py'
559--- lib/lp/soyuz/tests/test_build_set.py 2014-11-06 02:29:29 +0000
560+++ lib/lp/soyuz/tests/test_build_set.py 2014-11-06 02:44:46 +0000
561@@ -360,53 +360,98 @@
562 self.assertBuildsMatch({'sparc': True, 'avr': False}, builds)
563
564
565-class TestFindBySourceAndLocation(TestCaseWithFactory):
566- """Tests for the _findBySourceAndLocation helper."""
567-
568- layer = ZopelessDatabaseLayer
569-
570- def test_finds_build_with_matching_pub(self):
571- # _findBySourceAndLocation finds builds for a source package
572- # release. In particular, an arch-independent BPR is published in
573- # multiple architectures. But findBuildsByArchitecture only counts
574- # the publication for the same architecture it was built in.
575- distroseries = self.factory.makeDistroSeries()
576- archive = distroseries.main_archive
577- # The series has a nominated arch-indep architecture.
578- distroseries.nominatedarchindep = self.factory.makeDistroArchSeries(
579- distroseries=distroseries)
580-
581- bpb = self.factory.makeBinaryPackageBuild(
582- distroarchseries=distroseries.nominatedarchindep)
583- bpr = self.factory.makeBinaryPackageRelease(
584- build=bpb, architecturespecific=False)
585- spr = bpr.build.source_package_release
586-
587- # The series also has other architectures.
588- self.factory.makeDistroArchSeries(distroseries=distroseries)
589-
590- # makeBinaryPackagePublishingHistory will actually publish an
591- # arch-indep BPR everywhere.
592- self.factory.makeBinaryPackagePublishingHistory(
593- binarypackagerelease=bpr, archive=archive,
594- distroarchseries=distroseries.nominatedarchindep)
595-
596- naked_spr = removeSecurityProxy(spr)
597- self.assertEqual(
598- {distroseries.nominatedarchindep.architecturetag: bpr.build},
599- BinaryPackageBuildSet()._findBySourceAndLocation(
600- naked_spr, archive, distroseries))
601-
602-
603-class TestGetBySourceAndLocation(TestCaseWithFactory):
604- """Tests for BinaryPackageBuildSet.getRelevantToSourceAndLocation()."""
605-
606- layer = ZopelessDatabaseLayer
607+class TestFindBuiltOrPublishedBySourceAndArchive(TestCaseWithFactory):
608+ """Tests for findBuiltOrPublishedBySourceAndArchive()."""
609+
610+ layer = ZopelessDatabaseLayer
611+
612+ def setUp(self):
613+ super(TestFindBuiltOrPublishedBySourceAndArchive, self).setUp()
614+ self.bpbs = getUtility(IBinaryPackageBuildSet)
615+
616+ def test_trivial(self):
617+ # Builds with status FULLYBUILT with a matching
618+ # SourcePackageRelease and Archive are returned.
619+ bpb1 = self.factory.makeBinaryPackageBuild(
620+ status=BuildStatus.FULLYBUILT)
621+ bpb2 = self.factory.makeBinaryPackageBuild(
622+ source_package_release=bpb1.source_package_release,
623+ archive=bpb1.archive)
624+ self.assertEqual(
625+ {bpb1.distro_arch_series.architecturetag: bpb1},
626+ self.bpbs.findBuiltOrPublishedBySourceAndArchive(
627+ bpb1.source_package_release, bpb1.archive))
628+ bpb2.updateStatus(BuildStatus.FULLYBUILT)
629+ self.assertEqual(
630+ {bpb1.distro_arch_series.architecturetag: bpb1,
631+ bpb2.distro_arch_series.architecturetag: bpb2},
632+ self.bpbs.findBuiltOrPublishedBySourceAndArchive(
633+ bpb1.source_package_release, bpb1.archive))
634+
635+ def test_trivial_mismatch(self):
636+ # Builds for other sources and archives are ignored.
637+ bpb = self.factory.makeBinaryPackageBuild()
638+ self.assertEqual(
639+ {},
640+ self.bpbs.findBuiltOrPublishedBySourceAndArchive(
641+ bpb.source_package_release, self.factory.makeArchive()))
642+ self.assertEqual(
643+ {},
644+ self.bpbs.findBuiltOrPublishedBySourceAndArchive(
645+ self.factory.makeSourcePackageRelease(), bpb.archive))
646+
647+ def test_copies_are_found(self):
648+ # If a build's binaries are published (with a
649+ # BinaryPackagePublishingHistory) in another archive, it shows
650+ # up in requests for that archive.
651+ bpb1 = self.factory.makeBinaryPackageBuild(
652+ status=BuildStatus.FULLYBUILT)
653+ bpr1 = self.factory.makeBinaryPackageRelease(build=bpb1)
654+ bpb2 = self.factory.makeBinaryPackageBuild(
655+ source_package_release=bpb1.source_package_release,
656+ archive=bpb1.archive, status=BuildStatus.FULLYBUILT)
657+ bpr2 = self.factory.makeBinaryPackageRelease(build=bpb2)
658+
659+ # A fresh archive sees no builds.
660+ target = self.factory.makeArchive()
661+ self.assertEqual(
662+ {},
663+ self.bpbs.findBuiltOrPublishedBySourceAndArchive(
664+ bpb1.source_package_release, target))
665+
666+ # But copying one build over makes it appear.
667+ self.factory.makeBinaryPackagePublishingHistory(
668+ binarypackagerelease=bpr1, archive=target)
669+ self.assertEqual(
670+ {bpb1.distro_arch_series.architecturetag: bpb1},
671+ self.bpbs.findBuiltOrPublishedBySourceAndArchive(
672+ bpb1.source_package_release, target))
673+
674+ # Copying the second gives us both.
675+ self.factory.makeBinaryPackagePublishingHistory(
676+ binarypackagerelease=bpr2, archive=target)
677+ self.assertEqual(
678+ {bpb1.distro_arch_series.architecturetag: bpb1,
679+ bpb2.distro_arch_series.architecturetag: bpb2},
680+ self.bpbs.findBuiltOrPublishedBySourceAndArchive(
681+ bpb1.source_package_release, target))
682+ self.assertEqual(
683+ self.bpbs.findBuiltOrPublishedBySourceAndArchive(
684+ bpb1.source_package_release, bpb1.archive),
685+ self.bpbs.findBuiltOrPublishedBySourceAndArchive(
686+ bpb1.source_package_release, target))
687+
688+ # A third archive still shows nothing.
689+ untarget = self.factory.makeArchive()
690+ self.assertEqual(
691+ {},
692+ self.bpbs.findBuiltOrPublishedBySourceAndArchive(
693+ bpb1.source_package_release, untarget))
694
695 def test_can_find_build_in_derived_distro_parent(self):
696 # If a derived distribution inherited its binaries from its
697- # parent then getRelevantToSourceAndLocation() should look in
698- # the parent to find the build.
699+ # parent then findBuiltOrPublishedBySourceAndArchive() should
700+ # look in the parent to find the build.
701 dsp = self.factory.makeDistroSeriesParent()
702 parent_archive = dsp.parent_series.main_archive
703
704@@ -444,6 +489,6 @@
705 # Searching for the build in the derived series architecture
706 # should automatically pick it up from the parent.
707 found_build = getUtility(
708- IBinaryPackageBuildSet).getRelevantToSourceAndLocation(
709- spr, derived_archive, das_derived)
710+ IBinaryPackageBuildSet).findBuiltOrPublishedBySourceAndArchive(
711+ spr, derived_archive).get(das_derived.architecturetag)
712 self.assertEqual(orig_build, found_build)
713
714=== modified file 'lib/lp/soyuz/tests/test_doc.py'
715--- lib/lp/soyuz/tests/test_doc.py 2013-06-27 06:59:35 +0000
716+++ lib/lp/soyuz/tests/test_doc.py 2014-11-06 02:44:46 +0000
717@@ -134,10 +134,6 @@
718 setUp=setUp,
719 layer=LaunchpadZopelessLayer,
720 ),
721- 'sourcepackagerelease-build-lookup.txt': LayeredDocFileSuite(
722- '../doc/sourcepackagerelease-build-lookup.txt',
723- layer=LaunchpadZopelessLayer,
724- ),
725 }
726
727