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 for f in os.listdir(path):
105 try:
106 os.unlink(os.path.join(path,f))
107 except IOError:
108 r = False
109
110
111 path = apath('%s/sessions/' % app, request)
112 for f in os.listdir(path):
113 try:
114 recursive_unlink(os.path.join(path,f))
115 except IOError:
116 r = False
117
118
119 path = apath('%s/sessions/' % app, request)
120 for f in os.listdir(path):
121 try:
122 os.unlink(os.path.join(path,f))
123 except IOError:
124 r = False
125
126 return r
127
128
149
150 -def app_create(app, request,force=False,key=None):
151 """
152 Create a copy of welcome.w2p (scaffolding) app
153
154 Parameters
155 ----------
156 app:
157 application name
158 request:
159 the global request object
160
161 """
162 try:
163 path = apath(app, request)
164 os.mkdir(path)
165 except:
166 if not force:
167 return False
168 try:
169 w2p_unpack('welcome.w2p', path)
170 for subfolder in ['models','views','controllers', 'databases',
171 'modules','cron','errors','sessions',
172 'languages','static','private','uploads']:
173 subpath = os.path.join(path,subfolder)
174 if not os.path.exists(subpath):
175 os.mkdir(subpath)
176 db = os.path.join(path, 'models', 'db.py')
177 if os.path.exists(db):
178 fp = open(db,'r')
179 data = fp.read()
180 fp.close()
181 data = data.replace('<your secret key>',
182 'sha512:'+(key or web2py_uuid()))
183 fp = open(db,'w')
184 fp.write(data)
185 fp.close()
186 return True
187 except:
188 rmtree(path)
189 return False
190
191
192 -def app_install(app, fobj, request, filename, overwrite=None):
193 """
194 Installs an application:
195
196 - Identifies file type by filename
197 - Writes `fobj` contents to the `../deposit/` folder
198 - Calls `w2p_unpack()` to do the job.
199
200 Parameters
201 ----------
202 app:
203 new application name
204 fobj:
205 file object containing the application to be installed
206 request:
207 the global request object
208 filename:
209 original filename of the `fobj`, required to determine extension
210
211 Returns
212 -------
213 upname:
214 name of the file where app is temporarily stored or `None` on failure
215 """
216 did_mkdir = False
217 if filename[-4:] == '.w2p':
218 extension = 'w2p'
219 elif filename[-7:] == '.tar.gz':
220 extension = 'tar.gz'
221 else:
222 extension = 'tar'
223 upname = apath('../deposit/%s.%s' % (app, extension), request)
224
225 try:
226 upfile = open(upname, 'wb')
227 upfile.write(fobj.read())
228 upfile.close()
229 path = apath(app, request)
230 if not overwrite:
231 os.mkdir(path)
232 did_mkdir = True
233 w2p_unpack(upname, path)
234 if extension != 'tar':
235 os.unlink(upname)
236 fix_newlines(path)
237 return upname
238 except Exception:
239 if did_mkdir:
240 rmtree(path)
241 return False
242
243
245 """
246 Uninstalls the application.
247
248 Parameters
249 ----------
250 app:
251 application name
252 request:
253 the global request object
254
255 Returns
256 -------
257 `True` on success, `False` on failure
258 """
259 try:
260
261 path = apath(app, request)
262 rmtree(path)
263 return True
264 except Exception:
265 return False
266
268 """
269 Builds a w2p package for the application
270
271 Parameters
272 ----------
273 app:
274 application name
275 plugin_name:
276 the name of the plugin without plugin_ prefix
277 request:
278 the current request app
279
280 Returns
281 -------
282 filename:
283 filename of the w2p file or None on error
284 """
285 try:
286 filename = apath('../deposit/web2py.plugin.%s.w2p' % plugin_name, request)
287 w2p_pack_plugin(filename, apath(app, request), plugin_name)
288 return filename
289 except Exception:
290 return False
291
293 """
294 Installs an application:
295
296 - Identifies file type by filename
297 - Writes `fobj` contents to the `../deposit/` folder
298 - Calls `w2p_unpack()` to do the job.
299
300 Parameters
301 ----------
302 app:
303 new application name
304 fobj:
305 file object containing the application to be installed
306 request:
307 the global request object
308 filename:
309 original filename of the `fobj`, required to determine extension
310
311 Returns
312 -------
313 upname:
314 name of the file where app is temporarily stored or `None` on failure
315 """
316
317 upname = apath('../deposit/%s' % filename, request)
318
319 try:
320 upfile = open(upname, 'wb')
321 upfile.write(fobj.read())
322 upfile.close()
323 path = apath(app, request)
324 w2p_unpack_plugin(upname, path)
325 fix_newlines(path)
326 return upname
327 except Exception:
328 os.unlink(upname)
329 return False
330
332 """
333 Compares current web2py's version with the latest stable web2py version.
334
335 Parameters
336 ----------
337 myversion:
338 the current version as stored in file `web2py/VERSION`
339 version_URL:
340 the URL that contains the version of the latest stable release
341
342 Returns
343 -------
344 state:
345 `True` if upgrade available, `False` if current version if up-to-date,
346 -1 on error
347 version:
348 the most up-to-version available
349 """
350 try:
351 from urllib import urlopen
352 version = urlopen(version_URL).read()
353 except Exception:
354 return -1, myversion
355
356 if version > myversion:
357 return True, version
358 else:
359 return False, version
360
361 -def unzip(filename, dir, subfolder=''):
362 """
363 Unzips filename into dir (.zip only, no .gz etc)
364 if subfolder!='' it unzip only files in subfolder
365 """
366 filename = abspath(filename)
367 if not zipfile.is_zipfile(filename):
368 raise RuntimeError, 'Not a valid zipfile'
369 zf = zipfile.ZipFile(filename)
370 if not subfolder.endswith('/'):
371 subfolder = subfolder + '/'
372 n = len(subfolder)
373 for name in sorted(zf.namelist()):
374 if not name.startswith(subfolder):
375 continue
376
377 if name.endswith('/'):
378 folder = os.path.join(dir,name[n:])
379 if not os.path.exists(folder):
380 os.mkdir(folder)
381 else:
382 outfile = open(os.path.join(dir, name[n:]), 'wb')
383 outfile.write(zf.read(name))
384 outfile.close()
385
386
387 -def upgrade(request, url='http://web2py.com'):
388 """
389 Upgrades web2py (src, osx, win) is a new version is posted.
390 It detects whether src, osx or win is running and downloads the right one
391
392 Parameters
393 ----------
394 request:
395 the current request object, required to determine version and path
396 url:
397 the incomplete url where to locate the latest web2py
398 actual url is url+'/examples/static/web2py_(src|osx|win).zip'
399
400 Returns
401 -------
402 True on success, False on failure (network problem or old version)
403 """
404 web2py_version = request.env.web2py_version
405 gluon_parent = request.env.gluon_parent
406 if not gluon_parent.endswith('/'):
407 gluon_parent = gluon_parent + '/'
408 (check, version) = check_new_version(web2py_version,
409 url+'/examples/default/version')
410 if not check:
411 return (False, 'Already latest version')
412 if os.path.exists(os.path.join(gluon_parent, 'web2py.exe')):
413 version_type = 'win'
414 destination = gluon_parent
415 subfolder = 'web2py/'
416 elif gluon_parent.endswith('/Contents/Resources/'):
417 version_type = 'osx'
418 destination = gluon_parent[:-len('/Contents/Resources/')]
419 subfolder = 'web2py/web2py.app/'
420 else:
421 version_type = 'src'
422 destination = gluon_parent
423 subfolder = 'web2py/'
424
425 full_url = url + '/examples/static/web2py_%s.zip' % version_type
426 filename = abspath('web2py_%s_downloaded.zip' % version_type)
427 file = None
428 try:
429 file = open(filename,'wb')
430 file.write(urllib.urlopen(full_url).read())
431 file.close()
432 except Exception,e:
433 file and file.close()
434 return False, e
435 try:
436 unzip(filename, destination, subfolder)
437 return True, None
438 except Exception,e:
439 return False, e
440
442 sys.path = [path]+[p for p in sys.path if (not p==path and not p==(path+'/'))]
443
452
454 if not global_settings.web2py_runtime_gae:
455 if request.folder not in global_settings.app_folders:
456 for subfolder in ('models', 'views', 'controllers', 'databases',
457 'modules', 'cron', 'errors', 'sessions',
458 'languages', 'static', 'private', 'uploads'):
459 path = os.path.join(request.folder, subfolder)
460 if not os.path.exists(path):
461 os.mkdir(path)
462 global_settings.app_folders.add(request.folder)
463