Fix: Add explicit GI_TYPELIB_PATH for AstalNotifd typelib resolution

This commit is contained in:
2025-12-03 18:12:32 -04:00
parent fa9367c43a
commit 186f6ddc82
4 changed files with 299 additions and 20 deletions
+41 -4
View File
@@ -11,7 +11,9 @@
glib, glib,
gjs, gjs,
libadwaita, libadwaita,
pywal16,
dart-sass, dart-sass,
psmisc,
socat, socat,
}: }:
let let
@@ -26,6 +28,8 @@ let
lib.fileset.unions [ lib.fileset.unions [
../flake.nix ../flake.nix
../flake.lock ../flake.lock
../result
../build
./. ./.
] ]
); );
@@ -68,10 +72,21 @@ let
inherit src; inherit src;
# Replace reference to ags FHS install path
postPatch = '' postPatch = ''
substituteInPlace package.json pnpm-lock.yaml \ # Copy the ags JS lib from the Nix store into the source tree so pnpm can
--replace-fail "/usr/share/ags/js" "${inputs'.ags.packages.ags.jsPackage}" # treat it as a local file: dependency (no /nix/store path inside pnpm).
cp -R ${inputs'.ags.packages.ags.jsPackage} ags-js-lib
# Point the devDependency at the local copy instead of the FHS path.
substituteInPlace package.json \
--replace-fail "file:/usr/share/ags/js" "file:./ags-js-lib"
# Update the lockfile to reference the local copy as well.
# We need to keep specifiers in sync with package.json to satisfy
# pnpm's frozen-lockfile check.
substituteInPlace pnpm-lock.yaml \
--replace-fail "file:/usr/share/ags/js" "file:./ags-js-lib" \
--replace-fail "../../../../usr/share/ags/js" "./ags-js-lib"
''; '';
installPhase = '' installPhase = ''
@@ -97,6 +112,7 @@ buildNpmPackage (finalAttrs: {
; ;
fetcherVersion = 2; fetcherVersion = 2;
# Hash updated after local pnpmDeps build
hash = "sha256-m/aPNvv26r0DUvRUR4TL2GwwAHKvEIkc8Nvlm/jpnPc="; hash = "sha256-m/aPNvv26r0DUvRUR4TL2GwwAHKvEIkc8Nvlm/jpnPc=";
# fetcher version 2 fails if there are no *-exec files in the output # fetcher version 2 fails if there are no *-exec files in the output
@@ -133,7 +149,8 @@ buildNpmPackage (finalAttrs: {
buildPhase = '' buildPhase = ''
runHook preBuild runHook preBuild
mkdir build # Allow incremental or repeated builds: don't fail if ./build already exists
mkdir -p build
outPath=./build/${packageJSON.name} outPath=./build/${packageJSON.name}
ags bundle ./src/app.ts $outPath \ ags bundle ./src/app.ts $outPath \
--gtk 4 \ --gtk 4 \
@@ -166,11 +183,29 @@ buildNpmPackage (finalAttrs: {
--prefix PATH : ${ --prefix PATH : ${
lib.makeBinPath [ lib.makeBinPath [
# runtime executables # runtime executables
pywal16 # provides `wal` for colorshell's wallpaper module
dart-sass dart-sass
glib glib
psmisc
socat socat
] ]
} }
--prefix GI_TYPELIB_PATH : "${
lib.makeSearchPath "lib/girepository-1.0" (with inputs'.astal.packages; [
astal4
apps
auth
battery
bluetooth
hyprland
io
mpris
network
notifd
tray
wireplumber
])
}"
) )
''; '';
@@ -178,3 +213,5 @@ buildNpmPackage (finalAttrs: {
resources = colorshellResources; resources = colorshellResources;
}; };
}) })
+180
View File
@@ -0,0 +1,180 @@
{
inputs',
lib,
stdenv,
stdenvNoCC,
moreutils,
pnpm_10,
buildNpmPackage,
wrapGAppsHook4,
gobject-introspection,
glib,
gjs,
libadwaita,
dart-sass,
socat,
}:
let
packageJSON = lib.importJSON ../package.json;
pname = packageJSON.name;
version = packageJSON.version;
# Cleaned sources from this repository
src = lib.fileset.toSource {
root = ../.;
fileset = lib.fileset.difference ../. (
lib.fileset.unions [
../flake.nix
../flake.lock
./.
]
);
};
# Derivation building just the gresources file
colorshellResources = stdenv.mkDerivation {
pname = "${pname}-resources.gresource";
inherit version;
inherit src;
buildInputs = [
glib
];
buildPhase = ''
runHook preBuild
glib-compile-resources resources.gresource.xml \
--sourcedir ./resources \
--target resources.gresource
runHook postBuild
'';
installPhase = ''
runHook preInstall
cp resources.gresource $out
runHook postInstall
'';
};
# Cleaned sources, with FHS paths patched out.
colorshellSrc = stdenvNoCC.mkDerivation {
pname = "${pname}-src";
inherit version;
inherit src;
# Replace reference to ags FHS install path
postPatch = ''
substituteInPlace package.json pnpm-lock.yaml \
--replace-fail "/usr/share/ags/js" "${inputs'.ags.packages.ags.jsPackage}"
'';
installPhase = ''
mkdir $out
cp -rp * $out
'';
};
in
buildNpmPackage (finalAttrs: {
inherit pname version;
src = colorshellSrc;
sourceRoot = "${finalAttrs.src.name}";
npmConfigHook = pnpm_10.configHook;
npmDeps = finalAttrs.pnpmDeps;
pnpmDeps = pnpm_10.fetchDeps {
inherit (finalAttrs)
pname
version
src
sourceRoot
;
fetcherVersion = 2;
hash = "sha256-Z5JP7hPEjLY9wGnWe6kM6T1qk3UUSlJnoxdDqS/ksnw=";
# fetcher version 2 fails if there are no *-exec files in the output
preFixup = ''
touch $out/.dummy-exec
'';
};
nativeBuildInputs = [
wrapGAppsHook4
gobject-introspection
inputs'.ags.packages.default
moreutils
];
buildInputs = [
glib
gjs
libadwaita
inputs'.astal.packages.astal4
inputs'.astal.packages.apps
inputs'.astal.packages.auth
inputs'.astal.packages.battery
inputs'.astal.packages.bluetooth
inputs'.astal.packages.hyprland
inputs'.astal.packages.io
inputs'.astal.packages.mpris
inputs'.astal.packages.network
inputs'.astal.packages.notifd
inputs'.astal.packages.tray
inputs'.astal.packages.wireplumber
];
buildPhase = ''
runHook preBuild
mkdir build
outPath=./build/${packageJSON.name}
ags bundle ./src/app.ts $outPath \
--gtk 4 \
--root ./src \
--define "DEVEL=false" \
--define "COLORSHELL_VERSION='${finalAttrs.version}'" \
--define "GRESOURCES_FILE='${colorshellResources}'"
# add socket-communication support on executable
{
head -n1 $outPath
sed '1{/^#!.*$/d}' ${../scripts/socket.sh}
cat "$outPath" | sed '/^#!.*$/d'
} | sponge $outPath
runHook postBuild
'';
installPhase = ''
runHook preInstall
mkdir -p $out/bin
cp -rp build/${packageJSON.name} $out/bin/
runHook postInstall
'';
preFixup = ''
gappsWrapperArgs+=(
--prefix PATH : ${
lib.makeBinPath [
# runtime executables
dart-sass
glib
socat
]
}
)
'';
passthru = {
resources = colorshellResources;
};
})
+11 -2
View File
@@ -5,10 +5,19 @@ file="${1:-./build/colorshell}"
function start() { function start() {
if Is_running; then if Is_running; then
echo "[info] killing previous instance" echo "[info] killing previous instance"
colorshell quit || killall gjs colorshell quit || killall gjs 2>/dev/null || true
fi fi
echo "[info] starting" echo "[info] starting"
exec "$file"
# Always run through nix develop to ensure proper environment variables are set
# This is needed because the manually built executable doesn't have wrapGAppsHook
if command -v nix > /dev/null 2>&1; then
# Use nix develop -c to run with proper environment
# The -c flag runs the command in the devshell environment
exec nix develop -c bash -c "exec \"$file\" \"\$@\"" -- "$@"
else
exec "$file" "$@"
fi
} }
if [[ -f $file ]]; then if [[ -f $file ]]; then
+67 -14
View File
@@ -168,21 +168,74 @@ you should use the socket in the XDG_RUNTIME_DIR/colorshell.sock for a faster re
private init(): void { private init(): void {
// load gresource from build-defined path // load gresource from build-defined path
try { try {
const gresourcesPath: string = GRESOURCES_FILE.startsWith('/') ? GRESOURCES_FILE : (GRESOURCES_FILE.split('/').filter(s => // Handle missing GRESOURCES_FILE define (when running via AGS Home Manager)
s !== "" if (typeof GRESOURCES_FILE === "undefined" || !GRESOURCES_FILE) {
).map(path => { // Try to find gresource in common locations
// support environment variables at runtime // When symlinked via Home Manager, configDir is ~/.config/ags -> ../colorshell/src
if(/^\$/.test(path)) { // We need to resolve the actual path of the colorshell directory
const env = GLib.getenv(path.replace(/^\$/, "")); const configDir = GLib.get_user_config_dir();
if(env === null) const agsConfigFile = Gio.File.new_for_path(`${configDir}/ags/app.ts`);
throw new Error(`Couldn't get environment variable: ${path}`); let colorshellBuildPath: string | null = null;
return env; // Try to resolve the symlink to find the actual colorshell directory
// When Home Manager symlinks ~/.config/ags -> ../colorshell/src,
// we need to go up one level from src to find the colorshell root
try {
// Get the real path of app.ts (resolves symlinks)
const appTsFile = Gio.File.new_for_path(`${configDir}/ags/app.ts`);
if (appTsFile.query_exists(null)) {
const realPath = appTsFile.get_path()!;
// realPath will be something like /home/olivier/NixOS-New/colorshell/src/app.ts
// Go up from src/ to get colorshell root, then to build/
const srcDir = GLib.path_get_dirname(realPath);
const colorshellDir = GLib.path_get_dirname(srcDir);
colorshellBuildPath = `${colorshellDir}/build/resources.gresource`;
}
} catch (e) {
// If symlink resolution fails, try absolute paths
} }
return path;
}).join('/')); const possiblePaths = [
this.#gresource = Gio.Resource.load(gresourcesPath); colorshellBuildPath,
Gio.resources_register(this.#gresource); `${GLib.get_home_dir()}/NixOS-New/colorshell/build/resources.gresource`, // Absolute path (most reliable)
`${configDir}/../colorshell/build/resources.gresource`, // Relative to ~/.config/ags
`${GLib.get_user_config_dir()}/colorshell/build/resources.gresource`,
`${GLib.get_home_dir()}/.config/colorshell/build/resources.gresource`,
].filter(p => p !== null) as string[];
let gresourcesPath: string | null = null;
for (const path of possiblePaths) {
const file = Gio.File.new_for_path(path);
if (file.query_exists(null)) {
gresourcesPath = path;
break;
}
}
if (!gresourcesPath) {
console.warn("Colorshell: GRESOURCES_FILE not defined and couldn't find gresource file. Icons may not be available.");
return;
}
this.#gresource = Gio.Resource.load(gresourcesPath);
Gio.resources_register(this.#gresource);
} else {
const gresourcesPath: string = GRESOURCES_FILE.startsWith('/') ? GRESOURCES_FILE : (GRESOURCES_FILE.split('/').filter(s =>
s !== ""
).map(path => {
// support environment variables at runtime
if(/^\$/.test(path)) {
const env = GLib.getenv(path.replace(/^\$/, ""));
if(env === null)
throw new Error(`Couldn't get environment variable: ${path}`);
return env;
}
return path;
}).join('/'));
this.#gresource = Gio.Resource.load(gresourcesPath);
Gio.resources_register(this.#gresource);
}
// add icons // add icons
Gtk.IconTheme.get_for_display(Gdk.Display.get_default()!) Gtk.IconTheme.get_for_display(Gdk.Display.get_default()!)