Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
1{ pkgs, config, buildPackages, lib, stdenv, libiconv, mkNugetDeps, mkNugetSource, gixy }: 2 3let 4 aliases = if config.allowAliases then (import ./aliases.nix lib) else prev: {}; 5 6 writers = with lib; rec { 7 # Base implementation for non-compiled executables. 8 # Takes an interpreter, for example `${pkgs.bash}/bin/bash` 9 # 10 # Examples: 11 # writeBash = makeScriptWriter { interpreter = "${pkgs.bash}/bin/bash"; } 12 # makeScriptWriter { interpreter = "${pkgs.dash}/bin/dash"; } "hello" "echo hello world" 13 makeScriptWriter = { interpreter, check ? "" }: nameOrPath: content: 14 assert lib.or (types.path.check nameOrPath) (builtins.match "([0-9A-Za-z._])[0-9A-Za-z._-]*" nameOrPath != null); 15 assert lib.or (types.path.check content) (types.str.check content); 16 let 17 name = last (builtins.split "/" nameOrPath); 18 in 19 20 pkgs.runCommandLocal name (if (types.str.check content) then { 21 inherit content interpreter; 22 passAsFile = [ "content" ]; 23 } else { 24 inherit interpreter; 25 contentPath = content; 26 }) '' 27 # On darwin a script cannot be used as an interpreter in a shebang but 28 # there doesn't seem to be a limit to the size of shebang and multiple 29 # arguments to the interpreter are allowed. 30 if [[ -n "${toString pkgs.stdenvNoCC.isDarwin}" ]] && isScript $interpreter 31 then 32 wrapperInterpreterLine=$(head -1 "$interpreter" | tail -c+3) 33 # Get first word from the line (note: xargs echo remove leading spaces) 34 wrapperInterpreter=$(echo "$wrapperInterpreterLine" | xargs echo | cut -d " " -f1) 35 36 if isScript $wrapperInterpreter 37 then 38 echo "error: passed interpreter ($interpreter) is a script which has another script ($wrapperInterpreter) as an interpreter, which is not supported." 39 exit 1 40 fi 41 42 # This should work as long as wrapperInterpreter is a shell, which is 43 # the case for programs wrapped with makeWrapper, like 44 # python3.withPackages etc. 45 interpreterLine="$wrapperInterpreterLine $interpreter" 46 else 47 interpreterLine=$interpreter 48 fi 49 50 echo "#! $interpreterLine" > $out 51 cat "$contentPath" >> $out 52 ${optionalString (check != "") '' 53 ${check} $out 54 ''} 55 chmod +x $out 56 ${optionalString (types.path.check nameOrPath) '' 57 mv $out tmp 58 mkdir -p $out/$(dirname "${nameOrPath}") 59 mv tmp $out/${nameOrPath} 60 ''} 61 ''; 62 63 # Base implementation for compiled executables. 64 # Takes a compile script, which in turn takes the name as an argument. 65 # 66 # Examples: 67 # writeSimpleC = makeBinWriter { compileScript = name: "gcc -o $out $contentPath"; } 68 makeBinWriter = { compileScript, strip ? true }: nameOrPath: content: 69 assert lib.or (types.path.check nameOrPath) (builtins.match "([0-9A-Za-z._])[0-9A-Za-z._-]*" nameOrPath != null); 70 assert lib.or (types.path.check content) (types.str.check content); 71 let 72 name = last (builtins.split "/" nameOrPath); 73 in 74 pkgs.runCommand name ((if (types.str.check content) then { 75 inherit content; 76 passAsFile = [ "content" ]; 77 } else { 78 contentPath = content; 79 }) // lib.optionalAttrs (stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isAarch64) { 80 # post-link-hook expects codesign_allocate to be in PATH 81 # https://github.com/NixOS/nixpkgs/issues/154203 82 # https://github.com/NixOS/nixpkgs/issues/148189 83 nativeBuildInputs = [ stdenv.cc.bintools ]; 84 }) '' 85 ${compileScript} 86 ${lib.optionalString strip 87 "${lib.getBin buildPackages.bintools-unwrapped}/bin/${buildPackages.bintools-unwrapped.targetPrefix}strip -S $out"} 88 # Sometimes binaries produced for darwin (e. g. by GHC) won't be valid 89 # mach-o executables from the get-go, but need to be corrected somehow 90 # which is done by fixupPhase. 91 ${lib.optionalString pkgs.stdenvNoCC.hostPlatform.isDarwin "fixupPhase"} 92 ${optionalString (types.path.check nameOrPath) '' 93 mv $out tmp 94 mkdir -p $out/$(dirname "${nameOrPath}") 95 mv tmp $out/${nameOrPath} 96 ''} 97 ''; 98 99 # Like writeScript but the first line is a shebang to bash 100 # 101 # Example: 102 # writeBash "example" '' 103 # echo hello world 104 # '' 105 writeBash = makeScriptWriter { 106 interpreter = "${pkgs.bash}/bin/bash"; 107 }; 108 109 # Like writeScriptBin but the first line is a shebang to bash 110 writeBashBin = name: 111 writeBash "/bin/${name}"; 112 113 # Like writeScript but the first line is a shebang to dash 114 # 115 # Example: 116 # writeDash "example" '' 117 # echo hello world 118 # '' 119 writeDash = makeScriptWriter { 120 interpreter = "${pkgs.dash}/bin/dash"; 121 }; 122 123 # Like writeScriptBin but the first line is a shebang to dash 124 writeDashBin = name: 125 writeDash "/bin/${name}"; 126 127 # Like writeScript but the first line is a shebang to fish 128 # 129 # Example: 130 # writeFish "example" '' 131 # echo hello world 132 # '' 133 writeFish = makeScriptWriter { 134 interpreter = "${pkgs.fish}/bin/fish --no-config"; 135 check = "${pkgs.fish}/bin/fish --no-config --no-execute"; # syntax check only 136 }; 137 138 # Like writeScriptBin but the first line is a shebang to fish 139 writeFishBin = name: 140 writeFish "/bin/${name}"; 141 142 # writeHaskell takes a name, an attrset with libraries and haskell version (both optional) 143 # and some haskell source code and returns an executable. 144 # 145 # Example: 146 # writeHaskell "missiles" { libraries = [ pkgs.haskellPackages.acme-missiles ]; } '' 147 # import Acme.Missiles 148 # 149 # main = launchMissiles 150 # ''; 151 writeHaskell = name: { 152 libraries ? [], 153 ghc ? pkgs.ghc, 154 ghcArgs ? [], 155 threadedRuntime ? true, 156 strip ? true 157 }: 158 let 159 appendIfNotSet = el: list: if elem el list then list else list ++ [ el ]; 160 ghcArgs' = if threadedRuntime then appendIfNotSet "-threaded" ghcArgs else ghcArgs; 161 162 in makeBinWriter { 163 compileScript = '' 164 cp $contentPath tmp.hs 165 ${ghc.withPackages (_: libraries )}/bin/ghc ${lib.escapeShellArgs ghcArgs'} tmp.hs 166 mv tmp $out 167 ''; 168 inherit strip; 169 } name; 170 171 # writeHaskellBin takes the same arguments as writeHaskell but outputs a directory (like writeScriptBin) 172 writeHaskellBin = name: 173 writeHaskell "/bin/${name}"; 174 175 writeRust = name: { 176 rustc ? pkgs.rustc, 177 rustcArgs ? [], 178 strip ? true 179 }: 180 let 181 darwinArgs = lib.optionals stdenv.isDarwin [ "-L${lib.getLib libiconv}/lib" ]; 182 in 183 makeBinWriter { 184 compileScript = '' 185 cp "$contentPath" tmp.rs 186 PATH=${makeBinPath [pkgs.gcc]} ${lib.getBin rustc}/bin/rustc ${lib.escapeShellArgs rustcArgs} ${lib.escapeShellArgs darwinArgs} -o "$out" tmp.rs 187 ''; 188 inherit strip; 189 } name; 190 191 writeRustBin = name: 192 writeRust "/bin/${name}"; 193 194 # writeJS takes a name an attributeset with libraries and some JavaScript sourcecode and 195 # returns an executable 196 # 197 # Example: 198 # writeJS "example" { libraries = [ pkgs.nodePackages.uglify-js ]; } '' 199 # var UglifyJS = require("uglify-js"); 200 # var code = "function add(first, second) { return first + second; }"; 201 # var result = UglifyJS.minify(code); 202 # console.log(result.code); 203 # '' 204 writeJS = name: { libraries ? [] }: content: 205 let 206 node-env = pkgs.buildEnv { 207 name = "node"; 208 paths = libraries; 209 pathsToLink = [ 210 "/lib/node_modules" 211 ]; 212 }; 213 in writeDash name '' 214 export NODE_PATH=${node-env}/lib/node_modules 215 exec ${pkgs.nodejs}/bin/node ${pkgs.writeText "js" content} "$@" 216 ''; 217 218 # writeJSBin takes the same arguments as writeJS but outputs a directory (like writeScriptBin) 219 writeJSBin = name: 220 writeJS "/bin/${name}"; 221 222 awkFormatNginx = builtins.toFile "awkFormat-nginx.awk" '' 223 awk -f 224 {sub(/^[ \t]+/,"");idx=0} 225 /\{/{ctx++;idx=1} 226 /\}/{ctx--} 227 {id="";for(i=idx;i<ctx;i++)id=sprintf("%s%s", id, "\t");printf "%s%s\n", id, $0} 228 ''; 229 230 writeNginxConfig = name: text: pkgs.runCommandLocal name { 231 inherit text; 232 passAsFile = [ "text" ]; 233 nativeBuildInputs = [ gixy ]; 234 } /* sh */ '' 235 # nginx-config-formatter has an error - https://github.com/1connect/nginx-config-formatter/issues/16 236 awk -f ${awkFormatNginx} "$textPath" | sed '/^\s*$/d' > $out 237 gixy $out 238 ''; 239 240 # writePerl takes a name an attributeset with libraries and some perl sourcecode and 241 # returns an executable 242 # 243 # Example: 244 # writePerl "example" { libraries = [ pkgs.perlPackages.boolean ]; } '' 245 # use boolean; 246 # print "Howdy!\n" if true; 247 # '' 248 writePerl = name: { libraries ? [] }: 249 makeScriptWriter { 250 interpreter = "${pkgs.perl.withPackages (p: libraries)}/bin/perl"; 251 } name; 252 253 # writePerlBin takes the same arguments as writePerl but outputs a directory (like writeScriptBin) 254 writePerlBin = name: 255 writePerl "/bin/${name}"; 256 257 # makePythonWriter takes python and compatible pythonPackages and produces python script writer, 258 # which validates the script with flake8 at build time. If any libraries are specified, 259 # python.withPackages is used as interpreter, otherwise the "bare" python is used. 260 makePythonWriter = python: pythonPackages: buildPythonPackages: name: { libraries ? [], flakeIgnore ? [] }: 261 let 262 ignoreAttribute = optionalString (flakeIgnore != []) "--ignore ${concatMapStringsSep "," escapeShellArg flakeIgnore}"; 263 in 264 makeScriptWriter { 265 interpreter = 266 if libraries == [] 267 then "${python}/bin/python" 268 else "${python.withPackages (ps: libraries)}/bin/python" 269 ; 270 check = optionalString python.isPy3k (writeDash "pythoncheck.sh" '' 271 exec ${buildPythonPackages.flake8}/bin/flake8 --show-source ${ignoreAttribute} "$1" 272 ''); 273 } name; 274 275 # writePyPy2 takes a name an attributeset with libraries and some pypy2 sourcecode and 276 # returns an executable 277 # 278 # Example: 279 # writePyPy2 "test_pypy2" { libraries = [ pkgs.pypy2Packages.enum ]; } '' 280 # from enum import Enum 281 # 282 # class Test(Enum): 283 # a = "success" 284 # 285 # print Test.a 286 # '' 287 writePyPy2 = makePythonWriter pkgs.pypy2 pkgs.pypy2Packages buildPackages.pypy2Packages; 288 289 # writePyPy2Bin takes the same arguments as writePyPy2 but outputs a directory (like writeScriptBin) 290 writePyPy2Bin = name: 291 writePyPy2 "/bin/${name}"; 292 293 # writePython3 takes a name an attributeset with libraries and some python3 sourcecode and 294 # returns an executable 295 # 296 # Example: 297 # writePython3 "test_python3" { libraries = [ pkgs.python3Packages.pyyaml ]; } '' 298 # import yaml 299 # 300 # y = yaml.load(""" 301 # - test: success 302 # """) 303 # print(y[0]['test']) 304 # '' 305 writePython3 = makePythonWriter pkgs.python3 pkgs.python3Packages buildPackages.python3Packages; 306 307 # writePython3Bin takes the same arguments as writePython3 but outputs a directory (like writeScriptBin) 308 writePython3Bin = name: 309 writePython3 "/bin/${name}"; 310 311 # writePyPy3 takes a name an attributeset with libraries and some pypy3 sourcecode and 312 # returns an executable 313 # 314 # Example: 315 # writePyPy3 "test_pypy3" { libraries = [ pkgs.pypy3Packages.pyyaml ]; } '' 316 # import yaml 317 # 318 # y = yaml.load(""" 319 # - test: success 320 # """) 321 # print(y[0]['test']) 322 # '' 323 writePyPy3 = makePythonWriter pkgs.pypy3 pkgs.pypy3Packages buildPackages.pypy3Packages; 324 325 # writePyPy3Bin takes the same arguments as writePyPy3 but outputs a directory (like writeScriptBin) 326 writePyPy3Bin = name: 327 writePyPy3 "/bin/${name}"; 328 329 330 makeFSharpWriter = { dotnet-sdk ? pkgs.dotnet-sdk, fsi-flags ? "", libraries ? _: [] }: nameOrPath: 331 let 332 fname = last (builtins.split "/" nameOrPath); 333 path = if strings.hasSuffix ".fsx" nameOrPath then nameOrPath else "${nameOrPath}.fsx"; 334 _nugetDeps = mkNugetDeps { name = "${fname}-nuget-deps"; nugetDeps = libraries; }; 335 336 nuget-source = mkNugetSource { 337 name = "${fname}-nuget-source"; 338 description = "A Nuget source with the dependencies for ${fname}"; 339 deps = [ _nugetDeps ]; 340 }; 341 342 fsi = writeBash "fsi" '' 343 export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 344 export DOTNET_CLI_TELEMETRY_OPTOUT=1 345 export DOTNET_NOLOGO=1 346 script="$1"; shift 347 ${dotnet-sdk}/bin/dotnet fsi --quiet --nologo --readline- ${fsi-flags} "$@" < "$script" 348 ''; 349 350 in content: writers.makeScriptWriter { 351 interpreter = fsi; 352 } path 353 '' 354 #i "nuget: ${nuget-source}/lib" 355 ${ content } 356 exit 0 357 ''; 358 359 writeFSharp = 360 makeFSharpWriter {}; 361 362 writeFSharpBin = name: 363 writeFSharp "/bin/${name}"; 364 365}; 366in 367writers // (aliases writers)