Merge lp:~jtv/launchpad/bug-779701 into lp:launchpad

Proposed by Jeroen T. Vermeulen
Status: Merged
Approved by: Jeroen T. Vermeulen
Approved revision: no longer in the source branch.
Merged at revision: 13002
Proposed branch: lp:~jtv/launchpad/bug-779701
Merge into: lp:launchpad
Diff against target: 349 lines (+137/-76)
2 files modified
lib/lp/archivepublisher/scripts/publish_ftpmaster.py (+33/-29)
lib/lp/archivepublisher/tests/test_publish_ftpmaster.py (+104/-47)
To merge this branch: bzr merge lp:~jtv/launchpad/bug-779701
Reviewer Review Type Date Requested Status
Henning Eggers (community) code Approve
Review via email: mp+60346@code.launchpad.net

Commit message

[r=henninge][bug=779701] Create distroseries indexes per suite.

Description of the change

The new, python-based publish-ftpmaster script will create archive indexes for a new distroseries. In the Ubuntu release process this removes a manual "publish-distro.py -A" run for the distroseries. However we want the indexes for each suite in the series created separately, with a separate publish-distro run. This will make it easier to add pockets in the future, for instance. Index creation should be tracked separately for each suite.

This branch makes the index-creation code use the suite name instead of the distroseries name for the marker files that indicate that indexes have been created. It then runs publish-distro separately for each suite.

To test:
{{{
./bin/test -vvc lp.archivepublisher.tests.test_publish_ftpmaster
}}}

To Q/A:
 * Create a new distroseries for an existing distribution.
 * Run cronscripts/publish-ftpmaster.py -d <distro> -s <series>.
 * See that indexes have been created.
 * Note marker files in the distribution's archive root, one for each suites.

(The marker files are dot files, so may not show up by default).

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/archivepublisher/scripts/publish_ftpmaster.py
  lib/lp/archivepublisher/tests/test_publish_ftpmaster.py

To post a comment you must log in.
Revision history for this message
Henning Eggers (henninge) wrote :

Thank you for this nice improvement. All I have to add is this:

- Consider using a local factory method for the frozen distro series that also explains why it needs to be frozen.

- The test naming is inconsistent. You used the right convention for the new tests but left the old ones as they were. Would be nice if you could update those, too, where applicable (test_methodName_condition).

Cheers,
Henning

review: Approve (code)
Revision history for this message
Jeroen T. Vermeulen (jtv) wrote :

Thanks. Implemented the changes.

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 2011-05-06 03:10:14 +0000
3+++ lib/lp/archivepublisher/scripts/publish_ftpmaster.py 2011-05-09 10:48:36 +0000
4@@ -228,19 +228,18 @@
5 (archive.purpose, getPubConfig(archive))
6 for archive in self.archives)
7
8- def locateIndexesMarker(self, distroseries):
9+ def locateIndexesMarker(self, suite):
10 """Give path for marker file whose presence marks index creation.
11
12- The file will be created once the archive indexes for
13- `distroseries` have been created. This is how future runs will
14- know that this work is done.
15+ The file will be created once the archive indexes for `suite`
16+ have been created. This is how future runs will know that this
17+ work is done.
18 """
19 archive_root = self.configs[ArchivePurpose.PRIMARY].archiveroot
20- return os.path.join(
21- archive_root, ".created-indexes-for-%s" % distroseries.name)
22+ return os.path.join(archive_root, ".created-indexes-for-%s" % suite)
23
24- def needsIndexesCreated(self, distroseries):
25- """Does `distroseries` still need its archive indexes created?
26+ def listSuitesNeedingIndexes(self, distroseries):
27+ """Find suites in `distroseries` that need indexes created.
28
29 Checks for the marker left by `markIndexCreationComplete`.
30 """
31@@ -249,36 +248,39 @@
32 # is in any other state yet has not been marked as having
33 # its indexes created, that's because it predates automatic
34 # index creation.
35- return False
36+ return []
37 distro = distroseries.distribution
38 publisher_config_set = getUtility(IPublisherConfigSet)
39 if publisher_config_set.getByDistribution(distro) is None:
40 # We won't be able to do a thing without a publisher config,
41 # but that's alright: we have those for all distributions
42 # that we want to publish.
43- return False
44- return not file_exists(self.locateIndexesMarker(distroseries))
45-
46- def markIndexCreationComplete(self, distroseries):
47- """Note that archive indexes for `distroseries` have been created.
48-
49- This tells `needsIndexesCreated` that no, this series no longer needs
50- archive indexes to be set up.
51+ return []
52+
53+ # May need indexes for this series.
54+ suites = [
55+ distroseries.getSuite(pocket)
56+ for pocket in pocketsuffix.iterkeys()]
57+ return [
58+ suite for suite in suites
59+ if not file_exists(self.locateIndexesMarker(suite))]
60+
61+ def markIndexCreationComplete(self, suite):
62+ """Note that archive indexes for `suite` have been created.
63+
64+ This tells `listSuitesNeedingIndexes` that no, this suite no
65+ longer needs archive indexes to be set up.
66 """
67- with file(self.locateIndexesMarker(distroseries), "w") as marker:
68+ with file(self.locateIndexesMarker(suite), "w") as marker:
69 marker.write(
70 "Indexes for %s were created on %s.\n"
71- % (distroseries, datetime.now(utc)))
72+ % (suite, datetime.now(utc)))
73
74- def createIndexes(self, distroseries):
75+ def createIndexes(self, suite):
76 """Create archive indexes for `distroseries`."""
77- self.logger.info(
78- "Creating archive indexes for series %s.", distroseries)
79- suites = [
80- distroseries.getSuite(pocket)
81- for pocket in pocketsuffix.iterkeys()]
82- self.runPublishDistro(args=['-A'], suites=suites)
83- self.markIndexCreationComplete(distroseries)
84+ self.logger.info("Creating archive indexes for %s.", suite)
85+ self.runPublishDistro(args=['-A'], suites=[suite])
86+ self.markIndexCreationComplete(suite)
87
88 def processAccepted(self):
89 """Run the process-accepted script."""
90@@ -556,8 +558,10 @@
91 self.recoverWorkingDists()
92
93 for series in self.distribution.series:
94- if self.needsIndexesCreated(series):
95- self.createIndexes(series)
96+ suites_needing_indexes = self.listSuitesNeedingIndexes(series)
97+ if len(suites_needing_indexes) > 0:
98+ for suite in suites_needing_indexes:
99+ self.createIndexes(suite)
100 # Don't try to do too much in one run. Leave the rest
101 # of the work for next time.
102 return
103
104=== modified file 'lib/lp/archivepublisher/tests/test_publish_ftpmaster.py'
105--- lib/lp/archivepublisher/tests/test_publish_ftpmaster.py 2011-05-06 03:10:14 +0000
106+++ lib/lp/archivepublisher/tests/test_publish_ftpmaster.py 2011-05-09 10:48:36 +0000
107@@ -108,6 +108,19 @@
108 return file(os.path.join(*path)).read()
109
110
111+def get_a_suite(distroseries):
112+ """Return some suite name for `distroseries`."""
113+ # Don't pick Release; it's too easy.
114+ return distroseries.getSuite(PackagePublishingPocket.SECURITY)
115+
116+
117+def get_marker_files(script, distroseries):
118+ suites = [
119+ distroseries.getSuite(pocket)
120+ for pocket in pocketsuffix.iterkeys()]
121+ return [script.locateIndexesMarker(suite) for suite in suites]
122+
123+
124 class HelpersMixin:
125 """Helpers for the PublishFTPMaster tests."""
126
127@@ -769,58 +782,90 @@
128
129 def createIndexesMarkerDir(self, script, distroseries):
130 """Create the directory for `distroseries`'s indexes marker."""
131- marker = script.locateIndexesMarker(distroseries)
132+ marker = script.locateIndexesMarker(get_a_suite(distroseries))
133 os.makedirs(os.path.dirname(marker))
134
135- def test_new_frozen_series_needs_indexes_created(self):
136+ def makeDistroSeriesNeedingIndexes(self, distribution=None):
137+ """Create `DistroSeries` that needs indexes created."""
138+ return self.factory.makeDistroSeries(
139+ status=SeriesStatus.FROZEN, distribution=distribution)
140+
141+ def test_listSuitesNeedingIndexes_is_nonempty_for_new_frozen_series(self):
142 # If a distroseries is Frozen and has not had its indexes
143- # created yet, needsIndexesCreated returns True for it.
144- series = self.factory.makeDistroSeries(status=SeriesStatus.FROZEN)
145- script = self.makeScript(series.distribution)
146- script.setUp()
147- self.assertTrue(script.needsIndexesCreated(series))
148-
149- def test_new_nonfrozen_series_does_not_need_indexes_created(self):
150- # needsIndexesCreated only returns True for Frozen distroseries.
151+ # created yet, listSuitesNeedingIndexes returns a nonempty list
152+ # for it.
153+ series = self.makeDistroSeriesNeedingIndexes()
154+ script = self.makeScript(series.distribution)
155+ script.setUp()
156+ self.assertNotEqual([], list(script.listSuitesNeedingIndexes(series)))
157+
158+ def test_listSuitesNeedingIndexes_initially_includes_entire_series(self):
159+ # If a series has not had any of its indexes created yet,
160+ # listSuitesNeedingIndexes returns all of its suites.
161+ series = self.makeDistroSeriesNeedingIndexes()
162+ script = self.makeScript(series.distribution)
163+ script.setUp()
164+ self.assertContentEqual(
165+ [series.getSuite(pocket) for pocket in pocketsuffix.iterkeys()],
166+ script.listSuitesNeedingIndexes(series))
167+
168+ def test_listSuitesNeedingIndexes_is_empty_for_nonfrozen_series(self):
169+ # listSuitesNeedingIndexes only returns suites for Frozen
170+ # distroseries.
171 series = self.factory.makeDistroSeries()
172 script = self.makeScript(series.distribution)
173- self.assertFalse(script.needsIndexesCreated(series))
174+ self.assertEqual([], script.listSuitesNeedingIndexes(series))
175
176- def test_distro_without_publisher_config_gets_no_indexes(self):
177- # needsIndexesCreated returns False for distributions that have
178- # no publisher config, such as Debian. We don't want to publish
179- # these distributions.
180- series = self.factory.makeDistroSeries(status=SeriesStatus.FROZEN)
181+ def test_listSuitesNeedingIndexes_is_empty_for_configless_distro(self):
182+ # listSuitesNeedingIndexes returns no suites for distributions
183+ # that have no publisher config, such as Debian. We don't want
184+ # to publish such distributions.
185+ series = self.makeDistroSeriesNeedingIndexes()
186 pub_config = get_pub_config(series.distribution)
187 IMasterStore(pub_config).remove(pub_config)
188 script = self.makeScript(series.distribution)
189- self.assertFalse(script.needsIndexesCreated(series))
190+ self.assertEqual([], script.listSuitesNeedingIndexes(series))
191
192- def test_markIndexCreationComplete_tells_needsIndexesCreated_no(self):
193- # The effect of markIndexCreationComplete is to make
194- # needsIndexesCreated for that distroseries return False.
195+ def test_markIndexCreationComplete_repels_listSuitesNeedingIndexes(self):
196+ # The effect of markIndexCreationComplete is to remove the suite
197+ # in question from the results of listSuitesNeedingIndexes for
198+ # that distroseries.
199 distro = self.makeDistroWithPublishDirectory()
200- series = self.factory.makeDistroSeries(
201- status=SeriesStatus.FROZEN, distribution=distro)
202+ series = self.makeDistroSeriesNeedingIndexes(distribution=distro)
203 script = self.makeScript(distro)
204 script.setUp()
205 self.createIndexesMarkerDir(script, series)
206
207- self.assertTrue(script.needsIndexesCreated(series))
208- script.markIndexCreationComplete(series)
209- self.assertFalse(script.needsIndexesCreated(series))
210+ needful_suites = script.listSuitesNeedingIndexes(series)
211+ suite = get_a_suite(series)
212+ script.markIndexCreationComplete(suite)
213+ needful_suites.remove(suite)
214+ self.assertContentEqual(
215+ needful_suites, script.listSuitesNeedingIndexes(series))
216+
217+ def test_listSuitesNeedingIndexes_ignores_other_series(self):
218+ # listSuitesNeedingIndexes only returns suites for series that
219+ # need indexes created. It ignores other distroseries.
220+ series = self.makeDistroSeriesNeedingIndexes()
221+ self.factory.makeDistroSeries(distribution=series.distribution)
222+ script = self.makeScript(series.distribution)
223+ script.setUp()
224+ suites = list(script.listSuitesNeedingIndexes(series))
225+ self.assertNotEqual([], suites)
226+ for suite in suites:
227+ self.assertThat(suite, StartsWith(series.name))
228
229 def test_createIndexes_marks_index_creation_complete(self):
230- # createIndexes calls markIndexCreationComplete for the
231- # distroseries.
232+ # createIndexes calls markIndexCreationComplete for the suite.
233 distro = self.makeDistroWithPublishDirectory()
234 series = self.factory.makeDistroSeries(distribution=distro)
235 script = self.makeScript(distro)
236 script.markIndexCreationComplete = FakeMethod()
237 script.runPublishDistro = FakeMethod()
238- script.createIndexes(series)
239+ suite = get_a_suite(series)
240+ script.createIndexes(suite)
241 self.assertEqual(
242- [((series, ), {})], script.markIndexCreationComplete.calls)
243+ [((suite, ), {})], script.markIndexCreationComplete.calls)
244
245 def test_failed_index_creation_is_not_marked_complete(self):
246 # If index creation fails, it is not marked as having been
247@@ -833,7 +878,7 @@
248 script.markIndexCreationComplete = FakeMethod()
249 script.runPublishDistro = FakeMethod(failure=Boom("Sorry!"))
250 try:
251- script.createIndexes(series)
252+ script.createIndexes(get_a_suite(series))
253 except:
254 pass
255 self.assertEqual([], script.markIndexCreationComplete.calls)
256@@ -846,20 +891,30 @@
257 script.setUp()
258 archive_root = script.configs[ArchivePurpose.PRIMARY].archiveroot
259 self.assertThat(
260- script.locateIndexesMarker(series),
261+ script.locateIndexesMarker(get_a_suite(series)),
262 StartsWith(os.path.normpath(archive_root)))
263
264- def test_locateIndexesMarker_uses_separate_files_per_series(self):
265- # Different release series of the same distribution get separate
266- # marker files for index creation.
267+ def test_locateIndexesMarker_uses_separate_files_per_suite(self):
268+ # Each suite in a distroseries gets its own marker file for
269+ # index creation.
270+ distro = self.makeDistroWithPublishDirectory()
271+ series = self.factory.makeDistroSeries(distribution=distro)
272+ script = self.makeScript(distro)
273+ script.setUp()
274+ markers = get_marker_files(script, series)
275+ self.assertEqual(sorted(markers), sorted(list(set(markers))))
276+
277+ def test_locateIndexesMarker_separates_distroseries(self):
278+ # Each distroseries gets its own marker files for index
279+ # creation.
280 distro = self.makeDistroWithPublishDirectory()
281 series1 = self.factory.makeDistroSeries(distribution=distro)
282 series2 = self.factory.makeDistroSeries(distribution=distro)
283 script = self.makeScript(distro)
284 script.setUp()
285- self.assertNotEqual(
286- script.locateIndexesMarker(series1),
287- script.locateIndexesMarker(series2))
288+ markers1 = set(get_marker_files(script, series1))
289+ markers2 = set(get_marker_files(script, series2))
290+ self.assertEqual(set(), markers1.intersection(markers2))
291
292 def test_locateIndexMarker_uses_hidden_file(self):
293 # The index-creation marker file is a "dot file," so it's not
294@@ -867,20 +922,23 @@
295 series = self.factory.makeDistroSeries()
296 script = self.makeScript(series.distribution)
297 script.setUp()
298+ suite = get_a_suite(series)
299 self.assertThat(
300- os.path.basename(script.locateIndexesMarker(series)),
301+ os.path.basename(script.locateIndexesMarker(suite)),
302 StartsWith("."))
303
304 def test_script_calls_createIndexes_for_new_series(self):
305 # If the script's main() finds a distroseries that needs its
306 # indexes created, it calls createIndexes on that distroseries.
307 distro = self.makeDistroWithPublishDirectory()
308- series = self.factory.makeDistroSeries(
309- status=SeriesStatus.FROZEN, distribution=distro)
310+ series = self.makeDistroSeriesNeedingIndexes(distribution=distro)
311 script = self.makeScript(distro)
312 script.createIndexes = FakeMethod()
313 script.main()
314- self.assertEqual([((series, ), {})], script.createIndexes.calls)
315+ expected_calls = [
316+ ((series.getSuite(pocket), ), {})
317+ for pocket in pocketsuffix.iterkeys()]
318+ self.assertContentEqual(expected_calls, script.createIndexes.calls)
319
320 def test_createIndexes_ignores_other_series(self):
321 # createIndexes does not accidentally also touch other
322@@ -892,14 +950,13 @@
323 script.setUp()
324 script.runPublishDistro = FakeMethod()
325 self.createIndexesMarkerDir(script, series)
326+ suite = get_a_suite(series)
327
328- script.createIndexes(series)
329+ script.createIndexes(suite)
330
331 args, kwargs = script.runPublishDistro.calls[0]
332- suites = kwargs['suites']
333- self.assertEqual(len(pocketsuffix), len(suites))
334- for suite in suites:
335- self.assertThat(suite, StartsWith(series.name))
336+ self.assertEqual([suite], kwargs['suites'])
337+ self.assertThat(kwargs['suites'][0], StartsWith(series.name))
338
339 def test_script_creates_indexes(self):
340 # End-to-end test: the script creates indexes for distroseries
341@@ -913,7 +970,7 @@
342 self.setUpForScriptRun(series.distribution)
343 script = self.makeScript(series.distribution)
344 script.main()
345- self.assertFalse(script.needsIndexesCreated(series))
346+ self.assertEqual([], script.listSuitesNeedingIndexes(series))
347 sources = os.path.join(
348 script.configs[ArchivePurpose.PRIMARY].distsroot,
349 series.name, "main", "source", "Sources")