Skip to content

Make CLI bundle self-extraction conditional based on distribution mode #15938

@radical

Description

@radical

Summary

Today the bundled Aspire CLI always embeds bundle.tar.gz as a manifest resource and self-extracts it at runtime (BundleService.EnsureExtractedAsync). This means the CLI needs write permissions to its installation directory regardless of how it was distributed.

For archive and installer distributions the layout is already fully extracted on disk — self-extraction is unnecessary. Only the dotnet-tool distribution (Aspire.Cli.Tool.csproj) genuinely needs self-extraction because NuGet enforces a fixed package layout that cannot include the pre-extracted bundle.

Proposal

Make self-extraction conditional by introducing an MSBuild property that gets baked into the binary at build time.

Mechanism

  1. New MSBuild property — e.g. <SelfExtractingBundle>true</SelfExtractingBundle> — controls whether the CLI binary should perform self-extraction at runtime.
  2. Bake into the binary — surface the property value as assembly metadata (e.g. [assembly: AssemblyMetadata("SelfExtractingBundle", "true")]) or a compile-time constant so BundleService can read it without additional files.
  3. Set per distribution mode:
    • Aspire.Cli.Tool.csproj (dotnet-tool): set SelfExtractingBundle=true — payload is embedded and extracted on first run.
    • eng/clipack projects (archives/installers): set SelfExtractingBundle=false (or omit, defaulting to false) — the layout is already on disk.
  4. Update BundleService — check the new flag alongside the existing IsBundle (embedded resource) check. When the flag is false, skip extraction and rely on the pre-extracted layout discovered via BundleDiscovery.

Benefits

  • No write permissions required for installers/archives — the CLI can run from read-only installation directories (e.g. /usr/local/, Program Files).
  • Faster first-run for archive installs — no extraction step needed.
  • dotnet-tool continues to work — self-extraction is preserved where it is actually necessary due to NuGet packaging constraints.

Key files

File Role
src/Aspire.Cli/Bundles/BundleService.cs Runtime self-extraction logic; IsBundle / EnsureExtractedAsync
src/Aspire.Cli/Aspire.Cli.csproj Embeds bundle.tar.gz when BundlePayloadPath is set
src/Aspire.Cli/Aspire.Cli.Tool.csproj dotnet-tool packaging; sets IsCliToolProject=true
eng/clipack/Common.projitems Shared build logic for archive/installer distributions
src/Shared/BundleDiscovery.cs Layout discovery (works for both extracted and pre-extracted layouts)

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions