A somewhat common theme I’ve noticed when working on various projects is the need for “one-off” re-usable scripts, these are typically more than a few lines of code.

For example, in my Advent of Code repository I have a small Python script that pulls the input down given a year and day. But rather than wanting to manage this script explicitly, I wanted to encapsulate it as part of my flake so I can call it directly via nix.

It turns out, Nix has the concept of writers. These are functions that allow you to write other languages inline, in nix code.1 One other nice thing about this: you can add language-specific libraries as dependencies.

Here’s my Python script now:

pkgs.writers.writePython3Bin "get_input" {
  libraries = [ pkgs.python3Packages.requests ];
} ''
  import requests
  import sys

  year, day = sys.argv[1], sys.argv[2]
  url = 'https://adventofcode.com/{}/day/{}/input'.format(year, day)
  cookie = open('cookie.txt').read().strip()

  r = requests.get(url, cookies={'session': cookie})
  print(r.text)
'';

Notice I was able to add requests as a library. From here, I am able to call this script directly via the command:

$ nix run . -- 2022 5

There are some other ways this can be extended of course:

  1. Adding more scripts, effectively making the flake a trivial command runner.
  2. If the script becomes too large, you can always split it back out into its own file, then directly reading that file into the flake.
  3. Placing the script as a package in a dev shell, so that it’s available via nix develop.

  1. Thank you fellow Nix enthusiasts in the Matrix channel for pointing me to these. ↩︎