Merge lp:~allenap/launchpad/dd-initseries-bug-727105-derive-distro-series into lp:launchpad
- dd-initseries-bug-727105-derive-distro-series
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Gavin Panella |
Approved revision: | no longer in the source branch. |
Merged at revision: | 12705 |
Proposed branch: | lp:~allenap/launchpad/dd-initseries-bug-727105-derive-distro-series |
Merge into: | lp:launchpad |
Prerequisite: | lp:~allenap/launchpad/dd-initseries-bug-727105-copy-options |
Diff against target: |
621 lines (+167/-108) 10 files modified
lib/lp/registry/configure.zcml (+3/-0) lib/lp/registry/interfaces/distroseries.py (+2/-1) lib/lp/registry/model/distroseries.py (+4/-3) lib/lp/registry/tests/test_derivedistroseries.py (+13/-11) lib/lp/soyuz/model/distributionjob.py (+11/-10) lib/lp/soyuz/model/initialisedistroseriesjob.py (+27/-12) lib/lp/soyuz/scripts/initialise_distroseries.py (+14/-5) lib/lp/soyuz/scripts/tests/test_initialise_distroseries.py (+18/-17) lib/lp/soyuz/tests/test_initialisedistroseriesjob.py (+56/-38) scripts/ftpmaster-tools/initialise-from-parent.py (+19/-11) |
To merge this branch: | bzr merge lp:~allenap/launchpad/dd-initseries-bug-727105-derive-distro-series |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gavin Panella (community) | Approve | ||
Steve Kowalik (community) | code | Approve | |
Review via email: mp+54742@code.launchpad.net |
Commit message
Description of the change
Currently, InitializeDistr
parent_series property set. However, other parts of the code consider
parent_series to be a marker for when a series has *already* been
initialized.
This branch changes the assumption. The InitialiseDistr
takes another parameter, parent, that it stores in its metadata, and
InitialiseDistr
latter's responsibility for updating the child's parent_series
property. This also means that failed initializations (aka
derivations) don't leave the series in a limbo state.
IDistroSeries.
launchpad.Admin. However, it is exported to the API as read-only, so
it cannot be modified except by internal code.
Gavin Panella (allenap) : | # |
Gavin Panella (allenap) wrote : | # |
> This looks great to me, expect for the error message of "Parent
> series has already been initialized." It strikes me as ambiguous,
> since the parent series *has* been initialized, but you mean the
> child's parent series has already been set.
Oops, good catch. I've changed it to:
DistroSeries child-name has been initialized; it derives from
parent-
Thanks for the review!
Gavin.
Preview Diff
1 | === modified file 'lib/lp/registry/configure.zcml' |
2 | --- lib/lp/registry/configure.zcml 2011-03-23 16:28:51 +0000 |
3 | +++ lib/lp/registry/configure.zcml 2011-03-30 16:11:08 +0000 |
4 | @@ -195,6 +195,9 @@ |
5 | permission="launchpad.Edit" |
6 | interface="lp.registry.interfaces.distroseries.IDistroSeriesEditRestricted"/> |
7 | <require |
8 | + permission="launchpad.Admin" |
9 | + set_attributes="parent_series"/> |
10 | + <require |
11 | permission="launchpad.TranslationsAdmin" |
12 | set_attributes="hide_all_translations defer_translation_imports"/> |
13 | <require |
14 | |
15 | === modified file 'lib/lp/registry/interfaces/distroseries.py' |
16 | --- lib/lp/registry/interfaces/distroseries.py 2011-03-30 16:11:05 +0000 |
17 | +++ lib/lp/registry/interfaces/distroseries.py 2011-03-30 16:11:08 +0000 |
18 | @@ -242,7 +242,8 @@ |
19 | title=_("Parent series"), |
20 | description=_("The series from which this one was branched."), |
21 | required=True, schema=Interface, # Really IDistroSeries, see below |
22 | - vocabulary='DistroSeries')) |
23 | + vocabulary='DistroSeries'), |
24 | + readonly=True) |
25 | owner = exported( |
26 | PublicPersonChoice(title=_("Owner"), vocabulary='ValidOwner')) |
27 | date_created = exported( |
28 | |
29 | === modified file 'lib/lp/registry/model/distroseries.py' |
30 | --- lib/lp/registry/model/distroseries.py 2011-03-28 20:54:50 +0000 |
31 | +++ lib/lp/registry/model/distroseries.py 2011-03-30 16:11:08 +0000 |
32 | @@ -1963,12 +1963,13 @@ |
33 | child = distribution.newSeries( |
34 | name=name, displayname=displayname, title=title, |
35 | summary=summary, description=description, |
36 | - version=version, parent_series=self, owner=user) |
37 | + version=version, parent_series=None, owner=user) |
38 | IStore(self).add(child) |
39 | else: |
40 | - if child.parent_series is not self: |
41 | + if child.parent_series is not None: |
42 | raise DerivationError( |
43 | - "DistroSeries %s parent series isn't %s" % ( |
44 | + "DistroSeries %s parent series is %s, " |
45 | + "but it must not be set" % ( |
46 | child.name, self.name)) |
47 | initialise_series = InitialiseDistroSeries(child) |
48 | try: |
49 | |
50 | === modified file 'lib/lp/registry/tests/test_derivedistroseries.py' |
51 | --- lib/lp/registry/tests/test_derivedistroseries.py 2011-03-09 09:53:59 +0000 |
52 | +++ lib/lp/registry/tests/test_derivedistroseries.py 2011-03-30 16:11:08 +0000 |
53 | @@ -6,6 +6,10 @@ |
54 | |
55 | __metaclass__ = type |
56 | |
57 | +from zope.component import getUtility |
58 | +from zope.security.interfaces import Unauthorized |
59 | +from zope.security.proxy import removeSecurityProxy |
60 | + |
61 | from canonical.testing.layers import LaunchpadFunctionalLayer |
62 | from lp.registry.interfaces.distroseries import DerivationError |
63 | from lp.soyuz.interfaces.distributionjob import ( |
64 | @@ -17,8 +21,6 @@ |
65 | TestCaseWithFactory, |
66 | ) |
67 | from lp.testing.sampledata import ADMIN_EMAIL |
68 | -from zope.component import getUtility |
69 | -from zope.security.interfaces import Unauthorized |
70 | |
71 | |
72 | class TestDeriveDistroSeries(TestCaseWithFactory): |
73 | @@ -29,8 +31,7 @@ |
74 | super(TestDeriveDistroSeries, self).setUp() |
75 | self.soyuz = self.factory.makeTeam(name='soyuz-team') |
76 | self.parent = self.factory.makeDistroSeries() |
77 | - self.child = self.factory.makeDistroSeries( |
78 | - parent_series=self.parent) |
79 | + self.child = self.factory.makeDistroSeries() |
80 | |
81 | def test_no_permission_to_call(self): |
82 | login(ADMIN_EMAIL) |
83 | @@ -50,13 +51,15 @@ |
84 | self.parent.deriveDistroSeries, self.soyuz.teamowner, |
85 | 'newdistro') |
86 | |
87 | - def test_parent_is_not_self(self): |
88 | - other = self.factory.makeDistroSeries() |
89 | + def test_parent_is_not_set(self): |
90 | + # When parent_series is set it means that the distroseries has already |
91 | + # been derived, and it is forbidden to derive more than once. |
92 | + removeSecurityProxy(self.child).parent_series = self.parent |
93 | self.assertRaisesWithContent( |
94 | DerivationError, |
95 | - "DistroSeries %s parent series isn't %s" % ( |
96 | - self.child.name, other.name), |
97 | - other.deriveDistroSeries, self.soyuz.teamowner, |
98 | + ("DistroSeries {self.child.name} parent series is " |
99 | + "{self.parent.name}, but it must not be set").format(self=self), |
100 | + self.parent.deriveDistroSeries, self.soyuz.teamowner, |
101 | self.child.name, self.child.distribution) |
102 | |
103 | def test_create_new_distroseries(self): |
104 | @@ -79,8 +82,7 @@ |
105 | # Make two distroseries with the same name and different |
106 | # distributions to check that the right distroseries is initialised. |
107 | self.factory.makeDistroSeries(name='bar') |
108 | - bar = self.factory.makeDistroSeries( |
109 | - name='bar', parent_series=self.parent) |
110 | + bar = self.factory.makeDistroSeries(name='bar') |
111 | self.parent.deriveDistroSeries( |
112 | self.soyuz.teamowner, 'bar', distribution=bar.parent, |
113 | displayname='Bar', title='The Bar', summary='Bar', |
114 | |
115 | === modified file 'lib/lp/soyuz/model/distributionjob.py' |
116 | --- lib/lp/soyuz/model/distributionjob.py 2011-03-10 14:05:51 +0000 |
117 | +++ lib/lp/soyuz/model/distributionjob.py 2011-03-30 16:11:08 +0000 |
118 | @@ -8,27 +8,28 @@ |
119 | "DistributionJobDerived", |
120 | ] |
121 | |
122 | +from lazr.delegates import delegates |
123 | import simplejson |
124 | - |
125 | -from storm.locals import And, Int, Reference, Unicode |
126 | - |
127 | +from storm.locals import ( |
128 | + And, |
129 | + Int, |
130 | + Reference, |
131 | + Unicode, |
132 | + ) |
133 | from zope.interface import implements |
134 | |
135 | from canonical.database.enumcol import EnumCol |
136 | from canonical.launchpad.interfaces.lpstorm import IStore |
137 | - |
138 | -from lazr.delegates import delegates |
139 | - |
140 | from lp.app.errors import NotFoundError |
141 | from lp.registry.model.distribution import Distribution |
142 | from lp.registry.model.distroseries import DistroSeries |
143 | +from lp.services.database.stormbase import StormBase |
144 | +from lp.services.job.model.job import Job |
145 | +from lp.services.job.runner import BaseRunnableJob |
146 | from lp.soyuz.interfaces.distributionjob import ( |
147 | DistributionJobType, |
148 | IDistributionJob, |
149 | ) |
150 | -from lp.services.job.model.job import Job |
151 | -from lp.services.job.runner import BaseRunnableJob |
152 | -from lp.services.database.stormbase import StormBase |
153 | |
154 | |
155 | class DistributionJob(StormBase): |
156 | @@ -106,7 +107,7 @@ |
157 | |
158 | def getOopsVars(self): |
159 | """See `IRunnableJob`.""" |
160 | - vars = BaseRunnableJob.getOopsVars(self) |
161 | + vars = super(DistributionJobDerived, self).getOopsVars() |
162 | vars.extend([ |
163 | ('distribution_id', self.context.distribution.id), |
164 | ('distroseries_id', self.context.distroseries.id), |
165 | |
166 | === modified file 'lib/lp/soyuz/model/initialisedistroseriesjob.py' |
167 | --- lib/lp/soyuz/model/initialisedistroseriesjob.py 2010-10-13 05:04:41 +0000 |
168 | +++ lib/lp/soyuz/model/initialisedistroseriesjob.py 2011-03-30 16:11:08 +0000 |
169 | @@ -7,10 +7,16 @@ |
170 | "InitialiseDistroSeriesJob", |
171 | ] |
172 | |
173 | -from zope.interface import classProvides, implements |
174 | - |
175 | -from canonical.launchpad.interfaces.lpstorm import IMasterStore |
176 | - |
177 | +from zope.interface import ( |
178 | + classProvides, |
179 | + implements, |
180 | + ) |
181 | + |
182 | +from canonical.launchpad.interfaces.lpstorm import ( |
183 | + IMasterStore, |
184 | + IStore, |
185 | + ) |
186 | +from lp.registry.model.distroseries import DistroSeries |
187 | from lp.soyuz.interfaces.distributionjob import ( |
188 | DistributionJobType, |
189 | IInitialiseDistroSeriesJob, |
190 | @@ -20,9 +26,7 @@ |
191 | DistributionJob, |
192 | DistributionJobDerived, |
193 | ) |
194 | -from lp.soyuz.scripts.initialise_distroseries import ( |
195 | - InitialiseDistroSeries, |
196 | - ) |
197 | +from lp.soyuz.scripts.initialise_distroseries import InitialiseDistroSeries |
198 | |
199 | |
200 | class InitialiseDistroSeriesJob(DistributionJobDerived): |
201 | @@ -33,21 +37,26 @@ |
202 | classProvides(IInitialiseDistroSeriesJobSource) |
203 | |
204 | @classmethod |
205 | - def create(cls, distroseries, arches=(), packagesets=(), |
206 | - rebuild=False): |
207 | + def create(cls, parent, child, arches=(), packagesets=(), rebuild=False): |
208 | """See `IInitialiseDistroSeriesJob`.""" |
209 | metadata = { |
210 | + 'parent': parent.id, |
211 | 'arches': arches, |
212 | 'packagesets': packagesets, |
213 | 'rebuild': rebuild, |
214 | } |
215 | job = DistributionJob( |
216 | - distroseries.distribution, distroseries, cls.class_job_type, |
217 | + child.distribution, child, cls.class_job_type, |
218 | metadata) |
219 | IMasterStore(DistributionJob).add(job) |
220 | return cls(job) |
221 | |
222 | @property |
223 | + def parent(self): |
224 | + return IStore(DistroSeries).get( |
225 | + DistroSeries, self.metadata["parent"]) |
226 | + |
227 | + @property |
228 | def arches(self): |
229 | return tuple(self.metadata['arches']) |
230 | |
231 | @@ -62,7 +71,13 @@ |
232 | def run(self): |
233 | """See `IRunnableJob`.""" |
234 | ids = InitialiseDistroSeries( |
235 | - self.distroseries, self.arches, self.packagesets, |
236 | - self.rebuild) |
237 | + self.parent, self.distroseries, self.arches, |
238 | + self.packagesets, self.rebuild) |
239 | ids.check() |
240 | ids.initialise() |
241 | + |
242 | + def getOopsVars(self): |
243 | + """See `IRunnableJob`.""" |
244 | + vars = super(InitialiseDistroSeriesJob, self).getOopsVars() |
245 | + vars.append(('parent_distroseries_id', self.metadata.get("parent"))) |
246 | + return vars |
247 | |
248 | === modified file 'lib/lp/soyuz/scripts/initialise_distroseries.py' |
249 | --- lib/lp/soyuz/scripts/initialise_distroseries.py 2011-03-29 23:48:03 +0000 |
250 | +++ lib/lp/soyuz/scripts/initialise_distroseries.py 2011-03-30 16:11:08 +0000 |
251 | @@ -40,7 +40,8 @@ |
252 | Preconditions: |
253 | The distroseries must exist, and be completly unused, with no source |
254 | or binary packages existing, as well as no distroarchseries set up. |
255 | - Section and component selections must be empty. |
256 | + Section and component selections must be empty. It must not have a |
257 | + parent series. |
258 | |
259 | Outcome: |
260 | The distroarchseries set up in the parent series will be copied. |
261 | @@ -60,11 +61,11 @@ |
262 | """ |
263 | |
264 | def __init__( |
265 | - self, distroseries, arches=(), packagesets=(), rebuild=False): |
266 | + self, parent, distroseries, arches=(), packagesets=(), rebuild=False): |
267 | # Avoid circular imports |
268 | from lp.registry.model.distroseries import DistroSeries |
269 | + self.parent = parent |
270 | self.distroseries = distroseries |
271 | - self.parent = self.distroseries.parent_series |
272 | self.arches = arches |
273 | self.packagesets = [ |
274 | ensure_unicode(packageset) for packageset in packagesets] |
275 | @@ -72,8 +73,12 @@ |
276 | self._store = IMasterStore(DistroSeries) |
277 | |
278 | def check(self): |
279 | - if self.parent is None: |
280 | - raise InitialisationError("Parent series required.") |
281 | + if self.distroseries.parent_series is not None: |
282 | + raise InitialisationError( |
283 | + ("DistroSeries {child.name} has been initialized; it already " |
284 | + "derives from {child.parent_series.distribution.name}/" |
285 | + "{child.parent_series.name}.").format( |
286 | + child=self.distroseries)) |
287 | self._checkBuilds() |
288 | self._checkQueue() |
289 | self._checkSeries() |
290 | @@ -127,10 +132,14 @@ |
291 | raise InitialisationError(error) |
292 | |
293 | def initialise(self): |
294 | + self._set_parent() |
295 | self._copy_architectures() |
296 | self._copy_packages() |
297 | self._copy_packagesets() |
298 | |
299 | + def _set_parent(self): |
300 | + self.distroseries.parent_series = self.parent |
301 | + |
302 | def _copy_architectures(self): |
303 | include = '' |
304 | if self.arches: |
305 | |
306 | === modified file 'lib/lp/soyuz/scripts/tests/test_initialise_distroseries.py' |
307 | --- lib/lp/soyuz/scripts/tests/test_initialise_distroseries.py 2011-03-29 23:48:03 +0000 |
308 | +++ lib/lp/soyuz/scripts/tests/test_initialise_distroseries.py 2011-03-30 16:11:08 +0000 |
309 | @@ -9,6 +9,8 @@ |
310 | import subprocess |
311 | import sys |
312 | |
313 | +from testtools.content import Content |
314 | +from testtools.content_type import UTF8_TEXT |
315 | import transaction |
316 | from zope.component import getUtility |
317 | |
318 | @@ -83,17 +85,11 @@ |
319 | pocket=PackagePublishingPocket.RELEASE, |
320 | status=PackagePublishingStatus.PUBLISHED) |
321 | |
322 | - def test_failure_with_no_parent_series(self): |
323 | - # Initialising a new distro series requires a parent series to be set |
324 | - ids = InitialiseDistroSeries(self.factory.makeDistroSeries()) |
325 | - self.assertRaisesWithContent( |
326 | - InitialisationError, "Parent series required.", ids.check) |
327 | - |
328 | def test_failure_for_already_released_distroseries(self): |
329 | # Initialising a distro series that has already been used will error |
330 | - child = self.factory.makeDistroSeries(parent_series=self.parent) |
331 | + child = self.factory.makeDistroSeries() |
332 | self.factory.makeDistroArchSeries(distroseries=child) |
333 | - ids = InitialiseDistroSeries(child) |
334 | + ids = InitialiseDistroSeries(self.parent, child) |
335 | self.assertRaisesWithContent( |
336 | InitialisationError, |
337 | "Can not copy distroarchseries from parent, there are already " |
338 | @@ -105,9 +101,8 @@ |
339 | distroseries=self.parent, |
340 | pocket=PackagePublishingPocket.RELEASE) |
341 | source.createMissingBuilds() |
342 | - child = self.factory.makeDistroSeries( |
343 | - parent_series=self.parent) |
344 | - ids = InitialiseDistroSeries(child) |
345 | + child = self.factory.makeDistroSeries() |
346 | + ids = InitialiseDistroSeries(self.parent, child) |
347 | self.assertRaisesWithContent( |
348 | InitialisationError, "Parent series has pending builds.", |
349 | ids.check) |
350 | @@ -118,8 +113,8 @@ |
351 | self.parent.createQueueEntry( |
352 | PackagePublishingPocket.RELEASE, |
353 | 'foo.changes', 'bar', self.parent.main_archive) |
354 | - child = self.factory.makeDistroSeries(parent_series=self.parent) |
355 | - ids = InitialiseDistroSeries(child) |
356 | + child = self.factory.makeDistroSeries() |
357 | + ids = InitialiseDistroSeries(self.parent, child) |
358 | self.assertRaisesWithContent( |
359 | InitialisationError, "Parent series queues are not empty.", |
360 | ids.check) |
361 | @@ -160,10 +155,9 @@ |
362 | |
363 | def _full_initialise(self, arches=(), packagesets=(), rebuild=False, |
364 | distribution=None): |
365 | - child = self.factory.makeDistroSeries( |
366 | - parent_series=self.parent, |
367 | - distribution=distribution) |
368 | - ids = InitialiseDistroSeries(child, arches, packagesets, rebuild) |
369 | + child = self.factory.makeDistroSeries(distribution=distribution) |
370 | + ids = InitialiseDistroSeries( |
371 | + self.parent, child, arches, packagesets, rebuild) |
372 | ids.check() |
373 | ids.initialise() |
374 | return child |
375 | @@ -347,6 +341,11 @@ |
376 | test1.addSources('udev') |
377 | getUtility(IArchivePermissionSet).newPackagesetUploader( |
378 | self.parent.main_archive, uploader, test1) |
379 | + # The child must have a parent series because initialise-from-parent |
380 | + # expects it; this script supports the old-style derivation of |
381 | + # distribution series where the parent series is specified at the time |
382 | + # of adding the series. New-style derivation leaves the specification |
383 | + # of the parent series until later. |
384 | child = self.factory.makeDistroSeries(parent_series=self.parent) |
385 | transaction.commit() |
386 | ifp = os.path.join( |
387 | @@ -356,6 +355,8 @@ |
388 | [sys.executable, ifp, "-vv", "-d", child.parent.name, |
389 | child.name], stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
390 | stdout, stderr = process.communicate() |
391 | + self.addDetail("stdout", Content(UTF8_TEXT, lambda: stdout)) |
392 | + self.addDetail("stderr", Content(UTF8_TEXT, lambda: stderr)) |
393 | self.assertEqual(process.returncode, 0) |
394 | self.assertTrue( |
395 | "DEBUG Committing transaction." in stderr.split('\n')) |
396 | |
397 | === modified file 'lib/lp/soyuz/tests/test_initialisedistroseriesjob.py' |
398 | --- lib/lp/soyuz/tests/test_initialisedistroseriesjob.py 2010-12-02 16:13:51 +0000 |
399 | +++ lib/lp/soyuz/tests/test_initialisedistroseriesjob.py 2011-03-30 16:11:08 +0000 |
400 | @@ -13,7 +13,11 @@ |
401 | from zope.security.proxy import removeSecurityProxy |
402 | |
403 | from canonical.config import config |
404 | -from canonical.testing import LaunchpadZopelessLayer |
405 | +from canonical.database.sqlbase import flush_database_caches |
406 | +from canonical.testing import ( |
407 | + DatabaseFunctionalLayer, |
408 | + LaunchpadZopelessLayer, |
409 | + ) |
410 | from lp.buildmaster.enums import BuildStatus |
411 | from lp.registry.interfaces.pocket import PackagePublishingPocket |
412 | from lp.soyuz.interfaces.distributionjob import ( |
413 | @@ -30,18 +34,23 @@ |
414 | class InitialiseDistroSeriesJobTests(TestCaseWithFactory): |
415 | """Test case for InitialiseDistroSeriesJob.""" |
416 | |
417 | - layer = LaunchpadZopelessLayer |
418 | + layer = DatabaseFunctionalLayer |
419 | + |
420 | + @property |
421 | + def job_source(self): |
422 | + return getUtility(IInitialiseDistroSeriesJobSource) |
423 | |
424 | def test_getOopsVars(self): |
425 | + parent = self.factory.makeDistroSeries() |
426 | distroseries = self.factory.makeDistroSeries() |
427 | - job = getUtility(IInitialiseDistroSeriesJobSource).create( |
428 | - distroseries) |
429 | + job = self.job_source.create(parent, distroseries) |
430 | vars = job.getOopsVars() |
431 | naked_job = removeSecurityProxy(job) |
432 | self.assertIn( |
433 | ('distribution_id', distroseries.distribution.id), vars) |
434 | self.assertIn(('distroseries_id', distroseries.id), vars) |
435 | self.assertIn(('distribution_job_id', naked_job.context.id), vars) |
436 | + self.assertIn(('parent_distroseries_id', parent.id), vars) |
437 | |
438 | def _getJobs(self): |
439 | """Return the pending InitialiseDistroSeriesJobs as a list.""" |
440 | @@ -53,52 +62,62 @@ |
441 | return len(self._getJobs()) |
442 | |
443 | def test_create_only_creates_one(self): |
444 | + parent = self.factory.makeDistroSeries() |
445 | distroseries = self.factory.makeDistroSeries() |
446 | # If there's already a InitialiseDistroSeriesJob for a |
447 | # DistroSeries, InitialiseDistroSeriesJob.create() won't create |
448 | # a new one. |
449 | - getUtility(IInitialiseDistroSeriesJobSource).create( |
450 | - distroseries) |
451 | - transaction.commit() |
452 | - |
453 | - # There will now be one job in the queue. |
454 | - self.assertEqual(1, self._getJobCount()) |
455 | - |
456 | - getUtility(IInitialiseDistroSeriesJobSource).create( |
457 | - distroseries) |
458 | - |
459 | - # This is less than ideal |
460 | - self.assertRaises(IntegrityError, self._getJobCount) |
461 | - |
462 | - def test_run(self): |
463 | - """Test that InitialiseDistroSeriesJob.run() actually |
464 | - initialises builds and copies from the parent.""" |
465 | - distroseries = self.factory.makeDistroSeries() |
466 | - |
467 | - job = getUtility(IInitialiseDistroSeriesJobSource).create( |
468 | - distroseries) |
469 | - |
470 | - # Since our new distroseries doesn't have a parent set, and the first |
471 | - # thing that run() will execute is checking the distroseries, if it |
472 | - # returns an InitialisationError, then it's good. |
473 | + self.job_source.create(parent, distroseries) |
474 | + self.job_source.create(parent, distroseries) |
475 | + self.assertRaises(IntegrityError, flush_database_caches) |
476 | + |
477 | + def test_run_with_parent_series_already_set(self): |
478 | + # InitialisationError is raised if the parent series is already set on |
479 | + # the child. |
480 | + parent = self.factory.makeDistroSeries() |
481 | + distroseries = self.factory.makeDistroSeries(parent_series=parent) |
482 | + job = self.job_source.create(parent, distroseries) |
483 | + expected_message = ( |
484 | + "DistroSeries {child.name} has been initialized; it already " |
485 | + "derives from {parent.distribution.name}/{parent.name}.").format( |
486 | + parent=parent, child=distroseries) |
487 | self.assertRaisesWithContent( |
488 | - InitialisationError, "Parent series required.", job.run) |
489 | + InitialisationError, expected_message, job.run) |
490 | |
491 | def test_arguments(self): |
492 | """Test that InitialiseDistroSeriesJob specified with arguments can |
493 | be gotten out again.""" |
494 | + parent = self.factory.makeDistroSeries() |
495 | distroseries = self.factory.makeDistroSeries() |
496 | arches = (u'i386', u'amd64') |
497 | packagesets = (u'foo', u'bar', u'baz') |
498 | |
499 | - job = getUtility(IInitialiseDistroSeriesJobSource).create( |
500 | - distroseries, arches, packagesets) |
501 | + job = self.job_source.create( |
502 | + parent, distroseries, arches, packagesets) |
503 | |
504 | naked_job = removeSecurityProxy(job) |
505 | self.assertEqual(naked_job.distroseries, distroseries) |
506 | self.assertEqual(naked_job.arches, arches) |
507 | self.assertEqual(naked_job.packagesets, packagesets) |
508 | self.assertEqual(naked_job.rebuild, False) |
509 | + self.assertEqual(naked_job.metadata["parent"], parent.id) |
510 | + |
511 | + def test_parent(self): |
512 | + parent = self.factory.makeDistroSeries() |
513 | + distroseries = self.factory.makeDistroSeries() |
514 | + job = self.job_source.create(parent, distroseries) |
515 | + naked_job = removeSecurityProxy(job) |
516 | + self.assertEqual(parent, naked_job.parent) |
517 | + |
518 | + |
519 | +class InitialiseDistroSeriesJobTestsWithPackages(TestCaseWithFactory): |
520 | + """Test case for InitialiseDistroSeriesJob.""" |
521 | + |
522 | + layer = LaunchpadZopelessLayer |
523 | + |
524 | + @property |
525 | + def job_source(self): |
526 | + return getUtility(IInitialiseDistroSeriesJobSource) |
527 | |
528 | def _create_child(self): |
529 | pf = self.factory.makeProcessorFamily() |
530 | @@ -125,16 +144,14 @@ |
531 | distroseries=parent) |
532 | test1.addSources('udev') |
533 | parent.updatePackageCount() |
534 | - child = self.factory.makeDistroSeries(parent_series=parent) |
535 | - |
536 | - # Make sure everything hits the database, switching db users |
537 | - # aborts. |
538 | + child = self.factory.makeDistroSeries() |
539 | + # Make sure everything hits the database, switching db users aborts. |
540 | transaction.commit() |
541 | return parent, child |
542 | |
543 | def test_job(self): |
544 | parent, child = self._create_child() |
545 | - job = getUtility(IInitialiseDistroSeriesJobSource).create(child) |
546 | + job = self.job_source.create(parent, child) |
547 | self.layer.switchDbUser('initialisedistroseries') |
548 | |
549 | job.run() |
550 | @@ -145,8 +162,9 @@ |
551 | def test_job_with_arguments(self): |
552 | parent, child = self._create_child() |
553 | arch = parent.nominatedarchindep.architecturetag |
554 | - job = getUtility(IInitialiseDistroSeriesJobSource).create( |
555 | - child, packagesets=('test1',), arches=(arch,), rebuild=True) |
556 | + job = self.job_source.create( |
557 | + parent, child, packagesets=('test1',), arches=(arch,), |
558 | + rebuild=True) |
559 | self.layer.switchDbUser('initialisedistroseries') |
560 | |
561 | job.run() |
562 | |
563 | === modified file 'scripts/ftpmaster-tools/initialise-from-parent.py' |
564 | --- scripts/ftpmaster-tools/initialise-from-parent.py 2010-11-08 12:52:43 +0000 |
565 | +++ scripts/ftpmaster-tools/initialise-from-parent.py 2011-03-30 16:11:08 +0000 |
566 | @@ -5,23 +5,27 @@ |
567 | |
568 | """Initialise a new distroseries from its parent series.""" |
569 | |
570 | +from optparse import OptionParser |
571 | +import sys |
572 | + |
573 | import _pythonpath |
574 | - |
575 | -import sys |
576 | -from optparse import OptionParser |
577 | - |
578 | +from contrib.glock import GlobalLock |
579 | from zope.component import getUtility |
580 | -from contrib.glock import GlobalLock |
581 | |
582 | from canonical.config import config |
583 | -from lp.registry.interfaces.distribution import IDistributionSet |
584 | from canonical.launchpad.scripts import ( |
585 | - execute_zcml_for_scripts, logger, logger_options) |
586 | + execute_zcml_for_scripts, |
587 | + logger, |
588 | + logger_options, |
589 | + ) |
590 | from canonical.lp import initZopeless |
591 | - |
592 | from lp.app.errors import NotFoundError |
593 | +from lp.registry.interfaces.distribution import IDistributionSet |
594 | from lp.soyuz.scripts.initialise_distroseries import ( |
595 | - InitialisationError, InitialiseDistroSeries) |
596 | + InitialisationError, |
597 | + InitialiseDistroSeries, |
598 | + ) |
599 | + |
600 | |
601 | def main(): |
602 | # Parse command-line arguments |
603 | @@ -77,7 +81,12 @@ |
604 | arches = () |
605 | if options.arches is not None: |
606 | arches = tuple(options.arches.split(',')) |
607 | - ids = InitialiseDistroSeries(distroseries, arches) |
608 | + # InitialiseDistroSeries does not like it if the parent series is |
609 | + # specified on the child, so we must unset it and pass it in. This is |
610 | + # a temporary hack until confidence in InitialiseDistroSeriesJob is |
611 | + # good, at which point this script will be obsolete. |
612 | + parent, distroseries.parent_series = distroseries.parent_series, None |
613 | + ids = InitialiseDistroSeries(parent, distroseries, arches) |
614 | ids.check() |
615 | log.debug('initialising from parent, copying publishing records.') |
616 | ids.initialise() |
617 | @@ -99,4 +108,3 @@ |
618 | |
619 | if __name__ == '__main__': |
620 | sys.exit(main()) |
621 | - |
This looks great to me, expect for the error message of "Parent series has already been initialized." It strikes me as ambiguous, since the parent series *has* been initialized, but you mean the child's parent series has already been set.