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