mirror of
https://github.com/imjasonh/krust
synced 2026-07-08 06:45:32 +00:00
Add Cargo.toml-based configuration for base image
- Add support for [package.metadata.krust] in Cargo.toml - Change default base image to cgr.dev/chainguard/static:latest - Add ProjectConfig struct to load project-specific settings - Update documentation and example to show configuration usage - Fix integration tests to explicitly pass directory argument - This is the idiomatic way for Rust build tools to be configured
This commit is contained in:
parent
5d254c7eca
commit
11083dc527
6 changed files with 74 additions and 7 deletions
24
README.md
24
README.md
|
|
@ -144,10 +144,23 @@ The tradeoff is that musl has slightly different behavior than glibc in some edg
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
krust looks for configuration at `~/.config/krust/config.toml`:
|
### Project Configuration (Cargo.toml)
|
||||||
|
|
||||||
|
You can configure krust on a per-project basis by adding a `[package.metadata.krust]` section to your project's `Cargo.toml`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
base_image = "gcr.io/distroless/static:nonroot"
|
[package.metadata.krust]
|
||||||
|
base-image = "cgr.dev/chainguard/static:latest" # Override the default base image
|
||||||
|
```
|
||||||
|
|
||||||
|
This is the idiomatic way to configure build tools in Rust, similar to how `cargo-deb`, `wasm-pack`, and other Cargo extensions work.
|
||||||
|
|
||||||
|
### Global Configuration
|
||||||
|
|
||||||
|
krust also looks for global configuration at `~/.config/krust/config.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
base_image = "cgr.dev/chainguard/static:latest" # Default base image for all projects
|
||||||
default_registry = "ghcr.io"
|
default_registry = "ghcr.io"
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
|
|
@ -160,6 +173,13 @@ password = "mytoken"
|
||||||
|
|
||||||
Note: Registry authentication is not yet implemented. Currently, krust uses anonymous authentication.
|
Note: Registry authentication is not yet implemented. Currently, krust uses anonymous authentication.
|
||||||
|
|
||||||
|
### Configuration Precedence
|
||||||
|
|
||||||
|
When determining the base image, krust uses this precedence order:
|
||||||
|
1. Project-specific config in `Cargo.toml` (highest priority)
|
||||||
|
2. Global config in `~/.config/krust/config.toml`
|
||||||
|
3. Built-in default: `cgr.dev/chainguard/static:latest` (lowest priority)
|
||||||
|
|
||||||
## Key Features
|
## Key Features
|
||||||
|
|
||||||
- **Docker-free** - Builds OCI container images without requiring Docker daemon
|
- **Docker-free** - Builds OCI container images without requiring Docker daemon
|
||||||
|
|
|
||||||
|
|
@ -4,3 +4,7 @@ version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
||||||
|
# Example: Configure krust to use a specific base image for this project
|
||||||
|
[package.metadata.krust]
|
||||||
|
base-image = "cgr.dev/chainguard/static:latest"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::PathBuf;
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
@ -45,7 +45,7 @@ pub struct RegistryAuth {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_base_image() -> String {
|
fn default_base_image() -> String {
|
||||||
"gcr.io/distroless/static:nonroot".to_string()
|
"cgr.dev/chainguard/static:latest".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
|
|
@ -59,6 +59,14 @@ impl Default for Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Project-specific configuration from Cargo.toml
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
|
pub struct ProjectConfig {
|
||||||
|
/// Base image for this project
|
||||||
|
#[serde(rename = "base-image")]
|
||||||
|
pub base_image: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn load() -> anyhow::Result<Self> {
|
pub fn load() -> anyhow::Result<Self> {
|
||||||
if let Some(config_dir) = dirs::config_dir() {
|
if let Some(config_dir) = dirs::config_dir() {
|
||||||
|
|
@ -71,4 +79,27 @@ impl Config {
|
||||||
}
|
}
|
||||||
Ok(Config::default())
|
Ok(Config::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Load project-specific configuration from Cargo.toml
|
||||||
|
pub fn load_project_config(project_path: &Path) -> anyhow::Result<ProjectConfig> {
|
||||||
|
let cargo_toml_path = project_path.join("Cargo.toml");
|
||||||
|
if !cargo_toml_path.exists() {
|
||||||
|
return Ok(ProjectConfig::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
let content = std::fs::read_to_string(&cargo_toml_path)?;
|
||||||
|
let value: toml::Value = toml::from_str(&content)?;
|
||||||
|
|
||||||
|
// Look for [package.metadata.krust] section
|
||||||
|
if let Some(metadata) = value
|
||||||
|
.get("package")
|
||||||
|
.and_then(|p| p.get("metadata"))
|
||||||
|
.and_then(|m| m.get("krust"))
|
||||||
|
{
|
||||||
|
let project_config: ProjectConfig = metadata.clone().try_into()?;
|
||||||
|
return Ok(project_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ProjectConfig::default())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_default_config() {
|
fn test_default_config() {
|
||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
assert_eq!(config.base_image, "gcr.io/distroless/static:nonroot");
|
assert_eq!(config.base_image, "cgr.dev/chainguard/static:latest");
|
||||||
assert!(config.default_registry.is_none());
|
assert!(config.default_registry.is_none());
|
||||||
assert!(config.registries.is_empty());
|
assert!(config.registries.is_empty());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
11
src/main.rs
11
src/main.rs
|
|
@ -38,6 +38,14 @@ async fn main() -> Result<()> {
|
||||||
let config = Config::load()?;
|
let config = Config::load()?;
|
||||||
let project_path = path.unwrap_or_else(|| PathBuf::from("."));
|
let project_path = path.unwrap_or_else(|| PathBuf::from("."));
|
||||||
|
|
||||||
|
// Load project-specific config from Cargo.toml
|
||||||
|
let project_config = Config::load_project_config(&project_path)?;
|
||||||
|
|
||||||
|
// Determine base image (project config takes precedence)
|
||||||
|
let base_image = project_config
|
||||||
|
.base_image
|
||||||
|
.unwrap_or(config.base_image.clone());
|
||||||
|
|
||||||
// Determine the image name
|
// Determine the image name
|
||||||
let image_ref = if let Some(image) = image {
|
let image_ref = if let Some(image) = image {
|
||||||
// Use explicit image if provided
|
// Use explicit image if provided
|
||||||
|
|
@ -56,8 +64,7 @@ async fn main() -> Result<()> {
|
||||||
let binary_path = builder.build()?;
|
let binary_path = builder.build()?;
|
||||||
|
|
||||||
// Build container image
|
// Build container image
|
||||||
let image_builder =
|
let image_builder = ImageBuilder::new(binary_path, base_image, platform.clone());
|
||||||
ImageBuilder::new(binary_path, config.base_image.clone(), platform.clone());
|
|
||||||
|
|
||||||
let (config_data, layer_data, manifest) = image_builder.build()?;
|
let (config_data, layer_data, manifest) = image_builder.build()?;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ fn test_build_requires_repo_or_image() -> Result<()> {
|
||||||
let mut cmd = Command::cargo_bin("krust")?;
|
let mut cmd = Command::cargo_bin("krust")?;
|
||||||
cmd.arg("build")
|
cmd.arg("build")
|
||||||
.arg("--no-push")
|
.arg("--no-push")
|
||||||
|
.arg(".") // Explicitly pass current directory
|
||||||
.current_dir(&example_dir)
|
.current_dir(&example_dir)
|
||||||
.env_remove("KRUST_REPO");
|
.env_remove("KRUST_REPO");
|
||||||
|
|
||||||
|
|
@ -71,6 +72,7 @@ fn test_build_with_krust_repo_env() -> Result<()> {
|
||||||
let mut cmd = Command::cargo_bin("krust")?;
|
let mut cmd = Command::cargo_bin("krust")?;
|
||||||
cmd.arg("build")
|
cmd.arg("build")
|
||||||
.arg("--no-push")
|
.arg("--no-push")
|
||||||
|
.arg(".") // Explicitly pass current directory
|
||||||
.env("KRUST_REPO", "test.local")
|
.env("KRUST_REPO", "test.local")
|
||||||
.current_dir(&example_dir);
|
.current_dir(&example_dir);
|
||||||
|
|
||||||
|
|
@ -95,6 +97,7 @@ fn test_command_substitution_syntax() -> Result<()> {
|
||||||
.arg("--no-push")
|
.arg("--no-push")
|
||||||
.arg("--image")
|
.arg("--image")
|
||||||
.arg("test.local/hello:latest")
|
.arg("test.local/hello:latest")
|
||||||
|
.arg(".") // Explicitly pass current directory
|
||||||
.current_dir(&example_dir)
|
.current_dir(&example_dir)
|
||||||
.output()?;
|
.output()?;
|
||||||
|
|
||||||
|
|
@ -122,6 +125,7 @@ fn test_verbose_logging() -> Result<()> {
|
||||||
.arg("--no-push")
|
.arg("--no-push")
|
||||||
.arg("--image")
|
.arg("--image")
|
||||||
.arg("test.local/hello:latest")
|
.arg("test.local/hello:latest")
|
||||||
|
.arg(".") // Explicitly pass current directory
|
||||||
.current_dir(&example_dir);
|
.current_dir(&example_dir);
|
||||||
|
|
||||||
cmd.assert()
|
cmd.assert()
|
||||||
|
|
@ -151,6 +155,7 @@ fn test_full_build_and_run_workflow() -> Result<()> {
|
||||||
let mut cmd = Command::cargo_bin("krust")?;
|
let mut cmd = Command::cargo_bin("krust")?;
|
||||||
let output = cmd
|
let output = cmd
|
||||||
.arg("build")
|
.arg("build")
|
||||||
|
.arg(".") // Explicitly pass current directory
|
||||||
.env("KRUST_REPO", "ttl.sh/krust-test")
|
.env("KRUST_REPO", "ttl.sh/krust-test")
|
||||||
.current_dir(&example_dir)
|
.current_dir(&example_dir)
|
||||||
.output()?;
|
.output()?;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue