1
0
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:
ankostis on tokoti 2015-12-20 19:18:27 +02:00
parent e55a325477
commit 8a8d9e4f16
3 changed files with 91 additions and 98 deletions

@ -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"
@ -254,7 +259,7 @@ def main(argv=None):
print(usage())
sys.exit(0)
if (not authed_ops_list and password_file != '.' or
if (not authed_ops_list and password_file != '.' or
authed_ops_list and password_file == '.'):
auth_err = "When auth-ops-list is empty (-a=.), password-file (-P=%r) must also be empty ('.')!"
sys.exit(auth_err % password_file)
@ -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,81 +77,104 @@ 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,
redirect_to_fallback=redirect_to_fallback,
fallback_url=fallback_url,
authenticated=authenticated,
password_file=password_file,
overwrite=overwrite,
welcome_file=welcome_file,
log_req_frmt=log_req_frmt,
log_res_frmt=log_res_frmt,
log_err_frmt=log_err_frmt,
cache_control=cache_control,
alt_auth=alt_auth))
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,
password_file=password_file,
overwrite=overwrite,
welcome_file=welcome_file,
log_req_frmt=log_req_frmt,
log_res_frmt=log_res_frmt,
log_err_frmt=log_err_frmt,
cache_control=cache_control,
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
if password_file and password_file != '.':
from passlib.apache import HtpasswdFile
config.htpasswdfile = HtpasswdFile(password_file)
config.overwrite = overwrite
authenticated = authenticated or []
if not callable(auther):
auther = auth_by_htpasswd_file
if password_file and password_file != '.':
from passlib.apache import HtpasswdFile
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')