~launchpad-pqm/launchpad/devel

14047.3.17 by Jeroen Vermeulen
Cosmetic.
1
# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
7675.391.27 by Muharem Hrnjadovic
More fixes.
2
# GNU Affero General Public License version 3 (see the file LICENSE).
3
4
__metaclass__ = type
10667.4.5 by Michael Nelson
Generalised to BuildFarmJobDelegate.
5
__all__ = [
6
    'BuildFarmJob',
10667.4.7 by Michael Nelson
Renamed BuildFarmJobDelegate->Derived, and moved delegates() statement there.
7
    'BuildFarmJobDerived',
7675.687.43 by Michael Nelson
Cleaned up the interfaces so that the old in-memory BuildFarmJob interfaces stay intact until they are removed, rather than merging them with the new.
8
    'BuildFarmJobOld',
7675.687.46 by Michael Nelson
Created BuildFarmJobOldDerived and updated BRANCH.TODO to ensure they are later removed.
9
    'BuildFarmJobOldDerived',
10667.4.5 by Michael Nelson
Generalised to BuildFarmJobDelegate.
10
    ]
11
12
10793.1.1 by Jeroen Vermeulen
Delegate deletion of build-farm jobs to IBuildFarmJobDerived.
13
import hashlib
14
10667.4.7 by Michael Nelson
Renamed BuildFarmJobDelegate->Derived, and moved delegates() statement there.
15
from lazr.delegates import delegates
7675.688.4 by Michael Nelson
Turned BuildFarmJob into a concrete class and added basic test.
16
import pytz
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
17
from storm.expr import (
12346.3.1 by Julian Edwards
Convert BuildFarmJobSet.getBuildsForBuilder()'s query into a faster one
18
    And,
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
19
    Desc,
20
    LeftJoin,
21
    Or,
12346.3.1 by Julian Edwards
Convert BuildFarmJobSet.getBuildsForBuilder()'s query into a faster one
22
    Select,
23
    Union,
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
24
    )
25
from storm.locals import (
26
    Bool,
27
    DateTime,
28
    Int,
29
    Reference,
30
    Storm,
31
    )
7675.688.18 by Michael Nelson
Merged db-build-generalisation-db-changes into db-build-farm-job-model and resolved conflicts.
32
from storm.store import Store
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
33
from zope.component import (
34
    ComponentLookupError,
35
    getUtility,
36
    )
37
from zope.interface import (
38
    classProvides,
39
    implements,
40
    )
11005.3.9 by Michael Nelson
Removed outer proxy after nested proxy confusion.
41
from zope.proxy import isProxy
10677.2.1 by Jeroen Vermeulen
Replace slave build id with slave build cookie.
42
from zope.security.proxy import removeSecurityProxy
10137.5.8 by Jeroen Vermeulen
Delegated the BuildQueue.specific_job query to BuildFarmJob, and specialized for my build-farm job class; added interface.
43
7675.688.12 by Michael Nelson
Moved the default implementation for concrete buildfarmjobs and tested, ensuring the previous behavior will continue for non-concrete buildfarmjobs.
44
from canonical.database.constants import UTC_NOW
7675.688.4 by Michael Nelson
Turned BuildFarmJob into a concrete class and added basic test.
45
from canonical.database.enumcol import DBEnum
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
46
from canonical.launchpad.interfaces.lpstorm import (
47
    IMasterStore,
48
    IStore,
49
    )
10667.4.5 by Michael Nelson
Generalised to BuildFarmJobDelegate.
50
from canonical.launchpad.webapp.interfaces import (
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
51
    DEFAULT_FLAVOR,
52
    IStoreSelector,
53
    MAIN_STORE,
54
    )
11039.2.43 by Jelmer Vernooij
Fix tests.
55
from lp.app.errors import NotFoundError
13130.1.12 by Curtis Hovey
Sorted imports.
56
from lp.app.interfaces.launchpad import ILaunchpadCelebrities
57
from lp.buildmaster.enums import (
58
    BuildFarmJobType,
59
    BuildStatus,
60
    )
10137.5.8 by Jeroen Vermeulen
Delegated the BuildQueue.specific_job query to BuildFarmJob, and specialized for my build-farm job class; added interface.
61
from lp.buildmaster.interfaces.buildfarmjob import (
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
62
    IBuildFarmJob,
63
    IBuildFarmJobOld,
64
    IBuildFarmJobSet,
65
    IBuildFarmJobSource,
66
    InconsistentBuildFarmJobError,
12961.1.6 by William Grant
Replace ISpecificBuildFarmJob uses with ISpecificBuildFarmJobSource.getByBuildFarmJob.
67
    ISpecificBuildFarmJobSource,
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
68
    )
10677.2.1 by Jeroen Vermeulen
Replace slave build id with slave build cookie.
69
from lp.buildmaster.interfaces.buildqueue import IBuildQueueSet
11005.3.18 by Michael Nelson
Implemented IBuildFarmJobSet.getBuildsForBuilder().
70
from lp.registry.model.teammembership import TeamParticipation
7675.390.7 by Muharem Hrnjadovic
Review comments, round 3.
71
72
7675.687.43 by Michael Nelson
Cleaned up the interfaces so that the old in-memory BuildFarmJob interfaces stay intact until they are removed, rather than merging them with the new.
73
class BuildFarmJobOld:
74
    """See `IBuildFarmJobOld`."""
75
    implements(IBuildFarmJobOld)
76
    processor = None
77
    virtualized = None
78
79
    def score(self):
80
        """See `IBuildFarmJobOld`."""
81
        raise NotImplementedError
82
83
    def getLogFileName(self):
84
        """See `IBuildFarmJobOld`."""
85
        return 'buildlog.txt'
86
87
    def getName(self):
88
        """See `IBuildFarmJobOld`."""
89
        raise NotImplementedError
90
91
    def getTitle(self):
92
        """See `IBuildFarmJobOld`."""
93
        raise NotImplementedError
94
95
    def makeJob(self):
96
        """See `IBuildFarmJobOld`."""
97
        raise NotImplementedError
98
7675.687.128 by Michael Nelson
Fixed test_buildfarmjob and test_buildqueue.
99
    def getByJob(self, job):
7675.695.6 by Michael Nelson
Removed IBuildFarmJobDerived, putting its attributes on IBuildFarmJob.
100
        """See `IBuildFarmJobOld`."""
101
        raise NotImplementedError
102
7675.687.43 by Michael Nelson
Cleaned up the interfaces so that the old in-memory BuildFarmJob interfaces stay intact until they are removed, rather than merging them with the new.
103
    def jobStarted(self):
104
        """See `IBuildFarmJobOld`."""
105
        pass
106
107
    def jobReset(self):
108
        """See `IBuildFarmJobOld`."""
109
        pass
110
111
    def jobAborted(self):
112
        """See `IBuildFarmJobOld`."""
113
        pass
114
14206.2.2 by Julian Edwards
merge remainder of backed out branch
115
    def jobCancel(self):
116
        """See `IBuildFarmJobOld`."""
117
        pass
118
7675.695.6 by Michael Nelson
Removed IBuildFarmJobDerived, putting its attributes on IBuildFarmJob.
119
    @staticmethod
120
    def addCandidateSelectionCriteria(processor, virtualized):
121
        """See `IBuildFarmJobOld`."""
7675.687.92 by Michael Nelson
Changes for buildd-dispatching.txt
122
        raise NotImplementedError
7675.695.6 by Michael Nelson
Removed IBuildFarmJobDerived, putting its attributes on IBuildFarmJob.
123
124
    @staticmethod
125
    def postprocessCandidate(job, logger):
126
        """See `IBuildFarmJobOld`."""
7675.687.123 by Michael Nelson
lp.translations.tests, lp.registry.tests and lp.code.tests
127
        raise NotImplementedError
7675.695.6 by Michael Nelson
Removed IBuildFarmJobDerived, putting its attributes on IBuildFarmJob.
128
129
    def cleanUp(self):
130
        """See `IBuildFarmJob`."""
7675.687.69 by Michael Nelson
test_binarypackagebuild finally passes.
131
        pass
7675.695.6 by Michael Nelson
Removed IBuildFarmJobDerived, putting its attributes on IBuildFarmJob.
132
133
    def generateSlaveBuildCookie(self):
134
        """See `IBuildFarmJobOld`."""
135
        raise NotImplementedError
136
7675.687.43 by Michael Nelson
Cleaned up the interfaces so that the old in-memory BuildFarmJob interfaces stay intact until they are removed, rather than merging them with the new.
137
7675.687.46 by Michael Nelson
Created BuildFarmJobOldDerived and updated BRANCH.TODO to ensure they are later removed.
138
class BuildFarmJobOldDerived:
7675.695.6 by Michael Nelson
Removed IBuildFarmJobDerived, putting its attributes on IBuildFarmJob.
139
    """Setup the delegation and provide some common implementation."""
7675.687.46 by Michael Nelson
Created BuildFarmJobOldDerived and updated BRANCH.TODO to ensure they are later removed.
140
    delegates(IBuildFarmJobOld, context='build_farm_job')
141
142
    def __init__(self, *args, **kwargs):
143
        """Ensure the instance to which we delegate is set on creation."""
144
        self._set_build_farm_job()
145
        super(BuildFarmJobOldDerived, self).__init__(*args, **kwargs)
146
147
    def __storm_loaded__(self):
148
        """Set the attribute for our IBuildFarmJob delegation.
149
150
        This is needed here as __init__() is not called when a storm object
151
        is loaded from the database.
152
        """
153
        self._set_build_farm_job()
154
155
    def _set_build_farm_job(self):
156
        """Set the build farm job to which we will delegate.
157
7675.687.47 by Michael Nelson
Some lint.
158
        Deriving classes must set the build_farm_job attribute for the
159
        delegation.
7675.687.46 by Michael Nelson
Created BuildFarmJobOldDerived and updated BRANCH.TODO to ensure they are later removed.
160
        """
161
        raise NotImplementedError
162
163
    @classmethod
164
    def getByJob(cls, job):
7675.695.6 by Michael Nelson
Removed IBuildFarmJobDerived, putting its attributes on IBuildFarmJob.
165
        """See `IBuildFarmJobOld`."""
7675.687.46 by Michael Nelson
Created BuildFarmJobOldDerived and updated BRANCH.TODO to ensure they are later removed.
166
        store = getUtility(IStoreSelector).get(MAIN_STORE, DEFAULT_FLAVOR)
167
        return store.find(cls, cls.job == job).one()
168
169
    def generateSlaveBuildCookie(self):
7675.695.6 by Michael Nelson
Removed IBuildFarmJobDerived, putting its attributes on IBuildFarmJob.
170
        """See `IBuildFarmJobOld`."""
7675.687.46 by Michael Nelson
Created BuildFarmJobOldDerived and updated BRANCH.TODO to ensure they are later removed.
171
        buildqueue = getUtility(IBuildQueueSet).getByJob(self.job)
172
173
        if buildqueue.processor is None:
174
            processor = '*'
175
        else:
176
            processor = repr(buildqueue.processor.id)
177
178
        contents = ';'.join([
179
            repr(removeSecurityProxy(self.job).id),
180
            self.job.date_created.isoformat(),
181
            repr(buildqueue.id),
182
            buildqueue.job_type.name,
183
            processor,
184
            self.getName(),
185
            ])
186
187
        return hashlib.sha1(contents).hexdigest()
188
7675.687.69 by Michael Nelson
test_binarypackagebuild finally passes.
189
    def cleanUp(self):
190
        """See `IBuildFarmJob`.
191
192
        Classes that derive from BuildFarmJobOld need to clean up
193
        after themselves correctly.
194
        """
195
        Store.of(self).remove(self)
196
7675.687.92 by Michael Nelson
Changes for buildd-dispatching.txt
197
    @staticmethod
198
    def addCandidateSelectionCriteria(processor, virtualized):
199
        """See `IBuildFarmJobOld`."""
200
        return ('')
201
7675.687.123 by Michael Nelson
lp.translations.tests, lp.registry.tests and lp.code.tests
202
    @staticmethod
203
    def postprocessCandidate(job, logger):
204
        """See `IBuildFarmJobOld`."""
205
        return True
206
7675.687.43 by Michael Nelson
Cleaned up the interfaces so that the old in-memory BuildFarmJob interfaces stay intact until they are removed, rather than merging them with the new.
207
208
class BuildFarmJob(BuildFarmJobOld, Storm):
10667.4.2 by Michael Nelson
Updated BuildPackageJob to delegate to buildfarmjob.
209
    """A base implementation for `IBuildFarmJob` classes."""
7675.688.4 by Michael Nelson
Turned BuildFarmJob into a concrete class and added basic test.
210
    __storm_table__ = 'BuildFarmJob'
7675.688.5 by Michael Nelson
Re-merged delegate-to-buildfarmjob and resolved conflicts.
211
7675.390.7 by Muharem Hrnjadovic
Review comments, round 3.
212
    implements(IBuildFarmJob)
7675.688.4 by Michael Nelson
Turned BuildFarmJob into a concrete class and added basic test.
213
    classProvides(IBuildFarmJobSource)
214
215
    id = Int(primary=True)
216
217
    processor_id = Int(name='processor', allow_none=True)
218
    processor = Reference(processor_id, 'Processor.id')
219
7675.688.8 by Michael Nelson
Updated to use date_first_dispatched on IBuildFarmJob and ensured test_save_model passes.
220
    virtualized = Bool()
7675.688.4 by Michael Nelson
Turned BuildFarmJob into a concrete class and added basic test.
221
222
    date_created = DateTime(
223
        name='date_created', allow_none=False, tzinfo=pytz.UTC)
224
225
    date_started = DateTime(
226
        name='date_started', allow_none=True, tzinfo=pytz.UTC)
227
228
    date_finished = DateTime(
7675.688.8 by Michael Nelson
Updated to use date_first_dispatched on IBuildFarmJob and ensured test_save_model passes.
229
        name='date_finished', allow_none=True, tzinfo=pytz.UTC)
230
231
    date_first_dispatched = DateTime(
232
        name='date_first_dispatched', allow_none=True, tzinfo=pytz.UTC)
7675.688.4 by Michael Nelson
Turned BuildFarmJob into a concrete class and added basic test.
233
234
    builder_id = Int(name='builder', allow_none=True)
235
    builder = Reference(builder_id, 'Builder.id')
236
237
    status = DBEnum(name='status', allow_none=False, enum=BuildStatus)
238
239
    log_id = Int(name='log', allow_none=True)
240
    log = Reference(log_id, 'LibraryFileAlias.id')
241
242
    job_type = DBEnum(
243
        name='job_type', allow_none=False, enum=BuildFarmJobType)
244
10888.7.2 by Julian Edwards
add model/interface/test for BuildFarmJob.failure_count
245
    failure_count = Int(name='failure_count', allow_none=False)
246
7675.822.16 by Jeroen Vermeulen
Small fix.
247
    dependencies = None
248
7675.688.15 by Michael Nelson
Updates from Abel's review - some comment updates and setting default for BuildFarmJob.status.
249
    def __init__(self, job_type, status=BuildStatus.NEEDSBUILD,
7675.687.90 by Michael Nelson
Gets rest of build.txt passing.
250
                 processor=None, virtualized=None, date_created=None):
7675.687.47 by Michael Nelson
Some lint.
251
        super(BuildFarmJob, self).__init__()
7675.687.59 by Michael Nelson
Updated estimatedDuration to not error.
252
        self.job_type, self.status, self.processor, self.virtualized = (
7675.688.6 by Michael Nelson
Updated to get test working, but fails on a db-constraint.
253
            job_type,
254
            status,
255
            processor,
256
            virtualized,
257
            )
7675.687.90 by Michael Nelson
Gets rest of build.txt passing.
258
        if date_created is not None:
259
            self.date_created = date_created
7675.688.6 by Michael Nelson
Updated to get test working, but fails on a db-constraint.
260
7675.688.4 by Michael Nelson
Turned BuildFarmJob into a concrete class and added basic test.
261
    @classmethod
7675.688.15 by Michael Nelson
Updates from Abel's review - some comment updates and setting default for BuildFarmJob.status.
262
    def new(cls, job_type, status=BuildStatus.NEEDSBUILD, processor=None,
7675.687.90 by Michael Nelson
Gets rest of build.txt passing.
263
            virtualized=None, date_created=None):
7675.688.4 by Michael Nelson
Turned BuildFarmJob into a concrete class and added basic test.
264
        """See `IBuildFarmJobSource`."""
7675.688.6 by Michael Nelson
Updated to get test working, but fails on a db-constraint.
265
        build_farm_job = BuildFarmJob(
7675.687.90 by Michael Nelson
Gets rest of build.txt passing.
266
            job_type, status, processor, virtualized, date_created)
7675.688.4 by Michael Nelson
Turned BuildFarmJob into a concrete class and added basic test.
267
268
        store = IMasterStore(BuildFarmJob)
269
        store.add(build_farm_job)
270
        return build_farm_job
7675.391.27 by Muharem Hrnjadovic
More fixes.
271
7675.688.12 by Michael Nelson
Moved the default implementation for concrete buildfarmjobs and tested, ensuring the previous behavior will continue for non-concrete buildfarmjobs.
272
    @property
7675.687.27 by Michael Nelson
More moving and testing of IBuildBase->IPackageBuild attributes and properties.
273
    def title(self):
274
        """See `IBuildFarmJob`."""
275
        return self.job_type.title
276
7675.687.86 by Michael Nelson
Added duration as a property on IBuildFarmJob.
277
    @property
278
    def duration(self):
279
        """See `IBuildFarmJob`."""
280
        if self.date_started is None or self.date_finished is None:
281
            return None
282
        return self.date_finished - self.date_started
283
7675.687.35 by Michael Nelson
Moved getUploaderCommand/Content and stubbed makeJob.
284
    def makeJob(self):
7675.822.4 by Jeroen Vermeulen
Implement makeJob; minor upheaval in TranslationTemplatesBuildJob factory.
285
        """See `IBuildFarmJobOld`."""
7675.687.35 by Michael Nelson
Moved getUploaderCommand/Content and stubbed makeJob.
286
        raise NotImplementedError
287
7675.391.27 by Muharem Hrnjadovic
More fixes.
288
    def jobStarted(self):
7675.390.7 by Muharem Hrnjadovic
Review comments, round 3.
289
        """See `IBuildFarmJob`."""
7675.688.12 by Michael Nelson
Moved the default implementation for concrete buildfarmjobs and tested, ensuring the previous behavior will continue for non-concrete buildfarmjobs.
290
        self.status = BuildStatus.BUILDING
291
        # The build started, set the start time if not set already.
292
        self.date_started = UTC_NOW
293
        if self.date_first_dispatched is None:
294
            self.date_first_dispatched = UTC_NOW
7675.391.27 by Muharem Hrnjadovic
More fixes.
295
296
    def jobReset(self):
7675.390.7 by Muharem Hrnjadovic
Review comments, round 3.
297
        """See `IBuildFarmJob`."""
7675.688.12 by Michael Nelson
Moved the default implementation for concrete buildfarmjobs and tested, ensuring the previous behavior will continue for non-concrete buildfarmjobs.
298
        self.status = BuildStatus.NEEDSBUILD
299
        self.date_started = None
7675.391.27 by Muharem Hrnjadovic
More fixes.
300
7675.688.12 by Michael Nelson
Moved the default implementation for concrete buildfarmjobs and tested, ensuring the previous behavior will continue for non-concrete buildfarmjobs.
301
    # The implementation of aborting a job is the same as resetting
302
    # a job.
303
    jobAborted = jobReset
7675.391.27 by Muharem Hrnjadovic
More fixes.
304
14206.1.2 by Julian Edwards
merge a chunk of the backed-out change from r14192
305
    def jobCancel(self):
306
        """See `IBuildFarmJob`."""
307
        self.status = BuildStatus.CANCELLED
308
7675.452.1 by Muharem Hrnjadovic
imported old development branch
309
    @staticmethod
7675.452.10 by Muharem Hrnjadovic
jtv's review comments
310
    def addCandidateSelectionCriteria(processor, virtualized):
10667.4.8 by Michael Nelson
Merged IBuildFarmCandidateJobSelection into IBuildFarmJob.
311
        """See `IBuildFarmJob`."""
7675.464.1 by Muharem Hrnjadovic
imported fix for candidate job selection
312
        return ('')
7675.452.1 by Muharem Hrnjadovic
imported old development branch
313
314
    @staticmethod
7675.452.10 by Muharem Hrnjadovic
jtv's review comments
315
    def postprocessCandidate(job, logger):
10667.4.8 by Michael Nelson
Merged IBuildFarmCandidateJobSelection into IBuildFarmJob.
316
        """See `IBuildFarmJob`."""
7675.452.1 by Muharem Hrnjadovic
imported old development branch
317
        return True
7675.503.4 by Muharem Hrnjadovic
test passes
318
7675.687.25 by Michael Nelson
More updates to bfj/pb interfaces to match IBuildBase.
319
    @property
320
    def buildqueue_record(self):
321
        """See `IBuildFarmJob`."""
7675.687.52 by Michael Nelson
More lint.
322
        return None
7675.687.25 by Michael Nelson
More updates to bfj/pb interfaces to match IBuildBase.
323
324
    @property
325
    def is_private(self):
326
        """See `IBuildFarmJob`.
327
328
        This base implementation assumes build farm jobs are public, but
329
        derived implementations can override as required.
330
        """
331
        return False
332
7675.687.28 by Michael Nelson
Added tests for log_url and upload_log url properties after setting up the URL definition.
333
    @property
334
    def log_url(self):
335
        """See `IBuildFarmJob`.
336
337
        This base implementation of the property always returns None. Derived
338
        implementations need to override for their specific context.
339
        """
340
        return None
341
7675.695.6 by Michael Nelson
Removed IBuildFarmJobDerived, putting its attributes on IBuildFarmJob.
342
    def cleanUp(self):
343
        """See `IBuildFarmJobOld`.
344
345
        XXX 2010-05-04 michael.nelson bug=570939
346
        This can be removed once IBuildFarmJobOld is no longer used
347
        and services jobs are linked directly to IBuildFarmJob.
348
        """
349
        pass
350
11005.3.3 by Michael Nelson
Initial IBuildFarmJob.specific_job implementation.
351
    @property
352
    def was_built(self):
353
        """See `IBuild`"""
354
        return self.status not in [BuildStatus.NEEDSBUILD,
355
                                   BuildStatus.BUILDING,
14206.1.2 by Julian Edwards
merge a chunk of the backed-out change from r14192
356
                                   BuildStatus.CANCELLED,
357
                                   BuildStatus.CANCELLING,
11039.2.47 by Jelmer Vernooij
Display uploading builds in counts.
358
                                   BuildStatus.UPLOADING,
11005.3.3 by Michael Nelson
Initial IBuildFarmJob.specific_job implementation.
359
                                   BuildStatus.SUPERSEDED]
360
11005.3.9 by Michael Nelson
Removed outer proxy after nested proxy confusion.
361
    def getSpecificJob(self):
11005.3.3 by Michael Nelson
Initial IBuildFarmJob.specific_job implementation.
362
        """See `IBuild`"""
11005.3.7 by Michael Nelson
Update the specific_job attribute so that it's configurable rather than hard-coded.
363
        # Adapt ourselves based on our job type.
11005.3.9 by Michael Nelson
Removed outer proxy after nested proxy confusion.
364
        try:
12961.1.6 by William Grant
Replace ISpecificBuildFarmJob uses with ISpecificBuildFarmJobSource.getByBuildFarmJob.
365
            source = getUtility(
366
                ISpecificBuildFarmJobSource, self.job_type.name)
11005.3.9 by Michael Nelson
Removed outer proxy after nested proxy confusion.
367
        except ComponentLookupError:
368
            raise InconsistentBuildFarmJobError(
12961.1.6 by William Grant
Replace ISpecificBuildFarmJob uses with ISpecificBuildFarmJobSource.getByBuildFarmJob.
369
                "No source was found for the build farm job type %s." % (
11005.3.9 by Michael Nelson
Removed outer proxy after nested proxy confusion.
370
                    self.job_type.name))
371
12961.1.6 by William Grant
Replace ISpecificBuildFarmJob uses with ISpecificBuildFarmJobSource.getByBuildFarmJob.
372
        build = source.getByBuildFarmJob(self)
11005.3.9 by Michael Nelson
Removed outer proxy after nested proxy confusion.
373
12961.1.6 by William Grant
Replace ISpecificBuildFarmJob uses with ISpecificBuildFarmJobSource.getByBuildFarmJob.
374
        if build is None:
11005.3.9 by Michael Nelson
Removed outer proxy after nested proxy confusion.
375
            raise InconsistentBuildFarmJobError(
376
                "There is no related specific job for the build farm "
377
                "job with id %d." % self.id)
378
379
        # Just to be on the safe side, make sure the build is still
380
        # proxied before returning it.
12961.1.6 by William Grant
Replace ISpecificBuildFarmJob uses with ISpecificBuildFarmJobSource.getByBuildFarmJob.
381
        assert isProxy(build), (
382
            "Unproxied result returned from ISpecificBuildFarmJobSource.")
11005.3.9 by Michael Nelson
Removed outer proxy after nested proxy confusion.
383
12961.1.6 by William Grant
Replace ISpecificBuildFarmJob uses with ISpecificBuildFarmJobSource.getByBuildFarmJob.
384
        return build
11005.3.3 by Michael Nelson
Initial IBuildFarmJob.specific_job implementation.
385
10888.7.27 by Julian Edwards
another review round with jml
386
    def gotFailure(self):
387
        """See `IBuildFarmJob`."""
388
        self.failure_count += 1
389
10667.4.4 by Michael Nelson
Initial refactoring into a common PackageBuildFarmJobDelegate class.
390
10667.4.7 by Michael Nelson
Renamed BuildFarmJobDelegate->Derived, and moved delegates() statement there.
391
class BuildFarmJobDerived:
7675.695.6 by Michael Nelson
Removed IBuildFarmJobDerived, putting its attributes on IBuildFarmJob.
392
    implements(IBuildFarmJob)
7675.687.21 by Michael Nelson
Fixed tests after changing the name of the delegate context.
393
    delegates(IBuildFarmJob, context='build_farm_job')
11005.3.16 by Michael Nelson
Initial failing tests for getBuildsForBuilder.
394
395
396
class BuildFarmJobSet:
397
    implements(IBuildFarmJobSet)
398
11005.3.17 by Michael Nelson
Initial work for IBuildFarmJobSet.getBuildsForBuilder().
399
    def getBuildsForBuilder(self, builder_id, status=None, user=None):
11005.3.16 by Michael Nelson
Initial failing tests for getBuildsForBuilder.
400
        """See `IBuildFarmJobSet`."""
11005.3.18 by Michael Nelson
Implemented IBuildFarmJobSet.getBuildsForBuilder().
401
        # Imported here to avoid circular imports.
402
        from lp.buildmaster.model.packagebuild import PackageBuild
403
        from lp.soyuz.model.archive import Archive
404
11005.3.25 by Michael Nelson
Refactored the query to use a union instead of OR clauses.
405
        extra_clauses = [BuildFarmJob.builder == builder_id]
406
        if status is not None:
407
            extra_clauses.append(BuildFarmJob.status == status)
408
11005.3.18 by Michael Nelson
Implemented IBuildFarmJobSet.getBuildsForBuilder().
409
        # We need to ensure that we don't include any private builds.
410
        # Currently only package builds can be private (via their
411
        # related archive), but not all build farm jobs will have a
412
        # related package build - hence the left join.
12346.3.1 by Julian Edwards
Convert BuildFarmJobSet.getBuildsForBuilder()'s query into a faster one
413
        origin = [
414
            BuildFarmJob,
7675.745.133 by Michael Nelson
Changes from edwin's review - include joins only when necessary.
415
            LeftJoin(
416
                PackageBuild,
417
                PackageBuild.build_farm_job == BuildFarmJob.id),
418
            ]
11005.3.25 by Michael Nelson
Refactored the query to use a union instead of OR clauses.
419
12346.3.3 by Julian Edwards
fix lint
420
        # STORM syntax has totally obfuscated this query and wasted
421
        # THREE hours of my time converting perfectly good SQL syntax.  I'm
422
        # really sorry if you're the poor sap who has to maintain this.
423
12346.3.1 by Julian Edwards
Convert BuildFarmJobSet.getBuildsForBuilder()'s query into a faster one
424
        inner_privacy_query = (
425
            Union(
426
                Select(
427
                    Archive.id,
428
                    tables=(Archive,),
13228.4.3 by Timothy R. Chavez
Update Storm expressions to use _private rather than private
429
                    where=(Archive._private == False)
12346.3.1 by Julian Edwards
Convert BuildFarmJobSet.getBuildsForBuilder()'s query into a faster one
430
                    ),
431
                Select(
432
                    Archive.id,
12346.3.3 by Julian Edwards
fix lint
433
                    tables=(Archive,),
12346.3.1 by Julian Edwards
Convert BuildFarmJobSet.getBuildsForBuilder()'s query into a faster one
434
                    where=And(
13228.4.3 by Timothy R. Chavez
Update Storm expressions to use _private rather than private
435
                        Archive._private == True,
12346.3.2 by Julian Edwards
Fix bad storm syntax
436
                        Archive.ownerID.is_in(
12346.3.1 by Julian Edwards
Convert BuildFarmJobSet.getBuildsForBuilder()'s query into a faster one
437
                            Select(
12346.3.2 by Julian Edwards
Fix bad storm syntax
438
                                TeamParticipation.teamID,
12346.3.3 by Julian Edwards
fix lint
439
                                where=(TeamParticipation.person == user),
440
                                distinct=True
12346.3.1 by Julian Edwards
Convert BuildFarmJobSet.getBuildsForBuilder()'s query into a faster one
441
                            )
442
                        )
443
                    )
444
                )
445
            )
446
        )
447
11005.3.18 by Michael Nelson
Implemented IBuildFarmJobSet.getBuildsForBuilder().
448
        if user is None:
11005.3.25 by Michael Nelson
Refactored the query to use a union instead of OR clauses.
449
            # Anonymous requests don't get to see private builds at all.
12346.3.1 by Julian Edwards
Convert BuildFarmJobSet.getBuildsForBuilder()'s query into a faster one
450
            extra_clauses.append(
451
                Or(
452
                    PackageBuild.id == None,
12346.3.2 by Julian Edwards
Fix bad storm syntax
453
                    PackageBuild.archive_id.is_in(
454
                        Select(
455
                            Archive.id,
456
                            tables=(Archive,),
13228.4.3 by Timothy R. Chavez
Update Storm expressions to use _private rather than private
457
                            where=(Archive._private == False)
12346.3.2 by Julian Edwards
Fix bad storm syntax
458
                            )
12346.3.1 by Julian Edwards
Convert BuildFarmJobSet.getBuildsForBuilder()'s query into a faster one
459
                        )
460
                    )
461
                )
11005.3.25 by Michael Nelson
Refactored the query to use a union instead of OR clauses.
462
463
        elif user.inTeam(getUtility(ILaunchpadCelebrities).admin):
464
            # Admins get to see everything.
465
            pass
466
        else:
7675.745.131 by Michael Nelson
Updated storm query removing nested joins.
467
            # Everyone else sees all public builds and the
11005.3.25 by Michael Nelson
Refactored the query to use a union instead of OR clauses.
468
            # specific private builds to which they have access.
7675.745.131 by Michael Nelson
Updated storm query removing nested joins.
469
            extra_clauses.append(
12346.3.1 by Julian Edwards
Convert BuildFarmJobSet.getBuildsForBuilder()'s query into a faster one
470
                Or(
471
                    PackageBuild.id == None,
12346.3.3 by Julian Edwards
fix lint
472
                    PackageBuild.archive_id.is_in(inner_privacy_query)
12346.3.1 by Julian Edwards
Convert BuildFarmJobSet.getBuildsForBuilder()'s query into a faster one
473
                    )
474
                )
7675.745.131 by Michael Nelson
Updated storm query removing nested joins.
475
7675.745.133 by Michael Nelson
Changes from edwin's review - include joins only when necessary.
476
        filtered_builds = IStore(BuildFarmJob).using(*origin).find(
477
            BuildFarmJob, *extra_clauses)
11005.3.17 by Michael Nelson
Initial work for IBuildFarmJobSet.getBuildsForBuilder().
478
11005.3.24 by Michael Nelson
Lint/comment indentation.
479
        filtered_builds.order_by(
480
            Desc(BuildFarmJob.date_finished), BuildFarmJob.id)
7675.745.131 by Michael Nelson
Updated storm query removing nested joins.
481
        filtered_builds.config(distinct=True)
11005.3.19 by Michael Nelson
Ensured ordering matches that on BinaryPackageBuild.
482
11005.3.17 by Michael Nelson
Initial work for IBuildFarmJobSet.getBuildsForBuilder().
483
        return filtered_builds
11039.2.43 by Jelmer Vernooij
Fix tests.
484
11039.2.48 by Jelmer Vernooij
Fix typo, rename BuildFarmJobSet.__getitem__ -> BuildFarmJobSet.getByID.
485
    def getByID(self, job_id):
11039.2.43 by Jelmer Vernooij
Fix tests.
486
        """See `IBuildfarmJobSet`."""
487
        job = IStore(BuildFarmJob).find(BuildFarmJob,
488
                BuildFarmJob.id == job_id).one()
489
        if job is None:
490
            raise NotFoundError(job_id)
491
        return job