├── LICENSE.md ├── README.md ├── flake.lock ├── flake.nix ├── functions └── marsnix │ ├── default.nix │ ├── get-me-all-the-fods.nix │ └── read-drvs-from-file.nix └── pkgs └── marsnix └── default.nix /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Matthew Croughan 4 | Copyright (c) 2022 Nix.How LTD 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | `marsnix` is a function that uses recursive nix to realise all FODs gathered for 4 | a given nixpkgs path. The function expects a path to the root of nixpkgs, where 5 | it will begin evaluating using `nix-eval-jobs`. Below are some valid example invocations: 6 | 7 | ``` 8 | marsnix { nixpkgs = (builtins.getFlake "github:nixos/nixpkgs/b5883c36db04fb19386d9051e1d77af54225e091"); } 9 | ``` 10 | 11 | ``` 12 | marsnix { nixpkgs = pkgs.path; } 13 | ``` 14 | 15 | You could then map it over a list and symlinkJoin the result in order to fetch all FODs for all the revision(s) you're 16 | interested in. An example of this exists in [./functions/marsnix/get-me-all-the-fods.nix](./functions/marsnix/get-me-all-the-fods.nix), which can also be built as an output of this flake, by running `nix build .#marsnix-example-invocation -L` 17 | 18 | ```nix 19 | { marsnix }: 20 | pkgs.symlinkJoin { 21 | name = "get-me-all-the-fods"; 22 | paths = map (x: marsnix { nixpkgs = x; }) [ 23 | (builtins.fetchGit { 24 | url = "https://github.com/NixOS/nixpkgs.git"; 25 | rev = "da044451c6a70518db5b730fe277b70f494188f1"; # nixos-24.11 26 | allRefs = true; 27 | }) 28 | (builtins.fetchGit { 29 | url = "https://github.com/NixOS/nixpkgs.git"; 30 | rev = "205fd4226592cc83fd4c0885a3e4c9c400efabb5"; # nixos-23.11 31 | allRefs = true; 32 | }) 33 | ]; 34 | } 35 | ``` 36 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-parts": { 4 | "inputs": { 5 | "nixpkgs-lib": "nixpkgs-lib" 6 | }, 7 | "locked": { 8 | "lastModified": 1741352980, 9 | "narHash": "sha256-+u2UunDA4Cl5Fci3m7S643HzKmIDAe+fiXrLqYsR2fs=", 10 | "owner": "hercules-ci", 11 | "repo": "flake-parts", 12 | "rev": "f4330d22f1c5d2ba72d3d22df5597d123fdb60a9", 13 | "type": "github" 14 | }, 15 | "original": { 16 | "owner": "hercules-ci", 17 | "repo": "flake-parts", 18 | "type": "github" 19 | } 20 | }, 21 | "nixpkgs": { 22 | "locked": { 23 | "lastModified": 1742069588, 24 | "narHash": "sha256-C7jVfohcGzdZRF6DO+ybyG/sqpo1h6bZi9T56sxLy+k=", 25 | "owner": "nixos", 26 | "repo": "nixpkgs", 27 | "rev": "c80f6a7e10b39afcc1894e02ef785b1ad0b0d7e5", 28 | "type": "github" 29 | }, 30 | "original": { 31 | "owner": "nixos", 32 | "ref": "nixos-unstable", 33 | "repo": "nixpkgs", 34 | "type": "github" 35 | } 36 | }, 37 | "nixpkgs-lib": { 38 | "locked": { 39 | "lastModified": 1740877520, 40 | "narHash": "sha256-oiwv/ZK/2FhGxrCkQkB83i7GnWXPPLzoqFHpDD3uYpk=", 41 | "owner": "nix-community", 42 | "repo": "nixpkgs.lib", 43 | "rev": "147dee35aab2193b174e4c0868bd80ead5ce755c", 44 | "type": "github" 45 | }, 46 | "original": { 47 | "owner": "nix-community", 48 | "repo": "nixpkgs.lib", 49 | "type": "github" 50 | } 51 | }, 52 | "root": { 53 | "inputs": { 54 | "flake-parts": "flake-parts", 55 | "nixpkgs": "nixpkgs" 56 | } 57 | } 58 | }, 59 | "root": "root", 60 | "version": 7 61 | } 62 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Taking Nix Offline"; 3 | nixConfig = { 4 | extra-substituters = [ "https://matthewcroughan.cachix.org" ]; 5 | extra-trusted-public-keys = [ "matthewcroughan.cachix.org-1:fON2C9BdzJlp1qPan4t5AF0xlnx8sB0ghZf8VDo7+e8=" ]; 6 | }; 7 | inputs = { 8 | nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; 9 | flake-parts.url = "github:hercules-ci/flake-parts"; 10 | }; 11 | outputs = { self, flake-parts, ... }: 12 | flake-parts.lib.mkFlake { inherit self; } { 13 | systems = [ 14 | "x86_64-linux" 15 | "aarch64-linux" 16 | ]; 17 | flake = { 18 | herculesCI.ciSystems = [ "x86_64-linux" ]; 19 | overlay = final: prev: { 20 | marsnix-cli = self.packages.${prev.stdenv.hostPlatform.system}.marsnix; 21 | marsnix = self.packages.${prev.stdenv.hostPlatform.system}.marsnix; 22 | }; 23 | }; 24 | perSystem = { config, self', inputs', pkgs, system, ... }: { 25 | legacyPackages = { 26 | marsnix = pkgs.callPackage ./functions/marsnix {}; 27 | marsnix-example-invocation = pkgs.callPackage ./functions/marsnix/get-me-all-the-fods.nix { inherit pkgs; }; 28 | }; 29 | packages = rec { 30 | default = marsnix-cli; 31 | marsnix-cli = pkgs.callPackage ./pkgs/marsnix {}; 32 | }; 33 | }; 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /functions/marsnix/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | nixVersions, 3 | runCommand, 4 | nix-eval-jobs, 5 | jq, 6 | pkgs, 7 | }: 8 | { 9 | nixpkgs ? pkgs.path 10 | }: 11 | let 12 | # nix does not instantiated drv files upon nix-env evaluating them, without this patch 13 | patchedNix = nixVersions.latest.overrideAttrs (_: { 14 | prePatch = '' 15 | substituteInPlace src/nix-env/nix-env.cc \ 16 | --replace 'settings.readOnlyMode = true' 'settings.readOnlyMode = false' 17 | ''; 18 | }); 19 | all-drvPaths = 20 | runCommand "all-drvPaths" 21 | { 22 | buildInputs = [ 23 | patchedNix 24 | nix-eval-jobs 25 | jq 26 | ]; 27 | requiredSystemFeatures = [ "recursive-nix" ]; 28 | } 29 | '' 30 | set -x 31 | export NIX_CONFIG="experimental-features = nix-command" 32 | 33 | # nix-env -f "${nixpkgs}" -qa --drv-path \ 34 | # nix-eval-jobs --max-memory-size 500 --workers $(expr $(nproc) / 2) --quiet --gc-roots-dir $TMP --eval-store unix:///build/.nix-socket "${nixpkgs}" 2>/dev/null \ 35 | 36 | nix-eval-jobs --max-memory-size 1024 --quiet --gc-roots-dir $TMP --eval-store unix:///build/.nix-socket "${nixpkgs}" 2>/dev/null \ 37 | | jq -r 'if .drvPath != null then .drvPath else empty end' \ 38 | | xargs --max-lines=1000 nix derivation show -r \ 39 | | jq -r 'to_entries | .[] | select(.value.outputs.out.hash).key' \ 40 | | sort -u \ 41 | > $out 42 | ''; 43 | realise-drvPaths = 44 | runCommand "realise-drvPaths" 45 | { 46 | buildInputs = [ 47 | patchedNix 48 | jq 49 | ]; 50 | requiredSystemFeatures = [ "recursive-nix" ]; 51 | } 52 | '' 53 | set -x 54 | export NIX_CONFIG="experimental-features = nix-command" 55 | 56 | export DRVS="${all-drvPaths}" 57 | nix build --impure --option auto-optimize-store true -f ${./read-drvs-from-file.nix} 58 | cp ${all-drvPaths} $out 59 | ''; 60 | in 61 | realise-drvPaths 62 | -------------------------------------------------------------------------------- /functions/marsnix/get-me-all-the-fods.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs ? import { }, 3 | marsnix ? pkgs.callPackage ./default.nix {}, 4 | }: 5 | pkgs.symlinkJoin { 6 | name = "get-me-all-the-fods"; 7 | paths = map (x: marsnix { nixpkgs = x; }) [ 8 | (builtins.fetchGit { 9 | url = "https://github.com/NixOS/nixpkgs.git"; 10 | rev = "1272bba1877a9f7cfe1d4d2b62fb36b0e85bd91b"; 11 | allRefs = true; 12 | }) 13 | (builtins.fetchGit { 14 | url = "https://github.com/NixOS/nixpkgs.git"; 15 | rev = "f82c0d5417abfb3565275dfedc96bae0c2a8241f"; 16 | allRefs = true; 17 | }) 18 | ]; 19 | } 20 | -------------------------------------------------------------------------------- /functions/marsnix/read-drvs-from-file.nix: -------------------------------------------------------------------------------- 1 | let 2 | b = builtins; 3 | # read newline separated drv paths from file. 4 | text = b.readFile (b.getEnv "DRVS"); 5 | lines = b.filter (x: x != [ ] && x != "") (b.split "\n" text); 6 | 7 | # load a .drv file so that the evaluator accepts it as derivation 8 | loadDrv = drvFile: { 9 | name = ""; 10 | type = "derivation"; 11 | drvPath = b.appendContext drvFile { 12 | "${drvFile}" = { 13 | allOutputs = true; 14 | }; 15 | }; 16 | outputName = "out"; 17 | }; 18 | 19 | # generate list of derivations 20 | drvs = map loadDrv lines; 21 | in 22 | drvs 23 | -------------------------------------------------------------------------------- /pkgs/marsnix/default.nix: -------------------------------------------------------------------------------- 1 | { writeShellApplication, nixVersions, jq }: 2 | let 3 | patchedNix = nixVersions.latest.overrideAttrs (_: { 4 | prePatch = '' 5 | substituteInPlace src/nix-env/nix-env.cc \ 6 | --replace 'settings.readOnlyMode = true' 'settings.readOnlyMode = false' 7 | ''; 8 | }); 9 | in 10 | writeShellApplication { 11 | name = "marsnix"; 12 | runtimeInputs = [ 13 | patchedNix 14 | jq 15 | ]; 16 | text = '' 17 | set -euo pipefail 18 | NIXPKGS_PATH=$(nix eval "$1"#pkgs.path) 19 | nix-env -f "$NIXPKGS_PATH" -qa --drv-path \ 20 | | tr -s ' ' | cut -d ' ' -f2 \ 21 | | xargs nix show-derivation -r \ 22 | | jq -r 'to_entries | .[] | select(.value.outputs.out.hash).key' \ 23 | | sort -u \ 24 | | xargs nix build --option auto-optimize-store true 25 | ''; 26 | 27 | # nativeBuildInputs = [ makeWrapper ]; 28 | 29 | # installPhase = '' 30 | # runHook preInstall 31 | # install -Dm555 marsnix $out/bin/marsnix 32 | # wrapProgram $out/bin/marsnix \ 33 | # --set PATH "${lib.makeBinPath runtimeInputs}" 34 | # runHook postInstall 35 | # ''; 36 | 37 | #meta = with lib; { 38 | # description = "Taking Nix Offline"; 39 | # homepage = "https://github.com/nix-how/marsnix"; 40 | # license = licenses.mit; 41 | # platforms = platforms.unix; 42 | # maintainers = with maintainers; [ matthewcroughan ]; 43 | #}; 44 | } 45 | --------------------------------------------------------------------------------