-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Expand file tree
/
Copy pathflake.nix
More file actions
270 lines (240 loc) · 9.16 KB
/
flake.nix
File metadata and controls
270 lines (240 loc) · 9.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
{
description = "Handy - A free, open source, and extensible speech-to-text application that works completely offline";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
# bun2nix: generates per-package Nix fetchurl expressions from bun.lock,
# replacing the old FOD approach where a single hash covered the entire
# node_modules directory (that hash would break on bun version changes).
# See: https://github.com/nix-community/bun2nix
bun2nix = {
url = "github:nix-community/bun2nix/2.0.8";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs =
{
self,
nixpkgs,
bun2nix,
}:
let
supportedSystems = [
"x86_64-linux"
"aarch64-linux"
];
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
# Read version from Cargo.toml
cargoToml = fromTOML (builtins.readFile ./src-tauri/Cargo.toml);
version = cargoToml.package.version;
# Shared native library dependencies for both package build and dev shell.
# Keep in sync: if a native dep is needed for compilation, add it here.
commonNativeDeps = pkgs: with pkgs; [
webkitgtk_4_1
gtk3
glib
libsoup_3
alsa-lib
onnxruntime
libayatana-appindicator
libevdev
libxtst
gtk-layer-shell
openssl
vulkan-loader
vulkan-headers
shaderc
];
# GStreamer plugins for WebKitGTK audio/video
gstPlugins = pkgs: with pkgs.gst_all_1; [
gstreamer
gst-plugins-base
gst-plugins-good
gst-plugins-bad
gst-plugins-ugly
];
# Shared environment variables for Rust/native builds
commonEnv = pkgs: let lib = pkgs.lib; in {
ORT_LIB_LOCATION = "${pkgs.onnxruntime}/lib";
ORT_PREFER_DYNAMIC_LINK = "1";
GST_PLUGIN_SYSTEM_PATH_1_0 = "${lib.makeSearchPathOutput "lib" "lib/gstreamer-1.0" (gstPlugins pkgs)}";
};
in
{
packages = forAllSystems (
system:
let
pkgs = import nixpkgs {
inherit system;
overlays = [
bun2nix.overlays.default
];
};
lib = pkgs.lib;
combinedAlsaPlugins = pkgs.symlinkJoin {
name = "combined-alsa-plugins";
paths = [
"${pkgs.pipewire}/lib/alsa-lib"
"${pkgs.alsa-plugins}/lib/alsa-lib"
];
};
in
{
handy = pkgs.rustPlatform.buildRustPackage {
pname = "handy";
inherit version;
src = self;
cargoRoot = "src-tauri";
cargoLock = {
lockFile = ./src-tauri/Cargo.lock;
# Automatically fetch git dependencies using builtins.fetchGit.
# This eliminates the need for manual outputHashes that had to be
# updated every time a git dependency changed in Cargo.lock.
# Safe for standalone flakes (not allowed in nixpkgs, it is needed something like crate2nix).
allowBuiltinFetchGit = true;
};
postPatch = ''
${pkgs.jq}/bin/jq 'del(.build.beforeBuildCommand) | .bundle.createUpdaterArtifacts = false' \
src-tauri/tauri.conf.json > $TMPDIR/tauri.conf.json
cp $TMPDIR/tauri.conf.json src-tauri/tauri.conf.json
# Strip postinstall hook — it runs check-nix-deps.ts which is only
# needed during local development, not inside the Nix sandbox.
${pkgs.jq}/bin/jq 'del(.scripts.postinstall)' \
package.json > $TMPDIR/package.json
cp $TMPDIR/package.json package.json
# Point libappindicator-sys to the Nix store path
substituteInPlace \
$cargoDepsCopy/libappindicator-sys-*/src/lib.rs \
--replace-fail \
"libayatana-appindicator3.so.1" \
"${pkgs.libayatana-appindicator}/lib/libayatana-appindicator3.so.1"
# Disable cbindgen in ferrous-opencc (calls cargo metadata which fails in sandbox)
# Upstream removed this call in v0.3.1+
substituteInPlace $cargoDepsCopy/ferrous-opencc-0.2.3/build.rs \
--replace-fail '.expect("Unable to generate bindings")' '.ok();'
substituteInPlace $cargoDepsCopy/ferrous-opencc-0.2.3/build.rs \
--replace-fail '.write_to_file("opencc.h");' '// skipped'
'';
# Bun dependencies: fetched per-package using hashes from .nix/bun.nix.
# This file is auto-generated by `bunx bun2nix -o .nix/bun.nix` and
# kept in sync via the postinstall hook in package.json.
# To regenerate manually: bun scripts/check-nix-deps.ts
bunDeps = pkgs.bun2nix.fetchBunDeps {
bunNix = ./.nix/bun.nix;
};
nativeBuildInputs = with pkgs; [
cargo-tauri.hook
pkg-config
wrapGAppsHook4
bun
# pkgs.bun2nix (from overlay), not the flake input — `with pkgs;`
# doesn't shadow function arguments in Nix.
pkgs.bun2nix.hook # Sets up node_modules from pre-fetched bun cache
jq
cmake
rustPlatform.bindgenHook
shaderc
];
preBuild = ''
# bun2nix.hook has already set up node_modules from pre-fetched cache.
# Build the frontend with bun (tsc + vite).
export HOME=$TMPDIR
bun run build
'';
# Tests require runtime resources (audio devices, model files, GPU/Vulkan)
# not available in the Nix build sandbox
doCheck = false;
# The tauri hook's installPhase expects target/ in cwd, but our
# cargoRoot puts it under src-tauri/. Override to extract the DEB.
installPhase = ''
runHook preInstall
mkdir -p $out
cd src-tauri
mv target/${pkgs.stdenv.hostPlatform.rust.rustcTarget}/release/bundle/deb/*/data/usr/* $out/
runHook postInstall
'';
buildInputs = commonNativeDeps pkgs ++ (with pkgs; [
glib-networking
libx11
]) ++ gstPlugins pkgs;
env = commonEnv pkgs // {
OPENSSL_NO_VENDOR = "1";
};
preFixup = ''
gappsWrapperArgs+=(
--set WEBKIT_DISABLE_DMABUF_RENDERER 1
--set ALSA_PLUGIN_DIR "${combinedAlsaPlugins}"
--prefix LD_LIBRARY_PATH : "${
lib.makeLibraryPath [
pkgs.vulkan-loader
pkgs.onnxruntime
]
}"
)
'';
meta = {
description = "A free, open source, and extensible speech-to-text application that works completely offline";
homepage = "https://github.com/cjpais/Handy";
license = lib.licenses.mit;
mainProgram = "handy";
platforms = supportedSystems;
};
};
default = self.packages.${system}.handy;
}
);
# NixOS module for system-level integration (udev, input group)
nixosModules.default =
{ lib, pkgs, ... }:
{
imports = [ ./nix/module.nix ];
programs.handy.package = lib.mkDefault self.packages.${pkgs.stdenv.hostPlatform.system}.handy;
};
# Home-manager module for per-user service
homeManagerModules.default =
{ lib, pkgs, ... }:
{
imports = [ ./nix/hm-module.nix ];
services.handy.package = lib.mkDefault self.packages.${pkgs.stdenv.hostPlatform.system}.handy;
};
# Development shell for building from source
devShells = forAllSystems (
system:
let
pkgs = import nixpkgs {
inherit system;
};
in
{
default = pkgs.mkShell {
buildInputs = commonNativeDeps pkgs ++ (with pkgs; [
# Rust toolchain
rustc
cargo
rust-analyzer
clippy
# Frontend
nodejs
bun
# Build tools
cargo-tauri
pkg-config
rustPlatform.bindgenHook
cmake
]);
inherit (commonEnv pkgs)
ORT_LIB_LOCATION
ORT_PREFER_DYNAMIC_LINK
GST_PLUGIN_SYSTEM_PATH_1_0;
LD_LIBRARY_PATH = "${pkgs.lib.makeLibraryPath [ pkgs.libayatana-appindicator pkgs.onnxruntime pkgs.vulkan-loader ]}";
# Same as wrapGAppsHook4
XDG_DATA_DIRS = "${pkgs.gsettings-desktop-schemas}/share/gsettings-schemas/${pkgs.gsettings-desktop-schemas.name}:${pkgs.gtk3}/share/gsettings-schemas/${pkgs.gtk3.name}:${pkgs.hicolor-icon-theme}/share";
shellHook = ''
echo "Handy development environment"
bun install
echo "Run 'bun run tauri dev' to start"
'';
};
}
);
};
}