Merge ~cjwatson/launchpad:fix-ftparchive-avoid-empty-overrides into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: c4cee494af3a5c9c19ee0d892666cf99fb2c169f
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:fix-ftparchive-avoid-empty-overrides
Merge into: launchpad:master
Diff against target: 189 lines (+79/-12)
2 files modified
lib/lp/archivepublisher/model/ftparchive.py (+23/-8)
lib/lp/archivepublisher/tests/test_ftparchive.py (+56/-4)
Reviewer Review Type Date Requested Status
Tom Wardill (community) Approve
Review via email: mp+399985@code.launchpad.net

Commit message

Generate empty override and file list files where necessary

Description of the change

Commit 25ce0c1d87 stopped `FTPArchive.createEmptyPocketRequests` from writing empty override and file list files for all suites/components, instead merely making sure that they exist. However, this broke in the case where a suite/component (or suite/component/architecture) was non-empty and then became empty, because the previous non-empty overrides and file lists were left in place.

To avoid this, ensure that `FTPArchive.publishOverrides` writes override files for all relevant components, and that `FTPArchive.publishFileLists` writes file list files for all relevant components/architectures; these may be empty if there are no publications in the corresponding contexts. This doesn't suffer from the problem that the aforementioned commit was fixing, because these files are put in place atomically.

It's possible that this comes close to making `FTPArchive.createEmptyPocketRequests` entirely unnecessary, but I haven't yet tried to remove it.

To post a comment you must log in.
Revision history for this message
Tom Wardill (twom) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/archivepublisher/model/ftparchive.py b/lib/lp/archivepublisher/model/ftparchive.py
2index a13269e..624aebf 100644
3--- a/lib/lp/archivepublisher/model/ftparchive.py
4+++ b/lib/lp/archivepublisher/model/ftparchive.py
5@@ -382,10 +382,9 @@ class FTPArchiveHandler:
6
7 spphs = self.getSourcesForOverrides(distroseries, pocket)
8 bpphs = self.getBinariesForOverrides(distroseries, pocket)
9- self.publishOverrides(
10- distroseries.getSuite(pocket), spphs, bpphs)
11+ self.publishOverrides(distroseries, pocket, spphs, bpphs)
12
13- def publishOverrides(self, suite,
14+ def publishOverrides(self, distroseries, pocket,
15 source_publications, binary_publications):
16 """Output a set of override files for use in apt-ftparchive.
17
18@@ -408,8 +407,15 @@ class FTPArchiveHandler:
19 # test_ftparchive.
20 from lp.archivepublisher.publishing import FORMAT_TO_SUBCOMPONENT
21
22+ suite = distroseries.getSuite(pocket)
23+
24 # overrides[component][src/bin] = sets of tuples
25 overrides = defaultdict(lambda: defaultdict(set))
26+ # Ensure that we generate overrides for all the expected components,
27+ # even if they're currently empty.
28+ for component in self.publisher.archive.getComponentsForSeries(
29+ distroseries):
30+ overrides[component.name]
31
32 def updateOverride(packagename, component, section, archtag=None,
33 priority=None, binpackageformat=None,
34@@ -666,16 +672,25 @@ class FTPArchiveHandler:
35 continue
36 spps = self.getSourceFiles(distroseries, pocket)
37 pps = self.getBinaryFiles(distroseries, pocket)
38- self.publishFileLists(distroseries.getSuite(pocket), spps, pps)
39+ self.publishFileLists(distroseries, pocket, spps, pps)
40
41- def publishFileLists(self, suite, sourcefiles, binaryfiles):
42+ def publishFileLists(self, distroseries, pocket, sourcefiles, binaryfiles):
43 """Collate the set of source files and binary files provided and
44 write out all the file list files for them.
45
46 listroot/distroseries_component_source
47 listroot/distroseries_component_binary-archname
48 """
49+ suite = distroseries.getSuite(pocket)
50+
51 filelist = defaultdict(lambda: defaultdict(list))
52+ # Ensure that we generate file lists for all the expected components
53+ # and architectures, even if they're currently empty.
54+ for component in self.publisher.archive.getComponentsForSeries(
55+ distroseries):
56+ filelist[component.name]["source"]
57+ for das in distroseries.enabled_architectures:
58+ filelist[component.name]["binary-%s" % das.architecturetag]
59
60 def updateFileList(sourcepackagename, filename, component,
61 architecturetag=None):
62@@ -698,7 +713,6 @@ class FTPArchiveHandler:
63 updateFileList(*file_details)
64
65 self.log.debug("Writing file lists for %s" % suite)
66- series, pocket = self.distro.getDistroSeriesAndPocket(suite)
67 for component, architectures in six.iteritems(filelist):
68 for architecture, file_names in six.iteritems(architectures):
69 # XXX wgrant 2010-10-06: There must be a better place to do
70@@ -708,7 +722,7 @@ class FTPArchiveHandler:
71 else:
72 # The "[7:]" strips the "binary-" prefix off the
73 # architecture names we get here.
74- das = series.getDistroArchSeries(architecture[7:])
75+ das = distroseries.getDistroArchSeries(architecture[7:])
76 enabled = das.enabled
77 if enabled:
78 self.writeFileList(
79@@ -740,7 +754,8 @@ class FTPArchiveHandler:
80 with open(new_path, 'w') as f:
81 files[subcomp].sort(key=package_name)
82 f.write("\n".join(files[subcomp]))
83- f.write("\n")
84+ if files[subcomp]:
85+ f.write("\n")
86 os.rename(new_path, final_path)
87
88 #
89diff --git a/lib/lp/archivepublisher/tests/test_ftparchive.py b/lib/lp/archivepublisher/tests/test_ftparchive.py
90index 3a9665a..94b68fc 100755
91--- a/lib/lp/archivepublisher/tests/test_ftparchive.py
92+++ b/lib/lp/archivepublisher/tests/test_ftparchive.py
93@@ -186,13 +186,17 @@ class TestFTPArchive(TestCaseWithFactory):
94 'tiny', component, section, 'i386',
95 PackagePublishingPriority.EXTRA, binpackageformat,
96 phased_update_percentage)])
97- fa.publishOverrides('hoary-test', source_overrides, binary_overrides)
98+ fa.publishOverrides(
99+ self._distribution['hoary-test'], PackagePublishingPocket.RELEASE,
100+ source_overrides, binary_overrides)
101
102 def _publishDefaultFileLists(self, fa, component):
103 source_files = FakeSelectResult([('tiny', 'tiny_0.1.dsc', component)])
104 binary_files = FakeSelectResult(
105 [('tiny', 'tiny_0.1_i386.deb', component, 'binary-i386')])
106- fa.publishFileLists('hoary-test', source_files, binary_files)
107+ fa.publishFileLists(
108+ self._distribution['hoary-test'], PackagePublishingPocket.RELEASE,
109+ source_files, binary_files)
110
111 def test_createEmptyPocketRequests_preserves_existing(self):
112 # createEmptyPocketRequests leaves existing override and file list
113@@ -362,6 +366,29 @@ class TestFTPArchive(TestCaseWithFactory):
114 self.assertEqual(
115 ["tiny\textra\tdevel"], result_file.read().splitlines())
116
117+ def test_publishOverrides_empties_missing_components(self):
118+ # publishOverrides writes empty overrides files for components that
119+ # have no publications.
120+ fa = self._setUpFTPArchiveHandler()
121+ empty_overrides = []
122+ for component in ("restricted", "universe", "multiverse"):
123+ empty_overrides.extend([
124+ "override.hoary-test.%s" % component,
125+ "override.hoary-test.%s.src" % component,
126+ "override.hoary-test.extra.%s" % component,
127+ ])
128+ for override in empty_overrides:
129+ write_file(
130+ os.path.join(self._overdir, override), b"previous contents\n")
131+
132+ self._publishDefaultOverrides(fa, "main")
133+
134+ self._verifyFile("override.hoary-test.main", self._overdir)
135+ self._verifyFile("override.hoary-test.main.src", self._overdir)
136+ self._verifyFile("override.hoary-test.extra.main", self._overdir)
137+ for override in empty_overrides:
138+ self._verifyEmpty(os.path.join(self._overdir, override))
139+
140 def test_generateOverrides(self):
141 # generateOverrides generates all the overrides from start to finish.
142 self._distribution = getUtility(IDistributionSet).getByName('ubuntu')
143@@ -459,6 +486,27 @@ class TestFTPArchive(TestCaseWithFactory):
144 self._verifyFile("hoary-test_main_source", self._listdir)
145 self._verifyFile("hoary-test_main_binary-i386", self._listdir)
146
147+ def test_publishFileLists_empties_missing_components(self):
148+ # publishFileLists writes empty file list files for components that
149+ # have no publications.
150+ fa = self._setUpFTPArchiveHandler()
151+ empty_filelists = []
152+ for component in ("restricted", "universe", "multiverse"):
153+ empty_filelists.extend([
154+ "hoary-test_%s_source" % component,
155+ "hoary-test_%s_binary-i386" % component,
156+ ])
157+ for filelist in empty_filelists:
158+ write_file(
159+ os.path.join(self._listdir, filelist), b"previous contents\n")
160+
161+ self._publishDefaultFileLists(fa, "main")
162+
163+ self._verifyFile("hoary-test_main_source", self._listdir)
164+ self._verifyFile("hoary-test_main_binary-i386", self._listdir)
165+ for filelist in empty_filelists:
166+ self._verifyEmpty(os.path.join(self._listdir, filelist))
167+
168 def test_generateConfig(self):
169 # Generate apt-ftparchive configuration file and run it.
170
171@@ -727,12 +775,16 @@ class TestFTPArchive(TestCaseWithFactory):
172 "bin%d" % i, "main", "misc", "i386",
173 PackagePublishingPriority.EXTRA, BinaryPackageFormat.DEB, None)
174 for i in range(50)])
175- fa.publishOverrides("hoary-test", source_overrides, binary_overrides)
176+ fa.publishOverrides(
177+ self._distribution["hoary-test"], PackagePublishingPocket.RELEASE,
178+ source_overrides, binary_overrides)
179 source_files = FakeSelectResult([("tiny", "tiny_0.1.dsc", "main")])
180 binary_files = FakeSelectResult([(
181 "bin%d" % i, "bin%d_1_i386.deb" % i, "main", "binary-i386")
182 for i in range(50)])
183- fa.publishFileLists("hoary-test", source_files, binary_files)
184+ fa.publishFileLists(
185+ self._distribution["hoary-test"], PackagePublishingPocket.RELEASE,
186+ source_files, binary_files)
187 self._addRepositoryFile("main", "tiny", "tiny_0.1.dsc")
188 for i in range(50):
189 self._addRepositoryFile(

Subscribers

People subscribed via source and target branches

to status/vote changes: