From f5c07acf889ca2cc5db3c382bb6c833f58e98c72 Mon Sep 17 00:00:00 2001 From: tahahawa Date: Thu, 12 Jun 2025 00:48:49 -0400 Subject: [PATCH] WIP compilation, docker, cargo, etc --- Cargo.lock | 309 ++++++++++++----------------------- harmony_composer/Cargo.toml | 4 +- harmony_composer/src/main.rs | 178 ++++++++++++++++---- 3 files changed, 257 insertions(+), 234 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 09a76be..34c8441 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -195,28 +195,6 @@ dependencies = [ "wait-timeout", ] -[[package]] -name = "async-stream" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "async-trait" version = "0.1.88" @@ -240,53 +218,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" -[[package]] -name = "axum" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" -dependencies = [ - "async-trait", - "axum-core", - "bytes", - "futures-util", - "http 1.3.1", - "http-body 1.0.1", - "http-body-util", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper 1.0.2", - "tower 0.5.2", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 1.3.1", - "http-body 1.0.1", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper 1.0.2", - "tower-layer", - "tower-service", -] - [[package]] name = "backtrace" version = "0.3.75" @@ -415,26 +346,48 @@ dependencies = [ ] [[package]] -name = "bon" -version = "2.3.0" +name = "bollard" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97493a391b4b18ee918675fb8663e53646fd09321c58b46afa04e8ce2499c869" +checksum = "af706e9dc793491dd382c99c22fde6e9934433d4cc0d6a4b34eb2cdc57a5c917" dependencies = [ - "bon-macros", - "rustversion", + "base64 0.22.1", + "bollard-stubs", + "bytes", + "futures-core", + "futures-util", + "hex", + "http 1.3.1", + "http-body-util", + "hyper 1.6.0", + "hyper-named-pipe", + "hyper-util", + "hyperlocal", + "log", + "pin-project-lite", + "serde", + "serde_derive", + "serde_json", + "serde_repr", + "serde_urlencoded", + "thiserror 2.0.12", + "tokio", + "tokio-util", + "tower-service", + "url", + "winapi", ] [[package]] -name = "bon-macros" -version = "2.3.0" +name = "bollard-stubs" +version = "1.48.2-rc.28.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2af3eac944c12cdf4423eab70d310da0a8e5851a18ffb192c0a5e3f7ae1663" +checksum = "79cdf0fccd5341b38ae0be74b74410bdd5eceeea8876dc149a13edfe57e3b259" dependencies = [ - "darling", - "ident_case", - "proc-macro2", - "quote", - "syn", + "serde", + "serde_json", + "serde_repr", + "serde_with", ] [[package]] @@ -1104,6 +1057,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "current_platform" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a74858bcfe44b22016cb49337d7b6f04618c58e5dbfdef61b06b8c434324a0bc" + [[package]] name = "curve25519-dalek" version = "4.1.3" @@ -1286,17 +1245,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" -[[package]] -name = "docker_utils" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a64876aa646872a68ad74a6dba097f35a6641530767cb7c74a74d7a58099f3" -dependencies = [ - "bon", - "tokio", - "wait_utils", -] - [[package]] name = "dockerfile_builder" version = "0.1.5" @@ -2835,10 +2783,12 @@ name = "harmony_composer" version = "0.1.0" dependencies = [ "assert_cmd", + "bollard", "cargo", "clap", - "docker_utils", + "current_platform", "env_logger", + "futures-util", "inquire", "log", "tokio", @@ -3171,6 +3121,21 @@ dependencies = [ "tower-service", ] +[[package]] +name = "hyper-named-pipe" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b7d8abf35697b81a825e386fc151e0d503e8cb5fcb93cc8669c376dfd6f278" +dependencies = [ + "hex", + "hyper 1.6.0", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", + "winapi", +] + [[package]] name = "hyper-rustls" version = "0.27.5" @@ -3252,6 +3217,21 @@ dependencies = [ "tracing", ] +[[package]] +name = "hyperlocal" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "986c5ce3b994526b3cd75578e62554abd09f0899d6206de48b3e96ab34ccc8c7" +dependencies = [ + "hex", + "http-body-util", + "hyper 1.6.0", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + [[package]] name = "iana-time-zone" version = "0.1.63" @@ -3433,6 +3413,7 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", + "serde", ] [[package]] @@ -3443,6 +3424,7 @@ checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", "hashbrown 0.15.3", + "serde", ] [[package]] @@ -3720,7 +3702,7 @@ dependencies = [ "thiserror 2.0.12", "tokio", "tokio-util", - "tower 0.5.2", + "tower", "tower-http", "tracing", ] @@ -3934,12 +3916,6 @@ dependencies = [ "regex-automata 0.1.10", ] -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - [[package]] name = "maybe-async" version = "0.2.10" @@ -4206,7 +4182,7 @@ dependencies = [ "serde_urlencoded", "snafu", "tokio", - "tower 0.5.2", + "tower", "tower-http", "tracing", "url", @@ -4783,29 +4759,6 @@ dependencies = [ "parking_lot", ] -[[package]] -name = "prost" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-derive" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" -dependencies = [ - "anyhow", - "itertools 0.14.0", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "punycode" version = "0.4.1" @@ -5071,7 +5024,7 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-util", - "tower 0.5.2", + "tower", "tower-service", "url", "wasm-bindgen", @@ -5621,6 +5574,17 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "serde_spanned" version = "0.6.9" @@ -5654,6 +5618,23 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.9.0", + "serde", + "serde_derive", + "serde_json", + "time", +] + [[package]] name = "serde_yaml" version = "0.9.34+deprecated" @@ -6320,69 +6301,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" -[[package]] -name = "tonic" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" -dependencies = [ - "async-stream", - "async-trait", - "axum", - "base64 0.22.1", - "bytes", - "h2 0.4.10", - "http 1.3.1", - "http-body 1.0.1", - "http-body-util", - "hyper 1.6.0", - "hyper-timeout", - "hyper-util", - "percent-encoding", - "pin-project", - "prost", - "socket2", - "tokio", - "tokio-stream", - "tower 0.4.13", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tonic-health" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1eaf34ddb812120f5c601162d5429933c9b527d901ab0e7f930d3147e33a09b2" -dependencies = [ - "async-stream", - "prost", - "tokio", - "tokio-stream", - "tonic", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "indexmap 1.9.3", - "pin-project", - "pin-project-lite", - "rand 0.8.5", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - [[package]] name = "tower" version = "0.5.2" @@ -6415,7 +6333,7 @@ dependencies = [ "iri-string", "mime", "pin-project-lite", - "tower 0.5.2", + "tower", "tower-layer", "tower-service", "tracing", @@ -6712,17 +6630,6 @@ dependencies = [ "libc", ] -[[package]] -name = "wait_utils" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b85a9ad6d6ec47dbc18c38417377a5dc3de1587fbb2b92a2e33c0ae0c6aea9" -dependencies = [ - "tokio", - "tonic", - "tonic-health", -] - [[package]] name = "walkdir" version = "2.5.0" diff --git a/harmony_composer/Cargo.toml b/harmony_composer/Cargo.toml index 87f15cc..9554e96 100644 --- a/harmony_composer/Cargo.toml +++ b/harmony_composer/Cargo.toml @@ -13,4 +13,6 @@ tokio.workspace = true env_logger.workspace = true log.workspace = true cargo = "0.88.0" -docker_utils = "0.2.3" +bollard = "0.19.0" +current_platform = "0.2.0" +futures-util = "0.3.31" diff --git a/harmony_composer/src/main.rs b/harmony_composer/src/main.rs index dbeee37..57057ee 100644 --- a/harmony_composer/src/main.rs +++ b/harmony_composer/src/main.rs @@ -1,17 +1,28 @@ +use bollard::models::ContainerCreateBody; +use bollard::query_parameters::{ + AttachContainerOptions, CreateContainerOptionsBuilder, ListContainersOptionsBuilder, + RemoveContainerOptions, StartContainerOptions, WaitContainerOptions, +}; +use bollard::secret::HostConfig; +use clap::{Args, Parser, Subcommand}; +use futures_util::StreamExt; +use log::info; +use std::collections::HashMap; use std::path::Path; use std::process::Command; -use clap::builder::ArgPredicate; -use clap::{Args, Parser, Subcommand}; -use inquire::Confirm; -use log::{debug, info, warn}; - #[derive(Parser)] #[command(version, about, long_about = None, flatten_help = true, propagate_version = true)] struct GlobalArgs { #[arg(long, default_value = "harmony")] harmony_path: String, + #[arg(long)] + compile_method: Option, + + #[arg(long)] + compile_platform: Option, + #[command(subcommand)] command: Option, } @@ -60,7 +71,8 @@ struct AllArgs { deploy: DeployArgs, } -fn main() { +#[tokio::main] +async fn main() { env_logger::init(); let cli_args = GlobalArgs::parse(); @@ -69,28 +81,36 @@ fn main() { .expect("couldn't check if path exists"); match harmony_path { - true => compile_harmony(cli_args.harmony_path.clone()), + true => compile_harmony(cli_args.compile_method, None, cli_args.harmony_path.clone()).await, false => todo!("implement autodetect code"), } match cli_args.command { Some(command) => match command { Commands::Check(args) => { - let check_script = match Path::new(&format!( - "{}/{}", - cli_args.harmony_path, args.check_script_path - )) - .try_exists() + let check_script_str = + format!("{}/{}", cli_args.harmony_path, args.check_script_path); + + let check_script = Path::new(&check_script_str); + + match check_script + .try_exists() + .expect("couldn't check if path exists") { - Ok(path) => path, - Err(_) => todo!("implement logic when couldn't find check script"), + true => (), + false => todo!("implement couldn't find path logic"), }; let check_output = Command::new("sh") .arg("-c") - .arg(check_script.to_string()) + .arg(check_script) .output() .expect("failed to run check script"); + info!( + "check stdout: {}, check stderr: {}", + String::from_utf8(check_output.stdout).expect("couldn't parse from utf8"), + String::from_utf8(check_output.stderr).expect("couldn't parse from utf8") + ); } Commands::Package(args) => { if args.publish { @@ -108,7 +128,7 @@ fn main() { } todo!("implement deployment logic"); } - Commands::All(args) => todo!( + Commands::All(_args) => todo!( "take all previous match arms and turn them into separate functions, and call them all one after the other" ), }, @@ -116,27 +136,121 @@ fn main() { } } -fn compile_harmony(harmony_location: String) { +#[derive(Clone, Debug, clap::ValueEnum)] +enum CompileMethod { + LocalCargo, + Docker, +} + +async fn compile_harmony( + method: Option, + platform: Option, + harmony_location: String, +) { + let platform = match platform { + Some(p) => p, + None => current_platform::CURRENT_PLATFORM.to_string(), + }; + let gctx = cargo::util::context::GlobalContext::default().unwrap(); let cargo_exists = gctx.cargo_exe().unwrap().exists(); - if cargo_exists { - let _cargo_build = cargo::ops::compile( - &cargo::core::Workspace::new( - &Path::new(&format!("{}/Cargo.toml", harmony_location)) - .canonicalize() - .expect("Couldn't find Cargo.toml in harmony dir"), - &gctx, - ) - .unwrap(), - &cargo::ops::CompileOptions::new(&gctx, cargo::core::compiler::CompileMode::Build) - .unwrap(), + let method = match method { + Some(m) => m, + None => { + if cargo_exists { + compile_cargo(gctx, harmony_location).await; + return; + } else { + compile_docker(platform, harmony_location).await; + return; + } + } + }; + + match method { + CompileMethod::LocalCargo => compile_cargo(gctx, harmony_location).await, + CompileMethod::Docker => compile_docker(platform, harmony_location).await, + }; +} + +async fn compile_cargo(gctx: cargo::util::context::GlobalContext, harmony_location: String) { + let _cargo_build = cargo::ops::compile( + &cargo::core::Workspace::new( + &Path::new(&format!("{}/Cargo.toml", harmony_location)) + .canonicalize() + .expect("Couldn't find Cargo.toml in harmony dir"), + &gctx, ) - .expect("build didn't go successfully"); - return; + .unwrap(), + &cargo::ops::CompileOptions::new(&gctx, cargo::core::compiler::CompileMode::Build).unwrap(), + ) + .expect("build didn't go successfully"); + return; +} + +async fn compile_docker(platform: String, harmony_location: String) { + let docker_client = + bollard::Docker::connect_with_local_defaults().expect("couldn't connect to docker"); + + let mut filters = HashMap::new(); + filters.insert(String::from("name"), vec![String::from("harmony_build")]); + let list_containers_options = ListContainersOptionsBuilder::new() + .all(true) + .filters(&filters) + .build(); + + let containers = &docker_client + .list_containers(Some(list_containers_options)) + .await + .expect("list containers failed"); + + if containers.len() > 0 { + docker_client + .remove_container("harmony_build", None::) + .await + .expect("failed to remove container"); } - let _docker_util = docker_utils::DockerUtil::new().expect("Failed to create DockerUtil"); + let options = Some( + CreateContainerOptionsBuilder::new() + .name("harmony_build") + .build(), + ); - todo!("implement docker build container"); + let config = ContainerCreateBody { + image: Some("docker.io/rust:1.87.0".to_string()), + working_dir: Some("/mnt".to_string()), + entrypoint: Some(vec![ + "cargo".to_string(), + "build".to_string(), + format!("--target={}", platform), + "--release".to_string(), + ]), + host_config: Some(HostConfig { + binds: Some(vec![format!("{}:/mnt", harmony_location)]), + ..Default::default() + }), + ..Default::default() + }; + + docker_client + .create_container(options, config) + .await + .expect("couldn't create container"); + + docker_client + .start_container("harmony_build", None::) + .await + .expect("couldn't start container"); + + let wait_options = WaitContainerOptions { + condition: "not-running".to_string(), + }; + let mut wait = docker_client + .wait_container("harmony_build", Some(wait_options)) + .boxed(); + + // wait until container is no longer running + while let Some(_) = wait.next().await {} }