8000 nickel/flake.nix at master · gominimal/nickel · GitHub
[go: up one dir, main page]

Skip to content

Latest commit

 

History

History
810 lines (721 loc) · 30.9 KB

flake.nix

File metadata and controls

810 lines (721 loc) · 30.9 KB
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
pre-commit-hooks = {
url = "github:cachix/git-hooks.nix";
inputs.nixpkgs.follows = "nixpkgs";
};
rust-overlay = {
url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs";
};
crane = {
url = "github:ipetkov/crane";
};
};
nixConfig = {
extra-substituters = [ "https://tweag-nickel.cachix.org" ];
extra-trusted-public-keys = [ "tweag-nickel.cachix.org-1:GIthuiK4LRgnW64ALYEoioVUQBWs0jexyoYVeLDBwRA=" ];
};
outputs =
{ self
, nixpkgs
, flake-utils
, pre-commit-hooks
, rust-overlay
, crane
}:
let
SYSTEMS = [
"aarch64-darwin"
"aarch64-linux"
"x86_64-darwin"
"x86_64-linux"
];
cargoTOML = builtins.fromTOML (builtins.readFile ./Cargo.toml);
cargoLock = builtins.fromTOML (builtins.readFile ./Cargo.lock);
inherit (cargoTOML.workspace.package) version;
in
flake-utils.lib.eachSystem SYSTEMS (system:
let
pkgs = import nixpkgs {
inherit system;
overlays = [
(import rust-overlay)
# gnulib tests in diffutils fail for musl arm64, cf. https://github.com/NixOS/nixpkgs/pull/241281
(final: prev: {
diffutils =
if !(final.stdenv.hostPlatform.isMusl && final.stdenv.hostPlatform.isAarch64) then
prev.diffutils
else
prev.diffutils.overrideAttrs (old: {
postPatch = ''
sed -i 's:gnulib-tests::g' Makefile.in
'';
});
})
];
};
# Provide a `wasm-bindgen-cli` package which has the exact same version as
# the Rust 8000 dependency `wasm-bindgen` locked in the Cargo.lock file. This
# is needed to properly build the WASM REPL.
wasm-bindgen-cli =
let
wasmBindgenCargoVersions = builtins.map ({ version, ... }: version) (builtins.filter ({ name, ... }: name == "wasm-bindgen") cargoLock.package);
wasmBindgenVersion = assert builtins.length wasmBindgenCargoVersions == 1; builtins.elemAt wasmBindgenCargoVersions 0;
in
pkgs.buildWasmBindgenCli rec {
src = pkgs.fetchCrate {
pname = "wasm-bindgen-cli";
version = wasmBindgenVersion;
hash = "sha256-3RJzK7mkYFrs7C/WkhW9Rr4LdP5ofb2FdYGz1P7Uxog=";
};
cargoDeps = pkgs.rustPlatform.fetchCargoVendor {
inherit src;
inherit (src) pname version;
hash = "sha256-qsO12332HSjWCVKtf1cUePWWb9IdYUmT+8OPj/XP2WE=";
};
};
# Additional packages required to build Nickel on Darwin
systemSpecificPkgs =
if pkgs.stdenv.isDarwin then
[ pkgs.darwin.libiconv ]
else
[ ];
mkRust =
let
inherit (pkgs.stdenv) hostPlatform;
in
{ rustExtensions ? [
"rustfmt"
"clippy"
]
, targets ? [ pkgs.stdenv.hostPlatform.rust.rustcTarget ]
++ pkgs.lib.optional (!hostPlatform.isMacOS) pkgs.pkgsMusl.stdenv.hostPlatform.rust.rustcTarget
}:
(pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml).override {
extensions = rustExtensions;
inherit targets;
};
# A note on check_format: the way we invoke rustfmt here works locally but fails on CI.
# Since the formatting is checked on CI anyway - as part of the rustfmt check - we
# disable rustfmt in the pre-commit hook when running checks, but enable it when
# running in a dev shell.
pre-commit-builder = { rust ? mkRust { }, checkFormat ? false }: pre-commit-hooks.lib.${system}.run {
src = self;
hooks = {
nixpkgs-fmt = {
enable = true;
# Excluded because they are generated by Node2nix
excludes = [
"lsp/vscode-extension/default.nix"
"lsp/vscode-extension/node-env.nix"
"lsp/vscode-extension/node-packages.nix"
];
};
rustfmt = {
enable = checkFormat;
entry = pkgs.lib.mkForce "${rust}/bin/cargo-fmt fmt -- --check --color always";
};
markdownlint = {
enable = true;
excludes = [
"notes/(.+)\\.md$"
"^RELEASES\\.md$"
];
};
# We could use Topiary here, but the Topiary version pulled from Nix
# and the one baked in Nickel could differ. It's saner that what we
# check in the CI is matching exactly the formatting performed by the
# `nickel` binary of this repo.
nickel-format = {
name = "nickel-format";
description = "The nickel formatter";
entry = "${pkgs.lib.getExe self.packages."${system}".nickel-check-fmt}";
types = [ "text" ];
enable = true;
# Some tests are currently failing the idempotency check, and
# formatting is less important there. We at least want the examples
# as well as the stdlib to be properly formatted.
files = "\\.ncl$";
excludes = [
"/tests/(.+)\\.ncl$"
];
};
};
};
# Customize source filtering for Crane as Nickel uses non-standard-Rust
# files like `*.lalrpop`.
filterNickelSrc = filterCargoSources:
let
mkFilter = regexp: path: _type: builtins.match regexp path != null;
lalrpopFilter = mkFilter ".*lalrpop$";
nclFilter = mkFilter ".*ncl$";
txtFilter = mkFilter ".*txt$";
snapFilter = mkFilter ".*snap$";
scmFilter = mkFilter ".*scm$";
# include markdown files for checking snippets in the documentation
mdFilter = mkFilter ".*md$";
cxxFilter = mkFilter ".*(cc|hh)$";
# include all files that are used in tests
importsFilter = mkFilter ".*/core/tests/integration/inputs/imports/imported/.*$";
testsInputsFilter = mkFilter ".*/cli/tests/integration/inputs/.*$";
cliTestsImportsFilter = mkFilter ".*/cli/tests/snapshot/imports/.*$";
nlsTestsInputsFilter = mkFilter ".*/lsp/nls/tests/.*$";
in
pkgs.lib.cleanSourceWith {
src = pkgs.lib.cleanSource ./.;
# Combine our custom filters with the default one from Crane
# See https://github.com/ipetkov/crane/blob/master/docs/API.md#libfiltercargosources
filter = path: type:
builtins.any (filter: filter path type) [
lalrpopFilter
nclFilter
txtFilter
snapFilter
scmFilter
mdFilter
cxxFilter
filterCargoSources
importsFilter
testsInputsFilter
cliTestsImportsFilter
nlsTestsInputsFilter
];
};
# if we directly set the revision, it would invalidate the cache on every commit.
# instead we set a static dummy hash and edit the binary in a separate (fast) derivation.
dummyRev = "DUMMYREV_THIS_SHOULD_NOT_APPEAR_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
# pad a string with the tail of another string
padWith = pad: str:
str +
builtins.substring
(builtins.stringLength str)
(builtins.stringLength pad)
pad;
# We want `nickel --version` and `nls --version` to print the git revision
# that nickel was compiled from. However, putting self.shortRev in a
# derivation invalidates the cache on any change, even if otherwise the
# derivation is identical. To mitigate this, we pass an unchanging string
# as the revision in `NICKEL_NIX_BUILD_REV`, and then have a small wrapper
# that replaces that string in the output binary. On every new commit this
# fast derivation will have to be rebuilt, but the slow compilation of
# rust code will only happen on more substantial changes. This is only
# needed for binaries that actually make use of this information (the
# cli and the language server).
fixupGitRevision = pkg: pkgs.stdenv.mkDerivation {
pname = pkg.pname + "-rev-fixup";
inherit (pkg) version meta;
src = pkg;
buildInputs = [ pkgs.bbe ]
++ pkgs.lib.optionals pkgs.stdenv.isDarwin [ pkgs.darwin.autoSignDarwinBinariesHook ];
phases = [ "fixupPhase" ];
fixupPhase = ''
runHook preFixup
mkdir -p $out/bin
for srcBin in $src/bin/*; do
outBin="$out/bin/$(basename $srcBin)"
'' +
# [dirty] must have 7 characters to match dummyRev (hard coded in
# nickel-lang-cli and nickel-lang-lsp)
# we have to pad them out to the same length as dummyRev so they fit
# in the same spot in the binary
''
bbe -e 's/${dummyRev}/${padWith dummyRev (self.shortRev or "[dirty]")}/' \
$srcBin > $outBin
chmod +x $outBin
done
runHook postFixup
'';
};
craneOverrideToolchain =
(crane.mkLib pkgs).overrideToolchain;
# Given a rust toolchain, provide Nickel's Rust dependencies, Nickel, as
# well as rust tools (like clippy)
mkCraneArtifacts = { rust ? mkRust { }, noRunBench ? false, profile ? "release" }:
let
craneLib = craneOverrideToolchain rust;
# suffixes get added via pnameSuffix
pname = "nickel-lang";
# Customize source filtering as Nickel uses non-standard-Rust files like `*.lalrpop`.
src = filterNickelSrc craneLib.filterCargoSources;
# set of cargo args common to all builds
cargoBuildExtraArgs = "--frozen --offline";
# Build *just* the cargo dependencies, so we can reuse all of that work (e.g. via cachix) when running in CI
cargoArtifactsDeps = craneLib.buildDepsOnly {
inherit pname src;
buildPhaseCargoCommand = ''
cargo check --workspace --locked
cargo check --workspace --locked --all-features
cargo check --workspace --locked --features=package-experimental
cargo build --workspace --locked
cargo build --workspace --locked --all-features
cargo build --workspace --locked --features=package-experimental
'';
# pyo3 needs a Python interpreter in the build environment
# https://pyo3.rs/v0.17.3/building_and_distribution#configuring-the-python-version
nativeBuildInputs = with pkgs; [ pkg-config python3 ];
buildInputs = [
pkgs.nix
pkgs.boost # implicit dependency of nix
];
# seems to be needed for consumer cargoArtifacts to be able to use
# zstd mode properly
installCargoArtifactsMode = "use-zstd";
CARGO_PROFILE = profile;
env.PYO3_PYTHON = "${pkgs.python3}/bin/python";
};
env = {
NICKEL_NIX_BUILD_REV = dummyRev;
};
buildWorkspace = { pnameSuffix ? "", extraNickelFeatures ? [ ], extraBuildArgs ? "", extraArgs ? { } }:
let
featuresArg = pkgs.lib.optionalString
(extraNickelFeatures != [ ])
("--features " + pkgs.lib.strings.concatStringsSep " " extraNickelFeatures);
in
# The `cargoArtifacts` are the dependencies of the workspace, so we
# can reuse them in the build.
craneLib.buildPackage ({
inherit
pname
pnameSuffix
src
version
cargoArtifacts;
# pyo3 needs a Python interpreter in the build environment
# https://pyo3.rs/v0.17.3/building_and_distribution#configuring-the-python-version
nativeBuildInputs = with pkgs; [ pkg-config python3 ];
# A git binary is needed for some of the tests
buildInputs = with pkgs;
[ git ]
++ pkgs.lib.optionals
(builtins.elem "nix-experimental" extraNickelFeatures)
[ boost nix ];
cargoExtraArgs = "${cargoBuildExtraArgs} ${featuresArg} ${extraBuildArgs} --workspace";
CARGO_PROFILE = profile;
env.PYO3_PYTHON = "${pkgs.python3}/bin/python";
} // extraArgs);
# To build Nickel and its dependencies statically we use the musl
# libc and clang with libc++ to build C and C++ dependencies. We
# tried building with libstdc++ but without success.
buildStaticWorkspace = { pnameSuffix, extraNickelFeatures ? [ ], extraBuildArgs ? "", extraArgs ? { } }:
let
# The `cc` crate (which is used by tree-sitter) gets its C
# compilers from env variables like CC_x86_64_unknown_linux_musl.
# (It's important that we don't override the more general CC env
# variable because we want things like build scripts to use the
# default platform compiler.)
env_tgt = builtins.replaceStrings [ "-" ] [ "_" ] pkgs.pkgsMusl.stdenv.hostPlatform.rust.rustcTarget;
in
(buildWorkspace {
inherit pnameSuffix extraNickelFeatures extraBuildArgs;
extraArgs = {
inherit env;
CARGO_BUILD_TARGET = pkgs.pkgsMusl.stdenv.hostPlatform.rust.rustcTarget;
doCheck = false;
CARGO_PROFILE = profile;
"CC_${env_tgt}" = "${pkgs.pkgsMusl.gcc}/bin/gcc";
# We used to support building the nix-experimental feature
# statically but we don't anymore because some of the pkgsMusl
# stuff isn't in the binary cache, and building them was taking
# hours in CI. Here are the incantations that allowed statically
# linking nix:
# RUSTFLAGS = "-L${pkgs.pkgsMusl.llvmPackages.libcxx}/lib -lstatic=c++abi -C link-arg=-lc";
# CXXSTDLIB = "static=c++";
# stdenv = p: p.pkgsMusl.libcxxStdenv;
} // extraArgs;
});
buildCApi = { pnameSuffix ? "", extraBuildArgs ? "", extraArgs ? { } }:
craneLib.buildPackage ({
inherit
pname
pnameSuffix
src
version
cargoArtifacts;
cargoExtraArgs = "${cargoBuildExtraArgs} ${extraBuildArgs} --features capi --package nickel-lang";
CARGO_PROFILE = profile;
postInstall = ''
mkdir -p $out/include
${pkgs.rust-cbindgen}/bin/cbindgen nickel --lockfile ./Cargo.lock --output $out/include/nickel_lang.h --cpp-compat
'';
} // extraArgs);
shrinkStaticLib = { pnameSuffix ? "", extraBuildArgs ? "", extraArgs ? { } }:
let
cApi = buildCApi { inherit pnameSuffix extraBuildArgs extraArgs; };
in
pkgs.stdenv.mkDerivation {
name = pname + pnameSuffix;
src = ./scripts/shrink_archive.sh;
dontUnpack = true;
nativeBuildInputs = [ pkgs.llvmPackages.bintools ];
buildPhase = ''
${pkgs.bash}/bin/bash $src -o libnickel_lang.a ${cApi}/lib/libnickel_lang.a
'';
installPhase = ''
mkdir -p $out/lib
mkdir -p $out/include
cp libnickel_lang.a $out/lib/libnickel_lang.a
if [ -e ${cApi}/lib/libnickel_lang.so ]; then
ln -sf ${cApi}/lib/libnickel_lang.so $out/lib/libnickel_lang.so
fi
if [ -e ${cApi}/lib/libnickel_lang.dylib ]; then
ln -sf ${cApi}/lib/libnickel_lang.dylib $out/lib/libnickel_lang.dylib
fi
ln -sf ${cApi}/include/nickel_lang.h $out/include/nickel_lang.h
'';
};
# In addition to external dependencies, we build the lalrpop file in a
# separate derivation because it's expensive to build but needs to be
# rebuilt infrequently.
cargoArtifacts = craneLib.buildPackage {
inherit pname version;
pnameSuffix = "-parser-lalrpop";
src = craneLib.mkDummySrc {
inherit src;
# after stubbing out, reset things back just enough for lalrpop build
extraDummyScript = ''
mkdir -p $out/parser/src/
cp ${./parser/build.rs} $out/parser/build.rs
cp ${./parser/src/grammar.lalrpop} $out/parser/src/grammar.lalrpop
'' +
# package.build gets set to a dummy file. reset it to use local build.rs
# tomlq -i broken (https://github.com/kislyuk/yq/issues/130 not in nixpkgs yet)
''
${pkgs.yq}/bin/tomlq -t 'del(.package.build)' $out/parser/Cargo.toml > tmp
mv tmp $out/parser/Cargo.toml
'';
};
cargoArtifacts = cargoArtifactsDeps;
cargoExtraArgs = "--package nickel-lang-core";
# the point of this is to cache lalrpop compilation
doInstallCargoArtifacts = true;
# we need the target/ directory to be writable
installCargoArtifactsMode = "use-zstd";
CARGO_PROFILE = profile;
};
in
rec {
inherit cargoArtifacts cargoArtifactsDeps;
nickel-lang = fixupGitRevision (buildWorkspace {
extraArgs = {
inherit env;
meta.mainProgram = "nickel";
};
});
# A version of the Nickel CLI with the experimental package management
# feature enabled.
nickel-lang-pkg = fixupGitRevision (buildWorkspace {
pnameSuffix = "-pkg";
extraNickelFeatures = [ "package-experimental" ];
extraArgs = {
inherit env;
meta.mainProgram = "nickel";
};
});
# A version of the Nickel CLI with the experimental Nix interop
# feature enabled.
nickel-lang-nix = fixupGitRevision (buildWorkspace {
pnameSuffix = "-nix";
extraNickelFeatures = [ "nix-experimental" ];
extraArgs = {
inherit env;
meta.mainProgram = "nickel";
};
});
# Static building isn't really possible on MacOS because the system
# call ABIs aren't stable. This output shouldn't be used on MacOS.
nickel-static =
fixupGitRevision (buildStaticWorkspace {
pnameSuffix = "-static";
extraArgs = { meta.mainProgram = "nickel"; };
});
# See nickel-static
nickel-pkg-static =
fixupGitRevision (buildStaticWorkspace {
pnameSuffix = "-pkg-static";
extraNickelFeatures = [ "package-experimental" ];
extraArgs = { meta.mainProgram = "nickel"; };
});
nickel-lang-c = shrinkStaticLib { pnameSuffix = "-c-api"; };
nickel-lang-c-test = pkgs.stdenv.mkDerivation {
name = "nickel-lang-c-test";
inherit version;
src = ./nickel/capi-tests;
buildPhase = ''
mkdir -p $out/bin
$CC -I "${nickel-lang-c}/include/" run_tests.c "${nickel-lang-c}/lib/libnickel_lang.a" -lm -o $out/bin/run_tests
'';
doCheck = true;
checkPhase = ''
$out/bin/run_tests
'';
};
nickel-check-fmt = craneLib.buildPackage {
pname = "nickel-check-fmt";
cargoArtifacts = null;
cargoExtraArgs = "--package nickel-check-fmt";
# We can't just declare ./fmt to be the source: we depend on the workspace for
# dependencies. So we just stub out the whole workspace and then copy ./fmt
# back in.
src = craneLib.mkDummySrc {
src = ./.;
extraDummyScript = ''
cp -r ${./fmt} $out/
'';
};
doCheck = false;
meta.mainProgram = "nickel-check-fmt";
CARGO_PROFILE = "dev";
};
benchmarks = craneLib.mkCargoDerivation {
inherit pname src version cargoArtifacts env;
pnameSuffix = "-bench";
# If we aren't running the benchmarks, use the provided profile for maximum cache re-use.
# (If we're running the benchmarks, let `cargo bench` choose the profile.)
buildPhaseCargoCommand = ''
cargo bench -p nickel-lang-core ${pkgs.lib.optionalString noRunBench "--no-run --profile ${profile}"}
'';
doInstallCargoArtifacts = false;
};
# Check that documentation builds without warnings or errors
checkRustDoc = craneLib.cargoDoc {
inherit pname src version cargoArtifacts env;
inherit (cargoArtifactsDeps) nativeBuildInputs buildInputs;
RUSTDOCFLAGS = "-D warnings";
cargoExtraArgs = "${cargoBuildExtraArgs} --workspace --all-features";
doInstallCargoArtifacts = false;
};
rustfmt = craneLib.cargoFmt {
# Notice that unlike other Crane derivations, we do not pass `cargoArtifacts` to `cargoFmt`, because it does not need access to dependencies to format the code.
inherit pname src;
cargoExtraArgs = "--all";
# `-- --check` is automatically prepended by Crane
rustFmtExtraArgs = "--color always";
};
clippy = craneLib.cargoClippy {
inherit pname src cargoArtifacts env;
inherit (cargoArtifactsDeps) nativeBuildInputs buildInputs;
cargoExtraArgs = cargoBuildExtraArgs;
cargoClippyExtraArgs = "--all-features --all-targets --workspace -- --deny warnings --allow clippy::new-without-default --allow clippy::match_like_matches_macro";
CARGO_PROFILE = "dev";
};
};
makeDevShell = { rust }: pkgs.mkShell {
# Get deps needed to build. Get them from cargoArtifactsDeps so we build
# the minimal amount possible to get there. It is a waste of time to
# build the cargoArtifacts, because cargo won't use them anyways.
inputsFrom = [ (mkCraneArtifacts { inherit rust; profile = "dev"; }).cargoArtifactsDeps ];
buildInputs = [
pkgs.cargo-flamegraph
pkgs.cargo-insta
pkgs.cargo-nextest
pkgs.rust-cbindgen
pkgs.nixpkgs-fmt
pkgs.nodejs
pkgs.yarn
pkgs.yq
pkgs.nodePackages.markdownlint-cli
pkgs.python3
];
shellHook = (pre-commit-builder { inherit rust; checkFormat = true; }).shellHook + ''
echo "=== Nickel development shell ==="
echo "Info: Git hooks can be installed using \`pre-commit install\`"
'';
RUST_SRC_PATH = "${rust}/lib/rustlib/src/rust/library";
};
# Profile is passed to `wasm-pack`, and is either "dev" (with debug
# symbols and no optimization), "release" (with optimization and without
# debug symbols) or "profiling". Right now only dev and release are used:
# - release for the production build
# - dev for checks where we don't care about optimizations but WASM
# optimization takes time
buildNickelWasm =
{ rust ? mkRust { targets = [ "wasm32-unknown-unknown" ]; }
, profile ? "release"
}:
let
# Build the various Crane artifacts (dependencies, packages, rustfmt, clippy) for a given Rust toolchain
craneLib = craneOverrideToolchain rust;
# suffixes get added via pnameSuffix
pname = "nickel-lang-wasm";
# Customize source filtering as Nickel uses non-standard-Rust files like `*.lalrpop`.
src = filterNickelSrc craneLib.filterCargoSources;
cargoExtraArgs = "-p nickel-wasm-repl --target wasm32-unknown-unknown --frozen --offline";
# * --mode no-install prevents wasm-pack from trying to download and
# vendor tools like wasm-bindgen, wasm-opt, etc. but use the one
# provided by Nix
# * --no-default-features disable some default features of Nickel that
# aren't useful for the WASM REPL (and possibly incompatible with
# WASM build)
wasmPackExtraArgs = "--${profile} --mode no-install -- --no-default-features --frozen --offline";
# Build *just* the cargo dependencies, so we can reuse all of that work (e.g. via cachix) when running in CI
cargoArtifacts = craneLib.buildDepsOnly {
inherit pname src cargoExtraArgs;
doCheck = false;
CARGO_PROFILE = profile;
};
in
craneLib.mkCargoDerivation {
inherit pname cargoArtifacts src;
buildPhaseCargoCommand = ''
WASM_PACK_CACHE=.wasm-pack-cache wasm-pack build wasm-repl ${wasmPackExtraArgs}
'';
# nickel-lang.org expects an interface `nickel-repl.wasm`, hence the
# `ln`
installPhaseCommand = ''
mkdir -p $out
cp -r wasm-repl/pkg $out/nickel-repl
ln -s $out/nickel-repl/nickel_wasm_repl_bg.wasm $out/nickel-repl/nickel_repl.wasm
'';
nativeBuildInputs = [
rust
pkgs.wasm-pack
wasm-bindgen-cli
pkgs.binaryen
# Used to include the git revision in the Nickel binary, for `--version`
pkgs.git
] ++ systemSpecificPkgs;
CARGO_PROFILE = profile;
};
buildDocker = nickel: pkgs.dockerTools.buildLayeredImage {
name = "nickel";
tag = version;
contents = [
nickel
];
config = {
# Must be an array, not a string (https://github.com/moby/docker-image-spec/blob/f1d00ebd2d6d6805170d5543dbca4b850f35f9af/spec.md#image-json-field-descriptions)
# See https://github.com/tweag/nickel/issues/2261
Entrypoint = [ (pkgs.lib.getExe nickel) ];
# Labels that are recognized by GHCR
# See https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry#labelling-container-images
Labels = {
"org.opencontainers.image.source" = "https://github.com/tweag/nickel";
"org.opencontainers.image.description" = "Nickel: better configuration for less";
"org.opencontainers.image.licenses" = "MIT";
};
};
};
# Build the Nickel VSCode extension
vscodeExtension = pkgs.mkYarnPackage {
pname = "vscode-nickel";
src = pkgs.lib.cleanSource ./lsp/vscode-extension;
buildPhase = ''
# yarn tries to create a .yarn file in $HOME. There's probably a
# better way to fix this but setting HOME to TMPDIR works for now.
export HOME="$TMPDIR"
cd deps/vscode-nickel
yarn --offline compile
yarn --offline vsce package --yarn -o $pname.vsix
'';
installPhase = ''
mkdir $out
mv $pname.vsix $out
'';
distPhase = "true";
};
# Copy the markdown user manual to $out.
userManual = pkgs.stdenv.mkDerivation {
name = "nickel-user-manual-${version}";
src = ./doc/manual;
installPhase = ''
mkdir -p $out
cp -r ./ $out
'';
};
# Generate the stdlib documentation from `nickel doc` as `format`.
stdlibDoc = format:
let
extension =
{
"markdown" = "md";
}."${format}" or format;
in
pkgs.stdenv.mkDerivation {
name = "nickel-stdlib-doc-${format}-${version}";
src = ./core/stdlib;
installPhase = ''
mkdir -p $out
for file in $(ls *.ncl | grep -v 'internals.ncl')
do
module=$(basename $file .ncl)
${pkgs.lib.getExe self.packages."${system}".default} doc --format "${format}" "$module.ncl" \
--output "$out/$module.${extension}"
done
'';
};
stdlibTests = pkgs.runCommandLocal "stdlib-test" { }
''
${pkgs.lib.getExe self.checks."${system}".nickel-lang} test ${./core/stdlib/std.ncl} && mkdir $out
'';
# This flake used to build nickel-lang-cli and nickel-lang-lsp packages with separate
# crane invocations. We switched to building the full workspace for better cargo caching,
# but we also support the old packages for backwards-compatibility.
compatPackage = { nickel-lang, binary, name }: pkgs.runCommand name
{
meta.mainProgram = binary;
} ''
mkdir -p $out/bin
cp -r "${nickel-lang}/bin/${binary}" $out/bin/
'';
in
rec {
packages = {
inherit (mkCraneArtifacts { })
nickel-lang
nickel-lang-pkg
nickel-lang-nix
nickel-lang-c
nickel-check-fmt
benchmarks
cargoArtifactsDeps
cargoArtifacts;
default = packages.nickel-lang;
nickel-lang-cli = compatPackage { inherit (packages) nickel-lang; binary = "nickel"; name = "nickel-lang-cli"; };
nickel-lang-lsp = compatPackage { inherit (packages) nickel-lang; binary = "nls"; name = "nickel-lang-lsp"; };
nickelWasm = buildNickelWasm { };
dockerImage = buildDocker packages.nickel-lang; # TODO: docker image should be a passthru
inherit vscodeExtension;
inherit userManual;
stdlibMarkdown = stdlibDoc "markdown";
stdlibJson = stdlibDoc "json";
} // pkgs.lib.optionalAttrs (!pkgs.stdenv.hostPlatform.isDarwin) {
inherit (mkCraneArtifacts { }) nickel-static nickel-pkg-static;
# Use the statically linked binary for the docker image if we're not on MacOS.
dockerImage = buildDocker packages.nickel-static;
};
apps = {
default = {
type = "app";
program = pkgs.lib.getExe packages.nickel-lang;
};
};
devShells.default = makeDevShell {
rust = mkRust {
targets = [ "wasm32-unknown-unknown" ];
rustExtensions = [
"rustfmt"
"clippy"
"rust-src"
"rust-analyzer"
];
};
};
checks = {
inherit (mkCraneArtifacts { noRunBench = true; profile = "dev"; })
benchmarks
clippy
checkRustDoc
nickel-lang
nickel-lang-c-test
nickel-lang-pkg
rustfmt;
nickelWasm = buildNickelWasm { profile = "dev"; };
inherit vscodeExtension stdlibTests;
pre-commit = pre-commit-builder { };
};
});
}
0