Merge lp:~rvb/launchpad/override-bug-826870 into lp:launchpad

Proposed by Raphaël Badin
Status: Merged
Approved by: Julian Edwards
Approved revision: no longer in the source branch.
Merged at revision: 13769
Proposed branch: lp:~rvb/launchpad/override-bug-826870
Merge into: lp:launchpad
Diff against target: 313 lines (+140/-30)
6 files modified
lib/lp/archiveuploader/nascentupload.py (+5/-16)
lib/lp/soyuz/adapters/overrides.py (+44/-9)
lib/lp/soyuz/adapters/tests/test_overrides.py (+25/-0)
lib/lp/soyuz/model/packagecopyjob.py (+4/-3)
lib/lp/soyuz/tests/test_packagecopyjob.py (+61/-1)
lib/lp/soyuz/tests/test_publishing.py (+1/-1)
To merge this branch: bzr merge lp:~rvb/launchpad/override-bug-826870
Reviewer Review Type Date Requested Status
Julian Edwards (community) Approve
Review via email: mp+72586@code.launchpad.net

Commit message

[r=julian-edwards][bug=826870] Fix UnknownOverridePolicy to put sources from debian into the right default component.

Description of the change

This branch fixes the UnknownOverridePolicy so that sources from debian are put into the right component by default ('contrib'=> 'multiverse', 'non-free'=> 'multiverse', all else => 'universe'). It also refactors the code in nascentupload.py (processUnknownFile) to use the same code from UnknownOverridePolicy.

= Tests =

./bin/test -vvc test_overrides test_getComponentOverride_default_name
./bin/test -vvc test_overrides test_getComponentOverride_default_component
./bin/test -vvc test_overrides test_getComponentOverride_return_component
./bin/test -vvc test_packagecopyjob test_copying_to_main_archive_debian_override_contrib
./bin/test -vvc test_packagecopyjob test_copying_to_main_archive_debian_override_nonfree

= QA =

Upload sources into debian components 'non-free' and 'contrib' and make sure that the default selected components for these source uploads are 'multiverse'.

To post a comment you must log in.
Revision history for this message
Julian Edwards (julian-edwards) wrote :

That is a little bit of a quandary over the sources vs source. Since we can pass multiple sources at once then the choice is either to assume they are all the same component in their source, or pass multiple components. Since we generally only process one source at a time in PCJ I am fine with the single component here. If we ever do multiple then we'll have to batch overrides by source component.

So overall, it looks good - just a couple of things, I'd s/sources_component/source_component/g and move the DEBIAN_COMPONENT_OVERRIDE_MAP/DEFAULT_OVERRIDE_COMPONENT into the class, I don't think it's useful having it at the module level since we want to encourage people to use the new method.

168 + # getComponentOverride returns the default component namewhen an

Typo "namewhen"

Thanks for the change!

review: Approve
Revision history for this message
Raphaël Badin (rvb) wrote :

> That is a little bit of a quandary over the sources vs source. Since we can
> pass multiple sources at once then the choice is either to assume they are all
> the same component in their source, or pass multiple components. Since we
> generally only process one source at a time in PCJ I am fine with the single
> component here. If we ever do multiple then we'll have to batch overrides by
> source component.
>
> So overall, it looks good - just a couple of things, I'd
> s/sources_component/source_component/g and move the
> DEBIAN_COMPONENT_OVERRIDE_MAP/DEFAULT_OVERRIDE_COMPONENT into the class, I
> don't think it's useful having it at the module level since we want to
> encourage people to use the new method.

Done.

>
> 168 + # getComponentOverride returns the default component namewhen an
>
> Typo "namewhen"

Fixed.

Thanks for the review.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/archiveuploader/nascentupload.py'
2--- lib/lp/archiveuploader/nascentupload.py 2011-08-19 02:47:35 +0000
3+++ lib/lp/archiveuploader/nascentupload.py 2011-08-23 15:24:55 +0000
4@@ -41,6 +41,7 @@
5 from lp.registry.interfaces.pocket import PackagePublishingPocket
6 from lp.registry.interfaces.sourcepackage import SourcePackageFileType
7 from lp.registry.interfaces.sourcepackagename import ISourcePackageNameSet
8+from lp.soyuz.adapters.overrides import UnknownOverridePolicy
9 from lp.soyuz.interfaces.archive import MAIN_ARCHIVE_PURPOSES
10 from lp.soyuz.interfaces.queue import QueueInconsistentStateError
11
12@@ -720,15 +721,7 @@
13 def processUnknownFile(self, uploaded_file):
14 """Apply a set of actions for newly-uploaded (unknown) files.
15
16- Newly-uploaded files have a default set of overrides to be applied.
17- This reduces the amount of work that archive admins have to do
18- since they override the majority of new uploads with the same
19- values. The rules for overriding are: (See bug #120052)
20- 'contrib' -> 'multiverse'
21- 'non-free' -> 'multiverse'
22- everything else -> 'universe'
23- This mainly relates to Debian syncs, where the default component
24- is 'main' but should not be in main for Ubuntu.
25+ Here we use the override policy defined in UnknownOverridePolicy.
26
27 In the case of a PPA, files are not touched. They are always
28 overridden to 'main' at publishing time, though.
29@@ -751,14 +744,10 @@
30 # Don't override partner uploads.
31 return
32
33- component_override_map = {
34- 'contrib': 'multiverse',
35- 'non-free': 'multiverse',
36- }
37-
38 # Apply the component override and default to universe.
39- uploaded_file.component_name = component_override_map.get(
40- uploaded_file.component_name, 'universe')
41+ component_name_override = UnknownOverridePolicy.getComponentOverride(
42+ uploaded_file.component_name)
43+ uploaded_file.component_name = component_name_override
44
45 def find_and_apply_overrides(self):
46 """Look for ancestry and overrides information.
47
48=== modified file 'lib/lp/soyuz/adapters/overrides.py'
49--- lib/lp/soyuz/adapters/overrides.py 2011-07-20 08:50:10 +0000
50+++ lib/lp/soyuz/adapters/overrides.py 2011-08-23 15:24:55 +0000
51@@ -139,13 +139,15 @@
52 keep the same component and section as their ancestor publications.
53 """
54
55- def calculateSourceOverrides(archive, distroseries, pocket, sources):
56+ def calculateSourceOverrides(archive, distroseries, pocket, sources,
57+ source_component=None):
58 """Calculate source overrides.
59
60 :param archive: The target `IArchive`.
61 :param distroseries: The target `IDistroSeries`.
62 :param pocket: The target `PackagePublishingPocket`.
63 :param sources: A tuple of `ISourcePackageName`s.
64+ :param source_component: The sources' `IComponent` (optional).
65
66 :return: A list of `ISourceOverride`
67 """
68@@ -171,7 +173,7 @@
69 implements(IOverridePolicy)
70
71 def calculateSourceOverrides(self, archive, distroseries, pocket,
72- sources):
73+ sources, source_component=None):
74 raise NotImplementedError()
75
76 def calculateBinaryOverrides(self, archive, distroseries, pocket,
77@@ -188,7 +190,8 @@
78 for the latest published binary publication.
79 """
80
81- def calculateSourceOverrides(self, archive, distroseries, pocket, spns):
82+ def calculateSourceOverrides(self, archive, distroseries, pocket, spns,
83+ source_component=None):
84 # Avoid circular imports.
85 from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease
86 from lp.soyuz.model.publishing import SourcePackagePublishingHistory
87@@ -276,12 +279,43 @@
88
89 Override policy that assumes everything passed in doesn't exist, so
90 returns the defaults.
91+
92+ Newly-uploaded files have a default set of overrides to be applied.
93+ This reduces the amount of work that archive admins have to do
94+ since they override the majority of new uploads with the same
95+ values. The rules for overriding are: (See bug #120052)
96+ 'contrib' -> 'multiverse'
97+ 'non-free' -> 'multiverse'
98+ everything else -> 'universe'
99+ This mainly relates to Debian syncs, where the default component
100+ is 'main' but should not be in main for Ubuntu.
101 """
102
103+ DEBIAN_COMPONENT_OVERRIDE_MAP = {
104+ 'contrib': 'multiverse',
105+ 'non-free': 'multiverse',
106+ }
107+
108+ DEFAULT_OVERRIDE_COMPONENT = 'universe'
109+
110+ @classmethod
111+ def getComponentOverride(cls, component=None, return_component=False):
112+ # component can be a Component object or a component name.
113+ if isinstance(component, Component):
114+ component = component.name
115+ override_component_name = cls.DEBIAN_COMPONENT_OVERRIDE_MAP.get(
116+ component, cls.DEFAULT_OVERRIDE_COMPONENT)
117+ if return_component:
118+ return getUtility(IComponentSet)[override_component_name]
119+ else:
120+ return override_component_name
121+
122 def calculateSourceOverrides(self, archive, distroseries, pocket,
123- sources):
124- default_component = archive.default_component or getUtility(
125- IComponentSet)['universe']
126+ sources, source_component=None):
127+ default_component = (
128+ archive.default_component or
129+ UnknownOverridePolicy.getComponentOverride(
130+ source_component, return_component=True))
131 return [
132 SourceOverride(source, default_component, None)
133 for source in sources]
134@@ -304,15 +338,16 @@
135 """
136
137 def calculateSourceOverrides(self, archive, distroseries, pocket,
138- sources):
139+ sources, source_component=None):
140 total = set(sources)
141 overrides = FromExistingOverridePolicy.calculateSourceOverrides(
142- self, archive, distroseries, pocket, sources)
143+ self, archive, distroseries, pocket, sources, source_component)
144 existing = set(override.source_package_name for override in overrides)
145 missing = total.difference(existing)
146 if missing:
147 unknown = UnknownOverridePolicy.calculateSourceOverrides(
148- self, archive, distroseries, pocket, missing)
149+ self, archive, distroseries, pocket, missing,
150+ source_component)
151 overrides.extend(unknown)
152 return overrides
153
154
155=== modified file 'lib/lp/soyuz/adapters/tests/test_overrides.py'
156--- lib/lp/soyuz/adapters/tests/test_overrides.py 2011-07-20 08:49:48 +0000
157+++ lib/lp/soyuz/adapters/tests/test_overrides.py 2011-08-23 15:24:55 +0000
158@@ -149,6 +149,31 @@
159 distroseries.main_archive, distroseries, pocket, bpns)
160 self.assertThat(recorder, HasQueryCount(Equals(4)))
161
162+ def test_getComponentOverride_default_name(self):
163+ # getComponentOverride returns the default component name when an
164+ # unknown component name is passed.
165+ component_name = UnknownOverridePolicy.getComponentOverride('no-name')
166+
167+ self.assertEqual('universe', component_name)
168+
169+ def test_getComponentOverride_default_component(self):
170+ # getComponentOverride also accepts a component object (as
171+ # opposed to a component's name).
172+ component = getUtility(IComponentSet)['universe']
173+ component_name = UnknownOverridePolicy.getComponentOverride(component)
174+
175+ self.assertEqual('universe', component_name)
176+
177+ def test_getComponentOverride_return_component(self):
178+ # Passing return_component=True to getComponentOverride makes it
179+ # return the Component object (as opposed to the component's
180+ # name).
181+ universe_component = getUtility(IComponentSet)['universe']
182+ component = UnknownOverridePolicy.getComponentOverride(
183+ universe_component, return_component=True)
184+
185+ self.assertEqual(universe_component, component)
186+
187 def test_unknown_sources(self):
188 # If the unknown policy is used, it does no checks, just returns the
189 # defaults.
190
191=== modified file 'lib/lp/soyuz/model/packagecopyjob.py'
192--- lib/lp/soyuz/model/packagecopyjob.py 2011-08-16 15:12:42 +0000
193+++ lib/lp/soyuz/model/packagecopyjob.py 2011-08-23 15:24:55 +0000
194@@ -402,7 +402,7 @@
195
196 return SourceOverride(source_package_name, component, section)
197
198- def _checkPolicies(self, source_name):
199+ def _checkPolicies(self, source_name, source_component=None):
200 # This helper will only return if it's safe to carry on with the
201 # copy, otherwise it raises SuspendJobException to tell the job
202 # runner to suspend the job.
203@@ -418,7 +418,7 @@
204 # metadata.
205 defaults = UnknownOverridePolicy().calculateSourceOverrides(
206 self.target_archive, self.target_distroseries,
207- self.target_pocket, [source_name])
208+ self.target_pocket, [source_name], source_component)
209 self.addSourceOverride(defaults[0])
210
211 approve_new = copy_policy.autoApproveNew(
212@@ -502,7 +502,8 @@
213 pu = getUtility(IPackageUploadSet).getByPackageCopyJobIDs(
214 [self.context.id]).any()
215 if pu is None:
216- self._checkPolicies(source_name)
217+ self._checkPolicies(
218+ source_name, source_package.sourcepackagerelease.component)
219
220 # The package is free to go right in, so just copy it now.
221 override = self.getSourceOverride()
222
223=== modified file 'lib/lp/soyuz/tests/test_packagecopyjob.py'
224--- lib/lp/soyuz/tests/test_packagecopyjob.py 2011-08-18 20:07:33 +0000
225+++ lib/lp/soyuz/tests/test_packagecopyjob.py 2011-08-23 15:24:55 +0000
226@@ -705,7 +705,6 @@
227 self.assertEqual(None, existing_sources.any())
228
229 # Now, run the copy job.
230-
231 source = getUtility(IPlainPackageCopyJobSource)
232 requester = self.factory.makePerson()
233 job = source.create(
234@@ -731,6 +730,67 @@
235 # UnknownOverridePolicy policy.
236 self.assertEqual('universe', pcj.metadata['component_override'])
237
238+ def createCopyJob(self, sourcename, component, section, version):
239+ # Helper method to create a package copy job for a package with
240+ # the given sourcename, component, section and version.
241+ publisher = SoyuzTestPublisher()
242+ publisher.prepareBreezyAutotest()
243+ distroseries = publisher.breezy_autotest
244+
245+ target_archive = self.factory.makeArchive(
246+ distroseries.distribution, purpose=ArchivePurpose.PRIMARY)
247+ source_archive = self.factory.makeArchive()
248+
249+ # Publish a package in the source archive with some overridable
250+ # properties set to known values.
251+ publisher.getPubSource(
252+ distroseries=distroseries, sourcename=sourcename,
253+ component=component, section=section,
254+ version=version, status=PackagePublishingStatus.PUBLISHED,
255+ archive=source_archive)
256+
257+ # Now, run the copy job.
258+ source = getUtility(IPlainPackageCopyJobSource)
259+ requester = self.factory.makePerson()
260+ job = source.create(
261+ package_name=sourcename,
262+ package_version=version,
263+ source_archive=source_archive,
264+ target_archive=target_archive,
265+ target_distroseries=distroseries,
266+ target_pocket=PackagePublishingPocket.RELEASE,
267+ include_binaries=False,
268+ requester=requester)
269+
270+ # Run the job so it gains a PackageUpload.
271+ self.assertRaises(SuspendJobException, self.runJob, job)
272+ pcj = removeSecurityProxy(job).context
273+ return pcj
274+
275+ def test_copying_to_main_archive_debian_override_contrib(self):
276+ # The job uses the overrides to map debian components to
277+ # the right components.
278+ # 'contrib' gets mapped to 'multiverse'.
279+
280+ # Create debian component.
281+ self.factory.makeComponent('contrib')
282+ # Create a copy job for a package in 'contrib'.
283+ pcj = self.createCopyJob('package', 'contrib', 'web', '2.8.1')
284+
285+ self.assertEqual('multiverse', pcj.metadata['component_override'])
286+
287+ def test_copying_to_main_archive_debian_override_nonfree(self):
288+ # The job uses the overrides to map debian components to
289+ # the right components.
290+ # 'nonfree' gets mapped to 'multiverse'.
291+
292+ # Create debian component.
293+ self.factory.makeComponent('non-free')
294+ # Create a copy job for a package in 'non-free'.
295+ pcj = self.createCopyJob('package', 'non-free', 'web', '2.8.1')
296+
297+ self.assertEqual('multiverse', pcj.metadata['component_override'])
298+
299 def test_copying_to_main_archive_unapproved(self):
300 # Uploading to a series that is in a state that precludes auto
301 # approval will cause the job to suspend and a packageupload
302
303=== modified file 'lib/lp/soyuz/tests/test_publishing.py'
304--- lib/lp/soyuz/tests/test_publishing.py 2011-08-15 03:41:35 +0000
305+++ lib/lp/soyuz/tests/test_publishing.py 2011-08-23 15:24:55 +0000
306@@ -886,7 +886,7 @@
307 self.assertEquals(copy.component.name, 'universe')
308
309 def test_overrideFromAncestry_fallback_to_source_component(self):
310- # overrideFromancestry on the lack of ancestry, falls back to the
311+ # overrideFromAncestry on the lack of ancestry, falls back to the
312 # component the source was originally uploaded to.
313 source = self.makeSource()
314