1{ 2 lib, 3 stdenv, 4 fetchgit, 5 fetchzip, 6 runCommand, 7 xorg, 8 nim, 9 nimOverrides, 10}: 11 12let 13 fetchers = { 14 fetchzip = 15 { url, sha256, ... }: 16 fetchzip { 17 name = "source"; 18 inherit url sha256; 19 }; 20 fetchgit = 21 { 22 fetchSubmodules ? false, 23 leaveDotGit ? false, 24 rev, 25 sha256, 26 url, 27 ... 28 }: 29 fetchgit { 30 inherit 31 fetchSubmodules 32 leaveDotGit 33 rev 34 sha256 35 url 36 ; 37 }; 38 }; 39 40 filterPropertiesToAttrs = 41 prefix: properties: 42 lib.pipe properties [ 43 (builtins.filter ({ name, ... }: (lib.strings.hasPrefix prefix name))) 44 (map ( 45 { name, value }: 46 { 47 name = lib.strings.removePrefix prefix name; 48 inherit value; 49 } 50 )) 51 builtins.listToAttrs 52 ]; 53 54 buildNimCfg = 55 { backend, components, ... }: 56 let 57 componentSrcDirs = map ( 58 { properties, ... }: 59 let 60 fodProps = filterPropertiesToAttrs "nix:fod:" properties; 61 fod = fetchers.${fodProps.method} fodProps; 62 srcDir = fodProps.srcDir or ""; 63 in 64 if srcDir == "" then fod else "${fod}/${srcDir}" 65 ) components; 66 in 67 runCommand "nim.cfg" 68 { 69 outputs = [ 70 "out" 71 "src" 72 ]; 73 nativeBuildInputs = [ xorg.lndir ]; 74 } 75 '' 76 cat << EOF >> $out 77 backend:${backend} 78 path:"$src" 79 EOF 80 mkdir -p "$src" 81 ${lib.strings.concatMapStrings (d: '' 82 lndir "${d}" "$src" 83 '') componentSrcDirs} 84 ''; 85 86 buildCommands = lib.attrsets.mapAttrsToList ( 87 output: input: '' 88 nim compile $nimFlags --out:${output} ${input} 89 '' 90 ); 91 92 installCommands = lib.attrsets.mapAttrsToList ( 93 output: input: '' 94 install -Dt $out/bin ${output} 95 '' 96 ); 97 98 applySbom = 99 sbom: 100 { 101 nimFlags ? [ ], 102 nimRelease ? true, 103 passthru ? { }, 104 ... 105 }@prevAttrs: 106 let 107 properties = # SBOM metadata.component.properties as an attrset. 108 lib.attrsets.recursiveUpdate (builtins.listToAttrs sbom.metadata.component.properties) 109 passthru.properties or { }; 110 111 nimBin = # A mapping of Nim module file paths to names of programs. 112 lib.attrsets.recursiveUpdate (lib.pipe properties [ 113 (lib.attrsets.filterAttrs (name: value: lib.strings.hasPrefix "nim:bin:" name)) 114 (lib.attrsets.mapAttrs' ( 115 name: value: { 116 name = lib.strings.removePrefix "nim:bin:" name; 117 value = "${properties."nim:binDir" or (properties."nim:srcDir" or ".")}/${value}"; 118 } 119 )) 120 ]) passthru.nimBin or { }; 121 in 122 { 123 strictDeps = true; 124 125 pname = prevAttrs.pname or sbom.metadata.component.name; 126 version = prevAttrs.version or sbom.metadata.component.version or null; 127 128 nimFlags = 129 nimFlags 130 ++ (lib.optional nimRelease "-d:release") 131 ++ ( 132 let 133 srcDir = properties."nim:srcDir" or ""; 134 in 135 lib.optional (srcDir != "") "--path:${srcDir}" 136 ); 137 138 configurePhase = 139 prevAttrs.configurePhase or '' 140 runHook preConfigure 141 echo "nim.cfg << $nimCfg" 142 cat $nimCfg >> nim.cfg 143 cat << EOF >> nim.cfg 144 nimcache:"$NIX_BUILD_TOP/nimcache" 145 parallelBuild:$NIX_BUILD_CORES 146 EOF 147 runHook postConfigure 148 ''; 149 150 buildPhase = 151 prevAttrs.buildPhase or '' 152 runHook preBuild 153 ${lib.strings.concatLines (buildCommands nimBin)} 154 runHook postBuild 155 ''; 156 157 installPhase = 158 prevAttrs.installPhase or '' 159 runHook preInstall 160 ${lib.strings.concatLines (installCommands nimBin)} 161 runHook postInstall 162 ''; 163 164 nativeBuildInputs = (prevAttrs.nativeBuildInputs or [ ]) ++ [ nim ]; 165 166 nimCfg = 167 prevAttrs.nimCfg or (buildNimCfg { 168 backend = prevAttrs.nimBackend or properties."nim:backend" or "c"; 169 inherit (sbom) components; 170 }); 171 172 passthru = passthru // { 173 inherit sbom properties nimBin; 174 }; 175 }; 176 177 applyOverrides = 178 prevAttrs: 179 builtins.foldl' ( 180 prevAttrs: 181 { name, ... }@component: 182 if (builtins.hasAttr name nimOverrides) then 183 let 184 result = nimOverrides.${name} component prevAttrs; 185 in 186 prevAttrs // (if builtins.isAttrs result then result else result { }) 187 else 188 prevAttrs 189 ) prevAttrs prevAttrs.passthru.sbom.components; 190 191 compose = 192 callerArg: sbom: finalAttrs: 193 let 194 callerAttrs = if builtins.isAttrs callerArg then callerArg else callerArg finalAttrs; 195 sbomAttrs = callerAttrs // (applySbom sbom callerAttrs); 196 overrideAttrs = sbomAttrs // (applyOverrides sbomAttrs); 197 in 198 overrideAttrs; 199in 200callerArg: sbomArg: 201let 202 sbom = if builtins.isAttrs sbomArg then sbomArg else builtins.fromJSON (builtins.readFile sbomArg); 203 overrideSbom = f: stdenv.mkDerivation (compose callerArg (sbom // (f sbom))); 204in 205(stdenv.mkDerivation (compose callerArg sbom)) // { inherit overrideSbom; }