Package Gnumed :: Package pycommon :: Module gmNetworkTools
[frames] | no frames]

Source Code for Module Gnumed.pycommon.gmNetworkTools

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