lib/filesystem/map.py
author Tero Marttila <terom@fixme.fi>
Sat, 07 Feb 2009 17:07:06 +0200
branchsites
changeset 33 19ea04f4b0cd
parent 32 be954df4f0e8
permissions -rw-r--r--
make Page a RequestHandler in its own right, move code from FilesystemMapper

import os, os.path

from lib import http, template, map

import page, page_tree

class FilesystemMapper (map.Mapper) :
    """
        Translates requests to handlers based on a filesystem directory containing various kinds of files
    """

    # list of page handlers, by type
    PAGE_TYPES = [
        ('html',                    page.HTMLPage           ),
        (template.TEMPLATE_EXT,     page.TemplatePage       ),
    ]

    def __init__ (self, path, template) :
        """
            Create, path is where the pages are stored. The list of pages is loaded from $path/list
        """
        
        # store
        self.path = path 
        self.template = template

        # load the page tree
        self.tree = page_tree.PageTree(path + '/list')
    
    def _lookup_page_type (self, url, path, filename, basename, extension, tail) :
        """
            We found the file that we looked for, now get the correct type
        """

        # find appropriate handler
        for handler_ext, type in self.PAGE_TYPES :
            # match against file extension?
            if handler_ext == extension :
                # found handler, return instance
                return type(self, url, path, basename, tail)

        # no handler found
        raise PageError("No handler found for page %r of type %r" % (url, extension))

    def _lookup_page (self, name) :
        """
            Look up and return a Page object for the given page, or raise an error
        """

        # inital path
        path = self.path
        url_segments = []

        # name segments
        segments = name.split('/')

        # iterate through the parts of the page segments
        while True :
            segment = None

            # pop segment
            if segments :
                segment = segments.pop(0)

                url_segments.append(segment)

            # translate empty -> index
            if not segment :
                segment = 'index'

            # look for it in the dir
            for filename in os.listdir(path) :
                # build full file path
                file_path = os.path.join(path, filename)

                # stat, recurse into subdirectory?
                if os.path.isdir(file_path) and filename == segment :
                    # use new dir
                    path = file_path

                    # break for-loop to look at next segment
                    break
     
                # split into basename + extension
                basename, extension = os.path.splitext(filename)

                # ...remove that dot
                extension = extension.lstrip('.')
                
                # match against requested page name?
                if basename == segment :
                    # found the file we wanted
                    return self._lookup_page_type('/'.join(url_segments), file_path, filename, basename, extension, '/'.join(segments))
                
                else :
                    # inspect next file in dir
                    continue

            else :
                # did not find any dir or file, break out of while loop
                break

        # did not find the filename we were looking for in os.listdir
        raise PageError("Page not found: %s" % name, status='404 Not Found')

    def handle_request (self, request) :
        """
            Looks up the appropriate Page, and then renders it
        """

        # determine the page name
        page_name = request.get_page_name()

        # get the page handler
        page = self._lookup_page(page_name)
        
        # pass on
        return page.handle_request(request)