[plugin] Fix: resolve the container CLI matching the cross-compile method (lambda-build & archive)#678
Merged
Merged
Conversation
05aa2e9 to
b77604a
Compare
The Swift 6.4 'archive' deprecation passthrough always resolved the docker binary and forwarded it as --docker-tool-path, ignoring the requested cross-compile method. As a result `archive --cross-compile container` (and the legacy --container-cli container alias) ran container-style arguments against the docker binary and failed. Resolve the container CLI matching the requested method, mirroring the fix in AWSLambdaBuilder. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
sebsto
added a commit
that referenced
this pull request
Jun 29, 2026
…in args (#679) ### Summary Refactors the internals of the `lambda-build` build path into a pluggable backend architecture, and tidies the plugin→helper argument plumbing. This is an internal refactor: no user-facing flag, no `--cross-compile` value, no output ZIP path, and no public Swift API changes. Behaviour is identical; the goal is to make adding new cross-compilation backends (podman, finch, colima, swift-static-sdk, custom-sdk, …) a localised, additive change. ### 1. Pluggable build backends (`lambda-build`) The build logic in `Builder.swift` was a hard-coded native-vs-docker/container branch with an enum (`CrossCompileMethod`) that carried both the parsed user choice *and* the argv-building logic. It's now split along two independent axes: - **`BuildBackend` protocol** — *how* a build runs: `NativeBuildBackend` (on an Amazon Linux host) and `ContainerBuildBackend` (inside a container). - **`ContainerCLI` protocol** — the *argument flavor* of a container runtime: `DockerCLI` and `AppleContainerCLI`. A single `ContainerBuildBackend` serves both (and future runtimes) since only the argv spelling differs, not the build flow. `CrossCompileMethod` keeps only the parsed value, `parse(...)`, and a `makeBackend(configuration:)` factory; its `pullArguments`/`runArguments` (and the `fatalError` SDK stubs) are gone. `Builder.build(...)` is now select-and-delegate (~8 lines); `Builder.swift` shrinks from ~700 to ~460 lines. **No shared argv helper between CLIs — by design.** Each `ContainerCLI` builds its complete argument vector independently (no base struct, no default implementation, no shared closure). docker and Apple `container` argv may diverge in future CLI versions, and future runtimes may not be compatible at all; a shared helper is exactly the coupling that caused the earlier docker/container mix-up (#678). Each CLI is covered by its own golden-argv tests with no shared fixtures. Adding a backend later is now additive: a new `*CLI.swift` + a `CrossCompileMethod` case + one line in `makeBackend` (container runtimes), or a new `BuildBackend` type (SDK methods). No edits to `Builder` or existing CLIs. File layout: ``` lambda-build/ Builder.swift # build() select+delegate, package(), BuilderConfiguration, BuilderErrors CrossCompileMethod.swift # enum + parse + makeBackend factory Backends/ BuildBackend.swift # protocol NativeBuildBackend.swift ContainerBuildBackend.swift ContainerCLI.swift # protocol DockerCLI.swift AppleContainerCLI.swift ``` ### 2. Thin-layer plugin argument plumbing The plugins are meant to be the thinnest possible layer: resolve only the values that need `PluginContext` / the package graph, then forward everything else to the helper. `lambda-build` and the deprecated `archive` (Swift 6.4 passthrough) were re-appending the *original* arguments after extracting some, so options like `--products` reached the helper twice (and, for `--products`, caused the product to be built twice). Both now forward `argumentExtractor.remainingArguments`, so a consumed option is never forwarded again. The same one-line bug (`+ arguments` → `+ argumentExtractor.remainingArguments`) is fixed in `lambda-deploy`, which had it too. The internal plugin→helper flag `--docker-tool-path` is renamed to `--cross-compile-tool-path` (and the config field `dockerToolPath` → `crossCompileToolPath`) so it no longer implies docker — it can carry any cross-compile tool. This flag is internal (plugin→helper), not user-facing. > Note: the deprecated pre-6.4 `archive` implementation (`Plugin.swift`, behind > `#if swift(<6.4)`) is intentionally left untouched. ### Testing - New `BuildBackendTests.swift`: separate golden-argv tests for `DockerCLI` and `AppleContainerCLI` (no shared fixtures), plus `makeBackend` factory tests (docker → DockerCLI, container → AppleContainerCLI, SDK methods throw). - All `AWSLambdaPluginHelperTests` pass (84 tests); `swift build` and `swift format lint --strict` clean. - End-to-end against a sample project: `lambda-build` default (docker) and `--cross-compile container` emit byte-for-byte identical argv to before the refactor; `--products` is no longer doubled.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Cross-compiling with Apple's
containerCLI did not work — neither via the newlambda-buildplugin nor the legacyarchiveplugin. The build failed with:Both plugins always resolved the Docker binary (
context.tool(named: "docker")) and forwarded it as the container CLI path, regardless of the selected cross-compilation method. So whencontainerwas requested, the plugin generated correctcontainer-style arguments (image pull …) but executed them with the docker binary, which then failed.Tool resolution has to happen in the plugin (the SwiftPM sandbox can only run tools it resolves up front), so the fix belongs there rather than in the helper.
Fix
Both plugins now peek the cross-compilation flag and resolve the matching tool —
containerwhencontaineris requested,dockerotherwise — before invoking the helper. The original arguments are still forwarded unchanged.AWSLambdaBuilder(lambda-build): honours--cross-compile(and the deprecated--container-clialias).AWSLambdaPackager(archive, Swift 6.4 deprecation passthrough): same bug, same fix; honours both--cross-compileand the legacy--container-cli.Testing
Verified end-to-end against a sample project for both commands:
/usr/local/bin/docker— unchanged behaviour.--cross-compile container/--container-cli container: resolves/usr/local/bin/container; the plugin now runs/usr/local/bin/container image pull …and the Linux container starts and builds.Note
There is a separate, pre-existing limitation: Apple's
containerCLI communicates with its daemon over XPC, which the SwiftPM plugin sandbox blocks (XPC connection error: Connection invalid). The same command succeeds with--disable-sandbox. That sandbox issue is out of scope for this PR (which fixes the tool-resolution bug) and should be tracked separately.