~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/archiveuploader/nascentupload.py

  • Committer: Launchpad Patch Queue Manager
  • Date: 2011-06-25 08:55:37 UTC
  • mfrom: (13287.1.8 bug-800652)
  • Revision ID: launchpad@pqm.canonical.com-20110625085537-moikyoo2pe98zs7r
[r=jcsackett, julian-edwards][bug=800634,
        800652] Enable and display overrides on sync package uploads.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright 2009-2011 Canonical Ltd.  This software is licensed under the
 
1
# Copyright 2009 Canonical Ltd.  This software is licensed under the
2
2
# GNU Affero General Public License version 3 (see the file LICENSE).
3
3
 
4
4
"""The processing of nascent uploads.
23
23
import apt_pkg
24
24
from zope.component import getUtility
25
25
 
 
26
from canonical.launchpad.interfaces.librarian import ILibraryFileAliasSet
26
27
from lp.app.errors import NotFoundError
27
28
from lp.archiveuploader.changesfile import ChangesFile
28
29
from lp.archiveuploader.dscfile import DSCFile
32
33
    DdebBinaryUploadFile,
33
34
    DebBinaryUploadFile,
34
35
    SourceUploadFile,
35
 
    UdebBinaryUploadFile,
36
36
    UploadError,
37
37
    UploadWarning,
38
38
    )
41
41
from lp.registry.interfaces.pocket import PackagePublishingPocket
42
42
from lp.registry.interfaces.sourcepackage import SourcePackageFileType
43
43
from lp.registry.interfaces.sourcepackagename import ISourcePackageNameSet
44
 
from lp.services.librarian.interfaces import ILibraryFileAliasSet
45
 
from lp.soyuz.adapters.overrides import UnknownOverridePolicy
46
44
from lp.soyuz.interfaces.archive import MAIN_ARCHIVE_PURPOSES
47
45
from lp.soyuz.interfaces.queue import QueueInconsistentStateError
48
46
 
50
48
PARTNER_COMPONENT_NAME = 'partner'
51
49
 
52
50
 
 
51
class FatalUploadError(Exception):
 
52
    """A fatal error occurred processing the upload; processing aborted."""
 
53
 
 
54
 
53
55
class EarlyReturnUploadError(Exception):
54
56
    """An error occurred that prevented further error collection."""
55
57
 
111
113
    def from_changesfile_path(cls, changesfile_path, policy, logger):
112
114
        """Create a NascentUpload from the given changesfile path.
113
115
 
114
 
        May raise UploadError due to unrecoverable problems building
 
116
        May raise FatalUploadError due to unrecoverable problems building
115
117
        the ChangesFile object.
116
118
 
117
119
        :param changesfile_path: path to the changesfile to be uploaded.
118
120
        :param policy: the upload policy to be used.
119
121
        :param logger: the logger to be used.
120
122
        """
121
 
        changesfile = ChangesFile(changesfile_path, policy, logger)
 
123
        try:
 
124
            changesfile = ChangesFile(changesfile_path, policy, logger)
 
125
        except UploadError, e:
 
126
            # We can't run reject() because unfortunately we don't have
 
127
            # the address of the uploader to notify -- we broke in that
 
128
            # exact step.
 
129
            # XXX cprov 2007-03-26: we should really be emailing this
 
130
            # rejection to the archive admins. For now, this will end
 
131
            # up in the script log.
 
132
            raise FatalUploadError(str(e))
122
133
        return cls(changesfile, policy, logger)
123
134
 
124
135
    def process(self, build=None):
179
190
            # before doing component verifications because the component
180
191
            # actually comes from overrides for packages that are not NEW.
181
192
            self.find_and_apply_overrides()
182
 
            self._overrideDDEBSs()
183
193
 
184
194
        # Override archive location if necessary.
185
195
        self.overrideArchive()
349
359
                    unmatched_ddebs[ddeb_key] = uploaded_file
350
360
 
351
361
        for uploaded_file in self.changes.files:
352
 
            is_deb = isinstance(uploaded_file, DebBinaryUploadFile)
353
 
            is_udeb = isinstance(uploaded_file, UdebBinaryUploadFile)
354
 
            is_ddeb = isinstance(uploaded_file, DdebBinaryUploadFile)
355
 
            # We need exactly a DEB or UDEB, not a DDEB.
356
 
            if (is_deb or is_udeb) and not is_ddeb:
 
362
            # We need exactly a DEB, not a DDEB.
 
363
            if (isinstance(uploaded_file, DebBinaryUploadFile) and
 
364
                not isinstance(uploaded_file, DdebBinaryUploadFile)):
357
365
                try:
358
366
                    matching_ddeb = unmatched_ddebs.pop(
359
367
                        (uploaded_file.package + '-dbgsym',
369
377
                "Orphaned debug packages: %s" % ', '.join(
370
378
                    '%s %s (%s)' % d for d in unmatched_ddebs))
371
379
 
372
 
    def _overrideDDEBSs(self):
373
 
        """Make sure that any DDEBs in the upload have the same overrides
374
 
        as their counterpart DEBs.  This method needs to be called *after*
375
 
        _matchDDEBS.
376
 
 
377
 
        This is required so that domination can supersede both files in
378
 
        lockstep.
379
 
        """
380
 
        for uploaded_file in self.changes.files:
381
 
            if isinstance(uploaded_file, DdebBinaryUploadFile):
382
 
                if uploaded_file.deb_file is not None:
383
 
                    self._overrideBinaryFile(uploaded_file,
384
 
                                             uploaded_file.deb_file)
385
380
    #
386
381
    # Helpers for warnings and rejections
387
382
    #
388
 
 
389
383
    def run_and_check_error(self, callable):
390
384
        """Run the given callable and process errors and warnings.
391
385
 
394
388
        try:
395
389
            callable()
396
390
        except UploadError, error:
397
 
            self.reject("".join(error.args))
 
391
            self.reject("".join(error.args).encode("utf8"))
398
392
        except UploadWarning, error:
399
 
            self.warn("".join(error.args))
 
393
            self.warn("".join(error.args).encode("utf8"))
400
394
 
401
395
    def run_and_collect_errors(self, callable):
402
396
        """Run 'special' callable that generates a list of errors/warnings.
416
410
        """
417
411
        for error in callable():
418
412
            if isinstance(error, UploadError):
419
 
                self.reject("".join(error.args))
 
413
                self.reject("".join(error.args).encode("utf8"))
420
414
            elif isinstance(error, UploadWarning):
421
 
                self.warn("".join(error.args))
 
415
                self.warn("".join(error.args).encode("utf8"))
422
416
            else:
423
417
                raise AssertionError(
424
418
                    "Unknown error occurred: %s" % str(error))
655
649
 
656
650
    def _checkVersion(self, proposed_version, archive_version, filename):
657
651
        """Check if the proposed version is higher than the one in archive."""
658
 
        if apt_pkg.version_compare(proposed_version, archive_version) < 0:
 
652
        if apt_pkg.VersionCompare(proposed_version, archive_version) < 0:
659
653
            self.reject("%s: Version older than that in the archive. %s <= %s"
660
654
                        % (filename, proposed_version, archive_version))
661
655
 
715
709
            override.binarypackagerelease.title,
716
710
            override.distroarchseries.architecturetag,
717
711
            override.pocket.name))
718
 
        self._overrideBinaryFile(uploaded_file, override)
719
712
 
720
 
    def _overrideBinaryFile(self, uploaded_file, override):
721
713
        uploaded_file.component_name = override.component.name
722
714
        uploaded_file.section_name = override.section.name
723
715
        # Both, changesfiles and nascentuploadfile local maps, reffer to
728
720
    def processUnknownFile(self, uploaded_file):
729
721
        """Apply a set of actions for newly-uploaded (unknown) files.
730
722
 
731
 
        Here we use the override policy defined in UnknownOverridePolicy.
 
723
        Newly-uploaded files have a default set of overrides to be applied.
 
724
        This reduces the amount of work that archive admins have to do
 
725
        since they override the majority of new uploads with the same
 
726
        values.  The rules for overriding are: (See bug #120052)
 
727
            'contrib' -> 'multiverse'
 
728
            'non-free' -> 'multiverse'
 
729
            everything else -> 'universe'
 
730
        This mainly relates to Debian syncs, where the default component
 
731
        is 'main' but should not be in main for Ubuntu.
732
732
 
733
733
        In the case of a PPA, files are not touched.  They are always
734
734
        overridden to 'main' at publishing time, though.
751
751
            # Don't override partner uploads.
752
752
            return
753
753
 
 
754
        component_override_map = {
 
755
            'contrib': 'multiverse',
 
756
            'non-free': 'multiverse',
 
757
            }
 
758
 
754
759
        # Apply the component override and default to universe.
755
 
        component_name_override = UnknownOverridePolicy.getComponentOverride(
756
 
            uploaded_file.component_name)
757
 
        uploaded_file.component_name = component_name_override
 
760
        uploaded_file.component_name = component_override_map.get(
 
761
            uploaded_file.component_name, 'universe')
758
762
 
759
763
    def find_and_apply_overrides(self):
760
764
        """Look for ancestry and overrides information.
768
772
            if isinstance(uploaded_file, DSCFile):
769
773
                self.logger.debug(
770
774
                    "Checking for %s/%s source ancestry"
771
 
                    % (uploaded_file.package, uploaded_file.version))
 
775
                    %(uploaded_file.package, uploaded_file.version))
772
776
                ancestry = self.getSourceAncestry(uploaded_file)
773
777
                if ancestry is not None:
774
778
                    self.checkSourceVersion(uploaded_file, ancestry)
788
792
            elif isinstance(uploaded_file, BaseBinaryUploadFile):
789
793
                self.logger.debug(
790
794
                    "Checking for %s/%s/%s binary ancestry"
791
 
                    % (
792
 
                        uploaded_file.package,
793
 
                        uploaded_file.version,
794
 
                        uploaded_file.architecture,
795
 
                        ))
 
795
                    %(uploaded_file.package, uploaded_file.version,
 
796
                      uploaded_file.architecture))
796
797
                try:
797
798
                    ancestry = self.getBinaryAncestry(uploaded_file)
798
799
                except NotFoundError:
927
928
            return distroseries.createQueueEntry(
928
929
                PackagePublishingPocket.RELEASE,
929
930
                distroseries.main_archive, self.changes.filename,
930
 
                self.changes.raw_content, signing_key=self.changes.signingkey)
 
931
                self.changes.raw_content, self.changes.signingkey)
931
932
        else:
932
933
            return distroseries.createQueueEntry(
933
934
                self.policy.pocket, self.policy.archive,
934
935
                self.changes.filename, self.changes.raw_content,
935
 
                signing_key=self.changes.signingkey)
 
936
                self.changes.signingkey)
936
937
 
937
938
    #
938
939
    # Inserting stuff in the database