From 15106b641f916acb8df23570a19f946b3cc9d643 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Sun, 11 Oct 2026 11:55:14 -0400 Subject: [PATCH] Linux: AppImage, deb, rpm and Arch packages from one AppDir, installed to /opt/ely-office (L1.5) Co-Authored-By: Claude Opus 5.5 --- agents.md | 8 +- crates/ely-platform/src/apps.rs | 8 ++ packaging/linux/Dockerfile | 2 +- packaging/linux/depends.tsv | 27 +++++ packaging/linux/{appimage.sh => package.sh} | 103 ++++++++++++++++-- scripts/build-libreoffice.sh | 20 ++++ scripts/ci.sh | 2 +- tasks/TASKS.md | 2 +- tasks/reviews/L1.5-r1.md | 11 ++ tasks/reviews/L1.5-r2.md | 3 + tasks/reviews/L1.5-r3.md | 1 + tests/scripts/desktop-files.sh | 2 +- tests/scripts/linux-packages.sh | 65 +++++++++++ .../{appimage-pins.sh => linux-pins.sh} | 16 ++- tests/scripts/types.sh | 2 +- 15 files changed, 251 insertions(+), 21 deletions(-) create mode 100644 packaging/linux/depends.tsv rename packaging/linux/{appimage.sh => package.sh} (50%) create mode 100644 tasks/reviews/L1.5-r1.md create mode 100644 tasks/reviews/L1.5-r2.md create mode 100644 tasks/reviews/L1.5-r3.md create mode 100755 tests/scripts/linux-packages.sh rename tests/scripts/{appimage-pins.sh => linux-pins.sh} (66%) diff --git a/agents.md b/agents.md index c54e9e4..a8a7501 100644 --- a/agents.md +++ b/agents.md @@ -135,6 +135,9 @@ tests/scripts/linux-idle.sh 真窗口 ElyTree:打开仓库后、Omarchy tests/scripts/linux-backends.sh Linux 构建带 Wayland 与 X11;Hyprland 上 ElyTree 在两者上都映射出窗口、画出页面与起始页文字(截窗口量色,tesseract 读字) packaging/linux/container.sh 命令 在 Ubuntu 26.04 镜像里运行(引擎、应用、打包;目标在 target/ubuntu) tests/scripts/linux-glibc.sh Linux 的应用、worker 与引擎要求的 glibc 不高于 2.43 +packaging/linux/package.sh 应用 出该应用的 AppImage、deb、rpm 与 Arch 包到 dist/(在容器里运行) +tests/scripts/linux-packages.sh deb、rpm、Arch 包在干净的 Ubuntu 26.04、Fedora 44、Arch 容器里装上,每个 ELF 都找得到库 +tests/scripts/linux-pins.sh Linux 打包工具(appimagetool、linuxdeploy、运行时、nfpm)的下载与钉的散列相符 cargo test -p ely-show --test compose 切换半程帧经 Metal 取像素(主线程,仅 macOS) tests/scripts/*.sh *.py 脚本测试(缺工具时报 SKIP) packaging/macos/bundle.sh ely-doc debug 出 dist/ElyDoc.app(带图标、文档类型与该应用的引擎) @@ -287,15 +290,16 @@ cargo run -p ely-doc 启动一个应用(ElyDoc 先 cargo build -p ely - 2026-10-09:每个应用只跑一份(缺陷清单 X-03)。`ely_ui::run` 在写日志之前取应用数据目录的 `instance.lock`(`ely_platform::instance::hold`;Unix 为 fcntl 记录锁,进程结束即放,被拒时以 `F_GETLK` 向系统问出持锁的进程号,不另存进程号文件,同时启动的几份也报得准;Windows 为 LockFileEx,不报进程号);已有一份在跑时第二份不启动,报“已在运行(进程号)”。原先第二份启动即清空第一份的工作目录、把它的恢复点当作干净结束删掉、改写崩溃锁。macOS 经访达打开文件本就交给运行中的那份;`open -n` 与 Linux 每文件一个进程时第二份被拒,文件须在已开的窗口里打开(未做转交)。`tests/scripts/one-instance.sh` 核对。 - 2026-10-10:ElyMark 的链接(M-05,我定,同常见编辑器):可视模式单击链接是编辑,Cmd 单击(Windows、Linux 为 Ctrl)交应用;预览单击即交应用;应用照 ElyPDF:http、https、mailto 交系统打开,其余提示拒绝。 - 2026-10-10:Windows 与 Linux 的构建环境(E-01)。Windows:MSVC(VS 2022,v143);MuPDF 由 `build-mupdf.sh` 以 MSBuild 编上游 `platform/win32` 的 `libmupdf`(静态运行库 /MT,同 Rust 的 `crt-static`;`HAVE_LIBCRYPTO`,`libmupdf.lib` 内含第三方、Tesseract 与 PKCS#7);静态 OpenSSL 取自钉在 2026.07.29 的 vcpkg(`engines/vcpkg`,`openssl:x64-windows-static`);Git 为 Git for Windows 的 MinGit 2.56.0(钉散列,`engines/git/cmd/git.exe`,LFS 在 `ucrt64/libexec/git-core`);CEF 照 cef-dll-sys 放在可执行文件旁(Windows、Linux 都是),不另载入;`%TEMP%` 下的程序被系统的应用控制拦下,构建与探针都不放那里;cmake 与 ninja 须在 PATH;LibreOffice 的 configure 只认 VS 自带的 CMake(组件 `VC.CMake.Project`)。仓库与 `reference/` 一律 LF(`core.autocrlf false`、`core.eol lf`;`fetch-references.sh` 对每个上游照设)。Linux:WSL 的 Ubuntu 26.04;静态 libcrypto 另需其 pkg-config 列出的库(jitterentropy、zstd、z)。LibreOffice 在 Linux 照 Collabora 的 LOKit 配置构建(无图形后端、cairo RGBA、自带各库)。 -- 2026-10-10:Windows 与 Linux 的内核与 worker(W-01、K-01,用户定:0.1.3 先三端发布)。内核只认合并库(`ffi::KERNEL`:`libmergedlo.dylib`、`libmergedlo.so`、`mergedlo.dll`;`sofficeapp` 在合并构建里是文本占位);Windows 载入时一并搜索该 DLL 所在的 `program/`。查找次序照旧,Windows 与 Linux 的包内位置是应用旁的 `libreoffice/program`,开发构建为 `engines/lo-src/instdir/program`。worker 的主循环:macOS 照旧以 GCD;Linux 以 unipoll,`runLoop` 的轮询回调里每次答一个请求,内核的唤醒回调往同一队列放信号(`worker/unipoll.rs`;回调的数据指针须非空,VCL 见空即不调用);Windows 也以 unipoll:LOK 不另起主线程,worker 的主线程跑 `runLoop`(Windows 的消息循环),请求经只收消息的窗口投到这条线程上执行(`worker/messages.rs`),同 macOS 的 GCD;原先 LOK 自起主线程、worker 在另一线程作答,载入表格即死锁。Windows 的循环不调轮询回调,但须传非空的回调,`isUnipoll` 只看它。补丁 `0043-lok-callbacks-flush-inline-everywhere.patch`:回调队列在各平台都即时冲出(原只 macOS),否则请求里等的命令结果与状态要等下一轮主循环才到。`0042-svx-boost-json-needs-no-library.patch`:svxcore 与 sd 定义 `BOOST_ALL_NO_LIB`,MSVC 不再按 Boost 的自动链接索要 `libboost_json`、`libboost_container`。Linux 的内核以 cairo 画图块(worker 设 `SAL_DISABLESKIA`;构建去掉 `--enable-cairo-rgba`,自带的 cairo 要清掉重建),字节为 BGRA,同 macOS 与 Windows;`getTileMode` 只看 cairo 开关,不可信。worker 启动核对在三端都画一段红字,按 BGRA 找不到红色即拒绝。`scripts/apply-lo-patches.sh` 的临时库设 `core.autocrlf false`(Windows 默认转换使任何前缀都对不上)。Windows 的 LibreOffice 在 Cygwin 下构建(`build-libreoffice.sh` 的 CYGWIN 分支:去掉 Unix 专用开关,加 VS 2022,用 `/opt/lo/bin` 的 make,清掉 Git Bash 带进来的 `MSYSTEM`);构建目录与 Cygwin 排除在 Defender 扫描之外(否则并行 configure 删不掉 `conftest.dir`)。英文词典扩展里的 Lightproof(Python 写的语法检查)在构建后删去:macOS 与 Linux 的内核不带 Python,它本不生效;Windows 必带内置 Python(Cygwin 下 configure 不许去掉),第二次用同一配置启动时初始化它,worker 挂起。worker 以 `SAL_NOLOCK_PROFILE` 运行,`ely.xcd` 关掉 LibreOffice 的文档锁(`Common/Misc/UseLocking`):被强杀的 worker 留下的锁会让下次启动或载入弹出交互而挂起;每个应用只有一个 worker 用自己的配置,冲突由 Ely 自己核对。三端发布(CI-01):`.gitea/workflows/release.yml` 在打标签时于三台运行器上执行 `scripts/ci.sh`:macOS 在 Mac mini 的常驻克隆里按需从零构建引擎,Windows 在本机运行器上把 `engines` 与 `reference` 接到开发克隆,Linux 由同一台 Windows 运行器经 WSL 构建(服务器上的 Linux 运行器是一次性容器,建不了内核);各自打包后上传到该标签的发布。Windows 为 NSIS 安装程序,Linux 为 AppImage,都由 `packaging/stage.sh` 分装引擎;更新清单只含 macOS(Windows 与 Linux 的自动安装未做)。 +- 2026-10-10:Windows 与 Linux 的内核与 worker(W-01、K-01,用户定:0.1.3 先三端发布)。内核只认合并库(`ffi::KERNEL`:`libmergedlo.dylib`、`libmergedlo.so`、`mergedlo.dll`;`sofficeapp` 在合并构建里是文本占位);Windows 载入时一并搜索该 DLL 所在的 `program/`。查找次序照旧,Windows 与 Linux 的包内位置是应用旁的 `libreoffice/program`,开发构建为 `engines/lo-src/instdir/program`。worker 的主循环:macOS 照旧以 GCD;Linux 以 unipoll,`runLoop` 的轮询回调里每次答一个请求,内核的唤醒回调往同一队列放信号(`worker/unipoll.rs`;回调的数据指针须非空,VCL 见空即不调用);Windows 也以 unipoll:LOK 不另起主线程,worker 的主线程跑 `runLoop`(Windows 的消息循环),请求经只收消息的窗口投到这条线程上执行(`worker/messages.rs`),同 macOS 的 GCD;原先 LOK 自起主线程、worker 在另一线程作答,载入表格即死锁。Windows 的循环不调轮询回调,但须传非空的回调,`isUnipoll` 只看它。补丁 `0043-lok-callbacks-flush-inline-everywhere.patch`:回调队列在各平台都即时冲出(原只 macOS),否则请求里等的命令结果与状态要等下一轮主循环才到。`0042-svx-boost-json-needs-no-library.patch`:svxcore 与 sd 定义 `BOOST_ALL_NO_LIB`,MSVC 不再按 Boost 的自动链接索要 `libboost_json`、`libboost_container`。Linux 的内核以 cairo 画图块(worker 设 `SAL_DISABLESKIA`;构建去掉 `--enable-cairo-rgba`,自带的 cairo 要清掉重建),字节为 BGRA,同 macOS 与 Windows;`getTileMode` 只看 cairo 开关,不可信。worker 启动核对在三端都画一段红字,按 BGRA 找不到红色即拒绝。`scripts/apply-lo-patches.sh` 的临时库设 `core.autocrlf false`(Windows 默认转换使任何前缀都对不上)。Windows 的 LibreOffice 在 Cygwin 下构建(`build-libreoffice.sh` 的 CYGWIN 分支:去掉 Unix 专用开关,加 VS 2022,用 `/opt/lo/bin` 的 make,清掉 Git Bash 带进来的 `MSYSTEM`);构建目录与 Cygwin 排除在 Defender 扫描之外(否则并行 configure 删不掉 `conftest.dir`)。英文词典扩展里的 Lightproof(Python 写的语法检查)在构建后删去:macOS 与 Linux 的内核不带 Python,它本不生效;Windows 必带内置 Python(Cygwin 下 configure 不许去掉),第二次用同一配置启动时初始化它,worker 挂起。worker 以 `SAL_NOLOCK_PROFILE` 运行,`ely.xcd` 关掉 LibreOffice 的文档锁(`Common/Misc/UseLocking`):被强杀的 worker 留下的锁会让下次启动或载入弹出交互而挂起;每个应用只有一个 worker 用自己的配置,冲突由 Ely 自己核对。三端发布(CI-01):`.gitea/workflows/release.yml` 在打标签时于三台运行器上执行 `scripts/ci.sh`:macOS 在 Mac mini 的常驻克隆里按需从零构建引擎,Windows 在本机运行器上把 `engines` 与 `reference` 接到开发克隆,Linux 由同一台 Windows 运行器经 WSL 构建(服务器上的 Linux 运行器是一次性容器,建不了内核);各自打包后上传到该标签的发布。Windows 为 NSIS 安装程序,Linux 为 AppImage、deb、rpm 与 Arch 包,都由 `packaging/stage.sh` 分装引擎;更新清单只含 macOS(Windows 与 Linux 的自动安装未做)。 - 2026-10-11:gpui 的 Windows 窗口关闭(W-03 冒烟查出)。`gpui-pre-windows` 0.3.8 在窗口关闭时报三条错:系统已销毁窗口(ElyTree 的关窗交给系统)后 Drop 仍对旧句柄 `RevokeDragDrop` 与 `DestroyWindow`(拖放处理器因此不释放,连带窗口状态);销毁时的失活回报排在异步任务里,执行时窗口已移除(“window not found”);退出后后台任务向已销毁的平台窗口投递(`Invalid window handle`)。修复在 `vendor/gpui-pre-windows`:`WM_DESTROY` 时记下已销毁、在句柄仍有效时撤销拖放、去掉失活回调,Drop 见已销毁即不再动句柄;平台窗口已不在时投递失败只记 debug(应用已退出),其余投递失败照报。三个应用关窗与退出的日志无错。 - 2026-10-11(用户报:Windows 启动带黑色命令行窗口、“打开方式”里无图标、点 X 不退出、表格全黑无网格线):四处根因。命令行窗口:应用是控制台子系统;发行构建改为 `windows_subsystem = "windows"`(开发构建照旧有控制台看日志),子进程(两个 worker、Git、`cmd start`)一律经 `ely_ipc::windowless` 以 `CREATE_NO_WINDOW` 启动。图标:exe 里只有 gpui 的清单资源;各应用共用构建脚本 `packaging/windows/icon.rs`,把 `assets/icons/<应用>.ico` 编成资源 1(gpui 的窗口图标也取资源 1)。点 X 不退出:窗口其实弹了“保存更改”询问。`ely.xcd` 深色方案的 `CalcNotesBackground` 与浅色不同,Calc 在配色变化时改写批注样式并记一步撤销(`ScDetectiveFunc::UpdateAllComments`),未动的表格切到深色即算已修改;两套方案的批注底色改为同一值(LibreOffice 默认的浅黄),切换主题不再改文档,三端同此(`sheet.rs` 的 `a_theme_switch_is_no_edit`)。全黑:Win32 的虚拟设备没有 `SetSizeUsingBuffer`(基类默认返回假,断言在发行构建里不在),给客户缓冲区的设备停在 1×1 像素,Calc 图块只画了一个像素,放映图层同空;补丁 `0044-lok-win32-paints-then-copies.patch` 让 Windows 走 macOS 的路:按全尺寸画进设备,再拷进客户缓冲区(`doc_paintTile` 与 `SlideshowLayerRenderer`)。Writer 自设设备尺寸,原本不受影响。`tests/scripts/lo-patches.sh` 的临时库也设 `core.autocrlf false`(原先在 Windows 上恒失败)。 - 2026-10-11(用户报:Windows 上标题栏的最小化、最大化、关闭三个按钮都按不动):gpui 回答系统的命中测试(`WM_NCHITTEST`)时按绘制次序取第一个含指针的窗口控制区,标题栏的拖动区先于其中的按钮画出,按钮上一律答“标题栏”,系统把按下当作拖动窗口的开始,点击到不了按钮。修复在 `vendor/gpui-pre`(原样一个提交,其后是修复):按命中测试的次序取最上层的控制区,且只看未被遮挡的部分(同 `is_hovered`,盖在标题栏上的对话框挡住其下的按钮)。实测(发行构建,DPI 感知的探针移动真实指针):自右向左依次答关闭、最大化、最小化、拖动;按下最小化即最小化,最大化即最大化,关闭即退出、worker 随之结束;v0.1.3 的安装版同一探针处处答拖动。该回调只有 Windows 平台调用。 - 2026-10-11:Linux 标题栏按钮(核查 Windows 按钮问题时查出)。macOS 的红绿灯由系统画,不受影响;Linux 为客户端装饰,按钮由组件库画在标题栏的拖动区里,拖动区对任何按下都准备移动窗口,按住按钮时指针动一像素即开始移动窗口,合成器接管指针,松开到不了按钮,点击落空。组件库 3eb4d34:`drag_region` 只在按下未被里面的按钮认领(按钮以 `prevent_default` 认领)时才准备移动;`shell/title_tests.rs` 核对晃动的按下点得动 Linux 的关闭、标题栏空处照样移动窗口(去掉修复时前者失败)。未在真 Linux 桌面上点过。 - 2026-10-11(用户报:ElyTree 改动列表里文件名长时盖住行尾的打开按钮):组件库 bd01470:`ChangesList` 行里的文件名原为不缩的盒子,长名越过行宽压在按钮下;现可缩、以省略号结尾,先于按钮让位;`git/tests/narrow.rs` 核对 260 宽时文件名止于按钮之前(原布局时失败)。 - 2026-10-11(用户定:ElyTree 状态栏去掉 Git 的版本与路径那一项):所用 Git 的版本与路径只记日志。同时查出 Windows 上 `std::fs::canonicalize` 给出 `\\?\C:\…` 形式,仓库根、Git 目录、工作树与文件的真实路径一律改用 `dunce::canonicalize`(能写成普通路径即普通路径,同一文件仍是同一真实路径),状态栏的仓库路径随之为普通形式;ElyTree 的单测在 Windows 上由 44 个失败降到 8 个,余下 8 个改前同样失败(如写入 Windows 不许的文件名),未处理。 -- 2026-10-11:ElyMark 的 AppImage(0.1.3 的 Linux 发布查出)。`linuxdeploy` 把可执行文件的 RUNPATH 改成 `$ORIGIN/../lib`,并把它找得到的 `libcef.so` 拷进 `usr/lib`:原先 `libcef.so` 与 CEF 的资料在 `usr/bin`,结果是两份 1.45 GB 的内核、程序载入 `usr/lib` 那份、CEF 在它旁边找不到 ICU 数据而退出(从未在 AppImage 里启动过)。现在 `appimage.sh` 把从 `engines/cef` 分装来的全部条目移进 `usr/lib`(按名字对照 CEF 文件夹,清单仍只在 `stage.sh`),以 `LD_LIBRARY_PATH=AppDir/usr/lib` 运行 `linuxdeploy`,`libcef.so` 只此一份、依赖照样带上,CEF 按所载 `libcef.so` 的文件夹取资料(`ely-web-content` 的 `open`)。ElyMark 的 AppImage 由 715 MB 降到 423 MB;WSL 里启动后 CEF 载入、窗口打开(WSL 里各应用都不出首帧,未在真桌面上验证)。 +- 2026-10-11:ElyMark 的 AppImage(0.1.3 的 Linux 发布查出)。`linuxdeploy` 把可执行文件的 RUNPATH 改成 `$ORIGIN/../lib`,并把它找得到的 `libcef.so` 拷进 `usr/lib`:原先 `libcef.so` 与 CEF 的资料在 `usr/bin`,结果是两份 1.45 GB 的内核、程序载入 `usr/lib` 那份、CEF 在它旁边找不到 ICU 数据而退出(从未在 AppImage 里启动过)。现在 `package.sh` 把从 `engines/cef` 分装来的全部条目移进 `usr/lib`(按名字对照 CEF 文件夹,清单仍只在 `stage.sh`),以 `LD_LIBRARY_PATH=AppDir/usr/lib` 运行 `linuxdeploy`,`libcef.so` 只此一份、依赖照样带上,CEF 按所载 `libcef.so` 的文件夹取资料(`ely-web-content` 的 `open`)。ElyMark 的 AppImage 由 715 MB 降到 423 MB;WSL 里启动后 CEF 载入、窗口打开(WSL 里各应用都不出首帧,未在真桌面上验证)。 - 2026-10-09(用户定):代码与发布从 GitHub 搬到自建的 Gitea(git.zacharyzhang.com;GitHub 账号被封,推送与发布都被拒)。公开仓库 `ZacharyZhang-NY/ElyOffice`(原样推上 main、缺陷清单分支与 v0.1.0、v0.1.1 标签),组件库为同站的 `ZacharyZhang-NY/Ely-GPUI-Components`(Cargo 的 git 依赖与 `fetch-references.sh` 随之改址,钉的提交不变)。v0.1.1 的六个 dmg 与两个源码包重新发在 Gitea 的 v0.1.1 发布里。官网的下载与源码链接指向 Gitea(`releases/latest` 会跳到最新发布页)。`.github/workflows` 删去(它们靠 GitHub 的 macOS 机器与 `gh`,发布改在本机以 `packaging/macos/release.sh` 构建、经 Gitea API 上传)。发布视频里写的地址已在源文件改为 Gitea,已发布的成片仍是旧地址,重渲染后才更新。上游项目(LibreOffice、MuPDF、git-lfs、tessdata 等)照旧从它们自己的 GitHub 地址取。 - 2026-10-11(用户报:Omarchy 上六个 AppImage 都打不开):`gpui-pre-platform` 对 `gpui-pre-linux` 关了默认特性,Wayland 与 X11 只经它自己的 `wayland`、`x11` 特性打开;工作区原只开 `font-kit`,Linux 上 gpui 退成无头平台,日志照写“window open”,合成器里从无窗口。工作区的 `gpui_platform` 加开两者;`tests/scripts/linux-backends.sh` 核对特性,在 Hyprland 上核对 Wayland 与 X11 两路都映射出窗口、截图里有均匀的深色页面,tesseract 读出起始页的 “Open a repository”(不交缓冲的窗口 Hyprland 不映射;不画字形时读不出)。 - 2026-10-11:Linux 的 inotify 把打开文件报成事件(notify 的 `Access`),macOS 的 FSEvents 不报;四处文件监视原把任何事件当作改动,重读本身又触发下一次:Omarchy 主题与通用设置在第一次改动后、ElyTree 打开仓库起(`git status` 读仓库),空闲时每 250 毫秒重读。四处都经 `ely_ui::watching::only_read` 略去读取(打开、读、只读关闭),写后关闭照算改动(经内存映射的写入只报 CLOSE_WRITE,不报 MODIFY);`tests/scripts/linux-idle.sh` 以 inotifywait 从外面数空闲时的读取与 git status 次数。 - 2026-10-11(用户定):Linux 的引擎、应用与包都在 `ubuntu:26.04` 容器里构建(`packaging/linux/Dockerfile`,钉摘要;glibc 2.43),不在本机(Arch 的 glibc 更新,建出的程序在 Ubuntu 上起不来)。`packaging/linux/container.sh` 以本人身份运行,Cargo 的目标与家目录另放 `target/ubuntu*`;`stage.sh` 取 `CARGO_TARGET_DIR`;Git 2.56 用自己的 `target/` 链接其 Rust 部分,`build-git.sh` 为它去掉该变量。`tests/scripts/linux-glibc.sh` 核对每个动态链接的 ELF(静态的 git-lfs 不算)。 +- 2026-10-11(用户要求:Linux 不只 AppImage):`packaging/linux/package.sh` 由同一个 AppDir 出四种包:AppImage,以及经 nfpm v2.47.0(钉散列)的 deb、rpm、Arch 包。包把 AppDir 的 `usr` 装到 `/opt/ely-office/<应用>`,`/usr/bin/<应用>` 为链接,桌面项与 512 像素图标在 `/usr/share`。依赖由 AppDir 里每个 ELF 所需而未随包的库,加 gpui 按名载入的 Vulkan 与 Wayland 客户端库得出:deb 与 Arch 按 `packaging/linux/depends.tsv` 换成包名(表里没有即打包失败),rpm 直接依赖库名(`libxcb.so.1()(64bit)`)。同级应用多找一处 `/opt/ely-office/<应用>/bin`(ElyMark 打开 ElyTree)。LibreOffice 的 cairo 由 meson 构建,内核直接拷其构建目录的产物,RUNPATH 仍指向构建树里的 pixman 与 fontconfig(别的机器上找不到);`build-libreoffice.sh` 在 Linux 上把指向源码树的 RUNPATH 改为 `$ORIGIN`(patchelf)。 diff --git a/crates/ely-platform/src/apps.rs b/crates/ely-platform/src/apps.rs index 2b57e00..0293ce9 100644 --- a/crates/ely-platform/src/apps.rs +++ b/crates/ely-platform/src/apps.rs @@ -25,6 +25,10 @@ fn beside(exe: &Path, app: AppId) -> Vec { if let Some(suite) = dir.parent() { places.push(suite.join(app.name()).join(&file)); } + // Linux packages: /opt/ely-office//bin. + if let Some(opt) = dir.parent().and_then(Path::parent) { + places.push(opt.join(app.slug()).join("bin").join(&file)); + } places } @@ -160,6 +164,10 @@ mod tests { assert!(places.contains(&PathBuf::from(format!( "/Ely Office/ElyMark/ely-mark{suffix}" )))); + let places = super::beside(Path::new("/opt/ely-office/ely-tree/bin/ely-tree"), AppId::Mark); + assert!(places.contains(&PathBuf::from(format!( + "/opt/ely-office/ely-mark/bin/ely-mark{suffix}" + )))); } } diff --git a/packaging/linux/Dockerfile b/packaging/linux/Dockerfile index 13856fa..6020bab 100644 --- a/packaging/linux/Dockerfile +++ b/packaging/linux/Dockerfile @@ -8,7 +8,7 @@ RUN sed -i 's/^Types: deb$/Types: deb deb-src/' /etc/apt/sources.list.d/ubuntu.s && rm -rf /var/lib/apt/lists/* RUN apt-get update \ && apt-get install -y --no-install-recommends \ - curl ca-certificates git rsync patch file jq python3 nodejs npm rustup \ + curl ca-certificates git rsync patch patchelf file jq python3 nodejs npm rustup \ cmake ninja-build pkg-config nasm \ libssl-dev libjitterentropy3-dev libzstd-dev zlib1g-dev \ libxkbcommon-dev libxkbcommon-x11-dev libwayland-dev libx11-xcb-dev libxcb1-dev libfontconfig-dev \ diff --git a/packaging/linux/depends.tsv b/packaging/linux/depends.tsv new file mode 100644 index 0000000..132747c --- /dev/null +++ b/packaging/linux/depends.tsv @@ -0,0 +1,27 @@ +ld-linux-x86-64.so.2 libc6 glibc +ld-linux-aarch64.so.1 libc6 glibc +libc.so.6 libc6 glibc +libm.so.6 libc6 glibc +libdl.so.2 libc6 glibc +libpthread.so.0 libc6 glibc +libresolv.so.2 libc6 glibc +libgcc_s.so.1 libgcc-s1 libgcc +libstdc++.so.6 libstdc++6 libstdc++ +libgssapi_krb5.so.2 libgssapi-krb5-2 krb5 +libcom_err.so.2 libcom-err2 e2fsprogs +libxcb.so.1 libxcb1 libxcb +libX11.so.6 libx11-6 libx11 +libvulkan.so.1 libvulkan1 vulkan-icd-loader +libwayland-client.so.0 libwayland-client0 wayland +libcrypto.so.3 libssl3t64 openssl +libssl.so.3 libssl3t64 openssl +libcurl.so.4 libcurl4t64 curl +libexpat.so.1 libexpat1 expat +libz.so.1 zlib1g zlib +libasound.so.2 libasound2t64 alsa-lib +libfontconfig.so.1 libfontconfig1 fontconfig +libfreetype.so.6 libfreetype6 freetype2 +libfribidi.so.0 libfribidi0 fribidi +libgbm.so.1 libgbm1 mesa +libgmp.so.10 libgmp10 gmp +libharfbuzz.so.0 libharfbuzz0b harfbuzz diff --git a/packaging/linux/appimage.sh b/packaging/linux/package.sh similarity index 50% rename from packaging/linux/appimage.sh rename to packaging/linux/package.sh index 309ac8e..8572493 100755 --- a/packaging/linux/appimage.sh +++ b/packaging/linux/package.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Builds dist/--linux-.AppImage. Usage: appimage.sh [--desktop] +# Usage: package.sh [--desktop] ; AppImage, deb, rpm, Arch. set -euo pipefail root=$(cd "$(dirname "$0")/../.." && pwd) @@ -13,13 +13,13 @@ dist=${ELY_DIST:-$root/dist} row=$(awk -F'\t' -v slug="$slug" '$1 == slug { print $2 "\t" $3 }' "$root/packaging/apps.tsv") [ -n "$row" ] || { - echo "appimage.sh: unknown app $slug" >&2 + echo "package.sh: unknown app $slug" >&2 exit 1 } name=${row%%$'\t'*} categories=${row##*$'\t'} # The types it opens, from packaging/types.tsv; none drops the line. -mimes=$(awk -F'\t' -v slug="$slug" '$1 == slug { printf "%s;", $3 }' "$root/packaging/types.tsv") +mimes=$(awk -F'\t' -v slug="$slug" '$1 == slug && !seen[$3]++ { printf "%s;", $3 }' "$root/packaging/types.tsv") desktop_entry() { sed -e "s/@NAME@/$name/" -e "s/@SLUG@/$slug/g" -e "s/@CATEGORIES@/$categories/" -e "s|@MIME@|$mimes|" \ -e '/^MimeType=$/d' "$root/packaging/linux/app.desktop.in" @@ -31,29 +31,35 @@ if [ -n "$desktop_only" ]; then fi [ "$(uname)" = Linux ] || { - echo "appimage.sh: Linux only" >&2 + echo "package.sh: Linux only" >&2 exit 1 } arch=$(uname -m) case $arch in x86_64) + goarch=amd64 + nfpm_arch=x86_64 pack_sha=ed4ce84f0d9caff66f50bcca6ff6f35aae54ce8135408b3fa33abfc3cb384eb0 deploy_sha=c20cd71e3a4e3b80c3483cef793cda3f4e990aca14014d23c544ca3ce1270b4d runtime_sha=2fca8b443c92510f1483a883f60061ad09b46b978b2631c807cd873a47ec260d + nfpm_sha=0660ca602b2d2d2ae4781a06c692b3eeb9d437ffea05b831d76e41f4a3188783 ;; aarch64) + goarch=arm64 + nfpm_arch=arm64 pack_sha=f0837e7448a0c1e4e650a93bb3e85802546e60654ef287576f46c71c126a9158 deploy_sha=620095110d693282b8ebeb244a95b5e911cf8f65f76c88b4b47d16ae6346fcff runtime_sha=00cbdfcf917cc6c0ff6d3347d59e0ca1f7f45a6df1a428a0d6d8a78664d87444 + nfpm_sha=1c0f5f2999b9a974bfb04fdb0cc3306096de530ac5dbb25d739cc5f5219c919c ;; *) - echo "appimage.sh: no AppImage tools for $arch" >&2 + echo "package.sh: no packaging tools for $arch" >&2 exit 1 ;; esac icon=$root/assets/icons/$slug.png [ -f "$icon" ] || { - echo "appimage.sh: $icon is missing; the icons are not designed yet" >&2 + echo "package.sh: $icon is missing" >&2 exit 1 } @@ -68,14 +74,23 @@ fetch_tool() { # file url sha256 pack=$root/engines/appimagetool-1.9.1-$arch.AppImage deploy=$root/engines/linuxdeploy-1-alpha-20251107-1-$arch.AppImage runtime=$root/engines/type2-runtime-20251108-$arch +nfpm_tar=$root/engines/nfpm_2.47.0_Linux_$nfpm_arch.tar.gz fetch_tool "$pack" "https://github.com/AppImage/appimagetool/releases/download/1.9.1/appimagetool-$arch.AppImage" "$pack_sha" fetch_tool "$deploy" "https://github.com/linuxdeploy/linuxdeploy/releases/download/1-alpha-20251107-1/linuxdeploy-$arch.AppImage" "$deploy_sha" fetch_tool "$runtime" "https://github.com/AppImage/type2-runtime/releases/download/20251108/runtime-$arch" "$runtime_sha" +fetch_tool "$nfpm_tar" "https://github.com/goreleaser/nfpm/releases/download/v2.47.0/nfpm_2.47.0_Linux_$nfpm_arch.tar.gz" "$nfpm_sha" +nfpm=$root/engines/nfpm-2.47.0-$arch +if [ ! -x "$nfpm" ]; then + tar -xzf "$nfpm_tar" -O nfpm >"$nfpm.part" + chmod +x "$nfpm.part" + mv "$nfpm.part" "$nfpm" +fi stage=$root/target/stage/$slug "$root/packaging/stage.sh" "$slug" "$stage" -work=$(mktemp -d) -trap 'rm -rf "$work"' EXIT +work=$root/target/package/$slug +rm -rf "$work" +mkdir -p "$work" desktop_entry >"$work/$slug.desktop" appdir=$work/$name.AppDir bin=$appdir/usr/bin @@ -108,3 +123,75 @@ version=$(awk -F'"' '/^version = / { print $2; exit }' "$root/Cargo.toml") out=$dist/$name-$version-linux-$arch.AppImage ARCH=$arch "$pack" --appimage-extract-and-run --runtime-file "$runtime" "$appdir" "$out" echo "$out" + +# Libraries the AppDir needs and does not bundle. +broken() { + echo "package.sh: $*" >&2 + exit 1 +} +find "$appdir" \( -type f -o -type l \) -name '*.so*' -print0 >"$work/libs.list" || broken "cannot list $appdir" +find "$appdir" -type f -print0 >"$work/files.list" || broken "cannot list $appdir" +declare -A bundled=() +while IFS= read -r -d '' file; do + bundled[${file##*/}]=1 +done <"$work/libs.list" +# gpui loads these by name. +needed=(libvulkan.so.1 libwayland-client.so.0) +while IFS= read -r -d '' file; do + magic=$(head -c 4 "$file" | od -An -c | tr -d ' ') || broken "cannot read $file" + [ "$magic" = '177ELF' ] || continue + dynamic=$(readelf -dW "$file") || broken "readelf cannot read $file" + while IFS= read -r lib; do + [ -n "${bundled[$lib]:-}" ] || needed+=("$lib") + done < <(sed -n 's/.*Shared library: \[\(.*\)\]/\1/p' <<<"$dynamic") +done <"$work/files.list" +deb=() pacman=() rpm=() +while IFS= read -r lib; do + row=$(awk -F'\t' -v lib="$lib" '$1 == lib' "$root/packaging/linux/depends.tsv") + [ -n "$row" ] || { + broken "$lib is in no row of packaging/linux/depends.tsv" + } + IFS=$'\t' read -r _ deb_name pacman_name <<<"$row" + deb+=("$deb_name") + pacman+=("$pacman_name") + rpm+=("$lib()(64bit)") +done < <(printf '%s\n' "${needed[@]}" | sort -u) +yaml_list() { printf ' - "%s"\n' "$@" | sort -u; } + +# deb, rpm and Arch: the AppDir's usr under /opt/ely-office. +cat >"$work/nfpm.yaml" <"$files" || { + echo "build-libreoffice.sh: cannot list $src/instdir" >&2 + exit 1 + } + while IFS= read -r -d '' lib; do + magic=$(head -c 4 "$lib" | od -An -c | tr -d ' ') || exit 1 + [ "$magic" = '177ELF' ] || continue + dynamic=$(readelf -dW "$lib") || exit 1 + paths=$(sed -n 's/.*(R\(UN\)\{0,1\}PATH).*\[\(.*\)\]/\2/p' <<<"$dynamic") + if [[ $paths == *"$src"* ]]; then + # shellcheck disable=SC2016 + patchelf --set-rpath '$ORIGIN' "$lib" + echo "build-libreoffice.sh: $lib now loads from \$ORIGIN" + fi + done <"$files" + rm "$files" +fi if [ "$(uname)" = Darwin ]; then "$root/scripts/inert-lo.sh" "$src/instdir/LibreOffice.app" fi diff --git a/scripts/ci.sh b/scripts/ci.sh index 18596d9..50eb607 100755 --- a/scripts/ci.sh +++ b/scripts/ci.sh @@ -41,7 +41,7 @@ batch=$(awk -F'\t' '$4 == 1 { print $1 }' packaging/apps.tsv) case $os in macos) packaging/macos/release.sh 1 ;; windows) for slug in $batch; do packaging/windows/installer.sh "$slug"; done ;; - linux) for slug in $batch; do packaging/linux/appimage.sh "$slug"; done ;; + linux) for slug in $batch; do packaging/linux/package.sh "$slug"; done ;; *) echo "ci.sh: no release for $os" >&2 exit 1 diff --git a/tasks/TASKS.md b/tasks/TASKS.md index e0478d3..8f4c5b7 100644 --- a/tasks/TASKS.md +++ b/tasks/TASKS.md @@ -205,6 +205,6 @@ - [x] L1.2 Linux 上的文件监视把读取当作改动(inotify 报打开,FSEvents 不报):Omarchy 主题、通用设置在第一次改动后、ElyTree 打开仓库起,每次重读自己又触发下一次,空闲时每 250 毫秒读一遍;四处监视(主题、设置、ElyTree、ElyMark)经 `ely_ui::watching::only_read` 略去读取,写后关闭照算改动;`theme.name` 读不出不再吞掉;`tests/scripts/linux-idle.sh`(ElyMark 要 CEF,随 L1.6 实测) — R1 写后关闭也被略去、注释超长;R2 PASS - [x] L1.3 设置的单测在 Linux 上失败(“a menu bar needs menus”):Linux 未设菜单时给空表而非 None,测试未像应用那样先设菜单;真窗口里 Ctrl+, 打开设置不崩(已实测) — R1 PASS - [x] L1.4 Linux 构建环境:`ubuntu:26.04` 容器里构建全部引擎与六个应用(glibc 不高于 2.43);`packaging/linux/container.sh`、`tests/scripts/linux-glibc.sh` — R1 读不出当作静态、缺件照过、注释超长;R2 链接文件、读错;R3 链接目录;R4 PASS -- [ ] L1.5 Linux 包:deb、rpm、Arch(pkg.tar.zst)、AppImage 出自同一份分装,装到 `/opt/ely-office/<应用>`,带桌面项、图标与文件类型 +- [x] L1.5 Linux 包:deb、rpm、Arch(pkg.tar.zst)、AppImage 出自同一份分装,装到 `/opt/ely-office/<应用>`,带桌面项、图标与文件类型;依赖按 `packaging/linux/depends.tsv`;LibreOffice 的 cairo RUNPATH 改为 `$ORIGIN`;`tests/scripts/linux-packages.sh` — R1 列举与读错被吞、坏入口照过、无执行位;R2 坏 git-lfs 照过;R3 PASS - [ ] L1.6 本机出六个应用的四种包;Omarchy 上装 Arch 包与 AppImage 出窗口;deb、rpm 在各自发行版的容器里装上并冒烟 - [ ] L1.7 v0.1.3:删去旧 AppImage,上传新包;`ci.sh` 的 Linux 产出四种包;agents.md 与官网随之 diff --git a/tasks/reviews/L1.5-r1.md b/tasks/reviews/L1.5-r1.md new file mode 100644 index 0000000..4f5e6e0 --- /dev/null +++ b/tasks/reviews/L1.5-r1.md @@ -0,0 +1,11 @@ +FAIL + +1. packaging/linux/package.sh:131 — Both `find` process substitutions discard traversal failures, and line 135 treats a failed header read as a non-ELF file. Dependency discovery can therefore succeed without inspecting the payload. With `find` returning 74, the packaging tail generated all three native ElyTree packages with only Wayland and Vulkan dependencies, omitting the normal curl, OpenSSL, libxcb and other requirements (`.work/L1.5-r1-dependency-errors.log`). Such packages can install without their required libraries. Check enumeration and header-read status before consuming their output; abort packaging on failure and test these failure paths. + +2. scripts/build-libreoffice.sh:155 — The new RUNPATH repair ignores failed header reads, and its `find` failure at line 162 never reaches the parent shell. A traversal/read error leaves build-tree RUNPATHs intact while the script succeeds. Probing the post-build block with a copy of the existing cairo library confirmed that normal execution changes its RUNPATH to `$ORIGIN`, whereas either injected error returns zero and retains the source-tree path (`.work/L1.5-r1-lo-errors.log`). On another machine its private dependencies cannot resolve through that path. Make enumeration and file-read failures fatal and cover them without rebuilding LibreOffice. + +3. tests/scripts/linux-packages.sh:29 — The installed-package check ignores header-read and traversal failures and permits zero checked ELF files. Its inner shell also lacks `pipefail`. Against the freshly built, installed ElyTree deb, making either `find` or `head` fail with status 74 still printed `ely-tree: 0 ELF files link` and exited zero (`.work/L1.5-r1-test-errors.log`). This falsely certifies packages whose contents were never checked. Propagate listing/read failures, enable pipeline failure detection, and require the expected application binary to be inspected. + +4. tests/scripts/linux-packages.sh:31 — Any `ldd` error containing “not a dynamic executable” is accepted as a static binary without validating the ELF. Replacing the installed ElyTree executable with just the four ELF magic bytes still passed with “17 ELF files link”; replacing it with executable text also passed with 16 (`.work/L1.5-r1-broken-entry.log`). Neither application can start. Validate required entry points as complete ELF executables, and distinguish valid static executables from malformed files using checked ELF headers before allowing this exception. Add these negative cases. + +5. tests/scripts/linux-packages.sh:1 — The new script is committed as mode 100644, unlike the other shell tests. Running the command documented in agents.md, `tests/scripts/linux-packages.sh`, fails with permission denied and status 126 before checking any package (`.work/L1.5-r1-test-permission.log`). Commit its executable bit. diff --git a/tasks/reviews/L1.5-r2.md b/tasks/reviews/L1.5-r2.md new file mode 100644 index 0000000..cfbae1b --- /dev/null +++ b/tasks/reviews/L1.5-r2.md @@ -0,0 +1,3 @@ +FAIL + +1. tests/scripts/linux-packages.sh:37 — The static-binary exception still accepts malformed ELF files solely because their basename is `git-lfs`; round 1 defect 4 is only partly fixed. In a clean Ubuntu container with the rebuilt ElyTree deb installed, replacing its bundled `git/libexec/git-core/git-lfs` with the four bytes `\177ELF` still makes the package check print `ely-tree: 17 ELF files link` and exit zero. Executing that helper fails with “Exec format error” and status 126 (`.work/L1.5-r2-test-errors.log`). Validate complete ELF headers before accepting a static executable, and add a regression case for a malformed bundled helper. diff --git a/tasks/reviews/L1.5-r3.md b/tasks/reviews/L1.5-r3.md new file mode 100644 index 0000000..7ef22e9 --- /dev/null +++ b/tasks/reviews/L1.5-r3.md @@ -0,0 +1 @@ +PASS diff --git a/tests/scripts/desktop-files.sh b/tests/scripts/desktop-files.sh index a4e9513..562d4e8 100755 --- a/tests/scripts/desktop-files.sh +++ b/tests/scripts/desktop-files.sh @@ -17,7 +17,7 @@ command -v desktop-file-validate >/dev/null || { count=0 while IFS=$'\t' read -r slug name _; do file=$work/$slug.desktop - "$root/packaging/linux/appimage.sh" --desktop "$slug" >"$file" + "$root/packaging/linux/package.sh" --desktop "$slug" >"$file" report=$(desktop-file-validate "$file" 2>&1) || fail "$slug.desktop is not valid: $report" [ -z "$report" ] || fail "$slug.desktop has hints: $report" grep -qx "Name=$name" "$file" || fail "$slug.desktop has the wrong name" diff --git a/tests/scripts/linux-packages.sh b/tests/scripts/linux-packages.sh new file mode 100755 index 0000000..c5ef380 --- /dev/null +++ b/tests/scripts/linux-packages.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +# deb, rpm and Arch packages install cleanly and link. +set -euo pipefail + +root=$(cd "$(dirname "$0")/../.." && pwd) +dist=${ELY_DIST:-$root/dist} +fail() { + echo "FAIL: $*" >&2 + exit 1 +} +command -v docker >/dev/null || { + echo "SKIP: no docker" + exit 0 +} +version=$(awk -F'"' '/^version = / { print $2; exit }' "$root/Cargo.toml") +batch=$(awk -F'\t' '$4 == 1 { print $1 }' "$root/packaging/apps.tsv") +# Entry points exist; every ELF file finds its libraries. +check='set -euo pipefail +slug=$1 +entry=/opt/ely-office/$slug/bin/$slug +[ -x "/usr/bin/$slug" ] || { echo "no /usr/bin/$slug"; exit 1; } +[ "$(readlink -f "/usr/bin/$slug")" = "$entry" ] || { echo "bad /usr/bin/$slug"; exit 1; } +[ -f "/usr/share/applications/$slug.desktop" ] || { echo "no desktop entry"; exit 1; } +[ -f "/usr/share/icons/hicolor/512x512/apps/$slug.png" ] || { echo "no icon"; exit 1; } +for lib in libvulkan.so.1 libwayland-client.so.0; do + ldconfig -p | grep "$lib" >/dev/null || { echo "no $lib"; exit 1; } +done +ldd "$entry" >/dev/null || { echo "$entry is not a dynamic executable"; exit 1; } +find "/opt/ely-office/$slug" -type f -print0 >/tmp/files || { echo "cannot list files"; exit 1; } +checked=0 +while IFS= read -r -d "" file; do + magic=$(head -c 4 "$file" | od -An -c | tr -d " ") || { echo "cannot read $file"; exit 1; } + [ "$magic" = 177ELF ] || continue + checked=$((checked + 1)) + if ! out=$(ldd "$file" 2>&1); then + # git-lfs is static Go: it must run. + [ "${file##*/}" = git-lfs ] && "$file" version >/dev/null && continue + echo "$file: $out"; exit 1 + fi + if [[ $out == *"not found"* ]]; then + echo "$file:"; printf "%s\n" "$out" | grep "not found"; exit 1 + fi +done /tmp/install.log 2>&1 || + { tail -20 /tmp/install.log; exit 1; }; bash -c '$check' _ $4" || + fail "$3 does not install or link in $1" +} +ubuntu=ubuntu:26.04@sha256:f144425ff09be612d6d9ad965196e9cdc23dae1f42110a8a11a3e9a8198759f7 +fedora=fedora:44@sha256:43b29f65a41eb9c35e1cd5323e3bdf3b655c2357a9f4f1ff2f9c2798e5045d80 +arch=archlinux@sha256:4e77cf2ea5f410e6f8be5abf93ccf17ce2436e87a138c167208356711a405dbd +for slug in $batch; do + deb=$dist/${slug}_$version-1_amd64.deb + rpm=$dist/$slug-$version-1.x86_64.rpm + pkg=$dist/$slug-$version-1-x86_64.pkg.tar.zst + for file in "$deb" "$rpm" "$pkg"; do + [ -f "$file" ] || fail "no $file; run packaging/linux/package.sh $slug" + done + run "$ubuntu" "apt-get update -q && apt-get install -y -q" "$deb" "$slug" + run "$fedora" "dnf install -y -q" "$rpm" "$slug" + run "$arch" "pacman -Sy --noconfirm && pacman -U --noconfirm" "$pkg" "$slug" +done +echo "linux-packages: deb, rpm and Arch packages install and link" diff --git a/tests/scripts/appimage-pins.sh b/tests/scripts/linux-pins.sh similarity index 66% rename from tests/scripts/appimage-pins.sh rename to tests/scripts/linux-pins.sh index 01c61d2..30e2991 100755 --- a/tests/scripts/appimage-pins.sh +++ b/tests/scripts/linux-pins.sh @@ -1,9 +1,9 @@ #!/usr/bin/env bash -# Every AppImage tool the recipe downloads matches its pinned hash. +# Every Linux packaging tool downloaded matches its pinned hash. set -euo pipefail root=$(cd "$(dirname "$0")/../.." && pwd) -script=$root/packaging/linux/appimage.sh +script=$root/packaging/linux/package.sh fail() { echo "FAIL: $*" >&2 exit 1 @@ -12,18 +12,22 @@ fail() { pack=https://github.com/AppImage/appimagetool/releases/download/1.9.1 deploy=https://github.com/linuxdeploy/linuxdeploy/releases/download/1-alpha-20251107-1 runtime=https://github.com/AppImage/type2-runtime/releases/download/20251108 +nfpm=https://github.com/goreleaser/nfpm/releases/download/v2.47.0 curl -fsSI --max-time 20 "$pack/appimagetool-x86_64.AppImage" >/dev/null 2>&1 || { - echo "SKIP appimage-pins: GitHub is not reachable" + echo "SKIP linux-pins: GitHub is not reachable" exit 0 } grep -q "$pack/appimagetool-\$arch.AppImage" "$script" || fail "the script downloads another appimagetool" grep -q "$deploy/linuxdeploy-\$arch.AppImage" "$script" || fail "the script downloads another linuxdeploy" grep -q "$runtime/runtime-\$arch" "$script" || fail "the script downloads another runtime" +grep -q "$nfpm/nfpm_2.47.0_Linux_\$nfpm_arch.tar.gz" "$script" || fail "the script downloads another nfpm" grep -q -- '--runtime-file "\$runtime"' "$script" || fail "appimagetool fetches its own runtime" -for arch in x86_64 aarch64; do - for url in "$pack/appimagetool-$arch.AppImage" "$deploy/linuxdeploy-$arch.AppImage" "$runtime/runtime-$arch"; do +for pair in x86_64:x86_64 aarch64:arm64; do + arch=${pair%:*} + for url in "$pack/appimagetool-$arch.AppImage" "$deploy/linuxdeploy-$arch.AppImage" "$runtime/runtime-$arch" \ + "$nfpm/nfpm_2.47.0_Linux_${pair#*:}.tar.gz"; do sha=$(curl -fsSL "$url" | shasum -a 256 | cut -d' ' -f1) grep -q "$sha" "$script" || fail "$url has sha256 $sha, which the script does not pin" done done -echo "appimage-pins: 6 downloads match their pins" +echo "linux-pins: 8 downloads match their pins" diff --git a/tests/scripts/types.sh b/tests/scripts/types.sh index ded206e..26d9b72 100755 --- a/tests/scripts/types.sh +++ b/tests/scripts/types.sh @@ -10,7 +10,7 @@ fail() { } count=0 for slug in $(cut -f1 "$types" | sort -u); do - desktop=$("$root/packaging/linux/appimage.sh" --desktop "$slug") + desktop=$("$root/packaging/linux/package.sh" --desktop "$slug") windows=$("$root/packaging/windows/types.sh" "$slug") rows=$(awk -F'\t' -v slug="$slug" '$1 == slug' "$types") while IFS=$'\t' read -r _ ext mime; do