use std::path::Path; use std::path::PathBuf; use std::sync::Arc; use clap::Args; use clap::Parser; use clap::Subcommand; use clap::ValueEnum; #[derive(Parser)] #[command(author, version, about, long_about = None, subcommand_required = true)] pub struct Command { #[command(subcommand)] commands: Commands, #[command(flatten)] global: GlobalArgs, } #[derive(Subcommand)] pub enum Commands { #[command(subcommand_required = true)] Local { #[command(subcommand)] command: LocalCommands, }, PullRequest, Main, Release, } #[derive(Subcommand)] pub enum LocalCommands { Build { #[arg(long, default_value = "debug")] profile: BuildProfile, }, Test, DockerImage { #[arg(long)] tag: Option, }, PleaseRelease, } #[derive(Debug, Clone, ValueEnum)] pub enum BuildProfile { Debug, Release, } #[derive(Debug, Clone, Args)] pub struct GlobalArgs { #[arg(long, global = true, help_heading = "Global")] dry_run: bool, #[arg(long, global = true, help_heading = "Global")] rust_builder_image: Option, #[arg(long, global = true, help_heading = "Global")] source: Option, } #[tokio::main] async fn main() -> eyre::Result<()> { let _ = color_eyre::install(); let client = dagger_sdk::connect().await?; let cli = Command::parse(); match cli.commands { Commands::Local { command } => match command { LocalCommands::Build { .. } => { let base_image = base_rust_image(client.clone(), &cli.global).await?; build::execute(client, &cli.global, base_image).await?; } LocalCommands::Test => todo!(), LocalCommands::DockerImage { .. } => todo!(), LocalCommands::PleaseRelease => todo!(), }, Commands::PullRequest => todo!(), Commands::Main => todo!(), Commands::Release => todo!(), } Ok(()) } mod build { use std::sync::Arc; use crate::GlobalArgs; pub async fn execute( client: Arc, _args: &GlobalArgs, container: dagger_sdk::Container, ) -> eyre::Result<()> { let build_image = container .pipeline("rust:build") .with_exec(vec!["cargo", "build"]); build_image.exit_code().await?; let out = build_image .with_exec(vec!["./target/debug/cuddle-please", "-h"]) .stdout() .await?; println!("stdout: {}", out); Ok(()) } } pub fn get_src( client: Arc, args: &GlobalArgs, ) -> eyre::Result { let directory = client.host().directory_opts( args.source .clone() .unwrap_or(PathBuf::from(".")) .display() .to_string(), dagger_sdk::HostDirectoryOptsBuilder::default() .exclude(vec!["node_modules/", ".git/", "target/"]) .build()?, ); Ok(directory) } pub async fn get_rust_dep_src( client: Arc, args: &GlobalArgs, ) -> eyre::Result { let directory = client.host().directory_opts( args.source .clone() .unwrap_or(PathBuf::from(".")) .display() .to_string(), dagger_sdk::HostDirectoryOptsBuilder::default() .include(vec!["**/Cargo.toml", "**/Cargo.lock"]) .build()?, ); let mut rust_crates = vec![PathBuf::from("ci")]; let mut dirs = tokio::fs::read_dir("crates").await?; while let Some(entry) = dirs.next_entry().await? { if entry.metadata().await?.is_dir() { rust_crates.push(entry.path()) } } fn create_skeleton_files( directory: dagger_sdk::Directory, path: &Path, ) -> eyre::Result { let main_content = r#"fn main() {}"#; let lib_content = r#"fn some() {}"#; let directory = directory.with_new_file( path.join("src").join("main.rs").display().to_string(), main_content, ); let directory = directory.with_new_file( path.join("src").join("lib.rs").display().to_string(), lib_content, ); Ok(directory) } let mut directory = directory; for rust_crate in rust_crates.into_iter() { directory = create_skeleton_files(directory, &rust_crate)? } Ok(directory) } pub async fn base_rust_image( client: Arc, args: &GlobalArgs, ) -> eyre::Result { let dep_src = get_rust_dep_src(client.clone(), args).await?; let src = get_src(client.clone(), args)?; let client = client.pipeline("rust_base_image"); let rust_build_image = client.container().from( args.rust_builder_image .as_ref() .unwrap_or(&"rustlang/rust:nightly".into()), ); let target_cache = client.cache_volume("rust_target"); let rust_build_image = rust_build_image .with_workdir("/mnt/src") .with_directory("/mnt/src", dep_src.id().await?) .with_exec(vec!["cargo", "build"]) .with_mounted_cache("/mnt/src/target/", target_cache.id().await?) .with_directory("/mnt/src/crates", src.directory("crates").id().await?); Ok(rust_build_image) }