← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~cjwatson/launchpad/refactor-queue-custom into lp:launchpad

 

Colin Watson has proposed merging lp:~cjwatson/launchpad/refactor-queue-custom into lp:launchpad.

Commit message:
Use Zope component lookup to get custom upload handlers.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/refactor-queue-custom/+merge/295453

Use Zope component lookup to get custom upload handlers.

This is the first step towards eradicating archivepublisher imports from lp.soyuz.model.queue.  A subsequent branch will finish this off.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/refactor-queue-custom into lp:launchpad.
=== modified file 'lib/lp/archivepublisher/configure.zcml'
--- lib/lp/archivepublisher/configure.zcml	2013-06-03 07:26:52 +0000
+++ lib/lp/archivepublisher/configure.zcml	2016-05-23 11:17:51 +0000
@@ -1,4 +1,4 @@
-<!-- Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
+<!-- Copyright 2009-2016 Canonical Ltd.  This software is licensed under the
      GNU Affero General Public License version 3 (see the file LICENSE).
 -->
 
@@ -19,10 +19,8 @@
         for="lp.soyuz.interfaces.archive.IArchive"
         provides="lp.archivepublisher.interfaces.archivesigningkey.IArchiveSigningKey"
         factory="lp.archivepublisher.archivesigningkey.ArchiveSigningKey"
-
         />
 
-
     <!-- PublisherConfig -->
     <securedutility
         class="lp.archivepublisher.model.publisherconfig.PublisherConfigSet"
@@ -39,4 +37,48 @@
             set_schema="lp.archivepublisher.interfaces.publisherconfig.IPublisherConfig"/>
     </class>
 
+    <!-- Custom upload handlers
+
+         This is a marker as per the comment in lib/lp/soyuz/enums.py:
+         ##CUSTOMFORMAT##
+         If you change anything to do with custom formats, grep for the
+         marker in the codebase and make sure the same changes are made
+         everywhere which needs them.
+    -->
+    <securedutility
+        class="lp.archivepublisher.debian_installer.DebianInstallerUpload"
+        provides="lp.soyuz.interfaces.queue.ICustomUploadHandler"
+        name="DEBIAN_INSTALLER">
+        <allow
+            interface="lp.soyuz.interfaces.queue.ICustomUploadHandler"/>
+    </securedutility>
+    <securedutility
+        class="lp.archivepublisher.rosetta_translations.RosettaTranslationsUpload"
+        provides="lp.soyuz.interfaces.queue.ICustomUploadHandler"
+        name="ROSETTA_TRANSLATIONS">
+        <allow
+            interface="lp.soyuz.interfaces.queue.ICustomUploadHandler"/>
+    </securedutility>
+    <securedutility
+        class="lp.archivepublisher.dist_upgrader.DistUpgraderUpload"
+        provides="lp.soyuz.interfaces.queue.ICustomUploadHandler"
+        name="DIST_UPGRADER">
+        <allow
+            interface="lp.soyuz.interfaces.queue.ICustomUploadHandler"/>
+    </securedutility>
+    <securedutility
+        class="lp.archivepublisher.ddtp_tarball.DdtpTarballUpload"
+        provides="lp.soyuz.interfaces.queue.ICustomUploadHandler"
+        name="DDTP_TARBALL">
+        <allow
+            interface="lp.soyuz.interfaces.queue.ICustomUploadHandler"/>
+    </securedutility>
+    <securedutility
+        class="lp.archivepublisher.signing.SigningUpload"
+        provides="lp.soyuz.interfaces.queue.ICustomUploadHandler"
+        name="SIGNING">
+        <allow
+            interface="lp.soyuz.interfaces.queue.ICustomUploadHandler"/>
+    </securedutility>
+
 </configure>

=== modified file 'lib/lp/archivepublisher/customupload.py'
--- lib/lp/archivepublisher/customupload.py	2016-02-05 16:51:12 +0000
+++ lib/lp/archivepublisher/customupload.py	2016-05-23 11:17:51 +0000
@@ -13,21 +13,25 @@
 
 __metaclass__ = type
 
-__all__ = ['CustomUpload', 'CustomUploadError']
+__all__ = ['CustomUpload']
 
 import os
 import shutil
 import tarfile
 import tempfile
 
+from zope.interface import implementer
+
+from lp.archivepublisher.config import getPubConfig
 from lp.archivepublisher.debversion import (
     Version as make_version,
     VersionError,
     )
-
-
-class CustomUploadError(Exception):
-    """Base class for all errors associated with publishing custom uploads."""
+from lp.services.librarian.utils import copy_and_close
+from lp.soyuz.interfaces.queue import (
+    CustomUploadError,
+    ICustomUploadHandler,
+    )
 
 
 class CustomUploadTarballTarError(CustomUploadError):
@@ -88,12 +92,29 @@
         CustomUploadError.__init__(self, message)
 
 
+@implementer(ICustomUploadHandler)
 class CustomUpload:
     """Base class for custom upload handlers"""
 
     # This should be set as a class property on each subclass.
     custom_type = None
 
+    @classmethod
+    def publish(cls, packageupload, libraryfilealias, logger=None):
+        """See `ICustomUploadHandler`."""
+        temp_dir = tempfile.mkdtemp()
+        try:
+            tarfile_path = os.path.join(temp_dir, libraryfilealias.filename)
+            temp_file = open(tarfile_path, "wb")
+            libraryfilealias.open()
+            copy_and_close(libraryfilealias, temp_file)
+            pubconf = getPubConfig(packageupload.archive)
+            suite = packageupload.distroseries.getSuite(packageupload.pocket)
+            upload = cls(logger=logger)
+            upload.process(pubconf, tarfile_path, suite)
+        finally:
+            shutil.rmtree(temp_dir)
+
     def __init__(self, logger=None):
         self.targetdir = None
         self.version = None
@@ -102,11 +123,11 @@
         self.tmpdir = None
         self.logger = logger
 
-    def process(self, pubconf, tarfile_path, distroseries):
+    def process(self, pubconf, tarfile_path, suite):
         """Process the upload and install it into the archive."""
         self.tarfile_path = tarfile_path
         try:
-            self.setTargetDirectory(pubconf, tarfile_path, distroseries)
+            self.setTargetDirectory(pubconf, tarfile_path, suite)
             self.checkForConflicts()
             self.extract()
             self.installFiles()
@@ -126,7 +147,7 @@
         """Set instance variables based on decomposing the filename."""
         raise NotImplementedError
 
-    def setTargetDirectory(self, pubconf, tarfile_path, distroseries):
+    def setTargetDirectory(self, pubconf, tarfile_path, suite):
         """Set self.targetdir based on parameters.
 
         This should also set self.version and self.arch (if applicable) as a

=== modified file 'lib/lp/archivepublisher/ddtp_tarball.py'
--- lib/lp/archivepublisher/ddtp_tarball.py	2013-07-25 16:45:20 +0000
+++ lib/lp/archivepublisher/ddtp_tarball.py	2016-05-23 11:17:51 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2013 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2016 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """The processing of translated packages descriptions (ddtp) tarballs.
@@ -14,7 +14,6 @@
 
 __all__ = [
     'DdtpTarballUpload',
-    'process_ddtp_tarball',
     ]
 
 import os
@@ -59,10 +58,10 @@
         _, self.component, self.version = self.parsePath(tarfile_path)
         self.arch = None
 
-    def setTargetDirectory(self, pubconf, tarfile_path, distroseries):
+    def setTargetDirectory(self, pubconf, tarfile_path, suite):
         self.setComponents(tarfile_path)
         self.targetdir = os.path.join(
-            pubconf.archiveroot, 'dists', distroseries, self.component)
+            pubconf.archiveroot, 'dists', suite, self.component)
 
     @classmethod
     def getSeriesKey(cls, tarfile_path):
@@ -82,14 +81,3 @@
     def fixCurrentSymlink(self):
         # There is no symlink to fix up for DDTP uploads
         pass
-
-
-def process_ddtp_tarball(pubconf, tarfile_path, distroseries, logger=None):
-    """Process a raw-ddtp-tarball tarfile.
-
-    Unpacking it into the given archive for the given distroseries.
-    Raises CustomUploadError (or some subclass thereof) if
-    anything goes wrong.
-    """
-    upload = DdtpTarballUpload(logger=logger)
-    upload.process(pubconf, tarfile_path, distroseries)

=== modified file 'lib/lp/archivepublisher/debian_installer.py'
--- lib/lp/archivepublisher/debian_installer.py	2013-07-25 16:45:20 +0000
+++ lib/lp/archivepublisher/debian_installer.py	2016-05-23 11:17:51 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2013 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2016 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """The processing of debian installer tarballs."""
@@ -10,7 +10,6 @@
 
 __all__ = [
     'DebianInstallerUpload',
-    'process_debian_installer',
     ]
 
 import os
@@ -51,10 +50,10 @@
     def setComponents(self, tarfile_path):
         _, self.version, self.arch = self.parsePath(tarfile_path)
 
-    def setTargetDirectory(self, pubconf, tarfile_path, distroseries):
+    def setTargetDirectory(self, pubconf, tarfile_path, suite):
         self.setComponents(tarfile_path)
         self.targetdir = os.path.join(
-            pubconf.archiveroot, 'dists', distroseries, 'main',
+            pubconf.archiveroot, 'dists', suite, 'main',
             'installer-%s' % self.arch)
 
     @classmethod
@@ -75,14 +74,3 @@
 
     def shouldInstall(self, filename):
         return filename.startswith('%s/' % self.version)
-
-
-def process_debian_installer(pubconf, tarfile_path, distroseries, logger=None):
-    """Process a raw-installer tarfile.
-
-    Unpacking it into the given archive for the given distroseries.
-    Raises CustomUploadError (or some subclass thereof) if anything goes
-    wrong.
-    """
-    upload = DebianInstallerUpload(logger=logger)
-    upload.process(pubconf, tarfile_path, distroseries)

=== modified file 'lib/lp/archivepublisher/dist_upgrader.py'
--- lib/lp/archivepublisher/dist_upgrader.py	2013-07-25 16:45:20 +0000
+++ lib/lp/archivepublisher/dist_upgrader.py	2016-05-23 11:17:51 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2013 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2016 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """The processing of dist-upgrader tarballs."""
@@ -7,19 +7,16 @@
 
 __all__ = [
     'DistUpgraderUpload',
-    'process_dist_upgrader',
     ]
 
 import os
 
-from lp.archivepublisher.customupload import (
-    CustomUpload,
-    CustomUploadError,
-    )
+from lp.archivepublisher.customupload import CustomUpload
 from lp.archivepublisher.debversion import (
     BadUpstreamError,
     Version as make_version,
     )
+from lp.soyuz.interfaces.queue import CustomUploadError
 
 
 class DistUpgraderBadVersion(CustomUploadError):
@@ -68,10 +65,10 @@
     def setComponents(self, tarfile_path):
         _, self.version, self.arch = self.parsePath(tarfile_path)
 
-    def setTargetDirectory(self, pubconf, tarfile_path, distroseries):
+    def setTargetDirectory(self, pubconf, tarfile_path, suite):
         self.setComponents(tarfile_path)
         self.targetdir = os.path.join(
-            pubconf.archiveroot, 'dists', distroseries, 'main',
+            pubconf.archiveroot, 'dists', suite, 'main',
             'dist-upgrader-%s' % self.arch)
 
     @classmethod
@@ -101,14 +98,3 @@
         except BadUpstreamError as exc:
             raise DistUpgraderBadVersion(self.tarfile_path, exc)
         return version and not filename.startswith('current')
-
-
-def process_dist_upgrader(pubconf, tarfile_path, distroseries, logger=None):
-    """Process a raw-dist-upgrader tarfile.
-
-    Unpacking it into the given archive for the given distroseries.
-    Raises CustomUploadError (or some subclass thereof) if anything goes
-    wrong.
-    """
-    upload = DistUpgraderUpload(logger=logger)
-    upload.process(pubconf, tarfile_path, distroseries)

=== modified file 'lib/lp/archivepublisher/rosetta_translations.py'
--- lib/lp/archivepublisher/rosetta_translations.py	2015-07-08 15:13:48 +0000
+++ lib/lp/archivepublisher/rosetta_translations.py	2016-05-23 11:17:51 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2015 Canonical Ltd.  This software is licensed under the
+# Copyright 2009-2016 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """The processing of Rosetta translations tarballs.
@@ -11,7 +11,6 @@
 
 __all__ = [
     'RosettaTranslationsUpload',
-    'process_rosetta_translations',
     ]
 
 from zope.component import getUtility
@@ -48,6 +47,12 @@
 
     package_name = None
 
+    @classmethod
+    def publish(cls, packageupload, libraryfilealias, logger=None):
+        """See `ICustomUploadHandler`."""
+        upload = cls(logger=logger)
+        upload.process(packageupload, libraryfilealias)
+
     def process(self, packageupload, libraryfilealias):
         if packageupload.package_name is None:
             self.setComponents(libraryfilealias.filename)
@@ -154,9 +159,3 @@
             name=self.package_name, exact_match=True,
             distroseries=packageupload.distroseries,
             pocket=packageupload.pocket).first()
-
-
-def process_rosetta_translations(packageupload, libraryfilealias, logger=None):
-    """Process a Rosetta translation upload."""
-    upload = RosettaTranslationsUpload(logger)
-    upload.process(packageupload, libraryfilealias)

=== modified file 'lib/lp/archivepublisher/signing.py'
--- lib/lp/archivepublisher/signing.py	2016-05-19 16:53:54 +0000
+++ lib/lp/archivepublisher/signing.py	2016-05-23 11:17:51 +0000
@@ -14,7 +14,6 @@
 __metaclass__ = type
 
 __all__ = [
-    "process_signing",
     "SigningUpload",
     ]
 
@@ -25,11 +24,9 @@
 import tempfile
 import textwrap
 
-from lp.archivepublisher.customupload import (
-    CustomUpload,
-    CustomUploadError,
-    )
+from lp.archivepublisher.customupload import CustomUpload
 from lp.services.osutils import remove_if_exists
+from lp.soyuz.interfaces.queue import CustomUploadError
 
 
 class SigningUploadPackError(CustomUploadError):
@@ -78,7 +75,7 @@
         self.package, self.version, self.arch = self.parsePath(
             tarfile_path)
 
-    def setTargetDirectory(self, pubconf, tarfile_path, distroseries):
+    def setTargetDirectory(self, pubconf, tarfile_path, suite):
         if pubconf.signingroot is None:
             if self.logger is not None:
                 self.logger.warning(
@@ -103,9 +100,9 @@
         # symlink to signed.
         # NOTE: we rely on "signed" and "uefi"  being in the same directory.
         dists_signed = os.path.join(
-            pubconf.archiveroot, "dists", distroseries, "main", "signed")
+            pubconf.archiveroot, "dists", suite, "main", "signed")
         dists_uefi = os.path.join(
-            pubconf.archiveroot, "dists", distroseries, "main", "uefi")
+            pubconf.archiveroot, "dists", suite, "main", "uefi")
         if not os.path.exists(dists_signed):
             if os.path.isdir(dists_uefi):
                 os.rename(dists_uefi, dists_signed)
@@ -318,14 +315,3 @@
 
     def shouldInstall(self, filename):
         return filename.startswith("%s/" % self.version)
-
-
-def process_signing(pubconf, tarfile_path, distroseries, logger=None):
-    """Process a raw-uefi/raw-signing tarfile.
-
-    Unpacking it into the given archive for the given distroseries.
-    Raises CustomUploadError (or some subclass thereof) if anything goes
-    wrong.
-    """
-    upload = SigningUpload(logger=logger)
-    upload.process(pubconf, tarfile_path, distroseries)

=== modified file 'lib/lp/archivepublisher/tests/test_ddtp_tarball.py'
--- lib/lp/archivepublisher/tests/test_ddtp_tarball.py	2016-02-05 16:51:12 +0000
+++ lib/lp/archivepublisher/tests/test_ddtp_tarball.py	2016-05-23 11:17:51 +0000
@@ -9,10 +9,7 @@
 
 import os
 
-from lp.archivepublisher.ddtp_tarball import (
-    DdtpTarballUpload,
-    process_ddtp_tarball,
-    )
+from lp.archivepublisher.ddtp_tarball import DdtpTarballUpload
 from lp.services.tarfile_helpers import LaunchpadWriteTarFile
 from lp.testing import TestCase
 
@@ -43,7 +40,7 @@
     def process(self):
         self.archive.close()
         self.buffer.close()
-        process_ddtp_tarball(self.pubconf, self.path, self.suite)
+        DdtpTarballUpload().process(self.pubconf, self.path, self.suite)
 
     def getTranslationsPath(self, filename):
         return os.path.join(

=== modified file 'lib/lp/archivepublisher/tests/test_debian_installer.py'
--- lib/lp/archivepublisher/tests/test_debian_installer.py	2016-02-05 16:51:12 +0000
+++ lib/lp/archivepublisher/tests/test_debian_installer.py	2016-05-23 11:17:51 +0000
@@ -13,10 +13,7 @@
     CustomUploadAlreadyExists,
     CustomUploadBadUmask,
     )
-from lp.archivepublisher.debian_installer import (
-    DebianInstallerUpload,
-    process_debian_installer,
-    )
+from lp.archivepublisher.debian_installer import DebianInstallerUpload
 from lp.services.tarfile_helpers import LaunchpadWriteTarFile
 from lp.testing import TestCase
 
@@ -58,7 +55,7 @@
     def process(self):
         self.archive.close()
         self.buffer.close()
-        process_debian_installer(self.pubconf, self.path, self.suite)
+        DebianInstallerUpload().process(self.pubconf, self.path, self.suite)
 
     def getInstallerPath(self, versioned_filename=None):
         installer_path = os.path.join(

=== modified file 'lib/lp/archivepublisher/tests/test_dist_upgrader.py'
--- lib/lp/archivepublisher/tests/test_dist_upgrader.py	2016-02-05 16:51:12 +0000
+++ lib/lp/archivepublisher/tests/test_dist_upgrader.py	2016-05-23 11:17:51 +0000
@@ -16,7 +16,6 @@
 from lp.archivepublisher.dist_upgrader import (
     DistUpgraderBadVersion,
     DistUpgraderUpload,
-    process_dist_upgrader,
     )
 from lp.services.tarfile_helpers import LaunchpadWriteTarFile
 from lp.testing import TestCase
@@ -48,7 +47,7 @@
     def process(self):
         self.archive.close()
         self.buffer.close()
-        process_dist_upgrader(self.pubconf, self.path, self.suite)
+        DistUpgraderUpload().process(self.pubconf, self.path, self.suite)
 
     def getUpgraderPath(self):
         return os.path.join(

=== modified file 'lib/lp/archivepublisher/tests/test_rosetta_translations.py'
--- lib/lp/archivepublisher/tests/test_rosetta_translations.py	2015-08-07 11:25:04 +0000
+++ lib/lp/archivepublisher/tests/test_rosetta_translations.py	2016-05-23 11:17:51 +0000
@@ -1,4 +1,4 @@
-# Copyright 2013-2015 Canonical Ltd.  This software is licensed under the
+# Copyright 2013-2016 Canonical Ltd.  This software is licensed under the
 # GNU Affero General Public License version 3 (see the file LICENSE).
 
 """Test rosetta-translations custom uploads.
@@ -13,10 +13,7 @@
 from zope.security.proxy import removeSecurityProxy
 
 from lp.app.errors import NotFoundError
-from lp.archivepublisher.rosetta_translations import (
-    process_rosetta_translations,
-    RosettaTranslationsUpload,
-    )
+from lp.archivepublisher.rosetta_translations import RosettaTranslationsUpload
 from lp.registry.interfaces.distribution import IDistributionSet
 from lp.registry.interfaces.pocket import PackagePublishingPocket
 from lp.services.database.interfaces import IStore
@@ -243,23 +240,25 @@
         self.assertRaises(AssertionError,
                           rosetta_upload._findSourcePublication, None)
 
+    def process(self, packageupload, libraryfilealias):
+        with dbuser("process_accepted"):
+            upload = RosettaTranslationsUpload()
+            upload.process(packageupload, libraryfilealias)
+
     def test_basic_from_copy(self):
         spr, pu, lfa = self.makeJobElementsFromCopyJob()
         transaction.commit()
-        with dbuser("process_accepted"):
-            process_rosetta_translations(pu, lfa)
+        self.process(pu, lfa)
 
     def test_basic_from_upload(self):
         spr, pu, lfa = self.makeJobElements()
         transaction.commit()
-        with dbuser("process_accepted"):
-            process_rosetta_translations(pu, lfa)
+        self.process(pu, lfa)
 
     def test_correct_job_is_created_from_upload(self):
         spr, packageupload, libraryfilealias = self.makeJobElements()
         transaction.commit()
-        with dbuser("process_accepted"):
-            process_rosetta_translations(packageupload, libraryfilealias)
+        self.process(packageupload, libraryfilealias)
 
         jobs = list(PackageTranslationsUploadJob.iterReady())
         self.assertEqual(1, len(jobs))
@@ -272,8 +271,7 @@
         spr, packageupload, libraryfilealias = (
             self.makeJobElementsFromCopyJob())
         transaction.commit()
-        with dbuser("process_accepted"):
-            process_rosetta_translations(packageupload, libraryfilealias)
+        self.process(packageupload, libraryfilealias)
 
         jobs = list(PackageTranslationsUploadJob.iterReady())
         self.assertEqual(1, len(jobs))
@@ -288,8 +286,7 @@
             distroseries_name="vivid", archive_name="stable-phone-overlay")
         self.ensureDistroSeries("ubuntu-rtm", "15.04")
         transaction.commit()
-        with dbuser("process_accepted"):
-            process_rosetta_translations(packageupload, libraryfilealias)
+        self.process(packageupload, libraryfilealias)
 
         jobs = list(PackageTranslationsUploadJob.iterReady())
         self.assertEqual(1, len(jobs))
@@ -304,8 +301,7 @@
             distroseries_name="wily", archive_name="stable-phone-overlay")
         self.ensureDistroSeries("ubuntu-rtm", "15.04")
         transaction.commit()
-        with dbuser("process_accepted"):
-            process_rosetta_translations(packageupload, libraryfilealias)
+        self.process(packageupload, libraryfilealias)
 
         jobs = list(PackageTranslationsUploadJob.iterReady())
         self.assertEqual(0, len(jobs))
@@ -316,8 +312,7 @@
             distroseries_name="vivid", archive_name="landing-001")
         self.ensureDistroSeries("ubuntu-rtm", "15.04")
         transaction.commit()
-        with dbuser("process_accepted"):
-            process_rosetta_translations(packageupload, libraryfilealias)
+        self.process(packageupload, libraryfilealias)
 
         jobs = list(PackageTranslationsUploadJob.iterReady())
         self.assertEqual(0, len(jobs))
@@ -328,8 +323,7 @@
         transaction.commit()
         sourcepackage = packageupload.distroseries.getSourcePackage(spr.name)
         self.assertIsNone(sourcepackage.packaging)
-        with dbuser("process_accepted"):
-            process_rosetta_translations(packageupload, libraryfilealias)
+        self.process(packageupload, libraryfilealias)
         self.assertIsNone(sourcepackage.packaging)
 
     def test_skips_packaging_for_redirected_ppa_no_original(self):
@@ -343,8 +337,7 @@
         transaction.commit()
         sourcepackage = packageupload.distroseries.getSourcePackage(spr.name)
         self.assertIsNone(sourcepackage.packaging)
-        with dbuser("process_accepted"):
-            process_rosetta_translations(packageupload, libraryfilealias)
+        self.process(packageupload, libraryfilealias)
         self.assertIsNone(sourcepackage.packaging)
 
     def test_skips_existing_packaging_for_redirected_ppa(self):
@@ -366,8 +359,7 @@
         transaction.commit()
         self.assertEqual(
             current_upstream, sourcepackage.packaging.productseries)
-        with dbuser("process_accepted"):
-            process_rosetta_translations(packageupload, libraryfilealias)
+        self.process(packageupload, libraryfilealias)
         self.assertEqual(
             current_upstream, sourcepackage.packaging.productseries)
 
@@ -387,8 +379,7 @@
         transaction.commit()
         sourcepackage = redirected_series.getSourcePackage(spr.name)
         self.assertIsNone(sourcepackage.packaging)
-        with dbuser("process_accepted"):
-            process_rosetta_translations(packageupload, libraryfilealias)
+        self.process(packageupload, libraryfilealias)
         self.assertEqual(upstream, sourcepackage.packaging.productseries)
         # TranslationPackagingJobs are created to handle the Packaging
         # change (one TranslationMergeJob for each of ubuntu/vivid and

=== modified file 'lib/lp/soyuz/interfaces/queue.py'
--- lib/lp/soyuz/interfaces/queue.py	2016-05-09 18:08:42 +0000
+++ lib/lp/soyuz/interfaces/queue.py	2016-05-23 11:17:51 +0000
@@ -6,6 +6,8 @@
 __metaclass__ = type
 
 __all__ = [
+    'CustomUploadError',
+    'ICustomUploadHandler',
     'IHasQueueItems',
     'IPackageUploadQueue',
     'IPackageUpload',
@@ -643,14 +645,6 @@
             title=_("The file"), required=True, readonly=False,
             )
 
-    def temp_filename():
-        """Return a filename containing the libraryfile for this upload.
-
-        This filename will be in a temporary directory and can be the
-        ensure dir can be deleted once whatever needed the file is finished
-        with it.
-        """
-
     def publish(logger=None):
         """Publish this custom item directly into the filesystem.
 
@@ -802,3 +796,20 @@
 
     def getPackageUploadQueue(state):
         """Return an IPackageUploadQueue according to the given state."""
+
+
+class CustomUploadError(Exception):
+    """Base class for all errors associated with publishing custom uploads."""
+
+
+class ICustomUploadHandler(Interface):
+    """A custom upload handler."""
+
+    def publish(packageupload, libraryfilealias, logger=None):
+        """Publish a custom upload tarfile.
+
+        Unpack it into the archive and suite indicated by the given
+        `IPackageUpload`.
+
+        :raises CustomUploadError: if anything goes wrong.
+        """

=== modified file 'lib/lp/soyuz/model/queue.py'
--- lib/lp/soyuz/model/queue.py	2016-05-04 14:21:47 +0000
+++ lib/lp/soyuz/model/queue.py	2016-05-23 11:17:51 +0000
@@ -13,8 +13,6 @@
 
 from itertools import chain
 import os
-import shutil
-import tempfile
 
 from sqlobject import (
     ForeignKey,
@@ -44,7 +42,6 @@
 # This should not import from archivepublisher, but to avoid
 # that it needs a bit of redesigning here around the publication stuff.
 from lp.archivepublisher.config import getPubConfig
-from lp.archivepublisher.customupload import CustomUploadError
 from lp.archiveuploader.tagfiles import parse_tagfile_content
 from lp.registry.interfaces.gpg import IGPGKeySet
 from lp.registry.interfaces.pocket import PackagePublishingPocket
@@ -101,6 +98,8 @@
     name_priority_map,
     )
 from lp.soyuz.interfaces.queue import (
+    CustomUploadError,
+    ICustomUploadHandler,
     IPackageUpload,
     IPackageUploadBuild,
     IPackageUploadCustom,
@@ -1371,64 +1370,29 @@
 
         self.publisher_dispatch[self.customformat](self, logger)
 
-    def temp_filename(self):
-        """See `IPackageUploadCustom`."""
-        temp_dir = tempfile.mkdtemp()
-        temp_file_name = os.path.join(
-            temp_dir, self.libraryfilealias.filename)
-        temp_file = file(temp_file_name, "wb")
-        self.libraryfilealias.open()
-        copy_and_close(self.libraryfilealias, temp_file)
-        return temp_file_name
-
-    def _publishCustom(self, action_method, logger=None):
-        """Publish custom formats.
-
-        Publish Either an installer, an upgrader or a ddtp upload using the
-        supplied action method.
-        """
-        temp_filename = self.temp_filename()
-        suite = self.packageupload.distroseries.getSuite(
-            self.packageupload.pocket)
-        try:
-            # See the XXX near the import for getPubConfig.
-            archive_config = getPubConfig(self.packageupload.archive)
-            action_method(archive_config, temp_filename, suite, logger=logger)
-        finally:
-            shutil.rmtree(os.path.dirname(temp_filename))
-
     def publishDebianInstaller(self, logger=None):
         """See `IPackageUploadCustom`."""
-        # XXX cprov 2005-03-03: We need to use the Zope Component Lookup
-        # to instantiate the object in question and avoid circular imports
-        from lp.archivepublisher.debian_installer import (
-            process_debian_installer)
-
-        self._publishCustom(process_debian_installer, logger=logger)
+        handler = getUtility(ICustomUploadHandler, "DEBIAN_INSTALLER")
+        handler.publish(
+            self.packageupload, self.libraryfilealias, logger=logger)
 
     def publishDistUpgrader(self, logger=None):
         """See `IPackageUploadCustom`."""
-        # XXX cprov 2005-03-03: We need to use the Zope Component Lookup
-        # to instantiate the object in question and avoid circular imports
-        from lp.archivepublisher.dist_upgrader import process_dist_upgrader
-
-        self._publishCustom(process_dist_upgrader, logger=logger)
+        handler = getUtility(ICustomUploadHandler, "DIST_UPGRADER")
+        handler.publish(
+            self.packageupload, self.libraryfilealias, logger=logger)
 
     def publishDdtpTarball(self, logger=None):
         """See `IPackageUploadCustom`."""
-        # XXX cprov 2005-03-03: We need to use the Zope Component Lookup
-        # to instantiate the object in question and avoid circular imports
-        from lp.archivepublisher.ddtp_tarball import process_ddtp_tarball
-
-        self._publishCustom(process_ddtp_tarball, logger=logger)
+        handler = getUtility(ICustomUploadHandler, "DDTP_TARBALL")
+        handler.publish(
+            self.packageupload, self.libraryfilealias, logger=logger)
 
     def publishRosettaTranslations(self, logger=None):
         """See `IPackageUploadCustom`."""
-        from lp.archivepublisher.rosetta_translations import (
-            process_rosetta_translations)
-
-        process_rosetta_translations(self.packageupload,
-                                     self.libraryfilealias, logger=logger)
+        handler = getUtility(ICustomUploadHandler, "ROSETTA_TRANSLATIONS")
+        handler.publish(
+            self.packageupload, self.libraryfilealias, logger=logger)
 
     def publishStaticTranslations(self, logger=None):
         """See `IPackageUploadCustom`."""
@@ -1466,11 +1430,9 @@
 
     def publishSigning(self, logger=None):
         """See `IPackageUploadCustom`."""
-        # XXX cprov 2005-03-03: We need to use the Zope Component Lookup
-        # to instantiate the object in question and avoid circular imports
-        from lp.archivepublisher.signing import process_signing
-
-        self._publishCustom(process_signing, logger=logger)
+        handler = getUtility(ICustomUploadHandler, "SIGNING")
+        handler.publish(
+            self.packageupload, self.libraryfilealias, logger=logger)
 
     publisher_dispatch = {
         PackageUploadCustomFormat.DEBIAN_INSTALLER: publishDebianInstaller,


Follow ups