fn main() {
#[cfg(feature = "buildkit")]
generate_buildkit();
}
#[cfg(feature = "buildkit")]
fn generate_buildkit() {
let manifest = std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR");
let root = format!("{manifest}/specs/buildkit");
let bk = format!("{root}/github.com/moby/buildkit");
let fsutil = format!("{root}/github.com/tonistiigi/fsutil/types");
let files = [
format!("{bk}/api/services/control/control.proto"),
format!("{bk}/api/types/worker.proto"),
format!("{bk}/solver/pb/ops.proto"),
format!("{bk}/sourcepolicy/pb/policy.proto"),
format!("{root}/google/rpc/status.proto"),
format!("{bk}/session/filesync/filesync.proto"),
format!("{bk}/session/auth/auth.proto"),
format!("{bk}/session/secrets/secrets.proto"),
format!("{bk}/session/sshforward/ssh.proto"),
format!("{fsutil}/wire.proto"),
format!("{fsutil}/stat.proto"),
format!("{root}/grpc/health/v1/health.proto"),
format!("{bk}/frontend/gateway/pb/gateway.proto"),
format!("{bk}/util/apicaps/pb/caps.proto"),
];
buffa_build::Config::new()
.files(&files)
.includes(&[root.as_str()])
.generate_json(true)
.compile()
.expect("buffa-build: compile BuildKit control protos");
generate_services(&root, &files);
println!("cargo:rerun-if-changed={root}");
}
#[cfg(feature = "buildkit")]
fn generate_services(root: &str, files: &[String]) {
use prost::Message;
use prost_types::FileDescriptorSet;
let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR");
let protoc = std::env::var("PROTOC").unwrap_or_else(|_| "protoc".to_string());
let desc_path = format!("{out_dir}/buildkit_service_descriptors.bin");
let mut cmd = std::process::Command::new(&protoc);
cmd.arg("--include_imports")
.arg(format!("--descriptor_set_out={desc_path}"))
.arg(format!("-I{root}"));
for f in files {
cmd.arg(f);
}
let status = cmd.status().expect("run protoc for descriptor set");
assert!(status.success(), "protoc descriptor generation failed");
let bytes = std::fs::read(&desc_path).expect("read descriptor set");
let fds = FileDescriptorSet::decode(bytes.as_slice()).expect("decode descriptor set");
let targets: &[(&str, &str, &str)] = &[
("control.proto", "Control", "control_service.rs"),
("filesync.proto", "FileSync", "filesync_service.rs"),
("filesync.proto", "FileSend", "filesend_service.rs"),
("auth.proto", "Auth", "auth_service.rs"),
("secrets.proto", "Secrets", "secrets_service.rs"),
("ssh.proto", "SSH", "ssh_service.rs"),
("health.proto", "Health", "health_service.rs"),
("gateway.proto", "LLBBridge", "gateway_service.rs"),
];
for (file_suffix, service_name, out_name) in targets {
let file = fds
.file
.iter()
.find(|f| {
f.name
.as_deref()
.map_or(false, |n| n.ends_with(file_suffix))
})
.unwrap_or_else(|| panic!("descriptor for {file_suffix} not found"));
let mut one = file.clone();
one.service
.retain(|s| s.name.as_deref() == Some(service_name));
assert_eq!(
one.service.len(),
1,
"service {service_name} not found in {file_suffix}"
);
let code = foundation_connectrpc_codegen::generate_services(&[one]);
std::fs::write(format!("{out_dir}/{out_name}"), code).expect("write service code");
}
}