Merge lp:~cjwatson/launchpad/remove-query-distro-pending-suites into lp:launchpad

Proposed by Colin Watson on 2012-04-16
Status: Merged
Approved by: Jeroen T. Vermeulen on 2012-04-16
Approved revision: no longer in the source branch.
Merged at revision: 15103
Proposed branch: lp:~cjwatson/launchpad/remove-query-distro-pending-suites
Merge into: lp:launchpad
Diff against target: 428 lines (+54/-147)
7 files modified
lib/lp/archivepublisher/scripts/publish_ftpmaster.py (+18/-16)
lib/lp/archivepublisher/tests/test_publish_ftpmaster.py (+17/-9)
lib/lp/soyuz/interfaces/publishing.py (+3/-0)
lib/lp/soyuz/scripts/querydistro.py (+1/-76)
lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/scripts/ftpmaster-tools/lp-query-distro.py (+4/-8)
lib/lp/soyuz/scripts/tests/test_lpquerydistro.py (+11/-33)
scripts/ftpmaster-tools/lp-query-distro.py (+0/-5)
To merge this branch: bzr merge lp:~cjwatson/launchpad/remove-query-distro-pending-suites
Reviewer Review Type Date Requested Status
Jeroen T. Vermeulen (community) 2012-04-16 Approve on 2012-04-16
Review via email: mp+102129@code.launchpad.net

Commit Message

Re-land r15073 (LpQueryDistro clean-up), this time with correct load_related handling.

Description of the Change

== Summary ==

Fix regression caused by r15073, as outlined in bug 983165.

The bulk-loading suggested by Jeroen in https://code.launchpad.net/~cjwatson/launchpad/remove-query-distro-pending-suites/+merge/101174 broke, partly because I didn't notice that no tests would exercise this and partly because I cavalierly thought no QA was needed. I believe that this fixes it properly.

== Tests ==

bin/test -vvct getDirtySuites

== Demo and Q/A ==

Let's actually do some this time. I think it should be sufficient to upload a modified hello source package to dogfood/ubuntu/oneiric, wait for it to build on i386, and attempt to publish both source and binary.

To post a comment you must log in.
Jeroen T. Vermeulen (jtv) wrote :

Looks fine!

One very very small thing:

lib/lp/soyuz/interfaces/publishing.py

 724 distroarchseriesID = Int(
 725 title=_('The DB id for the distroarchseries.'),
 726 required=False, readonly=False)

I highly recommend double quotes for free-form text. It avoids widespread panic and looting as apostrophes destroy civilization.

Jeroen

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/archivepublisher/scripts/publish_ftpmaster.py'
2--- lib/lp/archivepublisher/scripts/publish_ftpmaster.py 2012-04-16 10:04:33 +0000
3+++ lib/lp/archivepublisher/scripts/publish_ftpmaster.py 2012-04-16 15:51:23 +0000
4@@ -21,16 +21,20 @@
5 from lp.registry.interfaces.pocket import pocketsuffix
6 from lp.registry.interfaces.series import SeriesStatus
7 from lp.services.config import config
8+from lp.services.database.bulk import load_related
9 from lp.services.scripts.base import (
10 LaunchpadCronScript,
11 LaunchpadScriptFailure,
12 )
13 from lp.services.utils import file_exists
14-from lp.soyuz.enums import ArchivePurpose
15+from lp.soyuz.enums import (
16+ ArchivePurpose,
17+ PackagePublishingStatus,
18+ )
19+from lp.soyuz.model.distroarchseries import DistroArchSeries
20 from lp.soyuz.scripts.custom_uploads_copier import CustomUploadsCopier
21 from lp.soyuz.scripts.processaccepted import ProcessAccepted
22 from lp.soyuz.scripts.publishdistro import PublishDistro
23-from lp.soyuz.scripts.querydistro import LpQueryDistro
24
25
26 def get_publishable_archives(distribution):
27@@ -121,13 +125,6 @@
28 return {"PATH": '"$PATH":%s' % shell_quote(scripts_dir)}
29
30
31-class StoreArgument:
32- """Helper class: receive argument and store it."""
33-
34- def __call__(self, argument):
35- self.argument = argument
36-
37-
38 def find_run_parts_dir(distro, parts):
39 """Find the requested run-parts directory, if it exists."""
40 run_parts_location = config.archivepublisher.run_parts_location
41@@ -327,14 +324,19 @@
42 script.main()
43
44 def getDirtySuites(self, distribution):
45- """Return list of suites that have packages pending publication."""
46+ """Return set of suites that have packages pending publication."""
47 self.logger.debug("Querying which suites are pending publication...")
48- query_distro = LpQueryDistro(
49- test_args=['-d', distribution.name, "pending_suites"],
50- logger=self.logger)
51- receiver = StoreArgument()
52- query_distro.runAction(presenter=receiver)
53- return receiver.argument.split()
54+
55+ archive = distribution.main_archive
56+ pending = PackagePublishingStatus.PENDING
57+ pending_sources = list(archive.getPublishedSources(status=pending))
58+ pending_binaries = list(archive.getAllPublishedBinaries(
59+ status=pending))
60+ load_related(
61+ DistroArchSeries, pending_binaries, ['distroarchseriesID'])
62+ return set(
63+ pub.distroseries.name + pocketsuffix[pub.pocket]
64+ for pub in pending_sources + pending_binaries)
65
66 def getDirtySecuritySuites(self, distribution):
67 """List security suites with pending publications."""
68
69=== modified file 'lib/lp/archivepublisher/tests/test_publish_ftpmaster.py'
70--- lib/lp/archivepublisher/tests/test_publish_ftpmaster.py 2012-04-16 10:04:33 +0000
71+++ lib/lp/archivepublisher/tests/test_publish_ftpmaster.py 2012-04-16 15:51:23 +0000
72@@ -1,4 +1,4 @@
73-# Copyright 2011 Canonical Ltd. This software is licensed under the
74+# Copyright 2011-2012 Canonical Ltd. This software is licensed under the
75 # GNU Affero General Public License version 3 (see the file LICENSE).
76
77 """Test publish-ftpmaster cron script."""
78@@ -63,9 +63,9 @@
79 return file_exists(os.path.join(*path_components))
80
81
82-def name_spph_suite(spph):
83- """Return name of `spph`'s suite."""
84- return spph.distroseries.name + pocketsuffix[spph.pocket]
85+def name_pph_suite(pph):
86+ """Return name of `pph`'s suite."""
87+ return pph.distroseries.name + pocketsuffix[pph.pocket]
88
89
90 def get_pub_config(distro):
91@@ -400,8 +400,8 @@
92 distro = spph.distroseries.distribution
93 script = self.makeScript(spph.distroseries.distribution)
94 script.setUp()
95- self.assertEqual(
96- [name_spph_suite(spph)], script.getDirtySuites(distro))
97+ self.assertContentEqual(
98+ [name_pph_suite(spph)], script.getDirtySuites(distro))
99
100 def test_getDirtySuites_returns_suites_with_pending_publications(self):
101 distro = self.makeDistroWithPublishDirectory()
102@@ -414,7 +414,7 @@
103 script = self.makeScript(distro)
104 script.setUp()
105 self.assertContentEqual(
106- [name_spph_suite(spph) for spph in spphs],
107+ [name_pph_suite(spph) for spph in spphs],
108 script.getDirtySuites(distro))
109
110 def test_getDirtySuites_ignores_suites_without_pending_publications(self):
111@@ -423,7 +423,15 @@
112 distro = spph.distroseries.distribution
113 script = self.makeScript(spph.distroseries.distribution)
114 script.setUp()
115- self.assertEqual([], script.getDirtySuites(distro))
116+ self.assertContentEqual([], script.getDirtySuites(distro))
117+
118+ def test_getDirtySuites_returns_suites_with_pending_binaries(self):
119+ bpph = self.factory.makeBinaryPackagePublishingHistory()
120+ distro = bpph.distroseries.distribution
121+ script = self.makeScript(bpph.distroseries.distribution)
122+ script.setUp()
123+ self.assertContentEqual(
124+ [name_pph_suite(bpph)], script.getDirtySuites(distro))
125
126 def test_getDirtySecuritySuites_returns_security_suites(self):
127 distro = self.makeDistroWithPublishDirectory()
128@@ -437,7 +445,7 @@
129 script = self.makeScript(distro)
130 script.setUp()
131 self.assertContentEqual(
132- [name_spph_suite(spph) for spph in spphs],
133+ [name_pph_suite(spph) for spph in spphs],
134 script.getDirtySecuritySuites(distro))
135
136 def test_getDirtySecuritySuites_ignores_non_security_suites(self):
137
138=== modified file 'lib/lp/soyuz/interfaces/publishing.py'
139--- lib/lp/soyuz/interfaces/publishing.py 2012-01-09 13:40:48 +0000
140+++ lib/lp/soyuz/interfaces/publishing.py 2012-04-16 15:51:23 +0000
141@@ -721,6 +721,9 @@
142 required=False, readonly=False)
143 binarypackagerelease = Attribute(
144 "The binary package release being published")
145+ distroarchseriesID = Int(
146+ title=_("The DB id for the distroarchseries."),
147+ required=False, readonly=False)
148 distroarchseries = exported(
149 Reference(
150 # Really IDistroArchSeries (fixed in
151
152=== modified file 'lib/lp/soyuz/scripts/querydistro.py'
153--- lib/lp/soyuz/scripts/querydistro.py 2012-04-16 10:04:33 +0000
154+++ lib/lp/soyuz/scripts/querydistro.py 2012-04-16 15:51:23 +0000
155@@ -7,7 +7,6 @@
156
157 __all__ = ['LpQueryDistro']
158
159-from lp.registry.interfaces.pocket import pocketsuffix
160 from lp.registry.interfaces.series import SeriesStatus
161 from lp.services.scripts.base import (
162 LaunchpadScript,
163@@ -17,7 +16,6 @@
164 build_package_location,
165 PackageLocationError,
166 )
167-from lp.soyuz.enums import PackagePublishingStatus
168
169
170 class LpQueryDistro(LaunchpadScript):
171@@ -28,9 +26,7 @@
172
173 Also initialize the list 'allowed_arguments'.
174 """
175- self.allowed_actions = [
176- 'current', 'development', 'supported', 'pending_suites', 'archs',
177- 'official_archs', 'nominated_arch_indep', 'pocket_suffixes']
178+ self.allowed_actions = ['development', 'supported', 'archs']
179 self.usage = '%%prog <%s>' % ' | '.join(self.allowed_actions)
180 LaunchpadScript.__init__(self, *args, **kwargs)
181
182@@ -122,23 +118,6 @@
183 "Action does not accept defined suite.")
184
185 @property
186- def current(self):
187- """Return the name of the CURRENT distroseries.
188-
189- It is restricted for the context distribution.
190-
191- It may raise LaunchpadScriptFailure if a suite was passed on the
192- command-line or if not CURRENT distroseries was found.
193- """
194- self.checkNoSuiteDefined()
195- series = self.location.distribution.getSeriesByStatus(
196- SeriesStatus.CURRENT)
197- if not series:
198- raise LaunchpadScriptFailure("No CURRENT series.")
199-
200- return series[0].name
201-
202- @property
203 def development(self):
204 """Return the name of the DEVELOPMENT distroseries.
205
206@@ -197,28 +176,6 @@
207 return " ".join(supported_series)
208
209 @property
210- def pending_suites(self):
211- """Return the suite names containing PENDING publication.
212-
213- It check for sources and/or binary publications.
214- """
215- self.checkNoSuiteDefined()
216- pending_suites = set()
217- pending_sources = self.location.archive.getPublishedSources(
218- status=PackagePublishingStatus.PENDING)
219- for pub in pending_sources:
220- pending_suites.add((pub.distroseries, pub.pocket))
221-
222- pending_binaries = self.location.archive.getAllPublishedBinaries(
223- status=PackagePublishingStatus.PENDING)
224- for pub in pending_binaries:
225- pending_suites.add(
226- (pub.distroarchseries.distroseries, pub.pocket))
227-
228- return " ".join([distroseries.name + pocketsuffix[pocket]
229- for distroseries, pocket in pending_suites])
230-
231- @property
232 def archs(self):
233 """Return a space-separated list of architecture tags.
234
235@@ -226,35 +183,3 @@
236 """
237 architectures = self.location.distroseries.architectures
238 return " ".join(arch.architecturetag for arch in architectures)
239-
240- @property
241- def official_archs(self):
242- """Return a space-separated list of official architecture tags.
243-
244- It is restricted to the context distribution and suite.
245- """
246- architectures = self.location.distroseries.architectures
247- return " ".join(arch.architecturetag
248- for arch in architectures
249- if arch.official)
250-
251- @property
252- def nominated_arch_indep(self):
253- """Return the nominated arch indep architecture tag.
254-
255- It is restricted to the context distribution and suite.
256- """
257- series = self.location.distroseries
258- return series.nominatedarchindep.architecturetag
259-
260- @property
261- def pocket_suffixes(self):
262- """Return a space-separated list of non-empty pocket suffixes.
263-
264- The RELEASE pocket (whose suffix is the empty string) is omitted.
265-
266- The returned space-separated string is ordered alphabetically.
267- """
268- sorted_non_empty_suffixes = sorted(
269- suffix for suffix in pocketsuffix.values() if suffix != '')
270- return " ".join(sorted_non_empty_suffixes)
271
272=== modified file 'lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/scripts/ftpmaster-tools/lp-query-distro.py'
273--- lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/scripts/ftpmaster-tools/lp-query-distro.py 2012-04-16 10:04:33 +0000
274+++ lib/lp/soyuz/scripts/tests/germinate-test-data/mock-lp-root/scripts/ftpmaster-tools/lp-query-distro.py 2012-04-16 15:51:23 +0000
275@@ -8,8 +8,8 @@
276
277
278 def error_and_exit():
279- sys.stderr.write("ERROR: I'm a mock, I only support 'development' "
280- "and 'supported' as argument\n")
281+ sys.stderr.write("ERROR: I'm a mock, I only support 'supported' as "
282+ "argument\n")
283 sys.exit(1)
284
285
286@@ -18,12 +18,8 @@
287 # test for it and error if it looks wrong
288 if len(args) == 2:
289 distro = args[1]
290- if distro == "development":
291- return "natty"
292- elif distro == "supported":
293- return "hardy jaunty karmic lucid maverick"
294- elif len(args) == 4 and args[1] == '-s' and args[3] == 'archs':
295- return "i386 amd64 powerpc armel"
296+ if distro == "supported":
297+ return "hardy jaunty karmic lucid maverick"
298 error_and_exit()
299
300
301
302=== modified file 'lib/lp/soyuz/scripts/tests/test_lpquerydistro.py'
303--- lib/lp/soyuz/scripts/tests/test_lpquerydistro.py 2012-04-16 10:04:33 +0000
304+++ lib/lp/soyuz/scripts/tests/test_lpquerydistro.py 2012-04-16 15:51:23 +0000
305@@ -50,15 +50,15 @@
306 Check that:
307 * return code is ZERO,
308 * standard error is empty
309- * standard output contains only the 'current distroseries' name
310+ * standard output contains only the 'development distroseries' name
311 """
312 returncode, out, err = self.runLpQueryDistro(
313- extra_args=['current'])
314+ extra_args=['development'])
315
316 self.assertEqual(
317 0, returncode, "\nScript Failed:%s\nStdout:\n%s\nStderr\n%s\n"
318 % (returncode, out, err))
319- self.assertEqual(out.strip(), 'warty')
320+ self.assertEqual(out.strip(), 'hoary')
321 self.assertEqual(err.strip(), '')
322
323 def testMissingAction(self):
324@@ -108,7 +108,7 @@
325 * standard error contains additional information about the failure.
326 """
327 returncode, out, err = self.runLpQueryDistro(
328- extra_args=['-s', 'hoary', 'current'])
329+ extra_args=['-s', 'warty', 'development'])
330
331 self.assertEqual(
332 1, returncode,
333@@ -140,15 +140,6 @@
334 """
335 self.test_output = '%s' % args
336
337- def testSuccessfullyAction(self):
338- """Check if the 'current' action is executed sucessfully."""
339- helper = self.getLpQueryDistro(test_args=['current'])
340- helper.runAction(presenter=self.presenter)
341- warty = self.ubuntu['warty']
342- self.assertEqual(warty.status.name, 'CURRENT')
343- self.assertEqual(helper.location.distribution.name, u'ubuntu')
344- self.assertEqual(self.test_output, u'warty')
345-
346 def testDevelopmentAndFrozenDistroSeries(self):
347 """The 'development' action should cope with FROZEN distroseries."""
348 helper = self.getLpQueryDistro(test_args=['development'])
349@@ -185,7 +176,8 @@
350 Some actions do not allow passing 'suite'.
351 See testActionswithDefinedSuite for further information.
352 """
353- helper = self.getLpQueryDistro(test_args=['-s', 'hoary', 'current'])
354+ helper = self.getLpQueryDistro(
355+ test_args=['-s', 'warty', 'development'])
356 self.assertRaises(LaunchpadScriptFailure,
357 helper.runAction, self.presenter)
358
359@@ -213,23 +205,16 @@
360 def testActionsWithUndefinedSuite(self):
361 """Check the actions supposed to work with undefined suite.
362
363- Only 'current', 'development' and 'supported' work with undefined
364- suite.
365- The other actions ('archs', 'official_arch', 'nominated_arch_indep')
366- will assume the CURRENT distroseries in context.
367+ Only 'development' and 'supported' work with undefined suite.
368+ The other actions ('archs') will assume the CURRENT distroseries in
369+ context.
370 """
371 helper = self.getLpQueryDistro(test_args=[])
372 helper._buildLocation()
373
374- self.assertEqual(helper.current, 'warty')
375 self.assertEqual(helper.development, 'hoary')
376 self.assertEqual(helper.supported, 'hoary warty')
377- self.assertEqual(helper.pending_suites, 'warty')
378 self.assertEqual(helper.archs, 'hppa i386')
379- self.assertEqual(helper.official_archs, 'i386')
380- self.assertEqual(helper.nominated_arch_indep, 'i386')
381- self.assertEqual(helper.pocket_suffixes,
382- '-backports -proposed -security -updates')
383
384 def assertAttributeRaisesScriptFailure(self, obj, attr_name):
385 """Asserts if accessing the given attribute name fails.
386@@ -242,20 +227,13 @@
387 def testActionsWithDefinedSuite(self):
388 """Opposite of testActionsWithUndefinedSuite.
389
390- Only some actions ('archs', 'official_arch', 'nominated_arch_indep',
391- and pocket_suffixes) work with defined suite, the other actions
392- ('current', 'development' and 'supported') will raise
393+ Only some actions ('archs') work with defined suite, the other
394+ actions ('development' and 'supported') will raise
395 LaunchpadScriptError if the suite is defined.
396 """
397 helper = self.getLpQueryDistro(test_args=['-s', 'warty'])
398 helper._buildLocation()
399
400- self.assertAttributeRaisesScriptFailure(helper, 'current')
401 self.assertAttributeRaisesScriptFailure(helper, 'development')
402 self.assertAttributeRaisesScriptFailure(helper, 'supported')
403- self.assertAttributeRaisesScriptFailure(helper, 'pending_suites')
404 self.assertEqual(helper.archs, 'hppa i386')
405- self.assertEqual(helper.official_archs, 'i386')
406- self.assertEqual(helper.nominated_arch_indep, 'i386')
407- self.assertEqual(helper.pocket_suffixes,
408- '-backports -proposed -security -updates')
409
410=== modified file 'scripts/ftpmaster-tools/lp-query-distro.py'
411--- scripts/ftpmaster-tools/lp-query-distro.py 2012-04-16 10:04:33 +0000
412+++ scripts/ftpmaster-tools/lp-query-distro.py 2012-04-16 15:51:23 +0000
413@@ -9,15 +9,10 @@
414 It should provide an easy way to retrieve current information from
415 Launchpad when using plain shell scripts, for example:
416
417- * CURRENT distroseries name: `./ubuntu-helper.py -d ubuntu current`
418 * DEVELOPMENT distroseries name:
419 `./ubuntu-helper.py -d ubuntu development`
420 * Distroseries architectures:
421 `./lp-query-distro.py -d ubuntu -s feisty archs`
422- * Distroseries official architectures:
423- `./lp-query-distro.py -d ubuntu -s feisty official_archs`
424- * Distroseries nominated-arch-indep:
425- `./lp-query-distro.py -d ubuntu -s feisty nominated_arch_indep`
426
427 Standard Output will carry the successfully executed information and
428 exit_code will be ZERO.