Nix Flake with 1-step Workflow

This commit is contained in:
James Brock 2022-12-11 00:14:35 +09:00
parent c65c3d2f1a
commit 780780be5c
8 changed files with 467 additions and 5 deletions

View File

@ -50,13 +50,13 @@ When using in your own Nix derivation, the best practice is calling generated sc
```nix
{ pkgs, stdenv }:
let
let
spagoPkgs = import ./spago-packages.nix { inherit pkgs; };
in
pkgs.stdenv.mkDerivation rec {
# < ... >
buildPhase =
''
buildPhase =
''
${spagoPkgs.installSpagoStyle} # == spago2nix install
${spagoPkgs.buildSpagoStyle} # == spago2nix build
${spagoPkgs.buildFromNixStore} # == spago2nix build
@ -145,6 +145,64 @@ This has a key drawback: steps 2 and 3 really ought to be a single step.
Because the `spago.dhall` file doesn't contain any cryptographic verification
of the dependencies, we can't do this as a pure one-step derivation.
## 1-Step Workflow with `flake.nix`
The 1-Step Workflow requires an impure Nix build.
There is a `flake.nix` which provides a package for building a PureScript
project in a Nix derivation. The package is a function
named `spago2nix_nativeBuildInputs` which has a “type signature” like this:
```nix
{
spago-dhall ? "spago.dhall", # the main spago.dhall file name, i.e. "spago.dhall"
srcs-dhall # array of .dhall files, i.e. [./spago.dhall ./packages.dhall]
}: []
```
The `spago2nix_nativeBuildInputs` function takes as inputs the PureScript
projects Spago `.dhall` files, and produces as output an array of
derivations to include in a `nativeBuildInputs`. For a derivation which
has those `nativeBuildInputs`, the PureScript project can be built
in the `buildPhase` by executing `build-spago-style`.
Example:
```nix
stdenv.mkDerivation {
name = "my-purescript-project";
nativeBuildInputs = [
easy-purescript-nix.purs
] ++ (
spago2nix_nativeBuildInputs {
srcs-dhall = [./spago.dhall ./packages.dhall];
}
);
src = nixpkgs.nix-gitignore.gitignoreSource [ ".git" ] ./.;
unpackPhase = ''
cp -r $src/src .
cp -r $src/test .
install-spago-style
'';
buildPhase = ''
build-spago-style "./src/**/*.purs" "./test/**/*.purs"
'';
installPhase = ''
mkdir -p $out
mv output $out/
'';
}
```
For another example, see [`test-flake/flake.nix`](test-flake/flake.nix)
in this repository which shows how to build the __uint__ package.
The `flake.nix` also has an `app` for running `spago2nix` off of Github,
for example:
```sh
nix run github:justinwoo/spago2nix#spago2nix
```
## Further Reading
@ -154,8 +212,8 @@ Here is a blog post I did about this project: <https://github.com/justinwoo/my-b
#### I get `MissingRevOrRepoResult` on a package with branch name as a version
Nix gives out the specific constant SHA256 hash for broken Git fetches, so the error is thrown.
One of the causes for a broken fetch is wrong checkout revision. Nix supports fetches by commit hash and tags out of the box, but fails at plain branch names.
Nix gives out the specific constant SHA256 hash for broken Git fetches, so the error is thrown.
One of the causes for a broken fetch is wrong checkout revision. Nix supports fetches by commit hash and tags out of the box, but fails at plain branch names.
You can use more verbose reference `refs/heads/branch-name` at `packages.dhall` before generating a `.nix` file.
However, __the branch name usage is discouraged in Spago__ ([refer to Note here](https://github.com/spacchetti/spago#override-a-package-in-the-package-set-with-a-remote-one)), it's better using a particular commit hash.

60
flake.lock Normal file
View File

@ -0,0 +1,60 @@
{
"nodes": {
"easy-purescript-nix": {
"flake": false,
"locked": {
"lastModified": 1670198178,
"narHash": "sha256-5KkyNpPakv4xIP2ba0S5GX+dcmd3AcO9kPhwa482BbA=",
"owner": "justinwoo",
"repo": "easy-purescript-nix",
"rev": "7a4cb3cd6ca53566ea1675692eab0aa13907ff09",
"type": "github"
},
"original": {
"owner": "justinwoo",
"repo": "easy-purescript-nix",
"type": "github"
}
},
"flake-utils": {
"locked": {
"lastModified": 1667395993,
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1670507980,
"narHash": "sha256-riNZa0xzM1it3pzxciwALeMs+0CsBMWIW2FqulzK8vM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "2787fc7d1e51404678614bf0fe92fc296746eec0",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"easy-purescript-nix": "easy-purescript-nix",
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

96
flake.nix Normal file
View File

@ -0,0 +1,96 @@
{
description = "PureScript build derivations from spago.dhall";
nixConfig.sandbox = "relaxed";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
easy-purescript-nix = {
url = "github:justinwoo/easy-purescript-nix";
flake = false;
};
};
outputs = { self, ... }@inputs:
inputs.flake-utils.lib.eachSystem ["x86_64-linux"] (system:
let
nixpkgs = inputs.nixpkgs.legacyPackages.${system};
easy-purescript-nix = import inputs.easy-purescript-nix {pkgs = nixpkgs;};
nix-prefetch-git-patched = import ./nix/nix-prefetch-git-patched.nix nixpkgs;
spago2nix = import ./default.nix {
pkgs = nixpkgs // {
nix-prefetch-git = nix-prefetch-git-patched;
};
};
# Generate spago-package.nix file from PureScript project Spago files.
spago-packages-nix = {
spago-dhall ? "spago.dhall", # the main spago.dhall file name, i.e. "spago.dhall"
srcs-dhall # array of .dhall files, i.e. [./spago.dhall ./packages.dhall]
}:
nixpkgs.stdenv.mkDerivation {
# https://zimbatm.com/notes/nix-packaging-the-heretic-way
# So that spago2nix can fetch packages from Github.
__noChroot = true;
# We need HTTPS to fetch from github.
SYSTEM_CERTIFICATE_PATH = "${nixpkgs.cacert}/etc/ssl/certs";
SSL_CERT_FILE = "${nixpkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
NIX_SSL_CERT_FILE = "${nixpkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
GIT_SSL_CAINFO = "${nixpkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
name = "spago-packages";
nativeBuildInputs = [
spago2nix
easy-purescript-nix.spago
];
srcs = srcs-dhall;
unpackPhase = ''
for _src in $srcs; do
cp "$_src" $(stripHash "$_src")
done
'';
buildPhase = ''
spago2nix generate 4 -- --config ${spago-dhall} --global-cache skip
'';
installPhase = ''
mkdir $out
cp spago-packages.nix $out/
'';
};
# Produce nativeBuildInputs from PureScript project Spago files.
#
# For a derivation which has those nativeBuildInputs,
# the PureScript project can be build in the buildPhase by executing
# install-spago-style or build-spago-style.
spago2nix_nativeBuildInputs = args@{
spago-dhall ? "spago.dhall", # the main spago.dhall file name, i.e. "spago.dhall"
srcs-dhall # array of .dhall files, i.e. [./spago.dhall ./packages.dhall]
}:
let
# https://nixos.wiki/wiki/Import_From_Derivation
ifd = import "${spago-packages-nix args}/spago-packages.nix" {pkgs=nixpkgs;};
in
[ ifd.installSpagoStyle ifd.buildSpagoStyle ];
in
{
packages = {
inherit spago2nix;
inherit spago-packages-nix;
inherit spago2nix_nativeBuildInputs;
};
apps = {
spago2nix = {
type = "app";
program = "${spago2nix}/bin/spago2nix";
};
};
}
);
}

View File

@ -0,0 +1,14 @@
diff --git a/nix-prefetch-git b/nix-prefetch-git
index 43f7c5a..a04566b 100755
--- a/nix-prefetch-git
+++ b/nix-prefetch-git
@@ -430,9 +430,6 @@ else
# Compute the hash.
hash=$(nix-hash --type $hashType --base32 "$tmpFile")
- # Add the downloaded file to the Nix store.
- finalPath=$(nix-store --add-fixed --recursive "$hashType" "$tmpFile")
-
if test -n "$expHash" -a "$expHash" != "$hash"; then
echo "hash mismatch for URL \`$url'. Got \`$hash'; expected \`$expHash'." >&2
exit 1

View File

@ -0,0 +1,36 @@
# taken from NixOS/nixpkgs
# https://github.com/NixOS/nixpkgs/blob/379690ba90695a6cefe20c2d51dfcd44a1e8b562/pkgs/tools/package-management/nix-prefetch-scripts/default.nix
#
# We patch nix-prefetch-git so that it doesn't call nix-store --add-fixed,
# because it requires access to the Nix daemon, which is not accessible
# in a build phase for spago2nix.
{ lib, stdenv, stdenvNoCC, gnused, nix, coreutils, findutils, gawk, git, path, makeWrapper, ... }:
let
mkPrefetchScript = tool: src: deps:
stdenv.mkDerivation {
name = "nix-prefetch-${tool}";
nativeBuildInputs = [ makeWrapper ];
dontUnpack = true;
installPhase = ''
install -vD ${src} $out/bin/$name;
wrapProgram $out/bin/$name \
--prefix PATH : ${lib.makeBinPath (deps ++ [ gnused nix ])} \
--set HOME /homeless-shelter
'';
preferLocalBuild = true;
};
patched-file = stdenvNoCC.mkDerivation {
src = "${path}/pkgs/build-support/fetchgit";
name = "nix-prefetch-git-patched";
patches = [ ./nix-prefetch-git-no-store.patch ];
phases = [ "unpackPhase" "patchPhase" "installPhase" ];
installPhase = ''
cp nix-prefetch-git $out
'';
};
in
mkPrefetchScript "git" patched-file [ coreutils findutils gawk git ]

1
test-flake/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/result

142
test-flake/flake.lock Normal file
View File

@ -0,0 +1,142 @@
{
"nodes": {
"easy-purescript-nix": {
"flake": false,
"locked": {
"lastModified": 1670198178,
"narHash": "sha256-5KkyNpPakv4xIP2ba0S5GX+dcmd3AcO9kPhwa482BbA=",
"owner": "justinwoo",
"repo": "easy-purescript-nix",
"rev": "7a4cb3cd6ca53566ea1675692eab0aa13907ff09",
"type": "github"
},
"original": {
"owner": "justinwoo",
"repo": "easy-purescript-nix",
"type": "github"
}
},
"easy-purescript-nix_2": {
"flake": false,
"locked": {
"lastModified": 1670198178,
"narHash": "sha256-5KkyNpPakv4xIP2ba0S5GX+dcmd3AcO9kPhwa482BbA=",
"owner": "justinwoo",
"repo": "easy-purescript-nix",
"rev": "7a4cb3cd6ca53566ea1675692eab0aa13907ff09",
"type": "github"
},
"original": {
"owner": "justinwoo",
"repo": "easy-purescript-nix",
"type": "github"
}
},
"flake-utils": {
"locked": {
"lastModified": 1667395993,
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"locked": {
"lastModified": 1667395993,
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1670507980,
"narHash": "sha256-riNZa0xzM1it3pzxciwALeMs+0CsBMWIW2FqulzK8vM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "2787fc7d1e51404678614bf0fe92fc296746eec0",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1670507980,
"narHash": "sha256-riNZa0xzM1it3pzxciwALeMs+0CsBMWIW2FqulzK8vM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "2787fc7d1e51404678614bf0fe92fc296746eec0",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"easy-purescript-nix": "easy-purescript-nix",
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"spago2nix": "spago2nix",
"uint": "uint"
}
},
"spago2nix": {
"inputs": {
"easy-purescript-nix": "easy-purescript-nix_2",
"flake-utils": "flake-utils_2",
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 0,
"narHash": "sha256-afN+dUKmI8qscuWOdKnGNRcXJT2II82wGz1WczVm47k=",
"path": "..",
"type": "path"
},
"original": {
"path": "..",
"type": "path"
}
},
"uint": {
"flake": false,
"locked": {
"lastModified": 1656899371,
"narHash": "sha256-HVYg43V/FlH+5cufN+cYA5Smy8hjTo8awdgyhZhfPzA=",
"owner": "purescript-contrib",
"repo": "purescript-uint",
"rev": "e5b5dbfcbab400976491da04d2eb71880fcc747b",
"type": "github"
},
"original": {
"owner": "purescript-contrib",
"repo": "purescript-uint",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

55
test-flake/flake.nix Normal file
View File

@ -0,0 +1,55 @@
# To test, run:
#
# nix build
#
{
description = "Test uint build with spago2nix_nativeBuildInputs";
nixConfig.sandbox = "relaxed";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
spago2nix.url = "path:..";
easy-purescript-nix = {
url = "github:justinwoo/easy-purescript-nix";
flake = false;
};
uint = {
url = "github:purescript-contrib/purescript-uint";
flake = false;
};
};
outputs = { self, uint, spago2nix, flake-utils, ... }@inputs:
flake-utils.lib.eachSystem ["x86_64-linux"] (system:
let
nixpkgs = inputs.nixpkgs.legacyPackages.${system};
easy-purescript-nix = import inputs.easy-purescript-nix {pkgs = nixpkgs;};
in
{
packages.default = nixpkgs.stdenv.mkDerivation {
name = "test-uint";
src = uint;
nativeBuildInputs = [
easy-purescript-nix.purs-0_15_4
] ++ (
spago2nix.packages.${system}.spago2nix_nativeBuildInputs {
srcs-dhall = [
"${uint}/spago.dhall" "${uint}/packages.dhall"];
}
);
unpackPhase = ''
cp -r $src/src .
install-spago-style
'';
buildPhase = ''
build-spago-style "./src/**/*.purs"
'';
installPhase = ''
mkdir -p $out
mv output $out/
'';
};
});
}