nix: switch to Nix Flake

This modernizes the Nix files of this project. Nix Flakes are the
de-facto standard way in Nix to package projects and specify their
inputs. Inputs can be any Nix or non-Nix project.

Updating Nix dependencies now is as easy as `nix flake update` and
a corresponding commit.

As they are still not stabilized yet, you need the line

    experimental-features = nix-command flakes

in /etc/nix/nix.conf to use the flake. By usage, I mean entering
the Nix development shell using `$ nix develop .` or if you want
to run `nix flake update`.

The package manager niv, we used to have, is basically dead.
This commit is contained in:
Philipp Schuster
2025-03-02 11:48:36 +01:00
parent 07938b6868
commit db9377c6e0
9 changed files with 135 additions and 336 deletions
+3 -2
View File
@@ -1,2 +1,3 @@
# If your shell has direnv support, it will automatically open a "nix-shell".
use nix
# If your shell has direnv support, it will automatically open a Nix shell with
# all relevant dependencies to develop this project.
use flake
+8 -11
View File
@@ -4,7 +4,7 @@ on:
push:
pull_request:
jobs:
# Job to run change detection
# Job to run change detection for Nix-related files
changes:
runs-on: ubuntu-latest
# Set job outputs to values from filter step.
@@ -19,13 +19,14 @@ jobs:
filters: |
nix-src:
- 'nix/**'
- 'shell.nix'
- 'flake.nix'
- 'flake.lock'
# This is a convenience test to verify that the toolchain provided by
# shell.nix is valid and can build + run the integration test.
#
# It only runs if the "nix-src" output of the "changes" job is true.
nix_shell_toolchain:
name: "Nix toolchain: `cargo xtask run` works"
name: "Nix shell toolchain: `cargo xtask run` works"
needs: changes
if: ${{ needs.changes.outputs.nix-src == 'true' }}
runs-on: ubuntu-latest
@@ -34,17 +35,13 @@ jobs:
uses: actions/checkout@v4
- uses: Swatinem/rust-cache@v2
- uses: cachix/install-nix-action@v30
with:
# This channel is only required to invoke "nix-shell".
# Everything inside that nix-shell will use a pinned version of nixpkgs.
nix_path: nixpkgs=channel:nixpkgs-unstable
# Dedicated step to separate all the
# "copying path '/nix/store/...' from 'https://cache.nixos.org'."
# messages from the actual build output. This job takes ~60secs.
# messages from the actual build output.
- name: Prepare Nix Store
run: nix-shell --pure --run "cargo --version"
run: nix develop --command bash -c "cargo --version"
- name: Run VM tests
run: |
COMMAND="cargo xtask run --target x86_64 --headless --ci --tpm=v1"
echo "Executing in nix shell: $COMMAND"
nix-shell --pure --run "$COMMAND"
echo "Executing in Nix shell: $COMMAND"
nix develop --command bash -c "$COMMAND"
Generated
+62
View File
@@ -0,0 +1,62 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1740743217,
"narHash": "sha256-brsCRzLqimpyhORma84c3W2xPbIidZlIc3JGIuQVSNI=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "b27ba4eb322d9d2bf2dc9ada9fd59442f50c8d7c",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-24.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1736320768,
"narHash": "sha256-nIYdTAiKIGnFNugbomgBJR+Xv5F1ZQU+HfaBqJKroC0=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "4bc9c909d9ac828a039f288cf872d16d38185db8",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs",
"rust-overlay": "rust-overlay"
}
},
"rust-overlay": {
"inputs": {
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1740882709,
"narHash": "sha256-VC+8GxWK4p08jjIbmsNfeFQajW2lsiOR/XQiOOvqgvs=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "f4d5a693c18b389f0d58f55b6f7be6ef85af186f",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
}
},
"root": "root",
"version": 7
}
+61
View File
@@ -0,0 +1,61 @@
{
description = "uefi-rs";
inputs = {
# We follow the latest stable release of nixpkgs
nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11";
rust-overlay.url = "github:oxalica/rust-overlay";
};
outputs =
inputs@{ self, nixpkgs, ... }:
let
# Systems definition for dev shells and exported packages,
# independent of the NixOS configurations and modules defined here. We
# just use "every system" here to not restrict any user. However, it
# likely happens that certain packages don't build for/under certain
# systems.
systems = nixpkgs.lib.systems.flakeExposed;
forAllSystems =
function: nixpkgs.lib.genAttrs systems (system: function nixpkgs.legacyPackages.${system});
# We directly instantiate the functionality, without using an
# nixpkgs overlay.
# https://github.com/oxalica/rust-overlay/blob/f4d5a693c18b389f0d58f55b6f7be6ef85af186f/docs/reference.md?plain=1#L26
rustToolchain =
pkgs:
let
rust-bin = (inputs.rust-overlay.lib.mkRustBin { }) pkgs;
rustToolchainBuilder = import ./nix/rust-toolchain.nix;
in
rustToolchainBuilder { inherit rust-bin; };
in
{
devShells = forAllSystems (pkgs: {
default = pkgs.mkShell {
packages = with pkgs; [
nixfmt-rfc-style
# Integration test dependencies
swtpm
qemu
# Rust toolchain
(rustToolchain pkgs)
# Other
cargo-llvm-cov
mdbook
yamlfmt
which # used by "cargo xtask fmt"
];
# Set ENV vars.
# OVMF_CODE="${pkgs.OVMF.firmware}";
# OVMF_VARS="${pkgs.OVMF.variables}";
# OVMF_SHELL="${pkgs.edk2-uefi-shell}";
};
});
formatter = forAllSystems (pkgs: pkgs.nixfmt-rfc-style);
};
}
-5
View File
@@ -1,5 +0,0 @@
let
sources = import ./sources.nix { };
rust-overlay = import sources.rust-overlay;
in
import sources.nixpkgs { overlays = [ rust-overlay ]; }
+1 -2
View File
@@ -1,5 +1,4 @@
# Returns the Rust toolchain for Nix compliant to the rust-toolchain.toml file
# but without rustup.
# Returns a Rust toolchain for Nix that matches the one from the toolchain file.
{
# Comes from rust-overlay
-26
View File
@@ -1,26 +0,0 @@
{
"nixpkgs": {
"branch": "nixos-24.05",
"description": "Nix Packages collection",
"homepage": null,
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "a9b86fc2290b69375c5542b622088eb6eca2a7c3",
"sha256": "1mssfzy1nsansjmp5ckyl8vbk32va3abchpg19ljyak0xblxnjs1",
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/a9b86fc2290b69375c5542b622088eb6eca2a7c3.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
},
"rust-overlay": {
"branch": "master",
"description": "Pure and reproducible nix overlay of binary distributed rust toolchains",
"homepage": "",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "ada8266712449c4c0e6ee6fcbc442b3c217c79e1",
"sha256": "1y5fq080nqknps35pmfdyxy7vys1bzdkqzrhh41fxq3jkiw74idg",
"type": "tarball",
"url": "https://github.com/oxalica/rust-overlay/archive/ada8266712449c4c0e6ee6fcbc442b3c217c79e1.tar.gz",
"url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
}
}
-250
View File
@@ -1,250 +0,0 @@
# This file has been generated by Niv.
let
#
# The fetchers. fetch_<type> fetches specs of type <type>.
#
fetch_file =
pkgs: name: spec:
let
name' = sanitizeName name + "-src";
in
if spec.builtin or true then
builtins_fetchurl {
inherit (spec) url sha256;
name = name';
}
else
pkgs.fetchurl {
inherit (spec) url sha256;
name = name';
};
fetch_tarball =
pkgs: name: spec:
let
name' = sanitizeName name + "-src";
in
if spec.builtin or true then
builtins_fetchTarball {
name = name';
inherit (spec) url sha256;
}
else
pkgs.fetchzip {
name = name';
inherit (spec) url sha256;
};
fetch_git =
name: spec:
let
ref =
if spec ? ref then
spec.ref
else if spec ? branch then
"refs/heads/${spec.branch}"
else if spec ? tag then
"refs/tags/${spec.tag}"
else
abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!";
submodules = if spec ? submodules then spec.submodules else false;
submoduleArg =
let
nixSupportsSubmodules = builtins.compareVersions builtins.nixVersion "2.4" >= 0;
emptyArgWithWarning =
if submodules == true then
builtins.trace (
"The niv input \"${name}\" uses submodules "
+ "but your nix's (${builtins.nixVersion}) builtins.fetchGit "
+ "does not support them"
) { }
else
{ };
in
if nixSupportsSubmodules then { inherit submodules; } else emptyArgWithWarning;
in
builtins.fetchGit (
{
url = spec.repo;
inherit (spec) rev;
inherit ref;
}
// submoduleArg
);
fetch_local = spec: spec.path;
fetch_builtin-tarball =
name:
throw ''
[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`.
$ niv modify ${name} -a type=tarball -a builtin=true'';
fetch_builtin-url =
name:
throw ''
[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`.
$ niv modify ${name} -a type=file -a builtin=true'';
#
# Various helpers
#
# https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695
sanitizeName =
name:
(concatMapStrings (s: if builtins.isList s then "-" else s) (
builtins.split "[^[:alnum:]+._?=-]+" ((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name)
));
# The set of packages used when specs are fetched using non-builtins.
mkPkgs =
sources: system:
let
sourcesNixpkgs = import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) {
inherit system;
};
hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath;
hasThisAsNixpkgsPath = <nixpkgs> == ./.;
in
if builtins.hasAttr "nixpkgs" sources then
sourcesNixpkgs
else if hasNixpkgsPath && !hasThisAsNixpkgsPath then
import <nixpkgs> { }
else
abort ''
Please specify either <nixpkgs> (through -I or NIX_PATH=nixpkgs=...) or
add a package called "nixpkgs" to your sources.json.
'';
# The actual fetching function.
fetch =
pkgs: name: spec:
if !builtins.hasAttr "type" spec then
abort "ERROR: niv spec ${name} does not have a 'type' attribute"
else if spec.type == "file" then
fetch_file pkgs name spec
else if spec.type == "tarball" then
fetch_tarball pkgs name spec
else if spec.type == "git" then
fetch_git name spec
else if spec.type == "local" then
fetch_local spec
else if spec.type == "builtin-tarball" then
fetch_builtin-tarball name
else if spec.type == "builtin-url" then
fetch_builtin-url name
else
abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}";
# If the environment variable NIV_OVERRIDE_${name} is set, then use
# the path directly as opposed to the fetched source.
replace =
name: drv:
let
saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name;
ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}";
in
if ersatz == "" then
drv
else
# this turns the string into an actual Nix path (for both absolute and
# relative paths)
if builtins.substring 0 1 ersatz == "/" then
/. + ersatz
else
/. + builtins.getEnv "PWD" + "/${ersatz}";
# Ports of functions for older nix versions
# a Nix version of mapAttrs if the built-in doesn't exist
mapAttrs =
builtins.mapAttrs or (
f: set:
with builtins;
listToAttrs (
map (attr: {
name = attr;
value = f attr set.${attr};
}) (attrNames set)
)
);
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
range =
first: last: if first > last then [ ] else builtins.genList (n: first + n) (last - first + 1);
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
# https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
concatMapStrings = f: list: concatStrings (map f list);
concatStrings = builtins.concatStringsSep "";
# https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331
optionalAttrs = cond: as: if cond then as else { };
# fetchTarball version that is compatible between all the versions of Nix
builtins_fetchTarball =
{
url,
name ? null,
sha256,
}@attrs:
let
inherit (builtins) lessThan nixVersion fetchTarball;
in
if lessThan nixVersion "1.12" then
fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
else
fetchTarball attrs;
# fetchurl version that is compatible between all the versions of Nix
builtins_fetchurl =
{
url,
name ? null,
sha256,
}@attrs:
let
inherit (builtins) lessThan nixVersion fetchurl;
in
if lessThan nixVersion "1.12" then
fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
else
fetchurl attrs;
# Create the final "sources" from the config
mkSources =
config:
mapAttrs (
name: spec:
if builtins.hasAttr "outPath" spec then
abort "The values in sources.json should not have an 'outPath' attribute"
else
spec // { outPath = replace name (fetch config.pkgs name spec); }
) config.sources;
# The "config" used by the fetchers
mkConfig =
{
sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null,
sources ? if isNull sourcesFile then { } else builtins.fromJSON (builtins.readFile sourcesFile),
system ? builtins.currentSystem,
pkgs ? mkPkgs sources system,
}:
rec {
# The sources, i.e. the attribute set of spec name to spec
inherit sources;
# The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
inherit pkgs;
};
in
mkSources (mkConfig { }) // { __functor = _: settings: mkSources (mkConfig settings); }
-40
View File
@@ -1,40 +0,0 @@
# Sets up a basic shell environment with all relevant tooling to run
# "cargo xtask run|test|clippy". It uses rustup rather than a pinned rust
# toolchain.
let
sources = import ./nix/sources.nix;
pkgs = import ./nix/nixpkgs.nix;
rustToolchain = pkgs.callPackage ./nix/rust-toolchain.nix { };
in
pkgs.mkShell {
nativeBuildInputs = with pkgs; [
# nix related stuff (such as dependency management)
niv
# TODO use "nixfmt" once it is stable - likely in nixpkgs @ NixOS 24.11
nixfmt-rfc-style
# Integration test dependencies
swtpm
qemu
# Rust toolchain
rustToolchain
# Other
cargo-llvm-cov
mdbook
yamlfmt
which # used by "cargo xtask fmt"
];
# Set ENV vars.
# OVMF_CODE="${pkgs.OVMF.firmware}";
# OVMF_VARS="${pkgs.OVMF.variables}";
# OVMF_SHELL="${pkgs.edk2-uefi-shell}";
# To invoke "nix-shell" in the CI-runner, we need a global Nix channel.
# For better reproducibility inside the Nix shell, we override this channel
# with the pinned nixpkgs version.
NIX_PATH = "nixpkgs=${sources.nixpkgs}";
}