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
|
#!/usr/bin/python3
# Copyright (C) 2015 Brian Murray <brian.murray@canonical.com>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
'''Remove an SRU fom the -proposed pocket for a release.
Remove a package from the -proposed pocket for a release of Ubuntu and comment
on bug reports regarding the removal of the package giving an explanation that
it was removed to due a failure for the SRU bug(s) to be verified in a timely
fashion.
USAGE:
sru-remove -s trusty -p homerun 12345
'''
from __future__ import print_function
import optparse
import re
import subprocess
import sys
from launchpadlib.launchpad import Launchpad
def parse_options():
'''Parse command line arguments.
Return (options, [bugs]) tuple.
'''
parser = optparse.OptionParser(
usage='Usage: %prog [options]')
parser.add_option(
"-l", "--launchpad", dest="launchpad_instance", default="production")
parser.add_option(
"-s", dest="release", default=default_release, metavar="RELEASE",
help="release (default: %s)" % default_release)
parser.add_option(
"-p", "--package", dest="sourcepkg")
parser.add_option(
"--reason", dest="reason", default="ancient",
help="reason for removal: ancient, failed (default: ancient)")
opts, args = parser.parse_args()
if opts.reason not in ('ancient', 'failed'):
parser.error('Reason can only be "ancient" or "failed".')
return (opts, args)
def process_bug(launchpad, distroseries, sourcepkg, num, reason):
bug_target_re = re.compile(
r'/ubuntu/(?:(?P<suite>[^/]+)/)?\+source/(?P<source>[^/]+)$')
bug = launchpad.bugs[num]
series_name = distroseries.name
open_task = False
for task in bug.bug_tasks:
# Ugly; we have to do URL-parsing to figure this out.
# /ubuntu/+source/foo can be fed to launchpad.load() to get a
# distribution_source_package, but /ubuntu/hardy/+source/foo can't.
match = bug_target_re.search(task.target.self_link)
if (not match or
(sourcepkg and
match.group('source') != sourcepkg)):
print("Ignoring task %s in bug %s" % (task.web_link, num))
continue
if (match.group('suite') != series_name and
match.group('suite') in supported_series and
task.status == "Fix Committed"):
open_task = True
if (match.group('suite') == series_name and
task.status == "Fix Committed"):
task.status = "Won't Fix"
task.lp_save()
print("Success: task %s in bug %s" % (task.web_link, num))
btags = bug.tags
series_v_needed = 'verification-needed-%s' % series_name
if series_v_needed in btags:
# this dance is needed due to
# https://bugs.launchpad.net/launchpadlib/+bug/254901
tags = btags
tags.remove(series_v_needed)
bug.tags = tags
bug.lp_save()
if reason == 'failed':
text = ('The version of %s in the proposed pocket of %s that was '
'purported to fix this bug report has been removed '
'because one or more bugs that were to be fixed by the '
'upload have failed verification and been in this state '
'for more than 10 days.' %
(sourcepkg, series_name.title()))
else: # 'ancient'
text = ('The version of %s in the proposed pocket of %s that was '
'purported to fix this bug report has been removed '
'because the bugs that were to be fixed by the upload '
'were not verified in a timely (105 days) fashion.' %
(sourcepkg, series_name.title()))
bug.newMessage(content=text,
subject='Proposed package removed from archive')
# remove verification-needed tag if there are no open tasks
if open_task:
return
# only unsubscribe the teams if there are no open tasks left
bug.unsubscribe(person=launchpad.people['ubuntu-sru'])
bug.unsubscribe(person=launchpad.people['sru-verification'])
if 'verification-needed' in btags:
# this dance is needed due to
# https://bugs.launchpad.net/launchpadlib/+bug/254901
tags = btags
tags.remove('verification-needed')
bug.tags = tags
bug.lp_save()
if __name__ == '__main__':
default_release = 'groovy'
(opts, bugs) = parse_options()
if opts.reason == 'failed':
removal_comment = ('The package was removed due to one or more of '
'its SRU bugs having failed verification.')
else: # 'ancient'
removal_comment = ('The package was removed due to its SRU bug(s) '
'not being verified in a timely fashion.')
launchpad = Launchpad.login_with('sru-remove', opts.launchpad_instance,
version="devel")
ubuntu = launchpad.distributions['ubuntu']
# determine series for which we issue SRUs
supported_series = []
for serie in ubuntu.series:
if serie.supported:
supported_series.append(serie.name)
series = ubuntu.getSeries(name_or_version=opts.release)
archive = ubuntu.main_archive
existing = [
pkg for pkg in archive.getPublishedSources(
exact_match=True, distro_series=series, pocket='Proposed',
source_name=opts.sourcepkg, status='Published')]
if not existing:
print("ERROR: %s was not found in -proposed for release %s." %
(opts.sourcepkg, opts.release), file=sys.stderr)
sys.exit(1)
rm_p_cmd = ["remove-package", "-m", removal_comment, "-y",
"-l", opts.launchpad_instance, "-s",
"%s-proposed" % opts.release, opts.sourcepkg]
ret = subprocess.call(rm_p_cmd)
if ret != 0:
print("ERROR: There was an error removing %s from %s-proposed.\n"
"The remove-package command returned %s." %
(opts.sourcepkg, opts.release, ret), file=sys.stderr)
sys.exit(1)
# only comment on the bugs after removing the package
for bug in bugs:
process_bug(launchpad, series, opts.sourcepkg, bug, opts.reason)
|