use std::{path::PathBuf}; use async_trait::async_trait; use dagger_rust::source::RustSource; use dagger_sdk::Container; use futures::{StreamExt}; use crate::{ cli, rust_service::architecture::{Architecture, Os}, MainAction, PullRequestAction, }; #[derive(Clone)] pub struct RustLib { client: dagger_sdk::Query, base_image: Option, source: Option, crates: Vec, arch: Option, os: Option, } impl RustLib { pub fn new(value: dagger_sdk::Query) -> Self { Self { client: value, source: None, crates: Vec::new(), arch: None, os: None, base_image: None, } } pub fn with_source(&mut self, path: impl Into) -> &mut Self { self.source = Some(path.into()); self } pub fn with_base_image(&mut self, base: dagger_sdk::Container) -> &mut Self { self.base_image = Some(base); self } pub fn with_crates( &mut self, crates: impl IntoIterator>, ) -> &mut Self { self.crates = crates.into_iter().map(|c| c.into()).collect(); self } pub fn with_arch(&mut self, arch: Architecture) -> &mut Self { self.arch = Some(arch); self } pub fn with_os(&mut self, os: Os) -> &mut Self { self.os = Some(os); self } fn get_src(&self) -> PathBuf { self.source .clone() .unwrap_or(std::env::current_dir().unwrap()) } fn get_arch(&self) -> Architecture { self.arch .clone() .unwrap_or_else(|| match std::env::consts::ARCH { "x86" | "x86_64" | "amd64" => Architecture::Amd64, "arm" => Architecture::Arm64, arch => panic!("unsupported architecture: {arch}"), }) } fn get_os(&self) -> Os { self.os .clone() .unwrap_or_else(|| match std::env::consts::OS { "linux" => Os::Linux, "macos" => Os::MacOS, os => panic!("unsupported os: {os}"), }) } pub async fn build_base(&self) -> eyre::Result { let rust_src = RustSource::new(self.client.clone()); let (src, dep_src) = rust_src .get_rust_src(Some(&self.get_src()), self.crates.clone()) .await?; let base_image = self .base_image .clone() .unwrap_or(self.client.container().from("rustlang/rust:nightly")); let cache = self.client.cache_volume("rust_target_cache"); let rust_prebuild = base_image .with_workdir("/mnt/src") .with_directory("/mnt/src", dep_src) .with_exec(vec!["cargo", "build", "--tests", "--workspace"]) .with_mounted_cache("/mnt/src/target/", cache); let incremental_dir = rust_src .get_rust_target_src(&self.get_src(), rust_prebuild.clone(), self.crates.clone()) .await?; let rust_with_src = base_image .with_workdir("/mnt/src") .with_directory( "/usr/local/cargo", rust_prebuild.directory("/usr/local/cargo"), ) .with_directory("/mnt/src/target", incremental_dir) .with_directory("/mnt/src/", src); Ok(rust_with_src) } pub async fn build_test(&self) -> eyre::Result<()> { let base = self.build_base().await?; base.with_exec(vec!["cargo", "test", "--tests", "--workspace"]) .sync() .await?; Ok(()) } } #[async_trait] impl PullRequestAction for RustLib { async fn execute_pull_request(&self, _ctx: &mut cli::Context) -> eyre::Result<()> { self.build_test().await?; Ok(()) } } #[async_trait] impl MainAction for RustLib { async fn execute_main(&self, _ctx: &mut cli::Context) -> eyre::Result<()> { self.build_test().await?; Ok(()) } }