view simpypi/factory.py @ 25:511210365ce3

WIP getting paste StaticURLParser to serve directories
author Jeff Hammel <jhammel@mozilla.com>
date Wed, 29 Feb 2012 10:29:11 -0800
parents 13ed82d10144
children fb03f34a982f
line wrap: on
line source

#!/usr/bin/env python

"""
factories for simpypi
"""

import optparse
import os
import shutil
import sys
import tempfile

from paste.httpexceptions import HTTPExceptionHandler
from paste.urlparser import StaticURLParser
from pkg_resources import resource_filename
from wsgi import SimPyPI
from wsgiref import simple_server

class DirectoryServer(StaticURLParser):
    def __init__(self, directory):
        StaticURLParser.__init__(self, directory)

    def index(self, directory):
        """
        generate a directory listing for a given directory
        """
        parts = ['<html><head><title>Simple Index</title></head><body>']
        listings = os.listdir(directory)
        listings = [(os.path.isdir(os.path.join(directory, entry)) and entry + '/' or entry, entry)
                    for entry in listings]
        for link, entry in listings:
            parts.append('<a href="%s">%s</a><br/>' % (link, entry))
        parts.append('</body></html>')
        return '\n'.join(parts)

    def __call__(self, environ, start_response):

        # normalize path
        # from paste.urlparser.StaticURLParser
        path_info = environ.get('PATH_INFO', '')
        if not path_info:
            return self.add_slash(environ, start_response)
        full = self.normpath(os.path.join(self.directory, path_info.strip('/')))
        if not full.startswith(self.root_directory):
            # Out of bounds
            return self.not_found(environ, start_response)

        # return index listing
        if os.path.isdir(full):
            if not path_info.endswith('/'):
                return self.add_slash(environ, start_response)
            index = self.index(full)
            response_headers = [('Content-Type', 'text/html'),
                                ('Content-Length', str(len(index)))]
            start_response('200 OK', response_headers)
            return [index]

        return StaticURLParser.__call__(self, environ, start_response)

class PassthroughFileserver(object):
    """serve files if they exist"""

    def __init__(self, app, directory):
        self.app = app
        self.directory = directory
        self.fileserver = StaticURLParser(directory)

    def __call__(self, environ, start_response):
        path = self.path(environ['PATH_INFO'].strip('/'))
        if path and os.path.exists(os.path.join(self.directory, path)):
            return self.fileserver(environ, start_response)
        return self.app(environ, start_response)

class NamespacedFileserver(DirectoryServer):

    def __init__(self, app, directory, namespace):
        DirectoryServer.__init__(self, directory)
        self.app = app
        self.namespace = namespace

    def __call__(self, environ, start_response):
        path = environ['PATH_INFO']
        if path == self.namespace:
            return self.add_slash(environ, start_response)
            environ['PATH_INFO'] = '/'
            return DirectoryServer.__call__(self, environ, start_response)
        elif path.startswith(self.namespace + '/'):
            environ['PATH_INFO'] = path[len(self.namespace):]
            return DirectoryServer.__call__(self, environ, start_response)
        return self.app(environ, start_response)


def factory(**app_conf):
    """create a webob view and wrap it in middleware"""
    directory = app_conf['directory']
    app = SimPyPI(**app_conf)
    return NamespacedFileserver(app, directory, '/index')

def main(args=sys.argv[:]):

    # parse command line options
    usage = '%prog [options]'
    parser = optparse.OptionParser(usage=usage)
    parser.add_option('-p', '--port', dest='port',
                      type='int', default=8080,
                      help="port to run the server on")
    parser.add_option('-d', '--directory', dest='directory',
                      help='directory to serve')
    options, args = parser.parse_args(args)

    # create a temporary directory, if none specified
    tmpdir = None
    if not options.directory:
        tmpdir = tempfile.mkdtemp()
        options.directory = tmpdir

    # serve
    print "http://localhost:%d/" % options.port
    try:
        app = factory(directory=options.directory)
        server = simple_server.make_server(host='0.0.0.0', port=options.port, app=app)
        server.serve_forever()
    finally:
        if tmpdir:
            shutil.rmtree(tmpdir)

if __name__ == '__main__':
    main()