1
1
mirror of https://github.com/tweag/nickel.git synced 2024-10-04 07:07:10 +03:00
nickel/flake.nix
2022-03-06 22:27:57 +01:00

376 lines
12 KiB
Nix

{
inputs.nixpkgs.url = "nixpkgs/nixos-unstable";
inputs.flake-utils.url = "github:numtide/flake-utils";
inputs.pre-commit-hooks.url = "github:cachix/pre-commit-hooks.nix";
inputs.pre-commit-hooks.inputs.nixpkgs.follows = "nixpkgs";
inputs.pre-commit-hooks.inputs.flake-utils.follows = "flake-utils";
inputs.rust-overlay.url = "github:oxalica/rust-overlay";
inputs.rust-overlay.inputs.nixpkgs.follows = "nixpkgs";
inputs.rust-overlay.inputs.flake-utils.follows = "flake-utils";
inputs.import-cargo.url = "github:edolstra/import-cargo";
nixConfig = {
extra-substituters = [ "https://nickel.cachix.org" ];
extra-trusted-public-keys = [ "nickel.cachix.org-1:ABoCOGpTJbAum7U6c+04VbjvLxG9f0gJP5kYihRRdQs=" ];
};
outputs =
{ self
, nixpkgs
, flake-utils
, pre-commit-hooks
, rust-overlay
, import-cargo
}:
let
SYSTEMS = [
"aarch64-darwin"
"aarch64-linux"
"x86_64-darwin"
"x86_64-linux"
];
RUST_CHANNELS = [
"stable"
"beta"
"nightly"
];
forEachRustChannel = fn: builtins.listToAttrs (builtins.map fn RUST_CHANNELS);
cargoTOML = builtins.fromTOML (builtins.readFile ./Cargo.toml);
WasmBindgenCargoVersion = cargoTOML.dependencies.wasm-bindgen.version;
WasmBindgenVersion = builtins.substring 1 (builtins.stringLength WasmBindgenCargoVersion) WasmBindgenCargoVersion;
version = "${cargoTOML.package.version}_${builtins.substring 0 8 self.lastModifiedDate}_${self.shortRev or "dirty"}";
customOverlay = final: prev: {
wasm-bindgen-cli = prev.wasm-bindgen-cli.overrideAttrs (old: rec {
version = WasmBindgenVersion;
src =
let
tarball = final.fetchFromGitHub {
owner = "rustwasm";
repo = "wasm-bindgen";
rev = WasmBindgenVersion;
hash = "sha256:041mp2ls78iji4w1v3kka2bbcj0pjwy7svpslk2rhldkymhxmjhs";
};
in
final.runCommand "source" { } ''
cp -R ${tarball} $out
chmod -R +w $out
cp ${./wasm-bindgen-api-Cargo.lock} $out/Cargo.lock
'';
checkInputs = [ ];
cargoTestFlags = [ ];
cargoBuildFlags = [ "-p" old.pname ];
cargoDeps = old.cargoDeps.overrideAttrs (final.lib.const {
name = "${old.pname}-${version}-vendor.tar.gz";
inherit src;
outputHash = "sha256:0bykharc2iq7r0n51d5rdg9s8dq86r9mc6vvbqlp6i468kp8hdvn";
});
});
};
in
flake-utils.lib.eachSystem SYSTEMS (system:
let
pkgs = import nixpkgs {
inherit system;
overlays = [
(import rust-overlay)
customOverlay
];
};
cargoHome = (import-cargo.builders.importCargo {
lockFile = ./Cargo.lock;
inherit pkgs;
}).cargoHome;
# Additional packages required for some systems to build Nickel
missingSysPkgs =
if pkgs.stdenv.isDarwin then
[
pkgs.darwin.apple_sdk.frameworks.Security
pkgs.darwin.libiconv
]
else
[ ];
mkRust =
{ rustProfile ? "minimal"
, rustExtensions ? [
"rust-src"
"rust-analysis"
"rustfmt-preview"
"clippy-preview"
]
, channel ? "stable"
, target ? pkgs.rust.toRustTarget pkgs.stdenv.hostPlatform
}:
let
_rust =
if channel == "nightly" then
pkgs.rust-bin.selectLatestNightlyWith
(toolchain: toolchain.${rustProfile}.override {
extensions = rustExtensions;
targets = [ target ];
})
else
pkgs.rust-bin.${channel}.latest.${rustProfile}.override {
extensions = rustExtensions;
targets = [ target ];
};
in
pkgs.buildEnv {
name = _rust.name;
inherit (_rust) meta;
buildInputs = [ pkgs.makeWrapper ];
paths = [ _rust ];
pathsToLink = [ "/" "/bin" ];
# XXX: This is needed because cargo and clippy commands need to
# also be aware of other binaries in order to work properly.
# https://github.com/cachix/pre-commit-hooks.nix/issues/126
postBuild = ''
for i in $out/bin/*; do
wrapProgram "$i" --prefix PATH : "$out/bin"
done
'';
};
buildNickel =
{ channel ? "stable"
, isDevShell ? false
, target ? pkgs.rust.toRustTarget pkgs.stdenv.hostPlatform
,
}:
let
rustProfile =
if isDevShell then "default"
else "minimal";
rust = mkRust { inherit rustProfile channel target; };
pre-commit = pre-commit-hooks.lib.${system}.run {
src = self;
hooks = {
nixpkgs-fmt = {
enable = true;
excludes = [
"lsp/client-extension/default.nix"
"lsp/client-extension/node-env.nix"
"lsp/client-extension/node-packages.nix"
];
};
rustfmt = {
enable = true;
entry = pkgs.lib.mkForce "${rust}/bin/cargo-fmt fmt -- --check --color always";
};
};
};
in
pkgs.stdenv.mkDerivation {
name = "nickel-${version}";
buildInputs =
[
rust
] ++ missingSysPkgs
++ (if isDevShell then [ pkgs.nodePackages.makam ]
else [ cargoHome ]);
src = if isDevShell then null else self;
buildPhase = ''
cargo build --workspace --release --frozen --offline
'';
doCheck = true;
checkPhase = ''
cargo test --release --frozen --offline
'' + (pkgs.lib.optionalString (channel == "stable") ''
cargo fmt --all -- --check
'');
installPhase = ''
mkdir -p $out
cargo install --frozen --offline --path . --root $out
cargo install --frozen --offline --path lsp/nls --root $out
rm $out/.crates.toml
'';
shellHook = pre-commit.shellHook + ''
echo "=== Nickel development shell ==="
echo "Info: Git hooks can be installed using \`pre-commit install\`"
'';
passthru = { inherit rust pre-commit; };
RUST_SRC_PATH = "${rust}/lib/rustlib/src/rust/library";
};
buildNickelWASM =
{ channel ? "stable"
, optimize ? true
}:
let
rust = mkRust {
inherit channel;
target = "wasm32-unknown-unknown";
};
in
pkgs.stdenv.mkDerivation {
name = "nickel-wasm-${version}";
src = self;
nativeBuildInputs = [ pkgs.jq ];
buildInputs = [
rust
pkgs.wasm-pack
pkgs.wasm-bindgen-cli
pkgs.binaryen
cargoHome
] ++ missingSysPkgs;
preBuild = ''
# Wasm-pack requires to change the crate type. Cargo doesn't yet
# support having different crate types depending on the target, so
# we switch there
sed -i 's/\[lib\]/[lib]\ncrate-type = ["cdylib", "rlib"]/' Cargo.toml
# This is a hack to prevent the fs2 crate from being compiled on wasm.
# This may be able to be removed once one or more of these issues are resolved:
# https://github.com/bheisler/criterion.rs/issues/461
# https://github.com/rust-lang/cargo/issues/1596
# https://github.com/rust-lang/cargo/issues/1197
# https://github.com/rust-lang/cargo/issues/5777
sed -i '/nickel-lang-utilities/d' Cargo.toml
'';
buildPhase = ''
runHook preBuild
wasm-pack build --mode no-install -- --no-default-features --features repl-wasm --frozen --offline
# Because of wasm-pack not using existing wasm-opt
# (https://github.com/rustwasm/wasm-pack/issues/869), we have to
# run wasm-opt manually
echo "[Nix build script]Manually running wasm-opt..."
wasm-opt ${if optimize then "-O4 " else "-O0"} pkg/nickel_lang_bg.wasm -o pkg/nickel_lang_bg.wasm
runHook postBuild
'';
postBuild = ''
# Wasm-pack forces the name of both the normal crate and the
# generated NPM package to be the same. Unfortunately, there already
# exists a nickel package in the NPM registry, so we use nickel-repl
# instead
jq '.name = "nickel-repl"' pkg/package.json > package.json.patched \
&& rm -f pkg/package.json \
&& mv package.json.patched pkg/package.json
'';
installPhase = ''
mkdir -p $out
cp -r pkg $out/nickel-repl
'';
};
buildDocker = nickel: pkgs.dockerTools.buildLayeredImage {
name = "nickel";
tag = version;
contents = [
nickel
pkgs.bashInteractive
];
config = {
Cmd = "bash";
};
};
makamSpecs = pkgs.stdenv.mkDerivation {
name = "nickel-makam-specs-${version}";
src = ./makam-spec/src;
buildInputs =
[
pkgs.nodePackages.makam
];
buildPhase = ''
# For some reason (bug) the first time I use makam here it doesn't generate any output
# That's why I'm "building" before testing
makam init.makam
makam --run-tests testnickel.makam
'';
installPhase = ''
echo "WORKS" > $out
'';
};
vscodeExtension =
let node-package = (pkgs.callPackage ./lsp/client-extension { }).package;
in
(node-package.override rec {
pname = "nls-client";
outputs = [ "vsix" "out" ];
nativeBuildInputs = with pkgs; [
nodePackages.typescript
# Required by `keytar`, which is a dependency of `vsce`.
pkg-config
libsecret
];
postInstall = ''
npm run compile
mkdir -p $vsix
echo y | npx vsce package -o $vsix/${pname}.vsix
'';
}).vsix;
userManual = pkgs.stdenv.mkDerivation {
name = "nickel-user-manual-${version}";
src = ./doc/manual;
installPhase = ''
mkdir -p $out
cp -r ./ "$out"
'';
};
in
rec {
defaultPackage = packages.build;
packages = {
build = buildNickel { };
buildWasm = buildNickelWASM { optimize = true; };
dockerImage = buildDocker packages.build; # TODO: docker image should be a passthru
inherit vscodeExtension;
inherit userManual;
};
devShell = devShells.stable;
devShells = forEachRustChannel
(channel: {
name = channel;
value = buildNickel { inherit channel; isDevShell = true; };
});
checks = {
# wasm-opt can take long: eschew optimizations in checks
wasm = buildNickelWASM { channel = "stable"; optimize = false; };
# out of sync, disabling for now -> https://github.com/tweag/nickel/issue/552
#specs = makamSpecs;
pre-commit = defaultPackage.pre-commit;
} // (forEachRustChannel (channel:
{
name = "nickel-against-${channel}-rust-channel";
value = buildNickel { inherit channel; };
}
));
}
);
}