Package gluon :: Module admin
[hide private]
[frames] | no frames]

Source Code for Module gluon.admin

  1  #!/usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  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
66 -def app_pack_compiled(app, request, raise_ex=False):
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
88 -def app_cleanup(app, request):
89 """Removes session, cache and error files 90 91 Args: 92 app(str): application name 93 request: the global request object 94 95 Returns: 96 True if everything went ok, False otherwise 97 98 """ 99 r = True 100 101 # Remove error files 102 path = apath('%s/errors/' % app, request) 103 if os.path.exists(path): 104 for f in os.listdir(path): 105 try: 106 if f[:1] != '.': os.unlink(os.path.join(path, f)) 107 except IOError: 108 r = False 109 110 # Remove session files 111 path = apath('%s/sessions/' % app, request) 112 if os.path.exists(path): 113 for f in os.listdir(path): 114 try: 115 if f[:1] != '.': recursive_unlink(os.path.join(path, f)) 116 except IOError: 117 r = False 118 119 # Remove cache files 120 path = apath('%s/cache/' % app, request) 121 if os.path.exists(path): 122 for f in os.listdir(path): 123 try: 124 if f[:1] != '.': os.unlink(os.path.join(path, f)) 125 except IOError: 126 r = False 127 return r
128 129
130 -def app_compile(app, request):
131 """Compiles the application 132 133 Args: 134 app(str): application name 135 request: the global request object 136 137 Returns: 138 None if everything went ok, traceback text if errors are found 139 140 """ 141 from compileapp import compile_application, remove_compiled_application 142 folder = apath(app, request) 143 try: 144 compile_application(folder) 145 return None 146 except (Exception, RestrictedError): 147 tb = traceback.format_exc(sys.exc_info) 148 remove_compiled_application(folder) 149 return tb
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
246 -def app_uninstall(app, request):
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 # Hey App, this is your end... 259 path = apath(app, request) 260 rmtree(path) 261 return True 262 except Exception: 263 return False
264 265
266 -def plugin_pack(app, plugin_name, request):
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
287 -def plugin_install(app, fobj, request, filename):
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
319 -def check_new_version(myversion, version_url):
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 #print name[n:] 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
431 -def add_path_first(path):
432 sys.path = [path] + [p for p in sys.path if ( 433 not p == path and not p == (path + '/'))] 434 if not global_settings.web2py_runtime_gae: 435 site.addsitedir(path)
436 437
438 -def create_missing_folders():
439 if not global_settings.web2py_runtime_gae: 440 for path in ('applications', 'deposit', 'site-packages', 'logs'): 441 path = abspath(path, gluon=True) 442 if not os.path.exists(path): 443 os.mkdir(path) 444 paths = (global_settings.gluon_parent, abspath( 445 'site-packages', gluon=True), abspath('gluon', gluon=True), '') 446 [add_path_first(path) for path in paths]
447 448
449 -def create_missing_app_folders(request):
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