diff --git a/applications/admin/controllers/default.py b/applications/admin/controllers/default.py index 3e615c1e..264f757a 100644 --- a/applications/admin/controllers/default.py +++ b/applications/admin/controllers/default.py @@ -484,9 +484,15 @@ def cleanup(): def compile_app(): app = get_app() - c = app_compile(app, request) + c = app_compile(app, request, + skip_failed_views = (request.args(1) == 'skip_failed_views')) if not c: session.flash = T('application compiled') + elif isinstance(c, list): + session.flash = DIV(*[T('application compiled'), BR(), BR(), + T('WARNING: The following views could not be compiled:'), BR()] + + [CAT(BR(), view) for view in c] + + [BR(), BR(), T('DO NOT use the "Pack compiled" feature.')]) else: session.flash = DIV(T('Cannot compile: there are errors in your app:'), CODE(c)) diff --git a/applications/admin/views/default/site.html b/applications/admin/views/default/site.html index 64fde5ec..d5240668 100644 --- a/applications/admin/views/default/site.html +++ b/applications/admin/views/default/site.html @@ -27,7 +27,9 @@ {{buttons.append((URL('pack',args=a), T("Pack all")))}} {{buttons.append((URL('pack_custom',args=a), T("Pack custom")))}} {{if not os.path.exists('applications/%s/compiled' % a):}} - {{buttons.append((URL('compile_app',args=a), T("Compile")))}} + {{buttons.append((URL('compile_app',args=[a, 'skip_failed_views']), + T("Compile (skip failed views)")))}} + {{buttons.append((URL('compile_app',args=a), T("Compile (all or nothing)")))}} {{else:}} {{buttons.append((URL('pack',args=(a, 'compiled')), T("Pack compiled")))}} {{if glob.glob('applications/%s/controllers/*.py' % a):}} diff --git a/gluon/admin.py b/gluon/admin.py index 77ce646d..d1b1f429 100644 --- a/gluon/admin.py +++ b/gluon/admin.py @@ -131,7 +131,7 @@ def app_cleanup(app, request): return r -def app_compile(app, request): +def app_compile(app, request, skip_failed_views=False): """Compiles the application Args: @@ -145,8 +145,8 @@ def app_compile(app, request): from compileapp import compile_application, remove_compiled_application folder = apath(app, request) try: - compile_application(folder) - return None + failed_views = compile_application(folder, skip_failed_views) + return failed_views except (Exception, RestrictedError): tb = traceback.format_exc(sys.exc_info) remove_compiled_application(folder) diff --git a/gluon/compileapp.py b/gluon/compileapp.py index 7486a931..c6bbba3b 100644 --- a/gluon/compileapp.py +++ b/gluon/compileapp.py @@ -464,22 +464,28 @@ def read_pyc(filename): return marshal.loads(data[8:]) -def compile_views(folder): +def compile_views(folder, skip_failed_views=False): """ Compiles all the views in the application specified by `folder` """ path = pjoin(folder, 'views') + failed_views = [] for fname in listdir(path, '^[\w/\-]+(\.\w+)*$'): try: data = parse_template(fname, path) except Exception, e: - raise Exception("%s in %s" % (e, fname)) - filename = 'views.%s.py' % fname.replace(os.path.sep, '.') - filename = pjoin(folder, 'compiled', filename) - write_file(filename, data) - save_pyc(filename) - os.unlink(filename) + if skip_failed_views: + failed_views.append(file) + else: + raise Exception("%s in %s" % (e, file)) + else: + filename = ('views/%s.py' % file).replace('/', '_').replace('\\', '_') + filename = pjoin(folder, 'compiled', filename) + write_file(filename, data) + save_pyc(filename) + os.unlink(filename) + return failed_views if failed_views else None def compile_models(folder): @@ -667,32 +673,28 @@ def run_view_in(environment): ccode = parse_template(view, pjoin(folder, 'views'), context=environment) restricted(ccode, environment, 'file stream') - elif os.path.exists(path): - x = view.replace('/', '.') - files = ['views.%s.pyc' % x] - if allow_generic: - files.append('views.generic.%s.pyc' % request.extension) - # for backward compatibility - x = view.replace('/', '_') - files.append('views_%s.pyc' % x) - if allow_generic: - files.append('views_generic.%s.pyc' % request.extension) - if request.extension == 'html': - files.append('views_%s.pyc' % x[:-5]) - if allow_generic: - files.append('views_generic.pyc') - # end backward compatibility code - for f in files: - filename = pjoin(path, f) - if os.path.exists(filename): - code = read_pyc(filename) - restricted(code, environment, layer=filename) - return - raise HTTP(404, - rewrite.THREAD_LOCAL.routes.error_message % badv, - web2py_error=badv) else: filename = pjoin(folder, 'views', view) + if os.path.exists(path): # compiled views + x = view.replace('/', '_') + files = ['views_%s.pyc' % x] + is_compiled = os.path.exists(pjoin(path, files[0])) + # Don't use a generic view if the non-compiled view exists. + if is_compiled or (not is_compiled and not os.path.exists(filename)): + if allow_generic: + files.append('views_generic.%s.pyc' % request.extension) + # for backward compatibility + if request.extension == 'html': + files.append('views_%s.pyc' % x[:-5]) + if allow_generic: + files.append('views_generic.pyc') + # end backward compatibility code + for f in files: + compiled = pjoin(path, f) + if os.path.exists(compiled): + code = read_pyc(compiled) + restricted(code, environment, layer=compiled) + return if not os.path.exists(filename) and allow_generic: view = 'generic.' + request.extension filename = pjoin(folder, 'views', view) @@ -726,7 +728,7 @@ def remove_compiled_application(folder): pass -def compile_application(folder): +def compile_application(folder, skip_failed_views=False): """ Compiles all models, views, controller for the application in `folder`. """ @@ -734,7 +736,8 @@ def compile_application(folder): os.mkdir(pjoin(folder, 'compiled')) compile_models(folder) compile_controllers(folder) - compile_views(folder) + failed_views = compile_views(folder, skip_failed_views) + return failed_views def test():