Skip to content

Commit 7dd3bfe

Browse files
sebstoclaude
andauthored
Fix: resolve the container CLI matching the cross-compile method (lambda-build & archive) (#678)
### Problem Cross-compiling with Apple's `container` CLI did not work — neither via the new `lambda-build` plugin nor the legacy `archive` plugin. The build failed with: ``` /usr/local/bin/docker image pull swift:amazonlinux2023 failed to connect to the docker API at unix:///Users/.../docker.sock ... ``` 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 when `container` was requested, the plugin generated correct `container`-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 — `container` when `container` is requested, `docker` otherwise — before invoking the helper. The original arguments are still forwarded unchanged. - **`AWSLambdaBuilder`** (`lambda-build`): honours `--cross-compile` (and the deprecated `--container-cli` alias). - **`AWSLambdaPackager`** (`archive`, Swift 6.4 deprecation passthrough): same bug, same fix; honours both `--cross-compile` and the legacy `--container-cli`. ### Testing Verified end-to-end against a sample project for both commands: - **Default (no flag):** resolves `/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 `container` CLI 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. --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 4a02a3e commit 7dd3bfe

3 files changed

Lines changed: 44 additions & 7 deletions

File tree

Plugins/AWSLambdaBuilder/Plugin.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ struct AWSLambdaBuilder: CommandPlugin {
2828
let packageID: String = context.package.id
2929
let packageDisplayName = context.package.displayName
3030
let packageDirectory = context.package.directoryURL
31-
let dockerToolPath = try context.tool(named: "docker").url
3231
let zipToolPath = try context.tool(named: "zip").url
3332

3433
// extract arguments that require PluginContext to fully resolve
@@ -39,6 +38,18 @@ struct AWSLambdaBuilder: CommandPlugin {
3938
let productsArgument = argumentExtractor.extractOption(named: "products")
4039
let configurationArgument = argumentExtractor.extractOption(named: "configuration")
4140

41+
// Resolve the container CLI that matches the requested cross-compilation method.
42+
// The plugin sandbox can only run tools it resolves up front, so we must pick the right
43+
// binary here — `container` for `--cross-compile container`, `docker` otherwise. Extracting
44+
// these options only peeks them for the plugin; the original `arguments` (which the helper
45+
// re-parses) is still forwarded unchanged below.
46+
// `--container-cli` is a deprecated alias for `--cross-compile`.
47+
let crossCompileArgument = argumentExtractor.extractOption(named: "cross-compile")
48+
let containerCliArgument = argumentExtractor.extractOption(named: "container-cli")
49+
let crossCompileMethod = (crossCompileArgument.first ?? containerCliArgument.first)?.lowercased()
50+
let containerCLIToolName = crossCompileMethod == "container" ? "container" : "docker"
51+
let containerToolPath = try context.tool(named: containerCLIToolName).url
52+
4253
if let outputPath = outputPathArgument.first {
4354
#if os(Linux)
4455
var isDirectory: Bool = false
@@ -87,7 +98,7 @@ struct AWSLambdaBuilder: CommandPlugin {
8798
"--package-id", packageID,
8899
"--package-display-name", packageDisplayName,
89100
"--package-directory", packageDirectory.path(),
90-
"--docker-tool-path", dockerToolPath.path,
101+
"--docker-tool-path", containerToolPath.path,
91102
"--zip-tool-path", zipToolPath.path,
92103
] + arguments
93104

Plugins/AWSLambdaPackager/Plugin@swift-6.4.swift

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ struct AWSLambdaPackager: CommandPlugin {
3939
let packageID: String = context.package.id
4040
let packageDisplayName = context.package.displayName
4141
let packageDirectory = context.package.directoryURL
42-
let dockerToolPath = try context.tool(named: "docker").url
4342
let zipToolPath = try context.tool(named: "zip").url
4443

4544
var argumentExtractor = ArgumentExtractor(arguments)
@@ -49,6 +48,17 @@ struct AWSLambdaPackager: CommandPlugin {
4948
let productsArgument = argumentExtractor.extractOption(named: "products")
5049
let configurationArgument = argumentExtractor.extractOption(named: "configuration")
5150

51+
// Resolve the container CLI that matches the requested cross-compilation method.
52+
// The plugin sandbox can only run tools it resolves up front, so we must pick the right
53+
// binary here — `container` for `container`, `docker` otherwise. Extracting these options
54+
// only peeks them for the plugin; the original `arguments` (which the helper re-parses) is
55+
// still forwarded unchanged below. `--container-cli` is the legacy alias for `--cross-compile`.
56+
let crossCompileArgument = argumentExtractor.extractOption(named: "cross-compile")
57+
let containerCliArgument = argumentExtractor.extractOption(named: "container-cli")
58+
let crossCompileMethod = (crossCompileArgument.first ?? containerCliArgument.first)?.lowercased()
59+
let containerCLIToolName = crossCompileMethod == "container" ? "container" : "docker"
60+
let containerToolPath = try context.tool(named: containerCLIToolName).url
61+
5262
// output directory
5363
if let outputPath = outputPathArgument.first ?? outputDirectoryArgument.first {
5464
#if os(Linux)
@@ -100,7 +110,7 @@ struct AWSLambdaPackager: CommandPlugin {
100110
"--package-id", packageID,
101111
"--package-display-name", packageDisplayName,
102112
"--package-directory", packageDirectory.path(),
103-
"--docker-tool-path", dockerToolPath.path,
113+
"--docker-tool-path", containerToolPath.path,
104114
"--zip-tool-path", zipToolPath.path,
105115
] + arguments
106116

Sources/AWSLambdaPluginHelper/lambda-build/Builder.swift

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -450,19 +450,35 @@ enum CrossCompileMethod: String, CustomStringConvertible {
450450
env: [String: String]?,
451451
command: String
452452
) -> [String] {
453-
switch self {
454-
case .docker, .container:
453+
func genericArgs() -> [String] {
455454
var args: [String] = ["run", "--rm"]
456455
for mount in mounts {
457456
args += ["-v", mount]
458457
}
459458
if let env {
460459
for (key, value) in env.sorted(by: { $0.key < $1.key }) {
461-
args += ["--env", "\(key)=\(value)"]
460+
args += ["-e", "\(key)=\(value)"]
462461
}
463462
}
464463
args += ["-w", workingDirectory, baseImage, "bash", "-cl", command]
465464
return args
465+
}
466+
switch self {
467+
468+
case .docker:
469+
return genericArgs()
470+
471+
case .container:
472+
var args = genericArgs()
473+
474+
// container's runtime needs a bit more memory
475+
if self == .container {
476+
args.insert("--memory", at: 1)
477+
args.insert("4G", at: 2)
478+
}
479+
480+
return args
481+
466482
case .swiftStaticSdk, .customSdk:
467483
fatalError("runArguments should not be called for unsupported cross-compile methods")
468484
}

0 commit comments

Comments
 (0)