lambda-zig/lambdabuild.zig
Emil Lerch e70b65260c
upgrade to zig 0.15 / rewrite build tooling as standalone CLI
This migrates from zig 0.13 to 0.15.2. In addition to dealing with
breaking changes in the build system and standard library APIs, the
architecture was changed substantially. We now build a standalone
CLI, and use that to execute the commands. This avoids sandboxing issues
related to TLS and enables easier testing. The commit also includes a
simple zip implementation (store only, single file) which avoids the
platform restriction (i.e. this build can now theoretically work on
Windows).
2026-02-02 11:05:20 -08:00

112 lines
4.2 KiB
Zig

//! Lambda Build Integration for Zig Build System
//!
//! This module provides build steps for packaging and deploying Lambda functions.
//! It builds the lambda-build CLI tool and invokes it for each operation.
const std = @import("std");
/// Configure Lambda build steps for a Zig project.
///
/// Adds the following build steps:
/// - awslambda_package: Package the function into a zip file
/// - awslambda_iam: Create/verify IAM role
/// - awslambda_deploy: Deploy the function to AWS
/// - awslambda_run: Invoke the deployed function
pub fn configureBuild(
b: *std.Build,
lambda_build_dep: *std.Build.Dependency,
exe: *std.Build.Step.Compile,
) !void {
// Get the lambda-build CLI artifact from the dependency
const cli = lambda_build_dep.artifact("lambda-build");
// Get configuration options
const function_name = b.option([]const u8, "function-name", "Function name for Lambda") orelse "zig-fn";
const region = b.option([]const u8, "region", "AWS region") orelse null;
const profile = b.option([]const u8, "profile", "AWS profile") orelse null;
const role_name = b.option(
[]const u8,
"role-name",
"IAM role name (default: lambda_basic_execution)",
) orelse "lambda_basic_execution";
const payload = b.option(
[]const u8,
"payload",
"Lambda invocation payload",
) orelse "{}";
// Determine architecture for Lambda
const target_arch = exe.root_module.resolved_target.?.result.cpu.arch;
const arch_str = blk: {
switch (target_arch) {
.aarch64 => break :blk "aarch64",
.x86_64 => break :blk "x86_64",
else => {
std.log.warn("Unsupported architecture for Lambda: {}, defaulting to x86_64", .{target_arch});
break :blk "x86_64";
},
}
};
// Package step - output goes to cache based on input hash
const package_cmd = b.addRunArtifact(cli);
package_cmd.step.name = try std.fmt.allocPrint(b.allocator, "{s} package", .{cli.name});
package_cmd.addArgs(&.{ "package", "--exe" });
package_cmd.addFileArg(exe.getEmittedBin());
package_cmd.addArgs(&.{"--output"});
const zip_output = package_cmd.addOutputFileArg("function.zip");
package_cmd.step.dependOn(&exe.step);
const package_step = b.step("awslambda_package", "Package the Lambda function");
package_step.dependOn(&package_cmd.step);
// IAM step
const iam_cmd = b.addRunArtifact(cli);
iam_cmd.step.name = try std.fmt.allocPrint(b.allocator, "{s} iam", .{cli.name});
if (profile) |p| iam_cmd.addArgs(&.{ "--profile", p });
if (region) |r| iam_cmd.addArgs(&.{ "--region", r });
iam_cmd.addArgs(&.{ "iam", "--role-name", role_name });
const iam_step = b.step("awslambda_iam", "Create/verify IAM role for Lambda");
iam_step.dependOn(&iam_cmd.step);
// Deploy step (depends on package)
const deploy_cmd = b.addRunArtifact(cli);
deploy_cmd.step.name = try std.fmt.allocPrint(b.allocator, "{s} deploy", .{cli.name});
if (profile) |p| deploy_cmd.addArgs(&.{ "--profile", p });
if (region) |r| deploy_cmd.addArgs(&.{ "--region", r });
deploy_cmd.addArgs(&.{
"deploy",
"--function-name",
function_name,
"--zip-file",
});
deploy_cmd.addFileArg(zip_output);
deploy_cmd.addArgs(&.{
"--role-name",
role_name,
"--arch",
arch_str,
});
deploy_cmd.step.dependOn(&package_cmd.step);
const deploy_step = b.step("awslambda_deploy", "Deploy the Lambda function");
deploy_step.dependOn(&deploy_cmd.step);
// Invoke/run step (depends on deploy)
const invoke_cmd = b.addRunArtifact(cli);
invoke_cmd.step.name = try std.fmt.allocPrint(b.allocator, "{s} invoke", .{cli.name});
if (profile) |p| invoke_cmd.addArgs(&.{ "--profile", p });
if (region) |r| invoke_cmd.addArgs(&.{ "--region", r });
invoke_cmd.addArgs(&.{
"invoke",
"--function-name",
function_name,
"--payload",
payload,
});
invoke_cmd.step.dependOn(&deploy_cmd.step);
const run_step = b.step("awslambda_run", "Invoke the deployed Lambda function");
run_step.dependOn(&invoke_cmd.step);
}