Skip to content

Conversation

@Flamefire
Copy link
Contributor

Resolve backreferences like authors.workspace = true

https://doc.rust-lang.org/cargo/reference/workspaces.html#the-package-table
For ruff-0.14.3 the salsa crate is using the [workspace.package] section where one can define values that can be inherited by members

So the members Cargo.toml file contains e.g.

[package]
name = "bar"
version.workspace = true
authors.workspace = true
description.workspace = true
documentation.workspace = true
[dependencies]
            leptos = { version = "0.6", features = ["csr"] }

For the offline builds we need to copy the members to standalone packages which has the side-effect that no "workspace" exists anymore causing cargo to fail with

  error: failed to get `anyhow` as a dependency of package `ruff v0.14.3 (/dev/shm/ruff/0.14.3/GCCcore-14.3.0/ruff-0.14.3/crates/ruff)`
  Caused by:
    failed to load source for dependency `anyhow`
  Caused by:
    Unable to update registry `crates-io`
  Caused by:
    failed to update replaced source registry `crates-io`
  Caused by:
    failed to parse manifest at `/dev/shm/ruff/0.14.3/GCCcore-14.3.0/easybuild_vendor/salsa-macros/Cargo.toml`
  Caused by:
    error inheriting `edition` from workspace root manifest's `workspace.package.edition`
  Caused by:
    failed to find a workspace root

Checking cargo vendor output: It replaces version.workspace = true by version = "1.2.3"

Hence we need to parse both TOML files, "merge" them to replace those references and write the result to the member Cargo.toml

For that I enhanced the minimal TOML parser I implemented for the "members" key to create a dict[str, dict[str, str]] with sections as outer keys, keys as inner keys mapping the 1:1 copy of the value. I.e. I don't parse the value at all besides trying to find the end: TOML values support lists, strings (single & double quotes), multiline strings (triple quotes), bools, numbers

The above example results in Python:

{
            'package': {
                "name": '"bar"',
                "version.workspace": 'true',
                "authors.workspace": 'true',
                "description.workspace": 'true',
                "documentation.workspace": 'true',
            },
            'dependencies': {
                "leptos": '{ version = "0.6", features = ["csr"] }',
            },
}

This works because we only need to copy the value 1:1 to the member file but doesn't support everything:

[workspace.dependencies]
cc = "1.0.73"
rand = "0.8.5"
regex = { version = "1.6.0", default-features = false, features = ["std"] }

Member:

[dependencies]
regex = { workspace = true, features = ["unicode"] }

would require merging the mappings, i.e. dict.update() in Python instead of a simple replacement.

But for that we likely need a proper TOML parser:

  • Python 3.11 has tomllib
  • There is a 2020 toml package on PYPI
  • A recent tomli package on PYPI
  • PIP 21.2+ vendors tomli so we could import pip._vendor.tomli

So my idea would be to try importing tomllib, tomli, import pip._vendor.tomli, toml in this order if the previous ones failed and error out if none are available

Or we stick with the minimal parser and extend if only necessary: YAGNI

Loosely parse everything that could be in a Cargo.toml file
Allow reusing the parsed result.
When there is a line
> key = """

the value starts and ends with the delimitter wrongly terminating the
value parser.
Check that there is anything else first.
'#'-signs can be embedded in strings
Resolve backreferences like `authors.workspace = true`
We use the line number only outside the loop which triggers
> Loop control variable 'num' not used within the loop body. If this is intended, start the name with an underscore.
@Flamefire Flamefire force-pushed the cargo_inherit_workspace branch from c5ac95a to 50602d7 Compare November 13, 2025 09:55
@Flamefire
Copy link
Contributor Author

Test report by @Flamefire

Overview of tested easyconfigs (in order)

  • SUCCESS alevin-fry-0.9.0-GCCcore-13.2.0.eb

  • SUCCESS bamtofastq-1.4.1-GCCcore-12.3.0.eb

  • SUCCESS bcrypt-4.0.1-GCCcore-12.3.0.eb

  • SUCCESS bcrypt-4.1.3-GCCcore-13.2.0.eb

  • SUCCESS bcrypt-4.3.0-GCCcore-13.3.0.eb

  • SUCCESS bcrypt-4.3.0-GCCcore-14.2.0.eb

  • SUCCESS bcrypt-4.3.0-GCCcore-14.3.0.eb

  • SUCCESS cargo-c-0.10.15-GCCcore-14.3.0.eb

  • SUCCESS cargo-c-0.9.32-GCCcore-13.3.0.eb

  • SUCCESS chopper-0.9.0-GCCcore-12.3.0.eb

  • SUCCESS Clarabel.rs-0.7.1-gfbf-2023a.eb

  • SUCCESS clearml-1.16.5-foss-2023b.eb

  • SUCCESS cramino-0.14.5-GCC-12.3.0.eb

  • SUCCESS cramjam-2.9.0-GCCcore-12.3.0.eb

  • SUCCESS cryptography-41.0.1-GCCcore-12.3.0.eb

  • SUCCESS cryptography-41.0.5-GCCcore-13.2.0.eb

  • SUCCESS cryptography-42.0.8-GCCcore-13.3.0.eb

  • SUCCESS cryptography-44.0.2-GCCcore-14.2.0.eb

  • SUCCESS cryptography-45.0.5-GCCcore-14.3.0.eb

  • SUCCESS DeltaLake-0.15.1-gfbf-2023a.eb

  • SUCCESS DeltaLake-0.25.5-gfbf-2023b.eb

  • SUCCESS DeltaLake-0.25.5-gfbf-2024a.eb

  • SUCCESS elfx86exts-0.6.2-GCC-12.3.0.eb

  • SUCCESS Evcxr-REPL-0.14.2-GCCcore-12.2.0-Rust-1.65.0.eb

  • SUCCESS fastparquet-2023.4.0-gfbf-2022b.eb

  • SUCCESS HERRO-0.1.0_20240808-foss-2023a.eb

  • SUCCESS huggingface_hub-0.34.4-GCCcore-13.3.0.eb

  • SUCCESS jiter-0.4.1-GCCcore-12.3.0.eb

  • SUCCESS juliaup-1.17.9-GCCcore-12.3.0.eb

  • SUCCESS jupyter-collaboration-2.1.1-GCCcore-13.2.0.eb

  • SUCCESS jupyter-server-2.14.0-GCCcore-13.2.0.eb

  • SUCCESS jupyter-server-2.14.2-GCCcore-13.3.0.eb

  • SUCCESS jupyter-server-2.16.0-GCCcore-14.2.0.eb

  • SUCCESS jupyter-server-2.17.0-GCCcore-14.3.0.eb

  • SUCCESS jupyter-server-2.7.2-GCCcore-12.3.0.eb

  • SUCCESS JupyterLab-4.0.3-GCCcore-12.2.0.eb

  • SUCCESS kyber-0.4.0-GCC-12.3.0.eb

  • SUCCESS lazrs-0.7.0-GCCcore-14.2.0.eb

  • SUCCESS Longshot-0.4.5-GCCcore-11.3.0.eb

  • SUCCESS Longshot-1.0.0-GCCcore-12.3.0.eb

  • SUCCESS Longshot-1.0.0-GCCcore-13.2.0.eb

  • SUCCESS maturin-1.1.0-GCCcore-12.2.0.eb

  • SUCCESS maturin-1.1.0-GCCcore-12.3.0.eb

  • SUCCESS maturin-1.3.1-GCCcore-13.2.0.eb

  • SUCCESS maturin-1.3.2-GCCcore-11.3.0-Rust-1.65.0.eb

  • SUCCESS maturin-1.4.0-GCCcore-12.2.0-Rust-1.75.0.eb

  • SUCCESS maturin-1.4.0-GCCcore-12.3.0-Rust-1.75.0.eb

  • SUCCESS maturin-1.5.0-GCCcore-13.2.0-Rust-1.76.0.eb

  • SUCCESS maturin-1.6.0-GCCcore-13.3.0.eb

  • SUCCESS maturin-1.7.8-GCCcore-12.3.0-Rust-1.81.0.eb

  • SUCCESS maturin-1.8.3-GCCcore-13.3.0-Rust-1.83.0.eb

  • SUCCESS maturin-1.8.3-GCCcore-14.2.0.eb

  • SUCCESS maturin-1.9.1-GCCcore-14.3.0.eb

  • SUCCESS mfqe-0.5.0-GCC-12.3.0.eb

  • SUCCESS modkit-0.3.3-GCCcore-12.3.0.eb

  • SUCCESS modkit-0.4.1-GCCcore-13.3.0.eb

  • SUCCESS modkit-0.5.0-GCCcore-13.3.0.eb

  • SUCCESS orjson-3.9.15-GCCcore-12.3.0.eb

  • SUCCESS phasius-0.2.0-GCC-12.3.0.eb

  • SUCCESS poetry-1.7.1-GCCcore-12.3.0.eb

  • SUCCESS poetry-1.7.1-GCCcore-13.2.0.eb

  • SUCCESS poetry-1.8.3-GCCcore-13.3.0.eb

  • SUCCESS poetry-2.1.2-GCCcore-14.2.0.eb

  • SUCCESS poetry-2.1.3-GCCcore-14.3.0.eb

  • SUCCESS polars-0.19.19-gfbf-2023a.eb

  • SUCCESS polars-0.20.2-gfbf-2023a.eb

  • FAIL polars-1.28.1-gfbf-2023b.eb (build issue)
    (partial log available at https://gist.github.com/Flamefire/becb7d61836a3ca4535949ac5bacc7c0)

  • SUCCESS polars-1.28.1-gfbf-2024a.eb

  • SUCCESS pybigtools-0.1.2-gfbf-2023a.eb

  • SUCCESS pydantic-2.11.7-GCCcore-14.2.0.eb

  • FAIL pydantic-2.5.3-GCCcore-12.2.0.eb (build issue)
    (partial log available at https://gist.github.com/Flamefire/80828e5d7fa1357800219ef9a736f2f0)

  • SUCCESS pydantic-2.5.3-GCCcore-12.3.0.eb

  • SUCCESS pydantic-2.6.4-GCCcore-13.2.0.eb

  • SUCCESS pydantic-2.7.4-GCCcore-13.2.0.eb

  • SUCCESS pydantic-2.9.1-GCCcore-13.3.0.eb

  • SUCCESS pymatgen-2023.12.18-foss-2023a.eb

  • SUCCESS Python-bundle-PyPI-2024.06-GCCcore-13.3.0.eb

  • SUCCESS Python-bundle-PyPI-2025.04-GCCcore-14.2.0.eb

  • SUCCESS Python-bundle-PyPI-2025.07-GCCcore-14.3.0.eb

  • SUCCESS RDP-0.13.5-GCCcore-13.3.0.eb

  • FAIL ripunzip-0.4.0.eb (build issue)
    (partial log available at https://gist.github.com/Flamefire/237147815197ed1e6eba67c305ad7ef7)

  • SUCCESS rustworkx-0.12.1-foss-2022a.eb

  • SUCCESS rustworkx-0.12.1-foss-2023a.eb

  • SUCCESS rustworkx-0.15.1-gfbf-2023a.eb

  • SUCCESS rustworkx-0.16.0-gfbf-2024a.eb

  • FAIL Safetensors-0.3.1-foss-2022a.eb (build issue)
    (partial log available at https://gist.github.com/Flamefire/91f2ff9e2e623519d311f4b8ce997ac2)

  • FAIL Safetensors-0.4.3-gfbf-2022b.eb (build issue)
    (partial log available at https://gist.github.com/Flamefire/c5aa4f1069c2504c6cef7ad454e39309)

  • SUCCESS Safetensors-0.4.3-gfbf-2023a.eb

  • SUCCESS Safetensors-0.4.4-gfbf-2023b.eb

  • SUCCESS Safetensors-0.6.2-gfbf-2024a.eb

  • SUCCESS scatac_fragment_tools-0.1.0-foss-2023a.eb

  • SUCCESS SKA2-0.3.7-GCCcore-12.2.0.eb

  • SUCCESS skani-0.2.2-GCCcore-12.3.0.eb

  • SUCCESS smafa-0.8.0-GCC-12.3.0.eb

  • FAIL SnapATAC2-2.9.0-dev0-20250630-foss-2024a.eb (build issue)
    (partial log available at https://gist.github.com/Flamefire/1ff346bf43118158418eee7978835416)

  • SUCCESS Spyder-6.0.1-GCCcore-13.2.0.eb

  • SUCCESS subset-bam-1.1.0-GCCcore-10.3.0.eb

  • SUCCESS tiktoken-0.6.0-GCCcore-12.3.0.eb

  • SUCCESS tiktoken-0.7.0-GCCcore-12.3.0.eb

  • SUCCESS tiktoken-0.7.0-GCCcore-13.2.0.eb

  • SUCCESS tiktoken-0.9.0-GCCcore-13.3.0.eb

  • SUCCESS timm-0.6.13-foss-2022a-CUDA-11.7.0.eb

  • FAIL timm-0.9.7-foss-2022a-CUDA-11.7.0.eb (build issue)
    (partial log available at https://gist.github.com/Flamefire/8eeb99959cb9fbe7fc0c486b9b35608e)

  • SUCCESS tlparse-0.3.37-GCCcore-13.3.0.eb

  • SUCCESS tlparse-0.3.5-GCCcore-13.2.0.eb

  • SUCCESS tokenizers-0.13.3-GCCcore-11.3.0.eb

  • SUCCESS tokenizers-0.13.3-GCCcore-12.2.0.eb

  • SUCCESS tokenizers-0.15.2-GCCcore-12.3.0.eb

  • SUCCESS tokenizers-0.19.1-GCCcore-13.2.0.eb

  • SUCCESS tokenizers-0.21.4-GCCcore-13.3.0.eb

  • SUCCESS torch-em-0.7.1-foss-2023a.eb

  • SUCCESS tree-sitter-0.25.3-GCCcore-14.2.0.eb

  • SUCCESS uv-0.2.30-GCCcore-13.3.0.eb

  • SUCCESS vLLM-0.4.0-foss-2023a-CUDA-12.1.1.eb

  • SUCCESS yacrd-1.0.0-foss-2023a.eb

Build succeeded for 108 out of 115 (total: 14 hours 23 mins 29 secs) (115 easyconfigs in total)
c9 - Linux Rocky Linux 9.6, x86_64, AMD EPYC 9334 32-Core Processor (zen4), 4 x NVIDIA NVIDIA H100, 580.65.06, Python 3.9.21
See https://gist.github.com/Flamefire/536cb0496b1c990fbacb6cb4238e179b for a full test report.

@Micket
Copy link
Contributor

Micket commented Nov 16, 2025

polars-1.28.1-gfbf-2023b.eb
ripunzip-0.4.0.eb
timm-0.9.7-foss-2022a-CUDA-11.7.0.eb
Safetensors-0.3.1-foss-2022a.eb
Safetensors-0.4.3-gfbf-2022b.eb

all fail from unrelated reasons, like missing dependencies that fail or were just missing or something.

SnapATAC2-2.9.0-dev0-20250630-foss-2024a.eb gets this

      Running `maturin pep517 build-wheel -i /software/genoa/r24.04/Python/3.12.3-GCCcore-13.3.0/bin/python --compatibility off`
      🍹 Building a mixed python/rust project
      🔗 Found pyo3 bindings
      🐍 Found CPython 3.12 at /software/genoa/r24.04/Python/3.12.3-GCCcore-13.3.0/bin/python
      📡 Using build options features from pyproject.toml
      error: rustc 1.86.0 is not supported by the following package:
        [email protected] requires rustc 1.88
      Either upgrade rustc or select compatible dependency versions with
      `cargo update <name>@<current-ver> --precise <compatible-ver>`
      where `<compatible-ver>` is the latest version supporting rustc 1.86.0

and I'm not sure how; we specify the vendord cargo packags to be home version 0.5.11, so I'm not sure how it's finding 0.5.12. I don't believe this is, or even could be caused by this. I would suspect the python/maturin or something is overriding the CARGO_OFFLINE that we have to protect against this, so I think the easyblock in this PR is fine, at least not introducing any of the issues here.

Micket
Micket previously approved these changes Nov 16, 2025
Copy link
Contributor

@Micket Micket left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

lots of code here, mostly the lack of a tomllib.

EB supporting really old pythons with no extra packages definitely is coming to bite us quite a bit.

@Flamefire
Copy link
Contributor Author

EB supporting really old pythons with no extra packages definitely is coming to bite us quite a bit.

Hence the question above if we want require at least some very basic ones. Even just pip seems to be fine here.

and I'm not sure how; we specify the vendord cargo packags to be home version 0.5.11, so I'm not sure how it's finding 0.5.12.

Hm, in the report I don't see a mention of unpacking crates. I'd better double check that they are actually used.

@Flamefire
Copy link
Contributor Author

Without the Cargo.Lock file and with offline = False in the easyconfig it uses the latest.

Removing offline = False causes new failures :

      Caused by:
        failed to load source for dependency `anndata`
      
      Caused by:
        Unable to update https://github.com/kaizhang/anndata-rs.git?rev=0d27ac475634ed7703ab1a23e01e6a3031a28541
      
      Caused by:
        the source https://github.com/kaizhang/anndata-rs.git?rev=0d27ac475634ed7703ab1a23e01e6a3031a28541 requires a lock file to be present first before it can be
        used against vendored source code

@Flamefire Flamefire force-pushed the cargo_inherit_workspace branch from fb80d38 to 18f8c2a Compare November 18, 2025 17:05
@boegel boegel added this to the next release (5.2.0) milestone Nov 19, 2025
@boegel boegel changed the title Implement merging Cargo.toml file with workspace file Implement merging Cargo.toml file with workspace file Nov 19, 2025
@Micket
Copy link
Contributor

Micket commented Nov 19, 2025

I'm unclear on the SnapATAC issue; was that present all along or somehow related to this easyblock change?
If you are done, I'm going to submit a bunch of tests in order to verify it works as is and merge this.

@Flamefire
Copy link
Contributor Author

I'm done here and working on supporting SnapATAC. The failure is not introduced by this change: SnapATAC used offline = False so all we do there is not done there. It now happens to fail because there are newer versions on crates.io now than at the time the EC was created.

However this highlights a larger issue we should make a decision about: When crates is set but offline=False (as in that case) then the crate sources will be unpacked but not used because we set the relevant cargo config entries only with offline = True and without that they are basically in a random folder.

We could:
a) Error out if offline and crates
b) Use print_warning when offline and crates
c) Only skip the $CARGO_NET_OFFLINE=true when offline and always do the modification to the cargo config. This may cause issues because we replaces crates.io with our vendored folder so I guess it won't be able to download other sources from crates.io making offline = False only affect e.g. git repos.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants