source: OpenRLabs-Git/deploy/rlabs-docker/web2py-rlabs/gluon/admin.py

main
Last change on this file was 42bd667, checked in by David Fuertes <dfuertes@…>, 4 years ago

Historial Limpio

  • Property mode set to 100755
File size: 12.8 KB
Line 
1# -*- coding: utf-8 -*-
2# vim: set ts=4 sw=4 et ai:
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
9Utility functions for the Admin application
10-------------------------------------------
11"""
12
13from __future__ import print_function
14
15import os
16import traceback
17from shutil import rmtree, copyfileobj
18import zipfile
19
20from gluon.fileutils import (w2p_pack, create_app, w2p_unpack,
21                             w2p_pack_plugin, w2p_unpack_plugin,
22                             up, fix_newlines, abspath, recursive_unlink,
23                             write_file, parse_version)
24from gluon.restricted import RestrictedError
25from gluon.settings import global_settings
26from gluon.cache import CacheOnDisk
27from gluon._compat import urlopen, to_native
28
29# TODO: move into add_path_first
30if not global_settings.web2py_runtime_gae:
31    pass
32
33
34REGEX_DEFINE_TABLE = r"""^\w+\.define_table\(\s*['"](?P<name>\w+)['"]"""
35REGEX_EXTEND = r"""^\s*(?P<all>\{\{\s*extend\s+['"](?P<name>[^'"]+)['"]\s*\}\})"""
36REGEX_INCLUDE = r"""(?P<all>\{\{\s*include\s+['"](?P<name>[^'"]+)['"]\s*\}\})"""
37
38
39# TODO: swap arguments, let first ('r' or whatever) be mandatory
40def apath(path='', r=None):
41    """Builds a path inside an application folder
42
43    Args:
44        path(str): path within the application folder
45        r: the global request object
46
47    """
48
49    opath = up(r.folder)
50    while path.startswith('../'):
51        opath = up(opath)
52        path = path[3:]
53    return os.path.join(opath, path).replace('\\', '/')
54
55
56def app_pack(app, request, raise_ex=False, filenames=None):
57    """Builds a w2p package for the application
58
59    Args:
60        app(str): application name
61        request: the global request object
62    Returns:
63        filename of the w2p file or None on error
64
65    """
66    try:
67        if filenames is None:
68            app_cleanup(app, request)
69        filename = apath('../deposit/web2py.app.%s.w2p' % app, request)
70        w2p_pack(filename, apath(app, request), filenames=filenames)
71        return filename
72    except Exception as e:
73        if raise_ex:
74            raise
75        return False
76
77
78def app_pack_compiled(app, request, raise_ex=False):
79    """Builds a w2p bytecode-compiled package for the application
80
81    Args:
82        app(str): application name
83        request: the global request object
84
85    Returns:
86        filename of the w2p file or None on error
87
88    """
89
90    try:
91        filename = apath('../deposit/%s.w2p' % app, request)
92        w2p_pack(filename, apath(app, request), compiled=True)
93        return filename
94    except Exception:
95        if raise_ex:
96            raise
97        return None
98
99
100def app_cleanup(app, request):
101    """Removes session, cache and error files
102
103    Args:
104        app(str): application name
105        request: the global request object
106
107    Returns:
108        True if everything went ok, False otherwise
109
110    """
111    r = True
112
113    # Remove error files
114    path = apath('%s/errors/' % app, request)
115    if os.path.exists(path):
116        for f in os.listdir(path):
117            try:
118                if not f.startswith('.'):
119                    os.unlink(os.path.join(path, f))
120            except IOError:
121                r = False
122
123    # Remove session files
124    path = apath('%s/sessions/' % app, request)
125    if os.path.exists(path):
126        for f in os.listdir(path):
127            try:
128                if not f.startswith('.'):
129                    recursive_unlink(os.path.join(path, f))
130            except (OSError, IOError):
131                r = False
132
133    # Remove cache files
134    path = apath('%s/cache/' % app, request)
135    if os.path.exists(path):
136        CacheOnDisk(folder=path).clear()
137        for f in os.listdir(path):
138            try:
139                if not f.startswith('.'):
140                    recursive_unlink(os.path.join(path, f))
141            except (OSError, IOError):
142                r = False
143    return r
144
145
146def app_compile(app, request, skip_failed_views=False):
147    """Compiles the application
148
149    Args:
150        app(str): application name
151        request: the global request object
152
153    Returns:
154        None if everything went ok, traceback text if errors are found
155
156    """
157    from gluon.compileapp import compile_application, remove_compiled_application
158    folder = apath(app, request)
159    try:
160        failed_views = compile_application(folder, skip_failed_views)
161        return failed_views
162    except (Exception, RestrictedError):
163        tb = traceback.format_exc()
164        remove_compiled_application(folder)
165        return tb
166
167
168def app_create(app, request, force=False, key=None, info=False):
169    """Create a copy of welcome.w2p (scaffolding) app
170
171    Args:
172        app(str): application name
173        request: the global request object
174
175    """
176    path = apath(app, request)
177    if not os.path.exists(path):
178        try:
179            os.mkdir(path)
180        except:
181            if info:
182                return False, traceback.format_exc()
183            else:
184                return False
185    elif not force:
186        if info:
187            return False, "Application exists"
188        else:
189            return False
190    try:
191        create_app(path)
192        if info:
193            return True, None
194        else:
195            return True
196    except:
197        rmtree(path)
198        if info:
199            return False, traceback.format_exc()
200        else:
201            return False
202
203
204def app_install(app, fobj, request, filename, overwrite=None):
205    """Installs an application:
206
207    - Identifies file type by filename
208    - Writes `fobj` contents to the `../deposit/` folder
209    - Calls `w2p_unpack()` to do the job.
210
211    Args:
212        app(str): new application name
213        fobj(obj): file object containing the application to be installed
214        request: the global request object
215        filename(str): original filename of the `fobj`,
216            required to determine extension
217        overwrite(bool): force overwrite of existing application
218
219    Returns:
220        name of the file where app is temporarily stored or `None` on failure
221
222    """
223    did_mkdir = False
224    if filename.endswith('.w2p'):
225        extension = 'w2p'
226    elif filename.endswith('.tar.gz'):
227        extension = 'tar.gz'
228    else:
229        extension = 'tar'
230    upname = apath('../deposit/%s.%s' % (app, extension), request)
231
232    try:
233        with open(upname, 'wb') as appfp:
234            copyfileobj(fobj, appfp, 4194304) # 4 MB buffer
235        path = apath(app, request)
236        if not overwrite:
237            os.mkdir(path)
238            did_mkdir = True
239        w2p_unpack(upname, path)
240        if extension != 'tar':
241            os.unlink(upname)
242        fix_newlines(path)
243        return upname
244    except Exception:
245        if did_mkdir:
246            rmtree(path)
247        return False
248
249
250def app_uninstall(app, request):
251    """Uninstalls the application.
252
253    Args:
254        app(str): application name
255        request: the global request object
256
257    Returns:
258        `True` on success, `False` on failure
259
260    """
261    try:
262        # Hey App, this is your end...
263        path = apath(app, request)
264        rmtree(path)
265        return True
266    except Exception:
267        return False
268
269
270def plugin_pack(app, plugin_name, request):
271    """Builds a w2p package for the plugin
272
273    Args:
274        app(str): application name
275        plugin_name(str): the name of the plugin without `plugin_` prefix
276        request: the current request app
277
278    Returns:
279        filename of the w2p file or False on error
280
281    """
282    try:
283        filename = apath(
284            '../deposit/web2py.plugin.%s.w2p' % plugin_name, request)
285        w2p_pack_plugin(filename, apath(app, request), plugin_name)
286        return filename
287    except Exception:
288        return False
289
290
291def plugin_install(app, fobj, request, filename):
292    """Installs a plugin:
293
294    - Identifies file type by filename
295    - Writes `fobj` contents to the `../deposit/` folder
296    - Calls `w2p_unpack_plugin()` to do the job.
297
298    Args:
299        app(str): new application name
300        fobj: file object containing the application to be installed
301        request: the global request object
302        filename: original filename of the `fobj`,
303            required to determine extension
304
305    Returns:
306        name of the file where plugin is temporarily stored
307        or `False` on failure
308
309    """
310    upname = apath('../deposit/%s' % filename, request)
311
312    try:
313        with open(upname, 'wb') as appfp:
314            copyfileobj(fobj, appfp, 4194304) # 4 MB buffer
315        path = apath(app, request)
316        w2p_unpack_plugin(upname, path)
317        fix_newlines(path)
318        return upname
319    except Exception:
320        os.unlink(upname)
321        return False
322
323
324def check_new_version(myversion, version_url):
325    """Compares current web2py's version with the latest stable web2py version.
326
327    Args:
328        myversion: the current version as stored in file `web2py/VERSION`
329        version_URL: the URL that contains the version
330                     of the latest stable release
331
332    Returns:
333        tuple: state, version
334
335        - state : `True` if upgrade available, `False` if current
336                  version is up-to-date, -1 on error,
337                  -2 when the system is likely to be offline (no
338                  internet link available)
339        - version : the most up-to-version available
340
341    """
342    try:
343        version = to_native(urlopen(version_url).read())
344        pversion = parse_version(version)
345        pmyversion = parse_version(myversion)
346    except IOError as e:
347        from socket import gaierror
348        if isinstance(getattr(e, 'reason', None), gaierror) and \
349            e.reason.errno == -2:
350            # assuming the version_url is ok the socket.gaierror
351            # (gaierror stands for getaddrinfo() error) that
352            # originates the exception is probably due to a
353            # missing internet link (i.e. the system is offline)
354            print('system is offline, cannot retrieve latest web2py version')
355            return -2, myversion
356        else:
357            print(traceback.format_exc())
358            return -1, myversion
359
360    if pversion[:3]+pversion[-6:] > pmyversion[:3]+pmyversion[-6:]:
361        return True, version
362    else:
363        return False, version
364
365
366def unzip(filename, dir, subfolder=''):
367    """Unzips filename into dir (.zip only, no .gz etc)
368
369    Args:
370        filename(str): archive
371        dir(str): destination
372        subfolder(str): if != '' unzips only files in subfolder
373
374    """
375    filename = abspath(filename)
376    if not zipfile.is_zipfile(filename):
377        raise RuntimeError('Not a valid zipfile')
378    zf = zipfile.ZipFile(filename)
379    if not subfolder.endswith('/'):
380        subfolder += '/'
381    n = len(subfolder)
382    for name in sorted(zf.namelist()):
383        if not name.startswith(subfolder):
384            continue
385        # print(name[n:])
386        if name.endswith('/'):
387            folder = os.path.join(dir, name[n:])
388            if not os.path.exists(folder):
389                os.mkdir(folder)
390        else:
391            write_file(os.path.join(dir, name[n:]), zf.read(name), 'wb')
392
393
394def upgrade(request, url='http://web2py.com'):
395    """Upgrades web2py (src, osx, win) if a new version is posted.
396    It detects whether src, osx or win is running and downloads the right one
397
398    Args:
399        request: the current request object
400            (required to determine version and path)
401        url: the incomplete url where to locate the latest web2py
402             (actual url is url+'/examples/static/web2py_(src|osx|win).zip')
403
404    Returns
405        tuple: completed, traceback
406
407        - completed: True on success, False on failure
408          (network problem or old version)
409        - traceback: None on success, raised exception details on failure
410
411    """
412    web2py_version = request.env.web2py_version
413    gluon_parent = request.env.gluon_parent
414    if not gluon_parent.endswith('/'):
415        gluon_parent += '/'
416    (check, version) = check_new_version(web2py_version,
417                                         url + '/examples/default/version')
418    if not check:
419        return False, 'Already latest version'
420    if os.path.exists(os.path.join(gluon_parent, 'web2py.exe')):
421        version_type = 'win'
422        destination = gluon_parent
423        subfolder = 'web2py/'
424    elif gluon_parent.endswith('/Contents/Resources/'):
425        version_type = 'osx'
426        destination = gluon_parent[:-len('/Contents/Resources/')]
427        subfolder = 'web2py/web2py.app/'
428    else:
429        version_type = 'src'
430        destination = gluon_parent
431        subfolder = 'web2py/'
432
433    full_url = url + '/examples/static/web2py_%s.zip' % version_type
434    filename = abspath('web2py_%s_downloaded.zip' % version_type)
435    try:
436        write_file(filename, urlopen(full_url).read(), 'wb')
437    except Exception as e:
438        return False, e
439    try:
440        unzip(filename, destination, subfolder)
441        return True, None
442    except Exception as e:
443        return False, e
Note: See TracBrowser for help on using the repository browser.