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