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