diff --git a/.github/workflows/linux-app.yml b/.github/workflows/linux-app.yml index cb1b02c5..cb29748f 100644 --- a/.github/workflows/linux-app.yml +++ b/.github/workflows/linux-app.yml @@ -5,17 +5,17 @@ # converter's Linux binary) in activate-studio-linux-x86_64.tar.gz, with a # manifest and a SHA-256. See docs/LINUX-APP.md. # -# GUFI and tesseract are built from source in a Rocky Linux 9 container -# (glibc 2.34, the oldest target), so one payload runs on Ubuntu 22.04 and -# later and on RHEL 9 and later; build_app.sh then checks that no file in +# GUFI and tesseract are built from source in a Rocky Linux 8 container +# (glibc 2.28, the oldest target), so one payload runs on RHEL 8 and later +# and on Ubuntu 22.04 and later; build_app.sh then checks that no file in # the tree needs a newer glibc. The archive is unpacked in clean Ubuntu -# 22.04, Ubuntu 24.04 and Rocky Linux 9 containers and run there as a plain -# user: indexing, search, Query, search by meaning, OCR, document +# 22.04, Ubuntu 24.04, Rocky Linux 8 and 9 and AlmaLinux 8 and 9 containers +# and run there as a plain user: indexing, search, Query, search by meaning, OCR, document # conversion and the update check. # # The window shell (desktop/wails, Wails v2) is built for both WebKitGTK # APIs, the 4.1 one on Ubuntu 22.04 (which runs on Ubuntu 24.04 too) and the -# 4.0 one on Rocky Linux 9, and goes into the tree with the launcher and the +# 4.0 one on Rocky Linux 8, and goes into the tree with the launcher and the # install scripts (desktop/linux). From that tree come the per-user archive # and the .deb (4.1 shell) and .rpm (4.0 shell), built with nfpm. Each # install type is then installed in a clean container of each target @@ -54,11 +54,11 @@ concurrency: env: # Base images for the build and the tests. Tags, not digests: the point of # the test jobs is to run on what a person has today. - BUILD_IMAGE: rockylinux:9 + BUILD_IMAGE: rockylinux:8 jobs: # GUFI (with sqlite-vec and sqlite-lembed) and tesseract, built in a - # Rocky 9 container. They do not depend on each other, so they build side + # Rocky 8 container. They do not depend on each other, so they build side # by side. native: strategy: @@ -82,7 +82,7 @@ jobs: with: persist-credentials: false ref: ${{ inputs.release }} - - name: build ${{ matrix.component }} in Rocky Linux 9 + - name: build ${{ matrix.component }} in Rocky Linux 8 env: COMPONENT: ${{ matrix.component }} run: | @@ -112,7 +112,7 @@ jobs: - variant: wk41 image: ubuntu:22.04 - variant: wk40 - image: rockylinux:9 + image: rockylinux:8 runs-on: ubuntu-24.04 timeout-minutes: 30 permissions: @@ -225,15 +225,46 @@ jobs: extra_packages: "" - image: ubuntu:24.04 extra_packages: "" - # Docker's official rockylinux:9 image is an old point release - # (9.3); the other two are current 9.x releases of the two - # rebuilds the Linux app targets. + # Docker's official rockylinux images are old point releases + # (8.9 and 9.3); the others are current releases of the two + # rebuilds the Linux app targets. The Rocky 8 images leave out + # findutils, which these checks use and the Studio does not. + - image: rockylinux:8 + extra_packages: findutils + - image: rockylinux/rockylinux:8 + extra_packages: findutils + - image: almalinux:8 + extra_packages: "" - image: rockylinux:9 extra_packages: "" - image: rockylinux/rockylinux:9 extra_packages: "" - image: almalinux:9 extra_packages: "" + # The rest of the Linux world the archive runs on. The minimal + # images leave out the tools these checks use. + - image: redhat/ubi8 + extra_packages: findutils procps-ng util-linux shadow-utils + - image: redhat/ubi9 + extra_packages: findutils procps-ng util-linux shadow-utils + - image: oraclelinux:8 + extra_packages: findutils + - image: oraclelinux:9 + extra_packages: findutils + - image: quay.io/centos/centos:stream9 + extra_packages: findutils + - image: fedora:43 + extra_packages: findutils procps-ng util-linux shadow-utils + - image: amazonlinux:2023 + extra_packages: findutils procps-ng util-linux shadow-utils tar gzip + - image: ubuntu:20.04 + extra_packages: "" + - image: debian:11 + extra_packages: "" + - image: debian:12 + extra_packages: "" + - image: debian:13 + extra_packages: "" runs-on: ubuntu-24.04 timeout-minutes: 30 permissions: @@ -345,10 +376,18 @@ jobs: - {image: "ubuntu:22.04", kind: deb, webkit: "", shell: wk41} - {image: "ubuntu:24.04", kind: tarball, webkit: libwebkit2gtk-4.1-0, shell: wk41} - {image: "ubuntu:24.04", kind: deb, webkit: "", shell: wk41} + - {image: "rockylinux/rockylinux:8", kind: tarball, webkit: webkit2gtk3, shell: wk40} + - {image: "rockylinux/rockylinux:8", kind: rpm, webkit: "", shell: wk40} + - {image: "almalinux:8", kind: tarball, webkit: webkit2gtk3, shell: wk40} + - {image: "almalinux:8", kind: rpm, webkit: "", shell: wk40} - {image: "rockylinux/rockylinux:9", kind: tarball, webkit: webkit2gtk3, shell: wk40} - {image: "rockylinux/rockylinux:9", kind: rpm, webkit: "", shell: wk40} - {image: "almalinux:9", kind: tarball, webkit: webkit2gtk3, shell: wk40} - {image: "almalinux:9", kind: rpm, webkit: "", shell: wk40} + - {image: "oraclelinux:8", kind: tarball, webkit: webkit2gtk3, shell: wk40} + - {image: "oraclelinux:8", kind: rpm, webkit: "", shell: wk40} + - {image: "debian:12", kind: tarball, webkit: libwebkit2gtk-4.1-0, shell: wk41} + - {image: "debian:12", kind: deb, webkit: "", shell: wk41} runs-on: ubuntu-24.04 timeout-minutes: 40 permissions: @@ -465,7 +504,7 @@ jobs: --title "ACTIVATE Studio for Linux" --notes "The newest Linux app." fi gh release upload linux -R "$GITHUB_REPOSITORY" --clobber "${files[@]}" - gh release edit linux -R "$GITHUB_REPOSITORY" --notes "ACTIVATE Studio $TAG for Linux, x86_64, glibc 2.34 or later (Ubuntu 22.04, RHEL 9 and later). + gh release edit linux -R "$GITHUB_REPOSITORY" --notes "ACTIVATE Studio $TAG for Linux, x86_64, glibc 2.28 or later (RHEL 8, Ubuntu 22.04 and later). A copy installed in a user's home folder updates itself from the release for its version. A copy installed from a .deb or .rpm package is updated through apt or dnf. diff --git a/README.md b/README.md index d6d30142..ab7e768e 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ A web workspace over a folder of documents. It indexes the folder, including the **On a Mac (Apple silicon, macOS 14 or later):** `curl -fsSL https://github.com/parallelworks/activate-studio/releases/download/macos/install.sh | bash` installs the ACTIVATE Studio app in `~/Applications`, which runs the Studio on your own folder with nothing else to install and no administrator rights, including on a managed Mac that does not allow LaunchAgents. The disk image on the [macOS release](https://github.com/parallelworks/activate-studio/releases/tag/macos) page does the same: double-click the app in it and choose Install. To remove it, choose **Uninstall ACTIVATE Studio…** in the app menu: it lists what it removes (the app, and by default its indexes, settings and logs) and never your documents. See [`docs/MACOS.md`](docs/MACOS.md). -**On Linux (x86_64, glibc 2.34 or newer):** a per-user install with no administrator rights (`activate-studio/install.sh` from the unpacked archive) or an administrator's `.deb` (Ubuntu, Debian) or `.rpm` (RHEL 9, Rocky, Alma) puts the same Studio in its own window, where WebKitGTK is installed, and in your browser where it is not. See [`docs/LINUX-APP.md`](docs/LINUX-APP.md). Test builds only for now. +**On Linux (x86_64, glibc 2.28 or newer, so RHEL 8 and 9 and their rebuilds, Ubuntu 20.04 and later, Debian 11 and later):** a per-user install with no administrator rights (`activate-studio/install.sh` from the unpacked archive) or an administrator's `.deb` (Ubuntu, Debian) or `.rpm` (RHEL, Rocky, Alma) puts the same Studio in its own window, where WebKitGTK is installed, and in your browser where it is not. See [`docs/LINUX-APP.md`](docs/LINUX-APP.md). **On Windows:** the Studio runs in WSL2 (Windows Subsystem for Linux) and opens in a Windows browser, or a browser can open a Studio that runs on a Linux machine. There is no native Windows build. See [`docs/WINDOWS.md`](docs/WINDOWS.md). diff --git a/deploy/common/lib.sh b/deploy/common/lib.sh index 24457cab..03a51929 100644 --- a/deploy/common/lib.sh +++ b/deploy/common/lib.sh @@ -23,6 +23,20 @@ fetch() { [ "$got" = "$sum" ] || die "$file has SHA-256 $got, expected $sum" } +# el8_tools: on RHEL 8 and its rebuilds, a compiler and a Python new enough +# for GUFI and tesseract, which GCC 8 and Python 3.6 are not, first on the +# PATH. gcc-toolset's GCC links what it adds to the C++ runtime statically, so +# the binaries still need only the system's libstdc++. Does nothing elsewhere. +el8_tools() { + [ "$(rpm -E '%{?rhel}' 2>/dev/null)" = 8 ] || return 0 + dnf install -y -q --setopt=install_weak_deps=False gcc-toolset-13-gcc-c++ gcc-toolset-13-binutils python3.11 >/dev/null + set +u + # shellcheck disable=SC1091 # a file of the package just installed + . /opt/rh/gcc-toolset-13/enable + set -u + ln -sf /usr/bin/python3.11 /usr/local/bin/python3 +} + # gcc_licenses DIR PREFIX: the GPL 3 and the GCC Runtime Library Exception # into DIR, as PREFIX-COPYING3.txt and PREFIX-COPYING.RUNTIME.txt (needs # CACHE_DIR and the pins). diff --git a/deploy/linux/build_app.sh b/deploy/linux/build_app.sh index bb6275ff..6b8869ac 100755 --- a/deploy/linux/build_app.sh +++ b/deploy/linux/build_app.sh @@ -12,9 +12,9 @@ # a standalone Python for the indexer (with pypdf, xlrd and olefile for # documents, and onnxruntime, tokenizers and numpy for the ONNX embedding # model), and the embedding models. Build GUFI and tesseract in a Rocky -# Linux 9 container (glibc 2.34) so the tree runs on Ubuntu 22.04 and later -# and on RHEL 9 and later: this script checks that no file in the tree -# needs a newer glibc (elf_check.py). +# Linux 8 container (glibc 2.28) so the tree runs on RHEL 8 and later and on +# Ubuntu 22.04 and later: this script checks that no file in the tree needs +# a newer glibc (elf_check.py). # # Usage: deploy/linux/build_app.sh # OUT_DIR where the outputs go (default deploy/linux/out) @@ -51,11 +51,11 @@ TOP=activate-studio # What only this platform pins (the rest is deploy/common/pins.sh). NODE_SHA256=cb5c9ce9c80d7b8821e3a258543c71b939138cf17c74d5cc44bbe85d6dbc5ad8 PY_SHA256=178d3d83b6e8e99285a65d3fce9c16b87952cc5efdb4d1a0e3ff3be18ff0fc9c -# The oldest targets' libraries: RHEL 9's glibc, and the libstdc++ GCC 11 +# The oldest targets' libraries: RHEL 8's glibc, and the libstdc++ GCC 8 # ships there. -MAX_GLIBC=2.34 -MAX_GLIBCXX=3.4.29 -MAX_CXXABI=1.3.13 +MAX_GLIBC=2.28 +MAX_GLIBCXX=3.4.25 +MAX_CXXABI=1.3.11 [ "$(uname -s)" = Linux ] && [ "$(uname -m)" = x86_64 ] || die "builds on Linux x86_64" for tool in python3 curl tar git pnpm patchelf; do diff --git a/deploy/linux/build_gufi.sh b/deploy/linux/build_gufi.sh index 726ad7e0..45080e25 100755 --- a/deploy/linux/build_gufi.sh +++ b/deploy/linux/build_gufi.sh @@ -10,8 +10,8 @@ # elf_check.py: it needs no glibc newer than --max-glibc, and every library # it loads is in the tree or one every desktop has. # -# Build it in the oldest glibc the app supports, a Rocky Linux 9 container -# (glibc 2.34), so one tree runs on Ubuntu 22.04 and later and on RHEL 9 and +# Build it in the oldest glibc the app supports, a Rocky Linux 8 container +# (glibc 2.28), so one tree runs on RHEL 8 and later and on Ubuntu 22.04 and # later. The build installs its tools with dnf when it finds one and runs as # root (SKIP_DEPS=1 to skip that). # @@ -56,6 +56,7 @@ if [ "${SKIP_DEPS:-}" != 1 ] && [ "$(id -u)" = 0 ] && command -v dnf >/dev/null util-linux attr libattr-devel diffutils patch gawk which file findutils \ autoconf automake libtool binutils zlib-devel libgomp libatomic epel-release >/dev/null dnf install -y -q patchelf >/dev/null + el8_tools fi for tool in gcc g++ cmake make git curl tar patchelf python3 column setfattr readelf; do command -v "$tool" >/dev/null 2>&1 || die "$tool is required" diff --git a/deploy/linux/build_ocr.sh b/deploy/linux/build_ocr.sh index 9da95a02..4fe01e13 100755 --- a/deploy/linux/build_ocr.sh +++ b/deploy/linux/build_ocr.sh @@ -22,7 +22,7 @@ # tesseract finds its data through TESSDATA_PREFIX, which studio-run.sh sets # to share/tessdata here. # -# Build it in the oldest glibc the app supports, a Rocky Linux 9 container +# Build it in the oldest glibc the app supports, a Rocky Linux 8 container # (see build_gufi.sh), which installs the tools with dnf when run as root # (SKIP_DEPS=1 to skip that). # @@ -52,6 +52,7 @@ if [ "${SKIP_DEPS:-}" != 1 ] && [ "$(id -u)" = 0 ] && command -v dnf >/dev/null echo "Build tools from dnf..." dnf install -y -q --setopt=install_weak_deps=False \ gcc gcc-c++ make cmake ca-certificates tar xz python3 pkgconf-pkg-config zlib-devel file binutils >/dev/null + el8_tools fi for tool in gcc g++ cmake make curl tar python3 readelf; do command -v "$tool" >/dev/null 2>&1 || die "$tool is required" diff --git a/deploy/linux/check_app.sh b/deploy/linux/check_app.sh index bb2e45b1..6faac6f0 100755 --- a/deploy/linux/check_app.sh +++ b/deploy/linux/check_app.sh @@ -40,9 +40,9 @@ done G="$APP/gufi" O="$APP/ocr" PY="$APP/python/bin/python3" -MAX_GLIBC="${MAX_GLIBC:-2.34}" -MAX_GLIBCXX="${MAX_GLIBCXX:-3.4.29}" -MAX_CXXABI="${MAX_CXXABI:-1.3.13}" +MAX_GLIBC="${MAX_GLIBC:-2.28}" +MAX_GLIBCXX="${MAX_GLIBCXX:-3.4.25}" +MAX_CXXABI="${MAX_CXXABI:-1.3.11}" failures=0 ok() { echo " ok $1"; } bad() { echo " FAIL $1"; failures=$((failures + 1)); } @@ -117,7 +117,7 @@ PY # The window shells and installer (desktop/linux), when the tree has them: # a shell links to the computer's own GTK and WebKitGTK, so only its CPU and # the newest glibc it needs are checked (a 4.1 shell is built on Ubuntu - # 22.04, so glibc 2.35; the 4.0 shell on RHEL 9, glibc 2.34). + # 22.04, so glibc 2.35; the 4.0 shell on RHEL 8, glibc 2.28). if [ -d "$APP/bin" ]; then echo "Desktop" for f in bin/activate-studio bin/activate-studio-wk41 bin/activate-studio-wk40 install.sh uninstall.sh \ diff --git a/deploy/linux/elf_check.py b/deploy/linux/elf_check.py index d15db631..eb9e2f3e 100755 --- a/deploy/linux/elf_check.py +++ b/deploy/linux/elf_check.py @@ -11,12 +11,12 @@ - no RUNPATH or RPATH names a directory outside --root, where the build machine's own copy would be found on that machine and nowhere else; - the newest glibc symbol version it needs is at most --max-glibc (the - oldest target's, 2.34 for RHEL 9), and likewise --max-glibcxx and + oldest target's, 2.28 for RHEL 8), and likewise --max-glibcxx and --max-cxxabi for libstdc++'s versions. It prints the newest versions across all files, and exits 1 on a problem. -Usage: elf_check.py --root DIR [--max-glibc 2.34] [--max-glibcxx 3.4.29] - [--max-cxxabi 1.3.13] [--list] FILE|DIR... +Usage: elf_check.py --root DIR [--max-glibc 2.28] [--max-glibcxx 3.4.25] + [--max-cxxabi 1.3.11] [--list] FILE|DIR... A directory is searched for ELF files (symbolic links are not followed). """ import argparse diff --git a/deploy/linux/test_in_container.sh b/deploy/linux/test_in_container.sh index 5110aca3..2844df51 100755 --- a/deploy/linux/test_in_container.sh +++ b/deploy/linux/test_in_container.sh @@ -57,6 +57,8 @@ fi echo echo "Dependencies" echo " the system libraries the payload's ELF files need, and the package that provides each here:" +# Some images (Oracle Linux) ship without the linker cache. +[ -e /etc/ld.so.cache ] || ldconfig 2>/dev/null || true for lib in $(sed -n 's/^ *"\(lib[^"]*\|ld-linux[^"]*\)",\{0,1\}$/\1/p' "$APP/manifest.json"); do path="$(ldconfig -p | awk -v l="$lib" '$1 == l {print $NF; exit}')" if [ -z "$path" ]; then echo " $lib: NOT FOUND"; continue; fi diff --git a/desktop/linux/build_packages.sh b/desktop/linux/build_packages.sh index 191495dc..25699352 100755 --- a/desktop/linux/build_packages.sh +++ b/desktop/linux/build_packages.sh @@ -9,7 +9,7 @@ # and nothing outside it but the link, the entry and the icons. # # .deb the WebKitGTK 4.1 shell (Ubuntu 22.04 and later, Debian 12 and later) -# .rpm the WebKitGTK 4.0 shell (RHEL 9 and its rebuilds) +# .rpm the WebKitGTK 4.0 shell (RHEL 8 and 9 and their rebuilds) # # Usage: build_packages.sh ARCHIVE OUT_DIR # Env: NFPM (the nfpm binary, default: nfpm on PATH) @@ -67,8 +67,8 @@ build() { done local lib_deps if [ "$fmt" = deb ]; then - # libc6 2.35: the 4.1 shell is built on Ubuntu 22.04. The rest of the - # tree needs 2.34 (libstdc++ 11 is GCC 11's, as on RHEL 9). + # libc6 2.35 and libstdc++ 11: the 4.1 shell is built on Ubuntu 22.04. + # The rest of the tree needs less (glibc 2.28, as on RHEL 8). lib_deps=" depends: - libwebkit2gtk-4.1-0 - libgtk-3-0t64 | libgtk-3-0 @@ -83,8 +83,8 @@ build() { lib_deps=" depends: - webkit2gtk3 - gtk3 - - libc.so.6(GLIBC_2.34)(64bit) - - libstdc++.so.6(GLIBCXX_3.4.29)(64bit) + - libc.so.6(GLIBC_2.28)(64bit) + - libstdc++.so.6(GLIBCXX_3.4.25)(64bit) - libgcc_s.so.1()(64bit) - libz.so.1()(64bit) recommends: diff --git a/desktop/linux/build_shell.sh b/desktop/linux/build_shell.sh index c2eb5026..bdbf597d 100755 --- a/desktop/linux/build_shell.sh +++ b/desktop/linux/build_shell.sh @@ -7,8 +7,8 @@ # # wk41 WebKitGTK 4.1 (libsoup 3): Ubuntu 22.04 and later, Debian 12 and # later, Fedora. Built on Ubuntu 22.04 (glibc 2.35). -# wk40 WebKitGTK 4.0 (libsoup 2): RHEL 9 and its rebuilds, Debian 11. -# Built on Rocky Linux 9 (glibc 2.34). +# wk40 WebKitGTK 4.0 (libsoup 2): RHEL 8 and 9 and their rebuilds, +# Debian 11. Built on Rocky Linux 8 (glibc 2.28). # # Usage: build_shell.sh wk41|wk40 # Env: SRC (the repository, default: this script's), OUT_DIR (default /out), @@ -36,7 +36,9 @@ if command -v apt-get >/dev/null 2>&1; then apt-get install -y -qq --no-install-recommends ca-certificates curl gcc pkg-config libgtk-3-dev "$dev" >/dev/null else dnf -y -q install epel-release dnf-plugins-core >/dev/null - dnf config-manager --set-enabled crb + # The repository with the development packages: crb from RHEL 9 on, + # powertools on RHEL 8. + dnf config-manager --set-enabled crb 2>/dev/null || dnf config-manager --set-enabled powertools dnf -y -q install gcc pkgconf-pkg-config tar gzip webkit2gtk3-devel gtk3-devel >/dev/null fi diff --git a/desktop/linux/install.sh b/desktop/linux/install.sh index dd27b9a7..0df5c6c0 100755 --- a/desktop/linux/install.sh +++ b/desktop/linux/install.sh @@ -18,7 +18,7 @@ # install.sh --move move it instead of copying (no second copy on the disk) # # Needs WebKitGTK for the Studio's own window (libwebkit2gtk-4.1-0 on Ubuntu 22.04 and -# later, webkit2gtk3 on RHEL 9 and its rebuilds, libwebkit2gtk-4.0-37 on Debian 11); without it the +# later, webkit2gtk3 on RHEL 8 and 9 and their rebuilds, libwebkit2gtk-4.0-37 on Debian 11); without it the # Studio opens in the default browser. A system package manager installs that; # this script installs nothing outside your home folder. # @@ -102,9 +102,11 @@ exec_path="$BIN_DIR/activate-studio" case "$exec_path" in *" "*) exec_path="\"$exec_path\"" ;; esac sed "s|@BIN@|$exec_path|g" "$TREE/share/applications/activate-studio.desktop" >"$APPS_DIR/activate-studio.desktop" if [ -d "$TREE/share/icons/hicolor" ]; then - (cd "$TREE/share/icons/hicolor" && find . -name activate-studio.png) | while IFS= read -r f; do - mkdir -p "$ICON_DIR/$(dirname "$f")" - cp "$TREE/share/icons/hicolor/$f" "$ICON_DIR/$f" + for f in "$TREE"/share/icons/hicolor/*/apps/activate-studio.png; do + [ -e "$f" ] || continue + rel="${f#"$TREE"/share/icons/hicolor/}" + mkdir -p "$ICON_DIR/$(dirname "$rel")" + cp "$f" "$ICON_DIR/$rel" done fi update-desktop-database "$APPS_DIR" >/dev/null 2>&1 || true diff --git a/desktop/linux/test_install.sh b/desktop/linux/test_install.sh index 29f2a311..91943956 100755 --- a/desktop/linux/test_install.sh +++ b/desktop/linux/test_install.sh @@ -66,7 +66,7 @@ if [ $PM = deb ]; then pm_install xvfb dbus-x11 procps imagemagick fonts-dejavu-core desktop-file-utils ca-certificates else dnf install -y -q epel-release >/dev/null 2>&1 || true - pm_install xorg-x11-server-Xvfb dbus-x11 dbus-daemon procps-ng ImageMagick dejavu-sans-fonts desktop-file-utils glibc-langpack-en + pm_install xorg-x11-server-Xvfb dbus-x11 dbus-daemon procps-ng findutils ImageMagick dejavu-sans-fonts desktop-file-utils glibc-langpack-en fi ok "Xvfb, a session bus, ImageMagick and desktop-file-utils installed" @@ -287,7 +287,8 @@ if [ "$KIND" = tarball ]; then as tester mv "$H/.local/lib/.activate-studio.new" "$R" NEWHASH="$(sha256sum "$R/bin/activate-studio-${EXPECT_SHELL:-wk41}" | cut -d' ' -f1)" touch "$T/up1/reopen"; chmod 666 "$T/up1/reopen" - if wait_for 120 sh -c "[ -s '$T/up1/ready' ] && [ \"\$(head -n 1 '$T/up1/ready')\" != '$OLDPID' ]"; then + # The new window removes the file as it starts, so read it once. + if wait_for 120 sh -c "p=\"\$(head -n 1 '$T/up1/ready' 2>/dev/null)\"; [ -n \"\$p\" ] && [ \"\$p\" != '$OLDPID' ]"; then NEWPID="$(head -n 1 "$T/up1/ready")" ok "the window reopened as a new process once the Studio drew again" check "the old window is gone" test ! -e "/proc/$OLDPID" diff --git a/desktop/linux/uninstall.sh b/desktop/linux/uninstall.sh index b8df16f3..054789bc 100755 --- a/desktop/linux/uninstall.sh +++ b/desktop/linux/uninstall.sh @@ -53,7 +53,9 @@ for suffix in previous new failed old; do done [ -f "$BIN" ] && grep -q 'ACTIVATE Studio command' "$BIN" && add command "$BIN" [ -f "$ENTRY" ] && add "menu entry" "$ENTRY" -while IFS= read -r f; do [ -n "$f" ] && add icon "$f"; done < <(find "$ICON_DIR" -path '*/apps/activate-studio.png' 2>/dev/null) +for f in "$ICON_DIR"/*/apps/activate-studio.png; do + if [ -e "$f" ]; then add icon "$f"; fi +done # The window's web view keeps a cache and its storage (what the page saved # in the browser's storage: theme, recent searches) in folders named for the # program the shell gives itself (titlebar_linux.go), the same for both diff --git a/docs/LINUX-APP.md b/docs/LINUX-APP.md index 5fb7b111..43ef2759 100644 --- a/docs/LINUX-APP.md +++ b/docs/LINUX-APP.md @@ -14,15 +14,15 @@ Both come from the same tree, so they behave the same, and the update contract b ## Requirements -A 64-bit Intel or AMD computer with glibc 2.34 or newer: Ubuntu 22.04 and 24.04, Debian 12, RHEL 9 and its rebuilds (Rocky Linux 9, AlmaLinux 9), or newer. RHEL 8 and Ubuntu 20.04 are too old. About 700 MB of disk for the program, plus the index. +A 64-bit Intel or AMD computer with glibc 2.28 or newer. Each release's checks run in containers of RHEL, Rocky Linux, AlmaLinux and Oracle Linux 8 and 9, CentOS Stream 9, Ubuntu 20.04, 22.04 and 24.04, Debian 11, 12 and 13, Fedora 43 and Amazon Linux 2023. RHEL 7 is too old. About 700 MB of disk for the program, plus the index. For the Studio's own window, WebKitGTK and GTK 3: | System | Package | Window shell used | |---|---|---| -| Ubuntu 22.04, 24.04, Debian 12, Fedora | `libwebkit2gtk-4.1-0` | WebKitGTK 4.1 | -| RHEL 9, Rocky 9, AlmaLinux 9 | `webkit2gtk3` | WebKitGTK 4.0 | -| Debian 11, Ubuntu 22.04 without 4.1 | `libwebkit2gtk-4.0-37` | WebKitGTK 4.0 | +| Ubuntu 22.04, 24.04, Debian 12 and 13, Fedora | `libwebkit2gtk-4.1-0` | WebKitGTK 4.1 | +| RHEL, Rocky, AlmaLinux, Oracle Linux 8 and 9, CentOS Stream 9 | `webkit2gtk3` | WebKitGTK 4.0 | +| Debian 11, Ubuntu 20.04, Ubuntu 22.04 without 4.1 | `libwebkit2gtk-4.0-37` | WebKitGTK 4.0 | The `.deb` and `.rpm` declare these as dependencies. For the tarball, they are installed by the system's package manager (the install script installs nothing outside your home folder). Without WebKitGTK, or without a desktop session, the Studio runs in the background and opens in the default browser instead; everything works there except the system folder chooser and the window's own handling of downloads. @@ -51,7 +51,7 @@ For everyone on the computer: ``` sudo apt install ./activate-studio__amd64.deb # Ubuntu, Debian -sudo dnf install ./activate-studio-.x86_64.rpm # RHEL 9, Rocky, Alma +sudo dnf install ./activate-studio-.x86_64.rpm # RHEL 8 or 9, Rocky, Alma, Oracle ``` The `.deb` carries the WebKitGTK 4.1 window shell and depends on `libwebkit2gtk-4.1-0`, which Ubuntu 22.04 and 24.04 both have. The `.rpm` carries the 4.0 shell and depends on `webkit2gtk3`. Neither runs a script when it is installed. The package adds `/usr/bin/activate-studio` and a menu entry. @@ -164,19 +164,20 @@ The window shell is a small Go program (Wails v2, `desktop/wails`) that links to ## What was measured -The archive is about 255 MiB (the tree 687 MB: Node 144 MB, Python 196 MB, GUFI 182 MB, tesseract 12 MB, the server's `node_modules` 69 MB, the web app 36 MB, the models 47 MB), against 503 MB for the macOS app, whose GUFI is 55 MB and Python 142 MB. In CI, GUFI builds in about 8 to 9 minutes, tesseract in 2 to 3, and the payload is assembled in under a minute after the web and server build. The newest symbol versions anywhere in the tree are glibc 2.34, libstdc++ 3.4.29 (GCC 11) and CXXABI 1.3.13, so it needs RHEL 9's or Ubuntu 22.04's C libraries or newer, and does not run on RHEL 8 or Ubuntu 20.04. +The archive is about 255 MiB (the tree 687 MB: Node 144 MB, Python 196 MB, GUFI 182 MB, tesseract 12 MB, the server's `node_modules` 69 MB, the web app 36 MB, the models 47 MB), against 503 MB for the macOS app, whose GUFI is 55 MB and Python 142 MB. In CI, GUFI builds in about 8 to 9 minutes, tesseract in 2 to 3, and the payload is assembled in under a minute after the web and server build. The build limits the tree to symbol versions of glibc 2.28, libstdc++ 3.4.25 (GCC 8) and CXXABI 1.3.11, so it needs RHEL 8's C libraries or newer. The WebKitGTK 4.1 shell is the exception: it is built on Ubuntu 22.04 and needs glibc 2.35, and it is used only where WebKitGTK 4.1 is installed. -The system libraries the tree needs are the C library (libc, libm, libdl, libpthread, librt, libutil, ld-linux), libstdc++, libgcc_s and zlib: packages `libc6`, `libstdc++6`, `libgcc-s1` and `zlib1g` on Ubuntu, `glibc`, `libstdc++`, `libgcc` and `zlib` on RHEL 9. Every desktop has them, and the clean images the tests start from needed no other package. Node's libatomic and GCC's libgomp, which a RHEL 9 install may lack, are in the tree. +The system libraries the tree needs are the C library (libc, libm, libdl, libpthread, librt, libutil, ld-linux), libstdc++, libgcc_s and zlib: packages `libc6`, `libstdc++6`, `libgcc-s1` and `zlib1g` on Ubuntu, `glibc`, `libstdc++`, `libgcc` and `zlib` on RHEL. Every desktop has them, and the clean images the tests start from needed no other package (the Rocky 8 images leave out findutils, which the checks themselves use and the Studio does not). Node's libatomic and GCC's libgomp, which a RHEL install may lack, are in the tree. ## Known limits - RHEL 9's WebKitGTK cannot construct `Intl.NumberFormat`; the Studio's page carries a small guard (`web/index.html`) that stands in for it. Only the pages the build's check opens were tried under that engine. - Not tested: Wayland, HiDPI, a physical GPU or the 3D map, SELinux enforcing, a real desktop session, microphone permission in the window, aarch64. - The window shell is not code signed and the packages are not signed. +- On Fedora 43 the window crashed at launch twice in about ten test launches (in `gtk_main`, in a container on a remote desktop), and opened on the next try. The cause is not known. - Ubuntu 24.04 restricts unprivileged user namespaces; WebKitGTK's sandbox (bubblewrap) works there through Ubuntu's own profile for `/usr/bin/bwrap`. ## How it is built and tested -`.github/workflows/linux-app.yml` builds GUFI and tesseract in a Rocky Linux 9 container (glibc 2.34), the two window shells (4.1 on Ubuntu 22.04, 4.0 on Rocky 9), puts the tree together (`deploy/linux/build_app.sh`, `desktop/linux/add_desktop.sh`), and builds the packages with nfpm (`desktop/linux/build_packages.sh`). `deploy/linux/check_app.sh` runs the payload in clean containers of Ubuntu 22.04, 24.04, Rocky 9 and AlmaLinux 9. `desktop/linux/test_install.sh` installs each package type in a clean container, launches it under Xvfb, checks that the Studio draws and a search finds a document, quits, checks that nothing is left running, uninstalls, and checks that nothing is left in the home folder but the data. `deploy/linux/elf_check.py` fails the build if a file in the tree needs a newer glibc than RHEL 9's. +`.github/workflows/linux-app.yml` builds GUFI and tesseract in a Rocky Linux 8 container (glibc 2.28, with GCC 13 from `gcc-toolset-13` and Python 3.11, as GCC 8 and Python 3.6 are too old for them), the two window shells (4.1 on Ubuntu 22.04, 4.0 on Rocky 8), puts the tree together (`deploy/linux/build_app.sh`, `desktop/linux/add_desktop.sh`), and builds the packages with nfpm (`desktop/linux/build_packages.sh`). `deploy/linux/check_app.sh` runs the payload in clean containers of Ubuntu 22.04, 24.04, Rocky 8 and 9 and AlmaLinux 8 and 9. `desktop/linux/test_install.sh` installs each package type in a clean container, launches it under Xvfb, checks that the Studio draws and a search finds a document, quits, checks that nothing is left running, uninstalls, and checks that nothing is left in the home folder but the data. `deploy/linux/elf_check.py` fails the build if a file in the tree needs a newer glibc than RHEL 8's. The sizes: the archive is about 264 MiB, each package about 246 MiB, the tree 700 MB.