PageRenderTime 61ms CodeModel.GetById 14ms app.highlight 42ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/galaxy/webapps/community/buildapp.py

https://bitbucket.org/cistrome/cistrome-harvard/
Python | 200 lines | 145 code | 11 blank | 44 comment | 27 complexity | 13880a16e1a90771fb2e772cfca652d7 MD5 | raw file
  1"""
  2Provides factory methods to assemble the Galaxy web application
  3"""
  4
  5import logging, atexit, os, os.path, sys, config
  6
  7from inspect import isclass
  8
  9from paste.request import parse_formvars
 10from paste.util import import_string
 11from paste import httpexceptions
 12from paste.deploy.converters import asbool
 13
 14import pkg_resources
 15
 16import galaxy.webapps.community.model
 17import galaxy.webapps.community.model.mapping
 18import galaxy.web.framework
 19from galaxy.webapps.community.framework.middleware import hg
 20
 21log = logging.getLogger( __name__ )
 22
 23def add_ui_controllers( webapp, app ):
 24    """
 25    Search for controllers in the 'galaxy.webapps.controllers' module and add 
 26    them to the webapp.
 27    """
 28    from galaxy.web.base.controller import BaseUIController
 29    from galaxy.web.base.controller import ControllerUnavailable
 30    import galaxy.webapps.community.controllers
 31    controller_dir = galaxy.webapps.community.controllers.__path__[0]
 32    for fname in os.listdir( controller_dir ):
 33        if not fname.startswith( "_" ) and fname.endswith( ".py" ):
 34            name = fname[:-3]
 35            module_name = "galaxy.webapps.community.controllers." + name
 36            module = __import__( module_name )
 37            for comp in module_name.split( "." )[1:]:
 38                module = getattr( module, comp )
 39            # Look for a controller inside the modules
 40            for key in dir( module ):
 41                T = getattr( module, key )
 42                if isclass( T ) and T is not BaseUIController and issubclass( T, BaseUIController ):
 43                    webapp.add_ui_controller( name, T( app ) )
 44    import galaxy.web.controllers
 45    controller_dir = galaxy.web.controllers.__path__[0]
 46    for fname in os.listdir( controller_dir ):
 47        # TODO: fix this if we decide to use, we don't need to inspect all controllers...
 48        if fname.startswith( 'user' ) and fname.endswith( ".py" ):
 49            name = fname[:-3]
 50            module_name = "galaxy.web.controllers." + name
 51            module = __import__( module_name )
 52            for comp in module_name.split( "." )[1:]:
 53                module = getattr( module, comp )
 54            # Look for a controller inside the modules
 55            for key in dir( module ):
 56                T = getattr( module, key )
 57                if isclass( T ) and T is not BaseUIController and issubclass( T, BaseUIController ):
 58                    webapp.add_ui_controller( name, T( app ) )
 59
 60def app_factory( global_conf, **kwargs ):
 61    """Return a wsgi application serving the root object"""
 62    # Create the Galaxy tool shed application unless passed in
 63    if 'app' in kwargs:
 64        app = kwargs.pop( 'app' )
 65    else:
 66        try:
 67            from galaxy.webapps.community.app import UniverseApplication
 68            app = UniverseApplication( global_conf=global_conf, **kwargs )
 69        except:
 70            import traceback, sys
 71            traceback.print_exc()
 72            sys.exit( 1 )
 73    atexit.register( app.shutdown )
 74    # Create the universe WSGI application
 75    webapp = galaxy.web.framework.WebApplication( app, session_cookie='galaxycommunitysession' )
 76    add_ui_controllers( webapp, app )
 77    webapp.add_route( '/:controller/:action', action='index' )
 78    webapp.add_route( '/:action', controller='repository', action='index' )
 79    webapp.add_route( '/repos/*path_info', controller='hg', action='handle_request', path_info='/' )
 80    webapp.finalize_config()
 81    # Wrap the webapp in some useful middleware
 82    if kwargs.get( 'middleware', True ):
 83        webapp = wrap_in_middleware( webapp, global_conf, **kwargs )
 84    if kwargs.get( 'static_enabled', True ):
 85        webapp = wrap_in_static( webapp, global_conf, **kwargs )
 86    # Close any pooled database connections before forking
 87    try:
 88        galaxy.webapps.community.model.mapping.metadata.engine.connection_provider._pool.dispose()
 89    except:
 90        pass
 91    # Return
 92    return webapp
 93
 94def wrap_in_middleware( app, global_conf, **local_conf ):
 95    """Based on the configuration wrap `app` in a set of common and useful middleware."""
 96    # Merge the global and local configurations
 97    conf = global_conf.copy()
 98    conf.update( local_conf )
 99    debug = asbool( conf.get( 'debug', False ) )
100    # First put into place httpexceptions, which must be most closely
101    # wrapped around the application (it can interact poorly with
102    # other middleware):
103    app = httpexceptions.make_middleware( app, conf )
104    log.debug( "Enabling 'httpexceptions' middleware" )
105    # The recursive middleware allows for including requests in other 
106    # requests or forwarding of requests, all on the server side.
107    if asbool(conf.get('use_recursive', True)):
108        from paste import recursive
109        app = recursive.RecursiveMiddleware( app, conf )
110        log.debug( "Enabling 'recursive' middleware" )
111    # Various debug middleware that can only be turned on if the debug
112    # flag is set, either because they are insecure or greatly hurt
113    # performance
114    if debug:
115        # Middleware to check for WSGI compliance
116        if asbool( conf.get( 'use_lint', True ) ):
117            from paste import lint
118            app = lint.make_middleware( app, conf )
119            log.debug( "Enabling 'lint' middleware" )
120        # Middleware to run the python profiler on each request
121        if asbool( conf.get( 'use_profile', False ) ):
122            import profile
123            app = profile.ProfileMiddleware( app, conf )
124            log.debug( "Enabling 'profile' middleware" )
125        # Middleware that intercepts print statements and shows them on the
126        # returned page
127        if asbool( conf.get( 'use_printdebug', True ) ):
128            from paste.debug import prints
129            app = prints.PrintDebugMiddleware( app, conf )
130            log.debug( "Enabling 'print debug' middleware" )
131    if debug and asbool( conf.get( 'use_interactive', False ) ):
132        # Interactive exception debugging, scary dangerous if publicly
133        # accessible, if not enabled we'll use the regular error printing
134        # middleware.
135        pkg_resources.require( "WebError" )
136        from weberror import evalexception
137        app = evalexception.EvalException( app, conf,
138                                           templating_formatters=build_template_error_formatters() )
139        log.debug( "Enabling 'eval exceptions' middleware" )
140    else:
141        # Not in interactive debug mode, just use the regular error middleware
142        from paste.exceptions import errormiddleware
143        app = errormiddleware.ErrorMiddleware( app, conf )
144        log.debug( "Enabling 'error' middleware" )
145    # Transaction logging (apache access.log style)
146    if asbool( conf.get( 'use_translogger', True ) ):
147        from paste.translogger import TransLogger
148        app = TransLogger( app )
149        log.debug( "Enabling 'trans logger' middleware" )
150    # Config middleware just stores the paste config along with the request,
151    # not sure we need this but useful
152    from paste.deploy.config import ConfigMiddleware
153    app = ConfigMiddleware( app, conf )
154    log.debug( "Enabling 'config' middleware" )
155    # X-Forwarded-Host handling
156    from galaxy.web.framework.middleware.xforwardedhost import XForwardedHostMiddleware
157    app = XForwardedHostMiddleware( app )
158    log.debug( "Enabling 'x-forwarded-host' middleware" )
159    app = hg.Hg( app, conf )
160    log.debug( "Enabling hg middleware" )
161    return app
162    
163def wrap_in_static( app, global_conf, **local_conf ):
164    from paste.urlmap import URLMap
165    from galaxy.web.framework.middleware.static import CacheableStaticURLParser as Static
166    urlmap = URLMap()
167    # Merge the global and local configurations
168    conf = global_conf.copy()
169    conf.update(local_conf)
170    # Get cache time in seconds
171    cache_time = conf.get( "static_cache_time", None )
172    if cache_time is not None:
173        cache_time = int( cache_time )
174    # Send to dynamic app by default
175    urlmap["/"] = app
176    # Define static mappings from config
177    urlmap["/static"] = Static( conf.get( "static_dir" ), cache_time )
178    urlmap["/images"] = Static( conf.get( "static_images_dir" ), cache_time )
179    urlmap["/static/scripts"] = Static( conf.get( "static_scripts_dir" ), cache_time )
180    urlmap["/static/style"] = Static( conf.get( "static_style_dir" ), cache_time )
181    urlmap["/favicon.ico"] = Static( conf.get( "static_favicon_dir" ), cache_time )
182    # URL mapper becomes the root webapp
183    return urlmap
184    
185def build_template_error_formatters():
186    """
187    Build a list of template error formatters for WebError. When an error
188    occurs, WebError pass the exception to each function in this list until
189    one returns a value, which will be displayed on the error page.
190    """
191    formatters = []
192    # Formatter for mako
193    import mako.exceptions
194    def mako_html_data( exc_value ):
195        if isinstance( exc_value, ( mako.exceptions.CompileException, mako.exceptions.SyntaxException ) ):
196            return mako.exceptions.html_error_template().render( full=False, css=False )
197        if isinstance( exc_value, AttributeError ) and exc_value.args[0].startswith( "'Undefined' object has no attribute" ):
198            return mako.exceptions.html_error_template().render( full=False, css=False )
199    formatters.append( mako_html_data )
200    return formatters