diff options
| author | Chris McDonough <chrism@agendaless.com> | 2009-06-30 21:02:00 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2009-06-30 21:02:00 +0000 |
| commit | d809ac74d19342bcc84e4fe043697709b2001cc0 (patch) | |
| tree | 9973b531b90336bf6ecf3811aa3b9ba753f4e6d8 /repoze/bfg/static.py | |
| parent | f9e73ea5a9d5a4210e3a346aa2f9483d70d22ab9 (diff) | |
| download | pyramid-d809ac74d19342bcc84e4fe043697709b2001cc0.tar.gz pyramid-d809ac74d19342bcc84e4fe043697709b2001cc0.tar.bz2 pyramid-d809ac74d19342bcc84e4fe043697709b2001cc0.zip | |
- Add a ``reload_resources`` configuration file setting (aka the
``BFG_RELOAD_RESOURCES`` environment variable). When this is set to
true, the server never needs to be restarted when moving files
between directory resource overrides (esp. for templates currently).
- Add a ``reload_all`` configuration file setting (aka the
``BFG_RELOAD_ALL`` environment variable) that implies both
``reload_resources`` and ``reload_templates``.
- The ``static`` helper view class now uses a ``PackageURLParser`` in
order to allow for the overriding of static resources (CSS / logo
files, etc) using the ``resource`` ZCML directive. The
``PackageURLParser`` class was added to a (new) ``static`` module in
BFG; it is a subclass of the ``StaticURLParser`` class in
``paste.urlparser``.
- The ``repoze.bfg.templating.renderer_from_cache`` function now
checks for the ``reload_resources`` setting; if it's true, it does
not register a template renderer (it won't use the registry as a
template renderer cache).
- Add ``pkg_resources`` to the glossary.
- Update the "Environment" docs to note the existence of
``reload_resources`` and ``reload_all``.
- Use a colon instead of a tab as the separator between package name
and relpath to form the "spec" when register a ITemplateRenderer.
Diffstat (limited to 'repoze/bfg/static.py')
| -rw-r--r-- | repoze/bfg/static.py | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/repoze/bfg/static.py b/repoze/bfg/static.py new file mode 100644 index 000000000..01ce98a30 --- /dev/null +++ b/repoze/bfg/static.py @@ -0,0 +1,78 @@ +import os +import pkg_resources + +from paste.httpheaders import ETAG +from paste.urlparser import StaticURLParser +from paste import httpexceptions +from paste import request + +class PackageURLParser(StaticURLParser): + """ This probably won't work with zipimported resources """ + def __init__(self, package_name, resource_name, root_resource=None, + cache_max_age=None): + self.package_name = package_name + self.resource_name = os.path.normpath(resource_name) + if root_resource is None: + root_resource = self.resource_name + self.root_resource = root_resource + self.cache_max_age = cache_max_age + + def __call__(self, environ, start_response): + path_info = environ.get('PATH_INFO', '') + if not path_info: + return self.add_slash(environ, start_response) + if path_info == '/': + # @@: This should obviously be configurable + filename = 'index.html' + else: + filename = request.path_info_pop(environ) + resource = os.path.normcase(os.path.normpath( + self.resource_name + '/' + filename)) + if ( (self.root_resource is not None) and + (not resource.startswith(self.root_resource)) ): + # Out of bounds + return self.not_found(environ, start_response) + if not pkg_resources.resource_exists(self.package_name, resource): + return self.not_found(environ, start_response) + if pkg_resources.resource_isdir(self.package_name, resource): + # @@: Cache? + child_root = (self.root_resource is not None and + self.root_resource or self.resource_name) + return self.__class__( + self.package_name, resource, root_resource=child_root, + cache_max_age=self.cache_max_age)(environ, start_response) + if (environ.get('PATH_INFO') + and environ.get('PATH_INFO') != '/'): # pragma: no cover + return self.error_extra_path(environ, start_response) + full = pkg_resources.resource_filename(self.package_name, resource) + if_none_match = environ.get('HTTP_IF_NONE_MATCH') + if if_none_match: + mytime = os.stat(full).st_mtime + if str(mytime) == if_none_match: + headers = [] + ETAG.update(headers, mytime) + start_response('304 Not Modified', headers) + return [''] # empty body + + fa = self.make_app(full) + if self.cache_max_age: + fa.cache_control(max_age=self.cache_max_age) + return fa(environ, start_response) + + def not_found(self, environ, start_response, debug_message=None): + comment=('SCRIPT_NAME=%r; PATH_INFO=%r; looking in package %s; ' + 'subdir %s ;debug: %s' % (environ.get('SCRIPT_NAME'), + environ.get('PATH_INFO'), + self.package_name, + self.resource_name, + debug_message or '(none)')) + exc = httpexceptions.HTTPNotFound( + 'The resource at %s could not be found' + % request.construct_url(environ), + comment=comment) + return exc.wsgi_application(environ, start_response) + + def __repr__(self): + return '<%s %s:%s at %s>' % (self.__class__.__name__, self.package_name, + self.root_resource, id(self)) + |
