Commit e53bfdd6 authored by Ophélie Gagnard's avatar Ophélie Gagnard

Add selection strategies for downloading objects.

Add a default strategies that returns the first match.
Add a most recent strategy that returns the object with the greater
timestamp.
Add a "version more than" strategy that returns the first match with
versions superior to that provided. There are two varients of this one:
"strictly more than" and "more than". Versions are required to be
compatible with Python project's version formats define here:
https://peps.python.org/pep-0440/
parent 673842a9
...@@ -24,6 +24,7 @@ import tarfile ...@@ -24,6 +24,7 @@ import tarfile
import tempfile import tempfile
import traceback import traceback
from base64 import b64encode, b64decode from base64 import b64encode, b64decode
from packaging import version
try: try:
import configparser import configparser
from http.client import HTTPConnection, HTTPSConnection from http.client import HTTPConnection, HTTPSConnection
...@@ -473,6 +474,51 @@ class NetworkcacheClient(object): ...@@ -473,6 +474,51 @@ class NetworkcacheClient(object):
pass pass
return False return False
def strategy_default(self, key, kw):
return next(self.select(key, kw))['sha512']
def strategy_most_recent(self, key, kw):
timestamp = 0
most_recent = None
for dictionary in self.select(key,kw):
try:
if int(dictionary['timestamp']) > timestamp:
most_recent = dictionary
timestamp = int(dictionary['timestamp'])
except ValueError:
logger.info('"timestamp" is not an integer (%r)',
dictionary['timestamp'])
except KeyError:
logger.info('No "timestamp" key (%r)',
dictionary)
return most_recent['sha512']
def strategy_higher_version(self, key, kw, strict=False):
# selection criteria:
# - match all non-version parameters
# - every asked version has a value in the dictionary
# - every such version is greater or equal to the asked version
# an entry in kw is read as a version if and only if its key contains "version" (case insensitive)
compare = version.Version.__gt__ if strict else version.Version.__ge__
version_dict = {k:version.Version(kw[k]) for k in kw if "version" in k.lower()}
# if there is no version restriction, then return most recent with same selection criteria
if len(version_dict) == 0:
return self.strategy_most_recent(key,kw)
selection_dict = {k:kw[k] for k in kw if "version" not in k.lower()}
first_match = None
for dictionary in self.select(key,selection_dict):
for k in version_dict:
try:
if k not in dictionary or not compare(version.parse(dictionary[k]),version_dict[k]):
break
except packaging.version.InvalidVersion:
logger.info('Failed to convert to Version (%r)',
dictionary[k])
print(dictionary['sha512'], file=sys.stderr)
else:
return dictionary['sha512']
raise StopIteration("No match.")
class NetworkcacheException(Exception): class NetworkcacheException(Exception):
pass pass
...@@ -533,6 +579,8 @@ def cmd_download(*args): ...@@ -533,6 +579,8 @@ def cmd_download(*args):
parser = _newArgumentParser("URL of data to download." + key_help) parser = _newArgumentParser("URL of data to download." + key_help)
parser.add_argument('--id', parser.add_argument('--id',
help="Identifier of the shadir URL, overriding --prefix-key and --suffix-key.") help="Identifier of the shadir URL, overriding --prefix-key and --suffix-key.")
parser.add_argument('-s', '--selection_strategy', choices=["default", "most_recent", "higher_version", "strictly_higher_version"],
help="Strategy to use to select the object to be downloaded.")
parser.add_argument('meta', nargs='*', metavar='KEY=VALUE', parser.add_argument('meta', nargs='*', metavar='KEY=VALUE',
help="Extra metadata.") help="Extra metadata.")
args = parser.parse_args(args or sys.argv[1:]) args = parser.parse_args(args or sys.argv[1:])
...@@ -544,5 +592,12 @@ def cmd_download(*args): ...@@ -544,5 +592,12 @@ def cmd_download(*args):
urlmd5 = hashlib.md5(args.url.encode()).hexdigest() urlmd5 = hashlib.md5(args.url.encode()).hexdigest()
key = args.prefix_key + urlmd5 + args.suffix_key key = args.prefix_key + urlmd5 + args.suffix_key
f = sys.stdout f = sys.stdout
shutil.copyfileobj(nc.download(next(nc.select(key, kw))['sha512']), if args.selection_strategy == "most_recent":
getattr(f, 'buffer', f)) strategy = nc.strategy_most_recent
elif args.selection_strategy == "higher_version":
strategy = nc.strategy_higher_version
elif args.selection_strategy == "strictly_higher_version":
strategy = nc.strategy_higher_version(strict=True)
else:
strategy = nc.strategy_default
shutil.copyfileobj(nc.download(strategy(key, kw)), getattr(f, 'buffer', f))
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment