2020-07-03 15:22:21 +03:00
{
2022-12-05 19:28:45 +03:00
inputs = {
nixpkgs . url = " n i x p k g s / n i x o s - u n s t a b l e " ;
flake-utils . url = " g i t h u b : n u m t i d e / f l a k e - u t i l s " ;
pre-commit-hooks = {
url = " g i t h u b : c a c h i x / p r e - c o m m i t - h o o k s . n i x " ;
inputs . nixpkgs . follows = " n i x p k g s " ;
inputs . flake-utils . follows = " f l a k e - u t i l s " ;
} ;
rust-overlay = {
url = " g i t h u b : o x a l i c a / r u s t - o v e r l a y " ;
inputs . nixpkgs . follows = " n i x p k g s " ;
inputs . flake-utils . follows = " f l a k e - u t i l s " ;
} ;
crane = {
url = " g i t h u b : i p e t k o v / c r a n e " ;
inputs . nixpkgs . follows = " n i x p k g s " ;
} ;
} ;
2020-07-03 15:22:21 +03:00
2021-11-17 14:25:22 +03:00
nixConfig = {
2022-08-01 16:51:45 +03:00
extra-substituters = [ " h t t p s : / / t w e a g - n i c k e l . c a c h i x . o r g " ] ;
extra-trusted-public-keys = [ " t w e a g - n i c k e l . c a c h i x . o r g - 1 : G I t h u i K 4 L R g n W 6 4 A L Y E o i o V U Q B W s 0 j e x y o Y V e L D B w R A = " ] ;
2021-11-17 14:25:22 +03:00
} ;
2022-01-19 01:11:10 +03:00
outputs =
{ self
, nixpkgs
, flake-utils
, pre-commit-hooks
, rust-overlay
2022-12-05 19:28:45 +03:00
, crane
2022-01-19 01:11:10 +03:00
} :
2020-07-03 15:22:21 +03:00
let
2021-01-15 16:23:16 +03:00
SYSTEMS = [
2021-09-13 22:20:54 +03:00
" a a r c h 6 4 - d a r w i n "
" a a r c h 6 4 - l i n u x "
2021-01-15 16:23:16 +03:00
" x 8 6 _ 6 4 - d a r w i n "
2021-09-13 22:20:54 +03:00
" x 8 6 _ 6 4 - l i n u x "
2021-01-15 16:23:16 +03:00
] ;
2021-01-15 16:16:59 +03:00
2022-01-17 14:53:18 +03:00
RUST_CHANNELS = [
2021-01-23 21:46:38 +03:00
" s t a b l e "
" b e t a "
] ;
2022-01-19 01:11:10 +03:00
forEachRustChannel = fn : builtins . listToAttrs ( builtins . map fn RUST_CHANNELS ) ;
2022-01-15 00:47:05 +03:00
cargoTOML = builtins . fromTOML ( builtins . readFile ./Cargo.toml ) ;
2022-01-17 01:17:41 +03:00
version = " ${ cargoTOML . package . version } _ ${ builtins . substring 0 8 self . lastModifiedDate } _ ${ self . shortRev or " d i r t y " } " ;
customOverlay = final : prev : {
2022-11-03 13:36:34 +03:00
# The version of `wasm-bindgen` CLI *must* be the same as the `wasm-bindgen` Rust dependency in `Cargo.toml`.
# The definition of `wasm-bindgen-cli` in Nixpkgs does not allow overriding directly the attrset passed to `buildRustPackage`.
# We instead override the attrset that `buildRustPackage` generates and passes to `mkDerivation`.
# See https://discourse.nixos.org/t/is-it-possible-to-override-cargosha256-in-buildrustpackage/4393
wasm-bindgen-cli = prev . wasm-bindgen-cli . overrideAttrs ( oldAttrs :
let
wasmBindgenCargoVersion = cargoTOML . dependencies . wasm-bindgen . version ;
# Remove the pinning `=` prefix of the version
wasmBindgenVersion = builtins . substring 1 ( builtins . stringLength wasmBindgenCargoVersion ) wasmBindgenCargoVersion ;
in
rec {
pname = " w a s m - b i n d g e n - c l i " ;
version = wasmBindgenVersion ;
src = final . fetchCrate {
inherit pname version ;
sha256 = " s h a 2 5 6 - + P W x e R L 5 M k I f J t f N 3 / D j a D l q R g B g W Z M a 6 d B t 1 Q + l p d 0 = " ;
} ;
cargoDeps = oldAttrs . cargoDeps . overrideAttrs ( final . lib . const {
# This `inherit src` is important, otherwise, the old `src` would be used here
inherit src ;
outputHash = " s h a 2 5 6 - G w L e A 6 x L t 7 I + N z R a q j w V p t 1 p z R e x 1 / s n q 3 0 D P v 4 F R + g = " ;
} ) ;
2022-01-15 00:47:05 +03:00
} ) ;
} ;
2022-01-19 01:11:10 +03:00
in
flake-utils . lib . eachSystem SYSTEMS ( system :
let
pkgs = import nixpkgs {
inherit system ;
overlays = [
( import rust-overlay )
customOverlay
] ;
} ;
2022-12-21 14:36:53 +03:00
# Additional packages required to build Nickel on Darwin
2022-01-19 01:11:10 +03:00
missingSysPkgs =
if pkgs . stdenv . isDarwin then
[
pkgs . darwin . apple_sdk . frameworks . Security
pkgs . darwin . libiconv
]
else
[ ] ;
2022-01-19 11:23:22 +03:00
mkRust =
{ rustProfile ? " m i n i m a l "
, rustExtensions ? [
" r u s t - s r c "
" r u s t - a n a l y s i s "
2022-12-05 19:28:45 +03:00
" r u s t f m t "
" c l i p p y "
2022-01-19 11:23:22 +03:00
]
, channel ? " s t a b l e "
, target ? pkgs . rust . toRustTarget pkgs . stdenv . hostPlatform
} :
2022-12-05 19:28:45 +03:00
if channel == " n i g h t l y " 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 ] ;
} ;
2022-01-19 11:23:22 +03:00
2022-12-06 12:50:37 +03:00
# 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 {
2022-12-05 19:28:45 +03:00
src = self ;
hooks = {
nixpkgs-fmt = {
enable = true ;
# Excluded because they are generated by Node2nix
excludes = [
" l s p / c l i e n t - e x t e n s i o n / d e f a u l t . n i x "
" l s p / c l i e n t - e x t e n s i o n / n o d e - e n v . n i x "
" l s p / c l i e n t - e x t e n s i o n / n o d e - p a c k a g e s . n i x "
] ;
} ;
2022-01-19 11:23:22 +03:00
2022-12-05 19:28:45 +03:00
rustfmt = {
2022-12-06 12:50:37 +03:00
enable = checkFormat ;
entry = pkgs . lib . mkForce " ${ rust } / b i n / c a r g o - f m t f m t - - - - c h e c k - - c o l o r a l w a y s " ;
2022-12-05 19:28:45 +03:00
} ;
2022-01-19 01:11:10 +03:00
2022-12-05 19:28:45 +03:00
markdownlint = {
enable = true ;
excludes = [
" n o t e s / ( . + ) \\ . m d $ "
" ^ R E L E A S E S \\ . m d $ "
] ;
} ;
2022-01-17 14:53:18 +03:00
2022-12-05 19:28:45 +03:00
} ;
} ;
2022-11-17 20:18:49 +03:00
2022-12-21 14:36:53 +03:00
# 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 " . * l a l r p o p $ " ;
nclFilter = mkFilter " . * n c l $ " ;
txtFilter = mkFilter " . * t x t $ " ;
2023-01-09 13:32:40 +03:00
snapFilter = mkFilter " . * s n a p $ " ;
2022-12-21 14:36:53 +03:00
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
2023-01-09 13:32:40 +03:00
snapFilter
2022-12-21 14:36:53 +03:00
filterCargoSources
] ;
} ;
# Given a rust toolchain, provide Nickel's Rust dependencies, Nickel, as
# well as rust tools (like clippy)
2022-12-05 19:28:45 +03:00
mkCraneArtifacts = { rust ? mkRust { } }:
let
craneLib = crane . lib . ${ system } . overrideToolchain rust ;
# Customize source filtering as Nickel uses non-standard-Rust files like `*.lalrpop`.
2022-12-21 14:36:53 +03:00
src = filterNickelSrc craneLib . filterCargoSources ;
2022-11-17 20:18:49 +03:00
2023-01-14 18:03:32 +03:00
# set of cargo args common to all builds
cargoBuildExtraArgs = " - - f r o z e n - - o f f l i n e " ;
2022-12-05 19:28:45 +03:00
# Build *just* the cargo dependencies, so we can reuse all of that work (e.g. via cachix) when running in CI
cargoArtifacts = craneLib . buildDepsOnly {
2023-01-14 18:03:32 +03:00
inherit src ;
cargoExtraArgs = " ${ cargoBuildExtraArgs } - - w o r k s p a c e " ;
2023-01-16 17:28:57 +03:00
# pyo3 needs a Python interpreter in the build environment
# https://pyo3.rs/v0.17.3/building_and_distribution#configuring-the-python-version
2023-01-14 18:03:32 +03:00
buildInputs = [ pkgs . python3 ] ;
2022-01-17 01:17:41 +03:00
} ;
2021-08-31 12:05:36 +03:00
2023-01-14 18:03:32 +03:00
buildPackage = packageName :
craneLib . buildPackage {
inherit
src
cargoArtifacts ;
cargoExtraArgs = " ${ cargoBuildExtraArgs } - - p a c k a g e ${ packageName } " ;
} ;
in
rec {
nickel = buildPackage " n i c k e l - l a n g " ;
lsp-nls = buildPackage " n i c k e l - l a n g - l s p " ;
2022-01-17 14:53:18 +03:00
2022-12-05 19:28:45 +03:00
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 src ;
2022-01-17 01:17:41 +03:00
2022-12-05 19:28:45 +03:00
cargoExtraArgs = " - - a l l " ;
2022-01-17 01:17:41 +03:00
2022-12-05 19:28:45 +03:00
# `-- --check` is automatically prepended by Crane
rustFmtExtraArgs = " - - c o l o r a l w a y s " ;
} ;
2022-01-17 01:17:41 +03:00
2022-12-05 19:28:45 +03:00
clippy = craneLib . cargoClippy {
inherit
src
cargoArtifacts ;
2022-01-17 01:17:41 +03:00
2023-01-14 18:03:32 +03:00
cargoExtraArgs = cargoBuildExtraArgs ;
2022-12-05 19:28:45 +03:00
cargoClippyExtraArgs = " - - a l l - t a r g e t s - - - - d e n y w a r n i n g s - - a l l o w c l i p p y : : n e w - w i t h o u t - d e f a u l t - - a l l o w c l i p p y : : m a t c h _ l i k e _ m a t c h e s _ m a c r o " ;
} ;
2022-11-17 20:18:49 +03:00
} ;
2021-08-31 12:05:36 +03:00
2022-11-17 20:18:49 +03:00
makeDevShell = { rust }: pkgs . mkShell {
2022-12-05 19:28:45 +03:00
# Trick found in Crane's examples to get a nice dev shell
# See https://github.com/ipetkov/crane/blob/master/examples/quick-start/flake.nix
inputsFrom = builtins . attrValues ( mkCraneArtifacts { inherit rust ; } ) ;
2022-11-21 14:42:16 +03:00
buildInputs = [
pkgs . rust-analyzer
2023-01-09 13:32:40 +03:00
pkgs . cargo-insta
pkgs . nixpkgs-fmt
2022-11-21 14:42:16 +03:00
pkgs . nodejs
pkgs . node2nix
pkgs . nodePackages . markdownlint-cli
2023-01-08 21:45:01 +03:00
pkgs . python3
2022-11-21 14:42:16 +03:00
] ;
2021-02-07 21:43:11 +03:00
2022-12-06 12:50:37 +03:00
shellHook = ( pre-commit-builder { inherit rust ; checkFormat = true ; } ) . shellHook + ''
2022-11-17 20:18:49 +03:00
echo " = = = N i c k e l d e v e l o p m e n t s h e l l = = = "
echo " I n f o : G i t h o o k s c a n b e i n s t a l l e d u s i n g \` p r e - c o m m i t i n s t a l l \` "
'' ;
RUST_SRC_PATH = " ${ rust } / l i b / r u s t l i b / s r c / r u s t / l i b r a r y " ;
} ;
2021-01-24 13:18:00 +03:00
2022-12-21 14:36:53 +03:00
# 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, as the code isn't optimized, and WASM optimization
# takes time
2022-06-15 12:02:48 +03:00
buildNickelWasm =
2022-11-17 20:18:49 +03:00
{ rust ? mkRust { target = " w a s m 3 2 - u n k n o w n - u n k n o w n " ; }
2022-12-21 14:36:53 +03:00
, profile ? " r e l e a s e "
2022-01-19 01:11:10 +03:00
} :
2022-12-21 14:36:53 +03:00
let
# Build the various Crane artifacts (dependencies, packages, rustfmt, clippy) for a given Rust toolchain
craneLib = crane . lib . ${ system } . overrideToolchain rust ;
2021-09-27 18:02:07 +03:00
2022-12-21 14:36:53 +03:00
# Customize source filtering as Nickel uses non-standard-Rust files like `*.lalrpop`.
src = filterNickelSrc craneLib . filterCargoSources ;
2021-09-27 18:02:07 +03:00
2022-12-21 14:36:53 +03:00
cargoExtraArgs = " - p n i c k e l - r e p l - - t a r g e t w a s m 3 2 - u n k n o w n - u n k n o w n - - f r o z e n - - o f f l i n e " ;
2022-12-25 14:17:39 +03:00
# * --mode no-install prevents wasm-pack from trying to download and
2022-12-21 14:36:53 +03:00
# 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
2022-12-25 14:17:39 +03:00
# aren't useful for the WASM REPL (and possibly incompatible with
2022-12-21 14:36:53 +03:00
# WASM build)
wasmPackExtraArgs = " - - ${ profile } - - m o d e n o - i n s t a l l - - - - n o - d e f a u l t - f e a t u r e s - - f r o z e n - - o f f l i n e " ;
2022-01-19 11:23:22 +03:00
2022-12-21 14:36:53 +03:00
# 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
src
cargoExtraArgs ;
doCheck = false ;
} ;
in
craneLib . mkCargoDerivation {
inherit cargoArtifacts src ;
buildPhaseCargoCommand = ''
wasm-pack build nickel-wasm-repl $ { wasmPackExtraArgs }
2022-01-19 01:11:10 +03:00
'' ;
2021-12-10 14:07:47 +03:00
2022-12-21 14:36:53 +03:00
# nickel-lang.org expects an interface `nickel-repl.wasm`, hence the
# `ln`
installPhaseCommand = ''
2022-01-19 11:23:22 +03:00
mkdir - p $ out
2022-12-21 14:36:53 +03:00
cp - r nickel-wasm-repl/pkg $ out/nickel-repl
ln - s $ out/nickel-repl/nickel_repl_bg.wasm $ out/nickel-repl/nickel_repl.wasm
2022-01-19 11:23:22 +03:00
'' ;
2022-12-21 14:36:53 +03:00
nativeBuildInputs = [
rust
pkgs . wasm-pack
pkgs . wasm-bindgen-cli
pkgs . binaryen
] ++ missingSysPkgs ;
2022-01-19 01:11:10 +03:00
} ;
2021-09-27 18:02:07 +03:00
2022-01-19 01:11:10 +03:00
buildDocker = nickel : pkgs . dockerTools . buildLayeredImage {
name = " n i c k e l " ;
tag = version ;
contents = [
nickel
pkgs . bashInteractive
] ;
config = {
Cmd = " b a s h " ;
} ;
} ;
2021-09-27 18:02:07 +03:00
2022-12-21 14:36:53 +03:00
# Build the Nickel VSCode extension. The extension seems to be required
# for the LSP to work.
2022-01-19 01:11:10 +03:00
vscodeExtension =
let node-package = ( pkgs . callPackage ./lsp/client-extension { } ) . package ;
in
( node-package . override rec {
pname = " n l s - c l i e n t " ;
outputs = [ " v s i x " " o u t " ] ;
nativeBuildInputs = with pkgs ; [
2022-11-21 14:42:16 +03:00
# `vsce` depends on `keytar`, which depends on `pkg-config` and `libsecret`
2022-01-19 01:11:10 +03:00
pkg-config
libsecret
] ;
postInstall = ''
npm run compile
mkdir - p $ vsix
echo y | npx vsce package - o $ vsix / $ { pname } . vsix
'' ;
} ) . vsix ;
2022-12-21 14:36:53 +03:00
# Copy the markdown user manual to $out.
2022-02-28 20:09:25 +03:00
userManual = pkgs . stdenv . mkDerivation {
name = " n i c k e l - u s e r - m a n u a l - ${ version } " ;
src = ./doc/manual ;
installPhase = ''
mkdir - p $ out
2022-06-21 20:32:33 +03:00
cp - r . / $ out
'' ;
} ;
2022-12-21 14:36:53 +03:00
# Generate the stdlib documentation from `nickel doc`.
2022-06-21 20:32:33 +03:00
stdlibDoc = pkgs . stdenv . mkDerivation {
name = " n i c k e l - s t d l i b - d o c - ${ version } " ;
src = ./stdlib ;
installPhase = ''
mkdir - p $ out
for file in *
do
module = $ ( basename $ file . ncl )
2022-08-03 17:15:41 +03:00
$ { self . packages . " ${ system } " . default } /bin/nickel doc - f " $ m o d u l e . n c l " \
2022-06-21 20:32:33 +03:00
- - output " $ o u t / $ m o d u l e . m d "
done
2022-02-28 20:09:25 +03:00
'' ;
} ;
2022-01-19 01:11:10 +03:00
in
rec {
packages = {
2022-12-05 19:28:45 +03:00
nickel = ( mkCraneArtifacts { } ) . nickel ;
default = packages . nickel ;
nickelWasm = buildNickelWasm { } ;
dockerImage = buildDocker packages . nickel ; # TODO: docker image should be a passthru
2022-01-19 01:11:10 +03:00
inherit vscodeExtension ;
2022-02-28 20:09:25 +03:00
inherit userManual ;
2022-06-21 20:32:33 +03:00
inherit stdlibDoc ;
2022-01-19 01:11:10 +03:00
} ;
2021-09-27 18:02:07 +03:00
2022-12-23 12:57:27 +03:00
apps = {
default = {
type = " a p p " ;
program = " ${ packages . nickel } / b i n / n i c k e l " ;
} ;
} ;
2022-12-05 19:28:45 +03:00
devShells = ( forEachRustChannel ( channel : {
name = channel ;
value = makeDevShell { rust = mkRust { inherit channel ; rustProfile = " d e f a u l t " ; } ; } ;
} ) ) // {
2022-08-03 17:15:41 +03:00
default = devShells . stable ;
2022-12-05 19:28:45 +03:00
} ;
2022-01-19 01:11:10 +03:00
checks = {
2022-12-05 19:28:45 +03:00
inherit ( mkCraneArtifacts { } )
nickel
2023-01-14 18:03:32 +03:00
lsp-nls
2022-12-05 19:28:45 +03:00
clippy
rustfmt ;
2022-12-21 14:36:53 +03:00
# An optimizing release build is long: eschew optimizations in checks by
# building a dev profile
nickelWasm = buildNickelWasm { profile = " d e v " ; } ;
2022-11-21 14:56:42 +03:00
inherit vscodeExtension ;
2022-12-05 19:28:45 +03:00
pre-commit = pre-commit-builder { } ;
} ;
2022-01-19 01:11:10 +03:00
}
2022-01-17 01:17:41 +03:00
) ;
2020-07-03 15:22:21 +03:00
}