From ca55fc175cd12cd2a516d7b5cc3d84580656754c Mon Sep 17 00:00:00 2001 From: chinboy Date: Fri, 14 Aug 2026 23:48:27 +0800 Subject: [PATCH] fix(Build): centralize generated artifact exclusions --- .gitignore | 2 + build/AtomUI.Repository.targets | 4 + .../AtomUIGallery/AtomUIGallery.csproj | 4 - .../foundations/build-and-packaging.md | 16 ++-- ...8-14-build-infrastructure-layout-design.md | 8 +- .../AtomUI.Controls.Shared.csproj | 4 - src/AtomUI.Controls/AtomUI.Controls.csproj | 4 - src/AtomUI.Core/AtomUI.Core.csproj | 4 - ...AtomUI.Desktop.Controls.ColorPicker.csproj | 4 - .../AtomUI.Desktop.Controls.DataGrid.csproj | 4 - .../AtomUI.Desktop.Controls.Extras.csproj | 4 - .../AtomUI.Desktop.Controls.csproj | 32 -------- .../AtomUI.Toolkits.GalleryBase.csproj | 4 - .../BuildInfrastructure/BuildLayoutTests.cs | 80 +++++++++++++++++++ 14 files changed, 101 insertions(+), 73 deletions(-) diff --git a/.gitignore b/.gitignore index 9b409e800..0bf53e641 100644 --- a/.gitignore +++ b/.gitignore @@ -163,6 +163,8 @@ tools/* !tools/AtomUI.Docs.LLMsGenerator/** !tools/performances/ !tools/performances/** +tools/**/[Bb]in/ +tools/**/[Oo]bj/ .nuget artifacts/ nuget diff --git a/build/AtomUI.Repository.targets b/build/AtomUI.Repository.targets index b68b4b8de..68364cdf2 100644 --- a/build/AtomUI.Repository.targets +++ b/build/AtomUI.Repository.targets @@ -13,6 +13,10 @@ + + + + - - - - diff --git a/docs/architecture/foundations/build-and-packaging.md b/docs/architecture/foundations/build-and-packaging.md index ca8ad2519..13ec0d3d6 100644 --- a/docs/architecture/foundations/build-and-packaging.md +++ b/docs/architecture/foundations/build-and-packaging.md @@ -41,9 +41,9 @@ NativeAOT 应用和测试,补充 Homebrew OpenSSL/Brotli linker 搜索路径 `$(AtomUIBuildTasksAssembly)`、显式 NuGet build asset 清单和 Generator tool asset 清单,然后导入 `AtomUI.Generator.props`。 -`AtomUI.Repository.targets` 定义第一方库的 AOT/Trim 默认值、排除 `.DotSettings`,导入 -`AtomUI.Generator.targets`,并为声明 `AtomUIRegistrationPackageId` 的产品包注入 consumer target、共享构建资产和 -工具程序集。 +`AtomUI.Repository.targets` 定义第一方库的 AOT/Trim 默认值,集中排除 `.DotSettings` 和项目目录中的 compiler-generated +源码快照,导入 `AtomUI.Generator.targets`,并为声明 `AtomUIRegistrationPackageId` 的产品包注入 consumer target、 +共享构建资产和工具程序集。 `AtomUI.Repository.props` 是 Generator build assets 的唯一清单: @@ -53,6 +53,10 @@ NativeAOT 应用和测试,补充 Homebrew OpenSSL/Brotli linker 搜索路径 `tools/netstandard2.0/`。 - `AtomUI.Generator.csproj` 与注册型产品包只能消费这两个 item,不得各自维护第二份文件清单。 +`OutputPaths.props` 对仓库内所有项目统一设置 `PackageOutputPath`、`OutputPath` 和 `BaseIntermediateOutputPath`。这同样 +适用于 `tools/` 下的项目;工具源码的 `.gitignore` 反向规则之后必须重新排除 `tools/**/bin/` 和 `tools/**/obj/`, +避免配置迁移或 IDE 中间态产生的本地二进制进入待提交列表。 + ## NuGet 入口 `build/AtomUI.Generator.props` 和 `build/AtomUI.Generator.targets` 是包根自动导入入口。它们分别导入 Linked @@ -108,17 +112,17 @@ Repository 配置、`MacOSHomebrewNativeAot.targets` 或 `scripts/` 资产。 ## 源生成输出 -多个项目启用: +需要把源生成结果写到仓库目录的项目只声明标准 SDK 属性: ```xml true GeneratedFiles - ``` `GeneratedFiles/` 是本地编译产物,默认由 `.gitignore` 忽略;只有 GalleryBase 中被结构测试直接读取的少量快照保留跟踪。 -生成文件输出到项目内 `GeneratedFiles/`,但从编译输入中移除该目录,避免重复编译。源生成器通过 Analyzer 方式参与当前编译。 +`AtomUI.Repository.targets` 根据 `CompilerGeneratedFilesOutputPath` 统一从 `Compile` 移除这些快照,避免第二次构建把上次 +生成结果作为普通源码再次编译。项目文件不得重复声明同一条 `Compile Remove`。源生成器通过 Analyzer 方式参与当前编译。 ## Analyzer 引用方式 diff --git a/docs/superpowers/specs/2026-08-14-build-infrastructure-layout-design.md b/docs/superpowers/specs/2026-08-14-build-infrastructure-layout-design.md index d5aebc556..b90bd19c7 100644 --- a/docs/superpowers/specs/2026-08-14-build-infrastructure-layout-design.md +++ b/docs/superpowers/specs/2026-08-14-build-infrastructure-layout-design.md @@ -91,8 +91,8 @@ Directory.Build.targets ``` `AtomUI.Repository.props` 在导入 Generator props 前设置源码构建使用的 `$(AtomUIBuildTasksAssembly)`。Repository -targets 同时拥有第一方库 AOT/Trim 默认值、`.DotSettings` 排除和产品包 build asset 注入,不再为这些短逻辑保留 -独立聚合文件。 +targets 同时拥有第一方库 AOT/Trim 默认值、`.DotSettings` 与 compiler-generated 源码快照排除,以及产品包 build +asset 注入,不再为这些短逻辑保留独立聚合文件。 ## 文件职责 @@ -103,7 +103,7 @@ targets 同时拥有第一方库 AOT/Trim 默认值、`.DotSettings` 排除和 | `PackageMetadata.props` | NuGet 公共元数据及仓库资产路径 | | `OutputPaths.props` | NuGet、编译输出和集中式中间产物路径 | | `AtomUI.Repository.props` | Repository props 聚合、Build Tasks 源码路径、NuGet/tool 显式资产清单 | -| `AtomUI.Repository.targets` | AOT/Trim 默认值、产品包资产注入、Generator targets 聚合 | +| `AtomUI.Repository.targets` | AOT/Trim 默认值、生成源码快照排除、产品包资产注入、Generator targets 聚合 | | `AtomUI.Generator.props/targets` | NuGet 自动导入入口和 feature 编排 | | `AtomUI.GeneratorConsumer.targets` | 注册型产品包 consumer target 模板 | | `AtomUI.LinkedRegistration.*` | linked publish 注册构建管线 | @@ -198,6 +198,8 @@ Repository 构建在 `AtomUI.Repository.props` 中把它指向集中输出目录 - Generator 和 Build Tasks 不进入应用运行时依赖、输出或 publish 目录。 - Localization target 名称、时序和行为保持等价。 - 集中输出布局不会把项目目录中的旧 `obj/**/*.cs` 重新纳入 Compile。 +- 设置 `CompilerGeneratedFilesOutputPath` 的项目由 Repository targets 统一排除生成源码,不在各 `.csproj` 重复规则。 +- `tools/` 源码反向 ignore 规则之后重新排除 `bin/` 和 `obj/`,中间态构建产物不能进入版本控制候选。 ## 验证 diff --git a/src/AtomUI.Controls.Shared/AtomUI.Controls.Shared.csproj b/src/AtomUI.Controls.Shared/AtomUI.Controls.Shared.csproj index 415d5e2bf..298341571 100644 --- a/src/AtomUI.Controls.Shared/AtomUI.Controls.Shared.csproj +++ b/src/AtomUI.Controls.Shared/AtomUI.Controls.Shared.csproj @@ -7,10 +7,6 @@ GeneratedFiles - - - - diff --git a/src/AtomUI.Controls/AtomUI.Controls.csproj b/src/AtomUI.Controls/AtomUI.Controls.csproj index f7f07f680..6af626749 100644 --- a/src/AtomUI.Controls/AtomUI.Controls.csproj +++ b/src/AtomUI.Controls/AtomUI.Controls.csproj @@ -11,10 +11,6 @@ 2 - - - - diff --git a/src/AtomUI.Core/AtomUI.Core.csproj b/src/AtomUI.Core/AtomUI.Core.csproj index a40b67844..f56d3eb14 100644 --- a/src/AtomUI.Core/AtomUI.Core.csproj +++ b/src/AtomUI.Core/AtomUI.Core.csproj @@ -7,10 +7,6 @@ GeneratedFiles - - - - true - - - - diff --git a/src/AtomUI.Desktop.Controls.DataGrid/AtomUI.Desktop.Controls.DataGrid.csproj b/src/AtomUI.Desktop.Controls.DataGrid/AtomUI.Desktop.Controls.DataGrid.csproj index bc2f00376..45e5b26f6 100644 --- a/src/AtomUI.Desktop.Controls.DataGrid/AtomUI.Desktop.Controls.DataGrid.csproj +++ b/src/AtomUI.Desktop.Controls.DataGrid/AtomUI.Desktop.Controls.DataGrid.csproj @@ -12,10 +12,6 @@ AtomUI.Desktop.Controls - - - - diff --git a/src/AtomUI.Desktop.Controls.Extras/AtomUI.Desktop.Controls.Extras.csproj b/src/AtomUI.Desktop.Controls.Extras/AtomUI.Desktop.Controls.Extras.csproj index dee305afa..6731313e4 100644 --- a/src/AtomUI.Desktop.Controls.Extras/AtomUI.Desktop.Controls.Extras.csproj +++ b/src/AtomUI.Desktop.Controls.Extras/AtomUI.Desktop.Controls.Extras.csproj @@ -11,10 +11,6 @@ AtomUI.Desktop.Controls - - - - true - - - - - - @@ -38,30 +32,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/AtomUI.Toolkits.GalleryBase/AtomUI.Toolkits.GalleryBase.csproj b/src/AtomUI.Toolkits.GalleryBase/AtomUI.Toolkits.GalleryBase.csproj index 46fe7765f..4d9779a4d 100644 --- a/src/AtomUI.Toolkits.GalleryBase/AtomUI.Toolkits.GalleryBase.csproj +++ b/src/AtomUI.Toolkits.GalleryBase/AtomUI.Toolkits.GalleryBase.csproj @@ -12,10 +12,6 @@ 2 - - - - diff --git a/tests/AtomUI.Generator.Tests/BuildInfrastructure/BuildLayoutTests.cs b/tests/AtomUI.Generator.Tests/BuildInfrastructure/BuildLayoutTests.cs index be2510ba8..c895c57b6 100644 --- a/tests/AtomUI.Generator.Tests/BuildInfrastructure/BuildLayoutTests.cs +++ b/tests/AtomUI.Generator.Tests/BuildInfrastructure/BuildLayoutTests.cs @@ -159,6 +159,86 @@ public sealed class BuildLayoutTests excludes.Value.ShouldContain("$(MSBuildProjectDirectory)/obj/**"); } + [Fact] + public void Repository_Output_Paths_Centralize_Binaries_And_Intermediate_Files() + { + var outputPaths = XDocument.Load(GetRepoFile("build/OutputPaths.props")); + + outputPaths.Descendants("PackageOutputPath") + .ShouldHaveSingleItem() + .Value.ShouldBe("$(MSBuildThisFileDirectory)../output/Nuget/$(Configuration)"); + outputPaths.Descendants("OutputPathWithoutFramework") + .ShouldHaveSingleItem() + .Value.ShouldBe("$(MSBuildThisFileDirectory)../output/bin/$(Configuration)"); + outputPaths.Descendants("OutputPath") + .ShouldHaveSingleItem() + .Value.ShouldBe("$(OutputPathWithoutFramework)"); + outputPaths.Descendants("BaseIntermediateOutputPath") + .ShouldHaveSingleItem() + .Value.ShouldBe( + "$(MSBuildThisFileDirectory)../output/$(MSBuildProjectName)/obj"); + } + + [Fact] + public void Tool_Source_Exceptions_Do_Not_Expose_Build_Output_Directories() + { + var ignoreLines = File.ReadAllLines(GetRepoFile(".gitignore")); + var lastToolSourceException = Array.FindLastIndex(ignoreLines, line => + line is "!tools/AtomUI.Docs.LLMsGenerator/**" or "!tools/performances/**"); + var binIgnore = Array.IndexOf(ignoreLines, "tools/**/[Bb]in/"); + var objIgnore = Array.IndexOf(ignoreLines, "tools/**/[Oo]bj/"); + + lastToolSourceException.ShouldBeGreaterThanOrEqualTo(0); + binIgnore.ShouldBeGreaterThan(lastToolSourceException); + objIgnore.ShouldBeGreaterThan(lastToolSourceException); + } + + [Fact] + public void Repository_Targets_Exclude_Compiler_Generated_Files_Once() + { + const string generatedFilesPattern = "$(CompilerGeneratedFilesOutputPath)/**/*.cs"; + var repositoryTargets = XDocument.Load(GetRepoFile("build/AtomUI.Repository.targets")); + var removal = repositoryTargets.Descendants("Compile") + .Where(element => + (string?)element.Attribute("Remove") == generatedFilesPattern) + .ShouldHaveSingleItem(); + + ((string?)removal.Parent?.Attribute("Condition")) + .ShouldBe("'$(CompilerGeneratedFilesOutputPath)' != ''"); + + var repositoryRoot = GetRepositoryRoot(); + var projectFiles = new[] { "src", "controlgallery", "tests", "tools" } + .Select(directory => Path.Combine(repositoryRoot, directory)) + .Where(Directory.Exists) + .SelectMany(directory => Directory.EnumerateFiles( + directory, + "*.csproj", + SearchOption.AllDirectories)); + foreach (var projectFile in projectFiles) + { + var project = XDocument.Load(projectFile); + if (!project.Descendants("CompilerGeneratedFilesOutputPath").Any()) + { + continue; + } + + project.Descendants("Compile") + .ShouldNotContain(element => + (string?)element.Attribute("Remove") == generatedFilesPattern, + projectFile); + } + } + + [Fact] + public void Desktop_Project_Does_Not_Keep_Stale_Window_Directory_Exclusions() + { + var project = File.ReadAllText(GetRepoFile( + "src/AtomUI.Desktop.Controls/AtomUI.Desktop.Controls.csproj")); + + project.ShouldNotContain("Window\\Reflection"); + project.ShouldNotContain("Window\\Visuals"); + } + [Fact] public void NuGet_Generator_Entry_Points_Import_Flat_Feature_Files() {