Merge lp:~cjwatson/launchpad/copy-set-phase into lp:launchpad
- copy-set-phase
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Colin Watson |
Approved revision: | no longer in the source branch. |
Merged at revision: | 16697 |
Proposed branch: | lp:~cjwatson/launchpad/copy-set-phase |
Merge into: | lp:launchpad |
Diff against target: |
721 lines (+191/-53) 17 files modified
lib/lp/archiveuploader/tests/nascentupload-ddebs.txt (+5/-3) lib/lp/soyuz/adapters/overrides.py (+25/-6) lib/lp/soyuz/adapters/tests/test_overrides.py (+46/-5) lib/lp/soyuz/interfaces/archive.py (+11/-2) lib/lp/soyuz/interfaces/packagecopyjob.py (+8/-2) lib/lp/soyuz/interfaces/publishing.py (+1/-1) lib/lp/soyuz/model/archive.py (+14/-4) lib/lp/soyuz/model/packagecopyjob.py (+10/-3) lib/lp/soyuz/model/publishing.py (+16/-11) lib/lp/soyuz/model/queue.py (+2/-1) lib/lp/soyuz/scripts/packagecopier.py (+12/-4) lib/lp/soyuz/scripts/tests/test_copypackage.py (+21/-0) lib/lp/soyuz/stories/soyuz/xx-person-packages.txt (+8/-5) lib/lp/soyuz/tests/test_archive.py (+4/-2) lib/lp/soyuz/tests/test_packagecopyjob.py (+3/-1) lib/lp/soyuz/tests/test_publishing.py (+4/-2) lib/lp/testing/factory.py (+1/-1) |
To merge this branch: | bzr merge lp:~cjwatson/launchpad/copy-set-phase |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
William Grant | code | Approve | |
Review via email: mp+170775@code.launchpad.net |
Commit message
Allow setting the phased-
Description of the change
== Summary ==
Copying packages to the -updates pocket but gradually phasing them in using the phased_
== Proposed fix ==
Add a phased_
== LOC Rationale ==
+133. This is making an existing feature properly usable so I think it's reasonable; and I have a good track record at removing LoC from LP ...
== Tests ==
bin/test -vvct lp.soyuz.
== Demo and Q/A ==
''Explain how to demonstrate the fix and how to carry out QA on it.''
On DF, pick two packages in PROPOSED pockets but not elsewhere and copy them to UPDATES, one with phased_
Preview Diff
1 | === modified file 'lib/lp/archiveuploader/tests/nascentupload-ddebs.txt' |
2 | --- lib/lp/archiveuploader/tests/nascentupload-ddebs.txt 2013-05-24 03:05:34 +0000 |
3 | +++ lib/lp/archiveuploader/tests/nascentupload-ddebs.txt 2013-06-21 17:17:27 +0000 |
4 | @@ -81,6 +81,7 @@ |
5 | |
6 | We override the binary to main/devel, and accept it into the archive. |
7 | |
8 | + >>> from operator import attrgetter |
9 | >>> from lp.soyuz.interfaces.component import IComponentSet |
10 | >>> from lp.soyuz.interfaces.section import ISectionSet |
11 | >>> main = getUtility(IComponentSet)['main'] |
12 | @@ -99,7 +100,8 @@ |
13 | |
14 | >>> switch_dbuser(config.uploadqueue.dbuser) |
15 | |
16 | - >>> bin_pubs = bin.queue_root.realiseUpload() |
17 | + >>> bin_pubs = sorted( |
18 | + ... bin.queue_root.realiseUpload(), key=attrgetter('displayname')) |
19 | |
20 | >>> switch_dbuser('uploader') |
21 | |
22 | @@ -109,8 +111,8 @@ |
23 | ... print '%s %s %s %s' % ( |
24 | ... bin_pub.displayname, bin_pub.status.name, |
25 | ... bin_pub.component.name, bin_pub.section.name) |
26 | + debug-bin 1.0-1 in hoary i386 PENDING main devel |
27 | debug-bin-dbgsym 1.0-1 in hoary i386 PENDING main devel |
28 | - debug-bin 1.0-1 in hoary i386 PENDING main devel |
29 | |
30 | DEBs and DDEBs are uploaded to separate archives, because the size |
31 | impact of uploading them to a single archive on mirrors would be |
32 | @@ -118,7 +120,7 @@ |
33 | |
34 | The DDEB is stored appropriately in the database. |
35 | |
36 | - >>> [ddeb_pub, deb_pub] = bin_pubs |
37 | + >>> [deb_pub, ddeb_pub] = bin_pubs |
38 | >>> ddeb = ddeb_pub.binarypackagerelease |
39 | |
40 | >>> print ddeb.title |
41 | |
42 | === modified file 'lib/lp/soyuz/adapters/overrides.py' |
43 | --- lib/lp/soyuz/adapters/overrides.py 2013-06-20 05:50:00 +0000 |
44 | +++ lib/lp/soyuz/adapters/overrides.py 2013-06-21 17:17:27 +0000 |
45 | @@ -70,6 +70,8 @@ |
46 | "The IDistroArchSeries for the publication") |
47 | priority = Attribute( |
48 | "The PackagePublishingPriority that's being overridden") |
49 | + phased_update_percentage = Attribute( |
50 | + "The phased update percentage that's being overridden") |
51 | |
52 | |
53 | class Override: |
54 | @@ -109,11 +111,12 @@ |
55 | implements(IBinaryOverride) |
56 | |
57 | def __init__(self, binary_package_name, distro_arch_series, component, |
58 | - section, priority): |
59 | + section, priority, phased_update_percentage): |
60 | super(BinaryOverride, self).__init__(component, section) |
61 | self.binary_package_name = binary_package_name |
62 | self.distro_arch_series = distro_arch_series |
63 | self.priority = priority |
64 | + self.phased_update_percentage = phased_update_percentage |
65 | |
66 | def __eq__(self, other): |
67 | return ( |
68 | @@ -121,13 +124,16 @@ |
69 | self.distro_arch_series == other.distro_arch_series and |
70 | self.component == other.component and |
71 | self.section == other.section and |
72 | - self.priority == other.priority) |
73 | + self.priority == other.priority and |
74 | + self.phased_update_percentage == other.phased_update_percentage) |
75 | |
76 | def __repr__(self): |
77 | return ("<BinaryOverride at %x component=%r section=%r " |
78 | - "binary_package_name=%r distro_arch_series=%r priority=%r>" % |
79 | + "binary_package_name=%r distro_arch_series=%r priority=%r " |
80 | + "phased_update_percentage=%r>" % |
81 | (id(self), self.component, self.section, self.binary_package_name, |
82 | - self.distro_arch_series, self.priority)) |
83 | + self.distro_arch_series, self.priority, |
84 | + self.phased_update_percentage)) |
85 | |
86 | |
87 | class IOverridePolicy(Interface): |
88 | @@ -140,6 +146,9 @@ |
89 | keep the same component and section as their ancestor publications. |
90 | """ |
91 | |
92 | + phased_update_percentage = Attribute( |
93 | + "The phased update percentage to apply to binary publications.") |
94 | + |
95 | def calculateSourceOverrides(archive, distroseries, pocket, sources, |
96 | source_component=None): |
97 | """Calculate source overrides. |
98 | @@ -173,6 +182,10 @@ |
99 | |
100 | implements(IOverridePolicy) |
101 | |
102 | + def __init__(self, phased_update_percentage=None): |
103 | + super(BaseOverridePolicy, self).__init__() |
104 | + self.phased_update_percentage = phased_update_percentage |
105 | + |
106 | def calculateSourceOverrides(self, archive, distroseries, pocket, |
107 | sources, source_component=None): |
108 | raise NotImplementedError() |
109 | @@ -245,6 +258,8 @@ |
110 | for bpn, das in expanded if das is not None] |
111 | if len(candidates) == 0: |
112 | return [] |
113 | + # Do not copy phased_update_percentage from existing publications; |
114 | + # it is too context-dependent to copy. |
115 | already_published = DecoratedResultSet( |
116 | store.find( |
117 | (BinaryPackagePublishingHistory.binarypackagenameID, |
118 | @@ -269,7 +284,9 @@ |
119 | None)), |
120 | pre_iter_hook=eager_load) |
121 | return [ |
122 | - BinaryOverride(name, das, component, section, priority) |
123 | + BinaryOverride( |
124 | + name, das, component, section, priority, |
125 | + self.phased_update_percentage) |
126 | for name, das, component, section, priority in already_published] |
127 | |
128 | |
129 | @@ -324,7 +341,9 @@ |
130 | default_component = archive.default_component or getUtility( |
131 | IComponentSet)['universe'] |
132 | return [ |
133 | - BinaryOverride(binary, das, default_component, None, None) |
134 | + BinaryOverride( |
135 | + binary, das, default_component, None, None, |
136 | + self.phased_update_percentage) |
137 | for binary, das in calculate_target_das(distroseries, binaries)] |
138 | |
139 | |
140 | |
141 | === modified file 'lib/lp/soyuz/adapters/tests/test_overrides.py' |
142 | --- lib/lp/soyuz/adapters/tests/test_overrides.py 2013-05-23 07:06:42 +0000 |
143 | +++ lib/lp/soyuz/adapters/tests/test_overrides.py 2013-06-21 17:17:27 +0000 |
144 | @@ -1,4 +1,4 @@ |
145 | -# Copyright 2011 Canonical Ltd. This software is licensed under the |
146 | +# Copyright 2011-2013 Canonical Ltd. This software is licensed under the |
147 | # GNU Affero General Public License version 3 (see the file LICENSE). |
148 | |
149 | """Test generic override policy classes.""" |
150 | @@ -124,7 +124,7 @@ |
151 | BinaryOverride( |
152 | bpph.binarypackagerelease.binarypackagename, |
153 | bpph.distroarchseries, bpph.component, bpph.section, |
154 | - bpph.priority)] |
155 | + bpph.priority, None)] |
156 | self.assertEqual(expected, overrides) |
157 | |
158 | def test_binary_overrides_constant_query_count(self): |
159 | @@ -203,7 +203,7 @@ |
160 | expected = [ |
161 | BinaryOverride( |
162 | bpph.binarypackagerelease.binarypackagename, |
163 | - bpph.distroarchseries, universe, None, None)] |
164 | + bpph.distroarchseries, universe, None, None, None)] |
165 | self.assertEqual(expected, overrides) |
166 | |
167 | def test_ubuntu_override_policy_sources(self): |
168 | @@ -259,13 +259,14 @@ |
169 | expected.append( |
170 | BinaryOverride( |
171 | bpn, distroarchseries, bpph.component, bpph.section, |
172 | - bpph.priority)) |
173 | + bpph.priority, None)) |
174 | for i in xrange(2): |
175 | distroarchseries = self.factory.makeDistroArchSeries( |
176 | distroseries=distroseries) |
177 | bpns.append((bpn, distroarchseries.architecturetag)) |
178 | expected.append( |
179 | - BinaryOverride(bpn, distroarchseries, universe, None, None)) |
180 | + BinaryOverride( |
181 | + bpn, distroarchseries, universe, None, None, None)) |
182 | distroseries.nominatedarchindep = distroarchseries |
183 | policy = UbuntuOverridePolicy() |
184 | overrides = policy.calculateBinaryOverrides( |
185 | @@ -294,3 +295,43 @@ |
186 | distroseries.main_archive, distroseries, pocket, ((bpn, 'i386'),)) |
187 | |
188 | self.assertEqual([], overrides) |
189 | + |
190 | + def test_phased_update_percentage(self): |
191 | + # A policy with a phased_update_percentage applies it to new binary |
192 | + # overrides. |
193 | + universe = getUtility(IComponentSet)['universe'] |
194 | + distroseries = self.factory.makeDistroSeries() |
195 | + pocket = self.factory.getAnyPocket() |
196 | + bpn = self.factory.makeBinaryPackageName() |
197 | + bpns = [] |
198 | + expected = [] |
199 | + distroarchseries = self.factory.makeDistroArchSeries( |
200 | + distroseries=distroseries) |
201 | + bpb = self.factory.makeBinaryPackageBuild( |
202 | + distroarchseries=distroarchseries) |
203 | + bpr = self.factory.makeBinaryPackageRelease( |
204 | + build=bpb, binarypackagename=bpn, architecturespecific=True) |
205 | + bpph = self.factory.makeBinaryPackagePublishingHistory( |
206 | + binarypackagerelease=bpr, distroarchseries=distroarchseries, |
207 | + archive=distroseries.main_archive, pocket=pocket) |
208 | + bpns.append((bpn, distroarchseries.architecturetag)) |
209 | + expected.append( |
210 | + BinaryOverride( |
211 | + bpn, distroarchseries, bpph.component, bpph.section, |
212 | + bpph.priority, 50)) |
213 | + distroarchseries = self.factory.makeDistroArchSeries( |
214 | + distroseries=distroseries) |
215 | + bpns.append((bpn, distroarchseries.architecturetag)) |
216 | + expected.append( |
217 | + BinaryOverride(bpn, distroarchseries, universe, None, None, 50)) |
218 | + distroseries.nominatedarchindep = distroarchseries |
219 | + policy = UbuntuOverridePolicy(phased_update_percentage=50) |
220 | + overrides = policy.calculateBinaryOverrides( |
221 | + distroseries.main_archive, distroseries, pocket, bpns) |
222 | + self.assertEqual(2, len(overrides)) |
223 | + key = attrgetter("binary_package_name.name", |
224 | + "distro_arch_series.architecturetag", |
225 | + "component.name") |
226 | + sorted_expected = sorted(expected, key=key) |
227 | + sorted_overrides = sorted(overrides, key=key) |
228 | + self.assertEqual(sorted_expected, sorted_overrides) |
229 | |
230 | === modified file 'lib/lp/soyuz/interfaces/archive.py' |
231 | --- lib/lp/soyuz/interfaces/archive.py 2013-05-24 04:49:14 +0000 |
232 | +++ lib/lp/soyuz/interfaces/archive.py 2013-06-21 17:17:27 +0000 |
233 | @@ -1042,7 +1042,7 @@ |
234 | def getPockets(): |
235 | """Return iterable containing valid pocket names for this archive.""" |
236 | |
237 | - def getOverridePolicy(): |
238 | + def getOverridePolicy(phased_update_percentage=None): |
239 | """Returns an instantiated `IOverridePolicy` for the archive.""" |
240 | |
241 | buildd_secret = TextLine( |
242 | @@ -1356,13 +1356,20 @@ |
243 | from_pocket=TextLine(title=_("Source pocket name"), required=False), |
244 | from_series=TextLine( |
245 | title=_("Source distroseries name"), required=False), |
246 | + phased_update_percentage=Int( |
247 | + title=_("Phased update percentage"), |
248 | + description=_("The percentage of users for whom this package" |
249 | + " should be recommended, or None to publish the" |
250 | + " update for everyone."), |
251 | + required=False), |
252 | ) |
253 | @export_write_operation() |
254 | @operation_for_version('devel') |
255 | def copyPackage(source_name, version, from_archive, to_pocket, |
256 | person, to_series=None, include_binaries=False, |
257 | sponsored=None, unembargo=False, auto_approve=False, |
258 | - from_pocket=None, from_series=None): |
259 | + from_pocket=None, from_series=None, |
260 | + phased_update_percentage=None): |
261 | """Copy a single named source into this archive. |
262 | |
263 | Asynchronously copy a specific version of a named source to the |
264 | @@ -1393,6 +1400,8 @@ |
265 | copy from any pocket with a matching version. |
266 | :param from_series: the source distroseries (as a string). If |
267 | omitted, copy from any series with a matching version. |
268 | + :param phased_update_percentage: the phased update percentage to |
269 | + apply to the copied publication. |
270 | |
271 | :raises NoSuchSourcePackageName: if the source name is invalid |
272 | :raises PocketNotFound: if the pocket name is invalid |
273 | |
274 | === modified file 'lib/lp/soyuz/interfaces/packagecopyjob.py' |
275 | --- lib/lp/soyuz/interfaces/packagecopyjob.py 2012-10-23 12:36:50 +0000 |
276 | +++ lib/lp/soyuz/interfaces/packagecopyjob.py 2013-06-21 17:17:27 +0000 |
277 | @@ -1,4 +1,4 @@ |
278 | -# Copyright 2010-2012 Canonical Ltd. This software is licensed under the |
279 | +# Copyright 2010-2013 Canonical Ltd. This software is licensed under the |
280 | # GNU Affero General Public License version 3 (see the file LICENSE). |
281 | |
282 | __metaclass__ = type |
283 | @@ -129,7 +129,8 @@ |
284 | include_binaries=False, package_version=None, |
285 | copy_policy=PackageCopyPolicy.INSECURE, requester=None, |
286 | sponsored=None, unembargo=False, auto_approve=False, |
287 | - source_distroseries=None, source_pocket=None): |
288 | + source_distroseries=None, source_pocket=None, |
289 | + phased_update_percentage=None): |
290 | """Create a new `IPlainPackageCopyJob`. |
291 | |
292 | :param package_name: The name of the source package to copy. |
293 | @@ -157,6 +158,8 @@ |
294 | :param source_pocket: The pocket from which to copy the packages. |
295 | Must be a member of `PackagePublishingPocket`. If omitted, copy |
296 | from any pocket with a matching version. |
297 | + :param phased_update_percentage: The phased update percentage to |
298 | + apply to the copied publication. |
299 | """ |
300 | |
301 | def createMultiple(target_distroseries, copy_tasks, requester, |
302 | @@ -242,6 +245,9 @@ |
303 | title=_("Source package publishing pocket"), required=False, |
304 | readonly=True) |
305 | |
306 | + phased_update_percentage = Int( |
307 | + title=_("Phased update percentage"), required=False, readonly=True) |
308 | + |
309 | def addSourceOverride(override): |
310 | """Add an `ISourceOverride` to the metadata.""" |
311 | |
312 | |
313 | === modified file 'lib/lp/soyuz/interfaces/publishing.py' |
314 | --- lib/lp/soyuz/interfaces/publishing.py 2013-05-31 04:00:53 +0000 |
315 | +++ lib/lp/soyuz/interfaces/publishing.py 2013-06-21 17:17:27 +0000 |
316 | @@ -991,7 +991,7 @@ |
317 | :param pocket: The target `PackagePublishingPocket`. |
318 | :param binaries: A dict mapping `BinaryPackageReleases` to their |
319 | desired overrides as (`Component`, `Section`, |
320 | - `PackagePublishingPriority`) tuples. |
321 | + `PackagePublishingPriority`, `phased_update_percentage`) tuples. |
322 | |
323 | :return: A list of new `IBinaryPackagePublishingHistory` records. |
324 | """ |
325 | |
326 | === modified file 'lib/lp/soyuz/model/archive.py' |
327 | --- lib/lp/soyuz/model/archive.py 2013-06-20 05:50:00 +0000 |
328 | +++ lib/lp/soyuz/model/archive.py 2013-06-21 17:17:27 +0000 |
329 | @@ -1635,9 +1635,17 @@ |
330 | def copyPackage(self, source_name, version, from_archive, to_pocket, |
331 | person, to_series=None, include_binaries=False, |
332 | sponsored=None, unembargo=False, auto_approve=False, |
333 | - from_pocket=None, from_series=None): |
334 | + from_pocket=None, from_series=None, |
335 | + phased_update_percentage=None): |
336 | """See `IArchive`.""" |
337 | # Asynchronously copy a package using the job system. |
338 | + if phased_update_percentage is not None: |
339 | + if phased_update_percentage < 0 or phased_update_percentage > 100: |
340 | + raise ValueError( |
341 | + "phased_update_percentage must be between 0 and 100 " |
342 | + "(inclusive).") |
343 | + elif phased_update_percentage == 100: |
344 | + phased_update_percentage = None |
345 | pocket = self._text_to_pocket(to_pocket) |
346 | series = self._text_to_series(to_series) |
347 | if from_pocket: |
348 | @@ -1663,7 +1671,8 @@ |
349 | copy_policy=PackageCopyPolicy.INSECURE, requester=person, |
350 | sponsored=sponsored, unembargo=unembargo, |
351 | auto_approve=auto_approve, source_distroseries=from_series, |
352 | - source_pocket=from_pocket) |
353 | + source_pocket=from_pocket, |
354 | + phased_update_percentage=phased_update_percentage) |
355 | |
356 | def copyPackages(self, source_names, from_archive, to_pocket, |
357 | person, to_series=None, from_series=None, |
358 | @@ -1996,14 +2005,15 @@ |
359 | # understandiung EnumItems. |
360 | return list(PackagePublishingPocket.items) |
361 | |
362 | - def getOverridePolicy(self): |
363 | + def getOverridePolicy(self, phased_update_percentage=None): |
364 | """See `IArchive`.""" |
365 | # Circular imports. |
366 | from lp.soyuz.adapters.overrides import UbuntuOverridePolicy |
367 | # XXX StevenK: bug=785004 2011-05-19 Return PPAOverridePolicy() for |
368 | # a PPA that overrides the component/pocket to main/RELEASE. |
369 | if self.purpose in MAIN_ARCHIVE_PURPOSES: |
370 | - return UbuntuOverridePolicy() |
371 | + return UbuntuOverridePolicy( |
372 | + phased_update_percentage=phased_update_percentage) |
373 | return None |
374 | |
375 | def removeCopyNotification(self, job_id): |
376 | |
377 | === modified file 'lib/lp/soyuz/model/packagecopyjob.py' |
378 | --- lib/lp/soyuz/model/packagecopyjob.py 2013-06-20 05:50:00 +0000 |
379 | +++ lib/lp/soyuz/model/packagecopyjob.py 2013-06-21 17:17:27 +0000 |
380 | @@ -272,7 +272,7 @@ |
381 | def _makeMetadata(cls, target_pocket, package_version, |
382 | include_binaries, sponsored=None, unembargo=False, |
383 | auto_approve=False, source_distroseries=None, |
384 | - source_pocket=None): |
385 | + source_pocket=None, phased_update_percentage=None): |
386 | """Produce a metadata dict for this job.""" |
387 | return { |
388 | 'target_pocket': target_pocket.value, |
389 | @@ -284,6 +284,7 @@ |
390 | 'source_distroseries': |
391 | source_distroseries.name if source_distroseries else None, |
392 | 'source_pocket': source_pocket.value if source_pocket else None, |
393 | + 'phased_update_percentage': phased_update_percentage, |
394 | } |
395 | |
396 | @classmethod |
397 | @@ -292,13 +293,15 @@ |
398 | include_binaries=False, package_version=None, |
399 | copy_policy=PackageCopyPolicy.INSECURE, requester=None, |
400 | sponsored=None, unembargo=False, auto_approve=False, |
401 | - source_distroseries=None, source_pocket=None): |
402 | + source_distroseries=None, source_pocket=None, |
403 | + phased_update_percentage=None): |
404 | """See `IPlainPackageCopyJobSource`.""" |
405 | assert package_version is not None, "No package version specified." |
406 | assert requester is not None, "No requester specified." |
407 | metadata = cls._makeMetadata( |
408 | target_pocket, package_version, include_binaries, sponsored, |
409 | - unembargo, auto_approve, source_distroseries, source_pocket) |
410 | + unembargo, auto_approve, source_distroseries, source_pocket, |
411 | + phased_update_percentage) |
412 | job = PackageCopyJob( |
413 | job_type=cls.class_job_type, |
414 | source_archive=source_archive, |
415 | @@ -451,6 +454,10 @@ |
416 | return None |
417 | return PackagePublishingPocket.items[name] |
418 | |
419 | + @property |
420 | + def phased_update_percentage(self): |
421 | + return self.metadata.get('phased_update_percentage') |
422 | + |
423 | def _createPackageUpload(self, unapproved=False): |
424 | pu = self.target_distroseries.createQueueEntry( |
425 | pocket=self.target_pocket, archive=self.target_archive, |
426 | |
427 | === modified file 'lib/lp/soyuz/model/publishing.py' |
428 | --- lib/lp/soyuz/model/publishing.py 2013-06-21 02:49:33 +0000 |
429 | +++ lib/lp/soyuz/model/publishing.py 2013-06-21 17:17:27 +0000 |
430 | @@ -1445,20 +1445,18 @@ |
431 | return [] |
432 | |
433 | BPPH = BinaryPackagePublishingHistory |
434 | - # XXX cjwatson 2013-02-13: We do not currently set the |
435 | - # phased_update_percentage here. However, it might be useful in |
436 | - # future to be able to copy a package from PROPOSED to UPDATES and |
437 | - # immediately set its phased_update_percentage to zero; this should |
438 | - # perhaps be an option. |
439 | return bulk.create( |
440 | (BPPH.archive, BPPH.distroarchseries, BPPH.pocket, |
441 | BPPH.binarypackagerelease, BPPH.binarypackagename, |
442 | - BPPH.component, BPPH.section, BPPH.priority, BPPH.status, |
443 | - BPPH.datecreated), |
444 | + BPPH.component, BPPH.section, BPPH.priority, |
445 | + BPPH.phased_update_percentage, BPPH.status, BPPH.datecreated), |
446 | [(archive, das, pocket, bpr, bpr.binarypackagename, |
447 | get_component(archive, das.distroseries, component), |
448 | - section, priority, PackagePublishingStatus.PENDING, UTC_NOW) |
449 | - for (das, bpr, (component, section, priority)) in needed], |
450 | + section, priority, phased_update_percentage, |
451 | + PackagePublishingStatus.PENDING, UTC_NOW) |
452 | + for (das, bpr, |
453 | + (component, section, priority, |
454 | + phased_update_percentage)) in needed], |
455 | get_objects=True) |
456 | |
457 | def copyBinaries(self, archive, distroseries, pocket, bpphs, policy=None): |
458 | @@ -1500,7 +1498,14 @@ |
459 | new_component = override.component or bpph.component |
460 | new_section = override.section or bpph.section |
461 | new_priority = override.priority or bpph.priority |
462 | - calculated = (new_component, new_section, new_priority) |
463 | + # No "or bpph.phased_update_percentage" here; if the |
464 | + # override doesn't specify one then we leave it at None |
465 | + # (a.k.a. 100% of users). |
466 | + new_phased_update_percentage = ( |
467 | + override.phased_update_percentage) |
468 | + calculated = ( |
469 | + new_component, new_section, new_priority, |
470 | + new_phased_update_percentage) |
471 | with_overrides[bpph.binarypackagerelease] = calculated |
472 | |
473 | # If there is a corresponding DDEB then give it our |
474 | @@ -1514,7 +1519,7 @@ |
475 | else: |
476 | with_overrides = dict( |
477 | (bpph.binarypackagerelease, (bpph.component, bpph.section, |
478 | - bpph.priority)) for bpph in bpphs) |
479 | + bpph.priority, None)) for bpph in bpphs) |
480 | if not with_overrides: |
481 | return list() |
482 | return self.publishBinaries( |
483 | |
484 | === modified file 'lib/lp/soyuz/model/queue.py' |
485 | --- lib/lp/soyuz/model/queue.py 2013-06-20 05:50:00 +0000 |
486 | +++ lib/lp/soyuz/model/queue.py 2013-06-21 17:17:27 +0000 |
487 | @@ -1207,7 +1207,8 @@ |
488 | binary.version, |
489 | 'Specific' if binary.architecturespecific else 'Independent', |
490 | )) |
491 | - bins[binary] = (binary.component, binary.section, binary.priority) |
492 | + bins[binary] = ( |
493 | + binary.component, binary.section, binary.priority, None) |
494 | return getUtility(IPublishingSet).publishBinaries( |
495 | self.packageupload.archive, distroseries, |
496 | self.packageupload.pocket, bins) |
497 | |
498 | === modified file 'lib/lp/soyuz/scripts/packagecopier.py' |
499 | --- lib/lp/soyuz/scripts/packagecopier.py 2013-06-21 02:39:33 +0000 |
500 | +++ lib/lp/soyuz/scripts/packagecopier.py 2013-06-21 17:17:27 +0000 |
501 | @@ -506,7 +506,8 @@ |
502 | person=None, check_permissions=True, overrides=None, |
503 | send_email=False, strict_binaries=True, close_bugs=True, |
504 | create_dsd_job=True, announce_from_person=None, sponsored=None, |
505 | - packageupload=None, unembargo=False, logger=None): |
506 | + packageupload=None, unembargo=False, phased_update_percentage=None, |
507 | + logger=None): |
508 | """Perform the complete copy of the given sources incrementally. |
509 | |
510 | Verifies if each copy can be performed using `CopyChecker` and |
511 | @@ -553,6 +554,8 @@ |
512 | :param unembargo: If True, allow copying restricted files from a private |
513 | archive to a public archive, and unrestrict their library files when |
514 | doing so. |
515 | + :param phased_update_percentage: The phased update percentage to apply |
516 | + to the copied publication. |
517 | :param logger: An optional logger. |
518 | |
519 | :raise CannotCopy when one or more copies were not allowed. The error |
520 | @@ -628,7 +631,8 @@ |
521 | source, archive, destination_series, pocket, include_binaries, |
522 | override, close_bugs=close_bugs, create_dsd_job=create_dsd_job, |
523 | close_bugs_since_version=old_version, creator=creator, |
524 | - sponsor=sponsor, packageupload=packageupload, logger=logger) |
525 | + sponsor=sponsor, packageupload=packageupload, |
526 | + phased_update_percentage=phased_update_percentage, logger=logger) |
527 | if send_email: |
528 | notify( |
529 | person, source.sourcepackagerelease, [], [], archive, |
530 | @@ -655,7 +659,8 @@ |
531 | def _do_direct_copy(source, archive, series, pocket, include_binaries, |
532 | override=None, close_bugs=True, create_dsd_job=True, |
533 | close_bugs_since_version=None, creator=None, |
534 | - sponsor=None, packageupload=None, logger=None): |
535 | + sponsor=None, packageupload=None, |
536 | + phased_update_percentage=None, logger=None): |
537 | """Copy publishing records to another location. |
538 | |
539 | Copy each item of the given list of `SourcePackagePublishingHistory` |
540 | @@ -685,6 +690,8 @@ |
541 | :param sponsor: the sponsor `IPerson`, if this copy is being sponsored. |
542 | :param packageupload: The `IPackageUpload` that caused this publication |
543 | to be created. |
544 | + :param phased_update_percentage: The phased update percentage to apply |
545 | + to the copied publication. |
546 | :param logger: An optional logger. |
547 | |
548 | :return: a list of `ISourcePackagePublishingHistory` and |
549 | @@ -703,7 +710,8 @@ |
550 | version=source.sourcepackagerelease.version, |
551 | status=active_publishing_status, |
552 | distroseries=series, pocket=pocket) |
553 | - policy = archive.getOverridePolicy() |
554 | + policy = archive.getOverridePolicy( |
555 | + phased_update_percentage=phased_update_percentage) |
556 | if source_in_destination.is_empty(): |
557 | # If no manual overrides were specified and the archive has an |
558 | # override policy then use that policy to get overrides. |
559 | |
560 | === modified file 'lib/lp/soyuz/scripts/tests/test_copypackage.py' |
561 | --- lib/lp/soyuz/scripts/tests/test_copypackage.py 2013-05-29 07:24:13 +0000 |
562 | +++ lib/lp/soyuz/scripts/tests/test_copypackage.py 2013-06-21 17:17:27 +0000 |
563 | @@ -1380,6 +1380,27 @@ |
564 | section=override.section) |
565 | self.assertThat(copied_source, matcher) |
566 | |
567 | + def test_copy_with_phased_update_percentage(self): |
568 | + # Test the phased_update_percentage parameter for do_copy. |
569 | + nobby, archive, source = self._setup_archive( |
570 | + use_nobby=True, pocket=PackagePublishingPocket.PROPOSED) |
571 | + [bin_i386, bin_hppa] = self.test_publisher.getPubBinaries( |
572 | + pub_source=source, distroseries=nobby, |
573 | + pocket=PackagePublishingPocket.PROPOSED) |
574 | + transaction.commit() |
575 | + switch_dbuser('archivepublisher') |
576 | + [copied_source, copied_bin_i386, copied_bin_hppa] = do_copy( |
577 | + [source], archive, nobby, PackagePublishingPocket.UPDATES, |
578 | + include_binaries=True, check_permissions=False) |
579 | + self.assertIsNone(copied_bin_i386.phased_update_percentage) |
580 | + self.assertIsNone(copied_bin_hppa.phased_update_percentage) |
581 | + [copied_source, copied_bin_i386, copied_bin_hppa] = do_copy( |
582 | + [source], archive, nobby, PackagePublishingPocket.BACKPORTS, |
583 | + include_binaries=True, check_permissions=False, |
584 | + phased_update_percentage=50) |
585 | + self.assertEqual(50, copied_bin_i386.phased_update_percentage) |
586 | + self.assertEqual(50, copied_bin_hppa.phased_update_percentage) |
587 | + |
588 | def test_copy_ppa_generates_notification(self): |
589 | # When a copy into a PPA is performed, a notification is sent. |
590 | nobby, archive, source = self._setup_archive() |
591 | |
592 | === modified file 'lib/lp/soyuz/stories/soyuz/xx-person-packages.txt' |
593 | --- lib/lp/soyuz/stories/soyuz/xx-person-packages.txt 2013-06-20 05:50:00 +0000 |
594 | +++ lib/lp/soyuz/stories/soyuz/xx-person-packages.txt 2013-06-21 17:17:27 +0000 |
595 | @@ -189,9 +189,11 @@ |
596 | Create some new source packages, source1 and source2, both created by cprov |
597 | so that they appear in his +packages page. |
598 | |
599 | + >>> from storm.expr import SQL |
600 | >>> from zope.component import getUtility |
601 | >>> from lp.registry.interfaces.distribution import IDistributionSet |
602 | >>> from lp.registry.interfaces.person import IPersonSet |
603 | + >>> from lp.services.database.constants import UTC_NOW |
604 | >>> from lp.soyuz.tests.test_publishing import SoyuzTestPublisher |
605 | >>> from lp.soyuz.enums import PackagePublishingStatus |
606 | |
607 | @@ -207,7 +209,8 @@ |
608 | >>> source1 = test_publisher.getPubSource( |
609 | ... status=PackagePublishingStatus.PUBLISHED, |
610 | ... sourcename='source1', |
611 | - ... archive=cprov.archive) |
612 | + ... archive=cprov.archive, |
613 | + ... date_uploaded=UTC_NOW - SQL("INTERVAL '1 second'")) |
614 | >>> source1.sourcepackagerelease.creator=cprov |
615 | >>> source1_mark = source1.copyTo( |
616 | ... source1.distroseries, source1.pocket, mark.archive) |
617 | @@ -260,17 +263,17 @@ |
618 | >>> nopriv_browser = setupBrowser(auth="Basic no-priv@canonical.com:test") |
619 | >>> nopriv_browser.open("http://launchpad.dev/~cprov/+related-packages") |
620 | >>> print_ppa_rows(nopriv_browser) |
621 | + source2 PPA named p3a for No Priv... Ubuntutest Breezy-autotest 666 |
622 | + ...ago None |
623 | source1 PPA for Celso Providelo - Ubuntutest Breezy-autotest 666 |
624 | ...ago None |
625 | - source2 PPA named p3a for No Priv... Ubuntutest Breezy-autotest 666 |
626 | - ...ago None |
627 | |
628 | >>> admin_browser.open("http://launchpad.dev/~cprov/+related-packages") |
629 | >>> print_ppa_rows(admin_browser) |
630 | + source2 PPA named p3a for No Priv... Ubuntutest Breezy-autotest 666 |
631 | + ...ago None |
632 | source1 PPA for Celso Providelo - Ubuntutest Breezy-autotest 666 |
633 | ...ago None |
634 | - source2 PPA named p3a for No Priv... Ubuntutest Breezy-autotest 666 |
635 | - ...ago None |
636 | |
637 | Let's move the publication of source1 from mark's public archive to his |
638 | private one and the view the page again. |
639 | |
640 | === modified file 'lib/lp/soyuz/tests/test_archive.py' |
641 | --- lib/lp/soyuz/tests/test_archive.py 2013-06-20 05:50:00 +0000 |
642 | +++ lib/lp/soyuz/tests/test_archive.py 2013-06-21 17:17:27 +0000 |
643 | @@ -2154,7 +2154,8 @@ |
644 | target_archive.copyPackage( |
645 | source_name, version, source_archive, to_pocket.name, |
646 | to_series=to_series.name, include_binaries=False, |
647 | - person=target_archive.owner, sponsored=sponsored) |
648 | + person=target_archive.owner, sponsored=sponsored, |
649 | + phased_update_percentage=30) |
650 | |
651 | # The source should not be published yet in the target_archive. |
652 | published = target_archive.getPublishedSources( |
653 | @@ -2175,7 +2176,8 @@ |
654 | target_pocket=to_pocket, |
655 | include_binaries=False, |
656 | sponsored=sponsored, |
657 | - copy_policy=PackageCopyPolicy.INSECURE)) |
658 | + copy_policy=PackageCopyPolicy.INSECURE, |
659 | + phased_update_percentage=30)) |
660 | |
661 | def test_copyPackage_disallows_non_primary_archive_uploaders(self): |
662 | # If copying to a primary archive and you're not an uploader for |
663 | |
664 | === modified file 'lib/lp/soyuz/tests/test_packagecopyjob.py' |
665 | --- lib/lp/soyuz/tests/test_packagecopyjob.py 2013-06-20 05:50:00 +0000 |
666 | +++ lib/lp/soyuz/tests/test_packagecopyjob.py 2013-06-21 17:17:27 +0000 |
667 | @@ -206,7 +206,8 @@ |
668 | target_pocket=PackagePublishingPocket.RELEASE, |
669 | package_version="1.0-1", include_binaries=False, |
670 | copy_policy=PackageCopyPolicy.MASS_SYNC, |
671 | - requester=requester, sponsored=sponsored) |
672 | + requester=requester, sponsored=sponsored, |
673 | + phased_update_percentage=20) |
674 | self.assertProvides(job, IPackageCopyJob) |
675 | self.assertEqual(archive1.id, job.source_archive_id) |
676 | self.assertEqual(archive1, job.source_archive) |
677 | @@ -220,6 +221,7 @@ |
678 | self.assertEqual(PackageCopyPolicy.MASS_SYNC, job.copy_policy) |
679 | self.assertEqual(requester, job.requester) |
680 | self.assertEqual(sponsored, job.sponsored) |
681 | + self.assertEqual(20, job.phased_update_percentage) |
682 | |
683 | def test_createMultiple_creates_one_job_per_copy(self): |
684 | mother = self.factory.makeDistroSeriesParent() |
685 | |
686 | === modified file 'lib/lp/soyuz/tests/test_publishing.py' |
687 | --- lib/lp/soyuz/tests/test_publishing.py 2013-05-17 02:40:30 +0000 |
688 | +++ lib/lp/soyuz/tests/test_publishing.py 2013-06-21 17:17:27 +0000 |
689 | @@ -1422,7 +1422,7 @@ |
690 | 'binaries': dict( |
691 | (bpr, (self.factory.makeComponent(), |
692 | self.factory.makeSection(), |
693 | - PackagePublishingPriority.REQUIRED)) for bpr in bprs), |
694 | + PackagePublishingPriority.REQUIRED, 50)) for bpr in bprs), |
695 | } |
696 | |
697 | def test_architecture_dependent(self): |
698 | @@ -1445,7 +1445,9 @@ |
699 | (args['archive'], target_das, args['pocket']), |
700 | (bpph.archive, bpph.distroarchseries, bpph.pocket)) |
701 | self.assertEqual( |
702 | - overrides, (bpph.component, bpph.section, bpph.priority)) |
703 | + overrides, |
704 | + (bpph.component, bpph.section, bpph.priority, |
705 | + bpph.phased_update_percentage)) |
706 | self.assertEqual(PackagePublishingStatus.PENDING, bpph.status) |
707 | |
708 | def test_architecture_independent(self): |
709 | |
710 | === modified file 'lib/lp/testing/factory.py' |
711 | --- lib/lp/testing/factory.py 2013-06-20 05:50:00 +0000 |
712 | +++ lib/lp/testing/factory.py 2013-06-21 17:17:27 +0000 |
713 | @@ -3809,7 +3809,7 @@ |
714 | archive, distroarchseries.distroseries, pocket, |
715 | {binarypackagerelease: ( |
716 | binarypackagerelease.component, binarypackagerelease.section, |
717 | - priority)}) |
718 | + priority, None)}) |
719 | for bpph in bpphs: |
720 | naked_bpph = removeSecurityProxy(bpph) |
721 | naked_bpph.status = status |
Oops, this slipped under the radar. Looks fine to me, thanks.