Skip to content

Commit 399119c

Browse files
committed
feat(linux): x86_64 预编译 AppImage —— CI 构建 + install.sh 下载即用
与 normal 分支同步:scripts/build-appimage.sh(jammy 内 linuxdeploy bundle GTK)、 .github/workflows/linux-appimage.yml(tag 触发 CI 构建 AppImage 附加到 release)、 cli/install.sh(Linux x86_64 默认下载 AppImage)、README 更新。
1 parent df1d305 commit 399119c

5 files changed

Lines changed: 248 additions & 27 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# 在 tag 推送时为 Linux x86_64 构建 AppImage 并附加到对应 release。
2+
#
3+
# 流程:release.sh(Mac)构建 macOS 双变体 + 建 release + 推 tag → 本 workflow 被 tag 触发 →
4+
# 在 swift:6.0-jammy 容器(glibc 2.35,覆盖 2022+ 发行版)里 checkout normal(含 Linux 源码)
5+
# → 跑 scripts/build-appimage.sh → 把 TokenClock-x86_64.AppImage + .sha256 附加到该 release。
6+
# 与 release.sh 之间是异步的(AppImage 约在发版后 5–10 分钟出现);softprops/action-gh-release
7+
# 的 create-or-update 语义避免「release 还没建好」的竞态。
8+
name: linux-appimage
9+
10+
on:
11+
push:
12+
tags: ['v*']
13+
workflow_dispatch: # 允许手动触发,便于在不打 tag 时验证
14+
15+
permissions:
16+
contents: write # 附加资产到 release 需要
17+
18+
jobs:
19+
build:
20+
runs-on: ubuntu-latest
21+
container:
22+
image: swift:6.0-jammy
23+
steps:
24+
- name: Checkout normal branch (Linux sources + build script)
25+
uses: actions/checkout@v4
26+
with:
27+
ref: normal
28+
29+
- name: Build AppImage
30+
run: |
31+
chmod +x scripts/build-appimage.sh
32+
./scripts/build-appimage.sh
33+
34+
- name: Attach AppImage + SHA256 to the release
35+
uses: softprops/action-gh-release@v2
36+
with:
37+
tag_name: ${{ github.ref_name }}
38+
files: |
39+
TokenClock-x86_64.AppImage
40+
TokenClock-x86_64.AppImage.sha256

README.md

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -206,32 +206,38 @@ curl -fsSL https://raw.githubusercontent.com/Neo-Isshin/TokenClock/main/cli/inst
206206

207207
### Linux normal build
208208

209-
Linux intentionally ships the **normal classic dial only**. It uses GTK3, keeps the existing 14 local usage parsers, stores history under XDG data directories, registers XDG autostart, and exposes the same loopback API on `127.0.0.1:9988`. Liquid Glass, the macOS theme editor, and weather/location UI are not part of the Linux build.
209+
Linux intentionally ships the **normal classic dial only** (GTK3). It keeps the existing 14 local usage parsers, stores history under XDG data directories, registers XDG autostart, and exposes the same loopback API on `127.0.0.1:9988`. Liquid Glass, the macOS theme editor, and weather/location UI are not part of the Linux build.
210210

211-
Install [Swift 6](https://www.swift.org/install/linux/) first, then:
211+
**x86_64 — prebuilt AppImage (default):** the universal one-liner downloads a self-contained AppImage (GTK3 bundled, needs only glibc ≥ 2.35) — no Swift, no compilation, no dev headers:
212212

213213
```bash
214-
# Ubuntu / Debian build dependencies
215-
sudo apt install git pkg-config libcurl4 libgtk-3-dev libsqlite3-dev
216-
217-
# same universal one-liner — detects Linux and builds the normal GTK3 build from source
214+
# the same universal one-liner — on x86_64 Linux it fetches the prebuilt AppImage
218215
curl -fsSL https://raw.githubusercontent.com/Neo-Isshin/TokenClock/main/cli/install.sh | bash
219216
```
220217

218+
The AppImage needs `libfuse2` at runtime (present on most desktop distros; if missing: `sudo apt install libfuse2`, or `libfuse2t64` on Ubuntu 24.04+).
219+
220+
**Other arches / `--build-from-source`** — build from source (needs Swift 6 + GTK3/SQLite3 dev headers):
221+
222+
```bash
223+
sudo apt install git pkg-config libcurl4 libgtk-3-dev libsqlite3-dev # Ubuntu/Debian build deps
224+
curl -fsSL https://raw.githubusercontent.com/Neo-Isshin/TokenClock/main/cli/install.sh | bash -s -- --build-from-source
225+
```
226+
221227
Or use the reproducible container build:
222228

223229
```bash
224230
docker build -f Dockerfile.linux -t tokenclock-linux .
225231
```
226232

227-
Options: `--normal` / `--glass` (pick the variant) / `--no-start` (don't auto-launch) / `--build-from-source` (force a local build) / `--check` (check only, don't install) / `--debug` (debug build).
233+
Options: `--normal` / `--glass` (pick the variant) / `--no-start` (don't auto-launch) / `--build-from-source` (force a local source build) / `--check` (check only, don't install) / `--debug` (debug build).
228234

229-
> Or build manually from source below.
235+
> Note: on newer-glibc distros the AppImage may print a harmless `libgvfs … undefined symbol / Failed to load module` line to the terminal — TokenClock doesn't use gvfs; ignore it (it's invisible when launched from the desktop menu).
230236
231237
### Prerequisites
232238
- **macOS 12+** (normal build); **macOS 26+** (Liquid Glass build)
233239
- The precompiled install needs **no toolchain at all**; Swift 6 (Xcode 16+ / Command Line Tools) is only required for `--build-from-source` local builds
234-
- **Linux normal:** Swift 6, GTK3 development headers, SQLite3 development headers, `libcurl4`, and `pkg-config`
240+
- **Linux normal:** x86_64 uses the prebuilt AppImage (needs only `libfuse2` + glibc ≥ 2.35, both standard on desktop distros); other arches / `--build-from-source` need Swift 6, GTK3/SQLite3 dev headers, `libcurl4`, and `pkg-config`
235241

236242
### Build & run from source
237243

README.zh-CN.md

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -207,30 +207,36 @@ curl -fsSL https://raw.githubusercontent.com/Neo-Isshin/TokenClock/main/cli/inst
207207

208208
Linux 仅适配 **normal 经典不透明表盘**:使用 GTK3,复用现有 14 个本地用量解析器,历史数据按 XDG 目录保存,支持 XDG 登录自启动,并在 `127.0.0.1:9988` 提供同构 API。Linux 版不包含 Liquid Glass、macOS 主题编辑器和天气/定位界面。
209209

210-
先安装 [Swift 6](https://www.swift.org/install/linux/),然后执行
210+
**x86_64 —— 预编译 AppImage(默认):** 通用一键命令会下载一个自带 GTK3 的 AppImage(仅要求 glibc ≥ 2.35),无需 Swift、无需编译、无需开发头文件
211211

212212
```bash
213-
# Ubuntu / Debian 构建依赖
214-
sudo apt install git pkg-config libcurl4 libgtk-3-dev libsqlite3-dev
215-
216-
# 同一条通用安装命令 —— 自动识别 Linux 并从源码编译 normal GTK3 版
213+
# 同一条通用安装命令 —— 在 x86_64 Linux 上自动下载预编译 AppImage
217214
curl -fsSL https://raw.githubusercontent.com/Neo-Isshin/TokenClock/main/cli/install.sh | bash
218215
```
219216

217+
AppImage 运行期需要 `libfuse2`(多数桌面发行版自带;缺失时:`sudo apt install libfuse2`,Ubuntu 24.04+ 为 `libfuse2t64`)。
218+
219+
**其它架构 / `--build-from-source`** —— 从源码编译(需要 Swift 6 + GTK3/SQLite3 开发头文件):
220+
221+
```bash
222+
sudo apt install git pkg-config libcurl4 libgtk-3-dev libsqlite3-dev # Ubuntu/Debian 构建依赖
223+
curl -fsSL https://raw.githubusercontent.com/Neo-Isshin/TokenClock/main/cli/install.sh | bash -s -- --build-from-source
224+
```
225+
220226
也可以使用可复现的容器构建:
221227

222228
```bash
223229
docker build -f Dockerfile.linux -t tokenclock-linux .
224230
```
225231

226-
可选参数:`--normal` / `--glass`(指定变体)/ `--no-start`(装完不自动启动)/ `--build-from-source`强制本地编译)/ `--check`(仅检查不安装)/ `--debug`(debug 构建)。
232+
可选参数:`--normal` / `--glass`(指定变体)/ `--no-start`(装完不自动启动)/ `--build-from-source`强制本地源码编译)/ `--check`(仅检查不安装)/ `--debug`(debug 构建)。
227233

228-
> 也可手动从源码构建,见下方
234+
> 注:在较新 glibc 的发行版上,AppImage 启动时终端可能打印一行无害的 `libgvfs … undefined symbol / Failed to load module` —— TokenClock 不使用 gvfs,可忽略(从桌面菜单启动时看不到)
229235
230236
### 前置要求
231237
- **macOS 12+**(普通版);**macOS 26+**(Liquid Glass 版)
232238
- 预编译安装**无需任何工具链**;仅 `--build-from-source` 本地编译时需要 Swift 6(Xcode 16+ / Command Line Tools)
233-
- **Linux normal**:Swift 6、GTK3/SQLite3 开发头文件、`libcurl4``pkg-config`
239+
- **Linux normal**x86_64 走预编译 AppImage(仅需 `libfuse2` + glibc ≥ 2.35,桌面发行版均自带);其它架构 / `--build-from-source`Swift 6、GTK3/SQLite3 开发头文件、`libcurl4``pkg-config`
234240

235241
### 从源码构建运行
236242

cli/install.sh

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ FORCE=0 # --force: bypass the "no change" short-circuit and redeploy
4141
DEPLOYED_ANYTHING=0 # whether anything was actually deployed this run (reported to tokenclock update to decide whether to restart)
4242
BUILT_BINS=() # collected build-artifact paths, as path:variant
4343
BUILD_FROM_SOURCE=0 # --build-from-source: skip the prebuilt download and force a local swift build
44+
LINUX_APPIMAGE=0 # Linux x86_64 默认走预编译 AppImage(置 1 后由 download_appimage 处理)
4445

4546
say() { printf '%s\n' "$*"; }
4647
step() { printf '\n🛠 %s\n' "$*"; }
@@ -97,16 +98,28 @@ case "$KERNEL" in
9798
Linux)
9899
PLATFORM=linux
99100
OS_MAJOR=0
100-
BUILD_FROM_SOURCE=1
101101
[ "$VARIANT" != glass ] || die "Linux supports the normal variant only; remove --glass."
102-
command -v git >/dev/null 2>&1 || die "git is required on Linux."
103-
command -v swift >/dev/null 2>&1 || die "Swift 6 is required on Linux (https://www.swift.org/install/linux/)."
104-
command -v pkg-config >/dev/null 2>&1 || die "pkg-config is required on Linux."
105-
pkg-config --exists gtk+-3.0 || die "GTK3 development files are required (Ubuntu/Debian: sudo apt install libgtk-3-dev)."
106-
pkg-config --exists sqlite3 || die "SQLite development files are required (Ubuntu/Debian: sudo apt install libsqlite3-dev)."
102+
if [ "$(uname -m)" = x86_64 ] && [ "$BUILD_FROM_SOURCE" -eq 0 ]; then
103+
# x86_64 默认走预编译 AppImage:无需 Swift/GTK 工具链,下载即用。
104+
# AppImage 运行期需要 libfuse2(多数桌面发行版自带;缺失时给一行安装提示)。
105+
LINUX_APPIMAGE=1
106+
if ! ldconfig -p 2>/dev/null | grep -q 'libfuse.so.2'; then
107+
say " ⚠ 未检测到 libfuse2(AppImage 运行所需)。如启动失败请安装:"
108+
say " Ubuntu/Debian: sudo apt install libfuse2 (24.04+ 为 libfuse2t64)"
109+
fi
110+
say " Linux $(uname -m) · 预编译 AppImage(--build-from-source 可改走源码编译)"
111+
else
112+
# 其它架构(如 aarch64)或 --build-from-source:源码编译,需 Swift6 + GTK/SQLite 开发头文件。
113+
BUILD_FROM_SOURCE=1
114+
command -v git >/dev/null 2>&1 || die "git is required on Linux."
115+
command -v swift >/dev/null 2>&1 || die "Swift 6 is required on Linux (https://www.swift.org/install/linux/)."
116+
command -v pkg-config >/dev/null 2>&1 || die "pkg-config is required on Linux."
117+
pkg-config --exists gtk+-3.0 || die "GTK3 development files are required (Ubuntu/Debian: sudo apt install libgtk-3-dev)."
118+
pkg-config --exists sqlite3 || die "SQLite development files are required (Ubuntu/Debian: sudo apt install libsqlite3-dev)."
119+
say " Linux $(uname -r) · normal GTK3 build · source build"
120+
fi
107121
[ "$INSTALL_URL" != "https://raw.githubusercontent.com/Neo-Isshin/TokenClock/main/cli/install.sh" ] \
108122
|| INSTALL_URL="https://raw.githubusercontent.com/Neo-Isshin/TokenClock/normal/cli/install.sh"
109-
say " Linux $(uname -r) · normal GTK3 build · source build"
110123
;;
111124
*)
112125
die "Unsupported platform: $KERNEL (TokenClock supports macOS and Linux)."
@@ -245,6 +258,36 @@ download_variant() {
245258
return 0
246259
}
247260

261+
# Linux x86_64: 下载预编译 AppImage + sidecar SHA256(由 CI 在发版后产出,故不写死在脚本里),
262+
# 校验通过则把 AppImage 路径写入全局 APPIMAGE_PATH 并返回 0;失败返回 1(调用方回退源码编译)。
263+
APPIMAGE_PATH=""
264+
download_appimage() {
265+
local name="TokenClock-x86_64.AppImage" sha_name="$name.sha256" url tmp got expect
266+
url="$RELEASE_URL_BASE/$name"
267+
step "Downloading prebuilt AppImage (Linux x86_64 · $RELEASE_TAG)"
268+
tmp="$(mktemp -d 2>/dev/null)" || return 1
269+
if ! curl -fL --retry 6 --retry-delay 2 --retry-all-errors --connect-timeout 15 -o "$tmp/$name" "$url" 2>/dev/null; then
270+
say " ⚠ AppImage 下载失败($url,可能 CI 尚未构建完成)→ 回退源码编译"
271+
rm -rf "$tmp"; return 1
272+
fi
273+
if ! curl -fL --retry 6 --retry-delay 2 --retry-all-errors --connect-timeout 15 -o "$tmp/$sha_name" "$RELEASE_URL_BASE/$sha_name" 2>/dev/null; then
274+
say " ⚠ AppImage 的 SHA256 sidecar 下载失败 → 回退源码编译"
275+
rm -rf "$tmp"; return 1
276+
fi
277+
expect="$(awk '{print $1}' "$tmp/$sha_name" 2>/dev/null)"
278+
[ -n "$expect" ] || { say " ⚠ SHA256 sidecar 为空 → 回退源码编译"; rm -rf "$tmp"; return 1; }
279+
got="$(sha256_file "$tmp/$name")"
280+
if [ "$got" != "$expect" ]; then
281+
say " ⚠ AppImage SHA256 不符(expected ${expect:0:12}… got ${got:0:12}…)→ 回退源码编译"
282+
rm -rf "$tmp"; return 1
283+
fi
284+
chmod +x "$tmp/$name"
285+
say " ✓ AppImage 就绪(SHA256 ${got:0:12}…)"
286+
APPIMAGE_PATH="$tmp/$name"
287+
DOWNLOAD_TMPDIRS+=("$tmp")
288+
return 0
289+
}
290+
248291
# Local source build: on macOS 27 with only CLT, automatically pin to the 26 SDK (works around missing SwiftUIMacros).
249292
swift_build_fallback() {
250293
local subdir="$1"
@@ -263,13 +306,19 @@ for i in "${!VARIANTS[@]}"; do
263306
branch="${BRANCHES[$i]}"
264307
subdir="$BUILD_DIR/$branch"
265308

266-
# 4a. Prefer the prebuilt binary
267-
if [ "$BUILD_FROM_SOURCE" -eq 0 ] && download_variant "$variant"; then
309+
# 4a. Linux x86_64: 优先下载预编译 AppImage
310+
if [ "${LINUX_APPIMAGE:-0}" = 1 ] && download_appimage; then
311+
BUILT_BINS+=("$APPIMAGE_PATH:$variant")
312+
continue
313+
fi
314+
315+
# 4b. macOS: 优先下载预编译 universal 二进制(Linux 上不下载 macOS tarball)
316+
if [ "$PLATFORM" != linux ] && [ "$BUILD_FROM_SOURCE" -eq 0 ] && download_variant "$variant"; then
268317
BUILT_BINS+=("$DL_DIR/TokenClock:$variant")
269318
continue
270319
fi
271320

272-
# 4b. Fallback: build from source locally (this is the only path that needs a clone)
321+
# 4c. Fallback: build from source locally (this is the only path that needs a clone)
273322
ensure_source "$variant" "$branch"
274323
step "Building [$variant] (swift build -c $CONFIG · first run may take a few minutes)"
275324
swift_build_fallback "$subdir" \

scripts/build-appimage.sh

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
#!/usr/bin/env bash
2+
#
3+
# build-appimage.sh —— 在 swift:6.0-jammy 容器内构建 Linux x86_64 AppImage。
4+
#
5+
# 产物(落在仓库根):TokenClock-x86_64.AppImage + TokenClock-x86_64.AppImage.sha256
6+
#
7+
# 用法(在装有 Docker 的 Linux/x86_64 主机上,于仓库根执行):
8+
# docker run --rm -v "$PWD":/src -w /src swift:6.0-jammy bash scripts/build-appimage.sh
9+
#
10+
# 设计要点:
11+
# * swift:6.0-jammy = Ubuntu 22.04 / glibc 2.35 → AppImage 兼容 2022+ 主流发行版。
12+
# * -Xswiftc -static-stdlib:静态链 Swift 运行时,去掉对目标机 Swift 运行时的依赖。
13+
# * linuxdeploy + GTK 插件:把 GTK3 及其依赖打进 AppDir,用户机无需装 GTK,
14+
# 只剩 glibc ≥ 2.35 一个运行期要求。
15+
# * APPIMAGE_EXTRACT_AND_RUN=1:容器内通常无 /dev/fuse,让 linuxdeploy/appimagetool
16+
# 这俩 AppImage 工具自解压到 /tmp 运行,免 FUSE。
17+
#
18+
set -euo pipefail
19+
20+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
21+
cd "$ROOT"
22+
23+
ARCH=x86_64
24+
APP=TokenClock
25+
APPIMAGE="$APP-$ARCH.AppImage"
26+
ICON_NAME=tokenclock
27+
28+
step() { printf '\n🛠 %s\n' "$*"; }
29+
ok() { printf ' ✓ %s\n' "$*"; }
30+
die() { printf '\n❌ %s\n' "$*" >&2; exit 1; }
31+
32+
# ── 1. 构建依赖 ──
33+
step "Installing build deps (apt)"
34+
export DEBIAN_FRONTEND=noninteractive
35+
apt-get update -qq
36+
apt-get install -y --no-install-recommends \
37+
libgtk-3-dev libsqlite3-dev libcurl4-openssl-dev \
38+
pkg-config file ca-certificates wget libfuse2 \
39+
>/dev/null
40+
ok "deps installed"
41+
42+
# ── 2. 编译 ──
43+
step "Building TokenClock (swift build -c release · x86_64 · static stdlib)"
44+
swift build -c release -Xswiftc -static-stdlib
45+
BIN="$ROOT/.build/release/$APP"
46+
[ -f "$BIN" ] || die "build artifact not found: $BIN"
47+
ok "binary: $BIN ($(du -h "$BIN" | cut -f1))"
48+
49+
# ── 3. 组装 AppDir ──
50+
step "Assembling AppDir"
51+
APPDIR="$ROOT/AppDir"
52+
rm -rf "$APPDIR"
53+
mkdir -p "$APPDIR/usr/bin" "$APPDIR/usr/share/applications" "$APPDIR/usr/share/icons/hicolor/256x256/apps"
54+
55+
cp "$BIN" "$APPDIR/usr/bin/$APP"
56+
chmod +x "$APPDIR/usr/bin/$APP"
57+
58+
ICON_SRC="$ROOT/Sources/TokenClock/Resources/glass_disc.png"
59+
[ -f "$ICON_SRC" ] || die "icon source not found: $ICON_SRC"
60+
cp "$ICON_SRC" "$APPDIR/usr/share/icons/hicolor/256x256/apps/$ICON_NAME.png"
61+
ok "icon installed ($ICON_SRC)"
62+
63+
cat > "$APPDIR/usr/share/applications/$APP.desktop" <<EOF
64+
[Desktop Entry]
65+
Name=TokenClock
66+
Comment=Token usage clock for AI coding tools
67+
Exec=$APP
68+
Icon=$ICON_NAME
69+
Type=Application
70+
Categories=Utility;
71+
Terminal=false
72+
StartupWMClass=TokenClock
73+
EOF
74+
ok "desktop entry written"
75+
76+
# ── 4. linuxdeploy → bundle 全部动态依赖(含 GTK3 全家桶,经 ldd 发现),产出 AppImage ──
77+
# 注:官方 linuxdeploy-plugin-gtk 当前无预编译 release(仓库 releases 页为空),
78+
# 故改用 linuxdeploy 核心:它经 ldd 把二进制链接的全部 .so(含 libgtk-3/glib/pango/cairo/…)
79+
# 连同 gdk-pixbuf loaders、glib schemas 一起收进 AppDir,用户机无需装 GTK,只剩 glibc ≥ 2.35。
80+
step "Fetching linuxdeploy"
81+
TOOLS="$ROOT/.appimage-tools"
82+
mkdir -p "$TOOLS"
83+
LD="$TOOLS/linuxdeploy-$ARCH.AppImage"
84+
[ -f "$LD" ] || wget -q -O "$LD" "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-$ARCH.AppImage"
85+
[ -s "$LD" ] || die "linuxdeploy download failed (empty file)"
86+
chmod +x "$LD"
87+
ok "linuxdeploy ready"
88+
89+
# 容器内无 FUSE:让 linuxdeploy 这个 AppImage 自解压到 /tmp 运行
90+
export APPIMAGE_EXTRACT_AND_RUN=1
91+
export ARCH="$ARCH"
92+
export VERSION="${VERSION:-0.0.0}" # linuxdeploy 要求 VERSION 环境变量
93+
export OUTPUT="$APPIMAGE"
94+
95+
step "Packaging AppImage (linuxdeploy --output appimage)"
96+
"$LD" --appdir "$APPDIR" \
97+
--desktop-file "$APPDIR/usr/share/applications/$APP.desktop" \
98+
--icon-file "$APPDIR/usr/share/icons/hicolor/256x256/apps/$ICON_NAME.png" \
99+
--output appimage \
100+
|| die "linuxdeploy packaging failed"
101+
[ -f "$ROOT/$APPIMAGE" ] || die "AppImage not produced: $ROOT/$APPIMAGE"
102+
chmod +x "$ROOT/$APPIMAGE"
103+
ok "$APPIMAGE ($(du -h "$ROOT/$APPIMAGE" | cut -f1))"
104+
105+
# ── 5. SHA256 sidecar ──
106+
step "SHA256 sidecar"
107+
( cd "$ROOT" && sha256sum "$APPIMAGE" > "$APPIMAGE.sha256" )
108+
ok "$APPIMAGE.sha256"
109+
110+
# ── 6. 修产物/中间产物属主(容器内以 root 构建、挂载到主机时,把属主还给主机用户)──
111+
# CI 里 workspace 通常属 root → 守卫跳过;Debian 开发主机挂载属普通用户 → 还原,便于清理。
112+
HOST_OWNER="$(stat -c %u:%g "$ROOT" 2>/dev/null || true)"
113+
if [ -n "$HOST_OWNER" ] && [ "$(id -u)" = 0 ] && [ "${HOST_OWNER%%:*}" != 0 ]; then
114+
chown -R "$HOST_OWNER" "$ROOT/.build" "$ROOT/AppDir" "$ROOT/.appimage-tools" \
115+
"$ROOT/$APPIMAGE" "$ROOT/$APPIMAGE.sha256" 2>/dev/null || true
116+
ok "ownership → $HOST_OWNER"
117+
fi
118+
119+
echo
120+
echo "Done: $ROOT/$APPIMAGE (+ $APPIMAGE.sha256)"

0 commit comments

Comments
 (0)