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

# Source Code for Module web2py.gluon.admin

      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
     41 -def app_pack(app, request):
     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
     66 -def app_pack_compiled(app, request):
     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
     90 -def app_cleanup(app, request):
     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      # Remove error files
    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      # Remove session files
    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      # Remove cache files
    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
    132 -def app_compile(app, request):
    133      """
    134      Compiles the application
    135
    136      Parameters
    137      ----------
    138      app:
    139          application name
    140      request:
    141          the global request object
    142      """
    143      from compileapp import compile_application, remove_compiled_application
    144      folder = apath(app, request)
    145      try:
    146          compile_application(folder)
    147          return None
    148      except (Exception, RestrictedError):
    149          tb = traceback.format_exc(sys.exc_info)
    150          remove_compiled_application(folder)
    151          return tb
    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
    241 -def app_uninstall(app, request):
    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          # Hey App, this is your end...
    258          path = apath(app, request)
    259          rmtree(path)
    260          return True
    261      except Exception:
    262          return False
    263
    264 -def plugin_pack(app, plugin_name, request):
    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
    289 -def plugin_install(app, fobj, request, filename):
    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
    326 -def check_new_version(myversion, version_URL):
    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          #print name[n:]
    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
    431 -def add_path_first(path):
    432      sys.path = [path]+[p for p in sys.path if (not p==path and not p==(path+'/'))]
    433
    434 -def create_missing_folders():
    435      if not global_settings.web2py_runtime_gae:
    436          for path in ('applications', 'deposit', 'site-packages', 'logs'):
    437              path = abspath(path, gluon=True)
    438              if not os.path.exists(path):
    439                  os.mkdir(path)
    440      paths = (global_settings.gluon_parent, abspath('site-packages', gluon=True),  abspath('gluon', gluon=True), '')
    441      [add_path_first(path) for path in paths]
    442
    443 -def create_missing_app_folders(request):
    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