Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
1{ stdenv 2, lib 3, fetchurl 4, fetchpatch 5, coreutils 6, which 7, gnused 8, gnugrep 9, groff 10, gawk 11, man-db 12, getent 13, libiconv 14, pcre2 15, gettext 16, ncurses 17, python3 18, cmake 19, fishPlugins 20, procps 21 22# used to generate autocompletions from manpages and for configuration editing in the browser 23, usePython ? true 24 25, runCommand 26, writeText 27, nixosTests 28, nix-update-script 29, useOperatingSystemEtc ? true 30 # An optional string containing Fish code that initializes the environment. 31 # This is run at the very beginning of initialization. If it sets $NIX_PROFILES 32 # then Fish will use that to configure its function, completion, and conf.d paths. 33 # For example: 34 # fishEnvPreInit = "source /etc/fish/my-env-preinit.fish"; 35 # It can also be a function that takes one argument, which is a function that 36 # takes a path to a bash file and converts it to fish. For example: 37 # fishEnvPreInit = source: source "${nix}/etc/profile.d/nix-daemon.sh"; 38, fishEnvPreInit ? null 39}: 40let 41 etcConfigAppendix = writeText "config.fish.appendix" '' 42 ############### Nix hook for sourcing /etc/fish/config.fish ############### 43 # # 44 # Origin: 45 # This fish package was called with the attribute 46 # "useOperatingSystemEtc = true;". 47 # 48 # Purpose: 49 # Fish ordinarily sources /etc/fish/config.fish as 50 # $__fish_sysconfdir/config.fish, 51 # and $__fish_sysconfdir is defined at compile-time, baked into the C++ 52 # component of fish. By default, it is set to "/etc/fish". When building 53 # through Nix, $__fish_sysconfdir gets set to $out/etc/fish. Here we may 54 # have included a custom $out/etc/config.fish in the fish package, 55 # as specified, but according to the value of useOperatingSystemEtc, we 56 # may want to further source the real "/etc/fish/config.fish" file. 57 # 58 # When this option is enabled, this segment should appear the very end of 59 # "$out/etc/config.fish". This is to emulate the behavior of fish itself 60 # with respect to /etc/fish/config.fish and ~/.config/fish/config.fish: 61 # source both, but source the more global configuration files earlier 62 # than the more local ones, so that more local configurations inherit 63 # from but override the more global locations. 64 # 65 # Special care needs to be taken, when fish is called from an FHS user env 66 # or similar setup, because this configuration file will then be relocated 67 # to /etc/fish/config.fish, so we test for this case to avoid nontermination. 68 69 if test -f /etc/fish/config.fish && test /etc/fish/config.fish != (status filename) 70 source /etc/fish/config.fish 71 end 72 73 # # 74 ############### Nix hook for sourcing /etc/fish/config.fish ############### 75 ''; 76 77 fishPreInitHooks = writeText "__fish_build_paths_suffix.fish" '' 78 # source nixos environment 79 # note that this is required: 80 # 1. For all shells, not just login shells (mosh needs this as do some other command-line utilities) 81 # 2. Before the shell is initialized, so that config snippets can find the commands they use on the PATH 82 builtin status --is-login 83 or test -z "$__fish_nixos_env_preinit_sourced" -a -z "$ETC_PROFILE_SOURCED" -a -z "$ETC_ZSHENV_SOURCED" 84 ${if fishEnvPreInit != null then '' 85 and begin 86 ${lib.removeSuffix "\n" (if lib.isFunction fishEnvPreInit then fishEnvPreInit sourceWithFenv else fishEnvPreInit)} 87 end'' else '' 88 and test -f /etc/fish/nixos-env-preinit.fish 89 and source /etc/fish/nixos-env-preinit.fish''} 90 and set -gx __fish_nixos_env_preinit_sourced 1 91 92 test -n "$NIX_PROFILES" 93 and begin 94 # We ensure that __extra_* variables are read in $__fish_datadir/config.fish 95 # with a preference for user-configured data by making sure the package-specific 96 # data comes last. Files are loaded/sourced in encounter order, duplicate 97 # basenames get skipped, so we assure this by prepending Nix profile paths 98 # (ordered in reverse of the $NIX_PROFILE variable) 99 # 100 # Note that at this point in evaluation, there is nothing whatsoever on the 101 # fish_function_path. That means we don't have most fish builtins, e.g., `eval`. 102 103 104 # additional profiles are expected in order of precedence, which means the reverse of the 105 # NIX_PROFILES variable (same as config.environment.profiles) 106 set -l __nix_profile_paths (string split ' ' $NIX_PROFILES)[-1..1] 107 108 set -p __extra_completionsdir \ 109 $__nix_profile_paths"/etc/fish/completions" \ 110 $__nix_profile_paths"/share/fish/vendor_completions.d" 111 set -p __extra_functionsdir \ 112 $__nix_profile_paths"/etc/fish/functions" \ 113 $__nix_profile_paths"/share/fish/vendor_functions.d" 114 set -p __extra_confdir \ 115 $__nix_profile_paths"/etc/fish/conf.d" \ 116 $__nix_profile_paths"/share/fish/vendor_conf.d" 117 end 118 ''; 119 120 # This is wrapped in begin/end in case the user wants to apply redirections. 121 # This does mean the basic usage of sourcing a single file will produce 122 # `begin; begin; …; end; end` but that's ok. 123 sourceWithFenv = path: '' 124 begin # fenv 125 # This happens before $__fish_datadir/config.fish sets fish_function_path, so it is currently 126 # unset. We set it and then completely erase it, leaving its configuration to $__fish_datadir/config.fish 127 set fish_function_path ${fishPlugins.foreign-env}/share/fish/vendor_functions.d $__fish_datadir/functions 128 fenv source ${lib.escapeShellArg path} 129 set -l fenv_status $status 130 # clear fish_function_path so that it will be correctly set when we return to $__fish_datadir/config.fish 131 set -e fish_function_path 132 test $fenv_status -eq 0 133 end # fenv 134 ''; 135 136 fish = stdenv.mkDerivation rec { 137 pname = "fish"; 138 version = "3.6.1"; 139 140 src = fetchurl { 141 # There are differences between the release tarball and the tarball GitHub 142 # packages from the tag. Specifically, it comes with a file containing its 143 # version, which is used in `build_tools/git_version_gen.sh` to determine 144 # the shell's actual version (and what it displays when running `fish 145 # --version`), as well as the local documentation for all builtins (and 146 # maybe other things). 147 url = "https://github.com/fish-shell/fish-shell/releases/download/${version}/${pname}-${version}.tar.xz"; 148 hash = "sha256-VUArtHymc52KuiXkF4CQW1zhvOCl4N0X3KkItbwLSbI="; 149 }; 150 151 # Fix FHS paths in tests 152 postPatch = '' 153 # src/fish_tests.cpp 154 sed -i 's|/bin/ls|${coreutils}/bin/ls|' src/fish_tests.cpp 155 sed -i 's|is_potential_path(L"/usr"|is_potential_path(L"/nix"|' src/fish_tests.cpp 156 sed -i 's|L"/bin/echo"|L"${coreutils}/bin/echo"|' src/fish_tests.cpp 157 sed -i 's|L"/bin/c"|L"${coreutils}/bin/c"|' src/fish_tests.cpp 158 sed -i 's|L"/bin/ca"|L"${coreutils}/bin/ca"|' src/fish_tests.cpp 159 160 # tests/checks/cd.fish 161 sed -i 's|/bin/pwd|${coreutils}/bin/pwd|' tests/checks/cd.fish 162 163 # tests/checks/redirect.fish 164 sed -i 's|/bin/echo|${coreutils}/bin/echo|' tests/checks/redirect.fish 165 166 # tests/checks/vars_as_commands.fish 167 sed -i 's|/usr/bin|${coreutils}/bin|' tests/checks/vars_as_commands.fish 168 169 # tests/checks/jobs.fish 170 sed -i 's|ps -o stat|${procps}/bin/ps -o stat|' tests/checks/jobs.fish 171 sed -i 's|/bin/echo|${coreutils}/bin/echo|' tests/checks/jobs.fish 172 173 # tests/checks/job-control-noninteractive.fish 174 sed -i 's|/bin/echo|${coreutils}/bin/echo|' tests/checks/job-control-noninteractive.fish 175 176 # tests/checks/complete.fish 177 sed -i 's|/bin/ls|${coreutils}/bin/ls|' tests/checks/complete.fish 178 '' + lib.optionalString stdenv.isDarwin '' 179 # Tests use pkill/pgrep which are currently not built on Darwin 180 # See https://github.com/NixOS/nixpkgs/pull/103180 181 rm tests/pexpects/exit.py 182 rm tests/pexpects/job_summary.py 183 rm tests/pexpects/signals.py 184 185 # pexpect tests are flaky in general 186 # See https://github.com/fish-shell/fish-shell/issues/8789 187 rm tests/pexpects/bind.py 188 '' + lib.optionalString stdenv.isLinux '' 189 # pexpect tests are flaky on aarch64-linux (also x86_64-linux) 190 # See https://github.com/fish-shell/fish-shell/issues/8789 191 rm tests/pexpects/exit_handlers.py 192 ''; 193 194 outputs = [ "out" "doc" ]; 195 strictDeps = true; 196 nativeBuildInputs = [ 197 cmake 198 gettext 199 ]; 200 201 buildInputs = [ 202 ncurses 203 libiconv 204 pcre2 205 ]; 206 207 cmakeFlags = [ 208 "-DCMAKE_INSTALL_DOCDIR=${placeholder "doc"}/share/doc/fish" 209 ] ++ lib.optionals stdenv.isDarwin [ 210 "-DMAC_CODESIGN_ID=OFF" 211 ]; 212 213 # The optional string is kind of an inelegant way to get fish to cross compile. 214 # Fish needs coreutils as a runtime dependency, and it gets put into 215 # CMAKE_PREFIX_PATH, which cmake uses to look up build time programs, so it 216 # was clobbering the PATH. It probably needs to be fixed at a lower level. 217 preConfigure = '' 218 patchShebangs ./build_tools/git_version_gen.sh 219 '' + lib.optionalString (stdenv.hostPlatform != stdenv.buildPlatform) '' 220 export CMAKE_PREFIX_PATH= 221 ''; 222 223 # Required binaries during execution 224 propagatedBuildInputs = [ 225 coreutils 226 gnugrep 227 gnused 228 groff 229 gettext 230 ] ++ lib.optional (!stdenv.isDarwin) man-db; 231 232 doCheck = true; 233 234 nativeCheckInputs = [ 235 coreutils 236 (python3.withPackages (ps: [ ps.pexpect ])) 237 procps 238 ]; 239 240 checkPhase = '' 241 make test 242 ''; 243 244 postInstall = with lib; '' 245 sed -r "s|command grep|command ${gnugrep}/bin/grep|" \ 246 -i "$out/share/fish/functions/grep.fish" 247 sed -e "s|\|cut|\|${coreutils}/bin/cut|" \ 248 -i "$out/share/fish/functions/fish_prompt.fish" 249 sed -e "s|uname|${coreutils}/bin/uname|" \ 250 -i "$out/share/fish/functions/__fish_pwd.fish" \ 251 "$out/share/fish/functions/prompt_pwd.fish" 252 sed -e "s|sed |${gnused}/bin/sed |" \ 253 -i "$out/share/fish/functions/alias.fish" \ 254 "$out/share/fish/functions/prompt_pwd.fish" 255 sed -i "s|nroff|${groff}/bin/nroff|" \ 256 "$out/share/fish/functions/__fish_print_help.fish" 257 sed -e "s|clear;|${getBin ncurses}/bin/clear;|" \ 258 -i "$out/share/fish/functions/fish_default_key_bindings.fish" 259 sed -i "s|/usr/local/sbin /sbin /usr/sbin||" \ 260 $out/share/fish/completions/{sudo.fish,doas.fish} 261 sed -e "s| awk | ${gawk}/bin/awk |" \ 262 -i $out/share/fish/functions/{__fish_print_packages.fish,__fish_print_addresses.fish,__fish_describe_command.fish,__fish_complete_man.fish,__fish_complete_convert_options.fish} \ 263 $out/share/fish/completions/{cwebp,adb,ezjail-admin,grunt,helm,heroku,lsusb,make,p4,psql,rmmod,vim-addons}.fish 264 265 '' + optionalString usePython '' 266 cat > $out/share/fish/functions/__fish_anypython.fish <<EOF 267 function __fish_anypython 268 echo ${python3.interpreter} 269 return 0 270 end 271 EOF 272 273 '' + optionalString stdenv.isLinux '' 274 for cur in $out/share/fish/functions/*.fish; do 275 sed -e "s|/usr/bin/getent|${getent}/bin/getent|" \ 276 -i "$cur" 277 done 278 279 '' + optionalString (!stdenv.isDarwin) '' 280 sed -i "s|Popen(\['manpath'|Popen(\['${man-db}/bin/manpath'|" \ 281 "$out/share/fish/tools/create_manpage_completions.py" 282 sed -i "s|command manpath|command ${man-db}/bin/manpath|" \ 283 "$out/share/fish/functions/man.fish" 284 '' + optionalString useOperatingSystemEtc '' 285 tee -a $out/etc/fish/config.fish < ${etcConfigAppendix} 286 '' + '' 287 tee -a $out/share/fish/__fish_build_paths.fish < ${fishPreInitHooks} 288 ''; 289 290 meta = with lib; { 291 description = "Smart and user-friendly command line shell"; 292 homepage = "https://fishshell.com/"; 293 license = licenses.gpl2; 294 platforms = platforms.unix; 295 maintainers = with maintainers; [ cole-h winter srapenne ]; 296 }; 297 298 passthru = { 299 shellPath = "/bin/fish"; 300 tests = { 301 nixos = nixosTests.fish; 302 303 # Test the fish_config tool by checking the generated splash page. 304 # Since the webserver requires a port to run, it is not started. 305 fishConfig = 306 let fishScript = writeText "test.fish" '' 307 set -x __fish_bin_dir ${fish}/bin 308 echo $__fish_bin_dir 309 cp -r ${fish}/share/fish/tools/web_config/* . 310 chmod -R +w * 311 312 # if we don't set `delete=False`, the file will get cleaned up 313 # automatically (leading the test to fail because there's no 314 # tempfile to check) 315 sed -e 's@, mode="w"@, mode="w", delete=False@' -i webconfig.py 316 317 # we delete everything after the fileurl is assigned 318 sed -e '/fileurl =/q' -i webconfig.py 319 echo "print(fileurl)" >> webconfig.py 320 321 # and check whether the message appears on the page 322 cat (${python3}/bin/python ./webconfig.py \ 323 | tail -n1 | sed -ne 's|.*\(/build/.*\)|\1|p' \ 324 ) | grep 'a href="http://localhost.*Start the Fish Web config' 325 326 # cannot test the http server because it needs a localhost port 327 ''; 328 in 329 runCommand "test-web-config" { } '' 330 HOME=$(mktemp -d) 331 ${fish}/bin/fish ${fishScript} && touch $out 332 ''; 333 }; 334 updateScript = nix-update-script { }; 335 }; 336 }; 337in 338fish