~launchpad-pqm/launchpad/devel

13007.1.2 by Jeroen Vermeulen
Tests passing.
1
# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
8687.15.17 by Karl Fogel
Add the copyright header block to the rest of the files under lib/lp/.
2
# GNU Affero General Public License version 3 (see the file LICENSE).
3
6455.2.1 by Celso Providelo
Moving PackageCopier & UnembargoSecurityPackage script classes out of ftpmaster.py file.
4
"""PackageCopier utilities."""
5
6
__metaclass__ = type
7
8
__all__ = [
9
    'PackageCopier',
10
    'UnembargoSecurityPackage',
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
11
    'CopyChecker',
13007.1.2 by Jeroen Vermeulen
Tests passing.
12
    'check_copy_permissions',
6455.2.2 by Celso Providelo
moving the auxiliary copy-methos to scripts/packagecopier.py.
13
    'do_copy',
7675.235.5 by Celso Providelo
applying review comments, r=abentley.
14
    '_do_delayed_copy',
15
    '_do_direct_copy',
8589.3.4 by Celso Providelo
name extracted functions appropriately.
16
    're_upload_file',
17
    'update_files_privacy',
6455.2.1 by Celso Providelo
Moving PackageCopier & UnembargoSecurityPackage script classes out of ftpmaster.py file.
18
    ]
19
20
import os
21
import tempfile
22
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
23
import apt_pkg
7675.575.1 by William Grant
Move lp.soyuz.interfaces.build.BuildStatus to lp.buildmaster.interfaces.buildbase. Sort various imports along the way.
24
from lazr.delegates import delegates
6455.2.1 by Celso Providelo
Moving PackageCopier & UnembargoSecurityPackage script classes out of ftpmaster.py file.
25
from zope.component import getUtility
26
8426.3.4 by Celso Providelo
Another importing order issue.
27
from canonical.launchpad.interfaces.librarian import ILibraryFileAliasSet
28
from canonical.librarian.utils import copy_and_close
12177.12.5 by William Grant
do_delayed_copy no longer copies builds without a corresponding enabled architecture in the target series.
29
from lp.app.errors import NotFoundError
11458.1.1 by Jelmer Vernooij
Move enums of buildmaster.
30
from lp.buildmaster.enums import BuildStatus
14168.3.9 by Jeroen Vermeulen
Format imports.
31
from lp.soyuz.adapters.notification import notify
7675.575.1 by William Grant
Move lp.soyuz.interfaces.build.BuildStatus to lp.buildmaster.interfaces.buildbase. Sort various imports along the way.
32
from lp.soyuz.adapters.packagelocation import build_package_location
12981.1.2 by Raphael Badin
Roll back 12977.
33
from lp.soyuz.enums import (
34
    ArchivePurpose,
14191.2.3 by Julian Edwards
Prevent copying of DDEBs into primary archives.
35
    BinaryPackageFileType,
12981.1.2 by Raphael Badin
Roll back 12977.
36
    SourcePackageFormat,
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
37
    )
12981.1.2 by Raphael Badin
Roll back 12977.
38
from lp.soyuz.interfaces.archive import CannotCopy
10667.2.2 by Michael Nelson
Mass renaming of imports and references to IBuild/Build/IBuildSet
39
from lp.soyuz.interfaces.binarypackagebuild import BuildSetStatus
8294.6.1 by Julian Edwards
First stab at code-reorg. Still got a discrepancy on stuff I assigned to registry but not migrated yet.
40
from lp.soyuz.interfaces.publishing import (
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
41
    active_publishing_status,
42
    IBinaryPackagePublishingHistory,
43
    IPublishingSet,
44
    ISourcePackagePublishingHistory,
45
    )
10549.1.1 by Steve Kowalik
Also copy custom files from the restricted librarian when doing a delayed copy
46
from lp.soyuz.interfaces.queue import (
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
47
    IPackageUpload,
48
    IPackageUploadCustom,
49
    IPackageUploadSet,
50
    )
51
from lp.soyuz.scripts.ftpmasterbase import (
52
    SoyuzScript,
53
    SoyuzScriptError,
54
    )
7675.575.1 by William Grant
Move lp.soyuz.interfaces.build.BuildStatus to lp.buildmaster.interfaces.buildbase. Sort various imports along the way.
55
from lp.soyuz.scripts.processaccepted import close_bugs_for_sourcepublication
6455.2.1 by Celso Providelo
Moving PackageCopier & UnembargoSecurityPackage script classes out of ftpmaster.py file.
56
14027.3.1 by Jeroen Vermeulen
Fix lots of lint in recently-changed files.
57
8589.3.4 by Celso Providelo
name extracted functions appropriately.
58
def re_upload_file(libraryfile, restricted=False):
8589.3.3 by Celso Providelo
Extracting and testing unembaroging base procedures.
59
    """Re-upload a librarian file to the public server.
60
61
    :param libraryfile: a `LibraryFileAlias`.
8589.3.5 by Celso Providelo
applying review comments, r=gmb.
62
    :param restricted: whether or not the new file should be restricted.
8589.3.3 by Celso Providelo
Extracting and testing unembaroging base procedures.
63
8589.3.5 by Celso Providelo
applying review comments, r=gmb.
64
    :return: A new `LibraryFileAlias`.
8589.3.1 by Celso Providelo
Make the functions used for delayed-copies standalone and ensure the tests pass.
65
    """
14027.3.1 by Jeroen Vermeulen
Fix lots of lint in recently-changed files.
66
    # XXX cprov 2009-06-12: This function could be incorporated in ILFA.
67
    # I just don't see a clear benefit in doing that right now.
68
8589.3.3 by Celso Providelo
Extracting and testing unembaroging base procedures.
69
    # Open the the libraryfile for reading.
70
    libraryfile.open()
8589.3.1 by Celso Providelo
Make the functions used for delayed-copies standalone and ensure the tests pass.
71
72
    # Make a temporary file to hold the download.  It's annoying
73
    # having to download to a temp file but there are no guarantees
74
    # how large the files are, so using StringIO would be dangerous.
75
    fd, filepath = tempfile.mkstemp()
9209.5.1 by Celso Providelo
Fixing opened-file leak when processing delayed-copies.
76
    temp_file = os.fdopen(fd, 'wb')
8589.3.1 by Celso Providelo
Make the functions used for delayed-copies standalone and ensure the tests pass.
77
78
    # Read the old library file into the temp file.
8589.3.3 by Celso Providelo
Extracting and testing unembaroging base procedures.
79
    copy_and_close(libraryfile, temp_file)
8589.3.1 by Celso Providelo
Make the functions used for delayed-copies standalone and ensure the tests pass.
80
81
    # Upload the file to the unrestricted librarian and make
82
    # sure the publishing record points to it.
8589.3.3 by Celso Providelo
Extracting and testing unembaroging base procedures.
83
    new_lfa = getUtility(ILibraryFileAliasSet).create(
84
        libraryfile.filename, libraryfile.content.filesize,
85
        open(filepath, "rb"), libraryfile.mimetype, restricted=restricted)
8589.3.1 by Celso Providelo
Make the functions used for delayed-copies standalone and ensure the tests pass.
86
87
    # Junk the temporary file.
88
    os.remove(filepath)
89
90
    return new_lfa
91
13007.1.2 by Jeroen Vermeulen
Tests passing.
92
7675.249.1 by Celso Providelo
Integrating delayed-copies and other minor tweaks (db permissions and build creation for source-only delayed copies). All copy methods (web UI, API and 'copy-package' script) will use delayed-copies instead of direct-copies when file privacy mismatch is detected. 'unembargo-package' continues to work with direct-copies and fixing privacy mismatch in place.
93
# XXX cprov 2009-06-12: this function should be incorporated in
94
# IPublishing.
8589.3.4 by Celso Providelo
name extracted functions appropriately.
95
def update_files_privacy(pub_record):
10549.1.1 by Steve Kowalik
Also copy custom files from the restricted librarian when doing a delayed copy
96
    """Update file privacy according the publishing destination
8589.3.1 by Celso Providelo
Make the functions used for delayed-copies standalone and ensure the tests pass.
97
98
    :param pub_record: One of a SourcePackagePublishingHistory or
99
        BinaryPackagePublishingHistory record.
8589.3.3 by Celso Providelo
Extracting and testing unembaroging base procedures.
100
101
    :return: a list of re-uploaded `LibraryFileAlias` objects.
8589.3.1 by Celso Providelo
Make the functions used for delayed-copies standalone and ensure the tests pass.
102
    """
8589.3.3 by Celso Providelo
Extracting and testing unembaroging base procedures.
103
    package_files = []
10549.1.1 by Steve Kowalik
Also copy custom files from the restricted librarian when doing a delayed copy
104
    archive = None
8589.3.1 by Celso Providelo
Make the functions used for delayed-copies standalone and ensure the tests pass.
105
    if ISourcePackagePublishingHistory.providedBy(pub_record):
10549.1.1 by Steve Kowalik
Also copy custom files from the restricted librarian when doing a delayed copy
106
        archive = pub_record.archive
8589.3.3 by Celso Providelo
Extracting and testing unembaroging base procedures.
107
        # Re-upload the package files files if necessary.
8589.3.1 by Celso Providelo
Make the functions used for delayed-copies standalone and ensure the tests pass.
108
        sourcepackagerelease = pub_record.sourcepackagerelease
8589.3.3 by Celso Providelo
Extracting and testing unembaroging base procedures.
109
        package_files.extend(
110
            [(source_file, 'libraryfile')
111
             for source_file in sourcepackagerelease.files])
112
        # Re-upload the package diff files if necessary.
113
        package_files.extend(
114
            [(diff, 'diff_content')
115
             for diff in sourcepackagerelease.package_diffs])
8589.3.1 by Celso Providelo
Make the functions used for delayed-copies standalone and ensure the tests pass.
116
        # Re-upload the source upload changesfile if necessary.
117
        package_upload = sourcepackagerelease.package_upload
8589.3.3 by Celso Providelo
Extracting and testing unembaroging base procedures.
118
        package_files.append((package_upload, 'changesfile'))
12792.3.2 by Julian Edwards
Add fix
119
        package_files.append((sourcepackagerelease, 'changelog'))
8589.3.1 by Celso Providelo
Make the functions used for delayed-copies standalone and ensure the tests pass.
120
    elif IBinaryPackagePublishingHistory.providedBy(pub_record):
10549.1.1 by Steve Kowalik
Also copy custom files from the restricted librarian when doing a delayed copy
121
        archive = pub_record.archive
8589.3.3 by Celso Providelo
Extracting and testing unembaroging base procedures.
122
        # Re-upload the binary files if necessary.
123
        binarypackagerelease = pub_record.binarypackagerelease
124
        package_files.extend(
125
            [(binary_file, 'libraryfile')
126
             for binary_file in binarypackagerelease.files])
127
        # Re-upload the upload changesfile file as necessary.
128
        build = binarypackagerelease.build
8589.3.1 by Celso Providelo
Make the functions used for delayed-copies standalone and ensure the tests pass.
129
        package_upload = build.package_upload
8589.3.3 by Celso Providelo
Extracting and testing unembaroging base procedures.
130
        package_files.append((package_upload, 'changesfile'))
8589.3.1 by Celso Providelo
Make the functions used for delayed-copies standalone and ensure the tests pass.
131
        # Re-upload the buildlog file as necessary.
7675.687.131 by Michael Nelson
test_copypackage
132
        package_files.append((build, 'log'))
10549.1.1 by Steve Kowalik
Also copy custom files from the restricted librarian when doing a delayed copy
133
    elif IPackageUploadCustom.providedBy(pub_record):
134
        # Re-upload the custom files included
135
        package_files.append((pub_record, 'libraryfilealias'))
136
        # And set archive to the right attribute for PUCs
137
        archive = pub_record.packageupload.archive
8589.3.1 by Celso Providelo
Make the functions used for delayed-copies standalone and ensure the tests pass.
138
    else:
139
        raise AssertionError(
10549.1.1 by Steve Kowalik
Also copy custom files from the restricted librarian when doing a delayed copy
140
            "pub_record is not one of SourcePackagePublishingHistory, "
141
            "BinaryPackagePublishingHistory or PackageUploadCustom.")
8589.3.1 by Celso Providelo
Make the functions used for delayed-copies standalone and ensure the tests pass.
142
8589.3.3 by Celso Providelo
Extracting and testing unembaroging base procedures.
143
    re_uploaded_files = []
144
    for obj, attr_name in package_files:
145
        old_lfa = getattr(obj, attr_name, None)
146
        # Only reupload restricted files published in public archives,
147
        # not the opposite. We don't have a use-case for privatizing
148
        # files yet.
149
        if (old_lfa is None or
10549.1.1 by Steve Kowalik
Also copy custom files from the restricted librarian when doing a delayed copy
150
            old_lfa.restricted == archive.private or
8589.3.3 by Celso Providelo
Extracting and testing unembaroging base procedures.
151
            old_lfa.restricted == False):
8589.3.1 by Celso Providelo
Make the functions used for delayed-copies standalone and ensure the tests pass.
152
            continue
8589.3.4 by Celso Providelo
name extracted functions appropriately.
153
        new_lfa = re_upload_file(
10549.1.1 by Steve Kowalik
Also copy custom files from the restricted librarian when doing a delayed copy
154
            old_lfa, restricted=archive.private)
8589.3.3 by Celso Providelo
Extracting and testing unembaroging base procedures.
155
        setattr(obj, attr_name, new_lfa)
156
        re_uploaded_files.append(new_lfa)
157
158
    return re_uploaded_files
159
160
7675.249.1 by Celso Providelo
Integrating delayed-copies and other minor tweaks (db permissions and build creation for source-only delayed copies). All copy methods (web UI, API and 'copy-package' script) will use delayed-copies instead of direct-copies when file privacy mismatch is detected. 'unembargo-package' continues to work with direct-copies and fixing privacy mismatch in place.
161
# XXX cprov 2009-07-01: should be part of `ISourcePackagePublishingHistory`.
162
def has_restricted_files(source):
163
    """Whether or not a given source files has restricted files."""
164
    for source_file in source.sourcepackagerelease.files:
165
        if source_file.libraryfile.restricted:
166
            return True
167
168
    for binary in source.getBuiltBinaries():
169
        for binary_file in binary.binarypackagerelease.files:
170
            if binary_file.libraryfile.restricted:
171
                return True
172
173
    return False
174
175
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
176
class CheckedCopy:
177
    """Representation of a copy that was checked and approved.
178
179
    Decorates `ISourcePackagePublishingHistory`, tweaking
180
    `getStatusSummaryForBuilds` to return `BuildSetStatus.NEEDSBUILD`
181
    for source-only copies.
7675.249.1 by Celso Providelo
Integrating delayed-copies and other minor tweaks (db permissions and build creation for source-only delayed copies). All copy methods (web UI, API and 'copy-package' script) will use delayed-copies instead of direct-copies when file privacy mismatch is detected. 'unembargo-package' continues to work with direct-copies and fixing privacy mismatch in place.
182
183
    It also store the 'delayed' boolean, which controls the way this source
184
    should be copied to the destionation archive (see `_do_delayed_copy` and
185
    `_do_direct_copy`)
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
186
    """
187
    delegates(ISourcePackagePublishingHistory)
188
7675.249.1 by Celso Providelo
Integrating delayed-copies and other minor tweaks (db permissions and build creation for source-only delayed copies). All copy methods (web UI, API and 'copy-package' script) will use delayed-copies instead of direct-copies when file privacy mismatch is detected. 'unembargo-package' continues to work with direct-copies and fixing privacy mismatch in place.
189
    def __init__(self, context, include_binaries, delayed):
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
190
        self.context = context
191
        self.include_binaries = include_binaries
7675.249.1 by Celso Providelo
Integrating delayed-copies and other minor tweaks (db permissions and build creation for source-only delayed copies). All copy methods (web UI, API and 'copy-package' script) will use delayed-copies instead of direct-copies when file privacy mismatch is detected. 'unembargo-package' continues to work with direct-copies and fixing privacy mismatch in place.
192
        self.delayed = delayed
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
193
194
    def getStatusSummaryForBuilds(self):
195
        """Always `BuildSetStatus.NEEDSBUILD` for source-only copies."""
196
        if self.include_binaries:
7675.249.1 by Celso Providelo
Integrating delayed-copies and other minor tweaks (db permissions and build creation for source-only delayed copies). All copy methods (web UI, API and 'copy-package' script) will use delayed-copies instead of direct-copies when file privacy mismatch is detected. 'unembargo-package' continues to work with direct-copies and fixing privacy mismatch in place.
197
            return self.context.getStatusSummaryForBuilds()
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
198
        else:
199
            return {'status': BuildSetStatus.NEEDSBUILD}
200
201
13007.1.2 by Jeroen Vermeulen
Tests passing.
202
def check_copy_permissions(person, archive, series, pocket,
13007.1.6 by Jeroen Vermeulen
Check permissions for all packages at once, to accommodate planned optimizations.
203
                           sourcepackagenames):
13007.1.2 by Jeroen Vermeulen
Tests passing.
204
    """Check that `person` has permission to copy a package.
205
206
    :param person: User attempting the upload.
207
    :param archive: Destination `Archive`.
208
    :param series: Destination `DistroSeries`.
209
    :param pocket: Destination `Pocket`.
13007.1.6 by Jeroen Vermeulen
Check permissions for all packages at once, to accommodate planned optimizations.
210
    :param sourcepackagenames: Sequence of `SourcePackageName`s for the
211
        packages to be copied.
13007.1.2 by Jeroen Vermeulen
Tests passing.
212
    :raises CannotCopy: If the copy is not allowed.
213
    """
214
    if person is None:
215
        raise CannotCopy("Cannot check copy permissions (no requester).")
216
217
    # If there is a requester, check that he has upload permission into
218
    # the destination (archive, component, pocket). This check is done
219
    # here rather than in the security adapter because it requires more
220
    # info than is available in the security adapter.
13007.1.6 by Jeroen Vermeulen
Check permissions for all packages at once, to accommodate planned optimizations.
221
    for spn in set(sourcepackagenames):
222
        package = series.getSourcePackage(spn)
223
        destination_component = package.latest_published_component
224
225
        # If destination_component is not None, make sure the person
226
        # has upload permission for this component.  Otherwise, any
227
        # upload permission on this archive will do.
228
        strict_component = destination_component is not None
229
        reason = archive.checkUpload(
230
            person, series, spn, destination_component, pocket,
231
            strict_component=strict_component)
232
233
        if reason is not None:
234
            raise CannotCopy(reason)
13007.1.2 by Jeroen Vermeulen
Tests passing.
235
236
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
237
class CopyChecker:
238
    """Check copy candiates.
239
240
    Allows the checker function to identify conflicting copy candidates
241
    within the copying batch.
242
    """
13168.12.23 by Raphael Badin
Refactor initialization to use the packagecopier if the destination archive is not empty.
243
    def __init__(self, archive, include_binaries, allow_delayed_copies=True,
244
                 strict_binaries=True):
13168.12.30 by Raphael Badin
Add doc tests.
245
        """Initialize a copy checker.
246
247
        :param archive: the target `IArchive`.
248
        :param include_binaries: controls whether or not the published
249
            binaries for each given source should be also copied along
250
            with the source.
251
        :param allow_delayed_copies: boolean indicating whether or not private
252
            sources can be copied to public archives using delayed_copies.
13168.12.32 by Raphael Badin
Apply MP's comments.
253
        :param strict_binaries: If 'include_binaries' is True then setting
254
            this to True will make the copy fail if binaries cannot be also
255
            copied.
13168.12.30 by Raphael Badin
Add doc tests.
256
        """
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
257
        self.archive = archive
258
        self.include_binaries = include_binaries
13168.12.23 by Raphael Badin
Refactor initialization to use the packagecopier if the destination archive is not empty.
259
        self.strict_binaries = strict_binaries
7675.249.1 by Celso Providelo
Integrating delayed-copies and other minor tweaks (db permissions and build creation for source-only delayed copies). All copy methods (web UI, API and 'copy-package' script) will use delayed-copies instead of direct-copies when file privacy mismatch is detected. 'unembargo-package' continues to work with direct-copies and fixing privacy mismatch in place.
260
        self.allow_delayed_copies = allow_delayed_copies
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
261
        self._inventory = {}
262
263
    def _getInventoryKey(self, candidate):
264
        """Return a key representing the copy candidate in the inventory.
265
266
        :param candidate: a `ISourcePackagePublishingHistory` copy candidate.
267
        :return: a tuple with the source (name, version) strings.
268
        """
269
        return (
270
            candidate.source_package_name, candidate.source_package_version)
271
7675.249.1 by Celso Providelo
Integrating delayed-copies and other minor tweaks (db permissions and build creation for source-only delayed copies). All copy methods (web UI, API and 'copy-package' script) will use delayed-copies instead of direct-copies when file privacy mismatch is detected. 'unembargo-package' continues to work with direct-copies and fixing privacy mismatch in place.
272
    def addCopy(self, source, delayed):
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
273
        """Story a copy in the inventory as a `CheckedCopy` instance."""
274
        inventory_key = self._getInventoryKey(source)
7675.249.1 by Celso Providelo
Integrating delayed-copies and other minor tweaks (db permissions and build creation for source-only delayed copies). All copy methods (web UI, API and 'copy-package' script) will use delayed-copies instead of direct-copies when file privacy mismatch is detected. 'unembargo-package' continues to work with direct-copies and fixing privacy mismatch in place.
275
        checked_copy = CheckedCopy(source, self.include_binaries, delayed)
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
276
        candidates = self._inventory.setdefault(inventory_key, [])
7675.249.1 by Celso Providelo
Integrating delayed-copies and other minor tweaks (db permissions and build creation for source-only delayed copies). All copy methods (web UI, API and 'copy-package' script) will use delayed-copies instead of direct-copies when file privacy mismatch is detected. 'unembargo-package' continues to work with direct-copies and fixing privacy mismatch in place.
277
        candidates.append(checked_copy)
278
279
    def getCheckedCopies(self):
280
        """Return a list of copies allowed to be performed."""
281
        for copies in self._inventory.values():
282
            for copy in copies:
283
                yield copy
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
284
285
    def getConflicts(self, candidate):
286
        """Conflicting `CheckedCopy` objects in the inventory.
287
288
        :param candidate: a `ISourcePackagePublishingHistory` copy candidate.
289
        :return: a list of conflicting copies in the inventory, in case
290
            of non-conflicting candidates an empty list is returned.
291
        """
292
        inventory_key = self._getInventoryKey(candidate)
293
        return self._inventory.get(inventory_key, [])
294
295
    def _checkArchiveConflicts(self, source, series):
296
        """Check for possible conflicts in the destination archive.
297
298
        Check if there is a source with the same name and version published
299
        in the destination archive or in the inventory of copies already
300
        approved. If it exists (regardless of the series and pocket) and
301
        it has built or will build binaries, do not allow the copy without
302
        binaries.
303
304
        This is because the copied source will rebuild binaries that
305
        conflict with existing ones.
306
307
        Even when the binaries are included, they are checked for conflict.
308
309
        :param source: copy candidate, `ISourcePackagePublishingHistory`.
310
        :param series: destination `IDistroSeries`.
311
312
        :raise CannotCopy: when a copy is not allowed to be performed
313
            containing the reason of the error.
314
        """
315
        destination_archive_conflicts = self.archive.getPublishedSources(
316
            name=source.sourcepackagerelease.name,
317
            version=source.sourcepackagerelease.version,
318
            exact_match=True)
319
320
        inventory_conflicts = self.getConflicts(source)
321
10827.6.7 by Steve Kowalik
* Correct some thinkos in the interface docstring.
322
        # If there are no conflicts with the same version, we can skip the
323
        # rest of the checks, but we still want to check conflicting files
12505.4.1 by Robert Collins
Hopefully fix bug 727560 by permitting a much better query plan for folk querying the primary archive.
324
        if (destination_archive_conflicts.is_empty() and
7675.677.1 by Steve Kowalik
Merge from lp:~stevenk/launchpad/more-copypackage-fixes branch. This fixes three issues with copying packages.
325
            len(inventory_conflicts) == 0):
326
            self._checkConflictingFiles(source)
327
            return
328
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
329
        # Cache the conflicting publications because they will be iterated
330
        # more than once.
331
        destination_archive_conflicts = list(destination_archive_conflicts)
332
        destination_archive_conflicts.extend(inventory_conflicts)
333
334
        # Identify published binaries and incomplete builds or unpublished
335
        # binaries from archive conflicts. Either will deny source-only
336
        # copies, since a rebuild will result in binaries that cannot be
337
        # published in the archive because they will conflict with the
338
        # existent ones.
339
        published_binaries = set()
340
        for candidate in destination_archive_conflicts:
341
            # If the candidate refers to a different sourcepackagerelease
342
            # with the same name and version there is a high chance that
343
            # they have conflicting files that cannot be published in the
344
            # repository pool. So, we deny the copy until the existing
345
            # source gets deleted (and removed from the archive).
346
            if (source.sourcepackagerelease.id !=
347
                candidate.sourcepackagerelease.id):
348
                raise CannotCopy(
349
                    'a different source with the same version is published '
350
                    'in the destination archive')
351
352
            # If the conflicting candidate (which we already know refer to
353
            # the same sourcepackagerelease) was found in the copy
354
            # destination series we don't have to check its building status
355
            # if binaries are included. It's not going to change in terms of
356
            # new builds and the resulting binaries will match. See more
357
            # details in `ISourcePackageRelease.getBuildsByArch`.
358
            if (candidate.distroseries.id == series.id and
359
                self.archive.id == source.archive.id and
360
                self.include_binaries):
361
                continue
362
363
            # Conflicting candidates pending build or building in a different
364
            # series are a blocker for the copy. The copied source will
365
            # certainly produce conflicting binaries.
366
            build_summary = candidate.getStatusSummaryForBuilds()
367
            building_states = (
368
                BuildSetStatus.NEEDSBUILD,
369
                BuildSetStatus.BUILDING,
370
                )
371
            if build_summary['status'] in building_states:
372
                raise CannotCopy(
373
                    "same version already building in the destination "
374
                    "archive for %s" % candidate.distroseries.displayname)
375
376
            # If the set of built binaries does not match the set of published
377
            # ones the copy should be denied and the user should wait for the
378
            # next publishing cycle to happen before copying the package.
379
            # The copy is only allowed when all built binaries are published,
380
            # this way there is no chance of a conflict.
381
            if build_summary['status'] == BuildSetStatus.FULLYBUILT_PENDING:
382
                raise CannotCopy(
383
                    "same version has unpublished binaries in the "
384
                    "destination archive for %s, please wait for them to be "
385
                    "published before copying" %
386
                    candidate.distroseries.displayname)
387
388
            # Update published binaries inventory for the conflicting
389
            # candidates.
390
            archive_binaries = set(
391
                pub_binary.binarypackagerelease.id
392
                for pub_binary in candidate.getBuiltBinaries())
393
            published_binaries.update(archive_binaries)
394
395
        if not self.include_binaries:
396
            if len(published_binaries) > 0:
397
                raise CannotCopy(
398
                    "same version already has published binaries in the "
399
                    "destination archive")
400
        else:
401
            # Since DEB files are compressed with 'ar' (encoding the creation
402
            # timestamp) and serially built by our infrastructure, it's
403
            # correct to assume that the set of BinaryPackageReleases being
404
            # copied can only be a superset of the set of
405
            # BinaryPackageReleases published in the destination archive.
406
            copied_binaries = set(
407
                pub.binarypackagerelease.id
408
                for pub in source.getBuiltBinaries())
409
            if not copied_binaries.issuperset(published_binaries):
410
                raise CannotCopy(
411
                    "binaries conflicting with the existing ones")
7675.687.131 by Michael Nelson
test_copypackage
412
        self._checkConflictingFiles(source)
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
413
7675.677.1 by Steve Kowalik
Merge from lp:~stevenk/launchpad/more-copypackage-fixes branch. This fixes three issues with copying packages.
414
    def _checkConflictingFiles(self, source):
415
        # If both the source and destination archive are the same, we don't
416
        # need to perform this test, since that guarantees the filenames
417
        # do not conflict.
418
        if source.archive.id == self.archive.id:
419
            return None
10827.6.5 by Steve Kowalik
* Fix IArchive.getFilesAndSha1s() to take a list of source files, rather than
420
        source_files = [
7675.687.131 by Michael Nelson
test_copypackage
421
            sprf.libraryfile.filename for sprf in
10827.6.5 by Steve Kowalik
* Fix IArchive.getFilesAndSha1s() to take a list of source files, rather than
422
            source.sourcepackagerelease.files]
423
        destination_sha1s = self.archive.getFilesAndSha1s(source_files)
10652.3.2 by Steve Kowalik
Change some variable names, from a suggestion from noodles
424
        for lf in source.sourcepackagerelease.files:
10827.6.4 by Steve Kowalik
* Write IArchive.getFilesAndSha1s() that returns the filenames and sha1s for
425
            if lf.libraryfile.filename in destination_sha1s:
10827.2.1 by Steve Kowalik
Compare the sha1 of the files, since comparing the LFA objects themselves is wrong. Add a test that checks that.
426
                sha1 = lf.libraryfile.content.sha1
10827.6.4 by Steve Kowalik
* Write IArchive.getFilesAndSha1s() that returns the filenames and sha1s for
427
                if sha1 != destination_sha1s[lf.libraryfile.filename]:
10561.2.2 by Steve Kowalik
Re-order the conflicting files check to the end to avoid stomping over the other checks performed.
428
                    raise CannotCopy(
429
                        "%s already exists in destination archive with "
10652.3.2 by Steve Kowalik
Change some variable names, from a suggestion from noodles
430
                        "different contents." % lf.libraryfile.filename)
10561.2.2 by Steve Kowalik
Re-order the conflicting files check to the end to avoid stomping over the other checks performed.
431
12981.1.2 by Raphael Badin
Roll back 12977.
432
    def checkCopy(self, source, series, pocket, person=None,
433
                  check_permissions=True):
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
434
        """Check if the source can be copied to the given location.
435
436
        Check possible conflicting publications in the destination archive.
437
        See `_checkArchiveConflicts()`.
438
439
        Also checks if the version of the source being copied is equal or
440
        higher than any version of the same source present in the
441
        destination suite (series + pocket).
442
12981.1.2 by Raphael Badin
Roll back 12977.
443
        If person is not None, check that this person has upload rights to
444
        the destination (archive, component, pocket).
445
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
446
        :param source: copy candidate, `ISourcePackagePublishingHistory`.
447
        :param series: destination `IDistroSeries`.
448
        :param pocket: destination `PackagePublishingPocket`.
12981.1.2 by Raphael Badin
Roll back 12977.
449
        :param person: requester `IPerson`.
450
        :param check_permissions: boolean indicating whether or not the
451
            requester's permissions to copy should be checked.
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
452
453
        :raise CannotCopy when a copy is not allowed to be performed
454
            containing the reason of the error.
455
        """
12981.1.2 by Raphael Badin
Roll back 12977.
456
        if check_permissions:
13007.1.2 by Jeroen Vermeulen
Tests passing.
457
            check_copy_permissions(
458
                person, self.archive, series, pocket,
13007.1.9 by Jeroen Vermeulen
Last-minute fix: check_copy_permissions now takes a list of SPNs, not just one SPN.
459
                [source.sourcepackagerelease.sourcepackagename])
12981.1.2 by Raphael Badin
Roll back 12977.
460
9965.4.1 by Jelmer Vernooij
Allow copies between distributions as long as the target distroseries exists for the target distribution.
461
        if series not in self.archive.distribution.series:
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
462
            raise CannotCopy(
9965.4.1 by Jelmer Vernooij
Allow copies between distributions as long as the target distroseries exists for the target distribution.
463
                "No such distro series %s in distribution %s." %
464
                (series.name, source.distroseries.distribution.name))
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
465
7675.424.28 by William Grant
s/SourceFormatSelection/SourcePackageFormatSelection/, and make it use an enum instead.
466
        format = SourcePackageFormat.getTermByToken(
467
            source.sourcepackagerelease.dsc_format).value
468
7675.424.30 by William Grant
Fix token lookup in the copier.
469
        if not series.isSourcePackageFormatPermitted(format):
7675.424.22 by William Grant
Forbid source copies to series that do not support the necessary format.
470
            raise CannotCopy(
471
                "Source format '%s' not supported by target series %s." %
472
                (source.sourcepackagerelease.dsc_format, series.name))
473
10806.1.1 by Steve Kowalik
Refuse to copy expired sources.
474
        # Deny copies of source publications containing files with an
475
        # expiration date set.
476
        for source_file in source.sourcepackagerelease.files:
477
            if source_file.libraryfile.expires is not None:
478
                raise CannotCopy('source contains expired files')
479
13168.12.23 by Raphael Badin
Refactor initialization to use the packagecopier if the destination archive is not empty.
480
        if self.include_binaries and self.strict_binaries:
12301.2.5 by William Grant
Use getBuiltBinaries(want_files) in checkCopy's expiry check, eliminating hundreds of queries from large copies.
481
            built_binaries = source.getBuiltBinaries(want_files=True)
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
482
            if len(built_binaries) == 0:
483
                raise CannotCopy("source has no binaries to be copied")
484
            # Deny copies of binary publications containing files with
485
            # expiration date set. We only set such value for immediate
486
            # expiration of old superseded binaries, so no point in
487
            # checking its content, the fact it is set is already enough
488
            # for denying the copy.
489
            for binary_pub in built_binaries:
490
                for binary_file in binary_pub.binarypackagerelease.files:
491
                    if binary_file.libraryfile.expires is not None:
492
                        raise CannotCopy('source has expired binaries')
14191.2.3 by Julian Edwards
Prevent copying of DDEBs into primary archives.
493
                    if (self.archive.is_main and
494
                        binary_file.filetype == BinaryPackageFileType.DDEB):
495
                        raise CannotCopy(
496
                            "Cannot copy DDEBs to a primary archive")
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
497
498
        # Check if there is already a source with the same name and version
499
        # published in the destination archive.
500
        self._checkArchiveConflicts(source, series)
501
502
        ancestry = source.getAncestry(
503
            self.archive, series, pocket, status=active_publishing_status)
504
        if ancestry is not None:
505
            ancestry_version = ancestry.sourcepackagerelease.version
506
            copy_version = source.sourcepackagerelease.version
507
            apt_pkg.InitSystem()
508
            if apt_pkg.VersionCompare(copy_version, ancestry_version) < 0:
509
                raise CannotCopy(
510
                    "version older than the %s published in %s" %
511
                    (ancestry.displayname, ancestry.distroseries.name))
7954.2.1 by Celso Providelo
Fix bug #340660 (deny copy request that will cause file conflicts in the repository).
512
7675.249.1 by Celso Providelo
Integrating delayed-copies and other minor tweaks (db permissions and build creation for source-only delayed copies). All copy methods (web UI, API and 'copy-package' script) will use delayed-copies instead of direct-copies when file privacy mismatch is detected. 'unembargo-package' continues to work with direct-copies and fixing privacy mismatch in place.
513
        delayed = (
514
            self.allow_delayed_copies and
515
            not self.archive.private and
516
            has_restricted_files(source))
517
518
        if delayed:
519
            upload_conflict = getUtility(IPackageUploadSet).findSourceUpload(
520
                name=source.sourcepackagerelease.name,
521
                version=source.sourcepackagerelease.version,
522
                archive=self.archive, distribution=series.distribution)
523
            if upload_conflict is not None:
524
                raise CannotCopy(
525
                    'same version already uploaded and waiting in '
526
                    'ACCEPTED queue')
527
528
        # Copy is approved, update the copy inventory.
529
        self.addCopy(source, delayed)
7548.3.1 by Celso Providelo
Fixing bug #316424 (denying copies of private sources to public archives).
530
531
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
532
def do_copy(sources, archive, series, pocket, include_binaries=False,
7675.1191.29 by Julian Edwards
Add override processing to do_copy
533
            allow_delayed_copies=True, person=None, check_permissions=True,
13403.2.1 by Raphael Badin
Add a parameter to control the creation of dsd jobs.
534
            overrides=None, send_email=False, strict_binaries=True,
14421.2.2 by Julian Edwards
Fix packagecopier to accept a "sponsored" IPerson for sponsored syncs/copies.
535
            close_bugs=True, create_dsd_job=True,  announce_from_person=None,
536
            sponsored=None):
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
537
    """Perform the complete copy of the given sources incrementally.
538
539
    Verifies if each copy can be performed using `CopyChecker` and
540
    raises `CannotCopy` if one or more copies could not be performed.
541
14168.3.1 by Jeroen Vermeulen
Make get_recipients a bit easier to follow.
542
    When `CannotCopy` is raised, call sites are responsible for rolling
543
    back the transaction.  Otherwise, performed copies will be commited.
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
544
545
    Wrapper for `do_direct_copy`.
546
12981.1.2 by Raphael Badin
Roll back 12977.
547
    :param sources: a list of `ISourcePackagePublishingHistory`.
548
    :param archive: the target `IArchive`.
549
    :param series: the target `IDistroSeries`, if None is given the same
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
550
        current source distroseries will be used as destination.
12981.1.2 by Raphael Badin
Roll back 12977.
551
    :param pocket: the target `PackagePublishingPocket`.
552
    :param include_binaries: optional boolean, controls whether or
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
553
        not the published binaries for each given source should be also
554
        copied along with the source.
7675.249.1 by Celso Providelo
Integrating delayed-copies and other minor tweaks (db permissions and build creation for source-only delayed copies). All copy methods (web UI, API and 'copy-package' script) will use delayed-copies instead of direct-copies when file privacy mismatch is detected. 'unembargo-package' continues to work with direct-copies and fixing privacy mismatch in place.
555
    :param allow_delayed_copies: boolean indicating whether or not private
556
        sources can be copied to public archives using delayed_copies.
557
        Defaults to True, only set as False in the UnembargoPackage context.
12981.1.2 by Raphael Badin
Roll back 12977.
558
    :param person: the requester `IPerson`.
559
    :param check_permissions: boolean indicating whether or not the
560
        requester's permissions to copy should be checked.
7675.1191.29 by Julian Edwards
Add override processing to do_copy
561
    :param overrides: A list of `IOverride` as returned from one of the copy
562
        policies which will be used as a manual override insyead of using the
563
        default override returned by IArchive.getOverridePolicy().  There
564
        must be the same number of overrides as there are sources and each
565
        override must be for the corresponding source in the sources list.
566
        Overrides will be ignored for delayed copies.
13136.1.2 by Steve Kowalik
Clean up the e-mail body when we have no changes file.
567
    :param send_email: Should we notify for the copy performed?
13697.7.4 by Julian Edwards
Changes from allenap's review.
568
        NOTE: If running in zopeless mode, the email is sent even if the
569
        transaction is later aborted. (See bug 29744)
13543.4.3 by Julian Edwards
Make sure that announcement emails for syncs into distros are sent from the
570
    :param announce_from_person: If send_email is True,
571
        then send announcement emails with this person as the From:
13168.12.32 by Raphael Badin
Apply MP's comments.
572
    :param strict_binaries: If 'include_binaries' is True then setting this
573
        to True will make the copy fail if binaries cannot be also copied.
13403.3.1 by Raphael Badin
Do not close bugs on the copied publication when initializing.
574
    :param close_bugs: A boolean indicating whether or not bugs on the
575
        copied publications should be closed.
13457.4.4 by Raphael Badin
Create DSDJs outside the packages copy loop.
576
    :param create_dsd_job: A boolean indicating whether or not a dsd job
577
         should be created for the new source publication.
14421.2.2 by Julian Edwards
Fix packagecopier to accept a "sponsored" IPerson for sponsored syncs/copies.
578
    :param sponsored: An `IPerson` representing the person who is
579
        being sponsored for this copy. May be None, but if present will
580
        affect the "From:" address on notifications and the creator of the
581
        publishing record will be set to this person.
13403.3.1 by Raphael Badin
Do not close bugs on the copied publication when initializing.
582
6455.2.2 by Celso Providelo
moving the auxiliary copy-methos to scripts/packagecopier.py.
583
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
584
    :raise CannotCopy when one or more copies were not allowed. The error
585
        will contain the reason why each copy was denied.
586
7675.235.3 by Celso Providelo
Extract do_direct_copy() and implement do_delayed_copy() with the same signature. Very soon we can embed the decision to whether copying with direct or delayed mode in do_copy().
587
    :return: a list of `ISourcePackagePublishingHistory` and
588
        `BinaryPackagePublishingHistory` corresponding to the copied
589
        publications.
590
    """
591
    copies = []
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
592
    errors = []
7675.249.1 by Celso Providelo
Integrating delayed-copies and other minor tweaks (db permissions and build creation for source-only delayed copies). All copy methods (web UI, API and 'copy-package' script) will use delayed-copies instead of direct-copies when file privacy mismatch is detected. 'unembargo-package' continues to work with direct-copies and fixing privacy mismatch in place.
593
    copy_checker = CopyChecker(
13168.12.23 by Raphael Badin
Refactor initialization to use the packagecopier if the destination archive is not empty.
594
        archive, include_binaries, allow_delayed_copies,
595
        strict_binaries=strict_binaries)
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
596
597
    for source in sources:
598
        if series is None:
599
            destination_series = source.distroseries
600
        else:
601
            destination_series = series
602
        try:
12981.1.2 by Raphael Badin
Roll back 12977.
603
            copy_checker.checkCopy(
604
                source, destination_series, pocket, person, check_permissions)
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
605
        except CannotCopy, reason:
606
            errors.append("%s (%s)" % (source.displayname, reason))
607
            continue
608
609
    if len(errors) != 0:
13697.7.2 by Julian Edwards
Code somewhat fixed.
610
        error_text = "\n".join(errors)
611
        if send_email:
612
            source = sources[0]
13697.7.4 by Julian Edwards
Changes from allenap's review.
613
            # Although the interface allows multiple sources to be copied
614
            # at once, we can only send rejection email if a single source
615
            # is specified for now.  This is only relied on by packagecopyjob
616
            # which will only process one package at a time.  We need to
617
            # make the notification code handle atomic rejections such that
618
            # it notifies about multiple packages.
13697.7.2 by Julian Edwards
Code somewhat fixed.
619
            if series is None:
620
                series = source.distroseries
13697.7.4 by Julian Edwards
Changes from allenap's review.
621
            # In zopeless mode this email will be sent immediately.
13697.7.2 by Julian Edwards
Code somewhat fixed.
622
            notify(
623
                person, source.sourcepackagerelease, [], [], archive,
14168.3.8 by Jeroen Vermeulen
Move recipients gathering back into notify, as per chat w Julian.
624
                series, pocket, summary_text=error_text, action='rejected')
13697.7.2 by Julian Edwards
Code somewhat fixed.
625
        raise CannotCopy(error_text)
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
626
7675.1191.29 by Julian Edwards
Add override processing to do_copy
627
    overrides_index = 0
7675.249.1 by Celso Providelo
Integrating delayed-copies and other minor tweaks (db permissions and build creation for source-only delayed copies). All copy methods (web UI, API and 'copy-package' script) will use delayed-copies instead of direct-copies when file privacy mismatch is detected. 'unembargo-package' continues to work with direct-copies and fixing privacy mismatch in place.
628
    for source in copy_checker.getCheckedCopies():
7675.235.3 by Celso Providelo
Extract do_direct_copy() and implement do_delayed_copy() with the same signature. Very soon we can embed the decision to whether copying with direct or delayed mode in do_copy().
629
        if series is None:
630
            destination_series = source.distroseries
631
        else:
632
            destination_series = series
7675.249.1 by Celso Providelo
Integrating delayed-copies and other minor tweaks (db permissions and build creation for source-only delayed copies). All copy methods (web UI, API and 'copy-package' script) will use delayed-copies instead of direct-copies when file privacy mismatch is detected. 'unembargo-package' continues to work with direct-copies and fixing privacy mismatch in place.
633
        if source.delayed:
634
            delayed_copy = _do_delayed_copy(
13136.1.1 by Steve Kowalik
First shot at generating notifications from copies.
635
                source, archive, destination_series, pocket,
636
                include_binaries)
7675.249.1 by Celso Providelo
Integrating delayed-copies and other minor tweaks (db permissions and build creation for source-only delayed copies). All copy methods (web UI, API and 'copy-package' script) will use delayed-copies instead of direct-copies when file privacy mismatch is detected. 'unembargo-package' continues to work with direct-copies and fixing privacy mismatch in place.
637
            sub_copies = [delayed_copy]
638
        else:
7675.1191.31 by Julian Edwards
Fix test failures caused by db-devel merge
639
            override = None
640
            if overrides:
641
                override = overrides[overrides_index]
13785.8.21 by Julian Edwards
Make sure old_version is always set regardless of whether we're sending
642
            # Make a note of the destination source's version for use
643
            # in sending the email notification and closing bugs.
644
            existing = archive.getPublishedSources(
645
                name=source.sourcepackagerelease.name, exact_match=True,
646
                status=active_publishing_status,
647
                distroseries=series, pocket=pocket).first()
648
            if existing:
649
                old_version = existing.sourcepackagerelease.version
650
            else:
651
                old_version = None
14421.2.2 by Julian Edwards
Fix packagecopier to accept a "sponsored" IPerson for sponsored syncs/copies.
652
            if sponsored is not None:
653
                announce_from_person = sponsored
654
                creator = sponsored
655
            else:
656
                creator = person
7675.249.1 by Celso Providelo
Integrating delayed-copies and other minor tweaks (db permissions and build creation for source-only delayed copies). All copy methods (web UI, API and 'copy-package' script) will use delayed-copies instead of direct-copies when file privacy mismatch is detected. 'unembargo-package' continues to work with direct-copies and fixing privacy mismatch in place.
657
            sub_copies = _do_direct_copy(
13136.1.1 by Steve Kowalik
First shot at generating notifications from copies.
658
                source, archive, destination_series, pocket,
13457.4.4 by Raphael Badin
Create DSDJs outside the packages copy loop.
659
                include_binaries, override, close_bugs=close_bugs,
13785.8.19 by Julian Edwards
Make changes to the packagecopier so it will close bugs for all bugs
660
                create_dsd_job=create_dsd_job,
14421.2.2 by Julian Edwards
Fix packagecopier to accept a "sponsored" IPerson for sponsored syncs/copies.
661
                close_bugs_since_version=old_version, creator=creator)
13136.1.2 by Steve Kowalik
Clean up the e-mail body when we have no changes file.
662
            if send_email:
663
                notify(
664
                    person, source.sourcepackagerelease, [], [], archive,
14168.3.4 by Jeroen Vermeulen
Externalize recipients gathering for soyuz upload notifications.
665
                    destination_series, pocket, action='accepted',
13755.2.15 by Julian Edwards
re-instate backed out changes and move the aggregate_changelog method to SPPH and make it parse changelog instead of iterating over many changelog_entry
666
                    announce_from_person=announce_from_person,
14168.3.8 by Jeroen Vermeulen
Move recipients gathering back into notify, as per chat w Julian.
667
                    previous_version=old_version)
7675.235.3 by Celso Providelo
Extract do_direct_copy() and implement do_delayed_copy() with the same signature. Very soon we can embed the decision to whether copying with direct or delayed mode in do_copy().
668
7675.1191.29 by Julian Edwards
Add override processing to do_copy
669
        overrides_index += 1
7675.235.3 by Celso Providelo
Extract do_direct_copy() and implement do_delayed_copy() with the same signature. Very soon we can embed the decision to whether copying with direct or delayed mode in do_copy().
670
        copies.extend(sub_copies)
671
672
    return copies
673
674
7675.1191.29 by Julian Edwards
Add override processing to do_copy
675
def _do_direct_copy(source, archive, series, pocket, include_binaries,
13785.8.19 by Julian Edwards
Make changes to the packagecopier so it will close bugs for all bugs
676
                    override=None, close_bugs=True, create_dsd_job=True,
14017.1.1 by Raphael Badin
Code changes for the creation of spph.creator.
677
                    close_bugs_since_version=None, creator=None):
7675.235.3 by Celso Providelo
Extract do_direct_copy() and implement do_delayed_copy() with the same signature. Very soon we can embed the decision to whether copying with direct or delayed mode in do_copy().
678
    """Copy publishing records to another location.
679
6455.2.2 by Celso Providelo
moving the auxiliary copy-methos to scripts/packagecopier.py.
680
    Copy each item of the given list of `SourcePackagePublishingHistory`
6755.4.2 by Celso Providelo
Fixing bug #251492 (Avoid duplications copying packages incrementally and removing check denying copies of source with in-progress builds or with unpublished binaries).
681
    to the given destination if they are not yet available (previously
682
    copied).
683
684
    Also copy published binaries for each source if requested to. Again,
685
    only copy binaries that were not yet copied before.
6455.2.2 by Celso Providelo
moving the auxiliary copy-methos to scripts/packagecopier.py.
686
12981.1.2 by Raphael Badin
Roll back 12977.
687
    :param source: an `ISourcePackagePublishingHistory`.
688
    :param archive: the target `IArchive`.
689
    :param series: the target `IDistroSeries`, if None is given the same
7675.235.5 by Celso Providelo
applying review comments, r=abentley.
690
        current source distroseries will be used as destination.
12981.1.2 by Raphael Badin
Roll back 12977.
691
    :param pocket: the target `PackagePublishingPocket`.
692
    :param include_binaries: optional boolean, controls whether or
6455.2.2 by Celso Providelo
moving the auxiliary copy-methos to scripts/packagecopier.py.
693
        not the published binaries for each given source should be also
7675.235.5 by Celso Providelo
applying review comments, r=abentley.
694
        copied along with the source.
7675.1191.29 by Julian Edwards
Add override processing to do_copy
695
    :param override: An `IOverride` as per do_copy().
13403.3.1 by Raphael Badin
Do not close bugs on the copied publication when initializing.
696
    :param close_bugs: A boolean indicating whether or not bugs on the
697
        copied publication should be closed.
13457.4.4 by Raphael Badin
Create DSDJs outside the packages copy loop.
698
    :param create_dsd_job: A boolean indicating whether or not a dsd job
699
         should be created for the new source publication.
13785.8.19 by Julian Edwards
Make changes to the packagecopier so it will close bugs for all bugs
700
    :param close_bugs_since_version: If close_bugs is True,
701
        then this parameter says which changelog entries to parse looking
702
        for bugs to close.  See `close_bugs_for_sourcepackagerelease`.
14017.1.1 by Raphael Badin
Code changes for the creation of spph.creator.
703
    :param creator: the requester `IPerson`.
7675.235.3 by Celso Providelo
Extract do_direct_copy() and implement do_delayed_copy() with the same signature. Very soon we can embed the decision to whether copying with direct or delayed mode in do_copy().
704
6455.2.3 by Celso Providelo
Fixing bug #237353 (Duplicated arch-indep copies causes confusion in domination sub-system). Unifying copy-package backend, now both, UI and scripts, use check_copy/do_copy functions which is safe agains duplications and other problematic copies.
705
    :return: a list of `ISourcePackagePublishingHistory` and
6455.2.2 by Celso Providelo
moving the auxiliary copy-methos to scripts/packagecopier.py.
706
        `BinaryPackagePublishingHistory` corresponding to the copied
707
        publications.
708
    """
709
    copies = []
7675.235.3 by Celso Providelo
Extract do_direct_copy() and implement do_delayed_copy() with the same signature. Very soon we can embed the decision to whether copying with direct or delayed mode in do_copy().
710
711
    # Copy source if it's not yet copied.
712
    source_in_destination = archive.getPublishedSources(
713
        name=source.sourcepackagerelease.name, exact_match=True,
714
        version=source.sourcepackagerelease.version,
715
        status=active_publishing_status,
716
        distroseries=series, pocket=pocket)
7675.1174.2 by Julian Edwards
fix my stupidity
717
    policy = archive.getOverridePolicy()
12505.4.1 by Robert Collins
Hopefully fix bug 727560 by permitting a much better query plan for folk querying the primary archive.
718
    if source_in_destination.is_empty():
7675.1191.29 by Julian Edwards
Add override processing to do_copy
719
        # If no manual overrides were specified and the archive has an
720
        # override policy then use that policy to get overrides.
721
        if override is None and policy is not None:
7675.1174.2 by Julian Edwards
fix my stupidity
722
            package_names = (source.sourcepackagerelease.sourcepackagename,)
7675.1181.4 by Julian Edwards
fix the silly list arguemnt for overrides on copyTo since it will only ever override a single source
723
            # Only one override can be returned so take the first
724
            # element of the returned list.
7675.1181.12 by Julian Edwards
fix bustage caused by merging db-devel that had jtv's changes to the job schema.
725
            overrides = policy.calculateSourceOverrides(
726
                archive, series, pocket, package_names)
7675.1181.4 by Julian Edwards
fix the silly list arguemnt for overrides on copyTo since it will only ever override a single source
727
            # Only one override can be returned so take the first
728
            # element of the returned list.
7675.1181.9 by Julian Edwards
Stupid typos R me
729
            assert len(overrides) == 1, (
7675.1181.8 by Julian Edwards
review comments from allenap
730
                "More than one override encountered, something is wrong.")
7675.1181.9 by Julian Edwards
Stupid typos R me
731
            override = overrides[0]
13403.2.1 by Raphael Badin
Add a parameter to control the creation of dsd jobs.
732
        source_copy = source.copyTo(
14017.1.1 by Raphael Badin
Code changes for the creation of spph.creator.
733
            series, pocket, archive, override, create_dsd_job=create_dsd_job,
734
            creator=creator)
13403.3.1 by Raphael Badin
Do not close bugs on the copied publication when initializing.
735
        if close_bugs:
13785.8.19 by Julian Edwards
Make changes to the packagecopier so it will close bugs for all bugs
736
            close_bugs_for_sourcepublication(
737
                source_copy, close_bugs_since_version)
7675.235.3 by Celso Providelo
Extract do_direct_copy() and implement do_delayed_copy() with the same signature. Very soon we can embed the decision to whether copying with direct or delayed mode in do_copy().
738
        copies.append(source_copy)
739
    else:
12505.4.1 by Robert Collins
Hopefully fix bug 727560 by permitting a much better query plan for folk querying the primary archive.
740
        source_copy = source_in_destination.first()
7675.235.3 by Celso Providelo
Extract do_direct_copy() and implement do_delayed_copy() with the same signature. Very soon we can embed the decision to whether copying with direct or delayed mode in do_copy().
741
742
    if not include_binaries:
7399.1.1 by Celso Providelo
Try to create missing builds when copying packages, even when copying binaries. It makes copies to distroseries with new architectures more efficient and useful.
743
        source_copy.createMissingBuilds()
7675.235.3 by Celso Providelo
Extract do_direct_copy() and implement do_delayed_copy() with the same signature. Very soon we can embed the decision to whether copying with direct or delayed mode in do_copy().
744
        return copies
745
746
    # Copy missing binaries for the matching architectures in the
747
    # destination series. ISPPH.getBuiltBinaries() return only
7675.235.5 by Celso Providelo
applying review comments, r=abentley.
748
    # unique publication per binary package releases (i.e. excludes
7675.235.3 by Celso Providelo
Extract do_direct_copy() and implement do_delayed_copy() with the same signature. Very soon we can embed the decision to whether copying with direct or delayed mode in do_copy().
749
    # irrelevant arch-indep publications) and IBPPH.copy is prepared
750
    # to expand arch-indep publications.
13168.12.28 by Raphael Badin
Check emptiness of binaries inside copyBinariesTo.
751
    binary_copies = getUtility(IPublishingSet).copyBinariesTo(
752
        source.getBuiltBinaries(), series, pocket, archive, policy=policy)
9792.2.5 by Michael Nelson
Updated the packagecopier script to use the new copyBinariesTo utility method.
753
13168.12.33 by Raphael Badin
Raise InitializationError if do_copy raises CannotCopy.
754
    if binary_copies is not None:
755
        copies.extend(binary_copies)
7675.235.3 by Celso Providelo
Extract do_direct_copy() and implement do_delayed_copy() with the same signature. Very soon we can embed the decision to whether copying with direct or delayed mode in do_copy().
756
757
    # Always ensure the needed builds exist in the copy destination
758
    # after copying the binaries.
759
    source_copy.createMissingBuilds()
7399.1.1 by Celso Providelo
Try to create missing builds when copying packages, even when copying binaries. It makes copies to distroseries with new architectures more efficient and useful.
760
6455.2.2 by Celso Providelo
moving the auxiliary copy-methos to scripts/packagecopier.py.
761
    return copies
762
763
7675.249.1 by Celso Providelo
Integrating delayed-copies and other minor tweaks (db permissions and build creation for source-only delayed copies). All copy methods (web UI, API and 'copy-package' script) will use delayed-copies instead of direct-copies when file privacy mismatch is detected. 'unembargo-package' continues to work with direct-copies and fixing privacy mismatch in place.
764
class DelayedCopy:
765
    """Decorates `IPackageUpload` with a more descriptive 'displayname'."""
766
767
    delegates(IPackageUpload)
768
769
    def __init__(self, context):
770
        self.context = context
771
772
    @property
773
    def displayname(self):
774
        return 'Delayed copy of %s (%s)' % (
775
            self.context.sourcepackagerelease.title,
776
            self.context.displayarchs)
777
778
7675.235.5 by Celso Providelo
applying review comments, r=abentley.
779
def _do_delayed_copy(source, archive, series, pocket, include_binaries):
7675.235.3 by Celso Providelo
Extract do_direct_copy() and implement do_delayed_copy() with the same signature. Very soon we can embed the decision to whether copying with direct or delayed mode in do_copy().
780
    """Schedule the given source for copy.
781
7675.235.5 by Celso Providelo
applying review comments, r=abentley.
782
    Schedule the copy of each item of the given list of
7675.235.3 by Celso Providelo
Extract do_direct_copy() and implement do_delayed_copy() with the same signature. Very soon we can embed the decision to whether copying with direct or delayed mode in do_copy().
783
    `SourcePackagePublishingHistory` to the given destination.
784
785
    Also include published builds for each source if requested to.
786
12981.1.2 by Raphael Badin
Roll back 12977.
787
    :param source: an `ISourcePackagePublishingHistory`.
788
    :param archive: the target `IArchive`.
789
    :param series: the target `IDistroSeries`.
790
    :param pocket: the target `PackagePublishingPocket`.
791
    :param include_binaries: optional boolean, controls whether or
7675.235.3 by Celso Providelo
Extract do_direct_copy() and implement do_delayed_copy() with the same signature. Very soon we can embed the decision to whether copying with direct or delayed mode in do_copy().
792
        not the published binaries for each given source should be also
7675.235.5 by Celso Providelo
applying review comments, r=abentley.
793
        copied along with the source.
7675.235.3 by Celso Providelo
Extract do_direct_copy() and implement do_delayed_copy() with the same signature. Very soon we can embed the decision to whether copying with direct or delayed mode in do_copy().
794
795
    :return: a list of `IPackageUpload` corresponding to the publications
796
        scheduled for copy.
797
    """
7675.235.5 by Celso Providelo
applying review comments, r=abentley.
798
    # XXX cprov 2009-06-22 bug=385503: At some point we will change
799
    # the copy signature to allow a user to be passed in, so will
800
    # be able to annotate that information in delayed copied as well,
801
    # by using the right key. For now it's undefined.
7675.235.3 by Celso Providelo
Extract do_direct_copy() and implement do_delayed_copy() with the same signature. Very soon we can embed the decision to whether copying with direct or delayed mode in do_copy().
802
    # See also the comment on acceptFromCopy()
803
    delayed_copy = getUtility(IPackageUploadSet).createDelayedCopy(
804
        archive, series, pocket, None)
805
806
    # Include the source and any custom upload.
807
    delayed_copy.addSource(source.sourcepackagerelease)
808
    original_source_upload = source.sourcepackagerelease.package_upload
809
    for custom in original_source_upload.customfiles:
810
        delayed_copy.addCustom(
811
            custom.libraryfilealias, custom.customformat)
812
7675.235.5 by Celso Providelo
applying review comments, r=abentley.
813
    # If binaries are included in the copy we include binary custom files.
7675.235.3 by Celso Providelo
Extract do_direct_copy() and implement do_delayed_copy() with the same signature. Very soon we can embed the decision to whether copying with direct or delayed mode in do_copy().
814
    if include_binaries:
815
        for build in source.getBuilds():
12177.12.5 by William Grant
do_delayed_copy no longer copies builds without a corresponding enabled architecture in the target series.
816
            # Don't copy builds that aren't yet done, or those without a
817
            # corresponding enabled architecture in the new series.
818
            try:
819
                target_arch = series[build.arch_tag]
820
            except NotFoundError:
821
                continue
822
            if (not target_arch.enabled or
823
                build.status != BuildStatus.FULLYBUILT):
7675.254.1 by Celso Providelo
Fixing the way we handle delayed-copies of partially built sources.
824
                continue
7675.235.3 by Celso Providelo
Extract do_direct_copy() and implement do_delayed_copy() with the same signature. Very soon we can embed the decision to whether copying with direct or delayed mode in do_copy().
825
            delayed_copy.addBuild(build)
826
            original_build_upload = build.package_upload
827
            for custom in original_build_upload.customfiles:
828
                delayed_copy.addCustom(
829
                    custom.libraryfilealias, custom.customformat)
830
7675.235.5 by Celso Providelo
applying review comments, r=abentley.
831
    # XXX cprov 2009-06-22 bug=385503: when we have a 'user' responsible
832
    # for the copy we can also decide whether a copy should be immediately
833
    # accepted or moved to the UNAPPROVED queue, based on the user's
834
    # permission to the destination context.
835
836
    # Accept the delayed-copy, which implicitly verifies if it fits
7675.235.3 by Celso Providelo
Extract do_direct_copy() and implement do_delayed_copy() with the same signature. Very soon we can embed the decision to whether copying with direct or delayed mode in do_copy().
837
    # the destination context.
838
    delayed_copy.acceptFromCopy()
839
7675.249.1 by Celso Providelo
Integrating delayed-copies and other minor tweaks (db permissions and build creation for source-only delayed copies). All copy methods (web UI, API and 'copy-package' script) will use delayed-copies instead of direct-copies when file privacy mismatch is detected. 'unembargo-package' continues to work with direct-copies and fixing privacy mismatch in place.
840
    return DelayedCopy(delayed_copy)
7675.235.3 by Celso Providelo
Extract do_direct_copy() and implement do_delayed_copy() with the same signature. Very soon we can embed the decision to whether copying with direct or delayed mode in do_copy().
841
842
6455.2.1 by Celso Providelo
Moving PackageCopier & UnembargoSecurityPackage script classes out of ftpmaster.py file.
843
class PackageCopier(SoyuzScript):
844
    """SoyuzScript that copies published packages between locations.
845
846
    Possible exceptions raised are:
847
    * PackageLocationError: specified package or distro does not exist
848
    * PackageCopyError: the copy operation itself has failed
849
    * LaunchpadScriptFailure: only raised if entering via main(), ie this
850
        code is running as a genuine script.  In this case, this is
851
        also the _only_ exception to be raised.
852
853
    The test harness doesn't enter via main(), it calls doCopy(), so
854
    it only sees the first two exceptions.
855
    """
856
857
    usage = '%prog -s warty mozilla-firefox --to-suite hoary'
858
    description = 'MOVE or COPY a published package to another suite.'
7675.249.1 by Celso Providelo
Integrating delayed-copies and other minor tweaks (db permissions and build creation for source-only delayed copies). All copy methods (web UI, API and 'copy-package' script) will use delayed-copies instead of direct-copies when file privacy mismatch is detected. 'unembargo-package' continues to work with direct-copies and fixing privacy mismatch in place.
859
    allow_delayed_copies = True
6455.2.1 by Celso Providelo
Moving PackageCopier & UnembargoSecurityPackage script classes out of ftpmaster.py file.
860
861
    def add_my_options(self):
862
863
        SoyuzScript.add_my_options(self)
864
865
        self.parser.add_option(
866
            "-b", "--include-binaries", dest="include_binaries",
867
            default=False, action="store_true",
868
            help='Whether to copy related binaries or not.')
869
870
        self.parser.add_option(
871
            '--to-distribution', dest='to_distribution',
872
            default='ubuntu', action='store',
873
            help='Destination distribution name.')
874
875
        self.parser.add_option(
876
            '--to-suite', dest='to_suite', default=None,
877
            action='store', help='Destination suite name.')
878
879
        self.parser.add_option(
880
            '--to-ppa', dest='to_ppa', default=None,
881
            action='store', help='Destination PPA owner name.')
882
883
        self.parser.add_option(
7548.5.5 by Julian Edwards
Resurrection part 5
884
            '--to-ppa-name', dest='to_ppa_name', default='ppa',
885
            action='store', help='Destination PPA name.')
886
887
        self.parser.add_option(
6455.2.1 by Celso Providelo
Moving PackageCopier & UnembargoSecurityPackage script classes out of ftpmaster.py file.
888
            '--to-partner', dest='to_partner', default=False,
889
            action='store_true', help='Destination set to PARTNER archive.')
890
891
    def checkCopyOptions(self):
892
        """Check if the locations options are sane.
893
894
         * Catch Cross-PARTNER copies, they are not allowed.
895
         * Catch simulataneous PPA and PARTNER locations or destinations,
896
           results are unpredictable (in fact, the code will ignore PPA and
897
           operate only in PARTNER, but that's odd)
898
        """
899
        if ((self.options.partner_archive and not self.options.to_partner)
900
            or (self.options.to_partner and not
901
                self.options.partner_archive)):
902
            raise SoyuzScriptError(
903
                "Cross-PARTNER copies are not allowed.")
904
905
        if self.options.archive_owner_name and self.options.partner_archive:
906
            raise SoyuzScriptError(
907
                "Cannot operate with location PARTNER and PPA "
908
                "simultaneously.")
909
910
        if self.options.to_ppa and self.options.to_partner:
911
            raise SoyuzScriptError(
912
                "Cannot operate with destination PARTNER and PPA "
913
                "simultaneously.")
914
915
    def mainTask(self):
916
        """Execute package copy procedure.
917
918
        Copy source publication and optionally also copy its binaries by
919
        passing '-b' (include_binary) option.
920
921
        Modules using this class outside of its normal usage in the
922
        copy-package.py script can call this method to start the copy.
923
924
        In this case the caller can override test_args on __init__
925
        to set the command line arguments.
926
927
        Can raise SoyuzScriptError.
928
        """
929
        assert self.location, (
930
            "location is not available, call PackageCopier.setupLocation() "
931
            "before dealing with mainTask.")
932
933
        self.checkCopyOptions()
934
935
        sourcename = self.args[0]
936
937
        self.setupDestination()
938
939
        self.logger.info("FROM: %s" % (self.location))
940
        self.logger.info("TO: %s" % (self.destination))
941
942
        to_copy = []
943
        source_pub = self.findLatestPublishedSource(sourcename)
944
        to_copy.append(source_pub)
945
        if self.options.include_binaries:
946
            to_copy.extend(source_pub.getPublishedBinaries())
947
948
        self.logger.info("Copy candidates:")
949
        for candidate in to_copy:
950
            self.logger.info('\t%s' % candidate.displayname)
951
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
952
        sources = [source_pub]
6455.2.3 by Celso Providelo
Fixing bug #237353 (Duplicated arch-indep copies causes confusion in domination sub-system). Unifying copy-package backend, now both, UI and scripts, use check_copy/do_copy functions which is safe agains duplications and other problematic copies.
953
        try:
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
954
            copies = do_copy(
955
                sources, self.destination.archive,
6455.2.3 by Celso Providelo
Fixing bug #237353 (Duplicated arch-indep copies causes confusion in domination sub-system). Unifying copy-package backend, now both, UI and scripts, use check_copy/do_copy functions which is safe agains duplications and other problematic copies.
956
                self.destination.distroseries, self.destination.pocket,
12981.1.2 by Raphael Badin
Roll back 12977.
957
                self.options.include_binaries, self.allow_delayed_copies,
958
                check_permissions=False)
8730.2.2 by Celso Providelo
Fixes bug #387613 (changing do_copy() to identify conflicting candidates in the same batch keeping its transactional behavior without relying on the DB transaction to be aborted).
959
        except CannotCopy, error:
960
            self.logger.error(str(error))
6455.2.3 by Celso Providelo
Fixing bug #237353 (Duplicated arch-indep copies causes confusion in domination sub-system). Unifying copy-package backend, now both, UI and scripts, use check_copy/do_copy functions which is safe agains duplications and other problematic copies.
961
            return []
962
7675.249.1 by Celso Providelo
Integrating delayed-copies and other minor tweaks (db permissions and build creation for source-only delayed copies). All copy methods (web UI, API and 'copy-package' script) will use delayed-copies instead of direct-copies when file privacy mismatch is detected. 'unembargo-package' continues to work with direct-copies and fixing privacy mismatch in place.
963
        self.logger.info("Copied:")
964
        for copy in copies:
965
            self.logger.info('\t%s' % copy.displayname)
966
6455.2.1 by Celso Providelo
Moving PackageCopier & UnembargoSecurityPackage script classes out of ftpmaster.py file.
967
        if len(copies) == 1:
968
            self.logger.info(
969
                "%s package successfully copied." % len(copies))
970
        elif len(copies) > 1:
971
            self.logger.info(
972
                "%s packages successfully copied." % len(copies))
973
        else:
6876.4.1 by Celso Providelo
Fixing misleading copy-package script output.
974
            self.logger.info("No packages copied.")
6455.2.1 by Celso Providelo
Moving PackageCopier & UnembargoSecurityPackage script classes out of ftpmaster.py file.
975
976
        # Information returned mainly for the benefit of the test harness.
977
        return copies
978
979
    def setupDestination(self):
980
        """Build PackageLocation for the destination context."""
981
        if self.options.to_partner:
982
            self.destination = build_package_location(
983
                self.options.to_distribution,
984
                self.options.to_suite,
985
                ArchivePurpose.PARTNER)
986
        elif self.options.to_ppa:
987
            self.destination = build_package_location(
988
                self.options.to_distribution,
989
                self.options.to_suite,
990
                ArchivePurpose.PPA,
7548.5.5 by Julian Edwards
Resurrection part 5
991
                self.options.to_ppa,
992
                self.options.to_ppa_name)
6455.2.1 by Celso Providelo
Moving PackageCopier & UnembargoSecurityPackage script classes out of ftpmaster.py file.
993
        else:
994
            self.destination = build_package_location(
995
                self.options.to_distribution,
996
                self.options.to_suite)
997
998
        if self.location == self.destination:
999
            raise SoyuzScriptError(
1000
                "Can not sync between the same locations: '%s' to '%s'" % (
1001
                self.location, self.destination))
1002
1003
1004
class UnembargoSecurityPackage(PackageCopier):
1005
    """`SoyuzScript` that unembargoes security packages and their builds.
1006
1007
    Security builds are done in the ubuntu-security private PPA.
1008
    When they are ready to be unembargoed, this script will copy
1009
    them from the PPA to the Ubuntu archive and re-upload any files
1010
    from the restricted librarian into the non-restricted one.
1011
1012
    This script simply wraps up PackageCopier with some nicer options,
1013
    and implements the file re-uploading.
1014
1015
    An assumption is made, to reduce the number of command line options,
7250.4.5 by Julian Edwards
Expand on the class docstring to talk about the staging via -proposed.
1016
    that packages are always copied between the same distroseries.  The user
1017
    can, however, select which target pocket to unembargo into.  This is
1018
    useful to the security team when there are major version upgrades
1019
    and they want to stage it through -proposed first for testing.
6455.2.1 by Celso Providelo
Moving PackageCopier & UnembargoSecurityPackage script classes out of ftpmaster.py file.
1020
    """
1021
7250.4.1 by Julian Edwards
Allow overiding of the destination suite when unembargoing.
1022
    usage = ("%prog [-d <distribution>] [-s <suite>] [--ppa <private ppa>] "
6455.2.1 by Celso Providelo
Moving PackageCopier & UnembargoSecurityPackage script classes out of ftpmaster.py file.
1023
             "<package(s)>")
1024
    description = ("Unembargo packages in a private PPA by copying to the "
1025
                   "specified location and re-uploading any files to the "
1026
                   "unrestricted librarian.")
7675.249.1 by Celso Providelo
Integrating delayed-copies and other minor tweaks (db permissions and build creation for source-only delayed copies). All copy methods (web UI, API and 'copy-package' script) will use delayed-copies instead of direct-copies when file privacy mismatch is detected. 'unembargo-package' continues to work with direct-copies and fixing privacy mismatch in place.
1027
    allow_delayed_copies = False
6455.2.1 by Celso Providelo
Moving PackageCopier & UnembargoSecurityPackage script classes out of ftpmaster.py file.
1028
1029
    def add_my_options(self):
1030
        """Add -d, -s, dry-run and confirmation options."""
1031
        SoyuzScript.add_distro_options(self)
1032
        SoyuzScript.add_transaction_options(self)
1033
1034
        self.parser.add_option(
1035
            "-p", "--ppa", dest="archive_owner_name",
1036
            default="ubuntu-security", action="store",
1037
            help="Private PPA owner's name.")
1038
7548.5.5 by Julian Edwards
Resurrection part 5
1039
        self.parser.add_option(
1040
            "--ppa-name", dest="archive_name",
1041
            default="ppa", action="store",
1042
            help="Private PPA name.")
1043
7250.4.1 by Julian Edwards
Allow overiding of the destination suite when unembargoing.
1044
    def setUpCopierOptions(self):
7250.4.4 by Julian Edwards
Don't assume -security any more; explicitly fail the operation if someone forgets to supply a pocket.
1045
        """Set up options needed by PackageCopier.
7399.1.3 by Celso Providelo
Modifying ISPPH.getBuiltBinaries() and IBPPH.copyTo to deal easily with arch-indep binaries.
1046
7250.4.4 by Julian Edwards
Don't assume -security any more; explicitly fail the operation if someone forgets to supply a pocket.
1047
        :return: False if there is a problem with the options.
1048
        """
6455.2.1 by Celso Providelo
Moving PackageCopier & UnembargoSecurityPackage script classes out of ftpmaster.py file.
1049
        # Set up the options for PackageCopier that are needed in addition
1050
        # to the ones that this class sets up.
1051
        self.options.to_partner = False
1052
        self.options.to_ppa = False
1053
        self.options.partner_archive = None
1054
        self.options.include_binaries = True
1055
        self.options.to_distribution = self.options.distribution_name
7250.4.4 by Julian Edwards
Don't assume -security any more; explicitly fail the operation if someone forgets to supply a pocket.
1056
        from_suite = self.options.suite.split("-")
1057
        if len(from_suite) == 1:
1058
            self.logger.error("Can't unembargo into the release pocket")
1059
            return False
7250.4.1 by Julian Edwards
Allow overiding of the destination suite when unembargoing.
1060
        else:
7250.4.4 by Julian Edwards
Don't assume -security any more; explicitly fail the operation if someone forgets to supply a pocket.
1061
            # The PackageCopier parent class uses options.suite as the
1062
            # source suite, so we need to override it to remove the
1063
            # pocket since PPAs are pocket-less.
7250.4.1 by Julian Edwards
Allow overiding of the destination suite when unembargoing.
1064
            self.options.to_suite = self.options.suite
7250.4.4 by Julian Edwards
Don't assume -security any more; explicitly fail the operation if someone forgets to supply a pocket.
1065
            self.options.suite = from_suite[0]
6455.2.1 by Celso Providelo
Moving PackageCopier & UnembargoSecurityPackage script classes out of ftpmaster.py file.
1066
        self.options.version = None
1067
        self.options.component = None
1068
7250.4.4 by Julian Edwards
Don't assume -security any more; explicitly fail the operation if someone forgets to supply a pocket.
1069
        return True
1070
7250.4.1 by Julian Edwards
Allow overiding of the destination suite when unembargoing.
1071
    def mainTask(self):
1072
        """Invoke PackageCopier to copy the package(s) and re-upload files."""
7250.4.4 by Julian Edwards
Don't assume -security any more; explicitly fail the operation if someone forgets to supply a pocket.
1073
        if not self.setUpCopierOptions():
1074
            return None
1075
1076
        # Generate the location for PackageCopier after overriding the
1077
        # options.
1078
        self.setupLocation()
7250.4.1 by Julian Edwards
Allow overiding of the destination suite when unembargoing.
1079
6455.2.1 by Celso Providelo
Moving PackageCopier & UnembargoSecurityPackage script classes out of ftpmaster.py file.
1080
        # Invoke the package copy operation.
1081
        copies = PackageCopier.mainTask(self)
1082
8589.3.3 by Celso Providelo
Extracting and testing unembaroging base procedures.
1083
        # Fix copies by overriding them according the current ancestry
1084
        # and re-upload files with privacy mismatch.
6455.2.1 by Celso Providelo
Moving PackageCopier & UnembargoSecurityPackage script classes out of ftpmaster.py file.
1085
        for pub_record in copies:
8720.3.1 by Celso Providelo
PackageCopier cleanup, implementing getAncestry() and overrideFromAncestry() on IPublishing.
1086
            pub_record.overrideFromAncestry()
8589.3.4 by Celso Providelo
name extracted functions appropriately.
1087
            for new_file in update_files_privacy(pub_record):
8589.3.3 by Celso Providelo
Extracting and testing unembaroging base procedures.
1088
                self.logger.info(
1089
                    "Re-uploaded %s to librarian" % new_file.filename)
6455.2.1 by Celso Providelo
Moving PackageCopier & UnembargoSecurityPackage script classes out of ftpmaster.py file.
1090
1091
        # Return this for the benefit of the test suite.
1092
        return copies