More R package support.

This commit is contained in:
Jelmer Vernooij 2021-03-19 14:41:43 +00:00
parent 2ceef03c8a
commit 4fbc36c7ff
4 changed files with 81 additions and 3 deletions

View file

@ -27,6 +27,7 @@ from . import shebang_binary, UnidentifiedError
from .outputs import ( from .outputs import (
BinaryOutput, BinaryOutput,
PythonPackageOutput, PythonPackageOutput,
RPackageOutput,
) )
from .requirements import ( from .requirements import (
BinaryRequirement, BinaryRequirement,
@ -34,6 +35,7 @@ from .requirements import (
PerlModuleRequirement, PerlModuleRequirement,
NodePackageRequirement, NodePackageRequirement,
CargoCrateRequirement, CargoCrateRequirement,
RPackageRequirement,
) )
from .fix_build import run_with_build_fixers from .fix_build import run_with_build_fixers
@ -456,16 +458,41 @@ class R(BuildSystem):
return "%s(%r)" % (type(self).__name__, self.path) return "%s(%r)" % (type(self).__name__, self.path)
def build(self, session, resolver, fixers): def build(self, session, resolver, fixers):
pass
def dist(self, session, resolver, fixers, quiet=False):
run_with_build_fixers(session, ["R", "CMD", "build", "."], fixers) run_with_build_fixers(session, ["R", "CMD", "build", "."], fixers)
def install(self, session, resolver, fixers, install_target):
run_with_build_fixers(session, ["R", "CMD", "INSTALL", "."], fixers)
def test(self, session, resolver, fixers): def test(self, session, resolver, fixers):
run_with_build_fixers(session, ["R", "CMD", "test", "."], fixers) run_with_build_fixers(session, ["R", "CMD", "check", "."], fixers)
@classmethod @classmethod
def probe(cls, path): def probe(cls, path):
if os.path.exists(os.path.join(path, 'DESCRIPTION')): if os.path.exists(os.path.join(path, 'DESCRIPTION')):
return cls(path) return cls(path)
def _read_description(self):
path = os.path.join(self.path, 'DESCRIPTION')
from email.parser import BytesParser
with open(path, 'rb') as f:
return BytesParser().parse(f)
def get_declared_dependencies(self, session, fixers=None):
description = self._read_description()
if 'Suggests' in description:
suggests = [s.strip() for s in description['Suggests'].split(',') if s.strip()]
for s in suggests:
# TODO(jelmer): Look at version
yield "build", RPackageRequirement.from_str(s)
def get_declared_outputs(self, session, fixers=None):
description = self._read_description()
if 'Package' in description:
yield RPackageOutput(description['Package'])
class Meson(BuildSystem): class Meson(BuildSystem):

View file

@ -46,3 +46,15 @@ class PythonPackageOutput(UpstreamOutput):
self.name, self.name,
self.python_version, self.python_version,
) )
class RPackageOutput(UpstreamOutput):
def __init__(self, name):
super(RPackageOutput, self).__init__("r-package")
self.name = name
def __str__(self):
return "R package: %s" % self.name
def __repr__(self):
return "%s(%r)" % (type(self).__name__, self.name)

View file

@ -17,6 +17,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import posixpath import posixpath
import re
import subprocess import subprocess
from typing import Optional, List, Tuple, Set from typing import Optional, List, Tuple, Set
@ -249,6 +250,30 @@ class RPackageRequirement(Requirement):
self.package = package self.package = package
self.minimum_version = minimum_version self.minimum_version = minimum_version
def __repr__(self):
return "%s(%r, minimum_version=%r)" % (
type(self).__name__,
self.package,
self.minimum_version,
)
def __str__(self):
if self.minimum_version:
return "R package: %s (>= %s)" % (self.package, self.minimum_version)
else:
return "R package: %s" % (self.package,)
@classmethod
def from_str(cls, text):
# TODO(jelmer): More complex parser
m = re.fullmatch(r'(.*) \(>= (.*)\)', text)
if m:
return cls(m.group(1), m.group(2))
m = re.fullmatch(r'([^ ]+)', text)
if m:
return cls(m.group(1))
raise ValueError(text)
class LibraryRequirement(Requirement): class LibraryRequirement(Requirement):

View file

@ -76,8 +76,8 @@ class CPANResolver(Resolver):
raise UnsatisfiedRequirements(missing) raise UnsatisfiedRequirements(missing)
class CRANResolver(Resolver): class RResolver(Resolver):
def __init__(self, session, repos='"http://cran.r-project.org'): def __init__(self, session, repos):
self.session = session self.session = session
self.repos = repos self.repos = repos
@ -114,6 +114,19 @@ class CRANResolver(Resolver):
raise UnsatisfiedRequirements(missing) raise UnsatisfiedRequirements(missing)
class CRANResolver(RResolver):
def __init__(self, session):
super(CRANResolver, self).__init__(session, 'http://cran.r-project.org')
class BioconductorResolver(RResolver):
def __init__(self, session):
super(BioconductorResolver, self).__init__(
session, 'https://hedgehog.fhcrc.org/bioconductor')
class HackageResolver(Resolver): class HackageResolver(Resolver):
def __init__(self, session): def __init__(self, session):
self.session = session self.session = session
@ -307,6 +320,7 @@ NATIVE_RESOLVER_CLS = [
GoResolver, GoResolver,
HackageResolver, HackageResolver,
CRANResolver, CRANResolver,
BioconductorResolver,
] ]