2020-04-22 09:28:58 +00:00
|
|
|
from typing import Iterable
|
|
|
|
|
|
|
|
import distlib.markers
|
|
|
|
import pkg_resources
|
|
|
|
from distlib.markers import DEFAULT_CONTEXT
|
|
|
|
from packaging.version import parse, _Version
|
|
|
|
from pkg_resources._vendor.packaging.specifiers import SpecifierSet
|
|
|
|
|
2020-08-07 07:35:50 +00:00
|
|
|
from mach_nix.cache import cached
|
2020-04-22 09:28:58 +00:00
|
|
|
from mach_nix.versions import PyVer
|
|
|
|
|
|
|
|
|
2020-08-09 13:24:12 +00:00
|
|
|
def context(py_ver: PyVer, platform: str, system: str):
|
2020-04-22 09:28:58 +00:00
|
|
|
context = DEFAULT_CONTEXT.copy()
|
|
|
|
context.update(dict(
|
2020-08-09 13:24:12 +00:00
|
|
|
platform_version='', # remove impure platform_version
|
|
|
|
platform_release='', # remove impure kernel verison
|
|
|
|
platform_system=system[0].upper() + system[1:], # eg. Linux or Darwin
|
|
|
|
platform_machine=platform, # eg. x86_64
|
2020-04-22 09:28:58 +00:00
|
|
|
python_version=py_ver.python_version(),
|
2020-05-19 09:46:48 +00:00
|
|
|
python_full_version=py_ver.python_full_version()
|
2020-04-22 09:28:58 +00:00
|
|
|
))
|
|
|
|
return context
|
|
|
|
|
|
|
|
|
|
|
|
class Requirement(pkg_resources.Requirement):
|
|
|
|
def __init__(self, line):
|
|
|
|
super(Requirement, self).__init__(line)
|
|
|
|
self.name = self.name.lower().replace('_', '-')
|
|
|
|
self.specs = list(self.norm_specs(self.specs))
|
|
|
|
self.specifier = SpecifierSet(','.join(f"{op}{ver}" for op, ver in self.specs))
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def norm_specs(specs):
|
|
|
|
# PEP 440: Compatible Release
|
|
|
|
for spec in specs:
|
|
|
|
if spec[0] == "~=":
|
|
|
|
ver = spec[1]
|
|
|
|
yield ('>=', ver)
|
|
|
|
ver = parse(parse(ver).base_version)
|
|
|
|
ver_as_dict = ver._version._asdict()
|
|
|
|
ver_as_dict['release'] = ver_as_dict['release'][:-1] + ('*',)
|
|
|
|
ver._version = _Version(**ver_as_dict)
|
|
|
|
yield ('==', str(ver))
|
|
|
|
else:
|
|
|
|
yield spec
|
|
|
|
|
|
|
|
|
2020-05-19 09:46:48 +00:00
|
|
|
def filter_reqs_by_eval_marker(reqs: Iterable[Requirement], context: dict, selected_extras=None):
|
2020-04-22 09:28:58 +00:00
|
|
|
# filter requirements relevant for current environment
|
|
|
|
for req in reqs:
|
2020-05-19 09:46:48 +00:00
|
|
|
if req.marker is None:
|
2020-04-22 09:28:58 +00:00
|
|
|
yield req
|
2020-05-19 09:46:48 +00:00
|
|
|
elif selected_extras:
|
|
|
|
for extra in selected_extras:
|
|
|
|
extra_context = context.copy()
|
|
|
|
extra_context['extra'] = extra
|
|
|
|
if distlib.markers.interpret(str(req.marker), extra_context):
|
|
|
|
yield req
|
|
|
|
else:
|
|
|
|
if distlib.markers.interpret(str(req.marker), context):
|
|
|
|
yield req
|
|
|
|
|
2020-04-22 09:28:58 +00:00
|
|
|
|
2020-08-07 07:35:50 +00:00
|
|
|
@cached(lambda args: tuple(args[0]) if isinstance(args[0], list) else args[0])
|
2020-04-22 09:28:58 +00:00
|
|
|
def parse_reqs(strs):
|
|
|
|
reqs = list(pkg_resources.parse_requirements(strs))
|
|
|
|
for req in reqs:
|
|
|
|
r = Requirement(str(req))
|
|
|
|
yield r
|