diff --git a/Cargo.toml b/Cargo.toml index a96416c..ab0bea1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,9 @@ edition = "2021" [dependencies] axum = { version = "0.8.1" } bollard = { version = "0.18.1", registry = "cratesio" } +futures-util = { version = "0.3.31", registry = "cratesio" } git2 = { version = "0.20.0" } +serde = { version = "1.0.217", features = ["derive"] } tokio = { version = "1.43.0", features = ["full"] } tower-http = { version = "0.6.2", features = ["trace"] } tracing = { version = "0.1.41" } diff --git a/src/bin/main.rs b/src/bin/main.rs index e424ef1..2fa07ea 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,30 +1,97 @@ -use std::process::ExitCode; +use std::{collections::HashMap, process::ExitCode, sync::Arc}; -use axum::{routing::get, Router}; -use bollard::Docker; +use axum::{ + extract::State, + http::StatusCode, + routing::{get, post}, + Json, Router, +}; +use bollard::{image::BuildImageOptions, Docker}; +use futures_util::stream::StreamExt; use git2::Repository; +use serde::Deserialize; +use tokio::sync::Mutex; use tower_http::trace::TraceLayer; use tracing::level_filters::LevelFilter; -#[tokio::main] -async fn download_repository(url: &str, name: &str) { - let folder = format!("/tmp/{name}"); +struct AppState { + docker: Docker, + pub(crate) name: Option, +} - match tokio::fs::try_exists(&folder).await { +#[derive(Deserialize)] +struct CdBuild { + url: String, + path: String, + serve: bool, + name: String, +} + +async fn build( + State(state): State>>, + Json(cd): Json, +) -> (StatusCode, &'static str) { + match tokio::fs::try_exists(&cd.path).await { Ok(true) => { - let repo = Repository::open(folder).unwrap(); + let repo = Repository::open(&cd.path).unwrap(); repo.find_remote("origin") .unwrap() .fetch(&["main"], None, None) .unwrap(); } Ok(false) => { - Repository::clone(url, folder).unwrap(); + Repository::clone(&cd.url, &cd.path).unwrap(); } Err(error) => { tracing::error!("{error}"); } + } + + let build_image_options = BuildImageOptions { + dockerfile: "Dockerfile", + t: "bollard-build-example", + extrahosts: Some("myhost:127.0.0.1"), + remote: "", + q: false, + nocache: false, + cachefrom: vec![], + pull: true, + rm: true, + forcerm: true, + memory: Some(120_000_000), + memswap: Some(500_000), + cpushares: Some(2), + cpusetcpus: "0-3", + cpuperiod: Some(2000), + cpuquota: Some(1000), + buildargs: HashMap::new(), + shmsize: Some(1_000_000), + squash: false, + labels: HashMap::new(), + networkmode: "host", + platform: "linux/x86_64", + target: "", + #[cfg(feature = "buildkit")] + session: None, + #[cfg(feature = "buildkit")] + outputs: None, + version: bollard::image::BuilderVersion::BuilderV1, }; + + { + let mtx = state.lock().await; + let mut image_build_stream = mtx.docker.build_image(build_image_options, None, None); + while let Some(msg) = image_build_stream.next().await { + tracing::info!("{msg:?}"); + } + } + + if cd.serve { + let mut mtx = state.lock().await; + mtx.name = Some(cd.name); + } + + (StatusCode::OK, "ok") } #[tokio::main] @@ -65,17 +132,14 @@ async fn main() -> ExitCode { } }; - let app = Router::new() - .route( - "/api/v1/image/build", - get({ - download_repository("URL", "microdeploy"); + let shared_state = Arc::new(Mutex::new(AppState { docker, name: None })); - "todo" - }), - ) - .route("/api/v1/image/serve", get("todo")) - .layer(TraceLayer::new_for_http()); + let app = Router::new() + .route("/api/v1/build", post(build)) + .route("/api/v1/serve", get("todo")) + .route("/api/v1/stop", get("todo")) + .layer(TraceLayer::new_for_http()) + .with_state(shared_state); match axum::serve(listener, app).await { Ok(()) => ExitCode::SUCCESS,