I have been using Nix for a couple of month, from a purely consumer perspective. In all tools that I wanted to master, producing is a great teaching tool, sometimes more than consuming.
In that effect, I wanted to see how I could install bat, without using the
predefined package.
The plan π
Download the source code
This is achieved with
fetchFromGitHub.Compile the rust binary
This is achieved with
buildRustPackage.Install it
This step varies, see below.
Nix-only π
Build π
# ./bat/default.nix
{
rustPlatform,
fetchFromGitHub,
lib,
pkgs,
...
}:
let
repo = "bat";
version = "v0.26.1";
in
rustPlatform.buildRustPackage {
pname = repo;
version = version;
src = fetchFromGitHub {
owner = "sharkdp";
repo = "bat";
rev = version;
hash = "sha256-[redacted]";
};
cargoHash = "sha256-[redacted]";
meta = {
description = "A cat(1) clone with wings";
homepage = "https://github.com/sharkdp/bat";
license = lib.licenses.asl20;
};
}
fetchFromGitHubfetches the repository, based on itsowner,repoandrev(commit, tag, or branch), and validates the downloaded content against thehash.It enables precise installation, instead of “latest”-only, and ensures that if a branch/tag changes. You need to update the hash manually, reminding you that you probably should inspect the diff as well.
rustPlatform.buildRustPackagebuilds the Rust package, from itssrc.cargoHashensures the downloaded content, including dependencies, is locked.metaadds various metadata to the package.
Install π
In your configuration.nix, add the following:
{ pkgs, ... }:
let
bat = pkgs.callPackage ./bat { };
in
{
# ...
environment.systemPackages = [ bat ];
# ...
}
This binds the variable bat to the result of the bat/default.nix
compilation. You can then install it, here as a system package.
Nix with flake π
nix flake is an experimental feature that enables packaging nix code in a
reproducible and discoverable way. It’s like a Dockerfile, but better.
Build π
# ./bat_flake/flake.nix
{
inputs.nixpkgs.url = "nixpkgs";
outputs =
{ self, nixpkgs }:
{
packages = nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed (
system:
let
pkgs = import nixpkgs { inherit system; };
repo = "bat";
version = "v0.26.0";
in
{
default = pkgs.rustPlatform.buildRustPackage {
pname = repo;
version = version;
src = pkgs.fetchFromGitHub {
owner = "sharkdp";
repo = repo;
rev = version;
hash = "sha256-[redacted]";
};
cargoHash = "sha256-[redacted]";
doCheck = false;
meta = with pkgs.lib; {
description = "A cat(1) clone with wings";
homepage = "https://github.com/sharkdp/bat";
license = licenses.asl20;
platforms = platforms.linux;
};
};
}
);
};
}
Lots of similarities with the no-flake version, and some differences:
inputs: the dependencies for this flake, here only rely onnixpkgs, and using the default.outputs: the “product” of this flake.outputs.packages: loops through all the available systems withgenAttrsandflakeExposed.It defines a
defaultfor each available system.getAttrsandflakeExposedshowcasenix-repl> lib = (import <nixpkgs> {}).lib nix-repl> lib.genAttrs [ "foo" "bar" ] (name: "hello-${name}") { bar = "hello-bar"; foo = "hello-foo"; } nix-repl> lib.systems.flakeExposed [ "x86_64-linux" "x86_64-darwin" # ... ] nix-repl> lib.genAttrs lib.systems.flakeExposed (name: {default = "${name}";} { x86_64-linux = { default = "x86_64-linux"; }; # ... }outputs.packages.${system}.defaultthe “default” output for the specified system.It directly uses the result of
buildRustPackage, as seen previously.It is required when running
nix build, ornixos-rebuild.
Build the flake with:
$ nix build
It creates a flake.lock to lock components to their hash, and produces a
result directory:
$ tree -l
.
βββ flake.lock
βββ flake.nix
βββ result -> /nix/store/[redacted]-bat-v0.26.0
βββ bin
βββ bat
Note: it builds only the current system:
$ nix flake show
git+file:///path/to?dir=nixos/packages/bat_flake
ββββpackages
ββββaarch64-darwin
β ββββdefault omitted (use '--all-systems' to show)
β # ...
ββββx86_64-linux
ββββdefault: package 'bat-v0.26.0'
Install π
In your configuration.nix, add the following:
{ ... }:
let
system = pkgs.stdenv.hostPlatform.system;
bat = (builtins.getFlake (toString ./bat_flake)).packages.${system}.default
in
{
# ...
environment.systemPackages = [ bat ];
# ...
}
The only difference with the previous method is the usage of builtins.getFlake
to build the specified flake.
toString is used to convert the relative path ./bat_flake to an absolute
path. E.g.
$ nix eval --expr 'builtins.toString ./bat_flake'
"/path/to/nixos/packages/bat_flake"
system references the current system, which matches against the built one.
Rebuilding π
In both cases, rebuilding can be achieved with:
$ nixos-rebuild
Thoughts π
- In a non-
flaked environment, using a non-flakeinstallation method seems simpler, as it requires fewer steps around the actual fetch+compilation. - Flake enable a faster iteration, as it doesn’t require a full-rebuild each time during prototyping.
- Flake are still experimental, but at this point it seems to be mostly an historical naming, because it’s one of the most used feature of nix.
- In either case, having the ability to lock down any package to the version, or commit creates amazing possibilities.
Future π
- Explore how to install two versions side by side. This require some post-build steps that I don’t yet know how to perform.
- Probably not move my config to Flake-based, as I don’t see too much benefits for now.
Acknowledments π
Thanks @tebriel for reviewing and suggesting improvements.
- https://nixos.org/
- https://github.com/sharkdp/bat
- https://github.com/NixOS/nixpkgs/blob/25.11/doc/build-helpers/fetchers.chapter.md#fetchfromgithub-fetchfromgithub
- https://github.com/NixOS/nixpkgs/blob/25.11/doc/languages-frameworks/rust.section.md#buildrustpackage-compiling-rust-applications-with-cargo-compiling-rust-applications-with-cargo
- https://github.com/NixOS/nixpkgs/blob/25.11/pkgs/by-name/ba/bat/package.nix
- https://github.com/NixOS/nixpkgs/blob/25.11/lib/systems/default.nix#L50-L58
- https://github.com/NixOS/nixpkgs/blob/25.11/lib/systems/flake-systems.nix
- https://github.com/NixOS/nixpkgs/blob/25.11/pkgs/by-name/ba/bat/package.nix
- https://nixos.org/manual/nixpkgs/stable/#function-library-lib.customisation.callPackageWith
- https://nix.dev/manual/nix/2.33/command-ref/new-cli/nix3-flake
- https://nix.dev/manual/nix/2.33/command-ref/new-cli/nix3-eval.html
- https://nix.dev/manual/nix/2.33/command-ref/new-cli/nix3-flake-show.html
- https://nix.dev/manual/nix/2.33/language/builtins#builtins-getAttr
- https://jvns.ca/blog/2023/11/11/notes-on-nix-flakes/