Windows kernel no longer hangs on a second start; CI for three platforms
Lightproof, the Python grammar checker in the English dictionaries, hung the Windows worker whenever a profile was reused; macOS and Linux carry no Python, so it never ran there. The build now drops it. A killed worker's profile and document locks hung the next start or load: the worker runs with SAL_NOLOCK_PROFILE and ely.xcd turns off LibreOffice's locking; Ely checks conflicts itself. release.yml runs scripts/ci.sh for each platform on tag push: the Mac mini builds its engines once in a lasting clone, the Windows runner links this machine's engines, and Linux builds in WSL on that runner. makensis reads the script as UTF-8. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
126175e589
commit
e48035cdd5
8 files changed
+151
-19
No files matched your search
@@ -1,16 +0,0 @@
|
||||
name: probe
|
||||
on: workflow_dispatch
|
||||
jobs:
|
||||
probe:
|
||||
runs-on: macos-arm64
|
||||
steps:
|
||||
- name: Where the Mac keeps Rust and Ely Office
|
||||
shell: bash
|
||||
run: |
|
||||
ls "$HOME/.cargo/bin" 2>/dev/null | head -5
|
||||
find "$HOME" -maxdepth 5 -type d -name ElyOffice -not -path "*/Library/*" 2>/dev/null | head -5
|
||||
for d in $(find "$HOME" -maxdepth 5 -type d -name ElyOffice -not -path "*/Library/*" 2>/dev/null | head -3); do
|
||||
echo "== $d"; ls "$d/engines" 2>/dev/null | tr '\n' ' '; echo; git -C "$d" log --oneline -1 2>/dev/null
|
||||
ls "$d/engines/lo-src/instdir/LibreOffice.app/Contents/Frameworks/libmergedlo.dylib" 2>/dev/null
|
||||
done
|
||||
security find-identity -v -p codesigning 2>/dev/null | head -3
|
||||
@@ -0,0 +1,57 @@
|
||||
# A tag builds, packages and uploads all three platforms.
|
||||
name: release
|
||||
on:
|
||||
push:
|
||||
tags: ['v*']
|
||||
jobs:
|
||||
macos:
|
||||
runs-on: macos-arm64
|
||||
timeout-minutes: 720
|
||||
steps:
|
||||
- name: Build, package and upload for macOS
|
||||
shell: bash
|
||||
env:
|
||||
ELY_RELEASE_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
ELY_PATH: /Users/zacharyzhang/.cargo/bin:/opt/homebrew/bin
|
||||
run: |
|
||||
dir=$HOME/ely-ci/ElyOffice
|
||||
[ -d "$dir/.git" ] || git clone https://git.zacharyzhang.com/ZacharyZhang-NY/ElyOffice.git "$dir"
|
||||
git -C "$dir" fetch --force --tags origin
|
||||
git -C "$dir" checkout --force "${{ github.sha }}"
|
||||
"$dir/scripts/ci.sh" macos "${{ github.ref_name }}"
|
||||
windows:
|
||||
runs-on: windows
|
||||
timeout-minutes: 360
|
||||
steps:
|
||||
- name: Build, package and upload for Windows
|
||||
shell: bash
|
||||
env:
|
||||
ELY_RELEASE_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
ELY_SHARE: /c/Users/zhang/Documents/Github/ElyOffice
|
||||
ELY_PATH: /c/Program Files/CMake/bin:/c/Users/zhang/AppData/Local/Microsoft/WinGet/Packages/Ninja-build.Ninja_Microsoft.Winget.Source_8wekyb3d8bbwe
|
||||
run: |
|
||||
dir=$HOME/ely-ci/ElyOffice
|
||||
[ -d "$dir/.git" ] || git clone https://git.zacharyzhang.com/ZacharyZhang-NY/ElyOffice.git "$dir"
|
||||
git -C "$dir" fetch --force --tags origin
|
||||
git -C "$dir" checkout --force "${{ github.sha }}"
|
||||
"$dir/scripts/ci.sh" windows "${{ github.ref_name }}"
|
||||
linux:
|
||||
# WSL on the Windows runner keeps a built kernel.
|
||||
runs-on: windows
|
||||
needs: windows
|
||||
timeout-minutes: 360
|
||||
steps:
|
||||
- name: Build, package and upload for Linux
|
||||
shell: bash
|
||||
env:
|
||||
ELY_RELEASE_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
WSLENV: ELY_RELEASE_TOKEN
|
||||
run: |
|
||||
wsl -d Ubuntu -- bash -lc '
|
||||
set -euo pipefail
|
||||
dir=$HOME/ely-ci/ElyOffice
|
||||
[ -d "$dir/.git" ] || git clone https://git.zacharyzhang.com/ZacharyZhang-NY/ElyOffice.git "$dir"
|
||||
git -C "$dir" fetch --force --tags origin
|
||||
git -C "$dir" checkout --force "${{ github.sha }}"
|
||||
ELY_SHARE=$HOME/Documents/Github/ElyOffice "$dir/scripts/ci.sh" linux "${{ github.ref_name }}"
|
||||
'
|
||||
@@ -282,5 +282,5 @@ 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`)。
|
||||
- 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-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 地址取。
|
||||
@@ -150,7 +150,9 @@ impl Worker {
|
||||
command
|
||||
.arg(install)
|
||||
.arg(profile_dir)
|
||||
.env("SAL_FORCE_HIDPI_SCALING", "1");
|
||||
.env("SAL_FORCE_HIDPI_SCALING", "1")
|
||||
// A killed worker's profile lock would hang the next.
|
||||
.env("SAL_NOLOCK_PROFILE", "1");
|
||||
// Linux tiles via cairo are BGRA; Skia there is RGBA.
|
||||
match cfg!(target_os = "linux") {
|
||||
true => command.env("SAL_DISABLESKIA", "1"),
|
||||
|
||||
@@ -77,4 +77,12 @@
|
||||
</node>
|
||||
</node>
|
||||
</oor:component-data>
|
||||
<!-- Ely checks conflicts itself; a crash's lock file would hang the next load. -->
|
||||
<oor:component-data oor:package="org.openoffice.Office" oor:name="Common">
|
||||
<node oor:name="Misc">
|
||||
<prop oor:name="UseLocking">
|
||||
<value>false</value>
|
||||
</prop>
|
||||
</node>
|
||||
</oor:component-data>
|
||||
</oor:data>
|
||||
@@ -22,7 +22,7 @@ types=$root/target/stage/$slug-types.nsh
|
||||
"$root/packaging/windows/types.sh" "$slug" >"$types"
|
||||
mkdir -p "$dist"
|
||||
out=$dist/$name-$version-windows-x86_64-setup.exe
|
||||
"$makensis" -V2 -DAPP_NAME="$name" -DAPP_SLUG="$slug" -DVERSION="$version" \
|
||||
"$makensis" -V2 -INPUTCHARSET UTF8 -DAPP_NAME="$name" -DAPP_SLUG="$slug" -DVERSION="$version" \
|
||||
-DSTAGE="$(cygpath -w "$stage")" -DICON="$(cygpath -w "$root/assets/icons/$slug.ico")" \
|
||||
-DTYPES="$(cygpath -w "$types")" -DOUTFILE="$(cygpath -w "$out")" \
|
||||
"$(cygpath -w "$root/packaging/windows/installer.nsi")"
|
||||
|
||||
@@ -132,6 +132,20 @@ for dict in "$extensions"/dict-*; do
|
||||
fi
|
||||
done
|
||||
echo "build-libreoffice.sh: dictionaries kept: $(ls "$extensions" | tr '\n' ' ')"
|
||||
# Lightproof is Python: inert without it, a hang on Windows.
|
||||
en=$extensions/dict-en
|
||||
rm -rf "$en/Lightproof.py" "$en/Lightproof.components" "$en/Linguistic.xcu" "$en/pythonpath" "$en/dialog"
|
||||
python3 - "$en/META-INF/manifest.xml" <<'PY'
|
||||
import re, sys
|
||||
path = sys.argv[1]
|
||||
text = open(path, encoding="utf-8").read()
|
||||
gone = r'\s*<manifest:file-entry[^>]*?"(?:Lightproof\.components|Linguistic\.xcu|dialog/[^"]*)"[^>]*/>'
|
||||
kept = re.sub(gone, "", text, flags=re.S)
|
||||
for left in ("Lightproof", "Linguistic.xcu", "dialog/"):
|
||||
if left in kept:
|
||||
sys.exit(f"build-libreoffice.sh: {left} is still in {path}")
|
||||
open(path, "w", encoding="utf-8").write(kept)
|
||||
PY
|
||||
# Ely's kernel defaults: Excel A1 formulas.
|
||||
cp "$root/packaging/libreoffice/ely.xcd" "$app/registry/"
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env bash
|
||||
# A platform's release. Usage: ci.sh <macos|windows|linux> <tag>
|
||||
set -euo pipefail
|
||||
|
||||
root=$(cd "$(dirname "$0")/.." && pwd)
|
||||
os=${1:?macos, windows or linux}
|
||||
tag=${2:?the release tag, such as v0.1.3}
|
||||
version=$(awk -F'"' '/^version = / { print $2; exit }' "$root/Cargo.toml")
|
||||
[ "$tag" = "v$version" ] || {
|
||||
echo "ci.sh: tag $tag is not v$version" >&2
|
||||
exit 1
|
||||
}
|
||||
: "${ELY_RELEASE_TOKEN:?the Gitea token that uploads}"
|
||||
[ -z "${ELY_PATH:-}" ] || PATH=$ELY_PATH:$PATH
|
||||
cd "$root"
|
||||
|
||||
# Engines another clone on this host built; else built here.
|
||||
if [ -n "${ELY_SHARE:-}" ]; then
|
||||
for part in engines reference; do
|
||||
if [ ! -e "$part" ]; then
|
||||
case $os in
|
||||
windows) cmd //c mklink /J "$part" "$(cygpath -w "$ELY_SHARE/$part")" ;;
|
||||
*) ln -s "$ELY_SHARE/$part" "$part" ;;
|
||||
esac
|
||||
fi
|
||||
done
|
||||
else
|
||||
scripts/fetch-references.sh
|
||||
scripts/build-mupdf.sh
|
||||
scripts/fetch-cef.sh
|
||||
scripts/build-git.sh
|
||||
scripts/fetch-git-lfs.sh
|
||||
scripts/fetch-tessdata.sh
|
||||
scripts/build-mark-content.sh
|
||||
scripts/build-libreoffice.sh
|
||||
fi
|
||||
|
||||
dist=$root/dist
|
||||
rm -rf "$dist"
|
||||
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 ;;
|
||||
*)
|
||||
echo "ci.sh: no release for $os" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# The tag's release, made by whichever platform comes first.
|
||||
api=https://git.zacharyzhang.com/api/v1/repos/ZacharyZhang-NY/ElyOffice
|
||||
auth="Authorization: token $ELY_RELEASE_TOKEN"
|
||||
release_id() { curl -fsS -H "$auth" "$api/releases/tags/$tag" | python3 -c 'import json, sys; print(json.load(sys.stdin)["id"])'; }
|
||||
if ! id=$(release_id 2>/dev/null); then
|
||||
body="{\"tag_name\": \"$tag\", \"name\": \"Ely Office $version\"}"
|
||||
# Another platform may make it first; the read decides.
|
||||
curl -fsS -H "$auth" -H "Content-Type: application/json" -d "$body" "$api/releases" >/dev/null || true
|
||||
id=$(release_id)
|
||||
fi
|
||||
for file in "$dist"/*; do
|
||||
[ -f "$file" ] || continue
|
||||
name=$(basename "$file")
|
||||
echo "ci.sh: uploading $name"
|
||||
curl -fsS -H "$auth" -F "attachment=@$file" "$api/releases/$id/assets?name=$name" >/dev/null
|
||||
done
|
||||
echo "ci.sh: $os uploaded to $tag"
|
||||
Reference in new issue
Block a user