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
21
22
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
48
51
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
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
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
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
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
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
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
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
263
264
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
293 part = writer.nextpart()
294 body = part.startbody('text/plain')
295 part.flushheaders()
296 body.write(message.encode(encoding))
297
298
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
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
362
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
381
382
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
390
391 test_dl_data_pack()
392
393
394