""" his file is part of a custom distribution of the web2py Web Framework, version 1.99.7, licensed by the copyright holder (Massimo Di Pierro ) to Bosch Rexroth (Germany) for use in embedded devices according to the attached non-exclusive license (web2py-commercial-license-Bosh-2012-07-07.pdf, SHA-1 Hash: 42ed39335a669f6a1ba9a7d169063054b147c49c) The original file distributed with web2py is and remains properly of the copyright holder and licensed under LGPLv3 (http://www.gnu.org/licenses/lgpl.html) Utility functions for the Admin application =========================================== """ import os import sys import traceback import zipfile import urllib from shutil import rmtree from utils import web2py_uuid from fileutils import w2p_pack, w2p_unpack, w2p_pack_plugin, w2p_unpack_plugin from fileutils import up, fix_newlines, abspath, recursive_unlink from fileutils import read_file, write_file, parse_version from restricted import RestrictedError from settings import global_settings def apath(path='', r=None): """ Builds a path inside an application folder Parameters ---------- path: path within the application folder r: the global request object """ opath = up(r.folder) while path[:3] == '../': (opath, path) = (up(opath), path[3:]) return os.path.join(opath, path).replace('\\', '/') def app_pack(app, request): """ Builds a w2p package for the application Parameters ---------- app: application name request: the global request object Returns ------- filename: filename of the w2p file or None on error """ try: app_cleanup(app, request) filename = apath('../deposit/%s.w2p' % app, request) w2p_pack(filename, apath(app, request)) return filename except Exception: return False def app_pack_compiled(app, request): """ Builds a w2p bytecode-compiled package for the application Parameters ---------- app: application name request: the global request object Returns ------- filename: filename of the w2p file or None on error """ try: filename = apath('../deposit/%s.w2p' % app, request) w2p_pack(filename, apath(app, request), compiled=True) return filename except Exception: return None def app_cleanup(app, request): """ Removes session, cache and error files Parameters ---------- app: application name request: the global request object """ r = True # Remove error files path = apath('%s/errors/' % app, request) if os.path.exists(path): for f in os.listdir(path): try: if f[:1]!='.': os.unlink(os.path.join(path,f)) except IOError: r = False # Remove session files path = apath('%s/sessions/' % app, request) if os.path.exists(path): for f in os.listdir(path): try: if f[:1]!='.': recursive_unlink(os.path.join(path,f)) except IOError: r = False # Remove cache files path = apath('%s/sessions/' % app, request) if os.path.exists(path): for f in os.listdir(path): try: if f[:1]!='.': os.unlink(os.path.join(path,f)) except IOError: r = False return r def app_compile(app, request): """ Compiles the application Parameters ---------- app: application name request: the global request object """ from compileapp import compile_application, remove_compiled_application folder = apath(app, request) try: compile_application(folder) return None except (Exception, RestrictedError): tb = traceback.format_exc(sys.exc_info) remove_compiled_application(folder) return tb def app_create(app, request,force=False,key=None): """ Create a copy of welcome.w2p (scaffolding) app Parameters ---------- app: application name request: the global request object """ try: path = apath(app, request) os.mkdir(path) except: if not force: return False try: w2p_unpack('welcome.w2p', path) for subfolder in ['models','views','controllers', 'databases', 'modules','cron','errors','sessions', 'languages','static','private','uploads']: subpath = os.path.join(path,subfolder) if not os.path.exists(subpath): os.mkdir(subpath) db = os.path.join(path, 'models', 'db.py') if os.path.exists(db): data = read_file(db) data = data.replace('', 'sha512:'+(key or web2py_uuid())) write_file(db, data) return True except: rmtree(path) return False def app_install(app, fobj, request, filename, overwrite=None): """ Installs an application: - Identifies file type by filename - Writes `fobj` contents to the `../deposit/` folder - Calls `w2p_unpack()` to do the job. Parameters ---------- app: new application name fobj: file object containing the application to be installed request: the global request object filename: original filename of the `fobj`, required to determine extension Returns ------- upname: name of the file where app is temporarily stored or `None` on failure """ did_mkdir = False if filename[-4:] == '.w2p': extension = 'w2p' elif filename[-7:] == '.tar.gz': extension = 'tar.gz' else: extension = 'tar' upname = apath('../deposit/%s.%s' % (app, extension), request) try: write_file(upname, fobj.read(), 'wb') path = apath(app, request) if not overwrite: os.mkdir(path) did_mkdir = True w2p_unpack(upname, path) if extension != 'tar': os.unlink(upname) fix_newlines(path) return upname except Exception: if did_mkdir: rmtree(path) return False def app_uninstall(app, request): """ Uninstalls the application. Parameters ---------- app: application name request: the global request object Returns ------- `True` on success, `False` on failure """ try: # Hey App, this is your end... path = apath(app, request) rmtree(path) return True except Exception: return False def plugin_pack(app, plugin_name, request): """ Builds a w2p package for the application Parameters ---------- app: application name plugin_name: the name of the plugin without plugin_ prefix request: the current request app Returns ------- filename: filename of the w2p file or None on error """ try: filename = apath('../deposit/web2py.plugin.%s.w2p' % plugin_name, request) w2p_pack_plugin(filename, apath(app, request), plugin_name) return filename except Exception: return False def plugin_install(app, fobj, request, filename): """ Installs an application: - Identifies file type by filename - Writes `fobj` contents to the `../deposit/` folder - Calls `w2p_unpack()` to do the job. Parameters ---------- app: new application name fobj: file object containing the application to be installed request: the global request object filename: original filename of the `fobj`, required to determine extension Returns ------- upname: name of the file where app is temporarily stored or `None` on failure """ upname = apath('../deposit/%s' % filename, request) try: write_file(upname, fobj.read(), 'wb') path = apath(app, request) w2p_unpack_plugin(upname, path) fix_newlines(path) return upname except Exception: os.unlink(upname) return False def check_new_version(myversion, version_URL): """ Compares current web2py's version with the latest stable web2py version. Parameters ---------- myversion: the current version as stored in file `web2py/VERSION` version_URL: the URL that contains the version of the latest stable release Returns ------- state: `True` if upgrade available, `False` if current version if up-to-date, -1 on error version: the most up-to-version available """ try: from urllib import urlopen version = parse_version(urlopen(version_URL).read()) except Exception: return -1, myversion if version > myversion: return True, version else: return False, version def unzip(filename, dir, subfolder=''): """ Unzips filename into dir (.zip only, no .gz etc) if subfolder!='' it unzip only files in subfolder """ filename = abspath(filename) if not zipfile.is_zipfile(filename): raise RuntimeError, 'Not a valid zipfile' zf = zipfile.ZipFile(filename) if not subfolder.endswith('/'): subfolder = subfolder + '/' n = len(subfolder) for name in sorted(zf.namelist()): if not name.startswith(subfolder): continue #print name[n:] if name.endswith('/'): folder = os.path.join(dir,name[n:]) if not os.path.exists(folder): os.mkdir(folder) else: write_file(os.path.join(dir, name[n:]), zf.read(name), 'wb') def upgrade(request, url='http://web2py.com'): """ Upgrades web2py (src, osx, win) is a new version is posted. It detects whether src, osx or win is running and downloads the right one Parameters ---------- request: the current request object, required to determine version and path url: the incomplete url where to locate the latest web2py actual url is url+'/examples/static/web2py_(src|osx|win).zip' Returns ------- True on success, False on failure (network problem or old version) """ web2py_version = request.env.web2py_version gluon_parent = request.env.gluon_parent if not gluon_parent.endswith('/'): gluon_parent = gluon_parent + '/' (check, version) = check_new_version(web2py_version, url+'/examples/default/version') if not check: return (False, 'Already latest version') if os.path.exists(os.path.join(gluon_parent, 'web2py.exe')): version_type = 'win' destination = gluon_parent subfolder = 'web2py/' elif gluon_parent.endswith('/Contents/Resources/'): version_type = 'osx' destination = gluon_parent[:-len('/Contents/Resources/')] subfolder = 'web2py/web2py.app/' else: version_type = 'src' destination = gluon_parent subfolder = 'web2py/' full_url = url + '/examples/static/web2py_%s.zip' % version_type filename = abspath('web2py_%s_downloaded.zip' % version_type) file = None try: write_file(filename, urllib.urlopen(full_url).read(), 'wb') except Exception,e: return False, e try: unzip(filename, destination, subfolder) return True, None except Exception,e: return False, e def add_path_first(path): sys.path = [path]+[p for p in sys.path if (not p==path and not p==(path+'/'))] def create_missing_folders(): if not global_settings.web2py_runtime_gae: for path in ('applications', 'deposit', 'site-packages', 'logs'): path = abspath(path, gluon=True) if not os.path.exists(path): os.mkdir(path) paths = (global_settings.gluon_parent, abspath('site-packages', gluon=True), abspath('gluon', gluon=True), '') [add_path_first(path) for path in paths] def create_missing_app_folders(request): if not global_settings.web2py_runtime_gae: if request.folder not in global_settings.app_folders: for subfolder in ('models', 'views', 'controllers', 'databases', 'modules', 'cron', 'errors', 'sessions', 'languages', 'static', 'private', 'uploads'): path = os.path.join(request.folder, subfolder) if not os.path.exists(path): os.mkdir(path) global_settings.app_folders.add(request.folder)