Skip to content

[build] Provision .NET SDK via standard scripts, drop xaprepare's installer#11636

Merged
jonathanpeppers merged 10 commits into
mainfrom
jonathanpeppers/sdk-provisioning-audit
Jun 24, 2026
Merged

[build] Provision .NET SDK via standard scripts, drop xaprepare's installer#11636
jonathanpeppers merged 10 commits into
mainfrom
jonathanpeppers/sdk-provisioning-audit

Conversation

@jonathanpeppers

Copy link
Copy Markdown
Member

Context

Today, dotnet/android provisions the .NET SDK with bespoke C# code in
build-tools/xaprepare/xaprepare/Steps/Step_InstallDotNetPreview.cs
(220 lines) — fetching dotnet-install.{sh,ps1} from a hard-coded URL,
running it with config-driven args, and supporting a --with-archive
override for offline scenarios. Other .NET repos (dotnet/sdk,
dotnet/runtime, dotnet/aspnetcore) all use Arcade's standard
eng/common/dotnet-install.{sh,ps1} flow — there's no reason for us to
maintain a custom one.

Phase 1 of a longer migration

This PR is the SDK-provisioning slice of a larger effort to delete
xaprepare entirely
so the build collapses to:

./eng/install-dotnet.sh                 # one-time bootstrap
dotnet build Xamarin.Android.sln        # everything else

xaprepare today is 333 KB / 116 files but only 4 step files have real
logic (Step_PrepareDotNetWorkloads, Step_GenerateFiles,
Step_GenerateFiles.Windows, Step_GenerateCGManifest). Once each step
has an MSBuild equivalent, the surrounding 332 KB of plumbing
(Application/, ToolRunners/, OperatingSystems/) can also be
deleted. Follow-up PRs are planned for each remaining step.

What changes here

New: eng/install-dotnet.{sh,ps1}

Thin bootstrap wrappers that:

  1. Read <MicrosoftNETSdkPackageVersion> from eng/Versions.props
    (single source of truth, kept up to date by darc when
    Microsoft.NET.Sdk flows from dotnet/dotnet).
  2. Download Microsoft's official dotnet-install.{sh,ps1} from
    https://builds.dotnet.microsoft.com/dotnet/scripts/v1/ (cached
    under bin/$Configuration/dotnet/).
  3. Invoke it with --version <pinned> and --install-dir bin/$Configuration/dotnet.

Install location stays at bin/$Configuration/dotnet/ (where xaprepare
put it) so dotnet-local.{cmd,sh} continues to work unchanged.

Wired in everywhere xaprepare ran the install before

  • Makefile: prepare: target now depends on a new install-dotnet
    target that calls ./eng/install-dotnet.sh.
  • build-tools/scripts/PrepareWindows.targets: new _InstallDotNet
    target runs eng/install-dotnet.ps1 before _BuildXAPrepare.
  • build.cmd: unchanged — the existing dotnet msbuild ... -t:Prepare
    flow still works because _BuildXAPrepare now installs the SDK first.

Step_InstallDotNetPreviewStep_PrepareDotNetWorkloads

The old 220-line installer step is deleted. A new ~120-line
Step_PrepareDotNetWorkloads.cs replaces it and only does
Android-specific workload prep (NuGet cleanup, package-download.proj
restore with 3-attempt retry, and workload manifest copy). Everything
SDK-install-related (download script, archive override,
InstallDotNetAsync etc.) is gone.

global.json:tools.dotnetNOT added

I originally tried pinning the SDK version in global.json:tools.dotnet
(the standard Arcade convention), but verified in
arcade-services/.../DependencyFileManager.cs that darc
does not auto-update global.json:tools.dotnet
when the
Microsoft.NET.Sdk asset flows. Only specific Arcade/Helix SDK names
and the literal name dotnet are special-cased. So a tools.dotnet
pin would have permanently drifted from the auto-flowed
eng/Versions.props:MicrosoftNETSdkPackageVersion.

The wrappers therefore read the version from Versions.props directly
and bypass Arcade's eng/common/tools.{sh,ps1} (which would otherwise
strict-mode-read $GlobalJson.tools). Single source of truth = the
darc-flowed eng/Versions.props.

Other cleanups

  • Configurables.{Unix,Windows}.cs: removed Urls.DotNetInstallScript
    (no longer needed).
  • Context.cs + Main.cs: removed LocalDotNetSdkArchive /
    --dotnet-sdk-archive plumbing. (The replacement is the standard
    DOTNET_INSTALL_DIR env var that anyone needing offline support can
    set themselves.)

Verified on Windows

Action Time
Cold eng/install-dotnet.ps1 (with download) ~12s
Warm re-run (idempotent fast path) ~2.5s
Full dotnet msbuild Xamarin.Android.sln -t:Prepare ~88s

The dotnet --list-sdks output after a cold install correctly shows
11.0.100-preview.5.26268.112 at
bin/Debug/dotnet/sdk. Re-running Prepare is silent (no spurious
re-installs, no extra workload restores).

Migration path for the rest of xaprepare (future PRs)

Step Migration target
Step_PrepareDotNetWorkloads MSBuild .targets file
Step_GenerateCGManifest CI yaml step or .targets file
Step_GenerateFiles[.Windows] Per-file MSBuild targets with Inputs/Outputs
(everything) Delete build-tools/xaprepare/ and PrepareWindows.targets

End state: ./eng/install-dotnet.sh + dotnet build. Nothing else.

jonathanpeppers and others added 3 commits June 11, 2026 10:08
Replace xaprepare's bespoke `dotnet-install` invocation with Arcade's
standard `eng/common/tools.{sh,ps1}` bootstrap, matching dotnet/sdk,
dotnet/runtime, and dotnet/aspnetcore.

* `global.json`: pin `tools.dotnet` so Arcade's `InitializeDotNetCli`
  knows which SDK to install. darc auto-updates this whenever
  `Microsoft.NET.Sdk` flows from dotnet/dotnet via the existing
  Maestro subscription.
* `eng/install-dotnet.{sh,ps1}`: thin wrappers that set
  `DOTNET_INSTALL_DIR=DOTNET_GLOBAL_INSTALL_DIR=bin/$(Configuration)/dotnet/`
  (preserving the existing install location) and call
  `InitializeDotNetCli` from `eng/common/tools.{sh,ps1}`.
* `Makefile`: `prepare` now depends on a new `install-dotnet` target
  that runs `./eng/install-dotnet.sh` first.
* `build-tools/scripts/PrepareWindows.targets`: add an
  `_InstallDotNet` target that invokes `eng/install-dotnet.ps1`
  before `_BuildXAPrepare`, so `dotnet msbuild Xamarin.Android.sln
  -t:Prepare` (used on Windows CI) is self-bootstrapping.
* `Step_InstallDotNetPreview.cs` is deleted and replaced by
  `Step_PrepareDotNetWorkloads.cs`. The new step assumes the SDK
  is already installed at `bin/$(Configuration)/dotnet/` and only
  performs the Android-specific workload prep:
    * Cleans stale Mono Android runtime/workload NuGet directories.
    * Restores `package-download.proj` (Mono runtime packs +
      Mono/Emscripten workload manifest packages).
    * Copies the workload manifests into the local SDK's
      `sdk-manifests/`.
* Removes obsolete configuration:
    * `Configurables.Urls.DotNetInstallScript` (Unix and Windows)
    * `--dotnet-sdk-archive` xaprepare option and its
      `Context.LocalDotNetSdkArchive` plumbing
    * `DownloadDotNetInstallScript`, `GetInstallationScriptArgs`,
      `InstallDotNetAsync`, `InstallDotNetFromLocalArchiveAsync`
      methods (~150 lines of bespoke install logic).

The SDK install location stays at `bin/$(Configuration)/dotnet/`,
so `dotnet-local.{cmd,sh}` and other consumers continue to work
without changes. CI's `use-dot-net.yaml` is unchanged: it still
provisions a system .NET to bootstrap xaprepare; the pinned preview
SDK install simply moves from xaprepare to Arcade.

Verified locally on Windows: `dotnet msbuild Xamarin.Android.sln
-t:Prepare` after `git clean -xdf bin/Debug/dotnet/` installs the
pinned 11.0.100-preview.5.26268.112 SDK and copies the Mono +
Emscripten workload manifests into `sdk-manifests/`.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
darc does not auto-update global.json:tools.dotnet when Microsoft.NET.Sdk
flows from dotnet/dotnet (verified in arcade-services
DependencyFileManager.cs: only Microsoft.DotNet.Arcade.Sdk, the
*.SharedFramework.Sdk family, Microsoft.DotNet.CMake.Sdk,
Microsoft.NET.Sdk.IL, and the literal name "dotnet" are special-cased).

Pinning the SDK version in global.json would have permanently drifted
from the auto-flowed eng/Versions.props value. Read the version directly
from eng/Versions.props instead, making it the single source of truth.

eng/install-dotnet.{sh,ps1} now download Microsoft's official
dotnet-install.{sh,ps1} from
https://builds.dotnet.microsoft.com/dotnet/scripts/v1/ (cached under
bin/$Configuration/dotnet/) and invoke it with the version parsed from
eng/Versions.props:MicrosoftNETSdkPackageVersion. This bypasses Arcade's
eng/common/tools.{sh,ps1} (which strict-mode-reads $GlobalJson.tools)
and lets us drop the tools.dotnet pin from global.json entirely.

Verified on Windows:
  - cold install:   ~12s
  - warm re-run:    ~2.5s (idempotent fast path)
  - full Prepare:   ~88s

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
CI failed with "Permission denied" when `make jenkins` ran
`./eng/install-dotnet.sh` because the file was committed as 100644.
The file from `make prepare` is invoked directly (not via `bash`), so
it needs the executable bit set.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread build-tools/xaprepare/xaprepare/Scenarios/Scenario_AndroidTestDependencies.cs Outdated
jonathanpeppers and others added 3 commits June 12, 2026 08:45
Reverts the executable-bit change from 2645bdb. Windows clones with
core.filemode=false would have shown spurious mode changes when editing
the file; running it via `bash ./eng/install-dotnet.sh` from the
Makefile sidesteps the bit entirely. Same trick for the cached
dotnet-install.sh we download under bin/.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This finishes the second half of the SDK provisioning audit started in
PR #11636. The first half moved the .NET SDK install into Microsoft's
official `dotnet-install.{sh,ps1}` scripts driven by `eng/install-dotnet`.
This commit replaces the leftover xaprepare logic that prepared
Android-specific .NET workloads against that SDK.

What `Step_PrepareDotNetWorkloads` did (now deleted):

* Restored `package-download.proj` to pull down the Mono Android runtime
  packs and the Mono/Emscripten workload manifest packages.
* Copied the workload manifests from the NuGet package cache into the
  local SDK's `sdk-manifests/` folder.

What `src/workloads/workloads.csproj` does (single MSBuild project, no
C#, no scenarios):

* Carries the same `<PackageDownload>` items that lived in
  `package-download.proj` (run via NuGet's auto-restore).
* Has a `_CopyWorkloadManifests` target that runs `AfterTargets="Build"`
  and copies each `microsoft.net.workload.{mono,emscripten}.<flavor>`
  manifest's `data/` into the local SDK's
  `sdk-manifests/<band>/microsoft.net.workload.<flavor>.<dotnet>/<ver>/`.

Per @jonathanpeppers' suggestion in
#11636 (comment 3403797084):
"move it to like `src/workloads/workloads.csproj` and that project is
built first."

Wiring:

* `Makefile prepare:` now runs
  `dotnet build src/workloads/workloads.csproj` after the BootstrapTasks
  build, before `PrepareJavaInterop`.
* `build-tools/scripts/PrepareWindows.targets`'s `Prepare` target adds
  an `<MSBuild Projects=".../workloads.csproj" />` invocation in the
  same spot.
* `build-tools/automation/yaml-templates/setup-test-environment-steps.yaml`
  no longer invokes xaprepare. Test agents now run
  `eng/install-dotnet.{sh,ps1}` (provisions the SDK at
  `bin/$Config/dotnet/`) followed by
  `dotnet build src/workloads/workloads.csproj` (provisions the
  workloads against that SDK). This fixes the AndroidTestDependencies CI
  failure introduced when the prior commit removed
  `Step_InstallDotNetPreview`'s SDK download.

Cleanup:

* `Step_PrepareDotNetWorkloads.cs` and `package-download.proj` deleted.
* `Scenario_Standard` and `Scenario_AndroidTestDependencies` no longer
  add `Step_PrepareDotNetWorkloads`.
* The `xaprepareScenario` parameter (and the now-unused
  `run-xaprepare.yaml` template) are removed across all CI YAMLs.
* Dead `Configurables.MicrosoftNETWorkload*Dir` properties are removed.

Verified locally on Windows:

* `bin/Debug/dotnet/sdk-manifests/<band>/microsoft.net.workload.{mono.toolchain,emscripten}.{net6..net10,current}/<ver>/WorkloadManifest.json`
  is populated after `dotnet build src/workloads/workloads.csproj` (12
  manifests total).
* Re-running is idempotent (~0.5s warm; `Copy SkipUnchangedFiles="true"`).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers jonathanpeppers marked this pull request as ready for review June 17, 2026 20:04
Copilot AI review requested due to automatic review settings June 17, 2026 20:04

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 migrates dotnet/android’s .NET SDK provisioning from xaprepare’s custom C# installer to the standard dotnet-install.{sh,ps1} flow, keeping the install location at bin/$Configuration/dotnet/ and moving Android-specific workload prep into a standalone MSBuild project.

Changes:

  • Add eng/install-dotnet.{sh,ps1} wrappers that read the pinned SDK version from eng/Versions.props, download dotnet-install.{sh,ps1}, and install into bin/$Configuration/dotnet.
  • Wire the new install/workload-prep flow into Makefile, Windows PrepareWindows.targets, and CI templates; remove xaprepare’s SDK-install step and related plumbing.
  • Introduce src/workloads/workloads.csproj to restore required runtime packs + workload manifest packages and copy manifests into the locally installed SDK.

Reviewed changes

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

Show a summary per file
File Description
src/Xamarin.Installer.Build.Tasks/README.md Updates developer instructions to use eng/install-dotnet.* + build workloads project.
src/workloads/workloads.csproj New MSBuild project to restore runtime packs/manifests and copy manifests into the local SDK.
Makefile Adds install-dotnet prerequisite and runs workloads provisioning during prepare.
eng/install-dotnet.sh New Unix bootstrap script to install pinned SDK into bin/$Configuration/dotnet.
eng/install-dotnet.ps1 New Windows bootstrap script to install pinned SDK into bin\$Configuration\dotnet.
build-tools/xaprepare/xaprepare/Steps/Step_InstallDotNetPreview.cs Deletes the bespoke xaprepare SDK installer step.
build-tools/xaprepare/xaprepare/Scenarios/Scenario_Standard.cs Removes SDK install step from the standard xaprepare scenario.
build-tools/xaprepare/xaprepare/Scenarios/Scenario_AndroidTestDependencies.cs Removes SDK install step from Android test dependency scenario.
build-tools/xaprepare/xaprepare/package-download.proj Deletes the old runtime-pack restore project used by xaprepare.
build-tools/xaprepare/xaprepare/Main.cs Removes --dotnet-sdk-archive option plumbing.
build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.Windows.cs Removes DotNet install script URL configurable (no longer needed).
build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.Unix.cs Removes DotNet install script URL configurable (no longer needed).
build-tools/xaprepare/xaprepare/ConfigAndData/Configurables.cs Removes workload manifest path helpers tied to the deleted step.
build-tools/xaprepare/xaprepare/Application/Context.cs Removes LocalDotNetSdkArchive property.
build-tools/scripts/PrepareWindows.targets Ensures SDK install runs before building xaprepare; adds workloads provisioning to Prepare.
build-tools/automation/yaml-templates/stage-package-tests.yaml Removes xaprepare scenario parameter usage from test setup.
build-tools/automation/yaml-templates/stage-msbuild-emulator-tests.yaml Removes xaprepare scenario parameter usage from test setup.
build-tools/automation/yaml-templates/setup-test-environment.yaml Removes xaprepareScenario parameter pass-through.
build-tools/automation/yaml-templates/setup-test-environment-steps.yaml Replaces xaprepare invocation with eng/install-dotnet.* + workloads provisioning.
build-tools/automation/yaml-templates/setup-test-environment-public.yaml Removes xaprepareScenario parameter pass-through.
build-tools/automation/yaml-templates/run-xaprepare.yaml Deletes the shared pipeline template that ran xaprepare.
build-tools/automation/yaml-templates/run-emulator-tests.yaml Removes xaprepare scenario parameter usage from test setup.
build-tools/automation/azure-pipelines-public.yaml Removes xaprepare scenario parameter usage from test environment setup.
build-tools/automation/azure-pipelines-nightly.yaml Removes xaprepare scenario parameter usage from test environment setup.

Comment thread Makefile Outdated
Comment thread eng/install-dotnet.ps1
jonathanpeppers and others added 2 commits June 17, 2026 15:43
* Makefile install-dotnet: pass CONFIGURATION through to install-dotnet.sh
  so 'make CONFIGURATION=Release prepare' installs the SDK under
  bin/Release/dotnet to match the rest of the build.
* eng/install-dotnet.ps1: null-check the result of SelectSingleNode before
  dereferencing .InnerText so the script fails with the intended friendly
  error message if <MicrosoftNETSdkPackageVersion> is ever removed from
  eng/Versions.props.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The previous commit accidentally captured local submodule pointer changes
for external/Java.Interop and external/xamarin-android-tools that have
nothing to do with the SDK provisioning audit. Restore them to the
pointers used by the rest of this PR (and main).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jonathanpeppers jonathanpeppers added the ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable). label Jun 22, 2026
@jonathanpeppers

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Jun 22, 2026

Copy link
Copy Markdown

Android PR Reviewer completed successfully!

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🤖 Android PR Review — [build] Provision .NET SDK via standard scripts, drop xaprepare's installer

I reviewed the diff independently before reading the description. This is a well-scoped, largely subtractive change: the bespoke ~220-line Step_InstallDotNetPreview + package-download.proj are replaced by thin eng/install-dotnet.{sh,ps1} bootstrappers and a src/workloads/workloads.csproj (Microsoft.Build.NoTargets) that PackageDownloads the runtime packs / workload manifests and copies the manifests into the locally-installed SDK. Good direction — collapsing toward dotnet-install + dotnet build is a real maintainability win.

Verified OK (potential concerns I checked and dismissed)

  • ✅ No dangling references to the removed symbols (Step_InstallDotNetPreview, DotNetInstallScript, the MicrosoftNETWorkloadMono*Dir configurables, package-download.proj).
  • ✅ Every xaprepareScenario / run-xaprepare.yaml consumer was removed — no orphaned YAML parameters that would break pipeline parsing.
  • ✅ No provisioning silently dropped: androidsdk.csproj (SDK/JDK) and emulator setup are untouched; the affected scenarios were effectively no-ops apart from the removed step.
  • ✅ Property/import ordering in workloads.csproj is fine — DotNetStableTargetFramework, MicrosoftNETCoreAppRefPackageVersion, and the manifest bands resolve via Directory.Build.propseng/Versions.props (auto-imported before the body); XAPackagesDir / DotNetPreviewPath exist by the time the target runs. Microsoft.Build.NoTargets is pinned in global.json.
  • ✅ Backslash path separators in the copy target normalize correctly on Linux/macOS (verified empirically).
  • Makefile passes -p:Configuration=$(CONFIGURATION) to prepare-workloads, matching the install-dotnet install path (bin/$Configuration/dotnet).

Findings (none merge-blocking)

Sev Area Note
⚠️ install scripts A failed/partial download poisons the cached dotnet-install.{sh,ps1} — no temp-then-move, and an empty cached script silently "succeeds".
⚠️ workloads Drops the old forced stale-cache cleanup before copy; possible stale runtime packs/manifests if an internal version string is reused.
💡 workloads target _CopyWorkloadManifests has no Inputs/Outputs and uses AfterTargets="Build".
💡 formatting <Error> Condition should come first (Postmortem #33).

Notes

  • 📝 The PR description is slightly stale — it refers to a Step_PrepareDotNetWorkloads.cs replacement, but the actual change introduces src/workloads/workloads.csproj (and deletes package-download.proj). Worth updating so reviewers/git log archaeologists aren't misled.
  • CI for the head commit (11dc706) is still in progress (combined status pending; the dotnet-android build is queued/running). Please confirm it goes green before merging — an earlier commit's legs passed, but the current head hasn't completed.

Nice cleanup overall. 👍

Generated by Android PR Reviewer for issue #11636 · 1.7K AIC · ⌖ 66.1 AIC · ⊞ 37.8K
Comment /review to run again

Comment thread eng/install-dotnet.sh Outdated
Comment thread src/workloads/workloads.csproj
Comment thread src/workloads/workloads.csproj
Comment thread src/workloads/workloads.csproj
jonathanpeppers and others added 2 commits June 22, 2026 16:11
* eng/install-dotnet.{sh,ps1}: download Microsoft's dotnet-install
  script to a temp file and atomically rename into place so a failed
  or interrupted download cannot poison the cached script. Restores
  the temp-then-move pattern the old Step_InstallDotNetPreview used.
* src/workloads/workloads.csproj: put Condition attribute first on the
  <Error> task per repo convention.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
These keep slipping into commits because the local worktree has stale
submodule pointers. Restore them to the PR's prior commit.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@simonrozsival simonrozsival enabled auto-merge (squash) June 23, 2026 10:26
@jonathanpeppers jonathanpeppers disabled auto-merge June 24, 2026 18:44
@jonathanpeppers jonathanpeppers merged commit c0f2623 into main Jun 24, 2026
38 of 40 checks passed
@jonathanpeppers jonathanpeppers deleted the jonathanpeppers/sdk-provisioning-audit branch June 24, 2026 18:44
simonrozsival pushed a commit that referenced this pull request Jun 25, 2026
After PR #11636 hollowed out `Scenario_AndroidTestDependencies` and
`Scenario_EmulatorTestDependencies`, their `AddSteps()` methods no
longer add any steps -- they only set `AllowProgramInstallation=false`
and `IgnoreMissingPrograms=true`, which have no effect when no steps
run. `Scenario_EmulatorTestDependencies` inherited from the former and
added nothing.

Delete both vestigial scenarios. Also update the now-obsolete error
message in `GradleCLI.cs` that referenced the deleted scenario; Gradle
is committed to the repo at `build-tools/gradle/`, so the generic
"not found" wording is sufficient.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
simonrozsival pushed a commit that referenced this pull request Jun 26, 2026
Many xaprepare provisioning steps have been removed over the past year (#11332, #11348, #11399, #11440, #11441, #11636 and follow-up cleanups in #11568, #11580, #11608, #11613, #11631, #11657, #11658, #11731, #11732, #11733, #11737). The supporting scaffolding around those steps was left behind. This PR removes the verified-dead pieces in two passes.

## Files removed (first pass — original audit)

| File | Justification |
| --- | --- |
| `Application/TestAssembly.cs` | Orphan test infra; only referenced by `TestAssemblyType.cs`. |
| `Application/TestAssemblyType.cs` | Only referenced by `TestAssembly.cs`. |
| `Application/StepWithDownloadProgress.cs` | No subclasses remain. |
| `Application/NDKTool.cs` | NDK provisioning moved to MSBuild in #11440. Last consumer was the also-dead `Configurables.NDKTools` collection (removed below). |
| `ToolRunners/SnRunner.cs` | Strong-naming tool runner; never instantiated. |
| `ToolRunners/SnRunner.OutputSink.cs` | Partial sibling of `SnRunner`. |
| `ToolRunners/CMakeRunner.cs` | Never instantiated. |
| `ToolRunners/CMakeRunner.OutputSink.cs` | Partial sibling of `CMakeRunner`. |

## Files removed (second pass — repo-wide re-audit)

| File | Justification |
| --- | --- |
| `ToolRunners/MakeRunner.Linux.cs` | Partial of `MakeRunner`; type never instantiated. |
| `ToolRunners/MakeRunner.MacOS.cs` | Partial of `MakeRunner`. |
| `ToolRunners/MakeRunner.OutputSink.Unix.cs` | Partial of `MakeRunner`. |
| `ToolRunners/MakeRunner.Unix.cs` | Partial of `MakeRunner`. |
| `ToolRunners/MSBuildRunner.cs` | Never instantiated. |
| `ToolRunners/MSBuildRunner.OutputSink.cs` | Partial sibling of `MSBuildRunner`. |
| `ToolRunners/NinjaRunner.cs` | Never instantiated. |
| `ToolRunners/NinjaRunner.OutputSink.cs` | Partial sibling of `NinjaRunner`. |
| `Application/ScenarioNoStandardEndSteps.cs` | Abstract class with zero subclasses. |

## Cascading cleanup

- `ConfigAndData/Configurables.cs` — removed the dead `NDKTools` `List<NDKTool>` collection (lines 132–145). Rest of the file unchanged.

## Removed from initial deletion list after verification

- `Application/Extensions.DictionaryOfProgramVersionParser.cs` — initial name-only audit flagged it as dead, but its `Add` extension method is consumed via dictionary collection-initializer syntax in `Application/VersionFetchers.cs`. The consumer never references the static class by name, which is why the first audit missed it. The file stays.
- `Scenarios/Scenario_Required.cs` — looks unreferenced by static grep, but `Scenario` subclasses are reflectively discovered via the `[Scenario]` attribute in `Context.cs` (`Utilities.GetTypesWithCustomAttribute<ScenarioAttribute> ()`). Live. The file stays.

## Verification

- `git grep -n -w <TypeName>` for each deleted type now returns 0 real hits (only unrelated `"TestAssembly"` string literals in `tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/` remain — those are assembly-name strings, not the C# type).
- `dotnet build build-tools/xaprepare/xaprepare/xaprepare.csproj -c Debug` → 0 warnings, 0 errors.

## Deferred follow-up

The csproj conditionally excludes `*MacOS*` files from compilation when `HostOS != Darwin`, so static dead-code analysis from a Windows/Linux host can't see whether the macOS-only consumers are themselves live. These candidates need verification on a Mac host (or a build matrix) before deletion:

- `Application/PkgProgram.MacOS.cs`
- `Application/HomebrewProgram.MacOS.cs`
- `ToolRunners/BrewRunner.MacOS.cs`
- `ToolRunners/PkgutilRunner.MacOS.cs`
- `ConfigAndData/Dependencies/MacOS.cs`
simonrozsival pushed a commit that referenced this pull request Jun 30, 2026
### Context

After #11636 (dotnet provisioning step removed) and #11731 (test-deps scenarios removed), `Context.AutoProvision` is `false` by default everywhere except hand-run dev provisioning, which is no longer in use. The per-OS package lists are populated at `OS.Init()` time but `EnsureDependencies` is effectively a no-op:

- `OS.EnsureDependencies()` returns early when `AutoProvision` is false (the default),
- nothing else in the codebase reads from the `Program` derivatives' install/uninstall paths,
- the `BuildToolsInventory` writer remains driven only from `EssentialTools.MacOS.cs` (homebrew version detection).

The `OS.Init() / InitializeDependencies() / EnsureDependencies()` machinery on `OS.cs` itself is intentionally **left in place** here — that's a larger refactor for a follow-up PR. This PR only strips the now-vestigial package-list data and the program/runner classes that fed it.

### Files deleted (Phase F — macOS, 4 files)

- `Application/HomebrewProgram.MacOS.cs`
- `Application/PkgProgram.MacOS.cs`
- `ToolRunners/BrewRunner.MacOS.cs`
- `ToolRunners/PkgutilRunner.MacOS.cs`

### Files deleted (Phase G — Linux, 5 files)

- `Application/Program.Linux.cs` (`LinuxProgram` base — orphan after subclasses go)
- `Application/Program.ArchLinux.cs`
- `Application/Program.DebianLinux.cs`
- `Application/Program.FedoraLinux.cs`
- `Application/Program.GentooLinux.cs`

### Files deleted (Phase 3 — orphan)

- `Application/IBuildInventoryItem.cs` (only implementor was `HomebrewProgram`; `BuildToolsInventory` itself stays, populated directly by `EssentialTools.MacOS.cs`).

### Files reduced to empty stubs

`ConfigAndData/Dependencies/`:
- `MacOS.cs` — `InitializeDependencies()` no-op (was Homebrew formula list + git fallback).
- `Linux.Arch.cs` — class kept (referenced by `distroMap`); package list removed.
- `Linux.Fedora.cs` — same.
- `Linux.Gentoo.cs` — same.
- `Linux.DebianCommon.cs` — common Debian/Ubuntu package list removed; `Flavor = "Debian"` kept.
- `Linux.UbuntuCommon.cs` — `libtoolPackages` + `NeedLibtool` virtual + `InitOS` override removed (all dead).
- `Linux.Debian.cs` — all per-version package lists (`packages`, `packagesPre10`, `packagesPreTrixie`, `packagesTrixieAndLater`, `packages10AndNewerBuildBots`) removed; release/codename detection (`EnsureVersionInformation`, `DebianUnstableVersionMap`, `IsDebian10OrNewer`, etc.) preserved as conservative scope.
- `Linux.Ubuntu.cs` — `preCosmicPackages`, `cosmicPackages`, `preDiscoPackages` lists + `NeedLibtool` override removed; `UbuntuRelease` + `EnsureVersionInformation` preserved.
- `Linux.Mint.cs` — `NeedLibtool` override removed (the property is gone from the base).

`ConfigAndData/Dependencies/Windows.cs` was already a no-op stub — no edit.

### Verification

Orphan audit (each `git grep -nw <Type> -- 'build-tools/xaprepare/*'` reports **0 hits**):

- `HomebrewProgram`, `PkgProgram`, `BrewRunner`, `PkgutilRunner`
- `ArchLinuxProgram`, `DebianLinuxProgram`, `FedoraLinuxProgram`, `GentooLinuxProgram`, `LinuxProgram`
- `IBuildInventoryItem`

Build:

```
dotnet build build-tools\xaprepare\xaprepare\xaprepare.csproj -c Debug
Build succeeded.  0 Warning(s)  0 Error(s)
```

### Out of scope (follow-up)

- Removing the abstract `OS.InitializeDependencies()` declaration and the surrounding `EnsureDependencies()` machinery from `OperatingSystems/OS.cs`.
- `VersionFetchers` / `ProgramVersionParser` / `RegexProgramVersionParser` / `SevenZipVersionParser` / `Extensions.DictionaryOfProgramVersionParser.cs` are kept — `Utilities.GetProgramVersion` still queries them from `Program.cs`, `ToolRunner.cs`, `EssentialTools.MacOS.cs`, and `OperatingSystems/MacOS.cs` (brew detection).

### Precedent

#11568, #11580, #11608, #11613, #11631, #11657, #11658, #11731, #11732, #11733, #11737, #11740, #11760
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-review This PR is ready to review/merge, I think any CI failures are just flaky (ignorable).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants