forked from github.com/pypiserver
move bottle app function to _app module
I'd like to run multiple pypiserver wsgi apps inside one process and plan to do so by reloading pypiserver._app. this is the first step. we move all of the @route'd functions to _app.
This commit is contained in:
parent
ace7c63fa5
commit
c0f82470c6
@ -6,7 +6,7 @@ def app(root=None,
|
||||
redirect_to_fallback=True,
|
||||
fallback_url=None):
|
||||
import os
|
||||
from pypiserver import core
|
||||
from pypiserver import core, _app
|
||||
import bottle
|
||||
|
||||
if root is None:
|
||||
@ -16,9 +16,7 @@ def app(root=None,
|
||||
fallback_url="http://pypi.python.org/simple"
|
||||
|
||||
os.listdir(root)
|
||||
core.packages = core.pkgset(root)
|
||||
core.config.redirect_to_fallback = redirect_to_fallback
|
||||
core.config.fallback_url = fallback_url
|
||||
_app.configure(root=root, redirect_to_fallback=redirect_to_fallback, fallback_url=fallback_url)
|
||||
bottle.debug(True)
|
||||
return bottle.default_app()
|
||||
|
||||
|
143
pypiserver/_app.py
Normal file
143
pypiserver/_app.py
Normal file
@ -0,0 +1,143 @@
|
||||
import sys, os
|
||||
|
||||
if sys.version_info >= (3, 0):
|
||||
from urllib.parse import urljoin
|
||||
else:
|
||||
from urlparse import urljoin
|
||||
|
||||
from bottle import route, static_file, redirect, request, HTTPError
|
||||
from pypiserver import __version__
|
||||
from pypiserver.core import is_allowed_path
|
||||
packages = None
|
||||
|
||||
class configuration(object):
|
||||
def __init__(self):
|
||||
self.fallback_url = "http://pypi.python.org/simple"
|
||||
self.redirect_to_fallback = True
|
||||
|
||||
config = configuration()
|
||||
|
||||
def configure(root=None,
|
||||
redirect_to_fallback=True,
|
||||
fallback_url=None):
|
||||
from pypiserver.core import pkgset
|
||||
global packages
|
||||
|
||||
if root is None:
|
||||
root = os.path.expanduser("~/packages")
|
||||
|
||||
if fallback_url is None:
|
||||
fallback_url="http://pypi.python.org/simple"
|
||||
|
||||
packages = pkgset(root)
|
||||
config.redirect_to_fallback = redirect_to_fallback
|
||||
config.fallback_url = fallback_url
|
||||
|
||||
|
||||
@route("/favicon.ico")
|
||||
def favicon():
|
||||
return HTTPError(404)
|
||||
|
||||
|
||||
@route('/')
|
||||
def root():
|
||||
try:
|
||||
numpkgs = len(packages.find_packages())
|
||||
except:
|
||||
numpkgs = 0
|
||||
|
||||
return """<html><head><title>Welcome to pypiserver!</title></head><body>
|
||||
<h1>Welcome to pypiserver!</h1>
|
||||
<p>This is a PyPI compatible package index serving %(NUMPKGS)s packages.</p>
|
||||
|
||||
<p> To use this server with pip, run the the following command:
|
||||
<blockquote><pre>
|
||||
pip install -i %(URL)ssimple/ PACKAGE [PACKAGE2...]
|
||||
</pre></blockquote></p>
|
||||
|
||||
<p> To use this server with easy_install, run the the following command:
|
||||
<blockquote><pre>
|
||||
easy_install -i %(URL)ssimple/ PACKAGE
|
||||
</pre></blockquote></p>
|
||||
|
||||
<p>The complete list of all packages can be found <a href="packages/">here</a> or via the <a href="simple/">simple</a> index.</p>
|
||||
|
||||
<p>This instance is running version %(VERSION)s of the <a href="http://pypi.python.org/pypi/pypiserver">pypiserver</a> software.</p>
|
||||
</body></html>
|
||||
""" % dict(URL=request.url, VERSION=__version__, NUMPKGS=numpkgs)
|
||||
|
||||
|
||||
@route("/simple")
|
||||
def simpleindex_redirect():
|
||||
return redirect(request.fullpath + "/")
|
||||
|
||||
|
||||
@route("/simple/")
|
||||
def simpleindex():
|
||||
prefixes = list(packages.find_prefixes())
|
||||
prefixes.sort()
|
||||
res = ["<html><head><title>Simple Index</title></head><body>\n"]
|
||||
for x in prefixes:
|
||||
res.append('<a href="%s/">%s</a><br>\n' % (x, x))
|
||||
res.append("</body></html>")
|
||||
return "".join(res)
|
||||
|
||||
|
||||
@route("/simple/:prefix")
|
||||
@route("/simple/:prefix/")
|
||||
def simple(prefix=""):
|
||||
fp = request.fullpath
|
||||
if not fp.endswith("/"):
|
||||
fp += "/"
|
||||
|
||||
files = packages.find_packages(prefix)
|
||||
if not files:
|
||||
if config.redirect_to_fallback:
|
||||
return redirect("%s/%s/" % (config.fallback_url.rstrip("/"), prefix))
|
||||
return HTTPError(404)
|
||||
files.sort()
|
||||
res = ["<html><head><title>Links for %s</title></head><body>\n" % prefix]
|
||||
res.append("<h1>Links for %s</h1>\n" % prefix)
|
||||
for x in files:
|
||||
abspath = urljoin(fp, "../../packages/%s" % x)
|
||||
|
||||
res.append('<a href="%s">%s</a><br>\n' % (abspath, os.path.basename(x)))
|
||||
res.append("</body></html>\n")
|
||||
return "".join(res)
|
||||
|
||||
|
||||
@route('/packages')
|
||||
@route('/packages/')
|
||||
def list_packages():
|
||||
fp = request.fullpath
|
||||
if not fp.endswith("/"):
|
||||
fp += "/"
|
||||
|
||||
files = packages.find_packages()
|
||||
files.sort()
|
||||
res = ["<html><head><title>Index of packages</title></head><body>\n"]
|
||||
for x in files:
|
||||
res.append('<a href="%s">%s</a><br>\n' % (urljoin(fp, x), x))
|
||||
res.append("</body></html>\n")
|
||||
return "".join(res)
|
||||
|
||||
|
||||
@route('/packages/:filename#.*#')
|
||||
def server_static(filename):
|
||||
if not is_allowed_path(filename):
|
||||
return HTTPError(404)
|
||||
|
||||
return static_file(filename, root=packages.root)
|
||||
|
||||
|
||||
@route('/:prefix')
|
||||
@route('/:prefix/')
|
||||
def bad_url(prefix):
|
||||
p = request.fullpath
|
||||
if not p.endswith("/"):
|
||||
p += "/"
|
||||
p += "../simple/%s/" % prefix
|
||||
|
||||
return redirect(p)
|
||||
|
||||
# return redirect("../simple/%s/" % prefix)
|
@ -2,27 +2,13 @@
|
||||
"""minimal PyPI like server for use with pip/easy_install"""
|
||||
|
||||
import os, sys, getopt, re, mimetypes
|
||||
if sys.version_info >= (3, 0):
|
||||
from urllib.parse import urljoin
|
||||
else:
|
||||
from urlparse import urljoin
|
||||
|
||||
from pypiserver import bottle, __version__
|
||||
sys.modules["bottle"] = bottle
|
||||
from bottle import run, debug, server_names
|
||||
|
||||
from bottle import route, run, static_file, redirect, request, debug, server_names, HTTPError
|
||||
mimetypes.add_type("application/octet-stream", ".egg")
|
||||
|
||||
packages = None
|
||||
|
||||
|
||||
class configuration(object):
|
||||
def __init__(self):
|
||||
self.fallback_url = "http://pypi.python.org/simple"
|
||||
self.redirect_to_fallback = True
|
||||
|
||||
config = configuration()
|
||||
|
||||
|
||||
def guess_pkgname(path):
|
||||
pkgname = re.split(r"-\d+", os.path.basename(path))[0]
|
||||
@ -80,113 +66,6 @@ class pkgset(object):
|
||||
return prefixes
|
||||
|
||||
|
||||
@route("/favicon.ico")
|
||||
def favicon():
|
||||
return HTTPError(404)
|
||||
|
||||
|
||||
@route('/')
|
||||
def root():
|
||||
try:
|
||||
numpkgs = len(packages.find_packages())
|
||||
except:
|
||||
numpkgs = 0
|
||||
|
||||
return """<html><head><title>Welcome to pypiserver!</title></head><body>
|
||||
<h1>Welcome to pypiserver!</h1>
|
||||
<p>This is a PyPI compatible package index serving %(NUMPKGS)s packages.</p>
|
||||
|
||||
<p> To use this server with pip, run the the following command:
|
||||
<blockquote><pre>
|
||||
pip install -i %(URL)ssimple/ PACKAGE [PACKAGE2...]
|
||||
</pre></blockquote></p>
|
||||
|
||||
<p> To use this server with easy_install, run the the following command:
|
||||
<blockquote><pre>
|
||||
easy_install -i %(URL)ssimple/ PACKAGE
|
||||
</pre></blockquote></p>
|
||||
|
||||
<p>The complete list of all packages can be found <a href="packages/">here</a> or via the <a href="simple/">simple</a> index.</p>
|
||||
|
||||
<p>This instance is running version %(VERSION)s of the <a href="http://pypi.python.org/pypi/pypiserver">pypiserver</a> software.</p>
|
||||
</body></html>
|
||||
""" % dict(URL=request.url, VERSION=__version__, NUMPKGS=numpkgs)
|
||||
|
||||
|
||||
@route("/simple")
|
||||
def simpleindex_redirect():
|
||||
return redirect(request.fullpath + "/")
|
||||
|
||||
|
||||
@route("/simple/")
|
||||
def simpleindex():
|
||||
prefixes = list(packages.find_prefixes())
|
||||
prefixes.sort()
|
||||
res = ["<html><head><title>Simple Index</title></head><body>\n"]
|
||||
for x in prefixes:
|
||||
res.append('<a href="%s/">%s</a><br>\n' % (x, x))
|
||||
res.append("</body></html>")
|
||||
return "".join(res)
|
||||
|
||||
|
||||
@route("/simple/:prefix")
|
||||
@route("/simple/:prefix/")
|
||||
def simple(prefix=""):
|
||||
fp = request.fullpath
|
||||
if not fp.endswith("/"):
|
||||
fp += "/"
|
||||
|
||||
files = packages.find_packages(prefix)
|
||||
if not files:
|
||||
if config.redirect_to_fallback:
|
||||
return redirect("%s/%s/" % (config.fallback_url.rstrip("/"), prefix))
|
||||
return HTTPError(404)
|
||||
files.sort()
|
||||
res = ["<html><head><title>Links for %s</title></head><body>\n" % prefix]
|
||||
res.append("<h1>Links for %s</h1>\n" % prefix)
|
||||
for x in files:
|
||||
abspath = urljoin(fp, "../../packages/%s" % x)
|
||||
|
||||
res.append('<a href="%s">%s</a><br>\n' % (abspath, os.path.basename(x)))
|
||||
res.append("</body></html>\n")
|
||||
return "".join(res)
|
||||
|
||||
|
||||
@route('/packages')
|
||||
@route('/packages/')
|
||||
def list_packages():
|
||||
fp = request.fullpath
|
||||
if not fp.endswith("/"):
|
||||
fp += "/"
|
||||
|
||||
files = packages.find_packages()
|
||||
files.sort()
|
||||
res = ["<html><head><title>Index of packages</title></head><body>\n"]
|
||||
for x in files:
|
||||
res.append('<a href="%s">%s</a><br>\n' % (urljoin(fp, x), x))
|
||||
res.append("</body></html>\n")
|
||||
return "".join(res)
|
||||
|
||||
|
||||
@route('/packages/:filename#.*#')
|
||||
def server_static(filename):
|
||||
if not is_allowed_path(filename):
|
||||
return HTTPError(404)
|
||||
|
||||
return static_file(filename, root=packages.root)
|
||||
|
||||
|
||||
@route('/:prefix')
|
||||
@route('/:prefix/')
|
||||
def bad_url(prefix):
|
||||
p = request.fullpath
|
||||
if not p.endswith("/"):
|
||||
p += "/"
|
||||
p += "../simple/%s/" % prefix
|
||||
|
||||
return redirect(p)
|
||||
|
||||
# return redirect("../simple/%s/" % prefix)
|
||||
|
||||
|
||||
def usage():
|
||||
@ -257,6 +136,8 @@ def main(argv=None):
|
||||
host = "0.0.0.0"
|
||||
port = 8080
|
||||
server = None
|
||||
redirect_to_fallback = True
|
||||
|
||||
update_dry_run = True
|
||||
update_directory = None
|
||||
update_stable_only = True
|
||||
@ -275,7 +156,7 @@ def main(argv=None):
|
||||
elif k in ("-r", "--root"):
|
||||
roots.append(v)
|
||||
elif k == "--disable-fallback":
|
||||
config.redirect_to_fallback = False
|
||||
redirect_to_fallback = False
|
||||
elif k == "--server":
|
||||
if v not in server_names:
|
||||
sys.exit("unknown server %r. choose one of %s" % (v, ", ".join(server_names.keys())))
|
||||
@ -308,13 +189,15 @@ def main(argv=None):
|
||||
err = sys.exc_info()[1]
|
||||
sys.exit("Error: while trying to list %r: %s" % (root, err))
|
||||
|
||||
packages = pkgset(root)
|
||||
|
||||
if command == "update":
|
||||
packages = pkgset(root)
|
||||
from pypiserver import manage
|
||||
manage.update(packages, update_directory, update_dry_run, stable_only=update_stable_only)
|
||||
return
|
||||
|
||||
from pypiserver import _app
|
||||
_app.configure(root=root, redirect_to_fallback=redirect_to_fallback)
|
||||
server = server or "auto"
|
||||
debug(True)
|
||||
sys.stdout.write("This is pypiserver %s serving %r on %s:%s\n\n" % (__version__, root, host, port))
|
||||
|
@ -9,7 +9,7 @@ try:
|
||||
except ImportError:
|
||||
loadapp = None
|
||||
|
||||
from pypiserver import core
|
||||
from pypiserver import core, _app
|
||||
import bottle
|
||||
bottle.debug(True)
|
||||
|
||||
@ -25,9 +25,9 @@ def pytest_funcarg__root(request):
|
||||
|
||||
tmpdir = request.getfuncargvalue("tmpdir")
|
||||
monkeypatch = request.getfuncargvalue("monkeypatch")
|
||||
|
||||
monkeypatch.setattr(core, "packages", core.pkgset(tmpdir.strpath))
|
||||
monkeypatch.setattr(core, "config", core.configuration())
|
||||
from pypiserver import _app
|
||||
monkeypatch.setattr(_app, "packages", core.pkgset(tmpdir.strpath))
|
||||
monkeypatch.setattr(_app, "config", _app.configuration())
|
||||
|
||||
if loadapp:
|
||||
pini = tmpdir.join(".paste.ini")
|
||||
@ -101,13 +101,13 @@ def test_favicon(root):
|
||||
|
||||
|
||||
def test_fallback(root):
|
||||
assert core.config.redirect_to_fallback
|
||||
assert _app.config.redirect_to_fallback
|
||||
final_url = go("/simple/pypiserver/")
|
||||
assert final_url == "http://pypi.python.org/simple/pypiserver/"
|
||||
|
||||
|
||||
def test_no_fallback(root):
|
||||
core.config.redirect_to_fallback = False
|
||||
_app.config.redirect_to_fallback = False
|
||||
final_url = go("/simple/pypiserver/")
|
||||
assert final_url == "http://localhost:8080/simple/pypiserver/"
|
||||
code(404)
|
||||
@ -116,6 +116,7 @@ def test_no_fallback(root):
|
||||
def test_serve_no_dotfiles(root):
|
||||
root.join(".foo-1.0.zip").write("secret")
|
||||
go("/packages/.foo-1.0.zip")
|
||||
show()
|
||||
code(404)
|
||||
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
import os
|
||||
import pytest
|
||||
from pypiserver import core
|
||||
from pypiserver import core, _app
|
||||
|
||||
|
||||
class main_wrapper(object):
|
||||
@ -32,8 +32,8 @@ def pytest_funcarg__main(request):
|
||||
monkeypatch = request.getfuncargvalue("monkeypatch")
|
||||
monkeypatch.setattr(core, "run", run)
|
||||
monkeypatch.setattr(os, "listdir", listdir)
|
||||
monkeypatch.setattr(core, "packages", None)
|
||||
monkeypatch.setattr(core, "config", core.configuration())
|
||||
monkeypatch.setattr(_app, "packages", None)
|
||||
monkeypatch.setattr(_app, "config", _app.configuration())
|
||||
|
||||
return main
|
||||
|
||||
@ -61,13 +61,13 @@ def test_server(main):
|
||||
|
||||
def test_root(main):
|
||||
main(["--root", "."])
|
||||
assert core.packages.root == os.path.abspath(".")
|
||||
assert _app.packages.root == os.path.abspath(".")
|
||||
assert main.pkgdir == os.path.abspath(".")
|
||||
|
||||
|
||||
def test_root_r(main):
|
||||
main(["-r", "."])
|
||||
assert core.packages.root == os.path.abspath(".")
|
||||
assert _app.packages.root == os.path.abspath(".")
|
||||
assert main.pkgdir == os.path.abspath(".")
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user