RPackage: parse description for incomplete dependencies
This commit is contained in:
parent
eaabde6ee9
commit
0cd97d584e
@ -1,12 +1,19 @@
|
||||
# Copyright Spack Project Developers. See COPYRIGHT file for details.
|
||||
#
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
import re
|
||||
from typing import Optional, Tuple
|
||||
|
||||
import llnl.util.filesystem as fs
|
||||
import llnl.util.lang as lang
|
||||
import llnl.util.tty as tty
|
||||
import spack.deptypes as dt
|
||||
from llnl.util.filesystem import mkdirp
|
||||
from llnl.util.lang import ClassProperty, classproperty
|
||||
|
||||
from spack.dependency import Dependency
|
||||
from spack.directives import extends
|
||||
from spack.spec import Spec
|
||||
|
||||
from .generic import GenericBuilder, Package
|
||||
|
||||
@ -38,6 +45,59 @@ def install(self, pkg, spec, prefix):
|
||||
"""Installs an R package."""
|
||||
mkdirp(pkg.module.r_lib_dir)
|
||||
|
||||
try:
|
||||
# TODO: use a more sustainable dcf parser
|
||||
import pycran
|
||||
|
||||
# Read DESCRIPTION file with dependency information
|
||||
# https://r-pkgs.org/description.html
|
||||
r_deps = []
|
||||
with open(fs.join_path(self.stage.source_path, 'DESCRIPTION')) as file:
|
||||
for desc in pycran.parse(file.read()):
|
||||
r_deps.extend([d.strip() for d in desc.get("Imports", None).split(",")])
|
||||
r_deps.extend([d.strip() for d in desc.get("Depends", None).split(",")])
|
||||
|
||||
# Convert to spack dependencies format for comparison
|
||||
deps = {}
|
||||
for r_dep in r_deps:
|
||||
p = re.search(r"^[\w_-]+", r_dep) # first word, incl. underscore or dash
|
||||
v = re.search("(?<=[(]).*(?=[)])", r_dep) # everything between parentheses
|
||||
# require valid package
|
||||
assert(p, f"Unable to find package name in {r_dep}")
|
||||
r_spec = f"r-{p[0].strip().lower()}" if p[0].lower() != "r" else "r"
|
||||
# allow minimum or pinned versions
|
||||
if v:
|
||||
v = re.sub(r">=\s([\d.-]+)", r"@\1:", v[0]) # >=
|
||||
v = re.sub(r"==\s([\d.-]+)", r"@\1", v) # ==
|
||||
deps[r_spec] = Dependency(pkg, Spec(r_spec + v), dt.BUILD | dt.RUN)
|
||||
else:
|
||||
deps[r_spec] = Dependency(pkg, Spec(r_spec), dt.BUILD | dt.RUN)
|
||||
|
||||
# Retrieve dependencies for current spack package and version
|
||||
spack_dependencies = []
|
||||
for when, dep in pkg.dependencies.items():
|
||||
if spec.satisfies(when):
|
||||
spack_dependencies.append(dep)
|
||||
merged_dependencies = {}
|
||||
for dep in spack_dependencies:
|
||||
for n, d in dep.items():
|
||||
if d in merged_dependencies:
|
||||
merged_dependencies[n].merge(d)
|
||||
else:
|
||||
merged_dependencies[n] = d
|
||||
|
||||
# For each R dependency, ensure Spack dependency is at least as strong
|
||||
for dep in sorted(deps.keys()):
|
||||
if dep in merged_dependencies:
|
||||
if not merged_dependencies[dep].spec.satisfies(deps[dep].spec):
|
||||
tty.debug(f' depends_on("{deps[dep].spec}", when="@{pkg.version}:", type=("build", "run"))')
|
||||
else:
|
||||
tty.debug(f' depends_on("{deps[dep].spec}", when="@{pkg.version}:", type=("build", "run"))')
|
||||
|
||||
except ImportError:
|
||||
tty.debug("R package dependency verification requires pycran")
|
||||
pass
|
||||
|
||||
config_args = self.configure_args()
|
||||
config_vars = self.configure_vars()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user