nixpkgs mirror (for testing) github.com/NixOS/nixpkgs
nix
at python-updates 1361 lines 36 kB view raw
1{ 2 buildPackages, 3 gixy, 4 lib, 5 libiconv, 6 makeBinaryWrapper, 7 mkNugetDeps, 8 mkNugetSource, 9 pkgs, 10 stdenv, 11}: 12let 13 inherit (lib) 14 concatMapStringsSep 15 elem 16 escapeShellArg 17 last 18 optionalString 19 strings 20 types 21 ; 22in 23rec { 24 /** 25 `makeScriptWriter` returns a derivation which creates an executable script. 26 27 # Inputs 28 29 config (AttrSet) 30 : `interpreter` (String) 31 : the [interpreter](https://en.wikipedia.org/wiki/Shebang_(Unix)) to use for the script. 32 : `check` (String) 33 : A command to check the script. For example, this could be a linting check. 34 : `makeWrapperArgs` (Optional, [ String ], Default: []) 35 : Arguments forwarded to (`makeWrapper`)[#fun-makeWrapper]. 36 37 `nameOrPath` (String) 38 : The name of the script or the path to the script. 39 40 When a `string` starting with "/" is passed, the script will be created at the specified path in $out. 41 I.e. `"/bin/hello"` will create a script at `$out/bin/hello`. 42 43 Any other `string` is interpreted as a filename. 44 It must be a [POSIX filename](https://en.wikipedia.org/wiki/Filename) starting with a letter, digit, dot, or underscore. 45 Spaces or special characters are not allowed. 46 47 `content` (String) 48 : The content of the script. 49 50 :::{.note} 51 This function is used as base implementation for other high-level writer functions. 52 53 For example, `writeBash` can (roughly) be implemented as: 54 55 ```nix 56 writeBash = makeScriptWriter { interpreter = "${pkgs.bash}/bin/bash"; } 57 ``` 58 ::: 59 60 # Examples 61 :::{.example} 62 ## `pkgs.writers.makeScriptWriter` dash example 63 64 ```nix-repl 65 :b makeScriptWriter { interpreter = "${pkgs.dash}/bin/dash"; } "hello" "echo hello world" 66 -> /nix/store/indvlr9ckmnv4f0ynkmasv2h4fxhand0-hello 67 ``` 68 69 The above example creates a script named `hello` that outputs `hello world` when executed. 70 71 ```sh 72 > /nix/store/indvlr9ckmnv4f0ynkmasv2h4fxhand0-hello 73 hello world 74 ``` 75 ::: 76 77 :::{.example} 78 ## `pkgs.writers.makeScriptWriter` python example 79 80 ```nix-repl 81 :b makeScriptWriter { interpreter = "${pkgs.python3}/bin/python"; } "python-hello" "print('hello world')" 82 -> /nix/store/4kvby1hqr45ffcdrvfpnpj62hanskw93-python-hello 83 ``` 84 85 ```sh 86 > /nix/store/4kvby1hqr45ffcdrvfpnpj62hanskw93-python-hello 87 hello world 88 ``` 89 ::: 90 */ 91 makeScriptWriter = 92 { 93 interpreter, 94 check ? "", 95 makeWrapperArgs ? [ ], 96 }: 97 nameOrPath: content: 98 assert 99 (types.path.check nameOrPath) 100 || (builtins.match "([0-9A-Za-z._])[0-9A-Za-z._-]*" nameOrPath != null); 101 assert (types.path.check content) || (types.str.check content); 102 let 103 nameIsPath = types.path.check nameOrPath; 104 name = last (builtins.split "/" nameOrPath); 105 path = if nameIsPath then nameOrPath else "/bin/${name}"; 106 # The inner derivation which creates the executable under $out/bin (never at $out directly) 107 # This is required in order to support wrapping, as wrapped programs consist of 108 # at least two files: the executable and the wrapper. 109 inner = 110 pkgs.runCommandLocal name 111 ( 112 { 113 inherit makeWrapperArgs; 114 nativeBuildInputs = [ makeBinaryWrapper ]; 115 meta.mainProgram = name; 116 } 117 // ( 118 if (types.str.check content) then 119 { 120 inherit content interpreter; 121 passAsFile = [ "content" ]; 122 } 123 else 124 { 125 inherit interpreter; 126 contentPath = content; 127 } 128 ) 129 ) 130 '' 131 # On darwin a script cannot be used as an interpreter in a shebang but 132 # there doesn't seem to be a limit to the size of shebang and multiple 133 # arguments to the interpreter are allowed. 134 if [[ -n "${toString pkgs.stdenvNoCC.hostPlatform.isDarwin}" ]] && isScript $interpreter 135 then 136 wrapperInterpreterLine=$(head -1 "$interpreter" | tail -c+3) 137 # Get first word from the line (note: xargs echo remove leading spaces) 138 wrapperInterpreter=$(echo "$wrapperInterpreterLine" | xargs echo | cut -d " " -f1) 139 140 if isScript $wrapperInterpreter 141 then 142 echo "error: passed interpreter ($interpreter) is a script which has another script ($wrapperInterpreter) as an interpreter, which is not supported." 143 exit 1 144 fi 145 146 # This should work as long as wrapperInterpreter is a shell, which is 147 # the case for programs wrapped with makeWrapper, like 148 # python3.withPackages etc. 149 interpreterLine="$wrapperInterpreterLine $interpreter" 150 else 151 interpreterLine=$interpreter 152 fi 153 154 echo "#! $interpreterLine" > $out 155 cat "$contentPath" >> $out 156 ${optionalString (check != "") '' 157 ${check} $out 158 ''} 159 chmod +x $out 160 161 # Relocate executable 162 # Wrap it if makeWrapperArgs are specified 163 mv $out tmp 164 mkdir -p $out/$(dirname "${path}") 165 mv tmp $out/${path} 166 if [ -n "''${makeWrapperArgs+''${makeWrapperArgs[@]}}" ]; then 167 wrapProgram $out/${path} ''${makeWrapperArgs[@]} 168 fi 169 ''; 170 in 171 if nameIsPath then 172 inner 173 # In case nameOrPath is a name, the user intends the executable to be located at $out. 174 # This is achieved by creating a separate derivation containing a symlink at $out linking to ${inner}/bin/${name}. 175 # This breaks the override pattern. 176 # In case this turns out to be a problem, we can still add more magic 177 else 178 pkgs.runCommandLocal name { } '' 179 ln -s ${inner}/bin/${name} $out 180 ''; 181 182 /** 183 `makeBinWriter` returns a derivation which compiles the given script into an executable format. 184 185 :::{.note} 186 This function is the base implementation for other compile language `writers`, such as `writeHaskell` and `writeRust`. 187 ::: 188 189 # Inputs 190 191 config (AttrSet) 192 : `compileScript` (String) 193 : The script that compiles the given content into an executable. 194 195 : `strip` (Boolean, Default: true) 196 : Whether to [strip](https://nixos.org/manual/nixpkgs/stable/#ssec-fixup-phase) the executable or not. 197 198 : `makeWrapperArgs` (Optional, [ String ], Default: []) 199 : Arguments forwarded to (`makeWrapper`)[#fun-makeWrapper] 200 201 `nameOrPath` (String) 202 : The name of the script or the path to the script. 203 204 When a `string` starting with "/" is passed, the script will be created at the specified path in $out. 205 For example, `"/bin/hello"` will create a script at `$out/bin/hello`. 206 207 Any other `string` is interpreted as a filename. 208 It must be a [POSIX filename](https://en.wikipedia.org/wiki/Filename) starting with a letter, digit, dot, or underscore. 209 Spaces or special characters are not allowed. 210 211 # Examples 212 :::{.example} 213 ## `pkgs.writers.makeBinWriter` example 214 215 ```c 216 // main.c 217 #include <stdio.h> 218 219 int main() 220 { 221 printf("Hello, World!\n"); 222 return 0; 223 } 224 ``` 225 226 ```nix-repl 227 :b makeBinWriter { compileScript = "${pkgs.gcc}/bin/gcc -o $out $contentPath"; } "hello" ./main.c 228 out -> /nix/store/f6crc8mwj3lvcxqclw7n09cm8nb6kxbh-hello 229 ``` 230 231 The above example creates an executable named `hello` that outputs `Hello, World!` when executed. 232 233 ```sh 234 > /nix/store/f6crc8mwj3lvcxqclw7n09cm8nb6kxbh-hello 235 Hello, World! 236 ``` 237 ::: 238 */ 239 makeBinWriter = 240 { 241 compileScript, 242 strip ? true, 243 makeWrapperArgs ? [ ], 244 }: 245 nameOrPath: content: 246 assert 247 (types.path.check nameOrPath) 248 || (builtins.match "([0-9A-Za-z._])[0-9A-Za-z._-]*" nameOrPath != null); 249 assert (types.path.check content) || (types.str.check content); 250 let 251 nameIsPath = types.path.check nameOrPath; 252 name = last (builtins.split "/" nameOrPath); 253 path = if nameIsPath then nameOrPath else "/bin/${name}"; 254 # The inner derivation which creates the executable under $out/bin (never at $out directly) 255 # This is required in order to support wrapping, as wrapped programs consist of at least two files: the executable and the wrapper. 256 inner = 257 pkgs.runCommandLocal name 258 ( 259 { 260 inherit makeWrapperArgs; 261 nativeBuildInputs = [ makeBinaryWrapper ]; 262 meta.mainProgram = name; 263 } 264 // ( 265 if (types.str.check content) then 266 { 267 inherit content; 268 passAsFile = [ "content" ]; 269 } 270 else 271 { contentPath = content; } 272 ) 273 ) 274 '' 275 ${compileScript} 276 ${lib.optionalString strip "${lib.getBin buildPackages.bintools-unwrapped}/bin/${buildPackages.bintools-unwrapped.targetPrefix}strip -S $out"} 277 # Sometimes binaries produced for darwin (e. g. by GHC) won't be valid 278 # mach-o executables from the get-go, but need to be corrected somehow 279 # which is done by fixupPhase. 280 ${lib.optionalString pkgs.stdenvNoCC.hostPlatform.isDarwin "fixupPhase"} 281 mv $out tmp 282 mkdir -p $out/$(dirname "${path}") 283 mv tmp $out/${path} 284 if [ -n "''${makeWrapperArgs+''${makeWrapperArgs[@]}}" ]; then 285 wrapProgram $out/${path} ''${makeWrapperArgs[@]} 286 fi 287 ''; 288 in 289 if nameIsPath then 290 inner 291 # In case nameOrPath is a name, the user intends the executable to be located at $out. 292 # This is achieved by creating a separate derivation containing a symlink at $out linking to ${inner}/bin/${name}. 293 # This breaks the override pattern. 294 # In case this turns out to be a problem, we can still add more magic 295 else 296 pkgs.runCommandLocal name { } '' 297 ln -s ${inner}/bin/${name} $out 298 ''; 299 300 /** 301 Like writeScript but the first line is a shebang to bash 302 Can be called with or without extra arguments. 303 304 # Examples 305 :::{.example} 306 307 ## Without arguments 308 309 ```nix 310 writeBash "example" '' 311 echo hello world 312 '' 313 ``` 314 315 ## With arguments 316 317 ```nix 318 writeBash "example" 319 { 320 makeWrapperArgs = [ 321 "--prefix" "PATH" ":" "${lib.makeBinPath [ pkgs.hello ]}" 322 ]; 323 } 324 '' 325 hello 326 '' 327 ``` 328 ::: 329 */ 330 writeBash = 331 name: argsOrScript: 332 if lib.isAttrs argsOrScript && !lib.isDerivation argsOrScript then 333 makeScriptWriter (argsOrScript // { interpreter = "${lib.getExe pkgs.bashNonInteractive}"; }) name 334 else 335 makeScriptWriter { interpreter = "${lib.getExe pkgs.bashNonInteractive}"; } name argsOrScript; 336 337 /** 338 Like writeScriptBin but the first line is a shebang to bash 339 340 Can be called with or without extra arguments. 341 342 ## Examples 343 :::{.example} 344 ## `pkgs.writers.writeBashBin` example without arguments 345 346 ```nix 347 writeBashBin "example" '' 348 echo hello world 349 '' 350 ``` 351 ::: 352 353 :::{.example} 354 ## `pkgs.writers.writeBashBin` example with arguments 355 356 ```nix 357 writeBashBin "example" 358 { 359 makeWrapperArgs = [ 360 "--prefix" "PATH" ":" "${lib.makeBinPath [ pkgs.hello ]}" 361 ]; 362 } 363 '' 364 hello 365 '' 366 ``` 367 ::: 368 */ 369 writeBashBin = name: writeBash "/bin/${name}"; 370 371 /** 372 Like writeScript but the first line is a shebang to dash 373 374 Can be called with or without extra arguments. 375 376 # Example 377 :::{.example} 378 ## `pkgs.writers.writeDash` example without arguments 379 380 ```nix 381 writeDash "example" '' 382 echo hello world 383 '' 384 ``` 385 ::: 386 387 :::{.example} 388 ## `pkgs.writers.writeDash` example with arguments 389 390 ```nix 391 writeDash "example" 392 { 393 makeWrapperArgs = [ 394 "--prefix" "PATH" ":" "${lib.makeBinPath [ pkgs.hello ]}" 395 ]; 396 } 397 '' 398 hello 399 '' 400 ``` 401 ::: 402 */ 403 writeDash = 404 name: argsOrScript: 405 if lib.isAttrs argsOrScript && !lib.isDerivation argsOrScript then 406 makeScriptWriter (argsOrScript // { interpreter = "${lib.getExe pkgs.dash}"; }) name 407 else 408 makeScriptWriter { interpreter = "${lib.getExe pkgs.dash}"; } name argsOrScript; 409 410 /** 411 Like writeScriptBin but the first line is a shebang to dash 412 413 Can be called with or without extra arguments. 414 415 # Examples 416 :::{.example} 417 ## `pkgs.writers.writeDashBin` without arguments 418 419 ```nix 420 writeDashBin "example" '' 421 echo hello world 422 '' 423 ``` 424 ::: 425 426 :::{.example} 427 ## `pkgs.writers.writeDashBin` with arguments 428 429 ```nix 430 writeDashBin "example" 431 { 432 makeWrapperArgs = [ 433 "--prefix" "PATH" ":" "${lib.makeBinPath [ pkgs.hello ]}" 434 ]; 435 } 436 '' 437 hello 438 '' 439 ``` 440 ::: 441 */ 442 writeDashBin = name: writeDash "/bin/${name}"; 443 444 /** 445 Like writeScript but the first line is a shebang to fish 446 447 Can be called with or without extra arguments. 448 449 :::{.example} 450 ## `pkgs.writers.writeFish` without arguments 451 452 ```nix 453 writeFish "example" '' 454 echo hello world 455 '' 456 ``` 457 ::: 458 459 :::{.example} 460 ## `pkgs.writers.writeFish` with arguments 461 462 ```nix 463 writeFish "example" 464 { 465 makeWrapperArgs = [ 466 "--prefix" "PATH" ":" "${lib.makeBinPath [ pkgs.hello ]}" 467 ]; 468 } 469 '' 470 hello 471 '' 472 ``` 473 ::: 474 */ 475 writeFish = 476 name: argsOrScript: 477 if lib.isAttrs argsOrScript && !lib.isDerivation argsOrScript then 478 makeScriptWriter ( 479 argsOrScript 480 // { 481 interpreter = "${lib.getExe pkgs.fish} --no-config"; 482 check = "${lib.getExe pkgs.fish} --no-config --no-execute"; # syntax check only 483 } 484 ) name 485 else 486 makeScriptWriter { 487 interpreter = "${lib.getExe pkgs.fish} --no-config"; 488 check = "${lib.getExe pkgs.fish} --no-config --no-execute"; # syntax check only 489 } name argsOrScript; 490 491 /** 492 Like writeScriptBin but the first line is a shebang to fish 493 494 Can be called with or without extra arguments. 495 496 # Examples 497 :::{.example} 498 ## `pkgs.writers.writeFishBin` without arguments 499 500 ```nix 501 writeFishBin "example" '' 502 echo hello world 503 '' 504 ``` 505 ::: 506 507 :::{.example} 508 ## `pkgs.writers.writeFishBin` with arguments 509 510 ```nix 511 writeFishBin "example" 512 { 513 makeWrapperArgs = [ 514 "--prefix" "PATH" ":" "${lib.makeBinPath [ pkgs.hello ]}" 515 ]; 516 } 517 '' 518 hello 519 '' 520 ``` 521 ::: 522 */ 523 writeFishBin = name: writeFish "/bin/${name}"; 524 525 /** 526 writeBabashka takes a name, an attrset with babashka interpreter and linting check (both optional) 527 and some babashka source code and returns an executable. 528 529 `pkgs.babashka-unwrapped` is used as default interpreter for small closure size. If dependencies needed, use `pkgs.babashka` instead. Pass empty string to check to disable the default clj-kondo linting. 530 531 # Examples 532 :::{.example} 533 ## `pkgs.writers.writeBabashka` with empty arguments 534 535 ```nix 536 writeBabashka "example" { } '' 537 (println "hello world") 538 '' 539 ``` 540 ::: 541 542 :::{.example} 543 ## `pkgs.writers.writeBabashka` with arguments 544 545 ```nix 546 writeBabashka "example" 547 { 548 makeWrapperArgs = [ 549 "--prefix" "PATH" ":" "${lib.makeBinPath [ pkgs.hello ]}" 550 ]; 551 } 552 '' 553 (require '[babashka.tasks :as tasks]) 554 (tasks/shell "hello" "-g" "Hello babashka!") 555 '' 556 ``` 557 ::: 558 559 :::{.note} 560 Babashka needs Java for fetching dependencies. Wrapped babashka contains jdk, 561 pass wrapped version `pkgs.babashka` to babashka if dependencies are required. 562 563 For example: 564 565 ```nix 566 writeBabashka "example" 567 { 568 babashka = pkgs.babashka; 569 } 570 '' 571 (require '[babashka.deps :as deps]) 572 (deps/add-deps '{:deps {medley/medley {:mvn/version "1.3.0"}}}) 573 (require '[medley.core :as m]) 574 (prn (m/index-by :id [{:id 1} {:id 2}])) 575 '' 576 ``` 577 ::: 578 579 :::{.note} 580 Disable clj-kondo linting: 581 582 ```nix 583 writeBabashka "example" 584 { 585 check = ""; 586 } 587 '' 588 (println "hello world") 589 '' 590 ``` 591 ::: 592 */ 593 writeBabashka = 594 name: 595 { 596 makeWrapperArgs ? [ ], 597 babashka ? pkgs.babashka-unwrapped, 598 check ? "${lib.getExe pkgs.clj-kondo} --lint", 599 ... 600 }@args: 601 makeScriptWriter ( 602 (removeAttrs args [ 603 "babashka" 604 ]) 605 // { 606 interpreter = "${lib.getExe babashka}"; 607 } 608 ) name; 609 610 /** 611 writeBabashkaBin takes the same arguments as writeBabashka but outputs a directory 612 (like writeScriptBin) 613 */ 614 writeBabashkaBin = name: writeBabashka "/bin/${name}"; 615 616 /** 617 `writeGuile` returns a derivation that creates an executable Guile script. 618 619 # Inputs 620 621 `nameOrPath` (String) 622 : Name of or path to the script. The semantics is the same as that of 623 `makeScriptWriter`. 624 625 `config` (AttrSet) 626 : `guile` (Optional, Derivation, Default: `pkgs.guile`) 627 : Guile package used for the script. 628 : `libraries` (Optional, [ Derivation ], Default: []) 629 : Extra Guile libraries exposed to the script. 630 : `r6rs` and `r7rs` (Optional, Boolean, Default: false) 631 : Whether to adapt Guiles initial environment to better support R6RS/ 632 R7RS. See the [Guile Reference Manual](https://www.gnu.org/software/guile/manual/html_node/index.html) 633 for details. 634 : `srfi` (Optional, [ Int ], Default: []) 635 : SRFI module to be loaded into the interpreter before evaluating a 636 script file or starting the REPL. See the Guile Reference Manual to 637 know which SRFI are supported. 638 : Other attributes are directly passed to `makeScriptWriter`. 639 640 `content` (String) 641 : Content of the script. 642 643 # Examples 644 645 :::{.example} 646 ## `pkgs.writers.writeGuile` with default config 647 648 ```nix 649 writeGuile "guile-script" { } 650 '' 651 (display "Hello, world!") 652 '' 653 ``` 654 ::: 655 656 :::{.example} 657 ## `pkgs.writers.writeGuile` with SRFI-1 enabled and extra libraries 658 659 ```nix 660 writeGuile "guile-script" { 661 libraries = [ pkgs.guile-semver ]; 662 srfi = [ 1 ]; 663 } 664 '' 665 (use-modules (semver)) 666 (make-semver 1 (third '(2 3 4)) 5) ; => #<semver 1.4.5> 667 '' 668 ``` 669 ::: 670 */ 671 writeGuile = 672 nameOrPath: 673 { 674 guile ? pkgs.guile, 675 libraries ? [ ], 676 r6rs ? false, 677 r7rs ? false, 678 srfi ? [ ], 679 ... 680 }@config: 681 content: 682 assert builtins.all builtins.isInt srfi; 683 let 684 finalGuile = pkgs.buildEnv { 685 name = "guile-env"; 686 paths = [ guile ] ++ libraries; 687 passthru = { 688 inherit (guile) siteDir siteCcacheDir; 689 }; 690 meta.mainProgram = guile.meta.mainProgram or "guile"; 691 }; 692 in 693 makeScriptWriter 694 ( 695 (removeAttrs config [ 696 "guile" 697 "libraries" 698 "r6rs" 699 "r7rs" 700 "srfi" 701 ]) 702 // { 703 interpreter = "${lib.getExe finalGuile} \\"; 704 makeWrapperArgs = [ 705 "--set" 706 "GUILE_LOAD_PATH" 707 "${finalGuile}/${finalGuile.siteDir}:${finalGuile}/lib/scheme-libs" 708 "--set" 709 "GUILE_LOAD_COMPILED_PATH" 710 "${finalGuile}/${finalGuile.siteCcacheDir}:${finalGuile}/lib/libobj" 711 "--set" 712 "LD_LIBRARY_PATH" 713 "${finalGuile}/lib/ffi" 714 "--set" 715 "DYLD_LIBRARY_PATH" 716 "${finalGuile}/lib/ffi" 717 ]; 718 } 719 ) 720 nameOrPath 721 /* 722 Spaces, newlines and tabs are significant for the "meta switch" of Guile, so 723 certain complication must be made to ensure correctness. 724 */ 725 ( 726 lib.concatStringsSep "\n" [ 727 (lib.concatStringsSep " " ( 728 [ "--no-auto-compile" ] 729 ++ lib.optional r6rs "--r6rs" 730 ++ lib.optional r7rs "--r7rs" 731 ++ lib.optional (srfi != [ ]) ("--use-srfi=" + concatMapStringsSep "," toString srfi) 732 ++ [ "-s" ] 733 )) 734 "!#" 735 content 736 ] 737 ); 738 739 /** 740 writeGuileBin takes the same arguments as writeGuile but outputs a directory 741 (like writeScriptBin) 742 */ 743 writeGuileBin = name: writeGuile "/bin/${name}"; 744 745 /** 746 writeHaskell takes a name, an attrset with libraries and haskell version (both optional) 747 and some haskell source code and returns an executable. 748 749 # Examples 750 :::{.example} 751 ## `pkgs.writers.writeHaskell` usage example 752 753 ```nix 754 writeHaskell "missiles" { libraries = [ pkgs.haskellPackages.acme-missiles ]; } '' 755 import Acme.Missiles 756 757 main = launchMissiles 758 ''; 759 ``` 760 ::: 761 */ 762 writeHaskell = 763 name: 764 { 765 ghc ? pkgs.ghc, 766 ghcArgs ? [ ], 767 libraries ? [ ], 768 makeWrapperArgs ? [ ], 769 strip ? true, 770 threadedRuntime ? true, 771 }: 772 let 773 appendIfNotSet = el: list: if elem el list then list else list ++ [ el ]; 774 ghcArgs' = if threadedRuntime then appendIfNotSet "-threaded" ghcArgs else ghcArgs; 775 776 in 777 makeBinWriter { 778 compileScript = '' 779 cp $contentPath tmp.hs 780 ${(ghc.withPackages (_: libraries))}/bin/ghc ${lib.escapeShellArgs ghcArgs'} tmp.hs 781 mv tmp $out 782 ''; 783 inherit makeWrapperArgs strip; 784 } name; 785 786 /** 787 writeHaskellBin takes the same arguments as writeHaskell but outputs a directory (like writeScriptBin) 788 */ 789 writeHaskellBin = name: writeHaskell "/bin/${name}"; 790 791 /** 792 writeNim takes a name, an attrset with an optional Nim compiler, and some 793 Nim source code, returning an executable. 794 795 # Examples 796 :::{.example} 797 ## `pkgs.writers.writeNim` usage example 798 799 ```nix 800 writeNim "hello-nim" { nim = pkgs.nim2; } '' 801 echo "hello nim" 802 ''; 803 ``` 804 ::: 805 */ 806 writeNim = 807 name: 808 { 809 makeWrapperArgs ? [ ], 810 nim ? pkgs.nim2, 811 nimCompileOptions ? { }, 812 strip ? true, 813 }: 814 let 815 optionFormat = optionName: { 816 option = "--${optionName}"; 817 sep = ":"; 818 explicitBool = false; 819 }; 820 821 nimCompileCmdArgs = lib.cli.toCommandLineShell optionFormat ( 822 { 823 d = "release"; 824 nimcache = "."; 825 } 826 // nimCompileOptions 827 ); 828 in 829 makeBinWriter { 830 compileScript = '' 831 cp $contentPath tmp.nim 832 ${lib.getExe nim} compile ${nimCompileCmdArgs} tmp.nim 833 mv tmp $out 834 ''; 835 inherit makeWrapperArgs strip; 836 } name; 837 838 /** 839 writeNimBin takes the same arguments as writeNim but outputs a directory 840 (like writeScriptBin) 841 */ 842 writeNimBin = name: writeNim "/bin/${name}"; 843 844 /** 845 Like writeScript but the first line is a shebang to nu 846 847 Can be called with or without extra arguments. 848 849 # Examples 850 :::{.example} 851 ## `pkgs.writers.writeNu` without arguments 852 853 ```nix 854 writeNu "example" '' 855 echo hello world 856 '' 857 ``` 858 ::: 859 860 :::{.example} 861 ## `pkgs.writers.writeNu` with arguments 862 863 ```nix 864 writeNu "example" 865 { 866 makeWrapperArgs = [ 867 "--prefix" "PATH" ":" "${lib.makeBinPath [ pkgs.hello ]}" 868 ]; 869 } 870 '' 871 hello 872 '' 873 ``` 874 ::: 875 */ 876 writeNu = 877 name: argsOrScript: 878 if lib.isAttrs argsOrScript && !lib.isDerivation argsOrScript then 879 makeScriptWriter ( 880 argsOrScript // { interpreter = "${lib.getExe pkgs.nushell} --no-config-file"; } 881 ) name 882 else 883 makeScriptWriter { interpreter = "${lib.getExe pkgs.nushell} --no-config-file"; } name argsOrScript; 884 885 /** 886 Like writeScriptBin but the first line is a shebang to nu 887 888 Can be called with or without extra arguments. 889 890 # Examples 891 :::{.example} 892 ## `pkgs.writers.writeNuBin` without arguments 893 894 ```nix 895 writeNuBin "example" '' 896 echo hello world 897 '' 898 ``` 899 ::: 900 901 :::{.example} 902 ## `pkgs.writers.writeNuBin` with arguments 903 904 ```nix 905 writeNuBin "example" 906 { 907 makeWrapperArgs = [ 908 "--prefix" "PATH" ":" "${lib.makeBinPath [ pkgs.hello ]}" 909 ]; 910 } 911 '' 912 hello 913 '' 914 ``` 915 ::: 916 */ 917 writeNuBin = name: writeNu "/bin/${name}"; 918 919 /** 920 makeRubyWriter takes ruby and compatible rubyPackages and produces ruby script writer, 921 If any libraries are specified, ruby.withPackages is used as interpreter, otherwise the "bare" ruby is used. 922 */ 923 makeRubyWriter = 924 ruby: rubyPackages: buildRubyPackages: name: 925 { 926 libraries ? [ ], 927 ... 928 }@args: 929 makeScriptWriter ( 930 (removeAttrs args [ "libraries" ]) 931 // { 932 interpreter = 933 if libraries == [ ] then "${ruby}/bin/ruby" else "${(ruby.withPackages (ps: libraries))}/bin/ruby"; 934 # Rubocop doesn't seem to like running in this fashion. 935 #check = (writeDash "rubocop.sh" '' 936 # exec ${lib.getExe buildRubyPackages.rubocop} "$1" 937 #''); 938 } 939 ) name; 940 941 /** 942 Like writeScript but the first line is a shebang to ruby 943 944 # Examples 945 :::{.example} 946 ## `pkgs.writers.writeRuby` usage example 947 948 ```nix 949 writeRuby "example" { libraries = [ pkgs.rubyPackages.git ]; } '' 950 puts "hello world" 951 '' 952 ``` 953 954 ::: 955 */ 956 writeRuby = makeRubyWriter pkgs.ruby pkgs.rubyPackages buildPackages.rubyPackages; 957 958 writeRubyBin = name: writeRuby "/bin/${name}"; 959 960 /** 961 makeLuaWriter takes lua and compatible luaPackages and produces lua script writer, 962 which validates the script with luacheck at build time. If any libraries are specified, 963 lua.withPackages is used as interpreter, otherwise the "bare" lua is used. 964 */ 965 makeLuaWriter = 966 lua: luaPackages: buildLuaPackages: name: 967 { 968 libraries ? [ ], 969 ... 970 }@args: 971 makeScriptWriter ( 972 (removeAttrs args [ "libraries" ]) 973 // { 974 interpreter = lua.interpreter; 975 # if libraries == [] 976 # then lua.interpreter 977 # else (lua.withPackages (ps: libraries)).interpreter 978 # This should support packages! I just cant figure out why some dependency collision happens whenever I try to run this. 979 check = ( 980 writeDash "luacheck.sh" '' 981 exec ${buildLuaPackages.luacheck}/bin/luacheck "$1" 982 '' 983 ); 984 } 985 ) name; 986 987 /** 988 writeLua takes a name an attributeset with libraries and some lua source code and 989 returns an executable (should also work with luajit) 990 991 # Examples 992 :::{.example} 993 ## `pkgs.writers.writeLua` usage example 994 995 ```nix 996 writeLua "test_lua" { libraries = [ pkgs.luaPackages.say ]; } '' 997 s = require("say") 998 s:set_namespace("en") 999 1000 s:set('money', 'I have %s dollars') 1001 s:set('wow', 'So much money!') 1002 1003 print(s('money', {1000})) -- I have 1000 dollars 1004 1005 s:set_namespace("fr") -- switch to french! 1006 s:set('wow', "Tant d'argent!") 1007 1008 print(s('wow')) -- Tant d'argent! 1009 s:set_namespace("en") -- switch back to english! 1010 print(s('wow')) -- So much money! 1011 '' 1012 ``` 1013 1014 ::: 1015 */ 1016 writeLua = makeLuaWriter pkgs.lua pkgs.luaPackages buildPackages.luaPackages; 1017 1018 writeLuaBin = name: writeLua "/bin/${name}"; 1019 1020 writeRust = 1021 name: 1022 { 1023 makeWrapperArgs ? [ ], 1024 rustc ? pkgs.rustc, 1025 rustcArgs ? [ ], 1026 strip ? true, 1027 }: 1028 let 1029 darwinArgs = lib.optionals stdenv.hostPlatform.isDarwin [ "-L${lib.getLib libiconv}/lib" ]; 1030 in 1031 makeBinWriter { 1032 compileScript = '' 1033 cp "$contentPath" tmp.rs 1034 PATH=${lib.makeBinPath [ pkgs.gcc ]} ${rustc}/bin/rustc ${lib.escapeShellArgs rustcArgs} ${lib.escapeShellArgs darwinArgs} -o "$out" tmp.rs 1035 ''; 1036 inherit makeWrapperArgs strip; 1037 } name; 1038 1039 writeRustBin = name: writeRust "/bin/${name}"; 1040 1041 /** 1042 writeJS takes a name an attributeset with libraries and some JavaScript sourcecode and 1043 returns an executable 1044 1045 # Inputs 1046 1047 `name` 1048 1049 : 1\. Function argument 1050 1051 `attrs` 1052 1053 : 2\. Function argument 1054 1055 `content` 1056 1057 : 3\. Function argument 1058 1059 # Examples 1060 :::{.example} 1061 ## `pkgs.writers.writeJS` usage example 1062 1063 ```nix 1064 writeJS "example" { libraries = [ pkgs.uglify-js ]; } '' 1065 var UglifyJS = require("uglify-js"); 1066 var code = "function add(first, second) { return first + second; }"; 1067 var result = UglifyJS.minify(code); 1068 console.log(result.code); 1069 '' 1070 ``` 1071 1072 ::: 1073 */ 1074 writeJS = 1075 name: 1076 { 1077 libraries ? [ ], 1078 }: 1079 content: 1080 let 1081 node-env = pkgs.buildEnv { 1082 name = "node"; 1083 paths = libraries; 1084 pathsToLink = [ "/lib/node_modules" ]; 1085 }; 1086 in 1087 writeDash name '' 1088 export NODE_PATH=${node-env}/lib/node_modules 1089 exec ${lib.getExe pkgs.nodejs} ${pkgs.writeText "js" content} "$@" 1090 ''; 1091 1092 /** 1093 writeJSBin takes the same arguments as writeJS but outputs a directory (like writeScriptBin) 1094 */ 1095 writeJSBin = name: writeJS "/bin/${name}"; 1096 1097 awkFormatNginx = builtins.toFile "awkFormat-nginx.awk" '' 1098 awk -f 1099 {sub(/^[ \t]+/,"");idx=0} 1100 /\{/{ctx++;idx=1} 1101 /\}/{ctx--} 1102 {id="";for(i=idx;i<ctx;i++)id=sprintf("%s%s", id, "\t");printf "%s%s\n", id, $0} 1103 ''; 1104 1105 writeNginxConfig = 1106 name: text: 1107 pkgs.runCommandLocal name 1108 { 1109 inherit text; 1110 passAsFile = [ "text" ]; 1111 nativeBuildInputs = [ gixy ]; 1112 } # sh 1113 '' 1114 # nginx-config-formatter has an error - https://github.com/1connect/nginx-config-formatter/issues/16 1115 awk -f ${awkFormatNginx} "$textPath" | sed '/^\s*$/d' > $out 1116 gixy $out || (echo "\n\nThis can be caused by combining multiple incompatible services on the same hostname.\n\nFull merged config:\n\n"; cat $out; exit 1) 1117 ''; 1118 1119 /** 1120 writePerl takes a name an attributeset with libraries and some perl sourcecode and 1121 returns an executable 1122 1123 # Examples 1124 :::{.example} 1125 ## `pkgs.writers.writePerl` usage example 1126 1127 ```nix 1128 writePerl "example" { libraries = [ pkgs.perlPackages.boolean ]; } '' 1129 use boolean; 1130 print "Howdy!\n" if true; 1131 '' 1132 ``` 1133 1134 ::: 1135 */ 1136 writePerl = 1137 name: 1138 { 1139 libraries ? [ ], 1140 ... 1141 }@args: 1142 makeScriptWriter ( 1143 (removeAttrs args [ "libraries" ]) 1144 // { 1145 interpreter = "${lib.getExe (pkgs.perl.withPackages (p: libraries))}"; 1146 } 1147 ) name; 1148 1149 /** 1150 writePerlBin takes the same arguments as writePerl but outputs a directory (like writeScriptBin) 1151 */ 1152 writePerlBin = name: writePerl "/bin/${name}"; 1153 1154 /** 1155 makePythonWriter takes python and compatible pythonPackages and produces python script writer, 1156 which validates the script with flake8 at build time. If any libraries are specified, 1157 python.withPackages is used as interpreter, otherwise the "bare" python is used. 1158 1159 # Inputs 1160 1161 `python` 1162 1163 : 1\. Function argument 1164 1165 `pythonPackages` 1166 1167 : 2\. Function argument 1168 1169 `buildPythonPackages` 1170 1171 : 3\. Function argument 1172 1173 `name` 1174 1175 : 4\. Function argument 1176 1177 `attrs` 1178 1179 : 5\. Function argument 1180 */ 1181 makePythonWriter = 1182 python: pythonPackages: buildPythonPackages: name: 1183 { 1184 libraries ? [ ], 1185 flakeIgnore ? [ ], 1186 doCheck ? true, 1187 ... 1188 }@args: 1189 let 1190 ignoreAttribute = 1191 optionalString (flakeIgnore != [ ]) 1192 "--ignore ${concatMapStringsSep "," escapeShellArg flakeIgnore}"; 1193 in 1194 makeScriptWriter ( 1195 (removeAttrs args [ 1196 "libraries" 1197 "flakeIgnore" 1198 "doCheck" 1199 ]) 1200 // { 1201 interpreter = 1202 if pythonPackages != pkgs.pypy2Packages || pythonPackages != pkgs.pypy3Packages then 1203 if libraries == [ ] then 1204 python.interpreter 1205 else if (lib.isFunction libraries) then 1206 (python.withPackages libraries).interpreter 1207 else 1208 (python.withPackages (ps: libraries)).interpreter 1209 else 1210 python.interpreter; 1211 check = optionalString (python.isPy3k && doCheck) ( 1212 writeDash "pythoncheck.sh" '' 1213 exec ${buildPythonPackages.flake8}/bin/flake8 --show-source ${ignoreAttribute} "$1" 1214 '' 1215 ); 1216 } 1217 ) name; 1218 1219 /** 1220 writePyPy2 takes a name an attributeset with libraries and some pypy2 sourcecode and 1221 returns an executable 1222 1223 # Examples 1224 :::{.example} 1225 ## `pkgs.writers.writePyPy2` usage example 1226 1227 ```nix 1228 writePyPy2 "test_pypy2" { libraries = [ pkgs.pypy2Packages.enum ]; } '' 1229 from enum import Enum 1230 1231 class Test(Enum): 1232 a = "success" 1233 1234 print Test.a 1235 '' 1236 ``` 1237 1238 ::: 1239 */ 1240 writePyPy2 = makePythonWriter pkgs.pypy2 pkgs.pypy2Packages buildPackages.pypy2Packages; 1241 1242 /** 1243 writePyPy2Bin takes the same arguments as writePyPy2 but outputs a directory (like writeScriptBin) 1244 */ 1245 writePyPy2Bin = name: writePyPy2 "/bin/${name}"; 1246 1247 /** 1248 writePython3 takes a name an attributeset with libraries and some python3 sourcecode and 1249 returns an executable 1250 1251 # Examples 1252 :::{.example} 1253 ## `pkgs.writers.writePython3` usage example 1254 1255 ```nix 1256 writePython3 "test_python3" { libraries = [ pkgs.python3Packages.pyyaml ]; } '' 1257 import yaml 1258 1259 y = yaml.safe_load(""" 1260 - test: success 1261 """) 1262 print(y[0]['test']) 1263 '' 1264 ``` 1265 1266 ::: 1267 */ 1268 writePython3 = makePythonWriter pkgs.python3 pkgs.python3Packages buildPackages.python3Packages; 1269 1270 # writePython3Bin takes the same arguments as writePython3 but outputs a directory (like writeScriptBin) 1271 writePython3Bin = name: writePython3 "/bin/${name}"; 1272 1273 /** 1274 writePyPy3 takes a name an attributeset with libraries and some pypy3 sourcecode and 1275 returns an executable 1276 1277 # Examples 1278 :::{.example} 1279 ## `pkgs.writers.writePyPy3` usage example 1280 1281 ```nix 1282 writePyPy3 "test_pypy3" { libraries = [ pkgs.pypy3Packages.pyyaml ]; } '' 1283 import yaml 1284 1285 y = yaml.safe_load(""" 1286 - test: success 1287 """) 1288 print(y[0]['test']) 1289 '' 1290 ``` 1291 1292 ::: 1293 */ 1294 writePyPy3 = makePythonWriter pkgs.pypy3 pkgs.pypy3Packages buildPackages.pypy3Packages; 1295 1296 /** 1297 writePyPy3Bin takes the same arguments as writePyPy3 but outputs a directory (like writeScriptBin) 1298 */ 1299 writePyPy3Bin = name: writePyPy3 "/bin/${name}"; 1300 1301 makeFSharpWriter = 1302 { 1303 dotnet-sdk ? pkgs.dotnet-sdk, 1304 fsi-flags ? "", 1305 libraries ? _: [ ], 1306 ... 1307 }@args: 1308 nameOrPath: 1309 let 1310 fname = last (builtins.split "/" nameOrPath); 1311 path = if strings.hasSuffix ".fsx" nameOrPath then nameOrPath else "${nameOrPath}.fsx"; 1312 _nugetDeps = mkNugetDeps { 1313 name = "${fname}-nuget-deps"; 1314 nugetDeps = libraries; 1315 }; 1316 1317 nuget-source = mkNugetSource { 1318 name = "${fname}-nuget-source"; 1319 description = "Nuget source with the dependencies for ${fname}"; 1320 deps = [ _nugetDeps ]; 1321 }; 1322 1323 fsi = writeBash "fsi" '' 1324 set -euo pipefail 1325 export HOME=$NIX_BUILD_TOP/.home 1326 export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 1327 export DOTNET_CLI_TELEMETRY_OPTOUT=1 1328 export DOTNET_NOLOGO=1 1329 export DOTNET_SKIP_WORKLOAD_INTEGRITY_CHECK=1 1330 script="$1"; shift 1331 ( 1332 ${lib.getExe dotnet-sdk} new nugetconfig 1333 ${lib.getExe dotnet-sdk} nuget disable source nuget 1334 ) > /dev/null 1335 ${lib.getExe dotnet-sdk} fsi --quiet --nologo --readline- ${fsi-flags} "$@" < "$script" 1336 ''; 1337 1338 in 1339 content: 1340 makeScriptWriter 1341 ( 1342 (removeAttrs args [ 1343 "dotnet-sdk" 1344 "fsi-flags" 1345 "libraries" 1346 ]) 1347 // { 1348 interpreter = fsi; 1349 } 1350 ) 1351 path 1352 '' 1353 #i "nuget: ${nuget-source}/lib" 1354 ${content} 1355 exit 0 1356 ''; 1357 1358 writeFSharp = makeFSharpWriter { }; 1359 1360 writeFSharpBin = name: writeFSharp "/bin/${name}"; 1361}