docs: explain application entry points and tooling workflows
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
# macOS 应用打包入口:构建 release 可执行文件并组装最小 Tessera.app;脚本本身不运行测试或部署。
|
||||
# 执行会产生构建产物,应在已确认的 macOS 构建环境中调用。
|
||||
# 任一命令失败或使用未定义变量即退出,避免在失败编译后继续打包旧文件。
|
||||
# 构建调用方显式执行此脚本才产生文件;阅读或 sh -n 仅检查语法,不会运行下方 Cargo。
|
||||
set -eu
|
||||
# 此入口只能在 macOS 使用;构建授权由调用方确认,脚本不自动执行测试或部署。
|
||||
if [ "$(uname -s)" != Darwin ]; then
|
||||
@@ -11,17 +12,21 @@ fi
|
||||
# 以脚本所在目录的父目录作为仓库根;清空这一次 cd 的 CDPATH,防止用户 shell 配置改变目录解析。
|
||||
cd "$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)"
|
||||
# 锁定依赖并生成 release 可执行文件;附加参数原样交给 Cargo。
|
||||
# 这里确实触发编译,不是只验证清单;依赖锁不匹配时 --locked 要求失败而非自动更新 Cargo.lock。
|
||||
cargo build --release --locked "$@"
|
||||
# 从 Cargo 包元数据读取首个 version 值,空值由 test 拒绝,不生成缺版本的 bundle。
|
||||
# version 从清单文本读取,后面用于两个 plist 版本键;脚本不调用构建后的 Tessera 来查询版本。
|
||||
version=$(awk -F '"' '$1 ~ /^version[[:space:]]*=/ { print $2; exit }' Cargo.toml)
|
||||
test -n "$version"
|
||||
# macOS bundle 约定:Contents/MacOS 保存入口二进制,Contents/Info.plist 保存系统识别信息。
|
||||
bundle="$(pwd)/target/release/Tessera.app"
|
||||
# 创建/复用固定 release 产物目录,不清空旧 bundle;后面逐文件替换主二进制和元数据。
|
||||
mkdir -p "$bundle/Contents/MacOS"
|
||||
# 先写临时文件再重命名,避免复制途中将半个二进制留作 bundle 的主程序。
|
||||
cp target/release/tessera "$bundle/Contents/MacOS/tessera.new"
|
||||
mv -f "$bundle/Contents/MacOS/tessera.new" "$bundle/Contents/MacOS/tessera"
|
||||
# 生成最小 macOS bundle 元数据;应用名、入口与高分辨率标志供系统启动/显示使用。
|
||||
# heredoc 展开本次 version,XML 文本与入口文件名相互对应;这里没有签名、公证或安装动作。
|
||||
cat > "$bundle/Contents/Info.plist.new" <<PLIST
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
|
||||
@@ -6,6 +6,7 @@ import { readFile, readdir, mkdir, writeFile } from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||
|
||||
// 文档维护者从命令行执行本脚本;运行时入口不导入它,依赖应事先安装,本脚本不执行包管理器。
|
||||
const tools = process.env.UML_RENDER_TOOLS;
|
||||
// 工具依赖放在独立目录,避免给应用运行依赖增加文档渲染包。
|
||||
if (!tools) throw new Error('Set UML_RENDER_TOOLS to the documentation tool directory; see docs/architecture/uml/README.md');
|
||||
@@ -67,6 +68,7 @@ document.createElementNS = (namespace, tag) => {
|
||||
document.body = element('body');
|
||||
document.documentElement.appendChild(document.body);
|
||||
globalThis.document = document;
|
||||
// 全局 DOM/Canvas 适配已设置完毕才加载引擎,避免模块初始化读取到缺失的浏览器接口。
|
||||
const { renderToString } = await import(pathToFileURL(require.resolve('@plantuml/core')));
|
||||
// 仓库位置由脚本 URL 确定,与调用者工作目录无关;输出目录不存在时创建。
|
||||
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||
@@ -80,6 +82,7 @@ for (const filename of (await readdir(source)).filter(name => name.endsWith('.pu
|
||||
// 将引擎 resolve/reject 回调适配为 Promise,逐图等待;渲染失败直接终止,不覆盖该图产物。
|
||||
const rendered = await new Promise((resolve, reject) => renderToString(text.split('\n'), resolve, reject));
|
||||
const xml = new DOMParser().parseFromString(rendered, 'image/svg+xml');
|
||||
// 引擎有时以正常 SVG 输出错误页,所以不能只判断 Promise resolve;还要检查文字层的错误标签。
|
||||
const labels = Array.from(xml.getElementsByTagName('text'), node => node.textContent).join('\n');
|
||||
if (xml.documentElement.tagName !== 'svg' || /syntax error|error line|assumed diagram type|an error has occurr/i.test(labels)) {
|
||||
throw new Error(`${filename}: renderer returned an error diagram\n${labels}`);
|
||||
@@ -88,9 +91,11 @@ for (const filename of (await readdir(source)).filter(name => name.endsWith('.pu
|
||||
const paper = xml.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
||||
for (const [key, value] of Object.entries({ x: '0', y: '0', width: '100%', height: '100%', fill: '#FFFFFF' })) paper.setAttribute(key, value);
|
||||
xml.documentElement.insertBefore(paper, xml.documentElement.firstChild);
|
||||
// 序列化修改后的 DOM,而不是直接写引擎原字符串,确保白底矩形进入两个导出格式。
|
||||
const svg = new XMLSerializer().serializeToString(xml);
|
||||
// 同时保存可缩放 SVG 和通用 PNG;写完读取 PNG 元数据确认生成尺寸。
|
||||
const stem = filename.slice(0, -5);
|
||||
// 两种产物顺序写入且不组成事务;SVG 成功后若 PNG 失败,前面已写出的文件不会自动回滚。
|
||||
await writeFile(path.join(output, `${stem}.svg`), svg);
|
||||
// 以 192 DPI 光栅化为 PNG 供通用预览;SVG 同时保留矢量文字和缩放能力。
|
||||
const png = sharp(Buffer.from(svg), { density: 192 });
|
||||
|
||||
Reference in New Issue
Block a user