Merge lp:~cjwatson/launchpad/remove-copy-package into lp:launchpad

Proposed by Colin Watson
Status: Merged
Approved by: Steve Kowalik
Approved revision: no longer in the source branch.
Merged at revision: 15772
Proposed branch: lp:~cjwatson/launchpad/remove-copy-package
Merge into: lp:launchpad
Diff against target: 1098 lines (+14/-859)
11 files modified
lib/lp/security.py (+2/-2)
lib/lp/soyuz/model/sourcepackagerelease.py (+3/-3)
lib/lp/soyuz/scripts/ftpmasterbase.py (+0/-54)
lib/lp/soyuz/scripts/packagecopier.py (+1/-197)
lib/lp/soyuz/scripts/populate_archive.py (+0/-2)
lib/lp/soyuz/scripts/tests/test_copypackage.py (+1/-492)
lib/lp/soyuz/scripts/tests/test_populatearchive.py (+1/-1)
lib/lp/soyuz/scripts/tests/test_soyuzscript.py (+1/-82)
lib/lp/soyuz/stories/ppa/xx-copy-packages.txt (+4/-4)
lib/lp/soyuz/stories/webservice/xx-archive.txt (+1/-2)
scripts/ftpmaster-tools/copy-package.py (+0/-20)
To merge this branch: bzr merge lp:~cjwatson/launchpad/remove-copy-package
Reviewer Review Type Date Requested Status
Steve Kowalik (community) code Approve
Review via email: mp+117616@code.launchpad.net

Commit message

Remove copy-package.py. Archive.copyPackage is now a sufficient replacement.

Description of the change

Once r15722 has been deployed with the fix for bug 1006871, we'll be able to convert our last use of copy-package.py (automatically copying packages from -security to -updates) to a cronned API script. At that point there will be no further need to keep copy-package.py in the tree. I've already moved all the useful tests elsewhere; the remaining ones were pure tests of script behaviour and are no longer needed.

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) wrote :

r15722 has been deployed, and I've landed and deployed the new cronned API script, so this should be unblocked.

Revision history for this message
Steve Kowalik (stevenk) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/security.py'
2--- lib/lp/security.py 2012-07-24 19:50:54 +0000
3+++ lib/lp/security.py 2012-08-08 12:00:29 +0000
4@@ -1831,8 +1831,8 @@
5 # If the permission check on the sourcepackagerelease for this
6 # build passes then it means the build can be released from
7 # privacy since the source package is published publicly.
8- # This happens when copy-package is used to re-publish a private
9- # package in the primary archive.
10+ # This happens when Archive.copyPackage is used to re-publish a
11+ # private package in the primary archive.
12 auth_spr = ViewSourcePackageRelease(self.obj.source_package_release)
13 if auth_spr.checkAuthenticated(user):
14 return True
15
16=== modified file 'lib/lp/soyuz/model/sourcepackagerelease.py'
17--- lib/lp/soyuz/model/sourcepackagerelease.py 2012-07-09 12:32:23 +0000
18+++ lib/lp/soyuz/model/sourcepackagerelease.py 2012-08-08 12:00:29 +0000
19@@ -214,9 +214,9 @@
20 @property
21 def builds(self):
22 """See `ISourcePackageRelease`."""
23- # Excluding PPA builds may seem like a strange thing to do but
24- # when copy-package works for copying packages across archives,
25- # a build may well have a different archive to the corresponding
26+ # Excluding PPA builds may seem like a strange thing to do, but,
27+ # since Archive.copyPackage can copy packages across archives, a
28+ # build may well have a different archive to the corresponding
29 # sourcepackagerelease.
30 return BinaryPackageBuild.select("""
31 source_package_release = %s AND
32
33=== modified file 'lib/lp/soyuz/scripts/ftpmasterbase.py'
34--- lib/lp/soyuz/scripts/ftpmasterbase.py 2012-07-05 09:43:58 +0000
35+++ lib/lp/soyuz/scripts/ftpmasterbase.py 2012-08-08 12:00:29 +0000
36@@ -13,17 +13,12 @@
37 'SoyuzScript',
38 ]
39
40-from zope.component import getUtility
41-
42-from lp.app.errors import NotFoundError
43 from lp.services.scripts.base import (
44 LaunchpadScript,
45 LaunchpadScriptFailure,
46 )
47 from lp.soyuz.adapters.packagelocation import build_package_location
48 from lp.soyuz.enums import ArchivePurpose
49-from lp.soyuz.interfaces.component import IComponentSet
50-from lp.soyuz.interfaces.publishing import active_publishing_status
51
52
53 class SoyuzScriptError(Exception):
54@@ -94,15 +89,6 @@
55 def add_package_location_options(self):
56 """Add SoyuzScript package location-related options."""
57 self.parser.add_option(
58- "-a", "--architecture", dest="architecture", default=None,
59- help="Architecture tag.")
60-
61- self.parser.add_option(
62- '-e', '--version', dest='version', default=None,
63- action='store',
64- help='Optional package version, defaults to the current version.')
65-
66- self.parser.add_option(
67 "-c", "--component", dest="component", default=None,
68 help="Component name.")
69
70@@ -121,46 +107,6 @@
71 action='store_true',
72 help='Specify partner archive')
73
74- def _validatePublishing(self, currently_published):
75- """Validate the given publishing record.
76-
77- Check if it matches the desired 'pocket' and 'component'.
78- """
79- if not self.options.component:
80- return
81-
82- try:
83- desired_component = getUtility(IComponentSet)[
84- self.options.component]
85- except NotFoundError as err:
86- raise SoyuzScriptError(err)
87-
88- if currently_published.component != desired_component:
89- raise SoyuzScriptError(
90- "%s was skipped because it is not in %s component" % (
91- currently_published.displayname,
92- desired_component.name.upper()))
93-
94- def findLatestPublishedSource(self, name):
95- """Return a suitable `SourcePackagePublishingHistory`."""
96- assert self.location is not None, 'Undefined location.'
97-
98- published_sources = self.location.archive.getPublishedSources(
99- name=name, version=self.options.version,
100- status=active_publishing_status,
101- distroseries=self.location.distroseries,
102- pocket=self.location.pocket,
103- exact_match=True)
104-
105- try:
106- latest_source = published_sources[0]
107- except IndexError:
108- raise SoyuzScriptError(
109- "Could not find source '%s/%s' in %s" % (
110- name, self.options.version, self.location))
111- self._validatePublishing(latest_source)
112- return latest_source
113-
114 def _getUserConfirmation(self, full_question=None, valid_answers=None):
115 """Use raw_input to collect user feedback.
116
117
118=== modified file 'lib/lp/soyuz/scripts/packagecopier.py'
119--- lib/lp/soyuz/scripts/packagecopier.py 2012-08-08 05:43:18 +0000
120+++ lib/lp/soyuz/scripts/packagecopier.py 2012-08-08 12:00:29 +0000
121@@ -1,12 +1,11 @@
122 # Copyright 2009-2012 Canonical Ltd. This software is licensed under the
123 # GNU Affero General Public License version 3 (see the file LICENSE).
124
125-"""PackageCopier utilities."""
126+"""Package copying utilities."""
127
128 __metaclass__ = type
129
130 __all__ = [
131- 'PackageCopier',
132 'CopyChecker',
133 'check_copy_permissions',
134 'do_copy',
135@@ -27,9 +26,7 @@
136 from lp.buildmaster.enums import BuildStatus
137 from lp.services.database.bulk import load_related
138 from lp.soyuz.adapters.notification import notify
139-from lp.soyuz.adapters.packagelocation import build_package_location
140 from lp.soyuz.enums import (
141- ArchivePurpose,
142 BinaryPackageFileType,
143 SourcePackageFormat,
144 )
145@@ -47,10 +44,6 @@
146 IPackageUploadSet,
147 )
148 from lp.soyuz.scripts.custom_uploads_copier import CustomUploadsCopier
149-from lp.soyuz.scripts.ftpmasterbase import (
150- SoyuzScript,
151- SoyuzScriptError,
152- )
153
154 # XXX cprov 2009-06-12: this function should be incorporated in
155 # IPublishing.
156@@ -881,192 +874,3 @@
157 delayed_copy.acceptFromCopy()
158
159 return DelayedCopy(delayed_copy)
160-
161-
162-class PackageCopier(SoyuzScript):
163- """SoyuzScript that copies published packages between locations.
164-
165- Possible exceptions raised are:
166- * PackageLocationError: specified package or distro does not exist
167- * PackageCopyError: the copy operation itself has failed
168- * LaunchpadScriptFailure: only raised if entering via main(), ie this
169- code is running as a genuine script. In this case, this is
170- also the _only_ exception to be raised.
171-
172- The test harness doesn't enter via main(), it calls doCopy(), so
173- it only sees the first two exceptions.
174- """
175-
176- usage = '%prog -s warty mozilla-firefox --to-suite hoary'
177- description = 'MOVE or COPY a published package to another suite.'
178-
179- def add_my_options(self):
180-
181- SoyuzScript.add_my_options(self)
182-
183- self.parser.add_option(
184- "-b", "--include-binaries", dest="include_binaries",
185- default=False, action="store_true",
186- help='Whether to copy related binaries or not.')
187-
188- self.parser.add_option(
189- '--to-distribution', dest='to_distribution',
190- default='ubuntu', action='store',
191- help='Destination distribution name.')
192-
193- self.parser.add_option(
194- '--to-suite', dest='to_suite', default=None,
195- action='store', help='Destination suite name.')
196-
197- self.parser.add_option(
198- '--to-ppa', dest='to_ppa', default=None,
199- action='store', help='Destination PPA owner name.')
200-
201- self.parser.add_option(
202- '--to-ppa-name', dest='to_ppa_name', default='ppa',
203- action='store', help='Destination PPA name.')
204-
205- self.parser.add_option(
206- '--to-partner', dest='to_partner', default=False,
207- action='store_true', help='Destination set to PARTNER archive.')
208-
209- self.parser.add_option(
210- '--unembargo', dest='unembargo', default=False,
211- action='store_true',
212- help='Allow copying from a private archive to a public archive.')
213-
214- def checkCopyOptions(self):
215- """Check if the locations options are sane.
216-
217- * Catch Cross-PARTNER copies, they are not allowed.
218- * Catch simulataneous PPA and PARTNER locations or destinations,
219- results are unpredictable (in fact, the code will ignore PPA and
220- operate only in PARTNER, but that's odd)
221- """
222- if ((self.options.partner_archive and not self.options.to_partner)
223- or (self.options.to_partner and not
224- self.options.partner_archive)):
225- raise SoyuzScriptError(
226- "Cross-PARTNER copies are not allowed.")
227-
228- if self.options.archive_owner_name and self.options.partner_archive:
229- raise SoyuzScriptError(
230- "Cannot operate with location PARTNER and PPA "
231- "simultaneously.")
232-
233- if self.options.to_ppa and self.options.to_partner:
234- raise SoyuzScriptError(
235- "Cannot operate with destination PARTNER and PPA "
236- "simultaneously.")
237-
238- def checkPrivacyOptions(self):
239- """Check privacy-related location options.
240-
241- We can copy from a private archive to a public archive, but only
242- with the --unembargo option (to avoid accidents). Unembargoing into
243- the release pocket of a distribution is not permitted.
244- """
245- if (self.location.archive.private and
246- not self.destination.archive.private):
247- if not self.options.unembargo:
248- raise SoyuzScriptError(
249- "Copying from a private archive to a public archive "
250- "requires the --unembargo option.")
251-
252- if not self.destination.archive.canModifySuite(
253- self.destination.distroseries, self.destination.pocket):
254- raise SoyuzScriptError(
255- "Can't unembargo into suite '%s' of a distribution." %
256- self.destination.distroseries.getSuite(
257- self.destination.pocket))
258-
259- def mainTask(self):
260- """Execute package copy procedure.
261-
262- Copy source publication and optionally also copy its binaries by
263- passing '-b' (include_binary) option.
264-
265- Modules using this class outside of its normal usage in the
266- copy-package.py script can call this method to start the copy.
267-
268- In this case the caller can override test_args on __init__
269- to set the command line arguments.
270-
271- Can raise SoyuzScriptError.
272- """
273- assert self.location, (
274- "location is not available, call PackageCopier.setupLocation() "
275- "before dealing with mainTask.")
276-
277- self.checkCopyOptions()
278-
279- sourcename = self.args[0]
280-
281- self.setupDestination()
282-
283- self.checkPrivacyOptions()
284-
285- self.logger.info("FROM: %s" % (self.location))
286- self.logger.info("TO: %s" % (self.destination))
287-
288- to_copy = []
289- source_pub = self.findLatestPublishedSource(sourcename)
290- to_copy.append(source_pub)
291- if self.options.include_binaries:
292- to_copy.extend(source_pub.getPublishedBinaries())
293-
294- self.logger.info("Copy candidates:")
295- for candidate in to_copy:
296- self.logger.info('\t%s' % candidate.displayname)
297-
298- sources = [source_pub]
299- try:
300- copies = do_copy(
301- sources, self.destination.archive,
302- self.destination.distroseries, self.destination.pocket,
303- self.options.include_binaries, allow_delayed_copies=False,
304- check_permissions=False, unembargo=self.options.unembargo,
305- logger=self.logger)
306- except CannotCopy as error:
307- self.logger.error(str(error))
308- return []
309-
310- self.logger.info("Copied:")
311- for copy in copies:
312- self.logger.info('\t%s' % copy.displayname)
313-
314- if len(copies) == 1:
315- self.logger.info(
316- "%s package successfully copied." % len(copies))
317- elif len(copies) > 1:
318- self.logger.info(
319- "%s packages successfully copied." % len(copies))
320- else:
321- self.logger.info("No packages copied.")
322-
323- # Information returned mainly for the benefit of the test harness.
324- return copies
325-
326- def setupDestination(self):
327- """Build PackageLocation for the destination context."""
328- if self.options.to_partner:
329- self.destination = build_package_location(
330- self.options.to_distribution,
331- self.options.to_suite,
332- ArchivePurpose.PARTNER)
333- elif self.options.to_ppa:
334- self.destination = build_package_location(
335- self.options.to_distribution,
336- self.options.to_suite,
337- ArchivePurpose.PPA,
338- self.options.to_ppa,
339- self.options.to_ppa_name)
340- else:
341- self.destination = build_package_location(
342- self.options.to_distribution,
343- self.options.to_suite)
344-
345- if self.location == self.destination:
346- raise SoyuzScriptError(
347- "Can not sync between the same locations: '%s' to '%s'" % (
348- self.location, self.destination))
349
350=== modified file 'lib/lp/soyuz/scripts/populate_archive.py'
351--- lib/lp/soyuz/scripts/populate_archive.py 2012-07-05 09:43:58 +0000
352+++ lib/lp/soyuz/scripts/populate_archive.py 2012-08-08 12:00:29 +0000
353@@ -324,8 +324,6 @@
354 """
355 SoyuzScript.add_my_options(self)
356
357- self.parser.remove_option('-a')
358-
359 self.parser.add_option(
360 "-a", "--architecture", dest="arch_tags", action="append",
361 help="The architecture tags for which to create build "
362
363=== modified file 'lib/lp/soyuz/scripts/tests/test_copypackage.py'
364--- lib/lp/soyuz/scripts/tests/test_copypackage.py 2012-07-30 20:03:41 +0000
365+++ lib/lp/soyuz/scripts/tests/test_copypackage.py 2012-08-08 12:00:29 +0000
366@@ -4,14 +4,10 @@
367 __metaclass__ = type
368
369 import datetime
370-import os
371-import subprocess
372-import sys
373 from textwrap import (
374 dedent,
375 fill,
376 )
377-import unittest
378
379 import pytz
380 from testtools.content import text_content
381@@ -32,16 +28,11 @@
382 from lp.bugs.interfaces.bugtask import BugTaskStatus
383 from lp.buildmaster.enums import BuildStatus
384 from lp.registry.interfaces.distribution import IDistributionSet
385-from lp.registry.interfaces.person import IPersonSet
386 from lp.registry.interfaces.pocket import PackagePublishingPocket
387 from lp.registry.interfaces.series import SeriesStatus
388 from lp.services.config import config
389 from lp.services.database.sqlbase import flush_database_caches
390-from lp.services.librarian.interfaces import ILibraryFileAliasSet
391-from lp.services.librarianserver.testing.server import fillLibrarianFile
392-from lp.services.log.logger import BufferLogger
393 from lp.soyuz.adapters.overrides import SourceOverride
394-from lp.soyuz.adapters.packagelocation import PackageLocationError
395 from lp.soyuz.enums import (
396 ArchivePermissionType,
397 ArchivePurpose,
398@@ -62,17 +53,11 @@
399 ISourcePackageFormatSelectionSet,
400 )
401 from lp.soyuz.model.archivepermission import ArchivePermission
402-from lp.soyuz.model.publishing import (
403- BinaryPackagePublishingHistory,
404- SourcePackagePublishingHistory,
405- )
406-from lp.soyuz.scripts.ftpmasterbase import SoyuzScriptError
407 from lp.soyuz.scripts.packagecopier import (
408 _do_delayed_copy,
409 _do_direct_copy,
410 CopyChecker,
411 do_copy,
412- PackageCopier,
413 update_files_privacy,
414 )
415 from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
416@@ -85,10 +70,7 @@
417 dbuser,
418 switch_dbuser,
419 )
420-from lp.testing.layers import (
421- DatabaseLayer,
422- LaunchpadZopelessLayer,
423- )
424+from lp.testing.layers import LaunchpadZopelessLayer
425 from lp.testing.mail_helpers import pop_notifications
426 from lp.testing.matchers import HasQueryCount
427
428@@ -2315,476 +2297,3 @@
429 proposed_bug = getUtility(IBugSet).get(proposed_bug_id)
430 [proposed_bug_task] = proposed_bug.bugtasks
431 self.assertEqual(proposed_bug_task.status, BugTaskStatus.NEW)
432-
433-
434-class CopyPackageScriptTestCase(unittest.TestCase):
435- """Test the copy-package.py script."""
436- layer = LaunchpadZopelessLayer
437-
438- def runCopyPackage(self, extra_args=None):
439- """Run copy-package.py, returning the result and output.
440-
441- Returns a tuple of the process's return code, stdout output and
442- stderr output.
443- """
444- if extra_args is None:
445- extra_args = []
446- script = os.path.join(
447- config.root, "scripts", "ftpmaster-tools", "copy-package.py")
448- args = [sys.executable, script, '-y']
449- args.extend(extra_args)
450- process = subprocess.Popen(
451- args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
452- # The subprocess commits to the database so we need to tell the layer
453- # to fully tear down and restore the testing database.
454- DatabaseLayer.force_dirty_database()
455- stdout, stderr = process.communicate()
456- return (process.returncode, stdout, stderr)
457-
458- def testSimpleRun(self):
459- """Try a simple copy-package.py run.
460-
461- Uses the default case, copy mozilla-firefox source with binaries
462- from warty to hoary.
463- """
464- # Count the records in SSPPH and SBPPH to check later that they
465- # increased by one each.
466- num_source_pub = SourcePackagePublishingHistory.select(
467- "True").count()
468- num_bin_pub = BinaryPackagePublishingHistory.select(
469- "True").count()
470-
471- # Fill the source package changelog so it can be processed
472- # for closing bugs.
473- fillLibrarianFile(52, content='Format: 1.7\n')
474-
475- returncode, out, err = self.runCopyPackage(
476- extra_args=['-s', 'warty', 'mozilla-firefox',
477- '--to-suite', 'hoary', '-b'])
478- # Need to print these or you can't see what happened if the
479- # return code is bad:
480- if returncode != 0:
481- print "\nStdout:\n%s\nStderr\n%s\n" % (out, err)
482- self.assertEqual(0, returncode)
483-
484- # Test that the database has been modified. We're only checking
485- # that the number of rows has increase; content checks are done
486- # in other tests.
487- self.layer.txn.abort()
488-
489- num_source_pub_after = SourcePackagePublishingHistory.select(
490- "True").count()
491- num_bin_pub_after = BinaryPackagePublishingHistory.select(
492- "True").count()
493-
494- self.assertEqual(num_source_pub + 1, num_source_pub_after)
495- # 'mozilla-firefox' source produced 4 binaries.
496- self.assertEqual(num_bin_pub + 4, num_bin_pub_after)
497-
498-
499-class CopyPackageTestCase(TestCaseWithFactory):
500- """Test the CopyPackageHelper class."""
501- layer = LaunchpadZopelessLayer
502- dbuser = config.archivepublisher.dbuser
503-
504- def setUp(self):
505- """Anotate pending publishing records provided in the sampledata.
506-
507- The records annotated will be excluded during the operation checks,
508- see checkCopies().
509- """
510- super(CopyPackageTestCase, self).setUp()
511- pending_sources = SourcePackagePublishingHistory.selectBy(
512- status=PackagePublishingStatus.PENDING)
513- self.sources_pending_ids = [pub.id for pub in pending_sources]
514- pending_binaries = BinaryPackagePublishingHistory.selectBy(
515- status=PackagePublishingStatus.PENDING)
516- self.binaries_pending_ids = [pub.id for pub in pending_binaries]
517-
518- # Run test cases in the production context.
519- switch_dbuser(self.dbuser)
520-
521- def getCopier(self, sourcename='mozilla-firefox', sourceversion=None,
522- from_distribution='ubuntu', from_suite='warty',
523- to_distribution='ubuntu', to_suite='hoary',
524- component=None, from_ppa=None, to_ppa=None,
525- from_partner=False, to_partner=False,
526- confirm_all=True, include_binaries=True, unembargo=False):
527- """Return a PackageCopier instance.
528-
529- Allow tests to use a set of default options and pass an
530- inactive logger to PackageCopier.
531- """
532- test_args = ['-s', from_suite,
533- '-d', from_distribution,
534- '--to-suite', to_suite,
535- '--to-distribution', to_distribution]
536-
537- if confirm_all:
538- test_args.append('-y')
539-
540- if include_binaries:
541- test_args.append('-b')
542-
543- if unembargo:
544- test_args.append('--unembargo')
545-
546- if sourceversion is not None:
547- test_args.extend(['-e', sourceversion])
548-
549- if component is not None:
550- test_args.extend(['-c', component])
551-
552- if from_partner:
553- test_args.append('-j')
554-
555- if to_partner:
556- test_args.append('--to-partner')
557-
558- if from_ppa is not None:
559- test_args.extend(['-p', from_ppa])
560-
561- if to_ppa is not None:
562- test_args.extend(['--to-ppa', to_ppa])
563-
564- test_args.append(sourcename)
565-
566- copier = PackageCopier(name='copy-package', test_args=test_args)
567- copier.logger = BufferLogger()
568- copier.setupLocation()
569- return copier
570-
571- def checkCopies(self, copied, target_archive, size):
572- """Perform overall checks in the copied records list.
573-
574- * check if the size is expected,
575- * check if all copied records are PENDING,
576- * check if the list copied matches the list of PENDING records
577- retrieved from the target_archive.
578- """
579- self.assertEqual(len(copied), size)
580-
581- for candidate in copied:
582- self.assertEqual(PackagePublishingStatus.PENDING, candidate.status)
583-
584- def excludeOlds(found, old_pending_ids):
585- return [pub.id for pub in found if pub.id not in old_pending_ids]
586-
587- sources_pending = target_archive.getPublishedSources(
588- status=PackagePublishingStatus.PENDING)
589- sources_pending_ids = excludeOlds(
590- sources_pending, self.sources_pending_ids)
591-
592- binaries_pending = target_archive.getAllPublishedBinaries(
593- status=PackagePublishingStatus.PENDING)
594- binaries_pending_ids = excludeOlds(
595- binaries_pending, self.binaries_pending_ids)
596-
597- copied_ids = [pub.id for pub in copied]
598- pending_ids = sources_pending_ids + binaries_pending_ids
599-
600- self.assertEqual(
601- sorted(copied_ids), sorted(pending_ids),
602- "The copy did not succeed.\nExpected IDs: %s\nFound IDs: %s" % (
603- sorted(copied_ids), sorted(pending_ids)))
604-
605- def testCopyBetweenDistroSeries(self):
606- """Check the copy operation between distroseries."""
607- # Fill the source changesfiles, so it can be properly processed
608- # for closing bugs.
609- fillLibrarianFile(52, content='Format: 1.7\n')
610-
611- copy_helper = self.getCopier()
612- copied = copy_helper.mainTask()
613-
614- # Check locations. They should be the same as the defaults defined
615- # in the getCopier method.
616- self.assertEqual(str(copy_helper.location),
617- 'Primary Archive for Ubuntu Linux: warty-RELEASE')
618- self.assertEqual(str(copy_helper.destination),
619- 'Primary Archive for Ubuntu Linux: hoary-RELEASE')
620-
621- # Check stored results. The number of copies should be 5
622- # (1 source and 2 binaries in 2 architectures).
623- target_archive = copy_helper.destination.archive
624- self.checkCopies(copied, target_archive, 5)
625-
626- def testCopyBetweenPockets(self):
627- """Check the copy operation between pockets.
628-
629- That's normally how SECURITY publications get propagated to UPDATES
630- in order to reduce the burden on ubuntu servers.
631- """
632- # Fill the source changesfiles, so it can be properly processed
633- # for closing bugs.
634- fillLibrarianFile(52, content='Format: 1.7\n')
635-
636- copy_helper = self.getCopier(
637- from_suite='warty', to_suite='warty-updates')
638- copied = copy_helper.mainTask()
639-
640- self.assertEqual(str(copy_helper.location),
641- 'Primary Archive for Ubuntu Linux: warty-RELEASE')
642- self.assertEqual(str(copy_helper.destination),
643- 'Primary Archive for Ubuntu Linux: warty-UPDATES')
644-
645- target_archive = copy_helper.destination.archive
646- self.checkCopies(copied, target_archive, 5)
647-
648- def testCopyAncestryLookup(self):
649- """Check the ancestry lookup used in copy-package.
650-
651- This test case exercises the 'ancestry lookup' mechanism used to
652- verify if the copy candidate version is higher than the currently
653- published version of the same source/binary in the destination
654- context.
655-
656- We emulate a conflict with a pre-existing version of 'firefox-3.0'
657- in hardy-updates, a version of 'firefox' present in hardy and a copy
658- copy candidate 'firefox' from hardy-security.
659-
660- As described in bug #245416, the ancestry lookup was erroneously
661- considering the 'firefox-3.0' as an ancestor to the 'firefox' copy
662- candidate. It was caused because the lookup was not restricted to
663- 'exact_match' names. See `scripts/packagecopier.py`.
664- """
665- ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
666- hoary = ubuntu.getSeries('hoary')
667- test_publisher = self.getTestPublisher(hoary)
668-
669- # Create the described publishing scenario.
670- ancestry_source = test_publisher.getPubSource(
671- sourcename='firefox', version='1.0',
672- archive=ubuntu.main_archive, distroseries=hoary,
673- pocket=PackagePublishingPocket.RELEASE,
674- status=PackagePublishingStatus.PUBLISHED)
675-
676- test_publisher.getPubSource(
677- sourcename='firefox-3.0', version='1.2',
678- archive=ubuntu.main_archive, distroseries=hoary,
679- pocket=PackagePublishingPocket.UPDATES,
680- status=PackagePublishingStatus.PUBLISHED)
681-
682- candidate_source = test_publisher.getPubSource(
683- sourcename='firefox', version='1.1',
684- archive=ubuntu.main_archive, distroseries=hoary,
685- pocket=PackagePublishingPocket.SECURITY,
686- status=PackagePublishingStatus.PUBLISHED)
687-
688- # Commit to ensure librarian files are written.
689- self.layer.txn.commit()
690-
691- # Perform the copy.
692- copy_helper = self.getCopier(
693- sourcename='firefox', include_binaries=False,
694- from_suite='hoary-security', to_suite='hoary-updates')
695- copied = copy_helper.mainTask()
696-
697- # Check if the copy was performed as expected.
698- target_archive = copy_helper.destination.archive
699- self.checkCopies(copied, target_archive, 1)
700-
701- # Verify the resulting publishing scenario.
702- [updates, security,
703- release] = ubuntu.main_archive.getPublishedSources(
704- name='firefox', exact_match=True)
705-
706- # Context publications remain the same.
707- self.assertEqual(release, ancestry_source)
708- self.assertEqual(security, candidate_source)
709-
710- # The copied source is published in the 'updates' pocket as expected.
711- self.assertEqual(updates.displayname, 'firefox 1.1 in hoary')
712- self.assertEqual(updates.pocket, PackagePublishingPocket.UPDATES)
713- self.assertEqual(len(updates.getBuilds()), 1)
714-
715- def testCopyAcrossPartner(self):
716- """Check the copy operation across PARTNER archive.
717-
718- This operation is required to propagate partner uploads across several
719- suites, avoiding to build (and modify) the package multiple times to
720- have it available for all supported suites independent of the
721- time they were released.
722- """
723- copy_helper = self.getCopier(
724- sourcename='commercialpackage', from_partner=True,
725- to_partner=True, from_suite='breezy-autotest', to_suite='hoary')
726- copied = copy_helper.mainTask()
727-
728- self.assertEqual(
729- str(copy_helper.location),
730- 'Partner Archive for Ubuntu Linux: breezy-autotest-RELEASE')
731- self.assertEqual(
732- str(copy_helper.destination),
733- 'Partner Archive for Ubuntu Linux: hoary-RELEASE')
734-
735- # 'commercialpackage' has only one binary built for i386.
736- # The source and the binary got copied.
737- target_archive = copy_helper.destination.archive
738- self.checkCopies(copied, target_archive, 2)
739-
740- def getTestPublisher(self, distroseries):
741- """Return a initialized `SoyuzTestPublisher` object.
742-
743- Setup a i386 chroot for the given distroseries, so it can build
744- and publish binaries.
745- """
746- fake_chroot = getUtility(ILibraryFileAliasSet)[1]
747- distroseries['i386'].addOrUpdateChroot(fake_chroot)
748- test_publisher = SoyuzTestPublisher()
749- test_publisher.setUpDefaultDistroSeries(distroseries)
750- test_publisher.person = getUtility(IPersonSet).getByName("name16")
751- return test_publisher
752-
753- def testCopyAcrossPPAs(self):
754- """Check the copy operation across PPAs.
755-
756- This operation is useful to propagate dependencies across
757- collaborative PPAs without requiring new uploads.
758- """
759- copy_helper = self.getCopier(
760- sourcename='iceweasel', from_ppa='cprov',
761- from_suite='warty', to_suite='hoary', to_ppa='mark')
762- copied = copy_helper.mainTask()
763-
764- self.assertEqual('cprov: warty-RELEASE', str(copy_helper.location))
765- self.assertEqual('mark: hoary-RELEASE', str(copy_helper.destination))
766-
767- target_archive = copy_helper.destination.archive
768- self.checkCopies(copied, target_archive, 2)
769-
770- def testSourceLookupFailure(self):
771- """Check if it raises when the target source can't be found.
772-
773- SoyuzScriptError is raised when a lookup fails.
774- """
775- copy_helper = self.getCopier(sourcename='zaphod')
776-
777- self.assertRaisesWithContent(
778- SoyuzScriptError,
779- "Could not find source 'zaphod/None' in "
780- "Primary Archive for Ubuntu Linux: warty-RELEASE",
781- copy_helper.mainTask)
782-
783- def testFailIfValidPackageButNotInSpecifiedSuite(self):
784- """It fails if the package is not published in the source location.
785-
786- SoyuzScriptError is raised when a lookup fails
787- """
788- copy_helper = self.getCopier(from_suite="breezy-autotest")
789-
790- self.assertRaisesWithContent(
791- SoyuzScriptError,
792- "Could not find source 'mozilla-firefox/None' in "
793- "Primary Archive for Ubuntu Linux: breezy-autotest-RELEASE",
794- copy_helper.mainTask)
795-
796- def testFailIfSameLocations(self):
797- """It fails if the source and destination locations are the same.
798-
799- SoyuzScriptError is raise when the copy cannot be performed.
800- """
801- copy_helper = self.getCopier(from_suite='warty', to_suite='warty')
802-
803- self.assertRaisesWithContent(
804- SoyuzScriptError,
805- "Can not sync between the same locations: "
806- "'Primary Archive for Ubuntu Linux: warty-RELEASE' to "
807- "'Primary Archive for Ubuntu Linux: warty-RELEASE'",
808- copy_helper.mainTask)
809-
810- def testBadDistributionDestination(self):
811- """Check if it raises if the distribution is invalid.
812-
813- PackageLocationError is raised for unknown destination distribution.
814- """
815- copy_helper = self.getCopier(to_distribution="beeblebrox")
816-
817- self.assertRaisesWithContent(
818- PackageLocationError,
819- "Could not find distribution 'beeblebrox'",
820- copy_helper.mainTask)
821-
822- def testBadSuiteDestination(self):
823- """Check that it fails when specifying a bad distroseries.
824-
825- PackageLocationError is raised for unknown destination distroseries.
826- """
827- copy_helper = self.getCopier(to_suite="slatibartfast")
828-
829- self.assertRaisesWithContent(
830- PackageLocationError,
831- "Could not find suite 'slatibartfast'",
832- copy_helper.mainTask)
833-
834- def testBadPPADestination(self):
835- """Check that it fails when specifying a bad PPA destination.
836-
837- PackageLocationError is raised for unknown destination PPA.
838- """
839- copy_helper = self.getCopier(to_ppa="slatibartfast")
840-
841- self.assertRaisesWithContent(
842- PackageLocationError,
843- "Could not find a PPA for slatibartfast named ppa",
844- copy_helper.mainTask)
845-
846- def testCrossPartnerCopiesFails(self):
847- """Check that it fails when cross-PARTNER copies are requested.
848-
849- SoyuzScriptError is raised for cross-PARTNER copies, packages
850- published in PARTNER archive can only be copied within PARTNER
851- archive.
852- """
853- copy_helper = self.getCopier(from_partner=True)
854-
855- self.assertRaisesWithContent(
856- SoyuzScriptError,
857- "Cross-PARTNER copies are not allowed.",
858- copy_helper.mainTask)
859-
860- copy_helper = self.getCopier(to_partner=True)
861-
862- self.assertRaisesWithContent(
863- SoyuzScriptError,
864- "Cross-PARTNER copies are not allowed.",
865- copy_helper.mainTask)
866-
867- def testPpaPartnerInconsistentLocations(self):
868- """Check if PARTNER and PPA inconsistent arguments are caught.
869-
870- SoyuzScriptError is raised for when inconsistences in the PARTNER
871- and PPA location or destination are spotted.
872- """
873- copy_helper = self.getCopier(
874- from_partner=True, from_ppa='cprov', to_partner=True)
875-
876- self.assertRaisesWithContent(
877- SoyuzScriptError,
878- "Cannot operate with location PARTNER and PPA simultaneously.",
879- copy_helper.mainTask)
880-
881- copy_helper = self.getCopier(
882- from_partner=True, to_ppa='cprov', to_partner=True)
883-
884- self.assertRaisesWithContent(
885- SoyuzScriptError,
886- "Cannot operate with destination PARTNER and PPA simultaneously.",
887- copy_helper.mainTask)
888-
889- def testUnembargoStableReleasePocketForbidden(self):
890- """Unembargoing into release pocket of stable series is forbidden."""
891- # Set up a private PPA.
892- joe = self.factory.makePerson(name="joe")
893- ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
894- self.factory.makeArchive(
895- owner=joe, name='ppa', private=True, distribution=ubuntu)
896-
897- copy_helper = self.getCopier(
898- sourcename='foo', from_ppa='joe',
899- include_binaries=True, from_suite='warty',
900- to_suite='warty', unembargo=True)
901- self.assertRaisesWithContent(
902- SoyuzScriptError,
903- "Can't unembargo into suite 'warty' of a distribution.",
904- copy_helper.mainTask)
905
906=== modified file 'lib/lp/soyuz/scripts/tests/test_populatearchive.py'
907--- lib/lp/soyuz/scripts/tests/test_populatearchive.py 2012-01-19 03:09:38 +0000
908+++ lib/lp/soyuz/scripts/tests/test_populatearchive.py 2012-08-08 12:00:29 +0000
909@@ -43,7 +43,7 @@
910
911
912 class TestPopulateArchiveScript(TestCaseWithFactory):
913- """Test the copy-package.py script."""
914+ """Test the populate-archive.py script."""
915
916 layer = LaunchpadZopelessLayer
917 expected_build_spns = [
918
919=== modified file 'lib/lp/soyuz/scripts/tests/test_soyuzscript.py'
920--- lib/lp/soyuz/scripts/tests/test_soyuzscript.py 2012-06-19 17:29:32 +0000
921+++ lib/lp/soyuz/scripts/tests/test_soyuzscript.py 2012-08-08 12:00:29 +0000
922@@ -9,14 +9,8 @@
923
924 import unittest
925
926-from zope.component import getUtility
927-
928-from lp.registry.interfaces.person import IPersonSet
929 from lp.services.log.logger import BufferLogger
930-from lp.soyuz.scripts.ftpmasterbase import (
931- SoyuzScript,
932- SoyuzScriptError,
933- )
934+from lp.soyuz.scripts.ftpmasterbase import SoyuzScript
935 from lp.testing.layers import LaunchpadZopelessLayer
936
937
938@@ -60,81 +54,6 @@
939 soyuz.setupLocation()
940 return soyuz
941
942- def testFindLatestPublishedSourceInPRIMARY(self):
943- """Source lookup in PRIMARY archive."""
944- soyuz = self.getSoyuz()
945- src = soyuz.findLatestPublishedSource('pmount')
946- self.assertEqual(src.displayname, 'pmount 0.1-2 in hoary')
947-
948- self.assertRaises(
949- SoyuzScriptError, soyuz.findLatestPublishedSource, 'marvin')
950-
951- soyuz = self.getSoyuz(suite='hoary-security')
952- self.assertRaises(
953- SoyuzScriptError, soyuz.findLatestPublishedSource, 'pmount')
954-
955- def testFindLatestPublishedSourceInPARTNER(self):
956- """Source lookup in PARTNER archive."""
957- soyuz = self.getSoyuz(suite='breezy-autotest', partner=True)
958- src = soyuz.findLatestPublishedSource('commercialpackage')
959- self.assertEqual(
960- src.displayname, 'commercialpackage 1.0-1 in breezy-autotest')
961-
962- self.assertRaises(
963- SoyuzScriptError, soyuz.findLatestPublishedSource, 'marvin')
964-
965- soyuz = self.getSoyuz(suite='warty', partner=True)
966- self.assertRaises(
967- SoyuzScriptError, soyuz.findLatestPublishedSource,
968- 'commercialpackage')
969-
970- def testFindLatestPublishedSourceInPPA(self):
971- """Source lookup in PPAs."""
972- soyuz = self.getSoyuz(ppa='cprov', suite='warty')
973- src = soyuz.findLatestPublishedSource('pmount')
974- self.assertEqual(src.displayname, 'pmount 0.1-1 in warty')
975-
976- self.assertRaises(
977- SoyuzScriptError, soyuz.findLatestPublishedSource, 'marvin')
978-
979- soyuz = self.getSoyuz(ppa='cprov', suite='warty-security')
980- self.assertRaises(
981- SoyuzScriptError, soyuz.findLatestPublishedSource, 'pmount')
982-
983- # Bug 159151 occurred because we were printing unicode characters
984- # to an ascii codec in the exception, which originated in the PPA
985- # owner's name. Let's munge cprov's name to be unicode and ensure
986- # we still get the right exception raised (a UnicodeError is raised
987- # if the bug is present).
988- cprov = getUtility(IPersonSet).getByName('cprov')
989- cprov.displayname = u'\xe7\xe3o'
990- self.assertRaises(
991- SoyuzScriptError, soyuz.findLatestPublishedSource, 'pmount')
992-
993- def testFindLatestPublishedSourceAndCheckComponent(self):
994- """Before returning the source publication component is checked.
995-
996- Despite of existing the found publication should match the given
997- component (if given) otherwise an error is raised.
998- """
999- soyuz = self.getSoyuz(suite='hoary', component='main')
1000- src = soyuz.findLatestPublishedSource('pmount')
1001- self.assertEqual(src.displayname, 'pmount 0.1-2 in hoary')
1002-
1003- soyuz = self.getSoyuz(component='multiverse')
1004- self.assertRaises(
1005- SoyuzScriptError, soyuz.findLatestPublishedSource, 'pmount')
1006-
1007- def testFindLatestPublishedSourceWithSpecificVersion(self):
1008- """Source lookups for specific version."""
1009- soyuz = self.getSoyuz(version='0.1-2')
1010- src = soyuz.findLatestPublishedSource('pmount')
1011- self.assertEqual(src.displayname, 'pmount 0.1-2 in hoary')
1012-
1013- soyuz = self.getSoyuz(version='666')
1014- self.assertRaises(
1015- SoyuzScriptError, soyuz.findLatestPublishedSource, 'pmount')
1016-
1017 def testFinishProcedure(self):
1018 """Make sure finishProcedure returns the correct boolean."""
1019 soyuz = self.getSoyuz()
1020
1021=== modified file 'lib/lp/soyuz/stories/ppa/xx-copy-packages.txt'
1022--- lib/lp/soyuz/stories/ppa/xx-copy-packages.txt 2012-01-15 11:06:57 +0000
1023+++ lib/lp/soyuz/stories/ppa/xx-copy-packages.txt 2012-08-08 12:00:29 +0000
1024@@ -44,7 +44,7 @@
1025 Unauthorized: ... 'launchpad.AnyPerson')
1026
1027 James is a valid user, however he doesn't have access to any PPA, he
1028-is allowed to access the copy-package interface in Celso's PPA, but
1029+is allowed to access the copy-packages interface in Celso's PPA, but
1030 the form is not rendered, instead he is advised to activate his own
1031 PPA in order to be able to copy packages.
1032
1033@@ -581,7 +581,7 @@
1034 In the minute after James had deleted the package, he discovered that
1035 'pmount' might work correctly in warty.
1036
1037-No problem, he goes back to the copy-package interface in his PPA and
1038+No problem, he goes back to the copy-packages interface in his PPA and
1039 still able to copy the deleted source to the warty series.
1040
1041 By default the copy view presents only PUBLISHED or PENDING packages.
1042@@ -704,7 +704,7 @@
1043 >>> jblack_browser.getControl(name='field.selected_sources').value = (
1044 ... [iceweasel_pub_id, pmount_pub_id])
1045
1046-Now that James have access to more than one PPA, the copy-package form
1047+Now that James have access to more than one PPA, the copy-packages form
1048 allows him to select one of them.
1049
1050 >>> print jblack_browser.getControl(
1051@@ -891,7 +891,7 @@
1052
1053 >>> print_ppa_packages(jblack_browser.contents)
1054
1055-Not yet happy, James goes back to his PPA to check if the copy-package
1056+Not yet happy, James goes back to his PPA to check if the copy-packages
1057 interface can be used to resurrect deleted packages.
1058
1059 >>> jblack_browser.open(
1060
1061=== modified file 'lib/lp/soyuz/stories/webservice/xx-archive.txt'
1062--- lib/lp/soyuz/stories/webservice/xx-archive.txt 2012-06-14 03:22:43 +0000
1063+++ lib/lp/soyuz/stories/webservice/xx-archive.txt 2012-08-08 12:00:29 +0000
1064@@ -796,8 +796,7 @@
1065
1066 IArchive contains 2 custom operations to copy packages from another archive.
1067 These are syncSource() and syncSources(). Both are wrappers of the
1068-`PackageCopier` infrastructure, see more information in
1069-scripts/packagecopier.py.
1070+`do_copy` infrastructure, see more information in scripts/packagecopier.py.
1071
1072 For testing purposes we will create some publications.
1073
1074
1075=== removed file 'scripts/ftpmaster-tools/copy-package.py'
1076--- scripts/ftpmaster-tools/copy-package.py 2011-12-29 05:29:36 +0000
1077+++ scripts/ftpmaster-tools/copy-package.py 1970-01-01 00:00:00 +0000
1078@@ -1,20 +0,0 @@
1079-#!/usr/bin/python -S
1080-#
1081-# Copyright 2009 Canonical Ltd. This software is licensed under the
1082-# GNU Affero General Public License version 3 (see the file LICENSE).
1083-
1084-# pylint: disable-msg=W0403
1085-
1086-"""Copy publications across suites."""
1087-
1088-import _pythonpath
1089-
1090-from lp.services.config import config
1091-from lp.soyuz.scripts.packagecopier import PackageCopier
1092-
1093-
1094-if __name__ == '__main__':
1095- script = PackageCopier(
1096- 'copy-package', dbuser=config.archivepublisher.dbuser)
1097- script.lock_and_run()
1098-