← Back to team overview

launchpad-reviewers team mailing list archive

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

 

Colin Watson has proposed merging lp:~cjwatson/launchpad/remove-copy-package into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #334858 in Launchpad itself: "Require a way to copy [P]PPA packages into Ubuntu"
  https://bugs.launchpad.net/launchpad/+bug/334858

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/remove-copy-package/+merge/117616

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.
-- 
https://code.launchpad.net/~cjwatson/launchpad/remove-copy-package/+merge/117616
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/remove-copy-package into lp:launchpad.
=== modified file 'lib/lp/security.py'
--- lib/lp/security.py	2012-07-24 19:50:54 +0000
+++ lib/lp/security.py	2012-08-01 11:16:28 +0000
@@ -1831,8 +1831,8 @@
         # If the permission check on the sourcepackagerelease for this
         # build passes then it means the build can be released from
         # privacy since the source package is published publicly.
-        # This happens when copy-package is used to re-publish a private
-        # package in the primary archive.
+        # This happens when Archive.copyPackage is used to re-publish a
+        # private package in the primary archive.
         auth_spr = ViewSourcePackageRelease(self.obj.source_package_release)
         if auth_spr.checkAuthenticated(user):
             return True

=== modified file 'lib/lp/soyuz/model/sourcepackagerelease.py'
--- lib/lp/soyuz/model/sourcepackagerelease.py	2012-07-09 12:32:23 +0000
+++ lib/lp/soyuz/model/sourcepackagerelease.py	2012-08-01 11:16:28 +0000
@@ -214,9 +214,9 @@
     @property
     def builds(self):
         """See `ISourcePackageRelease`."""
-        # Excluding PPA builds may seem like a strange thing to do but
-        # when copy-package works for copying packages across archives,
-        # a build may well have a different archive to the corresponding
+        # Excluding PPA builds may seem like a strange thing to do, but,
+        # since Archive.copyPackage can copy packages across archives, a
+        # build may well have a different archive to the corresponding
         # sourcepackagerelease.
         return BinaryPackageBuild.select("""
             source_package_release = %s AND

=== modified file 'lib/lp/soyuz/scripts/ftpmasterbase.py'
--- lib/lp/soyuz/scripts/ftpmasterbase.py	2012-07-05 09:43:58 +0000
+++ lib/lp/soyuz/scripts/ftpmasterbase.py	2012-08-01 11:16:28 +0000
@@ -13,17 +13,12 @@
     'SoyuzScript',
     ]
 
-from zope.component import getUtility
-
-from lp.app.errors import NotFoundError
 from lp.services.scripts.base import (
     LaunchpadScript,
     LaunchpadScriptFailure,
     )
 from lp.soyuz.adapters.packagelocation import build_package_location
 from lp.soyuz.enums import ArchivePurpose
-from lp.soyuz.interfaces.component import IComponentSet
-from lp.soyuz.interfaces.publishing import active_publishing_status
 
 
 class SoyuzScriptError(Exception):
@@ -94,15 +89,6 @@
     def add_package_location_options(self):
         """Add SoyuzScript package location-related options."""
         self.parser.add_option(
-            "-a", "--architecture", dest="architecture", default=None,
-            help="Architecture tag.")
-
-        self.parser.add_option(
-            '-e', '--version', dest='version', default=None,
-            action='store',
-            help='Optional package version, defaults to the current version.')
-
-        self.parser.add_option(
             "-c", "--component", dest="component", default=None,
             help="Component name.")
 
@@ -121,46 +107,6 @@
             action='store_true',
             help='Specify partner archive')
 
-    def _validatePublishing(self, currently_published):
-        """Validate the given publishing record.
-
-        Check if it matches the desired 'pocket' and 'component'.
-        """
-        if not self.options.component:
-            return
-
-        try:
-            desired_component = getUtility(IComponentSet)[
-                self.options.component]
-        except NotFoundError as err:
-            raise SoyuzScriptError(err)
-
-        if currently_published.component != desired_component:
-            raise SoyuzScriptError(
-                "%s was skipped because it is not in %s component" % (
-                currently_published.displayname,
-                desired_component.name.upper()))
-
-    def findLatestPublishedSource(self, name):
-        """Return a suitable `SourcePackagePublishingHistory`."""
-        assert self.location is not None, 'Undefined location.'
-
-        published_sources = self.location.archive.getPublishedSources(
-            name=name, version=self.options.version,
-            status=active_publishing_status,
-            distroseries=self.location.distroseries,
-            pocket=self.location.pocket,
-            exact_match=True)
-
-        try:
-            latest_source = published_sources[0]
-        except IndexError:
-            raise SoyuzScriptError(
-                "Could not find source '%s/%s' in %s" % (
-                name, self.options.version, self.location))
-        self._validatePublishing(latest_source)
-        return latest_source
-
     def _getUserConfirmation(self, full_question=None, valid_answers=None):
         """Use raw_input to collect user feedback.
 

=== modified file 'lib/lp/soyuz/scripts/packagecopier.py'
--- lib/lp/soyuz/scripts/packagecopier.py	2012-07-30 20:14:38 +0000
+++ lib/lp/soyuz/scripts/packagecopier.py	2012-08-01 11:16:28 +0000
@@ -1,12 +1,11 @@
 # Copyright 2009-2012 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
-"""PackageCopier utilities."""
+"""Package copying utilities."""
 
 __metaclass__ = type
 
 __all__ = [
-    'PackageCopier',
     'CopyChecker',
     'check_copy_permissions',
     'do_copy',
@@ -27,9 +26,7 @@
 from lp.buildmaster.enums import BuildStatus
 from lp.services.database.bulk import load_related
 from lp.soyuz.adapters.notification import notify
-from lp.soyuz.adapters.packagelocation import build_package_location
 from lp.soyuz.enums import (
-    ArchivePurpose,
     BinaryPackageFileType,
     SourcePackageFormat,
     )
@@ -47,10 +44,6 @@
     IPackageUploadSet,
     )
 from lp.soyuz.scripts.custom_uploads_copier import CustomUploadsCopier
-from lp.soyuz.scripts.ftpmasterbase import (
-    SoyuzScript,
-    SoyuzScriptError,
-    )
 
 
 # XXX cprov 2009-06-12: this function should be incorporated in
@@ -882,192 +875,3 @@
     delayed_copy.acceptFromCopy()
 
     return DelayedCopy(delayed_copy)
-
-
-class PackageCopier(SoyuzScript):
-    """SoyuzScript that copies published packages between locations.
-
-    Possible exceptions raised are:
-    * PackageLocationError: specified package or distro does not exist
-    * PackageCopyError: the copy operation itself has failed
-    * LaunchpadScriptFailure: only raised if entering via main(), ie this
-        code is running as a genuine script.  In this case, this is
-        also the _only_ exception to be raised.
-
-    The test harness doesn't enter via main(), it calls doCopy(), so
-    it only sees the first two exceptions.
-    """
-
-    usage = '%prog -s warty mozilla-firefox --to-suite hoary'
-    description = 'MOVE or COPY a published package to another suite.'
-
-    def add_my_options(self):
-
-        SoyuzScript.add_my_options(self)
-
-        self.parser.add_option(
-            "-b", "--include-binaries", dest="include_binaries",
-            default=False, action="store_true",
-            help='Whether to copy related binaries or not.')
-
-        self.parser.add_option(
-            '--to-distribution', dest='to_distribution',
-            default='ubuntu', action='store',
-            help='Destination distribution name.')
-
-        self.parser.add_option(
-            '--to-suite', dest='to_suite', default=None,
-            action='store', help='Destination suite name.')
-
-        self.parser.add_option(
-            '--to-ppa', dest='to_ppa', default=None,
-            action='store', help='Destination PPA owner name.')
-
-        self.parser.add_option(
-            '--to-ppa-name', dest='to_ppa_name', default='ppa',
-            action='store', help='Destination PPA name.')
-
-        self.parser.add_option(
-            '--to-partner', dest='to_partner', default=False,
-            action='store_true', help='Destination set to PARTNER archive.')
-
-        self.parser.add_option(
-            '--unembargo', dest='unembargo', default=False,
-            action='store_true',
-            help='Allow copying from a private archive to a public archive.')
-
-    def checkCopyOptions(self):
-        """Check if the locations options are sane.
-
-         * Catch Cross-PARTNER copies, they are not allowed.
-         * Catch simulataneous PPA and PARTNER locations or destinations,
-           results are unpredictable (in fact, the code will ignore PPA and
-           operate only in PARTNER, but that's odd)
-        """
-        if ((self.options.partner_archive and not self.options.to_partner)
-            or (self.options.to_partner and not
-                self.options.partner_archive)):
-            raise SoyuzScriptError(
-                "Cross-PARTNER copies are not allowed.")
-
-        if self.options.archive_owner_name and self.options.partner_archive:
-            raise SoyuzScriptError(
-                "Cannot operate with location PARTNER and PPA "
-                "simultaneously.")
-
-        if self.options.to_ppa and self.options.to_partner:
-            raise SoyuzScriptError(
-                "Cannot operate with destination PARTNER and PPA "
-                "simultaneously.")
-
-    def checkPrivacyOptions(self):
-        """Check privacy-related location options.
-
-        We can copy from a private archive to a public archive, but only
-        with the --unembargo option (to avoid accidents).  Unembargoing into
-        the release pocket of a distribution is not permitted.
-        """
-        if (self.location.archive.private and
-            not self.destination.archive.private):
-            if not self.options.unembargo:
-                raise SoyuzScriptError(
-                    "Copying from a private archive to a public archive "
-                    "requires the --unembargo option.")
-
-            if not self.destination.archive.canModifySuite(
-                self.destination.distroseries, self.destination.pocket):
-                raise SoyuzScriptError(
-                    "Can't unembargo into suite '%s' of a distribution." %
-                    self.destination.distroseries.getSuite(
-                        self.destination.pocket))
-
-    def mainTask(self):
-        """Execute package copy procedure.
-
-        Copy source publication and optionally also copy its binaries by
-        passing '-b' (include_binary) option.
-
-        Modules using this class outside of its normal usage in the
-        copy-package.py script can call this method to start the copy.
-
-        In this case the caller can override test_args on __init__
-        to set the command line arguments.
-
-        Can raise SoyuzScriptError.
-        """
-        assert self.location, (
-            "location is not available, call PackageCopier.setupLocation() "
-            "before dealing with mainTask.")
-
-        self.checkCopyOptions()
-
-        sourcename = self.args[0]
-
-        self.setupDestination()
-
-        self.checkPrivacyOptions()
-
-        self.logger.info("FROM: %s" % (self.location))
-        self.logger.info("TO: %s" % (self.destination))
-
-        to_copy = []
-        source_pub = self.findLatestPublishedSource(sourcename)
-        to_copy.append(source_pub)
-        if self.options.include_binaries:
-            to_copy.extend(source_pub.getPublishedBinaries())
-
-        self.logger.info("Copy candidates:")
-        for candidate in to_copy:
-            self.logger.info('\t%s' % candidate.displayname)
-
-        sources = [source_pub]
-        try:
-            copies = do_copy(
-                sources, self.destination.archive,
-                self.destination.distroseries, self.destination.pocket,
-                self.options.include_binaries, allow_delayed_copies=False,
-                check_permissions=False, unembargo=self.options.unembargo,
-                logger=self.logger)
-        except CannotCopy as error:
-            self.logger.error(str(error))
-            return []
-
-        self.logger.info("Copied:")
-        for copy in copies:
-            self.logger.info('\t%s' % copy.displayname)
-
-        if len(copies) == 1:
-            self.logger.info(
-                "%s package successfully copied." % len(copies))
-        elif len(copies) > 1:
-            self.logger.info(
-                "%s packages successfully copied." % len(copies))
-        else:
-            self.logger.info("No packages copied.")
-
-        # Information returned mainly for the benefit of the test harness.
-        return copies
-
-    def setupDestination(self):
-        """Build PackageLocation for the destination context."""
-        if self.options.to_partner:
-            self.destination = build_package_location(
-                self.options.to_distribution,
-                self.options.to_suite,
-                ArchivePurpose.PARTNER)
-        elif self.options.to_ppa:
-            self.destination = build_package_location(
-                self.options.to_distribution,
-                self.options.to_suite,
-                ArchivePurpose.PPA,
-                self.options.to_ppa,
-                self.options.to_ppa_name)
-        else:
-            self.destination = build_package_location(
-                self.options.to_distribution,
-                self.options.to_suite)
-
-        if self.location == self.destination:
-            raise SoyuzScriptError(
-                "Can not sync between the same locations: '%s' to '%s'" % (
-                self.location, self.destination))

=== modified file 'lib/lp/soyuz/scripts/tests/test_copypackage.py'
--- lib/lp/soyuz/scripts/tests/test_copypackage.py	2012-07-30 20:03:41 +0000
+++ lib/lp/soyuz/scripts/tests/test_copypackage.py	2012-08-01 11:16:28 +0000
@@ -4,14 +4,10 @@
 __metaclass__ = type
 
 import datetime
-import os
-import subprocess
-import sys
 from textwrap import (
     dedent,
     fill,
     )
-import unittest
 
 import pytz
 from testtools.content import text_content
@@ -32,16 +28,11 @@
 from lp.bugs.interfaces.bugtask import BugTaskStatus
 from lp.buildmaster.enums import BuildStatus
 from lp.registry.interfaces.distribution import IDistributionSet
-from lp.registry.interfaces.person import IPersonSet
 from lp.registry.interfaces.pocket import PackagePublishingPocket
 from lp.registry.interfaces.series import SeriesStatus
 from lp.services.config import config
 from lp.services.database.sqlbase import flush_database_caches
-from lp.services.librarian.interfaces import ILibraryFileAliasSet
-from lp.services.librarianserver.testing.server import fillLibrarianFile
-from lp.services.log.logger import BufferLogger
 from lp.soyuz.adapters.overrides import SourceOverride
-from lp.soyuz.adapters.packagelocation import PackageLocationError
 from lp.soyuz.enums import (
     ArchivePermissionType,
     ArchivePurpose,
@@ -62,17 +53,11 @@
     ISourcePackageFormatSelectionSet,
     )
 from lp.soyuz.model.archivepermission import ArchivePermission
-from lp.soyuz.model.publishing import (
-    BinaryPackagePublishingHistory,
-    SourcePackagePublishingHistory,
-    )
-from lp.soyuz.scripts.ftpmasterbase import SoyuzScriptError
 from lp.soyuz.scripts.packagecopier import (
     _do_delayed_copy,
     _do_direct_copy,
     CopyChecker,
     do_copy,
-    PackageCopier,
     update_files_privacy,
     )
 from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
@@ -85,10 +70,7 @@
     dbuser,
     switch_dbuser,
     )
-from lp.testing.layers import (
-    DatabaseLayer,
-    LaunchpadZopelessLayer,
-    )
+from lp.testing.layers import LaunchpadZopelessLayer
 from lp.testing.mail_helpers import pop_notifications
 from lp.testing.matchers import HasQueryCount
 
@@ -2315,476 +2297,3 @@
         proposed_bug = getUtility(IBugSet).get(proposed_bug_id)
         [proposed_bug_task] = proposed_bug.bugtasks
         self.assertEqual(proposed_bug_task.status, BugTaskStatus.NEW)
-
-
-class CopyPackageScriptTestCase(unittest.TestCase):
-    """Test the copy-package.py script."""
-    layer = LaunchpadZopelessLayer
-
-    def runCopyPackage(self, extra_args=None):
-        """Run copy-package.py, returning the result and output.
-
-        Returns a tuple of the process's return code, stdout output and
-        stderr output.
-        """
-        if extra_args is None:
-            extra_args = []
-        script = os.path.join(
-            config.root, "scripts", "ftpmaster-tools", "copy-package.py")
-        args = [sys.executable, script, '-y']
-        args.extend(extra_args)
-        process = subprocess.Popen(
-            args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-        # The subprocess commits to the database so we need to tell the layer
-        # to fully tear down and restore the testing database.
-        DatabaseLayer.force_dirty_database()
-        stdout, stderr = process.communicate()
-        return (process.returncode, stdout, stderr)
-
-    def testSimpleRun(self):
-        """Try a simple copy-package.py run.
-
-        Uses the default case, copy mozilla-firefox source with binaries
-        from warty to hoary.
-        """
-        # Count the records in SSPPH and SBPPH to check later that they
-        # increased by one each.
-        num_source_pub = SourcePackagePublishingHistory.select(
-            "True").count()
-        num_bin_pub = BinaryPackagePublishingHistory.select(
-            "True").count()
-
-        # Fill the source package changelog so it can be processed
-        # for closing bugs.
-        fillLibrarianFile(52, content='Format: 1.7\n')
-
-        returncode, out, err = self.runCopyPackage(
-            extra_args=['-s', 'warty', 'mozilla-firefox',
-                        '--to-suite', 'hoary', '-b'])
-        # Need to print these or you can't see what happened if the
-        # return code is bad:
-        if returncode != 0:
-            print "\nStdout:\n%s\nStderr\n%s\n" % (out, err)
-        self.assertEqual(0, returncode)
-
-        # Test that the database has been modified.  We're only checking
-        # that the number of rows has increase; content checks are done
-        # in other tests.
-        self.layer.txn.abort()
-
-        num_source_pub_after = SourcePackagePublishingHistory.select(
-            "True").count()
-        num_bin_pub_after = BinaryPackagePublishingHistory.select(
-            "True").count()
-
-        self.assertEqual(num_source_pub + 1, num_source_pub_after)
-        # 'mozilla-firefox' source produced 4 binaries.
-        self.assertEqual(num_bin_pub + 4, num_bin_pub_after)
-
-
-class CopyPackageTestCase(TestCaseWithFactory):
-    """Test the CopyPackageHelper class."""
-    layer = LaunchpadZopelessLayer
-    dbuser = config.archivepublisher.dbuser
-
-    def setUp(self):
-        """Anotate pending publishing records provided in the sampledata.
-
-        The records annotated will be excluded during the operation checks,
-        see checkCopies().
-        """
-        super(CopyPackageTestCase, self).setUp()
-        pending_sources = SourcePackagePublishingHistory.selectBy(
-            status=PackagePublishingStatus.PENDING)
-        self.sources_pending_ids = [pub.id for pub in pending_sources]
-        pending_binaries = BinaryPackagePublishingHistory.selectBy(
-            status=PackagePublishingStatus.PENDING)
-        self.binaries_pending_ids = [pub.id for pub in pending_binaries]
-
-        # Run test cases in the production context.
-        switch_dbuser(self.dbuser)
-
-    def getCopier(self, sourcename='mozilla-firefox', sourceversion=None,
-                  from_distribution='ubuntu', from_suite='warty',
-                  to_distribution='ubuntu', to_suite='hoary',
-                  component=None, from_ppa=None, to_ppa=None,
-                  from_partner=False, to_partner=False,
-                  confirm_all=True, include_binaries=True, unembargo=False):
-        """Return a PackageCopier instance.
-
-        Allow tests to use a set of default options and pass an
-        inactive logger to PackageCopier.
-        """
-        test_args = ['-s', from_suite,
-                     '-d', from_distribution,
-                     '--to-suite', to_suite,
-                     '--to-distribution', to_distribution]
-
-        if confirm_all:
-            test_args.append('-y')
-
-        if include_binaries:
-            test_args.append('-b')
-
-        if unembargo:
-            test_args.append('--unembargo')
-
-        if sourceversion is not None:
-            test_args.extend(['-e', sourceversion])
-
-        if component is not None:
-            test_args.extend(['-c', component])
-
-        if from_partner:
-            test_args.append('-j')
-
-        if to_partner:
-            test_args.append('--to-partner')
-
-        if from_ppa is not None:
-            test_args.extend(['-p', from_ppa])
-
-        if to_ppa is not None:
-            test_args.extend(['--to-ppa', to_ppa])
-
-        test_args.append(sourcename)
-
-        copier = PackageCopier(name='copy-package', test_args=test_args)
-        copier.logger = BufferLogger()
-        copier.setupLocation()
-        return copier
-
-    def checkCopies(self, copied, target_archive, size):
-        """Perform overall checks in the copied records list.
-
-         * check if the size is expected,
-         * check if all copied records are PENDING,
-         * check if the list copied matches the list of PENDING records
-           retrieved from the target_archive.
-        """
-        self.assertEqual(len(copied), size)
-
-        for candidate in copied:
-            self.assertEqual(PackagePublishingStatus.PENDING, candidate.status)
-
-        def excludeOlds(found, old_pending_ids):
-            return [pub.id for pub in found if pub.id not in old_pending_ids]
-
-        sources_pending = target_archive.getPublishedSources(
-            status=PackagePublishingStatus.PENDING)
-        sources_pending_ids = excludeOlds(
-            sources_pending, self.sources_pending_ids)
-
-        binaries_pending = target_archive.getAllPublishedBinaries(
-            status=PackagePublishingStatus.PENDING)
-        binaries_pending_ids = excludeOlds(
-            binaries_pending, self.binaries_pending_ids)
-
-        copied_ids = [pub.id for pub in copied]
-        pending_ids = sources_pending_ids + binaries_pending_ids
-
-        self.assertEqual(
-            sorted(copied_ids), sorted(pending_ids),
-            "The copy did not succeed.\nExpected IDs: %s\nFound IDs: %s" % (
-                sorted(copied_ids), sorted(pending_ids)))
-
-    def testCopyBetweenDistroSeries(self):
-        """Check the copy operation between distroseries."""
-        # Fill the source changesfiles, so it can be properly processed
-        # for closing bugs.
-        fillLibrarianFile(52, content='Format: 1.7\n')
-
-        copy_helper = self.getCopier()
-        copied = copy_helper.mainTask()
-
-        # Check locations.  They should be the same as the defaults defined
-        # in the getCopier method.
-        self.assertEqual(str(copy_helper.location),
-                         'Primary Archive for Ubuntu Linux: warty-RELEASE')
-        self.assertEqual(str(copy_helper.destination),
-                         'Primary Archive for Ubuntu Linux: hoary-RELEASE')
-
-        # Check stored results. The number of copies should be 5
-        # (1 source and 2 binaries in 2 architectures).
-        target_archive = copy_helper.destination.archive
-        self.checkCopies(copied, target_archive, 5)
-
-    def testCopyBetweenPockets(self):
-        """Check the copy operation between pockets.
-
-        That's normally how SECURITY publications get propagated to UPDATES
-        in order to reduce the burden on ubuntu servers.
-        """
-        # Fill the source changesfiles, so it can be properly processed
-        # for closing bugs.
-        fillLibrarianFile(52, content='Format: 1.7\n')
-
-        copy_helper = self.getCopier(
-            from_suite='warty', to_suite='warty-updates')
-        copied = copy_helper.mainTask()
-
-        self.assertEqual(str(copy_helper.location),
-                         'Primary Archive for Ubuntu Linux: warty-RELEASE')
-        self.assertEqual(str(copy_helper.destination),
-                         'Primary Archive for Ubuntu Linux: warty-UPDATES')
-
-        target_archive = copy_helper.destination.archive
-        self.checkCopies(copied, target_archive, 5)
-
-    def testCopyAncestryLookup(self):
-        """Check the ancestry lookup used in copy-package.
-
-        This test case exercises the 'ancestry lookup' mechanism used to
-        verify if the copy candidate version is higher than the currently
-        published version of the same source/binary in the destination
-        context.
-
-        We emulate a conflict with a pre-existing version of 'firefox-3.0'
-        in hardy-updates, a version of 'firefox' present in hardy and a copy
-        copy candidate 'firefox' from hardy-security.
-
-        As described in bug #245416, the ancestry lookup was erroneously
-        considering the 'firefox-3.0' as an ancestor to the 'firefox' copy
-        candidate. It was caused because the lookup was not restricted to
-        'exact_match' names. See `scripts/packagecopier.py`.
-        """
-        ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
-        hoary = ubuntu.getSeries('hoary')
-        test_publisher = self.getTestPublisher(hoary)
-
-        # Create the described publishing scenario.
-        ancestry_source = test_publisher.getPubSource(
-            sourcename='firefox', version='1.0',
-            archive=ubuntu.main_archive, distroseries=hoary,
-            pocket=PackagePublishingPocket.RELEASE,
-            status=PackagePublishingStatus.PUBLISHED)
-
-        test_publisher.getPubSource(
-            sourcename='firefox-3.0', version='1.2',
-            archive=ubuntu.main_archive, distroseries=hoary,
-            pocket=PackagePublishingPocket.UPDATES,
-            status=PackagePublishingStatus.PUBLISHED)
-
-        candidate_source = test_publisher.getPubSource(
-            sourcename='firefox', version='1.1',
-            archive=ubuntu.main_archive, distroseries=hoary,
-            pocket=PackagePublishingPocket.SECURITY,
-            status=PackagePublishingStatus.PUBLISHED)
-
-        # Commit to ensure librarian files are written.
-        self.layer.txn.commit()
-
-        # Perform the copy.
-        copy_helper = self.getCopier(
-            sourcename='firefox', include_binaries=False,
-            from_suite='hoary-security', to_suite='hoary-updates')
-        copied = copy_helper.mainTask()
-
-        # Check if the copy was performed as expected.
-        target_archive = copy_helper.destination.archive
-        self.checkCopies(copied, target_archive, 1)
-
-        # Verify the resulting publishing scenario.
-        [updates, security,
-         release] = ubuntu.main_archive.getPublishedSources(
-            name='firefox', exact_match=True)
-
-        # Context publications remain the same.
-        self.assertEqual(release, ancestry_source)
-        self.assertEqual(security, candidate_source)
-
-        # The copied source is published in the 'updates' pocket as expected.
-        self.assertEqual(updates.displayname, 'firefox 1.1 in hoary')
-        self.assertEqual(updates.pocket, PackagePublishingPocket.UPDATES)
-        self.assertEqual(len(updates.getBuilds()), 1)
-
-    def testCopyAcrossPartner(self):
-        """Check the copy operation across PARTNER archive.
-
-        This operation is required to propagate partner uploads across several
-        suites, avoiding to build (and modify) the package multiple times to
-        have it available for all supported suites independent of the
-        time they were released.
-        """
-        copy_helper = self.getCopier(
-            sourcename='commercialpackage', from_partner=True,
-            to_partner=True, from_suite='breezy-autotest', to_suite='hoary')
-        copied = copy_helper.mainTask()
-
-        self.assertEqual(
-            str(copy_helper.location),
-            'Partner Archive for Ubuntu Linux: breezy-autotest-RELEASE')
-        self.assertEqual(
-            str(copy_helper.destination),
-            'Partner Archive for Ubuntu Linux: hoary-RELEASE')
-
-        # 'commercialpackage' has only one binary built for i386.
-        # The source and the binary got copied.
-        target_archive = copy_helper.destination.archive
-        self.checkCopies(copied, target_archive, 2)
-
-    def getTestPublisher(self, distroseries):
-        """Return a initialized `SoyuzTestPublisher` object.
-
-        Setup a i386 chroot for the given distroseries, so it can build
-        and publish binaries.
-        """
-        fake_chroot = getUtility(ILibraryFileAliasSet)[1]
-        distroseries['i386'].addOrUpdateChroot(fake_chroot)
-        test_publisher = SoyuzTestPublisher()
-        test_publisher.setUpDefaultDistroSeries(distroseries)
-        test_publisher.person = getUtility(IPersonSet).getByName("name16")
-        return test_publisher
-
-    def testCopyAcrossPPAs(self):
-        """Check the copy operation across PPAs.
-
-        This operation is useful to propagate dependencies across
-        collaborative PPAs without requiring new uploads.
-        """
-        copy_helper = self.getCopier(
-            sourcename='iceweasel', from_ppa='cprov',
-            from_suite='warty', to_suite='hoary', to_ppa='mark')
-        copied = copy_helper.mainTask()
-
-        self.assertEqual('cprov: warty-RELEASE', str(copy_helper.location))
-        self.assertEqual('mark: hoary-RELEASE', str(copy_helper.destination))
-
-        target_archive = copy_helper.destination.archive
-        self.checkCopies(copied, target_archive, 2)
-
-    def testSourceLookupFailure(self):
-        """Check if it raises when the target source can't be found.
-
-        SoyuzScriptError is raised when a lookup fails.
-        """
-        copy_helper = self.getCopier(sourcename='zaphod')
-
-        self.assertRaisesWithContent(
-            SoyuzScriptError,
-            "Could not find source 'zaphod/None' in "
-            "Primary Archive for Ubuntu Linux: warty-RELEASE",
-            copy_helper.mainTask)
-
-    def testFailIfValidPackageButNotInSpecifiedSuite(self):
-        """It fails if the package is not published in the source location.
-
-        SoyuzScriptError is raised when a lookup fails
-        """
-        copy_helper = self.getCopier(from_suite="breezy-autotest")
-
-        self.assertRaisesWithContent(
-            SoyuzScriptError,
-            "Could not find source 'mozilla-firefox/None' in "
-            "Primary Archive for Ubuntu Linux: breezy-autotest-RELEASE",
-            copy_helper.mainTask)
-
-    def testFailIfSameLocations(self):
-        """It fails if the source and destination locations are the same.
-
-        SoyuzScriptError is raise when the copy cannot be performed.
-        """
-        copy_helper = self.getCopier(from_suite='warty', to_suite='warty')
-
-        self.assertRaisesWithContent(
-            SoyuzScriptError,
-            "Can not sync between the same locations: "
-            "'Primary Archive for Ubuntu Linux: warty-RELEASE' to "
-            "'Primary Archive for Ubuntu Linux: warty-RELEASE'",
-            copy_helper.mainTask)
-
-    def testBadDistributionDestination(self):
-        """Check if it raises if the distribution is invalid.
-
-        PackageLocationError is raised for unknown destination distribution.
-        """
-        copy_helper = self.getCopier(to_distribution="beeblebrox")
-
-        self.assertRaisesWithContent(
-            PackageLocationError,
-            "Could not find distribution 'beeblebrox'",
-            copy_helper.mainTask)
-
-    def testBadSuiteDestination(self):
-        """Check that it fails when specifying a bad distroseries.
-
-        PackageLocationError is raised for unknown destination distroseries.
-        """
-        copy_helper = self.getCopier(to_suite="slatibartfast")
-
-        self.assertRaisesWithContent(
-            PackageLocationError,
-            "Could not find suite 'slatibartfast'",
-            copy_helper.mainTask)
-
-    def testBadPPADestination(self):
-        """Check that it fails when specifying a bad PPA destination.
-
-        PackageLocationError is raised for unknown destination PPA.
-        """
-        copy_helper = self.getCopier(to_ppa="slatibartfast")
-
-        self.assertRaisesWithContent(
-            PackageLocationError,
-            "Could not find a PPA for slatibartfast named ppa",
-            copy_helper.mainTask)
-
-    def testCrossPartnerCopiesFails(self):
-        """Check that it fails when cross-PARTNER copies are requested.
-
-        SoyuzScriptError is raised for cross-PARTNER copies, packages
-        published in PARTNER archive can only be copied within PARTNER
-        archive.
-        """
-        copy_helper = self.getCopier(from_partner=True)
-
-        self.assertRaisesWithContent(
-            SoyuzScriptError,
-            "Cross-PARTNER copies are not allowed.",
-            copy_helper.mainTask)
-
-        copy_helper = self.getCopier(to_partner=True)
-
-        self.assertRaisesWithContent(
-            SoyuzScriptError,
-            "Cross-PARTNER copies are not allowed.",
-            copy_helper.mainTask)
-
-    def testPpaPartnerInconsistentLocations(self):
-        """Check if PARTNER and PPA inconsistent arguments are caught.
-
-        SoyuzScriptError is raised for when inconsistences in the PARTNER
-        and PPA location or destination are spotted.
-        """
-        copy_helper = self.getCopier(
-            from_partner=True, from_ppa='cprov', to_partner=True)
-
-        self.assertRaisesWithContent(
-            SoyuzScriptError,
-            "Cannot operate with location PARTNER and PPA simultaneously.",
-            copy_helper.mainTask)
-
-        copy_helper = self.getCopier(
-            from_partner=True, to_ppa='cprov', to_partner=True)
-
-        self.assertRaisesWithContent(
-            SoyuzScriptError,
-            "Cannot operate with destination PARTNER and PPA simultaneously.",
-            copy_helper.mainTask)
-
-    def testUnembargoStableReleasePocketForbidden(self):
-        """Unembargoing into release pocket of stable series is forbidden."""
-        # Set up a private PPA.
-        joe = self.factory.makePerson(name="joe")
-        ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
-        self.factory.makeArchive(
-            owner=joe, name='ppa', private=True, distribution=ubuntu)
-
-        copy_helper = self.getCopier(
-            sourcename='foo', from_ppa='joe',
-            include_binaries=True, from_suite='warty',
-            to_suite='warty', unembargo=True)
-        self.assertRaisesWithContent(
-            SoyuzScriptError,
-            "Can't unembargo into suite 'warty' of a distribution.",
-            copy_helper.mainTask)

=== modified file 'lib/lp/soyuz/scripts/tests/test_populatearchive.py'
--- lib/lp/soyuz/scripts/tests/test_populatearchive.py	2012-01-19 03:09:38 +0000
+++ lib/lp/soyuz/scripts/tests/test_populatearchive.py	2012-08-01 11:16:28 +0000
@@ -43,7 +43,7 @@
 
 
 class TestPopulateArchiveScript(TestCaseWithFactory):
-    """Test the copy-package.py script."""
+    """Test the populate-archive.py script."""
 
     layer = LaunchpadZopelessLayer
     expected_build_spns = [

=== modified file 'lib/lp/soyuz/scripts/tests/test_soyuzscript.py'
--- lib/lp/soyuz/scripts/tests/test_soyuzscript.py	2012-06-19 17:29:32 +0000
+++ lib/lp/soyuz/scripts/tests/test_soyuzscript.py	2012-08-01 11:16:28 +0000
@@ -9,14 +9,8 @@
 
 import unittest
 
-from zope.component import getUtility
-
-from lp.registry.interfaces.person import IPersonSet
 from lp.services.log.logger import BufferLogger
-from lp.soyuz.scripts.ftpmasterbase import (
-    SoyuzScript,
-    SoyuzScriptError,
-    )
+from lp.soyuz.scripts.ftpmasterbase import SoyuzScript
 from lp.testing.layers import LaunchpadZopelessLayer
 
 
@@ -60,81 +54,6 @@
         soyuz.setupLocation()
         return soyuz
 
-    def testFindLatestPublishedSourceInPRIMARY(self):
-        """Source lookup in PRIMARY archive."""
-        soyuz = self.getSoyuz()
-        src = soyuz.findLatestPublishedSource('pmount')
-        self.assertEqual(src.displayname, 'pmount 0.1-2 in hoary')
-
-        self.assertRaises(
-            SoyuzScriptError, soyuz.findLatestPublishedSource, 'marvin')
-
-        soyuz = self.getSoyuz(suite='hoary-security')
-        self.assertRaises(
-            SoyuzScriptError, soyuz.findLatestPublishedSource, 'pmount')
-
-    def testFindLatestPublishedSourceInPARTNER(self):
-        """Source lookup in PARTNER archive."""
-        soyuz = self.getSoyuz(suite='breezy-autotest', partner=True)
-        src = soyuz.findLatestPublishedSource('commercialpackage')
-        self.assertEqual(
-            src.displayname, 'commercialpackage 1.0-1 in breezy-autotest')
-
-        self.assertRaises(
-            SoyuzScriptError, soyuz.findLatestPublishedSource, 'marvin')
-
-        soyuz = self.getSoyuz(suite='warty', partner=True)
-        self.assertRaises(
-            SoyuzScriptError, soyuz.findLatestPublishedSource,
-            'commercialpackage')
-
-    def testFindLatestPublishedSourceInPPA(self):
-        """Source lookup in PPAs."""
-        soyuz = self.getSoyuz(ppa='cprov', suite='warty')
-        src = soyuz.findLatestPublishedSource('pmount')
-        self.assertEqual(src.displayname, 'pmount 0.1-1 in warty')
-
-        self.assertRaises(
-            SoyuzScriptError, soyuz.findLatestPublishedSource, 'marvin')
-
-        soyuz = self.getSoyuz(ppa='cprov', suite='warty-security')
-        self.assertRaises(
-            SoyuzScriptError, soyuz.findLatestPublishedSource, 'pmount')
-
-        # Bug 159151 occurred because we were printing unicode characters
-        # to an ascii codec in the exception, which originated in the PPA
-        # owner's name.  Let's munge cprov's name to be unicode and ensure
-        # we still get the right exception raised (a UnicodeError is raised
-        # if the bug is present).
-        cprov = getUtility(IPersonSet).getByName('cprov')
-        cprov.displayname = u'\xe7\xe3o'
-        self.assertRaises(
-            SoyuzScriptError, soyuz.findLatestPublishedSource, 'pmount')
-
-    def testFindLatestPublishedSourceAndCheckComponent(self):
-        """Before returning the source publication component is checked.
-
-        Despite of existing the found publication should match the given
-        component (if given) otherwise an error is raised.
-        """
-        soyuz = self.getSoyuz(suite='hoary', component='main')
-        src = soyuz.findLatestPublishedSource('pmount')
-        self.assertEqual(src.displayname, 'pmount 0.1-2 in hoary')
-
-        soyuz = self.getSoyuz(component='multiverse')
-        self.assertRaises(
-            SoyuzScriptError, soyuz.findLatestPublishedSource, 'pmount')
-
-    def testFindLatestPublishedSourceWithSpecificVersion(self):
-        """Source lookups for specific version."""
-        soyuz = self.getSoyuz(version='0.1-2')
-        src = soyuz.findLatestPublishedSource('pmount')
-        self.assertEqual(src.displayname, 'pmount 0.1-2 in hoary')
-
-        soyuz = self.getSoyuz(version='666')
-        self.assertRaises(
-            SoyuzScriptError, soyuz.findLatestPublishedSource, 'pmount')
-
     def testFinishProcedure(self):
         """Make sure finishProcedure returns the correct boolean."""
         soyuz = self.getSoyuz()

=== modified file 'lib/lp/soyuz/stories/ppa/xx-copy-packages.txt'
--- lib/lp/soyuz/stories/ppa/xx-copy-packages.txt	2012-01-15 11:06:57 +0000
+++ lib/lp/soyuz/stories/ppa/xx-copy-packages.txt	2012-08-01 11:16:28 +0000
@@ -44,7 +44,7 @@
     Unauthorized: ... 'launchpad.AnyPerson')
 
 James is a valid user, however he doesn't have access to any PPA, he
-is allowed to access the copy-package interface in Celso's PPA, but
+is allowed to access the copy-packages interface in Celso's PPA, but
 the form is not rendered, instead he is advised to activate his own
 PPA in order to be able to copy packages.
 
@@ -581,7 +581,7 @@
 In the minute after James had deleted the package, he discovered that
 'pmount' might work correctly in warty.
 
-No problem, he goes back to the copy-package interface in his PPA and
+No problem, he goes back to the copy-packages interface in his PPA and
 still able to copy the deleted source to the warty series.
 
 By default the copy view presents only PUBLISHED or PENDING packages.
@@ -704,7 +704,7 @@
     >>> jblack_browser.getControl(name='field.selected_sources').value = (
     ...     [iceweasel_pub_id, pmount_pub_id])
 
-Now that James have access to more than one PPA, the copy-package form
+Now that James have access to more than one PPA, the copy-packages form
 allows him to select one of them.
 
     >>> print jblack_browser.getControl(
@@ -891,7 +891,7 @@
 
     >>> print_ppa_packages(jblack_browser.contents)
 
-Not yet happy, James goes back to his PPA to check if the copy-package
+Not yet happy, James goes back to his PPA to check if the copy-packages
 interface can be used to resurrect deleted packages.
 
     >>> jblack_browser.open(

=== modified file 'lib/lp/soyuz/stories/webservice/xx-archive.txt'
--- lib/lp/soyuz/stories/webservice/xx-archive.txt	2012-06-14 03:22:43 +0000
+++ lib/lp/soyuz/stories/webservice/xx-archive.txt	2012-08-01 11:16:28 +0000
@@ -796,8 +796,7 @@
 
 IArchive contains 2 custom operations to copy packages from another archive.
 These are syncSource() and syncSources(). Both are wrappers of the
-`PackageCopier` infrastructure, see more information in
-scripts/packagecopier.py.
+`do_copy` infrastructure, see more information in scripts/packagecopier.py.
 
 For testing purposes we will create some publications.
 

=== removed file 'scripts/ftpmaster-tools/copy-package.py'
--- scripts/ftpmaster-tools/copy-package.py	2011-12-29 05:29:36 +0000
+++ scripts/ftpmaster-tools/copy-package.py	1970-01-01 00:00:00 +0000
@@ -1,20 +0,0 @@
-#!/usr/bin/python -S
-#
-# Copyright 2009 Canonical Ltd.  This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-# pylint: disable-msg=W0403
-
-"""Copy publications across suites."""
-
-import _pythonpath
-
-from lp.services.config import config
-from lp.soyuz.scripts.packagecopier import PackageCopier
-
-
-if __name__ == '__main__':
-    script = PackageCopier(
-        'copy-package', dbuser=config.archivepublisher.dbuser)
-    script.lock_and_run()
-


Follow ups