~launchpad-pqm/launchpad/devel

11070.3.3 by Paul Hummer
Created lp.code.browser.sourcepackagerecipebuild
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
"""SourcePackageRecipeBuild views."""
5
6
__metaclass__ = type
7
8
__all__ = [
11070.3.6 by Paul Hummer
Made the menu show up in the UI
9
    'SourcePackageRecipeBuildContextMenu',
11070.3.3 by Paul Hummer
Created lp.code.browser.sourcepackagerecipebuild
10
    'SourcePackageRecipeBuildNavigation',
11
    'SourcePackageRecipeBuildView',
11070.3.15 by Paul Hummer
Made changes per Aaron's review
12
    'SourcePackageRecipeBuildCancelView',
11070.4.1 by Paul Hummer
Added rescore flow
13
    'SourcePackageRecipeBuildRescoreView',
11070.3.3 by Paul Hummer
Created lp.code.browser.sourcepackagerecipebuild
14
    ]
15
11070.3.8 by Paul Hummer
Tests, working, hooraybzr break-lock
16
from zope.interface import Interface
11227.1.2 by Paul Hummer
Fixed rescore to use a text field
17
from zope.schema import Int
11070.3.8 by Paul Hummer
Tests, working, hooraybzr break-lock
18
11929.9.1 by Tim Penhey
Move launchpadform into lp.app.browser.
19
from lp.app.browser.launchpadform import (
20
    action,
21
    LaunchpadFormView,
22
    )
11458.1.1 by Jelmer Vernooij
Move enums of buildmaster.
23
from lp.buildmaster.enums import BuildStatus
11070.3.3 by Paul Hummer
Created lp.code.browser.sourcepackagerecipebuild
24
from lp.code.interfaces.sourcepackagerecipebuild import (
11403.1.4 by Henning Eggers
Reformatted imports using format-imports script r32.
25
    ISourcePackageRecipeBuild,
26
    )
11070.3.3 by Paul Hummer
Created lp.code.browser.sourcepackagerecipebuild
27
from lp.services.job.interfaces.job import JobStatus
14578.2.1 by William Grant
Move librarian stuff from canonical.launchpad to lp.services.librarian. canonical.librarian remains untouched.
28
from lp.services.librarian.browser import FileNavigationMixin
14513.4.3 by Raphael Badin
Cleanup cache when appropriate.
29
from lp.services.propertycache import (
30
    cachedproperty,
31
    )
14612.2.1 by William Grant
format-imports on lib/. So many imports.
32
from lp.services.webapp import (
33
    canonical_url,
34
    ContextMenu,
35
    enabled_with_permission,
36
    LaunchpadView,
37
    Link,
38
    Navigation,
39
    )
11070.3.3 by Paul Hummer
Created lp.code.browser.sourcepackagerecipebuild
40
41
11213.1.1 by Paul Hummer
Cancel builds when in a non-final state.
42
UNEDITABLE_BUILD_STATES = (
43
    BuildStatus.FULLYBUILT,
44
    BuildStatus.FAILEDTOBUILD,
45
    BuildStatus.SUPERSEDED,
46
    BuildStatus.FAILEDTOUPLOAD,)
47
12176.1.1 by Aaron Bentley
No oopses when rescoring non-queued recipe builds.
48
11070.3.3 by Paul Hummer
Created lp.code.browser.sourcepackagerecipebuild
49
class SourcePackageRecipeBuildNavigation(Navigation, FileNavigationMixin):
50
51
    usedfor = ISourcePackageRecipeBuild
52
53
11070.3.6 by Paul Hummer
Made the menu show up in the UI
54
class SourcePackageRecipeBuildContextMenu(ContextMenu):
11070.3.3 by Paul Hummer
Created lp.code.browser.sourcepackagerecipebuild
55
    """Navigation menu for sourcepackagerecipe build."""
56
57
    usedfor = ISourcePackageRecipeBuild
58
59
    facet = 'branches'
60
11070.4.1 by Paul Hummer
Added rescore flow
61
    links = ('cancel', 'rescore')
11070.3.6 by Paul Hummer
Made the menu show up in the UI
62
11316.3.6 by Paul Hummer
Swapped recipe build permissions launchpad.Edit to launchpad.Admin
63
    @enabled_with_permission('launchpad.Admin')
11070.3.14 by Paul Hummer
Got cancel build working in the UI
64
    def cancel(self):
11213.1.3 by Paul Hummer
Prevent breakage in db-devel
65
        if self.context.status in UNEDITABLE_BUILD_STATES:
11070.4.4 by Paul Hummer
Made it so that the build can't be created in a wrong state
66
            enabled = False
67
        else:
68
            enabled = True
69
        return Link('+cancel', 'Cancel build', icon='remove', enabled=enabled)
11070.3.3 by Paul Hummer
Created lp.code.browser.sourcepackagerecipebuild
70
11316.3.6 by Paul Hummer
Swapped recipe build permissions launchpad.Edit to launchpad.Admin
71
    @enabled_with_permission('launchpad.Admin')
11070.4.1 by Paul Hummer
Added rescore flow
72
    def rescore(self):
11213.1.3 by Paul Hummer
Prevent breakage in db-devel
73
        if self.context.status in UNEDITABLE_BUILD_STATES:
11070.4.3 by Paul Hummer
Enforced that the build actually has to be in progress to be able to rescore it
74
            enabled = False
75
        else:
76
            enabled = True
77
        return Link('+rescore', 'Rescore build', icon='edit', enabled=enabled)
11070.4.1 by Paul Hummer
Added rescore flow
78
11070.3.3 by Paul Hummer
Created lp.code.browser.sourcepackagerecipebuild
79
80
class SourcePackageRecipeBuildView(LaunchpadView):
81
    """Default view of a SourcePackageRecipeBuild."""
82
83
    @property
84
    def status(self):
85
        """A human-friendly status string."""
11121.4.7 by Aaron Bentley
Merged db-devel into package-build-recipe.
86
        if (self.context.status == BuildStatus.NEEDSBUILD
11070.3.3 by Paul Hummer
Created lp.code.browser.sourcepackagerecipebuild
87
            and self.eta is None):
88
            return 'No suitable builders'
89
        return {
90
            BuildStatus.NEEDSBUILD: 'Pending build',
11039.2.31 by Jelmer Vernooij
Display uploading status properly.
91
            BuildStatus.UPLOADING: 'Build uploading',
11070.3.3 by Paul Hummer
Created lp.code.browser.sourcepackagerecipebuild
92
            BuildStatus.FULLYBUILT: 'Successful build',
93
            BuildStatus.MANUALDEPWAIT: (
94
                'Could not build because of missing dependencies'),
95
            BuildStatus.CHROOTWAIT: (
96
                'Could not build because of chroot problem'),
97
            BuildStatus.SUPERSEDED: (
98
                'Could not build because source package was superseded'),
99
            BuildStatus.FAILEDTOUPLOAD: 'Could not be uploaded correctly',
11121.4.7 by Aaron Bentley
Merged db-devel into package-build-recipe.
100
            }.get(self.context.status, self.context.status.title)
11070.3.3 by Paul Hummer
Created lp.code.browser.sourcepackagerecipebuild
101
11889.4.4 by Tim Penhey
Cache some build properties in the view used on the recipe pages.
102
    @cachedproperty
11070.3.3 by Paul Hummer
Created lp.code.browser.sourcepackagerecipebuild
103
    def eta(self):
104
        """The datetime when the build job is estimated to complete.
105
106
        This is the BuildQueue.estimated_duration plus the
107
        Job.date_started or BuildQueue.getEstimatedJobStartTime.
108
        """
109
        if self.context.buildqueue_record is None:
110
            return None
111
        queue_record = self.context.buildqueue_record
112
        if queue_record.job.status == JobStatus.WAITING:
113
            start_time = queue_record.getEstimatedJobStartTime()
114
            if start_time is None:
115
                return None
116
        else:
117
            start_time = queue_record.job.date_started
118
        duration = queue_record.estimated_duration
119
        return start_time + duration
120
11889.4.4 by Tim Penhey
Cache some build properties in the view used on the recipe pages.
121
    @cachedproperty
11070.3.3 by Paul Hummer
Created lp.code.browser.sourcepackagerecipebuild
122
    def date(self):
123
        """The date when the build completed or is estimated to complete."""
124
        if self.estimate:
125
            return self.eta
11121.4.7 by Aaron Bentley
Merged db-devel into package-build-recipe.
126
        return self.context.date_finished
11070.3.3 by Paul Hummer
Created lp.code.browser.sourcepackagerecipebuild
127
11889.4.4 by Tim Penhey
Cache some build properties in the view used on the recipe pages.
128
    @cachedproperty
11070.3.3 by Paul Hummer
Created lp.code.browser.sourcepackagerecipebuild
129
    def estimate(self):
130
        """If true, the date value is an estimate."""
11121.4.7 by Aaron Bentley
Merged db-devel into package-build-recipe.
131
        if self.context.date_finished is not None:
11070.3.3 by Paul Hummer
Created lp.code.browser.sourcepackagerecipebuild
132
            return False
133
        return self.eta is not None
134
135
    def binary_builds(self):
136
        return list(self.context.binary_builds)
137
138
11070.3.14 by Paul Hummer
Got cancel build working in the UI
139
class SourcePackageRecipeBuildCancelView(LaunchpadFormView):
11070.3.16 by Paul Hummer
More changes from review
140
    """View for cancelling a build."""
11070.3.8 by Paul Hummer
Tests, working, hooraybzr break-lock
141
142
    class schema(Interface):
11070.3.15 by Paul Hummer
Made changes per Aaron's review
143
        """Schema for cancelling a build."""
11070.3.8 by Paul Hummer
Tests, working, hooraybzr break-lock
144
11070.3.14 by Paul Hummer
Got cancel build working in the UI
145
    page_title = label = "Cancel build"
11070.3.8 by Paul Hummer
Tests, working, hooraybzr break-lock
146
147
    @property
148
    def cancel_url(self):
149
        return canonical_url(self.context)
11070.3.14 by Paul Hummer
Got cancel build working in the UI
150
    next_url = cancel_url
11070.3.8 by Paul Hummer
Tests, working, hooraybzr break-lock
151
11070.3.14 by Paul Hummer
Got cancel build working in the UI
152
    @action('Cancel build', name='cancel')
11070.3.8 by Paul Hummer
Tests, working, hooraybzr break-lock
153
    def request_action(self, action, data):
11070.3.14 by Paul Hummer
Got cancel build working in the UI
154
        """Cancel the build."""
155
        self.context.cancelBuild()
11070.4.1 by Paul Hummer
Added rescore flow
156
157
158
class SourcePackageRecipeBuildRescoreView(LaunchpadFormView):
159
    """View for rescoring a build."""
160
161
    class schema(Interface):
162
        """Schema for deleting a build."""
11227.1.2 by Paul Hummer
Fixed rescore to use a text field
163
        score = Int(
11070.4.1 by Paul Hummer
Added rescore flow
164
            title=u'Score', required=True,
165
            description=u'The score of the recipe.')
166
167
    page_title = label = "Rescore build"
168
12176.1.1 by Aaron Bentley
No oopses when rescoring non-queued recipe builds.
169
    def __call__(self):
170
        if self.context.buildqueue_record is not None:
171
            return super(SourcePackageRecipeBuildRescoreView, self).__call__()
172
        self.request.response.addWarningNotification(
173
            'Cannot rescore this build because it is not queued.')
174
        self.request.response.redirect(canonical_url(self.context))
175
11070.4.1 by Paul Hummer
Added rescore flow
176
    @property
177
    def cancel_url(self):
178
        return canonical_url(self.context)
179
    next_url = cancel_url
180
181
    @action('Rescore build', name='rescore')
182
    def request_action(self, action, data):
183
        """Rescore the build."""
184
        self.context.buildqueue_record.lastscore = int(data['score'])
185
186
    @property
187
    def initial_values(self):
188
        return {'score': str(self.context.buildqueue_record.lastscore)}