Merge lp:~wgrant/launchpad/flatten-bfj-2-garbo into lp:launchpad

Proposed by William Grant
Status: Merged
Merged at revision: 16467
Proposed branch: lp:~wgrant/launchpad/flatten-bfj-2-garbo
Merge into: lp:launchpad
Prerequisite: lp:~wgrant/launchpad/flatten-bfj-1-populate
Diff against target: 543 lines (+380/-1)
5 files modified
database/schema/security.cfg (+4/-0)
lib/lp/scripts/garbo.py (+227/-0)
lib/lp/scripts/tests/test_garbo.py (+136/-1)
lib/lp/soyuz/interfaces/binarypackagebuild.py (+3/-0)
lib/lp/soyuz/model/binarypackagebuild.py (+10/-0)
To merge this branch: bzr merge lp:~wgrant/launchpad/flatten-bfj-2-garbo
Reviewer Review Type Date Requested Status
Steve Kowalik (community) code Approve
Review via email: mp+145542@code.launchpad.net

Commit message

Add garbo jobs to backfill the denormalised BPB/SRPB/TTB columns.

Description of the change

The build farm job schema is being reworked to improve performance. Columns from PackageBuild and BuildFarmJob are being merged into tables that previously delegated to them. The PackageBuild table will end up dying entirely, but BuildFarmJob will remain, a shadow of its former self, to answer questions about Archive:+builds and Builder:+history. Additionally, BinaryPackageBuild is growing new distribution, distroseries, sourcepackagename and is_distro_archive columns to make searches even faster.

This is the second app part: a garbo job to backfill the values that I started setting in the prereq.

To post a comment you must log in.
Revision history for this message
Steve Kowalik (stevenk) wrote :

You could *almost* get away with refactoring this into a base class and then having 3 smaller classes that use the base as a super class. But this code should be short lived enough that it probably does not matter.

518 + is_distro_archive = Attribute(
519 + "Whether the target archive belongs to the distro")

Terrible message is terrible.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'database/schema/security.cfg'
--- database/schema/security.cfg 2013-02-04 02:04:26 +0000
+++ database/schema/security.cfg 2013-02-04 02:04:26 +0000
@@ -2218,6 +2218,7 @@
2218public.answercontact = SELECT, DELETE2218public.answercontact = SELECT, DELETE
2219public.branch = SELECT, UPDATE2219public.branch = SELECT, UPDATE
2220public.branchjob = SELECT, DELETE2220public.branchjob = SELECT, DELETE
2221public.binarypackagebuild = SELECT, UPDATE
2221public.binarypackagename = SELECT2222public.binarypackagename = SELECT
2222public.binarypackagerelease = SELECT2223public.binarypackagerelease = SELECT
2223public.binarypackagepublishinghistory = SELECT, UPDATE2224public.binarypackagepublishinghistory = SELECT, UPDATE
@@ -2240,6 +2241,7 @@
2240public.bugtaskflat = SELECT2241public.bugtaskflat = SELECT
2241public.bugwatch = SELECT, UPDATE2242public.bugwatch = SELECT, UPDATE
2242public.bugwatchactivity = SELECT, DELETE2243public.bugwatchactivity = SELECT, DELETE
2244public.buildfarmjob = SELECT, UPDATE
2243public.codeimportevent = SELECT, DELETE2245public.codeimportevent = SELECT, DELETE
2244public.codeimporteventdata = SELECT, DELETE2246public.codeimporteventdata = SELECT, DELETE
2245public.codeimportresult = SELECT, DELETE2247public.codeimportresult = SELECT, DELETE
@@ -2263,6 +2265,7 @@
2263public.revisionauthor = SELECT, UPDATE2265public.revisionauthor = SELECT, UPDATE
2264public.revisioncache = SELECT, DELETE2266public.revisioncache = SELECT, DELETE
2265public.sourcepackagename = SELECT2267public.sourcepackagename = SELECT
2268public.sourcepackagerecipebuild = SELECT, UPDATE
2266public.sourcepackagerelease = SELECT2269public.sourcepackagerelease = SELECT
2267public.sourcepackagepublishinghistory = SELECT, UPDATE2270public.sourcepackagepublishinghistory = SELECT, UPDATE
2268public.suggestivepotemplate = INSERT, DELETE2271public.suggestivepotemplate = INSERT, DELETE
@@ -2270,6 +2273,7 @@
2270public.teamparticipation = SELECT, DELETE2273public.teamparticipation = SELECT, DELETE
2271public.translationmessage = SELECT, DELETE2274public.translationmessage = SELECT, DELETE
2272public.translationtemplateitem = SELECT, DELETE2275public.translationtemplateitem = SELECT, DELETE
2276public.translationtemplatesbuild = SELECT, UPDATE
2273type=user2277type=user
22742278
2275[garbo_daily]2279[garbo_daily]
22762280
=== modified file 'lib/lp/scripts/garbo.py'
--- lib/lp/scripts/garbo.py 2013-01-17 00:25:48 +0000
+++ lib/lp/scripts/garbo.py 2013-02-04 02:04:26 +0000
@@ -57,6 +57,8 @@
57 BugWatchScheduler,57 BugWatchScheduler,
58 MAX_SAMPLE_SIZE,58 MAX_SAMPLE_SIZE,
59 )59 )
60from lp.buildmaster.model.buildfarmjob import BuildFarmJob
61from lp.buildmaster.model.packagebuild import PackageBuild
60from lp.code.interfaces.revision import IRevisionSet62from lp.code.interfaces.revision import IRevisionSet
61from lp.code.model.codeimportevent import CodeImportEvent63from lp.code.model.codeimportevent import CodeImportEvent
62from lp.code.model.codeimportresult import CodeImportResult64from lp.code.model.codeimportresult import CodeImportResult
@@ -64,8 +66,10 @@
64 RevisionAuthor,66 RevisionAuthor,
65 RevisionCache,67 RevisionCache,
66 )68 )
69from lp.code.model.sourcepackagerecipebuild import SourcePackageRecipeBuild
67from lp.hardwaredb.model.hwdb import HWSubmission70from lp.hardwaredb.model.hwdb import HWSubmission
68from lp.registry.model.commercialsubscription import CommercialSubscription71from lp.registry.model.commercialsubscription import CommercialSubscription
72from lp.registry.model.distroseries import DistroSeries
69from lp.registry.model.person import Person73from lp.registry.model.person import Person
70from lp.registry.model.product import Product74from lp.registry.model.product import Product
71from lp.registry.model.teammembership import TeamMembership75from lp.registry.model.teammembership import TeamMembership
@@ -104,6 +108,7 @@
104from lp.services.librarian.model import TimeLimitedToken108from lp.services.librarian.model import TimeLimitedToken
105from lp.services.log.logger import PrefixFilter109from lp.services.log.logger import PrefixFilter
106from lp.services.looptuner import TunableLoop110from lp.services.looptuner import TunableLoop
111from lp.services.memcache.interfaces import IMemcacheClient
107from lp.services.oauth.model import OAuthNonce112from lp.services.oauth.model import OAuthNonce
108from lp.services.openid.model.openidconsumer import OpenIDConsumerNonce113from lp.services.openid.model.openidconsumer import OpenIDConsumerNonce
109from lp.services.propertycache import cachedproperty114from lp.services.propertycache import cachedproperty
@@ -118,7 +123,10 @@
118 )123 )
119from lp.services.session.model import SessionData124from lp.services.session.model import SessionData
120from lp.services.verification.model.logintoken import LoginToken125from lp.services.verification.model.logintoken import LoginToken
126from lp.soyuz.interfaces.archive import MAIN_ARCHIVE_PURPOSES
121from lp.soyuz.model.archive import Archive127from lp.soyuz.model.archive import Archive
128from lp.soyuz.model.binarypackagebuild import BinaryPackageBuild
129from lp.soyuz.model.distroarchseries import DistroArchSeries
122from lp.soyuz.model.publishing import SourcePackagePublishingHistory130from lp.soyuz.model.publishing import SourcePackagePublishingHistory
123from lp.soyuz.model.reporting import LatestPersonSourcePackageReleaseCache131from lp.soyuz.model.reporting import LatestPersonSourcePackageReleaseCache
124from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease132from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease
@@ -129,6 +137,9 @@
129from lp.translations.model.translationtemplateitem import (137from lp.translations.model.translationtemplateitem import (
130 TranslationTemplateItem,138 TranslationTemplateItem,
131 )139 )
140from lp.translations.model.translationtemplatesbuild import (
141 TranslationTemplatesBuild,
142 )
132from lp.translations.scripts.scrub_pofiletranslator import (143from lp.translations.scripts.scrub_pofiletranslator import (
133 ScrubPOFileTranslator,144 ScrubPOFileTranslator,
134 )145 )
@@ -1335,6 +1346,219 @@
1335 transaction.commit()1346 transaction.commit()
13361347
13371348
1349class BinaryPackageBuildFlattener(TunableLoop):
1350 """Populates the new denormalised columns on BinaryPackageBuild."""
1351
1352 maximum_chunk_size = 5000
1353
1354 def __init__(self, log, abort_time=None):
1355 super(BinaryPackageBuildFlattener, self).__init__(log, abort_time)
1356
1357 self.memcache_key = '%s:bpb-flattener' % config.instance_name
1358 watermark = getUtility(IMemcacheClient).get(self.memcache_key)
1359 self.start_at = watermark or 0
1360 self.store = IMasterStore(BinaryPackageBuild)
1361
1362 def findIDs(self):
1363 return self.store.find(
1364 BinaryPackageBuild.id,
1365 BinaryPackageBuild.id >= self.start_at,
1366 ).order_by(BinaryPackageBuild.id)
1367
1368 def isDone(self):
1369 return (
1370 not getFeatureFlag('soyuz.flatten_bfj.garbo.enabled')
1371 or self.findIDs().is_empty())
1372
1373 def __call__(self, chunk_size):
1374 """See `ITunableLoop`."""
1375 ids = list(self.findIDs()[:chunk_size])
1376 updated_columns = {
1377 BinaryPackageBuild._new_archive_id: PackageBuild.archive_id,
1378 BinaryPackageBuild._new_pocket: PackageBuild.pocket,
1379 BinaryPackageBuild._new_processor_id: BuildFarmJob.processor_id,
1380 BinaryPackageBuild._new_virtualized: BuildFarmJob.virtualized,
1381 BinaryPackageBuild._new_date_created: BuildFarmJob.date_created,
1382 BinaryPackageBuild._new_date_started: BuildFarmJob.date_started,
1383 BinaryPackageBuild._new_date_finished: BuildFarmJob.date_finished,
1384 BinaryPackageBuild._new_date_first_dispatched:
1385 BuildFarmJob.date_first_dispatched,
1386 BinaryPackageBuild._new_builder_id: BuildFarmJob.builder_id,
1387 BinaryPackageBuild._new_status: BuildFarmJob.status,
1388 BinaryPackageBuild._new_log_id: BuildFarmJob.log_id,
1389 BinaryPackageBuild._new_upload_log_id: PackageBuild.upload_log_id,
1390 BinaryPackageBuild._new_dependencies: PackageBuild.dependencies,
1391 BinaryPackageBuild._new_failure_count: BuildFarmJob.failure_count,
1392 BinaryPackageBuild._new_build_farm_job_id: BuildFarmJob.id,
1393 BinaryPackageBuild._new_distribution_id:
1394 DistroSeries.distributionID,
1395 BinaryPackageBuild._new_distro_series_id: DistroSeries.id,
1396 BinaryPackageBuild._new_source_package_name_id:
1397 SourcePackageRelease.sourcepackagenameID,
1398 BinaryPackageBuild._new_is_distro_archive:
1399 Archive.purpose.is_in(MAIN_ARCHIVE_PURPOSES),
1400 }
1401 condition = And(
1402 BinaryPackageBuild.id.is_in(ids),
1403 PackageBuild.id == BinaryPackageBuild.package_build_id,
1404 BuildFarmJob.id == PackageBuild.build_farm_job_id)
1405 extra_condition = And(
1406 condition,
1407 SourcePackageRelease.id ==
1408 BinaryPackageBuild.source_package_release_id,
1409 Archive.id == PackageBuild.archive_id,
1410 DistroArchSeries.id == BinaryPackageBuild.distro_arch_series_id,
1411 DistroSeries.id == DistroArchSeries.distroseriesID)
1412 self.store.execute(
1413 BulkUpdate(
1414 updated_columns, table=BinaryPackageBuild,
1415 values=(
1416 PackageBuild, BuildFarmJob, Archive, DistroArchSeries,
1417 DistroSeries, SourcePackageRelease),
1418 where=And(condition, extra_condition)))
1419 self.store.execute(
1420 BulkUpdate(
1421 {BuildFarmJob.archive_id: PackageBuild.archive_id},
1422 table=BuildFarmJob, values=(PackageBuild, BinaryPackageBuild),
1423 where=condition))
1424 transaction.commit()
1425 self.start_at = ids[-1] + 1
1426 getUtility(IMemcacheClient).set(self.memcache_key, self.start_at)
1427
1428
1429class SourcePackageRecipeBuildFlattener(TunableLoop):
1430 """Populates the new denormalised columns on SourcePackageRecipeBuild."""
1431
1432 maximum_chunk_size = 5000
1433
1434 def __init__(self, log, abort_time=None):
1435 super(SourcePackageRecipeBuildFlattener, self).__init__(
1436 log, abort_time)
1437
1438 self.memcache_key = '%s:sprb-flattener' % config.instance_name
1439 watermark = getUtility(IMemcacheClient).get(self.memcache_key)
1440 self.start_at = watermark or 0
1441 self.store = IMasterStore(SourcePackageRecipeBuild)
1442
1443 def findIDs(self):
1444 return self.store.find(
1445 SourcePackageRecipeBuild.id,
1446 SourcePackageRecipeBuild.id >= self.start_at,
1447 ).order_by(SourcePackageRecipeBuild.id)
1448
1449 def isDone(self):
1450 return (
1451 not getFeatureFlag('soyuz.flatten_bfj.garbo.enabled')
1452 or self.findIDs().is_empty())
1453
1454 def __call__(self, chunk_size):
1455 """See `ITunableLoop`."""
1456 ids = list(self.findIDs()[:chunk_size])
1457 updated_columns = {
1458 SourcePackageRecipeBuild._new_archive_id: PackageBuild.archive_id,
1459 SourcePackageRecipeBuild._new_pocket: PackageBuild.pocket,
1460 SourcePackageRecipeBuild._new_processor_id:
1461 BuildFarmJob.processor_id,
1462 SourcePackageRecipeBuild._new_virtualized:
1463 BuildFarmJob.virtualized,
1464 SourcePackageRecipeBuild._new_date_created:
1465 BuildFarmJob.date_created,
1466 SourcePackageRecipeBuild._new_date_started:
1467 BuildFarmJob.date_started,
1468 SourcePackageRecipeBuild._new_date_finished:
1469 BuildFarmJob.date_finished,
1470 SourcePackageRecipeBuild._new_date_first_dispatched:
1471 BuildFarmJob.date_first_dispatched,
1472 SourcePackageRecipeBuild._new_builder_id: BuildFarmJob.builder_id,
1473 SourcePackageRecipeBuild._new_status: BuildFarmJob.status,
1474 SourcePackageRecipeBuild._new_log_id: BuildFarmJob.log_id,
1475 SourcePackageRecipeBuild._new_upload_log_id:
1476 PackageBuild.upload_log_id,
1477 SourcePackageRecipeBuild._new_dependencies:
1478 PackageBuild.dependencies,
1479 SourcePackageRecipeBuild._new_failure_count:
1480 BuildFarmJob.failure_count,
1481 SourcePackageRecipeBuild._new_build_farm_job_id: BuildFarmJob.id,
1482 }
1483 condition = And(
1484 SourcePackageRecipeBuild.id.is_in(ids),
1485 PackageBuild.id == SourcePackageRecipeBuild.package_build_id,
1486 BuildFarmJob.id == PackageBuild.build_farm_job_id)
1487 self.store.execute(
1488 BulkUpdate(
1489 updated_columns, table=SourcePackageRecipeBuild,
1490 values=(PackageBuild, BuildFarmJob), where=condition))
1491 self.store.execute(
1492 BulkUpdate(
1493 {BuildFarmJob.archive_id: PackageBuild.archive_id},
1494 table=BuildFarmJob,
1495 values=(PackageBuild, SourcePackageRecipeBuild),
1496 where=condition))
1497 transaction.commit()
1498 self.start_at = ids[-1] + 1
1499 getUtility(IMemcacheClient).set(self.memcache_key, self.start_at)
1500
1501
1502class TranslationTemplatesBuildFlattener(TunableLoop):
1503 """Populates the new denormalised columns on TranslationTemplatesBuild."""
1504
1505 maximum_chunk_size = 5000
1506
1507 def __init__(self, log, abort_time=None):
1508 super(TranslationTemplatesBuildFlattener, self).__init__(
1509 log, abort_time)
1510
1511 self.memcache_key = '%s:ttb-flattener' % config.instance_name
1512 watermark = getUtility(IMemcacheClient).get(self.memcache_key)
1513 self.start_at = watermark or 0
1514 self.store = IMasterStore(TranslationTemplatesBuild)
1515
1516 def findIDs(self):
1517 return self.store.find(
1518 TranslationTemplatesBuild.id,
1519 TranslationTemplatesBuild.id >= self.start_at,
1520 ).order_by(TranslationTemplatesBuild.id)
1521
1522 def isDone(self):
1523 return (
1524 not getFeatureFlag('soyuz.flatten_bfj.garbo.enabled')
1525 or self.findIDs().is_empty())
1526
1527 def __call__(self, chunk_size):
1528 """See `ITunableLoop`."""
1529 ids = list(self.findIDs()[:chunk_size])
1530 updated_columns = {
1531 TranslationTemplatesBuild._new_processor_id:
1532 BuildFarmJob.processor_id,
1533 TranslationTemplatesBuild._new_virtualized:
1534 BuildFarmJob.virtualized,
1535 TranslationTemplatesBuild._new_date_created:
1536 BuildFarmJob.date_created,
1537 TranslationTemplatesBuild._new_date_started:
1538 BuildFarmJob.date_started,
1539 TranslationTemplatesBuild._new_date_finished:
1540 BuildFarmJob.date_finished,
1541 TranslationTemplatesBuild._new_date_first_dispatched:
1542 BuildFarmJob.date_first_dispatched,
1543 TranslationTemplatesBuild._new_builder_id: BuildFarmJob.builder_id,
1544 TranslationTemplatesBuild._new_status: BuildFarmJob.status,
1545 TranslationTemplatesBuild._new_log_id: BuildFarmJob.log_id,
1546 TranslationTemplatesBuild._new_failure_count:
1547 BuildFarmJob.failure_count,
1548 }
1549 self.store.execute(
1550 BulkUpdate(
1551 updated_columns, table=TranslationTemplatesBuild,
1552 values=BuildFarmJob,
1553 where=And(
1554 TranslationTemplatesBuild.id.is_in(ids),
1555 BuildFarmJob.id ==
1556 TranslationTemplatesBuild.build_farm_job_id)))
1557 transaction.commit()
1558 self.start_at = ids[-1] + 1
1559 getUtility(IMemcacheClient).set(self.memcache_key, self.start_at)
1560
1561
1338class BaseDatabaseGarbageCollector(LaunchpadCronScript):1562class BaseDatabaseGarbageCollector(LaunchpadCronScript):
1339 """Abstract base class to run a collection of TunableLoops."""1563 """Abstract base class to run a collection of TunableLoops."""
1340 script_name = None # Script name for locking and database user. Override.1564 script_name = None # Script name for locking and database user. Override.
@@ -1590,6 +1814,9 @@
1590 UnusedSessionPruner,1814 UnusedSessionPruner,
1591 DuplicateSessionPruner,1815 DuplicateSessionPruner,
1592 BugHeatUpdater,1816 BugHeatUpdater,
1817 BinaryPackageBuildFlattener,
1818 SourcePackageRecipeBuildFlattener,
1819 TranslationTemplatesBuildFlattener,
1593 ]1820 ]
1594 experimental_tunable_loops = []1821 experimental_tunable_loops = []
15951822
15961823
=== modified file 'lib/lp/scripts/tests/test_garbo.py'
--- lib/lp/scripts/tests/test_garbo.py 2013-01-17 00:25:48 +0000
+++ lib/lp/scripts/tests/test_garbo.py 2013-02-04 02:04:26 +0000
@@ -31,6 +31,7 @@
31from testtools.matchers import (31from testtools.matchers import (
32 Equals,32 Equals,
33 GreaterThan,33 GreaterThan,
34 MatchesStructure,
34 )35 )
35import transaction36import transaction
36from zope.component import getUtility37from zope.component import getUtility
@@ -42,6 +43,7 @@
42 BugNotification,43 BugNotification,
43 BugNotificationRecipient,44 BugNotificationRecipient,
44 )45 )
46from lp.buildmaster.enums import BuildStatus
45from lp.code.bzr import (47from lp.code.bzr import (
46 BranchFormat,48 BranchFormat,
47 RepositoryFormat,49 RepositoryFormat,
@@ -58,6 +60,7 @@
58 BranchSharingPolicy,60 BranchSharingPolicy,
59 BugSharingPolicy,61 BugSharingPolicy,
60 )62 )
63from lp.code.model.sourcepackagerecipebuild import SourcePackageRecipeBuild
61from lp.registry.interfaces.accesspolicy import IAccessPolicySource64from lp.registry.interfaces.accesspolicy import IAccessPolicySource
62from lp.registry.interfaces.person import IPersonSet65from lp.registry.interfaces.person import IPersonSet
63from lp.registry.interfaces.teammembership import TeamMembershipStatus66from lp.registry.interfaces.teammembership import TeamMembershipStatus
@@ -114,6 +117,7 @@
114from lp.services.verification.model.logintoken import LoginToken117from lp.services.verification.model.logintoken import LoginToken
115from lp.services.worlddata.interfaces.language import ILanguageSet118from lp.services.worlddata.interfaces.language import ILanguageSet
116from lp.soyuz.enums import PackagePublishingStatus119from lp.soyuz.enums import PackagePublishingStatus
120from lp.soyuz.model.binarypackagebuild import BinaryPackageBuild
117from lp.soyuz.model.reporting import LatestPersonSourcePackageReleaseCache121from lp.soyuz.model.reporting import LatestPersonSourcePackageReleaseCache
118from lp.testing import (122from lp.testing import (
119 FakeAdapterMixin,123 FakeAdapterMixin,
@@ -121,7 +125,10 @@
121 TestCase,125 TestCase,
122 TestCaseWithFactory,126 TestCaseWithFactory,
123 )127 )
124from lp.testing.dbuser import switch_dbuser128from lp.testing.dbuser import (
129 dbuser,
130 switch_dbuser,
131 )
125from lp.testing.layers import (132from lp.testing.layers import (
126 DatabaseLayer,133 DatabaseLayer,
127 LaunchpadScriptLayer,134 LaunchpadScriptLayer,
@@ -133,6 +140,9 @@
133from lp.translations.model.translationtemplateitem import (140from lp.translations.model.translationtemplateitem import (
134 TranslationTemplateItem,141 TranslationTemplateItem,
135 )142 )
143from lp.translations.model.translationtemplatesbuild import (
144 TranslationTemplatesBuild,
145 )
136146
137147
138class TestGarboScript(TestCase):148class TestGarboScript(TestCase):
@@ -1273,6 +1283,131 @@
1273 'PopulateLatestPersonSourcePackageReleaseCache')1283 'PopulateLatestPersonSourcePackageReleaseCache')
1274 self.assertEqual(spph_2.id, job_data['last_spph_id'])1284 self.assertEqual(spph_2.id, job_data['last_spph_id'])
12751285
1286 def test_BinaryPackageBuildFlattener(self):
1287 store = IMasterStore(BinaryPackageBuild)
1288 # Sampledata builds start off with the new columns set to None,
1289 # and garbo won't run without a feature flag set.
1290 self.runHourly()
1291 self.assertNotEqual(
1292 0, store.find(BinaryPackageBuild, _new_archive=None).count())
1293
1294 # But after a garbo run they're all set properly.
1295 with dbuser('testadmin'):
1296 IMasterStore(FeatureFlag).add(FeatureFlag(
1297 u'default', 0, u'soyuz.flatten_bfj.garbo.enabled', u'true'))
1298 self.runHourly()
1299 self.assertEqual(
1300 0, store.find(BinaryPackageBuild, _new_archive=None).count())
1301
1302 with dbuser('testadmin'):
1303 # Create a build with lots of attributes set.
1304 build = self.factory.makeBinaryPackageBuild()
1305 build.gotFailure()
1306 build.updateStatus(
1307 BuildStatus.BUILDING, builder=self.factory.makeBuilder())
1308 build.updateStatus(BuildStatus.FULLYBUILT)
1309 build.setLog(self.factory.makeLibraryFileAlias())
1310 build.storeUploadLog('uploaded')
1311
1312 # Manually unset the build's denormed columns.
1313 attrs = (
1314 'archive', 'pocket', 'processor', 'virtualized',
1315 'date_created', 'date_started', 'date_finished',
1316 'date_first_dispatched', 'builder', 'status', 'log',
1317 'upload_log', 'dependencies', 'failure_count',
1318 'build_farm_job', 'distribution', 'distro_series',
1319 'source_package_name', 'is_distro_archive')
1320 for attr in attrs:
1321 setattr(removeSecurityProxy(build), '_new_' + attr, None)
1322 removeSecurityProxy(build.build_farm_job).archive = None
1323 self.assertEqual(
1324 1, store.find(BinaryPackageBuild, _new_archive=None).count())
1325 self.runHourly()
1326 self.assertEqual(
1327 0, store.find(BinaryPackageBuild, _new_archive=None).count())
1328
1329 self.assertThat(
1330 removeSecurityProxy(build),
1331 MatchesStructure.byEquality(
1332 **dict(
1333 ('_new_' + attr, getattr(build, attr)) for attr in attrs)))
1334 self.assertEqual(
1335 build.archive, removeSecurityProxy(build.build_farm_job).archive)
1336
1337 def test_SourcePackageRecipeBuildFlattener(self):
1338 store = IMasterStore(BinaryPackageBuild)
1339 with dbuser('testadmin'):
1340 IMasterStore(FeatureFlag).add(FeatureFlag(
1341 u'default', 0, u'soyuz.flatten_bfj.garbo.enabled', u'true'))
1342
1343 with dbuser('testadmin'):
1344 # Create a build with lots of attributes set.
1345 build = self.factory.makeSourcePackageRecipeBuild()
1346 build.gotFailure()
1347 build.updateStatus(
1348 BuildStatus.BUILDING, builder=self.factory.makeBuilder())
1349 build.updateStatus(BuildStatus.FULLYBUILT)
1350 build.setLog(self.factory.makeLibraryFileAlias())
1351 build.storeUploadLog('uploaded')
1352
1353 # Manually unset the build's denormed columns.
1354 attrs = (
1355 'archive', 'pocket', 'processor', 'virtualized',
1356 'date_created', 'date_started', 'date_finished',
1357 'date_first_dispatched', 'builder', 'status', 'log',
1358 'upload_log', 'dependencies', 'failure_count',
1359 'build_farm_job')
1360 for attr in attrs:
1361 setattr(removeSecurityProxy(build), '_new_' + attr, None)
1362 removeSecurityProxy(build).build_farm_job.archive = None
1363 self.assertEqual(
1364 1, store.find(SourcePackageRecipeBuild, _new_archive=None).count())
1365 self.runHourly()
1366 self.assertEqual(
1367 0, store.find(SourcePackageRecipeBuild, _new_archive=None).count())
1368
1369 self.assertThat(
1370 removeSecurityProxy(build),
1371 MatchesStructure.byEquality(
1372 **dict(
1373 ('_new_' + attr, getattr(build, attr)) for attr in attrs)))
1374 self.assertEqual(
1375 build.archive, removeSecurityProxy(build.build_farm_job).archive)
1376
1377 def test_TranslationTemplatesBuildFlattener(self):
1378 store = IMasterStore(BinaryPackageBuild)
1379 with dbuser('testadmin'):
1380 IMasterStore(FeatureFlag).add(FeatureFlag(
1381 u'default', 0, u'soyuz.flatten_bfj.garbo.enabled', u'true'))
1382
1383 with dbuser('testadmin'):
1384 # Create a build with lots of attributes set.
1385 build = self.factory.makeTranslationTemplatesBuildJob().build
1386 build.gotFailure()
1387 build.updateStatus(
1388 BuildStatus.BUILDING, builder=self.factory.makeBuilder())
1389 build.updateStatus(BuildStatus.FULLYBUILT)
1390 build.setLog(self.factory.makeLibraryFileAlias())
1391
1392 # Manually unset the build's denormed columns.
1393 attrs = (
1394 'processor', 'virtualized', 'date_created', 'date_started',
1395 'date_finished', 'date_first_dispatched', 'builder', 'status',
1396 'log', 'failure_count')
1397 for attr in attrs:
1398 setattr(removeSecurityProxy(build), '_new_' + attr, None)
1399 self.assertEqual(
1400 1, store.find(TranslationTemplatesBuild, _new_status=None).count())
1401 self.runHourly()
1402 self.assertEqual(
1403 0, store.find(TranslationTemplatesBuild, _new_status=None).count())
1404
1405 self.assertThat(
1406 removeSecurityProxy(build),
1407 MatchesStructure.byEquality(
1408 **dict(
1409 ('_new_' + attr, getattr(build, attr)) for attr in attrs)))
1410
12761411
1277class TestGarboTasks(TestCaseWithFactory):1412class TestGarboTasks(TestCaseWithFactory):
1278 layer = LaunchpadZopelessLayer1413 layer = LaunchpadZopelessLayer
12791414
=== modified file 'lib/lp/soyuz/interfaces/binarypackagebuild.py'
--- lib/lp/soyuz/interfaces/binarypackagebuild.py 2013-01-22 08:31:09 +0000
+++ lib/lp/soyuz/interfaces/binarypackagebuild.py 2013-02-04 02:04:26 +0000
@@ -100,6 +100,9 @@
100 distro_series = Attribute("Direct parent needed by CanonicalURL")100 distro_series = Attribute("Direct parent needed by CanonicalURL")
101 arch_tag = exported(101 arch_tag = exported(
102 Text(title=_("Architecture tag"), required=False))102 Text(title=_("Architecture tag"), required=False))
103 source_package_name = Attribute("Source package name")
104 is_distro_archive = Attribute(
105 "Whether the target archive belongs to the distro")
103 distributionsourcepackagerelease = Attribute("The page showing the "106 distributionsourcepackagerelease = Attribute("The page showing the "
104 "details for this sourcepackagerelease in this distribution.")107 "details for this sourcepackagerelease in this distribution.")
105 binarypackages = Attribute(108 binarypackages = Attribute(
106109
=== modified file 'lib/lp/soyuz/model/binarypackagebuild.py'
--- lib/lp/soyuz/model/binarypackagebuild.py 2013-02-04 02:04:26 +0000
+++ lib/lp/soyuz/model/binarypackagebuild.py 2013-02-04 02:04:26 +0000
@@ -265,6 +265,16 @@
265 return self.distro_series.distribution265 return self.distro_series.distribution
266266
267 @property267 @property
268 def source_package_name(self):
269 """See `IBinaryPackageBuild`."""
270 return self.source_package_release.sourcepackagename
271
272 @property
273 def is_distro_archive(self):
274 """See `IBinaryPackageBuild`."""
275 return self.archive.is_main
276
277 @property
268 def is_virtualized(self):278 def is_virtualized(self):
269 """See `IBuild`"""279 """See `IBuild`"""
270 return self.archive.require_virtualized280 return self.archive.require_virtualized