← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~cjwatson/launchpad/remove-delayed-copies into lp:launchpad

 

Colin Watson has proposed merging lp:~cjwatson/launchpad/remove-delayed-copies into lp:launchpad.

Commit message:
Remove delayed copies, now entirely superseded by PackageCopyJobs.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #503226 in Launchpad itself: "Delayed binary copy email notifications are suboptimal"
  https://bugs.launchpad.net/launchpad/+bug/503226
  Bug #730509 in Launchpad itself: "Delayed copies can fail if a direct copy was performed in the meantime"
  https://bugs.launchpad.net/launchpad/+bug/730509
  Bug #741489 in Launchpad itself: "Archive:+copy-packages times out on delayed copies of lots of binaries"
  https://bugs.launchpad.net/launchpad/+bug/741489

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/remove-delayed-copies/+merge/134389

== Summary ==

Delayed copies are elderly, crufty, and the source of multiple critical bugs.  Nobody likes them, everybody hates them, and they should just go and eat worms.

== Proposed fix ==

Now that PackageCopyJobs support unembargoing private uploads and all callers have been converted to them, we can delete delayed copies.  This does mean that if somebody goes to the effort of looking up old delayed copies in +queue then they'll be rendered under the expander triangle as a list of source files rather than as "Copied from <source archive>" (example: https://qastaging.launchpad.net/ubuntu/hardy/+queue?queue_state=4&queue_text=php5), but that seems very minor indeed and should be an acceptable trade-off for getting rid of the entire feature rather than having a few little bits and pieces lying around.

Note that this must not be landed until r16270 has been deployed to production and we've verified with webops that there are no pending delayed uploads on production.

== Special deployment instructions ==

It is vitally important that, after this change is deployed, we do a little happy dance.

== Tests ==

bin/test -vvct archiveuploader -t soyuz

== Lint ==

One false positive:

./lib/lp/soyuz/model/sourcepackagerelease.py
     196: redefinition of function 'copyright' from line 187
-- 
https://code.launchpad.net/~cjwatson/launchpad/remove-delayed-copies/+merge/134389
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/remove-delayed-copies into lp:launchpad.
=== modified file 'database/schema/comments.sql'
--- database/schema/comments.sql	2012-10-24 23:57:38 +0000
+++ database/schema/comments.sql	2012-11-15 02:05:24 +0000
@@ -1182,7 +1182,7 @@
 
 COMMENT ON COLUMN PackageUpload.pocket IS 'This is the pocket the upload is targeted at.';
 
-COMMENT ON COLUMN PackageUpload.changesfile IS 'The changes file associated with this upload. It is null for records refering to a delayed-copy.';
+COMMENT ON COLUMN PackageUpload.changesfile IS 'The changes file associated with this upload.';
 
 COMMENT ON COLUMN PackageUpload.archive IS 'The archive to which this upload is targetted.';
 

=== modified file 'lib/lp/archiveuploader/tests/test_sync_notification.py'
--- lib/lp/archiveuploader/tests/test_sync_notification.py	2012-10-24 09:43:58 +0000
+++ lib/lp/archiveuploader/tests/test_sync_notification.py	2012-11-15 02:05:24 +0000
@@ -91,8 +91,7 @@
         self.makeUploader(requester, target_archive, spph.component)
         [synced_spph] = do_copy(
             [spph], target_archive, target_distroseries,
-            pocket=spph.pocket, person=requester, allow_delayed_copies=False,
-            close_bugs=False)
+            pocket=spph.pocket, person=requester, close_bugs=False)
         return synced_spph
 
     def makeChangesFile(self, spph, maintainer, maintainer_address,

=== modified file 'lib/lp/security.py'
--- lib/lp/security.py	2012-11-12 23:03:24 +0000
+++ lib/lp/security.py	2012-11-15 02:05:24 +0000
@@ -1833,18 +1833,10 @@
     usedfor = IPackageUpload
 
     def checkAuthenticated(self, user):
-        """Return True if user has an ArchivePermission or is an admin.
-
-        If it's a delayed-copy, check if the user can upload to its targeted
-        archive.
-        """
+        """Return True if user has an ArchivePermission or is an admin."""
         if AdminByAdminsTeam.checkAuthenticated(self, user):
             return True
 
-        if self.obj.is_delayed_copy:
-            archive_append = AppendArchive(self.obj.archive)
-            return archive_append.checkAuthenticated(user)
-
         return self.obj.archive.canAdministerQueue(
             user.person, self.obj.components, self.obj.pocket,
             self.obj.distroseries)

=== modified file 'lib/lp/soyuz/browser/queue.py'
--- lib/lp/soyuz/browser/queue.py	2012-08-13 01:53:37 +0000
+++ lib/lp/soyuz/browser/queue.py	2012-11-15 02:05:24 +0000
@@ -222,12 +222,7 @@
         if len(uploads) == 0:
             return None
 
-        # Operate only on upload and/or processed delayed-copies.
-        upload_ids = [
-            upload.id
-            for upload in uploads
-            if not (upload.is_delayed_copy and
-                    upload.status != PackageUploadStatus.DONE)]
+        upload_ids = [upload.id for upload in uploads]
         binary_file_set = getUtility(IBinaryPackageFileSet)
         binary_files = binary_file_set.getByPackageUploadIDs(upload_ids)
         binary_file_set.loadLibraryFiles(binary_files)
@@ -529,24 +524,6 @@
             self.package_sets = []
 
     @property
-    def pending_delayed_copy(self):
-        """Whether the context is a delayed-copy pending processing."""
-        return (
-            self.is_delayed_copy and self.status != PackageUploadStatus.DONE)
-
-    @property
-    def changesfile(self):
-        """Return the upload changesfile object, even for delayed-copies.
-
-        If the context `PackageUpload` is a delayed-copy, which doesn't
-        have '.changesfile' by design, return the changesfile originally
-        used to upload the contained source.
-        """
-        if self.is_delayed_copy:
-            return self.sourcepackagerelease.upload_changesfile
-        return self.context.changesfile
-
-    @property
     def display_package_sets(self):
         """Package sets, if any, for display on the +queue page."""
         return ' '.join(sorted(
@@ -611,7 +588,7 @@
         """Compose HTML: upload name and link to changes file."""
         raw_displayname = self.displayname
         displayname = cgi.escape(raw_displayname)
-        if self.pending_delayed_copy or self.changesfile is None:
+        if self.changesfile is None:
             return displayname
         else:
             return '<a href="%s" title="Changes file for %s">%s</a>' % (

=== modified file 'lib/lp/soyuz/configure.zcml'
--- lib/lp/soyuz/configure.zcml	2012-11-13 13:07:59 +0000
+++ lib/lp/soyuz/configure.zcml	2012-11-15 02:05:24 +0000
@@ -184,7 +184,6 @@
                 displayname
                 displayarchs
                 displayversion
-                is_delayed_copy
                 isPPA
                 package_copy_job
                 package_copy_job_id
@@ -206,7 +205,6 @@
                 addCustom
                 syncUpdate
                 notify
-                acceptFromCopy
                 acceptFromUploader
                 acceptFromQueue
                 rejectFromQueue

=== modified file 'lib/lp/soyuz/doc/closing-bugs-from-changelogs.txt'
--- lib/lp/soyuz/doc/closing-bugs-from-changelogs.txt	2012-01-20 15:42:44 +0000
+++ lib/lp/soyuz/doc/closing-bugs-from-changelogs.txt	2012-11-15 02:05:24 +0000
@@ -242,28 +242,6 @@
     Before: NEW
     After: NEW
 
-Delayed-copies to allowed archives and pockets will close bugs when
-processed.
-
-    # Create the cdrkit 'original upload' in ubuntu/breezy-autotest
-    # with an appropriate 'changelog_entry'.
-    >>> original_upload = add_package_upload(
-    ...     cdrkit_release, cdrkit_bug_id,
-    ...     distroseries=cdrkit_release.upload_distroseries)
-    >>> from zope.security.proxy import removeSecurityProxy
-    >>> removeSecurityProxy(cdrkit_release).changelog_entry = 'Something!'
-
-    # Create a delayed-copy for cdrkit in ubuntu/hoary.
-    >>> from lp.soyuz.interfaces.queue import IPackageUploadSet
-    >>> delayed_copy = getUtility(IPackageUploadSet).createDelayedCopy(
-    ...     archive=ubuntu.main_archive, distroseries=ubuntu_hoary,
-    ...     pocket=PackagePublishingPocket.RELEASE, signing_key=None)
-    >>> unused = delayed_copy.addSource(cdrkit_release)
-
-    >>> close_bugs_and_check_status([cdrkit_bug_id], delayed_copy)
-    Before: NEW
-    After: FIXRELEASED
-
 It's possible to specify more than one bug in the Launchpad-bugs-fixed
 header, each will be marked as Fix Released. If a nonexistent bug,
 '666', is specified, it's ignored.

=== modified file 'lib/lp/soyuz/doc/distroseriesqueue.txt'
--- lib/lp/soyuz/doc/distroseriesqueue.txt	2012-07-04 17:08:56 +0000
+++ lib/lp/soyuz/doc/distroseriesqueue.txt	2012-11-15 02:05:24 +0000
@@ -880,141 +880,3 @@
 
     >>> from lp.testing.layers import LibrarianLayer
     >>> LibrarianLayer.librarian_fixture.clear()
-
-
-Delayed copies
---------------
-
-IPackageUploadSet allows call sites to create 'delayed-copy'
-PackageUpload records.
-
-    >>> from lp.registry.interfaces.gpg import IGPGKeySet
-    >>> testing_key = getUtility(IGPGKeySet).get(1)
-
-    >>> from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
-    >>> test_publisher = SoyuzTestPublisher()
-    >>> test_publisher.addFakeChroots(hoary)
-    >>> ignore = test_publisher.setUpDefaultDistroSeries(hoary)
-    >>> from lp.registry.interfaces.person import IPersonSet
-    >>> cprov = getUtility(IPersonSet).getByName('cprov')
-
-A 'delayed-copy' is a PackageUpload record.
-
-    >>> delayed_copy = getUtility(IPackageUploadSet).createDelayedCopy(
-    ...     ubuntu.main_archive, hoary,
-    ...     PackagePublishingPocket.RELEASE, testing_key)
-
-Delayed copies are manipulated exactly as normal uploads
-are. Contents can be attached to it.
-
-    >>> a_source_package = test_publisher.createSource(
-    ...     cprov.archive, 'foocomm', '1.0-1', new_version='2.0-1')
-    >>> transaction.commit()
-    >>> unused = delayed_copy.addSource(a_source_package.sourcepackagerelease)
-
-    >>> print delayed_copy.displayname
-    foocomm (delayed)
-
-    >>> verifyObject(IPackageUpload, delayed_copy)
-    True
-
-The distinction between normal uploads and delayed-copies can be made
-by checking IPackageUpload.is_delayed_copy.
-
-    >>> delayed_copy.is_delayed_copy
-    True
-
-    >>> normal_upload = breezy_autotest.createQueueEntry(
-    ...     PackagePublishingPocket.RELEASE,
-    ...     ubuntu.main_archive, 'foo.changes',
-    ...     'something')
-
-    >>> normal_upload.is_delayed_copy
-    False
-
-Delayed-copies are targeted to a publication context (archive,
-distroseries, pocket).
-
-    >>> print delayed_copy.archive.displayname
-    Primary Archive for Ubuntu Linux
-
-    >>> print delayed_copy.distroseries.displayname
-    Hoary
-
-    >>> print delayed_copy.pocket.name
-    RELEASE
-
-And are created in NEW state, so they have to pass through the upload
-state-machine.
-
-    >>> print delayed_copy.status.name
-    NEW
-
-However they have no 'changesfile', only a signing_key representing the
-requester of the copy.
-
-    >>> print delayed_copy.changesfile
-    None
-
-    >>> print delayed_copy.signing_key.owner.displayname
-    Foo Bar
-
-IPackageUpload.acceptFromCopy() simply checks and accepts a
-delayed-copy record. Bugs mentioned in the changelog are closed by
-`process-accepted` (transition to ACCEPTED to DONE) see
-closing-bugs-from-changelogs.txt for more information.
-
-    >>> print delayed_copy.status.name
-    NEW
-
-    >>> delayed_copy.acceptFromCopy()
-
-    >>> print delayed_copy.status.name
-    ACCEPTED
-
-Once accepted a delayed-copy is published as a normal upload, via
-IPackageUpload.realiseUpload().
-
-    >>> publishing_records = delayed_copy.realiseUpload()
-
-    >>> for pub_record in publishing_records:
-    ...     print pub_record.displayname, pub_record.status.name
-    foocomm 2.0-1 in hoary PENDING
-
-    >>> print delayed_copy.status.name
-    DONE
-
-As mentioned above, delayed copies wait in the ACCEPTED upload queue
-until they get processed, resulting in the corresponding publishing
-records.
-
-For that period of time, between creation and processing, a
-delayed-copy existence is not apparent in the publishing domain and
-creating a duplicated delayed-copy is perfectly possible.
-
-    >>> dup_delayed_copy = getUtility(IPackageUploadSet).createDelayedCopy(
-    ...     ubuntu.main_archive, breezy_autotest,
-    ...     PackagePublishingPocket.RELEASE, testing_key)
-
-    >>> unused = dup_delayed_copy.addSource(
-    ...     a_source_package.sourcepackagerelease)
-
-Although it cannot be accepted.
-
-    >>> dup_delayed_copy.acceptFromCopy()
-    Traceback (most recent call last):
-    ...
-    QueueInconsistentStateError: The source foocomm - 2.0-1 is already
-    accepted in ubuntu/hoary and you cannot upload the same version within the
-    same distribution. You have to modify the source version and re-upload.
-
-For detecting conflicting delayed copies we have to inspect the
-ACCEPTED and DONE queue for uploads of sources matching a given
-(name, version) pair in a publishing context, archive and
-distribution.
-
-    >>> conflict = getUtility(IPackageUploadSet).findSourceUpload(
-    ...     'foocomm', '2.0-1', ubuntu.main_archive, ubuntu)
-
-    >>> conflict.id == delayed_copy.id
-    True

=== modified file 'lib/lp/soyuz/interfaces/queue.py'
--- lib/lp/soyuz/interfaces/queue.py	2012-08-13 06:25:46 +0000
+++ lib/lp/soyuz/interfaces/queue.py	2012-11-15 02:05:24 +0000
@@ -257,8 +257,6 @@
         "whether or not this upload contains a signed UEFI boot loader image")
     isPPA = Attribute(
         "Return True if this PackageUpload is a PPA upload.")
-    is_delayed_copy = Attribute(
-        "Whether or not this PackageUpload record is a delayed-copy.")
 
     components = Attribute(
         """The set of components used in this upload.
@@ -344,17 +342,6 @@
          * Publish and close bugs for 'single-source' uploads.
          * Skip bug-closing for PPA uploads.
          * Grant karma to people involved with the upload.
-
-        :raises: AssertionError if the context is a delayed-copy.
-        """
-
-    def acceptFromCopy():
-        """Perform upload acceptance for a delayed-copy record.
-
-         * Move the upload to accepted queue in all cases.
-
-        :raises: AssertionError if the context is not a delayed-copy or
-            has no sources associated to it.
         """
 
     @export_write_operation()
@@ -364,8 +351,6 @@
         """Call setAccepted, do a syncUpdate, and send notification email.
 
          * Grant karma to people involved with the upload.
-
-        :raises: AssertionError if the context is a delayed-copy.
         """
 
     @export_write_operation()
@@ -737,17 +722,6 @@
         distroseries, same for pocket.
         """
 
-    def createDelayedCopy(archive, distroseries, pocket, signing_key):
-        """Return a `PackageUpload` record for a delayed-copy operation.
-
-        :param archive: target `IArchive`,
-        :param distroseries: target `IDistroSeries`,
-        :param pocket: target `PackagePublishingPocket`,
-        :param signing_key: `IGPGKey` of the user requesting this copy.
-
-        :return: an `IPackageUpload` record in NEW state.
-        """
-
     def getAll(distroseries, created_since_date=None, status=None,
                archive=None, pocket=None, custom_type=None,
                name=None, version=None, exact_match=False):

=== modified file 'lib/lp/soyuz/model/binarypackagebuild.py'
--- lib/lp/soyuz/model/binarypackagebuild.py	2012-10-10 22:22:36 +0000
+++ lib/lp/soyuz/model/binarypackagebuild.py	2012-11-15 02:05:24 +0000
@@ -8,7 +8,6 @@
     ]
 
 import datetime
-import logging
 import operator
 
 import apt_pkg
@@ -55,11 +54,7 @@
     IStoreSelector,
     MAIN_STORE,
     )
-from lp.services.database.lpstorm import (
-    IMasterObject,
-    ISlaveStore,
-    IStore,
-    )
+from lp.services.database.lpstorm import IStore
 from lp.services.database.sqlbase import (
     SQLBase,
     sqlvalues,
@@ -177,11 +172,9 @@
     def package_upload(self):
         """See `IBuild`."""
         store = Store.of(self)
-        # The join on 'changesfile' is not only used only for
-        # pre-fetching the corresponding library file, so callsites
-        # don't have to issue an extra query. It is also important
-        # for excluding delayed-copies, because they might match
-        # the publication context but will not contain as changesfile.
+        # The join on 'changesfile' is used for pre-fetching the
+        # corresponding library file, so callsites don't have to issue an
+        # extra query.
         origin = [
             PackageUploadBuild,
             Join(PackageUpload,

=== modified file 'lib/lp/soyuz/model/queue.py'
--- lib/lp/soyuz/model/queue.py	2012-11-09 12:42:32 +0000
+++ lib/lp/soyuz/model/queue.py	2012-11-15 02:05:24 +0000
@@ -91,7 +91,6 @@
 from lp.soyuz.interfaces.packagecopyjob import IPackageCopyJobSource
 from lp.soyuz.interfaces.publishing import (
     IPublishingSet,
-    ISourcePackagePublishingHistory,
     name_priority_map,
     )
 from lp.soyuz.interfaces.queue import (
@@ -541,8 +540,6 @@
 
     def acceptFromUploader(self, changesfile_path, logger=None):
         """See `IPackageUpload`."""
-        assert not self.is_delayed_copy, 'Cannot process delayed copies.'
-
         debug(logger, "Setting it to ACCEPTED")
         self.setAccepted()
 
@@ -570,8 +567,6 @@
 
         assert self.package_copy_job is not None, (
             "This method is for copy-job uploads only.")
-        assert not self.is_delayed_copy, (
-            "This method is not for delayed copies.")
 
         if self.status == PackageUploadStatus.REJECTED:
             raise QueueInconsistentStateError(
@@ -596,8 +591,6 @@
 
         assert self.package_copy_job is None, (
             "This method is not for copy-job uploads.")
-        assert not self.is_delayed_copy, (
-            "This method is not for delayed copies.")
 
         self.setAccepted()
 
@@ -629,8 +622,6 @@
 
     def acceptFromQueue(self, logger=None, dry_run=False, user=None):
         """See `IPackageUpload`."""
-        assert not self.is_delayed_copy, 'Cannot process delayed copies.'
-
         if self.package_copy_job is None:
             self._acceptNonSyncFromQueue(logger, dry_run)
         else:
@@ -639,13 +630,6 @@
             client = AuditorClient()
             client.send(self, 'packageupload-accepted', user)
 
-    def acceptFromCopy(self):
-        """See `IPackageUpload`."""
-        assert self.is_delayed_copy, 'Can only process delayed-copies.'
-        assert len(self.sources) == 1, (
-            'Source is mandatory for delayed copies.')
-        self.setAccepted()
-
     def rejectFromQueue(self, logger=None, dry_run=False, user=None):
         """See `IPackageUpload`."""
         self.setRejected()
@@ -675,11 +659,6 @@
             client = AuditorClient()
             client.send(self, 'packageupload-rejected', user)
 
-    @property
-    def is_delayed_copy(self):
-        """See `IPackageUpload`."""
-        return self.changesfile is None and self.package_copy_job is None
-
     def _isSingleSourceUpload(self):
         """Return True if this upload contains only a single source."""
         return ((len(self.sources) == 1) and
@@ -794,10 +773,7 @@
             names.append(queue_custom.libraryfilealias.filename)
         # Make sure the list items have a whitespace separator so
         # that they can be wrapped in table cells in the UI.
-        ret = ", ".join(names)
-        if self.is_delayed_copy:
-            ret += " (delayed)"
-        return ret
+        return ", ".join(names)
 
     @cachedproperty
     def displayarchs(self):
@@ -844,8 +820,6 @@
             # them here.  The runner is also responsible for calling
             # setDone().
             return
-        # Circular imports.
-        from lp.soyuz.scripts.packagecopier import update_files_privacy
         assert self.status == PackageUploadStatus.ACCEPTED, (
             "Can not publish a non-ACCEPTED queue record (%s)" % self.id)
         # Explode if something wrong like warty/RELEASE pass through
@@ -872,40 +846,6 @@
                     logger.error("Queue item ignored: %s" % e)
                     return []
 
-        # Adjust component and file privacy of delayed_copies.
-        if self.is_delayed_copy:
-            for pub_record in publishing_records:
-                pub_record.overrideFromAncestry()
-
-                # Grab the .changes file of the original source package while
-                # it's available.
-                changes_file = None
-                if ISourcePackagePublishingHistory.providedBy(pub_record):
-                    release = pub_record.sourcepackagerelease
-                    changes_file = StringIO.StringIO(
-                        release.package_upload.changesfile.read())
-
-                for new_file in update_files_privacy(pub_record):
-                    debug(logger, "Made %s public" % new_file.filename)
-                for custom_file in self.customfiles:
-                    update_files_privacy(custom_file)
-                    debug(logger,
-                          "Made custom file %s public" %
-                          custom_file.libraryfilealias.filename)
-                if ISourcePackagePublishingHistory.providedBy(pub_record):
-                    pas_verify = BuildDaemonPackagesArchSpecific(
-                        config.builddmaster.root, self.distroseries)
-                    pub_record.createMissingBuilds(
-                        pas_verify=pas_verify, logger=logger)
-
-                if changes_file is not None:
-                    debug(
-                        logger,
-                        "sending email to %s" % self.distroseries.changeslist)
-                    self.notify(
-                        changes_file_object=changes_file, logger=logger)
-                    self.syncUpdate()
-
         self.setDone()
 
         return publishing_records
@@ -1242,27 +1182,10 @@
         """See `IPackageUploadBuild`."""
         distroseries = self.packageupload.distroseries
         is_ppa = self.packageupload.archive.is_ppa
-        is_delayed_copy = self.packageupload.is_delayed_copy
 
         for binary in self.build.binarypackages:
-            component = binary.component
-
-            if is_delayed_copy:
-                # For a delayed copy the component will not yet have
-                # had the chance to be overridden, so we'll check the value
-                # that will be overridden by querying the ancestor in
-                # the destination archive - if one is available.
-                binary_name = binary.name
-                ancestry = getUtility(IPublishingSet).getNearestAncestor(
-                    package_name=binary_name,
-                    archive=self.packageupload.archive,
-                    distroseries=self.packageupload.distroseries, binary=True)
-
-                if ancestry is not None:
-                    component = ancestry.component
-
-            if (not is_ppa and component not in
-                distroseries.upload_components):
+            if (not is_ppa and
+                binary.component not in distroseries.upload_components):
                 # Only complain about non-PPA uploads.
                 raise QueueBuildAcceptError(
                     'Component "%s" is not allowed in %s'
@@ -1396,20 +1319,6 @@
         distroseries = self.packageupload.distroseries
         component = self.sourcepackagerelease.component
 
-        if self.packageupload.is_delayed_copy:
-            # For a delayed copy the component will not yet have
-            # had the chance to be overridden, so we'll check the value
-            # that will be overridden by querying the ancestor in
-            # the destination archive - if one is available.
-            source_name = self.sourcepackagerelease.name
-            ancestry = getUtility(IPublishingSet).getNearestAncestor(
-                package_name=source_name,
-                archive=self.packageupload.archive,
-                distroseries=self.packageupload.distroseries)
-
-            if ancestry is not None:
-                component = ancestry.component
-
         if (not self.packageupload.archive.is_ppa and
             component not in distroseries.upload_components):
             # Only complain about non-PPA uploads.
@@ -1648,13 +1557,6 @@
         except SQLObjectNotFound:
             raise NotFoundError(queue_id)
 
-    def createDelayedCopy(self, archive, distroseries, pocket,
-                          signing_key):
-        """See `IPackageUploadSet`."""
-        return PackageUpload(
-            archive=archive, distroseries=distroseries, pocket=pocket,
-            status=PackageUploadStatus.NEW, signing_key=signing_key)
-
     def findSourceUpload(self, name, version, archive, distribution):
         """See `IPackageUploadSet`."""
         # Avoiding circular imports.

=== modified file 'lib/lp/soyuz/model/sourcepackagerelease.py'
--- lib/lp/soyuz/model/sourcepackagerelease.py	2012-09-21 12:23:40 +0000
+++ lib/lp/soyuz/model/sourcepackagerelease.py	2012-11-15 02:05:24 +0000
@@ -495,11 +495,9 @@
     def package_upload(self):
         """See `ISourcepackageRelease`."""
         store = Store.of(self)
-        # The join on 'changesfile' is not only used only for
-        # pre-fetching the corresponding library file, so callsites
-        # don't have to issue an extra query. It is also important
-        # for excluding delayed-copies, because they might match
-        # the publication context but will not contain as changesfile.
+        # The join on 'changesfile' is used for pre-fetching the
+        # corresponding library file, so callsites don't have to issue an
+        # extra query.
         origin = [
             PackageUploadSource,
             Join(PackageUpload,

=== modified file 'lib/lp/soyuz/scripts/packagecopier.py'
--- lib/lp/soyuz/scripts/packagecopier.py	2012-10-24 11:34:10 +0000
+++ lib/lp/soyuz/scripts/packagecopier.py	2012-11-15 02:05:24 +0000
@@ -9,7 +9,6 @@
     'CopyChecker',
     'check_copy_permissions',
     'do_copy',
-    '_do_delayed_copy',
     '_do_direct_copy',
     'update_files_privacy',
     ]
@@ -22,8 +21,6 @@
 from zope.component import getUtility
 from zope.security.proxy import removeSecurityProxy
 
-from lp.app.errors import NotFoundError
-from lp.buildmaster.enums import BuildStatus
 from lp.services.database.bulk import load_related
 from lp.soyuz.adapters.notification import notify
 from lp.soyuz.enums import (
@@ -38,13 +35,10 @@
     IPublishingSet,
     ISourcePackagePublishingHistory,
     )
-from lp.soyuz.interfaces.queue import (
-    IPackageUpload,
-    IPackageUploadCustom,
-    IPackageUploadSet,
-    )
+from lp.soyuz.interfaces.queue import IPackageUploadCustom
 from lp.soyuz.scripts.custom_uploads_copier import CustomUploadsCopier
 
+
 # XXX cprov 2009-06-12: this function should be incorporated in
 # IPublishing.
 def update_files_privacy(pub_record):
@@ -134,17 +128,12 @@
     Decorates `ISourcePackagePublishingHistory`, tweaking
     `getStatusSummaryForBuilds` to return `BuildSetStatus.NEEDSBUILD`
     for source-only copies.
-
-    It also store the 'delayed' boolean, which controls the way this source
-    should be copied to the destionation archive (see `_do_delayed_copy` and
-    `_do_direct_copy`)
     """
     delegates(ISourcePackagePublishingHistory)
 
-    def __init__(self, context, include_binaries, delayed):
+    def __init__(self, context, include_binaries):
         self.context = context
         self.include_binaries = include_binaries
-        self.delayed = delayed
 
     def getStatusSummaryForBuilds(self):
         """Always `BuildSetStatus.NEEDSBUILD` for source-only copies."""
@@ -230,16 +219,14 @@
     Allows the checker function to identify conflicting copy candidates
     within the copying batch.
     """
-    def __init__(self, archive, include_binaries, allow_delayed_copies=False,
-                 strict_binaries=True, unembargo=False):
+    def __init__(self, archive, include_binaries, strict_binaries=True,
+                 unembargo=False):
         """Initialize a copy checker.
 
         :param archive: the target `IArchive`.
         :param include_binaries: controls whether or not the published
             binaries for each given source should be also copied along
             with the source.
-        :param allow_delayed_copies: boolean indicating whether or not private
-            sources can be copied to public archives using delayed_copies.
         :param strict_binaries: If 'include_binaries' is True then setting
             this to True will make the copy fail if binaries cannot be also
             copied.
@@ -249,7 +236,6 @@
         self.archive = archive
         self.include_binaries = include_binaries
         self.strict_binaries = strict_binaries
-        self.allow_delayed_copies = allow_delayed_copies
         self.unembargo = unembargo
         self._inventory = {}
 
@@ -262,10 +248,10 @@
         return (
             candidate.source_package_name, candidate.source_package_version)
 
-    def addCopy(self, source, delayed):
-        """Story a copy in the inventory as a `CheckedCopy` instance."""
+    def addCopy(self, source):
+        """Store a copy in the inventory as a `CheckedCopy` instance."""
         inventory_key = self._getInventoryKey(source)
-        checked_copy = CheckedCopy(source, self.include_binaries, delayed)
+        checked_copy = CheckedCopy(source, self.include_binaries)
         candidates = self._inventory.setdefault(inventory_key, [])
         candidates.append(checked_copy)
 
@@ -504,31 +490,21 @@
 
         requires_unembargo = (
             not self.archive.private and has_restricted_files(source))
-        delayed = self.allow_delayed_copies and requires_unembargo
 
-        if delayed:
-            upload_conflict = getUtility(IPackageUploadSet).findSourceUpload(
-                name=source.sourcepackagerelease.name,
-                version=source.sourcepackagerelease.version,
-                archive=self.archive, distribution=series.distribution)
-            if upload_conflict is not None:
-                raise CannotCopy(
-                    'same version already uploaded and waiting in '
-                    'ACCEPTED queue')
-        elif requires_unembargo and not self.unembargo:
+        if requires_unembargo and not self.unembargo:
             raise CannotCopy(
                 "Cannot copy restricted files to a public archive without "
                 "explicit unembargo option.")
 
         # Copy is approved, update the copy inventory.
-        self.addCopy(source, delayed)
+        self.addCopy(source)
 
 
 def do_copy(sources, archive, series, pocket, include_binaries=False,
-            allow_delayed_copies=False, person=None, check_permissions=True,
-            overrides=None, send_email=False, strict_binaries=True,
-            close_bugs=True, create_dsd_job=True,  announce_from_person=None,
-            sponsored=None, packageupload=None, unembargo=False, logger=None):
+            person=None, check_permissions=True, overrides=None,
+            send_email=False, strict_binaries=True, close_bugs=True,
+            create_dsd_job=True, announce_from_person=None, sponsored=None,
+            packageupload=None, unembargo=False, logger=None):
     """Perform the complete copy of the given sources incrementally.
 
     Verifies if each copy can be performed using `CopyChecker` and
@@ -547,9 +523,6 @@
     :param include_binaries: optional boolean, controls whether or
         not the published binaries for each given source should be also
         copied along with the source.
-    :param allow_delayed_copies: boolean indicating whether or not private
-        sources can be copied to public archives using delayed_copies.
-        Defaults to False.
     :param person: the requester `IPerson`.
     :param check_permissions: boolean indicating whether or not the
         requester's permissions to copy should be checked.
@@ -558,7 +531,6 @@
         default override returned by IArchive.getOverridePolicy().  There
         must be the same number of overrides as there are sources and each
         override must be for the corresponding source in the sources list.
-        Overrides will be ignored for delayed copies.
     :param send_email: Should we notify for the copy performed?
         NOTE: If running in zopeless mode, the email is sent even if the
         transaction is later aborted. (See bug 29744)
@@ -591,8 +563,8 @@
     copies = []
     errors = []
     copy_checker = CopyChecker(
-        archive, include_binaries, allow_delayed_copies,
-        strict_binaries=strict_binaries, unembargo=unembargo)
+        archive, include_binaries, strict_binaries=strict_binaries,
+        unembargo=unembargo)
 
     for source in sources:
         if series is None:
@@ -630,57 +602,48 @@
             destination_series = source.distroseries
         else:
             destination_series = series
-        if source.delayed:
-            delayed_copy = _do_delayed_copy(
-                source, archive, destination_series, pocket,
-                include_binaries)
-            sub_copies = [delayed_copy]
-        else:
-            override = None
-            if overrides:
-                override = overrides[overrides_index]
-            # Make a note of the destination source's version for use
-            # in sending the email notification and closing bugs.
-            existing = archive.getPublishedSources(
-                name=source.sourcepackagerelease.name, exact_match=True,
-                status=active_publishing_status,
-                distroseries=series, pocket=pocket).first()
-            if existing:
-                old_version = existing.sourcepackagerelease.version
-            else:
-                old_version = None
-            if sponsored is not None:
-                announce_from_person = sponsored
-                creator = sponsored
-                sponsor = person
-            else:
-                creator = person
-                sponsor = None
-            sub_copies = _do_direct_copy(
-                source, archive, destination_series, pocket,
-                include_binaries, override, close_bugs=close_bugs,
-                create_dsd_job=create_dsd_job,
-                close_bugs_since_version=old_version, creator=creator,
-                sponsor=sponsor, packageupload=packageupload)
-            if send_email:
-                notify(
-                    person, source.sourcepackagerelease, [], [], archive,
-                    destination_series, pocket, action='accepted',
-                    announce_from_person=announce_from_person,
-                    previous_version=old_version)
-            if not archive.private and has_restricted_files(source):
-                # Fix copies by overriding them according to the current
-                # ancestry and unrestrict files with privacy mismatch.  We
-                # must do this *after* calling notify (which only actually
-                # sends mail on commit), because otherwise the new changelog
-                # LFA won't be visible without a commit, which may not be
-                # safe here.
-                for pub_record in sub_copies:
-                    pub_record.overrideFromAncestry()
-                    for changed_file in update_files_privacy(pub_record):
-                        if logger is not None:
-                            logger.info(
-                                "Made %s public" % changed_file.filename)
+        override = None
+        if overrides:
+            override = overrides[overrides_index]
+        # Make a note of the destination source's version for use in sending
+        # the email notification and closing bugs.
+        existing = archive.getPublishedSources(
+            name=source.sourcepackagerelease.name, exact_match=True,
+            status=active_publishing_status, distroseries=series,
+            pocket=pocket).first()
+        if existing:
+            old_version = existing.sourcepackagerelease.version
+        else:
+            old_version = None
+        if sponsored is not None:
+            announce_from_person = sponsored
+            creator = sponsored
+            sponsor = person
+        else:
+            creator = person
+            sponsor = None
+        sub_copies = _do_direct_copy(
+            source, archive, destination_series, pocket, include_binaries,
+            override, close_bugs=close_bugs, create_dsd_job=create_dsd_job,
+            close_bugs_since_version=old_version, creator=creator,
+            sponsor=sponsor, packageupload=packageupload)
+        if send_email:
+            notify(
+                person, source.sourcepackagerelease, [], [], archive,
+                destination_series, pocket, action='accepted',
+                announce_from_person=announce_from_person,
+                previous_version=old_version)
+        if not archive.private and has_restricted_files(source):
+            # Fix copies by overriding them according to the current
+            # ancestry and unrestrict files with privacy mismatch.  We must
+            # do this *after* calling notify (which only actually sends mail
+            # on commit), because otherwise the new changelog LFA won't be
+            # visible without a commit, which may not be safe here.
+            for pub_record in sub_copies:
+                pub_record.overrideFromAncestry()
+                for changed_file in update_files_privacy(pub_record):
+                    if logger is not None:
+                        logger.info("Made %s public" % changed_file.filename)
 
         overrides_index += 1
         copies.extend(sub_copies)
@@ -798,82 +761,3 @@
     source_copy.createMissingBuilds()
 
     return copies
-
-
-class DelayedCopy:
-    """Decorates `IPackageUpload` with a more descriptive 'displayname'."""
-
-    delegates(IPackageUpload)
-
-    def __init__(self, context):
-        self.context = context
-
-    @property
-    def displayname(self):
-        return 'Delayed copy of %s (%s)' % (
-            self.context.sourcepackagerelease.title,
-            self.context.displayarchs)
-
-
-def _do_delayed_copy(source, archive, series, pocket, include_binaries):
-    """Schedule the given source for copy.
-
-    Schedule the copy of each item of the given list of
-    `SourcePackagePublishingHistory` to the given destination.
-
-    Also include published builds for each source if requested to.
-
-    :param source: an `ISourcePackagePublishingHistory`.
-    :param archive: the target `IArchive`.
-    :param series: the target `IDistroSeries`.
-    :param pocket: the target `PackagePublishingPocket`.
-    :param include_binaries: optional boolean, controls whether or
-        not the published binaries for each given source should be also
-        copied along with the source.
-
-    :return: a list of `IPackageUpload` corresponding to the publications
-        scheduled for copy.
-    """
-    # XXX cprov 2009-06-22 bug=385503: At some point we will change
-    # the copy signature to allow a user to be passed in, so will
-    # be able to annotate that information in delayed copied as well,
-    # by using the right key. For now it's undefined.
-    # See also the comment on acceptFromCopy()
-    delayed_copy = getUtility(IPackageUploadSet).createDelayedCopy(
-        archive, series, pocket, None)
-
-    # Include the source and any custom upload.
-    delayed_copy.addSource(source.sourcepackagerelease)
-    original_source_upload = source.sourcepackagerelease.package_upload
-    for custom in original_source_upload.customfiles:
-        delayed_copy.addCustom(
-            custom.libraryfilealias, custom.customformat)
-
-    # If binaries are included in the copy we include binary custom files.
-    if include_binaries:
-        for build in source.getBuilds():
-            # Don't copy builds that aren't yet done, or those without a
-            # corresponding enabled architecture in the new series.
-            try:
-                target_arch = series[build.arch_tag]
-            except NotFoundError:
-                continue
-            if (not target_arch.enabled or
-                build.status != BuildStatus.FULLYBUILT):
-                continue
-            delayed_copy.addBuild(build)
-            original_build_upload = build.package_upload
-            for custom in original_build_upload.customfiles:
-                delayed_copy.addCustom(
-                    custom.libraryfilealias, custom.customformat)
-
-    # XXX cprov 2009-06-22 bug=385503: when we have a 'user' responsible
-    # for the copy we can also decide whether a copy should be immediately
-    # accepted or moved to the UNAPPROVED queue, based on the user's
-    # permission to the destination context.
-
-    # Accept the delayed-copy, which implicitly verifies if it fits
-    # the destination context.
-    delayed_copy.acceptFromCopy()
-
-    return DelayedCopy(delayed_copy)

=== modified file 'lib/lp/soyuz/scripts/processaccepted.py'
--- lib/lp/soyuz/scripts/processaccepted.py	2012-09-24 20:37:00 +0000
+++ lib/lp/soyuz/scripts/processaccepted.py	2012-11-15 02:05:24 +0000
@@ -122,11 +122,7 @@
         return
 
     if changesfile_object is None:
-        if queue_item.is_delayed_copy:
-            sourcepackagerelease = queue_item.sources[0].sourcepackagerelease
-            changesfile_object = sourcepackagerelease.upload_changesfile
-        else:
-            changesfile_object = queue_item.changesfile
+        changesfile_object = queue_item.changesfile
 
     for source_queue_item in queue_item.sources:
         close_bugs_for_sourcepackagerelease(

=== modified file 'lib/lp/soyuz/scripts/tests/test_copypackage.py'
--- lib/lp/soyuz/scripts/tests/test_copypackage.py	2012-10-03 07:47:08 +0000
+++ lib/lp/soyuz/scripts/tests/test_copypackage.py	2012-11-15 02:05:24 +0000
@@ -29,16 +29,12 @@
 from lp.buildmaster.enums import BuildStatus
 from lp.registry.interfaces.distribution import IDistributionSet
 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.soyuz.adapters.overrides import SourceOverride
 from lp.soyuz.enums import (
     ArchivePermissionType,
     ArchivePurpose,
     PackagePublishingStatus,
-    PackageUploadCustomFormat,
-    PackageUploadStatus,
     SourcePackageFormat,
     )
 from lp.soyuz.interfaces.archive import CannotCopy
@@ -48,13 +44,15 @@
     active_publishing_status,
     IPublishingSet,
     )
-from lp.soyuz.interfaces.queue import QueueInconsistentStateError
 from lp.soyuz.interfaces.sourcepackageformat import (
     ISourcePackageFormatSelectionSet,
     )
 from lp.soyuz.model.archivepermission import ArchivePermission
+from lp.soyuz.model.publishing import (
+    BinaryPackagePublishingHistory,
+    SourcePackagePublishingHistory,
+    )
 from lp.soyuz.scripts.packagecopier import (
-    _do_delayed_copy,
     _do_direct_copy,
     CopyChecker,
     do_copy,
@@ -328,7 +326,7 @@
 class CopyCheckerHarness:
     """Basic checks common for all scenarios."""
 
-    def assertCanCopySourceOnly(self, delayed=False):
+    def assertCanCopySourceOnly(self, **kwargs):
         """Source-only copy is allowed.
 
         Initialize a `CopyChecker` and assert a `checkCopy` call returns
@@ -339,11 +337,9 @@
          * 1 'CheckedCopy' was allowed and stored as so.
          * Since it was source-only, the `CheckedCopy` objects is in
            NEEDSBUILD state.
-         * Finally check whether is a delayed-copy or not according to the
-           given state.
         """
         copy_checker = CopyChecker(
-            self.archive, include_binaries=False, allow_delayed_copies=delayed)
+            self.archive, include_binaries=False, **kwargs)
         self.assertIsNone(
             copy_checker.checkCopy(
                 self.source, self.series, self.pocket,
@@ -354,9 +350,8 @@
         self.assertEqual(
             BuildSetStatus.NEEDSBUILD,
             checked_copy.getStatusSummaryForBuilds()['status'])
-        self.assertEqual(delayed, checked_copy.delayed)
 
-    def assertCanCopyBinaries(self, delayed=False):
+    def assertCanCopyBinaries(self, **kwargs):
         """Source and binary copy is allowed.
 
         Initialize a `CopyChecker` and assert a `checkCopy` call returns
@@ -367,11 +362,9 @@
          * 1 'CheckedCopy' was allowed and stored as so.
          * The `CheckedCopy` objects is in FULLYBUILT_PENDING or FULLYBUILT
            status, so there are binaries to be copied.
-         * Finally check whether is a delayed-copy or not according to the
-           given state.
         """
         copy_checker = CopyChecker(
-            self.archive, include_binaries=True, allow_delayed_copies=delayed)
+            self.archive, include_binaries=True, **kwargs)
         self.assertIsNone(
             copy_checker.checkCopy(
                 self.source, self.series, self.pocket,
@@ -382,15 +375,15 @@
         self.assertTrue(
             checked_copy.getStatusSummaryForBuilds()['status'] >=
             BuildSetStatus.FULLYBUILT_PENDING)
-        self.assertEqual(delayed, checked_copy.delayed)
 
     def assertCannotCopySourceOnly(self, msg, person=None,
-                                   check_permissions=False):
+                                   check_permissions=False, **kwargs):
         """`CopyChecker.checkCopy()` for source-only copy raises CannotCopy.
 
         No `CheckedCopy` is stored.
         """
-        copy_checker = CopyChecker(self.archive, include_binaries=False)
+        copy_checker = CopyChecker(
+            self.archive, include_binaries=False, **kwargs)
         self.assertRaisesWithContent(
             CannotCopy, msg,
             copy_checker.checkCopy, self.source, self.series, self.pocket,
@@ -398,12 +391,13 @@
         checked_copies = list(copy_checker.getCheckedCopies())
         self.assertEqual(0, len(checked_copies))
 
-    def assertCannotCopyBinaries(self, msg):
+    def assertCannotCopyBinaries(self, msg, **kwargs):
         """`CopyChecker.checkCopy()` including binaries raises CannotCopy.
 
         No `CheckedCopy` is stored.
         """
-        copy_checker = CopyChecker(self.archive, include_binaries=True)
+        copy_checker = CopyChecker(
+            self.archive, include_binaries=True, **kwargs)
         self.assertRaisesWithContent(
             CannotCopy, msg,
             copy_checker.checkCopy, self.source, self.series, self.pocket,
@@ -671,18 +665,24 @@
 
     def test_can_copy_only_source_from_private_archives(self):
         # Source-only copies from private archives to public ones
-        # are allowed and result in a delayed-copy.
+        # are allowed, but only with unembargo=True.
         self.switchToAPrivateSource()
-        self.assertCanCopySourceOnly(delayed=True)
+        self.assertCannotCopySourceOnly(
+            "Cannot copy restricted files to a public archive without "
+            "explicit unembargo option.")
+        self.assertCanCopySourceOnly(unembargo=True)
 
     def test_can_copy_binaries_from_private_archives(self):
         # Source and binary copies from private archives to public ones
-        # are allowed and result in a delayed-copy.
+        # are allowed, but only with unembargo=True.
         self.switchToAPrivateSource()
         self.test_publisher.getPubBinaries(
             pub_source=self.source,
             status=PackagePublishingStatus.PUBLISHED)
-        self.assertCanCopyBinaries(delayed=True)
+        self.assertCannotCopyBinaries(
+            "Cannot copy restricted files to a public archive without "
+            "explicit unembargo option.")
+        self.assertCanCopyBinaries(unembargo=True)
 
     def test_cannot_copy_ddebs_to_primary_archives(self):
         # The primary archive cannot (yet) cope with DDEBs, see bug
@@ -1033,78 +1033,6 @@
             copied_source, copied_source.distroseries, copied_source.pocket,
             None, False)
 
-    def test_checkCopy_identifies_delayed_copies_conflicts(self):
-        # checkCopy() detects copy conflicts in the upload queue for
-        # delayed-copies. This is mostly caused by previous delayed-copies
-        # that are waiting to be processed.
-
-        # Create a private archive with a restricted source publication.
-        private_archive = self.factory.makeArchive(
-            distribution=self.test_publisher.ubuntutest,
-            purpose=ArchivePurpose.PPA)
-        private_archive.buildd_secret = 'x'
-        private_archive.private = True
-        source = self.test_publisher.createSource(
-            private_archive, 'foocomm', '1.0-2')
-
-        archive = self.test_publisher.ubuntutest.main_archive
-        series = source.distroseries
-        pocket = source.pocket
-
-        # Commit so the just-created files are accessible and perform
-        # the delayed-copy.
-        self.layer.txn.commit()
-        do_copy(
-            [source], archive, series, pocket, include_binaries=False,
-            allow_delayed_copies=True, check_permissions=False)
-
-        # Repeating the copy is denied.
-        copy_checker = CopyChecker(
-            archive, include_binaries=False, allow_delayed_copies=True)
-        self.assertRaisesWithContent(
-            CannotCopy,
-            'same version already uploaded and waiting in ACCEPTED queue',
-            copy_checker.checkCopy, source, series, pocket, None, False)
-
-    def test_checkCopy_suppressing_delayed_copies(self):
-        # `CopyChecker` can request delayed-copies by passing
-        # `allow_delayed_copies` as True, which was an old mechanism to
-        # support restricted files being copied to public archives.  If this
-        # is disabled, which is the default, the operation will be performed
-        # as a direct-copy.
-
-        # Create a private archive with a restricted source publication.
-        private_archive = self.factory.makeArchive(
-            distribution=self.test_publisher.ubuntutest,
-            purpose=ArchivePurpose.PPA)
-        private_archive.buildd_secret = 'x'
-        private_archive.private = True
-        source = self.test_publisher.getPubSource(archive=private_archive)
-
-        archive = self.test_publisher.ubuntutest.main_archive
-        series = source.distroseries
-        pocket = source.pocket
-
-        # `CopyChecker` can store a delayed-copy representing this
-        # operation, since restricted files are being copied to public
-        # archives.
-        copy_checker = CopyChecker(
-            archive, include_binaries=False, allow_delayed_copies=True)
-        copy_checker.checkCopy(
-            source, series, pocket, check_permissions=False)
-        [checked_copy] = list(copy_checker.getCheckedCopies())
-        self.assertTrue(checked_copy.delayed)
-
-        # When 'allow_delayed_copies' is off, a direct-copy will be
-        # scheduled.  This requires an explicit option to say that we know
-        # we're going to be exposing previously restricted files.
-        copy_checker = CopyChecker(
-            archive, include_binaries=False, unembargo=True)
-        copy_checker.checkCopy(
-            source, series, pocket, check_permissions=False)
-        [checked_copy] = list(copy_checker.getCheckedCopies())
-        self.assertFalse(checked_copy.delayed)
-
 
 class BaseDoCopyTests:
 
@@ -1699,237 +1627,34 @@
 
         self.assertIsNone(copied_source.sponsor)
 
-
-class TestDoDelayedCopy(TestCaseWithFactory, BaseDoCopyTests):
-
-    layer = LaunchpadZopelessLayer
-    dbuser = config.archivepublisher.dbuser
-
-    def setUp(self):
-        super(TestDoDelayedCopy, self).setUp()
-
-        self.test_publisher = SoyuzTestPublisher()
-        self.test_publisher.prepareBreezyAutotest()
-
-        # Setup to copy into the main archive security pocket
-        self.copy_archive = self.test_publisher.ubuntutest.main_archive
-        self.copy_series = self.test_publisher.distroseries
-        self.copy_pocket = PackagePublishingPocket.SECURITY
-
-        # Make ubuntutest/breezy-autotest CURRENT so uploads to SECURITY
-        # pocket can be accepted.
-        self.test_publisher.breezy_autotest.status = SeriesStatus.CURRENT
-
-    def assertCopied(self, copy, series, arch_tags):
-        self.assertEqual(
-            copy.sources[0].sourcepackagerelease.title, 'foo - 666')
-        self.assertContentEqual(
-            arch_tags, [pub.build.arch_tag for pub in copy.builds])
-
-    def doCopy(self, source, archive, series, pocket, include_binaries):
-        return _do_delayed_copy(source, archive, series, pocket, True)
-
-    def createDelayedCopyContext(self):
-        """Create a context to allow delayed-copies test.
-
-        The returned source publication in a private archive with
-        binaries and a custom upload.
-        """
-        ppa = self.factory.makeArchive(
-            distribution=self.test_publisher.ubuntutest,
-            purpose=ArchivePurpose.PPA)
-        ppa.buildd_secret = 'x'
-        ppa.private = True
-
-        source = self.test_publisher.createSource(ppa, 'foocomm', '1.0-2')
-        self.test_publisher.getPubBinaries(pub_source=source)
-
-        [build] = source.getBuilds()
-        custom_file = self.factory.makeLibraryFileAlias(restricted=True)
-        build.package_upload.addCustom(
-            custom_file, PackageUploadCustomFormat.DIST_UPGRADER)
-
-        # Commit for making the just-create library files available.
-        self.layer.txn.commit()
-
-        return source
-
-    def do_delayed_copy(self, source):
-        """Execute and return the delayed copy."""
-
-        switch_dbuser(self.dbuser)
-
-        delayed_copy = _do_delayed_copy(
-            source, self.copy_archive, self.copy_series, self.copy_pocket,
-            True)
-
-        switch_dbuser('launchpad')
-        return delayed_copy
-
-    def test_do_delayed_copy_simple(self):
-        # _do_delayed_copy() return an `IPackageUpload` record configured
-        # as a delayed-copy and with the expected contents (source,
-        # binaries and custom uploads) in ACCEPTED state.
-        source = self.createDelayedCopyContext()
-
-        # Setup and execute the delayed copy procedure.
-        delayed_copy = self.do_delayed_copy(source)
-
-        # A delayed-copy `IPackageUpload` record is returned.
-        self.assertTrue(delayed_copy.is_delayed_copy)
-        self.assertEqual(PackageUploadStatus.ACCEPTED, delayed_copy.status)
-
-        # The returned object has a more descriptive 'displayname'
-        # attribute than plain `IPackageUpload` instances.
-        self.assertEqual(
-            'Delayed copy of foocomm - '
-            '1.0-2 (source, i386, raw-dist-upgrader)',
-            delayed_copy.displayname)
-
-        # It is targeted to the right publishing context.
-        self.assertEqual(self.copy_archive, delayed_copy.archive)
-        self.assertEqual(self.copy_series, delayed_copy.distroseries)
-        self.assertEqual(self.copy_pocket, delayed_copy.pocket)
-
-        # And it contains the source, build and custom files.
-        self.assertEqual(
-            [source.sourcepackagerelease],
-            [pus.sourcepackagerelease for pus in delayed_copy.sources])
-
-        [build] = source.getBuilds()
-        self.assertEqual([build], [pub.build for pub in delayed_copy.builds])
-
-        [custom_file] = [
-            custom.libraryfilealias
-            for custom in build.package_upload.customfiles]
-        self.assertEqual(
-            [custom_file],
-            [custom.libraryfilealias for custom in delayed_copy.customfiles])
-
-    def test_do_delayed_copy_wrong_component_no_ancestry(self):
-        """An original PPA upload for an invalid component will have been
-        overridden when uploaded to the PPA, but when copying it to another
-        archive, only the ancestry in the destination archive can be used.
-        If that ancestry doesn't exist, an exception is raised."""
-        # We'll simulate an upload that was overridden to main in the
-        # ppa, by explicitly setting the spr's and bpr's component to
-        # something else.
-        source = self.createDelayedCopyContext()
-        contrib = getUtility(IComponentSet).new('contrib')
-        source.sourcepackagerelease.component = contrib
-        [build] = source.getBuilds()
-        [binary] = build.binarypackages
-        binary.override(component=contrib)
-        self.layer.txn.commit()
-
-        # Setup and execute the delayed copy procedure. This should
-        # raise an exception, as it won't be able to find an ancestor
-        # whose component can be used for overriding.
-        do_delayed_copy_method = self.do_delayed_copy
-        self.assertRaises(
-            QueueInconsistentStateError, do_delayed_copy_method, source)
-
-    def test_do_delayed_copy_wrong_component_with_ancestry(self):
-        """An original PPA upload for an invalid component will have been
-        overridden when uploaded to the PPA, but when copying it to another
-        archive, only the ancestry in the destination archive can be used.
-        If an ancestor is found in the destination archive, its component
-        is assumed for this package upload."""
-        # We'll simulate an upload that was overridden to main in the
-        # ppa, by explicitly setting the spr's and bpr's component to
-        # something else.
-        source = self.createDelayedCopyContext()
-        contrib = getUtility(IComponentSet).new('contrib')
-        source.sourcepackagerelease.component = contrib
-        [build] = source.getBuilds()
-        [binary] = build.binarypackages
-        binary.override(component=contrib)
-
-        # This time, we'll ensure that there is already an ancestor for
-        # foocom in the destination archive with binaries.
-        ancestor = self.test_publisher.getPubSource(
-            'foocomm', '0.9', component='multiverse',
-            archive=self.copy_archive,
-            status=PackagePublishingStatus.PUBLISHED)
-        self.test_publisher.getPubBinaries(
-            binaryname='foo-bin', archive=self.copy_archive,
-            status=PackagePublishingStatus.PUBLISHED, pub_source=ancestor)
-        self.layer.txn.commit()
-
-        # Setup and execute the delayed copy procedure. This should
-        # now result in an accepted delayed upload.
-        delayed_copy = self.do_delayed_copy(source)
-        self.assertEqual(PackageUploadStatus.ACCEPTED, delayed_copy.status)
-
-        # And it contains the source, build and custom files.
-        self.assertEqual(
-            [source.sourcepackagerelease],
-            [pus.sourcepackagerelease for pus in delayed_copy.sources])
-
-        [build] = source.getBuilds()
-        self.assertEqual([build], [pub.build for pub in delayed_copy.builds])
-
-        [custom_file] = [
-            custom.libraryfilealias
-            for custom in build.package_upload.customfiles]
-        self.assertEqual(
-            [custom_file],
-            [custom.libraryfilealias for custom in delayed_copy.customfiles])
-
-    def createPartiallyBuiltDelayedCopyContext(self):
-        """Allow tests on delayed-copies of partially built sources.
-
-        Create an architecture-specific source publication in a private PPA
-        capable of building for i386 and hppa architectures.
-
-        Upload and publish only the i386 binary, letting the hppa build
-        in pending status.
-        """
-        self.test_publisher.prepareBreezyAutotest()
-
-        ppa = self.factory.makeArchive(
-            distribution=self.test_publisher.ubuntutest,
-            purpose=ArchivePurpose.PPA)
-        ppa.buildd_secret = 'x'
-        ppa.private = True
-        ppa.require_virtualized = False
-
-        source = self.test_publisher.getPubSource(
-            archive=ppa, architecturehintlist='any')
-
+    def test_copy_partially_built_sources(self):
+        # Copies of partially built sources are allowed and only the
+        # FULLYBUILT builds are copied.
+        nobby, archive, source = self._setup_archive()
+        target_archive = self.factory.makeArchive(
+            distribution=self.test_publisher.ubuntutest)
         [build_hppa, build_i386] = source.createMissingBuilds()
         lazy_bin = self.test_publisher.uploadBinaryForBuild(
             build_i386, 'lazy-bin')
-        self.test_publisher.publishBinaryInArchive(lazy_bin, source.archive)
+        self.test_publisher.publishBinaryInArchive(lazy_bin, archive)
         changes_file_name = '%s_%s_%s.changes' % (
             lazy_bin.name, lazy_bin.version, build_i386.arch_tag)
-        package_upload = self.test_publisher.addPackageUpload(
-            ppa, build_i386.distro_arch_series.distroseries,
-            build_i386.pocket, changes_file_content='anything',
+        self.test_publisher.addPackageUpload(
+            archive, nobby, build_i386.pocket, changes_file_content='anything',
             changes_file_name=changes_file_name)
-        package_upload.addBuild(build_i386)
 
-        # Commit for making the just-create library files available.
+        # Make the new library files available.
         self.layer.txn.commit()
 
-        return source
-
-    def test_do_delayed_copy_of_partially_built_sources(self):
-        # delayed-copies of partially built sources are allowed and only
-        # the FULLYBUILT builds are copied.
-        source = self.createPartiallyBuiltDelayedCopyContext()
-
-        # Perform the delayed-copy including binaries.
-        delayed_copy = self.do_delayed_copy(source)
-
-        # Only the i386 build is included in the delayed-copy.
-        # For the record, later on, when the delayed-copy gets processed,
-        # a new hppa build record will be created in the destination
-        # archive context. Also after this point, the same delayed-copy
-        # request will be denied by `CopyChecker`.
-        [build_hppa, build_i386] = source.getBuilds()
-        self.assertEqual(
-            [build_i386], [pub.build for pub in delayed_copy.builds])
+        # Only the source and the fully-built binary are copied.
+        copies = do_copy(
+            [source], target_archive, nobby, source.pocket,
+            include_binaries=True, person=target_archive.owner,
+            check_permissions=False, send_email=False)
+        self.assertEqual(2, len(copies))
+        self.assertIsInstance(copies[0], SourcePackagePublishingHistory)
+        self.assertIsInstance(copies[1], BinaryPackagePublishingHistory)
+        self.assertEqual("i386", copies[1].distroarchseries.architecturetag)
 
 
 class TestCopyBuildRecords(TestCaseWithFactory):

=== modified file 'lib/lp/soyuz/stories/ppa/xx-ppa-files.txt'
--- lib/lp/soyuz/stories/ppa/xx-ppa-files.txt	2012-09-28 06:34:26 +0000
+++ lib/lp/soyuz/stories/ppa/xx-ppa-files.txt	2012-11-15 02:05:24 +0000
@@ -275,8 +275,7 @@
     ...     no_priv_private_ppa.getPublishedSources(name=u'test-pkg'),
     ...     no_priv.archive, series=ubuntu['warty'],
     ...     pocket=PackagePublishingPocket.RELEASE,
-    ...     include_binaries=True, allow_delayed_copies=False,
-    ...     person=no_priv, unembargo=True)
+    ...     include_binaries=True, person=no_priv, unembargo=True)
     >>> source_copy = [copy for copy in copies
     ...                if ISourcePackagePublishingHistory.providedBy(copy)
     ...                   and copy.source_package_version == "1.0"][0]

=== removed file 'lib/lp/soyuz/stories/soyuz/xx-queue-pages-delayed-copies.txt'
--- lib/lp/soyuz/stories/soyuz/xx-queue-pages-delayed-copies.txt	2012-01-15 11:06:57 +0000
+++ lib/lp/soyuz/stories/soyuz/xx-queue-pages-delayed-copies.txt	1970-01-01 00:00:00 +0000
@@ -1,133 +0,0 @@
-Displaying delayed-copies
-=========================
-
-Delayed copies can be browsed in the UI as if they were normal uploads.
-
-We will create a testing delayed-copy for Ubuntu/breezy-autotest.
-
-    # Create a delayed-copy in ubuntu/breezy-autotest.
-    >>> from zope.component import getUtility
-    >>> from lp.registry.interfaces.distribution import IDistributionSet
-    >>> from lp.registry.interfaces.person import IPersonSet
-    >>> from lp.registry.interfaces.pocket import PackagePublishingPocket
-    >>> from lp.soyuz.interfaces.queue import IPackageUploadSet
-    >>> from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
-    >>> login('foo.bar@xxxxxxxxxxxxx')
-    >>> ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
-    >>> cprov = getUtility(IPersonSet).getByName('cprov')
-    >>> cprov_private_ppa = factory.makeArchive(
-    ...     private=True, owner=cprov, distribution=ubuntu,
-    ...     virtualized=False, name="p3a")
-    >>> stp = SoyuzTestPublisher()
-    >>> stp.prepareBreezyAutotest()
-    >>> [bin_hppa, bin_i386] = stp.getPubBinaries(archive=cprov_private_ppa)
-    >>> build = bin_hppa.binarypackagerelease.build
-    >>> breezy_autotest = ubuntu.getSeries('breezy-autotest')
-    >>> stp.addFakeChroots(breezy_autotest)
-    >>> delayed_copy = getUtility(IPackageUploadSet).createDelayedCopy(
-    ...     archive=ubuntu.main_archive, distroseries=breezy_autotest,
-    ...     pocket=PackagePublishingPocket.RELEASE, signing_key=None)
-    >>> unused = delayed_copy.addSource(build.source_package_release)
-    >>> unused = delayed_copy.addBuild(build)
-    >>> transaction.commit()
-    >>> delayed_copy.acceptFromCopy()
-    >>> logout()
-
-Any user accessing the breezy-autotest ACCEPTED queue will notice the
-delayed-copy. They show up in the ACCEPTED distro series queue while
-they are pending processing.
-
-    >>> anon_browser.open(
-    ...     "http://launchpad.dev/ubuntu/breezy-autotest/+queue";)
-    >>> anon_browser.getControl(
-    ...     name="queue_state", index=0).displayValue = ['Accepted']
-    >>> anon_browser.getControl("Update").click()
-
-It's is listed as a normal upload, however there is no link to the
-'changesfile'.
-
-    >>> for row in find_tags_by_class(anon_browser.contents, "queue-row"):
-    ...     print extract_text(row)
-    Package                           Version  Component Section Priority Sets Pocket When
-    foo, foo (delayed) (source, i386) 666      main      base    low      ...
-
-    >>> anon_browser.getLink('foo, foo')
-    Traceback (most recent call last):
-    ...
-    LinkNotFoundError
-
-On the corresponding expandable area, below the row, there is no file
-information, since the delayed-copy is still pending processing. A
-user can simply view where the delayed copy came from.
-
-    >>> print extract_text(
-    ...     first_tag_by_class(anon_browser.contents,
-    ...                        'queue-%s' % delayed_copy.id))
-    Copied from PPA named p3a for Celso Providelo
-
-The delayed-copy source archive is not linked, since the requester has
-no permission to view it.
-
-    >>> anon_browser.getLink('PPA named p3a for Celso Providelo')
-    Traceback (most recent call last):
-    ...
-    LinkNotFoundError
-
-While the delayed-copy is still in ACCEPTED state, i.e not processed,
-authenticated users with permission to view the archive from where the
-delayed-copy was issued can additionally access a link to its original
-archive, nothing else.
-
-    >>> cprov_browser = setupBrowser(
-    ...       auth="Basic celso.providelo@xxxxxxxxxxxxx:test")
-    >>> cprov_browser.open(anon_browser.url)
-
-    >>> for row in find_tags_by_class(cprov_browser.contents, "queue-row"):
-    ...     print extract_text(row)
-    Package                           Version  Component Section Priority Sets Pocket When
-    foo, foo (delayed) (source, i386) 666      main      base    low      ...
-
-    >>> anon_browser.getLink('foo, foo')
-    Traceback (most recent call last):
-    ...
-    LinkNotFoundError
-
-    >>> print extract_text(
-    ...     first_tag_by_class(cprov_browser.contents,
-    ...                        'queue-%s' % delayed_copy.id))
-    Copied from PPA named p3a for Celso Providelo
-
-    >>> print cprov_browser.getLink('PPA named p3a for Celso Providelo').url
-    http://launchpad.dev/~cprov/+archive/p3a
-
-When the delayed-copy is processed (moved to DONE queue) its contents
-become available to everyone.
-
-    # Process the delayed-copy using an external script call.  Since some
-    # DB objects that have no security adapter are modified during the
-    # delayed copy, the modification must be done in Zopeless mode.
-    >>> import os.path
-    >>> from lp.services.config import config
-    >>> from lp.testing.script import run_script
-    >>> script = os.path.join(config.root, "scripts/process-accepted.py")
-    >>> result, stdout, stderr = run_script(script, ["ubuntu"])
-    >>> if result != 0:
-    ...     print stderr
-
-Any user can access the DONE queue and access the delayed-copy
-'changesfile' and view its files in the expandable area.
-
-    >>> anon_browser.getControl(
-    ...     name="queue_state", index=0).displayValue = ['Done']
-    >>> anon_browser.getControl("Update").click()
-
-    >>> print anon_browser.getLink('foo, foo').url
-    http://.../.../foo_666_source.changes
-
-    >>> extra_information = find_tags_by_class(
-    ...     anon_browser.contents, 'queue-%s' % delayed_copy.id)
-    >>> for info in extra_information:
-    ...     print extract_text(info)
-    foo_666.dsc (28 bytes)
-    foo-bin_666_all.deb (18 bytes)   666   main   base   standard
-

=== modified file 'lib/lp/soyuz/templates/distroseries-queue.pt'
--- lib/lp/soyuz/templates/distroseries-queue.pt	2012-03-02 15:59:26 +0000
+++ lib/lp/soyuz/templates/distroseries-queue.pt	2012-11-15 02:05:24 +0000
@@ -220,25 +220,6 @@
     :packageupload: A PackageUpload record for which we display files.
   </tal:comment>
 
-    <tal:copy condition="packageupload/pending_delayed_copy">
-      <tr tal:define="archive
-                      packageupload/sourcepackagerelease/upload_archive">
-        <td />
-        <td tal:condition="view/availableActions" />
-        <td>Copied from
-          <tal:linked condition="archive/required:launchpad.View">
-            <a tal:attributes="href archive/fmt:url"
-               tal:content="archive/displayname" />
-          </tal:linked>
-          <tal:not_linked
-            condition="not: archive/required:launchpad.View"
-            replace="archive/displayname">
-          </tal:not_linked>
-        </td>
-        <td colspan="6" />
-      </tr>
-    </tal:copy>
-
     <tal:sync condition="packageupload/package_copy_job">
       <tr>
         <td />
@@ -256,17 +237,16 @@
       </tr>
     </tal:sync>
 
-    <tal:upload condition="not: packageupload/pending_delayed_copy">
-      <tr tal:repeat="file packageupload/source_files">
-        <td/>
-        <td tal:condition="view/availableActions"/>
-        <td
-          tal:define="libraryfilealias file/libraryfile"
-          tal:condition="libraryfilealias">
-          <metal:file use-macro="template/macros/package-file"/>
-        </td>
-        <td colspan="6"/>
-      </tr>
+    <tr tal:repeat="file packageupload/source_files">
+      <td/>
+      <td tal:condition="view/availableActions"/>
+      <td
+        tal:define="libraryfilealias file/libraryfile"
+        tal:condition="libraryfilealias">
+        <metal:file use-macro="template/macros/package-file"/>
+      </td>
+      <td colspan="6"/>
+    </tr>
 
     <tal:package repeat="package packageupload/binary_packages">
       <tal:define
@@ -312,7 +292,6 @@
         <td colspan="6"/>
       </tr>
     </tal:diffs>
-    </tal:upload>
 
 </metal:macro>
 

=== modified file 'lib/lp/soyuz/tests/test_packageupload.py'
--- lib/lp/soyuz/tests/test_packageupload.py	2012-09-21 12:23:40 +0000
+++ lib/lp/soyuz/tests/test_packageupload.py	2012-11-15 02:05:24 +0000
@@ -4,9 +4,6 @@
 """Test Build features."""
 
 from datetime import timedelta
-from email import message_from_string
-import os
-import shutil
 from urllib2 import (
     HTTPError,
     urlopen,
@@ -26,23 +23,17 @@
 from zope.testbrowser.browser import Browser
 from zope.testbrowser.testing import PublisherMechanizeBrowser
 
-from lp.archivepublisher.interfaces.publisherconfig import IPublisherConfigSet
 from lp.archiveuploader.tests import datadir
-from lp.buildmaster.enums import BuildStatus
-from lp.registry.interfaces.distribution import IDistributionSet
 from lp.registry.interfaces.pocket import PackagePublishingPocket
 from lp.registry.interfaces.series import SeriesStatus
 from lp.services.config import config
 from lp.services.database.lpstorm import IStore
 from lp.services.job.interfaces.job import JobStatus
 from lp.services.librarian.browser import ProxiedLibraryFileAlias
-from lp.services.log.logger import BufferLogger
 from lp.services.mail import stub
 from lp.services.mail.sendmail import format_address_for_person
 from lp.soyuz.adapters.overrides import SourceOverride
 from lp.soyuz.enums import (
-    ArchivePurpose,
-    PackagePublishingStatus,
     PackageUploadCustomFormat,
     PackageUploadStatus,
     )
@@ -65,7 +56,6 @@
     StormStatementRecorder,
     TestCaseWithFactory,
     )
-from lp.testing.dbuser import switch_dbuser
 from lp.testing.layers import (
     LaunchpadFunctionalLayer,
     LaunchpadZopelessLayer,
@@ -85,272 +75,6 @@
         super(PackageUploadTestCase, self).setUp()
         self.test_publisher = SoyuzTestPublisher()
 
-    def createEmptyDelayedCopy(self):
-        ubuntutest = getUtility(IDistributionSet).getByName('ubuntutest')
-        return getUtility(IPackageUploadSet).createDelayedCopy(
-            ubuntutest.main_archive,
-            ubuntutest.getSeries('breezy-autotest'),
-            PackagePublishingPocket.SECURITY,
-            None)
-
-    def test_acceptFromUpload_refuses_delayed_copies(self):
-        # Delayed-copies cannot be accepted via acceptFromUploader.
-        delayed_copy = self.createEmptyDelayedCopy()
-        self.assertRaisesWithContent(
-            AssertionError,
-            'Cannot process delayed copies.',
-            delayed_copy.acceptFromUploader, 'some-path')
-
-    def test_acceptFromQueue_refuses_delayed_copies(self):
-        # Delayed-copies cannot be accepted via acceptFromQueue.
-        delayed_copy = self.createEmptyDelayedCopy()
-        self.assertRaisesWithContent(
-            AssertionError,
-            'Cannot process delayed copies.', delayed_copy.acceptFromQueue)
-
-    def test_acceptFromCopy_refuses_empty_copies(self):
-        # Empty delayed-copies cannot be accepted.
-        delayed_copy = self.createEmptyDelayedCopy()
-        self.assertRaisesWithContent(
-            AssertionError,
-            'Source is mandatory for delayed copies.',
-            delayed_copy.acceptFromCopy)
-
-    def createDelayedCopy(self, source_only=False):
-        """Return a delayed-copy targeted to ubuntutest/breezy-autotest.
-
-        The delayed-copy is targeted to the SECURITY pocket with:
-
-          * source foo - 1.1
-
-        And if 'source_only' is False, the default behavior, also attach:
-
-          * binaries foo - 1.1 in i386 and hppa
-          * a DIST_UPGRADER custom file
-
-        All files are restricted.
-        """
-        self.test_publisher.prepareBreezyAutotest()
-        ppa = self.factory.makeArchive(
-            distribution=self.test_publisher.ubuntutest,
-            purpose=ArchivePurpose.PPA, private=True)
-
-        changesfile_path = (
-            'lib/lp/archiveuploader/tests/data/suite/'
-            'foocomm_1.0-2_binary/foocomm_1.0-2_i386.changes')
-
-        changesfile_content = ''
-        handle = open(changesfile_path, 'r')
-        try:
-            changesfile_content = handle.read()
-        finally:
-            handle.close()
-
-        source = self.test_publisher.getPubSource(
-            sourcename='foocomm', archive=ppa, version='1.0-2',
-            changes_file_content=changesfile_content)
-        delayed_copy = getUtility(IPackageUploadSet).createDelayedCopy(
-            self.test_publisher.ubuntutest.main_archive,
-            self.test_publisher.breezy_autotest,
-            PackagePublishingPocket.SECURITY,
-            self.test_publisher.person.gpg_keys[0])
-
-        delayed_copy.addSource(source.sourcepackagerelease)
-
-        announce_list = delayed_copy.distroseries.changeslist
-        if announce_list is None or len(announce_list.strip()) == 0:
-            announce_list = ('%s-changes@xxxxxxxxxxxxxxxx' %
-                             delayed_copy.distroseries.name)
-            delayed_copy.distroseries.changeslist = announce_list
-
-        if not source_only:
-            self.test_publisher.getPubBinaries(pub_source=source)
-            custom_path = datadir(
-                'dist-upgrader/dist-upgrader_20060302.0120_all.tar.gz')
-            custom_file = self.factory.makeLibraryFileAlias(
-                filename='dist-upgrader_20060302.0120_all.tar.gz',
-                content=open(custom_path).read(), restricted=True)
-            [build] = source.getBuilds()
-            build.package_upload.addCustom(
-                custom_file, PackageUploadCustomFormat.DIST_UPGRADER)
-            for build in source.getBuilds():
-                delayed_copy.addBuild(build)
-                for custom in build.package_upload.customfiles:
-                    delayed_copy.addCustom(
-                        custom.libraryfilealias, custom.customformat)
-
-        # Commit for using just-created library files.
-        self.layer.txn.commit()
-
-        return delayed_copy
-
-    def checkDelayedCopyPubRecord(self, pub_record, archive, pocket,
-                                  component, restricted):
-        """Ensure the given publication are in the expected state.
-
-        It should be a PENDING publication to the specified context and
-        its files should match the specifed privacy.
-        """
-        self.assertEquals(PackagePublishingStatus.PENDING, pub_record.status)
-        self.assertEquals(archive, pub_record.archive)
-        self.assertEquals(pocket, pub_record.pocket)
-        self.assertEquals(component, pub_record.component)
-        for pub_file in pub_record.files:
-            self.assertEqual(
-                restricted, pub_file.libraryfilealias.restricted)
-
-    def removeRepository(self, distro):
-        """Remove the testing repository root if it exists."""
-        root = getUtility(
-            IPublisherConfigSet).getByDistribution(distro).root_dir
-        if os.path.exists(root):
-            shutil.rmtree(root)
-
-    def test_realiseUpload_for_delayed_copies(self):
-        # Delayed-copies result in published records that were overridden
-        # and has their files privacy adjusted according test destination
-        # context.
-
-        # Create the default delayed-copy context.
-        delayed_copy = self.createDelayedCopy()
-
-        # Add a cleanup for removing the repository where the custom upload
-        # was published.
-        self.addCleanup(
-            self.removeRepository,
-            self.test_publisher.breezy_autotest.distribution)
-
-        # Delayed-copies targeted to unreleased pockets cannot be accepted.
-        self.assertRaisesWithContent(
-            AssertionError,
-            "Not permitted acceptance in the SECURITY pocket in a series "
-            "in the 'EXPERIMENTAL' state.",
-            delayed_copy.acceptFromCopy)
-
-        # Release ubuntutest/breezy-autotest, so delayed-copies to
-        # SECURITY pocket can be accepted.
-        self.test_publisher.breezy_autotest.status = (
-            SeriesStatus.CURRENT)
-
-        # Create an ancestry publication in 'multiverse'.
-        ancestry_source = self.test_publisher.getPubSource(
-            sourcename='foocomm', version='1.0', component='multiverse',
-            status=PackagePublishingStatus.PUBLISHED)
-        self.test_publisher.getPubBinaries(
-            pub_source=ancestry_source,
-            status=PackagePublishingStatus.PUBLISHED)
-        package_diff = ancestry_source.sourcepackagerelease.requestDiffTo(
-            requester=self.test_publisher.person,
-            to_sourcepackagerelease=delayed_copy.sourcepackagerelease)
-        package_diff.diff_content = self.factory.makeLibraryFileAlias(
-            restricted=True)
-
-        # Accept and publish the delayed-copy.
-        delayed_copy.acceptFromCopy()
-        self.assertEquals(
-            PackageUploadStatus.ACCEPTED, delayed_copy.status)
-
-        # Make sure no announcement email was sent at this point.
-        self.assertEquals(len(stub.test_emails), 0)
-
-        switch_dbuser(self.dbuser)
-
-        logger = BufferLogger()
-        # realiseUpload() assumes a umask of 022, which is normally true in
-        # production.  The user's environment might have a different umask, so
-        # just force it to what the test expects.
-        old_umask = os.umask(022)
-
-        try:
-            pub_records = delayed_copy.realiseUpload(logger=logger)
-        finally:
-            os.umask(old_umask)
-        self.assertEquals(
-            PackageUploadStatus.DONE, delayed_copy.status)
-
-        self.layer.txn.commit()
-
-        # Check the announcement email.
-        from_addr, to_addrs, raw_msg = stub.test_emails.pop()
-        msg = message_from_string(raw_msg)
-        body = msg.get_payload(0)
-        body = body.get_payload(decode=True)
-
-        self.assertEquals(
-            str(to_addrs), "['breezy-autotest-changes@xxxxxxxxxxxxxxxx']")
-
-        self.assertEquals('[ubuntutest/breezy-autotest-security]\n '
-            'dist-upgrader_20060302.0120_all.tar.gz, foocomm 1.0-2 (Accepted)',
-            msg['Subject'].replace('\n\t', '\n '))
-
-        self.assertEquals(body,
-            'foocomm (1.0-2) breezy; urgency=low\n\n'
-            '  * Initial version\n\n'
-            'Date: Thu, 16 Feb 2006 15:34:09 +0000\n'
-            'Changed-By: Foo Bar <foo.bar@xxxxxxxxxxxxx>\n'
-            'Maintainer: Launchpad team <launchpad@xxxxxxxxxxxxxxxxxxx>\n'
-            'http://launchpad.dev/ubuntutest/breezy-autotest/+source/'
-            'foocomm/1.0-2\n')
-
-        switch_dbuser('launchpad')
-
-        # One source and 2 binaries are pending publication. They all were
-        # overridden to multiverse and had their files moved to the public
-        # librarian.
-        self.assertEquals(3, len(pub_records))
-        self.assertEquals(
-            set([
-                u'foocomm 1.0-2 in breezy-autotest',
-                u'foo-bin 1.0-2 in breezy-autotest hppa',
-                u'foo-bin 1.0-2 in breezy-autotest i386']),
-            set([pub.displayname for pub in pub_records]))
-
-        for pub_record in pub_records:
-            self.checkDelayedCopyPubRecord(
-                pub_record, delayed_copy.archive, delayed_copy.pocket,
-                ancestry_source.component, False)
-
-        # The package diff file is now public.
-        self.assertFalse(package_diff.diff_content.restricted)
-
-        # The custom file was also published.
-        root_dir = getUtility(IPublisherConfigSet).getByDistribution(
-            self.test_publisher.breezy_autotest.distribution).root_dir
-        custom_path = os.path.join(
-            root_dir,
-            'ubuntutest/dists/breezy-autotest-security',
-            'main/dist-upgrader-all')
-        self.assertEquals(
-            ['20060302.0120', 'current'], sorted(os.listdir(custom_path)))
-
-        # The custom files were also copied to the public librarian
-        for customfile in delayed_copy.customfiles:
-            self.assertFalse(customfile.libraryfilealias.restricted)
-
-    def test_realiseUpload_for_source_only_delayed_copies(self):
-        # Source-only delayed-copies results in the source published
-        # in the destination archive and its corresponding build
-        # recors ready to be dispatched.
-
-        # Create the default delayed-copy context.
-        delayed_copy = self.createDelayedCopy(source_only=True)
-        self.test_publisher.breezy_autotest.status = (
-            SeriesStatus.CURRENT)
-        self.layer.txn.commit()
-
-        # Accept and publish the delayed-copy.
-        delayed_copy.acceptFromCopy()
-        logger = BufferLogger()
-        pub_records = delayed_copy.realiseUpload(logger=logger)
-
-        # Only the source is published and the needed builds are created
-        # in the destination archive.
-        self.assertEquals(1, len(pub_records))
-        [pub_record] = pub_records
-        [build] = pub_record.getBuilds()
-        self.assertEquals(
-            BuildStatus.NEEDSBUILD, build.status)
-
     def test_realiseUpload_for_overridden_component_archive(self):
         # If the component of an upload is overridden to 'Partner' for
         # example, then the new publishing record should be for the


Follow ups