root/galaxy-central/lib/galaxy/web/buildapp.py

リビジョン 2, 11.7 KB (コミッタ: hatakeyama, 14 年 前)

import galaxy-central

行番号 
1"""
2Provides factory methods to assemble the Galaxy web application
3"""
4
5import logging, atexit
6import os, os.path
7import sys, warnings
8
9from inspect import isclass
10
11from paste.request import parse_formvars
12from paste.util import import_string
13from paste import httpexceptions
14from paste.deploy.converters import asbool
15import pkg_resources
16
17log = logging.getLogger( __name__ )
18
19from galaxy import config, jobs, util, tools
20import galaxy.model
21import galaxy.model.mapping
22import galaxy.datatypes.registry
23import galaxy.web.framework
24
25def add_controllers( webapp, app ):
26    """
27    Search for controllers in the 'galaxy.web.controllers' module and add
28    them to the webapp.
29    """
30    from galaxy.web.base.controller import BaseController
31    from galaxy.web.base.controller import ControllerUnavailable
32    import galaxy.web.controllers
33    controller_dir = galaxy.web.controllers.__path__[0]
34    for fname in os.listdir( controller_dir ):
35        if not( fname.startswith( "_" ) ) and fname.endswith( ".py" ):
36            name = fname[:-3]
37            module_name = "galaxy.web.controllers." + name
38            try:
39                module = __import__( module_name )
40            except ControllerUnavailable, exc:
41                log.debug("%s could not be loaded: %s" % (module_name, str(exc)))
42                continue
43            for comp in module_name.split( "." )[1:]:
44                module = getattr( module, comp )
45            # Look for a controller inside the modules
46            for key in dir( module ):
47                T = getattr( module, key )
48                if isclass( T ) and T is not BaseController and issubclass( T, BaseController ):
49                    webapp.add_controller( name, T( app ) )
50
51def add_api_controllers( webapp, app ):
52    from galaxy.web.base.controller import BaseController
53    from galaxy.web.base.controller import ControllerUnavailable
54    import galaxy.web.api
55    controller_dir = galaxy.web.api.__path__[0]
56    for fname in os.listdir( controller_dir ):
57        if not( fname.startswith( "_" ) ) and fname.endswith( ".py" ):
58            name = fname[:-3]
59            module_name = "galaxy.web.api." + name
60            try:
61                module = __import__( module_name )
62            except ControllerUnavailable, exc:
63                log.debug("%s could not be loaded: %s" % (module_name, str(exc)))
64                continue
65            for comp in module_name.split( "." )[1:]:
66                module = getattr( module, comp )
67            for key in dir( module ):
68                T = getattr( module, key )
69                if isclass( T ) and T is not BaseController and issubclass( T, BaseController ):
70                    webapp.add_api_controller( name, T( app ) )
71
72def app_factory( global_conf, **kwargs ):
73    """
74    Return a wsgi application serving the root object
75    """
76    # Create the Galaxy application unless passed in
77    if 'app' in kwargs:
78        app = kwargs.pop( 'app' )
79    else:
80        try:
81            from galaxy.app import UniverseApplication
82            app = UniverseApplication( global_conf = global_conf, **kwargs )
83        except:
84            import traceback, sys
85            traceback.print_exc()
86            sys.exit( 1 )
87    atexit.register( app.shutdown )
88    # Create the universe WSGI application
89    webapp = galaxy.web.framework.WebApplication( app, session_cookie='galaxysession' )
90    add_controllers( webapp, app )
91    # Force /history to go to /root/history -- needed since the tests assume this
92    webapp.add_route( '/history', controller='root', action='history' )
93    # These two routes handle our simple needs at the moment
94    webapp.add_route( '/async/:tool_id/:data_id/:data_secret', controller='async', action='index', tool_id=None, data_id=None, data_secret=None )
95    webapp.add_route( '/:controller/:action', action='index' )
96    webapp.add_route( '/:action', controller='root', action='index' )
97    webapp.add_route( '/datasets/:dataset_id/:action/:filename', controller='dataset', action='index', dataset_id=None, filename=None)
98    webapp.add_route( '/display_application/:dataset_id/:app_name/:link_name/:user_id/:app_action/:action_param', controller='dataset', action='display_application', dataset_id=None, user_id=None, app_name = None, link_name = None, app_action = None, action_param = None )
99    webapp.add_route( '/u/:username/d/:slug', controller='dataset', action='display_by_username_and_slug' )
100    webapp.add_route( '/u/:username/p/:slug', controller='page', action='display_by_username_and_slug' )
101    webapp.add_route( '/u/:username/h/:slug', controller='history', action='display_by_username_and_slug' )
102    webapp.add_route( '/u/:username/w/:slug', controller='workflow', action='display_by_username_and_slug' )
103    webapp.add_route( '/u/:username/v/:slug', controller='visualization', action='display_by_username_and_slug' )
104    # If enabled, add the web API
105    if asbool( kwargs.get( 'enable_api', False ) ):
106        add_api_controllers( webapp, app )
107        webapp.api_mapper.resource( 'content', 'contents', path_prefix='/api/libraries/:library_id', parent_resources=dict( member_name='library', collection_name='libraries' ) )
108        webapp.api_mapper.resource( 'library', 'libraries', path_prefix='/api' )
109    webapp.finalize_config()
110    # Wrap the webapp in some useful middleware
111    if kwargs.get( 'middleware', True ):
112        webapp = wrap_in_middleware( webapp, global_conf, **kwargs )
113    if asbool( kwargs.get( 'static_enabled', True ) ):
114        webapp = wrap_in_static( webapp, global_conf, **kwargs )
115    # Close any pooled database connections before forking
116    try:
117        galaxy.model.mapping.metadata.engine.connection_provider._pool.dispose()
118    except:
119        pass
120    # Return
121    return webapp
122   
123def wrap_in_middleware( app, global_conf, **local_conf ):
124    """
125    Based on the configuration wrap `app` in a set of common and useful
126    middleware.
127    """
128    # Merge the global and local configurations
129    conf = global_conf.copy()
130    conf.update(local_conf)
131    debug = asbool( conf.get( 'debug', False ) )
132    # First put into place httpexceptions, which must be most closely
133    # wrapped around the application (it can interact poorly with
134    # other middleware):
135    app = httpexceptions.make_middleware( app, conf )
136    log.debug( "Enabling 'httpexceptions' middleware" )
137    # If we're using remote_user authentication, add middleware that
138    # protects Galaxy from improperly configured authentication in the
139    # upstream server
140    if asbool(conf.get( 'use_remote_user', False )):
141        from galaxy.web.framework.middleware.remoteuser import RemoteUser
142        app = RemoteUser( app, maildomain=conf.get( 'remote_user_maildomain', None ),
143                               ucsc_display_sites=conf.get( 'ucsc_display_sites', [] ),
144                               admin_users=conf.get( 'admin_users', '' ).split( ',' ) )
145        log.debug( "Enabling 'remote user' middleware" )
146    # The recursive middleware allows for including requests in other
147    # requests or forwarding of requests, all on the server side.
148    if asbool(conf.get('use_recursive', True)):
149        from paste import recursive
150        app = recursive.RecursiveMiddleware( app, conf )
151        log.debug( "Enabling 'recursive' middleware" )
152    # Various debug middleware that can only be turned on if the debug
153    # flag is set, either because they are insecure or greatly hurt
154    # performance
155    if debug:
156        # Middleware to check for WSGI compliance
157        if asbool( conf.get( 'use_lint', False ) ):
158            from paste import lint
159            app = lint.make_middleware( app, conf )
160            log.debug( "Enabling 'lint' middleware" )
161        # Middleware to run the python profiler on each request
162        if asbool( conf.get( 'use_profile', False ) ):
163            from paste.debug import profile
164            app = profile.ProfileMiddleware( app, conf )
165            log.debug( "Enabling 'profile' middleware" )
166        # Middleware that intercepts print statements and shows them on the
167        # returned page
168        if asbool( conf.get( 'use_printdebug', True ) ):
169            from paste.debug import prints
170            app = prints.PrintDebugMiddleware( app, conf )
171            log.debug( "Enabling 'print debug' middleware" )
172    if debug and asbool( conf.get( 'use_interactive', False ) ):
173        # Interactive exception debugging, scary dangerous if publicly
174        # accessible, if not enabled we'll use the regular error printing
175        # middleware.
176        pkg_resources.require( "WebError" )
177        from weberror import evalexception
178        app = evalexception.EvalException( app, conf,
179                                           templating_formatters=build_template_error_formatters() )
180        log.debug( "Enabling 'eval exceptions' middleware" )
181    else:
182        # Not in interactive debug mode, just use the regular error middleware
183        if sys.version_info[:2] >= ( 2, 6 ):
184            warnings.filterwarnings( 'ignore', '.*', DeprecationWarning, '.*serial_number_generator', 11, True )
185            from paste.exceptions import errormiddleware
186            warnings.filters.pop()
187        else:
188            from paste.exceptions import errormiddleware
189        app = errormiddleware.ErrorMiddleware( app, conf )
190        log.debug( "Enabling 'error' middleware" )
191    # Transaction logging (apache access.log style)
192    if asbool( conf.get( 'use_translogger', True ) ):
193        from framework.middleware.translogger import TransLogger
194        app = TransLogger( app )
195        log.debug( "Enabling 'trans logger' middleware" )
196    # Config middleware just stores the paste config along with the request,
197    # not sure we need this but useful
198    from paste.deploy.config import ConfigMiddleware
199    app = ConfigMiddleware( app, conf )
200    log.debug( "Enabling 'config' middleware" )
201    # X-Forwarded-Host handling
202    from galaxy.web.framework.middleware.xforwardedhost import XForwardedHostMiddleware
203    app = XForwardedHostMiddleware( app )
204    log.debug( "Enabling 'x-forwarded-host' middleware" )
205    return app
206   
207def wrap_in_static( app, global_conf, **local_conf ):
208    from paste.urlmap import URLMap
209    from galaxy.web.framework.middleware.static import CacheableStaticURLParser as Static
210    urlmap = URLMap()
211    # Merge the global and local configurations
212    conf = global_conf.copy()
213    conf.update(local_conf)
214    # Get cache time in seconds
215    cache_time = conf.get( "static_cache_time", None )
216    if cache_time is not None:
217        cache_time = int( cache_time )
218    # Send to dynamic app by default
219    urlmap["/"] = app
220    # Define static mappings from config
221    urlmap["/static"] = Static( conf.get( "static_dir" ), cache_time )
222    urlmap["/images"] = Static( conf.get( "static_images_dir" ), cache_time )
223    urlmap["/static/scripts"] = Static( conf.get( "static_scripts_dir" ), cache_time )
224    urlmap["/static/style"] = Static( conf.get( "static_style_dir" ), cache_time )
225    urlmap["/favicon.ico"] = Static( conf.get( "static_favicon_dir" ), cache_time )
226    # URL mapper becomes the root webapp
227    return urlmap
228   
229def build_template_error_formatters():
230    """
231    Build a list of template error formatters for WebError. When an error
232    occurs, WebError pass the exception to each function in this list until
233    one returns a value, which will be displayed on the error page.
234    """
235    formatters = []
236    # Formatter for mako
237    import mako.exceptions
238    def mako_html_data( exc_value ):
239        if isinstance( exc_value, ( mako.exceptions.CompileException, mako.exceptions.SyntaxException ) ):
240            return mako.exceptions.html_error_template().render( full=False, css=False )
241        if isinstance( exc_value, AttributeError ) and exc_value.args[0].startswith( "'Undefined' object has no attribute" ):
242            return mako.exceptions.html_error_template().render( full=False, css=False )
243    formatters.append( mako_html_data )
244    return formatters
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。