In my previous article, How to build with Nix, I explained how to write a Nix package and contribute it to
the official Nix package repository. One of the advantages of Nix is how easy it is to develop your own custom
Nix package repository, called a channel. A channel can be implemented simply as a tarball containing a
default.nix
file like this:
let
pkgs = import <nixpkgs> {};
in
{
knock = pkgs.callPackage ./pkgs/knock.nix {};
}
In this example, we take the knock
program described in the previous article and put it in a
pkgs
directory—this is optional, I just like to keep the directory organized this way.
The callPackage
function handles making sure that the knock.nix
package gets the parameters
it needs. The advantage of this pattern is that it allows you to develop your own packages just as
if you were doing it for the official repository:
{ lib, buildGoModule, installShellFiles, fetchFromGitHub }:
buildGoModule rec {
pname = "knock";
version = "0.0.2";
src = fetchFromGitHub {
owner = "nat-418";
repo = pname;
rev = "a3749685381cae178bb5836c67645e0fce7aa1d0";
hash = "sha256-VXrWphfBDGDNsz4iuUdwwd46oqnmhJ9i3TtzMqHoSJk=";
};
vendorHash = "sha256-wkSXdIgfkHbVJYsgm/hLAeKA9geof92U3mzSzt7eJE8=";
outputs = [ "out" "man" ];
nativeBuildInputs = [ installShellFiles ];
postInstall = ''
installManPage man/man1/knock.1
'';
meta = with lib; {
description = "A simple CLI network reachability tester";
homepage = "https://github.com/nat-418/knock";
license = licenses.bsd0;
changelog = "https://github.com/nat-418/knock/blob/${version}/CHANGELOG.md";
maintainers = with maintainers; [ nat-418 ];
};
}
Once you have the above, you can test it with a quick nix-build
. If that works,
it should produce a result
symlink pointing to artifacts in the Nix store.
If everything looks good, you just need to distribute this directory as a tarball.
Probably the easiest way to do this is using GitHub. Every GitHub repository has
an automatic archive accessible at
https://github.com/$USER_NAME/$REPO_NAME/archive/$BRANCH_NAME.tar.gz
.
You can add that as a Nix channel like so:
$ nix-channel --add https://github.com/nat-418/grimoire/archive/main.tar.gz grimoire
$ nix-channel --update
You can now use, e.g., <grimoire>
in your Nix files just as you use <nixpkgs>
.
Here's an example using Home Manager:
{pkgs, config, ...}:
let
grimoire = import <grimoire> {};
in
{
home = {
packages = with pkgs; [
abduco
age
# more packages
grimoire.knock
];
# more config
};
}
There are many uses for a custom channel: from project-specific tools to just getting your own software released without having to ask anyone else to accept a pull request. Nix gives you that flexibility in a simple and easy-to-maintain solution.