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