← Back to team overview

launchpad-reviewers team mailing list archive

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

 

Colin Watson has proposed merging lp:~cjwatson/launchpad/refactor-queue-custom-2 into lp:launchpad with lp:~cjwatson/launchpad/refactor-queue-custom as a prerequisite.

Commit message:
Eliminate circular archivepublisher imports from lp.soyuz.model.queue.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

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

Eliminate circular archivepublisher imports from lp.soyuz.model.queue.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/refactor-queue-custom-2 into lp:launchpad.
=== modified file 'lib/lp/archivepublisher/configure.zcml'
--- lib/lp/archivepublisher/configure.zcml	2016-05-23 11:22:25 +0000
+++ lib/lp/archivepublisher/configure.zcml	2016-05-23 11:22:25 +0000
@@ -74,6 +74,20 @@
             interface="lp.soyuz.interfaces.queue.ICustomUploadHandler"/>
     </securedutility>
     <securedutility
+        class="lp.archivepublisher.static_translations.StaticTranslationsUpload"
+        provides="lp.soyuz.interfaces.queue.ICustomUploadHandler"
+        name="STATIC_TRANSLATIONS">
+        <allow
+            interface="lp.soyuz.interfaces.queue.ICustomUploadHandler"/>
+    </securedutility>
+    <securedutility
+        class="lp.archivepublisher.meta_data.MetaDataUpload"
+        provides="lp.soyuz.interfaces.queue.ICustomUploadHandler"
+        name="META_DATA">
+        <allow
+            interface="lp.soyuz.interfaces.queue.ICustomUploadHandler"/>
+    </securedutility>
+    <securedutility
         class="lp.archivepublisher.signing.SigningUpload"
         provides="lp.soyuz.interfaces.queue.ICustomUploadHandler"
         name="SIGNING">

=== added file 'lib/lp/archivepublisher/meta_data.py'
--- lib/lp/archivepublisher/meta_data.py	1970-01-01 00:00:00 +0000
+++ lib/lp/archivepublisher/meta_data.py	2016-05-23 11:22:25 +0000
@@ -0,0 +1,54 @@
+# Copyright 2016 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Processing of archive meta-data uploads."""
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+__metaclass__ = type
+__all__ = [
+    "MetaDataUpload",
+    ]
+
+import os
+
+from lp.archivepublisher.config import getPubConfig
+from lp.archivepublisher.customupload import CustomUpload
+from lp.services.librarian.utils import copy_and_close
+
+
+class MetaDataUpload(CustomUpload):
+    """Meta-data custom upload.
+
+    Meta-data custom files are published, unmodified, to a special area
+    outside the actual archive directory.  This is so that the files can be
+    seen even when the archive is private, and allows commercial customers
+    to browse contents for potential later purchase.
+    """
+    custom_type = "meta-data"
+
+    @classmethod
+    def publish(cls, packageupload, libraryfilealias, logger=None):
+        """See `ICustomUploadHandler`."""
+        upload = cls(logger=logger)
+        upload.process(packageupload, libraryfilealias)
+
+    def process(self, packageupload, libraryfilealias):
+        pubconf = getPubConfig(packageupload.archive)
+        if pubconf.metaroot is None:
+            if self.logger is not None:
+                self.logger.debug(
+                    "Skipping meta-data for archive without metaroot.")
+            return
+
+        dest_file = os.path.join(pubconf.metaroot, libraryfilealias.filename)
+        if not os.path.isdir(pubconf.metaroot):
+            os.makedirs(pubconf.metaroot, 0o755)
+
+        # At this point we now have a directory of the format:
+        # <person_name>/meta/<ppa_name>
+        # We're ready to copy the file out of the librarian into it.
+
+        file_obj = open(dest_file, "wb")
+        libraryfilealias.open()
+        copy_and_close(libraryfilealias, file_obj)

=== added file 'lib/lp/archivepublisher/static_translations.py'
--- lib/lp/archivepublisher/static_translations.py	1970-01-01 00:00:00 +0000
+++ lib/lp/archivepublisher/static_translations.py	2016-05-23 11:22:25 +0000
@@ -0,0 +1,32 @@
+# Copyright 2016 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Processing of static translations uploads."""
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+__metaclass__ = type
+__all__ = [
+    "StaticTranslationsUpload",
+    ]
+
+from lp.archivepublisher.customupload import CustomUpload
+
+
+class StaticTranslationsUpload(CustomUpload):
+    """Static translations upload.
+
+    Static translations are not published.  Currently, they're only exposed
+    via webservice methods so that third parties can retrieve them from the
+    librarian.
+    """
+    custom_type = "static-translations"
+
+    @classmethod
+    def publish(cls, packageupload, libraryfilealias, logger=None):
+        """See `ICustomUploadHandler`."""
+        if logger is not None:
+            logger.debug("Skipping publishing of static translations.")
+
+    def process(self, packageupload, libraryfilealias):
+        pass

=== removed file 'lib/lp/archivepublisher/tests/publishing-meta-data-files.txt'
--- lib/lp/archivepublisher/tests/publishing-meta-data-files.txt	2014-07-07 07:36:54 +0000
+++ lib/lp/archivepublisher/tests/publishing-meta-data-files.txt	1970-01-01 00:00:00 +0000
@@ -1,88 +0,0 @@
-Publishing Meta-Data Custom Files
-=================================
-
-Meta-data custom files are published, unmodified, to a special area
-outside the actual archive directory.  This is so that the files can be
-seen even when the archive is private, and allows commercial customers
-to browse contents for potential later purchase.
-
-We can demonstrate this publishing behaviour by creating a
-PackageUploadCustom object for a meta-data upload:
-
-    >>> from lp.services.librarian.interfaces import (
-    ...     ILibraryFileAliasSet)
-    >>> from cStringIO import StringIO
-    >>> from lp.services.log.logger import FakeLogger
-    >>> from lp.registry.interfaces.distribution import IDistributionSet
-    >>> from lp.soyuz.enums import PackageUploadCustomFormat
-    >>> from lp.soyuz.interfaces.publishing import PackagePublishingPocket
-    >>> from lp.soyuz.model.queue import PackageUploadCustom
-
-    >>> hoary = getUtility(IDistributionSet)['ubuntu']['hoary']
-    >>> ppa = factory.makeArchive(distribution=hoary.distribution)
-    >>> package_upload = hoary.createQueueEntry(
-    ...     pocket=PackagePublishingPocket.RELEASE, changesfilename="test",
-    ...     changesfilecontent="test",
-    ...     archive=ppa)
-    >>> content = "test"
-    >>> test_file = getUtility(
-    ...     ILibraryFileAliasSet).create(
-    ...         "testmeta", len(content), StringIO(content), "text/plain")
-    >>> custom_upload = PackageUploadCustom()
-    >>> custom_upload.customformat = PackageUploadCustomFormat.META_DATA
-    >>> custom_upload.packageupload = package_upload
-    >>> custom_upload.libraryfilealias = test_file
-    >>> # commit so that the file is put in the librarian.
-    >>> import transaction
-    >>> transaction.commit()
-
-Now we can publish the custom upload:
-
-    >>> custom_upload.publish(logger=FakeLogger())
-    DEBUG Publishing custom testmeta to ubuntu/hoary
-
-The custom file is just called "testmeta" with the contents "test".  It will
-be published in a location of the scheme:
-
-/<person_name>/meta/<ppa_name>/<filename>
-
-    >>> import os
-    >>> from lp.archivepublisher.config import getPubConfig
-    >>> pub_config = getPubConfig(ppa)
-    >>> ppa_root = pub_config.distroroot
-    >>> final_destination = os.path.join(
-    ...     ppa_root, ppa.owner.name, "meta", ppa.name)
-    >>> published_file = os.path.join(
-    ...     final_destination, "testmeta")
-
-    >>> os.path.exists(published_file)
-    True
-
-    >>> with open(published_file, 'rb') as fp:
-    ...     content = fp.read()
-
-    >>> print content
-    test
-
-The meta-data directory is currently only defined for Ubuntu PPAs, so
-publishing a meta-data upload in a non-Ubuntu PPA is a no-op.
-
-    >>> bat = getUtility(IDistributionSet)['ubuntutest']['breezy-autotest']
-    >>> ppa = factory.makeArchive(distribution=bat.distribution)
-    >>> package_upload = bat.createQueueEntry(
-    ...     pocket=PackagePublishingPocket.RELEASE, changesfilename="test",
-    ...     changesfilecontent="test",
-    ...     archive=ppa)
-    >>> custom_upload = PackageUploadCustom()
-    >>> custom_upload.customformat = PackageUploadCustomFormat.META_DATA
-    >>> custom_upload.packageupload = package_upload
-    >>> custom_upload.libraryfilealias = test_file
-
-    >>> custom_upload.publish(logger=FakeLogger())
-    DEBUG Publishing custom testmeta to ubuntutest/breezy-autotest
-    DEBUG Skipping meta-data for archive without metaroot.
-
-    >>> final_destination = os.path.join(
-    ...     ppa_root, ppa.owner.name, "meta", ppa.name)
-    >>> os.path.exists(final_destination)
-    False

=== added file 'lib/lp/archivepublisher/tests/test_meta_data.py'
--- lib/lp/archivepublisher/tests/test_meta_data.py	1970-01-01 00:00:00 +0000
+++ lib/lp/archivepublisher/tests/test_meta_data.py	2016-05-23 11:22:25 +0000
@@ -0,0 +1,69 @@
+# Copyright 2016 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Test meta-data custom uploads."""
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+__metaclass__ = type
+
+import os
+
+from testtools.matchers import (
+    FileContains,
+    Not,
+    PathExists,
+    )
+import transaction
+from zope.component import getUtility
+
+from lp.archivepublisher.config import getPubConfig
+from lp.archivepublisher.meta_data import MetaDataUpload
+from lp.registry.interfaces.distribution import IDistributionSet
+from lp.services.log.logger import BufferLogger
+from lp.testing import TestCaseWithFactory
+from lp.testing.layers import LaunchpadZopelessLayer
+
+
+class TestMetaData(TestCaseWithFactory):
+
+    layer = LaunchpadZopelessLayer
+
+    def test_ubuntu_ppa(self):
+        """A meta-data upload to an Ubuntu PPA is published.
+
+        The custom file is published to
+        /<person_name>/meta/<ppa_name>/<filename>.
+        """
+        ubuntu = getUtility(IDistributionSet)["ubuntu"]
+        archive = self.factory.makeArchive(distribution=ubuntu)
+        packageupload = self.factory.makePackageUpload(archive=archive)
+        content = self.factory.getUniqueString()
+        libraryfilealias = self.factory.makeLibraryFileAlias(content=content)
+        transaction.commit()
+        logger = BufferLogger()
+        MetaDataUpload(logger=logger).process(packageupload, libraryfilealias)
+        self.assertEqual("", logger.getLogBuffer())
+        published_file = os.path.join(
+            getPubConfig(archive).distroroot, archive.owner.name, "meta",
+            archive.name, libraryfilealias.filename)
+        self.assertThat(published_file, FileContains(content))
+
+    def test_non_ubuntu_ppa(self):
+        """A meta-data upload to a non-Ubuntu PPA is not published.
+
+        The meta-data directory is currently only defined for Ubuntu PPAs.
+        """
+        archive = self.factory.makeArchive(
+            distribution=self.factory.makeDistribution())
+        packageupload = self.factory.makePackageUpload(archive=archive)
+        libraryfilealias = self.factory.makeLibraryFileAlias(db_only=True)
+        logger = BufferLogger()
+        MetaDataUpload(logger=logger).process(packageupload, libraryfilealias)
+        self.assertEqual(
+            "DEBUG Skipping meta-data for archive without metaroot.\n",
+            logger.getLogBuffer())
+        published_file = os.path.join(
+            getPubConfig(archive).distroroot, archive.owner.name, "meta",
+            archive.name, libraryfilealias.filename)
+        self.assertThat(published_file, Not(PathExists()))

=== modified file 'lib/lp/soyuz/model/queue.py'
--- lib/lp/soyuz/model/queue.py	2016-05-23 11:22:25 +0000
+++ lib/lp/soyuz/model/queue.py	2016-05-23 11:22:25 +0000
@@ -12,7 +12,6 @@
     ]
 
 from itertools import chain
-import os
 
 from sqlobject import (
     ForeignKey,
@@ -38,10 +37,6 @@
 from zope.interface import implementer
 
 from lp.app.errors import NotFoundError
-# XXX 2009-05-10 julian
-# 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.archiveuploader.tagfiles import parse_tagfile_content
 from lp.registry.interfaces.gpg import IGPGKeySet
 from lp.registry.interfaces.pocket import PackagePublishingPocket
@@ -73,7 +68,6 @@
     LibraryFileAlias,
     LibraryFileContent,
     )
-from lp.services.librarian.utils import copy_and_close
 from lp.services.mail.signedmessage import strip_pgp_signature
 from lp.services.propertycache import (
     cachedproperty,
@@ -121,10 +115,6 @@
 from lp.soyuz.model.distroarchseries import DistroArchSeries
 from lp.soyuz.model.section import Section
 
-# There are imports below in PackageUploadCustom for various bits
-# of the archivepublisher which cause circular import errors if they
-# are placed here.
-
 
 def debug(logger, msg):
     """Shorthand debug notation for publish() methods."""
@@ -1357,98 +1347,13 @@
 
     def publish(self, logger=None):
         """See `IPackageUploadCustom`."""
-        # This is a marker as per the comment in lib/lp/soyuz/enums.py:
-        ##CUSTOMFORMAT##
-        # Essentially, if you alter anything to do with what custom formats
-        # are, what their tags are, or anything along those lines, you should
-        # grep for the marker in the source tree and fix it up in every place
-        # so marked.
         debug(logger, "Publishing custom %s to %s/%s" % (
             self.packageupload.displayname,
             self.packageupload.distroseries.distribution.name,
             self.packageupload.distroseries.name))
-
-        self.publisher_dispatch[self.customformat](self, logger)
-
-    def publishDebianInstaller(self, logger=None):
-        """See `IPackageUploadCustom`."""
-        handler = getUtility(ICustomUploadHandler, "DEBIAN_INSTALLER")
-        handler.publish(
-            self.packageupload, self.libraryfilealias, logger=logger)
-
-    def publishDistUpgrader(self, logger=None):
-        """See `IPackageUploadCustom`."""
-        handler = getUtility(ICustomUploadHandler, "DIST_UPGRADER")
-        handler.publish(
-            self.packageupload, self.libraryfilealias, logger=logger)
-
-    def publishDdtpTarball(self, logger=None):
-        """See `IPackageUploadCustom`."""
-        handler = getUtility(ICustomUploadHandler, "DDTP_TARBALL")
-        handler.publish(
-            self.packageupload, self.libraryfilealias, logger=logger)
-
-    def publishRosettaTranslations(self, logger=None):
-        """See `IPackageUploadCustom`."""
-        handler = getUtility(ICustomUploadHandler, "ROSETTA_TRANSLATIONS")
-        handler.publish(
-            self.packageupload, self.libraryfilealias, logger=logger)
-
-    def publishStaticTranslations(self, logger=None):
-        """See `IPackageUploadCustom`."""
-        # Static translations are not published.  Currently, they're
-        # only exposed via webservice methods so that third parties can
-        # retrieve them from the librarian.
-        debug(logger, "Skipping publishing of static translations.")
-        return
-
-    def publishMetaData(self, logger=None):
-        """See `IPackageUploadCustom`."""
-        # In the future this could use the existing custom upload file
-        # processing which deals with versioning, etc., but that's too
-        # complicated for our needs right now.  Also, the existing code
-        # assumes that everything is a tarball and tries to unpack it.
-
-        # See the XXX near the import for getPubConfig.
-        archive_config = getPubConfig(self.packageupload.archive)
-        if archive_config.metaroot is None:
-            debug(logger, "Skipping meta-data for archive without metaroot.")
-            return
-
-        dest_file = os.path.join(
-            archive_config.metaroot, self.libraryfilealias.filename)
-        if not os.path.isdir(archive_config.metaroot):
-            os.makedirs(archive_config.metaroot, 0o755)
-
-        # At this point we now have a directory of the format:
-        # <person_name>/meta/<ppa_name>
-        # We're ready to copy the file out of the librarian into it.
-
-        file_obj = file(dest_file, "wb")
-        self.libraryfilealias.open()
-        copy_and_close(self.libraryfilealias, file_obj)
-
-    def publishSigning(self, logger=None):
-        """See `IPackageUploadCustom`."""
-        handler = getUtility(ICustomUploadHandler, "SIGNING")
-        handler.publish(
-            self.packageupload, self.libraryfilealias, logger=logger)
-
-    publisher_dispatch = {
-        PackageUploadCustomFormat.DEBIAN_INSTALLER: publishDebianInstaller,
-        PackageUploadCustomFormat.ROSETTA_TRANSLATIONS:
-            publishRosettaTranslations,
-        PackageUploadCustomFormat.DIST_UPGRADER: publishDistUpgrader,
-        PackageUploadCustomFormat.DDTP_TARBALL: publishDdtpTarball,
-        PackageUploadCustomFormat.STATIC_TRANSLATIONS:
-            publishStaticTranslations,
-        PackageUploadCustomFormat.META_DATA: publishMetaData,
-        PackageUploadCustomFormat.SIGNING: publishSigning,
-        }
-
-    # publisher_dispatch must have an entry for each value of
-    # PackageUploadCustomFormat.
-    assert len(publisher_dispatch) == len(PackageUploadCustomFormat)
+        handler = getUtility(ICustomUploadHandler, self.customformat.name)
+        handler.publish(
+            self.packageupload, self.libraryfilealias, logger=logger)
 
 
 @implementer(IPackageUploadSet)

=== modified file 'lib/lp/soyuz/tests/test_packageupload.py'
--- lib/lp/soyuz/tests/test_packageupload.py	2015-11-26 13:31:45 +0000
+++ lib/lp/soyuz/tests/test_packageupload.py	2016-05-23 11:22:25 +0000
@@ -16,7 +16,10 @@
     )
 from testtools.matchers import Equals
 import transaction
-from zope.component import getUtility
+from zope.component import (
+    getUtility,
+    queryUtility,
+    )
 from zope.schema import getFields
 from zope.security.interfaces import Unauthorized as ZopeUnauthorized
 from zope.security.proxy import removeSecurityProxy
@@ -39,6 +42,7 @@
 from lp.soyuz.interfaces.archivepermission import IArchivePermissionSet
 from lp.soyuz.interfaces.component import IComponentSet
 from lp.soyuz.interfaces.queue import (
+    ICustomUploadHandler,
     IPackageUpload,
     IPackageUploadSet,
     QueueAdminUnauthorizedError,
@@ -54,12 +58,14 @@
     person_logged_in,
     record_two_runs,
     StormStatementRecorder,
+    TestCase,
     TestCaseWithFactory,
     )
 from lp.testing.dbuser import dbuser
 from lp.testing.layers import (
     LaunchpadFunctionalLayer,
     LaunchpadZopelessLayer,
+    ZopelessLayer,
     )
 from lp.testing.matchers import (
     HasQueryCount,
@@ -573,6 +579,18 @@
         self.assertIs(None, pu.sourcepackagerelease)
 
 
+class TestPackageUploadCustom(TestCase):
+    """Unit tests for `PackageUploadCustom`."""
+
+    layer = ZopelessLayer
+
+    def test_handlers(self):
+        # Each element of `PackageUploadCustomFormat` has a handler.
+        for customformat in PackageUploadCustomFormat.items:
+            self.assertIsNotNone(
+                queryUtility(ICustomUploadHandler, customformat.name))
+
+
 class TestPackageUploadSet(TestCaseWithFactory):
     """Unit tests for `PackageUploadSet`."""
 


Follow ups