mirror of
https://github.com/pypiserver/pypiserver
synced 2025-02-22 19:19:37 +01:00
init: Enhance startup-sequence & Configuration class.
+ Remove duplication when setting start-up options. + Fix `g` prefix typo in log-format. + Log startup & final config options. + Configuration class prints options alphabetically. + Rename option `alt_auth` --> `auther`.
This commit is contained in:
parent
e55a325477
commit
8a8d9e4f16
@ -8,46 +8,10 @@ __summary__ = "A minimal PyPI server for use with pip/easy_install."
|
||||
__uri__ = "https://github.com/pypiserver/pypiserver"
|
||||
|
||||
|
||||
def app(root=None,
|
||||
redirect_to_fallback=True,
|
||||
fallback_url=None,
|
||||
authenticated=None,
|
||||
password_file=None,
|
||||
overwrite=None,
|
||||
log_req_frmt=None,
|
||||
log_res_frmt=None,
|
||||
log_err_frmt=None,
|
||||
welcome_file=None,
|
||||
cache_control=None,
|
||||
alt_auth=None
|
||||
):
|
||||
"""
|
||||
:param callable alt_auth:
|
||||
An API-only options that if it evaluates to a callable,
|
||||
it is invoked for granting auth (instead of htpaswd mechanism)
|
||||
like that::
|
||||
def app(**kwds):
|
||||
from . import _app, bottle
|
||||
|
||||
alt_auth(*bottle.request.auth)
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
from . import core, _app
|
||||
|
||||
from . import bottle
|
||||
|
||||
if root is None:
|
||||
root = os.path.expanduser("~/packages")
|
||||
|
||||
if fallback_url is None:
|
||||
fallback_url = "http://pypi.python.org/simple"
|
||||
|
||||
_app.configure(root=root, redirect_to_fallback=redirect_to_fallback, fallback_url=fallback_url,
|
||||
authenticated=authenticated or [], password_file=password_file, overwrite=overwrite,
|
||||
log_req_frmt=log_req_frmt, log_res_frmt=log_res_frmt, log_err_frmt=log_err_frmt,
|
||||
welcome_file=welcome_file, cache_control=cache_control, alt_auth=alt_auth
|
||||
)
|
||||
_app.configure(**kwds)
|
||||
_app.app.module = _app
|
||||
|
||||
bottle.debug(True)
|
||||
|
@ -1,4 +1,9 @@
|
||||
#! /usr/bin/env python
|
||||
"""
|
||||
.. NOTE:: To the developer:
|
||||
This module is moved to the root of the standalone zip-archive,
|
||||
to be used as its entry-point. Therefore DO NOT import relative.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
@ -148,13 +153,13 @@ def main(argv=None):
|
||||
port = 8080
|
||||
server = DEFAULT_SERVER
|
||||
redirect_to_fallback = True
|
||||
fallback_url = "http://pypi.python.org/simple"
|
||||
fallback_url = None
|
||||
authed_ops_list = ['update']
|
||||
password_file = None
|
||||
overwrite = False
|
||||
verbosity = 1
|
||||
log_file = None
|
||||
log_frmt = "g%(asctime)s|%(levelname)s|%(thread)d|%(message)s"
|
||||
log_frmt = "%(asctime)s|%(levelname)s|%(thread)d|%(message)s"
|
||||
log_req_frmt = "%(bottle.request)s"
|
||||
log_res_frmt = "%(status)s"
|
||||
log_err_frmt = "%(body)s: %(exception)s \n%(traceback)s"
|
||||
@ -288,7 +293,7 @@ def main(argv=None):
|
||||
server, ", ".join(server_names.keys())))
|
||||
|
||||
from pypiserver import __version__, app
|
||||
a=app(
|
||||
app = app(
|
||||
root=roots,
|
||||
redirect_to_fallback=redirect_to_fallback,
|
||||
authenticated=authed_ops_list,
|
||||
@ -301,7 +306,7 @@ def main(argv=None):
|
||||
)
|
||||
log.info("This is pypiserver %s serving %r on http://%s:%s\n\n",
|
||||
__version__, ", ".join(roots), host, port)
|
||||
run(app=a, host=host, port=port, server=server)
|
||||
run(app=app, host=host, port=port, server=server)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -8,6 +8,7 @@ import logging
|
||||
import pkg_resources
|
||||
|
||||
from . import core
|
||||
from collections import OrderedDict
|
||||
|
||||
try:
|
||||
from io import BytesIO
|
||||
@ -24,25 +25,25 @@ from . import __version__
|
||||
|
||||
log = logging.getLogger('pypiserver.http')
|
||||
packages = None
|
||||
|
||||
config = None
|
||||
|
||||
class Configuration(object):
|
||||
def __init__(self, **kwds):
|
||||
vars(self).update(kwds)
|
||||
|
||||
def __init__(self):
|
||||
self.fallback_url = "http://pypi.python.org/simple"
|
||||
self.redirect_to_fallback = True
|
||||
self.htpasswdfile = None
|
||||
self.welcome_file = None
|
||||
self.welcome_msg = None
|
||||
self.alt_auth = None
|
||||
def __repr__(self, *args, **kwargs):
|
||||
return 'Configuration(**%s)' % vars(self)
|
||||
|
||||
config = Configuration()
|
||||
def __str__(self, *args, **kwargs):
|
||||
return 'Configuration:\n%s' % '\n'.join('%16s = %s' % (k, v)
|
||||
for k, v in sorted(vars(self).items()))
|
||||
|
||||
|
||||
def validate_user(username, password):
|
||||
if config.htpasswdfile is not None:
|
||||
config.htpasswdfile.load_if_changed()
|
||||
return config.htpasswdfile.check_password(username, password)
|
||||
|
||||
def auth_by_htpasswd_file(username, password):
|
||||
if config.password_file is not None:
|
||||
config.password_file.load_if_changed()
|
||||
return config.password_file.check_password(username, password)
|
||||
|
||||
|
||||
class auth(object):
|
||||
@ -76,11 +77,23 @@ def configure(root=None,
|
||||
log_err_frmt=None,
|
||||
welcome_file=None,
|
||||
cache_control=None,
|
||||
alt_auth=None
|
||||
auther=None
|
||||
):
|
||||
global packages
|
||||
"""
|
||||
:param callable auther:
|
||||
An API-only options that if it evaluates to a callable,
|
||||
it is invoked to allow access to protected operations
|
||||
(instead of htpaswd mechanism) like that::
|
||||
|
||||
log.info("Starting(%s)", dict(root=root,
|
||||
auther(username, password): bool
|
||||
|
||||
When defined, `password_file` is ignored.
|
||||
|
||||
"""
|
||||
global packages, config
|
||||
|
||||
log.info("Invoked with: %s", Configuration(
|
||||
root=root,
|
||||
redirect_to_fallback=redirect_to_fallback,
|
||||
fallback_url=fallback_url,
|
||||
authenticated=authenticated,
|
||||
@ -91,66 +104,77 @@ def configure(root=None,
|
||||
log_res_frmt=log_res_frmt,
|
||||
log_err_frmt=log_err_frmt,
|
||||
cache_control=cache_control,
|
||||
alt_auth=alt_auth))
|
||||
auther=auther
|
||||
))
|
||||
|
||||
config.authenticated = authenticated or []
|
||||
config.auther = alt_auth if callable(alt_auth) else validate_user
|
||||
|
||||
if root is None:
|
||||
root = os.path.expanduser("~/packages")
|
||||
|
||||
if fallback_url is None:
|
||||
fallback_url = "http://pypi.python.org/simple"
|
||||
|
||||
if not isinstance(root, (list, tuple)):
|
||||
roots = [root]
|
||||
else:
|
||||
roots = root
|
||||
|
||||
roots = root if isinstance(root, (list, tuple)) else [root]
|
||||
roots = [os.path.abspath(r) for r in roots]
|
||||
for r in roots:
|
||||
try:
|
||||
os.listdir(r)
|
||||
except OSError:
|
||||
err = sys.exc_info()[1]
|
||||
sys.exit("Error: while trying to list %r: %s" % (r, err))
|
||||
sys.exit("Error: while trying to list root(%s): %s" % (r, err))
|
||||
|
||||
packages = lambda: itertools.chain(*[core.listdir(r) for r in roots])
|
||||
packages.root = roots[0]
|
||||
|
||||
config.redirect_to_fallback = redirect_to_fallback
|
||||
config.fallback_url = fallback_url
|
||||
config.cache_control = cache_control
|
||||
authenticated = authenticated or []
|
||||
if not callable(auther):
|
||||
auther = auth_by_htpasswd_file
|
||||
if password_file and password_file != '.':
|
||||
from passlib.apache import HtpasswdFile
|
||||
config.htpasswdfile = HtpasswdFile(password_file)
|
||||
config.overwrite = overwrite
|
||||
password_file = HtpasswdFile(password_file)
|
||||
|
||||
# Read welcome-msg from external file,
|
||||
# or failback to the embedded-msg (ie. in standalone mode).
|
||||
#
|
||||
try:
|
||||
if not welcome_file:
|
||||
config.welcome_file = "welcome.html"
|
||||
config.welcome_msg = pkg_resources.resource_string( # @UndefinedVariable
|
||||
welcome_file = "welcome.html"
|
||||
welcome_msg = pkg_resources.resource_string( # @UndefinedVariable
|
||||
__name__, "welcome.html").decode("utf-8") # @UndefinedVariable
|
||||
else:
|
||||
config.welcome_file = welcome_file
|
||||
welcome_file = welcome_file
|
||||
with io.open(welcome_file, 'r', encoding='utf-8') as fd:
|
||||
config.welcome_msg = fd.read()
|
||||
welcome_msg = fd.read()
|
||||
except Exception:
|
||||
log.warning(
|
||||
"Could not load welcome-file(%s)!", welcome_file, exc_info=1)
|
||||
config.log_req_frmt = log_req_frmt
|
||||
config.log_res_frmt = log_res_frmt
|
||||
config.log_err_frmt = log_err_frmt
|
||||
|
||||
if fallback_url is None:
|
||||
fallback_url = "http://pypi.python.org/simple"
|
||||
|
||||
log_req_frmt = log_req_frmt
|
||||
log_res_frmt = log_res_frmt
|
||||
log_err_frmt = log_err_frmt
|
||||
|
||||
config = Configuration(
|
||||
root=root,
|
||||
redirect_to_fallback=redirect_to_fallback,
|
||||
fallback_url=fallback_url,
|
||||
authenticated=authenticated,
|
||||
password_file=password_file,
|
||||
overwrite=overwrite,
|
||||
welcome_file=welcome_file,
|
||||
welcome_msg=welcome_msg,
|
||||
log_req_frmt=log_req_frmt,
|
||||
log_res_frmt=log_res_frmt,
|
||||
log_err_frmt=log_err_frmt,
|
||||
cache_control=cache_control,
|
||||
auther=auther
|
||||
)
|
||||
log.info("Starting with: %s", config)
|
||||
|
||||
app = Bottle()
|
||||
|
||||
|
||||
@app.hook('before_request')
|
||||
def log_request():
|
||||
log.info(config.log_req_frmt, request.environ)
|
||||
log.info(config. log_req_frmt, request.environ)
|
||||
|
||||
|
||||
@app.hook('after_request')
|
||||
|
Loading…
Reference in New Issue
Block a user