WIP compilation, docker, cargo, etc

This commit is contained in:
tahahawa
2025-06-12 00:48:49 -04:00
parent edf96780e7
commit f5c07acf88
3 changed files with 257 additions and 234 deletions

View File

@@ -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"

View File

@@ -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<CompileMethod>,
#[arg(long)]
compile_platform: Option<String>,
#[command(subcommand)]
command: Option<Commands>,
}
@@ -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<CompileMethod>,
platform: Option<String>,
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::<RemoveContainerOptions>)
.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::<StartContainerOptions>)
.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 {}
}