SeatFlow 构建命令、多平台发布脚本、确定性构建、GitCommit 自动生成和 SHA256 校验表
本页目录
全部文档
构建与发布
构建
环境要求
- .NET 10 SDK
- Windows / macOS(需要Apple开发者账号) / Linux
- 推荐 IDE:Rider、VS Code + C# 扩展、Visual Studio 2022+
构建命令
# 构建全部 9 个项目(使用 .slnx)
dotnet build
# 构建特定项目
dotnet build src/SeatFlow.Presentation.Avalonia/SeatFlow.Presentation.Avalonia.csproj
# 还原 NuGet 依赖
dotnet restore
解决方案结构
SeatFlow.slnx 使用新的 XML 格式(.slnx),包含 9 个项目:
| 项目 | 用途 |
|---|---|
SeatFlow.Core |
领域核心 |
SeatFlow.Core.Tests |
Core 层测试 |
SeatFlow.Contracts |
跨层契约 |
SeatFlow.Application |
应用层 |
SeatFlow.Application.Tests |
Application 层测试 |
SeatFlow.Infrastructure |
基础设施 |
SeatFlow.Infrastructure.Tests |
Infrastructure 层测试 |
SeatFlow.Plugins.Sdk |
插件 SDK |
SeatFlow.Presentation.Avalonia |
Avalonia 桌面应用 |
项目配置要点
关键 csproj 设置(SeatFlow.Presentation.Avalonia.csproj):
<!-- 输出文件名 -->
<AssemblyName>SeatFlow</AssemblyName>
<!-- 输出 EXE 为 SeatFlow.exe,而非 SeatFlow.Presentation.Avalonia.exe -->
<!-- 编译绑定 -->
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
<!-- 抑制 DI 构造函数警告 -->
<NoWarn>$(NoWarn);AVLN3001</NoWarn>
<!-- Designer.cs 条件编译 -->
<Compile Remove="Lang\Resources.Designer.cs"
Condition="!Exists('Lang\Resources.Designer.cs')" />
<!-- Windows DPI 感知 -->
<ApplicationManifest>app.manifest</ApplicationManifest>
确定性构建
项目配置了确定性构建,确保相同源码始终产生相同的输出哈希:
<Deterministic>true</Deterministic>
<PathMap>$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)'))=./</PathMap>
<Deterministic>true</Deterministic>:启用确定性编译,相同源码 → 相同 IL<PathMap>:将绝对路径映射为相对路径./,消除构建机器的路径差异
排查非确定性构建
如果多次 dotnet build 产生不同的输出哈希,检查以下常见原因:
- 自动生成的
GitCommit.g.cs是否包含提交哈希(每次提交不同,但相同提交应相同) - NuGet 包还原是否一致
- 时间戳属性(如
<SourceRevisionId>、<Version>)是否在构建间变化
GitCommit 自动生成
构建时自动生成 GitCommit.g.cs 文件,包含当前 git 提交哈希:
// $(IntermediateOutputPath)Generated\GitCommit.g.cs
internal static class GitCommit
{
public const string Hash = "abc1234";
}
实现机制
MSBuild 目标 GenerateGitCommit 在每次构建前运行:
<Target Name="GenerateGitCommit" BeforeTargets="BeforeBuild">
<Exec Command="git rev-parse --short HEAD"
ConsoleToMSBuild="true"
StandardOutputImportance="low"
IgnoreExitCode="true">
<Output TaskParameter="ConsoleOutput" PropertyName="GitCommitHash" />
</Exec>
<PropertyGroup>
<GitCommitHash Condition="'$(GitCommitHash)' == ''">unknown-commit-id</GitCommitHash>
</PropertyGroup>
<WriteLinesToFile
File="$(IntermediateOutputPath)Generated\GitCommit.g.cs"
Lines="...
public const string Hash = "$(GitCommitHash)";..."
Overwrite="true" />
</Target>
- 生成的文件位于
$(IntermediateOutputPath)Generated\GitCommit.g.cs(如obj/Debug/net10.0/Generated/) - 通过
obj/目录的.gitignore规则间接排除,不提交到版本控制 - git 不可用时回退到
"unknown-commit-id"
在代码中的使用
// TelemetryService.cs — 上报时附加提交标识
var commitId = GitCommit.Hash;
// AboutViewModel.cs — 版本号包含提交 ID
Version = $"{VersionInfo.Version}-{VersionInfo.CommitId}";
显示格式示例:1.5.0-abc1234
发布脚本
scripts/build/publish.sh(Linux/macOS)和 scripts/build/publish.ps1(Windows)是多平台发布工具,支持交互式和 CLI 模式。
交互模式
cd scripts/build
./publish.sh # 启动 TUI 交互界面
# 在交互界面中选择:
# - 发布类型(自包含/框架依赖/全部)
# - 目标平台(Windows x64、Linux x64、macOS x64/arm64)
# - 构建配置(Debug/Release)
# - 可选选项(裁剪、AOT)
CLI 模式
# 语法: publish.sh <mode> <config> [opt] [suffix] [version] [clean] [aot]
# 全平台自包含+框架依赖,裁剪+AOT
./publish.sh both Release opt "" "1.2.1" clean aot
# 仅 Windows x64 自包含发布
./publish.sh full Release "" "" "1.2.1" clean
# 仅框架依赖发布(不包含运行时)
./publish.sh slim Release "" "" "1.2.1"
# 为已有发布文件生成 SHA256 校验表
./publish.sh hash
发布类型
| 类型 | 参数 | 说明 |
|---|---|---|
| 全部(both) | both |
同时生成自包含和框架依赖两种发布 |
| 自包含(full) | full |
包含 .NET 运行时,无需预装 SDK |
| 框架依赖(slim) | slim |
不包含运行时,文件更小 |
发布选项
| 选项 | 参数 | 说明 |
|---|---|---|
| 清理 | clean |
构建前清理输出目录 |
| AOT | aot |
使用 Native AOT 预编译(仅自包含) |
| 裁剪 | opt |
启用 IL 裁剪减小体积(仅自包含) |
目标平台
| 平台 | RID | 说明 |
|---|---|---|
| Windows | win-x64 |
输出 .exe + .zip |
| Linux | linux-x64 |
输出 .tar.gz |
| macOS Intel | osx-x64 |
输出 .tar.gz |
| macOS Apple Silicon | osx-arm64 |
输出 .tar.gz |
SHA256 校验表
publish.sh hash 扫描 publish/ 目录下所有 SeatFlow-* 文件,输出 Markdown 格式的 SHA256 校验表到标准输出。校验表同时会嵌入 GitHub Release 正文中。
| File | SHA256 |
|------|--------|
| SeatFlow-1.2.1-win-x64.zip | a1b2c3d4... |
| SeatFlow-1.2.1-linux-x64.tar.gz | e5f6g7h8... |
| SeatFlow-1.2.1-osx-arm64.tar.gz | i9j0k1l2... |
清理脚本
scripts/build/clean.sh 和 scripts/build/clean.ps1 递归清理所有项目的 bin/ 和 obj/ 目录。
cd scripts/build
# 确认后删除
./clean.sh
# 预览模式(dry-run)
./clean.sh -n
# 强制删除(跳过确认)
./clean.sh -f
运行应用
# 开发模式运行
dotnet run --project SeatFlow.Presentation.Avalonia
# 发布后运行(自包含)
./publish/SeatFlow_1.2.1_linux-x64/SeatFlow
WatchdogService
生产运行时,WatchdogService 会监测 UI 线程响应。如果 UI 线程卡顿超过 45 秒,服务会:
- 收集进程信息(PID、内存、线程数、句柄数、CPU 时间)、所有线程状态和托管线程池信息
- 将诊断信息写入
err_<yyyyMMdd-HHmmss>.log - 尝试弹出错误对话框
- 通过
Environment.Exit(1)强制退出应用
这在开发调试时需要注意——如果断点暂停超过 45 秒,进程会被杀死。
Velopack 打包
SeatFlow 通过 release.py 编排完整的 Velopack 打包流程,包括:
- 自动更新支持
- 增量更新(delta updates)
- 静默安装和卸载
- 生成
.nupkg+ 安装程序 +releases.{channel}.json更新源
Velopack 深度集成在 Presentation 层:Program.cs 通过 VelopackApp.Build() 注册钩子,UpdateService 使用 UpdateManager 实现自动更新检查和下载,VelopackLocator 用于运行时目录检测。
详见 ADR-010。
构建验证清单
每次提交前执行:
# 1. 编译验证
dotnet build
# 2. 全部测试
dotnet test
# 3. 脚本测试
python3 -m pytest scripts/tests/ -v
# 4. i18n 一致性(可选)
python3 scripts/i18n.py check
故障排查
构建失败:Designer.cs 不存在
运行 python3 scripts/i18n.py sync 生成 Resources.Designer.cs。
构建失败:Avalonia 编译绑定错误
确保所有 {x:Static} 引用正确,且命名空间声明正确:
xmlns:lang="using:SeatFlow.Presentation.Avalonia.Lang"
发布失败:AOT 不支持某些 API
Native AOT 不支持以下功能:
- 运行时代码生成
- 反射(部分支持)
System.Reflection.Emit
如果在 AOT 构建中遇到错误,检查代码是否使用了不兼容的 API。