Skip to content

Commit

Permalink
RPACU-52 Parse the "LinkingTo:" field in the DESCRIPTION file
Browse files Browse the repository at this point in the history
  • Loading branch information
scanopm committed Nov 15, 2019
1 parent 4c5ec7b commit 19a1996
Show file tree
Hide file tree
Showing 11 changed files with 94 additions and 20 deletions.
1 change: 1 addition & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- RPACU-50 Switch the license from GPL v2 to Apache 2.0
- RPACU-51 Check the output messages from stderr and stdout even when
the R installation command returns a success code
- RPACU-52 Fix DESCRIPTION file parsing, read the "LinkingTo" field

0.1.9
-----
Expand Down
27 changes: 16 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,10 @@ Downloading R package: tmod_0.30.tar.gz
Done downloading R package: tmod_0.30.tar.gz
Package: tmod Version: 0.30 License: GPL (>= 2.0)
Repository path: R-3.1.2/tmod_0.30.tar.gz
Dependencies: beeswarm,pca3d,tagcloud,XML
Depends: R
Imports: beeswarm,tagcloud,XML,methods,plotwidgets
LinkingTo:
Suggests: testthat,knitr,rmarkdown,pca3d,limma
-------------------------------------
```
Expand Down Expand Up @@ -838,9 +841,9 @@ optional arguments:
"annotationData". CRAN: "snapshot date".
--packages PACKAGES Comma separated list of root packages to create the
graph, by default all will be included
--traverse TRAVERSE By default "imports,depends", to traverse both imports
and depends to build the dependency graph. "suggests"
is ignored by default.
--traverse TRAVERSE By default "imports,depends,linkingto", to traverse
all required packages to build the dependency
graph. "suggests" is ignored by default.
--config CONFIG RPackUtils configuration file, required unless you use
CRAN or Bioconductor as repository
--out OUT Output file where to write the GML
Expand All @@ -850,9 +853,10 @@ The *--packages* parameter is optional: you can choose to focus on one or
more particular packages if you like. All available packages in the
repository will be taken into account otherwise.
You can choose the list of fields from ['imports', 'depends', 'suggests']
to take into account while building the dependency graph. By default,
'imports' and 'depends' are used.
You can choose the list of fields from ['imports', 'depends',
'linkingto', 'suggests'] to take into account while building the
dependency graph. By default, 'imports', 'depends' and 'linkingto' are
used.
Here is an example to compute the dependency graph for all vailable R
packages from the *2016-05-03* snapshot. This snapshot contains more than
Expand All @@ -879,6 +883,7 @@ The gml file has the following attributes for each node:
| version | package version |
| depends | packages in depends |
| imports | packages in imports |
| linkingto | packages in linkingto |
| suggests | packages in suggests |
| license | package license |
| licenseclass | ALLOWED / RESTRICETD / BLACKLISTED / UNKNOWN |
Expand Down Expand Up @@ -922,10 +927,10 @@ Time elapsed: 22.923 seconds.
The output file, is a comma-separated format (CSV) and as a table, it looks
like the following:
| Name | Version | License | License class | Depends | Imports | Suggests | Installation allowed | Installation warning |
|----------|---------|--------------------|---------------|---------|-----------------|--------------------------|----------------------|----------------------|
| evaluate | 0.9 | MIT + file LICENSE | UNKNOWN | R | methods,stringr | testthat,lattice,ggplot2 | True | True |
| [...] | | | | | | | | |
| Name | Version | License | License class | Depends | Imports | LinkingTo | Suggests | Installation allowed | Installation warning |
|----------|---------|--------------------|---------------|---------|-----------------|-----------|--------------------------|----------------------|----------------------|
| evaluate | 0.9 | MIT + file LICENSE | UNKNOWN | R | methods,stringr | | testthat,lattice,ggplot2 | True | True |
| [...] | | | | | | | | | |
## Repository types
Expand Down
12 changes: 7 additions & 5 deletions rpackutils/cli/cliDepsGraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ def rpacks_deps_graph():
'--traverse',
dest='traverse',
action='store',
default='imports,depends',
default='imports,depends,linkingto',
required=False,
help=('By default \"imports,depends\", to traverse both '
'imports and depends to build the dependency graph. '
help=('By default \"imports,depends,linkingto\", to traverse all '
'required packages to build the dependency graph. '
'\"suggests\" is ignored by default.'),
) and None
parser.add_argument(
Expand Down Expand Up @@ -170,17 +170,19 @@ def rpacks_deps_graph():
or isinstance(repository, LocalRepository):
if repoparam is not None:
logger.warning('Ignoring the --repoparam argument')
# traverse options (imports, depends, suggests)
# traverse options (imports, depends, suggests, linkingto)
traverse_imports = ('imports' in traverse)
traverse_depends = ('depends' in traverse)
traverse_suggests = ('suggests' in traverse)
traverse_linkingto = ('linkingto' in traverse)
# construct the dependencies tree
dt = DepTree(repository,
lsargs,
packinfoargs,
traverse_imports,
traverse_depends,
traverse_suggests)
traverse_suggests,
traverse_linkingto)
logger.info('Building the dependencies graph ...')
dt.build(packagenames=packages)
if len(dt._g.nodes()) < 2:
Expand Down
2 changes: 2 additions & 0 deletions rpackutils/cli/cliQuery.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ def _query_packages(repositories, packages):
.format(",".join(packinfo.dependslist)))
logger.info('Imports: {}'
.format(",".join(packinfo.importslist)))
logger.info('LinkingTo: {}'
.format(",".join(packinfo.linkingtolist)))
logger.info('Suggests: {}'
.format(",".join(packinfo.suggestslist)))
# logger.info('Dependencies: {0}' \
Expand Down
1 change: 1 addition & 0 deletions rpackutils/cli/cliScan.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ def _scan_packages(repositories, out):
'License class': packinfo.licenseclass,
'Depends': ",".join(packinfo.dependslist),
'Imports': ",".join(packinfo.importslist),
'LinkingTo': ",".join(packinfo.linkingtolist),
'Suggests': ",".join(packinfo.suggestslist),
'Installation allowed': packinfo.installation_is_allowed,
'Installation warning': packinfo.installation_warning
Expand Down
18 changes: 15 additions & 3 deletions rpackutils/packinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import tempfile
import tarfile
import shutil
import codecs
import logging
from .utils import Utils
from .rbasepackages import RBasePackages
Expand Down Expand Up @@ -65,6 +64,7 @@ def __init__(self, path):
self.depends = None
self.imports = None
self.suggests = None
self.linkingto = None
self.license = None
self.licenseclass = None
self.installationisallowed = True
Expand Down Expand Up @@ -127,17 +127,21 @@ def dependslist(self):
def importslist(self):
return self.imports if self.imports else []

@property
def linkingtolist(self):
return self.linkingto if self.linkingto else []

@property
def suggestslist(self):
return self.suggests if self.suggests else []

def dependencies(self, withBasePackages=False):
"""
Returns an aggregated list of both imports and depends.
Returns an aggregated list of imports, depends and linkingto.
:param withBasepackages: if True, remove all R base packages
"""
all = self.importslist + self.dependslist
all = self.importslist + self.dependslist + self.linkingtolist
if not withBasePackages:
all = [x for x in all if x not in RBasePackages.getnames()]
return all
Expand Down Expand Up @@ -168,6 +172,12 @@ def has_imports(self):
return False
return len(self.imports) > 0

@property
def has_linkingto(self):
if self.linkingto is None:
return False
return len(self.linkingto) > 0

@property
def has_suggests(self):
if self.suggests is None:
Expand Down Expand Up @@ -224,6 +234,7 @@ def _do_parse_descriptionfile(self, descriptionfilepath):
'depends': None,
'imports': None,
'suggests': None,
'linkingto': None,
'version': None,
'license': None
}
Expand All @@ -232,6 +243,7 @@ def _do_parse_descriptionfile(self, descriptionfilepath):
self.depends = PackInfo._clean_children(d['depends'])
self.imports = PackInfo._clean_children(d['imports'])
self.suggests = PackInfo._clean_children(d['suggests'])
self.linkingto = PackInfo._clean_children(d['linkingto'])
self.version = d['version']
self.license = d['license']
# compute the license-class
Expand Down
10 changes: 9 additions & 1 deletion rpackutils/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class DepTree(object):
# FUTURE: we could use multiple providers instead of a single one
# in order ot search across several repositories
def __init__(self, provider, lsargs=None, packinfoargs=None,
imports=True, depends=True, suggests=False):
imports=True, depends=True, suggests=False, linkingto=True):
"""
Traverse Imports and Depends to build the dependency graph
and ignores Suggests.
Expand All @@ -27,6 +27,7 @@ def __init__(self, provider, lsargs=None, packinfoargs=None,
:param imports: traverse imports
:param depends: traverse depends
:param suggests: traverse suggests
:param linkingto: traverse linkingto
"""
self._g = nx.Graph()
self.excludes = copy.deepcopy(RBasePackages.getnames())
Expand All @@ -38,6 +39,7 @@ def __init__(self, provider, lsargs=None, packinfoargs=None,
self.imports = imports
self.depends = depends
self.suggests = suggests
self.linkingto = linkingto

def build(self, packagenames=None):
"""
Expand Down Expand Up @@ -89,6 +91,12 @@ def _add_node(self, packagename):
continue
self._add_node(sug_name)
self._connect(packinfo.name, sug_name, "suggests")
if self.linkingto and packinfo.has_linkingto:
for lt_name in packinfo.linkingto:
if lt_name in self.excludes:
continue
self._add_node(lt_name)
self._connect(packinfo.name, lt_name, "linkingto")

def _add_to_graph(self, packinfo):
self._g.add_node(packinfo.name, **packinfo.as_dict)
Expand Down
26 changes: 26 additions & 0 deletions tests/resources/bindrcpp/DESCRIPTION
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Package: bindrcpp
Title: An 'Rcpp' Interface to Active Bindings
Version: 0.2.2.9000
Date: 2018-03-29
Authors@R: c(
person("Kirill", "M\u00fcller", role = c("aut", "cre"), email = "krlmlr+r@mailbox.org", comment = c(ORCID = "0000-0002-1416-3412")),
person("RStudio", role = "cph")
)
Description: Provides an easy way to fill an environment with active bindings
that call a C++ function.
License: MIT + file LICENSE
URL: https://github.com/krlmlr/bindrcpp, https://krlmlr.github.io/bindrcpp
BugReports: https://github.com/krlmlr/bindrcpp/issues
Imports:
bindr (>= 0.1.1),
Rcpp (>= 0.12.16)
Suggests:
testthat
LinkingTo:
plogr,
Rcpp
Encoding: UTF-8
LazyData: true
Roxygen: list(markdown = TRUE)
RoxygenNote: 6.0.1.9000

1 change: 1 addition & 0 deletions tests/test_artifactory.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def __init__(self, path):
self.repos = None
self.depends = None
self.imports = None
self.linkingto = None
self.suggests = None
self.license = None

Expand Down
1 change: 1 addition & 0 deletions tests/test_depsmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ def __init__(self, name, status):
self.repos = None
self.depends = None
self.imports = None
self.linkingto = None
self.suggests = None
self.license = None
self.packagepath = None
Expand Down
15 changes: 15 additions & 0 deletions tests/test_packinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,18 @@ def test__parse_license():
assert(pi.suggests == ['Rtoto', 'Rtiti', 'Rtata'])
assert(pi.license == 'AGPL-3 | file LICENSE')
assert(pi.installationisallowed is False)


def test__parse_linkingto():
path = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
'resources',
'bindrcpp')
pi = PackInfo(path)
print(pi.as_dict)
assert(pi.name == 'bindrcpp')
assert(pi.version == '0.2.2.9000')
assert(pi.imports == ['bindr', 'Rcpp'])
assert(pi.suggests == ['testthat'])
assert(pi.linkingto == ['plogr', 'Rcpp'])
assert(pi.license == 'MIT + file LICENSE')

0 comments on commit 19a1996

Please sign in to comment.