forked from github.com/pypiserver

Updates the Docker configuration to use the gunicorn server with gevent workers by default. Adds `waitress` to the docker container, so that if no server is specified, we will fall back to that rather than `wsgiref`. Making this happen brought a few other issues to light, which are also addressed here. - Docker log output not immediately being flushed to stdout (#358): resolved by setting the `PYTHONUNBUFFERED` env var to `t` in the docker container - When the WSGIRef server is selected, its access logs are written directly to stderr, rather than going through the logging machinery: resolved by adding a new `WsgiHandler` class and passing in to bottle's `run()` method when running the wsgi server. This required a new `ServerCheck` class to determine whether the wsgi server is selected when the `auto` option is used - When using `gunicorn` along with the watchdog cache, package uplaods were not being picked up by the watcher. Updated the `add_package` and `remove_package` methods on the `CachingFileBackend` to bust the cache
133 lines
3.7 KiB
Bash
Executable File
133 lines
3.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
function run() {
|
|
# we're not root. Run as who we are.
|
|
if [[ "$EUID" -ne 0 ]]; then
|
|
eval "$@"
|
|
else
|
|
gosu pypiserver "$@"
|
|
fi
|
|
}
|
|
|
|
if [[ "$EUID" -ne 0 && "$EUID" -ne $(id -u pypiserver) ]]; then
|
|
USER_ID="$EUID"
|
|
WARN=(
|
|
"The pypiserver container was run as a non-root, non-pypiserver user."
|
|
"Pypiserver will be run as this user if possible, but this is not"
|
|
"officially supported."
|
|
)
|
|
echo "" 1>&2
|
|
echo "${WARN[@]}" 1>&2
|
|
echo "" 1>&2
|
|
else
|
|
USER_ID=$(id -u pypiserver)
|
|
fi
|
|
|
|
|
|
function print_permissions_help() {
|
|
MSG1=(
|
|
"If you are mounting a volume at /data or /data/packages and are running the"
|
|
"container on a linux system, you may need to add add a pypiserver"
|
|
"group to the host and give it permission to access the directories."
|
|
"Please see https://github.com/pypiserver/pypiserver/issues/256 for more"
|
|
"details."
|
|
)
|
|
MSG2=(
|
|
"Please see https://github.com/pypiserver/pypiserver/issues/256 for more"
|
|
"details."
|
|
)
|
|
echo "" 1>&2
|
|
echo "${MSG1[@]}" 1>&2
|
|
echo "" 1>&2
|
|
echo "${MSG2[@]}" 1>&2
|
|
}
|
|
|
|
|
|
# the user must have read and execute access to the /data directory
|
|
# (execute to be able to cd into directory and list content metadata)
|
|
if ! run test -r /data -a -x /data; then
|
|
|
|
chown -R "$USER_ID:pypiserver" /data || true
|
|
|
|
if ! run test -r /data -a -x /data; then
|
|
FAIL_MSG=(
|
|
"Cannot start pypiserver:"
|
|
"pypiserver user (UID $USER_ID)"
|
|
"or pypiserver group (GID $(id -g pypiserver))"
|
|
"must have read/execute access to /data"
|
|
)
|
|
echo "${FAIL_MSG[@]}" 1>&2
|
|
echo "" 1>&2
|
|
print_permissions_help
|
|
exit 1
|
|
fi
|
|
|
|
fi
|
|
|
|
# The /data/packages directory must exist
|
|
# It not existing is very unlikely, possibly impossible, because the VOLUME
|
|
# specification in the Dockerfile leads to its being created even if someone is
|
|
# mounting a volume at /data that does not contain a /packages subdirectory
|
|
if [[ ! -d "/data/packages" ]]; then
|
|
if ! run test -w /data; then
|
|
FAIL_MSG=(
|
|
"Cannot start pypiserver:"
|
|
"/data/packages does not exist and"
|
|
"pypiserver user (UID $USER_ID)"
|
|
"or pypiserver group (GID $(id -g pypiserver))"
|
|
"does not have write access to /data to create it"
|
|
)
|
|
echo "" 1>&2
|
|
echo "${FAIL_MSG[@]}" 1>&2
|
|
print_permissions_help
|
|
exit 1
|
|
fi
|
|
run mkdir /data/packages
|
|
fi
|
|
|
|
# The pypiserver user needs read/write/execute access to the packages directory
|
|
if ! run \
|
|
test -w /data/packages \
|
|
-a -r /data/packages \
|
|
-a -x /data/packages; then
|
|
|
|
# We'll try to chown as a last resort.
|
|
# Don't complain if it fails, since we'll bomb on the next check anyway.
|
|
chown -R "$USER_ID:pypiserver" /data/packages || true
|
|
|
|
if ! run \
|
|
test -w /data/packages \
|
|
-a -r /data/packages \
|
|
-a -x /data/packages; then
|
|
FAIL_MSG=(
|
|
"Cannot start pypiserver:"
|
|
"pypiserver user (UID $USER_ID)"
|
|
"or pypiserver group (GID $(id -g pypiserver))"
|
|
"must have read/write/execute access to /data/packages"
|
|
)
|
|
echo "" 1>&2
|
|
echo "${FAIL_MSG[@]}" 1>&2
|
|
print_permissions_help
|
|
exit 1
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
if [[ "$*" == "" ]]; then
|
|
# Use the gunicorn server by default, since it's more performant than
|
|
# bottle's default server
|
|
CMD=("run" "-p" "${PYPISERVER_PORT:-$PORT}" "--server" "gunicorn")
|
|
else
|
|
# this reassigns the array to the CMD variable
|
|
CMD=( "${@}" )
|
|
fi
|
|
|
|
if [[ "$EUID" -ne 0 ]]; then
|
|
exec pypi-server "${CMD[@]}"
|
|
else
|
|
exec gosu pypiserver pypi-server "${CMD[@]}"
|
|
fi
|