From 850fc57f56d9f6732e6eaa5688ce2d6e9f4f2d09 Mon Sep 17 00:00:00 2001 From: Matthew Leach Date: Wed, 28 Jul 2021 22:31:09 +0100 Subject: [PATCH] build-support: make-darwin-bundle: new Add a new module that allows darwin-style application bundles to be created --- .../element/element-desktop.nix | 3 +- .../make-darwin-bundle/default.nix | 26 ++++++++++ .../write-darwin-bundle.nix | 40 ++++++++++++++++ .../setup-hooks/desktop-to-darwin-bundle.sh | 48 +++++++++++++++++++ pkgs/top-level/all-packages.nix | 7 +++ 5 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 pkgs/build-support/make-darwin-bundle/default.nix create mode 100644 pkgs/build-support/make-darwin-bundle/write-darwin-bundle.nix create mode 100644 pkgs/build-support/setup-hooks/desktop-to-darwin-bundle.sh diff --git a/pkgs/applications/networking/instant-messengers/element/element-desktop.nix b/pkgs/applications/networking/instant-messengers/element/element-desktop.nix index 5ba7a1f7b205..d9683740667c 100644 --- a/pkgs/applications/networking/instant-messengers/element/element-desktop.nix +++ b/pkgs/applications/networking/instant-messengers/element/element-desktop.nix @@ -12,6 +12,7 @@ , Security , AppKit , CoreServices +, desktopToDarwinBundle }: let @@ -36,7 +37,7 @@ mkYarnPackage rec { sha256 = pinData.desktopYarnHash; }; - nativeBuildInputs = [ makeWrapper ]; + nativeBuildInputs = [ makeWrapper ] ++ lib.optionals stdenv.isDarwin [ desktopToDarwinBundle ]; seshat = callPackage ./seshat { inherit CoreServices; }; keytar = callPackage ./keytar { inherit Security AppKit; }; diff --git a/pkgs/build-support/make-darwin-bundle/default.nix b/pkgs/build-support/make-darwin-bundle/default.nix new file mode 100644 index 000000000000..b8f58882fff3 --- /dev/null +++ b/pkgs/build-support/make-darwin-bundle/default.nix @@ -0,0 +1,26 @@ +# given a package with an executable and an icon, make a darwin bundle for +# it. This package should be used when generating launchers for native Darwin +# applications. If the package conatins a .desktop file use +# `desktopToDarwinLauncher` instead. + +{ lib, writeShellScript, writeDarwinBundle }: + +{ name # The name of the Application file. +, exec # Executable file. +, icon ? "" # Optional icon file. +}: + +writeShellScript "make-darwin-bundle-${name}" ('' + function makeDarwinBundlePhase() { + mkdir -p "$out/Applications/${name}.app/Contents/MacOS" + mkdir -p "$out/Applications/${name}.app/Contents/Resources" + + if [ -n "${icon}" ]; then + ln -s "${icon}" "$out/Applications/${name}.app/Contents/Resources" + fi + + ${writeDarwinBundle}/bin/write-darwin-bundle "$out" "${name}" "${exec}" + } + + preDistPhases+=" makeDarwinBundlePhase" +'') diff --git a/pkgs/build-support/make-darwin-bundle/write-darwin-bundle.nix b/pkgs/build-support/make-darwin-bundle/write-darwin-bundle.nix new file mode 100644 index 000000000000..63ef7e655075 --- /dev/null +++ b/pkgs/build-support/make-darwin-bundle/write-darwin-bundle.nix @@ -0,0 +1,40 @@ +{ writeScriptBin, lib, ... }: + +let + pListText = lib.generators.toPlist { } { + CFBundleDevelopmentRegion = "English"; + CFBundleExecutable = "$name"; + CFBundleIconFiles = [ "$iconPlistArray" ]; + CFBundleIdentifier = "org.nixos.$name"; + CFBundleInfoDictionaryVersion = "6.0"; + CFBundleName = "$name"; + CFBundlePackageType = "APPL"; + CFBundleSignature = "???"; + }; + +# The generation of the CFBundleIconFiles array is a bit of a hack, since we +# will always end up with an empty first element () but macOS +# appears to ignore this which allows us to use the nix PList generator. +in writeScriptBin "write-darwin-bundle" '' + shopt -s nullglob + + readonly prefix="$1" + readonly name="$2" + readonly exec="$3" + iconPlistArray="" + + for icon in "$prefix/Applications/$name.app/Contents/Resources"/*; do + iconPlistArray="$iconPlistArray"$(basename "$icon")"" + done + + cat > "$prefix/Applications/$name.app/Contents/Info.plist" < "$prefix/Applications/$name.app/Contents/MacOS/$name" </dev/null); + local -r pixMaps=$(find "$out/share/pixmaps/" -name "${iconName}.xpm" 2>/dev/null); + + mkdir -p "$out/Applications/${name}.app/Contents/MacOS" + mkdir -p "$out/Applications/${name}.app/Contents/Resources" + + local i=0; + for icon in $iconFiles; do + ln -s "$icon" "$out/Applications/${name}.app/Contents/Resources/$i-$(basename "$icon")" + (( i +=1 )); + done + + for pixmap in $pixMaps; do + local newIconName="$i-$(basename "$pixmap")"; + convert "$pixmap" "$out/Applications/${name}.app/Contents/Resources/${newIconName%.xpm}.png" + (( i +=1 )); + done + + write-darwin-bundle "$out" "$name" "$exec" +} + +convertDesktopFiles() { + local dir="$1/share/applications/" + + if [ -d "${dir}" ]; then + for desktopFile in $(find "$dir" -iname "*.desktop"); do + convertDesktopFile "$desktopFile"; + done + fi +} diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 0bb3cbe5ec3b..5a28adb25aae 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -713,6 +713,8 @@ with pkgs; makeDesktopItem = callPackage ../build-support/make-desktopitem { }; + makeDarwinBundle = callPackage ../build-support/make-darwin-bundle { }; + makeAutostartItem = callPackage ../build-support/make-startupitem { }; makeInitrd = callPackage ../build-support/kernel/make-initrd.nix; # Args intentionally left out @@ -815,6 +817,11 @@ with pkgs; substitutions = { inherit (binutils) targetPrefix; }; } ../build-support/setup-hooks/fix-darwin-dylib-names.sh; + writeDarwinBundle = callPackage ../build-support/make-darwin-bundle/write-darwin-bundle.nix { }; + + desktopToDarwinBundle = makeSetupHook { deps = [ writeDarwinBundle imagemagick ]; } + ../build-support/setup-hooks/desktop-to-darwin-bundle.sh; + keepBuildTree = makeSetupHook { } ../build-support/setup-hooks/keep-build-tree.sh; enableGCOVInstrumentation = makeSetupHook { } ../build-support/setup-hooks/enable-coverage-instrumentation.sh;