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
=== modified file 'lib/lp/archivepublisher/scripts/publish_ftpmaster.py'
--- lib/lp/archivepublisher/scripts/publish_ftpmaster.py 2011-05-06 03:10:14 +0000
+++ lib/lp/archivepublisher/scripts/publish_ftpmaster.py 2011-05-09 10:48:36 +0000
@@ -228,19 +228,18 @@
228 (archive.purpose, getPubConfig(archive))228 (archive.purpose, getPubConfig(archive))
229 for archive in self.archives)229 for archive in self.archives)
230230
231 def locateIndexesMarker(self, distroseries):231 def locateIndexesMarker(self, suite):
232 """Give path for marker file whose presence marks index creation.232 """Give path for marker file whose presence marks index creation.
233233
234 The file will be created once the archive indexes for234 The file will be created once the archive indexes for `suite`
235 `distroseries` have been created. This is how future runs will235 have been created. This is how future runs will know that this
236 know that this work is done.236 work is done.
237 """237 """
238 archive_root = self.configs[ArchivePurpose.PRIMARY].archiveroot238 archive_root = self.configs[ArchivePurpose.PRIMARY].archiveroot
239 return os.path.join(239 return os.path.join(archive_root, ".created-indexes-for-%s" % suite)
240 archive_root, ".created-indexes-for-%s" % distroseries.name)
241240
242 def needsIndexesCreated(self, distroseries):241 def listSuitesNeedingIndexes(self, distroseries):
243 """Does `distroseries` still need its archive indexes created?242 """Find suites in `distroseries` that need indexes created.
244243
245 Checks for the marker left by `markIndexCreationComplete`.244 Checks for the marker left by `markIndexCreationComplete`.
246 """245 """
@@ -249,36 +248,39 @@
249 # is in any other state yet has not been marked as having248 # is in any other state yet has not been marked as having
250 # its indexes created, that's because it predates automatic249 # its indexes created, that's because it predates automatic
251 # index creation.250 # index creation.
252 return False251 return []
253 distro = distroseries.distribution252 distro = distroseries.distribution
254 publisher_config_set = getUtility(IPublisherConfigSet)253 publisher_config_set = getUtility(IPublisherConfigSet)
255 if publisher_config_set.getByDistribution(distro) is None:254 if publisher_config_set.getByDistribution(distro) is None:
256 # We won't be able to do a thing without a publisher config,255 # We won't be able to do a thing without a publisher config,
257 # but that's alright: we have those for all distributions256 # but that's alright: we have those for all distributions
258 # that we want to publish.257 # that we want to publish.
259 return False258 return []
260 return not file_exists(self.locateIndexesMarker(distroseries))259
261260 # May need indexes for this series.
262 def markIndexCreationComplete(self, distroseries):261 suites = [
263 """Note that archive indexes for `distroseries` have been created.262 distroseries.getSuite(pocket)
264263 for pocket in pocketsuffix.iterkeys()]
265 This tells `needsIndexesCreated` that no, this series no longer needs264 return [
266 archive indexes to be set up.265 suite for suite in suites
266 if not file_exists(self.locateIndexesMarker(suite))]
267
268 def markIndexCreationComplete(self, suite):
269 """Note that archive indexes for `suite` have been created.
270
271 This tells `listSuitesNeedingIndexes` that no, this suite no
272 longer needs archive indexes to be set up.
267 """273 """
268 with file(self.locateIndexesMarker(distroseries), "w") as marker:274 with file(self.locateIndexesMarker(suite), "w") as marker:
269 marker.write(275 marker.write(
270 "Indexes for %s were created on %s.\n"276 "Indexes for %s were created on %s.\n"
271 % (distroseries, datetime.now(utc)))277 % (suite, datetime.now(utc)))
272278
273 def createIndexes(self, distroseries):279 def createIndexes(self, suite):
274 """Create archive indexes for `distroseries`."""280 """Create archive indexes for `distroseries`."""
275 self.logger.info(281 self.logger.info("Creating archive indexes for %s.", suite)
276 "Creating archive indexes for series %s.", distroseries)282 self.runPublishDistro(args=['-A'], suites=[suite])
277 suites = [283 self.markIndexCreationComplete(suite)
278 distroseries.getSuite(pocket)
279 for pocket in pocketsuffix.iterkeys()]
280 self.runPublishDistro(args=['-A'], suites=suites)
281 self.markIndexCreationComplete(distroseries)
282284
283 def processAccepted(self):285 def processAccepted(self):
284 """Run the process-accepted script."""286 """Run the process-accepted script."""
@@ -556,8 +558,10 @@
556 self.recoverWorkingDists()558 self.recoverWorkingDists()
557559
558 for series in self.distribution.series:560 for series in self.distribution.series:
559 if self.needsIndexesCreated(series):561 suites_needing_indexes = self.listSuitesNeedingIndexes(series)
560 self.createIndexes(series)562 if len(suites_needing_indexes) > 0:
563 for suite in suites_needing_indexes:
564 self.createIndexes(suite)
561 # Don't try to do too much in one run. Leave the rest565 # Don't try to do too much in one run. Leave the rest
562 # of the work for next time.566 # of the work for next time.
563 return567 return
564568
=== modified file 'lib/lp/archivepublisher/tests/test_publish_ftpmaster.py'
--- lib/lp/archivepublisher/tests/test_publish_ftpmaster.py 2011-05-06 03:10:14 +0000
+++ lib/lp/archivepublisher/tests/test_publish_ftpmaster.py 2011-05-09 10:48:36 +0000
@@ -108,6 +108,19 @@
108 return file(os.path.join(*path)).read()108 return file(os.path.join(*path)).read()
109109
110110
111def 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
117def 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
111class HelpersMixin:124class HelpersMixin:
112 """Helpers for the PublishFTPMaster tests."""125 """Helpers for the PublishFTPMaster tests."""
113126
@@ -769,58 +782,90 @@
769782
770 def createIndexesMarkerDir(self, script, distroseries):783 def createIndexesMarkerDir(self, script, distroseries):
771 """Create the directory for `distroseries`'s indexes marker."""784 """Create the directory for `distroseries`'s indexes marker."""
772 marker = script.locateIndexesMarker(distroseries)785 marker = script.locateIndexesMarker(get_a_suite(distroseries))
773 os.makedirs(os.path.dirname(marker))786 os.makedirs(os.path.dirname(marker))
774787
775 def test_new_frozen_series_needs_indexes_created(self):788 def makeDistroSeriesNeedingIndexes(self, distribution=None):
789 """Create `DistroSeries` that needs indexes created."""
790 return self.factory.makeDistroSeries(
791 status=SeriesStatus.FROZEN, distribution=distribution)
792
793 def test_listSuitesNeedingIndexes_is_nonempty_for_new_frozen_series(self):
776 # If a distroseries is Frozen and has not had its indexes794 # If a distroseries is Frozen and has not had its indexes
777 # created yet, needsIndexesCreated returns True for it.795 # created yet, listSuitesNeedingIndexes returns a nonempty list
778 series = self.factory.makeDistroSeries(status=SeriesStatus.FROZEN)796 # for it.
779 script = self.makeScript(series.distribution)797 series = self.makeDistroSeriesNeedingIndexes()
780 script.setUp()798 script = self.makeScript(series.distribution)
781 self.assertTrue(script.needsIndexesCreated(series))799 script.setUp()
782800 self.assertNotEqual([], list(script.listSuitesNeedingIndexes(series)))
783 def test_new_nonfrozen_series_does_not_need_indexes_created(self):801
784 # needsIndexesCreated only returns True for Frozen distroseries.802 def test_listSuitesNeedingIndexes_initially_includes_entire_series(self):
803 # If a series has not had any of its indexes created yet,
804 # listSuitesNeedingIndexes returns all of its suites.
805 series = self.makeDistroSeriesNeedingIndexes()
806 script = self.makeScript(series.distribution)
807 script.setUp()
808 self.assertContentEqual(
809 [series.getSuite(pocket) for pocket in pocketsuffix.iterkeys()],
810 script.listSuitesNeedingIndexes(series))
811
812 def test_listSuitesNeedingIndexes_is_empty_for_nonfrozen_series(self):
813 # listSuitesNeedingIndexes only returns suites for Frozen
814 # distroseries.
785 series = self.factory.makeDistroSeries()815 series = self.factory.makeDistroSeries()
786 script = self.makeScript(series.distribution)816 script = self.makeScript(series.distribution)
787 self.assertFalse(script.needsIndexesCreated(series))817 self.assertEqual([], script.listSuitesNeedingIndexes(series))
788818
789 def test_distro_without_publisher_config_gets_no_indexes(self):819 def test_listSuitesNeedingIndexes_is_empty_for_configless_distro(self):
790 # needsIndexesCreated returns False for distributions that have820 # listSuitesNeedingIndexes returns no suites for distributions
791 # no publisher config, such as Debian. We don't want to publish821 # that have no publisher config, such as Debian. We don't want
792 # these distributions.822 # to publish such distributions.
793 series = self.factory.makeDistroSeries(status=SeriesStatus.FROZEN)823 series = self.makeDistroSeriesNeedingIndexes()
794 pub_config = get_pub_config(series.distribution)824 pub_config = get_pub_config(series.distribution)
795 IMasterStore(pub_config).remove(pub_config)825 IMasterStore(pub_config).remove(pub_config)
796 script = self.makeScript(series.distribution)826 script = self.makeScript(series.distribution)
797 self.assertFalse(script.needsIndexesCreated(series))827 self.assertEqual([], script.listSuitesNeedingIndexes(series))
798828
799 def test_markIndexCreationComplete_tells_needsIndexesCreated_no(self):829 def test_markIndexCreationComplete_repels_listSuitesNeedingIndexes(self):
800 # The effect of markIndexCreationComplete is to make830 # The effect of markIndexCreationComplete is to remove the suite
801 # needsIndexesCreated for that distroseries return False.831 # in question from the results of listSuitesNeedingIndexes for
832 # that distroseries.
802 distro = self.makeDistroWithPublishDirectory()833 distro = self.makeDistroWithPublishDirectory()
803 series = self.factory.makeDistroSeries(834 series = self.makeDistroSeriesNeedingIndexes(distribution=distro)
804 status=SeriesStatus.FROZEN, distribution=distro)
805 script = self.makeScript(distro)835 script = self.makeScript(distro)
806 script.setUp()836 script.setUp()
807 self.createIndexesMarkerDir(script, series)837 self.createIndexesMarkerDir(script, series)
808838
809 self.assertTrue(script.needsIndexesCreated(series))839 needful_suites = script.listSuitesNeedingIndexes(series)
810 script.markIndexCreationComplete(series)840 suite = get_a_suite(series)
811 self.assertFalse(script.needsIndexesCreated(series))841 script.markIndexCreationComplete(suite)
842 needful_suites.remove(suite)
843 self.assertContentEqual(
844 needful_suites, script.listSuitesNeedingIndexes(series))
845
846 def test_listSuitesNeedingIndexes_ignores_other_series(self):
847 # listSuitesNeedingIndexes only returns suites for series that
848 # need indexes created. It ignores other distroseries.
849 series = self.makeDistroSeriesNeedingIndexes()
850 self.factory.makeDistroSeries(distribution=series.distribution)
851 script = self.makeScript(series.distribution)
852 script.setUp()
853 suites = list(script.listSuitesNeedingIndexes(series))
854 self.assertNotEqual([], suites)
855 for suite in suites:
856 self.assertThat(suite, StartsWith(series.name))
812857
813 def test_createIndexes_marks_index_creation_complete(self):858 def test_createIndexes_marks_index_creation_complete(self):
814 # createIndexes calls markIndexCreationComplete for the859 # createIndexes calls markIndexCreationComplete for the suite.
815 # distroseries.
816 distro = self.makeDistroWithPublishDirectory()860 distro = self.makeDistroWithPublishDirectory()
817 series = self.factory.makeDistroSeries(distribution=distro)861 series = self.factory.makeDistroSeries(distribution=distro)
818 script = self.makeScript(distro)862 script = self.makeScript(distro)
819 script.markIndexCreationComplete = FakeMethod()863 script.markIndexCreationComplete = FakeMethod()
820 script.runPublishDistro = FakeMethod()864 script.runPublishDistro = FakeMethod()
821 script.createIndexes(series)865 suite = get_a_suite(series)
866 script.createIndexes(suite)
822 self.assertEqual(867 self.assertEqual(
823 [((series, ), {})], script.markIndexCreationComplete.calls)868 [((suite, ), {})], script.markIndexCreationComplete.calls)
824869
825 def test_failed_index_creation_is_not_marked_complete(self):870 def test_failed_index_creation_is_not_marked_complete(self):
826 # If index creation fails, it is not marked as having been871 # If index creation fails, it is not marked as having been
@@ -833,7 +878,7 @@
833 script.markIndexCreationComplete = FakeMethod()878 script.markIndexCreationComplete = FakeMethod()
834 script.runPublishDistro = FakeMethod(failure=Boom("Sorry!"))879 script.runPublishDistro = FakeMethod(failure=Boom("Sorry!"))
835 try:880 try:
836 script.createIndexes(series)881 script.createIndexes(get_a_suite(series))
837 except:882 except:
838 pass883 pass
839 self.assertEqual([], script.markIndexCreationComplete.calls)884 self.assertEqual([], script.markIndexCreationComplete.calls)
@@ -846,20 +891,30 @@
846 script.setUp()891 script.setUp()
847 archive_root = script.configs[ArchivePurpose.PRIMARY].archiveroot892 archive_root = script.configs[ArchivePurpose.PRIMARY].archiveroot
848 self.assertThat(893 self.assertThat(
849 script.locateIndexesMarker(series),894 script.locateIndexesMarker(get_a_suite(series)),
850 StartsWith(os.path.normpath(archive_root)))895 StartsWith(os.path.normpath(archive_root)))
851896
852 def test_locateIndexesMarker_uses_separate_files_per_series(self):897 def test_locateIndexesMarker_uses_separate_files_per_suite(self):
853 # Different release series of the same distribution get separate898 # Each suite in a distroseries gets its own marker file for
854 # marker files for index creation.899 # index creation.
900 distro = self.makeDistroWithPublishDirectory()
901 series = self.factory.makeDistroSeries(distribution=distro)
902 script = self.makeScript(distro)
903 script.setUp()
904 markers = get_marker_files(script, series)
905 self.assertEqual(sorted(markers), sorted(list(set(markers))))
906
907 def test_locateIndexesMarker_separates_distroseries(self):
908 # Each distroseries gets its own marker files for index
909 # creation.
855 distro = self.makeDistroWithPublishDirectory()910 distro = self.makeDistroWithPublishDirectory()
856 series1 = self.factory.makeDistroSeries(distribution=distro)911 series1 = self.factory.makeDistroSeries(distribution=distro)
857 series2 = self.factory.makeDistroSeries(distribution=distro)912 series2 = self.factory.makeDistroSeries(distribution=distro)
858 script = self.makeScript(distro)913 script = self.makeScript(distro)
859 script.setUp()914 script.setUp()
860 self.assertNotEqual(915 markers1 = set(get_marker_files(script, series1))
861 script.locateIndexesMarker(series1),916 markers2 = set(get_marker_files(script, series2))
862 script.locateIndexesMarker(series2))917 self.assertEqual(set(), markers1.intersection(markers2))
863918
864 def test_locateIndexMarker_uses_hidden_file(self):919 def test_locateIndexMarker_uses_hidden_file(self):
865 # The index-creation marker file is a "dot file," so it's not920 # The index-creation marker file is a "dot file," so it's not
@@ -867,20 +922,23 @@
867 series = self.factory.makeDistroSeries()922 series = self.factory.makeDistroSeries()
868 script = self.makeScript(series.distribution)923 script = self.makeScript(series.distribution)
869 script.setUp()924 script.setUp()
925 suite = get_a_suite(series)
870 self.assertThat(926 self.assertThat(
871 os.path.basename(script.locateIndexesMarker(series)),927 os.path.basename(script.locateIndexesMarker(suite)),
872 StartsWith("."))928 StartsWith("."))
873929
874 def test_script_calls_createIndexes_for_new_series(self):930 def test_script_calls_createIndexes_for_new_series(self):
875 # If the script's main() finds a distroseries that needs its931 # If the script's main() finds a distroseries that needs its
876 # indexes created, it calls createIndexes on that distroseries.932 # indexes created, it calls createIndexes on that distroseries.
877 distro = self.makeDistroWithPublishDirectory()933 distro = self.makeDistroWithPublishDirectory()
878 series = self.factory.makeDistroSeries(934 series = self.makeDistroSeriesNeedingIndexes(distribution=distro)
879 status=SeriesStatus.FROZEN, distribution=distro)
880 script = self.makeScript(distro)935 script = self.makeScript(distro)
881 script.createIndexes = FakeMethod()936 script.createIndexes = FakeMethod()
882 script.main()937 script.main()
883 self.assertEqual([((series, ), {})], script.createIndexes.calls)938 expected_calls = [
939 ((series.getSuite(pocket), ), {})
940 for pocket in pocketsuffix.iterkeys()]
941 self.assertContentEqual(expected_calls, script.createIndexes.calls)
884942
885 def test_createIndexes_ignores_other_series(self):943 def test_createIndexes_ignores_other_series(self):
886 # createIndexes does not accidentally also touch other944 # createIndexes does not accidentally also touch other
@@ -892,14 +950,13 @@
892 script.setUp()950 script.setUp()
893 script.runPublishDistro = FakeMethod()951 script.runPublishDistro = FakeMethod()
894 self.createIndexesMarkerDir(script, series)952 self.createIndexesMarkerDir(script, series)
953 suite = get_a_suite(series)
895954
896 script.createIndexes(series)955 script.createIndexes(suite)
897956
898 args, kwargs = script.runPublishDistro.calls[0]957 args, kwargs = script.runPublishDistro.calls[0]
899 suites = kwargs['suites']958 self.assertEqual([suite], kwargs['suites'])
900 self.assertEqual(len(pocketsuffix), len(suites))959 self.assertThat(kwargs['suites'][0], StartsWith(series.name))
901 for suite in suites:
902 self.assertThat(suite, StartsWith(series.name))
903960
904 def test_script_creates_indexes(self):961 def test_script_creates_indexes(self):
905 # End-to-end test: the script creates indexes for distroseries962 # End-to-end test: the script creates indexes for distroseries
@@ -913,7 +970,7 @@
913 self.setUpForScriptRun(series.distribution)970 self.setUpForScriptRun(series.distribution)
914 script = self.makeScript(series.distribution)971 script = self.makeScript(series.distribution)
915 script.main()972 script.main()
916 self.assertFalse(script.needsIndexesCreated(series))973 self.assertEqual([], script.listSuitesNeedingIndexes(series))
917 sources = os.path.join(974 sources = os.path.join(
918 script.configs[ArchivePurpose.PRIMARY].distsroot,975 script.configs[ArchivePurpose.PRIMARY].distsroot,
919 series.name, "main", "source", "Sources")976 series.name, "main", "source", "Sources")