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 utils import web2py_uuid
16 from fileutils import w2p_pack, w2p_unpack, w2p_pack_plugin, w2p_unpack_plugin
17 from fileutils import up, fix_newlines, abspath, recursive_unlink
18 from restricted import RestrictedError
19 from settings import global_settings
20
21 -def apath(path='', r=None):
22 """
23 Builds a path inside an application folder
24
25 Parameters
26 ----------
27 path:
28 path within the application folder
29 r:
30 the global request object
31
32 """
33
34 opath = up(r.folder)
35 while path[:3] == '../':
36 (opath, path) = (up(opath), path[3:])
37 return os.path.join(opath, path).replace('\\', '/')
38
39
41 """
42 Builds a w2p package for the application
43
44 Parameters
45 ----------
46 app:
47 application name
48 request:
49 the global request object
50
51 Returns
52 -------
53 filename:
54 filename of the w2p file or None on error
55 """
56 try:
57 app_cleanup(app, request)
58 filename = apath('../deposit/%s.w2p' % app, request)
59 w2p_pack(filename, apath(app, request))
60 return filename
61 except Exception:
62 return False
63
64
66 """
67 Builds a w2p bytecode-compiled package for the application
68
69 Parameters
70 ----------
71 app:
72 application name
73 request:
74 the global request object
75
76 Returns
77 -------
78 filename:
79 filename of the w2p file or None on error
80 """
81
82 try:
83 filename = apath('../deposit/%s.w2p' % app, request)
84 w2p_pack(filename, apath(app, request), compiled=True)
85 return filename
86 except Exception:
87 return None
88
90 """
91 Removes session, cache and error files
92
93 Parameters
94 ----------
95 app:
96 application name
97 request:
98 the global request object
99 """
100 r = True
101
102
103 path = apath('%s/errors/' % app, request)
104 if os.path.exists(path):
105 for f in os.listdir(path):
106 try:
107 os.unlink(os.path.join(path,f))
108 except IOError:
109 r = False
110
111
112 path = apath('%s/sessions/' % app, request)
113 if os.path.exists(path):
114 for f in os.listdir(path):
115 try:
116 recursive_unlink(os.path.join(path,f))
117 except IOError:
118 r = False
119
120
121 path = apath('%s/sessions/' % app, request)
122 if os.path.exists(path):
123 for f in os.listdir(path):
124 try:
125 os.unlink(os.path.join(path,f))
126 except IOError:
127 r = False
128 return r
129
130
151
152 -def app_create(app, request,force=False,key=None):
153 """
154 Create a copy of welcome.w2p (scaffolding) app
155
156 Parameters
157 ----------
158 app:
159 application name
160 request:
161 the global request object
162
163 """
164 try:
165 path = apath(app, request)
166 os.mkdir(path)
167 except:
168 if not force:
169 return False
170 try:
171 w2p_unpack('welcome.w2p', path)
172 for subfolder in ['models','views','controllers', 'databases',
173 'modules','cron','errors','sessions',
174 'languages','static','private','uploads']:
175 subpath = os.path.join(path,subfolder)
176 if not os.path.exists(subpath):
177 os.mkdir(subpath)
178 db = os.path.join(path, 'models', 'db.py')
179 if os.path.exists(db):
180 fp = open(db,'r')
181 data = fp.read()
182 fp.close()
183 data = data.replace('<your secret key>',
184 'sha512:'+(key or web2py_uuid()))
185 fp = open(db,'w')
186 fp.write(data)
187 fp.close()
188 return True
189 except:
190 rmtree(path)
191 return False
192
193
194 -def app_install(app, fobj, request, filename, overwrite=None):
195 """
196 Installs an application:
197
198 - Identifies file type by filename
199 - Writes `fobj` contents to the `../deposit/` folder
200 - Calls `w2p_unpack()` to do the job.
201
202 Parameters
203 ----------
204 app:
205 new application name
206 fobj:
207 file object containing the application to be installed
208 request:
209 the global request object
210 filename:
211 original filename of the `fobj`, required to determine extension
212
213 Returns
214 -------
215 upname:
216 name of the file where app is temporarily stored or `None` on failure
217 """
218 did_mkdir = False
219 if filename[-4:] == '.w2p':
220 extension = 'w2p'
221 elif filename[-7:] == '.tar.gz':
222 extension = 'tar.gz'
223 else:
224 extension = 'tar'
225 upname = apath('../deposit/%s.%s' % (app, extension), request)
226
227 try:
228 upfile = open(upname, 'wb')
229 upfile.write(fobj.read())
230 upfile.close()
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 """
248 Uninstalls the application.
249
250 Parameters
251 ----------
252 app:
253 application name
254 request:
255 the global request object
256
257 Returns
258 -------
259 `True` on success, `False` on failure
260 """
261 try:
262
263 path = apath(app, request)
264 rmtree(path)
265 return True
266 except Exception:
267 return False
268
270 """
271 Builds a w2p package for the application
272
273 Parameters
274 ----------
275 app:
276 application name
277 plugin_name:
278 the name of the plugin without plugin_ prefix
279 request:
280 the current request app
281
282 Returns
283 -------
284 filename:
285 filename of the w2p file or None on error
286 """
287 try:
288 filename = apath('../deposit/web2py.plugin.%s.w2p' % plugin_name, request)
289 w2p_pack_plugin(filename, apath(app, request), plugin_name)
290 return filename
291 except Exception:
292 return False
293
295 """
296 Installs an application:
297
298 - Identifies file type by filename
299 - Writes `fobj` contents to the `../deposit/` folder
300 - Calls `w2p_unpack()` to do the job.
301
302 Parameters
303 ----------
304 app:
305 new application name
306 fobj:
307 file object containing the application to be installed
308 request:
309 the global request object
310 filename:
311 original filename of the `fobj`, required to determine extension
312
313 Returns
314 -------
315 upname:
316 name of the file where app is temporarily stored or `None` on failure
317 """
318
319 upname = apath('../deposit/%s' % filename, request)
320
321 try:
322 upfile = open(upname, 'wb')
323 upfile.write(fobj.read())
324 upfile.close()
325 path = apath(app, request)
326 w2p_unpack_plugin(upname, path)
327 fix_newlines(path)
328 return upname
329 except Exception:
330 os.unlink(upname)
331 return False
332
334 """
335 Compares current web2py's version with the latest stable web2py version.
336
337 Parameters
338 ----------
339 myversion:
340 the current version as stored in file `web2py/VERSION`
341 version_URL:
342 the URL that contains the version of the latest stable release
343
344 Returns
345 -------
346 state:
347 `True` if upgrade available, `False` if current version if up-to-date,
348 -1 on error
349 version:
350 the most up-to-version available
351 """
352 try:
353 from urllib import urlopen
354 version = urlopen(version_URL).read()
355 except Exception:
356 return -1, myversion
357
358 if version > myversion:
359 return True, version
360 else:
361 return False, version
362
363 -def unzip(filename, dir, subfolder=''):
364 """
365 Unzips filename into dir (.zip only, no .gz etc)
366 if subfolder!='' it unzip only files in subfolder
367 """
368 filename = abspath(filename)
369 if not zipfile.is_zipfile(filename):
370 raise RuntimeError, 'Not a valid zipfile'
371 zf = zipfile.ZipFile(filename)
372 if not subfolder.endswith('/'):
373 subfolder = subfolder + '/'
374 n = len(subfolder)
375 for name in sorted(zf.namelist()):
376 if not name.startswith(subfolder):
377 continue
378
379 if name.endswith('/'):
380 folder = os.path.join(dir,name[n:])
381 if not os.path.exists(folder):
382 os.mkdir(folder)
383 else:
384 outfile = open(os.path.join(dir, name[n:]), 'wb')
385 outfile.write(zf.read(name))
386 outfile.close()
387
388
389 -def upgrade(request, url='http://web2py.com'):
390 """
391 Upgrades web2py (src, osx, win) is a new version is posted.
392 It detects whether src, osx or win is running and downloads the right one
393
394 Parameters
395 ----------
396 request:
397 the current request object, required to determine version and path
398 url:
399 the incomplete url where to locate the latest web2py
400 actual url is url+'/examples/static/web2py_(src|osx|win).zip'
401
402 Returns
403 -------
404 True on success, False on failure (network problem or old version)
405 """
406 web2py_version = request.env.web2py_version
407 gluon_parent = request.env.gluon_parent
408 if not gluon_parent.endswith('/'):
409 gluon_parent = gluon_parent + '/'
410 (check, version) = check_new_version(web2py_version,
411 url+'/examples/default/version')
412 if not check:
413 return (False, 'Already latest version')
414 if os.path.exists(os.path.join(gluon_parent, 'web2py.exe')):
415 version_type = 'win'
416 destination = gluon_parent
417 subfolder = 'web2py/'
418 elif gluon_parent.endswith('/Contents/Resources/'):
419 version_type = 'osx'
420 destination = gluon_parent[:-len('/Contents/Resources/')]
421 subfolder = 'web2py/web2py.app/'
422 else:
423 version_type = 'src'
424 destination = gluon_parent
425 subfolder = 'web2py/'
426
427 full_url = url + '/examples/static/web2py_%s.zip' % version_type
428 filename = abspath('web2py_%s_downloaded.zip' % version_type)
429 file = None
430 try:
431 file = open(filename,'wb')
432 file.write(urllib.urlopen(full_url).read())
433 file.close()
434 except Exception,e:
435 file and file.close()
436 return False, e
437 try:
438 unzip(filename, destination, subfolder)
439 return True, None
440 except Exception,e:
441 return False, e
442
444 sys.path = [path]+[p for p in sys.path if (not p==path and not p==(path+'/'))]
445
454
456 if not global_settings.web2py_runtime_gae:
457 if request.folder not in global_settings.app_folders:
458 for subfolder in ('models', 'views', 'controllers', 'databases',
459 'modules', 'cron', 'errors', 'sessions',
460 'languages', 'static', 'private', 'uploads'):
461 path = os.path.join(request.folder, subfolder)
462 if not os.path.exists(path):
463 os.mkdir(path)
464 global_settings.app_folders.add(request.folder)
465