1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
|
# Copyright 2010 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
__metaclass__ = type
__all__ = [
"InitializeDistroSeriesJob",
]
from zope.interface import (
classProvides,
implements,
)
from lp.services.database.lpstorm import (
IMasterStore,
IStore,
)
from lp.registry.model.distroseries import DistroSeries
from lp.services.job.interfaces.job import JobStatus
from lp.services.job.model.job import Job
from lp.soyuz.interfaces.distributionjob import (
DistributionJobType,
IInitializeDistroSeriesJob,
IInitializeDistroSeriesJobSource,
InitializationCompleted,
InitializationPending,
)
from lp.soyuz.model.distributionjob import (
DistributionJob,
DistributionJobDerived,
)
from lp.soyuz.model.packageset import Packageset
from lp.soyuz.scripts.initialize_distroseries import (
InitializationError,
InitializeDistroSeries,
)
class InitializeDistroSeriesJob(DistributionJobDerived):
implements(IInitializeDistroSeriesJob)
class_job_type = DistributionJobType.INITIALIZE_SERIES
classProvides(IInitializeDistroSeriesJobSource)
user_error_types = (InitializationError,)
@classmethod
def create(cls, child, parents, arches=(), archindep_archtag=None,
packagesets=(), rebuild=False, overlays=(),
overlay_pockets=(), overlay_components=()):
"""Create a new `InitializeDistroSeriesJob`.
:param child: The child `IDistroSeries` to initialize
:param parents: An iterable of `IDistroSeries` of parents to
initialize from.
:param arches: An iterable of architecture tags which lists the
architectures to enable in the child.
:param packagesets: An iterable of `PackageSet` IDs from which to
copy packages in parents.
:param rebuild: A boolean to say whether the child should rebuild
all the copied sources (if True), or to copy the parents'
binaries (if False).
:param overlays: An iterable of booleans corresponding exactly to
each parent in the "parents" parameter. Each boolean says
whether this corresponding parent is an overlay for the child
or not. An overlay allows the child to use the parent's
packages for build dependencies, and the overlay_pockets and
overlay_components parameters dictate from where the
dependencies may be used in the parent.
:param overlay_pockets: An iterable of textual pocket names
corresponding exactly to each parent. The name *must* be set
if the corresponding overlays boolean is True.
:param overlay_components: An iterable of textual component names
corresponding exactly to each parent. The name *must* be set
if the corresponding overlays boolean is True.
"""
store = IMasterStore(DistributionJob)
# Only one InitializeDistroSeriesJob can be present at a time.
distribution_job = store.find(
DistributionJob, DistributionJob.job_id == Job.id,
DistributionJob.job_type == cls.class_job_type,
DistributionJob.distroseries_id == child.id).one()
if distribution_job is not None:
if distribution_job.job.status == JobStatus.FAILED:
# Delete the failed job to allow initialization of the series
# to be rescheduled.
store.remove(distribution_job)
store.remove(distribution_job.job)
elif distribution_job.job.status == JobStatus.COMPLETED:
raise InitializationCompleted(cls(distribution_job))
else:
raise InitializationPending(cls(distribution_job))
# Schedule the initialization.
metadata = {
'parents': parents,
'arches': arches,
'archindep_archtag': archindep_archtag,
'packagesets': packagesets,
'rebuild': rebuild,
'overlays': overlays,
'overlay_pockets': overlay_pockets,
'overlay_components': overlay_components,
}
distribution_job = DistributionJob(
child.distribution, child, cls.class_job_type, metadata)
store.add(distribution_job)
return cls(distribution_job)
@classmethod
def get(cls, distroseries):
"""See `IInitializeDistroSeriesJob`."""
distribution_job = IStore(DistributionJob).find(
DistributionJob, DistributionJob.job_id == Job.id,
DistributionJob.job_type == cls.class_job_type,
DistributionJob.distroseries_id == distroseries.id).one()
return None if distribution_job is None else cls(distribution_job)
def __repr__(self):
"""Returns an informative representation of the job."""
# This code assumes the job is referentially intact with good data,
# or it will blow up.
parts = "%s for" % self.__class__.__name__
parts += " distribution: %s" % self.distribution.name
parts += ", distroseries: %s" % self.distroseries.name
parts += ", parent[overlay?/pockets/components]: "
parents = []
for i in range(len(self.overlays)):
series = DistroSeries.get(self.parents[i])
parents.append("%s[%s/%s/%s]" % (
series.name,
self.overlays[i],
self.overlay_pockets[i],
self.overlay_components[i]))
parts += ",".join(parents)
pkgsets = [
IStore(Packageset).get(Packageset, int(pkgsetid)).name
for pkgsetid in self.packagesets]
parts += ", architectures: %s" % (self.arches,)
parts += ", archindep_archtag: %s" % self.archindep_archtag
parts += ", packagesets: %s" % pkgsets
parts += ", rebuild: %s" % self.rebuild
return "<%s>" % parts
@property
def parents(self):
return tuple(self.metadata['parents'])
@property
def overlays(self):
if self.metadata['overlays'] is None:
return ()
else:
return tuple(self.metadata['overlays'])
@property
def overlay_pockets(self):
if self.metadata['overlay_pockets'] is None:
return ()
else:
return tuple(self.metadata['overlay_pockets'])
@property
def overlay_components(self):
if self.metadata['overlay_components'] is None:
return ()
else:
return tuple(self.metadata['overlay_components'])
@property
def arches(self):
if self.metadata['arches'] is None:
return ()
else:
return tuple(self.metadata['arches'])
@property
def archindep_archtag(self):
return self.metadata['archindep_archtag']
@property
def packagesets(self):
if self.metadata['packagesets'] is None:
return ()
else:
return tuple(self.metadata['packagesets'])
@property
def rebuild(self):
return self.metadata['rebuild']
@property
def error_description(self):
return self.metadata.get("error_description")
def run(self):
"""See `IRunnableJob`."""
ids = InitializeDistroSeries(
self.distroseries, self.parents, self.arches,
self.archindep_archtag, self.packagesets, self.rebuild,
self.overlays, self.overlay_pockets, self.overlay_components)
ids.check()
ids.initialize()
def notifyUserError(self, error):
"""Calls up and slso saves the error text in this job's metadata.
See `BaseRunnableJob`.
"""
# This method is called when error is an instance of
# self.user_error_types.
super(InitializeDistroSeriesJob, self).notifyUserError(error)
self.metadata = dict(self.metadata, error_description=unicode(error))
def getOopsVars(self):
"""See `IRunnableJob`."""
vars = super(InitializeDistroSeriesJob, self).getOopsVars()
vars.append(('parent_distroseries_ids', self.metadata.get("parents")))
return vars
|