nixpkgs mirror (for testing) github.com/NixOS/nixpkgs
nix
at devShellTools-shell 1355 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.bash}"; }) name 334 else 335 makeScriptWriter { interpreter = "${lib.getExe pkgs.bash}"; } 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 (builtins.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 (builtins.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 "," builtins.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 nimCompileCmdArgs = lib.cli.toGNUCommandLineShell { optionValueSeparator = ":"; } ( 816 { 817 d = "release"; 818 nimcache = "."; 819 } 820 // nimCompileOptions 821 ); 822 in 823 makeBinWriter { 824 compileScript = '' 825 cp $contentPath tmp.nim 826 ${lib.getExe nim} compile ${nimCompileCmdArgs} tmp.nim 827 mv tmp $out 828 ''; 829 inherit makeWrapperArgs strip; 830 } name; 831 832 /** 833 writeNimBin takes the same arguments as writeNim but outputs a directory 834 (like writeScriptBin) 835 */ 836 writeNimBin = name: writeNim "/bin/${name}"; 837 838 /** 839 Like writeScript but the first line is a shebang to nu 840 841 Can be called with or without extra arguments. 842 843 # Examples 844 :::{.example} 845 ## `pkgs.writers.writeNu` without arguments 846 847 ```nix 848 writeNu "example" '' 849 echo hello world 850 '' 851 ``` 852 ::: 853 854 :::{.example} 855 ## `pkgs.writers.writeNu` with arguments 856 857 ```nix 858 writeNu "example" 859 { 860 makeWrapperArgs = [ 861 "--prefix" "PATH" ":" "${lib.makeBinPath [ pkgs.hello ]}" 862 ]; 863 } 864 '' 865 hello 866 '' 867 ``` 868 ::: 869 */ 870 writeNu = 871 name: argsOrScript: 872 if lib.isAttrs argsOrScript && !lib.isDerivation argsOrScript then 873 makeScriptWriter ( 874 argsOrScript // { interpreter = "${lib.getExe pkgs.nushell} --no-config-file"; } 875 ) name 876 else 877 makeScriptWriter { interpreter = "${lib.getExe pkgs.nushell} --no-config-file"; } name argsOrScript; 878 879 /** 880 Like writeScriptBin but the first line is a shebang to nu 881 882 Can be called with or without extra arguments. 883 884 # Examples 885 :::{.example} 886 ## `pkgs.writers.writeNuBin` without arguments 887 888 ```nix 889 writeNuBin "example" '' 890 echo hello world 891 '' 892 ``` 893 ::: 894 895 :::{.example} 896 ## `pkgs.writers.writeNuBin` with arguments 897 898 ```nix 899 writeNuBin "example" 900 { 901 makeWrapperArgs = [ 902 "--prefix" "PATH" ":" "${lib.makeBinPath [ pkgs.hello ]}" 903 ]; 904 } 905 '' 906 hello 907 '' 908 ``` 909 ::: 910 */ 911 writeNuBin = name: writeNu "/bin/${name}"; 912 913 /** 914 makeRubyWriter takes ruby and compatible rubyPackages and produces ruby script writer, 915 If any libraries are specified, ruby.withPackages is used as interpreter, otherwise the "bare" ruby is used. 916 */ 917 makeRubyWriter = 918 ruby: rubyPackages: buildRubyPackages: name: 919 { 920 libraries ? [ ], 921 ... 922 }@args: 923 makeScriptWriter ( 924 (builtins.removeAttrs args [ "libraries" ]) 925 // { 926 interpreter = 927 if libraries == [ ] then "${ruby}/bin/ruby" else "${(ruby.withPackages (ps: libraries))}/bin/ruby"; 928 # Rubocop doesn't seem to like running in this fashion. 929 #check = (writeDash "rubocop.sh" '' 930 # exec ${lib.getExe buildRubyPackages.rubocop} "$1" 931 #''); 932 } 933 ) name; 934 935 /** 936 Like writeScript but the first line is a shebang to ruby 937 938 # Examples 939 :::{.example} 940 ## `pkgs.writers.writeRuby` usage example 941 942 ```nix 943 writeRuby "example" { libraries = [ pkgs.rubyPackages.git ]; } '' 944 puts "hello world" 945 '' 946 ``` 947 948 ::: 949 */ 950 writeRuby = makeRubyWriter pkgs.ruby pkgs.rubyPackages buildPackages.rubyPackages; 951 952 writeRubyBin = name: writeRuby "/bin/${name}"; 953 954 /** 955 makeLuaWriter takes lua and compatible luaPackages and produces lua script writer, 956 which validates the script with luacheck at build time. If any libraries are specified, 957 lua.withPackages is used as interpreter, otherwise the "bare" lua is used. 958 */ 959 makeLuaWriter = 960 lua: luaPackages: buildLuaPackages: name: 961 { 962 libraries ? [ ], 963 ... 964 }@args: 965 makeScriptWriter ( 966 (builtins.removeAttrs args [ "libraries" ]) 967 // { 968 interpreter = lua.interpreter; 969 # if libraries == [] 970 # then lua.interpreter 971 # else (lua.withPackages (ps: libraries)).interpreter 972 # This should support packages! I just cant figure out why some dependency collision happens whenever I try to run this. 973 check = ( 974 writeDash "luacheck.sh" '' 975 exec ${buildLuaPackages.luacheck}/bin/luacheck "$1" 976 '' 977 ); 978 } 979 ) name; 980 981 /** 982 writeLua takes a name an attributeset with libraries and some lua source code and 983 returns an executable (should also work with luajit) 984 985 # Examples 986 :::{.example} 987 ## `pkgs.writers.writeLua` usage example 988 989 ```nix 990 writeLua "test_lua" { libraries = [ pkgs.luaPackages.say ]; } '' 991 s = require("say") 992 s:set_namespace("en") 993 994 s:set('money', 'I have %s dollars') 995 s:set('wow', 'So much money!') 996 997 print(s('money', {1000})) -- I have 1000 dollars 998 999 s:set_namespace("fr") -- switch to french! 1000 s:set('wow', "Tant d'argent!") 1001 1002 print(s('wow')) -- Tant d'argent! 1003 s:set_namespace("en") -- switch back to english! 1004 print(s('wow')) -- So much money! 1005 '' 1006 ``` 1007 1008 ::: 1009 */ 1010 writeLua = makeLuaWriter pkgs.lua pkgs.luaPackages buildPackages.luaPackages; 1011 1012 writeLuaBin = name: writeLua "/bin/${name}"; 1013 1014 writeRust = 1015 name: 1016 { 1017 makeWrapperArgs ? [ ], 1018 rustc ? pkgs.rustc, 1019 rustcArgs ? [ ], 1020 strip ? true, 1021 }: 1022 let 1023 darwinArgs = lib.optionals stdenv.hostPlatform.isDarwin [ "-L${lib.getLib libiconv}/lib" ]; 1024 in 1025 makeBinWriter { 1026 compileScript = '' 1027 cp "$contentPath" tmp.rs 1028 PATH=${lib.makeBinPath [ pkgs.gcc ]} ${rustc}/bin/rustc ${lib.escapeShellArgs rustcArgs} ${lib.escapeShellArgs darwinArgs} -o "$out" tmp.rs 1029 ''; 1030 inherit makeWrapperArgs strip; 1031 } name; 1032 1033 writeRustBin = name: writeRust "/bin/${name}"; 1034 1035 /** 1036 writeJS takes a name an attributeset with libraries and some JavaScript sourcecode and 1037 returns an executable 1038 1039 # Inputs 1040 1041 `name` 1042 1043 : 1\. Function argument 1044 1045 `attrs` 1046 1047 : 2\. Function argument 1048 1049 `content` 1050 1051 : 3\. Function argument 1052 1053 # Examples 1054 :::{.example} 1055 ## `pkgs.writers.writeJS` usage example 1056 1057 ```nix 1058 writeJS "example" { libraries = [ pkgs.uglify-js ]; } '' 1059 var UglifyJS = require("uglify-js"); 1060 var code = "function add(first, second) { return first + second; }"; 1061 var result = UglifyJS.minify(code); 1062 console.log(result.code); 1063 '' 1064 ``` 1065 1066 ::: 1067 */ 1068 writeJS = 1069 name: 1070 { 1071 libraries ? [ ], 1072 }: 1073 content: 1074 let 1075 node-env = pkgs.buildEnv { 1076 name = "node"; 1077 paths = libraries; 1078 pathsToLink = [ "/lib/node_modules" ]; 1079 }; 1080 in 1081 writeDash name '' 1082 export NODE_PATH=${node-env}/lib/node_modules 1083 exec ${lib.getExe pkgs.nodejs} ${pkgs.writeText "js" content} "$@" 1084 ''; 1085 1086 /** 1087 writeJSBin takes the same arguments as writeJS but outputs a directory (like writeScriptBin) 1088 */ 1089 writeJSBin = name: writeJS "/bin/${name}"; 1090 1091 awkFormatNginx = builtins.toFile "awkFormat-nginx.awk" '' 1092 awk -f 1093 {sub(/^[ \t]+/,"");idx=0} 1094 /\{/{ctx++;idx=1} 1095 /\}/{ctx--} 1096 {id="";for(i=idx;i<ctx;i++)id=sprintf("%s%s", id, "\t");printf "%s%s\n", id, $0} 1097 ''; 1098 1099 writeNginxConfig = 1100 name: text: 1101 pkgs.runCommandLocal name 1102 { 1103 inherit text; 1104 passAsFile = [ "text" ]; 1105 nativeBuildInputs = [ gixy ]; 1106 } # sh 1107 '' 1108 # nginx-config-formatter has an error - https://github.com/1connect/nginx-config-formatter/issues/16 1109 awk -f ${awkFormatNginx} "$textPath" | sed '/^\s*$/d' > $out 1110 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) 1111 ''; 1112 1113 /** 1114 writePerl takes a name an attributeset with libraries and some perl sourcecode and 1115 returns an executable 1116 1117 # Examples 1118 :::{.example} 1119 ## `pkgs.writers.writePerl` usage example 1120 1121 ```nix 1122 writePerl "example" { libraries = [ pkgs.perlPackages.boolean ]; } '' 1123 use boolean; 1124 print "Howdy!\n" if true; 1125 '' 1126 ``` 1127 1128 ::: 1129 */ 1130 writePerl = 1131 name: 1132 { 1133 libraries ? [ ], 1134 ... 1135 }@args: 1136 makeScriptWriter ( 1137 (builtins.removeAttrs args [ "libraries" ]) 1138 // { 1139 interpreter = "${lib.getExe (pkgs.perl.withPackages (p: libraries))}"; 1140 } 1141 ) name; 1142 1143 /** 1144 writePerlBin takes the same arguments as writePerl but outputs a directory (like writeScriptBin) 1145 */ 1146 writePerlBin = name: writePerl "/bin/${name}"; 1147 1148 /** 1149 makePythonWriter takes python and compatible pythonPackages and produces python script writer, 1150 which validates the script with flake8 at build time. If any libraries are specified, 1151 python.withPackages is used as interpreter, otherwise the "bare" python is used. 1152 1153 # Inputs 1154 1155 `python` 1156 1157 : 1\. Function argument 1158 1159 `pythonPackages` 1160 1161 : 2\. Function argument 1162 1163 `buildPythonPackages` 1164 1165 : 3\. Function argument 1166 1167 `name` 1168 1169 : 4\. Function argument 1170 1171 `attrs` 1172 1173 : 5\. Function argument 1174 */ 1175 makePythonWriter = 1176 python: pythonPackages: buildPythonPackages: name: 1177 { 1178 libraries ? [ ], 1179 flakeIgnore ? [ ], 1180 doCheck ? true, 1181 ... 1182 }@args: 1183 let 1184 ignoreAttribute = 1185 optionalString (flakeIgnore != [ ]) 1186 "--ignore ${concatMapStringsSep "," escapeShellArg flakeIgnore}"; 1187 in 1188 makeScriptWriter ( 1189 (builtins.removeAttrs args [ 1190 "libraries" 1191 "flakeIgnore" 1192 "doCheck" 1193 ]) 1194 // { 1195 interpreter = 1196 if pythonPackages != pkgs.pypy2Packages || pythonPackages != pkgs.pypy3Packages then 1197 if libraries == [ ] then 1198 python.interpreter 1199 else if (lib.isFunction libraries) then 1200 (python.withPackages libraries).interpreter 1201 else 1202 (python.withPackages (ps: libraries)).interpreter 1203 else 1204 python.interpreter; 1205 check = optionalString (python.isPy3k && doCheck) ( 1206 writeDash "pythoncheck.sh" '' 1207 exec ${buildPythonPackages.flake8}/bin/flake8 --show-source ${ignoreAttribute} "$1" 1208 '' 1209 ); 1210 } 1211 ) name; 1212 1213 /** 1214 writePyPy2 takes a name an attributeset with libraries and some pypy2 sourcecode and 1215 returns an executable 1216 1217 # Examples 1218 :::{.example} 1219 ## `pkgs.writers.writePyPy2` usage example 1220 1221 ```nix 1222 writePyPy2 "test_pypy2" { libraries = [ pkgs.pypy2Packages.enum ]; } '' 1223 from enum import Enum 1224 1225 class Test(Enum): 1226 a = "success" 1227 1228 print Test.a 1229 '' 1230 ``` 1231 1232 ::: 1233 */ 1234 writePyPy2 = makePythonWriter pkgs.pypy2 pkgs.pypy2Packages buildPackages.pypy2Packages; 1235 1236 /** 1237 writePyPy2Bin takes the same arguments as writePyPy2 but outputs a directory (like writeScriptBin) 1238 */ 1239 writePyPy2Bin = name: writePyPy2 "/bin/${name}"; 1240 1241 /** 1242 writePython3 takes a name an attributeset with libraries and some python3 sourcecode and 1243 returns an executable 1244 1245 # Examples 1246 :::{.example} 1247 ## `pkgs.writers.writePython3` usage example 1248 1249 ```nix 1250 writePython3 "test_python3" { libraries = [ pkgs.python3Packages.pyyaml ]; } '' 1251 import yaml 1252 1253 y = yaml.safe_load(""" 1254 - test: success 1255 """) 1256 print(y[0]['test']) 1257 '' 1258 ``` 1259 1260 ::: 1261 */ 1262 writePython3 = makePythonWriter pkgs.python3 pkgs.python3Packages buildPackages.python3Packages; 1263 1264 # writePython3Bin takes the same arguments as writePython3 but outputs a directory (like writeScriptBin) 1265 writePython3Bin = name: writePython3 "/bin/${name}"; 1266 1267 /** 1268 writePyPy3 takes a name an attributeset with libraries and some pypy3 sourcecode and 1269 returns an executable 1270 1271 # Examples 1272 :::{.example} 1273 ## `pkgs.writers.writePyPy3` usage example 1274 1275 ```nix 1276 writePyPy3 "test_pypy3" { libraries = [ pkgs.pypy3Packages.pyyaml ]; } '' 1277 import yaml 1278 1279 y = yaml.safe_load(""" 1280 - test: success 1281 """) 1282 print(y[0]['test']) 1283 '' 1284 ``` 1285 1286 ::: 1287 */ 1288 writePyPy3 = makePythonWriter pkgs.pypy3 pkgs.pypy3Packages buildPackages.pypy3Packages; 1289 1290 /** 1291 writePyPy3Bin takes the same arguments as writePyPy3 but outputs a directory (like writeScriptBin) 1292 */ 1293 writePyPy3Bin = name: writePyPy3 "/bin/${name}"; 1294 1295 makeFSharpWriter = 1296 { 1297 dotnet-sdk ? pkgs.dotnet-sdk, 1298 fsi-flags ? "", 1299 libraries ? _: [ ], 1300 ... 1301 }@args: 1302 nameOrPath: 1303 let 1304 fname = last (builtins.split "/" nameOrPath); 1305 path = if strings.hasSuffix ".fsx" nameOrPath then nameOrPath else "${nameOrPath}.fsx"; 1306 _nugetDeps = mkNugetDeps { 1307 name = "${fname}-nuget-deps"; 1308 nugetDeps = libraries; 1309 }; 1310 1311 nuget-source = mkNugetSource { 1312 name = "${fname}-nuget-source"; 1313 description = "Nuget source with the dependencies for ${fname}"; 1314 deps = [ _nugetDeps ]; 1315 }; 1316 1317 fsi = writeBash "fsi" '' 1318 set -euo pipefail 1319 export HOME=$NIX_BUILD_TOP/.home 1320 export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 1321 export DOTNET_CLI_TELEMETRY_OPTOUT=1 1322 export DOTNET_NOLOGO=1 1323 export DOTNET_SKIP_WORKLOAD_INTEGRITY_CHECK=1 1324 script="$1"; shift 1325 ( 1326 ${lib.getExe dotnet-sdk} new nugetconfig 1327 ${lib.getExe dotnet-sdk} nuget disable source nuget 1328 ) > /dev/null 1329 ${lib.getExe dotnet-sdk} fsi --quiet --nologo --readline- ${fsi-flags} "$@" < "$script" 1330 ''; 1331 1332 in 1333 content: 1334 makeScriptWriter 1335 ( 1336 (builtins.removeAttrs args [ 1337 "dotnet-sdk" 1338 "fsi-flags" 1339 "libraries" 1340 ]) 1341 // { 1342 interpreter = fsi; 1343 } 1344 ) 1345 path 1346 '' 1347 #i "nuget: ${nuget-source}/lib" 1348 ${content} 1349 exit 0 1350 ''; 1351 1352 writeFSharp = makeFSharpWriter { }; 1353 1354 writeFSharpBin = name: writeFSharp "/bin/${name}"; 1355}