Merge lp:~wgrant/launchpad/simplify-getRelevantToSourceAndArchive into lp:launchpad
- simplify-getRelevantToSourceAndArchive
- Merge into devel
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
William Grant | code | Approve | |
Review via email: mp+240805@code.launchpad.net |
Commit message
BinaryPackageBu
Description of the change
BinaryPackageBu
The horrifying complexity arose over the 9 year history of the method (originally SourcePackageRe
findBuiltOrPubl
William Grant (wgrant) : | # |
Preview Diff
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 |