Skip to content

feat(generate-recipe): close remaining gaps in R recipe generation #2563

Description

@pb01ka

I may have made mistakes in my research - please correct me if anything below is wrong or incomplete.

Background

rattler-build generate-recipe is the only R recipe generator in the conda ecosystem that works today, targets the v1 recipe.yaml format, and uses a reliable data source. The two alternatives have both effectively stalled:

Quoting the correction,

Yes, that's a misinterpretation. 99.9% of R packages are in CRAN so R packages in github is a niche problem. conda skeleton cran is still the best way to generate R recipes.

  • grayskull - active, unresolved CRAN bugs (#616, #615). AFAIK, it generates v0 meta.yaml by default; an extra conda-recipe-manager conversion step is required for v1 output. Scrapes CRAN DESCRIPTION files directly - fragile and CRAN-only. (#532)
  • conda_r_skeleton_helper (bgruening) - a post-processor only; calls conda skeleton cran internally and inherits all of its brokenness.

rattler-build generate-recipe already has the right foundations:

  • Queries the R-universe JSON API - structured, reliable, and covers CRAN, Bioconductor, and GitHub-hosted R packages via --universe. (cran.rs:build_cran_recipe_and_deps())
  • Generates v1 recipe.yaml natively using ${{ }} Jinja syntax - the format conda-forge is migrating toward. (cran.rs:279-284)
  • Detects compilation requirements via the NeedsCompilation DESCRIPTION field and LinkingTo dependencies, and inserts C/C++ compilers automatically. (#2597)
  • Adds cross-r-base for cross-compilation support and sets rpaths for compiled packages. (#2597)
  • Marks pure-R packages as noarch: generic automatically. (#2597)
  • References r-base's bundled license texts via ${{ PREFIX }}/lib/R/share/licenses/ for standard SPDX licenses. (#2597)
  • Correctly pins r-base (with version constraint from Depends: R (>= x.y.z)) in both host and run. (#2597)
  • Passes ${R_ARGS} to R CMD INSTALL, matching the conda-forge convention for build-time flag injection. (#2597)
  • Written in Rust - fast, no subprocess calls, no arbitrary code execution.
  • Python bindings exposed via py-rattler-build (generate_cran_recipe(package, universe)). (recipe_generation.py:46)

Known gaps to address (As far as I could figure out - please correct me if I’m wrong or if there are others):

AFAICT, I have found no open issue currently tracks the following gaps.

Note: PR #2597 improved R recipe generation in several ways (cross-compilation, rpaths, noarch, license files, r-base pinning, R_ARGS) but did not address the two gaps below.

1. No conda-forge existence check for R dependencies

Impact: The generated recipe lists R dependencies by their CRAN name. If a dependency is not yet on conda-forge, the recipe will fail at solve time with no clear diagnostic.

Current behavior: cran.rs collects a remaining_deps HashSet for Imports, Depends, and LinkingTo packages but never uses it to check conda-forge availability - the set is silently dropped after dependency processing. The --tree flag only checks whether a local folder already exists, not whether the package is available on conda-forge.

Contrast with PyPI generator: pypi.rs fetches a live conda-forge name mapping from regro/cf-graph-countyfair at runtime (pypi.rs:225-228) and uses it to resolve PyPI -> conda-forge names. No equivalent exists for CRAN.

2. Suggests dependencies are commented out rather than conditionally handled

Impact: CRAN Suggests are optional test/example dependencies. The current output comments them out entirely (as # - r-foo # suggested inline in the run: block), losing structural information that downstream packagers or automated tools may need. A better default would be to emit them in a clearly marked optional section (e.g. under a run_constrained: block or a dedicated labelled comment block) so packagers know they exist and can make an informed choice.

Note: PR #2597 did not change this behavior - Suggests remain inline commented-out entries in the run: block.

TODO

Why invest here

rattler-build generate-recipe is the best option (AFAICT) for R recipe generator that is both working and targeting the right output format. The gaps above are bounded and well-understood. Closing them would make the tool production-ready for conda-forge R packaging workflows, without the dependency on conda skeleton or the CRAN scraper in grayskull.

I would re-iterate that I might have made incorrect claims. Please feel free to point out my incorrect claims. I would update the content of my issue as per the incoming feedback/comments. Thank you so much for reading till here. <3.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions