mirror of
https://github.com/imjasonh/krust
synced 2026-07-18 23:16:03 +00:00
Initial commit: krust - container image build tool for Rust
krust builds container images for Rust applications without Docker: - Builds static binaries using musl libc - Creates minimal OCI container images - Pushes to any OCI-compliant registry - Outputs digest to stdout for composability Inspired by ko.build for Go applications. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
commit
5e89023925
23 changed files with 1611 additions and 0 deletions
111
src/main.rs
Normal file
111
src/main.rs
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
use anyhow::{Context, Result};
|
||||
use clap::Parser;
|
||||
use krust::{
|
||||
builder::{get_rust_target_triple, RustBuilder},
|
||||
cli::{Cli, Commands},
|
||||
config::Config,
|
||||
image::ImageBuilder,
|
||||
registry::RegistryClient,
|
||||
};
|
||||
use std::path::PathBuf;
|
||||
use tracing::{error, info};
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let cli = Cli::parse();
|
||||
|
||||
// Initialize logging to stderr
|
||||
let filter = if cli.verbose {
|
||||
EnvFilter::new("debug")
|
||||
} else {
|
||||
EnvFilter::new("info")
|
||||
};
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(filter)
|
||||
.with_writer(std::io::stderr)
|
||||
.init();
|
||||
|
||||
match cli.command {
|
||||
Commands::Build {
|
||||
path,
|
||||
image,
|
||||
platform,
|
||||
no_push,
|
||||
repo,
|
||||
cargo_args,
|
||||
} => {
|
||||
let config = Config::load()?;
|
||||
let project_path = path.unwrap_or_else(|| PathBuf::from("."));
|
||||
|
||||
// Determine the image name
|
||||
let image_ref = if let Some(image) = image {
|
||||
// Use explicit image if provided
|
||||
image
|
||||
} else {
|
||||
// Build image name from repo and project name
|
||||
let repo = repo.context("Either --image or KRUST_REPO must be set")?;
|
||||
let project_name = get_project_name(&project_path)?;
|
||||
format!("{}/{}:latest", repo, project_name)
|
||||
};
|
||||
|
||||
// Build the Rust binary
|
||||
let target = get_rust_target_triple(&platform)?;
|
||||
let builder = RustBuilder::new(&project_path, &target).with_cargo_args(cargo_args);
|
||||
|
||||
let binary_path = builder.build()?;
|
||||
|
||||
// Build container image
|
||||
let image_builder =
|
||||
ImageBuilder::new(binary_path, config.base_image.clone(), platform.clone());
|
||||
|
||||
let (config_data, layer_data, manifest) = image_builder.build()?;
|
||||
|
||||
// Push by default unless --no-push is specified
|
||||
if !no_push {
|
||||
info!("Pushing image to registry...");
|
||||
let auth = oci_distribution::secrets::RegistryAuth::Anonymous;
|
||||
let mut registry_client = RegistryClient::new(auth)?;
|
||||
|
||||
let layers = vec![(layer_data, manifest.layers[0].media_type.clone())];
|
||||
|
||||
let digest_ref = registry_client
|
||||
.push_image(&image_ref, config_data, layers)
|
||||
.await?;
|
||||
|
||||
// Print only the digest reference to stdout
|
||||
println!("{}", digest_ref);
|
||||
} else {
|
||||
info!("Successfully built image: {}", image_ref);
|
||||
info!("Skipping push (--no-push specified)");
|
||||
}
|
||||
}
|
||||
Commands::Push { image } => {
|
||||
let _ = image;
|
||||
error!("Push command not yet implemented");
|
||||
std::process::exit(1);
|
||||
}
|
||||
Commands::Version => {
|
||||
println!("krust {}", env!("CARGO_PKG_VERSION"));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_project_name(project_path: &PathBuf) -> Result<String> {
|
||||
let cargo_toml_path = project_path.join("Cargo.toml");
|
||||
let content = std::fs::read_to_string(&cargo_toml_path)
|
||||
.context("Failed to read Cargo.toml")?;
|
||||
|
||||
let manifest: toml::Value = toml::from_str(&content)
|
||||
.context("Failed to parse Cargo.toml")?;
|
||||
|
||||
let name = manifest
|
||||
.get("package")
|
||||
.and_then(|p| p.get("name"))
|
||||
.and_then(|n| n.as_str())
|
||||
.context("Failed to get package name from Cargo.toml")?;
|
||||
|
||||
Ok(name.to_string())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue