Merge lp:~stevenk/launchpad/move-ifp-from-idistroseries into lp:launchpad
- move-ifp-from-idistroseries
- Merge into devel
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Steve Kowalik | ||||||||
Approved revision: | no longer in the source branch. | ||||||||
Merged at revision: | 11336 | ||||||||
Proposed branch: | lp:~stevenk/launchpad/move-ifp-from-idistroseries | ||||||||
Merge into: | lp:launchpad | ||||||||
Diff against target: |
853 lines (+303/-351) 9 files modified
lib/lp/archiveuploader/tests/test_uploadprocessor.py (+6/-7) lib/lp/registry/doc/distroseries.txt (+9/-11) lib/lp/registry/interfaces/distroseries.py (+0/-29) lib/lp/registry/model/distroseries.py (+2/-173) lib/lp/soyuz/doc/initialise-from-parent.txt (+1/-4) lib/lp/soyuz/doc/soyuz-set-of-uploads.txt (+7/-5) lib/lp/soyuz/scripts/initialise_distroseries.py (+256/-0) scripts/ftpmaster-tools/initialise-from-parent.py (+19/-104) utilities/soyuz-sampledata-setup.py (+3/-18) |
||||||||
To merge this branch: | bzr merge lp:~stevenk/launchpad/move-ifp-from-idistroseries | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jelmer Vernooij (community) | code | Approve | |
Review via email: mp+31520@code.launchpad.net |
Commit message
Move IDistroSeries.
Description of the change
This branch shifts IDistroSeries.
I had a few pre-implementation chats with Julian about it, who mentioned it would be nice to drop the cursor() usage from the script, and generally clean up i-f-p, by moving the functions from the script into the new class, and to not behave badly and assert() on error.
It also fixes another bug as a drive-by -- it no longer copies PARTNER archives when initialising.
Running tests:
bin/test -vv -t test_uploadproc
Lint: I cleaned up the majority of the lint warnings.
Blood Type: Don't know, and blame jtv for this bit. :-)
Preview Diff
1 | === modified file 'lib/lp/archiveuploader/tests/test_uploadprocessor.py' |
2 | --- lib/lp/archiveuploader/tests/test_uploadprocessor.py 2010-08-06 13:52:46 +0000 |
3 | +++ lib/lp/archiveuploader/tests/test_uploadprocessor.py 2010-08-13 01:50:16 +0000 |
4 | @@ -39,6 +39,7 @@ |
5 | from lp.registry.model.sourcepackagename import SourcePackageName |
6 | from lp.soyuz.model.sourcepackagerelease import ( |
7 | SourcePackageRelease) |
8 | +from lp.soyuz.scripts.initialise_distroseries import InitialiseDistroSeries |
9 | from canonical.launchpad.ftests import import_public_test_keys |
10 | from lp.registry.interfaces.distribution import IDistributionSet |
11 | from lp.registry.interfaces.series import SeriesStatus |
12 | @@ -211,15 +212,13 @@ |
13 | name, 'Breezy Badger', |
14 | 'The Breezy Badger', 'Black and White', 'Someone', |
15 | '5.10', bat, bat.owner) |
16 | - breezy_i386 = self.breezy.newArch( |
17 | - 'i386', bat['i386'].processorfamily, True, self.breezy.owner) |
18 | - self.breezy.nominatedarchindep = breezy_i386 |
19 | - |
20 | - fake_chroot = self.addMockFile('fake_chroot.tar.gz') |
21 | - breezy_i386.addOrUpdateChroot(fake_chroot) |
22 | |
23 | self.breezy.changeslist = 'breezy-changes@ubuntu.com' |
24 | - self.breezy.initialiseFromParent() |
25 | + ids = InitialiseDistroSeries(self.breezy) |
26 | + ids.initialise() |
27 | + |
28 | + fake_chroot = self.addMockFile('fake_chroot.tar.gz') |
29 | + self.breezy['i386'].addOrUpdateChroot(fake_chroot) |
30 | |
31 | if permitted_formats is None: |
32 | permitted_formats = [SourcePackageFormat.FORMAT_1_0] |
33 | |
34 | === modified file 'lib/lp/registry/doc/distroseries.txt' |
35 | --- lib/lp/registry/doc/distroseries.txt 2010-08-10 02:56:06 +0000 |
36 | +++ lib/lp/registry/doc/distroseries.txt 2010-08-13 01:50:16 +0000 |
37 | @@ -309,21 +309,21 @@ |
38 | publishing records etc. Essentially this is a "Do not push this button |
39 | again" type set of assertions. |
40 | |
41 | + >>> from lp.soyuz.scripts.initialise_distroseries import ( |
42 | + ... InitialiseDistroSeries) |
43 | >>> login("foo.bar@canonical.com") |
44 | >>> humpy = ubuntu.newSeries('humpy', 'Humpy Hippo', |
45 | ... 'The Humpy Hippo', 'Fat', 'Yo Momma', |
46 | ... '99.2',hoary, hoary.owner) |
47 | - >>> humpy_i386 = humpy.newArch('i386', hoary['i386'].processorfamily, |
48 | - ... True, humpy.owner) |
49 | - >>> humpy.nominatedarchindep = humpy_i386 |
50 | - >>> humpy.initialiseFromParent() |
51 | + >>> ids = InitialiseDistroSeries(humpy) |
52 | + >>> ids.initialise() |
53 | >>> len(hoary.getPublishedReleases('pmount')) |
54 | 1 |
55 | >>> len(humpy.getPublishedReleases('pmount')) |
56 | 1 |
57 | >>> len(hoary['i386'].getReleasedPackages('pmount')) |
58 | 1 |
59 | - >>> len(humpy_i386.getReleasedPackages('pmount')) |
60 | + >>> len(humpy['i386'].getReleasedPackages('pmount')) |
61 | 1 |
62 | |
63 | Check if the attributes of an DRSPR instance for the just initialised |
64 | @@ -349,11 +349,8 @@ |
65 | >>> bumpy = ubuntu.newSeries('bumpy', 'Bumpy', |
66 | ... 'The Bumpy', 'Fat', 'Boom', |
67 | ... '99.3', warty, warty.owner) |
68 | - |
69 | - >>> bumpy_i386 = bumpy.newArch('i386', warty['i386'].processorfamily, |
70 | - ... True, bumpy.owner) |
71 | - >>> bumpy.nominatedarchindep = bumpy_i386 |
72 | - >>> bumpy.initialiseFromParent() |
73 | + >>> ids = InitialiseDistroSeries(bumpy) |
74 | + >>> ids.initialise() |
75 | |
76 | Build a new ISourcePackage based in the new distroseries: |
77 | |
78 | @@ -364,11 +361,12 @@ |
79 | 'binaries' should be inherited from parent release. |
80 | |
81 | >>> bumpy_firefox_sp.currentrelease.binaries.count() |
82 | - 2 |
83 | + 3 |
84 | |
85 | >>> for bin in bumpy_firefox_sp.currentrelease.binaries: |
86 | ... print bin.id, bin.title, bin.build.distro_arch_series.title |
87 | 27 mozilla-firefox-data-0.9 The Warty Warthog Release for i386 (x86) |
88 | + 26 mozilla-firefox-0.9 The Warty Warthog Release for hppa (hppa) |
89 | 12 mozilla-firefox-0.9 The Warty Warthog Release for i386 (x86) |
90 | |
91 | |
92 | |
93 | === modified file 'lib/lp/registry/interfaces/distroseries.py' |
94 | --- lib/lp/registry/interfaces/distroseries.py 2010-08-12 21:02:47 +0000 |
95 | +++ lib/lp/registry/interfaces/distroseries.py 2010-08-13 01:50:16 +0000 |
96 | @@ -721,35 +721,6 @@ |
97 | supports_virtualized=False): |
98 | """Create a new port or DistroArchSeries for this DistroSeries.""" |
99 | |
100 | - def initialiseFromParent(): |
101 | - """Copy in all of the parent distroseries's configuration. This |
102 | - includes all configuration for distroseries and distroarchseries |
103 | - publishing and all publishing records for sources and binaries. |
104 | - |
105 | - Preconditions: |
106 | - The distroseries must have been set up with its distroarchseriess |
107 | - as needed. It should have its nominated arch-indep set up along |
108 | - with all other basic requirements for the structure of the |
109 | - distroseries. This distroseries and all its distroarchseriess |
110 | - must have empty publishing sets. Section and component selections |
111 | - must be empty. |
112 | - |
113 | - Outcome: |
114 | - The publishing structure will be copied from the parent. All |
115 | - PUBLISHED and PENDING packages in the parent will be created in |
116 | - this distroseries and its distroarchseriess. The lucille config |
117 | - will be copied in, all component and section selections will be |
118 | - duplicated as will any permission-related structures. |
119 | - |
120 | - Note: |
121 | - This method will assert all of its preconditions where possible. |
122 | - After this is run, you still need to construct chroots for building, |
123 | - you need to add anything missing wrt. ports etc. This method is |
124 | - only meant to give you a basic copy of a parent series in order |
125 | - to assist you in preparing a new series of a distribution or |
126 | - in the initialisation of a derivative. |
127 | - """ |
128 | - |
129 | def copyTranslationsFromParent(ztm): |
130 | """Copy any translation done in parent that we lack. |
131 | |
132 | |
133 | === modified file 'lib/lp/registry/model/distroseries.py' |
134 | --- lib/lp/registry/model/distroseries.py 2010-08-10 21:54:41 +0000 |
135 | +++ lib/lp/registry/model/distroseries.py 2010-08-13 01:50:16 +0000 |
136 | @@ -31,7 +31,7 @@ |
137 | from canonical.database.datetimecol import UtcDateTimeCol |
138 | from canonical.database.enumcol import EnumCol |
139 | from canonical.database.sqlbase import ( |
140 | - cursor, flush_database_caches, flush_database_updates, quote_like, |
141 | + flush_database_caches, flush_database_updates, quote_like, |
142 | quote, SQLBase, sqlvalues) |
143 | from canonical.launchpad.components.decoratedresultset import ( |
144 | DecoratedResultSet) |
145 | @@ -40,7 +40,6 @@ |
146 | POFileTranslator) |
147 | from lp.translations.model.pofile import POFile |
148 | from canonical.launchpad.interfaces.lpstorm import IStore |
149 | -from lp.soyuz.adapters.packagelocation import PackageLocation |
150 | from lp.soyuz.model.binarypackagename import BinaryPackageName |
151 | from lp.soyuz.model.binarypackagerelease import ( |
152 | BinaryPackageRelease) |
153 | @@ -66,7 +65,6 @@ |
154 | from lp.translations.model.languagepack import LanguagePack |
155 | from lp.registry.model.milestone import ( |
156 | HasMilestonesMixin, Milestone) |
157 | -from lp.soyuz.model.packagecloner import clone_packages |
158 | from lp.registry.model.packaging import Packaging |
159 | from lp.registry.model.person import Person |
160 | from canonical.launchpad.database.librarian import LibraryFileAlias |
161 | @@ -90,7 +88,7 @@ |
162 | HasTranslationImportsMixin) |
163 | from canonical.launchpad.helpers import shortlist |
164 | from lp.soyuz.interfaces.archive import ( |
165 | - ALLOW_RELEASE_BUILDS, ArchivePurpose, IArchiveSet, MAIN_ARCHIVE_PURPOSES) |
166 | + ALLOW_RELEASE_BUILDS, ArchivePurpose) |
167 | from lp.soyuz.interfaces.binarypackagebuild import IBinaryPackageBuildSet |
168 | from lp.soyuz.interfaces.buildrecords import IHasBuildRecords |
169 | from lp.soyuz.interfaces.binarypackagename import ( |
170 | @@ -1594,175 +1592,6 @@ |
171 | """See BugTargetBase.""" |
172 | return 'BugTask.distroseries = %s' % sqlvalues(self) |
173 | |
174 | - def initialiseFromParent(self): |
175 | - """See `IDistroSeries`.""" |
176 | - archives = self.distribution.all_distro_archive_ids |
177 | - assert self.parent_series is not None, "Parent series must be present" |
178 | - assert SourcePackagePublishingHistory.select(""" |
179 | - Distroseries = %s AND |
180 | - Archive IN %s""" % sqlvalues(self.id, archives)).count() == 0, ( |
181 | - "Source Publishing must be empty") |
182 | - for arch in self.architectures: |
183 | - assert BinaryPackagePublishingHistory.select(""" |
184 | - DistroArchSeries = %s AND |
185 | - Archive IN %s""" % sqlvalues(arch, archives)).count() == 0, ( |
186 | - "Binary Publishing must be empty") |
187 | - try: |
188 | - parent_arch = self.parent_series[arch.architecturetag] |
189 | - assert parent_arch.processorfamily == arch.processorfamily, ( |
190 | - "The arch tags must match the processor families.") |
191 | - except KeyError: |
192 | - raise AssertionError("Parent series lacks %s" % ( |
193 | - arch.architecturetag)) |
194 | - assert self.nominatedarchindep is not None, ( |
195 | - "Must have a nominated archindep architecture.") |
196 | - assert self.components.count() == 0, ( |
197 | - "Component selections must be empty.") |
198 | - assert self.sections.count() == 0, ( |
199 | - "Section selections must be empty.") |
200 | - |
201 | - # MAINTAINER: dsilvers: 20051031 |
202 | - # Here we go underneath the SQLObject caching layers in order to |
203 | - # generate what will potentially be tens of thousands of rows |
204 | - # in various tables. Thus we flush pending updates from the SQLObject |
205 | - # layer, perform our work directly in the transaction and then throw |
206 | - # the rest of the SQLObject cache away to make sure it hasn't cached |
207 | - # anything that is no longer true. |
208 | - |
209 | - # Prepare for everything by flushing updates to the database. |
210 | - flush_database_updates() |
211 | - cur = cursor() |
212 | - |
213 | - # Perform the copies |
214 | - self._copy_component_section_and_format_selections(cur) |
215 | - |
216 | - # Prepare the list of distroarchseries for which binary packages |
217 | - # shall be copied. |
218 | - distroarchseries_list = [] |
219 | - for arch in self.architectures: |
220 | - parent_arch = self.parent_series[arch.architecturetag] |
221 | - distroarchseries_list.append((parent_arch, arch)) |
222 | - # Now copy source and binary packages. |
223 | - self._copy_publishing_records(distroarchseries_list) |
224 | - self._copy_lucille_config(cur) |
225 | - self._copy_packaging_links(cur) |
226 | - |
227 | - # Finally, flush the caches because we've altered stuff behind the |
228 | - # back of sqlobject. |
229 | - flush_database_caches() |
230 | - |
231 | - def _copy_lucille_config(self, cur): |
232 | - """Copy all lucille related configuration from our parent series.""" |
233 | - cur.execute(''' |
234 | - UPDATE DistroSeries SET lucilleconfig=( |
235 | - SELECT pdr.lucilleconfig FROM DistroSeries AS pdr |
236 | - WHERE pdr.id = %s) |
237 | - WHERE id = %s |
238 | - ''' % sqlvalues(self.parent_series.id, self.id)) |
239 | - |
240 | - def _copy_publishing_records(self, distroarchseries_list): |
241 | - """Copy the publishing records from the parent arch series |
242 | - to the given arch series in ourselves. |
243 | - |
244 | - We copy all PENDING and PUBLISHED records as PENDING into our own |
245 | - publishing records. |
246 | - |
247 | - We copy only the RELEASE pocket in the PRIMARY and PARTNER |
248 | - archives. |
249 | - """ |
250 | - archive_set = getUtility(IArchiveSet) |
251 | - |
252 | - for archive in self.parent_series.distribution.all_distro_archives: |
253 | - # We only want to copy PRIMARY and PARTNER archives. |
254 | - if archive.purpose not in MAIN_ARCHIVE_PURPOSES: |
255 | - continue |
256 | - |
257 | - # XXX cprov 20080612: Implicitly creating a PARTNER archive for |
258 | - # the destination distroseries is bad. Why are we copying |
259 | - # partner to a series in another distribution anyway ? |
260 | - # See bug #239807 for further information. |
261 | - target_archive = archive_set.getByDistroPurpose( |
262 | - self.distribution, archive.purpose) |
263 | - if target_archive is None: |
264 | - target_archive = archive_set.new( |
265 | - distribution=self.distribution, purpose=archive.purpose, |
266 | - owner=self.distribution.owner) |
267 | - |
268 | - origin = PackageLocation( |
269 | - archive, self.parent_series.distribution, self.parent_series, |
270 | - PackagePublishingPocket.RELEASE) |
271 | - destination = PackageLocation( |
272 | - target_archive, self.distribution, self, |
273 | - PackagePublishingPocket.RELEASE) |
274 | - clone_packages(origin, destination, distroarchseries_list) |
275 | - |
276 | - def _copy_component_section_and_format_selections(self, cur): |
277 | - """Copy the section, component and format selections from the parent |
278 | - distro series into this one. |
279 | - """ |
280 | - # Copy the component selections |
281 | - cur.execute(''' |
282 | - INSERT INTO ComponentSelection (distroseries, component) |
283 | - SELECT %s AS distroseries, cs.component AS component |
284 | - FROM ComponentSelection AS cs WHERE cs.distroseries = %s |
285 | - ''' % sqlvalues(self.id, self.parent_series.id)) |
286 | - # Copy the section selections |
287 | - cur.execute(''' |
288 | - INSERT INTO SectionSelection (distroseries, section) |
289 | - SELECT %s as distroseries, ss.section AS section |
290 | - FROM SectionSelection AS ss WHERE ss.distroseries = %s |
291 | - ''' % sqlvalues(self.id, self.parent_series.id)) |
292 | - # Copy the source format selections |
293 | - cur.execute(''' |
294 | - INSERT INTO SourcePackageFormatSelection (distroseries, format) |
295 | - SELECT %s as distroseries, spfs.format AS format |
296 | - FROM SourcePackageFormatSelection AS spfs |
297 | - WHERE spfs.distroseries = %s |
298 | - ''' % sqlvalues(self.id, self.parent_series.id)) |
299 | - |
300 | - def _copy_packaging_links(self, cur): |
301 | - """Copy the packaging links from the parent series to this one.""" |
302 | - cur.execute(""" |
303 | - INSERT INTO |
304 | - Packaging( |
305 | - distroseries, sourcepackagename, productseries, |
306 | - packaging, owner) |
307 | - SELECT |
308 | - ChildSeries.id, |
309 | - Packaging.sourcepackagename, |
310 | - Packaging.productseries, |
311 | - Packaging.packaging, |
312 | - Packaging.owner |
313 | - FROM |
314 | - Packaging |
315 | - -- Joining the parent distroseries permits the query to build |
316 | - -- the data set for the series being updated, yet results are |
317 | - -- in fact the data from the original series. |
318 | - JOIN Distroseries ChildSeries |
319 | - ON Packaging.distroseries = ChildSeries.parent_series |
320 | - WHERE |
321 | - -- Select only the packaging links that are in the parent |
322 | - -- that are not in the child. |
323 | - ChildSeries.id = %s |
324 | - AND Packaging.sourcepackagename in ( |
325 | - SELECT sourcepackagename |
326 | - FROM Packaging |
327 | - WHERE distroseries in ( |
328 | - SELECT id |
329 | - FROM Distroseries |
330 | - WHERE id = ChildSeries.parent_series |
331 | - ) |
332 | - EXCEPT |
333 | - SELECT sourcepackagename |
334 | - FROM Packaging |
335 | - WHERE distroseries in ( |
336 | - SELECT id |
337 | - FROM Distroseries |
338 | - WHERE id = ChildSeries.id |
339 | - ) |
340 | - ) |
341 | - """ % self.id) |
342 | - |
343 | def copyTranslationsFromParent(self, transaction, logger=None): |
344 | """See `IDistroSeries`.""" |
345 | if logger is None: |
346 | |
347 | === modified file 'lib/lp/soyuz/doc/initialise-from-parent.txt' |
348 | --- lib/lp/soyuz/doc/initialise-from-parent.txt 2010-05-14 06:14:12 +0000 |
349 | +++ lib/lp/soyuz/doc/initialise-from-parent.txt 2010-08-13 01:50:16 +0000 |
350 | @@ -63,12 +63,9 @@ |
351 | DEBUG Check empty mutable queues in parentseries |
352 | DEBUG Check for no pending builds in parentseries |
353 | DEBUG Copying distroarchseries from parent and setting nominatedarchindep. |
354 | - Traceback (most recent call last): |
355 | - ... |
356 | - AssertionError: Can not copy distroarchseries from parent, there are already distroarchseries(s) initialised for this series. |
357 | + ERROR Can not copy distroarchseries from parent, there are already distroarchseries(s) initialised for this series. |
358 | <BLANKLINE> |
359 | |
360 | - |
361 | Let's initialise the just created distroseries: |
362 | |
363 | >>> process = subprocess.Popen([sys.executable, script, "-vv", |
364 | |
365 | === modified file 'lib/lp/soyuz/doc/soyuz-set-of-uploads.txt' |
366 | --- lib/lp/soyuz/doc/soyuz-set-of-uploads.txt 2010-07-12 13:06:41 +0000 |
367 | +++ lib/lp/soyuz/doc/soyuz-set-of-uploads.txt 2010-08-13 01:50:16 +0000 |
368 | @@ -70,6 +70,10 @@ |
369 | for the ubuntutest distribution. |
370 | |
371 | >>> from lp.registry.model.distribution import Distribution |
372 | + >>> from lp.registry.interfaces.pocket import PackagePublishingPocket |
373 | + >>> from lp.soyuz.interfaces.queue import PackageUploadStatus |
374 | + >>> from lp.soyuz.scripts.initialise_distroseries import ( |
375 | + ... InitialiseDistroSeries) |
376 | >>> from canonical.launchpad.database import LibraryFileAlias |
377 | >>> ubuntu = Distribution.byName('ubuntu') |
378 | >>> breezy_autotest = ubuntu['breezy-autotest'] |
379 | @@ -78,13 +82,11 @@ |
380 | ... 'breezy', 'Breezy Badger', 'The Breezy Badger', |
381 | ... 'Black and White', 'Someone', '5.10', breezy_autotest, |
382 | ... breezy_autotest.owner) |
383 | - >>> breezy_i386 = breezy.newArch( |
384 | - ... 'i386', breezy_autotest['i386'].processorfamily, True, breezy.owner) |
385 | - >>> breezy.nominatedarchindep = breezy_i386 |
386 | + >>> ids = InitialiseDistroSeries(breezy) |
387 | + >>> ids.initialise() |
388 | >>> breezy.changeslist = 'breezy-changes@ubuntu.com' |
389 | - >>> breezy.initialiseFromParent() |
390 | >>> fake_chroot = LibraryFileAlias.get(1) |
391 | - >>> unused = breezy_i386.addOrUpdateChroot(fake_chroot) |
392 | + >>> unused = breezy['i386'].addOrUpdateChroot(fake_chroot) |
393 | |
394 | Add disk content for file inherited from ubuntu/breezy-autotest: |
395 | |
396 | |
397 | === added file 'lib/lp/soyuz/scripts/initialise_distroseries.py' |
398 | --- lib/lp/soyuz/scripts/initialise_distroseries.py 1970-01-01 00:00:00 +0000 |
399 | +++ lib/lp/soyuz/scripts/initialise_distroseries.py 2010-08-13 01:50:16 +0000 |
400 | @@ -0,0 +1,256 @@ |
401 | +# Copyright 2009 Canonical Ltd. This software is licensed under the |
402 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
403 | + |
404 | +"""Initialise a distroseries from its parent distroseries.""" |
405 | + |
406 | + |
407 | +__metaclass__ = type |
408 | +__all__ = [ |
409 | + 'InitialisationError', |
410 | + 'InitialiseDistroSeries', |
411 | + ] |
412 | + |
413 | +from zope.component import getUtility |
414 | +from canonical.database.sqlbase import sqlvalues |
415 | +from canonical.launchpad.webapp.interfaces import ( |
416 | + IStoreSelector, MAIN_STORE, MASTER_FLAVOR) |
417 | + |
418 | +from lp.buildmaster.interfaces.buildbase import BuildStatus |
419 | +from lp.registry.interfaces.pocket import PackagePublishingPocket |
420 | +from lp.soyuz.adapters.packagelocation import PackageLocation |
421 | +from lp.soyuz.interfaces.archive import ArchivePurpose, IArchiveSet |
422 | +from lp.soyuz.interfaces.queue import PackageUploadStatus |
423 | +from lp.soyuz.model.packagecloner import clone_packages |
424 | + |
425 | + |
426 | +class InitialisationError(Exception): |
427 | + """Raised when there is an exception during the initialisation process.""" |
428 | + |
429 | + |
430 | +class InitialiseDistroSeries: |
431 | + """Copy in all of the parent distroseries's configuration. This |
432 | + includes all configuration for distroseries as well as distroarchseries, |
433 | + publishing and all publishing records for sources and binaries. |
434 | + |
435 | + Preconditions: |
436 | + The distroseries must exist, and be completly unused, with no source |
437 | + or binary packages existing, as well as no distroarchseries set up. |
438 | + Section and component selections must be empty. |
439 | + |
440 | + Outcome: |
441 | + The distroarchseries set up in the parent series will be copied. |
442 | + The publishing structure will be copied from the parent. All |
443 | + PUBLISHED and PENDING packages in the parent will be created in |
444 | + this distroseries and its distroarchseriess. The lucille config |
445 | + will be copied in, all component and section selections will be |
446 | + duplicated as will any permission-related structures. |
447 | + |
448 | + Note: |
449 | + This method will raise a InitialisationError when the pre-conditions |
450 | + are not met. After this is run, you still need to construct chroots |
451 | + for building, you need to add anything missing wrt. ports etc. This |
452 | + method is only meant to give you a basic copy of a parent series in |
453 | + order to assist you in preparing a new series of a distribution or |
454 | + in the initialisation of a derivative. |
455 | + """ |
456 | + |
457 | + def __init__(self, distroseries): |
458 | + self.distroseries = distroseries |
459 | + self.parent = self.distroseries.parent_series |
460 | + self._store = getUtility( |
461 | + IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR) |
462 | + |
463 | + def check(self): |
464 | + if self.parent is None: |
465 | + raise InitialisationError("Parent series required.") |
466 | + self._checkBuilds() |
467 | + self._checkQueue() |
468 | + self._checkSeries() |
469 | + |
470 | + def _checkBuilds(self): |
471 | + """Assert there are no pending builds for parent series. |
472 | + |
473 | + Only cares about the RELEASE pocket, which is the only one inherited |
474 | + via initialiseFromParent method. |
475 | + """ |
476 | + # only the RELEASE pocket is inherited, so we only check |
477 | + # pending build records for it. |
478 | + pending_builds = self.parent.getBuildRecords( |
479 | + BuildStatus.NEEDSBUILD, pocket=PackagePublishingPocket.RELEASE) |
480 | + |
481 | + if pending_builds.count(): |
482 | + raise InitialisationError("Parent series has pending builds.") |
483 | + |
484 | + def _checkQueue(self): |
485 | + """Assert upload queue is empty on parent series. |
486 | + |
487 | + Only cares about the RELEASE pocket, which is the only one inherited |
488 | + via initialiseFromParent method. |
489 | + """ |
490 | + # only the RELEASE pocket is inherited, so we only check |
491 | + # queue items for it. |
492 | + for queue in ( |
493 | + PackageUploadStatus.NEW, PackageUploadStatus.ACCEPTED, |
494 | + PackageUploadStatus.UNAPPROVED): |
495 | + items = self.parent.getQueueItems( |
496 | + queue, pocket=PackagePublishingPocket.RELEASE) |
497 | + if items: |
498 | + raise InitialisationError( |
499 | + "Parent series queues are not empty.") |
500 | + |
501 | + def _checkSeries(self): |
502 | + sources = self.distroseries.getAllPublishedSources() |
503 | + error = ( |
504 | + "Can not copy distroarchseries from parent, there are " |
505 | + "already distroarchseries(s) initialised for this series.") |
506 | + if sources.count(): |
507 | + raise InitialisationError(error) |
508 | + binaries = self.distroseries.getAllPublishedBinaries() |
509 | + if binaries.count(): |
510 | + raise InitialisationError(error) |
511 | + if self.distroseries.architectures.count(): |
512 | + raise InitialisationError(error) |
513 | + if self.distroseries.components.count(): |
514 | + raise InitialisationError(error) |
515 | + if self.distroseries.sections.count(): |
516 | + raise InitialisationError(error) |
517 | + |
518 | + def initialise(self): |
519 | + self._copy_architectures() |
520 | + self._copy_packages() |
521 | + |
522 | + def _copy_architectures(self): |
523 | + self._store.execute(""" |
524 | + INSERT INTO DistroArchSeries |
525 | + (distroseries, processorfamily, architecturetag, owner, official) |
526 | + SELECT %s, processorfamily, architecturetag, %s, official |
527 | + FROM DistroArchSeries WHERE distroseries = %s |
528 | + """ % sqlvalues(self.distroseries, self.distroseries.owner, |
529 | + self.parent)) |
530 | + |
531 | + self.distroseries.nominatedarchindep = self.distroseries[ |
532 | + self.parent.nominatedarchindep.architecturetag] |
533 | + |
534 | + def _copy_packages(self): |
535 | + # Perform the copies |
536 | + self._copy_component_section_and_format_selections() |
537 | + |
538 | + # Prepare the list of distroarchseries for which binary packages |
539 | + # shall be copied. |
540 | + distroarchseries_list = [] |
541 | + for arch in self.distroseries.architectures: |
542 | + parent_arch = self.parent[arch.architecturetag] |
543 | + distroarchseries_list.append((parent_arch, arch)) |
544 | + # Now copy source and binary packages. |
545 | + self._copy_publishing_records(distroarchseries_list) |
546 | + self._copy_lucille_config() |
547 | + self._copy_packaging_links() |
548 | + |
549 | + def _copy_lucille_config(self): |
550 | + """Copy all lucille related configuration from our parent series.""" |
551 | + self._store.execute(''' |
552 | + UPDATE DistroSeries SET lucilleconfig=( |
553 | + SELECT pdr.lucilleconfig FROM DistroSeries AS pdr |
554 | + WHERE pdr.id = %s) |
555 | + WHERE id = %s |
556 | + ''' % sqlvalues(self.parent.id, |
557 | + self.distroseries.id)) |
558 | + |
559 | + def _copy_publishing_records(self, distroarchseries_list): |
560 | + """Copy the publishing records from the parent arch series |
561 | + to the given arch series in ourselves. |
562 | + |
563 | + We copy all PENDING and PUBLISHED records as PENDING into our own |
564 | + publishing records. |
565 | + |
566 | + We copy only the RELEASE pocket in the PRIMARY and DEBUG archives. |
567 | + """ |
568 | + archive_set = getUtility(IArchiveSet) |
569 | + |
570 | + for archive in self.parent.distribution.all_distro_archives: |
571 | + if archive.purpose not in ( |
572 | + ArchivePurpose.PRIMARY, ArchivePurpose.DEBUG): |
573 | + continue |
574 | + |
575 | + target_archive = archive_set.getByDistroPurpose( |
576 | + self.distroseries.distribution, archive.purpose) |
577 | + if archive.purpose is ArchivePurpose.PRIMARY: |
578 | + assert target_archive is not None, ( |
579 | + "Target archive doesn't exist?") |
580 | + origin = PackageLocation( |
581 | + archive, self.parent.distribution, self.parent, |
582 | + PackagePublishingPocket.RELEASE) |
583 | + destination = PackageLocation( |
584 | + target_archive, self.distroseries.distribution, |
585 | + self.distroseries, PackagePublishingPocket.RELEASE) |
586 | + clone_packages(origin, destination, distroarchseries_list) |
587 | + |
588 | + def _copy_component_section_and_format_selections(self): |
589 | + """Copy the section, component and format selections from the parent |
590 | + distro series into this one. |
591 | + """ |
592 | + # Copy the component selections |
593 | + self._store.execute(''' |
594 | + INSERT INTO ComponentSelection (distroseries, component) |
595 | + SELECT %s AS distroseries, cs.component AS component |
596 | + FROM ComponentSelection AS cs WHERE cs.distroseries = %s |
597 | + ''' % sqlvalues(self.distroseries.id, |
598 | + self.parent.id)) |
599 | + # Copy the section selections |
600 | + self._store.execute(''' |
601 | + INSERT INTO SectionSelection (distroseries, section) |
602 | + SELECT %s as distroseries, ss.section AS section |
603 | + FROM SectionSelection AS ss WHERE ss.distroseries = %s |
604 | + ''' % sqlvalues(self.distroseries.id, |
605 | + self.parent.id)) |
606 | + # Copy the source format selections |
607 | + self._store.execute(''' |
608 | + INSERT INTO SourcePackageFormatSelection (distroseries, format) |
609 | + SELECT %s as distroseries, spfs.format AS format |
610 | + FROM SourcePackageFormatSelection AS spfs |
611 | + WHERE spfs.distroseries = %s |
612 | + ''' % sqlvalues(self.distroseries.id, |
613 | + self.parent.id)) |
614 | + |
615 | + def _copy_packaging_links(self): |
616 | + """Copy the packaging links from the parent series to this one.""" |
617 | + self._store.execute(""" |
618 | + INSERT INTO |
619 | + Packaging( |
620 | + distroseries, sourcepackagename, productseries, |
621 | + packaging, owner) |
622 | + SELECT |
623 | + ChildSeries.id, |
624 | + Packaging.sourcepackagename, |
625 | + Packaging.productseries, |
626 | + Packaging.packaging, |
627 | + Packaging.owner |
628 | + FROM |
629 | + Packaging |
630 | + -- Joining the parent distroseries permits the query to build |
631 | + -- the data set for the series being updated, yet results are |
632 | + -- in fact the data from the original series. |
633 | + JOIN Distroseries ChildSeries |
634 | + ON Packaging.distroseries = ChildSeries.parent_series |
635 | + WHERE |
636 | + -- Select only the packaging links that are in the parent |
637 | + -- that are not in the child. |
638 | + ChildSeries.id = %s |
639 | + AND Packaging.sourcepackagename in ( |
640 | + SELECT sourcepackagename |
641 | + FROM Packaging |
642 | + WHERE distroseries in ( |
643 | + SELECT id |
644 | + FROM Distroseries |
645 | + WHERE id = ChildSeries.parent_series |
646 | + ) |
647 | + EXCEPT |
648 | + SELECT sourcepackagename |
649 | + FROM Packaging |
650 | + WHERE distroseries in ( |
651 | + SELECT id |
652 | + FROM Distroseries |
653 | + WHERE id = ChildSeries.id |
654 | + ) |
655 | + ) |
656 | + """ % self.distroseries.id) |
657 | |
658 | === modified file 'scripts/ftpmaster-tools/initialise-from-parent.py' |
659 | --- scripts/ftpmaster-tools/initialise-from-parent.py 2010-08-02 02:13:52 +0000 |
660 | +++ scripts/ftpmaster-tools/initialise-from-parent.py 2010-08-13 01:50:16 +0000 |
661 | @@ -3,16 +3,7 @@ |
662 | # Copyright 2009 Canonical Ltd. This software is licensed under the |
663 | # GNU Affero General Public License version 3 (see the file LICENSE). |
664 | |
665 | -"""Initialise a new distroseries from its parent |
666 | - |
667 | -It performs two additional tasks before call initialiseFromParent: |
668 | - |
669 | -* check_queue (ensure parent's mutable queues are empty) |
670 | -* copy_architectures (copy parent's architectures and set |
671 | - nominatedarchindep properly) |
672 | - |
673 | -which eventually may be integrated in its workflow. |
674 | -""" |
675 | +"""Initialise a new distroseries from its parent series.""" |
676 | |
677 | import _pythonpath |
678 | |
679 | @@ -23,15 +14,14 @@ |
680 | from contrib.glock import GlobalLock |
681 | |
682 | from canonical.config import config |
683 | -from canonical.database.sqlbase import ( |
684 | - sqlvalues, flush_database_updates, cursor, flush_database_caches) |
685 | from canonical.launchpad.interfaces import IDistributionSet |
686 | from canonical.launchpad.scripts import ( |
687 | execute_zcml_for_scripts, logger, logger_options) |
688 | from canonical.lp import initZopeless |
689 | + |
690 | from lp.app.errors import NotFoundError |
691 | -from lp.soyuz.interfaces.queue import PackageUploadStatus |
692 | - |
693 | +from lp.soyuz.scripts.initialise_distroseries import ( |
694 | + InitialisationError, InitialiseDistroSeries) |
695 | |
696 | def main(): |
697 | # Parse command-line arguments |
698 | @@ -71,23 +61,21 @@ |
699 | distribution = getUtility(IDistributionSet)[options.distribution] |
700 | distroseries = distribution[distroseries_name] |
701 | except NotFoundError, info: |
702 | - log.error(info) |
703 | - return 1 |
704 | - |
705 | - # XXX cprov 2006-05-26: these two extra functions must be |
706 | - # integrated in IDistroSeries.initialiseFromParent workflow. |
707 | - log.debug('Check empty mutable queues in parentseries') |
708 | - check_queue(distroseries) |
709 | - |
710 | - log.debug('Check for no pending builds in parentseries') |
711 | - check_builds(distroseries) |
712 | - |
713 | - log.debug('Copying distroarchseries from parent ' |
714 | - 'and setting nominatedarchindep.') |
715 | - copy_architectures(distroseries) |
716 | - |
717 | - log.debug('initialising from parent, copying publishing records.') |
718 | - distroseries.initialiseFromParent() |
719 | + log.error('%s not found' % info) |
720 | + return 1 |
721 | + |
722 | + try: |
723 | + log.debug('Check empty mutable queues in parentseries') |
724 | + log.debug('Check for no pending builds in parentseries') |
725 | + log.debug('Copying distroarchseries from parent ' |
726 | + 'and setting nominatedarchindep.') |
727 | + ids = InitialiseDistroSeries(distroseries) |
728 | + ids.check() |
729 | + log.debug('initialising from parent, copying publishing records.') |
730 | + ids.initialise() |
731 | + except InitialisationError, e: |
732 | + log.error(e) |
733 | + return 1 |
734 | |
735 | if options.dryrun: |
736 | log.debug('Dry-Run mode, transaction aborted.') |
737 | @@ -101,79 +89,6 @@ |
738 | return 0 |
739 | |
740 | |
741 | -def check_builds(distroseries): |
742 | - """Assert there are no pending builds for parent series. |
743 | - |
744 | - Only cares about the RELEASE pocket, which is the only one inherited |
745 | - via initialiseFromParent method. |
746 | - """ |
747 | - # Avoid circular import. |
748 | - from lp.buildmaster.interfaces.buildbase import BuildStatus |
749 | - from lp.registry.interfaces.pocket import PackagePublishingPocket |
750 | - |
751 | - parentseries = distroseries.parent_series |
752 | - |
753 | - # only the RELEASE pocket is inherited, so we only check |
754 | - # pending build records for it. |
755 | - pending_builds = parentseries.getBuildRecords( |
756 | - BuildStatus.NEEDSBUILD, pocket=PackagePublishingPocket.RELEASE) |
757 | - |
758 | - assert pending_builds.count() == 0, ( |
759 | - 'Parent must not have PENDING builds') |
760 | - |
761 | -def check_queue(distroseries): |
762 | - """Assert upload queue is empty on parent series. |
763 | - |
764 | - Only cares about the RELEASE pocket, which is the only one inherited |
765 | - via initialiseFromParent method. |
766 | - """ |
767 | - # Avoid circular import. |
768 | - from lp.registry.interfaces.pocket import PackagePublishingPocket |
769 | - |
770 | - parentseries = distroseries.parent_series |
771 | - |
772 | - # only the RELEASE pocket is inherited, so we only check |
773 | - # queue items for it. |
774 | - new_items = parentseries.getQueueItems( |
775 | - PackageUploadStatus.NEW, |
776 | - pocket=PackagePublishingPocket.RELEASE) |
777 | - accepted_items = parentseries.getQueueItems( |
778 | - PackageUploadStatus.ACCEPTED, |
779 | - pocket=PackagePublishingPocket.RELEASE) |
780 | - unapproved_items = parentseries.getQueueItems( |
781 | - PackageUploadStatus.UNAPPROVED, |
782 | - pocket=PackagePublishingPocket.RELEASE) |
783 | - |
784 | - assert new_items.count() == 0, ( |
785 | - 'Parent NEW queue must be empty') |
786 | - assert accepted_items.count() == 0, ( |
787 | - 'Parent ACCEPTED queue must be empty') |
788 | - assert unapproved_items.count() == 0, ( |
789 | - 'Parent UNAPPROVED queue must be empty') |
790 | - |
791 | -def copy_architectures(distroseries): |
792 | - """Overlap SQLObject and copy architecture from the parent. |
793 | - |
794 | - Also set the nominatedarchindep properly in target. |
795 | - """ |
796 | - assert distroseries.architectures.count() is 0, ( |
797 | - "Can not copy distroarchseries from parent, there are already " |
798 | - "distroarchseries(s) initialised for this series.") |
799 | - flush_database_updates() |
800 | - cur = cursor() |
801 | - cur.execute(""" |
802 | - INSERT INTO DistroArchSeries |
803 | - (distroseries, processorfamily, architecturetag, owner, official) |
804 | - SELECT %s, processorfamily, architecturetag, %s, official |
805 | - FROM DistroArchSeries WHERE distroseries = %s |
806 | - """ % sqlvalues(distroseries, distroseries.owner, |
807 | - distroseries.parent_series)) |
808 | - flush_database_caches() |
809 | - |
810 | - distroseries.nominatedarchindep = distroseries[ |
811 | - distroseries.parent_series.nominatedarchindep.architecturetag] |
812 | - |
813 | - |
814 | if __name__ == '__main__': |
815 | sys.exit(main()) |
816 | |
817 | |
818 | === modified file 'utilities/soyuz-sampledata-setup.py' |
819 | --- utilities/soyuz-sampledata-setup.py 2010-07-09 15:19:10 +0000 |
820 | +++ utilities/soyuz-sampledata-setup.py 2010-08-13 01:50:16 +0000 |
821 | @@ -59,6 +59,7 @@ |
822 | ISourcePackageFormatSelectionSet, SourcePackageFormat) |
823 | from lp.soyuz.model.section import SectionSelection |
824 | from lp.soyuz.model.component import ComponentSelection |
825 | +from lp.soyuz.scripts.initialise_distroseries import InitialiseDistroSeries |
826 | from lp.testing.factory import LaunchpadObjectFactory |
827 | |
828 | |
829 | @@ -235,24 +236,8 @@ |
830 | new_series.status = status |
831 | notify(ObjectCreatedEvent(new_series)) |
832 | |
833 | - # This bit copied from scripts/ftpmaster-tools/initialise-from-parent.py. |
834 | - assert new_series.architectures.count() == 0, ( |
835 | - "Cannot copy distroarchseries from parent; this series already has " |
836 | - "distroarchseries.") |
837 | - |
838 | - store = Store.of(parent) |
839 | - store.execute(""" |
840 | - INSERT INTO DistroArchSeries |
841 | - (distroseries, processorfamily, architecturetag, owner, official) |
842 | - SELECT %s, processorfamily, architecturetag, %s, official |
843 | - FROM DistroArchSeries WHERE distroseries = %s |
844 | - """ % sqlvalues(new_series, owner, parent)) |
845 | - |
846 | - i386 = new_series.getDistroArchSeries('i386') |
847 | - i386.supports_virtualized = True |
848 | - new_series.nominatedarchindep = i386 |
849 | - |
850 | - new_series.initialiseFromParent() |
851 | + ids = InitialiseDistroSeries(new_series) |
852 | + ids.initialise() |
853 | return new_series |
854 | |
855 |
Please add a docstring to InitialiseDistr oSeries, perhaps based on the docstring for the original initialiseFromP arent() .
The module docstring of scripts/ ftpmaster- tools/initialis e-from- parent. py misses a tail dot.
I think the name InitialiseDistr oSeries is a bit confusing (but the same applied to initialiseFromP arent) as it suggests to me that it takes care of doing all of the initialization of the DistroSeries, not just the Soyuzy bits. I don't have any good suggestions, perhaps something like SetupDistroSeri esPackaging ?