From a7733d1d2bb0cdf6214b368245df3542317065cd Mon Sep 17 00:00:00 2001 From: Youwen Wu Date: Wed, 1 Jan 2025 03:36:12 -0800 Subject: [PATCH] feat: add nixos hacks --- content/Hacks/nixos-cheat-sheet.md | 193 +++++++++++++++++++++++++++++ content/index.md | 9 ++ 2 files changed, 202 insertions(+) create mode 100644 content/Hacks/nixos-cheat-sheet.md diff --git a/content/Hacks/nixos-cheat-sheet.md b/content/Hacks/nixos-cheat-sheet.md new file mode 100644 index 0000000..68ba015 --- /dev/null +++ b/content/Hacks/nixos-cheat-sheet.md @@ -0,0 +1,193 @@ +--- +id: nixos-cheat-sheet +aliases: [] +tags: + - nixos + - nixpkgs + - linux +--- + +# Assorted NixOS hacks and tricks + +The Nix package manager and NixOS Linux distribution are woefully +underdocumented. There are many, many powerful features that are difficult to +find, sans directly reading through source code. + +I can't fix that, but this document serves as a personal cheat sheet of all the +small Nix features that I don't want to forget. + +## Derivations + +Stuff related to writing derivations of software. + +### Sparse Checkout with fetchGit (and friends) + +You can do sparse checkouts when using `fetchgit` and its friends +`fetchFromGitHub`, etc. This is useful if you're cloning a large repository and +know you only need one specific directory. If you only need a specific file, +consider `fetchurl`. + +```nix +fetchgit { + url = "https://github.com/foo/bar"; + hash = "sha256-0000000000000000000000000000000"; + + # takes a list of directories that should be checked out + sparseCheckout = ["dir", "another/dir", "foo/bar/dir"]; +} +``` + +### The `callPackage` pattern + +This isn't even a note for myself since I use this feature so much, but I'm add +it anyways so I can point to it as a reference. + +When you look at `package.nix` files in the source code of `nixpkgs`, you'll +see they typically take the form: + +```nix +{ +stdenv, +libfoo, +libbar, +fetchFromGitHub, +... +}: +stdenv.mkDerivation { + nativeBuildInputs = [ stdenv libfoo libbar ]; + + src = fetchFromGitHub { + # blah blah + }; + # rest of file omitted for brevity +} +``` + +It's a lambda (anonymous function) that takes in an attrset of everything the +derivation needs, and returns the derivation. As you clearly see, the `...` +means that the attrset contains all of the attributes specified, but also +arbitrarily more. + +Exactly what attributes are available in this input attrset? It turns out that +this attrset is actually populated with the _entirety of nixpkgs_. Basically, +any package that can be referencd from `pkgs.xxx` is available in that input +attrset. + +This is very useful for writing clean derivations. Oftentimes I see people +haphazardly pass `pkgs` around to all their derivations and directly make use +of it. While this is fine in small derivations, it quickly gets messy in large +ones. I prefer to always write non-trivial derivations using the nixpkgs +pattern. However, how do we go from a file like the example above to an actual +package that we can, say, output from a flake? + +There's a function called `pkgs.callPackage` that handles precisely this task. +It takes in two arguments. Here is its pseudo type signature: + +``` +callPackage :: file -> attrset -> package +``` + +The first argument is the file that contains the derivation as shown in the +example. The second argument is an attrset that allows you to pass or overwrite +any values in the attrset passed to argument 1. + +Oftentimes the second argument is not even needed and so you simply pass an +empty attrset (`{ }`). + +```nix +packages.default = pkgs.callPackage ./my-derivation.nix { }; +``` + +An example of the second argument in use is in a situation where you have a +flake that provides multiple packages, but one of these packages depends on the +other. Then, you can pass the packages to each other using the attrset +argument. + +```nix +packages = rec { + foo = pkgs.callPackage ./foo.nix { inherit bar; }; + bar = pkgs.callPackage ./bar.nix { }; +}; +``` + +Then, in the corresponding derivation of `foo`, `bar` will be available as an input: + +```nix +# file: foo.nix +{ + stdenv, + libblah, + bar, # the bar package we provided is now available here + ... +}: +stdenv.mkDerivation { + buildInputs = [ bar ]; +} +``` + +## nixpkgs and the nixpkgs lib + +General stuff related to quirks in nixpkgs and `lib`. + +## Flakes + +Niche features of Nix flakes. + +### Nix flake inputs have additional properties + +Everyone knows the common properties of Nix flake inputs: the standard outputs +like `packages`, `apps`, `nixosModules`, etc. + +However, there a few that I have seen seldom used and hard to find mentions of +in documentation + +```nix +{ + inputs.cool-flake.url = "github:hackerman/cool-flake"; + + outputs = + { self, cool-flake, ...}: + { + # gives the commit hash of the flake + rev = cool-flake.rev; + + # gives the UNIX timestamp of the commit of the flake + lastModified = cool-flake.lastModified; + + # you can also get these attributes on the current flake using `self` + + # gets current git commit hash + # caveat: this property isn't defined if the git tree is dirty (there are uncommitted changes) + selfRev = self.rev; + + # I often use this pattern due to the above reason + selfRev' = if (self ? rev) then self.rev else "FALLBACK" + } +} +``` + +## NixOS + +Things from the NixOS distribution, including the module system. + +## Misc + +Stuff to do with other stuff. Potentially community made flakes. + +### Set the right time in Typix (and LaTeX) + +When using Typix to compile Typst documents, sometimes it's a little _too +reproducible_. Attempting to reference the current date and time in the Typst +document will always return `January 1st, 1980` when compiled in the Nix build +environment. + +You can set an environment variable to get the right time. + +``` +SOURCE_DATE_EPOCH = builtins.toString self.lastModified; +``` + +Here `self` is the self provided to the flake outputs that refers to the flake +itself. As shown in +[[./nixos-cheat-sheet.md#Nix-flake-inputs-have-additional-properties]], you can +get the timestamp of the current Git commit. diff --git a/content/index.md b/content/index.md index 6ba67b9..38369b3 100644 --- a/content/index.md +++ b/content/index.md @@ -1,4 +1,7 @@ --- +id: index +aliases: [] +tags: [] title: "Alexandria: a knowledge garden" --- @@ -15,6 +18,12 @@ which I took in the fall quarter of 2024. You can find them in [[./Fall-2024/as-am-5/week-2.md]] and [[./Fall-2024/mes-45/week-1.md]] being the weekly notes. +If you're interested in the Nix package manager, I've also started maintaining +a sort of "cheat sheet" or "tips and tricks" collection around variou quirks +and features of the NixOS / nixpkgs ecosystem in +[[assorted-nixos-hacks-and-tricks]]. Maybe you'll find something useful in +there! + Feel free to take a look around and appreciate the scenery. ## FAQ