Nix package creation: install a not yet supported font
By David WORMS
Mar 29, 2022
Never miss our publications about Open Source, big data and distributed systems, low frequency of one email every two months.
The Nix packages collection is large with over 60 000 packages. However, chances are that sometimes the package you need is not available. You must integrate it yourself.
I needed for some fonts which were not already present inside nixpkgs. In Nix, a font is distributed as a package like any other software. One of the fonts to install is Dancing Script. At the time of this writing, searching in nixpkgs doesn’t reveal any relevant match:
nix search nixpkgs dancing
Whether your system is running NixOS or just using the Nix package manager, as I do with macOS, creating a Nix package isn’t always so hard. The package we will create works for every Nix deployment. I provide the commands for Linux running NixOS and for macOS using nix-darwin. It is certainly intimidating. You must get your hands dirty and write some code. However, considering the Nix nature, the majority of us already have a few custom Nix configuration files. I’ll illustrate the process for creating and sharing a new Nix package with the community.
Fonts installation with NixOS
NixOS propose many font packages. For a font to be visible to all your applications, it must be registered inside the fonts.fonts
options list. For example, from your main configuration.nix
file:
{ config, pkgs, ... }:
{
imports =
[
./david-framework-hardware.nix
];
# ...
fonts.enableFontDir = true;
fonts.fonts = with pkgs; [ dejavu_fonts inter ]; # ...
}
Not every font is available from nixpkgs. This is how to install a not yet supported font inside the fonts.fonts
option list by creating our package. Once the package is ready, we publish it!
Finding an appropriate example
The NixOS documentation is confusing. It is split between multiple locations. Sometimes it lacks basic information and sometimes it goes so deep into the details that it is hard to understand. Reading the source code is a good and recommended approach to learn about the language and to customize your environment.
On every system, installing a font is about downloading it and placing it in the appropriate system location. Let’s find out how other fonts are installed. For example, the Inter typeface. Lookup inter
through the Nix search. There is a source
link that points to the package inside the nixpkgs repository:
{ lib, fetchzip }:
let
version = "3.19";
in fetchzip {
name = "inter-${version}";
url = "https://github.com/rsms/inter/releases/download/v${version}/Inter-${version}.zip";
postFetch = ''
mkdir -p $out/share/fonts/opentype
unzip -j $downloadedFile \*.otf -d $out/share/fonts/opentype
'';
sha256 = "sha256-8p15thg3xyvCA/8dH2jGQoc54nzESFDyv5m47FgWrSI=";
meta = with lib; {
homepage = "https://rsms.me/inter/";
description = "A typeface specially designed for user interfaces";
license = licenses.ofl;
platforms = platforms.all;
maintainers = with maintainers; [ demize dtzWill ];
};
}
The package contains some metadata such as the package name, a link to the official project, and a description. The url
and sha256
is used by fetchzip
to download the font files. Every .otf
file is extracted from the zip archive into the $out/share/fonts/opentype
folder.
Creating a package
Looking at the Dancing Script repository, there is no download available. Instead of the fetchzip
function used to download a .zip
archive, we use the fetchFromGitHub
function to download the snapshot of a GitHub repository.
The code is organized differently, with different properties, but it achieves the same purpose. Next to your configuration.nix
file, create the dancing-script/default.nix
file:
{ lib, fetchFromGitHub }:
let
pname = "dancing-script";
version = "2.0";
in fetchFromGitHub {
name = "${pname}-${version}";
owner = "impallari";
repo = "DancingScript";
rev = "f7f54bc1b8836601dae8696666bfacd306f77e34";
sha256 = "dfFvh8h+oMhAQL9XKMrNr07VUkdQdxAsA8+q27KWWCA=";
postFetch = ''
tar xf $downloadedFile --strip=1
install -m444 -Dt $out/share/fonts/truetype fonts/ttf/*.ttf
'';
meta = with lib; {
description = "Dancing Script";
longDescription = "A lively casual script where the letters bounce and change size slightly.";
homepage = "https://github.com/impallari/DancingScript";
license = licenses.ofl;
platforms = platforms.all;
maintainers = with maintainers; [ wdavidw ];
};
}
Once the GitHub repository is fetched, we install all the .ttf
files into the $out/share/fonts/truetype
folder.
Package declaration
Assuming that we are editing a configuration.nix
file collocated with the dancing-script
folder, we import the new package to fonts.fonts
option list:
{ config, pkgs, ... }:
let
dancing-script = import ./dancing-script/default.nix { inherit lib; fetchFromGitHub = pkgs.fetchFromGitHub; };in {
imports =
[
./david-framework-hardware.nix
];
# ...
fonts.enableFontDir = true;
fonts.fonts = with pkgs; [
dancing-script dejavu_fonts
inter
];
# ...
}
Note how we satisfy the package dependencies by injecting lib
and fetchFromGitHub
when calling import
. A shorter and easier approach uses callPackage
:
{ config, pkgs, ... }:
let
dancing-script = pkgs.callPackage ./dancing-script/default.nix { };in {
imports =
[
./david-framework-hardware.nix
];
# ...
fonts.enableFontDir = true;
fonts.fonts = with pkgs; [
dancing-script dejavu_fonts
inter
];
# ...
}
Running nixos-rebuild switch
(or darwin-rebuild switch
on macOS) loads the font in the system. On Linux, fc-list
lists the fonts available in the system:
fc-list | grep dancing/nix/store/fm8y81bjhcy8p4cp32230xr78807x0ii-dancing-script-2.000/share/fonts/truetype/DancingScript-Bold.ttf: Dancing Script:style=Bold
/nix/store/fm8y81bjhcy8p4cp32230xr78807x0ii-dancing-script-2.000/share/fonts/truetype/DancingScript-Regular.ttf: Dancing Script:style=Regular
Package integration with nixpkgs
Now that our package is working, the next step is to share our work with the community.
Start by forking the nixpkgs repository and clone the fork on your machine:
git clone origin https://github.com/wdavidw/nixpkgs.git
cd nixpkgs
Insights on how to contribute to the project are written in CONTRIBUTING.md
. Creating a merge request to propose a new package involve 3 commits:
- creating the package Nix file
- updating
pkgs/top-level/all-packages.nix
to register the package - updating the
maintainers/maintainer-list.nix
to register yourself unless already present
Inside pkgs/data/fonts
, create a new dancing-script
folder and import the default.nix
file present above.
Update the all-packages.nix
and maintainer-list.nix
files as well. Their content is self-explanatory. Also, there is some sort of order inside those two files but it is not strictly enforced.
The former register our new package:
# ...
dancing-script = callPackage ../data/fonts/dancing-script { };
# ...
The later register you as a contributor:
# ...
wdavidw = {
name = "David Worms";
email = "david@adaltas.com";
github = "wdavidw";
githubId = 46896;
};
# ...
Your githubId
value is exposed by the GitHub API at https://api.github.com/users/{username}
, replacing {username}
with your GitHub handle.
The dancing-script
package is now registered in nixpkgs.
Testing packages from nixpkgs
Before submitting the pull request, it is possible to associate and test our Nix configuration with the local nixpkgs
repository. Run the nixos-rebuild switch
command (or darwin-rebuild switch
on macOS) with the extra -I
argument to reconfigure the machine with the local nixpkgs packages including our latest addition.
First, we update and simplify our configuration.nix file accordingly:
{ config, pkgs, ... }:
{
imports =
[
./david-framework-hardware.nix
];
# ...
fonts.enableFontDir = true;
fonts.fonts = with pkgs; [
dancing-script
dejavu_fonts
inter
];
# ...
}
From the nixpkgs
directory, the command to reconfigure the machine using the local nixpkgs repository is:
nixos-rebuild switch -I nixpkgs=.
Package publication
The process to share the changes with the community is standard GitOps.
Changes are committed with:
git add \
maintainers/maintainer-list.nix \
pkgs/data/fonts/dancing-script/default.nix \
pkgs/top-level/all-packages.nix
git commit -m 'dancing-script: init at 2.0'
git push origin master
The commit message respects the guidelines found in CONTRIBUTING.md
. Go to your GitHub repository and create the pull request.
Conclusion
The final result was published just before this article. The merge request is visible online as “PR #166057, dancing-script: init at 2.0”. It is merged withing 24 hours and I am now an official NixOS maintainer!