1 """
2 This file is part of the web2py Web Framework
3 Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
4 License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
5
6 Utility functions for the Admin application
7 ===========================================
8 """
9 import os
10 import sys
11 import traceback
12 import zipfile
13 import urllib
14 from shutil import rmtree
15 from gluon.utils import web2py_uuid
16 from gluon.fileutils import w2p_pack, w2p_unpack, w2p_pack_plugin, w2p_unpack_plugin
17 from gluon.fileutils import up, fix_newlines, abspath, recursive_unlink
18 from gluon.fileutils import read_file, write_file, parse_version
19 from gluon.restricted import RestrictedError
20 from gluon.settings import global_settings
21
22
23 if not global_settings.web2py_runtime_gae:
24 import site
25
26
27 -def apath(path='', r=None):
28 """
29 Builds a path inside an application folder
30
31 Parameters
32 ----------
33 path:
34 path within the application folder
35 r:
36 the global request object
37
38 """
39
40 opath = up(r.folder)
41 while path[:3] == '../':
42 (opath, path) = (up(opath), path[3:])
43 return os.path.join(opath, path).replace('\\', '/')
44
45
46 -def app_pack(app, request, raise_ex=False, filenames=None):
47 """
48 Builds a w2p package for the application
49
50 Parameters
51 ----------
52 app:
53 application name
54 request:
55 the global request object
56
57 Returns
58 -------
59 filename:
60 filename of the w2p file or None on error
61 """
62 try:
63 if filenames is None: app_cleanup(app, request)
64 filename = apath('../deposit/web2py.app.%s.w2p' % app, request)
65 w2p_pack(filename, apath(app, request), filenames=filenames)
66 return filename
67 except Exception, e:
68 if raise_ex:
69 raise
70 return False
71
72
74 """
75 Builds a w2p bytecode-compiled package for the application
76
77 Parameters
78 ----------
79 app:
80 application name
81 request:
82 the global request object
83
84 Returns
85 -------
86 filename:
87 filename of the w2p file or None on error
88 """
89
90 try:
91 filename = apath('../deposit/%s.w2p' % app, request)
92 w2p_pack(filename, apath(app, request), compiled=True)
93 return filename
94 except Exception, e:
95 if raise_ex:
96 raise
97 return None
98
99
140
141
162
163
164 -def app_create(app, request, force=False, key=None, info=False):
165 """
166 Create a copy of welcome.w2p (scaffolding) app
167
168 Parameters
169 ----------
170 app:
171 application name
172 request:
173 the global request object
174
175 """
176 path = apath(app, request)
177 if not os.path.exists(path):
178 try:
179 os.mkdir(path)
180 except:
181 if info:
182 return False, traceback.format_exc(sys.exc_info)
183 else:
184 return False
185 elif not force:
186 if info:
187 return False, "Application exists"
188 else:
189 return False
190 try:
191 w2p_unpack('welcome.w2p', path)
192 for subfolder in [
193 'models', 'views', 'controllers', 'databases',
194 'modules', 'cron', 'errors', 'sessions', 'cache',
195 'languages', 'static', 'private', 'uploads']:
196 subpath = os.path.join(path, subfolder)
197 if not os.path.exists(subpath):
198 os.mkdir(subpath)
199 db = os.path.join(path, 'models', 'db.py')
200 if os.path.exists(db):
201 data = read_file(db)
202 data = data.replace('<your secret key>',
203 'sha512:' + (key or web2py_uuid()))
204 write_file(db, data)
205 if info:
206 return True, None
207 else:
208 return True
209 except:
210 rmtree(path)
211 if info:
212 return False, traceback.format_exc(sys.exc_info)
213 else:
214 return False
215
216
217 -def app_install(app, fobj, request, filename, overwrite=None):
218 """
219 Installs an application:
220
221 - Identifies file type by filename
222 - Writes `fobj` contents to the `../deposit/` folder
223 - Calls `w2p_unpack()` to do the job.
224
225 Parameters
226 ----------
227 app:
228 new application name
229 fobj:
230 file object containing the application to be installed
231 request:
232 the global request object
233 filename:
234 original filename of the `fobj`, required to determine extension
235
236 Returns
237 -------
238 upname:
239 name of the file where app is temporarily stored or `None` on failure
240 """
241 did_mkdir = False
242 if filename[-4:] == '.w2p':
243 extension = 'w2p'
244 elif filename[-7:] == '.tar.gz':
245 extension = 'tar.gz'
246 else:
247 extension = 'tar'
248 upname = apath('../deposit/%s.%s' % (app, extension), request)
249
250 try:
251 write_file(upname, fobj.read(), 'wb')
252 path = apath(app, request)
253 if not overwrite:
254 os.mkdir(path)
255 did_mkdir = True
256 w2p_unpack(upname, path)
257 if extension != 'tar':
258 os.unlink(upname)
259 fix_newlines(path)
260 return upname
261 except Exception:
262 if did_mkdir:
263 rmtree(path)
264 return False
265
266
268 """
269 Uninstalls the application.
270
271 Parameters
272 ----------
273 app:
274 application name
275 request:
276 the global request object
277
278 Returns
279 -------
280 `True` on success, `False` on failure
281 """
282 try:
283
284 path = apath(app, request)
285 rmtree(path)
286 return True
287 except Exception:
288 return False
289
290
292 """
293 Builds a w2p package for the application
294
295 Parameters
296 ----------
297 app:
298 application name
299 plugin_name:
300 the name of the plugin without plugin_ prefix
301 request:
302 the current request app
303
304 Returns
305 -------
306 filename:
307 filename of the w2p file or None on error
308 """
309 try:
310 filename = apath(
311 '../deposit/web2py.plugin.%s.w2p' % plugin_name, request)
312 w2p_pack_plugin(filename, apath(app, request), plugin_name)
313 return filename
314 except Exception:
315 return False
316
317
319 """
320 Installs an application:
321
322 - Identifies file type by filename
323 - Writes `fobj` contents to the `../deposit/` folder
324 - Calls `w2p_unpack()` to do the job.
325
326 Parameters
327 ----------
328 app:
329 new application name
330 fobj:
331 file object containing the application to be installed
332 request:
333 the global request object
334 filename:
335 original filename of the `fobj`, required to determine extension
336
337 Returns
338 -------
339 upname:
340 name of the file where app is temporarily stored or `None` on failure
341 """
342
343 upname = apath('../deposit/%s' % filename, request)
344
345 try:
346 write_file(upname, fobj.read(), 'wb')
347 path = apath(app, request)
348 w2p_unpack_plugin(upname, path)
349 fix_newlines(path)
350 return upname
351 except Exception:
352 os.unlink(upname)
353 return False
354
355
357 """
358 Compares current web2py's version with the latest stable web2py version.
359
360 Parameters
361 ----------
362 myversion:
363 the current version as stored in file `web2py/VERSION`
364 version_URL:
365 the URL that contains the version of the latest stable release
366
367 Returns
368 -------
369 state:
370 `True` if upgrade available, `False` if current version if up-to-date,
371 -1 on error
372 version:
373 the most up-to-version available
374 """
375 try:
376 from urllib import urlopen
377 version = urlopen(version_url).read()
378 pversion = parse_version(version)
379 pmyversion = parse_version(myversion)
380 except IOError:
381 import traceback
382 print traceback.format_exc()
383 return -1, myversion
384
385 if pversion[:3]+pversion[-6:] > pmyversion[:3]+pmyversion[-6:]:
386 return True, version
387 else:
388 return False, version
389
390
391 -def unzip(filename, dir, subfolder=''):
392 """
393 Unzips filename into dir (.zip only, no .gz etc)
394 if subfolder!='' it unzip only files in subfolder
395 """
396 filename = abspath(filename)
397 if not zipfile.is_zipfile(filename):
398 raise RuntimeError('Not a valid zipfile')
399 zf = zipfile.ZipFile(filename)
400 if not subfolder.endswith('/'):
401 subfolder += '/'
402 n = len(subfolder)
403 for name in sorted(zf.namelist()):
404 if not name.startswith(subfolder):
405 continue
406
407 if name.endswith('/'):
408 folder = os.path.join(dir, name[n:])
409 if not os.path.exists(folder):
410 os.mkdir(folder)
411 else:
412 write_file(os.path.join(dir, name[n:]), zf.read(name), 'wb')
413
414
415 -def upgrade(request, url='http://web2py.com'):
416 """
417 Upgrades web2py (src, osx, win) is a new version is posted.
418 It detects whether src, osx or win is running and downloads the right one
419
420 Parameters
421 ----------
422 request:
423 the current request object, required to determine version and path
424 url:
425 the incomplete url where to locate the latest web2py
426 actual url is url+'/examples/static/web2py_(src|osx|win).zip'
427
428 Returns
429 -------
430 True on success, False on failure (network problem or old version)
431 """
432 web2py_version = request.env.web2py_version
433 gluon_parent = request.env.gluon_parent
434 if not gluon_parent.endswith('/'):
435 gluon_parent += '/'
436 (check, version) = check_new_version(web2py_version,
437 url + '/examples/default/version')
438 if not check:
439 return False, 'Already latest version'
440 if os.path.exists(os.path.join(gluon_parent, 'web2py.exe')):
441 version_type = 'win'
442 destination = gluon_parent
443 subfolder = 'web2py/'
444 elif gluon_parent.endswith('/Contents/Resources/'):
445 version_type = 'osx'
446 destination = gluon_parent[:-len('/Contents/Resources/')]
447 subfolder = 'web2py/web2py.app/'
448 else:
449 version_type = 'src'
450 destination = gluon_parent
451 subfolder = 'web2py/'
452
453 full_url = url + '/examples/static/web2py_%s.zip' % version_type
454 filename = abspath('web2py_%s_downloaded.zip' % version_type)
455 try:
456 write_file(filename, urllib.urlopen(full_url).read(), 'wb')
457 except Exception, e:
458 return False, e
459 try:
460 unzip(filename, destination, subfolder)
461 return True, None
462 except Exception, e:
463 return False, e
464
465
471
472
482
483
485 if not global_settings.web2py_runtime_gae:
486 if request.folder not in global_settings.app_folders:
487 for subfolder in ('models', 'views', 'controllers', 'databases',
488 'modules', 'cron', 'errors', 'sessions',
489 'languages', 'static', 'private', 'uploads'):
490 path = os.path.join(request.folder, subfolder)
491 if not os.path.exists(path):
492 os.mkdir(path)
493 global_settings.app_folders.add(request.folder)
494