Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
at devShellTools-shell 430 lines 15 kB view raw
1{ 2 stdenv, 3 lib, 4 fetchFromGitHub, 5 coreutils, 6 darwin, 7 glibcLocales, 8 gnused, 9 gnugrep, 10 groff, 11 gawk, 12 man-db, 13 ninja, 14 getent, 15 libiconv, 16 pcre2, 17 pkg-config, 18 sphinx, 19 gettext, 20 ncurses, 21 python3, 22 cargo, 23 cmake, 24 fishPlugins, 25 procps, 26 rustc, 27 rustPlatform, 28 versionCheckHook, 29 writableTmpDirAsHomeHook, 30 31 # used to generate autocompletions from manpages and for configuration editing in the browser 32 usePython ? true, 33 34 runCommand, 35 writeText, 36 nixosTests, 37 nix-update-script, 38 useOperatingSystemEtc ? true, 39 # An optional string containing Fish code that initializes the environment. 40 # This is run at the very beginning of initialization. If it sets $NIX_PROFILES 41 # then Fish will use that to configure its function, completion, and conf.d paths. 42 # For example: 43 # fishEnvPreInit = "source /etc/fish/my-env-preinit.fish"; 44 # It can also be a function that takes one argument, which is a function that 45 # takes a path to a bash file and converts it to fish. For example: 46 # fishEnvPreInit = source: source "${nix}/etc/profile.d/nix-daemon.sh"; 47 fishEnvPreInit ? null, 48}: 49let 50 etcConfigAppendix = writeText "config.fish.appendix" '' 51 ############### Nix hook for sourcing /etc/fish/config.fish ############### 52 # # 53 # Origin: 54 # This fish package was called with the attribute 55 # "useOperatingSystemEtc = true;". 56 # 57 # Purpose: 58 # Fish ordinarily sources /etc/fish/config.fish as 59 # $__fish_sysconfdir/config.fish, 60 # and $__fish_sysconfdir is defined at compile-time, baked into the C++ 61 # component of fish. By default, it is set to "/etc/fish". When building 62 # through Nix, $__fish_sysconfdir gets set to $out/etc/fish. Here we may 63 # have included a custom $out/etc/config.fish in the fish package, 64 # as specified, but according to the value of useOperatingSystemEtc, we 65 # may want to further source the real "/etc/fish/config.fish" file. 66 # 67 # When this option is enabled, this segment should appear the very end of 68 # "$out/etc/config.fish". This is to emulate the behavior of fish itself 69 # with respect to /etc/fish/config.fish and ~/.config/fish/config.fish: 70 # source both, but source the more global configuration files earlier 71 # than the more local ones, so that more local configurations inherit 72 # from but override the more global locations. 73 # 74 # Special care needs to be taken, when fish is called from an FHS user env 75 # or similar setup, because this configuration file will then be relocated 76 # to /etc/fish/config.fish, so we test for this case to avoid nontermination. 77 78 if test -f /etc/fish/config.fish && test /etc/fish/config.fish != (status filename) 79 source /etc/fish/config.fish 80 end 81 82 # # 83 ############### Nix hook for sourcing /etc/fish/config.fish ############### 84 ''; 85 86 fishPreInitHooks = writeText "__fish_build_paths_suffix.fish" '' 87 # source nixos environment 88 # note that this is required: 89 # 1. For all shells, not just login shells (mosh needs this as do some other command-line utilities) 90 # 2. Before the shell is initialized, so that config snippets can find the commands they use on the PATH 91 builtin status is-login 92 or test -z "$__fish_nixos_env_preinit_sourced" -a -z "$ETC_PROFILE_SOURCED" -a -z "$ETC_ZSHENV_SOURCED" 93 ${ 94 if fishEnvPreInit != null then 95 '' 96 and begin 97 ${lib.removeSuffix "\n" ( 98 if lib.isFunction fishEnvPreInit then fishEnvPreInit sourceWithFenv else fishEnvPreInit 99 )} 100 end'' 101 else 102 '' 103 and test -f /etc/fish/nixos-env-preinit.fish 104 and source /etc/fish/nixos-env-preinit.fish'' 105 } 106 and set -gx __fish_nixos_env_preinit_sourced 1 107 108 test -n "$NIX_PROFILES" 109 and begin 110 # We ensure that __extra_* variables are read in $__fish_datadir/config.fish 111 # with a preference for user-configured data by making sure the package-specific 112 # data comes last. Files are loaded/sourced in encounter order, duplicate 113 # basenames get skipped, so we assure this by prepending Nix profile paths 114 # (ordered in reverse of the $NIX_PROFILE variable) 115 # 116 # Note that at this point in evaluation, there is nothing whatsoever on the 117 # fish_function_path. That means we don't have most fish builtins, e.g., `eval`. 118 119 120 # additional profiles are expected in order of precedence, which means the reverse of the 121 # NIX_PROFILES variable (same as config.environment.profiles) 122 set -l __nix_profile_paths (string split ' ' $NIX_PROFILES)[-1..1] 123 124 set -p __extra_completionsdir \ 125 $__nix_profile_paths"/etc/fish/completions" \ 126 $__nix_profile_paths"/share/fish/vendor_completions.d" 127 set -p __extra_functionsdir \ 128 $__nix_profile_paths"/etc/fish/functions" \ 129 $__nix_profile_paths"/share/fish/vendor_functions.d" 130 set -p __extra_confdir \ 131 $__nix_profile_paths"/etc/fish/conf.d" \ 132 $__nix_profile_paths"/share/fish/vendor_conf.d" 133 end 134 ''; 135 136 # This is wrapped in begin/end in case the user wants to apply redirections. 137 # This does mean the basic usage of sourcing a single file will produce 138 # `begin; begin; …; end; end` but that's ok. 139 sourceWithFenv = path: '' 140 begin # fenv 141 # This happens before $__fish_datadir/config.fish sets fish_function_path, so it is currently 142 # unset. We set it and then completely erase it, leaving its configuration to $__fish_datadir/config.fish 143 set fish_function_path ${fishPlugins.foreign-env}/share/fish/vendor_functions.d $__fish_datadir/functions 144 fenv source ${lib.escapeShellArg path} 145 set -l fenv_status $status 146 # clear fish_function_path so that it will be correctly set when we return to $__fish_datadir/config.fish 147 set -e fish_function_path 148 test $fenv_status -eq 0 149 end # fenv 150 ''; 151 152in 153stdenv.mkDerivation (finalAttrs: { 154 pname = "fish"; 155 version = "4.0.2"; 156 157 src = fetchFromGitHub { 158 owner = "fish-shell"; 159 repo = "fish-shell"; 160 tag = finalAttrs.version; 161 hash = "sha256-UpoZPipXZbzLWCOXzDjfyTDrsKyXGbh3Rkwj5IeWeY4="; 162 }; 163 164 env = { 165 FISH_BUILD_VERSION = finalAttrs.version; 166 # Skip tests that are known to be flaky in CI 167 CI = 1; 168 }; 169 170 cargoDeps = rustPlatform.fetchCargoVendor { 171 inherit (finalAttrs) src patches; 172 hash = "sha256-FkJB33vVVz7Kh23kfmjQDn61X2VkKLG9mUt8f3TrCHg="; 173 }; 174 175 patches = [ 176 # This test fails if the nix sandbox gets created on a filesystem that's 177 # mounted with the nosuid option. 178 ./disable_suid_test.patch 179 180 # We don’t want to run `/usr/libexec/path_helper` on nix-darwin, 181 # as it pulls in paths not tracked in the system configuration 182 # and messes up the order of `$PATH`. Upstream are unfortunately 183 # unwilling to accept a change for this and have recommended that 184 # it should be a distro‐specific patch instead. 185 # 186 # See: 187 # 188 # * <https://github.com/LnL7/nix-darwin/issues/122> 189 # * <https://github.com/fish-shell/fish-shell/issues/7142> 190 ./nix-darwin-path.patch 191 ]; 192 193 # Fix FHS paths in tests 194 postPatch = '' 195 substituteInPlace src/builtins/tests/test_tests.rs \ 196 --replace-fail '"/bin/ls"' '"${lib.getExe' coreutils "ls"}"' 197 198 substituteInPlace src/tests/highlight.rs \ 199 --replace-fail '"/bin/echo"' '"${lib.getExe' coreutils "echo"}"' \ 200 --replace-fail '"/bin/c"' '"${lib.getExe' coreutils "c"}"' \ 201 --replace-fail '"/bin/ca"' '"${lib.getExe' coreutils "ca"}"' \ 202 --replace-fail '/usr' '/' 203 204 substituteInPlace tests/checks/cd.fish \ 205 --replace-fail '/bin/pwd' '${lib.getExe' coreutils "pwd"}' 206 207 substituteInPlace tests/checks/redirect.fish \ 208 --replace-fail '/bin/echo' '${lib.getExe' coreutils "echo"}' 209 210 substituteInPlace tests/checks/vars_as_commands.fish \ 211 --replace-fail '/usr/bin' '${coreutils}/bin' 212 213 substituteInPlace tests/checks/jobs.fish \ 214 --replace-fail 'ps -o' '${lib.getExe' procps "ps"} -o' \ 215 --replace-fail '/bin/echo' '${lib.getExe' coreutils "echo"}' 216 217 substituteInPlace tests/checks/job-control-noninteractive.fish \ 218 --replace-fail '/bin/echo' '${lib.getExe' coreutils "echo"}' 219 220 substituteInPlace tests/checks/complete.fish \ 221 --replace-fail '/bin/ls' '${lib.getExe' coreutils "ls"}' 222 223 # Several pexpect tests are flaky 224 # See https://github.com/fish-shell/fish-shell/issues/8789 225 rm tests/pexpects/exit_handlers.py 226 rm tests/pexpects/private_mode.py 227 rm tests/pexpects/history.py 228 '' 229 + lib.optionalString stdenv.hostPlatform.isDarwin '' 230 # Tests use pkill/pgrep which are currently not built on Darwin 231 # See https://github.com/NixOS/nixpkgs/pull/103180 232 # and https://github.com/NixOS/nixpkgs/issues/141157 233 rm tests/pexpects/exit.py 234 rm tests/pexpects/job_summary.py 235 rm tests/pexpects/signals.py 236 rm tests/pexpects/fg.py 237 '' 238 + lib.optionalString (stdenv.hostPlatform.isAarch64 || stdenv.hostPlatform.isDarwin) '' 239 # This test seems to consistently fail on aarch64 and darwin 240 rm tests/checks/cd.fish 241 ''; 242 243 outputs = [ 244 "out" 245 "doc" 246 ]; 247 248 strictDeps = true; 249 250 nativeBuildInputs = [ 251 cargo 252 cmake 253 gettext 254 ninja 255 pkg-config 256 rustc 257 rustPlatform.cargoSetupHook 258 # Avoid warnings when building the manpages about HOME not being writable 259 writableTmpDirAsHomeHook 260 ]; 261 262 buildInputs = [ 263 libiconv 264 pcre2 265 ]; 266 267 cmakeFlags = [ 268 (lib.cmakeFeature "CMAKE_INSTALL_DOCDIR" "${placeholder "doc"}/share/doc/fish") 269 (lib.cmakeFeature "Rust_CARGO_TARGET" stdenv.hostPlatform.rust.rustcTarget) 270 ] 271 ++ lib.optionals stdenv.hostPlatform.isDarwin [ 272 (lib.cmakeBool "MAC_CODESIGN_ID" false) 273 ]; 274 275 # Fish’s test suite needs to be able to look up process information and send signals. 276 sandboxProfile = lib.optionalString stdenv.hostPlatform.isDarwin '' 277 (allow mach-lookup mach-task-name) 278 (allow signal (target children)) 279 ''; 280 281 # The optional string is kind of an inelegant way to get fish to cross compile. 282 # Fish needs coreutils as a runtime dependency, and it gets put into 283 # CMAKE_PREFIX_PATH, which cmake uses to look up build time programs, so it 284 # was clobbering the PATH. It probably needs to be fixed at a lower level. 285 preConfigure = '' 286 patchShebangs ./build_tools/git_version_gen.sh 287 patchShebangs ./tests/test_driver.py 288 '' 289 + lib.optionalString (stdenv.hostPlatform != stdenv.buildPlatform) '' 290 export CMAKE_PREFIX_PATH= 291 ''; 292 293 # Required binaries during execution 294 propagatedBuildInputs = [ 295 coreutils 296 gnugrep 297 gnused 298 groff 299 gettext 300 ] 301 ++ lib.optional (!stdenv.hostPlatform.isDarwin) man-db; 302 303 doCheck = true; 304 305 nativeCheckInputs = [ 306 coreutils 307 glibcLocales 308 (python3.withPackages (ps: [ ps.pexpect ])) 309 procps 310 sphinx 311 ] 312 ++ lib.optionals stdenv.hostPlatform.isDarwin [ 313 # For the getconf command, used in default-setup-path.fish 314 darwin.system_cmds 315 ]; 316 317 # we target the top-level make target which runs all the cmake/ctest 318 # tests, including test_cargo-test 319 checkTarget = "fish_run_tests"; 320 preCheck = '' 321 export TERMINFO="${ncurses}/share/terminfo" 322 ''; 323 324 nativeInstallCheckInputs = [ 325 versionCheckHook 326 ]; 327 versionCheckProgramArg = "--version"; 328 doInstallCheck = true; 329 330 # Ensure that we don't vendor libpcre2, but instead link against the one from nixpkgs 331 installCheckPhase = lib.optionalString (stdenv.hostPlatform.libc == "glibc") '' 332 runHook preInstallCheck 333 334 echo "Checking that we don't vendor pcre2" 335 ldd "$out/bin/fish" | grep ${lib.getLib pcre2} 336 337 runHook postInstallCheck 338 ''; 339 340 postInstall = '' 341 substituteInPlace "$out/share/fish/functions/grep.fish" \ 342 --replace-fail "command grep" "command ${lib.getExe gnugrep}" 343 344 substituteInPlace "$out/share/fish/functions/__fish_print_help.fish" \ 345 --replace-fail "nroff" "${lib.getExe' groff "nroff"}" 346 347 substituteInPlace $out/share/fish/completions/{sudo.fish,doas.fish} \ 348 --replace-fail "/usr/local/sbin /sbin /usr/sbin" "" 349 '' 350 + lib.optionalString usePython '' 351 cat > $out/share/fish/functions/__fish_anypython.fish <<EOF 352 function __fish_anypython 353 echo ${python3.interpreter} 354 return 0 355 end 356 EOF 357 '' 358 + lib.optionalString stdenv.hostPlatform.isLinux '' 359 for cur in $out/share/fish/functions/*.fish; do 360 substituteInPlace "$cur" \ 361 --replace-quiet '/usr/bin/getent' '${lib.getExe getent}' \ 362 --replace-quiet 'awk' '${lib.getExe' gawk "awk"}' 363 done 364 for cur in $out/share/fish/completions/*.fish; do 365 substituteInPlace "$cur" \ 366 --replace-quiet 'awk' '${lib.getExe' gawk "awk"}' 367 done 368 '' 369 + lib.optionalString useOperatingSystemEtc '' 370 tee -a $out/etc/fish/config.fish < ${etcConfigAppendix} 371 '' 372 + '' 373 tee -a $out/share/fish/__fish_build_paths.fish < ${fishPreInitHooks} 374 ''; 375 376 meta = { 377 description = "Smart and user-friendly command line shell"; 378 homepage = "https://fishshell.com/"; 379 changelog = "https://github.com/fish-shell/fish-shell/releases/tag/${finalAttrs.version}"; 380 license = lib.licenses.gpl2Only; 381 platforms = lib.platforms.unix; 382 maintainers = with lib.maintainers; [ 383 adamcstephens 384 cole-h 385 winter 386 sigmasquadron 387 rvdp 388 ]; 389 mainProgram = "fish"; 390 }; 391 392 passthru = { 393 shellPath = "/bin/fish"; 394 tests = { 395 nixos = lib.optionalAttrs stdenv.hostPlatform.isLinux nixosTests.fish; 396 397 # Test the fish_config tool by checking the generated splash page. 398 # Since the webserver requires a port to run, it is not started. 399 fishConfig = 400 let 401 fishScript = writeText "test.fish" '' 402 set -x __fish_bin_dir ${finalAttrs.finalPackage}/bin 403 echo $__fish_bin_dir 404 cp -r ${finalAttrs.finalPackage}/share/fish/tools/web_config/* . 405 chmod -R +w * 406 407 # if we don't set `delete=False`, the file will get cleaned up 408 # automatically (leading the test to fail because there's no 409 # tempfile to check) 410 ${lib.getExe gnused} -e 's@delete=True,@delete=False,@' -i webconfig.py 411 412 # we delete everything after the fileurl is assigned 413 ${lib.getExe gnused} -e '/fileurl =/q' -i webconfig.py 414 echo "print(fileurl)" >> webconfig.py 415 416 # and check whether the message appears on the page 417 # cannot test the http server because it needs a localhost port 418 cat (${python3}/bin/python ./webconfig.py \ 419 | tail -n1 | ${lib.getExe gnused} -e 's|file://||' \ 420 ) | ${lib.getExe gnugrep} -q 'a href="http://localhost.*Start the Fish Web config' 421 ''; 422 in 423 runCommand "test-web-config" { } '' 424 HOME=$(mktemp -d) 425 ${finalAttrs.finalPackage}/bin/fish ${fishScript} && touch $out 426 ''; 427 }; 428 updateScript = nix-update-script { }; 429 }; 430})