forked from github.com/pypiserver
Allow to override welcome-msg(/
) from a separate html file.
- Read welcome-msg in UTF-8. - Add cmd-line option for `welcome-file`. - Add TCs for welcome-file option and `/` http-req. - Update docs for new option. - Failback to in-code welcome-msg if unreadable (ie standalone mode, bad file).
This commit is contained in:
parent
d0946ebbcf
commit
c64b8c32d2
@ -9,6 +9,7 @@ include pypi-server-in.py
|
|||||||
include pypiserver/__init__.py
|
include pypiserver/__init__.py
|
||||||
include pypiserver/__main__.py
|
include pypiserver/__main__.py
|
||||||
include pypiserver/_app.py
|
include pypiserver/_app.py
|
||||||
|
include pypiserver/welcome.html
|
||||||
include pypiserver/bottle.py
|
include pypiserver/bottle.py
|
||||||
include pypiserver/core.py
|
include pypiserver/core.py
|
||||||
include pypiserver/manage.py
|
include pypiserver/manage.py
|
||||||
|
@ -112,6 +112,9 @@ pypi-server -h will print a detailed usage message::
|
|||||||
-o, --overwrite
|
-o, --overwrite
|
||||||
allow overwriting existing package files
|
allow overwriting existing package files
|
||||||
|
|
||||||
|
--welcome HTML_FILE
|
||||||
|
uses the ASCII contents of HTML_FILE as welcome message response.
|
||||||
|
|
||||||
-v
|
-v
|
||||||
enable INFO logging; repeate for more verbosity.
|
enable INFO logging; repeate for more verbosity.
|
||||||
|
|
||||||
|
@ -9,7 +9,8 @@ def app(root=None,
|
|||||||
overwrite=False,
|
overwrite=False,
|
||||||
log_req_frmt="%(bottle.request)s",
|
log_req_frmt="%(bottle.request)s",
|
||||||
log_res_frmt="%(status)s",
|
log_res_frmt="%(status)s",
|
||||||
log_err_frmt="%(body)s: %(exception)s \n%(traceback)s"):
|
log_err_frmt="%(body)s: %(exception)s \n%(traceback)s",
|
||||||
|
welcome_file=None):
|
||||||
import sys, os
|
import sys, os
|
||||||
from pypiserver import core
|
from pypiserver import core
|
||||||
sys.modules.pop("pypiserver._app", None)
|
sys.modules.pop("pypiserver._app", None)
|
||||||
@ -26,7 +27,8 @@ def app(root=None,
|
|||||||
|
|
||||||
_app.configure(root=root, redirect_to_fallback=redirect_to_fallback, fallback_url=fallback_url,
|
_app.configure(root=root, redirect_to_fallback=redirect_to_fallback, fallback_url=fallback_url,
|
||||||
password_file=password_file, overwrite=overwrite,
|
password_file=password_file, overwrite=overwrite,
|
||||||
log_req_frmt=log_req_frmt, log_res_frmt=log_res_frmt, log_err_frmt=log_err_frmt)
|
log_req_frmt=log_req_frmt, log_res_frmt=log_res_frmt, log_err_frmt=log_err_frmt,
|
||||||
|
welcome_file=welcome_file)
|
||||||
_app.app.module = _app
|
_app.app.module = _app
|
||||||
|
|
||||||
bottle.debug(True)
|
bottle.debug(True)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import sys, os, itertools, zipfile, mimetypes, logging
|
import sys, os, io, itertools, zipfile, mimetypes, logging, pkg_resources
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
@ -23,6 +23,8 @@ class configuration(object):
|
|||||||
self.fallback_url = "http://pypi.python.org/simple"
|
self.fallback_url = "http://pypi.python.org/simple"
|
||||||
self.redirect_to_fallback = True
|
self.redirect_to_fallback = True
|
||||||
self.htpasswdfile = None
|
self.htpasswdfile = None
|
||||||
|
self.welcome_file = None
|
||||||
|
self.welcome_msg = None
|
||||||
|
|
||||||
config = configuration()
|
config = configuration()
|
||||||
|
|
||||||
@ -40,7 +42,8 @@ def configure(root=None,
|
|||||||
overwrite=False,
|
overwrite=False,
|
||||||
log_req_frmt=None,
|
log_req_frmt=None,
|
||||||
log_res_frmt=None,
|
log_res_frmt=None,
|
||||||
log_err_frmt=None):
|
log_err_frmt=None,
|
||||||
|
welcome_file=None):
|
||||||
global packages
|
global packages
|
||||||
|
|
||||||
log.info("Starting(%s)", dict(root=root,
|
log.info("Starting(%s)", dict(root=root,
|
||||||
@ -48,6 +51,7 @@ def configure(root=None,
|
|||||||
fallback_url=fallback_url,
|
fallback_url=fallback_url,
|
||||||
password_file=password_file,
|
password_file=password_file,
|
||||||
overwrite=overwrite,
|
overwrite=overwrite,
|
||||||
|
welcome_file=welcome_file,
|
||||||
log_req_frmt=log_req_frmt,
|
log_req_frmt=log_req_frmt,
|
||||||
log_res_frmt=log_res_frmt,
|
log_res_frmt=log_res_frmt,
|
||||||
log_err_frmt=log_err_frmt))
|
log_err_frmt=log_err_frmt))
|
||||||
@ -81,6 +85,40 @@ def configure(root=None,
|
|||||||
config.htpasswdfile = HtpasswdFile(password_file)
|
config.htpasswdfile = HtpasswdFile(password_file)
|
||||||
config.overwrite = overwrite
|
config.overwrite = overwrite
|
||||||
|
|
||||||
|
## Read welcome-msg from external file,
|
||||||
|
# or failback to the embedded-msg (ie. in standalone mode).
|
||||||
|
#
|
||||||
|
try:
|
||||||
|
if not welcome_file:
|
||||||
|
welcome_file = pkg_resources.resource_filename(__name__, "welcome.html") # @UndefinedVariable
|
||||||
|
config.welcome_file = welcome_file
|
||||||
|
with io.open(config.welcome_file, 'r', encoding='utf-8') as fd:
|
||||||
|
config.welcome_msg = fd.read()
|
||||||
|
except Exception:
|
||||||
|
log.warning("Could not load welcome-file(%s)!", welcome_file, exc_info=1)
|
||||||
|
if not config.welcome_msg:
|
||||||
|
from textwrap import dedent
|
||||||
|
config.welcome_msg = dedent("""\
|
||||||
|
<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)s">here</a> or via the <a href="%(SIMPLE)s">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>\
|
||||||
|
""")
|
||||||
|
|
||||||
config.log_req_frmt = log_req_frmt
|
config.log_req_frmt = log_req_frmt
|
||||||
config.log_res_frmt = log_res_frmt
|
config.log_res_frmt = log_res_frmt
|
||||||
config.log_err_frmt = log_err_frmt
|
config.log_err_frmt = log_err_frmt
|
||||||
@ -122,27 +160,13 @@ def root():
|
|||||||
except:
|
except:
|
||||||
numpkgs = 0
|
numpkgs = 0
|
||||||
|
|
||||||
return """<html><head><title>Welcome to pypiserver!</title></head><body>
|
return config.welcome_msg % dict(
|
||||||
<h1>Welcome to pypiserver!</h1>
|
URL=request.url,
|
||||||
<p>This is a PyPI compatible package index serving %(NUMPKGS)s packages.</p>
|
VERSION=__version__,
|
||||||
|
NUMPKGS=numpkgs,
|
||||||
<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)s">here</a> or via the <a href="%(SIMPLE)s">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,
|
|
||||||
PACKAGES=urljoin(fp, "packages/"),
|
PACKAGES=urljoin(fp, "packages/"),
|
||||||
SIMPLE=urljoin(fp, "simple/"))
|
SIMPLE=urljoin(fp, "simple/")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.post('/')
|
@app.post('/')
|
||||||
|
@ -213,6 +213,9 @@ pypi-server understands the following options:
|
|||||||
-o, --overwrite
|
-o, --overwrite
|
||||||
allow overwriting existing package files
|
allow overwriting existing package files
|
||||||
|
|
||||||
|
--welcome HTML_FILE
|
||||||
|
uses the ASCII contents of HTML_FILE as welcome message response.
|
||||||
|
|
||||||
-v
|
-v
|
||||||
enable verbose logging; repeate for more verbosity.
|
enable verbose logging; repeate for more verbosity.
|
||||||
|
|
||||||
@ -283,6 +286,7 @@ def main(argv=None):
|
|||||||
log_req_frmt = None
|
log_req_frmt = None
|
||||||
log_res_frmt = None
|
log_res_frmt = None
|
||||||
log_err_frmt = None
|
log_err_frmt = None
|
||||||
|
welcome_file = None
|
||||||
|
|
||||||
update_dry_run = True
|
update_dry_run = True
|
||||||
update_directory = None
|
update_directory = None
|
||||||
@ -303,6 +307,7 @@ def main(argv=None):
|
|||||||
"log-req-frmt=",
|
"log-req-frmt=",
|
||||||
"log-res-frmt=",
|
"log-res-frmt=",
|
||||||
"log-err-frmt=",
|
"log-err-frmt=",
|
||||||
|
"welcome=",
|
||||||
"version",
|
"version",
|
||||||
"help"
|
"help"
|
||||||
])
|
])
|
||||||
@ -326,6 +331,8 @@ def main(argv=None):
|
|||||||
sys.exit("unknown server %r. choose one of %s" % (
|
sys.exit("unknown server %r. choose one of %s" % (
|
||||||
v, ", ".join(server_names.keys())))
|
v, ", ".join(server_names.keys())))
|
||||||
server = v
|
server = v
|
||||||
|
elif k == "--welcome":
|
||||||
|
welcome_file = v
|
||||||
elif k == "--version":
|
elif k == "--version":
|
||||||
sys.stdout.write("pypiserver %s\n" % __version__)
|
sys.stdout.write("pypiserver %s\n" % __version__)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
@ -379,6 +386,7 @@ def main(argv=None):
|
|||||||
fallback_url=fallback_url,
|
fallback_url=fallback_url,
|
||||||
overwrite=overwrite,
|
overwrite=overwrite,
|
||||||
log_req_frmt=log_req_frmt, log_res_frmt=log_res_frmt, log_err_frmt=log_err_frmt,
|
log_req_frmt=log_req_frmt, log_res_frmt=log_res_frmt, log_err_frmt=log_err_frmt,
|
||||||
|
welcome_file=welcome_file,
|
||||||
)
|
)
|
||||||
server = server or "auto"
|
server = server or "auto"
|
||||||
sys.stdout.write("This is pypiserver %s serving %r on http://%s:%s\n\n" % (__version__, ", ".join(roots), host, port))
|
sys.stdout.write("This is pypiserver %s serving %r on http://%s:%s\n\n" % (__version__, ", ".join(roots), host, port))
|
||||||
|
18
pypiserver/welcome.html
Normal file
18
pypiserver/welcome.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<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)s">here</a> or via the <a href="%(SIMPLE)s">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>
|
2
setup.py
2
setup.py
@ -32,6 +32,7 @@ setup(name="pypiserver",
|
|||||||
long_description=open("README.rst").read(),
|
long_description=open("README.rst").read(),
|
||||||
version=get_version(),
|
version=get_version(),
|
||||||
packages=["pypiserver"],
|
packages=["pypiserver"],
|
||||||
|
package_data={'pypiserver': ['welcome.html']},
|
||||||
url="https://github.com/schmir/pypiserver",
|
url="https://github.com/schmir/pypiserver",
|
||||||
maintainer="Ralf Schmitt",
|
maintainer="Ralf Schmitt",
|
||||||
maintainer_email="ralf@systemexit.de",
|
maintainer_email="ralf@systemexit.de",
|
||||||
@ -53,4 +54,5 @@ setup(name="pypiserver",
|
|||||||
"Programming Language :: Python :: 3.3",
|
"Programming Language :: Python :: 3.3",
|
||||||
"Topic :: Software Development :: Build Tools",
|
"Topic :: Software Development :: Build Tools",
|
||||||
"Topic :: System :: Software Distribution"],
|
"Topic :: System :: Software Distribution"],
|
||||||
|
zip_safe=False,
|
||||||
**extra)
|
**extra)
|
||||||
|
7
tests/sample_msg.html
Normal file
7
tests/sample_msg.html
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Hello pypiserver tester!
|
||||||
|
%(URL)s
|
||||||
|
%(VERSION)s
|
||||||
|
%(NUMPKGS)s
|
||||||
|
%(PACKAGES)s
|
||||||
|
%(SIMPLE)s
|
||||||
|
|
@ -55,6 +55,18 @@ def test_root_hostname(testapp):
|
|||||||
# go("http://systemexit.de/")
|
# go("http://systemexit.de/")
|
||||||
|
|
||||||
|
|
||||||
|
def test_root_welcome_msg(root):
|
||||||
|
wmsg = "Hey there!"
|
||||||
|
wfile = root.join("testwelcome.html")
|
||||||
|
wfile.write(wmsg)
|
||||||
|
|
||||||
|
from pypiserver import app
|
||||||
|
app = app(root=root.strpath, welcome_file=wfile.strpath)
|
||||||
|
testapp = webtest.TestApp(app)
|
||||||
|
resp = testapp.get("/")
|
||||||
|
resp.mustcontain(wmsg)
|
||||||
|
|
||||||
|
|
||||||
def test_packages_empty(testapp):
|
def test_packages_empty(testapp):
|
||||||
resp = testapp.get("/packages")
|
resp = testapp.get("/packages")
|
||||||
assert len(resp.html("a")) == 0
|
assert len(resp.html("a")) == 0
|
||||||
|
@ -102,3 +102,12 @@ def test_logging_verbosity(main):
|
|||||||
assert logging.getLogger().level == logging.DEBUG
|
assert logging.getLogger().level == logging.DEBUG
|
||||||
main(["-v", "-v", "-v"])
|
main(["-v", "-v", "-v"])
|
||||||
assert logging.getLogger().level == logging.NOTSET
|
assert logging.getLogger().level == logging.NOTSET
|
||||||
|
|
||||||
|
def test_welcome_file(main):
|
||||||
|
sample_msg_file = os.path.join(os.path.dirname(__file__), "sample_msg.html")
|
||||||
|
main(["--welcome", sample_msg_file])
|
||||||
|
assert "Hello pypiserver tester!" in main.app.module.config.welcome_msg
|
||||||
|
|
||||||
|
def test_welcome_file_default(main):
|
||||||
|
main([])
|
||||||
|
assert "Welcome to pypiserver!" in main.app.module.config.welcome_msg
|
||||||
|
Loading…
Reference in New Issue
Block a user