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
Crystal package builder #67510
Changes from 5 commits
8c60f67
a3aec20
1ffdf01
2f92cd6
1d07491
7f6a9ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# Crystal | ||
|
||
## Building a Crystal package | ||
|
||
This section uses [Mint](https://github.com/mint-lang/mint) as an example for how to build a Crystal package. | ||
|
||
If the Crystal project has any dependencies, the first step is to get a `shards.nix` file encoding those. Get a copy of the project and go to its root directory such that its `shard.lock` file is in the current directory, then run `crystal2nix` in it | ||
```bash | ||
$ git clone https://github.com/mint-lang/mint | ||
$ cd mint | ||
$ git checkout 0.5.0 | ||
$ nix-shell -p crystal2nix --run crystal2nix | ||
``` | ||
|
||
This should have generated a `shards.nix` file. | ||
|
||
Next create a Nix file for your derivation and use `pkgs.crystal.buildCrystalPackage` as follows: | ||
```nix | ||
with import <nixpkgs> {}; | ||
crystal.buildCrystalPackage rec { | ||
pname = "mint"; | ||
version = "0.5.0"; | ||
|
||
src = fetchFromGitHub { | ||
owner = "mint-lang"; | ||
repo = "mint"; | ||
rev = version; | ||
sha256 = "0vxbx38c390rd2ysvbwgh89v2232sh5rbsp3nk9wzb70jybpslvl"; | ||
}; | ||
|
||
# Insert the path to your shards.nix file here | ||
shardsFile = ./shards.nix; | ||
|
||
... | ||
} | ||
``` | ||
|
||
This won't build anything yet, because we haven't told it what files build. We can specify a mapping from binary names to source files with the `crystalBinaries` attribute. The project's compilation instructions should show this. For Mint, the binary is called "mint", which is compiled from the source file `src/mint.cr`, so we'll specify this as follows: | ||
|
||
```nix | ||
crystalBinaries.mint.src = "src/mint.cr"; | ||
|
||
# ... | ||
``` | ||
|
||
Additionally you can override the default `crystal build` options (which are currently `--release --progress --no-debug --verbose`) with | ||
|
||
```nix | ||
crystalBinaries.mint.options = [ "--release" "--verbose" ]; | ||
``` | ||
|
||
Depending on the project, you might need additional steps to get it to compile successfully. In Mint's case, we need to link against openssl, so in the end the Nix file looks as follows: | ||
|
||
```nix | ||
with import <nixpkgs> {}; | ||
crystal.buildCrystalPackage rec { | ||
version = "0.5.0"; | ||
pname = "mint"; | ||
src = fetchFromGitHub { | ||
owner = "mint-lang"; | ||
repo = "mint"; | ||
rev = version; | ||
sha256 = "0vxbx38c390rd2ysvbwgh89v2232sh5rbsp3nk9wzb70jybpslvl"; | ||
}; | ||
|
||
shardsFile = ./shards.nix; | ||
crystalBinaries.mint.src = "src/mint.cr"; | ||
|
||
buildInputs = [ openssl_1_0_2 ]; | ||
} | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
{ stdenv, lib, crystal, linkFarm, fetchFromGitHub }: | ||
{ # Generate shards.nix with `nix-shell -p crystal2nix --run crystal2nix` in the projects root | ||
shardsFile ? null | ||
# Specify binaries to build in the form { foo.src = "src/foo.cr"; } | ||
# The default `crystal build` options can be overridden with { foo.options = [ "--no-debug" ]; } | ||
, crystalBinaries ? {} | ||
, ... | ||
}@args: | ||
let | ||
mkDerivationArgs = builtins.removeAttrs args [ "shardsFile" "crystalBinaries" ]; | ||
|
||
crystalLib = linkFarm "crystal-lib" (lib.mapAttrsToList (name: value: { | ||
inherit name; | ||
path = fetchFromGitHub value; | ||
}) (import shardsFile)); | ||
|
||
defaultOptions = [ "--release" "--progress" "--no-debug" "--verbose" ]; | ||
|
||
in stdenv.mkDerivation (mkDerivationArgs // { | ||
|
||
configurePhase = args.configurePhase or '' | ||
runHook preConfigure | ||
${lib.optionalString (shardsFile != null) "ln -s ${crystalLib} lib"} | ||
runHook postConfigure | ||
''; | ||
|
||
buildInputs = args.buildInputs or [] ++ [ crystal ]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah same reason, in case There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 :) |
||
|
||
buildPhase = args.buildPhase or '' | ||
runHook preBuild | ||
${lib.concatStringsSep "\n" (lib.mapAttrsToList (bin: attrs: '' | ||
crystal ${lib.escapeShellArgs ([ | ||
"build" | ||
"-o" bin | ||
(attrs.src or (throw "No source file for crystal binary ${bin} provided")) | ||
] ++ attrs.options or defaultOptions)} | ||
'') crystalBinaries)} | ||
runHook postBuild | ||
''; | ||
|
||
installPhase = args.installPhase or '' | ||
runHook preInstall | ||
mkdir -p "$out/bin" | ||
${lib.concatMapStringsSep "\n" (bin: '' | ||
mv ${lib.escapeShellArgs [ bin "${placeholder "out"}/bin/${bin}" ]} | ||
'') (lib.attrNames crystalBinaries)} | ||
runHook postInstall | ||
''; | ||
|
||
meta = args.meta or {} // { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure why the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's parsed as |
||
platforms = args.meta.platforms or crystal.meta.platforms; | ||
}; | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ lib, crystal, nix-prefetch-git }: | ||
crystal.buildCrystalPackage { | ||
pname = "crystal2nix"; | ||
version = "unstable-2018-07-31"; | ||
|
||
nixPrefetchGit = "${lib.getBin nix-prefetch-git}/bin/nix-prefetch-git"; | ||
unpackPhase = "substituteAll ${./crystal2nix.cr} crystal2nix.cr"; | ||
|
||
crystalBinaries.crystal2nix.src = "crystal2nix.cr"; | ||
|
||
meta = with lib; { | ||
description = "Utility to convert Crystal's shard.lock files to a Nix file"; | ||
license = licenses.mit; | ||
maintainers = [ maintainers.manveru ]; | ||
}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,64 +1,27 @@ | ||
# Updating the dependencies for this package: | ||
# | ||
# wget https://raw.githubusercontent.com/mint-lang/mint/0.3.1/shard.lock | ||
# nix-shell -p crystal libyaml --run 'crystal run crystal2nix.cr' | ||
# | ||
{stdenv, lib, fetchFromGitHub, crystal, zlib, openssl, duktape, which, libyaml }: | ||
let | ||
crystalPackages = lib.mapAttrs (name: src: | ||
stdenv.mkDerivation { | ||
name = lib.replaceStrings ["/"] ["-"] name; | ||
src = fetchFromGitHub src; | ||
phases = "installPhase"; | ||
installPhase = ''cp -r $src $out''; | ||
passthru = { libName = name; }; | ||
} | ||
) (import ./shards.nix); | ||
|
||
crystalLib = stdenv.mkDerivation { | ||
name = "crystal-lib"; | ||
src = lib.attrValues crystalPackages; | ||
libNames = lib.mapAttrsToList (k: v: [k v]) crystalPackages; | ||
phases = "buildPhase"; | ||
buildPhase = '' | ||
mkdir -p $out | ||
linkup () { | ||
while [ "$#" -gt 0 ]; do | ||
ln -s $2 $out/$1 | ||
shift; shift | ||
done | ||
} | ||
linkup $libNames | ||
''; | ||
}; | ||
in | ||
stdenv.mkDerivation rec { | ||
{ lib, fetchFromGitHub, crystal, zlib, openssl_1_0_2, duktape, which, libyaml }: | ||
crystal.buildCrystalPackage rec { | ||
version = "0.5.0"; | ||
name = "mint-${version}"; | ||
pname = "mint"; | ||
src = fetchFromGitHub { | ||
owner = "mint-lang"; | ||
repo = "mint"; | ||
rev = version; | ||
sha256 = "0vxbx38c390rd2ysvbwgh89v2232sh5rbsp3nk9wzb70jybpslvl"; | ||
}; | ||
|
||
nativeBuildInputs = [ which crystal zlib openssl duktape libyaml ]; | ||
|
||
buildPhase = '' | ||
mkdir -p $out/bin tmp | ||
cd tmp | ||
ln -s ${crystalLib} lib | ||
cp -r $src/* . | ||
crystal build src/mint.cr -o $out/bin/mint --verbose --progress --release --no-debug | ||
''; | ||
buildInputs = [ openssl_1_0_2 ]; | ||
|
||
installPhase = ''true''; | ||
# Update with | ||
# nix-shell -p crystal2nix --run crystal2nix | ||
# with mint's shard.lock file in the current directory | ||
shardsFile = ./shards.nix; | ||
crystalBinaries.mint.src = "src/mint.cr"; | ||
|
||
meta = { | ||
description = "A refreshing language for the front-end web"; | ||
homepage = https://mint-lang.com/; | ||
license = stdenv.lib.licenses.bsd3; | ||
maintainers = with stdenv.lib.maintainers; [ manveru ]; | ||
license = lib.licenses.bsd3; | ||
maintainers = with lib.maintainers; [ manveru ]; | ||
platforms = [ "x86_64-linux" "i686-linux" "x86_64-darwin" ]; | ||
}; | ||
} |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 usersbuildInputs
would override our changedbuildInputs
which contains crystal.