/ flake.nix
flake.nix
  1  {
  2    description = "distrox";
  3    inputs = {
  4      nixpkgs.url = "nixpkgs/nixos-25.11";
  5      unstable.url = "nixpkgs/nixpkgs-unstable";
  6      flake-utils.url = "github:numtide/flake-utils";
  7      crane.url = "github:ipetkov/crane";
  8      rust-overlay = {
  9        url = "github:oxalica/rust-overlay";
 10        inputs.nixpkgs.follows = "nixpkgs";
 11      };
 12      treefmt-nix = {
 13        # Update to upstream as soon as https://github.com/numtide/treefmt-nix/pull/414 is merged
 14        url = "github:matthiasbeyer/treefmt-nix/configure-sqlfluff";
 15        inputs.nixpkgs.follows = "nixpkgs";
 16      };
 17  
 18      git-metrics-flake = {
 19        url = "github:matthiasbeyer/git-metrics-flake";
 20        inputs = {
 21          nixpkgs.follows = "nixpkgs";
 22          flake-utils.follows = "flake-utils";
 23          treefmt-nix.follows = "treefmt-nix";
 24        };
 25      };
 26  
 27      goyo = {
 28        url = "git+https://github.com/hahwul/goyo.git";
 29        flake = false;
 30      };
 31    };
 32  
 33    outputs =
 34      inputs@{
 35        self,
 36        nixpkgs,
 37        crane,
 38        flake-utils,
 39        rust-overlay,
 40        treefmt-nix,
 41        ...
 42      }:
 43      flake-utils.lib.eachSystem [ "x86_64-linux" ] (
 44        system:
 45        let
 46          pkgs = import nixpkgs {
 47            inherit system;
 48            overlays = [ (import rust-overlay) ];
 49          };
 50  
 51          pkgsUnstable = import inputs.unstable {
 52            inherit system;
 53          };
 54  
 55          nightlyRustTarget = pkgs.rust-bin.selectLatestNightlyWith (
 56            toolchain:
 57            pkgs.rust-bin.fromRustupToolchain {
 58              channel = "nightly-2025-10-03";
 59              components = [ "rustfmt" ];
 60            }
 61          );
 62  
 63          rustTarget = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
 64  
 65          craneLib = (inputs.crane.mkLib pkgs).overrideToolchain rustTarget;
 66  
 67          src =
 68            let
 69              markdownFilter = path: _type: pkgs.lib.hasSuffix ".md" path;
 70              filterPath =
 71                path: type:
 72                builtins.any (f: f path type) [
 73                  markdownFilter
 74                  craneLib.filterCargoSources
 75                  pkgs.lib.cleanSourceFilter
 76                ];
 77            in
 78            pkgs.lib.cleanSourceWith {
 79              src = ./.;
 80              filter = filterPath;
 81            };
 82  
 83          rustSrc = pkgs.lib.fileset.toSource {
 84            root = ./.;
 85            fileset =
 86              let
 87                includeFilesWithExt = ext: (pkgs.lib.fileset.fileFilter (file: file.hasExt ext) ./.);
 88              in
 89              pkgs.lib.fileset.unions (
 90                [
 91                  ./Cargo.lock
 92                  ./README.md
 93                ]
 94                ++ (builtins.map includeFilesWithExt [
 95                  "rs"
 96                  "toml"
 97                  "sql"
 98                  "snap"
 99                ])
100              );
101          };
102  
103          rustfmt' = pkgs.writeShellScriptBin "rustfmt" ''
104            exec "${nightlyRustTarget}/bin/rustfmt" "$@"
105          '';
106  
107          formatting =
108            let
109              treefmtEval = inputs.treefmt-nix.lib.evalModule pkgs ./lib/nix/treefmt.nix;
110            in
111            {
112              formatter = treefmtEval.config.build.wrapper;
113              check = treefmtEval.config.build.check src;
114            };
115  
116          commonCrateArgs = {
117            src = rustSrc;
118            strictDeps = true;
119  
120            nativeBuildInputs = [
121              pkgs.pkg-config
122            ];
123  
124            buildInputs = [
125              pkgs.sqlite
126            ];
127          };
128  
129          lib = pkgs.callPackage ./lib/nix {
130            inherit
131              craneLib
132              src
133              commonCrateArgs
134              rustTarget
135              inputs
136              ;
137  
138            mkMetric = inputs.git-metrics-flake.lib."${system}".mkMetric;
139            distrox-cli = inputs.self.packages."${system}".distrox-cli;
140            iroh-relay = inputs.self.packages."${system}".iroh-relay;
141          };
142  
143          callPackage = pkgs.lib.callPackageWith (
144            pkgs
145            // {
146              inherit (lib) workspace;
147              inherit craneLib;
148              inherit inputs;
149  
150              inherit (lib.config)
151                mkDistroxConfigFile
152                ;
153  
154              distrox-cli = inputs.self.packages."${system}".distrox-cli;
155              distrox-cli-no-tracy = inputs.self.packages."${system}".distrox-cli-no-tracy;
156              iroh-relay = inputs.self.packages."${system}".iroh-relay;
157              iroh-relay-module = lib.iroh-relay-module;
158              iroh-doctor = inputs.self.packages."${system}".iroh-doctor;
159  
160              mkMetric = inputs.git-metrics-flake.lib."${system}".mkMetric;
161            }
162            // lib.testUtils
163            // {
164              inherit callPackage;
165            }
166          );
167  
168          isNotOverride = name: name != "override" && name != "overrideDerivation";
169          attrsetWithoutOverrides = pkgs.lib.attrsets.filterAttrs (name: _: isNotOverride name);
170  
171          all-endtoend-tests = attrsetWithoutOverrides (callPackage ./tests { });
172  
173          distroxMeta = {
174            description = "The distrox social network";
175            mainProgram = "distrox-cli";
176            homepage = "https://distrox.net";
177            license = pkgs.lib.licenses.gpl2Only;
178            maintainers = with lib.maintainers; [
179              matthiasbeyer
180            ];
181          };
182  
183          customCargoMultiplexer = pkgs.writeShellScriptBin "cargo" ''
184            case "$1" in
185              +nightly)
186                shift
187                export PATH="${nightlyRustTarget}/bin/:''$PATH"
188                exec ${nightlyRustTarget}/bin/cargo "$@"
189                ;;
190              *)
191                exec ${rustTarget}/bin/cargo "$@"
192            esac
193          '';
194        in
195        {
196          inherit (formatting) formatter;
197  
198          checks =
199            lib.allCrateTests
200            // all-endtoend-tests
201            // {
202              formatting = formatting.check;
203              distrox-cli = lib.crates.distrox-cli.build;
204            };
205  
206          packages = {
207            distrox-cli = lib.crates.distrox-cli.build.overrideAttrs { meta = distroxMeta; };
208            distrox-cli-no-tracy = lib.crates.distrox-cli-no-tracy.overrideAttrs { meta = distroxMeta; };
209            depgraph = lib.depgraph;
210            depgraph-svg = lib.depgraph-svg;
211            manpages = lib.manpages;
212            website = callPackage ./website {
213              inherit (lib)
214                manpages
215                depgraph-svg
216                ;
217  
218              inherit (lib.packages) mantohtml;
219            };
220  
221            git-metrics-ci-script =
222              let
223                gmf-lib = inputs.git-metrics-flake.lib."${system}";
224              in
225              gmf-lib.mkCiScript {
226                inherit pkgs;
227                inherit (inputs.git-metrics-flake.packages."${system}") git-metrics;
228                drv = inputs.self.packages."${system}".distrox-cli;
229  
230                metrics =
231                  let
232                    all-crate-metrics-test-count = pkgs.lib.pipe lib.allCrateNames [
233                      (pkgs.lib.lists.filter (
234                        crateName: lib.filterForCratesWith "build" crateName && lib.filterForCratesWith "test" crateName
235                      ))
236                      (map (name: lib.mk-metric-test-count lib.crates."${name}"))
237                    ];
238                  in
239                  all-crate-metrics-test-count
240                  ++ [
241                    lib.metric-binary-size
242                    lib.metric-derivation-size
243                  ];
244              };
245          }
246          // attrsetWithoutOverrides lib.packages;
247  
248          apps = {
249            distrox-cli =
250              flake-utils.lib.mkApp {
251                drv = self.packages.${pkgs.stdenv.hostPlatform.system}.distrox-cli;
252                name = "distrox-cli";
253              }
254              // {
255                meta = distroxMeta;
256              };
257  
258            distrox-cli-no-tracy =
259              flake-utils.lib.mkApp {
260                drv = self.packages.${pkgs.stdenv.hostPlatform.system}.distrox-cli-no-tracy;
261                name = "distrox-cli";
262              }
263              // {
264                meta = distroxMeta;
265              };
266  
267            serve-website =
268              inputs.flake-utils.lib.mkApp {
269                drv = pkgs.writeShellApplication {
270                  name = "serve-website";
271                  runtimeInputs = [ pkgs.zola ];
272                  text = ''
273                    ln -vsn "${inputs.goyo}" ./website/themes/goyo ||:
274                    ln -vsn "${lib.depgraph-svg}/depgraph.svg" ./website/static/depgraph.svg ||:
275                    cd website
276                    zola serve
277                  '';
278                };
279              }
280              // {
281                meta = {
282                  description = "The distrox social network website";
283                  homepage = "https://distrox.net";
284                  license = pkgs.lib.licenses.gpl2Only;
285                  maintainers = with lib.maintainers; [
286                    matthiasbeyer
287                  ];
288                };
289              };
290          };
291  
292          devShells =
293            let
294              mkTestInstanceShell =
295                {
296                  number,
297                  config,
298                }:
299                pkgs.mkShell {
300                  buildInputs = [
301                    (pkgs.writeShellApplication {
302                      name = "distrox-cli";
303                      runtimeInputs = [
304                        inputs.self.packages.${pkgs.stdenv.hostPlatform.system}.distrox-cli
305                      ];
306  
307                      text = ''
308                        XDG_STATE_HOME="$(pwd)/instance-test/${toString number}/xdg/state/" \
309                        XDG_CONFIG_HOME="$(pwd)/instance-test/${toString number}/xdg/config/" \
310                        XDG_CACHE_HOME="$(pwd)/instance-test/${toString number}/xdg/cache/" \
311                          distrox-cli "$@"
312                      '';
313                    })
314                  ];
315  
316                  shellHook =
317                    let
318                      configFile = lib.config.mkDistroxConfigFile config;
319                    in
320                    ''
321                      mkdir -p "$(pwd)/instance-test/${toString number}/xdg/config/distrox"
322                      >&2 echo ">>> created: $(pwd)/instance-test/${toString number}/xdg/config/distrox/"
323  
324                      >&2 cp -v ${configFile} "$(pwd)/instance-test/${toString number}/xdg/config/distrox/config.toml"
325                      >&2 echo ">>> config file created: $(pwd)/instance-test/${toString number}/xdg/config/distrox/config.toml"
326  
327                      export RUST_LOG=debug,pkarr_publish=warn,hickory_proto=warn,actor=info,reportgen-actor=info,run-probe=info,poll=warn
328                      >&2 echo ">>> RUST_LOG = ''${RUST_LOG}"
329  
330                      echo >&2 ">>> Shell for Test instance ${toString number}";
331                    '';
332                };
333            in
334            {
335              default = pkgs.mkShell {
336                buildInputs = [
337                  customCargoMultiplexer
338                  inputs.git-metrics-flake.packages."${system}".git-metrics
339                  pkgs.cargo-depgraph
340                  pkgs.cargo-insta
341                  pkgs.cargo-nextest
342                  pkgs.gitlint
343                  pkgs.rainfrog
344                  pkgs.sqlite
345                  pkgsUnstable.diesel-cli
346                  rustTarget
347                  rustfmt'
348                ];
349              };
350            };
351  
352          website-shell = pkgs.mkShell {
353            buildInputs = [
354              inputs.git-metrics-flake.packages."${system}".git-metrics
355              pkgs.cargo-depgraph
356              pkgs.cargo-insta
357              pkgs.gitlint
358              pkgs.zola
359              rustTarget
360              rustfmt'
361            ];
362  
363            shellHook = ''
364              ln -vsn "${inputs.goyo}" ./website/themes/goyo
365              ln -vsn "${lib.depgraph-svg}/depgraph.svg" ./website/static/depgraph.svg ||:
366            '';
367          };
368        }
369      );
370  }