197 lines
7.3 KiB
Zig
197 lines
7.3 KiB
Zig
const std = @import("std");
|
|
const lambda_zig = @import("lambda_zig");
|
|
|
|
pub fn build(b: *std.Build) !void {
|
|
// Default to aarch64-linux for Lambda Graviton deployment
|
|
const target = b.standardTargetOptions(.{
|
|
.default_target = .{
|
|
.cpu_arch = .aarch64,
|
|
.os_tag = .linux,
|
|
},
|
|
});
|
|
const optimize = b.standardOptimizeOption(.{});
|
|
|
|
// Native target for build tools
|
|
const native_target = b.resolveTargetQuery(.{});
|
|
|
|
// Get lambda-zig dependency
|
|
const lambda_zig_dep = b.dependency("lambda_zig", .{
|
|
.target = target,
|
|
.optimize = optimize,
|
|
});
|
|
|
|
// Get controlr dependency for rinnai module
|
|
const controlr_dep = b.dependency("controlr", .{
|
|
.target = target,
|
|
.optimize = optimize,
|
|
});
|
|
|
|
// Create the main module
|
|
const main_module = b.createModule(.{
|
|
.root_source_file = b.path("src/main.zig"),
|
|
.target = target,
|
|
.optimize = optimize,
|
|
});
|
|
|
|
// Add lambda_runtime import
|
|
main_module.addImport("lambda_runtime", lambda_zig_dep.module("lambda_runtime"));
|
|
// Add rinnai import from controlr
|
|
main_module.addImport("rinnai", controlr_dep.module("rinnai"));
|
|
|
|
// Create executable
|
|
const exe = b.addExecutable(.{
|
|
.name = "house-control",
|
|
.root_module = main_module,
|
|
});
|
|
|
|
b.installArtifact(exe);
|
|
|
|
// Configure Lambda build steps and get deployment info
|
|
// Function name defaults to exe.name ("house-control")
|
|
const lambda = try lambda_zig.configureBuild(b, lambda_zig_dep, exe, .{});
|
|
|
|
// Get AWS profile option (already declared by lambda-zig)
|
|
const profile = b.user_input_options.get("profile");
|
|
const profile_str: ?[]const u8 = if (profile) |p| switch (p.value) {
|
|
.scalar => |s| s,
|
|
else => null,
|
|
} else null;
|
|
|
|
// Get AWS region option (already declared by lambda-zig)
|
|
const region = b.user_input_options.get("region");
|
|
const region_str: ?[]const u8 = if (region) |r| switch (r.value) {
|
|
.scalar => |s| s,
|
|
else => null,
|
|
} else null;
|
|
|
|
// Build the gen-skill-json tool (runs on host)
|
|
const gen_skill_json_module = b.createModule(.{
|
|
.root_source_file = b.path("tools/gen-skill-json.zig"),
|
|
.target = native_target,
|
|
.optimize = .ReleaseFast,
|
|
});
|
|
const gen_skill_json_exe = b.addExecutable(.{
|
|
.name = "gen-skill-json",
|
|
.root_module = gen_skill_json_module,
|
|
});
|
|
|
|
// Generate skill.json from template using Lambda ARN
|
|
const gen_skill_cmd = b.addRunArtifact(gen_skill_json_exe);
|
|
gen_skill_cmd.addFileArg(lambda.deploy_output);
|
|
gen_skill_cmd.addFileArg(b.path("skill.template.json"));
|
|
gen_skill_cmd.step.dependOn(lambda.deploy_step);
|
|
|
|
// Capture generated skill.json
|
|
const skill_json = gen_skill_cmd.captureStdOut();
|
|
|
|
// Write skill.json to skill-package directory (updates source files, necessary for the ask deploy)
|
|
const write_skill_json = b.addUpdateSourceFiles();
|
|
write_skill_json.addCopyFileToSource(skill_json, "skill-package/skill.json");
|
|
|
|
const gen_skill_step = b.step("gen_skill_json", "Generate skill.json from template (will deploy function)");
|
|
gen_skill_step.dependOn(&write_skill_json.step);
|
|
|
|
// ASK CLI deploy step for Alexa skill metadata
|
|
const ask_deploy_cmd = b.addSystemCommand(&.{
|
|
"bun", "x", "ask", "deploy", "--target", "skill-metadata",
|
|
});
|
|
// ASK deploy depends on skill.json being generated
|
|
ask_deploy_cmd.step.dependOn(&write_skill_json.step);
|
|
|
|
// Add Alexa skill-specific Lambda permission
|
|
//
|
|
// Alexa requires a skill-specific Lambda permission with the skill ID as an
|
|
// event_source_token condition. This is more secure than a generic principal-based
|
|
// permission (--allow-principal) and restricts invocation to only our specific skill.
|
|
//
|
|
// We use our own tool instead of lambda-zig's built-in --allow-principal because:
|
|
// 1. The skill ID isn't known until after ASK deploy runs
|
|
// 2. event_source_token is Alexa-specific (not supported by lambda-zig)
|
|
//
|
|
// Pipeline: Lambda deploy -> gen-skill-json -> ASK deploy -> add-alexa-permission
|
|
const aws_dep = b.dependency("aws", .{
|
|
.target = native_target,
|
|
.optimize = .ReleaseFast,
|
|
});
|
|
const add_alexa_perm_module = b.createModule(.{
|
|
.root_source_file = b.path("tools/add-alexa-permission.zig"),
|
|
.target = native_target,
|
|
.optimize = .ReleaseFast,
|
|
});
|
|
add_alexa_perm_module.addImport("aws", aws_dep.module("aws"));
|
|
const add_alexa_perm_exe = b.addExecutable(.{
|
|
.name = "add-alexa-permission",
|
|
.root_module = add_alexa_perm_module,
|
|
});
|
|
const add_alexa_perm_cmd = b.addRunArtifact(add_alexa_perm_exe);
|
|
add_alexa_perm_cmd.addFileArg(lambda.deploy_output);
|
|
add_alexa_perm_cmd.addFileArg(b.path(".ask/ask-states.json"));
|
|
if (profile_str) |p| {
|
|
add_alexa_perm_cmd.addArgs(&.{ "--profile", p });
|
|
}
|
|
if (region_str) |r| {
|
|
add_alexa_perm_cmd.addArgs(&.{ "--region", r });
|
|
}
|
|
// Must run after ASK deploy (which creates/updates skill ID) and Lambda deploy
|
|
add_alexa_perm_cmd.step.dependOn(&ask_deploy_cmd.step);
|
|
|
|
const ask_deploy_step = b.step("ask_deploy", "Deploy Alexa skill metadata via ASK CLI");
|
|
ask_deploy_step.dependOn(&add_alexa_perm_cmd.step);
|
|
|
|
// Full deploy step - deploys Lambda, generates skill.json, deploys Alexa skill, adds permission
|
|
const full_deploy_step = b.step("deploy", "Deploy Lambda function and Alexa skill");
|
|
full_deploy_step.dependOn(&add_alexa_perm_cmd.step);
|
|
|
|
// Test step - use native target for tests (not cross-compiled Lambda target)
|
|
const lambda_zig_dep_native = b.dependency("lambda_zig", .{
|
|
.target = native_target,
|
|
.optimize = optimize,
|
|
});
|
|
|
|
const controlr_dep_native = b.dependency("controlr", .{
|
|
.target = native_target,
|
|
.optimize = optimize,
|
|
});
|
|
|
|
const test_module = b.createModule(.{
|
|
.root_source_file = b.path("src/main.zig"),
|
|
.target = native_target,
|
|
.optimize = optimize,
|
|
});
|
|
test_module.addImport("lambda_runtime", lambda_zig_dep_native.module("lambda_runtime"));
|
|
test_module.addImport("rinnai", controlr_dep_native.module("rinnai"));
|
|
|
|
const main_tests = b.addTest(.{
|
|
.name = "test",
|
|
.root_module = test_module,
|
|
});
|
|
|
|
const run_main_tests = b.addRunArtifact(main_tests);
|
|
const test_step = b.step("test", "Run unit tests");
|
|
test_step.dependOn(&run_main_tests.step);
|
|
// Also verify tools compile
|
|
test_step.dependOn(&gen_skill_json_exe.step);
|
|
test_step.dependOn(&add_alexa_perm_exe.step);
|
|
|
|
// Run step for local testing (uses native target)
|
|
const run_module = b.createModule(.{
|
|
.root_source_file = b.path("src/main.zig"),
|
|
.target = native_target,
|
|
.optimize = optimize,
|
|
});
|
|
run_module.addImport("lambda_runtime", lambda_zig_dep_native.module("lambda_runtime"));
|
|
run_module.addImport("rinnai", controlr_dep_native.module("rinnai"));
|
|
|
|
const run_exe = b.addExecutable(.{
|
|
.name = exe.name,
|
|
.root_module = run_module,
|
|
});
|
|
|
|
const run_cmd = b.addRunArtifact(run_exe);
|
|
if (b.args) |args| {
|
|
run_cmd.addArgs(args);
|
|
}
|
|
|
|
const run_step = b.step("run", "Run locally for testing");
|
|
run_step.dependOn(&run_cmd.step);
|
|
}
|