crane icon indicating copy to clipboard operation
crane copied to clipboard

Fixed-output derivation variant of `vendorCargoDeps`

Open simonzkl opened this issue 8 months ago • 2 comments

Is your feature request related to a problem? Please describe. When src is a derivation, it's not possible to evaluate the package derivation without triggering IFD. This is because vendorCargoDeps parses Cargo.lock at evaluation time. When there's many remote crane packages, the evaluation grinds to a halt.

Describe the solution you'd like It would be nice if vendorCargoDeps (or a variant of it) was able to vendor dependencies by parsing Cargo.lock at build time. This would of course turn the vendor derivation into a fixed-output derivation (FOD), which would require maintianing an output hash. But this is alright in some circumstances (e.g. a centralized packate reporistory where updates are automated).

Describe alternatives you've considered There's nixpkgs's fetchCargoVendor which is a fixed-output derivation, however it doesn't support custom registries like crane does. If crane is not interested in filling this niche, maybe extending fetchCargoVendor would make more sense.

simonzkl avatar Apr 20 '25 11:04 simonzkl

Hi @simonzkl thanks for the report! Even if nixpkgs's fetchCargoVendor does end up supporting custom registries, it would still be useful to have our own equivalent, namely that can reuse all the existing plumbing for configuring custom registries so it doesn't have to be done again, so definitely open to reviewing a PR for such an addition!

I think it would be fine to introduce a new/separate vendor variant that operates as a fixed-output derivation. That way we can solve for having a nice/focused API without trying to shoe-horn it into the existing knobs for vendorCargoDeps (if it turns out there's a nice way to unify the two we can always do that later on)

ipetkov avatar Apr 22 '25 01:04 ipetkov

For now I just ended up wrapping cargo vendor with a FOD like this:

stdenvNoCC.mkDerivation {
  inherit name src;

  strictDeps = true;
  impureEnvVars = lib.fetchers.proxyImpureEnvVars ++ [ "SOME_AUTH_VAR" ];
  nativeBuildInputs = [ toolchain cacert ];

  buildPhase = ''
    # ... Use SOME_AUTH_VAR to authenticate with my private cargo registry

    cd $src
    mkdir -p $out/.cargo
    cargo vendor --locked $out | tee $out/.cargo/config.toml
    sed -i 's|directory = "[^"]*"|directory = "@vendor@"|' $out/.cargo/config.toml
    cp Cargo.lock $out
  '';

  dontUnpack = true;
  dontConfigure = true;
  dontInstall = true;
  dontFixup = true;

  outputHash = hash;
  outputHashAlgo = if hash == "" then "sha256" else null;
  outputHashMode = "recursive";
}

This was for nixpkgs.rustPlatform.buildRustPackage cargoDeps though, but I imagine you could do something very similar for crane.

I'm just not sure about the output hash guarantees of this approach. It might need to depend on the cargo resolver version or something, which you can't really know until fetching src. However you could probably version the vendoring function and validate that it matches the expected resolver version at project build time. But maybe the output hash could also be broken by cargo updates, I don't really know.

simonzkl avatar Apr 27 '25 18:04 simonzkl