diff --git a/agents.md b/agents.md index 34102c5..c54e9e4 100644 --- a/agents.md +++ b/agents.md @@ -133,6 +133,8 @@ tests/scripts/lo-patches.sh 补丁序列从中途接着打、再打一次为 tests/scripts/media-targets.sh 媒体播放接口在 Linux、Windows 目标可编译(缺目标时 SKIP) tests/scripts/linux-idle.sh 真窗口 ElyTree:打开仓库后、Omarchy 换主题与改设置后,空闲时不读主题、设置,不跑 git status;照样跟随换主题、改设置与改文件,经内存映射的写入也跟随 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 cargo test -p ely-show --test compose 切换半程帧经 Metal 取像素(主线程,仅 macOS) tests/scripts/*.sh *.py 脚本测试(缺工具时报 SKIP) packaging/macos/bundle.sh ely-doc debug 出 dist/ElyDoc.app(带图标、文档类型与该应用的引擎) @@ -296,3 +298,4 @@ cargo run -p ely-doc 启动一个应用(ElyDoc 先 cargo build -p ely - 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 不算)。 diff --git a/packaging/linux/Dockerfile b/packaging/linux/Dockerfile new file mode 100644 index 0000000..13856fa --- /dev/null +++ b/packaging/linux/Dockerfile @@ -0,0 +1,20 @@ +# Linux builds on glibc 2.43 run on Ubuntu 26.04 onward. +FROM ubuntu:26.04@sha256:f144425ff09be612d6d9ad965196e9cdc23dae1f42110a8a11a3e9a8198759f7 + +ENV DEBIAN_FRONTEND=noninteractive +RUN sed -i 's/^Types: deb$/Types: deb deb-src/' /etc/apt/sources.list.d/ubuntu.sources \ + && apt-get update \ + && apt-get build-dep -y libreoffice \ + && 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 \ + 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 \ + && rm -rf /var/lib/apt/lists/* +ENV RUSTUP_HOME=/opt/rustup +# As rust-toolchain.toml pins it. +RUN rustup toolchain install 1.96.0 --profile minimal --component rustfmt,clippy \ + && rustup default 1.96.0 \ + && chmod -R a+rX /opt/rustup diff --git a/packaging/linux/container.sh b/packaging/linux/container.sh new file mode 100755 index 0000000..597ccd7 --- /dev/null +++ b/packaging/linux/container.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# Usage: container.sh ; runs it in Ubuntu 26.04. +set -euo pipefail + +root=$(cd "$(dirname "$0")/../.." && pwd) +[ $# -gt 0 ] || { + echo "container.sh: give a command, such as scripts/build-libreoffice.sh" >&2 + exit 1 +} +image=ely-office-linux-build +docker build -q -t "$image" "$root/packaging/linux" >/dev/null +# Own target and Cargo home: host builds need newer glibc. +mkdir -p "$root/target/ubuntu" "$root/target/ubuntu-cargo" "$root/target/ubuntu-home" +docker run --rm --user "$(id -u):$(id -g)" -v "$root:$root" -w "$root" \ + -e HOME="$root/target/ubuntu-home" -e CARGO_HOME="$root/target/ubuntu-cargo" \ + -e CARGO_TARGET_DIR="$root/target/ubuntu" -e ELY_RELEASE_TOKEN \ + "$image" "$@" diff --git a/packaging/stage.sh b/packaging/stage.sh index 48d8435..d163d0d 100755 --- a/packaging/stage.sh +++ b/packaging/stage.sh @@ -25,16 +25,17 @@ need() { # path, what to run } } build() { cargo build --manifest-path "$root/Cargo.toml" --release "$@"; } +release=${CARGO_TARGET_DIR:-$root/target}/release rm -rf "$out" mkdir -p "$out" build -p "$slug" -cp "$root/target/release/$slug$exe" "$out/" +cp "$release/$slug$exe" "$out/" if uses ely-lok; then lo=${ELY_LO_DIR:-$root/engines/lo-src/instdir} need "$lo/program" scripts/build-libreoffice.sh build -p ely-lok --bin ely-lok-worker - cp "$root/target/release/ely-lok-worker$exe" "$out/" + cp "$release/ely-lok-worker$exe" "$out/" # The kernel in LibreOffice's layout, beside the app. mkdir "$out/libreoffice" cp -R "$lo/program" "$lo/share" "$lo/presets" "$out/libreoffice/" @@ -56,7 +57,7 @@ if uses ely-pdf-engine; then tessdata=${ELY_TESSDATA:-$root/engines/tessdata} need "$tessdata/eng.traineddata" scripts/fetch-tessdata.sh build -p ely-pdf-engine --bin ely-pdf-worker - cp "$root/target/release/ely-pdf-worker$exe" "$out/" + cp "$release/ely-pdf-worker$exe" "$out/" mkdir "$out/tessdata" cp "$tessdata"/{eng,chi_sim,chi_tra}.traineddata "$out/tessdata/" fi diff --git a/scripts/build-git.sh b/scripts/build-git.sh index af920b5..fc5a4d3 100755 --- a/scripts/build-git.sh +++ b/scripts/build-git.sh @@ -38,6 +38,6 @@ if [ "$(cat "$out/.flags" 2>/dev/null)" != "$flags" ]; then rm -rf "$out" fi # shellcheck disable=SC2086 -make -C "$src" $flags -j"$jobs" install +env -u CARGO_TARGET_DIR make -C "$src" $flags -j"$jobs" install # Git's Rust uses its target/ echo "$flags" >"$out/.flags" "$out/bin/git" --version diff --git a/tasks/TASKS.md b/tasks/TASKS.md index 95233db..e0478d3 100644 --- a/tasks/TASKS.md +++ b/tasks/TASKS.md @@ -204,7 +204,7 @@ - [x] L1.1 Linux 显示后端:`gpui_platform` 开 `wayland` 与 `x11`(原样无头,“window open”而合成器里没有窗口);Omarchy(Hyprland)上 ElyTree 在 Wayland 与 X11 上画出窗口(其余五个要引擎,随 L1.6 实测);`tests/scripts/linux-backends.sh` — R1 锁文件、目标目录、未证明交帧;R2 产物路径、字形未核;R3 语言、OCR 错误被吞;R4 PASS - [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 -- [ ] L1.4 Linux 构建环境:`ubuntu:26.04` 容器里构建全部引擎与六个应用(glibc 不高于 2.43) +- [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/<应用>`,带桌面项、图标与文件类型 - [ ] L1.6 本机出六个应用的四种包;Omarchy 上装 Arch 包与 AppImage 出窗口;deb、rpm 在各自发行版的容器里装上并冒烟 - [ ] L1.7 v0.1.3:删去旧 AppImage,上传新包;`ci.sh` 的 Linux 产出四种包;agents.md 与官网随之 diff --git a/tasks/reviews/L1.4-r1.md b/tasks/reviews/L1.4-r1.md new file mode 100644 index 0000000..d002a73 --- /dev/null +++ b/tasks/reviews/L1.4-r1.md @@ -0,0 +1,9 @@ +FAIL + +- tests/scripts/linux-glibc.sh:26 — A failed `readelf` command is treated as evidence that the ELF is static. With `readelf` forced to return 1, the existing outputs still exit 0 and report all 187 ELF files compliant (`.work/L1.4-r1-readelf-failure.log`). A missing tool or failed inspection therefore bypasses every glibc check. Check tool availability explicitly and propagate inspection errors; skip version analysis only after a successful inspection establishes that the binary is static. + +- tests/scripts/linux-glibc.sh:19 — Required outputs only need to exist; non-ELF files are skipped at line 23, and line 32 requires just one ELF across all inputs. A compiled probe with eight text files in place of the applications/workers, empty LibreOffice and CEF directories, and one unrelated ELF under Git exits 0 (`.work/L1.4-r1-non-elf.log`). Validate each required application/worker as an ELF and require the actual engine binaries before scanning their versions. + +- tests/scripts/linux-glibc.sh:31 — The `find` process substitution loses enumeration failures, allowing a partial scan to pass. With valid ELF inputs and an unreadable LibreOffice subdirectory containing another ELF, `find` reports permission denied, but the test exits 0 and declares the 11 accessible ELF files compliant (`.work/L1.4-r1-find-failure.log`). Check and propagate the enumeration status before reporting success. + +- packaging/linux/container.sh:2 — Scoped comments violate the mandatory one-line, ten-word limit: this line has 12 words, line 12 has 11, packaging/linux/Dockerfile:1 has 12, and tests/scripts/linux-glibc.sh:2 has 11. scripts/build-git.sh:40 and :41 also form consecutive comment lines. The repository comment checker rejects the shell comments (`.work/L1.4-r1-comments.log`). Shorten the long comments and remove or separate the consecutive explanation and directive. diff --git a/tasks/reviews/L1.4-r2.md b/tasks/reviews/L1.4-r2.md new file mode 100644 index 0000000..25ca8cb --- /dev/null +++ b/tasks/reviews/L1.4-r2.md @@ -0,0 +1,7 @@ +FAIL + +- packaging/linux/container.sh:2 — The round 1 comment defect remains: this comment has eleven words, and scripts/build-git.sh:40–41 still has consecutive comment lines. Running tests/scripts/comments.py exits 1 and rejects both (`.work/L1.4-r2-comments.log`). Shorten the remaining long comment and remove or separate the consecutive comments. + +- tests/scripts/linux-glibc.sh:28 — Required outputs may be symlinks, but `find -type f` excludes them from version inspection. A compiled application probe declaring GLIBC_2.99 fails as a regular file; replacing it with a symlink to the identical ELF makes the test exit 0 and report only ten compliant files (`.work/L1.4-r2-probes.log`). Inspect every required ELF regardless of symlinks and include referenced engine libraries in the scan. + +- tests/scripts/linux-glibc.sh:32 — `is_elf` conflates failed reads with non-ELF content, so engine inspection errors still produce success. An additional LibreOffice library declaring GLIBC_2.99 correctly fails while readable; making that file unreadable prints `head: Permission denied` but exits 0 and declares the eleven other ELF files compliant (`.work/L1.4-r2-probes.log`). Propagate header-read failures and skip files only after successfully reading and identifying non-ELF content. diff --git a/tasks/reviews/L1.4-r3.md b/tasks/reviews/L1.4-r3.md new file mode 100644 index 0000000..8e5fac3 --- /dev/null +++ b/tasks/reviews/L1.4-r3.md @@ -0,0 +1,3 @@ +FAIL + +- tests/scripts/linux-glibc.sh:28 — The scan checks symlinked files but never traverses symlinked directories, so required engines can still escape version inspection. In the probe, a regular LibreOffice `program` directory containing `libmergedlo.so` declaring GLIBC_2.99 correctly fails; replacing that directory with a symlink to the same contents exits 0 and reports ten compliant ELF files. A linked library subdirectory also hides an incompatible library (`.work/L1.4-r3-probes.log`). Follow engine directory links while propagating traversal errors, and ensure every required ELF receives version inspection regardless of its directory layout. diff --git a/tasks/reviews/L1.4-r4.md b/tasks/reviews/L1.4-r4.md new file mode 100644 index 0000000..7ef22e9 --- /dev/null +++ b/tasks/reviews/L1.4-r4.md @@ -0,0 +1 @@ +PASS diff --git a/tests/scripts/linux-glibc.sh b/tests/scripts/linux-glibc.sh new file mode 100755 index 0000000..a0ef368 --- /dev/null +++ b/tests/scripts/linux-glibc.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# Linux builds need glibc 2.43 at most, as Ubuntu 26.04. +set -euo pipefail + +root=$(cd "$(dirname "$0")/../.." && pwd) +limit=2.43 +fail() { + echo "FAIL: $*" >&2 + exit 1 +} +for tool in objdump readelf; do + command -v "$tool" >/dev/null || { + echo "SKIP: no $tool" + exit 0 + } +done +release=$root/target/ubuntu/release +lo=$root/engines/lo-src/instdir/program +required=("$release"/ely-{doc,table,show,pdf,tree,mark,lok-worker,pdf-worker} "$lo/libmergedlo.so" + "$root/engines/git/bin/git" "$root/engines/cef/libcef.so") +for file in "${required[@]}"; do + [ -f "$file" ] || fail "no $file; build in packaging/linux/container.sh" + magic=$(head -c 4 "$file" | od -An -c | tr -d ' ') || fail "cannot read $file" + [ "$magic" = '177ELF' ] || fail "$file is not an ELF file" +done +list=$(mktemp) +trap 'rm -f "$list"' EXIT +find -L "$release"/ely-{doc,table,show,pdf,tree,mark,lok-worker,pdf-worker} "$lo" "$root/engines/git" \ + "$root/engines/cef" -type f -print0 >"$list" || fail "cannot list every file" +checked=0 +while IFS= read -r -d '' file; do + magic=$(head -c 4 "$file" | od -An -c | tr -d ' ') || fail "cannot read $file" + [ "$magic" = '177ELF' ] || continue + checked=$((checked + 1)) + headers=$(readelf -lW "$file") || fail "readelf cannot read $file" + # Static binaries, like git-lfs, need no glibc. + grep -q ' DYNAMIC ' <<<"$headers" || continue + symbols=$(objdump -T "$file") || fail "objdump cannot read $file" + need=$(sed -n 's/.*GLIBC_\([0-9.]*\).*/\1/p' <<<"$symbols" | sort -V | tail -n 1) + [ -z "$need" ] && continue + [ "$(printf '%s\n%s\n' "$need" "$limit" | sort -V | tail -n 1)" = "$limit" ] || + fail "${file#"$root"/} needs glibc $need, above $limit" +done <"$list" +echo "linux: $checked ELF files need glibc $limit at most"