November 7, 2024

charmnailspa

Technological development

Nix package creation: install a not yet supported font

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 = "[email protected]";
    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!