Skip to content

Make template layouts incremental and remove stale outputs - #56005

Open
mthalman wants to merge 1 commit into
mainfrom
mthalman-redist-template-ownership
Open

Make template layouts incremental and remove stale outputs#56005
mthalman wants to merge 1 commit into
mainfrom
mthalman-redist-template-ownership

Conversation

@mthalman

Copy link
Copy Markdown
Member

Problem

The SDK and MSI template layout steps were not supportive of incremental builds. They repeated work on unchanged builds and lacked the state needed to skip safely.

They also did not explicitly track which outputs they owned. This could leave obsolete template packages behind, especially in the Windows MSI staging directory, while making cleanup risky for unrelated files.

Description

  • Skip template layout work when inputs and outputs have not changed.
  • Detect added, changed, removed, renamed, or missing template packages.
  • Remove only obsolete template outputs and preserve unrelated files.
  • Recover safely from missing or corrupted state and interrupted builds.
  • Rebuild template MSIs when their staged templates or installer settings change.
  • Add shared infrastructure for future redist incrementality work.

The new tracking adds a small amount of bookkeeping, which is intended to pay off as more redist targets become incremental and can avoid unnecessary work.

Validation

  • Production cold and warm builds completed successfully.
  • The warm build skipped unchanged template layout and MSI work.
  • A 220-sample benchmark across seven scenarios found no statistically significant performance changes.

Fixes #55867
Fixes #55868

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 1407e982-0490-4111-87b7-dfbb1ee3d25e
Copilot AI lite review requested due to automatic review settings August 28, 2026 20:44
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
2 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@mthalman

Copy link
Copy Markdown
Member Author

/azp run dotnet-unified-build

@azure-pipelines

Copy link
Copy Markdown
No pipelines are associated with this pull request.

@mthalman

Copy link
Copy Markdown
Member Author

/azp run dotnet-unified-build-full

@azure-pipelines

Copy link
Copy Markdown
No pipelines are associated with this pull request.

@mthalman

Copy link
Copy Markdown
Member Author

/azp run sdk-unified-build-full

@azure-pipelines

Copy link
Copy Markdown
No pipelines are associated with this pull request.

@mthalman

Copy link
Copy Markdown
Member Author

/azp run sdk-unified-build-full

@azure-pipelines

Copy link
Copy Markdown
No pipelines are associated with this pull request.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces incremental build infrastructure for template layout and Windows template MSI generation so unchanged inputs can be skipped safely, while also tracking and removing stale template outputs without deleting unrelated files.

Changes:

  • Added new MSBuild tasks (PrepareIncrementalLayout, CompleteIncrementalLayout) to validate layout mappings, compute stale outputs, and publish an atomic completion stamp.
  • Updated template layout and template MSI generation targets to use explicit “owned outputs” inventories and completion/in-progress stamps for safe incremental behavior and recovery.
  • Added focused regression tests covering added/removed/remapped inputs, stale-output cleanup, interrupted builds, and template MSI incremental rebuild triggers.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
test/UnitTests.proj Ships layout/MSI target files and templates.wixproj into the Helix test execution directory for tests that import these build assets.
test/sdk-tasks.Tests/TemplateMsiIncrementalityTests.cs Adds Windows-only binlog/MSI-level tests validating incremental behavior of the pinned WiX targets under property/payload changes.
test/sdk-tasks.Tests/sdk-tasks.Tests.csproj Adds Windows-only PackageDownload + content payloads to make WiX packages and MSI authoring inputs available to tests at runtime.
test/sdk-tasks.Tests/IncrementalLayoutTests.cs Adds unit/integration-style tests for incremental layout state, stale-output cleanup, interruption recovery, and MSI generation tracking behavior.
src/Tasks/sdk-tasks/sdk-tasks.InTree.targets Registers the new incremental layout tasks for in-tree builds.
src/Tasks/sdk-tasks/IncrementalLayout.cs Implements the new incremental layout tasks and supporting state helpers (path validation, atomic stamp writes).
src/Layout/redist/targets/GenerateMSIs.targets Adds an “in-progress” marker and per-RID rebuild recovery behavior for template MSI generation.
src/Layout/redist/targets/BundledTemplates.targets Makes SDK/MSI template layout incremental with explicit owned-output cleanup and completion stamps.
src/Layout/pkg/windows/msis/templates/templates.wixproj Extends the pinned WiX project to include additional incremental inputs (completion stamp + serialized define constants) to invalidate builds correctly.

Comment on lines 17 to 20
<!-- When building the sdk bundle only, the sdk and template msis are acquired via DownloadBundledComponents. -->
<GenerateSdkBundleDependsOn Condition="'$(GenerateSdkBundleOnly)' != 'true'">$(GenerateSdkBundleDependsOn);GenerateSdkMsi;GenerateTemplatesMsis</GenerateSdkBundleDependsOn>
<_TemplatesMsiGenerationInProgressFile>$(_IncrementalLayoutStateDirectory)templates-msi-generation-$(ProductMonikerRid).inprogress</_TemplatesMsiGenerationInProgressFile>
</PropertyGroup>
Comment on lines +320 to +327
private static void SetLastWriteTimeAfter(string path, DateTime timestamp)
{
while (File.GetLastWriteTimeUtc(path) <= timestamp)
{
Thread.Yield();
File.SetLastWriteTimeUtc(path, DateTime.UtcNow);
}
}
@joeloff

joeloff commented Aug 28, 2026

Copy link
Copy Markdown
Member

@mthalman have you tried this on an internal build with full signing - there were changes in how the wixpacks work for signing after we moved to v5/v6 of the toolset.

@mthalman

Copy link
Copy Markdown
Member Author

@mthalman have you tried this on an internal build with full signing - there were changes in how the wixpacks work for signing after we moved to v5/v6 of the toolset.

Not yet. I'm working on that.

@joeloff

joeloff commented Aug 28, 2026

Copy link
Copy Markdown
Member

@mthalman have you tried this on an internal build with full signing - there were changes in how the wixpacks work for signing after we moved to v5/v6 of the toolset.

Not yet. I'm working on that.

Cool, because I was thinking signing will fuss with the timestamps when files are changed and we inject those and rerun the build commands so things don't necessary go through the project again. We capture all the original properties of the corecompile step, replace the files and rerun wix directly.

continue;
}

sourcePaths.Add(sourcePath);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the source path be added before existence is checked? Also, if it doesn't exist, doesn't that make it invalid or are you checking for a valid path (no invalid path chars)?

return files;
}

private static void ReadMsiRows(string installerPath, string query, Action<uint> readRow)

@joeloff joeloff Aug 28, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For tests you could just use the DTF libraries from WiX. We use it for workloads: https://github.com/dotnet/arcade/blob/main/src/Microsoft.DotNet.Build.Tasks.Workloads/src/Msi/MsiUtils.wix.cs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make SDK and MSI template layouts own stale outputs Add reusable redist incrementality infrastructure and tests

3 participants