Skip to content
Merged
66 changes: 37 additions & 29 deletions pkgs/by-name/ha/handy/package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
cctools,
cargo-tauri,
jq,
llvmPackages,
writableTmpDirAsHomeHook,
makeBinaryWrapper,
swift,
apple-sdk_26,

# Linux-only
webkitgtk_4_1,
Expand Down Expand Up @@ -55,8 +55,17 @@ rustPlatform.buildRustPackage (
]
);

# Bun node_modules as a fixed-output derivation; --production is intentionally
# omitted because devDeps (e.g. @types/*) are required for `tsc` at build time.
# Per-platform bun node_modules hashes; --production is intentionally
# omitted because devDeps (e.g. @types/*) are required for tsc at
# build time. Bun downloads host-matching native binaries only, so
# each system has a distinct hash.
# Details: https://github.com/cjpais/Handy/pull/1256
# TODO: switch to bun.fetchDeps once NixOS/nixpkgs#376299 is merged.
frontendDepsHashes = {
"x86_64-linux" = "sha256-tJ6LK99dELOiR0BcsTRTt/vLyNamntujLxhBy5Xl/lc=";
"aarch64-linux" = "sha256-S+dX6ZVgv9dexxIHoa5PxP7e0nxf/d7cKUGty5eEi8A=";
"aarch64-darwin" = "sha256-DQbogNBQ9izK5GPmoOudqiB2lJvct1vZI2U5lp3WFy8=";
};
frontendDeps = stdenv.mkDerivation {
pname = "${finalAttrs.pname}-frontend-deps";
inherit (finalAttrs) version src;
Expand All @@ -68,7 +77,9 @@ rustPlatform.buildRustPackage (
buildPhase = ''
runHook preBuild
export BUN_INSTALL_CACHE_DIR=$(mktemp -d)
bun install --force --frozen-lockfile --ignore-scripts --no-progress
bun install --linker=isolated --force --frozen-lockfile \
--ignore-scripts --no-progress
bun --bun "$PWD/.nix/scripts/normalize-install.ts"
runHook postBuild
'';
installPhase = ''
Expand All @@ -78,28 +89,34 @@ rustPlatform.buildRustPackage (
runHook postInstall
'';
dontFixup = true;
outputHash = "sha256-AxE6WuFOGk40h+2w3Tyvnh64Eb5yHA5EZWgemYafRhg=";
outputHash =
frontendDepsHashes.${stdenv.hostPlatform.system} or (throw ''
handy: no frontendDeps hash for ${stdenv.hostPlatform.system}.
Run `nix-update --flake handy` (or the equivalent `passthru.updateScript`)
on a host of that system and paste the value into
pkgs/by-name/ha/handy/package.nix:frontendDepsHashes.
'');
outputHashMode = "recursive";
};
in
{
pname = "handy";
version = "0.8.2";
version = "0.8.3";

__structuredAttrs = true;

src = fetchFromGitHub {
owner = "cjpais";
repo = "Handy";
tag = "v${finalAttrs.version}";
hash = "sha256-X21uFe609Vitv7yvFMfT847a4E2gy3Uy/uPh1I8D7pA=";
hash = "sha256-sCCtp6UAxmCAcYeOM9+RW2czATh4Geqf1H8wXNMniYc=";
};

cargoRoot = "src-tauri";
cargoHash = "sha256-qwcKuPfSLVmjIkduKkIRCmVk6BPbxF5htfY6f+6yV0w=";
cargoHash = "sha256-mvOThNqfE24iMkVBM2zYexJkQxpMMgE4PPNXKy39hSg=";

postPatch = ''
# Strip updater artifacts; disable macOS code-signing (no identity in sandbox)
# Strip updater artifacts; disable macOS code-signing in sandbox
${jq}/bin/jq '
del(.build.beforeBuildCommand) |
.bundle.createUpdaterArtifacts = false |
Expand All @@ -111,7 +128,7 @@ rustPlatform.buildRustPackage (
${jq}/bin/jq 'del(.scripts.postinstall)' package.json > $TMPDIR/package.json
cp $TMPDIR/package.json package.json

# cbindgen calls `cargo metadata` which fails in the Nix sandbox.
# cbindgen's cargo metadata fails in the sandbox
find $cargoDepsCopy -path "*/ferrous-opencc-*/build.rs" \
-exec sed -i \
-e '/cbindgen::Builder::new/{:l;/write_to_file/!{N;bl};d}' \
Expand All @@ -122,9 +139,6 @@ rustPlatform.buildRustPackage (
-exec sed -i \
's|libayatana-appindicator3.so.1|${libayatana-appindicator}/lib/libayatana-appindicator3.so.1|' \
{} \;
''
+ lib.optionalString stdenv.hostPlatform.isDarwin ''
patch -p1 < ${./use-nix-swift.patch}
'';

nativeBuildInputs = [
Expand All @@ -134,7 +148,7 @@ rustPlatform.buildRustPackage (
nodejs
cargo-tauri.hook
jq
llvmPackages.libclang
rustPlatform.bindgenHook
]
++ lib.optionals stdenv.hostPlatform.isLinux [
wrapGAppsHook4
Expand All @@ -144,6 +158,7 @@ rustPlatform.buildRustPackage (
makeBinaryWrapper
cctools
swift
apple-sdk_26 # optional; enables Apple Intelligence on macOS 26+
];

buildInputs = [
Expand All @@ -168,13 +183,6 @@ rustPlatform.buildRustPackage (
++ gstPlugins;

env = {
LIBCLANG_PATH = "${llvmPackages.libclang.lib}/lib";
BINDGEN_EXTRA_CLANG_ARGS = lib.concatStringsSep " " (
[
"-isystem ${llvmPackages.libclang.lib}/lib/clang/${lib.getVersion llvmPackages.libclang}/include"
]
++ lib.optional stdenv.hostPlatform.isLinux "-isystem ${stdenv.cc.libc.dev}/include"
);
ORT_LIB_LOCATION = "${onnxruntime}/lib";
ORT_PREFER_DYNAMIC_LINK = "1";
GST_PLUGIN_SYSTEM_PATH_1_0 = lib.optionalString stdenv.hostPlatform.isLinux (
Expand Down Expand Up @@ -225,22 +233,22 @@ rustPlatform.buildRustPackage (
];
}
}"
--prefix LD_LIBRARY_PATH : "${
lib.makeLibraryPath [
vulkan-loader
onnxruntime
]
}"
)
'';

# Bake the onnxruntime dylib path into the binary's rpath so it can be found
# at runtime without relying on the infamous DYLD_LIBRARY_PATH (blocked by SIP on macOS).
# onnxruntime rpath (DYLD_LIBRARY_PATH is blocked by SIP on macOS)
postFixup = lib.optionalString stdenv.hostPlatform.isDarwin ''
install_name_tool -add_rpath ${onnxruntime}/lib \
"$out/Applications/Handy.app/Contents/MacOS/handy"
'';

passthru = {
inherit frontendDeps;
# nix-update-script cannot manage per-platform frontendDepsHashes;
# this wraps nix-update and refreshes the current host's entry.
updateScript = ./update.sh;
};

meta = {
description = "Free, open source, offline speech-to-text application";
longDescription = ''
Expand Down
65 changes: 65 additions & 0 deletions pkgs/by-name/ha/handy/update.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p nix-update nix gnused gnugrep gawk coreutils git
# shellcheck shell=bash

# 1. `nix-update handy` bumps version, src.hash, cargoHash.
# 2. On a version bump, all frontendDepsHashes entries are reset to lib.fakeHash.
# 3. Rebuilds handy.passthru.frontendDeps to capture the real hash for the current host.
# 4. Remaining entries stay lib.fakeHash — re-run on each target host to fill them in.

set -euo pipefail

repo_root=$(git rev-parse --show-toplevel)
pkg_file="$repo_root/pkgs/by-name/ha/handy/package.nix"
cd "$repo_root"

if [[ ! -f "$pkg_file" ]]; then
echo "update.sh: $pkg_file not found" >&2
exit 1
fi

read_version() {
sed -n 's|^\s*version = "\([^"]*\)";.*|\1|p' "$pkg_file" | head -n1
}

nix_update_args=(handy)
if [[ $# -gt 0 ]]; then
nix_update_args+=(--version "$1")
fi

old_version=$(read_version)
nix-update "${nix_update_args[@]}"
new_version=$(read_version)

if [[ "$old_version" != "$new_version" ]]; then
echo "update.sh: version bump $old_version → $new_version; resetting frontendDepsHashes"
sed -i -e '/frontendDepsHashes = {/,/^ };$/ s|"sha256-[^"]*"|lib.fakeHash|g' "$pkg_file"
fi

system=$(nix --extra-experimental-features nix-command eval --impure --raw --expr 'builtins.currentSystem')

# Force lib.fakeHash so the build reports the real hash via "got:" even
# when the existing value happens to still be correct.
sed -i "s|\"$system\" = \"sha256-[^\"]*\";|\"$system\" = lib.fakeHash;|" "$pkg_file"

if ! grep -q "\"$system\" = lib.fakeHash;" "$pkg_file"; then
echo "update.sh: no frontendDepsHashes entry for $system to refresh" >&2
exit 1
fi

echo "update.sh: rebuilding frontendDeps on $system"
build_out=$(nix-build -A handy.passthru.frontendDeps --no-out-link 2>&1 || true)
new_hash=$(awk '/got:/ { print $2; exit }' <<<"$build_out")
if [[ -z "${new_hash:-}" ]]; then
echo "update.sh: failed to parse the new hash from nix-build output" >&2
printf '%s\n' "$build_out" | tail -n40 >&2
exit 1
fi

sed -i "s|\"$system\" = lib.fakeHash;|\"$system\" = \"$new_hash\";|" "$pkg_file"

echo "update.sh: $system → $new_hash"
if [[ "$old_version" != "$new_version" ]]; then
echo "update.sh: other frontendDepsHashes entries are still lib.fakeHash;"
echo "update.sh: re-run on each target host to fill them in."
fi
60 changes: 0 additions & 60 deletions pkgs/by-name/ha/handy/use-nix-swift.patch

This file was deleted.

Loading