darwin/home: use @pperanich's trampolineApps script

see: https://github.com/nix-community/home-manager/issues/1341#issuecomment-1870352014
This commit is contained in:
Guanran Wang 2024-03-13 21:10:23 +08:00
parent 02ff42da62
commit 46626f24ba
Signed by: nyancat
SSH key fingerprint: SHA256:8oWGKciPALWut/6WA27oFKofX+6Wtc0gQnsefXLQx/8
3 changed files with 168 additions and 34 deletions

View file

@ -1,7 +1,7 @@
{
config,
pkgs,
lib,
config,
...
}: {
imports = map (n: ../../../../home/applications/${n}) [
@ -29,40 +29,36 @@
"telegram-desktop"
];
home = {
activation = {
# Workaround for spotlight indexing
# https://github.com/nix-community/home-manager/issues/1341#issuecomment-1705731962_
trampolineApps = let
apps = pkgs.buildEnv {
name = "home-manager-applications";
paths = config.home.packages;
pathsToLink = "/Applications";
};
in
lib.hm.dag.entryAfter ["writeBoundary"] ''
toDir="$HOME/Applications/Home Manager Trampolines"
fromDir="${apps}/Applications/"
rm -rf "$toDir"
mkdir "$toDir"
(
cd "$fromDir"
for app in *.app; do
/usr/bin/osacompile -o "$toDir/$app" -e 'do shell script "open '$fromDir/$app'"'
done
)
'';
# Install MacOS applications to the user Applications folder. Also update Docked applications
# Modified version of: https://github.com/nix-community/home-manager/issues/1341#issuecomment-1870352014
home.file."Applications/Home Manager Apps".enable = false;
home.activation.trampolineApps = let
apps = pkgs.buildEnv {
name = "home-manager-applications";
paths = config.home.packages;
pathsToLink = "/Applications";
};
in
lib.hm.dag.entryAfter ["writeBoundary"] ''
${builtins.readFile ./trampoline-apps.sh}
fromDir="${apps}/Applications"
toDir="$HOME/Applications/Home Manager Trampolines"
sync_trampolines "$fromDir" "$toDir"
'';
home.extraActivationPath = with pkgs; [
rsync
dockutil
gawk
];
packages = with pkgs; [
## GUI
### Tools
keka # un-archive-r
iterm2
### Misc
element-desktop
];
};
home.packages = with pkgs; [
## GUI
### Tools
keka # un-archive-r
iterm2
### Misc
element-desktop
];
# macOS don't have fontconfig
programs = let

View file

@ -0,0 +1,131 @@
# Utilities not in nixpkgs.
plutil="/usr/bin/plutil"
killall="/usr/bin/killall"
osacompile="/usr/bin/osacompile"
copyable_app_props=(
"CFBundleDevelopmentRegion"
"CFBundleDocumentTypes"
"CFBundleGetInfoString"
"CFBundleIconFile"
"CFBundleIdentifier"
"CFBundleInfoDictionaryVersion"
"CFBundleName"
"CFBundleShortVersionString"
"CFBundleURLTypes"
"NSAppleEventsUsageDescription"
"NSAppleScriptEnabled"
"NSDesktopFolderUsageDescription"
"NSDocumentsFolderUsageDescription"
"NSDownloadsFolderUsageDescription"
"NSPrincipalClass"
"NSRemovableVolumesUsageDescription"
"NSServices"
"UTExportedTypeDeclarations"
)
function sync_icons() {
local from="$1"
local to="$2"
from_resources="$from/Contents/Resources/"
to_resources="$to/Contents/Resources/"
find "$to_resources" -name "*.icns" -delete
rsync --include "*.icns" --exclude "*" --recursive "$from_resources" "$to_resources"
}
function copy_paths() {
local from="$1"
local to="$2"
local paths=("${@:3}")
keys=$(jq -n '$ARGS.positional' --args "${paths[@]}")
jqfilter='to_entries |[.[]| select(.key as $item| $keys | index($item) >= 0) ] | from_entries'
temp_dir=$(mktemp -d)
trap 'rm -rf "$temp_dir"' EXIT
pushd "$temp_dir" > /dev/null || exit
cp "$from" "orig"
chmod u+w "orig"
cp "$to" "bare-wrapper"
chmod u+w "bare-wrapper"
$plutil -convert json -- "orig"
$plutil -convert json -- "bare-wrapper"
jq --argjson keys "$keys" "$jqfilter" < "orig" > "filtered"
cat "bare-wrapper" "filtered" | jq -s add > "final"
$plutil -convert xml1 -- "final"
cp "final" "$to"
popd > /dev/null || exit
}
function sync_dock() {
# Make sure all environment variables are cleared that might affect dockutil
unset SUDO_USER
# Array of applications to sync
declare -a apps=("$@")
# Iterate through each provided app
for app_path in "${apps[@]}"; do
if [ -d "$app_path" ]; then
# Extract the name of the app from the path
app_name=$(basename "$app_path")
app_name=${app_name%.*} # Remove the '.app' extension
resolved_path=$(realpath "$app_path")
# Find the current Dock item for the app, if it exists
current_dock_item=$(dockutil --list --no-restart | grep "$app_name.app" | awk -F "\t" '{print $1}' || echo "")
if [ -n "$current_dock_item" ]; then
# The app is currently in the Dock, attempt to replace it
echo "Updating $app_name in Dock..."
dockutil --add "$resolved_path" --replacing "$current_dock_item" --no-restart
else
# The app is not in the Dock; you might choose to add it or do nothing
echo "$app_name is not currently in the Dock."
fi
else
echo "Warning: Provided path $app_path is not valid."
fi
done
# Restart the Dock to apply changes
$killall Dock
}
function mktrampoline() {
local app="$1"
local trampoline="$2"
if [[ ! -d $app ]]; then
echo "app path is not directory."
return 1
fi
cmd="do shell script \"open '$app'\""
$osacompile -o "$trampoline" -e "$cmd"
sync_icons "$app" "$trampoline"
copy_paths "$(realpath "$app/Contents/Info.plist")" "$(realpath "$trampoline/Contents/Info.plist")" "${copyable_app_props[@]}"
}
function sync_trampolines() {
[[ ! -d $1 ]] && echo "Source directory does not exist" && return 1
if [[ -d $2 ]]; then
rm -rf "$2"
fi
mkdir -p "$2"
apps=("$1"/*.app)
for app in "${apps[@]}"; do
trampoline="$2/$(basename "$app")"
mktrampoline "$app" "$trampoline"
done
sync_dock "${apps[@]}"
}

View file

@ -7,8 +7,15 @@
programs.alejandra.enable = true;
### shell
programs.shellcheck.enable = true;
programs.shfmt.enable = true;
settings.formatter.shfmt.options = ["-i" "2" "-sr"];
programs.shellcheck.enable = true;
settings.formatter.shellcheck.options = [
"-s"
"bash"
"-e"
"SC2016" # shfmt kept doing it, didn't find a toggle to turn it off
];
### toml
programs.taplo.enable = true;