~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
13891.1.6 by Gavin Panella
Switch to the JSON property raises other issues; reverting for now.
10
import simplejson
12494.1.80 by Gavin Panella
InitialiseDistroSeriesJob now take a mandatory parent argument.
11
from zope.interface import (
12
    classProvides,
13
    implements,
14
    )
13168.5.1 by Raphael Badin
Initialisedistroseriesjob should support None arguments.
15
12494.1.80 by Gavin Panella
InitialiseDistroSeriesJob now take a mandatory parent argument.
16
from canonical.launchpad.interfaces.lpstorm import (
17
    IMasterStore,
18
    IStore,
19
    )
13586.1.2 by Julian Edwards
Vague stab at an initializedistroseriesjob __repr__
20
from lp.registry.model.distroseries import DistroSeries
13237.1.2 by Gavin Panella
Restrict the delete to only failed jobs.
21
from lp.services.job.interfaces.job import JobStatus
13168.5.1 by Raphael Badin
Initialisedistroseriesjob should support None arguments.
22
from lp.services.job.model.job import Job
7675.818.6 by Steve Kowalik
* Rename InitialiseDistroSeriesJob to DistributionJob, and pass both a
23
from lp.soyuz.interfaces.distributionjob import (
24
    DistributionJobType,
13194.2.1 by Gavin Panella
Change all uses of 'initialise' to 'initialize'.
25
    IInitializeDistroSeriesJob,
26
    IInitializeDistroSeriesJobSource,
13237.1.3 by Gavin Panella
If the job is completed, raise InitializationCompleted instead.
27
    InitializationCompleted,
13237.1.1 by Gavin Panella
If there's an existing completed InitializeDistroSeriesJob when creating a new one, delete it first.
28
    InitializationPending,
7675.818.7 by Steve Kowalik
* Rename DoDistributionJob to InitialiseDistroSeriesJob.
29
    )
7675.818.6 by Steve Kowalik
* Rename InitialiseDistroSeriesJob to DistributionJob, and pass both a
30
from lp.soyuz.model.distributionjob import (
31
    DistributionJob,
7675.818.7 by Steve Kowalik
* Rename DoDistributionJob to InitialiseDistroSeriesJob.
32
    DistributionJobDerived,
33
    )
13586.1.2 by Julian Edwards
Vague stab at an initializedistroseriesjob __repr__
34
from lp.soyuz.model.packageset import Packageset
13891.1.3 by Gavin Panella
Populate the error_description property on InitializeDistroSeriesJob.
35
from lp.soyuz.scripts.initialize_distroseries import (
36
    InitializationError,
37
    InitializeDistroSeries,
38
    )
13194.2.1 by Gavin Panella
Change all uses of 'initialise' to 'initialize'.
39
40
41
class InitializeDistroSeriesJob(DistributionJobDerived):
42
43
    implements(IInitializeDistroSeriesJob)
44
45
    class_job_type = DistributionJobType.INITIALIZE_SERIES
46
    classProvides(IInitializeDistroSeriesJobSource)
7675.818.6 by Steve Kowalik
* Rename InitialiseDistroSeriesJob to DistributionJob, and pass both a
47
13891.1.3 by Gavin Panella
Populate the error_description property on InitializeDistroSeriesJob.
48
    user_error_types = (InitializationError,)
49
7675.818.6 by Steve Kowalik
* Rename InitialiseDistroSeriesJob to DistributionJob, and pass both a
50
    @classmethod
13117.2.8 by Raphael Badin
Add overlay support to initseries.
51
    def create(cls, child, parents, arches=(), packagesets=(),
13117.2.13 by Raphael Badin
Use immutable objects for default parameters (MP's comments).
52
               rebuild=False, overlays=(), overlay_pockets=(),
53
               overlay_components=()):
13586.1.4 by Julian Edwards
Add a lovely docstring.
54
        """Create a new `InitializeDistroSeriesJob`.
55
56
        :param child: The child `IDistroSeries` to initialize
57
        :param parents: An iterable of `IDistroSeries` of parents to
58
            initialize from.
59
        :param arches: An iterable of architecture tags which lists the
60
            architectures to enable in the child.
61
        :param packagesets: An iterable of `PackageSet` IDs from which to
62
            copy packages in parents.
63
        :param rebuild: A boolean to say whether the child should rebuild
64
            all the copied sources (if True), or to copy the parents'
65
            binaries (if False).
66
        :param overlays: An iterable of booleans corresponding exactly to
67
            each parent in the "parents" parameter.  Each boolean says
68
            whether this corresponding parent is an overlay for the child
69
            or not.  An overlay allows the child to use the parent's
70
            packages for build dependencies, and the overlay_pockets and
71
            overlay_components parameters dictate from where the
72
            dependencies may be used in the parent.
73
        :param overlay_pockets: An iterable of textual pocket names
74
            corresponding exactly to each parent.  The  name *must* be set
75
            if the corresponding overlays boolean is True.
76
        :param overlay_components: An iterable of textual component names
77
            corresponding exactly to each parent.  The  name *must* be set
78
            if the corresponding overlays boolean is True.
79
        """
13237.1.1 by Gavin Panella
If there's an existing completed InitializeDistroSeriesJob when creating a new one, delete it first.
80
        store = IMasterStore(DistributionJob)
81
        # Only one InitializeDistroSeriesJob can be present at a time.
82
        distribution_job = store.find(
83
            DistributionJob, DistributionJob.job_id == Job.id,
84
            DistributionJob.job_type == cls.class_job_type,
85
            DistributionJob.distroseries_id == child.id).one()
86
        if distribution_job is not None:
13237.1.2 by Gavin Panella
Restrict the delete to only failed jobs.
87
            if distribution_job.job.status == JobStatus.FAILED:
88
                # Delete the failed job to allow initialization of the series
89
                # to be rescheduled.
90
                store.remove(distribution_job)
91
                store.remove(distribution_job.job)
13237.1.3 by Gavin Panella
If the job is completed, raise InitializationCompleted instead.
92
            elif distribution_job.job.status == JobStatus.COMPLETED:
93
                raise InitializationCompleted(cls(distribution_job))
13237.1.2 by Gavin Panella
Restrict the delete to only failed jobs.
94
            else:
13237.1.1 by Gavin Panella
If there's an existing completed InitializeDistroSeriesJob when creating a new one, delete it first.
95
                raise InitializationPending(cls(distribution_job))
96
        # Schedule the initialization.
7675.877.3 by Steve Kowalik
Add all parameters
97
        metadata = {
13117.2.7 by Raphael Badin
Pass parents by id to initDerivedSeries.
98
            'parents': parents,
7675.877.6 by Steve Kowalik
Fix minor code formatting issue
99
            'arches': arches,
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,)
141
        parts += ", packagesets: %s" % pkgsets
142
        parts += ", rebuild: %s" % self.rebuild
143
        return "<%s>" % parts
144
12494.1.82 by Gavin Panella
No need for InitialiseDistroSeriesJob.parent to be cached.
145
    @property
13117.2.1 by Raphael Badin
Fix initseries to support multiple parents as an argument.
146
    def parents(self):
13117.2.5 by Raphael Badin
Fix initseriesjob's tests.
147
        return tuple(self.metadata['parents'])
12494.1.80 by Gavin Panella
InitialiseDistroSeriesJob now take a mandatory parent argument.
148
7675.877.1 by Steve Kowalik
* Change create to also accept an arches and packagesets argument.
149
    @property
13117.2.8 by Raphael Badin
Add overlay support to initseries.
150
    def overlays(self):
13168.5.1 by Raphael Badin
Initialisedistroseriesjob should support None arguments.
151
        if self.metadata['overlays'] is None:
152
            return ()
153
        else:
154
            return tuple(self.metadata['overlays'])
13117.2.8 by Raphael Badin
Add overlay support to initseries.
155
156
    @property
157
    def overlay_pockets(self):
13168.5.1 by Raphael Badin
Initialisedistroseriesjob should support None arguments.
158
        if self.metadata['overlay_pockets'] is None:
159
            return ()
160
        else:
161
            return tuple(self.metadata['overlay_pockets'])
13117.2.8 by Raphael Badin
Add overlay support to initseries.
162
163
    @property
164
    def overlay_components(self):
13168.5.1 by Raphael Badin
Initialisedistroseriesjob should support None arguments.
165
        if self.metadata['overlay_components'] is None:
166
            return ()
167
        else:
168
            return tuple(self.metadata['overlay_components'])
13117.2.8 by Raphael Badin
Add overlay support to initseries.
169
170
    @property
7675.877.1 by Steve Kowalik
* Change create to also accept an arches and packagesets argument.
171
    def arches(self):
13168.5.1 by Raphael Badin
Initialisedistroseriesjob should support None arguments.
172
        if self.metadata['arches'] is None:
173
            return ()
174
        else:
175
            return tuple(self.metadata['arches'])
7675.877.1 by Steve Kowalik
* Change create to also accept an arches and packagesets argument.
176
177
    @property
178
    def packagesets(self):
13168.5.1 by Raphael Badin
Initialisedistroseriesjob should support None arguments.
179
        if self.metadata['packagesets'] is None:
180
            return ()
181
        else:
182
            return tuple(self.metadata['packagesets'])
7675.877.1 by Steve Kowalik
* Change create to also accept an arches and packagesets argument.
183
7675.877.3 by Steve Kowalik
Add all parameters
184
    @property
185
    def rebuild(self):
186
        return self.metadata['rebuild']
187
13891.1.2 by Gavin Panella
Introduce the error_description property.
188
    @property
189
    def error_description(self):
190
        return self.metadata.get("error_description")
191
7675.818.6 by Steve Kowalik
* Rename InitialiseDistroSeriesJob to DistributionJob, and pass both a
192
    def run(self):
193
        """See `IRunnableJob`."""
13194.2.1 by Gavin Panella
Change all uses of 'initialise' to 'initialize'.
194
        ids = InitializeDistroSeries(
13117.2.1 by Raphael Badin
Fix initseries to support multiple parents as an argument.
195
            self.distroseries, self.parents, self.arches,
13117.2.8 by Raphael Badin
Add overlay support to initseries.
196
            self.packagesets, self.rebuild, self.overlays,
197
            self.overlay_pockets, self.overlay_components)
7675.818.6 by Steve Kowalik
* Rename InitialiseDistroSeriesJob to DistributionJob, and pass both a
198
        ids.check()
13194.2.1 by Gavin Panella
Change all uses of 'initialise' to 'initialize'.
199
        ids.initialize()
12494.1.80 by Gavin Panella
InitialiseDistroSeriesJob now take a mandatory parent argument.
200
13891.1.3 by Gavin Panella
Populate the error_description property on InitializeDistroSeriesJob.
201
    def notifyUserError(self, error):
202
        """Calls up and slso saves the error text in this job's metadata.
203
204
        See `BaseRunnableJob`.
205
        """
206
        # This method is called when error is an instance of
207
        # self.user_error_types.
208
        super(InitializeDistroSeriesJob, self).notifyUserError(error)
13891.1.6 by Gavin Panella
Switch to the JSON property raises other issues; reverting for now.
209
        metadata = dict(self.metadata, error_description=unicode(error))
210
        self.context._json_data = simplejson.dumps(metadata).decode("utf-8")
13891.1.3 by Gavin Panella
Populate the error_description property on InitializeDistroSeriesJob.
211
12494.1.80 by Gavin Panella
InitialiseDistroSeriesJob now take a mandatory parent argument.
212
    def getOopsVars(self):
213
        """See `IRunnableJob`."""
13194.2.1 by Gavin Panella
Change all uses of 'initialise' to 'initialize'.
214
        vars = super(InitializeDistroSeriesJob, self).getOopsVars()
13117.2.1 by Raphael Badin
Fix initseries to support multiple parents as an argument.
215
        vars.append(('parent_distroseries_ids', self.metadata.get("parents")))
12494.1.80 by Gavin Panella
InitialiseDistroSeriesJob now take a mandatory parent argument.
216
        return vars