From 556ddbd4f89e9cafcbc641d31e9c70576d60c6c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADtor=20Vasconcellos?= Date: Mon, 22 Jan 2024 07:52:26 -0300 Subject: [PATCH] Port AppImage build to use appimage-builder (#1785) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Initial port to appimage-builder * Almost * Fix appimage build on arm64 * Custom patch for external binaries run under appimage - Disable bubblewrap sandbox when running under appimage - Change cwd to APPDIR when running under appimage * AppImage Works (for the first lunch, then it crashes with Stack Smash 😭) * Fix stack smashing, now AppImage almos fully works \o/ (gstreamer is still broken) - Temporarily disable the volume watcher when running under appimage (Workaround for the stack smash error) - Wrap gnu lic version check for appimage under conditional compile for glibc targets - Add error handling for the justUpdatedCheck - Fix VITE_LANDING_ORIGIN being undefined * On non glibc systems default to runtime/compat * Use glibc version 2.8 instead of 0 for non-gnu systems * Fix video playback not working due to broken GstRegistry * Build and publish new AppImage release artifact - Fix model location when building deb - Improve model path resolution logic - Remove patchelf dependency from setup script - Fix incorrectly ignore gstreamer dependency in AppImage recipe * Fix clippy complaining about `get_path_relative_to_exe` - Read GLIBC_FAKE_VERSION or use 2.8 for musl in appimage (while the code is there, this is not really supported for now) * Remove appimage tauri target from release CI * Remove setup-buildx-action, not relly needed * typo fix * Fix git describe command running on cwd instead of the repo root dir * Attempt fix weird git permissions errors in CI+docker * Pass CI env to docker appimage * Only use git after installing it * Pass target to appimage build script * Fix permission after creating appimage * -_- * Swap envvar with github ci var * Format * Add instruction on how to manually build an AppImage * Fix typos * docs: add note about running podman with `--privileged` if there's a permission denied error * docs: fix typo and link directly to appimage-building `README.md` * refactor: streamline code and make it a bit cleaner --------- Co-authored-by: jake <77554505+brxken128@users.noreply.github.com> --- .github/workflows/release.yml | 14 ++- CONTRIBUTING.md | 6 +- apps/desktop/crates/linux/Cargo.toml | 3 +- apps/desktop/crates/linux/src/env.rs | 84 ++++++++++++- apps/desktop/src-tauri/tauri.conf.json | 2 +- apps/desktop/src/env.ts | 4 +- apps/desktop/src/updater.tsx | 16 ++- apps/landing/src/env.ts | 3 +- core/src/library/manager/mod.rs | 4 +- crates/ai/src/utils/mod.rs | 18 +-- scripts/appimage/.gitignore | 2 + scripts/appimage/AppImageBuilder.yml | 165 +++++++++++++++++++++++++ scripts/appimage/README.md | 30 +++++ scripts/appimage/build_appimage.sh | 92 ++++++++++++++ scripts/setup.sh | 8 +- 15 files changed, 420 insertions(+), 31 deletions(-) create mode 100644 scripts/appimage/.gitignore create mode 100644 scripts/appimage/AppImageBuilder.yml create mode 100644 scripts/appimage/README.md create mode 100755 scripts/appimage/build_appimage.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 880f06b4e..09cc78d98 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,14 +28,14 @@ jobs: # target: aarch64-pc-windows-msvc - host: ubuntu-20.04 target: x86_64-unknown-linux-gnu - bundles: deb,appimage + bundles: deb os: linux arch: x86_64 # - host: ubuntu-20.04 # target: x86_64-unknown-linux-musl # - host: ubuntu-20.04 # target: aarch64-unknown-linux-gnu - # bundles: deb # no appimage for now unfortunetly + # bundles: deb # - host: ubuntu-20.04 # target: aarch64-unknown-linux-musl name: Desktop - Main ${{ matrix.settings.target }} @@ -113,6 +113,16 @@ jobs: APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + - name: Build AppImage in Docker + if: ${{ runner.os == 'Linux' && ( matrix.settings.target == 'x86_64-unknown-linux-gnu' || matrix.settings.target == 'aarch64-unknown-linux-gnu' ) }} + run: | + set -euxo pipefail + docker run --rm -v $(pwd):/srv -e 'CI=true' -e 'TARGET=${{ matrix.settings.target }}' -w /srv debian:bookworm scripts/appimage/build_appimage.sh + cd 'target/${{ matrix.settings.target }}/release/bundle/appimage' + sudo chown "$(id -u):$(id -g)" -R . + tar -czf Updater.AppImage.tar.gz *.AppImage + pnpm tauri signer sign -k '${{ secrets.TAURI_PRIVATE_KEY }}' -p '${{ secrets.TAURI_KEY_PASSWORD }}' "$(pwd)/Updater.AppImage.tar.gz" + - name: Publish Artifacts uses: ./.github/actions/publish-artifacts with: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 51f9b76e2..03ab45ae6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -95,6 +95,10 @@ To run the mobile app: - `pnpm ios` (runs on iOS Emulator) - `pnpm start` (runs the metro bundler) +##### AppImage + +Specific instructions on how to build an AppImage release are located [here](scripts/appimage/README.md) + ### Pull Request Once you have finished making your changes, create a pull request (PR) to submit them. @@ -134,7 +138,7 @@ error: terminated(1): /us/bin/xcrun --sdk macos --show-sdk-platform-path output xcrun: error: unable to lookup item 'PlatformPath' from command line tools installation xcrun: error: unable to lookup item 'PlatformPath' in SDK '/Library/Developer /CommandLineTools/SDKs/MacOSX.sdk' ``` -Ensure that macOS is fully updated, and that you have XCode installed (via the app store). +Ensure that macOS is fully updated, and that you have Xcode installed (via the app store). Once that has completed, run `xcode-select --install` in the terminal to install the command line tools. If they are already installed, ensure that you update macOS to the latest version available. diff --git a/apps/desktop/crates/linux/Cargo.toml b/apps/desktop/crates/linux/Cargo.toml index 19a19cba1..d551fa03d 100644 --- a/apps/desktop/crates/linux/Cargo.toml +++ b/apps/desktop/crates/linux/Cargo.toml @@ -11,4 +11,5 @@ libc = "0.2" [target.'cfg(target_os = "linux")'.dependencies] # WARNING: gtk should follow the same version used by tauri -gtk = "=0.15" +# https://github.com/tauri-apps/tauri/blob/441eb4f4a5f9af206752c2e287975eb8d5ccfd01/core/tauri/Cargo.toml#L95 +gtk = { version = "0.15", features = [ "v3_20" ] } diff --git a/apps/desktop/crates/linux/src/env.rs b/apps/desktop/crates/linux/src/env.rs index d280877de..9f03592ff 100644 --- a/apps/desktop/crates/linux/src/env.rs +++ b/apps/desktop/crates/linux/src/env.rs @@ -2,12 +2,28 @@ use std::{ collections::HashSet, env, ffi::{CStr, OsStr, OsString}, - mem, + io, mem, os::unix::ffi::OsStrExt, path::{Path, PathBuf}, ptr, }; +fn version(version_str: &str) -> i32 { + let mut version_parts: Vec = version_str + .split('.') + .take(4) // Take up to 4 components + .map(|part| part.parse().unwrap_or(0)) + .collect(); + + // Pad with zeros if needed + version_parts.resize_with(4, Default::default); + + (version_parts[0] * 1_000_000_000) + + (version_parts[1] * 1_000_000) + + (version_parts[2] * 1_000) + + version_parts[3] +} + pub fn get_current_user_home() -> Option { use libc::{getpwuid_r, getuid, passwd, ERANGE}; @@ -175,6 +191,56 @@ pub fn normalize_environment() { ], ) .expect("PATH must be successfully normalized"); + + if let Ok(appdir) = get_appdir() { + println!("Running from APPIMAGE"); + + // Workaround for https://github.com/AppImageCrafters/appimage-builder/issues/175 + env::set_current_dir(appdir.join({ + let appimage_libc_version = version( + std::env::var("APPDIR_LIBC_VERSION") + .expect("AppImage Libc version must be set") + .as_str(), + ); + + let system_lic_version = version({ + #[cfg(target_env = "gnu")] + { + use libc::gnu_get_libc_version; + + let ptr = unsafe { gnu_get_libc_version() }; + if ptr.is_null() { + panic!("Couldn't read glic version"); + } + + unsafe { CStr::from_ptr(ptr) } + .to_str() + .expect("Couldn't read glic version") + } + #[cfg(not(target_env = "gnu"))] + { + // Use the same version as gcompat + // https://git.adelielinux.org/adelie/gcompat/-/blob/current/libgcompat/version.c + std::env::var("GLIBC_FAKE_VERSION").unwrap_or_else(|_| "2.8".to_string()) + } + }); + + if system_lic_version < appimage_libc_version { + "runtime/compat" + } else { + "runtime/default" + } + })) + .expect("Failed to set current directory to $APPDIR"); + + // Bubblewrap does not work from inside appimage + env::set_var("WEBKIT_FORCE_SANDBOX", "0"); + env::set_var("WEBKIT_DISABLE_SANDBOX_THIS_IS_DANGEROUS", "1"); + + // FIX-ME: This is required because appimage-builder generates a broken GstRegistry, which breaks video playback + env::remove_var("GST_REGISTRY"); + env::remove_var("GST_REGISTRY_UPDATE"); + } } pub(crate) fn remove_prefix_from_pathlist( @@ -205,13 +271,19 @@ pub fn is_snap() -> bool { false } +fn get_appdir() -> io::Result { + if let Some(appdir) = std::env::var_os("APPDIR").map(PathBuf::from) { + if appdir.is_absolute() && appdir.is_dir() { + return Ok(appdir); + } + } + + Err(io::Error::new(io::ErrorKind::NotFound, "AppDir not found")) +} + // Check if appimage by looking if APPDIR is set and is a valid directory pub fn is_appimage() -> bool { - if let Some(appdir) = std::env::var_os("APPDIR").map(PathBuf::from) { - appdir.is_absolute() && appdir.is_dir() - } else { - false - } + get_appdir().is_ok() } // Check if flatpak by looking if FLATPAK_ID is set and not empty and that the .flatpak-info file exists diff --git a/apps/desktop/src-tauri/tauri.conf.json b/apps/desktop/src-tauri/tauri.conf.json index 73b8cd9da..a137398de 100644 --- a/apps/desktop/src-tauri/tauri.conf.json +++ b/apps/desktop/src-tauri/tauri.conf.json @@ -28,7 +28,7 @@ "longDescription": "Cross-platform universal file explorer, powered by an open-source virtual distributed filesystem.", "deb": { "files": { - "/usr/share/models/yolov8s.onnx": "../../.deps/models/yolov8s.onnx" + "/usr/share/spacedrive/models/yolov8s.onnx": "../../.deps/models/yolov8s.onnx" }, "depends": ["libc6"] }, diff --git a/apps/desktop/src/env.ts b/apps/desktop/src/env.ts index e641fc7d8..e667deee7 100644 --- a/apps/desktop/src/env.ts +++ b/apps/desktop/src/env.ts @@ -6,5 +6,7 @@ export const env = createEnv({ client: { VITE_LANDING_ORIGIN: z.string().default('https://www.spacedrive.com') }, - runtimeEnv: import.meta.env + runtimeEnv: import.meta.env, + skipValidation: false, + emptyStringAsUndefined: true }); diff --git a/apps/desktop/src/updater.tsx b/apps/desktop/src/updater.tsx index 059df428d..c0a293e29 100644 --- a/apps/desktop/src/updater.tsx +++ b/apps/desktop/src/updater.tsx @@ -96,15 +96,23 @@ export function createUpdater() { if (lastVersion !== version) { localStorage.setItem(SD_VERSION_LOCALSTORAGE, version); + let tagline = null; - const { frontmatter } = await fetch( - `${import.meta.env.VITE_LANDING_ORIGIN}/api/releases/${version}` - ).then((r) => r.json()); + try { + const request = await fetch( + `${import.meta.env.VITE_LANDING_ORIGIN}/api/releases/${version}` + ); + const { frontmatter } = await request.json(); + tagline = frontmatter?.tagline; + } catch (error) { + console.warn('Failed to fetch release info'); + console.error(error); + } toast.success( { title: `Updated successfully, you're on version ${version}`, - body: frontmatter?.tagline + body: tagline }, { duration: 10 * 1000, diff --git a/apps/landing/src/env.ts b/apps/landing/src/env.ts index 497d96104..a4852b1f0 100644 --- a/apps/landing/src/env.ts +++ b/apps/landing/src/env.ts @@ -41,5 +41,6 @@ export const env = createEnv({ }, // In dev or in eslint disable checking. // Kinda sucks for in dev but you don't need the whole setup to change the docs. - skipValidation: process.env.VERCEL !== '1' + skipValidation: process.env.VERCEL !== '1', + emptyStringAsUndefined: true }); diff --git a/core/src/library/manager/mod.rs b/core/src/library/manager/mod.rs index 09444b7e9..37d4713e8 100644 --- a/core/src/library/manager/mod.rs +++ b/core/src/library/manager/mod.rs @@ -133,8 +133,8 @@ impl Libraries { .load(library_id, &db_path, config_path, None, true, node) .await?; - // This is compleaty breaking on linux now, no ideia why, but it will be irrelevant in a short while - // So let's leave it disable for now + // FIX-ME: Linux releases crashes with *** stack smashing detected *** if spawn_volume_watcher is enabled + // No ideia why, but this will be irrelevant after the UDisk API is implemented, so let's leave it disabled for now #[cfg(not(target_os = "linux"))] { use crate::volume::watcher::spawn_volume_watcher; diff --git a/crates/ai/src/utils/mod.rs b/crates/ai/src/utils/mod.rs index 83b5c06d8..e21dfef70 100644 --- a/crates/ai/src/utils/mod.rs +++ b/crates/ai/src/utils/mod.rs @@ -14,12 +14,14 @@ pub(crate) fn get_path_relative_to_exe(path: impl AsRef) -> PathBuf { .into() }) .parent() - .and_then(|parent_path| { - parent_path - .join(path.as_ref()) - .canonicalize() - .map_err(|e| error!("{e:#?}")) - .ok() - }) - .unwrap_or_else(|| path.as_ref().to_path_buf()) + .map_or_else( + || path.as_ref().to_path_buf(), + |parent| { + let path = parent.join(path.as_ref()); + path.canonicalize().unwrap_or_else(|e| { + error!("Failed to canonilize relative path to exe, return raw path and hope: {e:#?}"); + path + }) + }, + ) } diff --git a/scripts/appimage/.gitignore b/scripts/appimage/.gitignore new file mode 100644 index 000000000..d195820f2 --- /dev/null +++ b/scripts/appimage/.gitignore @@ -0,0 +1,2 @@ +AppDir +appimage-build diff --git a/scripts/appimage/AppImageBuilder.yml b/scripts/appimage/AppImageBuilder.yml new file mode 100644 index 000000000..522e2b801 --- /dev/null +++ b/scripts/appimage/AppImageBuilder.yml @@ -0,0 +1,165 @@ +# Reference: +# https://appimage-builder.readthedocs.io/en/latest/reference/version_1.html + +version: 1 + +script: | + set -eu + # Clean up directories created by the recipe + rm "$TARGET_APPDIR" -rf || true + rm "$REPO_DIR" -rf || true + # Create a temporary Debian repository folder to put the generated Debian + # packages on, so we can install it like any other packages + mkdir -p "$REPO_DIR" + _deb="$(find "${TARGET_APPIMAGE_DIR}/../deb" -type f -name '*.deb' | sort -t '_' -k '2,2' -V | tail -n 1)" + cp -f "$_deb" "$REPO_DIR" + CWD="$PWD" && cd "$REPO_DIR" && apt-ftparchive packages . > Packages && cd "$CWD" + # The following two commands are a workaround for the local APT package not + # being saved to the archives directory, as expected by appimage-builder + mkdir -p appimage-build/apt/archives + cp -f "$_deb" appimage-build/apt/archives + +AppDir: + path: !ENV '${TARGET_APPDIR}' + + app_info: + id: com.spacedrive + name: Spacedrive + icon: spacedrive + version: !ENV '${VERSION}' + exec: usr/bin/spacedrive + exec_args: $@ + + apt: + arch: !ENV ${TARGET_APPIMAGE_APT_ARCH} + sources: + - sourceline: !ENV 'deb [arch=${TARGET_APPIMAGE_APT_ARCH}] http://deb.debian.org/debian bookworm main' + key_url: 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x1f89983e0081fde018f3cc9673a4f27b8dd47936' + - sourceline: !ENV 'deb [arch=${TARGET_APPIMAGE_APT_ARCH}] http://security.debian.org/debian-security bookworm-security main' + key_url: 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x1f89983e0081fde018f3cc9673a4f27b8dd47936' + - sourceline: !ENV 'deb [arch=${TARGET_APPIMAGE_APT_ARCH}] http://deb.debian.org/debian bookworm-updates main' + key_url: 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xac530d520f2f3269f5e98313a48449044aad5c5d' + - sourceline: !ENV 'deb [trusted=yes] file:${REPO_DIR}/ ./' + + include: + - spacedrive + - gstreamer1.0-plugins-good + - gstreamer1.0-plugins-ugly + - gstreamer1.0-packagekit + # This package is necessary to avoid this: https://github.com/AppImageCrafters/appimage-builder/pull/191 + - shared-mime-info + + exclude: + - systemd + - systemd-sysv + - util-linux + - util-linux-extra + - xkb-data + - fdisk + - dmsetup + - mount + - dbus-daemon + - perl-base + - readline-common + - libpam-modules + - avahi-daemon + - adwaita-icon-theme + - humanity-icon-theme + - sensible-utils + - dconf-service + - ubuntu-mono + - fonts-*-core + - bubblewrap + - gstreamer1.0-plugins-bad + - gstreamer1.0-libav + + files: + exclude: + # Development, localization, documentation and configuration files + - usr/include + - usr/share/bug + - usr/share/man + - usr/share/doc + - usr/share/doc-base + - usr/share/lintian + - usr/share/sounds + - usr/share/bash-completion + - usr/share/zsh + - usr/share/applications + - usr/share/pkgconfig + - usr/share/pam + - usr/share/pam-configs + - usr/share/polkit-1 + - usr/share/util-linux + - usr/share/initramfs-tools + - usr/share/locale + - usr/share/systemd + - usr/lib/systemd + - usr/lib/*-linux-gnu/systemd + - usr/lib/udev + - usr/lib/*.d + - usr/lib/kernel + - usr/lib/tmpfiles.d + # using our own ALSA can cause issues, and the API is pretty stable anyway + - usr/lib/*/libasound.so.* + # produced by library compilation + - usr/lib/*.a + # produced by library compilation + - usr/lib/cmake + # produced by library compilation + - usr/lib/pkgconfig + - etc + - var + # systemd, pam, lsb, modprobe.d, udev and misc daemon files + - lib/systemd + - lib/*-linux-gnu/security + - lib/udev + - lib/lsb + - lib/modprobe.d + # Unneeded utility programs and libraries + - usr/sbin + # Remove any binary but spacedrive + - usr/bin/[!s]* + - usr/bin/s[!p]* + - usr/bin/sp[!a]* + - usr/bin/spa[!c]* + - usr/bin/spac[!e]* + - sbin + - bin + + runtime: + path_mappings: + - !ENV '/usr/lib/${TARGET_APPIMAGE_ARCH}-linux-gnu/webkit2gtk-4.0/injected-bundle/libwebkit2gtkinjectedbundle.so:$APPDIR/usr/lib/${TARGET_APPIMAGE_ARCH}-linux-gnu/webkit2gtk-4.0/injected-bundle/libwebkit2gtkinjectedbundle.so' + + # Patch webkit2gtk so it works under appimage + after_bundle: | + set -eux + + # libwebkit2gtk Patch for WebKit binaries + mv "${TARGET_APPDIR}/usr/lib/${TARGET_APPIMAGE_ARCH}-linux-gnu/webkit2gtk-4.0/WebKitWebProcess" "${TARGET_APPDIR}/usr/bin/WebKitWebProcess" + mv "${TARGET_APPDIR}/usr/lib/${TARGET_APPIMAGE_ARCH}-linux-gnu/webkit2gtk-4.0/WebKitNetworkProcess" "${TARGET_APPDIR}/usr/bin/WebKitNetworkProcess" + if [ "$TARGET_APPIMAGE_ARCH" == 'aarch64' ]; then + find "${TARGET_APPDIR}/usr/lib/aarch64-linux-gnu" -type f -name 'libwebkit2gtk-4.0.so*' -exec sed -i -e "s|/usr/lib/aarch64-linux-gnu/webkit2gtk-4.0\([^/][^i][^n]\)|../../././././././././././././././usr/bin\1|g" '{}' \; + else + find "${TARGET_APPDIR}/usr/lib/x86_64-linux-gnu" -type f -name 'libwebkit2gtk-4.0.so*' -exec sed -i -e "s|/usr/lib/x86_64-linux-gnu/webkit2gtk-4.0\([^/][^i][^n]\)|../.././././././././././././././usr/bin/\1|g" '{}' \; + fi + + # libwebkit2gtk Patch for gstreamer binaries + mv "${TARGET_APPDIR}/usr/libexec/pk-gstreamer-install" "${TARGET_APPDIR}/usr/bin/pk-gstreamer-install" + ln -sf pk-gstreamer-install "${TARGET_APPDIR}/usr/bin/gst-install-plugins-helper" + mv "${TARGET_APPDIR}/usr/lib/${TARGET_APPIMAGE_ARCH}-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-ptp-helper" "${TARGET_APPDIR}/usr/bin/gst-ptp-helper" + mv "${TARGET_APPDIR}/usr/lib/${TARGET_APPIMAGE_ARCH}-linux-gnu/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner" "${TARGET_APPDIR}/usr/bin/gst-plugin-scanner" + find "${TARGET_APPDIR}/usr/lib/${TARGET_APPIMAGE_ARCH}-linux-gnu" -type f -name 'libwebkit2gtk-4.0.so*' -exec sed -i -e "s|/usr/libexec/gstreamer-1.0|../../././././././usr/bin/|g" '{}' \; + + after_runtime: | + set -eux + + find "$TARGET_APPDIR" -type d -empty -delete + + # Tests don't work due to Tauri security checks we can't work around: + # https://github.com/tauri-apps/tauri/blob/35264b4c1801b381e0b867c1c35540f0fbb43365/core/tauri-utils/src/lib.rs#L202 + +AppImage: + arch: !ENV '${TARGET_APPIMAGE_ARCH}' + sign-key: None + update-information: None diff --git a/scripts/appimage/README.md b/scripts/appimage/README.md new file mode 100644 index 000000000..a8484b4ba --- /dev/null +++ b/scripts/appimage/README.md @@ -0,0 +1,30 @@ +# AppImage build script and files + +This directory contains the script and recipe to build an AppImage from a Spacedrive `.deb` using [appimage-builder](https://appimage-builder.readthedocs.io/en/latest/index.html). + +## Instructions (Requires a Linux environment) + +- Install one of the following container runtimes: + + - [Podman](https://podman.io/docs/installation#installing-on-linux) + + - [Docker](https://docs.docker.com/engine/install/#supported-platforms) + +- Set up your development environment following the steps in the [CONTRIBUTING](../../CONTRIBUTING.md) guide + +- Build a production release of Spacedrive by invoking `pnpm tauri` in a terminal window inside the Spacedrive repository root + + > After the build finishes you should end up with a `.deb` archive in `target/release/bundle/deb` + +- Change your current work directory to `scripts/appimage` + +- Execute the `build_appimage.sh` script inside a `debian:bookworm` container + + - Podman: `podman run --rm -v "$(CDPATH='' cd ../.. && pwd -P):/srv" -w /srv debian:bookworm scripts/appimage/build_appimage.sh` + - You may have to run Podman with `podman run --privileged` if you get a permission denied error + + - Docker: `docker run --rm -v "$(CDPATH='' cd ../.. && pwd -P):/srv" -w /srv debian:bookworm scripts/appimage/build_appimage.sh` + + > If you are running a system with selinux enforcing you will need mount the `/srv` volume with the `Z` flag to avoid `Permission denied` errors. [more info](https://docs.podman.io/en/latest/markdown/podman-run.1.html#volume-v-source-volume-host-dir-container-dir-options) + + > After the script finishes you should end up with an `.AppImage` executable in `target/release/bundle/appimage` diff --git a/scripts/appimage/build_appimage.sh b/scripts/appimage/build_appimage.sh new file mode 100755 index 000000000..aaf2309c1 --- /dev/null +++ b/scripts/appimage/build_appimage.sh @@ -0,0 +1,92 @@ +#!/usr/bin/env bash + +# Creates an AppImage with the specified Rust package binary and its dependencies. +# AppImage is an universal Linux application distribution format, similar +# to macOS bundles, which packs an application and its dependencies to +# allow running it across a wide variety of distros with no system changes +# and little user hassle. +# +# Relevant documentation: +# https://docs.appimage.org/packaging-guide/index.html +# https://appimage-builder.readthedocs.io/en/latest/index.html + +set -eEuo pipefail + +if [ "${CI:-}" = "true" ]; then + set -x +fi + +_root="$(CDPATH='' cd "$(dirname -- "$0")" && pwd -P)" +readonly _root + +# The appimage-builder recipe to use to generate the AppImage. +readonly RECIPE="${_root}/AppImageBuilder.yml" + +# The directory where the generated AppImage bundles will be stored. +readonly TARGET_APPIMAGE_DIR="${_root}/../../target/${TARGET:-.}/release/bundle/appimage" +export TARGET_APPIMAGE_DIR + +alias wget='wget -nc -nv --show-progress -P "$APPIMAGE_WORKDIR"' + +# Create a temporary working directory for this AppImage script +APPIMAGE_WORKDIR=$(mktemp -d -t spacedrive-appimagebuild.XXX) +readonly APPIMAGE_WORKDIR +trap '{ rm -rf "$APPIMAGE_WORKDIR" || true; } && { rm -rf appimage-build AppDir || true; }' EXIT INT TERM + +# Install required system dependencies +echo 'Installind required system dependencies...' +apt-get update && apt-get install -yq \ + git \ + zsync \ + dpkg-dev \ + apt-utils \ + libffi-dev \ + squashfs-tools \ + libglib2.0-bin \ + gstreamer1.0-tools \ + libgdk-pixbuf2.0-bin \ + gtk-update-icon-cache + +if [ "${CI:-}" = "true" ]; then + git config --global --add safe.directory '*' +fi + +# gdk-pixbuf-query-loaders is not in PATH by default +ln -fs /usr/lib/x86_64-linux-gnu/gdk-pixbuf-2.0/gdk-pixbuf-query-loaders /usr/local/bin/gdk-pixbuf-query-loaders + +export TARGET_APPIMAGE_ARCH="${TARGET_APPIMAGE_ARCH:-$(uname -m)}" + +if ! command -v appimage-builder >/dev/null 2>&1; then + apt-get install -yq python3 python3-dev python3-venv + + # Set up a virtual environment so that we do not pollute the global Python + # packages list with the packages we need to install + echo 'Setting up temporary Python virtual environment...' + python3 -m venv "$APPIMAGE_WORKDIR/.venv" + . "$APPIMAGE_WORKDIR/.venv/bin/activate" + + export MAKEFLAGS="-j$(nproc)" + + pip3 install wheel setuptools --upgrade + + echo 'Install appimage-build in temporary Python virtual environment...' + pip3 install git+https://github.com/AppImageCrafters/appimage-builder.git +fi + +echo 'Running appimage-builder...' +export TARGET_APPIMAGE_APT_ARCH="${TARGET_APPIMAGE_APT_ARCH:-$(dpkg-architecture -q DEB_HOST_ARCH)}" +export TARGET_APPDIR="${APPIMAGE_WORKDIR}/AppDir" +export REPO_DIR="$APPIMAGE_WORKDIR/pkgs" + +XDG_DATA_DIRS="$(pwd)/AppDir/usr/share:/usr/share:/usr/local/share:/var/lib/flatpak/exports/share" +export XDG_DATA_DIRS + +VERSION="$(CDPATH='' cd "${_root}/../.." && git describe --tags --dirty=-custom --always)" +export VERSION + +mkdir -p "$TARGET_APPIMAGE_DIR" + +appimage-builder --recipe "$RECIPE" --skip-test + +echo "> Moving generated AppImage to $TARGET_APPIMAGE_DIR" +mv -f ./*.AppImage* "$TARGET_APPIMAGE_DIR" diff --git a/scripts/setup.sh b/scripts/setup.sh index c42ddb65e..3c19b7f56 100755 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -136,7 +136,7 @@ case "$(uname)" in echo "Installing dependencies with apt..." # Tauri dependencies - set -- build-essential curl wget file patchelf openssl libssl-dev libgtk-3-dev librsvg2-dev \ + set -- build-essential curl wget file openssl libssl-dev libgtk-3-dev librsvg2-dev \ libwebkit2gtk-4.0-dev libayatana-appindicator3-dev # Webkit2gtk requires gstreamer plugins for video playback to work @@ -155,7 +155,7 @@ case "$(uname)" in echo "Installing dependencies with pacman..." # Tauri dependencies - set -- base-devel curl wget file patchelf openssl gtk3 librsvg webkit2gtk libayatana-appindicator + set -- base-devel curl wget file openssl gtk3 librsvg webkit2gtk libayatana-appindicator # Webkit2gtk requires gstreamer plugins for video playback to work set -- "$@" gst-plugins-base gst-plugins-good gst-plugins-ugly @@ -186,7 +186,7 @@ case "$(uname)" in fi # Tauri dependencies - set -- openssl openssl-dev curl wget file patchelf libappindicator-gtk3-devel librsvg2-devel + set -- openssl openssl-dev curl wget file libappindicator-gtk3-devel librsvg2-devel # Webkit2gtk requires gstreamer plugins for video playback to work set -- "$@" gstreamer1-devel gstreamer1-plugins-base-devel gstreamer1-plugins-good \ @@ -205,7 +205,7 @@ case "$(uname)" in echo "Alpine suport is experimental" >&2 # Tauri dependencies - set -- build-base curl wget file patchelf openssl-dev gtk+3.0-dev librsvg-dev \ + set -- build-base curl wget file openssl-dev gtk+3.0-dev librsvg-dev \ webkit2gtk-dev libayatana-indicator-dev # Webkit2gtk requires gstreamer plugins for video playback to work