about summary refs log tree commit diff
path: root/nixpkgs/pkgs/tools/nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/pkgs/tools/nix')
-rw-r--r--nixpkgs/pkgs/tools/nix/cached-nix-shell/default.nix46
-rw-r--r--nixpkgs/pkgs/tools/nix/dnadd/default.nix22
-rw-r--r--nixpkgs/pkgs/tools/nix/info/default.nix45
-rwxr-xr-xnixpkgs/pkgs/tools/nix/info/info.sh169
-rw-r--r--nixpkgs/pkgs/tools/nix/info/multiuser.nix12
-rw-r--r--nixpkgs/pkgs/tools/nix/info/relaxedsandbox.nix12
-rw-r--r--nixpkgs/pkgs/tools/nix/info/sandbox.nix10
-rw-r--r--nixpkgs/pkgs/tools/nix/manix/default.nix25
-rw-r--r--nixpkgs/pkgs/tools/nix/nar-serve/default.nix26
-rw-r--r--nixpkgs/pkgs/tools/nix/nix-output-monitor/default.nix41
-rw-r--r--nixpkgs/pkgs/tools/nix/nix-query-tree-viewer/default.nix32
-rw-r--r--nixpkgs/pkgs/tools/nix/nix-script/default.nix41
-rw-r--r--nixpkgs/pkgs/tools/nix/nix-store-gcs-proxy/default.nix24
-rw-r--r--nixpkgs/pkgs/tools/nix/nix-store-gcs-proxy/deps.nix813
-rw-r--r--nixpkgs/pkgs/tools/nix/nixdoc/default.nix25
-rw-r--r--nixpkgs/pkgs/tools/nix/nixos-generators/default.nix26
-rw-r--r--nixpkgs/pkgs/tools/nix/nixos-install-tools/default.nix69
-rw-r--r--nixpkgs/pkgs/tools/nix/nixos-option/CMakeLists.txt8
-rw-r--r--nixpkgs/pkgs/tools/nix/nixos-option/default.nix13
-rw-r--r--nixpkgs/pkgs/tools/nix/nixos-option/libnix-copy-paste.cc83
-rw-r--r--nixpkgs/pkgs/tools/nix/nixos-option/libnix-copy-paste.hh9
-rw-r--r--nixpkgs/pkgs/tools/nix/nixos-option/nixos-option.cc643
-rw-r--r--nixpkgs/pkgs/tools/nix/nixpkgs-fmt/default.nix21
-rw-r--r--nixpkgs/pkgs/tools/nix/rnix-hashes/default.nix30
24 files changed, 2245 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/tools/nix/cached-nix-shell/default.nix b/nixpkgs/pkgs/tools/nix/cached-nix-shell/default.nix
new file mode 100644
index 000000000000..acbb0be3b9cf
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/cached-nix-shell/default.nix
@@ -0,0 +1,46 @@
+{ lib, fetchFromGitHub, openssl, pkg-config, ronn, rustPlatform }:
+
+let
+  blake3-src = fetchFromGitHub {
+    owner = "BLAKE3-team";
+    repo = "BLAKE3";
+    rev = "0.3.3";
+    sha256 = "0av41ld0gqf3g60gcllpz59nqlr7r62v99mgfq9gs0p8diw5gi7x";
+  };
+
+in rustPlatform.buildRustPackage rec {
+  pname = "cached-nix-shell";
+  version = "0.1.4";
+
+  src = fetchFromGitHub {
+    owner = "xzfc";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "0w6khry1ncyqy5h6996xw1f6viw4wdrfji5m8lz9gm487xlq5v0b";
+  };
+
+  cargoSha256 = "05lcm5fzsn3h6dl2n2yq52r2vagrgmab08kafinz2kdcvv05wpk5";
+
+  # The BLAKE3 C library is intended to be built by the project depending on it
+  # rather than as a standalone library.
+  # https://github.com/BLAKE3-team/BLAKE3/blob/0.3.1/c/README.md#building
+  BLAKE3_CSRC = "${blake3-src}/c";
+
+  nativeBuildInputs = [ ronn ];
+
+  postBuild = ''
+    make -f nix/Makefile post-build
+  '';
+
+  postInstall = ''
+    make -f nix/Makefile post-install
+  '';
+
+  meta = with lib; {
+    description = "Instant startup time for nix-shell";
+    homepage = "https://github.com/xzfc/cached-nix-shell";
+    license = with licenses; [ unlicense /* or */ mit ];
+    maintainers = with maintainers; [ xzfc ];
+    platforms = platforms.linux;
+  };
+}
diff --git a/nixpkgs/pkgs/tools/nix/dnadd/default.nix b/nixpkgs/pkgs/tools/nix/dnadd/default.nix
new file mode 100644
index 000000000000..3f4d76a9c4d4
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/dnadd/default.nix
@@ -0,0 +1,22 @@
+{ lib, stdenv, fetchFromGitHub }:
+
+stdenv.mkDerivation rec {
+  pname = "dnadd";
+  version = "1.0.0";
+
+  src = fetchFromGitHub {
+    owner = "JoeLancaster";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "1vzbgz8y9gj4lszsx4iczfbrj373sl4wi43j7rp46zfcbw323d4r";
+  };
+
+  makeFlags = [ "PREFIX=$(out)" ];
+
+  meta = with lib; {
+    homepage = "https://github.com/joelancaster/dnadd";
+    description = "Adds packages declaratively on the command line";
+    license = licenses.gpl3Plus;
+    maintainers = with maintainers; [ joelancaster ];
+  };
+}
diff --git a/nixpkgs/pkgs/tools/nix/info/default.nix b/nixpkgs/pkgs/tools/nix/info/default.nix
new file mode 100644
index 000000000000..898026a62902
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/info/default.nix
@@ -0,0 +1,45 @@
+{ stdenv, lib, coreutils, findutils, gnugrep, darwin
+# Avoid having GHC in the build-time closure of all NixOS configurations
+, doCheck ? false, shellcheck
+}:
+
+stdenv.mkDerivation {
+  name = "nix-info";
+  src = ./info.sh;
+
+  path = lib.makeBinPath ([
+    coreutils findutils gnugrep
+  ] ++ (if stdenv.isDarwin then [ darwin.DarwinTools ] else []));
+  is_darwin = if stdenv.isDarwin then "yes" else "no";
+
+  sandboxtest = ./sandbox.nix;
+  relaxedsandboxtest = ./relaxedsandbox.nix;
+  multiusertest = ./multiuser.nix;
+
+  unpackCmd = ''
+    mkdir nix-info
+    cp $src ./nix-info/nix-info
+  '';
+
+  buildPhase  = ''
+    substituteAllInPlace ./nix-info
+  '';
+
+  inherit doCheck;
+  checkInputs = [ shellcheck ];
+
+  checkPhase = ''
+    shellcheck ./nix-info
+  '';
+
+  installPhase = ''
+    mkdir -p $out/bin
+    cp ./nix-info $out/bin/nix-info
+  '';
+
+  preferLocalBuild = true;
+
+  meta = {
+    platforms = lib.platforms.all;
+  };
+}
diff --git a/nixpkgs/pkgs/tools/nix/info/info.sh b/nixpkgs/pkgs/tools/nix/info/info.sh
new file mode 100755
index 000000000000..f108962b3bad
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/info/info.sh
@@ -0,0 +1,169 @@
+#!/bin/bash
+
+PATH="@path@:$PATH"
+IS_DARWIN="@is_darwin@"
+
+set -eu
+set -o pipefail
+
+DEBUG=0
+MARKDOWN=0
+HOST_OS=0
+SANDBOX=0
+while true; do
+    case "${1:-}" in
+        "")
+            break
+            ;;
+        -d | --debug)
+            set -x
+            DEBUG=1
+            shift
+            ;;
+        -m | --markdown)
+            MARKDOWN=1
+            HOST_OS=1
+            SANDBOX=1
+            shift
+            ;;
+        --host-os)
+            HOST_OS=1
+            shift
+            ;;
+        --sandbox)
+            SANDBOX=1
+            shift
+            ;;
+
+        * )
+            cat <<EOF
+nix-info - get high level info to help with debugging
+
+Options:
+
+ -m, --markdown   formatting for a GitHub issue
+                  implies: --host-os, --sandbox
+
+     --sandbox    include sandbox configuration
+     --host-os    include host OS details
+
+ -h, --help       show this message
+ -d, --debug      debug mode
+
+EOF
+            exit 1
+            ;;
+
+    esac
+done
+
+debuglog() {
+    if [ $DEBUG -eq 1 ]; then
+        cat >&2
+    else
+        cat > /dev/null
+    fi
+}
+
+nixev() {
+    nix-instantiate --eval --strict -E "$1"
+}
+
+desc_system() {
+    nixev '(import <nixpkgs> {}).system'
+}
+
+desc_host_os() {
+    printf "%s" "$(uname -sr)"
+
+    if [ "$IS_DARWIN" = "yes" ]; then
+        printf ", macOS %s" "$(sw_vers -productVersion)"
+    fi
+
+    if [ -f /etc/os-release ]; then
+        (
+            # shellcheck disable=SC1091
+            . /etc/os-release
+            printf ", %s, %s" "${NAME:-$(uname -v)}" "${VERSION:-noversion}"
+        )
+    fi
+}
+
+desc_multi_user() {
+    if nix-build --no-out-link  @multiusertest@ 2>&1 | debuglog; then
+        printf "yes"
+    else
+        printf "no"
+    fi
+}
+
+desc_nixpkgs_path() {
+    nixev '<nixpkgs>'
+}
+
+channel_facts() {
+    find /nix/var/nix/profiles/per-user \
+         -mindepth 2 \
+         -maxdepth 2 \
+         -name channels \
+         -print0 \
+    |\
+    while  IFS= read -r -d '' userchannelset; do
+        manifest="$userchannelset/manifest.nix"
+
+        if [ -e "$manifest" ]; then
+            userchannels=$(nixev \
+                           "builtins.concatStringsSep \", \"
+                             (map (ch: ch.name)
+                               (import \"$manifest\"))")
+
+            fact "channels($(echo "$manifest" | cut -d/ -f7))" \
+                 "$userchannels"
+        fi
+    done
+}
+
+desc_sandbox() {
+    if nix-build --no-out-link @sandboxtest@ 2>&1 | debuglog; then
+        printf "no"
+    elif nix-build --no-out-link @relaxedsandboxtest@ 2>&1 | debuglog; then
+        printf "relaxed"
+    else
+        printf "yes"
+    fi
+}
+
+fact() {
+    name="${1:-0}"
+    value="${2:-0}"
+    last="${3:-1}"
+    if [ $MARKDOWN -eq 0 ]; then
+        printf "%s: %s" "$name" "$value"
+        if [ "$last" -eq 1 ]; then
+            printf ", "
+        fi
+    else
+        printf " - %s: \`%s\`\\n" "$name" "$value"
+    fi
+
+    if [ "$last" -eq 0 ]; then
+        echo ""
+    fi
+}
+
+last_fact() {
+    fact "$1" "$2" 0
+}
+
+fact "system" "$(desc_system)"
+if [ $HOST_OS -eq 1 ]; then
+    fact "host os" "$(desc_host_os)"
+fi
+fact "multi-user?" "$(desc_multi_user)"
+if [ $SANDBOX -eq 1 ]; then
+    fact "sandbox" "$(desc_sandbox)"
+fi
+
+fact "version" "$(nix-env --version)"
+channel_facts
+last_fact "nixpkgs" "$(desc_nixpkgs_path)"
diff --git a/nixpkgs/pkgs/tools/nix/info/multiuser.nix b/nixpkgs/pkgs/tools/nix/info/multiuser.nix
new file mode 100644
index 000000000000..827d52987673
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/info/multiuser.nix
@@ -0,0 +1,12 @@
+let
+  pkgs = import <nixpkgs> {};
+in pkgs.runCommand "diagnostics-multiuser"
+  {  }
+  ''
+    set -x
+    # no cache: ${toString builtins.currentTime}
+    # For reproducibility, nix always uses nixbld group:
+    # https://github.com/NixOS/nix/blob/1dd29d7aebae706f3e90a18bbfae727f2ed03c70/src/libstore/build.cc#L1896-L1908
+    test "$(groups)" == "nixbld"
+    touch $out
+  ''
diff --git a/nixpkgs/pkgs/tools/nix/info/relaxedsandbox.nix b/nixpkgs/pkgs/tools/nix/info/relaxedsandbox.nix
new file mode 100644
index 000000000000..625a6ecc39e0
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/info/relaxedsandbox.nix
@@ -0,0 +1,12 @@
+let
+  pkgs = import <nixpkgs> {};
+in pkgs.runCommand "diagnostics-sandbox"
+  {
+    __noChroot = true;
+  }
+  ''
+    set -x
+    # no cache: ${toString builtins.currentTime}
+    test -d "$(dirname "$out")/../var/nix"
+    touch $out
+  ''
diff --git a/nixpkgs/pkgs/tools/nix/info/sandbox.nix b/nixpkgs/pkgs/tools/nix/info/sandbox.nix
new file mode 100644
index 000000000000..fa4288c2f944
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/info/sandbox.nix
@@ -0,0 +1,10 @@
+let
+  pkgs = import <nixpkgs> {};
+in pkgs.runCommand "diagnostics-sandbox"
+  { }
+  ''
+    set -x
+    # no cache: ${toString builtins.currentTime}
+    test -d "$(dirname "$out")/../var/nix"
+    touch $out
+  ''
diff --git a/nixpkgs/pkgs/tools/nix/manix/default.nix b/nixpkgs/pkgs/tools/nix/manix/default.nix
new file mode 100644
index 000000000000..768a283ebd26
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/manix/default.nix
@@ -0,0 +1,25 @@
+{ lib, stdenv, fetchFromGitHub, rustPlatform, darwin, Security }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "manix";
+  version = "0.6.3";
+
+  src = fetchFromGitHub {
+    owner = "mlvzk";
+    repo  = pname;
+    rev = "v${version}";
+    sha256 = "1b7xi8c2drbwzfz70czddc4j33s7g1alirv12dwl91hbqxifx8qs";
+  };
+
+  buildInputs = lib.optionals stdenv.isDarwin [ Security ];
+
+  cargoSha256 = "1yivx9vzk2fvncvlkwq5v11hb9llr1zlcmy69y12q6xnd9rd8x1b";
+
+  meta = with lib; {
+    description = "A Fast Documentation Searcher for Nix";
+    homepage    = "https://github.com/mlvzk/manix";
+    license     = [ licenses.mpl20 ];
+    maintainers = [ maintainers.mlvzk ];
+    platforms   = platforms.unix;
+  };
+}
diff --git a/nixpkgs/pkgs/tools/nix/nar-serve/default.nix b/nixpkgs/pkgs/tools/nix/nar-serve/default.nix
new file mode 100644
index 000000000000..1d7fd6beb4a7
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/nar-serve/default.nix
@@ -0,0 +1,26 @@
+{ buildGoModule
+, fetchFromGitHub
+, lib
+}:
+buildGoModule rec {
+  pname = "nar-serve";
+  version = "0.4.0";
+
+  src = fetchFromGitHub {
+    owner = "numtide";
+    repo = "nar-serve";
+    rev = "v${version}";
+    hash = "sha256-h/pzKRXgcGTpr1YUKppDa+iTLKak/PGhbYa8ZczWj1U=";
+  };
+
+  vendorSha256 = "sha256-eW+cul/5qJocpKV/6azxj7HTmkezDw6dNubPtAOP5HU=";
+
+  doCheck = false;
+
+  meta = with lib; {
+    description = "Serve NAR file contents via HTTP";
+    homepage = "https://github.com/numtide/nar-serve";
+    license = licenses.mit;
+    maintainers = with maintainers; [ rizary ];
+  };
+}
diff --git a/nixpkgs/pkgs/tools/nix/nix-output-monitor/default.nix b/nixpkgs/pkgs/tools/nix/nix-output-monitor/default.nix
new file mode 100644
index 000000000000..a94ae45ccea5
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/nix-output-monitor/default.nix
@@ -0,0 +1,41 @@
+{ mkDerivation, ansi-terminal, async, attoparsec, base, containers
+, cassava, directory, HUnit, mtl, nix-derivation, process, relude, lib
+, stm, terminal-size, text, time, unix, wcwidth, fetchFromGitHub
+, lock-file, data-default, expect, runtimeShell
+}:
+mkDerivation rec {
+  pname = "nix-output-monitor";
+  version = "1.0.3.3";
+  src = fetchFromGitHub {
+    owner = "maralorn";
+    repo = "nix-output-monitor";
+    sha256 = "1x26s9gzcygn96600g0r1a1sxqav6c38iq981rhmc808mqlyxmp8";
+    rev = "v${version}";
+  };
+  isLibrary = true;
+  isExecutable = true;
+  libraryHaskellDepends = [
+    ansi-terminal async attoparsec base cassava containers directory mtl
+    nix-derivation relude stm terminal-size text time unix wcwidth lock-file
+    data-default
+  ];
+  executableHaskellDepends = [
+    ansi-terminal async attoparsec base containers directory mtl
+    nix-derivation relude stm text time unix
+  ];
+  testHaskellDepends = [
+    ansi-terminal async attoparsec base containers directory HUnit mtl
+    nix-derivation process relude stm text time unix
+  ];
+  postInstall = ''
+    cat > $out/bin/nom-build << EOF
+    #!${runtimeShell}
+    ${expect}/bin/unbuffer nix-build "\$@" 2>&1 | exec $out/bin/nom
+    EOF
+    chmod a+x $out/bin/nom-build
+  '';
+  homepage = "https://github.com/maralorn/nix-output-monitor";
+  description = "Parses output of nix-build to show additional information";
+  license = lib.licenses.agpl3Plus;
+  maintainers = [ lib.maintainers.maralorn ];
+}
diff --git a/nixpkgs/pkgs/tools/nix/nix-query-tree-viewer/default.nix b/nixpkgs/pkgs/tools/nix/nix-query-tree-viewer/default.nix
new file mode 100644
index 000000000000..a27aa8d3c3bd
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/nix-query-tree-viewer/default.nix
@@ -0,0 +1,32 @@
+{ lib, fetchFromGitHub, rustPlatform, glib, gtk3, wrapGAppsHook }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "nix-query-tree-viewer";
+  version = "0.2.1";
+
+  src = fetchFromGitHub {
+    owner = "cdepillabout";
+    repo  = pname;
+    rev = "v${version}";
+    sha256 = "sha256-Lc9hfjybnRrkd7PZMa2ojxOM04bP4GJyagkZUX2nVwY=";
+  };
+
+  nativeBuildInputs = [
+    wrapGAppsHook
+  ];
+
+  buildInputs = [
+    glib
+    gtk3
+  ];
+
+  cargoSha256 = "sha256-NSLBIvgo5EdCvZq52d+UbAa7K4uOST++2zbhO9DW38E=";
+
+  meta = with lib; {
+    description = "GTK viewer for the output of `nix store --query --tree`";
+    homepage    = "https://github.com/cdepillabout/nix-query-tree-viewer";
+    license     = with licenses; [ mit ];
+    maintainers = with maintainers; [ cdepillabout ];
+    platforms   = platforms.unix;
+  };
+}
diff --git a/nixpkgs/pkgs/tools/nix/nix-script/default.nix b/nixpkgs/pkgs/tools/nix/nix-script/default.nix
new file mode 100644
index 000000000000..f9077ef13871
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/nix-script/default.nix
@@ -0,0 +1,41 @@
+{ lib, stdenv, haskellPackages, fetchFromGitHub }:
+
+stdenv.mkDerivation {
+  pname = "nix-script";
+  version = "2020-03-23";
+
+  src  = fetchFromGitHub {
+    owner  = "bennofs";
+    repo   = "nix-script";
+    rev    = "7706b45429ff22c35bab575734feb2926bf8840b";
+    sha256 = "0yiqljamcj9x8z801bwj7r30sskrwv4rm6sdf39j83jqql1fyq7y";
+  };
+
+  buildInputs  = [
+    (haskellPackages.ghcWithPackages (hs: with hs; [ posix-escape ]))
+  ];
+
+  buildPhase = ''
+    runHook preBuild
+
+    mkdir -p $out/bin
+    ghc -O2 $src/nix-script.hs -o $out/bin/nix-script -odir . -hidir .
+
+    runHook postBuild
+  '';
+  installPhase = ''
+    runHook preInstall
+
+    ln -s $out/bin/nix-script $out/bin/nix-scripti
+
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "A shebang for running inside nix-shell";
+    homepage    = "https://github.com/bennofs/nix-script";
+    license     = licenses.bsd3;
+    maintainers = with maintainers; [ bennofs rnhmjoj ];
+    platforms   = haskellPackages.ghc.meta.platforms;
+  };
+}
diff --git a/nixpkgs/pkgs/tools/nix/nix-store-gcs-proxy/default.nix b/nixpkgs/pkgs/tools/nix/nix-store-gcs-proxy/default.nix
new file mode 100644
index 000000000000..c782607da854
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/nix-store-gcs-proxy/default.nix
@@ -0,0 +1,24 @@
+{ lib, buildGoPackage, fetchFromGitHub }:
+buildGoPackage rec {
+  pname = "nix-store-gcs-proxy";
+  version = "0.1.0";
+
+  src = fetchFromGitHub {
+    owner = "tweag";
+    repo = "nix-store-gcs-proxy";
+    rev = "v${version}";
+    sha256 = "0804p65px4wd7gzxggpdxsazkd1hbz1p15zzaxf9ygc6sh26ncln";
+  };
+
+  goPackagePath = "github.com/tweag/nix-store-gcs-proxy";
+
+  goDeps = ./deps.nix;
+
+  meta = {
+    description = "A HTTP nix store that proxies requests to Google Storage";
+    homepage = "https://github.com/tweag/nix-store-gcs-proxy";
+    license = lib.licenses.asl20;
+    maintainers = with lib.maintainers; [ zimbatm ];
+  };
+}
+
diff --git a/nixpkgs/pkgs/tools/nix/nix-store-gcs-proxy/deps.nix b/nixpkgs/pkgs/tools/nix/nix-store-gcs-proxy/deps.nix
new file mode 100644
index 000000000000..b5ae542876d7
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/nix-store-gcs-proxy/deps.nix
@@ -0,0 +1,813 @@
+# file generated from go.mod using vgo2nix (https://github.com/adisbladis/vgo2nix)
+[
+  {
+    goPackagePath = "cloud.google.com/go";
+    fetch = {
+      type = "git";
+      url = "https://code.googlesource.com/gocloud";
+      rev = "v0.37.2";
+      sha256 = "1w6crdxy9vzd8vm672hng22spwld6d60z58kbr28dkiiz694wqvs";
+    };
+  }
+  {
+    goPackagePath = "github.com/BurntSushi/toml";
+    fetch = {
+      type = "git";
+      url = "https://github.com/BurntSushi/toml";
+      rev = "v0.3.1";
+      sha256 = "1fjdwwfzyzllgiwydknf1pwjvy49qxfsczqx5gz3y0izs7as99j6";
+    };
+  }
+  {
+    goPackagePath = "github.com/Shopify/sarama";
+    fetch = {
+      type = "git";
+      url = "https://github.com/Shopify/sarama";
+      rev = "v1.19.0";
+      sha256 = "0q1z3pvcd011yprwzws2s293v4cjvsszhai6vnfrahjcbsz79q0z";
+    };
+  }
+  {
+    goPackagePath = "github.com/Shopify/toxiproxy";
+    fetch = {
+      type = "git";
+      url = "https://github.com/Shopify/toxiproxy";
+      rev = "v2.1.4";
+      sha256 = "07yhsvscdv1qjfc2fyyh9qsrrdwrrw04wadk5gaq4qddcway7vig";
+    };
+  }
+  {
+    goPackagePath = "github.com/alecthomas/template";
+    fetch = {
+      type = "git";
+      url = "https://github.com/alecthomas/template";
+      rev = "a0175ee3bccc";
+      sha256 = "0qjgvvh26vk1cyfq9fadyhfgdj36f1iapbmr5xp6zqipldz8ffxj";
+    };
+  }
+  {
+    goPackagePath = "github.com/alecthomas/units";
+    fetch = {
+      type = "git";
+      url = "https://github.com/alecthomas/units";
+      rev = "2efee857e7cf";
+      sha256 = "1j65b91qb9sbrml9cpabfrcf07wmgzzghrl7809hjjhrmbzri5bl";
+    };
+  }
+  {
+    goPackagePath = "github.com/anmitsu/go-shlex";
+    fetch = {
+      type = "git";
+      url = "https://github.com/anmitsu/go-shlex";
+      rev = "648efa622239";
+      sha256 = "10rgdp5d106iisgz25ic8k6f44s9adh4sjh6fyxq9ccm21gw49b7";
+    };
+  }
+  {
+    goPackagePath = "github.com/apache/thrift";
+    fetch = {
+      type = "git";
+      url = "https://github.com/apache/thrift";
+      rev = "v0.12.0";
+      sha256 = "0g2g61rs189nimg3631wxfwdx12dsdz70qvncczlyvn34pcj7yby";
+    };
+  }
+  {
+    goPackagePath = "github.com/beorn7/perks";
+    fetch = {
+      type = "git";
+      url = "https://github.com/beorn7/perks";
+      rev = "3a771d992973";
+      sha256 = "1l2lns4f5jabp61201sh88zf3b0q793w4zdgp9nll7mmfcxxjif3";
+    };
+  }
+  {
+    goPackagePath = "github.com/bradfitz/go-smtpd";
+    fetch = {
+      type = "git";
+      url = "https://github.com/bradfitz/go-smtpd";
+      rev = "deb6d6237625";
+      sha256 = "1i33brqd44h0a9hbdnclka0hfg0f6qi5xy23f0ap9yixkhj4k9p6";
+    };
+  }
+  {
+    goPackagePath = "github.com/client9/misspell";
+    fetch = {
+      type = "git";
+      url = "https://github.com/client9/misspell";
+      rev = "v0.3.4";
+      sha256 = "1vwf33wsc4la25zk9nylpbp9px3svlmldkm0bha4hp56jws4q9cs";
+    };
+  }
+  {
+    goPackagePath = "github.com/coreos/go-systemd";
+    fetch = {
+      type = "git";
+      url = "https://github.com/coreos/go-systemd";
+      rev = "c6f51f82210d";
+      sha256 = "1vnccmnkjl6n539l4cliz6sznpqn6igf5v7mbmsgahb838742clb";
+    };
+  }
+  {
+    goPackagePath = "github.com/davecgh/go-spew";
+    fetch = {
+      type = "git";
+      url = "https://github.com/davecgh/go-spew";
+      rev = "v1.1.1";
+      sha256 = "0hka6hmyvp701adzag2g26cxdj47g21x6jz4sc6jjz1mn59d474y";
+    };
+  }
+  {
+    goPackagePath = "github.com/eapache/go-resiliency";
+    fetch = {
+      type = "git";
+      url = "https://github.com/eapache/go-resiliency";
+      rev = "v1.1.0";
+      sha256 = "1zmgw3c4w5r6m2r340n4jc5l5ll3m3nbszqrmrgbqc2xixxyk2gx";
+    };
+  }
+  {
+    goPackagePath = "github.com/eapache/go-xerial-snappy";
+    fetch = {
+      type = "git";
+      url = "https://github.com/eapache/go-xerial-snappy";
+      rev = "776d5712da21";
+      sha256 = "0ncc41dv7xwb1znyzmzh7cvs6j5fzz0f1n8h1v3grl9ma6s1si9d";
+    };
+  }
+  {
+    goPackagePath = "github.com/eapache/queue";
+    fetch = {
+      type = "git";
+      url = "https://github.com/eapache/queue";
+      rev = "v1.1.0";
+      sha256 = "07dp54n94gn3gsvdcki56yqh7py7wqqigxbamhxwgbr05n61fqyg";
+    };
+  }
+  {
+    goPackagePath = "github.com/flynn/go-shlex";
+    fetch = {
+      type = "git";
+      url = "https://github.com/flynn/go-shlex";
+      rev = "3f9db97f8568";
+      sha256 = "1j743lysygkpa2s2gii2xr32j7bxgc15zv4113b0q9jhn676ysia";
+    };
+  }
+  {
+    goPackagePath = "github.com/fsnotify/fsnotify";
+    fetch = {
+      type = "git";
+      url = "https://github.com/fsnotify/fsnotify";
+      rev = "v1.4.7";
+      sha256 = "07va9crci0ijlivbb7q57d2rz9h27zgn2fsm60spjsqpdbvyrx4g";
+    };
+  }
+  {
+    goPackagePath = "github.com/gliderlabs/ssh";
+    fetch = {
+      type = "git";
+      url = "https://github.com/gliderlabs/ssh";
+      rev = "v0.1.1";
+      sha256 = "0bylkc7yg8bxxffhchikcnzwli5n95cfmbji6v2a4mn1h5n36mdm";
+    };
+  }
+  {
+    goPackagePath = "github.com/go-kit/kit";
+    fetch = {
+      type = "git";
+      url = "https://github.com/go-kit/kit";
+      rev = "v0.8.0";
+      sha256 = "1rcywbc2pvab06qyf8pc2rdfjv7r6kxdv2v4wnpqnjhz225wqvc0";
+    };
+  }
+  {
+    goPackagePath = "github.com/go-logfmt/logfmt";
+    fetch = {
+      type = "git";
+      url = "https://github.com/go-logfmt/logfmt";
+      rev = "v0.3.0";
+      sha256 = "1gkgh3k5w1xwb2qbjq52p6azq3h1c1rr6pfwjlwj1zrijpzn2xb9";
+    };
+  }
+  {
+    goPackagePath = "github.com/go-stack/stack";
+    fetch = {
+      type = "git";
+      url = "https://github.com/go-stack/stack";
+      rev = "v1.8.0";
+      sha256 = "0wk25751ryyvxclyp8jdk5c3ar0cmfr8lrjb66qbg4808x66b96v";
+    };
+  }
+  {
+    goPackagePath = "github.com/gogo/protobuf";
+    fetch = {
+      type = "git";
+      url = "https://github.com/gogo/protobuf";
+      rev = "v1.2.0";
+      sha256 = "1c3y5m08mvrgvlw0kb9pldh3kkqcj99pa8gqmk1g3hp8ih3b2dv0";
+    };
+  }
+  {
+    goPackagePath = "github.com/golang/glog";
+    fetch = {
+      type = "git";
+      url = "https://github.com/golang/glog";
+      rev = "23def4e6c14b";
+      sha256 = "0jb2834rw5sykfr937fxi8hxi2zy80sj2bdn9b3jb4b26ksqng30";
+    };
+  }
+  {
+    goPackagePath = "github.com/golang/mock";
+    fetch = {
+      type = "git";
+      url = "https://github.com/golang/mock";
+      rev = "v1.2.0";
+      sha256 = "12ddj2g8ab87id6n2n67vnbhq6p8dvgsq1pzpqfriym4dk8w54fg";
+    };
+  }
+  {
+    goPackagePath = "github.com/golang/protobuf";
+    fetch = {
+      type = "git";
+      url = "https://github.com/golang/protobuf";
+      rev = "v1.2.0";
+      sha256 = "0kf4b59rcbb1cchfny2dm9jyznp8ri2hsb14n8iak1q8986xa0ab";
+    };
+  }
+  {
+    goPackagePath = "github.com/golang/snappy";
+    fetch = {
+      type = "git";
+      url = "https://github.com/golang/snappy";
+      rev = "2e65f85255db";
+      sha256 = "05w6mpc4qcy0pv8a2bzng8nf4s5rf5phfang4jwy9rgf808q0nxf";
+    };
+  }
+  {
+    goPackagePath = "github.com/google/btree";
+    fetch = {
+      type = "git";
+      url = "https://github.com/google/btree";
+      rev = "4030bb1f1f0c";
+      sha256 = "0ba430m9fbnagacp57krgidsyrgp3ycw5r7dj71brgp5r52g82p6";
+    };
+  }
+  {
+    goPackagePath = "github.com/google/go-cmp";
+    fetch = {
+      type = "git";
+      url = "https://github.com/google/go-cmp";
+      rev = "v0.2.0";
+      sha256 = "1fbv0x27k9sn8svafc0hjwsnckk864lv4yi7bvzrxvmd3d5hskds";
+    };
+  }
+  {
+    goPackagePath = "github.com/google/go-github";
+    fetch = {
+      type = "git";
+      url = "https://github.com/google/go-github";
+      rev = "v17.0.0";
+      sha256 = "1kvw95l77a5n5rgal9n1xjh58zxb3a40ij1j722b1h4z8yg9jhg4";
+    };
+  }
+  {
+    goPackagePath = "github.com/google/go-querystring";
+    fetch = {
+      type = "git";
+      url = "https://github.com/google/go-querystring";
+      rev = "v1.0.0";
+      sha256 = "0xl12bqyvmn4xcnf8p9ksj9rmnr7s40pvppsdmy8n9bzw1db0iwz";
+    };
+  }
+  {
+    goPackagePath = "github.com/google/martian";
+    fetch = {
+      type = "git";
+      url = "https://github.com/google/martian";
+      rev = "v2.1.0";
+      sha256 = "197hil6vrjk50b9wvwyzf61csid83whsjj6ik8mc9r2lryxlyyrp";
+    };
+  }
+  {
+    goPackagePath = "github.com/google/pprof";
+    fetch = {
+      type = "git";
+      url = "https://github.com/google/pprof";
+      rev = "3ea8567a2e57";
+      sha256 = "09rhjn3ms0a72dw0yzbp237p7yhqma772zspddn6mgkh3gi3kn4c";
+    };
+  }
+  {
+    goPackagePath = "github.com/googleapis/gax-go";
+    fetch = {
+      type = "git";
+      url = "https://github.com/googleapis/gax-go";
+      rev = "v2.0.4";
+      sha256 = "1iwnm6ky1x53lgs44mw3hpdkjzrm5qd0kfs50m0qcq2ml5m1cwdm";
+    };
+  }
+  {
+    goPackagePath = "github.com/gorilla/context";
+    fetch = {
+      type = "git";
+      url = "https://github.com/gorilla/context";
+      rev = "v1.1.1";
+      sha256 = "03p4hn87vcmfih0p9w663qbx9lpsf7i7j3lc7yl7n84la3yz63m4";
+    };
+  }
+  {
+    goPackagePath = "github.com/gorilla/mux";
+    fetch = {
+      type = "git";
+      url = "https://github.com/gorilla/mux";
+      rev = "v1.6.2";
+      sha256 = "0pvzm23hklxysspnz52mih6h1q74vfrdhjfm1l3sa9r8hhqmmld2";
+    };
+  }
+  {
+    goPackagePath = "github.com/gregjones/httpcache";
+    fetch = {
+      type = "git";
+      url = "https://github.com/gregjones/httpcache";
+      rev = "9cad4c3443a7";
+      sha256 = "0wjdwcwqqcx2d5y68qvhg6qyj977il5ijmnn9h9cd6wjbdy0ay6s";
+    };
+  }
+  {
+    goPackagePath = "github.com/hashicorp/golang-lru";
+    fetch = {
+      type = "git";
+      url = "https://github.com/hashicorp/golang-lru";
+      rev = "v0.5.0";
+      sha256 = "12k2cp2k615fjvfa5hyb9k2alian77wivds8s65diwshwv41939f";
+    };
+  }
+  {
+    goPackagePath = "github.com/hpcloud/tail";
+    fetch = {
+      type = "git";
+      url = "https://github.com/hpcloud/tail";
+      rev = "v1.0.0";
+      sha256 = "1njpzc0pi1acg5zx9y6vj9xi6ksbsc5d387rd6904hy6rh2m6kn0";
+    };
+  }
+  {
+    goPackagePath = "github.com/jellevandenhooff/dkim";
+    fetch = {
+      type = "git";
+      url = "https://github.com/jellevandenhooff/dkim";
+      rev = "f50fe3d243e1";
+      sha256 = "0qf5pypxfpciivj0v728i24rfjwhnwm07945mj6p3cw4gdphqhm0";
+    };
+  }
+  {
+    goPackagePath = "github.com/jstemmer/go-junit-report";
+    fetch = {
+      type = "git";
+      url = "https://github.com/jstemmer/go-junit-report";
+      rev = "af01ea7f8024";
+      sha256 = "1lp3n94ris12hac02wi31f3whs88lcrzwgdg43a5j6cafg9p1d0s";
+    };
+  }
+  {
+    goPackagePath = "github.com/julienschmidt/httprouter";
+    fetch = {
+      type = "git";
+      url = "https://github.com/julienschmidt/httprouter";
+      rev = "v1.2.0";
+      sha256 = "1k8bylc9s4vpvf5xhqh9h246dl1snxrzzz0614zz88cdh8yzs666";
+    };
+  }
+  {
+    goPackagePath = "github.com/konsorten/go-windows-terminal-sequences";
+    fetch = {
+      type = "git";
+      url = "https://github.com/konsorten/go-windows-terminal-sequences";
+      rev = "v1.0.1";
+      sha256 = "1lchgf27n276vma6iyxa0v1xds68n2g8lih5lavqnx5x6q5pw2ip";
+    };
+  }
+  {
+    goPackagePath = "github.com/kr/logfmt";
+    fetch = {
+      type = "git";
+      url = "https://github.com/kr/logfmt";
+      rev = "b84e30acd515";
+      sha256 = "02ldzxgznrfdzvghfraslhgp19la1fczcbzh7wm2zdc6lmpd1qq9";
+    };
+  }
+  {
+    goPackagePath = "github.com/kr/pty";
+    fetch = {
+      type = "git";
+      url = "https://github.com/kr/pty";
+      rev = "v1.1.3";
+      sha256 = "0knzlvndfgjm2k23vhp2xj1cv3fm31vbg5b20gdl1vnxk7rh549h";
+    };
+  }
+  {
+    goPackagePath = "github.com/matttproud/golang_protobuf_extensions";
+    fetch = {
+      type = "git";
+      url = "https://github.com/matttproud/golang_protobuf_extensions";
+      rev = "v1.0.1";
+      sha256 = "1d0c1isd2lk9pnfq2nk0aih356j30k3h1gi2w0ixsivi5csl7jya";
+    };
+  }
+  {
+    goPackagePath = "github.com/mwitkow/go-conntrack";
+    fetch = {
+      type = "git";
+      url = "https://github.com/mwitkow/go-conntrack";
+      rev = "cc309e4a2223";
+      sha256 = "0nbrnpk7bkmqg9mzwsxlm0y8m7s9qd9phr1q30qlx2qmdmz7c1mf";
+    };
+  }
+  {
+    goPackagePath = "github.com/onsi/ginkgo";
+    fetch = {
+      type = "git";
+      url = "https://github.com/onsi/ginkgo";
+      rev = "v1.7.0";
+      sha256 = "14wgpdrvpc35rdz3859bz53sc1g4vpr1fysy15wy3ff9gmqs14yg";
+    };
+  }
+  {
+    goPackagePath = "github.com/onsi/gomega";
+    fetch = {
+      type = "git";
+      url = "https://github.com/onsi/gomega";
+      rev = "v1.4.3";
+      sha256 = "1c8rqg5i2hz3snmq7s41yar1zjnzilb0fyiyhkg83v97afcfx79v";
+    };
+  }
+  {
+    goPackagePath = "github.com/openzipkin/zipkin-go";
+    fetch = {
+      type = "git";
+      url = "https://github.com/openzipkin/zipkin-go";
+      rev = "v0.1.6";
+      sha256 = "0fyf69w66khj3dxdpqydwjdhhhyhlh3caxa5ybnd1h2f6b5gbvvv";
+    };
+  }
+  {
+    goPackagePath = "github.com/pierrec/lz4";
+    fetch = {
+      type = "git";
+      url = "https://github.com/pierrec/lz4";
+      rev = "v2.0.5";
+      sha256 = "0y5rh7z01zycd59nnjpkqq0ydyjmcg9j1xw15q1i600l9j9g617p";
+    };
+  }
+  {
+    goPackagePath = "github.com/pkg/errors";
+    fetch = {
+      type = "git";
+      url = "https://github.com/pkg/errors";
+      rev = "v0.8.0";
+      sha256 = "001i6n71ghp2l6kdl3qq1v2vmghcz3kicv9a5wgcihrzigm75pp5";
+    };
+  }
+  {
+    goPackagePath = "github.com/pmezard/go-difflib";
+    fetch = {
+      type = "git";
+      url = "https://github.com/pmezard/go-difflib";
+      rev = "v1.0.0";
+      sha256 = "0c1cn55m4rypmscgf0rrb88pn58j3ysvc2d0432dp3c6fqg6cnzw";
+    };
+  }
+  {
+    goPackagePath = "github.com/prometheus/client_golang";
+    fetch = {
+      type = "git";
+      url = "https://github.com/prometheus/client_golang";
+      rev = "3c4408c8b829";
+      sha256 = "06d9cxxxkglks8fpfg3spxscyrq4lw7fckm4p6f0wshq65am2lxw";
+    };
+  }
+  {
+    goPackagePath = "github.com/prometheus/client_model";
+    fetch = {
+      type = "git";
+      url = "https://github.com/prometheus/client_model";
+      rev = "56726106282f";
+      sha256 = "19y4qs9mkxiiab5sh3b7cccjpl3xbp6sy8812ig9f1zg8vzkzj7j";
+    };
+  }
+  {
+    goPackagePath = "github.com/prometheus/common";
+    fetch = {
+      type = "git";
+      url = "https://github.com/prometheus/common";
+      rev = "v0.2.0";
+      sha256 = "02kym6lcfnlq23qbv277jr0q1n7jj0r14gqg93c7wn7gc44jv3vp";
+    };
+  }
+  {
+    goPackagePath = "github.com/prometheus/procfs";
+    fetch = {
+      type = "git";
+      url = "https://github.com/prometheus/procfs";
+      rev = "bf6a532e95b1";
+      sha256 = "0k65i2ikf3jp6863mpc1raf928i78r8jd7zn9djx6f4izls6l6j1";
+    };
+  }
+  {
+    goPackagePath = "github.com/rcrowley/go-metrics";
+    fetch = {
+      type = "git";
+      url = "https://github.com/rcrowley/go-metrics";
+      rev = "3113b8401b8a";
+      sha256 = "1m5q5dsvkqz809aag6dyan74wdrp69g2mb9killbv7z4ls2mlfr3";
+    };
+  }
+  {
+    goPackagePath = "github.com/sirupsen/logrus";
+    fetch = {
+      type = "git";
+      url = "https://github.com/sirupsen/logrus";
+      rev = "v1.2.0";
+      sha256 = "0r6334x2bls8ddznvzaldx4g88msjjns4mlks95rqrrg7h0ijigg";
+    };
+  }
+  {
+    goPackagePath = "github.com/stretchr/objx";
+    fetch = {
+      type = "git";
+      url = "https://github.com/stretchr/objx";
+      rev = "v0.1.1";
+      sha256 = "0iph0qmpyqg4kwv8jsx6a56a7hhqq8swrazv40ycxk9rzr0s8yls";
+    };
+  }
+  {
+    goPackagePath = "github.com/stretchr/testify";
+    fetch = {
+      type = "git";
+      url = "https://github.com/stretchr/testify";
+      rev = "v1.2.2";
+      sha256 = "0dlszlshlxbmmfxj5hlwgv3r22x0y1af45gn1vd198nvvs3pnvfs";
+    };
+  }
+  {
+    goPackagePath = "github.com/tarm/serial";
+    fetch = {
+      type = "git";
+      url = "https://github.com/tarm/serial";
+      rev = "98f6abe2eb07";
+      sha256 = "1yj4jiv2f3x3iawxdflrlmdan0k9xsbnccgc9yz658rmif1ag3pb";
+    };
+  }
+  {
+    goPackagePath = "github.com/urfave/cli";
+    fetch = {
+      type = "git";
+      url = "https://github.com/urfave/cli";
+      rev = "v1.20.0";
+      sha256 = "0y6f4sbzkiiwrxbl15biivj8c7qwxnvm3zl2dd3mw4wzg4x10ygj";
+    };
+  }
+  {
+    goPackagePath = "github.com/urfave/negroni";
+    fetch = {
+      type = "git";
+      url = "https://github.com/urfave/negroni";
+      rev = "v1.0.0";
+      sha256 = "1gp6j74adi1cn8fq5v3wzlzhwl4zg43n2746m4fzdcdimihk3ccp";
+    };
+  }
+  {
+    goPackagePath = "go.opencensus.io";
+    fetch = {
+      type = "git";
+      url = "https://github.com/census-instrumentation/opencensus-go";
+      rev = "v0.19.2";
+      sha256 = "1vlik5xwwrhcyy9yx2yc3y02y6hp9q80591hbhncv9c8wwfg9gjc";
+    };
+  }
+  {
+    goPackagePath = "go4.org";
+    fetch = {
+      type = "git";
+      url = "https://github.com/go4org/go4";
+      rev = "417644f6feb5";
+      sha256 = "013cvdg4fj15l9xg84br0vkb2d99j04s5b4g7zssqhng8dkwgr37";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/build";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/build";
+      rev = "5284462c4bec";
+      sha256 = "0w649zbs4n64b6rjx92hy7vc1y9sv4khhk5igbz8w7sxvz8778ij";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/crypto";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/crypto";
+      rev = "c2843e01d9a2";
+      sha256 = "01xgxbj5r79nmisdvpq48zfy8pzaaj90bn6ngd4nf33j9ar1dp8r";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/exp";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/exp";
+      rev = "509febef88a4";
+      sha256 = "02isrh39z8znrp5znplzy0dip2gnrl3jm1355raliyvhnhg04j6q";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/lint";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/lint";
+      rev = "5614ed5bae6f";
+      sha256 = "0fzn0zjv0x92xvfdq3a0v9w5sgkhr7hxkfy9zaqi8i57807z8bnx";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/net";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/net";
+      rev = "d8887717615a";
+      sha256 = "1wfm6ngxjyj7v5a2dqib6lw8bb2rdnf1kl48diykxjrsddn0s163";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/oauth2";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/oauth2";
+      rev = "e64efc72b421";
+      sha256 = "0djvwz2avx7knsjbl434vw1wqbrg53xp1kh599gfixn5icrggz4m";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/perf";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/perf";
+      rev = "6e6d33e29852";
+      sha256 = "1cyiy459bkjqnzgk051lsksz46hdkjc34q33zf946kiv3hilp1v2";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/sync";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/sync";
+      rev = "e225da77a7e6";
+      sha256 = "0bh3583smcfw6jw3w6lp0za93rz7hpxfdz8vhxng75b7a6vdlw4p";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/sys";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/sys";
+      rev = "d0b11bdaac8a";
+      sha256 = "18yfsmw622l7gc5sqriv5qmck6903vvhivpzp8i3xfy3z33dybdl";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/text";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/text";
+      rev = "17ff2d5776d2";
+      sha256 = "1rrh2mnmyxr45nsvy42zq3w3ly6gw6rl993knwvf1w71kyv0jjnj";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/time";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/time";
+      rev = "85acf8d2951c";
+      sha256 = "0yqnxsrarjk4qkda8kcxzmk7y90kkkxzx9iwryzrk7bzs87ky3xc";
+    };
+  }
+  {
+    goPackagePath = "golang.org/x/tools";
+    fetch = {
+      type = "git";
+      url = "https://go.googlesource.com/tools";
+      rev = "e65039ee4138";
+      sha256 = "0c094599cf70wdrms49a3879qkq122pqlp2av444gs2pvc8apdcx";
+    };
+  }
+  {
+    goPackagePath = "google.golang.org/api";
+    fetch = {
+      type = "git";
+      url = "https://code.googlesource.com/google-api-go-client";
+      rev = "v0.3.0";
+      sha256 = "1vvrhiq2zs677iz2j6s9iv4q3j3nhxz5ci9y4zrak248lrdln0zk";
+    };
+  }
+  {
+    goPackagePath = "google.golang.org/appengine";
+    fetch = {
+      type = "git";
+      url = "https://github.com/golang/appengine";
+      rev = "v1.4.0";
+      sha256 = "06zl7w4sxgdq2pl94wy9ncii6h0z3szl4xpqds0sv3b3wbdlhbnn";
+    };
+  }
+  {
+    goPackagePath = "google.golang.org/genproto";
+    fetch = {
+      type = "git";
+      url = "https://github.com/google/go-genproto";
+      rev = "5fe7a883aa19";
+      sha256 = "0qjkwig0r42q0j2qv57s4ahsgmmp41dz3ih3rnaqg0619n5w7lbs";
+    };
+  }
+  {
+    goPackagePath = "google.golang.org/grpc";
+    fetch = {
+      type = "git";
+      url = "https://github.com/grpc/grpc-go";
+      rev = "v1.19.0";
+      sha256 = "1znqwpj7ix3dpzx4zch0q70sdl3z5lvbb7v3q4i8sf8kas3yv71v";
+    };
+  }
+  {
+    goPackagePath = "gopkg.in/alecthomas/kingpin.v2";
+    fetch = {
+      type = "git";
+      url = "https://gopkg.in/alecthomas/kingpin.v2";
+      rev = "v2.2.6";
+      sha256 = "0mndnv3hdngr3bxp7yxfd47cas4prv98sqw534mx7vp38gd88n5r";
+    };
+  }
+  {
+    goPackagePath = "gopkg.in/check.v1";
+    fetch = {
+      type = "git";
+      url = "https://gopkg.in/check.v1";
+      rev = "788fd7840127";
+      sha256 = "0v3bim0j375z81zrpr5qv42knqs0y2qv2vkjiqi5axvb78slki1a";
+    };
+  }
+  {
+    goPackagePath = "gopkg.in/fsnotify.v1";
+    fetch = {
+      type = "git";
+      url = "https://gopkg.in/fsnotify.v1";
+      rev = "v1.4.7";
+      sha256 = "07va9crci0ijlivbb7q57d2rz9h27zgn2fsm60spjsqpdbvyrx4g";
+    };
+  }
+  {
+    goPackagePath = "gopkg.in/inf.v0";
+    fetch = {
+      type = "git";
+      url = "https://gopkg.in/inf.v0";
+      rev = "v0.9.1";
+      sha256 = "00k5iqjcp371fllqxncv7jkf80hn1zww92zm78cclbcn4ybigkng";
+    };
+  }
+  {
+    goPackagePath = "gopkg.in/tomb.v1";
+    fetch = {
+      type = "git";
+      url = "https://gopkg.in/tomb.v1";
+      rev = "dd632973f1e7";
+      sha256 = "1lqmq1ag7s4b3gc3ddvr792c5xb5k6sfn0cchr3i2s7f1c231zjv";
+    };
+  }
+  {
+    goPackagePath = "gopkg.in/yaml.v2";
+    fetch = {
+      type = "git";
+      url = "https://gopkg.in/yaml.v2";
+      rev = "v2.2.2";
+      sha256 = "01wj12jzsdqlnidpyjssmj0r4yavlqy7dwrg7adqd8dicjc4ncsa";
+    };
+  }
+  {
+    goPackagePath = "grpc.go4.org";
+    fetch = {
+      type = "git";
+      url = "https://github.com/go4org/grpc";
+      rev = "11d0a25b4919";
+      sha256 = "1d6akp2b3aa2viwbikc3jndhiljgjj87r4z7mg5b03f97f2wmz4f";
+    };
+  }
+  {
+    goPackagePath = "honnef.co/go/tools";
+    fetch = {
+      type = "git";
+      url = "https://github.com/dominikh/go-tools";
+      rev = "3f1c8253044a";
+      sha256 = "0d3vgh0fgfj1z7i648g1s6x2pwxd07sxfjwg1xn3yagr9h06jh3h";
+    };
+  }
+]
diff --git a/nixpkgs/pkgs/tools/nix/nixdoc/default.nix b/nixpkgs/pkgs/tools/nix/nixdoc/default.nix
new file mode 100644
index 000000000000..945809e7a767
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/nixdoc/default.nix
@@ -0,0 +1,25 @@
+{ lib, stdenv, fetchFromGitHub, rustPlatform, darwin }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "nixdoc";
+  version = "1.0.1";
+
+  src = fetchFromGitHub {
+    owner = "tazjin";
+    repo  = "nixdoc";
+    rev = "v${version}";
+    sha256 = "14d4dq06jdqazxvv7fq5872zy0capxyb0fdkp8qg06gxl1iw201s";
+  };
+
+  buildInputs =  lib.optionals stdenv.isDarwin [ darwin.Security ];
+
+  cargoSha256 = "1nv6g8rmjjbwqmjkrpqncypqvx5c7xp2zlx5h6rw2j9d1wlys0v5";
+
+  meta = with lib; {
+    description = "Generate documentation for Nix functions";
+    homepage    = "https://github.com/tazjin/nixdoc";
+    license     = [ licenses.gpl3 ];
+    maintainers = [ maintainers.tazjin ];
+    platforms   = platforms.unix;
+  };
+}
diff --git a/nixpkgs/pkgs/tools/nix/nixos-generators/default.nix b/nixpkgs/pkgs/tools/nix/nixos-generators/default.nix
new file mode 100644
index 000000000000..01e12e9fd58f
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/nixos-generators/default.nix
@@ -0,0 +1,26 @@
+{ stdenv, lib, fetchFromGitHub, makeWrapper, coreutils, jq, findutils, nix  }:
+
+stdenv.mkDerivation rec {
+  pname = "nixos-generators";
+  version = "1.4.0";
+  src = fetchFromGitHub {
+    owner = "nix-community";
+    repo = "nixos-generators";
+    rev = version;
+    sha256 = "1kn2anp8abpi0n3p7j0yczbpy7mdhk8rv84ywyghqdvf2wjmnlnp";
+  };
+  nativeBuildInputs = [ makeWrapper ];
+  installFlags = [ "PREFIX=$(out)" ];
+  postFixup = ''
+    wrapProgram $out/bin/nixos-generate \
+      --prefix PATH : ${lib.makeBinPath [ jq coreutils findutils nix ] }
+  '';
+
+  meta = with lib; {
+    description = "Collection of image builders";
+    homepage    = "https://github.com/nix-community/nixos-generators";
+    license     = licenses.mit;
+    maintainers = with maintainers; [ lassulus ];
+    platforms   = platforms.unix;
+  };
+}
diff --git a/nixpkgs/pkgs/tools/nix/nixos-install-tools/default.nix b/nixpkgs/pkgs/tools/nix/nixos-install-tools/default.nix
new file mode 100644
index 000000000000..8a00c15d905c
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/nixos-install-tools/default.nix
@@ -0,0 +1,69 @@
+{
+  buildEnv,
+  lib,
+  man,
+  nixos,
+  # TODO: replace indirect self-reference by proper self-reference
+  #       https://github.com/NixOS/nixpkgs/pull/119942
+  nixos-install-tools,
+  runCommand,
+  nixosTests,
+}:
+let
+  inherit (nixos {}) config;
+  version = config.system.nixos.version;
+in
+(buildEnv {
+  name = "nixos-install-tools-${version}";
+  paths = lib.attrValues {
+    # See nixos/modules/installer/tools/tools.nix
+    inherit (config.system.build)
+      nixos-install nixos-generate-config nixos-enter;
+
+    # Required for --help.
+    inherit (config.system.build.manual) manpages;
+  };
+
+  extraOutputsToInstall = ["man"];
+
+  meta = {
+    description = "The essential commands from the NixOS installer as a package";
+    longDescription = ''
+      With this package, you get the commands like nixos-generate-config and
+      nixos-install that you would otherwise only find on a NixOS system, such
+      as an installer image.
+
+      This way, you can install NixOS using a machine that only has Nix.
+    '';
+    license = lib.licenses.mit;
+    homepage = "https://nixos.org";
+    platforms = lib.platforms.linux;
+  };
+
+  passthru.tests = {
+    nixos-tests = lib.recurseIntoAttrs nixosTests.installer;
+    nixos-install-help = runCommand "test-nixos-install-help" {
+      nativeBuildInputs = [
+        man
+        nixos-install-tools
+      ];
+      meta.description = ''
+        Make sure that --help works. It's somewhat non-trivial because it
+        requires man.
+      '';
+    } ''
+      nixos-install --help | grep -F 'NixOS Reference Pages'
+      nixos-install --help | grep -F 'configuration.nix'
+      nixos-generate-config --help | grep -F 'NixOS Reference Pages'
+      nixos-generate-config --help | grep -F 'hardware-configuration.nix'
+
+      # FIXME: Tries to call unshare, which it must not do for --help
+      # nixos-enter --help | grep -F 'NixOS Reference Pages'
+
+      touch $out
+    '';
+  };
+}).overrideAttrs (o: {
+  inherit version;
+  pname = "nixos-install-tools";
+})
diff --git a/nixpkgs/pkgs/tools/nix/nixos-option/CMakeLists.txt b/nixpkgs/pkgs/tools/nix/nixos-option/CMakeLists.txt
new file mode 100644
index 000000000000..e5834598c4fd
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/nixos-option/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required (VERSION 2.6)
+project (nixos-option)
+
+add_executable(nixos-option nixos-option.cc libnix-copy-paste.cc)
+target_link_libraries(nixos-option PRIVATE -lnixmain -lnixexpr -lnixstore -lnixutil)
+target_compile_features(nixos-option PRIVATE cxx_std_17)
+
+install (TARGETS nixos-option DESTINATION bin)
diff --git a/nixpkgs/pkgs/tools/nix/nixos-option/default.nix b/nixpkgs/pkgs/tools/nix/nixos-option/default.nix
new file mode 100644
index 000000000000..9137e5a716c5
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/nixos-option/default.nix
@@ -0,0 +1,13 @@
+{lib, stdenv, boost, cmake, pkg-config, nix, ... }:
+
+stdenv.mkDerivation rec {
+  name = "nixos-option";
+  src = ./.;
+  nativeBuildInputs = [ cmake pkg-config ];
+  buildInputs = [ boost nix ];
+  meta = with lib; {
+    license = licenses.lgpl2Plus;
+    maintainers = with maintainers; [ chkno ];
+    platforms = platforms.all;
+  };
+}
diff --git a/nixpkgs/pkgs/tools/nix/nixos-option/libnix-copy-paste.cc b/nixpkgs/pkgs/tools/nix/nixos-option/libnix-copy-paste.cc
new file mode 100644
index 000000000000..875c07da6399
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/nixos-option/libnix-copy-paste.cc
@@ -0,0 +1,83 @@
+// These are useful methods inside the nix library that ought to be exported.
+// Since they are not, copy/paste them here.
+// TODO: Delete these and use the ones in the library as they become available.
+
+#include <nix/config.h> // for nix/globals.hh's reference to SYSTEM
+
+#include "libnix-copy-paste.hh"
+#include <boost/format/alt_sstream.hpp>           // for basic_altstringbuf...
+#include <boost/format/alt_sstream_impl.hpp>      // for basic_altstringbuf...
+#include <boost/format/format_class.hpp>          // for basic_format
+#include <boost/format/format_fwd.hpp>            // for format
+#include <boost/format/format_implementation.hpp> // for basic_format::basi...
+#include <boost/optional/optional.hpp>            // for get_pointer
+#include <iostream>                               // for operator<<, basic_...
+#include <nix/types.hh>                           // for Strings, Error
+#include <string>                                 // for string, basic_string
+
+using boost::format;
+using nix::Error;
+using nix::Strings;
+using std::string;
+
+// From nix/src/libexpr/attr-path.cc
+Strings parseAttrPath(const string & s)
+{
+    Strings res;
+    string cur;
+    string::const_iterator i = s.begin();
+    while (i != s.end()) {
+        if (*i == '.') {
+            res.push_back(cur);
+            cur.clear();
+        } else if (*i == '"') {
+            ++i;
+            while (1) {
+                if (i == s.end())
+                    throw Error(format("missing closing quote in selection path '%1%'") % s);
+                if (*i == '"')
+                    break;
+                cur.push_back(*i++);
+            }
+        } else
+            cur.push_back(*i);
+        ++i;
+    }
+    if (!cur.empty())
+        res.push_back(cur);
+    return res;
+}
+
+// From nix/src/nix/repl.cc
+bool isVarName(const string & s)
+{
+    if (s.size() == 0)
+        return false;
+    char c = s[0];
+    if ((c >= '0' && c <= '9') || c == '-' || c == '\'')
+        return false;
+    for (auto & i : s)
+        if (!((i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z') || (i >= '0' && i <= '9') || i == '_' || i == '-' ||
+              i == '\''))
+            return false;
+    return true;
+}
+
+// From nix/src/nix/repl.cc
+std::ostream & printStringValue(std::ostream & str, const char * string)
+{
+    str << "\"";
+    for (const char * i = string; *i; i++)
+        if (*i == '\"' || *i == '\\')
+            str << "\\" << *i;
+        else if (*i == '\n')
+            str << "\\n";
+        else if (*i == '\r')
+            str << "\\r";
+        else if (*i == '\t')
+            str << "\\t";
+        else
+            str << *i;
+    str << "\"";
+    return str;
+}
diff --git a/nixpkgs/pkgs/tools/nix/nixos-option/libnix-copy-paste.hh b/nixpkgs/pkgs/tools/nix/nixos-option/libnix-copy-paste.hh
new file mode 100644
index 000000000000..2274e9a0f853
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/nixos-option/libnix-copy-paste.hh
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <iostream>
+#include <nix/types.hh>
+#include <string>
+
+nix::Strings parseAttrPath(const std::string & s);
+bool isVarName(const std::string & s);
+std::ostream & printStringValue(std::ostream & str, const char * string);
diff --git a/nixpkgs/pkgs/tools/nix/nixos-option/nixos-option.cc b/nixpkgs/pkgs/tools/nix/nixos-option/nixos-option.cc
new file mode 100644
index 000000000000..f779d82edbd6
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/nixos-option/nixos-option.cc
@@ -0,0 +1,643 @@
+#include <nix/config.h> // for nix/globals.hh's reference to SYSTEM
+
+#include <exception>               // for exception_ptr, current_exception
+#include <functional>              // for function
+#include <iostream>                // for operator<<, basic_ostream, ostrin...
+#include <iterator>                // for next
+#include <list>                    // for _List_iterator
+#include <memory>                  // for allocator, unique_ptr, make_unique
+#include <new>                     // for operator new
+#include <nix/args.hh>             // for argvToStrings, UsageError
+#include <nix/attr-path.hh>        // for findAlongAttrPath
+#include <nix/attr-set.hh>         // for Attr, Bindings, Bindings::iterator
+#include <nix/common-eval-args.hh> // for MixEvalArgs
+#include <nix/eval-inline.hh>      // for EvalState::forceValue
+#include <nix/eval.hh>             // for EvalState, initGC, operator<<
+#include <nix/globals.hh>          // for initPlugins, Settings, settings
+#include <nix/nixexpr.hh>          // for Pos
+#include <nix/shared.hh>           // for getArg, LegacyArgs, printVersion
+#include <nix/store-api.hh>        // for openStore
+#include <nix/symbol-table.hh>     // for Symbol, SymbolTable
+#include <nix/types.hh>            // for Error, Path, Strings, PathSet
+#include <nix/util.hh>             // for absPath, baseNameOf
+#include <nix/value.hh>            // for Value, Value::(anonymous), Value:...
+#include <string>                  // for string, operator+, operator==
+#include <utility>                 // for move
+#include <variant>                 // for get, holds_alternative, variant
+#include <vector>                  // for vector<>::iterator, vector
+
+#include "libnix-copy-paste.hh"
+
+using nix::absPath;
+using nix::Bindings;
+using nix::Error;
+using nix::EvalError;
+using nix::EvalState;
+using nix::Path;
+using nix::PathSet;
+using nix::Strings;
+using nix::Symbol;
+using nix::tAttrs;
+using nix::ThrownError;
+using nix::tLambda;
+using nix::tString;
+using nix::UsageError;
+using nix::Value;
+
+// An ostream wrapper to handle nested indentation
+class Out
+{
+  public:
+    class Separator
+    {};
+    const static Separator sep;
+    enum LinePolicy
+    {
+        ONE_LINE,
+        MULTI_LINE
+    };
+    explicit Out(std::ostream & ostream) : ostream(ostream), policy(ONE_LINE), writeSinceSep(true) {}
+    Out(Out & o, const std::string & start, const std::string & end, LinePolicy policy);
+    Out(Out & o, const std::string & start, const std::string & end, int count)
+        : Out(o, start, end, count < 2 ? ONE_LINE : MULTI_LINE)
+    {}
+    Out(const Out &) = delete;
+    Out(Out &&) = default;
+    Out & operator=(const Out &) = delete;
+    Out & operator=(Out &&) = delete;
+    ~Out() { ostream << end; }
+
+  private:
+    std::ostream & ostream;
+    std::string indentation;
+    std::string end;
+    LinePolicy policy;
+    bool writeSinceSep;
+    template <typename T> friend Out & operator<<(Out & o, T thing);
+};
+
+template <typename T> Out & operator<<(Out & o, T thing)
+{
+    if (!o.writeSinceSep && o.policy == Out::MULTI_LINE) {
+        o.ostream << o.indentation;
+    }
+    o.writeSinceSep = true;
+    o.ostream << thing;
+    return o;
+}
+
+template <> Out & operator<<<Out::Separator>(Out & o, Out::Separator /* thing */)
+{
+    o.ostream << (o.policy == Out::ONE_LINE ? " " : "\n");
+    o.writeSinceSep = false;
+    return o;
+}
+
+Out::Out(Out & o, const std::string & start, const std::string & end, LinePolicy policy)
+    : ostream(o.ostream), indentation(policy == ONE_LINE ? o.indentation : o.indentation + "  "),
+      end(policy == ONE_LINE ? end : o.indentation + end), policy(policy), writeSinceSep(true)
+{
+    o << start;
+    *this << Out::sep;
+}
+
+// Stuff needed for evaluation
+struct Context
+{
+    Context(EvalState & state, Bindings & autoArgs, Value optionsRoot, Value configRoot)
+        : state(state), autoArgs(autoArgs), optionsRoot(optionsRoot), configRoot(configRoot),
+          underscoreType(state.symbols.create("_type"))
+    {}
+    EvalState & state;
+    Bindings & autoArgs;
+    Value optionsRoot;
+    Value configRoot;
+    Symbol underscoreType;
+};
+
+Value evaluateValue(Context & ctx, Value & v)
+{
+    ctx.state.forceValue(v);
+    if (ctx.autoArgs.empty()) {
+        return v;
+    }
+    Value called{};
+    ctx.state.autoCallFunction(ctx.autoArgs, v, called);
+    return called;
+}
+
+bool isOption(Context & ctx, const Value & v)
+{
+    if (v.type != tAttrs) {
+        return false;
+    }
+    const auto & actualType = v.attrs->find(ctx.underscoreType);
+    if (actualType == v.attrs->end()) {
+        return false;
+    }
+    try {
+        Value evaluatedType = evaluateValue(ctx, *actualType->value);
+        if (evaluatedType.type != tString) {
+            return false;
+        }
+        return static_cast<std::string>(evaluatedType.string.s) == "option";
+    } catch (Error &) {
+        return false;
+    }
+}
+
+// Add quotes to a component of a path.
+// These are needed for paths like:
+//    fileSystems."/".fsType
+//    systemd.units."dbus.service".text
+std::string quoteAttribute(const std::string & attribute)
+{
+    if (isVarName(attribute)) {
+        return attribute;
+    }
+    std::ostringstream buf;
+    printStringValue(buf, attribute.c_str());
+    return buf.str();
+}
+
+const std::string appendPath(const std::string & prefix, const std::string & suffix)
+{
+    if (prefix.empty()) {
+        return quoteAttribute(suffix);
+    }
+    return prefix + "." + quoteAttribute(suffix);
+}
+
+bool forbiddenRecursionName(std::string name) { return (!name.empty() && name[0] == '_') || name == "haskellPackages"; }
+
+void recurse(const std::function<bool(const std::string & path, std::variant<Value, std::exception_ptr>)> & f,
+             Context & ctx, Value v, const std::string & path)
+{
+    std::variant<Value, std::exception_ptr> evaluated;
+    try {
+        evaluated = evaluateValue(ctx, v);
+    } catch (Error &) {
+        evaluated = std::current_exception();
+    }
+    if (!f(path, evaluated)) {
+        return;
+    }
+    if (std::holds_alternative<std::exception_ptr>(evaluated)) {
+        return;
+    }
+    const Value & evaluated_value = std::get<Value>(evaluated);
+    if (evaluated_value.type != tAttrs) {
+        return;
+    }
+    for (const auto & child : evaluated_value.attrs->lexicographicOrder()) {
+        if (forbiddenRecursionName(child->name)) {
+            continue;
+        }
+        recurse(f, ctx, *child->value, appendPath(path, child->name));
+    }
+}
+
+bool optionTypeIs(Context & ctx, Value & v, const std::string & soughtType)
+{
+    try {
+        const auto & typeLookup = v.attrs->find(ctx.state.sType);
+        if (typeLookup == v.attrs->end()) {
+            return false;
+        }
+        Value type = evaluateValue(ctx, *typeLookup->value);
+        if (type.type != tAttrs) {
+            return false;
+        }
+        const auto & nameLookup = type.attrs->find(ctx.state.sName);
+        if (nameLookup == type.attrs->end()) {
+            return false;
+        }
+        Value name = evaluateValue(ctx, *nameLookup->value);
+        if (name.type != tString) {
+            return false;
+        }
+        return name.string.s == soughtType;
+    } catch (Error &) {
+        return false;
+    }
+}
+
+bool isAggregateOptionType(Context & ctx, Value & v)
+{
+    return optionTypeIs(ctx, v, "attrsOf") || optionTypeIs(ctx, v, "listOf");
+}
+
+MakeError(OptionPathError, EvalError);
+
+Value getSubOptions(Context & ctx, Value & option)
+{
+    Value getSubOptions = evaluateValue(ctx, *findAlongAttrPath(ctx.state, "type.getSubOptions", ctx.autoArgs, option));
+    if (getSubOptions.type != tLambda) {
+        throw OptionPathError("Option's type.getSubOptions isn't a function");
+    }
+    Value emptyString{};
+    nix::mkString(emptyString, "");
+    Value v;
+    ctx.state.callFunction(getSubOptions, emptyString, v, nix::Pos{});
+    return v;
+}
+
+// Carefully walk an option path, looking for sub-options when a path walks past
+// an option value.
+struct FindAlongOptionPathRet
+{
+    Value option;
+    std::string path;
+};
+FindAlongOptionPathRet findAlongOptionPath(Context & ctx, const std::string & path)
+{
+    Strings tokens = parseAttrPath(path);
+    Value v = ctx.optionsRoot;
+    std::string processedPath;
+    for (auto i = tokens.begin(); i != tokens.end(); i++) {
+        const auto & attr = *i;
+        try {
+            bool lastAttribute = std::next(i) == tokens.end();
+            v = evaluateValue(ctx, v);
+            if (attr.empty()) {
+                throw OptionPathError("empty attribute name");
+            }
+            if (isOption(ctx, v) && optionTypeIs(ctx, v, "submodule")) {
+                v = getSubOptions(ctx, v);
+            }
+            if (isOption(ctx, v) && isAggregateOptionType(ctx, v)) {
+                auto subOptions = getSubOptions(ctx, v);
+                if (lastAttribute && subOptions.attrs->empty()) {
+                    break;
+                }
+                v = subOptions;
+                // Note that we've consumed attr, but didn't actually use it.  This is the path component that's looked
+                // up in the list or attribute set that doesn't name an option -- the "root" in "users.users.root.name".
+            } else if (v.type != tAttrs) {
+                throw OptionPathError("Value is %s while a set was expected", showType(v));
+            } else {
+                const auto & next = v.attrs->find(ctx.state.symbols.create(attr));
+                if (next == v.attrs->end()) {
+                    throw OptionPathError("Attribute not found", attr, path);
+                }
+                v = *next->value;
+            }
+            processedPath = appendPath(processedPath, attr);
+        } catch (OptionPathError & e) {
+            throw OptionPathError("At '%s' in path '%s': %s", attr, path, e.msg());
+        }
+    }
+    return {v, processedPath};
+}
+
+// Calls f on all the option names at or below the option described by `path`.
+// Note that "the option described by `path`" is not trivial -- if path describes a value inside an aggregate
+// option (such as users.users.root), the *option* described by that path is one path component shorter
+// (eg: users.users), which results in f being called on sibling-paths (eg: users.users.nixbld1).  If f
+// doesn't want these, it must do its own filtering.
+void mapOptions(const std::function<void(const std::string & path)> & f, Context & ctx, const std::string & path)
+{
+    auto root = findAlongOptionPath(ctx, path);
+    recurse(
+        [f, &ctx](const std::string & path, std::variant<Value, std::exception_ptr> v) {
+            bool isOpt = std::holds_alternative<std::exception_ptr>(v) || isOption(ctx, std::get<Value>(v));
+            if (isOpt) {
+                f(path);
+            }
+            return !isOpt;
+        },
+        ctx, root.option, root.path);
+}
+
+// Calls f on all the config values inside one option.
+// Simple options have one config value inside, like sound.enable = true.
+// Compound options have multiple config values.  For example, the option
+// "users.users" has about 1000 config values inside it:
+//   users.users.avahi.createHome = false;
+//   users.users.avahi.cryptHomeLuks = null;
+//   users.users.avahi.description = "`avahi-daemon' privilege separation user";
+//   ...
+//   users.users.avahi.openssh.authorizedKeys.keyFiles = [ ];
+//   users.users.avahi.openssh.authorizedKeys.keys = [ ];
+//   ...
+//   users.users.avahi.uid = 10;
+//   users.users.avahi.useDefaultShell = false;
+//   users.users.cups.createHome = false;
+//   ...
+//   users.users.cups.useDefaultShell = false;
+//   users.users.gdm = ... ... ...
+//   users.users.messagebus = ... .. ...
+//   users.users.nixbld1 = ... .. ...
+//   ...
+//   users.users.systemd-timesync = ... .. ...
+void mapConfigValuesInOption(
+    const std::function<void(const std::string & path, std::variant<Value, std::exception_ptr> v)> & f,
+    const std::string & path, Context & ctx)
+{
+    Value * option;
+    try {
+        option = findAlongAttrPath(ctx.state, path, ctx.autoArgs, ctx.configRoot);
+    } catch (Error &) {
+        f(path, std::current_exception());
+        return;
+    }
+    recurse(
+        [f, ctx](const std::string & path, std::variant<Value, std::exception_ptr> v) {
+            bool leaf = std::holds_alternative<std::exception_ptr>(v) || std::get<Value>(v).type != tAttrs ||
+                        ctx.state.isDerivation(std::get<Value>(v));
+            if (!leaf) {
+                return true; // Keep digging
+            }
+            f(path, v);
+            return false;
+        },
+        ctx, *option, path);
+}
+
+std::string describeError(const Error & e) { return "«error: " + e.msg() + "»"; }
+
+void describeDerivation(Context & ctx, Out & out, Value v)
+{
+    // Copy-pasted from nix/src/nix/repl.cc  :(
+    Bindings::iterator i = v.attrs->find(ctx.state.sDrvPath);
+    PathSet pathset;
+    try {
+        Path drvPath = i != v.attrs->end() ? ctx.state.coerceToPath(*i->pos, *i->value, pathset) : "???";
+        out << "«derivation " << drvPath << "»";
+    } catch (Error & e) {
+        out << describeError(e);
+    }
+}
+
+Value parseAndEval(EvalState & state, const std::string & expression, const std::string & path)
+{
+    Value v{};
+    state.eval(state.parseExprFromString(expression, absPath(path)), v);
+    return v;
+}
+
+void printValue(Context & ctx, Out & out, std::variant<Value, std::exception_ptr> maybeValue, const std::string & path);
+
+void printList(Context & ctx, Out & out, Value & v)
+{
+    Out listOut(out, "[", "]", v.listSize());
+    for (unsigned int n = 0; n < v.listSize(); ++n) {
+        printValue(ctx, listOut, *v.listElems()[n], "");
+        listOut << Out::sep;
+    }
+}
+
+void printAttrs(Context & ctx, Out & out, Value & v, const std::string & path)
+{
+    Out attrsOut(out, "{", "}", v.attrs->size());
+    for (const auto & a : v.attrs->lexicographicOrder()) {
+        std::string name = a->name;
+        if (!forbiddenRecursionName(name)) {
+            attrsOut << name << " = ";
+            printValue(ctx, attrsOut, *a->value, appendPath(path, name));
+            attrsOut << ";" << Out::sep;
+        }
+    }
+}
+
+void multiLineStringEscape(Out & out, const std::string & s)
+{
+    int i;
+    for (i = 1; i < s.size(); i++) {
+        if (s[i - 1] == '$' && s[i] == '{') {
+            out << "''${";
+            i++;
+        } else if (s[i - 1] == '\'' && s[i] == '\'') {
+            out << "'''";
+            i++;
+        } else {
+            out << s[i - 1];
+        }
+    }
+    if (i == s.size()) {
+        out << s[i - 1];
+    }
+}
+
+void printMultiLineString(Out & out, const Value & v)
+{
+    std::string s = v.string.s;
+    Out strOut(out, "''", "''", Out::MULTI_LINE);
+    std::string::size_type begin = 0;
+    while (begin < s.size()) {
+        std::string::size_type end = s.find('\n', begin);
+        if (end == std::string::npos) {
+            multiLineStringEscape(strOut, s.substr(begin, s.size() - begin));
+            break;
+        }
+        multiLineStringEscape(strOut, s.substr(begin, end - begin));
+        strOut << Out::sep;
+        begin = end + 1;
+    }
+}
+
+void printValue(Context & ctx, Out & out, std::variant<Value, std::exception_ptr> maybeValue, const std::string & path)
+{
+    try {
+        if (auto ex = std::get_if<std::exception_ptr>(&maybeValue)) {
+            std::rethrow_exception(*ex);
+        }
+        Value v = evaluateValue(ctx, std::get<Value>(maybeValue));
+        if (ctx.state.isDerivation(v)) {
+            describeDerivation(ctx, out, v);
+        } else if (v.isList()) {
+            printList(ctx, out, v);
+        } else if (v.type == tAttrs) {
+            printAttrs(ctx, out, v, path);
+        } else if (v.type == tString && std::string(v.string.s).find('\n') != std::string::npos) {
+            printMultiLineString(out, v);
+        } else {
+            ctx.state.forceValueDeep(v);
+            out << v;
+        }
+    } catch (ThrownError & e) {
+        if (e.msg() == "The option `" + path + "' is used but not defined.") {
+            // 93% of errors are this, and just letting this message through would be
+            // misleading.  These values may or may not actually be "used" in the
+            // config.  The thing throwing the error message assumes that if anything
+            // ever looks at this value, it is a "use" of this value.  But here in
+            // nixos-option, we are looking at this value only to print it.
+            // In order to avoid implying that this undefined value is actually
+            // referenced, eat the underlying error message and emit "«not defined»".
+            out << "«not defined»";
+        } else {
+            out << describeError(e);
+        }
+    } catch (Error & e) {
+        out << describeError(e);
+    }
+}
+
+void printConfigValue(Context & ctx, Out & out, const std::string & path, std::variant<Value, std::exception_ptr> v)
+{
+    out << path << " = ";
+    printValue(ctx, out, std::move(v), path);
+    out << ";\n";
+}
+
+// Replace with std::starts_with when C++20 is available
+bool starts_with(const std::string & s, const std::string & prefix)
+{
+    return s.size() >= prefix.size() &&
+           std::equal(s.begin(), std::next(s.begin(), prefix.size()), prefix.begin(), prefix.end());
+}
+
+void printRecursive(Context & ctx, Out & out, const std::string & path)
+{
+    mapOptions(
+        [&ctx, &out, &path](const std::string & optionPath) {
+            mapConfigValuesInOption(
+                [&ctx, &out, &path](const std::string & configPath, std::variant<Value, std::exception_ptr> v) {
+                    if (starts_with(configPath, path)) {
+                        printConfigValue(ctx, out, configPath, v);
+                    }
+                },
+                optionPath, ctx);
+        },
+        ctx, path);
+}
+
+void printAttr(Context & ctx, Out & out, const std::string & path, Value & root)
+{
+    try {
+        printValue(ctx, out, *findAlongAttrPath(ctx.state, path, ctx.autoArgs, root), path);
+    } catch (Error & e) {
+        out << describeError(e);
+    }
+}
+
+bool hasExample(Context & ctx, Value & option)
+{
+    try {
+        findAlongAttrPath(ctx.state, "example", ctx.autoArgs, option);
+        return true;
+    } catch (Error &) {
+        return false;
+    }
+}
+
+void printOption(Context & ctx, Out & out, const std::string & path, Value & option)
+{
+    out << "Value:\n";
+    printAttr(ctx, out, path, ctx.configRoot);
+
+    out << "\n\nDefault:\n";
+    printAttr(ctx, out, "default", option);
+
+    out << "\n\nType:\n";
+    printAttr(ctx, out, "type.description", option);
+
+    if (hasExample(ctx, option)) {
+        out << "\n\nExample:\n";
+        printAttr(ctx, out, "example", option);
+    }
+
+    out << "\n\nDescription:\n";
+    printAttr(ctx, out, "description", option);
+
+    out << "\n\nDeclared by:\n";
+    printAttr(ctx, out, "declarations", option);
+
+    out << "\n\nDefined by:\n";
+    printAttr(ctx, out, "files", option);
+    out << "\n";
+}
+
+void printListing(Out & out, Value & v)
+{
+    out << "This attribute set contains:\n";
+    for (const auto & a : v.attrs->lexicographicOrder()) {
+        std::string name = a->name;
+        if (!name.empty() && name[0] != '_') {
+            out << name << "\n";
+        }
+    }
+}
+
+void printOne(Context & ctx, Out & out, const std::string & path)
+{
+    try {
+        auto result = findAlongOptionPath(ctx, path);
+        Value & option = result.option;
+        option = evaluateValue(ctx, option);
+        if (path != result.path) {
+            out << "Note: showing " << result.path << " instead of " << path << "\n";
+        }
+        if (isOption(ctx, option)) {
+            printOption(ctx, out, result.path, option);
+        } else {
+            printListing(out, option);
+        }
+    } catch (Error & e) {
+        std::cerr << "error: " << e.msg()
+                  << "\nAn error occurred while looking for attribute names. Are "
+                     "you sure that '"
+                  << path << "' exists?\n";
+    }
+}
+
+int main(int argc, char ** argv)
+{
+    bool recursive = false;
+    std::string path = ".";
+    std::string optionsExpr = "(import <nixpkgs/nixos> {}).options";
+    std::string configExpr = "(import <nixpkgs/nixos> {}).config";
+    std::vector<std::string> args;
+
+    struct MyArgs : nix::LegacyArgs, nix::MixEvalArgs
+    {
+        using nix::LegacyArgs::LegacyArgs;
+    };
+
+    MyArgs myArgs(nix::baseNameOf(argv[0]), [&](Strings::iterator & arg, const Strings::iterator & end) {
+        if (*arg == "--help") {
+            nix::showManPage("nixos-option");
+        } else if (*arg == "--version") {
+            nix::printVersion("nixos-option");
+        } else if (*arg == "-r" || *arg == "--recursive") {
+            recursive = true;
+        } else if (*arg == "--path") {
+            path = nix::getArg(*arg, arg, end);
+        } else if (*arg == "--options_expr") {
+            optionsExpr = nix::getArg(*arg, arg, end);
+        } else if (*arg == "--config_expr") {
+            configExpr = nix::getArg(*arg, arg, end);
+        } else if (!arg->empty() && arg->at(0) == '-') {
+            return false;
+        } else {
+            args.push_back(*arg);
+        }
+        return true;
+    });
+
+    myArgs.parseCmdline(nix::argvToStrings(argc, argv));
+
+    nix::initPlugins();
+    nix::initGC();
+    nix::settings.readOnlyMode = true;
+    auto store = nix::openStore();
+    auto state = std::make_unique<EvalState>(myArgs.searchPath, store);
+
+    Value optionsRoot = parseAndEval(*state, optionsExpr, path);
+    Value configRoot = parseAndEval(*state, configExpr, path);
+
+    Context ctx{*state, *myArgs.getAutoArgs(*state), optionsRoot, configRoot};
+    Out out(std::cout);
+
+    auto print = recursive ? printRecursive : printOne;
+    if (args.empty()) {
+        print(ctx, out, "");
+    }
+    for (const auto & arg : args) {
+        print(ctx, out, arg);
+    }
+
+    ctx.state.printStats();
+
+    return 0;
+}
diff --git a/nixpkgs/pkgs/tools/nix/nixpkgs-fmt/default.nix b/nixpkgs/pkgs/tools/nix/nixpkgs-fmt/default.nix
new file mode 100644
index 000000000000..b203d2992fbf
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/nixpkgs-fmt/default.nix
@@ -0,0 +1,21 @@
+{ lib, rustPlatform, fetchFromGitHub }:
+rustPlatform.buildRustPackage rec {
+  pname = "nixpkgs-fmt";
+  version = "1.2.0";
+
+  src = fetchFromGitHub {
+    owner = "nix-community";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "0dqirvn8pq6ssxjlf6rkqcsx6ndasws93lz2v9f9s01k9ny8x8mq";
+  };
+
+  cargoSha256 = "0mm79hfh8p1rs02pkpcv25p59b24q1rymwh11yxry4d4f12b6aw0";
+
+  meta = with lib; {
+    description = "Nix code formatter for nixpkgs";
+    homepage = "https://nix-community.github.io/nixpkgs-fmt";
+    license = licenses.asl20;
+    maintainers = with maintainers; [ zimbatm ];
+  };
+}
diff --git a/nixpkgs/pkgs/tools/nix/rnix-hashes/default.nix b/nixpkgs/pkgs/tools/nix/rnix-hashes/default.nix
new file mode 100644
index 000000000000..4aebb35bc935
--- /dev/null
+++ b/nixpkgs/pkgs/tools/nix/rnix-hashes/default.nix
@@ -0,0 +1,30 @@
+{ lib, rustPlatform, fetchFromGitHub, fetchpatch }:
+
+rustPlatform.buildRustPackage rec {
+  pname = "rnix-hashes";
+  version = "0.2.0";
+
+  src = fetchFromGitHub {
+    owner = "numtide";
+    repo = pname;
+    rev = "v${version}";
+    sha256 = "SzHyG5cEjaaPjTkn8puht6snjHMl8DtorOGDjxakJfA=";
+  };
+
+  patches = [
+    # fix test failure
+    (fetchpatch {
+      url = "https://github.com/numtide/rnix-hashes/commit/62ab96cfd1efeade7d98efd9829eae8677bac9cc.patch";
+      sha256 = "sha256-oE2fBt20FmO2cEUGivu2mKo3z6rbhVLXSF8SRvhibFs=";
+    })
+  ];
+
+  cargoSha256 = "sha256-p6W9NtOKzVViyFq5SQvnIsik7S3mqUqxI/05OiC+P+Q=";
+
+  meta = with lib; {
+    description = "Nix Hash Converter";
+    homepage = "https://github.com/numtide/rnix-hashes";
+    license = licenses.asl20;
+    maintainers = with maintainers; [ rizary SuperSandro2000 ];
+  };
+}