# HG changeset patch # User Jeff Hammel # Date 1330549751 28800 # Node ID 8d31e36f084e9fa0796c8333b006db1498b3ca36 initial stubbing diff -r 000000000000 -r 8d31e36f084e INSTALL.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/INSTALL.py Wed Feb 29 13:09:11 2012 -0800 @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +""" +installation script for FileServer +a simple static fileserver and directory index server in python (WSGI app) +""" + +import os +import sys +import urllib2 +import subprocess +try: + from subprocess import check_call as call +except: + from subprocess import call + +REPO='http://k0s.org/hg/FileServer' +DEST='FileServer' # name of the virtualenv +VIRTUALENV='https://raw.github.com/pypa/virtualenv/develop/virtualenv.py' + +def which(binary, path=os.environ['PATH']): + dirs = path.split(os.pathsep) + for dir in dirs: + if os.path.isfile(os.path.join(dir, fileName)): + return os.path.join(dir, fileName) + if os.path.isfile(os.path.join(dir, fileName + ".exe")): + return os.path.join(dir, fileName + ".exe") + +def main(args=sys.argv[1:]): + + # create a virtualenv + virtualenv = which('virtualenv') or which('virtualenv.py') + if virtualenv: + call([virtualenv, DEST]) + else: + process = subproces.Popen([sys.executable, '-', DEST], stdin=subprocess.PIPE) + process.communicate(stdin=urllib2.urlopen(VIRTUALENV).read()) + + # create a src directory + src = os.path.join(DEST, 'src') + os.mkdir(src) + + # clone the repository + call(['hg', 'clone', REPO], cwd=src) + +""" +XXX unfinished + +hg clone ${REPO} +cd FileServer +python setup.py develop +""" + diff -r 000000000000 -r 8d31e36f084e README.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.txt Wed Feb 29 13:09:11 2012 -0800 @@ -0,0 +1,11 @@ +FileServer +=========== + +a simple static fileserver and directory index server in python (WSGI app) + +---- + +Jeff Hammel + +http://k0s.org/hg/FileServer + diff -r 000000000000 -r 8d31e36f084e fileserver/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fileserver/__init__.py Wed Feb 29 13:09:11 2012 -0800 @@ -0,0 +1,2 @@ +# + diff -r 000000000000 -r 8d31e36f084e fileserver/web.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fileserver/web.py Wed Feb 29 13:09:11 2012 -0800 @@ -0,0 +1,82 @@ +#!/usr/bin/env python + +""" +WSGI app for FileServer + +Reference: +- http://docs.webob.org/en/latest/file-example.html +""" + +import mimetypes +import os +from webob import Request, Response, exc + +def get_mimetype(filename): + type, encoding = mimetypes.guess_type(filename) + # We'll ignore encoding, even though we shouldn't really + return type or 'application/octet-stream' + +def file_response(filename): + res = Response(content_type=get_mimetype(filename)) + res.body = open(filename, 'rb').read() + return res + +class FileApp(object): + """ + serve static files + """ + + def __init__(self, filename): + self.filename = filename + + def __call__(self, environ, start_response): + res = file_response(self.filename) + return res(environ, start_response) + +class DirectoryServer(object): + + def __init__(self, directory): + assert os.path.exists(directory), "'%s' does not exist" % directory + assert os.path.isdir(directory), "'%s' is not a directory" % directory + self.directory = directory + + @staticmethod + def normpath(path): + return os.path.normcase(os.path.abspath(path)) + + def __call__(self, environ, start_response): + request = Request(environ) + # TODO method_not_allowed: Allow: GET, HEAD + path_info = request.path_info + if not path_info: + pass # self.add slash + full = self.normpath(os.path.join(self.directory, path_info.strip('/'))) + if not full.startswith(self.directory): + # Out of bounds + return exc.HTTPNotFound()(environ, start_response) + if not os.path.exists(full): + return exc.HTTPNotFound()(environ, start_response) + + if os.path.isdir(full): + # serve directory index + 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)))] + response = Response(index, content_type='text/html') + return response(environ, start_response) + + # serve file + if path_info.endswith('/'): + # we create the `full` filename above by stripping off + # '/' from both sides; so we correct here + return exc.HTTPNotFound()(environ, start_response) + response = file_response(full) + return response(environ, start_response) + +if __name__ == '__main__': + from wsgiref import simple_server + app = Handler() + server = simple_server.make_server(host='0.0.0.0', port=8080, app=app) + server.serve_forever() diff -r 000000000000 -r 8d31e36f084e setup.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup.py Wed Feb 29 13:09:11 2012 -0800 @@ -0,0 +1,45 @@ +""" +setup packaging script for FileServer +""" + +import os + +version = "0.0" +dependencies = ['MakeItSo', 'webob'] + +# allow use of setuptools/distribute or distutils +kw = {} +try: + from setuptools import setup + kw['entry_points'] = """ + [console_scripts] + FileServer = FileServer.main:main + FileServer-template = FileServer.template:main +""" + kw['install_requires'] = dependencies +except ImportError: + from distutils.core import setup + kw['requires'] = dependencies + +try: + here = os.path.dirname(os.path.abspath(__file__)) + description = file(os.path.join(here, 'README.txt')).read() +except IOError: + description = '' + + +setup(name='FileServer', + version=version, + description="a simple static fileserver and directory index server in python (WSGI app)", + long_description=description, + classifiers=[], # Get strings from http://www.python.org/pypi?%3Aaction=list_classifiers + author='Jeff Hammel', + author_email='jhammel@mozilla.com', + url='http://k0s.org/hg/FileServer', + license='', + packages=['fileserver'], + include_package_data=True, + zip_safe=False, + **kw + ) + diff -r 000000000000 -r 8d31e36f084e tests/doctest.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/doctest.txt Wed Feb 29 13:09:11 2012 -0800 @@ -0,0 +1,11 @@ +Test FileServer +================ + +The obligatory imports: + + >>> import fileserver + +Run some tests. This test will fail, please fix it: + + >>> assert True == False + diff -r 000000000000 -r 8d31e36f084e tests/test.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test.py Wed Feb 29 13:09:11 2012 -0800 @@ -0,0 +1,60 @@ +#!/usr/bin/env python + +""" +doctest runner +""" + +import doctest +import os +import sys +from optparse import OptionParser + + +def run_tests(raise_on_error=False, report_first=False): + + # add results here + results = {} + + # doctest arguments + directory = os.path.dirname(os.path.abspath(__file__)) + extraglobs = {'here': directory} + doctest_args = dict(extraglobs=extraglobs, raise_on_error=raise_on_error) + if report_first: + doctest_args['optionflags'] = doctest.REPORT_ONLY_FIRST_FAILURE + + # gather tests + tests = [ test for test in os.listdir(directory) + if test.endswith('.txt') ] + + # run the tests + for test in tests: + try: + results[test] = doctest.testfile(test, **doctest_args) + except doctest.DocTestFailure, failure: + raise + except doctest.UnexpectedException, failure: + raise failure.exc_info[0], failure.exc_info[1], failure.exc_info[2] + + return results + +def main(args=sys.argv[1:]): + + # parse command line args + parser = OptionParser(description=__doc__) + parser.add_option('--raise', dest='raise_on_error', + default=False, action='store_true', + help="raise on first error") + parser.add_option('--report-first', dest='report_first', + default=False, action='store_true', + help="report the first error only (all tests will still run)") + options, args = parser.parse_args(args) + + # run the tests + results = run_tests(**options.__dict__) + if sum([i.failed for i in results.values()]): + sys.exit(1) # error + + +if __name__ == '__main__': + main() +