Merge pull request #141400 from lovesegfault/writeShellApplication

writeShellApplication: init

authored by

Bernardo Meurer and committed by
GitHub
342bd7ae dc4f539a

+83 -4
+22
doc/builders/trivial-builders.chapter.md
··· 47 47 48 48 Many more commands wrap `writeTextFile` including `writeText`, `writeTextDir`, `writeScript`, and `writeScriptBin`. These are convenience functions over `writeTextFile`. 49 49 50 + ## `writeShellApplication` {#trivial-builder-writeShellApplication} 51 + 52 + This can be used to easily produce a shell script that has some dependencies (`runtimeInputs`). It automatically sets the `PATH` of the script to contain all of the listed inputs, sets some sanity shellopts (`errexit`, `nounset`, `pipefail`), and checks the resulting script with [`shellcheck`](https://github.com/koalaman/shellcheck). 53 + 54 + For example, look at the following code: 55 + 56 + ```nix 57 + writeShellApplication { 58 + name = "show-nixos-org"; 59 + 60 + runtimeInputs = [ curl w3m ]; 61 + 62 + text = '' 63 + curl -s 'https://nixos.org' | w3m -dump -T text/html 64 + ''; 65 + } 66 + ``` 67 + 68 + Unlike with normal `writeShellScriptBin`, there is no need to manually write out `${curl}/bin/curl`, setting the PATH 69 + was handled by `writeShellApplication`. Moreover, the script is being checked with `shellcheck` for more strict 70 + validation. 71 + 50 72 ## `symlinkJoin` {#trivial-builder-symlinkJoin} 51 73 52 74 This can be used to put many derivations into the same directory structure. It works by creating a new derivation and adding symlinks to each of the paths listed. It expects two arguments, `name`, and `paths`. `name` is the name used in the Nix store path for the created derivation. `paths` is a list of paths that will be symlinked. These paths can be to Nix store derivations or any other subdirectory contained within.
+57 -2
pkgs/build-support/trivial-builders.nix
··· 1 - { lib, stdenv, stdenvNoCC, lndir, runtimeShell }: 1 + { lib, stdenv, stdenvNoCC, lndir, runtimeShell, shellcheck }: 2 2 3 3 rec { 4 4 ··· 111 111 , executable ? false # run chmod +x ? 112 112 , destination ? "" # relative path appended to $out eg "/bin/foo" 113 113 , checkPhase ? "" # syntax checks, e.g. for scripts 114 + , meta ? { } 114 115 }: 115 116 runCommand name 116 - { inherit text executable checkPhase; 117 + { inherit text executable checkPhase meta; 117 118 passAsFile = [ "text" ]; 118 119 # Pointless to do this on a remote machine. 119 120 preferLocalBuild = true; ··· 247 248 checkPhase = '' 248 249 ${stdenv.shell} -n $out/bin/${name} 249 250 ''; 251 + }; 252 + 253 + /* 254 + * Similar to writeShellScriptBin and writeScriptBin. 255 + * Writes an executable Shell script to /nix/store/<store path>/bin/<name> and 256 + * checks its syntax with shellcheck and the shell's -n option. 257 + * Automatically includes sane set of shellopts (errexit, nounset, pipefail) 258 + * and handles creation of PATH based on runtimeInputs 259 + * 260 + * Note that the checkPhase uses stdenv.shell for the test run of the script, 261 + * while the generated shebang uses runtimeShell. If, for whatever reason, 262 + * those were to mismatch you might lose fidelity in the default checks. 263 + * 264 + * Example: 265 + * # Writes my-file to /nix/store/<store path>/bin/my-file and makes executable. 266 + * writeShellApplication { 267 + * name = "my-file"; 268 + * runtimeInputs = [ curl w3m ]; 269 + * text = '' 270 + * curl -s 'https://nixos.org' | w3m -dump -T text/html 271 + * ''; 272 + * } 273 + */ 274 + writeShellApplication = 275 + { name 276 + , text 277 + , runtimeInputs ? [ ] 278 + , checkPhase ? null 279 + }: 280 + writeTextFile { 281 + inherit name; 282 + executable = true; 283 + destination = "/bin/${name}"; 284 + text = '' 285 + #!${runtimeShell} 286 + set -o errexit 287 + set -o nounset 288 + set -o pipefail 289 + 290 + export PATH="${lib.makeBinPath runtimeInputs}:$PATH" 291 + 292 + ${text} 293 + ''; 294 + 295 + checkPhase = 296 + if checkPhase == null then '' 297 + runHook preCheck 298 + ${stdenv.shell} -n $out/bin/${name} 299 + ${shellcheck}/bin/shellcheck $out/bin/${name} 300 + runHook postCheck 301 + '' 302 + else checkPhase; 303 + 304 + meta.mainProgram = name; 250 305 }; 251 306 252 307 # Create a C binary
+4 -2
pkgs/top-level/stage.nix
··· 76 76 77 77 trivialBuilders = self: super: 78 78 import ../build-support/trivial-builders.nix { 79 - inherit lib; inherit (self) stdenv stdenvNoCC; inherit (self.pkgsBuildHost.xorg) lndir; 80 - inherit (self) runtimeShell; 79 + inherit lib; 80 + inherit (self) runtimeShell stdenv stdenvNoCC; 81 + inherit (self.pkgsBuildHost) shellcheck; 82 + inherit (self.pkgsBuildHost.xorg) lndir; 81 83 }; 82 84 83 85 stdenvBootstappingAndPlatforms = self: super: let