Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
at devShellTools-shell 572 lines 19 kB view raw
1{ 2 stdenv, 3 lib, 4 makeDesktopItem, 5 makeWrapper, 6 lndir, 7 config, 8 buildPackages, 9 jq, 10 xdg-utils, 11 writeText, 12 13 ## various stuff that can be plugged in 14 ffmpeg, 15 xorg, 16 alsa-lib, 17 libpulseaudio, 18 libcanberra-gtk3, 19 libglvnd, 20 libnotify, 21 opensc, 22 adwaita-icon-theme, 23 pipewire, 24 udev, 25 libkrb5, 26 libva, 27 libgbm, 28 cups, 29 pciutils, 30 vulkan-loader, 31 sndio, 32 libjack2, 33 speechd-minimal, 34}: 35 36## configurability of the wrapper itself 37 38browser: 39 40let 41 isDarwin = stdenv.hostPlatform.isDarwin; 42 wrapper = 43 { 44 applicationName ? browser.binaryName or (lib.getName browser), # Note: this is actually *binary* name and is different from browser.applicationName, which is *app* name! 45 pname ? applicationName, 46 version ? lib.getVersion browser, 47 nameSuffix ? "", 48 icon ? applicationName, 49 wmClass ? applicationName, 50 nativeMessagingHosts ? [ ], 51 pkcs11Modules ? [ ], 52 useGlvnd ? (!isDarwin), 53 cfg ? config.${applicationName} or { }, 54 55 ## Following options are needed for extra prefs & policies 56 # For more information about anti tracking (german website) 57 # visit https://wiki.kairaven.de/open/app/firefox 58 extraPrefs ? "", 59 extraPrefsFiles ? [ ], 60 # For more information about policies visit 61 # https://mozilla.github.io/policy-templates/ 62 extraPolicies ? { }, 63 extraPoliciesFiles ? [ ], 64 libName ? browser.libName or applicationName, # Important for tor package or the like 65 nixExtensions ? null, 66 hasMozSystemDirPatch ? (lib.hasPrefix "firefox" pname && !lib.hasSuffix "-bin" pname), 67 }: 68 69 let 70 ffmpegSupport = browser.ffmpegSupport or false; 71 gssSupport = browser.gssSupport or false; 72 alsaSupport = browser.alsaSupport or false; 73 pipewireSupport = browser.pipewireSupport or false; 74 sndioSupport = browser.sndioSupport or false; 75 jackSupport = browser.jackSupport or false; 76 # PCSC-Lite daemon (services.pcscd) also must be enabled for firefox to access smartcards 77 smartcardSupport = cfg.smartcardSupport or false; 78 79 allNativeMessagingHosts = builtins.map lib.getBin nativeMessagingHosts; 80 81 libs = 82 lib.optionals stdenv.hostPlatform.isLinux ( 83 [ 84 udev 85 libva 86 libgbm 87 libnotify 88 xorg.libXScrnSaver 89 cups 90 pciutils 91 vulkan-loader 92 ] 93 ++ lib.optional (cfg.speechSynthesisSupport or true) speechd-minimal 94 ) 95 ++ lib.optional pipewireSupport pipewire 96 ++ lib.optional ffmpegSupport ffmpeg 97 ++ lib.optional gssSupport libkrb5 98 ++ lib.optional useGlvnd libglvnd 99 ++ lib.optionals (cfg.enableQuakeLive or false) ( 100 with xorg; 101 [ 102 stdenv.cc 103 libX11 104 libXxf86dga 105 libXxf86vm 106 libXext 107 libXt 108 alsa-lib 109 zlib 110 ] 111 ) 112 ++ lib.optional (config.pulseaudio or (!isDarwin)) libpulseaudio 113 ++ lib.optional alsaSupport alsa-lib 114 ++ lib.optional sndioSupport sndio 115 ++ lib.optional jackSupport libjack2 116 ++ lib.optional smartcardSupport opensc 117 ++ pkcs11Modules 118 ++ lib.optionals (!isDarwin) gtk_modules; 119 gtk_modules = [ libcanberra-gtk3 ]; 120 121 # Darwin does not rename bundled binaries 122 launcherName = "${applicationName}${lib.optionalString (!isDarwin) nameSuffix}"; 123 124 ######################### 125 # # 126 # EXTRA PREF CHANGES # 127 # # 128 ######################### 129 policiesJson = writeText "policies.json" (builtins.toJSON enterprisePolicies); 130 131 usesNixExtensions = nixExtensions != null; 132 133 nameArray = builtins.map (a: a.name) (lib.optionals usesNixExtensions nixExtensions); 134 135 # Check that every extension has a unique .name attribute 136 # and an extid attribute 137 extensions = 138 if nameArray != (lib.unique nameArray) then 139 throw "Firefox addon name needs to be unique" 140 else if browser.requireSigning || !browser.allowAddonSideload then 141 throw "Nix addons are only supported with signature enforcement disabled and addon sideloading enabled (eg. LibreWolf)" 142 else 143 builtins.map ( 144 a: 145 if !(builtins.hasAttr "extid" a) then 146 throw "nixExtensions has an invalid entry. Missing extid attribute. Please use fetchFirefoxAddon" 147 else 148 a 149 ) (lib.optionals usesNixExtensions nixExtensions); 150 151 enterprisePolicies = { 152 policies = { 153 DisableAppUpdate = true; 154 } 155 // lib.optionalAttrs usesNixExtensions { 156 ExtensionSettings = { 157 "*" = { 158 blocked_install_message = "You can't have manual extension mixed with nix extensions"; 159 installation_mode = "blocked"; 160 }; 161 } 162 // lib.foldr ( 163 e: ret: 164 ret 165 // { 166 "${e.extid}" = { 167 installation_mode = "allowed"; 168 }; 169 } 170 ) { } extensions; 171 172 Extensions = { 173 Install = lib.foldr (e: ret: ret ++ [ "${e.outPath}/${e.extid}.xpi" ]) [ ] extensions; 174 }; 175 } 176 // lib.optionalAttrs smartcardSupport { 177 SecurityDevices = { 178 "OpenSC PKCS#11 Module" = "opensc-pkcs11.so"; 179 }; 180 } 181 // extraPolicies; 182 }; 183 184 mozillaCfg = '' 185 // First line must be a comment 186 187 // Disables addon signature checking 188 // to be able to install addons that do not have an extid 189 // Security is maintained because only user whitelisted addons 190 // with a checksum can be installed 191 ${lib.optionalString usesNixExtensions ''lockPref("xpinstall.signatures.required", false);''} 192 ''; 193 194 ############################# 195 # # 196 # END EXTRA PREF CHANGES # 197 # # 198 ############################# 199 200 in 201 stdenv.mkDerivation (finalAttrs: { 202 __structuredAttrs = true; 203 inherit pname version; 204 205 desktopItem = makeDesktopItem ( 206 { 207 name = launcherName; 208 exec = "${launcherName} --name ${wmClass} %U"; 209 inherit icon; 210 desktopName = browser.applicationName; 211 startupNotify = true; 212 startupWMClass = wmClass; 213 terminal = false; 214 } 215 // ( 216 if libName == "thunderbird" then 217 { 218 genericName = "Email Client"; 219 comment = "Read and write e-mails or RSS feeds, or manage tasks on calendars."; 220 categories = [ 221 "Network" 222 "Chat" 223 "Email" 224 "Feed" 225 "GTK" 226 "News" 227 ]; 228 keywords = [ 229 "mail" 230 "email" 231 "e-mail" 232 "messages" 233 "rss" 234 "calendar" 235 "address book" 236 "addressbook" 237 "chat" 238 ]; 239 mimeTypes = [ 240 "message/rfc822" 241 "x-scheme-handler/mailto" 242 "text/calendar" 243 "text/x-vcard" 244 ]; 245 actions = { 246 profile-manager-window = { 247 name = "Profile Manager"; 248 exec = "${launcherName} --ProfileManager"; 249 }; 250 }; 251 } 252 else 253 { 254 genericName = "Web Browser"; 255 categories = [ 256 "Network" 257 "WebBrowser" 258 ]; 259 mimeTypes = [ 260 "text/html" 261 "text/xml" 262 "application/xhtml+xml" 263 "application/vnd.mozilla.xul+xml" 264 "x-scheme-handler/http" 265 "x-scheme-handler/https" 266 ]; 267 actions = { 268 new-window = { 269 name = "New Window"; 270 exec = "${launcherName} --new-window %U"; 271 }; 272 new-private-window = { 273 name = "New Private Window"; 274 exec = "${launcherName} --private-window %U"; 275 }; 276 profile-manager-window = { 277 name = "Profile Manager"; 278 exec = "${launcherName} --ProfileManager"; 279 }; 280 }; 281 } 282 ) 283 ); 284 285 nativeBuildInputs = [ 286 makeWrapper 287 lndir 288 jq 289 ]; 290 buildInputs = lib.optionals (!isDarwin) [ browser.gtk3 ]; 291 292 makeWrapperArgs = [ 293 "--prefix" 294 "LD_LIBRARY_PATH" 295 ":" 296 "${finalAttrs.libs}" 297 298 "--suffix" 299 "PATH" 300 ":" 301 "${placeholder "out"}/bin" 302 303 "--set" 304 "MOZ_APP_LAUNCHER" 305 launcherName 306 307 "--set" 308 "MOZ_LEGACY_PROFILES" 309 "1" 310 311 "--set" 312 "MOZ_ALLOW_DOWNGRADE" 313 "1" 314 ] 315 ++ lib.optionals (!isDarwin) [ 316 "--suffix" 317 "GTK_PATH" 318 ":" 319 "${lib.concatStringsSep ":" finalAttrs.gtk_modules}" 320 321 "--suffix" 322 "XDG_DATA_DIRS" 323 ":" 324 "${adwaita-icon-theme}/share" 325 326 "--set-default" 327 "MOZ_ENABLE_WAYLAND" 328 "1" 329 330 ] 331 ++ lib.optionals (!xdg-utils.meta.broken && !isDarwin) [ 332 # make xdg-open overridable at runtime 333 "--suffix" 334 "PATH" 335 ":" 336 "${lib.makeBinPath [ xdg-utils ]}" 337 338 ] 339 ++ lib.optionals hasMozSystemDirPatch [ 340 "--set" 341 "MOZ_SYSTEM_DIR" 342 "${placeholder "out"}/lib/mozilla" 343 344 ] 345 ++ lib.optionals (!hasMozSystemDirPatch && allNativeMessagingHosts != [ ]) [ 346 "--run" 347 ''mkdir -p ''${MOZ_HOME:-~/.mozilla}/native-messaging-hosts'' 348 349 ] 350 ++ lib.optionals (!hasMozSystemDirPatch) ( 351 lib.concatMap (ext: [ 352 "--run" 353 ''ln -sfLt ''${MOZ_HOME:-~/.mozilla}/native-messaging-hosts ${ext}/lib/mozilla/native-messaging-hosts/*'' 354 ]) allNativeMessagingHosts 355 ); 356 357 buildCommand = 358 let 359 appPath = "Applications/${browser.applicationName}.app"; 360 executablePrefix = if isDarwin then "${appPath}/Contents/MacOS" else "bin"; 361 executablePath = "${executablePrefix}/${applicationName}"; 362 finalBinaryPath = "${executablePath}" + lib.optionalString (!isDarwin) "${nameSuffix}"; 363 sourceBinary = "${browser}/${executablePath}"; 364 libDir = if isDarwin then "${appPath}/Contents/Resources" else "lib/${libName}"; 365 prefsDir = if isDarwin then "${libDir}/browser/defaults/preferences" else "${libDir}/defaults/pref"; 366 in 367 '' 368 if [ ! -x "${sourceBinary}" ] 369 then 370 echo "cannot find executable file \`${sourceBinary}'" 371 exit 1 372 fi 373 374 ######################### 375 # # 376 # EXTRA PREF CHANGES # 377 # # 378 ######################### 379 # Link the runtime. The executable itself has to be copied, 380 # because it will resolve paths relative to its true location. 381 # Any symbolic links have to be replicated as well. 382 cd "${browser}" 383 find . -type d -exec mkdir -p "$out"/{} \; 384 385 find . -type f \( -not -name "${applicationName}" \) -exec ln -sT "${browser}"/{} "$out"/{} \; 386 387 find . -type f \( -name "${applicationName}" -o -name "${applicationName}-bin" \) -print0 | while read -d $'\0' f; do 388 cp -P --no-preserve=mode,ownership --remove-destination "${browser}/$f" "$out/$f" 389 chmod a+rwx "$out/$f" 390 done 391 392 # fix links and absolute references 393 394 find . -type l -print0 | while read -d $'\0' l; do 395 target="$(readlink "$l")" 396 target=''${target/#"${browser}"/"$out"} 397 ln -sfT "$target" "$out/$l" 398 done 399 400 cd "$out" 401 402 '' 403 + lib.optionalString isDarwin '' 404 cd "${appPath}" 405 406 # The omni.ja files have to be copied and not symlinked, otherwise tabs crash. 407 # Maybe related to how omni.ja file is mmapped into memory. See: 408 # https://github.com/mozilla/gecko-dev/blob/b1662b447f306e6554647914090d4b73ac8e1664/modules/libjar/nsZipArchive.cpp#L204 409 # 410 # The *.dylib files are copied, otherwise some basic functionality, e.g. Crypto API, is broken. 411 for file in $(find . -name "omni.ja" -o -name "*.dylib"); do 412 rm "$file" 413 cp "${browser}/${appPath}/$file" "$file" 414 done 415 416 # Copy any embedded .app directories; plugin-container fails to start otherwise. 417 for dir in $(find . -type d -name '*.app'); do 418 rm -r "$dir" 419 cp -r "${browser}/${appPath}/$dir" "$dir" 420 done 421 422 cd .. 423 424 '' 425 + '' 426 427 # create the wrapper 428 429 executablePrefix="$out/${executablePrefix}" 430 executablePath="$out/${executablePath}" 431 oldWrapperArgs=() 432 433 if [[ -L $executablePath ]]; then 434 # Symbolic link: wrap the link's target. 435 oldExe="$(readlink -v --canonicalize-existing "$executablePath")" 436 rm "$executablePath" 437 elif wrapperCmd=$(${buildPackages.makeBinaryWrapper.extractCmd} "$executablePath"); [[ $wrapperCmd ]]; then 438 # If the executable is a binary wrapper, we need to update its target to 439 # point to $out, but we can't just edit the binary in-place because of length 440 # issues. So we extract the command used to create the wrapper and add the 441 # arguments to our wrapper. 442 parseMakeCWrapperCall() { 443 shift # makeCWrapper 444 oldExe=$1; shift 445 oldWrapperArgs=("$@") 446 } 447 eval "parseMakeCWrapperCall ''${wrapperCmd//"${browser}"/"$out"}" 448 rm "$executablePath" 449 else 450 if read -rn2 shebang < "$executablePath" && [[ $shebang == '#!' ]]; then 451 # Shell wrapper: patch in place to point to $out. 452 sed -i "s@${browser}@$out@g" "$executablePath" 453 fi 454 # Suffix the executable with -old, because -wrapped might already be used by the old wrapper. 455 oldExe="$executablePrefix/.${applicationName}"-old 456 mv "$executablePath" "$oldExe" 457 fi 458 '' 459 + lib.optionalString (!isDarwin) '' 460 appendToVar makeWrapperArgs --prefix XDG_DATA_DIRS : "$GSETTINGS_SCHEMAS_PATH" 461 '' 462 + '' 463 concatTo makeWrapperArgs oldWrapperArgs 464 465 makeWrapper "$oldExe" "$out/${finalBinaryPath}" "''${makeWrapperArgs[@]}" 466 467 ############################# 468 # # 469 # END EXTRA PREF CHANGES # 470 # # 471 ############################# 472 '' 473 + lib.optionalString (!isDarwin) '' 474 if [ -e "${browser}/share/icons" ]; then 475 mkdir -p "$out/share" 476 ln -s "${browser}/share/icons" "$out/share/icons" 477 else 478 for res in 16 32 48 64 128; do 479 mkdir -p "$out/share/icons/hicolor/''${res}x''${res}/apps" 480 icon=$( find "${browser}/lib/" -name "default''${res}.png" ) 481 if [ -e "$icon" ]; then ln -s "$icon" \ 482 "$out/share/icons/hicolor/''${res}x''${res}/apps/${icon}.png" 483 fi 484 done 485 fi 486 487 install -m 644 -D -t $out/share/applications $desktopItem/share/applications/* 488 489 '' 490 + lib.optionalString hasMozSystemDirPatch '' 491 mkdir -p $out/lib/mozilla/native-messaging-hosts 492 for ext in ${toString allNativeMessagingHosts}; do 493 ln -sLt $out/lib/mozilla/native-messaging-hosts $ext/lib/mozilla/native-messaging-hosts/* 494 done 495 '' 496 + '' 497 498 mkdir -p $out/lib/mozilla/pkcs11-modules 499 for ext in ${toString pkcs11Modules}; do 500 ln -sLt $out/lib/mozilla/pkcs11-modules $ext/lib/mozilla/pkcs11-modules/* 501 done 502 503 504 ######################### 505 # # 506 # EXTRA PREF CHANGES # 507 # # 508 ######################### 509 # user customization 510 libDir="$out/${libDir}" 511 512 # creating policies.json 513 mkdir -p "$libDir/distribution" 514 515 POL_PATH="$libDir/distribution/policies.json" 516 rm -f "$POL_PATH" 517 cat ${policiesJson} >> "$POL_PATH" 518 519 extraPoliciesFiles=(${builtins.toString extraPoliciesFiles}) 520 for extraPoliciesFile in "''${extraPoliciesFiles[@]}"; do 521 jq -s '.[0] * .[1]' $extraPoliciesFile "$POL_PATH" > .tmp.json 522 mv .tmp.json "$POL_PATH" 523 done 524 525 # preparing for autoconfig 526 prefsDir="$out/${prefsDir}" 527 mkdir -p "$prefsDir" 528 529 echo 'pref("general.config.filename", "mozilla.cfg");' > "$prefsDir/autoconfig.js" 530 echo 'pref("general.config.obscure_value", 0);' >> "$prefsDir/autoconfig.js" 531 532 cat > "$libDir/mozilla.cfg" << EOF 533 ${mozillaCfg} 534 EOF 535 536 extraPrefsFiles=(${builtins.toString extraPrefsFiles}) 537 for extraPrefsFile in "''${extraPrefsFiles[@]}"; do 538 cat "$extraPrefsFile" >> "$libDir/mozilla.cfg" 539 done 540 541 cat >> "$libDir/mozilla.cfg" << EOF 542 ${extraPrefs} 543 EOF 544 545 mkdir -p "$libDir/distribution/extensions" 546 547 ############################# 548 # # 549 # END EXTRA PREF CHANGES # 550 # # 551 ############################# 552 ''; 553 554 preferLocalBuild = true; 555 556 libs = lib.makeLibraryPath libs + ":" + lib.makeSearchPathOutput "lib" "lib64" libs; 557 gtk_modules = map (x: x + x.gtkModule) gtk_modules; 558 559 passthru = { 560 unwrapped = browser; 561 }; 562 563 disallowedRequisites = [ stdenv.cc ]; 564 meta = browser.meta // { 565 inherit (browser.meta) description; 566 mainProgram = launcherName; 567 hydraPlatforms = [ ]; 568 priority = (browser.meta.priority or lib.meta.defaultPriority) - 1; # prefer wrapper over the package 569 }; 570 }); 571in 572lib.makeOverridable wrapper