-
Notifications
You must be signed in to change notification settings - Fork 1
/
ptfdownload.py
executable file
·288 lines (225 loc) · 8.9 KB
/
ptfdownload.py
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
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
#!/usr/bin/python
# Copyright (c) 2018 Thomas Schulte. All rights reserved.
#
# This file is part of cupracer/ptfdownload.
#
# ptfdownload 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, either version 3 of the License, or
# (at your option) any later version.
#
# ptfdownload 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 ptfdownload. If not, see <http://www.gnu.org/licenses/>
import sys
import os
import subprocess
import getpass
import urllib2
import re
import base64
import getopt
def get_program_title(banner=False):
title = 'Program Temporary Fix (PTF) download helper'
if banner:
border = '############################################\n'
return border + title + "\n" + border
return title
def warn_root_uid():
if os.getuid() == 0:
print "WARNING! You're running this script with root permissions, which is not recommended."
def print_welcome():
print (get_program_title(True) + "\n"
"This script is intended to simplify the download of PTF packages.\n"
"For more information on using PTFs, please visit the following support articles:\n\n"
"* Best practice for applying Program Temporary Fixes (PTFs)\n"
" https://www.suse.com/support/kb/doc/?id=7016640\n\n"
"* SLES 12: How to import suse_key for signed PTF packages\n"
" https://www.suse.com/support/kb/doc/?id=7016511\n")
def check_build_key():
try:
devnull = open(os.devnull, 'w')
subprocess.check_call(['rpm', '-V', 'suse-build-key'], stdout=devnull, stderr=subprocess.STDOUT)
return True
except OSError:
print "Verification of RPM packages is not available on this system."
return False
except Exception as e:
print ("Notice:\n"
"Something seems to be wrong with the \"suse-build-key\" RPM package.\n"
"It may be required to (re)install it before being able to install any PTF packages on this system.\n"
"Raw error message: " + str(e))
return False
def download_item(name, url, base64auth, output_directory):
r = urllib2.Request(url)
r.add_header("Authorization", "Basic %s" % base64auth)
u = urllib2.urlopen(r)
f = open(output_directory + name, 'wb')
m = u.info()
target_file_size = int(m.getheaders("Content-Length")[0])
progress_file_size = 0
block_sz = 8192
while True:
read_buffer = u.read(block_sz)
if not read_buffer:
break
progress_file_size += len(read_buffer)
f.write(read_buffer)
status = r"%10d [%3.2f%%]" % (progress_file_size, progress_file_size * 100. / target_file_size)
status = status + chr(8) * (len(status) + 1)
print status
print ""
f.close()
def add_slash(str_to_edit):
if not str_to_edit.endswith('/'):
str_to_edit += '/'
return str_to_edit
def do_ptf_download_cli(output_directory, url, username, password, ignore_optional):
print ("\nPlease provide necessary information:\n\n")
if output_directory == '':
output_directory = raw_input("Output dir : ")
else:
print "Output dir : " + output_directory
if not output_directory:
print "No output directory given."
return False
output_directory = add_slash(output_directory)
if url == '':
url = raw_input("PTF URL : ")
else:
print "PTF URL : " + url
if not url:
print "No URL given."
return False
if username == '':
username = raw_input("SCC username : ")
else:
print "SCC username : " + username
if not username:
print "No username given."
return False
if password == '':
password = getpass.getpass("SCC password : ")
if not password:
print "No password given."
return False
if do_ptf_download(output_directory, url, username, password, ignore_optional):
print ("To install the downloaded packages please run (as root):\n\n"
"$ rpm -Fvh " + output_directory + "*.rpm\n")
return True
def do_ptf_download(output_directory, url, username, password, ignore_optional):
has_readme = False
base64auth = base64.b64encode('%s:%s' % (username, password))
is_single_download = False
if url.endswith('.rpm'):
# force-fake final paths for single rpm download:
is_single_download = True
base_url, filename = os.path.split(url)
url = base_url
links = [filename]
else:
try:
print "\nRetrieving PTF information..."
request = urllib2.Request(url)
request.add_header("Authorization", "Basic %s" % base64auth)
index_page = urllib2.urlopen(request)
index_html = index_page.read()
links = re.findall(' href="(.*rpm|.*readme.txt)"', index_html)
except Exception as e:
print ("Error while accessing given URL.\n"
"Raw error message: " + str(e))
return False
if not len(links) > 0:
print "Given URL does not seem to contain links to any downloadable files."
return False
output_directory = add_slash(output_directory)
if not os.path.isdir(output_directory):
print 'Directory "' + output_directory + '" does not seem to exist.'
return False
print 'Downloading to "' + output_directory + '":\n'
for link in links:
if '/' in link:
item_name = link.rsplit('/', 1)[-1]
else:
item_name = link
item_url = url
if not link.startswith('/'):
item_url = add_slash(item_url)
item_url += link
try:
if ignore_optional is True and is_single_download is False and (
item_url.endswith('.src.rpm') or 'debuginfo' in link or 'debugsource' in link):
print "* " + item_name + " (SKIPPED: optional)"
continue
else:
print "* " + item_name
download_item(item_name, item_url, base64auth, output_directory)
except Exception as e:
print ("\nSomething went wrong while downloading.\n"
"Raw error message: " + str(e))
return False
try:
if item_name.endswith('.rpm'):
check_downloaded_package(output_directory + item_name)
if item_name.endswith('.txt'):
has_readme = True
except Exception as e:
print "\nError: " + repr(e)
return False
print "\nDownloads finished."
if has_readme:
print "Output directory contains at least one .txt file. Please read!"
return True
def check_downloaded_package(package_path):
devnull = open(os.devnull, 'w')
process = subprocess.call(['rpm', '-K', package_path], stdout=devnull, stderr=subprocess.STDOUT)
if process != 0:
raise Exception('Signature not OK! Did you import the suse_ptf_key.asc as explained here? https://www.suse.com/support/kb/doc/?id=7016511')
def print_cmd_info():
print get_program_title() + "\n"
print ("""usage: %s [-d <output_directory>] [-p <url>] [-u <username>] [-i]
General:
-h, --help print this help
Recommended:
-d, --directory=DIR use specified download directory
Optional:
-p, --ptf-url=URL PTF URL to use
-u, --username=USER SCC username
-i, --ignore-optional ignore optional packages (src, debuginfo, debugsource)"""
% os.path.basename(__file__))
#####################################
def main():
output_directory = ''
url = ''
username = ''
password = ''
ignore_optional = False
try:
opts, args = getopt.getopt(sys.argv[1:],
"hd:p:u:i", ["help", "directory=", "ptf-url=", "username=", "ignore-optional"])
for opt, arg in opts:
if opt in ('-h', '--help'):
print_cmd_info()
exit()
elif opt in ('-d', '--directory'):
output_directory = arg
elif opt in ('-p', '--ptf-url'):
url = arg
elif opt in ('-u', '--username'):
username = arg
elif opt in ('-i', '--ignore-optional'):
ignore_optional = True
except getopt.GetoptError:
print_cmd_info()
exit(2)
print_welcome()
warn_root_uid()
check_build_key()
if not do_ptf_download_cli(output_directory, url, username, password, ignore_optional):
print "\nAborting."
if __name__ == '__main__':
main()