1
2 __doc__ = """GNUmed internetworking tools."""
3
4
5 __version__ = "$Revision: 1.98 $"
6 __author__ = "K. Hilbert <Karsten.Hilbert@gmx.net>"
7 __license__ = "GPL v2 or later (details at http://www.gnu.org)"
8
9
10 import sys
11 import os.path
12 import logging
13 import urllib2 as wget
14 import urllib
15 import MimeWriter
16 import mimetypes
17 import mimetools
18 import StringIO
19 import zipfile
20 import webbrowser
21
22
23
24 if __name__ == '__main__':
25 sys.path.insert(0, '../../')
26 from Gnumed.pycommon import gmLog2
27 from Gnumed.pycommon import gmTools
28 from Gnumed.pycommon import gmShellAPI
29 from Gnumed.pycommon import gmCfg2
30
31
32 _log = logging.getLogger('gm.net')
33
34
35
36
38
39 try:
40 webbrowser.open(url, new = new, autoraise = autoraise, **kwargs)
41 except (webbrowser.Error, OSError):
42 _log.exception('error calling browser')
43 return False
44 return True
45
61
62
63
66
68
69 _log.debug('downloading data pack from: %s', pack_url)
70 dp_fname = download_file(pack_url, filename = filename, suffix = 'zip')
71 _log.debug('downloading MD5 from: %s', md5_url)
72 md5_fname = download_file(md5_url, filename = dp_fname + u'.md5')
73
74 md5_file = open(md5_fname, 'rU')
75 md5_expected = md5_file.readline().strip('\n')
76 md5_file.close()
77 _log.debug('expected MD5: %s', md5_expected)
78 md5_calculated = gmTools.file2md5(dp_fname, return_hex = True)
79 _log.debug('calculated MD5: %s', md5_calculated)
80
81 if md5_calculated != md5_expected:
82 _log.error('mismatch of expected vs calculated MD5: [%s] vs [%s]', md5_expected, md5_calculated)
83 return (False, (md5_expected, md5_calculated))
84
85 return True, dp_fname
86
88
89 unzip_dir = os.path.splitext(filename)[0]
90 _log.debug('unzipping data pack into [%s]', unzip_dir)
91 gmTools.mkdir(unzip_dir)
92 try:
93 data_pack = zipfile.ZipFile(filename, 'r')
94 except (zipfile.BadZipfile):
95 _log.exception('cannot unzip data pack [%s]', filename)
96 gmLog2.log_stack_trace()
97 return None
98
99 data_pack.extractall(unzip_dir)
100
101 return unzip_dir
102
104 from Gnumed.pycommon import gmPsql
105 psql = gmPsql.Psql(conn)
106 sql_script = os.path.join(data_pack['unzip_dir'], 'install-data-pack.sql')
107 if psql.run(sql_script) == 0:
108 curs = conn.cursor()
109 curs.execute(u'select gm.log_script_insertion(%(name)s, %(ver)s)', {'name': data_pack['pack_url'], 'ver': u'current'})
110 curs.close()
111 conn.commit()
112 return True
113
114 _log.error('error installing data pack: %s', data_pack)
115 return False
116
118
119 if target_dir is None:
120 target_dir = gmTools.get_unique_filename(prefix = 'gm-dl-')
121
122 _log.debug('downloading [%s]', url)
123 _log.debug('unpacking into [%s]', target_dir)
124
125 gmTools.mkdir(directory = target_dir)
126
127
128
129 paths = gmTools.gmPaths()
130 local_script = os.path.join(paths.local_base_dir, '..', 'external-tools', 'gm-download_data')
131
132 candidates = [u'gm-download_data', u'gm-download_data.bat', local_script, u'gm-download_data.bat']
133 args = u' %s %s' % (url, target_dir)
134
135 success = gmShellAPI.run_first_available_in_shell (
136 binaries = candidates,
137 args = args,
138 blocking = True,
139 run_last_one_anyway = True
140 )
141
142 if success:
143 return True, target_dir
144
145 _log.error('download failed')
146 return False, None
147
148
149
151 """
152 0: left == right
153 -1: left < right
154 1: left > right
155 """
156 if left_version == right_version:
157 _log.debug('same version: [%s] = [%s]', left_version, right_version)
158 return 0
159
160 left_parts = left_version.split('.')
161 right_parts = right_version.split('.')
162
163 tmp, left_major = gmTools.input2decimal(u'%s.%s' % (left_parts[0], left_parts[1]))
164 tmp, right_major = gmTools.input2decimal(u'%s.%s' % (right_parts[0], right_parts[1]))
165
166 if left_major < right_major:
167 _log.debug('left version [%s] < right version [%s]: major part', left_version, right_version)
168 return -1
169
170 if left_major > right_major:
171 _log.debug('left version [%s] > right version [%s]: major part', left_version, right_version)
172 return 1
173
174 tmp, left_part3 = gmTools.input2decimal(left_parts[2].replace('rc', '0.'))
175 tmp, right_part3 = gmTools.input2decimal(right_parts[2].replace('rc', '0.'))
176
177 if left_part3 < right_part3:
178 _log.debug('left version [%s] < right version [%s]: minor part', left_version, right_version)
179 return -1
180
181 if left_part3 > right_part3:
182 _log.debug('left version [%s] > right version [%s]: minor part', left_version, right_version)
183 return 1
184
185 return 0
186
187 -def check_for_update(url=None, current_branch=None, current_version=None, consider_latest_branch=False):
188 """Check for new releases at <url>.
189
190 Returns (bool, text).
191 True: new release available
192 False: up to date
193 None: don't know
194 """
195 if current_version == u'GIT HEAD':
196 _log.debug('GIT HEAD always up to date')
197 return (False, None)
198
199 try:
200 remote_file = wget.urlopen(url)
201 except (wget.URLError, ValueError, OSError):
202 _log.exception("cannot retrieve version file from [%s]", url)
203 return (None, _('Cannot retrieve version information from:\n\n%s') % url)
204
205 _log.debug('retrieving version information from [%s]', url)
206
207 cfg = gmCfg2.gmCfgData()
208 try:
209 cfg.add_stream_source(source = 'gm-versions', stream = remote_file)
210 except (UnicodeDecodeError):
211 remote_file.close()
212 _log.exception("cannot read version file from [%s]", url)
213 return (None, _('Cannot read version information from:\n\n%s') % url)
214
215 remote_file.close()
216
217 latest_branch = cfg.get('latest branch', 'branch', source_order = [('gm-versions', 'return')])
218 latest_release_on_latest_branch = cfg.get('branch %s' % latest_branch, 'latest release', source_order = [('gm-versions', 'return')])
219 latest_release_on_current_branch = cfg.get('branch %s' % current_branch, 'latest release', source_order = [('gm-versions', 'return')])
220
221 cfg.remove_source('gm-versions')
222
223 _log.info('current release: %s', current_version)
224 _log.info('current branch: %s', current_branch)
225 _log.info('latest release on current branch: %s', latest_release_on_current_branch)
226 _log.info('latest branch: %s', latest_branch)
227 _log.info('latest release on latest branch: %s', latest_release_on_latest_branch)
228
229
230 no_release_information_available = (
231 (
232 (latest_release_on_current_branch is None) and
233 (latest_release_on_latest_branch is None)
234 ) or (
235 not consider_latest_branch and
236 (latest_release_on_current_branch is None)
237 )
238 )
239 if no_release_information_available:
240 _log.warning('no release information available')
241 msg = _('There is no version information available from:\n\n%s') % url
242 return (None, msg)
243
244
245 if consider_latest_branch:
246 _log.debug('latest branch taken into account')
247 if latest_release_on_latest_branch is None:
248 if compare_versions(latest_release_on_current_branch, current_version) in [-1, 0]:
249 _log.debug('up to date: current version >= latest version on current branch and no latest branch available')
250 return (False, None)
251 else:
252 if compare_versions(latest_release_on_latest_branch, current_version) in [-1, 0]:
253 _log.debug('up to date: current version >= latest version on latest branch')
254 return (False, None)
255 else:
256 _log.debug('latest branch not taken into account')
257 if compare_versions(latest_release_on_current_branch, current_version) in [-1, 0]:
258 _log.debug('up to date: current version >= latest version on current branch')
259 return (False, None)
260
261 new_release_on_current_branch_available = (
262 (latest_release_on_current_branch is not None) and
263 (compare_versions(latest_release_on_current_branch, current_version) == 1)
264 )
265 _log.info('%snew release on current branch available', gmTools.bool2str(new_release_on_current_branch_available, '', 'no '))
266
267 new_release_on_latest_branch_available = (
268 (latest_branch is not None)
269 and
270 (
271 (latest_branch > current_branch) or (
272 (latest_branch == current_branch) and
273 (compare_versions(latest_release_on_latest_branch, current_version) == 1)
274 )
275 )
276 )
277 _log.info('%snew release on latest branch available', gmTools.bool2str(new_release_on_latest_branch_available, '', 'no '))
278
279 if not (new_release_on_current_branch_available or new_release_on_latest_branch_available):
280 _log.debug('up to date: no new releases available')
281 return (False, None)
282
283
284 msg = _('A new version of GNUmed is available.\n\n')
285 msg += _(' Your current version: "%s"\n') % current_version
286 if consider_latest_branch:
287 if new_release_on_current_branch_available:
288 msg += u'\n'
289 msg += _(' New version: "%s"') % latest_release_on_current_branch
290 msg += u'\n'
291 msg += _(' - bug fixes only\n')
292 msg += _(' - database fixups may be needed\n')
293 if new_release_on_latest_branch_available:
294 if current_branch != latest_branch:
295 msg += u'\n'
296 msg += _(' New version: "%s"') % latest_release_on_latest_branch
297 msg += u'\n'
298 msg += _(' - bug fixes and new features\n')
299 msg += _(' - database upgrade required\n')
300 else:
301 msg += u'\n'
302 msg += _(' New version: "%s"') % latest_release_on_current_branch
303 msg += u'\n'
304 msg += _(' - bug fixes only\n')
305 msg += _(' - database fixups may be needed\n')
306
307 msg += u'\n\n'
308 msg += _(
309 'Note, however, that this version may not yet\n'
310 'be available *pre-packaged* for your system.'
311 )
312
313 msg += u'\n\n'
314 msg += _('Details are found on <http://wiki.gnumed.de>.\n')
315 msg += u'\n'
316 msg += _('Version information loaded from:\n\n %s') % url
317
318 return (True, msg)
319
320
321
322 default_mail_sender = u'gnumed@gmx.net'
323 default_mail_receiver = u'gnumed-devel@gnu.org'
324 default_mail_server = u'mail.gmx.net'
325
326 -def send_mail(sender=None, receiver=None, message=None, server=None, auth=None, debug=False, subject=None, encoding='quoted-printable', attachments=None):
327
328
329
330
331 if message is None:
332 return False
333
334 message = message.lstrip().lstrip('\r\n').lstrip()
335
336 if sender is None:
337 sender = default_mail_sender
338
339 if receiver is None:
340 receiver = [default_mail_receiver]
341
342 if server is None:
343 server = default_mail_server
344
345 if subject is None:
346 subject = u'gmTools.py: send_mail() test'
347
348 msg = StringIO.StringIO()
349 writer = MimeWriter.MimeWriter(msg)
350 writer.addheader('To', u', '.join(receiver))
351 writer.addheader('From', sender)
352 writer.addheader('Subject', subject[:50].replace('\r', '/').replace('\n', '/'))
353 writer.addheader('MIME-Version', '1.0')
354
355 writer.startmultipartbody('mixed')
356
357
358 part = writer.nextpart()
359 body = part.startbody('text/plain')
360 part.flushheaders()
361 body.write(message.encode(encoding))
362
363
364 if attachments is not None:
365 for a in attachments:
366 filename = os.path.basename(a[0])
367 try:
368 mtype = a[1]
369 encoding = a[2]
370 except IndexError:
371 mtype, encoding = mimetypes.guess_type(a[0])
372 if mtype is None:
373 mtype = 'application/octet-stream'
374 encoding = 'base64'
375 elif mtype == 'text/plain':
376 encoding = 'quoted-printable'
377 else:
378 encoding = 'base64'
379
380 part = writer.nextpart()
381 part.addheader('Content-Transfer-Encoding', encoding)
382 body = part.startbody("%s; name=%s" % (mtype, filename))
383 mimetools.encode(open(a[0], 'rb'), body, encoding)
384
385 writer.lastpart()
386
387 import smtplib
388 session = smtplib.SMTP(server)
389 session.set_debuglevel(debug)
390 if auth is not None:
391 session.login(auth['user'], auth['password'])
392 refused = session.sendmail(sender, receiver, msg.getvalue())
393 session.quit()
394 msg.close()
395 if len(refused) != 0:
396 _log.error("refused recipients: %s" % refused)
397 return False
398
399 return True
400
401
402
403 if __name__ == '__main__':
404
405 if len(sys.argv) < 2:
406 sys.exit()
407
408 if sys.argv[1] != 'test':
409 sys.exit()
410
411
427
429
430 test_data = [
431 ('http://www.gnumed.de/downloads/gnumed-versions.txt', None, None, False),
432 ('file:///home/ncq/gm-versions.txt', None, None, False),
433 ('file:///home/ncq/gm-versions.txt', '0.2', '0.2.8.1', False),
434 ('file:///home/ncq/gm-versions.txt', '0.2', '0.2.8.1', True),
435 ('file:///home/ncq/gm-versions.txt', '0.2', '0.2.8.5', True)
436 ]
437
438 for test in test_data:
439 print "arguments:", test
440 found, msg = check_for_update(test[0], test[1], test[2], test[3])
441 print msg
442
443 return
444
446
447
448 url = 'gmTools.py'
449 dl_name = download_data_pack(url)
450 print url, "->", dl_name
451 unzip_dir = unzip_data_pack(dl_name)
452 print "unzipped into", unzip_dir
453
458
459
460
461
462 test_browser()
463
464
465