[
  {
    "path": ".gitignore",
    "content": "result*\n"
  },
  {
    "path": "README.md",
    "content": "# nixos-flake-example\n\n## warning\n\n**WARNING**: You should understand that:\n\n- there is currently no path to flakes being stable\n- we can't even experiment with flakes alternatives without committing to pure-eval as a stepping stone\n- the people that CARE about the problems solved by flakes seem to care about solving this problem\n- the people using impurity everywhere don't seem very motivated to dive into this problem-space\n- as a result, the tooling is completely fractured and stagnant\n- besides some UX fixes, bugfixes, and other feature-work in Nix, this has more or less been the case for years\n- I'm tired of seeing (often self-proclaimed, repeated-from-others) FUD by non-flakes users\n \n  Anyway, now you know. Proceed at your own caution.\n\n## overview\n\n**NOTE**: [nixflk](https://github.com/nrdxp/nixflk) is a better example repo for a full \nNixOS config layout, this repo is mostly to provide more context+examples around flakes, \nand to show that you can produce the same EXACT system with flakes as with nix-build, \nif you know what to do.\n\nThis readme starts out with an attempt to explain and justify flakes. It also contains\nsome examples of `nix` cli flakes syntax and tips for adopting flakes in your project.\n\nFinally, [at the end of the readme](#example-nixos-config-with-optional-flake-support)\nis an example NixOS config with a supporting `flake.nix`,\nand instructions to build it with *and without* flakes support at the same time.\n\n- [Overview of Flakes (and why you want it)](#overview-of-flakes-and-why-you-want-it)\n- [Important Related Reading](#important-related-reading)\n- [Nix CLI - Flakes Usage](#nix-cli---flakes-usage)\n  - [Useful Commands and Examples](#useful-commands-and-examples)\n    - [nixos-rebuild](#nixos-rebuild)\n    - [nix build](#nix-build)\n    - [nix flake](#nix-flake)\n  - [Auto-coercion examples](#auto-coercion-examples)\n- [Tips for Porting to Flakes](#tips-for-porting-to-flakes)\n- [Example NixOS Config with optional Flake support](#example-nixos-config-with-optional-flake-support)\n\n## Overview of Flakes (and why you want it)\n\nFlakes is a few things:\n* `flake.nix`: a Nix file, with a specific structure to describe inputs and outputs for a Nix project\n  * See [NixOS Wiki - Flakes - Input Schema](https://nixos.wiki/wiki/Flakes#Input_schema) for flake input examples\n  * See [NixOS Wiki - Flakes - Output Schema](https://nixos.wiki/wiki/Flakes#Input_schema) for flake output examples\n* `flake.lock`: a manifest that \"locks\" inputs and records the exact versions in use\n* CLI support for flake-related features\n* pure (by default) evaluations\n\nThis ultimately enables:\n* properly hermetic builds\n* fully reproducable and portable Nix projects\n* faster Nix operations due to evaluation caching enabled by pure evaluations)\n\nThis removes the need for:\n* using `niv` or other tooling to lock dependencies\n* manually documenting or scripting to ensure `NIX_PATH` is set consistently for your team\n* the need for the *\"the impure eval tree of sorrow\"* that comes with all of today's Nix impurities\n\n## Important Related Reading\n\n* [NixOS Wiki - Flakes](https://nixos.wiki/wiki/Flakes)\n  * a somewhat haphazard collection of factoids/snippets related to flakes\n  * particularly look at: **[Flake Schema](https://nixos.wiki/wiki/Flakes#Flake_schema)**, and it's two sections: **[Input Schema](https://nixos.wiki/wiki/Flakes#Input_schema)**, **[Output Schema](https://nixos.wiki/wiki/Flakes#Output_schema)**\n* [Tweag - NixOS flakes](https://www.tweag.io/blog/2020-07-31-nixos-flakes/)\n  * this article describes how to enable flake support in `nix` and `nix-daemon`\n  * reading this article is a **pre-requisite**\n  * this README.md assumes you've enabled flakes system-wide\n  * omit using `boot.isContainer = true;` on `configuration.nix` (as the article suggests) if you want to use `nixos-rebuild` rather than `nixos-container` \n\n## Nix CLI - Flakes Usage\n\nNix is in flakes mode when:\n* `--flake` is used with the `nixos-rebuild` command\n* or, when `nix build` is used with an argument like `'.#something'`  (the hash symbol separates the flake source from the attribute to build)\n\nWhen in this mode:\n* Nix flake commands will implicitly take a directory path, it expects a `flake.nix` inside\n* when you see: `nix build '.#something'`, the `.` means current directory, and `#something` means to build the `something` output attribute\n\n### Useful Commands and Examples\n#### nixos-rebuild\n* `nixos-rebuild build --flake '.#'`\n  * looks for `flake.nix` in `.` (current dir)\n  * since it's `nixos-rebuild`, it automatically tries to build:\n    * `#nixosConfigurations.{hostname}.config.system.build.toplevel`\n* `nixos-rebuild build --flake '/code/nixos-config#mysystem'`\n  * looks for `flake.nix` in `/code/nixos-config`\n  * since it's `nixos-rebuild`, it automatically tries to build:\n    * `#nixosConfigurations.mysystem.config.system.build.toplevel`\n    * (note that this time we specifically asked, and got to build the `mysystem` config)\n#### nix build\n* `nix build 'github:colemickens/nixpkgs-wayland#obs-studio'`\n  * looks for `flake.nix`  in (a checkout of `github.com/colemickens/nixpkgs-wayland`)\n  * builds and run the first attribute found:\n    * `#obs-studio`\n    * `#packages.{currentSystem}.obs-studio`\n    * TODO: finish fleshing out this list\n#### nix flake\n* `nix flake update --recreate-lock-file`\n  * updates all inputs and recreating `flake.lock`\n* `nix flake update --update-input nixpkgs`\n  * updates a single input to latest and recording it in `flake.lock`\n\n### Auto-coercion examples\n\nNix CLI will try to be ... smart and auto-coerce some output attribute paths for you.\n\n* `nix build '/some/path#obs-studio'`:\n  * builds and run the first attribute found:\n    * `/some/path#obs-studio`\n    * `/some/path#packages.x86_64-linux.obs-studio`\n    * `/some/path#legacyPackages.x86_64-linux.obs-studio`\n    * TODO: finish fleshing out this list\n    * TODO: not sure about search order, presumably the bare one would be priority\n\n## Tips for Porting to Flakes\n\n**Remove Impurities** - Since nix flakes does a 'pure' build by default,\n  * `NIX_PATH` is ignored\n  * `<nixpkgs>` imports do not work, and explicitly error\n  * local user nixpkgs config (`~/.config/{nix,nixpkgs}`) are ignore\n  * unpinned imports (aka, `fetchTarball` without a pinned `rev`+`sha256`) are forbidden\n\nTo fix these:\n  * specify all remote imports in `flake.nix` instead of using `fetchTarball`\n    * the config in this repo shows an example of using the overlay from\n      `nixpkgs-wayland`.\n    * TODO: investigate `getFlake` vs  passing `inputs` in `specialArgs`\n\n## Example NixOS Config with optional Flake support\n\nConsider the nixos configuration in this repo:\n* [./configuration.nix](./configuration.nix)\n* [./hardware-configuration.nix](./hardware-configuration.nix)\n\nThese represent an example, minimal NixOS system configuration.\n\nThe easiest way to build it, without cloning this repo:\n```\nnix build 'github:colemickens/nixos-flake-example#nixosConfigurations.mysystem.config.system.build.toplevel'\n```\n\nLet's prove that we can build this config, with and without flakes:\n\n* Using `nixos-rebuild`:\n    ```shell\n    # with flakes\n    unset NIX_PATH\n    nixos-rebuild build --flake '.#mysystem'\n    readlink -f ./result\n    /nix/store/gg1jhmzqndqa0rfnwfdbnzrn8f74ckr6-nixos-system-mysystem-21.03pre-git\n\n    # !! for this next step, match the git SHA1 to what the flake.lock uses\n    #    otherwise you'll have a hash mismatch due to different nixpkgs\n\n    # without flakes\n    export NIX_PATH=nixpkgs=https://github.com/nixos/nixpkgs/archive/007126eef72271480cb7670e19e501a1ad2c1ff2.tar.gz:nixos-config=/home/cole/code/nixos-flake-example/configuration.nix\n    nixos-rebuild build\n    readlink -f ./result\n    /nix/store/gg1jhmzqndqa0rfnwfdbnzrn8f74ckr6-nixos-system-mysystem-21.03pre-git\n    ```\n\n* Using `nix build`:\n    ```shell\n    # with flakes\n    unset NIX_PATH\n    nix build '.#nixosConfigurations.mysystem.config.system.build.toplevel\n    readlink -f ./result\n    /nix/store/gg1jhmzqndqa0rfnwfdbnzrn8f74ckr6-nixos-system-mysystem-21.03pre-git\n\n    # without flakes\n    export NIX_PATH=nixpkgs=https://github.com/nixos/nixpkgs/archive/007126eef72271480cb7670e19e501a1ad2c1ff2.tar.gz:nixos-config=/home/cole/code/nixos-flake-example/configuration.nix\n    nix-build '<nixos/nixpkgs>' -A config.system.build.toplevel\n    readlink -f ./result\n    /nix/store/gg1jhmzqndqa0rfnwfdbnzrn8f74ckr6-nixos-system-mysystem-21.03pre-git\n    ```\n\n* The `./check.sh` script automates this process:\n\n    ```shell\n    cole@slynux ~/code/nixos-flake-example master* 7s\n    ❯ ./check.sh     \n\n    :: Updating the 'nixpkgs' input in flake.nix\n    + nix flake update --update-input nixpkgs\n    + set +x\n\n    :: Using 'nixos-rebuild' to build the 'mysystem' toplevel\n    + nixos-rebuild build --flake '.#mysystem'\n    warning: Git tree '/home/cole/code/nixos-flake-example' is dirty\n    building the system configuration...\n    warning: Git tree '/home/cole/code/nixos-flake-example' is dirty\n    + set +x\n\n    :: Using rev=007126eef72271480cb7670e19e501a1ad2c1ff2 for <nixpkgs> (extracted from flake.nix)\n\n    :: Setting NIX_PATH to the same values flakes is using\n    + NIX_PATH=nixpkgs=https://github.com/nixos/nixpkgs/archive/007126eef72271480cb7670e19e501a1ad2c1ff2.tar.gz:nixos-config=/home/cole/code/nixos-flake-example/configuration.nix\n    + nix-build '<nixpkgs/nixos>' -A config.system.build.toplevel\n    /nix/store/gg1jhmzqndqa0rfnwfdbnzrn8f74ckr6-nixos-system-mysystem-21.03pre-git\n    + set +x\n\n    flake: /nix/store/gg1jhmzqndqa0rfnwfdbnzrn8f74ckr6-nixos-system-mysystem-21.03pre-git\n    clssc: /nix/store/gg1jhmzqndqa0rfnwfdbnzrn8f74ckr6-nixos-system-mysystem-21.03pre-git\n    ```\n\n# Flake Feedback/Ponderings\n\n- Is the hash tag syntax really worth it?\n  - For example, is:\n    - `nix build 'github:colemickens/nixpkgs-wayland#obs-studio'`\n  - really better than:\n    - `nix build --flake 'github:colemickens/nixpkgs-wayland' 'obs-studio'` ?\n\n- Are the auto-coercion rules for attribute paths worth it?\n  They definitely add some mental overhead...\n\n- \n"
  },
  {
    "path": "check.sh",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\n\nrm -f result\nunset NIX_PATH\n\necho\necho \":: Updating the 'nixpkgs' input in flake.nix\"; set -x\nnix flake update --update-input nixpkgs &>/dev/null\nset +x\n\necho\necho \":: Using 'nixos-rebuild' to build the 'mysystem' toplevel\"; set -x\nnixos-rebuild build --flake '.#mysystem'\nset +x\nflake_path=\"$(readlink -f ./result)\"\n\n# extract rev from flake.lock so we can figure out the nixpkgs rev used\nrev=\"$(cat flake.lock| jq -r '.nodes.nixpkgs.locked.rev')\"\necho\necho \":: Using rev=${rev} for <nixpkgs> (extracted from flake.nix)\"; set +x\n\n\nrm -f result\nnixpkgs=\"https://github.com/nixos/nixpkgs/archive/${rev}.tar.gz\"\nnixosconfig=\"$(pwd)/configuration.nix\"\n\necho\necho \":: Setting NIX_PATH to the same values flakes is using\"; set -x\nNIX_PATH=\"nixpkgs=${nixpkgs}:nixos-config=${nixosconfig}\" \\\n  nix-build '<nixpkgs/nixos>' -A config.system.build.toplevel\nset +x\n\n#  nixos-rebuild build\n\nclassic_path=\"$(readlink -f ./result)\"\n\nset +x\necho\necho \"flake: ${flake_path}\"\necho \"clssc: ${classic_path}\"\n\nif [[ \"${flake_path}\" != \"${classic_path}\" ]]; then\n  exit -1\nfi\n\n"
  },
  {
    "path": "configuration.nix",
    "content": "# Edit this configuration file to define what should be installed on\n# your system.  Help is available in the configuration.nix(5) man page\n# and in the NixOS manual (accessible by running ‘nixos-help’).\n\n{ config, pkgs, lib, modulesPath, inputs, ... }:\n\n{\n\n  imports = [\n    ./hardware-configuration.nix\n  ];\n\n  services.sshd.enable = true;\n\n  networking.hostName = \"mysystem\";\n\n  nixpkgs.overlays = [ inputs.nur.overlay ];\n\n  environment.systemPackages = with pkgs; [\n    pkgs.nur.repos.mic92.hello-nur\n  ];\n}\n\n"
  },
  {
    "path": "flake.nix",
    "content": "\n{\n  description = \"An example NixOS configuration\";\n\n  inputs = {\n    nixpkgs = { url = \"github:nixos/nixpkgs/nixos-unstable\"; };\n    nur = { url = \"github:nix-community/NUR\"; };\n  };\n\n  outputs = inputs:\n    /* ignore:: */ let ignoreme = ({config,lib,...}: with lib; { system.nixos.revision = mkForce null; system.nixos.versionSuffix = mkForce \"pre-git\"; }); in\n  {\n    nixosConfigurations = {\n\n      mysystem = inputs.nixpkgs.lib.nixosSystem {\n        system = \"x86_64-linux\";\n        modules = [\n          ./configuration.nix\n\n          /* ignore */ ignoreme # ignore this; don't include it; it is a small helper for this example\n        ];\n        specialArgs = { inherit inputs; };\n      };\n    };\n  };\n}\n\n"
  },
  {
    "path": "hardware-configuration.nix",
    "content": "# these args are passed into every nixos module (or file that is in included in a nixos module imports=[...])\n{\n    modulesPath, # this variable, in particular, gives us the nixos modules path for our system config\n    ...\n}:\n\n{\n    imports = [\n        # note: this format can't be used with flakes, because it pulls from\n        # NIX_PATH, which is impure, and dis-allowed with flakes.\n        # Use the format shown in the line below it.\n\n        #<nixpkgs/nixos/modules/installer/scan/not-detected.nix>\n\n        \"${modulesPath}/installer/scan/not-detected.nix\"\n\n    ];\n    boot.loader.systemd-boot.enable = true; # (for UEFI systems only)\n    fileSystems.\"/\".device = \"/dev/disk/by-label/nixos\";\n}\n"
  }
]