diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5912d01c..5c1d01ad 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -73,6 +73,9 @@ jobs: TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} LDAI_UPDATE_INFORMATION: ${{ contains(matrix.platform, 'ubuntu') && 'gh-releases-zsync|tonhowtf|omniget|latest|*AppImage.zsync' || '' }} + # linuxdeploy bundles an old `strip` that fails on modern .relr.dyn + # relocations; disable stripping so AppImage bundling succeeds. + NO_STRIP: ${{ contains(matrix.platform, 'ubuntu') && '1' || '' }} NODE_OPTIONS: --max-old-space-size=6144 with: tagName: v__VERSION__ diff --git a/README.md b/README.md index 2d5d531d..dccfb0a1 100644 --- a/README.md +++ b/README.md @@ -381,6 +381,8 @@ Production build: pnpm tauri build --config '{"bundle":{"createUpdaterArtifacts":false}}' ``` +On Linux, use `pnpm tauri:appimage` instead (wraps the same flag, skips the strip step that fails on `.relr.dyn`, uses a patched `linuxdeploy-plugin-gtk.sh` that works on Arch). + Releases sign their updater artifacts with a private key only the maintainers hold, so a plain `pnpm tauri build` stops at the bundling step with *"A public key has been found, but no private key"*. The flag above turns those artifacts off for your local build — everything else is identical. It is passed on the command line rather than committed to `tauri.conf.json` on purpose: a config that disables them by default would silently ship a release with no signatures and break the auto-updater for everyone. ### Command line interface diff --git a/package.json b/package.json index 2a04ed08..062fc743 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "tauri": "tauri", + "tauri:appimage": "bash scripts/linux/appimage.sh", "version:set": "node scripts/bump-version.js", "generate:i18n-keys": "node scripts/generate-i18n-keys.js", "check:i18n": "node scripts/generate-i18n-keys.js --strict", @@ -74,7 +75,7 @@ "@sveltejs/adapter-static": "^3.0.6", "@sveltejs/kit": "^2.9.0", "@sveltejs/vite-plugin-svelte": "^5.0.0", - "@tauri-apps/cli": "^2", + "@tauri-apps/cli": "^2.11.4", "@types/katex": "^0.16.7", "@types/marked": "^6.0.0", "@types/node": "^25.6.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bf600cc2..90b84c59 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -157,8 +157,8 @@ importers: specifier: ^5.0.0 version: 5.1.1(svelte@5.51.0)(vite@6.4.1(@types/node@25.6.0)(yaml@2.8.4)) '@tauri-apps/cli': - specifier: ^2 - version: 2.10.0 + specifier: ^2.11.4 + version: 2.11.4 '@types/katex': specifier: ^0.16.7 version: 0.16.8 @@ -740,79 +740,79 @@ packages: '@tauri-apps/api@2.10.1': resolution: {integrity: sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw==} - '@tauri-apps/cli-darwin-arm64@2.10.0': - resolution: {integrity: sha512-avqHD4HRjrMamE/7R/kzJPcAJnZs0IIS+1nkDP5b+TNBn3py7N2aIo9LIpy+VQq0AkN8G5dDpZtOOBkmWt/zjA==} + '@tauri-apps/cli-darwin-arm64@2.11.4': + resolution: {integrity: sha512-1ryOF3ZhpZ/nemHV5zVwBQBz9jDGKmKPvWPADOhc83ig0P4bMc2iER4NbC6r9sjeIZ6RVQ4g3RZIYvezhcl4TQ==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@tauri-apps/cli-darwin-x64@2.10.0': - resolution: {integrity: sha512-keDmlvJRStzVFjZTd0xYkBONLtgBC9eMTpmXnBXzsHuawV2q9PvDo2x6D5mhuoMVrJ9QWjgaPKBBCFks4dK71Q==} + '@tauri-apps/cli-darwin-x64@2.11.4': + resolution: {integrity: sha512-uFsGQAAfuyz1k/yGLmkWfkBlgKAqZfxqlHmLWx81QU27RJWfmbNHCIq8T8w1e+VClleIuZUjpHWfoE4E3DLo3A==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@tauri-apps/cli-linux-arm-gnueabihf@2.10.0': - resolution: {integrity: sha512-e5u0VfLZsMAC9iHaOEANumgl6lfnJx0Dtjkd8IJpysZ8jp0tJ6wrIkto2OzQgzcYyRCKgX72aKE0PFgZputA8g==} + '@tauri-apps/cli-linux-arm-gnueabihf@2.11.4': + resolution: {integrity: sha512-IaHZn5CdBL21oUmjiVOS1ctw6Ip1O0pjp70FwOWmYz1myWe0SY96ZIj2FYf7pT0m8bI2h/hrs5ZbEXXh44/MkQ==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@tauri-apps/cli-linux-arm64-gnu@2.10.0': - resolution: {integrity: sha512-YrYYk2dfmBs5m+OIMCrb+JH/oo+4FtlpcrTCgiFYc7vcs6m3QDd1TTyWu0u01ewsCtK2kOdluhr/zKku+KP7HA==} + '@tauri-apps/cli-linux-arm64-gnu@2.11.4': + resolution: {integrity: sha512-N41/ukTRVe6XSuUTESuFdGeOW2i7k62tK+6gHK5Kd5/q5RPvvi19GaWAVPPb9u95HSGmTChSolBfzynUsssFaA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [glibc] - '@tauri-apps/cli-linux-arm64-musl@2.10.0': - resolution: {integrity: sha512-GUoPdVJmrJRIXFfW3Rkt+eGK9ygOdyISACZfC/bCSfOnGt8kNdQIQr5WRH9QUaTVFIwxMlQyV3m+yXYP+xhSVA==} + '@tauri-apps/cli-linux-arm64-musl@2.11.4': + resolution: {integrity: sha512-v277UnT/fB64xAfSroL5N3Km3tLmvATWqJJw/wRI+g6o+HkeD0slyE7gOhNs1MbjE41R7bQOTxMVoL3aomUJmw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [musl] - '@tauri-apps/cli-linux-riscv64-gnu@2.10.0': - resolution: {integrity: sha512-JO7s3TlSxshwsoKNCDkyvsx5gw2QAs/Y2GbR5UE2d5kkU138ATKoPOtxn8G1fFT1aDW4LH0rYAAfBpGkDyJJnw==} + '@tauri-apps/cli-linux-riscv64-gnu@2.11.4': + resolution: {integrity: sha512-qqgNkQ2u1yZHxjhxsZaxUtRDW8dIqIYm33rx/mzwQv0SfY9x1B+iraj8vWeFiXjjSVVhEMepXSOts1TqPzvXNQ==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] libc: [glibc] - '@tauri-apps/cli-linux-x64-gnu@2.10.0': - resolution: {integrity: sha512-Uvh4SUUp4A6DVRSMWjelww0GnZI3PlVy7VS+DRF5napKuIehVjGl9XD0uKoCoxwAQBLctvipyEK+pDXpJeoHng==} + '@tauri-apps/cli-linux-x64-gnu@2.11.4': + resolution: {integrity: sha512-2VRNWl84FOH0m2giiDkO2h0QXlcMJeX+zJDpI5kDIQAx6s+geF3v48F4DXfJez4GS/FdoDGnPnw1C2iYGbQ7bQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [glibc] - '@tauri-apps/cli-linux-x64-musl@2.10.0': - resolution: {integrity: sha512-AP0KRK6bJuTpQ8kMNWvhIpKUkQJfcPFeba7QshOQZjJ8wOS6emwTN4K5g/d3AbCMo0RRdnZWwu67MlmtJyxC1Q==} + '@tauri-apps/cli-linux-x64-musl@2.11.4': + resolution: {integrity: sha512-o9GyhYor/nc7xarmwDE3ka2szuW3uuZzXjHWh64Q8YX5AtSgxdQkFWzrY4O8KiGtVNvFBI14H3Q49Qj5TOIP/A==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [musl] - '@tauri-apps/cli-win32-arm64-msvc@2.10.0': - resolution: {integrity: sha512-97DXVU3dJystrq7W41IX+82JEorLNY+3+ECYxvXWqkq7DBN6FsA08x/EFGE8N/b0LTOui9X2dvpGGoeZKKV08g==} + '@tauri-apps/cli-win32-arm64-msvc@2.11.4': + resolution: {integrity: sha512-ld5Ehb598m0VkYyylRPNeCFsBe/km0jxis6KgMpl3IGY6I/i1RwQXO05I1AsXUXO2WC6AvB/Lw4qTf/asiuEiQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@tauri-apps/cli-win32-ia32-msvc@2.10.0': - resolution: {integrity: sha512-EHyQ1iwrWy1CwMalEm9z2a6L5isQ121pe7FcA2xe4VWMJp+GHSDDGvbTv/OPdkt2Lyr7DAZBpZHM6nvlHXEc4A==} + '@tauri-apps/cli-win32-ia32-msvc@2.11.4': + resolution: {integrity: sha512-12Hxi0XX/H5VFxO/bGgHkFWhml9VMgEOu9CidjeCeTNQ1l6fpUlbiGgSP7CLI3PFtW9/FfbeHieZ+kyWK5H7CA==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] - '@tauri-apps/cli-win32-x64-msvc@2.10.0': - resolution: {integrity: sha512-NTpyQxkpzGmU6ceWBTY2xRIEaS0ZLbVx1HE1zTA3TY/pV3+cPoPPOs+7YScr4IMzXMtOw7tLw5LEXo5oIG3qaQ==} + '@tauri-apps/cli-win32-x64-msvc@2.11.4': + resolution: {integrity: sha512-+vDiqBIU5dMISg/wNvX3sF+ZHfgJGJ5T0AcO+EHNXV9GGAG+P5fzodlDXD3QdKCRgZxMoCm5PPvj3BqLNjBthw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@tauri-apps/cli@2.10.0': - resolution: {integrity: sha512-ZwT0T+7bw4+DPCSWzmviwq5XbXlM0cNoleDKOYPFYqcZqeKY31KlpoMW/MOON/tOFBPgi31a2v3w9gliqwL2+Q==} + '@tauri-apps/cli@2.11.4': + resolution: {integrity: sha512-R8xGtMpwyetawSqm9kYOuMmEqkhUbvcUy8n0aNXIxollKBLESUu5f4Fx+64hgASYm1H+jSWq6jCW6zqTnH6hqQ==} engines: {node: '>= 10'} hasBin: true @@ -2505,52 +2505,52 @@ snapshots: '@tauri-apps/api@2.10.1': {} - '@tauri-apps/cli-darwin-arm64@2.10.0': + '@tauri-apps/cli-darwin-arm64@2.11.4': optional: true - '@tauri-apps/cli-darwin-x64@2.10.0': + '@tauri-apps/cli-darwin-x64@2.11.4': optional: true - '@tauri-apps/cli-linux-arm-gnueabihf@2.10.0': + '@tauri-apps/cli-linux-arm-gnueabihf@2.11.4': optional: true - '@tauri-apps/cli-linux-arm64-gnu@2.10.0': + '@tauri-apps/cli-linux-arm64-gnu@2.11.4': optional: true - '@tauri-apps/cli-linux-arm64-musl@2.10.0': + '@tauri-apps/cli-linux-arm64-musl@2.11.4': optional: true - '@tauri-apps/cli-linux-riscv64-gnu@2.10.0': + '@tauri-apps/cli-linux-riscv64-gnu@2.11.4': optional: true - '@tauri-apps/cli-linux-x64-gnu@2.10.0': + '@tauri-apps/cli-linux-x64-gnu@2.11.4': optional: true - '@tauri-apps/cli-linux-x64-musl@2.10.0': + '@tauri-apps/cli-linux-x64-musl@2.11.4': optional: true - '@tauri-apps/cli-win32-arm64-msvc@2.10.0': + '@tauri-apps/cli-win32-arm64-msvc@2.11.4': optional: true - '@tauri-apps/cli-win32-ia32-msvc@2.10.0': + '@tauri-apps/cli-win32-ia32-msvc@2.11.4': optional: true - '@tauri-apps/cli-win32-x64-msvc@2.10.0': + '@tauri-apps/cli-win32-x64-msvc@2.11.4': optional: true - '@tauri-apps/cli@2.10.0': + '@tauri-apps/cli@2.11.4': optionalDependencies: - '@tauri-apps/cli-darwin-arm64': 2.10.0 - '@tauri-apps/cli-darwin-x64': 2.10.0 - '@tauri-apps/cli-linux-arm-gnueabihf': 2.10.0 - '@tauri-apps/cli-linux-arm64-gnu': 2.10.0 - '@tauri-apps/cli-linux-arm64-musl': 2.10.0 - '@tauri-apps/cli-linux-riscv64-gnu': 2.10.0 - '@tauri-apps/cli-linux-x64-gnu': 2.10.0 - '@tauri-apps/cli-linux-x64-musl': 2.10.0 - '@tauri-apps/cli-win32-arm64-msvc': 2.10.0 - '@tauri-apps/cli-win32-ia32-msvc': 2.10.0 - '@tauri-apps/cli-win32-x64-msvc': 2.10.0 + '@tauri-apps/cli-darwin-arm64': 2.11.4 + '@tauri-apps/cli-darwin-x64': 2.11.4 + '@tauri-apps/cli-linux-arm-gnueabihf': 2.11.4 + '@tauri-apps/cli-linux-arm64-gnu': 2.11.4 + '@tauri-apps/cli-linux-arm64-musl': 2.11.4 + '@tauri-apps/cli-linux-riscv64-gnu': 2.11.4 + '@tauri-apps/cli-linux-x64-gnu': 2.11.4 + '@tauri-apps/cli-linux-x64-musl': 2.11.4 + '@tauri-apps/cli-win32-arm64-msvc': 2.11.4 + '@tauri-apps/cli-win32-ia32-msvc': 2.11.4 + '@tauri-apps/cli-win32-x64-msvc': 2.11.4 '@tauri-apps/plugin-clipboard-manager@2.3.2': dependencies: diff --git a/scripts/linux/appimage.sh b/scripts/linux/appimage.sh new file mode 100755 index 00000000..a2e998e9 --- /dev/null +++ b/scripts/linux/appimage.sh @@ -0,0 +1,30 @@ +#! /usr/bin/env bash +# +# Builds the Linux AppImage with our patched linuxdeploy-plugin-gtk. +# +# The Tauri bundler downloads linuxdeploy-plugin-gtk.sh once and never +# re-checks it, so dropping our copy where it looks pins that copy for every +# later build. We therefore turn on `bundle.useLocalToolsDir`, which moves the +# bundler's tool cache from the shared ~/.cache/tauri into this project's cargo +# target directory. Nothing outside the repo is touched, and `cargo clean` +# undoes it. + +set -e + +cd "$(dirname "$0")/../.." + +target_dir=$(cargo metadata --no-deps --format-version 1 \ + --manifest-path src-tauri/Cargo.toml | + node -e 'let s="";process.stdin.on("data",c=>s+=c).on("end",()=>console.log(JSON.parse(s).target_directory))') + +tools_dir="$target_dir/.tauri" +mkdir -p "$tools_dir" +cp scripts/linux/linuxdeploy-plugin-gtk.sh "$tools_dir/" +chmod +x "$tools_dir/linuxdeploy-plugin-gtk.sh" +echo "Using patched linuxdeploy-plugin-gtk.sh from $tools_dir" +echo "Tool cache is project-local (target/.tauri/); 'cargo clean' removes it." + +# NO_STRIP: linuxdeploy's strip step fails on the .relr.dyn sections newer +# linkers emit. createUpdaterArtifacts: a local build has no signing key. +exec env NO_STRIP=1 node_modules/.bin/tauri build --bundles appimage \ + --config '{"bundle":{"useLocalToolsDir":true,"createUpdaterArtifacts":false}}' "$@" diff --git a/scripts/linux/linuxdeploy-plugin-gtk.sh b/scripts/linux/linuxdeploy-plugin-gtk.sh new file mode 100755 index 00000000..4a3f6fe2 --- /dev/null +++ b/scripts/linux/linuxdeploy-plugin-gtk.sh @@ -0,0 +1,369 @@ +#! /usr/bin/env bash + +# Vendored copy of linuxdeploy-plugin-gtk, patched for OmniGet. +# +# Source: https://github.com/tauri-apps/linuxdeploy-plugin-gtk +# (a fork of https://github.com/linuxdeploy/linuxdeploy-plugin-gtk) +# Copied at: commit b5eb8d05b4c0ed40107fe2158c5d8527f94568ef (2024-01-04) +# This is the exact URL the Tauri bundler fetches at +# tauri-bundler/src/bundle/linux/appimage/linuxdeploy.rs. +# +# License: MIT. Copyright 2018-2019 TheAssassin and the linuxdeploy +# contributors. Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the Software +# without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: the above copyright notice and this permission notice +# shall be included in all copies or substantial portions of the +# Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +# ANY KIND, EXPRESS OR IMPLIED. See LICENSE.txt in the upstream +# repository for the full text. +# +# Local modifications (everything else is byte-identical to upstream): +# 1. copy_tree() skips sources that do not exist instead of aborting the +# build. Arch ships builtin gdk-pixbuf loaders, so the pkg-config paths +# upstream trusts can point at files that are not there. +# 2. The gdk-pixbuf loaders.cache directory is created before the cache is +# written, so the query tool has somewhere to write to. +# 3. The `sed -i` on loaders.cache moved inside the `-f` guard. Upstream ran +# it unconditionally, so a missing cache tripped `set -e` right after +# warning that it was only a warning. +# +# Re-syncing: diff this file against the upstream URL above, re-apply the three +# hunks, and update the commit and date recorded here. + +# GTK3 environment variables: https://developer.gnome.org/gtk3/stable/gtk-running.html +# GTK4 environment variables: https://developer.gnome.org/gtk4/stable/gtk-running.html + +# abort on all errors +set -e + +if [ "$DEBUG" != "" ]; then + set -x + verbose="--verbose" +fi + +script=$(readlink -f "$0") + +show_usage() { + echo "Usage: $script --appdir " + echo + echo "Bundles resources for applications that use GTK into an AppDir" + echo + echo "Required variables:" + echo " LINUXDEPLOY=\".../linuxdeploy\" path to linuxdeploy (e.g., AppImage); set automatically when plugin is run directly by linuxdeploy" + #echo + #echo "Optional variables:" + #echo " DEPLOY_GTK_VERSION (major version of GTK to deploy, e.g. '2', '3' or '4'; auto-detect by default)" +} + +variable_is_true() { + local var="$1" + + if [ -n "$var" ] && { [ "$var" == "true" ] || [ "$var" -gt 0 ]; } 2> /dev/null; then + return 0 # true + else + return 1 # false + fi +} + +get_pkgconf_variable() { + local variable="$1" + local library="$2" + local default_path="$3" + + path="$("$PKG_CONFIG" --variable="$variable" "$library")" + if [ -n "$path" ]; then + echo "$path" + elif [ -n "$default_path" ]; then + echo "$default_path" + else + echo "$0: there is no '$variable' variable for '$library' library." > /dev/stderr + echo "Please check the '$library.pc' file is present in \$PKG_CONFIG_PATH (you may need to install the appropriate -dev/-devel package)." > /dev/stderr + exit 1 + fi +} + +copy_tree() { + local src=("${@:1:$#-1}") + local dst="${*:$#}" + + for elem in "${src[@]}"; do + # Some distros (e.g. Arch with builtin gdk-pixbuf loaders) ship stale + # pkg-config paths; skip missing sources instead of failing the build. + if [ ! -e "$elem" ]; then + echo "WARNING: copy_tree: '$elem' does not exist, skipping" + continue + fi + mkdir -p "${dst::-1}$elem" + cp "$elem" --archive --parents --target-directory="$dst" $verbose + done +} + +search_tool() { + local tool="$1" + local directory="$2" + + if command -v "$tool"; then + return 0 + fi + + PATH_ARRAY=( + "/usr/lib/$(uname -m)-linux-gnu/$directory/$tool" + "/usr/lib/$directory/$tool" + "/usr/bin/$tool" + "/usr/bin/$tool-64" + "/usr/bin/$tool-32" + ) + + for path in "${PATH_ARRAY[@]}"; do + if [ -x "$path" ]; then + echo "$path" + return 0 + fi + done +} + +#DEPLOY_GTK_VERSION="${DEPLOY_GTK_VERSION:-0}" # When not set by user, this variable use the integer '0' as a sentinel value +DEPLOY_GTK_VERSION=3 # Force GTK3 for tauri apps +APPDIR= + +while [ "$1" != "" ]; do + case "$1" in + --plugin-api-version) + echo "0" + exit 0 + ;; + --appdir) + APPDIR="$2" + shift + shift + ;; + --help) + show_usage + exit 0 + ;; + *) + echo "Invalid argument: $1" + echo + show_usage + exit 1 + ;; + esac +done + +if [ "$APPDIR" == "" ]; then + show_usage + exit 1 +fi + +mkdir -p "$APPDIR" +# make lib64 writable again. +chmod +w "$APPDIR"/usr/lib64 || true + +if command -v pkgconf > /dev/null; then + PKG_CONFIG="pkgconf" +elif command -v pkg-config > /dev/null; then + PKG_CONFIG="pkg-config" +else + echo "$0: pkg-config/pkgconf not found in PATH, aborting" + exit 1 +fi + +if ! command -v find &>/dev/null && ! type find &>/dev/null; then + echo -e "$0: find not found.\nInstall findutils then re-run the plugin." + exit 1 +fi + +if [ -z "$LINUXDEPLOY" ]; then + echo -e "$0: LINUXDEPLOY environment variable is not set.\nDownload a suitable linuxdeploy AppImage, set the environment variable and re-run the plugin." + exit 1 +fi + +gtk_versions=0 # Count major versions of GTK when auto-detect GTK version +if [ "$DEPLOY_GTK_VERSION" -eq 0 ]; then + echo "Determining which GTK version to deploy" + while IFS= read -r -d '' file; do + if [ "$DEPLOY_GTK_VERSION" -ne 2 ] && ldd "$file" | grep -q "libgtk-x11-2.0.so"; then + DEPLOY_GTK_VERSION=2 + gtk_versions="$((gtk_versions+1))" + fi + if [ "$DEPLOY_GTK_VERSION" -ne 3 ] && ldd "$file" | grep -q "libgtk-3.so"; then + DEPLOY_GTK_VERSION=3 + gtk_versions="$((gtk_versions+1))" + fi + if [ "$DEPLOY_GTK_VERSION" -ne 4 ] && ldd "$file" | grep -q "libgtk-4.so"; then + DEPLOY_GTK_VERSION=4 + gtk_versions="$((gtk_versions+1))" + fi + done < <(find "$APPDIR/usr/bin" -executable -type f -print0) +fi + +if [ "$gtk_versions" -gt 1 ]; then + echo "$0: can not deploy multiple GTK versions at the same time." + echo "Please set DEPLOY_GTK_VERSION to {2, 3, 4}." + exit 1 +elif [ "$DEPLOY_GTK_VERSION" -eq 0 ]; then + echo "$0: failed to auto-detect GTK version." + echo "Please set DEPLOY_GTK_VERSION to {2, 3, 4}." + exit 1 +fi + +echo "Installing AppRun hook" +HOOKSDIR="$APPDIR/apprun-hooks" +HOOKFILE="$HOOKSDIR/linuxdeploy-plugin-gtk.sh" +mkdir -p "$HOOKSDIR" +cat > "$HOOKFILE" <<\EOF +#! /usr/bin/env bash + +gsettings get org.gnome.desktop.interface gtk-theme 2> /dev/null | grep -qi "dark" && GTK_THEME_VARIANT="dark" || GTK_THEME_VARIANT="light" +APPIMAGE_GTK_THEME="${APPIMAGE_GTK_THEME:-"Adwaita:$GTK_THEME_VARIANT"}" # Allow user to override theme (discouraged) + +export APPDIR="${APPDIR:-"$(dirname "$(realpath "$0")")"}" # Workaround to run extracted AppImage +export GTK_DATA_PREFIX="$APPDIR" +export GTK_THEME="$APPIMAGE_GTK_THEME" # Custom themes are broken +export GDK_BACKEND=x11 # Crash with Wayland backend on Wayland - We tested it without it and ended up with this: https://github.com/tauri-apps/tauri/issues/8541 +export XDG_DATA_DIRS="$APPDIR/usr/share:/usr/share:$XDG_DATA_DIRS" # g_get_system_data_dirs() from GLib +EOF + +echo "Installing GLib schemas" +# Note: schemasdir is undefined on Ubuntu 16.04 +glib_schemasdir="$(get_pkgconf_variable "schemasdir" "gio-2.0" "/usr/share/glib-2.0/schemas")" +copy_tree "$glib_schemasdir" "$APPDIR/" +glib-compile-schemas "$APPDIR/$glib_schemasdir" +cat >> "$HOOKFILE" <> "$HOOKFILE" < "$APPDIR/$gtk3_immodules_cache_file" + else + echo "WARNING: gtk-query-immodules-3.0 not found" + fi + if [ ! -f "$APPDIR/$gtk3_immodules_cache_file" ]; then + echo "WARNING: immodules.cache file is missing" + fi + sed -i "s|$gtk3_libdir/3.0.0/immodules/||g" "$APPDIR/$gtk3_immodules_cache_file" + ;; + 4) + echo "Installing GTK 4.0 modules" + gtk4_exec_prefix="$(get_pkgconf_variable "exec_prefix" "gtk4" "/usr")" + gtk4_libdir="$(get_pkgconf_variable "libdir" "gtk4")/gtk-4.0" + gtk4_path="$gtk4_libdir/modules" + copy_tree "$gtk4_libdir" "$APPDIR/" + cat >> "$HOOKFILE" <> "$HOOKFILE" < "$APPDIR/$gdk_pixbuf_cache_file" +else + echo "WARNING: gdk-pixbuf-query-loaders not found" +fi +if [ -f "$APPDIR/$gdk_pixbuf_cache_file" ]; then + sed -i "s|$gdk_pixbuf_moduledir/||g" "$APPDIR/$gdk_pixbuf_cache_file" +else + echo "WARNING: loaders.cache file is missing" +fi + +echo "Copying more libraries" +gobject_libdir="$(get_pkgconf_variable "libdir" "gobject-2.0")" +gio_libdir="$(get_pkgconf_variable "libdir" "gio-2.0")" +librsvg_libdir="$(get_pkgconf_variable "libdir" "librsvg-2.0")" +pango_libdir="$(get_pkgconf_variable "libdir" "pango")" +pangocairo_libdir="$(get_pkgconf_variable "libdir" "pangocairo")" +pangoft2_libdir="$(get_pkgconf_variable "libdir" "pangoft2")" +FIND_ARRAY=( + "$gdk_libdir" "libgdk_pixbuf-*.so*" + "$gobject_libdir" "libgobject-*.so*" + "$gio_libdir" "libgio-*.so*" + "$librsvg_libdir" "librsvg-*.so*" + "$pango_libdir" "libpango-*.so*" + "$pangocairo_libdir" "libpangocairo-*.so*" + "$pangoft2_libdir" "libpangoft2-*.so*" +) +LIBRARIES=() +for (( i=0; i<${#FIND_ARRAY[@]}; i+=2 )); do + directory=${FIND_ARRAY[i]} + library=${FIND_ARRAY[i+1]} + while IFS= read -r -d '' file; do + LIBRARIES+=( "--library=$file" ) + done < <(find "$directory" \( -type l -o -type f \) -name "$library" -print0) +done + +env LINUXDEPLOY_PLUGIN_MODE=1 "$LINUXDEPLOY" --appdir="$APPDIR" "${LIBRARIES[@]}" + +# Create symbolic links as a workaround +# Details: https://github.com/linuxdeploy/linuxdeploy-plugin-gtk/issues/24#issuecomment-1030026529 +echo "Manually setting rpath for GTK modules" +PATCH_ARRAY=( + "$gtk3_immodulesdir" + "$gtk3_printbackendsdir" + "$gdk_pixbuf_moduledir" +) +for directory in "${PATCH_ARRAY[@]}"; do + while IFS= read -r -d '' file; do + ln $verbose -s "${file/\/usr\/lib\//}" "$APPDIR/usr/lib" + done < <(find "$directory" -name '*.so' -print0) +done + +# set write permission on lib64 again to make it deletable. +chmod +w "$APPDIR"/usr/lib64 || true + +# We have to copy the files first to not get permission errors when we assign gio_extras_dir +find /usr/lib* -name libgiognutls.so -exec mkdir -p "$APPDIR"/"$(dirname '{}')" \; -exec cp --parents '{}' "$APPDIR/" \; || true +# related files that we seemingly don't need: +# libgiolibproxy.so - libgiognomeproxy.so - glib-pacrunner + +gio_extras_dir=$(find "$APPDIR"/usr/lib* -name libgiognutls.so -exec dirname '{}' \; 2>/dev/null) +cat >> "$HOOKFILE" <