forked from github.com/pypiserver
hashes, #53: Add `--hash-algo` option with TCs.
This commit is contained in:
parent
24eddb292a
commit
912d405a83
|
@ -270,6 +270,10 @@ Running ``pypi-server -h`` will print a detailed usage message::
|
|||
-o, --overwrite
|
||||
allow overwriting existing package files
|
||||
|
||||
--hash-algo ALGO
|
||||
any `hashlib` available algo used as fragments on package links.
|
||||
Set one of (0, no, off, false) to disabled it. (default: md5)
|
||||
|
||||
--welcome HTML_FILE
|
||||
uses the ASCII contents of HTML_FILE as welcome message response.
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ def default_config():
|
|||
authenticated = ['update'],
|
||||
password_file = None,
|
||||
overwrite = False,
|
||||
hash_algo = 'md5',
|
||||
verbosity = 1,
|
||||
log_file = None,
|
||||
log_frmt = "%(asctime)s|%(levelname)s|%(thread)d|%(message)s",
|
||||
|
@ -70,15 +71,15 @@ def app(**kwds):
|
|||
|
||||
return _app.app
|
||||
|
||||
def str2bool(s, default):
|
||||
if s is not None and s != '':
|
||||
return s.lower() not in ("no", "off", "0", "false")
|
||||
return default
|
||||
|
||||
def paste_app_factory(global_config, **local_conf):
|
||||
import os
|
||||
|
||||
def upd_bool_attr_from_dict_str_item(conf, attr, sdict):
|
||||
def str2bool(s, default):
|
||||
if s is not None and s != '':
|
||||
return s.lower() not in ("no", "off", "0", "false")
|
||||
return default
|
||||
setattr(conf, attr, str2bool(sdict.pop(attr, None), getattr(conf, attr)))
|
||||
|
||||
def _make_root(root):
|
||||
|
|
|
@ -83,6 +83,10 @@ def usage():
|
|||
-o, --overwrite
|
||||
allow overwriting existing package files
|
||||
|
||||
--hash-algo ALGO
|
||||
any `hashlib` available algo used as fragments on package links.
|
||||
Set one of (0, no, off, false) to disabled it. (default: md5)
|
||||
|
||||
--welcome HTML_FILE
|
||||
uses the ASCII contents of HTML_FILE as welcome message response.
|
||||
|
||||
|
@ -167,6 +171,7 @@ def main(argv=None):
|
|||
"fallback-url=",
|
||||
"disable-fallback",
|
||||
"overwrite",
|
||||
"hash-algo=",
|
||||
"log-file=",
|
||||
"log-frmt=",
|
||||
"log-req-frmt=",
|
||||
|
@ -226,6 +231,8 @@ def main(argv=None):
|
|||
c.password_file = v
|
||||
elif k in ("-o", "--overwrite"):
|
||||
c.overwrite = True
|
||||
elif k in ("--hash-algo"):
|
||||
c.hash_algo = None if not pypiserver.str2bool(v, c.hash_algo) else v
|
||||
elif k == "--log-file":
|
||||
c.log_file = v
|
||||
elif k == "--log-frmt":
|
||||
|
|
|
@ -192,7 +192,9 @@ def simple(prefix=""):
|
|||
return HTTPError(404)
|
||||
|
||||
links = [(os.path.basename(f.relfn),
|
||||
urljoin(fp, "../../packages/%s#%s" % (f.relfn_unix(), f.hash())))
|
||||
urljoin(fp, "../../packages/%s#%s" % (f.relfn_unix(),
|
||||
|
||||
f.hash(config.hash_algo))))
|
||||
for f in files]
|
||||
tmpl = """\
|
||||
<html>
|
||||
|
@ -222,7 +224,8 @@ def list_packages():
|
|||
key=lambda x: (os.path.dirname(x.relfn),
|
||||
x.pkgname,
|
||||
x.parsed_version))
|
||||
links = [(f.relfn_unix(), '%s#%s' % (urljoin(fp, f.relfn), f.hash()))
|
||||
links = [(f.relfn_unix(), '%s#%s' % (urljoin(fp, f.relfn),
|
||||
f.hash(config.hash_algo)))
|
||||
for f in files]
|
||||
tmpl = """\
|
||||
<html>
|
||||
|
|
|
@ -22,6 +22,7 @@ def configure(root=None,
|
|||
authenticated=None,
|
||||
password_file=None,
|
||||
overwrite=False,
|
||||
hash_algo='md5',
|
||||
log_file=None,
|
||||
log_frmt=None,
|
||||
log_req_frmt=None,
|
||||
|
@ -73,29 +74,15 @@ def configure(root=None,
|
|||
:return: a 2-tuple (Configure, package-list)
|
||||
|
||||
"""
|
||||
log.info("+++Pypiserver 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_file=log_file,
|
||||
log_frmt=log_frmt,
|
||||
log_req_frmt=log_req_frmt,
|
||||
log_res_frmt=log_res_frmt,
|
||||
log_err_frmt=log_err_frmt,
|
||||
cache_control=cache_control,
|
||||
auther=auther,
|
||||
host=host, port=port, server=server,
|
||||
verbosity=verbosity, VERSION=VERSION
|
||||
))
|
||||
return _configure(**locals())
|
||||
|
||||
def _configure(**kwds):
|
||||
c = Configuration(**kwds)
|
||||
log.info("+++Pypiserver invoked with: %s", c)
|
||||
|
||||
if root is None:
|
||||
root = os.path.expanduser("~/packages")
|
||||
roots = root if isinstance(root, (list, tuple)) else [root]
|
||||
if c.root is None:
|
||||
c. root = os.path.expanduser("~/packages")
|
||||
roots = c.root if isinstance(c.root, (list, tuple)) else [c.root]
|
||||
roots = [os.path.abspath(r) for r in roots]
|
||||
for r in roots:
|
||||
try:
|
||||
|
@ -107,56 +94,46 @@ def configure(root=None,
|
|||
packages = lambda: itertools.chain(*[listdir(r) for r in roots])
|
||||
packages.root = roots[0]
|
||||
|
||||
authenticated = authenticated or []
|
||||
if not callable(auther):
|
||||
if password_file and password_file != '.':
|
||||
if not c.authenticated:
|
||||
c.authenticated = []
|
||||
if not callable(c.auther):
|
||||
if c.password_file and c.password_file != '.':
|
||||
from passlib.apache import HtpasswdFile
|
||||
htPsswdFile = HtpasswdFile(password_file)
|
||||
htPsswdFile = HtpasswdFile(c.password_file)
|
||||
else:
|
||||
password_file = htPsswdFile = None
|
||||
auther = functools.partial(auth_by_htpasswd_file, htPsswdFile)
|
||||
c.password_file = htPsswdFile = None
|
||||
c.auther = functools.partial(auth_by_htpasswd_file, htPsswdFile)
|
||||
|
||||
# Read welcome-msg from external file,
|
||||
# or failback to the embedded-msg (ie. in standalone mode).
|
||||
#
|
||||
try:
|
||||
if not welcome_file:
|
||||
welcome_file = "welcome.html"
|
||||
welcome_msg = pkg_resources.resource_string( # @UndefinedVariable
|
||||
if not c.welcome_file:
|
||||
c.welcome_file = "welcome.html"
|
||||
c.welcome_msg = pkg_resources.resource_string( # @UndefinedVariable
|
||||
__name__, "welcome.html").decode("utf-8") # @UndefinedVariable
|
||||
else:
|
||||
welcome_file = welcome_file
|
||||
with io.open(welcome_file, 'r', encoding='utf-8') as fd:
|
||||
welcome_msg = fd.read()
|
||||
with io.open(c.welcome_file, 'r', encoding='utf-8') as fd:
|
||||
c.welcome_msg = fd.read()
|
||||
except Exception:
|
||||
log.warning(
|
||||
"Could not load welcome-file(%s)!", welcome_file, exc_info=1)
|
||||
"Could not load welcome-file(%s)!", c.welcome_file, exc_info=1)
|
||||
|
||||
if fallback_url is None:
|
||||
fallback_url = "http://pypi.python.org/simple"
|
||||
if c.fallback_url is None:
|
||||
c.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
|
||||
if c.hash_algo:
|
||||
try:
|
||||
halgos = hashlib.algorithms_available
|
||||
except AttributeError:
|
||||
halgos = ['md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512']
|
||||
|
||||
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("+++Pypiserver started with: %s", config)
|
||||
if c.hash_algo not in halgos:
|
||||
sys.exit('Hash-algorithm %s not one of: %s' % (c.hash_algo, halgos))
|
||||
|
||||
return config, packages
|
||||
log.info("+++Pypiserver started with: %s", c)
|
||||
|
||||
return c, packages
|
||||
|
||||
|
||||
def auth_by_htpasswd_file(htPsswdFile, username, password):
|
||||
|
@ -268,7 +245,7 @@ class PkgFile(object):
|
|||
def relfn_unix(self):
|
||||
return self.relfn.replace("\\", "/")
|
||||
|
||||
def hash(self, hash_algo='md5'):
|
||||
def hash(self, hash_algo):
|
||||
return '%s=%.32s' % (hash_algo, digest_file(self.fn, hash_algo))
|
||||
|
||||
|
||||
|
|
|
@ -89,11 +89,34 @@ def test_fallback_url_default(main):
|
|||
assert main.app.module.config.fallback_url == \
|
||||
"http://pypi.python.org/simple"
|
||||
|
||||
@pytest.fixture
|
||||
def logfile(tmpdir):
|
||||
return tmpdir.mkdir("logs").join('test.log')
|
||||
|
||||
def test_logging(main, logfile):
|
||||
def test_hash_algo_default(main):
|
||||
main([])
|
||||
assert main.app.module.config.hash_algo == 'md5'
|
||||
|
||||
def test_hash_algo(main):
|
||||
main(['--hash-algo=sha256'])
|
||||
assert main.app.module.config.hash_algo == 'sha256'
|
||||
|
||||
def test_hash_algo_off(main):
|
||||
main(['--hash-algo=off'])
|
||||
assert main.app.module.config.hash_algo is None
|
||||
main(['--hash-algo=0'])
|
||||
assert main.app.module.config.hash_algo is None
|
||||
main(['--hash-algo=no'])
|
||||
assert main.app.module.config.hash_algo is None
|
||||
main(['--hash-algo=false'])
|
||||
assert main.app.module.config.hash_algo is None
|
||||
|
||||
def test_hash_algo_BAD(main):
|
||||
with pytest.raises(SystemExit) as excinfo:
|
||||
main(['--hash-algo BAD'])
|
||||
#assert excinfo.value.message == 'some info' main(['--hash-algo BAD'])
|
||||
print(excinfo)
|
||||
|
||||
|
||||
def test_logging(main, tmpdir):
|
||||
logfile = tmpdir.mkdir("logs").join('test.log')
|
||||
main(["-v", "--log-file", logfile.strpath])
|
||||
assert logfile.check(), logfile
|
||||
|
||||
|
@ -122,14 +145,14 @@ def test_password_without_auth_list(main, monkeypatch):
|
|||
with pytest.raises(ValueError) as ex:
|
||||
main(["-P", "pswd-file", "-a", ""])
|
||||
assert ex.value.args[0] == 'BINGO'
|
||||
|
||||
|
||||
with pytest.raises(ValueError) as ex:
|
||||
main(["-a", "."])
|
||||
assert ex.value.args[0] == 'BINGO'
|
||||
with pytest.raises(ValueError) as ex:
|
||||
main(["-a", ""])
|
||||
assert ex.value.args[0] == 'BINGO'
|
||||
|
||||
|
||||
with pytest.raises(ValueError) as ex:
|
||||
main(["-P", "."])
|
||||
assert ex.value.args[0] == 'BINGO'
|
||||
|
@ -143,6 +166,6 @@ def test_password_alone(main, monkeypatch):
|
|||
def test_dot_password_without_auth_list(main, monkeypatch):
|
||||
main(["-P", ".", "-a", ""])
|
||||
assert main.app.module.config.authenticated == []
|
||||
|
||||
|
||||
main(["-P", ".", "-a", "."])
|
||||
assert main.app.module.config.authenticated == []
|
||||
|
|
Loading…
Reference in New Issue