terom@5: terom@5: from __future__ import with_statement terom@5: terom@5: # XXX: for _HTMLPage terom@5: import page terom@5: import templates terom@5: terom@5: from pages import error404 terom@5: terom@5: import os.path terom@5: import imp terom@5: terom@5: # the page dir terom@5: PAGE_DIR_PATH = "pages/" terom@5: terom@5: def build_page_path (*bits) : terom@5: # XXX: fix directory traversal... terom@5: terom@5: return os.path.join(PAGE_DIR_PATH, *bits) terom@5: terom@5: class PageLoader (object) : terom@5: """ terom@5: Load Page objects from files under pages/ terom@5: """ terom@5: terom@5: # file extension, e.g. '.html' or '.py' terom@5: suffix = None terom@5: terom@5: def __init__ (self, suffix) : terom@5: self.suffix = suffix terom@5: terom@5: def _build_path (self, page_path) : terom@5: """ terom@5: Builds a path from base_path + page_path + suffix. Returns None if the path does not exist terom@5: """ terom@5: terom@5: path = build_page_path(page_path) + self.suffix terom@5: terom@5: if os.path.exists(path) : terom@5: return path terom@5: terom@5: else : terom@5: return None terom@5: terom@5: def load (self, page_path) : terom@5: """ terom@5: Attempts to load the page at the given path, returns the class on success, None on failure terom@5: """ terom@5: terom@5: abstract terom@5: terom@5: class _HTMLPage (page.Page) : terom@5: # the path to the .html file terom@5: file_path = None terom@5: terom@5: # parent page terom@5: # parent = None terom@5: terom@5: def __init__ (self, *args) : terom@5: super(_HTMLPage, self).__init__(*args) terom@5: terom@5: # open the .html and read in the contents terom@5: with open(self.file_path, "r") as fh : terom@5: self.file_data = fh.read() terom@5: terom@5: def render_template (self) : terom@5: tpl = self._build_template(templates.layout) terom@5: terom@5: tpl.page_content = self.file_data terom@5: terom@5: return tpl terom@5: terom@5: class HTMLLoader (PageLoader) : terom@5: """ terom@5: Static .html files that are inserted into the layout template as-is terom@5: terom@5: Sub-pages are not supported... terom@5: """ terom@5: terom@5: def __init__ (self) : terom@5: super(HTMLLoader, self).__init__(".html") terom@5: terom@5: def get_title (self, page_path) : terom@5: head, tail = os.path.split(page_path) terom@5: terom@5: return tail.title() if tail else "Index" terom@5: terom@5: def load (self, _page_path) : terom@5: _file_path = self._build_path(_page_path) terom@5: terom@5: # ignore if it doesn't exist terom@5: if not _file_path : terom@5: return terom@5: terom@5: # get page title terom@5: _title = self.get_title(_page_path) terom@5: terom@5: # create a new class and return it terom@5: class _html_page (_HTMLPage) : terom@5: file_path = _file_path terom@5: title = _title terom@5: name = _title terom@5: path = _page_path terom@5: terom@5: # return it terom@5: return _html_page terom@5: terom@5: class PythonLoader (PageLoader) : terom@5: """ terom@5: Dynamic .py files that define a Page class terom@5: """ terom@5: terom@5: def __init__ (self) : terom@5: super(PythonLoader, self).__init__(".py") terom@5: terom@5: def load (self, page_path) : terom@5: path = self._build_path(page_path) terom@5: terom@5: # ignore if not exists terom@5: if not path : terom@5: return terom@5: terom@5: # load the module dynamically terom@5: module = imp.load_source("__dyn_%d" % id(path), path) terom@5: terom@5: # return the Page object terom@5: return module.Page terom@5: terom@5: # our defined loaders terom@5: loaders = [ terom@5: HTMLLoader(), terom@5: PythonLoader(), terom@5: ] terom@5: terom@5: def load_page (req) : terom@5: """ terom@5: Returns an instance of a Page object corresponding to the given req terom@5: """ terom@5: terom@5: # page path is given in req terom@5: page_path = req.page_path terom@5: terom@5: # if it's a dir, then add 'index' terom@5: if os.path.isdir(build_page_path(page_path)) : terom@5: page_path = os.path.join(page_path, "index") terom@5: terom@5: # try each loader in turn terom@5: for loader in loaders : terom@5: page = loader.load(req.page_path) terom@5: terom@5: # found? terom@5: if page : terom@5: break terom@5: terom@5: # 404 error... terom@5: if not page : terom@5: page = error404.Error404 terom@5: terom@5: return page(req, req.page_path) terom@5: