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

Crystal package builder #67510

Merged
merged 6 commits into from Aug 29, 2019
Merged

Crystal package builder #67510

merged 6 commits into from Aug 29, 2019

Conversation

infinisil
Copy link
Member

Motivation for this change

I'll be trying to package invidious soon, which uses crystal, so I thought why not first upgrade the crystal infrastructure in nixpkgs a bit.

I put the buildCrystalPackage function inside the compiler attributes such that you can select a version with e.g. pkgs.crystal_0_29.buildCrystalPackage, which is very simple.

I recommend viewing each commit separately

Ping @manveru @david50407 @peterhoeg

Things done
  • Built and tested all of the two crystal packages (the new crystal2nix and mint)
  • Ensured that relevant documentation is up to date. I don't really feel like writing docs right now


defaultOptions = [ "--release" "--progress" "--no-debug" "--verbose" ];

in stdenv.mkDerivation (mkDerivationArgs // {
Copy link
Contributor

Choose a reason for hiding this comment

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

Wouldn't it be nicer to allow overriding of all attributes by inverting the merge order?

Copy link
Member Author

Choose a reason for hiding this comment

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

@manveru For all attributes I'm setting in the derivation, I'm also propagating the ones from args (if any). This order is needed because otherwise e.g. the users buildInputs would override our changed buildInputs which contains crystal.

runHook postInstall
'';

meta = args.meta or {} // {
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure why the {} // is needed here.

Copy link
Member Author

Choose a reason for hiding this comment

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

It's parsed as (args.meta or {}) // { ... }, so this prevents it from failing when args doesn't have meta

runHook postConfigure
'';

buildInputs = args.buildInputs or [] ++ [ crystal ];
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the [] ++ needed here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah same reason, in case args doesn't have buildInputs set

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, I was reading the precedence wrong... really would prefer parenthesis in this case :)

@peterhoeg
Copy link
Member

We definitely need this! Any reason for building using crystal instead of shards?

@infinisil
Copy link
Member Author

@peterhoeg I have zero experience with both crystal and shards, I just followed what the mint derivation was doing. Maybe crystal is preferable here because it also allows the compilation of the single crystal2nix.cr file, whereas shards I'd think would need a shard.yaml file.

shards seems to automatically know what file to build though, so maybe that would be nice to support too (in the future?).

@infinisil
Copy link
Member Author

I pushed a minor mint change for removing all buildInputs except openssl, because the others didn't end up being needed

I also added a commit for adding a Crystal section to the nixpkgs docs

Copy link
Contributor

@jonringer jonringer left a comment

Choose a reason for hiding this comment

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

nix-review passes on NixOS
diff LGTM (But im also very unfamiliar with crystal, and it should probably be tested by building a crystal package)
has documentation 👍
executables still seem to work

[4 built, 33 copied (1293.6 MiB), 223.0 MiB DL]
https://github.com/NixOS/nixpkgs/pull/67510
2 package were build:
crystal2nix mint

@peterhoeg
Copy link
Member

whereas shards I'd think would need a shard.yaml file

When you do crystal init app foo, it will create a shard.yml file with (amongst other things), this:

targets:
  foo:
    main: src/foo.cr

Which is enough for you to build with shards build.

Except for crystal2nix.cr, I don't think anybody invokes the crystal compiler directly.

@infinisil infinisil mentioned this pull request Aug 29, 2019
2 tasks
@infinisil
Copy link
Member Author

@peterhoeg Since we need this functionality anyways for crystal2nix, I'd say let's just leave it at this for now. Adding a way of using shards to build packages is probably not worth it right now because there's almost no crystal packages, can always be added later though.

@infinisil
Copy link
Member Author

Just added a commit to switch crystal to openssl_1_0_2 which makes crystal play work.

@peterhoeg
Copy link
Member

I'd say let's just leave it at this for now.

Fair enough. It's definite improvement on the existing situation. lgtm when the darwin test passes.

@infinisil infinisil merged commit bfb06ec into NixOS:master Aug 29, 2019
@infinisil infinisil deleted the crystal-infra branch August 29, 2019 22:06
@bcardiff
Copy link
Contributor

bcardiff commented Jul 8, 2020

Hey, I wonder if there is a way to avoid needing crystal2nix. I would prefer if there story of someone using crystal on nix would not be that different from crystal on other platform.

When installing crystal dependencies described in a shard.yml a shard.lock is generated. That will have for example the git tag or the commit ref if the dependency was a branch.

When installing crystal dependencies with a shard.lock present that will be used. Nothing novel. I know that if the tag of a dependency is removed/changed the lock will be useless for reproducing.

If shards would include always the git commit in the lock file and install from it, would that be enough to avoid needing crystal2nix? Or what else would be needed?

@jonringer
Copy link
Contributor

using a lock file to pull in dependencies is something that's already done with rust and go packages. All it takes is someone implementing it.

@bcardiff
Copy link
Contributor

bcardiff commented Jul 8, 2020

Are there any requirements for those lock files to be enough for Nix? Eg: always include the explicit commit ref instead of tag.

@jonringer
Copy link
Contributor

generally there's some pull step in-which the dependencies defined in the lock file have to manifest themselves as a derivation which then can be consumed downstream.

For go, this is looking at the go.mod file, pulling all the related dependencies, then passing that to the actual build.

@infinisil
Copy link
Member Author

infinisil commented Jul 8, 2020

@bcardiff Almost transparent Nix support is possible with the following:

  • The lock file format needs to be parseable with Nix. While custom parsers can be written, this is difficult and error-prone as Nix isn't made for parsing, there are also no parsing libraries. So ideally a builtin parser should be usable, which are currently only builtins.fromJSON and builtins.fromTOML. So the lock file being JSON or TOML would be best and fastest.
  • The lock file needs to include content hashes for all dependencies. This is a bit of a problem though, because a lot of tarballs (e.g. the ones GitHub produces) change over time, which is why in Nix uses the hash of the unpacked directory (see here) instead. We can't hash directories though, so Nix actually first packs the directory into a deterministic NAR (Nix ARchive) format, from which it can compute and check the hash. So for hashes in a lock file to be usable by Nix, they need to be hashes over the NAR format. Since crystal probably shouldn't depend on Nix to compute these hashes, the NAR format could be implemented in crystal instead. Here is the reference implementation in Nix's source. Consequently, the hashes should then be under a narHash field in the lock file.
  • The format of the hashes is ideally SRI, which Nix recently gained support for.

The only project I know of that has transparent Nix support is poetry using poetry2nix which only exposes a set of Nix functions for building poetry projects without any code generation necessary. This is also what allows poetry2nix to be used in nixpkgs by just checking in the project and lock file. For poetry I believe they don't need to mess with NAR hashes because all dependencies are downloaded from pypi's servers, which probably don't ever update tarballs (unlike e.g. GitHub).

Pinging @adisbladis as poetry2nix author, and who pushed poetry towards making their lock files Nix compatible.

@peterhoeg
Copy link
Member

@manveru is already working on this ref #89863 (comment)

@infinisil
Copy link
Member Author

@manveru I think your lock file transformer function wouldn't work for nixpkgs because of builtins.fetchGit, which does eval time fetching and would therefore slow down hydras evaluation.

And ideally we wouldn't have to do IFD or code generation also (which is the case with poetry2nix). IFD is no good for nixpkgs and code generation is more maintenance.

With the points I mentioned above both of these problems wouldn't be there.

@infinisil
Copy link
Member Author

Oh actually poetry2nix used builtins.fetchGit too, is that not a problem for nixpkgs? If it's really not then I guess that could be used, and the NAR hashing wouldn't be necessary.

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.

None yet

5 participants