~launchpad-pqm/launchpad/devel

7675.818.6 by Steve Kowalik
* Rename InitialiseDistroSeriesJob to DistributionJob, and pass both a
1
# Copyright 2010 Canonical Ltd.  This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
3
4
__metaclass__ = type
5
6
__all__ = [
13194.2.1 by Gavin Panella
Change all uses of 'initialise' to 'initialize'.
7
    "InitializeDistroSeriesJob",
7675.818.6 by Steve Kowalik
* Rename InitialiseDistroSeriesJob to DistributionJob, and pass both a
8
]
9
12494.1.80 by Gavin Panella
InitialiseDistroSeriesJob now take a mandatory parent argument.
10
from zope.interface import (
11
    classProvides,
12
    implements,
13
    )
13168.5.1 by Raphael Badin
Initialisedistroseriesjob should support None arguments.
14
14560.2.29 by Curtis Hovey
Restored lpstorm module name because it lp engineers know that name.
15
from lp.services.database.lpstorm import (
12494.1.80 by Gavin Panella
InitialiseDistroSeriesJob now take a mandatory parent argument.
16
    IMasterStore,
17
    IStore,
18
    )
13586.1.2 by Julian Edwards
Vague stab at an initializedistroseriesjob __repr__
19
from lp.registry.model.distroseries import DistroSeries
13237.1.2 by Gavin Panella
Restrict the delete to only failed jobs.
20
from lp.services.job.interfaces.job import JobStatus
13168.5.1 by Raphael Badin
Initialisedistroseriesjob should support None arguments.
21
from lp.services.job.model.job import Job
7675.818.6 by Steve Kowalik
* Rename InitialiseDistroSeriesJob to DistributionJob, and pass both a
22
from lp.soyuz.interfaces.distributionjob import (
23
    DistributionJobType,
13194.2.1 by Gavin Panella
Change all uses of 'initialise' to 'initialize'.
24
    IInitializeDistroSeriesJob,
25
    IInitializeDistroSeriesJobSource,
13237.1.3 by Gavin Panella
If the job is completed, raise InitializationCompleted instead.
26
    InitializationCompleted,
13237.1.1 by Gavin Panella
If there's an existing completed InitializeDistroSeriesJob when creating a new one, delete it first.
27
    InitializationPending,
7675.818.7 by Steve Kowalik
* Rename DoDistributionJob to InitialiseDistroSeriesJob.
28
    )
7675.818.6 by Steve Kowalik
* Rename InitialiseDistroSeriesJob to DistributionJob, and pass both a
29
from lp.soyuz.model.distributionjob import (
30
    DistributionJob,
7675.818.7 by Steve Kowalik
* Rename DoDistributionJob to InitialiseDistroSeriesJob.
31
    DistributionJobDerived,
32
    )
13586.1.2 by Julian Edwards
Vague stab at an initializedistroseriesjob __repr__
33
from lp.soyuz.model.packageset import Packageset
13891.1.3 by Gavin Panella
Populate the error_description property on InitializeDistroSeriesJob.
34
from lp.soyuz.scripts.initialize_distroseries import (
35
    InitializationError,
36
    InitializeDistroSeries,
37
    )
13194.2.1 by Gavin Panella
Change all uses of 'initialise' to 'initialize'.
38
39
40
class InitializeDistroSeriesJob(DistributionJobDerived):
41
42
    implements(IInitializeDistroSeriesJob)
43
44
    class_job_type = DistributionJobType.INITIALIZE_SERIES
45
    classProvides(IInitializeDistroSeriesJobSource)
7675.818.6 by Steve Kowalik
* Rename InitialiseDistroSeriesJob to DistributionJob, and pass both a
46
13891.1.3 by Gavin Panella
Populate the error_description property on InitializeDistroSeriesJob.
47
    user_error_types = (InitializationError,)
48
7675.818.6 by Steve Kowalik
* Rename InitialiseDistroSeriesJob to DistributionJob, and pass both a
49
    @classmethod
14108.2.8 by Raphael Badin
Add a archindep_archtag optional argument to derived series initialization.
50
    def create(cls, child, parents, arches=(), archindep_archtag=None,
51
               packagesets=(), rebuild=False, overlays=(),
52
               overlay_pockets=(), overlay_components=()):
13586.1.4 by Julian Edwards
Add a lovely docstring.
53
        """Create a new `InitializeDistroSeriesJob`.
54
55
        :param child: The child `IDistroSeries` to initialize
56
        :param parents: An iterable of `IDistroSeries` of parents to
57
            initialize from.
58
        :param arches: An iterable of architecture tags which lists the
59
            architectures to enable in the child.
60
        :param packagesets: An iterable of `PackageSet` IDs from which to
61
            copy packages in parents.
62
        :param rebuild: A boolean to say whether the child should rebuild
63
            all the copied sources (if True), or to copy the parents'
64
            binaries (if False).
65
        :param overlays: An iterable of booleans corresponding exactly to
66
            each parent in the "parents" parameter.  Each boolean says
67
            whether this corresponding parent is an overlay for the child
68
            or not.  An overlay allows the child to use the parent's
69
            packages for build dependencies, and the overlay_pockets and
70
            overlay_components parameters dictate from where the
71
            dependencies may be used in the parent.
72
        :param overlay_pockets: An iterable of textual pocket names
73
            corresponding exactly to each parent.  The  name *must* be set
74
            if the corresponding overlays boolean is True.
75
        :param overlay_components: An iterable of textual component names
76
            corresponding exactly to each parent.  The  name *must* be set
77
            if the corresponding overlays boolean is True.
78
        """
13237.1.1 by Gavin Panella
If there's an existing completed InitializeDistroSeriesJob when creating a new one, delete it first.
79
        store = IMasterStore(DistributionJob)
80
        # Only one InitializeDistroSeriesJob can be present at a time.
81
        distribution_job = store.find(
82
            DistributionJob, DistributionJob.job_id == Job.id,
83
            DistributionJob.job_type == cls.class_job_type,
84
            DistributionJob.distroseries_id == child.id).one()
85
        if distribution_job is not None:
13237.1.2 by Gavin Panella
Restrict the delete to only failed jobs.
86
            if distribution_job.job.status == JobStatus.FAILED:
87
                # Delete the failed job to allow initialization of the series
88
                # to be rescheduled.
89
                store.remove(distribution_job)
90
                store.remove(distribution_job.job)
13237.1.3 by Gavin Panella
If the job is completed, raise InitializationCompleted instead.
91
            elif distribution_job.job.status == JobStatus.COMPLETED:
92
                raise InitializationCompleted(cls(distribution_job))
13237.1.2 by Gavin Panella
Restrict the delete to only failed jobs.
93
            else:
13237.1.1 by Gavin Panella
If there's an existing completed InitializeDistroSeriesJob when creating a new one, delete it first.
94
                raise InitializationPending(cls(distribution_job))
95
        # Schedule the initialization.
7675.877.3 by Steve Kowalik
Add all parameters
96
        metadata = {
13117.2.7 by Raphael Badin
Pass parents by id to initDerivedSeries.
97
            'parents': parents,
7675.877.6 by Steve Kowalik
Fix minor code formatting issue
98
            'arches': arches,
14108.2.8 by Raphael Badin
Add a archindep_archtag optional argument to derived series initialization.
99
            'archindep_archtag': archindep_archtag,
7675.877.6 by Steve Kowalik
Fix minor code formatting issue
100
            'packagesets': packagesets,
101
            'rebuild': rebuild,
13117.2.8 by Raphael Badin
Add overlay support to initseries.
102
            'overlays': overlays,
103
            'overlay_pockets': overlay_pockets,
104
            'overlay_components': overlay_components,
7675.877.6 by Steve Kowalik
Fix minor code formatting issue
105
            }
13237.1.1 by Gavin Panella
If there's an existing completed InitializeDistroSeriesJob when creating a new one, delete it first.
106
        distribution_job = DistributionJob(
107
            child.distribution, child, cls.class_job_type, metadata)
108
        store.add(distribution_job)
109
        return cls(distribution_job)
7675.818.6 by Steve Kowalik
* Rename InitialiseDistroSeriesJob to DistributionJob, and pass both a
110
12792.7.1 by Raphael Badin
Add stats portlet for derived series.
111
    @classmethod
13375.4.6 by Gavin Panella
There can only ever be one InitializeDistroSeriesJob per distroseries, so change getJobsForDistroseries() to simply get().
112
    def get(cls, distroseries):
13194.2.1 by Gavin Panella
Change all uses of 'initialise' to 'initialize'.
113
        """See `IInitializeDistroSeriesJob`."""
13375.4.6 by Gavin Panella
There can only ever be one InitializeDistroSeriesJob per distroseries, so change getJobsForDistroseries() to simply get().
114
        distribution_job = IStore(DistributionJob).find(
115
            DistributionJob, DistributionJob.job_id == Job.id,
13237.1.1 by Gavin Panella
If there's an existing completed InitializeDistroSeriesJob when creating a new one, delete it first.
116
            DistributionJob.job_type == cls.class_job_type,
13375.4.6 by Gavin Panella
There can only ever be one InitializeDistroSeriesJob per distroseries, so change getJobsForDistroseries() to simply get().
117
            DistributionJob.distroseries_id == distroseries.id).one()
118
        return None if distribution_job is None else cls(distribution_job)
12792.7.1 by Raphael Badin
Add stats portlet for derived series.
119
13586.1.2 by Julian Edwards
Vague stab at an initializedistroseriesjob __repr__
120
    def __repr__(self):
121
        """Returns an informative representation of the job."""
122
        # This code assumes the job is referentially intact with good data,
123
        # or it will blow up.
124
        parts = "%s for" % self.__class__.__name__
125
        parts += " distribution: %s" % self.distribution.name
126
        parts += ", distroseries: %s" % self.distroseries.name
127
        parts += ", parent[overlay?/pockets/components]: "
128
        parents = []
13586.1.5 by Julian Edwards
Make sure repr works when there's no overlays set. Useful for lazy tests
129
        for i in range(len(self.overlays)):
13586.1.2 by Julian Edwards
Vague stab at an initializedistroseriesjob __repr__
130
            series = DistroSeries.get(self.parents[i])
131
            parents.append("%s[%s/%s/%s]" % (
132
                series.name,
133
                self.overlays[i],
134
                self.overlay_pockets[i],
135
                self.overlay_components[i]))
136
        parts += ",".join(parents)
137
        pkgsets = [
138
            IStore(Packageset).get(Packageset, int(pkgsetid)).name
139
            for pkgsetid in  self.packagesets]
140
        parts += ", architectures: %s" % (self.arches,)
14108.2.9 by Raphael Badin
Fix style.
141
        parts += ", archindep_archtag: %s" % self.archindep_archtag
13586.1.2 by Julian Edwards
Vague stab at an initializedistroseriesjob __repr__
142
        parts += ", packagesets: %s" % pkgsets
143
        parts += ", rebuild: %s" % self.rebuild
144
        return "<%s>" % parts
145
12494.1.82 by Gavin Panella
No need for InitialiseDistroSeriesJob.parent to be cached.
146
    @property
13117.2.1 by Raphael Badin
Fix initseries to support multiple parents as an argument.
147
    def parents(self):
13117.2.5 by Raphael Badin
Fix initseriesjob's tests.
148
        return tuple(self.metadata['parents'])
12494.1.80 by Gavin Panella
InitialiseDistroSeriesJob now take a mandatory parent argument.
149
7675.877.1 by Steve Kowalik
* Change create to also accept an arches and packagesets argument.
150
    @property
13117.2.8 by Raphael Badin
Add overlay support to initseries.
151
    def overlays(self):
13168.5.1 by Raphael Badin
Initialisedistroseriesjob should support None arguments.
152
        if self.metadata['overlays'] is None:
153
            return ()
154
        else:
155
            return tuple(self.metadata['overlays'])
13117.2.8 by Raphael Badin
Add overlay support to initseries.
156
157
    @property
158
    def overlay_pockets(self):
13168.5.1 by Raphael Badin
Initialisedistroseriesjob should support None arguments.
159
        if self.metadata['overlay_pockets'] is None:
160
            return ()
161
        else:
162
            return tuple(self.metadata['overlay_pockets'])
13117.2.8 by Raphael Badin
Add overlay support to initseries.
163
164
    @property
165
    def overlay_components(self):
13168.5.1 by Raphael Badin
Initialisedistroseriesjob should support None arguments.
166
        if self.metadata['overlay_components'] is None:
167
            return ()
168
        else:
169
            return tuple(self.metadata['overlay_components'])
13117.2.8 by Raphael Badin
Add overlay support to initseries.
170
171
    @property
7675.877.1 by Steve Kowalik
* Change create to also accept an arches and packagesets argument.
172
    def arches(self):
13168.5.1 by Raphael Badin
Initialisedistroseriesjob should support None arguments.
173
        if self.metadata['arches'] is None:
174
            return ()
175
        else:
176
            return tuple(self.metadata['arches'])
7675.877.1 by Steve Kowalik
* Change create to also accept an arches and packagesets argument.
177
178
    @property
14108.2.8 by Raphael Badin
Add a archindep_archtag optional argument to derived series initialization.
179
    def archindep_archtag(self):
180
        return self.metadata['archindep_archtag']
181
182
    @property
7675.877.1 by Steve Kowalik
* Change create to also accept an arches and packagesets argument.
183
    def packagesets(self):
13168.5.1 by Raphael Badin
Initialisedistroseriesjob should support None arguments.
184
        if self.metadata['packagesets'] is None:
185
            return ()
186
        else:
187
            return tuple(self.metadata['packagesets'])
7675.877.1 by Steve Kowalik
* Change create to also accept an arches and packagesets argument.
188
7675.877.3 by Steve Kowalik
Add all parameters
189
    @property
190
    def rebuild(self):
191
        return self.metadata['rebuild']
192
13891.1.2 by Gavin Panella
Introduce the error_description property.
193
    @property
194
    def error_description(self):
195
        return self.metadata.get("error_description")
196
7675.818.6 by Steve Kowalik
* Rename InitialiseDistroSeriesJob to DistributionJob, and pass both a
197
    def run(self):
198
        """See `IRunnableJob`."""
13194.2.1 by Gavin Panella
Change all uses of 'initialise' to 'initialize'.
199
        ids = InitializeDistroSeries(
13117.2.1 by Raphael Badin
Fix initseries to support multiple parents as an argument.
200
            self.distroseries, self.parents, self.arches,
14108.2.8 by Raphael Badin
Add a archindep_archtag optional argument to derived series initialization.
201
            self.archindep_archtag, self.packagesets, self.rebuild,
202
            self.overlays, self.overlay_pockets, self.overlay_components)
7675.818.6 by Steve Kowalik
* Rename InitialiseDistroSeriesJob to DistributionJob, and pass both a
203
        ids.check()
13194.2.1 by Gavin Panella
Change all uses of 'initialise' to 'initialize'.
204
        ids.initialize()
12494.1.80 by Gavin Panella
InitialiseDistroSeriesJob now take a mandatory parent argument.
205
13891.1.3 by Gavin Panella
Populate the error_description property on InitializeDistroSeriesJob.
206
    def notifyUserError(self, error):
207
        """Calls up and slso saves the error text in this job's metadata.
208
209
        See `BaseRunnableJob`.
210
        """
211
        # This method is called when error is an instance of
212
        # self.user_error_types.
213
        super(InitializeDistroSeriesJob, self).notifyUserError(error)
13891.2.1 by Gavin Panella
Switch DistributionJob.metadata/_json_data to a single JSON property called metadata.
214
        self.metadata = dict(self.metadata, error_description=unicode(error))
13891.1.3 by Gavin Panella
Populate the error_description property on InitializeDistroSeriesJob.
215
12494.1.80 by Gavin Panella
InitialiseDistroSeriesJob now take a mandatory parent argument.
216
    def getOopsVars(self):
217
        """See `IRunnableJob`."""
13194.2.1 by Gavin Panella
Change all uses of 'initialise' to 'initialize'.
218
        vars = super(InitializeDistroSeriesJob, self).getOopsVars()
13117.2.1 by Raphael Badin
Fix initseries to support multiple parents as an argument.
219
        vars.append(('parent_distroseries_ids', self.metadata.get("parents")))
12494.1.80 by Gavin Panella
InitialiseDistroSeriesJob now take a mandatory parent argument.
220
        return vars