Skip to content

refactor(runtimes): split provider files to slim shim binary#266

Merged
CalvinAllen merged 1 commit into
mainfrom
refactor/runtimes/shim-build-tag
May 13, 2026
Merged

refactor(runtimes): split provider files to slim shim binary#266
CalvinAllen merged 1 commit into
mainfrom
refactor/runtimes/shim-build-tag

Conversation

@CalvinAllen
Copy link
Copy Markdown
Contributor

Summary

Splits each runtime provider (node, python, ruby) into a "shim half" (lite methods only) and a "full half" tagged //go:build !shim. Build the shim with -tags shim and the linker drops every heavy transitive dependency the shim never actually used.

Measured impact

Binary main (#264) This PR Δ
dtvem-shim.exe 5.70 MB 2.68 MB −3.0 MB (−53%)
dtvem.exe 10.94 MB 10.94 MB unchanged

Combined with the -trimpath work in #264, the shim is now 2.68 MB versus 8.20 MB on f1dfab5 (pre‑#264) — a −67% total reduction since this slimming effort started.

Symbol audit — what's gone

go tool nm on the new shim no longer contains any of:

  • github.com/bodgit/sevenzip (was 173 symbols)
  • github.com/klauspost/compress (was 235)
  • net/http (was 114)
  • github.com/ulikunitz/xz (was 102)
  • github.com/pierrec/lz4 (was 93)
  • github.com/andybalholm/brotli (was 74)
  • compress/bzip (was 50)
  • archive/zip / archive/tar / compress/gzip (was 34 combined)
  • crypto/tls (was 22)
  • github.com/spf13/afero (was 10)
  • github.com/hashicorp/golang-lru (was 10)
  • github.com/schollz/progressbar (was 3)
  • github.com/bodgit/plumbing (was 3)
  • The 1.3 MB of embedded manifest JSON (internal/manifest/data/*.json)
  • The Node.js release schedule (runtimes/node/data/schedule.json)
  • The testing package (transitively via provider_test_harness.go)

What remains is encoding/json (for the shim‑map and runtimes.json), fatih/color + mattn/go-isatty + mattn/go-colorable (the user‑facing error output), and dtvem's own code.

Approach

One change to interface shape, the rest is a mechanical file split.

  • internal/runtime/provider.go — keeps ShimProvider.
  • internal/runtime/provider_full.go (//go:build !shim) — defines the full Provider interface with all heavy methods.
  • internal/runtime/provider_shim.go (//go:build shim) — type Provider = ShimProvider (alias).

Because Provider always exists as a public type, the registry and its callers (including internal/shim/manager.go and every cmd/*.go file) need no changes. In default builds Provider is the full interface; in shim builds it collapses to ShimProvider and the heavy method calls on concrete types are gone — so klauspost/compress, sevenzip, et al. are no longer reachable.

Per‑runtime split (src/runtimes/{node,python,ruby}/):

  • provider.go (untagged) — Name, DisplayName, Shims, ExecutablePath, IsInstalled, InstallPath, ShouldReshimAfter, GetEnvironment, init(). Imports stay minimal: fmt, os, filepath, runtime, internal/config, internal/constants, internal/runtime.
  • provider_full.go (//go:build !shim) — Install, Uninstall, ListInstalled, ListAvailable, DetectInstalled, GlobalPackages, InstallGlobalPackages, ManualPackageInstallCommand, all version setters/getters, all install helpers. Heavy imports (internal/download, internal/manifest, internal/shim, internal/ui, encoding/json, os/exec, etc.) live only here.

Extras tagged !shim:

  • internal/runtime/provider_test_harness.go — uses full Provider methods on a concrete value; only consumed by tests (default build).
  • runtimes/node/lifecycle.go — embeds data/schedule.json and is only used by list-all.

Build config: -tags shim added to the build-shim step in rnr.yaml, .github/workflows/build.yml, and .github/workflows/release.yml. Main CLI build is untagged.

Test plan

  • ./rnr.cmd check passes (format, lint, full test suite — every package green)
  • go build ./... succeeds under the default build
  • go build -tags shim ./src/cmd/shim succeeds
  • Symbol audit (go tool nm) confirms the heavy packages are no longer present
  • Main CLI binary size unchanged (10.94 MB)
  • CI passes on all five matrix platforms
  • Manual smoke test post‑merge: install a runtime, run python --version / node --version / ruby --version through the shimmed executables, verify "no version configured" fallback still works

Risk

Mechanical refactor. Watch points:

  • Anything outside cmd/shim that calls full‑Provider methods needs to be in !shim files so the shim build compiles. Validated by build success on both tag configurations; the only file that needed tagging was provider_test_harness.go (and node/lifecycle.go, which is already tagged for the secondary win of dropping the embedded schedule).
  • Concrete provider types in shim builds satisfy ShimProvider (== Provider in that build). In default builds they satisfy the full Provider. Verified by go vet + go test.

Resolves #265

Move heavy install/list/migrate methods (Install, Uninstall, ListInstalled,
ListAvailable, DetectInstalled, GlobalPackages, InstallGlobalPackages,
ManualPackageInstallCommand, plus install helpers) and the version
getters/setters into provider_full.go files tagged //go:build !shim.
Provider remains an alias for ShimProvider in shim builds via the new
provider_shim.go, so the registry and its callers don't change. The
Node.js lifecycle helper and runtime test harness are also tagged !shim.

Build the shim with -tags shim (rnr.yaml + both CI workflows) so the
linker drops net/http, klauspost/compress, sevenzip, brotli, lz4, xz,
bzip2, archive/zip, crypto/tls, afero, hashicorp/golang-lru,
progressbar, the embedded manifest JSON, and the Node release schedule.
Shim drops from 5.70 MB to 2.68 MB (-53%); main CLI is unchanged.
@CalvinAllen
Copy link
Copy Markdown
Contributor Author

CalvinAllen commented May 13, 2026

/release-note Shim binary is now 67% smaller (8.2 MB → 2.7 MB), reducing disk footprint and cold-start cost for every shimmed command!

@CalvinAllen CalvinAllen merged commit c757a50 into main May 13, 2026
11 checks passed
@CalvinAllen CalvinAllen deleted the refactor/runtimes/shim-build-tag branch May 13, 2026 16:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

refactor(runtimes): split provider files to slim shim binary

1 participant