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  __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  # std libs 
 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  # GNUmed libs 
 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  # browser access 
 36  #--------------------------------------------------------------------------- 
37 -def open_url_in_browser(url, new=2, autoraise=True, *args, **kwargs):
38 # url, new=0, autoraise=True 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 #===========================================================================
46 -def download_file(url, filename=None, suffix=None):
47 48 if filename is None: 49 filename = gmTools.get_unique_filename(prefix = 'gm-dl-', suffix = suffix) 50 _log.debug('downloading [%s] into [%s]', url, filename) 51 52 try: 53 dl_name, headers = urllib.urlretrieve(url, filename) 54 except (ValueError, OSError, IOError): 55 _log.exception('cannot download from [%s]', url) 56 gmLog2.log_stack_trace() 57 return None 58 59 _log.debug(u'%s' % headers) 60 return dl_name
61 #=========================================================================== 62 # data pack handling 63 #---------------------------------------------------------------------------
64 -def download_data_packs_list(url, filename=None):
65 return download_file(url, filename = filename, suffix = 'conf')
66 #---------------------------------------------------------------------------
67 -def download_data_pack(pack_url, filename=None, md5_url=None):
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 #---------------------------------------------------------------------------
87 -def unzip_data_pack(filename=None):
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 #---------------------------------------------------------------------------
103 -def install_data_pack(data_pack=None, conn=None):
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 #---------------------------------------------------------------------------
117 -def download_data_pack_old(url, target_dir=None):
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 # FIXME: rewrite to use urllib.urlretrieve() and 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 # client update handling 149 #---------------------------------------------------------------------------
150 -def check_for_update(url=None, current_branch=None, current_version=None, consider_latest_branch=False):
151 """Check for new releases at <url>. 152 153 Returns (bool, text). 154 True: new release available 155 False: up to date 156 None: don't know 157 """ 158 try: 159 remote_file = wget.urlopen(url) 160 except (wget.URLError, ValueError, OSError): 161 _log.exception("cannot retrieve version file from [%s]", url) 162 return (None, _('Cannot retrieve version information from:\n\n%s') % url) 163 164 _log.debug('retrieving version information from [%s]', url) 165 166 cfg = gmCfg2.gmCfgData() 167 try: 168 cfg.add_stream_source(source = 'gm-versions', stream = remote_file) 169 except (UnicodeDecodeError): 170 remote_file.close() 171 _log.exception("cannot read version file from [%s]", url) 172 return (None, _('Cannot read version information from:\n\n%s') % url) 173 174 remote_file.close() 175 176 latest_branch = cfg.get('latest branch', 'branch', source_order = [('gm-versions', 'return')]) 177 latest_release_on_latest_branch = cfg.get('branch %s' % latest_branch, 'latest release', source_order = [('gm-versions', 'return')]) 178 latest_release_on_current_branch = cfg.get('branch %s' % current_branch, 'latest release', source_order = [('gm-versions', 'return')]) 179 180 cfg.remove_source('gm-versions') 181 182 _log.info('current release: %s', current_version) 183 _log.info('current branch: %s', current_branch) 184 _log.info('latest release on current branch: %s', latest_release_on_current_branch) 185 _log.info('latest branch: %s', latest_branch) 186 _log.info('latest release on latest branch: %s', latest_release_on_latest_branch) 187 188 # anything known ? 189 no_release_information_available = ( 190 ( 191 (latest_release_on_current_branch is None) and 192 (latest_release_on_latest_branch is None) 193 ) or ( 194 not consider_latest_branch and 195 (latest_release_on_current_branch is None) 196 ) 197 ) 198 if no_release_information_available: 199 _log.warning('no release information available') 200 msg = _('There is no version information available from:\n\n%s') % url 201 return (None, msg) 202 203 # up to date ? 204 if consider_latest_branch: 205 _log.debug('latest branch taken into account') 206 if current_version >= latest_release_on_latest_branch: 207 _log.debug('up to date: current version >= latest version on latest branch') 208 return (False, None) 209 if latest_release_on_latest_branch is None: 210 if current_version >= latest_release_on_current_branch: 211 _log.debug('up to date: current version >= latest version on current branch and no latest branch available') 212 return (False, None) 213 else: 214 _log.debug('latest branch not taken into account') 215 if current_version >= latest_release_on_current_branch: 216 _log.debug('up to date: current version >= latest version on current branch') 217 return (False, None) 218 219 new_release_on_current_branch_available = ( 220 (latest_release_on_current_branch is not None) and 221 (latest_release_on_current_branch > current_version) 222 ) 223 _log.info('%snew release on current branch available', gmTools.bool2str(new_release_on_current_branch_available, '', 'no ')) 224 225 new_release_on_latest_branch_available = ( 226 (latest_branch is not None) 227 and 228 ( 229 (latest_branch > current_branch) or ( 230 (latest_branch == current_branch) and 231 (latest_release_on_latest_branch > current_version) 232 ) 233 ) 234 ) 235 _log.info('%snew release on latest branch available', gmTools.bool2str(new_release_on_latest_branch_available, '', 'no ')) 236 237 if not (new_release_on_current_branch_available or new_release_on_latest_branch_available): 238 _log.debug('up to date: no new releases available') 239 return (False, None) 240 241 # not up to date 242 msg = _('A new version of GNUmed is available.\n\n') 243 msg += _(' Your current version: "%s"\n') % current_version 244 if consider_latest_branch: 245 if new_release_on_current_branch_available: 246 msg += u'\n' 247 msg += _(' New version: "%s"') % latest_release_on_current_branch 248 msg += u'\n' 249 msg += _(' - bug fixes only\n') 250 msg += _(' - database fixups may be needed\n') 251 if new_release_on_latest_branch_available: 252 if current_branch != latest_branch: 253 msg += u'\n' 254 msg += _(' New version: "%s"') % latest_release_on_latest_branch 255 msg += u'\n' 256 msg += _(' - bug fixes and new features\n') 257 msg += _(' - database upgrade required\n') 258 else: 259 msg += u'\n' 260 msg += _(' New version: "%s"') % latest_release_on_current_branch 261 msg += u'\n' 262 msg += _(' - bug fixes only\n') 263 msg += _(' - database fixups may be needed\n') 264 265 msg += u'\n\n' 266 msg += _( 267 'Note, however, that this version may not yet\n' 268 'be available *pre-packaged* for your system.' 269 ) 270 271 msg += u'\n\n' 272 msg += _('Details are found on <http://wiki.gnumed.de>.\n') 273 msg += u'\n' 274 msg += _('Version information loaded from:\n\n %s') % url 275 276 return (True, msg)
277 #=========================================================================== 278 # mail handling 279 #--------------------------------------------------------------------------- 280 default_mail_sender = u'gnumed@gmx.net' 281 default_mail_receiver = u'gnumed-devel@gnu.org' 282 default_mail_server = u'mail.gmx.net' 283
284 -def send_mail(sender=None, receiver=None, message=None, server=None, auth=None, debug=False, subject=None, encoding='quoted-printable', attachments=None):
285 # FIXME: How to generate and send mails: a step by step tutorial 286 # FIXME: http://groups.google.com/group/comp.lang.python/browse_thread/thread/e0793c1007361398/ 287 # FIXME: google for aspineux blog 288 289 if message is None: 290 return False 291 292 message = message.lstrip().lstrip('\r\n').lstrip() 293 294 if sender is None: 295 sender = default_mail_sender 296 297 if receiver is None: 298 receiver = [default_mail_receiver] 299 300 if server is None: 301 server = default_mail_server 302 303 if subject is None: 304 subject = u'gmTools.py: send_mail() test' 305 306 msg = StringIO.StringIO() 307 writer = MimeWriter.MimeWriter(msg) 308 writer.addheader('To', u', '.join(receiver)) 309 writer.addheader('From', sender) 310 writer.addheader('Subject', subject[:50].replace('\r', '/').replace('\n', '/')) 311 writer.addheader('MIME-Version', '1.0') 312 313 writer.startmultipartbody('mixed') 314 315 # start with a text/plain part 316 part = writer.nextpart() 317 body = part.startbody('text/plain') 318 part.flushheaders() 319 body.write(message.encode(encoding)) 320 321 # now add the attachments 322 if attachments is not None: 323 for a in attachments: 324 filename = os.path.basename(a[0]) 325 try: 326 mtype = a[1] 327 encoding = a[2] 328 except IndexError: 329 mtype, encoding = mimetypes.guess_type(a[0]) 330 if mtype is None: 331 mtype = 'application/octet-stream' 332 encoding = 'base64' 333 elif mtype == 'text/plain': 334 encoding = 'quoted-printable' 335 else: 336 encoding = 'base64' 337 338 part = writer.nextpart() 339 part.addheader('Content-Transfer-Encoding', encoding) 340 body = part.startbody("%s; name=%s" % (mtype, filename)) 341 mimetools.encode(open(a[0], 'rb'), body, encoding) 342 343 writer.lastpart() 344 345 import smtplib 346 session = smtplib.SMTP(server) 347 session.set_debuglevel(debug) 348 if auth is not None: 349 session.login(auth['user'], auth['password']) 350 refused = session.sendmail(sender, receiver, msg.getvalue()) 351 session.quit() 352 msg.close() 353 if len(refused) != 0: 354 _log.error("refused recipients: %s" % refused) 355 return False 356 357 return True
358 #=========================================================================== 359 # main 360 #--------------------------------------------------------------------------- 361 if __name__ == '__main__': 362 363 if len(sys.argv) < 2: 364 sys.exit() 365 366 if sys.argv[1] != 'test': 367 sys.exit() 368 369 #-----------------------------------------------------------------------
370 - def test_send_mail():
371 msg = u""" 372 To: %s 373 From: %s 374 Subject: gmTools test suite mail 375 376 This is a test mail from the gmTools.py module. 377 """ % (default_mail_receiver, default_mail_sender) 378 print "mail sending succeeded:", send_mail ( 379 receiver = [default_mail_receiver, u'karsten.hilbert@gmx.net'], 380 message = msg, 381 auth = {'user': default_mail_sender, 'password': u'gnumed-at-gmx-net'}, # u'gm/bugs/gmx' 382 debug = True, 383 attachments = [sys.argv[0]] 384 )
385 #-----------------------------------------------------------------------
386 - def test_check_for_update():
387 388 test_data = [ 389 ('http://www.gnumed.de/downloads/gnumed-versions.txt', None, None, False), 390 ('file:///home/ncq/gm-versions.txt', None, None, False), 391 ('file:///home/ncq/gm-versions.txt', '0.2', '0.2.8.1', False), 392 ('file:///home/ncq/gm-versions.txt', '0.2', '0.2.8.1', True), 393 ('file:///home/ncq/gm-versions.txt', '0.2', '0.2.8.5', True) 394 ] 395 396 for test in test_data: 397 print "arguments:", test 398 found, msg = check_for_update(test[0], test[1], test[2], test[3]) 399 print msg 400 401 return
402 #-----------------------------------------------------------------------
403 - def test_dl_data_pack():
404 #url = 'file:./x-data_pack.zip' 405 #url = 'missing-file.zip' 406 url = 'gmTools.py' 407 dl_name = download_data_pack(url) 408 print url, "->", dl_name 409 unzip_dir = unzip_data_pack(dl_name) 410 print "unzipped into", unzip_dir
411 #-----------------------------------------------------------------------
412 - def test_browser():
413 success = open_url_in_browser(sys.argv[2]) 414 print success 415 open_url_in_browser(sys.argv[2], abc=222)
416 #----------------------------------------------------------------------- 417 #test_check_for_update() 418 #test_send_mail() 419 #test_dl_data_pack() 420 test_browser() 421 422 #=========================================================================== 423