summaryrefslogtreecommitdiff
path: root/repoze/bfg/static.py
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-06-30 21:02:00 +0000
committerChris McDonough <chrism@agendaless.com>2009-06-30 21:02:00 +0000
commitd809ac74d19342bcc84e4fe043697709b2001cc0 (patch)
tree9973b531b90336bf6ecf3811aa3b9ba753f4e6d8 /repoze/bfg/static.py
parentf9e73ea5a9d5a4210e3a346aa2f9483d70d22ab9 (diff)
downloadpyramid-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.py78
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))
+