~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/soyuz/adapters/overrides.py

Merge db-devel.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2011 Canonical Ltd.  This software is licensed under the
 
2
# GNU Affero General Public License version 3 (see the file LICENSE).
 
3
 
 
4
"""Generic Override Policy classes.
 
5
"""
 
6
 
 
7
__metaclass__ = type
 
8
 
 
9
__all__ = [
 
10
    'FromExistingOverridePolicy',
 
11
    'UbuntuOverridePolicy',
 
12
    'UnknownOverridePolicy',
 
13
    ]
 
14
 
 
15
 
 
16
from storm.expr import (
 
17
    And,
 
18
    Desc,
 
19
    Or,
 
20
    SQL,
 
21
    )
 
22
 
 
23
from canonical.launchpad.components.decoratedresultset import (
 
24
    DecoratedResultSet,
 
25
    )
 
26
from canonical.launchpad.interfaces.lpstorm import IStore
 
27
from lp.registry.model.sourcepackagename import SourcePackageName
 
28
from lp.services.database import bulk
 
29
from lp.soyuz.interfaces.publishing import active_publishing_status
 
30
from lp.soyuz.model.binarypackagename import BinaryPackageName
 
31
from lp.soyuz.model.binarypackagerelease import BinaryPackageRelease
 
32
from lp.soyuz.model.component import Component
 
33
from lp.soyuz.model.distroarchseries import DistroArchSeries
 
34
from lp.soyuz.model.publishing import (
 
35
    BinaryPackagePublishingHistory,
 
36
    SourcePackagePublishingHistory,
 
37
    )
 
38
from lp.soyuz.model.section import Section
 
39
from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease
 
40
 
 
41
 
 
42
class BaseOverridePolicy:
 
43
 
 
44
    def calculateSourceOverrides(self, archive, distroseries, pocket,
 
45
                                 sources):
 
46
        raise NotImplementedError()
 
47
 
 
48
    def calculateBinaryOverrides(self, archive, distroseries, pocket,
 
49
                                 binaries):
 
50
        raise NotImplementedError()
 
51
 
 
52
 
 
53
class FromExistingOverridePolicy(BaseOverridePolicy):
 
54
    """Override policy that only searches for existing publications.
 
55
    
 
56
    Override policy that returns the SourcePackageName, component and
 
57
    section for the latest published source publication, or the
 
58
    BinaryPackageName, DistroArchSeries, component, section and priority
 
59
    for the latest published binary publication.
 
60
    """
 
61
 
 
62
    def calculateSourceOverrides(self, archive, distroseries, pocket, spns):
 
63
        store = IStore(SourcePackagePublishingHistory)
 
64
        def eager_load(rows):
 
65
            bulk.load(Component, (row[1] for row in rows))
 
66
            bulk.load(Section, (row[2] for row in rows))
 
67
        already_published = DecoratedResultSet(
 
68
            store.find(
 
69
                (SourcePackageRelease.sourcepackagenameID,
 
70
                 SourcePackagePublishingHistory.componentID,
 
71
                 SourcePackagePublishingHistory.sectionID),
 
72
                SourcePackagePublishingHistory.pocket == pocket,
 
73
                SourcePackagePublishingHistory.archiveID == archive.id,
 
74
                SourcePackagePublishingHistory.distroseriesID ==
 
75
                    distroseries.id,
 
76
                SourcePackagePublishingHistory.status.is_in(
 
77
                    active_publishing_status),
 
78
                SourcePackageRelease.id ==
 
79
                    SourcePackagePublishingHistory.sourcepackagereleaseID,
 
80
                SourcePackageRelease.sourcepackagenameID.is_in(
 
81
                    spn.id for spn in spns)).order_by(
 
82
                        SourcePackageRelease.sourcepackagenameID,
 
83
                        Desc(SourcePackagePublishingHistory.datecreated),
 
84
                        Desc(SourcePackagePublishingHistory.id),
 
85
                ).config(
 
86
                    distinct=(SourcePackageRelease.sourcepackagenameID,)),
 
87
            id_resolver((SourcePackageName, Component, Section)),
 
88
            pre_iter_hook=eager_load)
 
89
        return list(already_published)
 
90
 
 
91
    def calculateBinaryOverrides(self, archive, distroseries, pocket,
 
92
                                 binaries):
 
93
        store = IStore(BinaryPackagePublishingHistory)
 
94
        def eager_load(rows):
 
95
            bulk.load(Component, (row[2] for row in rows))
 
96
            bulk.load(Section, (row[3] for row in rows))
 
97
        expanded = calculate_target_das(distroseries, binaries)
 
98
        candidates = (
 
99
            make_package_condition(archive, das, bpn)
 
100
            for bpn, das in expanded)
 
101
        already_published = DecoratedResultSet(
 
102
            store.find(
 
103
                (BinaryPackageRelease.binarypackagenameID,
 
104
                 BinaryPackagePublishingHistory.distroarchseriesID,
 
105
                 BinaryPackagePublishingHistory.componentID,
 
106
                 BinaryPackagePublishingHistory.sectionID,
 
107
                 BinaryPackagePublishingHistory.priority),
 
108
                BinaryPackagePublishingHistory.pocket == pocket,
 
109
                BinaryPackagePublishingHistory.status.is_in(
 
110
                    active_publishing_status),
 
111
                BinaryPackageRelease.id ==
 
112
                    BinaryPackagePublishingHistory.binarypackagereleaseID,
 
113
                Or(*candidates)).order_by(
 
114
                    BinaryPackagePublishingHistory.distroarchseriesID,
 
115
                    BinaryPackageRelease.binarypackagenameID,
 
116
                    Desc(BinaryPackagePublishingHistory.datecreated),
 
117
                    Desc(BinaryPackagePublishingHistory.id),
 
118
                ).config(distinct=(
 
119
                    BinaryPackagePublishingHistory.distroarchseriesID,
 
120
                    BinaryPackageRelease.binarypackagenameID,
 
121
                    )
 
122
                ),
 
123
            id_resolver(
 
124
                (BinaryPackageName, DistroArchSeries, Component, Section,
 
125
                None)),
 
126
            pre_iter_hook=eager_load)
 
127
        return list(already_published)
 
128
 
 
129
 
 
130
class UnknownOverridePolicy(BaseOverridePolicy):
 
131
    """Override policy that returns defaults.
 
132
    
 
133
    Override policy that assumes everything passed in doesn't exist, so
 
134
    returns the defaults.
 
135
    """
 
136
    
 
137
    def calculateSourceOverrides(self, archive, distroseries, pocket,
 
138
                                 sources):
 
139
        default_component = archive.default_component or 'universe'
 
140
        return [(source, default_component, None) for source in sources]
 
141
 
 
142
    def calculateBinaryOverrides(self, archive, distroseries, pocket,
 
143
                                 binaries):
 
144
        default_component = archive.default_component or 'universe'
 
145
        return [
 
146
            (binary, das, default_component, None, None)
 
147
            for binary, das in calculate_target_das(distroseries, binaries)]
 
148
 
 
149
 
 
150
class UbuntuOverridePolicy(FromExistingOverridePolicy,
 
151
                           UnknownOverridePolicy):
 
152
    """Override policy for Ubuntu.
 
153
    
 
154
    An override policy that incorporates both the from existing policy 
 
155
    and the unknown policy.
 
156
    """
 
157
 
 
158
    def calculateSourceOverrides(self, archive, distroseries, pocket,
 
159
                                 sources):
 
160
        total = set(sources)
 
161
        overrides = FromExistingOverridePolicy.calculateSourceOverrides(
 
162
            self, archive, distroseries, pocket, sources)
 
163
        existing = set(override[0] for override in overrides)
 
164
        missing = total.difference(existing)
 
165
        if missing:
 
166
            unknown = UnknownOverridePolicy.calculateSourceOverrides(
 
167
                self, archive, distroseries, pocket, missing)
 
168
            overrides.extend(unknown)
 
169
        return overrides
 
170
 
 
171
    def calculateBinaryOverrides(self, archive, distroseries, pocket,
 
172
                                 binaries):
 
173
        total = set(binaries)
 
174
        overrides = FromExistingOverridePolicy.calculateBinaryOverrides(
 
175
            self, archive, distroseries, pocket, binaries)
 
176
        existing = set((
 
177
            overide[0], overide[1].architecturetag)
 
178
                for overide in overrides)
 
179
        missing = total.difference(existing)
 
180
        if missing:
 
181
            unknown = UnknownOverridePolicy.calculateBinaryOverrides(
 
182
                self, archive, distroseries, pocket, missing)
 
183
            overrides.extend(unknown)
 
184
        return overrides
 
185
 
 
186
 
 
187
def calculate_target_das(distroseries, binaries):
 
188
    arch_map = dict(
 
189
        (arch.architecturetag, arch)
 
190
        for arch in distroseries.enabled_architectures)
 
191
 
 
192
    with_das = []
 
193
    for bpn, archtag in binaries:
 
194
        if archtag is not None:
 
195
            with_das.append((bpn, arch_map.get(archtag)))
 
196
        else:
 
197
            with_das.append((bpn, distroseries.nominatedarchindep))
 
198
    return with_das
 
199
 
 
200
 
 
201
def make_package_condition(archive, das, bpn):
 
202
    return And(
 
203
        BinaryPackagePublishingHistory.archiveID == archive.id,
 
204
        BinaryPackagePublishingHistory.distroarchseriesID == das.id,
 
205
        BinaryPackageRelease.binarypackagenameID == bpn.id)
 
206
 
 
207
 
 
208
def id_resolver(lookups):
 
209
    def _resolve(row):
 
210
        store = IStore(SourcePackagePublishingHistory)
 
211
        return tuple(
 
212
            (value if cls is None else store.get(cls, value))
 
213
            for value, cls in zip(row, lookups))
 
214
    return _resolve