Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(rust): implement crane builder #83

Merged
merged 26 commits into from
Feb 28, 2022

Conversation

yusdacra
Copy link
Member

@yusdacra yusdacra commented Feb 13, 2022

This PR adds a crane builder. Crane builds a dependencies only derivation first, and then the actual crate. For this reason, I have made the deps only derivation use ${pname}-deps as override name and the actual crate just uses pname like normal.

@yusdacra yusdacra force-pushed the rust/crane-builder branch 3 times, most recently from ac8cee2 to 1c4b8aa Compare February 13, 2022 19:29
@yusdacra yusdacra marked this pull request as ready for review February 13, 2022 21:03
@yusdacra yusdacra force-pushed the rust/crane-builder branch 3 times, most recently from d1572ee to 1a73712 Compare February 15, 2022 19:36
flake.nix Outdated Show resolved Hide resolved
@@ -21,8 +21,10 @@
};

rust = rec {
default = buildRustPackage;
default = crane;
Copy link
Member Author

Choose a reason for hiding this comment

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

Should the default be made crane?

Copy link
Member

Choose a reason for hiding this comment

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

I leave that decision up to you.

Copy link
Member Author

Choose a reason for hiding this comment

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

I made it the default builder since it allows for more caching than buildRustPackage. It should be a sane default if we fix the IFD woes. It also seemed much simpler to me than how buildRustPackage reads / works, so I think it would be more easy to override.

src/default.nix Outdated
@@ -238,6 +298,7 @@ let
# build a dream lock via a specific builder
callBuilder =
{
source,
Copy link
Member Author

Choose a reason for hiding this comment

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

This is needed to pass the original source the user passed to riseAndShine so that it can be used in the crane builder, because crane expects a Cargo.lock and a Cargo.toml for a builds only dep, which will only be available at workspace root for workspaces. dream2nix dependency sources won't have this information if it's a workspace, of course.

Maybe the name could be changed to something else though?

Copy link
Member

Choose a reason for hiding this comment

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

Hm, but this will only be available if riseAndShine is called with a source tree as source. But it must also work if a dream-lock.json is passed as source. Therefore all necessary information for building must be in the dream-lock.

Actually since the dream-lock now supports more than one top-level package, we need to extend the path source type with a field that points to the root package source it resides in.
We could add for example a field named root pointing to a package name from .generic.packages.
Then we could add a builder function getSourceRoot or something like that.

What do you think?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, it is kind of hacky right now. It does try to handle it if it's a dream-lock but it's not good with that.

A getSourceRoot function that I would need should essentially just "resolve" path dependencies to their root, so without the relative path prepended. Everything else is a "root" on their own, so they don't matter.

Copy link
Member

@DavHau DavHau Feb 17, 2022

Choose a reason for hiding this comment

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

Would the getSourceRoot function even be sufficient for this? Or would there still be the problem that we don't know the exact location of the toml file and have to search for it again?

Another potential problem: Does crane read the cargo toml/lock during eval time?
If we build from dream-lock, then reading contents of files within the source would require IFD, because the source has to be fetched first, for evaluation to continue. We should prevent that.

In case we really need the Cargo.toml content during eval time, we can embed the toml content inside subsystemAttrs and then pass it to the builder. Not nice, but the architecture would be fine with it.

Copy link
Member Author

Choose a reason for hiding this comment

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

getSourceRoot should be enough, it will always contain a Cargo.lock. For path dependencies this means a workspace, for others they are either fetched from crates-io which will always have a Cargo.lock or they are fetched from github / gitlab but aren't a workspace.

IIRC the only place crane does read the Cargo.toml is for the cleanCargoToml function which is called when building the dummy source. I believe that could be moved to the dummy source derivation itself, can make an issue for it on the crane repo. I think it also does IFD while generating some dummy source files. It would be appreciated if you could check lib/mkDummySource.nix and lib/cleanCargoToml.nix on crane repo for IFDs.

Copy link
Member

Choose a reason for hiding this comment

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

To be honest I think I would prefer the custom solution. Part of the idea behind dream2nix was to go away from the monolithic lock-file -> nix derivations model which most other 2nix tools use, and instead separate the process in distinct phases (translation, fetching, building), so we can have generic (user) interfaces for all of these phases.

I'm worried now that if we circumvent that model and allow exceptions, that later we might run into trouble keeping our interfaces uniform and shift more complexity to the end user.
But also I'm currently unable to come up with a good example that underlines this point.

So maybe we should just go ahead and merge this if you think this already adds value to the project. I leave the decision up to you.

If we decide to keep this, then we should at least remove the source attribute being passed to the builder and add the getSourceRoot function we talked about.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure if I want to merge it since unlike buildRustPackage it doesn't use env variables in it's build / check / install phases which makes it hard to override those phases or some other stuff. buildRustPackage is fine for now IMO, until a granular builder lands.

I'll still keep the branch around though, in case someone has a better idea on how to do all this.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think we can still merge it though, I feel it would be better if people saw something like this is actually implemented, some people might still want a deps only drv for better caching.

I can add a warning that this requires IFD, and not make it the default builder. And also introduce getSourceRoot. How does that sound?

Copy link
Member

Choose a reason for hiding this comment

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

Sounds great! Let's do it.

Copy link
Member Author

Choose a reason for hiding this comment

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

I implemented what you said on the matrix room, and it seems to be working fine now! Both buildRustPackage and crane builder seem to be able to build things fine. buildRustPackage is still the default. I added a comment in src/builders/default.nix for crane that says it requires IFD. Should be ready to go now!

Copy link
Member

@DavHau DavHau left a comment

Choose a reason for hiding this comment

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

Thanks, please see comments below.

flake.nix Outdated Show resolved Hide resolved
@@ -21,8 +21,10 @@
};

rust = rec {
default = buildRustPackage;
default = crane;
Copy link
Member

Choose a reason for hiding this comment

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

I leave that decision up to you.

src/default.nix Show resolved Hide resolved
src/default.nix Outdated
@@ -238,6 +298,7 @@ let
# build a dream lock via a specific builder
callBuilder =
{
source,
Copy link
Member

Choose a reason for hiding this comment

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

Hm, but this will only be available if riseAndShine is called with a source tree as source. But it must also work if a dream-lock.json is passed as source. Therefore all necessary information for building must be in the dream-lock.

Actually since the dream-lock now supports more than one top-level package, we need to extend the path source type with a field that points to the root package source it resides in.
We could add for example a field named root pointing to a package name from .generic.packages.
Then we could add a builder function getSourceRoot or something like that.

What do you think?

…changes by upstream crane, share some stuff between deps - main drv
fix: remove source arg

fix: remove more source args

fix(rust/crane): remove unused logic

temp
@DavHau DavHau merged commit 4656834 into nix-community:main Feb 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants