Merge lp:~jml/launchpad/process-upload-checks into lp:launchpad/db-devel

Proposed by Jonathan Lange
Status: Merged
Approved by: Julian Edwards
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~jml/launchpad/process-upload-checks
Merge into: lp:launchpad/db-devel
Prerequisite: lp:~jml/launchpad/wellington
Diff against target: 843 lines (+283/-100)
20 files modified
configs/development/launchpad-lazr.conf (+1/-1)
configs/testrunner/launchpad-lazr.conf (+1/-1)
database/schema/security.cfg (+8/-0)
lib/lp/archiveuploader/nascentupload.py (+4/-4)
lib/lp/archiveuploader/uploadpolicy.py (+37/-2)
lib/lp/archiveuploader/uploadprocessor.py (+4/-1)
lib/lp/buildmaster/interfaces/buildbase.py (+18/-2)
lib/lp/buildmaster/interfaces/buildfarmjob.py (+3/-3)
lib/lp/buildmaster/model/buildbase.py (+50/-23)
lib/lp/buildmaster/model/builder.py (+1/-2)
lib/lp/buildmaster/model/buildfarmjob.py (+1/-1)
lib/lp/buildmaster/tests/test_buildbase.py (+82/-0)
lib/lp/soyuz/configure.zcml (+34/-29)
lib/lp/soyuz/interfaces/sourcepackagerecipebuild.py (+1/-0)
lib/lp/soyuz/model/build.py (+8/-2)
lib/lp/soyuz/model/buildpackagejob.py (+2/-2)
lib/lp/soyuz/model/recipebuilder.py (+5/-4)
lib/lp/soyuz/model/sourcepackagerecipebuild.py (+7/-5)
lib/lp/soyuz/model/sourcepackagerecipedata.py (+2/-2)
lib/lp/soyuz/tests/test_recipebuilder.py (+14/-16)
To merge this branch: bzr merge lp:~jml/launchpad/process-upload-checks
Reviewer Review Type Date Requested Status
Julian Edwards (community) Approve
Canonical Launchpad Engineering Pending
Review via email: mp+17443@code.launchpad.net

Commit message

Allow uploads from recipe jobs. Upload policies are now specified explicitly by Build objects, rather than in configuration files.

To post a comment you must log in.
Revision history for this message
Jonathan Lange (jml) wrote :

This branch changes the Soyuz uploader to allow uploads from the recipe job.

It has a few stages of work:

1. Tweaks to BuilderBase to be more readily testable
  - Lots of new getUploaderFoo methods. The one that's actually used externally is getUploaderCommand()

2. A new upload policy for recipes

3. Changes to the nascentupload process so that it delegates decisions

4. Change the Build and SourcePackageRecipeBuild objects to specify their upload policy explicitly

5. Change the BuilderBase to use those policies when spawning the upload processor.

6. Change the configs so that policies are not specified in the configs.

Revision history for this message
Jonathan Lange (jml) wrote :

I should note also that this has been tested, sort of, on wgrant's laptop, and that the config changes are somewhat in lock-step with the code changes. I'll submit a branch to change the production configs.

Revision history for this message
Jonathan Lange (jml) wrote :
Revision history for this message
Julian Edwards (julian-edwards) wrote :

The diff below has got conflict markers in it. Also, when I diffed locally, it's 8000 lines against devel, or 17000 against db-devel. WTF!

So, I'm backing off reviewing this for now. Can you grab me ASAP so we can get this done.

Revision history for this message
Jonathan Lange (jml) wrote :

Hi Julian,

I've fixed a whole bunch of conflicts as well as all of the failing tests from my last "fix all the conflicts and run the tests" run. I'm running the tests now, and will no doubt have fixed all of the errors by the time you wake.

jml

Revision history for this message
Jonathan Lange (jml) wrote :

The tests do pass.

Revision history for this message
Julian Edwards (julian-edwards) wrote :
Download full text (3.3 KiB)

Thanks for fixing things! Here's my review:

> + # XXX: JonathanLange 2010-01-15: This shouldn't instantiate policy
> + # types. They should instead have names as class variables.

The XXX should reference a bug :) Or better still, fix it, it's an easy change.

> + # XXX: JonathanLange 2010-01-15: This has to be exactly the same
> + # string as the one in SourcePackageRecipeBuild.policy_name. Factor
> + # out a shared constant.

Same here.

> class SourcePackageRecipeUploadPolicy(BuildDaemonUploadPolicy):

Did you double check the inherited policy options for this? I think it looks sane but I have to ask ...

> + # XXX: JonathanLange 2010-01-15: We should not be re-using magical
> + # string literals. Zombie Dijkstra will come and kill us in our sleep.

bug number *cough* :)

> - buildqueue_record = Attribute("Corespondent BuildQueue record")
> + buildqueue_record = Attribute("Corresponding BuildQueue record")

I know you're just fixing the text, but we can surely do better than "Attribute".

> + policy_name = Attribute(
> + "The upload policy to use for handling these builds.")

And here!

> + uploader_argv = list(config.builddmaster.uploader.split())

Can you rename this variable to something like "uploader_command". The "argv" bit made me look twice since I was expecting only parameters to the command but it's actually the base command from the config.

> + # XXX: Duplicated from getUploaderCommand
> uploader_logfilename = os.path.join(upload_dir, 'uploader.log')

Why not turn it into a property on the class then?

> - classProvides(IBuildFarmCandidateJobSelection, ISpecificBuildFarmJobClass)
> + classProvides(ISpecificBuildFarmJobClass)

Why did you remove that? I note that it's there in db-devel but not devel.

> + # XXX: BuildBase is supposed to implement IBuildBase, but doesn't atm.
> + # Since it's not the focus of the branch, we'll postpone the work.

From the code I just looked at, it does! If there's a genuine problem then we need a bug please - tag wellington of course. This is becoming known as the Wellington project I think!

FWIW, I think all classes should have basic doctests, I really don't like this unit testing for their basic features.

What layer is TestBuildBase going to run in if it's not explicitly specified?

> +class TestBuildBaseHarder(TestCaseWithFactory):

Crappy name alert! Perhaps "TestBuildBaseWithDatabase" ?

Or maybe, s/TestBuildBase/TestBuildBase<layer>/ where <layer> is whatever it's really using (and I think it should be explicit) and then s/TestBuildBaseHarder/TestBuildBase/. Your call.

> + <adapter factory="lp.soyuz.model.recipebuilder.RecipeBuildBehavior"
> + permission="zope.Public" />

You can fill a gap in my knowledge here, what does this do when declared without the "provides" and "for" ?

> + build_log_url = exported(

Why is this moved from BuildBase to Build?

> + # JRV 2010-01-15: The database table really should have a pocket
> + # column, although this is not a big problem at the moment as recipe
> + # builds only happen for PPA's (so far). (bug 507307)

Can you XXX this in the usual format please.

I guess I should tell Jelmer how this works too :)

> + distroseries.n...

Read more...

review: Needs Information (code)
Revision history for this message
Jonathan Lange (jml) wrote :
Download full text (5.1 KiB)

On Fri, Jan 22, 2010 at 3:11 AM, Julian Edwards
<email address hidden> wrote:
> Review: Needs Information code
> Thanks for fixing things!  Here's my review:
>

Hey Julian,

Thanks for the review.

As a meta-comment, I'd really appreciate it if you could leave the
filenames from the diff in your reply. It makes it much, much faster
to find the relevant code in my editor.

>> + # XXX: JonathanLange 2010-01-15: This shouldn't instantiate policy
>> + # types. They should instead have names as class variables.
>
> The XXX should reference a bug :)  Or better still, fix it, it's an easy change.
>

Bug filed. It's an easy change, but the branch is big enough as-is.
I'll make the change in a separate branch.

>> + # XXX: JonathanLange 2010-01-15: This has to be exactly the same
>> + # string as the one in SourcePackageRecipeBuild.policy_name. Factor
>> + # out a shared constant.
>
> Same here.
>

And same reply.

>> class SourcePackageRecipeUploadPolicy(BuildDaemonUploadPolicy):
>
> Did you double check the inherited policy options for this?  I think it looks sane but I have to ask ...
>

        self.unsigned_changes_ok = True
        self.unsigned_dsc_ok = True
        self.can_upload_source = False
        self.can_upload_mixed = False

I don't know if those bits are good. Your call.

>> + # XXX: JonathanLange 2010-01-15: We should not be re-using magical
>> + # string literals. Zombie Dijkstra will come and kill us in our sleep.
>
> bug number *cough* :)
>

Added.

>> - buildqueue_record = Attribute("Corespondent BuildQueue record")
>> + buildqueue_record = Attribute("Corresponding BuildQueue record")
>
> I know you're just fixing the text, but we can surely do better than "Attribute".
>

Changed to Object(...)

>> + policy_name = Attribute(
>> +     "The upload policy to use for handling these builds.")
>
> And here!
>

Changed to TextLine(...)

>> +     uploader_argv = list(config.builddmaster.uploader.split())
>
> Can you rename this variable to something like "uploader_command".  The "argv" bit made me look twice since I was expecting only parameters to the command but it's actually the base command from the config.

Ahh ok. FWIW, I used "argv" specifically because it corresponds to
argv arrays in C convention by including the argument.

Changed to uploader_command.

>
>> + # XXX: Duplicated from getUploaderCommand
>>   uploader_logfilename = os.path.join(upload_dir, 'uploader.log')
>
> Why not turn it into a property on the class then?
>

Because it's parametrized -- it depends on upload_leaf. I've made it
an argument to getUploaderCommand.

>> - classProvides(IBuildFarmCandidateJobSelection, ISpecificBuildFarmJobClass)
>> + classProvides(ISpecificBuildFarmJobClass)
>
> Why did you remove that?  I note that it's there in db-devel but not devel.
>

_Probably_ a bad merge. Restored.

>> + # XXX: BuildBase is supposed to implement IBuildBase, but doesn't atm.
>> + # Since it's not the focus of the branch, we'll postpone the work.
>
>
>From the code I just looked at, it does!  If there's a genuine problem then we need a bug please - tag wellington of course.  This is becoming known as the Wellington project I think!

It didn't when I su...

Read more...

Revision history for this message
Julian Edwards (julian-edwards) wrote :

 review approve
 merge approve

> As a meta-comment, I'd really appreciate it if you could leave the
> filenames from the diff in your reply. It makes it much, much faster
> to find the relevant code in my editor.

Right, sorry, I hate that too.

> Bug filed. It's an easy change, but the branch is big enough as-is.
> I'll make the change in a separate branch.

Cool, thank you.

> self.unsigned_changes_ok = True
> self.unsigned_dsc_ok = True
> self.can_upload_source = False
> self.can_upload_mixed = False
>
> I don't know if those bits are good. Your call.

That looks fine, thanks for checking (again).

> >> - buildqueue_record = Attribute("Corespondent BuildQueue record")
> >> + buildqueue_record = Attribute("Corresponding BuildQueue record")
> >
> > I know you're just fixing the text, but we can surely do better than
> > "Attribute".
>
> Changed to Object(...)

Isn't it a Reference() ?

> Ahh ok. FWIW, I used "argv" specifically because it corresponds to
> argv arrays in C convention by including the argument.
>
> Changed to uploader_command.

True. I always hated that :)

>
> >> + # XXX: Duplicated from getUploaderCommand
> >> uploader_logfilename = os.path.join(upload_dir, 'uploader.log')
> >
> > Why not turn it into a property on the class then?
>
> Because it's parametrized -- it depends on upload_leaf. I've made it
> an argument to getUploaderCommand.

D'oh, right.

> >> - classProvides(IBuildFarmCandidateJobSelection,
> >> ISpecificBuildFarmJobClass) + classProvides(ISpecificBuildFarmJobClass)
> >
> > Why did you remove that? I note that it's there in db-devel but not
> > devel.
>
> _Probably_ a bad merge. Restored.

Phew, thanks ;)

Since it didn't break anything, this indicates a missing test :/

> It didn't when I submitted this branch last week, and when I
> re-enabled the test, it failed. The problem is genuine, so I've filed
> a bug and added it to the comment.

Argh, ok, thanks. I was just looking at the "implements" rather than actually
looking to see what it was implementing!

> > FWIW, I think all classes should have basic doctests, I really don't like
> > this unit testing for their basic features.
>
> OK. I haven't added any doctests in this branch.

Yeah, it's a matter of policy I'll raise in a reviewers' meeting I think.

> > What layer is TestBuildBase going to run in if it's not explicitly
> > specified?
>
> No layer at all. It doesn't need to be run in a layer. We want more
> tests like this, because they are fast :)

Ah! Ok, that's cool. We need more of this! You should totally email the
list about that.

> I forwarded you an email on the subject from the Canonical thread.
> http://www.muthukadan.net/docs/zca.html#zcml has some other notes.

Right, I remember it now, thanks for the pointer.

> >> + build_log_url = exported(
> >
> > Why is this moved from BuildBase to Build?
>
> When I was trying to get the assertProvides(BuildBase, IBuildBase)
> thing to pass, it turned out that BuildBase didn't implement this, so
> I moved the declaration.

Righto.

> I look forward to hearing back from you.

Land it!

Cheers,
J.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'configs/development/launchpad-lazr.conf'
2--- configs/development/launchpad-lazr.conf 2010-01-19 12:49:35 +0000
3+++ configs/development/launchpad-lazr.conf 2010-01-29 17:17:19 +0000
4@@ -15,7 +15,7 @@
5
6 [builddmaster]
7 root: /var/tmp/builddmaster/
8-uploader: scripts/process-upload.py -Mvv --context buildd
9+uploader: scripts/process-upload.py -Mvv
10
11 [buildsequencer]
12 mailproblemsto: root
13
14=== modified file 'configs/testrunner/launchpad-lazr.conf'
15--- configs/testrunner/launchpad-lazr.conf 2010-01-22 04:59:09 +0000
16+++ configs/testrunner/launchpad-lazr.conf 2010-01-29 17:17:19 +0000
17@@ -17,7 +17,7 @@
18
19 [builddmaster]
20 socket_timeout: 10
21-uploader: scripts/process-upload.py -Mvv --context buildd
22+uploader: scripts/process-upload.py -Mvv
23
24 [buildsequencer]
25 mailproblemsto: -
26
27=== modified file 'database/schema/security.cfg'
28--- database/schema/security.cfg 2010-01-26 02:05:23 +0000
29+++ database/schema/security.cfg 2010-01-29 17:17:19 +0000
30@@ -835,6 +835,7 @@
31 public.archive = SELECT, UPDATE
32 public.archivearch = SELECT, UPDATE
33 public.archivedependency = SELECT
34+public.branch = SELECT
35 public.buildqueue = SELECT, INSERT, UPDATE, DELETE
36 public.job = SELECT, INSERT, UPDATE, DELETE
37 public.buildpackagejob = SELECT, INSERT, UPDATE, DELETE
38@@ -858,8 +859,15 @@
39 public.processor = SELECT
40 public.processorfamily = SELECT
41 public.pocketchroot = SELECT, INSERT, UPDATE
42+public.product = SELECT
43+public.productseries = SELECT
44 public.component = SELECT
45 public.section = SELECT
46+public.sourcepackagerecipe = SELECT
47+public.sourcepackagerecipebuild = SELECT, UPDATE
48+public.sourcepackagerecipebuildjob = SELECT, INSERT, UPDATE, DELETE
49+public.sourcepackagerecipedata = SELECT
50+public.sourcepackagerecipedatainstruction = SELECT
51 public.publishedpackage = SELECT
52 public.person = SELECT
53 public.emailaddress = SELECT
54
55=== modified file 'lib/lp/archiveuploader/nascentupload.py'
56--- lib/lp/archiveuploader/nascentupload.py 2009-11-24 23:12:23 +0000
57+++ lib/lp/archiveuploader/nascentupload.py 2010-01-29 17:17:19 +0000
58@@ -477,11 +477,12 @@
59 return
60
61 # Set up some convenient shortcut variables.
62- signer = self.changes.signer
63+
64+ uploader = self.policy.getUploader(self.changes)
65 archive = self.policy.archive
66
67 # If we have no signer, there's no ACL we can apply.
68- if signer is None:
69+ if uploader is None:
70 self.logger.debug("No signer, therefore ACL not processed")
71 return
72
73@@ -489,7 +490,7 @@
74 ISourcePackageNameSet).queryByName(self.changes.dsc.package)
75
76 rejection_reason = check_upload_to_archive(
77- signer, self.policy.distroseries, source_name, archive,
78+ uploader, self.policy.distroseries, source_name, archive,
79 self.changes.dsc.component, self.policy.pocket, not self.is_new)
80
81 if rejection_reason is not None:
82@@ -894,7 +895,6 @@
83 # Queue entries are created in the NEW state by default; at the
84 # end of this method we cope with uploads that aren't new.
85 self.logger.debug("Creating queue entry")
86- distroseries = self.policy.distroseries
87 self.queue_root = self._createQueueEntry()
88
89 # When binaryful and sourceful, we have a mixed-mode upload.
90
91=== modified file 'lib/lp/archiveuploader/uploadpolicy.py'
92--- lib/lp/archiveuploader/uploadpolicy.py 2009-12-14 00:04:19 +0000
93+++ lib/lp/archiveuploader/uploadpolicy.py 2010-01-29 17:17:19 +0000
94@@ -5,7 +5,11 @@
95
96 __metaclass__ = type
97
98-__all__ = ["findPolicyByName", "findPolicyByOptions", "UploadPolicyError"]
99+__all__ = [
100+ "findPolicyByName",
101+ "findPolicyByOptions",
102+ "UploadPolicyError",
103+ ]
104
105 from zope.component import getUtility
106
107@@ -13,6 +17,8 @@
108 from lp.registry.interfaces.distribution import IDistributionSet
109 from lp.registry.interfaces.series import SeriesStatus
110 from lp.registry.interfaces.pocket import PackagePublishingPocket
111+from lp.soyuz.interfaces.sourcepackagerecipebuild import (
112+ ISourcePackageRecipeBuildSource)
113
114
115 # Number of seconds in an hour (used later)
116@@ -85,6 +91,10 @@
117 # The earliest year we accept in a deb's file's mtime
118 self.earliest_year = 1984
119
120+ def getUploader(self, changes):
121+ """Get the person who is doing the uploading."""
122+ return changes.signer
123+
124 def setOptions(self, options):
125 """Store the options for later."""
126 self.options = options
127@@ -167,6 +177,8 @@
128 @classmethod
129 def _registerPolicy(cls, policy_type):
130 """Register the given policy type as belonging to its given name."""
131+ # XXX: JonathanLange 2010-01-15 bug=510892: This shouldn't instantiate
132+ # policy types. They should instead have names as class variables.
133 policy_name = policy_type().name
134 cls.policies[policy_name] = policy_type
135
136@@ -188,6 +200,7 @@
137 findPolicyByName = AbstractUploadPolicy.findPolicyByName
138 findPolicyByOptions = AbstractUploadPolicy.findPolicyByOptions
139
140+
141 class InsecureUploadPolicy(AbstractUploadPolicy):
142 """The insecure upload policy is used by the poppy interface."""
143
144@@ -306,7 +319,7 @@
145 """The build daemon upload policy is invoked by the slave scanner."""
146
147 def __init__(self):
148- AbstractUploadPolicy.__init__(self)
149+ super(BuildDaemonUploadPolicy, self).__init__()
150 self.name = 'buildd'
151 # We permit unsigned uploads because we trust our build daemons
152 self.unsigned_changes_ok = True
153@@ -334,6 +347,28 @@
154 AbstractUploadPolicy._registerPolicy(BuildDaemonUploadPolicy)
155
156
157+class SourcePackageRecipeUploadPolicy(BuildDaemonUploadPolicy):
158+ """Policy for uploading the results of a source package recipe build."""
159+
160+ def __init__(self):
161+ super(SourcePackageRecipeUploadPolicy, self).__init__()
162+ # XXX: JonathanLange 2010-01-15 bug=510894: This has to be exactly the
163+ # same string as the one in SourcePackageRecipeBuild.policy_name.
164+ # Factor out a shared constant.
165+ self.name = 'recipe'
166+ self.can_upload_source = True
167+ self.can_upload_binaries = False
168+
169+ def getUploader(self, changes):
170+ """Return the person doing the upload."""
171+ build_id = int(getattr(self.options, 'buildid'))
172+ sprb = getUtility(ISourcePackageRecipeBuildSource).getById(build_id)
173+ return sprb.requester
174+
175+
176+AbstractUploadPolicy._registerPolicy(SourcePackageRecipeUploadPolicy)
177+
178+
179 class SyncUploadPolicy(AbstractUploadPolicy):
180 """This policy is invoked when processing sync uploads."""
181
182
183=== modified file 'lib/lp/archiveuploader/uploadprocessor.py'
184--- lib/lp/archiveuploader/uploadprocessor.py 2009-06-24 23:33:29 +0000
185+++ lib/lp/archiveuploader/uploadprocessor.py 2010-01-29 17:17:19 +0000
186@@ -339,7 +339,10 @@
187
188 # Reject source upload to buildd upload paths.
189 first_path = relative_path.split(os.path.sep)[0]
190- if first_path.isdigit() and policy.name != 'buildd':
191+ # XXX: JonathanLange 2010-01-15 bug=510894: We should not be re-using
192+ # magical string literals. Zombie Dijkstra will come and kill us in
193+ # our sleep.
194+ if first_path.isdigit() and policy.name not in ('buildd', 'recipe'):
195 error_message = (
196 "Invalid upload path (%s) for this policy (%s)" %
197 (relative_path, policy.name))
198
199=== modified file 'lib/lp/buildmaster/interfaces/buildbase.py'
200--- lib/lp/buildmaster/interfaces/buildbase.py 2010-01-20 02:02:02 +0000
201+++ lib/lp/buildmaster/interfaces/buildbase.py 2010-01-29 17:17:19 +0000
202@@ -19,11 +19,14 @@
203 from lp.registry.interfaces.distribution import IDistribution
204 from lp.registry.interfaces.pocket import PackagePublishingPocket
205 from lp.soyuz.interfaces.archive import IArchive
206+from lp.soyuz.interfaces.buildqueue import IBuildQueue
207 from canonical.launchpad.interfaces.librarian import ILibraryFileAlias
208 from canonical.launchpad import _
209
210+
211 class IBuildBase(Interface):
212 """Common interface shared by farm jobs that build a package."""
213+
214 # XXX: wgrant 2010-01-20 bug=507712: Most of these attribute names
215 # are bad.
216 datecreated = exported(
217@@ -68,10 +71,16 @@
218 description=_("A URL for the build log. None if there is no "
219 "log available.")))
220
221- buildqueue_record = Attribute("Corespondent BuildQueue record")
222+ buildqueue_record = Object(
223+ schema=IBuildQueue, required=True,
224+ title=_("Corresponding BuildQueue record"))
225
226 is_private = Attribute("Whether the build should be treated as private.")
227
228+ policy_name = TextLine(
229+ title=_("Policy name"), required=True,
230+ description=_("The upload policy to use for handling these builds."))
231+
232 archive = exported(
233 Reference(
234 title=_("Archive"), schema=IArchive,
235@@ -100,7 +109,14 @@
236 title=_("Distribution"), required=True,
237 description=_("Shortcut for its distribution.")))
238
239- def handleStatus(status, queueItem, librarian, slave_status):
240+ def getUploaderCommand(upload_leaf):
241+ """Get the command to run as the uploader.
242+
243+ :return: A list of command line arguments, beginning with the
244+ executable.
245+ """
246+
247+ def handleStatus(status, librarian, slave_status):
248 """Handle a finished build status from a slave.
249
250 :param status: Slave build status string with 'BuildStatus.' stripped.
251
252=== modified file 'lib/lp/buildmaster/interfaces/buildfarmjob.py'
253--- lib/lp/buildmaster/interfaces/buildfarmjob.py 2010-01-18 22:01:19 +0000
254+++ lib/lp/buildmaster/interfaces/buildfarmjob.py 2010-01-29 17:17:19 +0000
255@@ -158,7 +158,7 @@
256
257 class IBuildFarmCandidateJobSelection(Interface):
258 """Operations for refining candidate job selection (optional).
259-
260+
261 Job type classes that do *not* need to refine candidate job selection may
262 be derived from `BuildFarmJob` which provides a base implementation of
263 this interface.
264@@ -178,7 +178,7 @@
265 SELECT TRUE
266 FROM Archive, Build, BuildPackageJob, DistroArchSeries
267 WHERE
268- BuildPackageJob.job = Job.id AND
269+ BuildPackageJob.job = Job.id AND
270 ..
271
272 :param processor: the type of processor that the candidate jobs are
273@@ -192,7 +192,7 @@
274 def postprocessCandidate(job, logger):
275 """True if the candidate job is fine and should be dispatched
276 to a builder, False otherwise.
277-
278+
279 :param job: The `BuildQueue` instance to be scrutinized.
280 :param logger: The logger to use.
281
282
283=== modified file 'lib/lp/buildmaster/model/buildbase.py'
284--- lib/lp/buildmaster/model/buildbase.py 2010-01-20 01:24:01 +0000
285+++ lib/lp/buildmaster/model/buildbase.py 2010-01-29 17:17:19 +0000
286@@ -14,9 +14,9 @@
287 import os
288 import pytz
289 import subprocess
290-import time
291
292 from storm.store import Store
293+from zope.interface import implements
294 from zope.security.proxy import removeSecurityProxy
295
296 from canonical.config import config
297@@ -24,12 +24,54 @@
298 from canonical.database.sqlbase import (
299 clear_current_connection_cache, cursor, flush_database_updates)
300 from canonical.librarian.utils import copy_and_close
301+from lp.buildmaster.interfaces.buildbase import IBuildBase
302 from lp.registry.interfaces.pocket import pocketsuffix
303 from lp.soyuz.interfaces.build import BuildStatus
304 from lp.soyuz.model.buildqueue import BuildQueue
305
306
307 class BuildBase:
308+
309+ implements(IBuildBase)
310+
311+ policy_name = 'buildd'
312+
313+ def getUploadLeaf(self, build_id, now=None):
314+ """Return a directory name to store build things in.
315+
316+ :param build_id: The id as returned by the slave, normally
317+ $BUILD_ID-$BUILDQUEUE_ID
318+ :param now: The `datetime` to use. If not provided, defaults to now.
319+ """
320+ # UPLOAD_LEAF: <TIMESTAMP>-<BUILD_ID>-<BUILDQUEUE_ID>
321+ if now is None:
322+ now = datetime.datetime.now()
323+ return '%s-%s' % (now.strftime("%Y%m%d-%H%M%S"), build_id)
324+
325+ def getUploadDir(self, upload_leaf):
326+ """Return the directory that things will be stored in."""
327+ return os.path.join(config.builddmaster.root, 'incoming', upload_leaf)
328+
329+ def getUploaderCommand(self, upload_leaf, uploader_logfilename):
330+ """See `IBuildBase`."""
331+ root = os.path.abspath(config.builddmaster.root)
332+ uploader_command = list(config.builddmaster.uploader.split())
333+
334+ # add extra arguments for processing a binary upload
335+ extra_args = [
336+ "--log-file", "%s" % uploader_logfilename,
337+ "-d", "%s" % self.distribution.name,
338+ "-s", "%s" % (self.distroseries.name +
339+ pocketsuffix[self.pocket]),
340+ "-b", "%s" % self.id,
341+ "-J", "%s" % upload_leaf,
342+ '--context=%s' % self.policy_name,
343+ "%s" % root,
344+ ]
345+
346+ uploader_command.extend(extra_args)
347+ return uploader_command
348+
349 def _getProxiedFileURL(self, library_file):
350 """Return the 'http_url' of a `ProxiedLibraryFileAlias`."""
351 # Avoiding circular imports.
352@@ -81,12 +123,10 @@
353 # ensure we have the correct build root as:
354 # <BUILDMASTER_ROOT>/incoming/<UPLOAD_LEAF>/<TARGET_PATH>/[FILES]
355 root = os.path.abspath(config.builddmaster.root)
356- incoming = os.path.join(root, 'incoming')
357
358 # create a single directory to store build result files
359- # UPLOAD_LEAF: <TIMESTAMP>-<BUILD_ID>-<BUILDQUEUE_ID>
360- upload_leaf = "%s-%s" % (time.strftime("%Y%m%d-%H%M%S"), buildid)
361- upload_dir = os.path.join(incoming, upload_leaf)
362+ upload_leaf = self.getUploadLeaf(buildid)
363+ upload_dir = self.getUploadDir(upload_leaf)
364 logger.debug("Storing build result at '%s'" % upload_dir)
365
366 # Build the right UPLOAD_PATH so the distribution and archive
367@@ -106,29 +146,16 @@
368 out_file = open(out_file_name, "wb")
369 copy_and_close(slave_file, out_file)
370
371- uploader_argv = list(config.builddmaster.uploader.split())
372 uploader_logfilename = os.path.join(upload_dir, 'uploader.log')
373- logger.debug("Saving uploader log at '%s'"
374- % uploader_logfilename)
375-
376- # add extra arguments for processing a binary upload
377- extra_args = [
378- "--log-file", "%s" % uploader_logfilename,
379- "-d", "%s" % self.distribution.name,
380- "-s", "%s" % (self.distroseries.name +
381- pocketsuffix[self.pocket]),
382- "-b", "%s" % self.id,
383- "-J", "%s" % upload_leaf,
384- "%s" % root,
385- ]
386-
387- uploader_argv.extend(extra_args)
388+ uploader_command = self.getUploaderCommand(
389+ upload_leaf, uploader_logfilename)
390+ logger.debug("Saving uploader log at '%s'" % uploader_logfilename)
391
392 logger.debug("Invoking uploader on %s" % root)
393- logger.debug("%s" % uploader_argv)
394+ logger.debug("%s" % uploader_command)
395
396 uploader_process = subprocess.Popen(
397- uploader_argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
398+ uploader_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
399
400 # Nothing should be written to the stdout/stderr.
401 upload_stdout, upload_stderr = uploader_process.communicate()
402
403=== modified file 'lib/lp/buildmaster/model/builder.py'
404--- lib/lp/buildmaster/model/builder.py 2010-01-21 10:48:25 +0000
405+++ lib/lp/buildmaster/model/builder.py 2010-01-29 17:17:18 +0000
406@@ -457,7 +457,7 @@
407 AND (
408 -- The processor values either match or the candidate
409 -- job is processor-independent.
410- buildqueue.processor = %s OR
411+ buildqueue.processor = %s OR
412 buildqueue.processor IS NULL)
413 AND (
414 -- The virtualized values either match or the candidate
415@@ -473,7 +473,6 @@
416 self.virtualized)
417 order_clause = " ORDER BY buildqueue.lastscore DESC, buildqueue.id"
418
419- extra_tables = set()
420 extra_queries = []
421 job_classes = specific_job_classes()
422 for job_type, job_class in job_classes.iteritems():
423
424=== modified file 'lib/lp/buildmaster/model/buildfarmjob.py'
425--- lib/lp/buildmaster/model/buildfarmjob.py 2010-01-20 04:04:15 +0000
426+++ lib/lp/buildmaster/model/buildfarmjob.py 2010-01-29 17:17:19 +0000
427@@ -19,7 +19,7 @@
428 class BuildFarmJob:
429 """Mix-in class for `IBuildFarmJob` implementations."""
430 implements(IBuildFarmJob)
431- classProvides(IBuildFarmCandidateJobSelection, ISpecificBuildFarmJobClass)
432+ classProvides(ISpecificBuildFarmJobClass, IBuildFarmCandidateJobSelection)
433
434 def score(self):
435 """See `IBuildFarmJob`."""
436
437=== added file 'lib/lp/buildmaster/tests/test_buildbase.py'
438--- lib/lp/buildmaster/tests/test_buildbase.py 1970-01-01 00:00:00 +0000
439+++ lib/lp/buildmaster/tests/test_buildbase.py 2010-01-29 17:17:19 +0000
440@@ -0,0 +1,82 @@
441+# Copyright 2010 Canonical Ltd. This software is licensed under the
442+# GNU Affero General Public License version 3 (see the file LICENSE).
443+
444+"""Tests for `IBuildBase`."""
445+
446+__metaclass__ = type
447+
448+from datetime import datetime
449+import os
450+import unittest
451+
452+from canonical.config import config
453+from canonical.testing.layers import DatabaseFunctionalLayer
454+from lp.buildmaster.interfaces.buildbase import IBuildBase
455+from lp.buildmaster.model.buildbase import BuildBase
456+from lp.registry.interfaces.pocket import pocketsuffix
457+from lp.testing import TestCase, TestCaseWithFactory
458+
459+
460+class TestBuildBase(TestCase):
461+ """Tests for `IBuildBase`."""
462+
463+ def disabled_test_build_base_provides_interface(self):
464+ # XXX: JonathanLange 2010-01-22 bug=510919: BuildBase is supposed to
465+ # implement IBuildBase, but doesn't atm. Since it's not the focus of
466+ # the branch, we'll postpone the work.
467+ build_base = BuildBase()
468+ self.assertProvides(build_base, IBuildBase)
469+
470+ def test_getUploadLeaf(self):
471+ # getUploadLeaf returns the current time, followed by the build id.
472+ build_base = BuildBase()
473+ now = datetime.now()
474+ build_id = self.factory.getUniqueInteger()
475+ upload_leaf = build_base.getUploadLeaf(build_id, now=now)
476+ self.assertEqual(
477+ '%s-%s' % (now.strftime("%Y%m%d-%H%M%S"), build_id), upload_leaf)
478+
479+ def test_getUploadDir(self):
480+ # getUploadDir is the absolute path to the directory in which things
481+ # are uploaded to.
482+ build_base = BuildBase()
483+ build_id = self.factory.getUniqueInteger()
484+ upload_leaf = build_base.getUploadLeaf(build_id)
485+ upload_dir = build_base.getUploadDir(upload_leaf)
486+ self.assertEqual(
487+ os.path.join(config.builddmaster.root, 'incoming', upload_leaf),
488+ upload_dir)
489+
490+
491+class TestBuildBaseWithDatabase(TestCaseWithFactory):
492+ """Tests for `IBuildBase` that need objects from the rest of Launchpad."""
493+
494+ layer = DatabaseFunctionalLayer
495+
496+ def test_getUploaderCommand(self):
497+ build_base = BuildBase()
498+ upload_leaf = self.factory.getUniqueString('upload-leaf')
499+ build_base.distroseries = self.factory.makeDistroSeries()
500+ build_base.distribution = build_base.distroseries.distribution
501+ build_base.pocket = self.factory.getAnyPocket()
502+ build_base.id = self.factory.getUniqueInteger()
503+ build_base.policy_name = self.factory.getUniqueString('policy-name')
504+ config_args = list(config.builddmaster.uploader.split())
505+ log_file = self.factory.getUniqueString('logfile')
506+ config_args.extend(
507+ ['--log-file', log_file,
508+ '-d', build_base.distribution.name,
509+ '-s', (build_base.distroseries.name
510+ + pocketsuffix[build_base.pocket]),
511+ '-b', str(build_base.id),
512+ '-J', upload_leaf,
513+ '--context=%s' % build_base.policy_name,
514+ os.path.abspath(config.builddmaster.root),
515+ ])
516+ uploader_command = build_base.getUploaderCommand(
517+ upload_leaf, log_file)
518+ self.assertEqual(config_args, uploader_command)
519+
520+
521+def test_suite():
522+ return unittest.TestLoader().loadTestsFromName(__name__)
523
524=== modified file 'lib/lp/soyuz/configure.zcml'
525--- lib/lp/soyuz/configure.zcml 2010-01-20 07:47:53 +0000
526+++ lib/lp/soyuz/configure.zcml 2010-01-29 17:17:19 +0000
527@@ -930,6 +930,39 @@
528 permission="zope.Public" />
529
530 <!-- SourcePackageRecipe -->
531+
532+ <securedutility
533+ component="lp.soyuz.model.sourcepackagerecipe.SourcePackageRecipe"
534+ provides="lp.soyuz.interfaces.sourcepackagerecipe.ISourcePackageRecipeSource">
535+ <allow interface="lp.soyuz.interfaces.sourcepackagerecipe.ISourcePackageRecipeSource"/>
536+ </securedutility>
537+
538+ <class
539+ class="lp.soyuz.model.sourcepackagerecipebuild.SourcePackageRecipeBuild">
540+ <allow interface="lp.soyuz.interfaces.sourcepackagerecipebuild.ISourcePackageRecipeBuild"/>
541+ </class>
542+
543+ <securedutility
544+ component="lp.soyuz.model.sourcepackagerecipebuild.SourcePackageRecipeBuild"
545+ provides="lp.soyuz.interfaces.sourcepackagerecipebuild.ISourcePackageRecipeBuildSource">
546+ <allow interface="lp.soyuz.interfaces.sourcepackagerecipebuild.ISourcePackageRecipeBuildSource"/>
547+ </securedutility>
548+
549+ <class
550+ class="lp.soyuz.model.sourcepackagerecipebuild.SourcePackageRecipeBuildJob">
551+ <allow interface="lp.soyuz.interfaces.sourcepackagerecipebuild.ISourcePackageRecipeBuildJob"/>
552+ </class>
553+
554+ <securedutility
555+ component="lp.soyuz.model.sourcepackagerecipebuild.SourcePackageRecipeBuildJob"
556+ provides="lp.soyuz.interfaces.sourcepackagerecipebuild.ISourcePackageRecipeBuildJobSource">
557+ <allow interface="lp.soyuz.interfaces.sourcepackagerecipebuild.ISourcePackageRecipeBuildJobSource"/>
558+ </securedutility>
559+
560+ <adapter factory="lp.soyuz.model.recipebuilder.RecipeBuildBehavior"
561+ permission="zope.Public" />
562+
563+ <!-- SourcePackageRecipe -->
564 <class
565 class="lp.soyuz.model.sourcepackagerecipe.SourcePackageRecipe">
566 <allow interface="lp.soyuz.interfaces.sourcepackagerecipe.ISourcePackageRecipe"/>
567@@ -953,37 +986,9 @@
568 class="bzrlib.plugins.builder.recipe.NestInstruction">
569 <allow attributes="as_tuple recipe_branch nest_path" />
570 </class>
571- <securedutility
572- component="lp.soyuz.model.sourcepackagerecipe.SourcePackageRecipe"
573- provides="lp.soyuz.interfaces.sourcepackagerecipe.ISourcePackageRecipeSource">
574- <allow interface="lp.soyuz.interfaces.sourcepackagerecipe.ISourcePackageRecipeSource"/>
575- </securedutility>
576-
577- <class
578- class="lp.soyuz.model.sourcepackagerecipebuild.SourcePackageRecipeBuild">
579- <allow interface="lp.soyuz.interfaces.sourcepackagerecipebuild.ISourcePackageRecipeBuild"/>
580- </class>
581-
582- <securedutility
583- component="lp.soyuz.model.sourcepackagerecipebuild.SourcePackageRecipeBuild"
584- provides="lp.soyuz.interfaces.sourcepackagerecipebuild.ISourcePackageRecipeBuildSource">
585- <allow interface="lp.soyuz.interfaces.sourcepackagerecipebuild.ISourcePackageRecipeBuildSource"/>
586- </securedutility>
587-
588- <class
589- class="lp.soyuz.model.sourcepackagerecipebuild.SourcePackageRecipeBuildJob">
590- <allow interface="lp.soyuz.interfaces.sourcepackagerecipebuild.ISourcePackageRecipeBuildJob"/>
591- </class>
592+
593 <utility component="lp.soyuz.model.sourcepackagerecipebuild.SourcePackageRecipeBuildJob"
594 name="RECIPEBRANCHBUILD"
595 provides="lp.buildmaster.interfaces.buildfarmjob.IBuildFarmJob"/>
596
597- <securedutility
598- component="lp.soyuz.model.sourcepackagerecipebuild.SourcePackageRecipeBuildJob"
599- provides="lp.soyuz.interfaces.sourcepackagerecipebuild.ISourcePackageRecipeBuildJobSource">
600- <allow interface="lp.soyuz.interfaces.sourcepackagerecipebuild.ISourcePackageRecipeBuildJobSource"/>
601- </securedutility>
602-
603- <adapter factory="lp.soyuz.model.recipebuilder.RecipeBuildBehavior"/>
604-
605 </configure>
606
607=== modified file 'lib/lp/soyuz/interfaces/sourcepackagerecipebuild.py'
608--- lib/lp/soyuz/interfaces/sourcepackagerecipebuild.py 2010-01-18 09:38:12 +0000
609+++ lib/lp/soyuz/interfaces/sourcepackagerecipebuild.py 2010-01-29 17:17:19 +0000
610@@ -49,6 +49,7 @@
611 schema=ISourcePackageRecipe, required=True,
612 title=_("The recipe being built."))
613
614+
615 class ISourcePackageRecipeBuildSource(Interface):
616 """A utility of this interface be used to create source package builds."""
617
618
619=== modified file 'lib/lp/soyuz/model/build.py'
620--- lib/lp/soyuz/model/build.py 2010-01-20 01:24:01 +0000
621+++ lib/lp/soyuz/model/build.py 2010-01-29 17:17:19 +0000
622@@ -11,6 +11,9 @@
623 import datetime
624 import logging
625 import operator
626+import os
627+import subprocess
628+import time
629
630 from zope.interface import implements
631 from zope.component import getUtility
632@@ -27,7 +30,8 @@
633 from canonical.database.datetimecol import UtcDateTimeCol
634 from canonical.database.enumcol import EnumCol
635 from canonical.database.sqlbase import (
636- cursor, quote_like, SQLBase, sqlvalues)
637+ clear_current_connection_cache, flush_database_updates, cursor,
638+ quote_like, SQLBase, sqlvalues)
639 from canonical.launchpad.components.decoratedresultset import (
640 DecoratedResultSet)
641 from canonical.launchpad.database.librarian import (
642@@ -43,10 +47,12 @@
643 from canonical.launchpad.webapp.interfaces import (
644 IStoreSelector, MAIN_STORE, DEFAULT_FLAVOR)
645 from canonical.launchpad.webapp.tales import DurationFormatterAPI
646+from canonical.librarian.utils import copy_and_close
647 from lp.archivepublisher.utils import get_ppa_reference
648 from lp.buildmaster.interfaces.buildfarmjob import BuildFarmJobType
649 from lp.buildmaster.model.buildbase import BuildBase
650-from lp.registry.interfaces.pocket import PackagePublishingPocket
651+from lp.registry.interfaces.pocket import (PackagePublishingPocket,
652+ pocketsuffix)
653 from lp.services.job.model.job import Job
654 from lp.soyuz.adapters.archivedependencies import get_components_for_building
655 from lp.soyuz.interfaces.archive import ArchivePurpose
656
657=== modified file 'lib/lp/soyuz/model/buildpackagejob.py'
658--- lib/lp/soyuz/model/buildpackagejob.py 2010-01-20 04:14:23 +0000
659+++ lib/lp/soyuz/model/buildpackagejob.py 2010-01-29 17:17:19 +0000
660@@ -213,8 +213,8 @@
661 sub_query = """
662 SELECT TRUE FROM Archive, Build, BuildPackageJob, DistroArchSeries
663 WHERE
664- BuildPackageJob.job = Job.id AND
665- BuildPackageJob.build = Build.id AND
666+ BuildPackageJob.job = Job.id AND
667+ BuildPackageJob.build = Build.id AND
668 Build.distroarchseries = DistroArchSeries.id AND
669 Build.archive = Archive.id AND
670 ((Archive.private IS TRUE AND
671
672=== modified file 'lib/lp/soyuz/model/recipebuilder.py'
673--- lib/lp/soyuz/model/recipebuilder.py 2010-01-18 09:38:12 +0000
674+++ lib/lp/soyuz/model/recipebuilder.py 2010-01-29 17:17:19 +0000
675@@ -68,7 +68,7 @@
676 args["ogrecomponent"] = get_primary_current_component(
677 self.build.archive, self.build.distroseries,
678 self.build.sourcepackagename.name)
679- args['archives'] = get_sources_list_for_building(self.build,
680+ args['archives'] = get_sources_list_for_building(self.build,
681 distroarchseries, self.build.sourcepackagename.name)
682 return args
683
684@@ -87,7 +87,7 @@
685
686 chroot = distroarchseries.getChroot()
687 if chroot is None:
688- raise CannotBuild("Unable to find a chroot for %s" %
689+ raise CannotBuild("Unable to find a chroot for %s" %
690 distroarchseries.displayname)
691 self._builder.slave.cacheFile(logger, chroot)
692
693@@ -131,10 +131,11 @@
694
695 # This should already have been checked earlier, but just check again
696 # here in case of programmer errors.
697- reason = check_upload_to_pocket(build.archive, build.distroseries, build.pocket)
698+ reason = check_upload_to_pocket(
699+ build.archive, build.distroseries, build.pocket)
700 assert reason is None, (
701 "%s (%s) can not be built for pocket %s: invalid pocket due "
702- "to the series status of %s." %
703+ "to the series status of %s." %
704 (build.title, build.id, build.pocket.name,
705 build.distroseries.name))
706
707
708=== modified file 'lib/lp/soyuz/model/sourcepackagerecipebuild.py'
709--- lib/lp/soyuz/model/sourcepackagerecipebuild.py 2010-01-20 04:14:23 +0000
710+++ lib/lp/soyuz/model/sourcepackagerecipebuild.py 2010-01-29 17:17:19 +0000
711@@ -39,6 +39,8 @@
712 class SourcePackageRecipeBuild(BuildBase, Storm):
713 __storm_table__ = 'SourcePackageRecipeBuild'
714
715+ policy_name = 'recipe'
716+
717 implements(ISourcePackageRecipeBuild)
718 classProvides(ISourcePackageRecipeBuildSource)
719
720@@ -87,9 +89,9 @@
721
722 @property
723 def pocket(self):
724- # JRV 2010-01-15: The database table really should have a pocket
725- # column, although this is not a big problem at the moment
726- # as recipe builds only happen for PPA's (so far). (bug 507307)
727+ # XXX: JRV 2010-01-15 bug=507307: The database table really should
728+ # have a pocket column, although this is not a big problem at the
729+ # moment as recipe builds only happen for PPA's (so far).
730 return PackagePublishingPocket.RELEASE
731
732 recipe_id = Int(name='recipe', allow_none=False)
733@@ -129,8 +131,8 @@
734 self.sourcepackagename = sourcepackagename
735
736 @classmethod
737- def new(
738- cls, sourcepackage, recipe, requester, archive, date_created=None):
739+ def new(cls, sourcepackage, recipe, requester, archive,
740+ date_created=None):
741 """See `ISourcePackageRecipeBuildSource`."""
742 store = IMasterStore(SourcePackageRecipeBuild)
743 if date_created is None:
744
745=== modified file 'lib/lp/soyuz/model/sourcepackagerecipedata.py'
746--- lib/lp/soyuz/model/sourcepackagerecipedata.py 2010-01-13 02:59:33 +0000
747+++ lib/lp/soyuz/model/sourcepackagerecipedata.py 2010-01-29 17:17:19 +0000
748@@ -127,8 +127,8 @@
749
750 sourcepackage_recipe_build_id = Int(
751 name='sourcepackage_recipe_build', allow_none=True)
752- #sourcepackage_recipe_build = Reference(
753- # sourcepackage_recipe_build_id, 'SourcePackageRecipeBuild.id')
754+ sourcepackage_recipe_build = Reference(
755+ sourcepackage_recipe_build_id, 'SourcePackageRecipeBuild.id')
756
757 def getRecipe(self):
758 """The BaseRecipeBranch version of the recipe."""
759
760=== modified file 'lib/lp/soyuz/tests/test_recipebuilder.py'
761--- lib/lp/soyuz/tests/test_recipebuilder.py 2010-01-21 04:34:44 +0000
762+++ lib/lp/soyuz/tests/test_recipebuilder.py 2010-01-29 17:17:19 +0000
763@@ -16,8 +16,8 @@
764 IBuildFarmJobBehavior)
765 from lp.buildmaster.manager import RecordingSlave
766 from lp.soyuz.adapters.archivedependencies import get_sources_list_for_building
767+from lp.soyuz.model.processor import ProcessorFamilySet
768 from lp.soyuz.model.recipebuilder import RecipeBuildBehavior
769-from lp.soyuz.model.processor import ProcessorFamilySet
770 from lp.soyuz.model.sourcepackagerecipebuild import (
771 SourcePackageRecipeBuild)
772 from lp.soyuz.tests.soyuzbuilddhelpers import (MockBuilder,
773@@ -48,21 +48,20 @@
774 """Create a sample `ISourcePackageRecipeBuildJob`."""
775 spn = self.factory.makeSourcePackageName("apackage")
776 distro = self.factory.makeDistribution(name="distro")
777- distroseries = self.factory.makeDistroSeries(name="mydistro",
778+ distroseries = self.factory.makeDistroSeries(name="mydistro",
779 distribution=distro)
780- processorfamily = ProcessorFamilySet().getByName('x86')
781- distroarchseries = self.factory.makeDistroArchSeries(
782- distroseries=distroseries, architecturetag='i386',
783- processorfamily=processorfamily)
784+ processorfamily = ProcessorFamilySet().getByProcessorName('386')
785+ distroseries.newArch(
786+ 'i386', processorfamily, True, self.factory.makePerson())
787 sourcepackage = self.factory.makeSourcePackage(spn, distroseries)
788 requester = self.factory.makePerson(email="requester@ubuntu.com",
789 name="joe", displayname="Joe User")
790- somebranch = self.factory.makeBranch(owner=requester, name="pkg",
791+ somebranch = self.factory.makeBranch(owner=requester, name="pkg",
792 product=self.factory.makeProduct("someapp"))
793- recipe = self.factory.makeSourcePackageRecipe(requester, requester,
794+ recipe = self.factory.makeSourcePackageRecipe(requester, requester,
795 distroseries, spn, u"recept", somebranch)
796- spb = self.factory.makeSourcePackageRecipeBuild(sourcepackage=sourcepackage,
797- recipe=recipe, requester=requester)
798+ spb = self.factory.makeSourcePackageRecipeBuild(
799+ sourcepackage=sourcepackage, recipe=recipe, requester=requester)
800 job = spb.makeJob()
801 job = IBuildFarmJobBehavior(job)
802 return job
803@@ -95,8 +94,7 @@
804 # _extraBuildArgs will return a sane set of additional arguments
805 job = self.makeJob()
806 distroarchseries = job.build.distroseries.architectures[0]
807- distroname = job.build.archive.distribution.name
808- self.assertEquals({
809+ self.assertEqual({
810 'author_email': u'requester@ubuntu.com',
811 'suite': u'mydistro',
812 'author_name': u'Joe User',
813@@ -105,7 +103,7 @@
814 'ogrecomponent': 'universe',
815 'recipe_text': '# bzr-builder format 0.2 deb-version 1.0\n'
816 'lp://dev/~joe/someapp/pkg\n',
817- 'archives': get_sources_list_for_building(job.build,
818+ 'archives': get_sources_list_for_building(job.build,
819 distroarchseries, job.build.sourcepackagename.name)
820 }, job._extraBuildArgs(distroarchseries))
821
822@@ -132,10 +130,10 @@
823 self.assertEquals(build_args[1], "sourcepackagerecipe")
824 self.assertEquals(build_args[3], {})
825 distroarchseries = job.build.distroseries.architectures[0]
826- self.assertEquals(build_args[4], job._extraBuildArgs(distroarchseries))
827+ self.assertEqual(build_args[4], job._extraBuildArgs(distroarchseries))
828
829 def test_dispatchBuildToSlave_nochroot(self):
830- # dispatchBuildToSlave will fail when there is not chroot tarball
831+ # dispatchBuildToSlave will fail when there is not chroot tarball
832 # available for the distroseries to build for.
833 job = self.makeJob()
834 builder = MockBuilder("bob-de-bouwer", SaneBuildingSlave())
835@@ -143,7 +141,7 @@
836 builder.processor = processorfamily.processors[0]
837 job.setBuilder(builder)
838 logger = BufferLogger()
839- self.assertRaises(CannotBuild, job.dispatchBuildToSlave,
840+ self.assertRaises(CannotBuild, job.dispatchBuildToSlave,
841 "someid", logger)
842
843 def test_getById(self):

Subscribers

People subscribed via source and target branches

to status/vote changes: