1
0
Fork 0
mirror of https://github.com/imjasonh/krust synced 2026-07-18 06:56:13 +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:
Jason Hall 2025-06-07 20:46:08 -04:00
commit 5e89023925
Failed to extract signature
23 changed files with 1611 additions and 0 deletions

74
src/config/mod.rs Normal file
View file

@ -0,0 +1,74 @@
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::PathBuf;
#[cfg(test)]
mod tests;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
/// Default base image for containers
#[serde(default = "default_base_image")]
pub base_image: String,
/// Default registry to push images to
pub default_registry: Option<String>,
/// Build configuration
#[serde(default)]
pub build: BuildConfig,
/// Registry authentication configuration
#[serde(default)]
pub registries: HashMap<String, RegistryAuth>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct BuildConfig {
/// Additional environment variables for cargo build
#[serde(default)]
pub env: HashMap<String, String>,
/// Default cargo build arguments
#[serde(default)]
pub cargo_args: Vec<String>,
/// Target directory for build artifacts
pub target_dir: Option<PathBuf>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RegistryAuth {
pub username: Option<String>,
pub password: Option<String>,
pub auth: Option<String>,
}
fn default_base_image() -> String {
"gcr.io/distroless/static:nonroot".to_string()
}
impl Default for Config {
fn default() -> Self {
Self {
base_image: default_base_image(),
default_registry: None,
build: BuildConfig::default(),
registries: HashMap::new(),
}
}
}
impl Config {
pub fn load() -> anyhow::Result<Self> {
if let Some(config_dir) = dirs::config_dir() {
let config_path = config_dir.join("krust").join("config.toml");
if config_path.exists() {
let content = std::fs::read_to_string(config_path)?;
let config: Config = toml::from_str(&content)?;
return Ok(config);
}
}
Ok(Config::default())
}
}

20
src/config/tests.rs Normal file
View file

@ -0,0 +1,20 @@
#[cfg(test)]
mod tests {
use super::super::*;
#[test]
fn test_default_config() {
let config = Config::default();
assert_eq!(config.base_image, "gcr.io/distroless/static:nonroot");
assert!(config.default_registry.is_none());
assert!(config.registries.is_empty());
}
#[test]
fn test_build_config_default() {
let build_config = BuildConfig::default();
assert!(build_config.env.is_empty());
assert!(build_config.cargo_args.is_empty());
assert!(build_config.target_dir.is_none());
}
}