use crate::error::{Error, Result};
use std::collections::HashMap;
use std::path::PathBuf;
#[derive(Debug, Clone)]
pub enum DockerfileSource {
Local {
context_path: PathBuf,
dockerfile_path: Option<PathBuf>,
},
GitHub {
repo_url: String,
git_ref: Option<String>,
dockerfile_path: Option<String>,
token: Option<String>,
},
}
#[derive(Debug, Clone)]
pub struct Platform {
pub os: String,
pub arch: String,
pub variant: Option<String>,
}
impl Platform {
pub fn linux_amd64() -> Self {
Self {
os: "linux".to_string(),
arch: "amd64".to_string(),
variant: None,
}
}
pub fn linux_arm64() -> Self {
Self {
os: "linux".to_string(),
arch: "arm64".to_string(),
variant: None,
}
}
pub fn parse(s: &str) -> Result<Self> {
let parts: Vec<&str> = s.split('/').collect();
match parts.as_slice() {
[os, arch] => Ok(Self {
os: os.to_string(),
arch: arch.to_string(),
variant: None,
}),
[os, arch, variant] => Ok(Self {
os: os.to_string(),
arch: arch.to_string(),
variant: Some(variant.to_string()),
}),
_ => Err(Error::InvalidPlatform(s.to_string())),
}
}
}
impl std::fmt::Display for Platform {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(variant) = &self.variant {
write!(f, "{}/{}/{}", self.os, self.arch, variant)
} else {
write!(f, "{}/{}", self.os, self.arch)
}
}
}
#[derive(Debug, Clone)]
pub struct RegistryAuth {
pub host: String,
pub username: String,
pub password: String,
}
#[derive(Debug, Clone)]
pub struct BuildConfig {
pub source: DockerfileSource,
pub build_args: HashMap<String, String>,
pub target: Option<String>,
pub platforms: Vec<Platform>,
pub tags: Vec<String>,
pub registry_auth: Option<RegistryAuth>,
pub cache_from: Vec<String>,
pub cache_to: Vec<String>,
pub secrets: HashMap<String, String>,
pub ssh_agents: Vec<String>,
pub no_cache: bool,
pub pull: bool,
}
impl Default for BuildConfig {
fn default() -> Self {
Self {
source: DockerfileSource::Local {
context_path: PathBuf::from("."),
dockerfile_path: None,
},
build_args: HashMap::new(),
target: None,
platforms: vec![Platform::linux_amd64()],
tags: Vec::new(),
registry_auth: None,
cache_from: Vec::new(),
cache_to: Vec::new(),
secrets: HashMap::new(),
ssh_agents: Vec::new(),
no_cache: false,
pull: false,
}
}
}
impl BuildConfig {
pub fn local(context_path: impl Into<PathBuf>) -> Self {
Self {
source: DockerfileSource::Local {
context_path: context_path.into(),
dockerfile_path: None,
},
..Default::default()
}
}
pub fn github(repo_url: impl Into<String>) -> Self {
Self {
source: DockerfileSource::GitHub {
repo_url: repo_url.into(),
git_ref: None,
dockerfile_path: None,
token: None,
},
..Default::default()
}
}
pub fn dockerfile(mut self, path: impl Into<String>) -> Self {
match &mut self.source {
DockerfileSource::Local { dockerfile_path, .. } => {
*dockerfile_path = Some(PathBuf::from(path.into()));
}
DockerfileSource::GitHub { dockerfile_path, .. } => {
*dockerfile_path = Some(path.into());
}
}
self
}
pub fn build_arg(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.build_args.insert(key.into(), value.into());
self
}
pub fn target(mut self, target: impl Into<String>) -> Self {
self.target = Some(target.into());
self
}
pub fn platform(mut self, platform: Platform) -> Self {
self.platforms.push(platform);
self
}
pub fn tag(mut self, tag: impl Into<String>) -> Self {
self.tags.push(tag.into());
self
}
pub fn registry_auth(mut self, auth: RegistryAuth) -> Self {
self.registry_auth = Some(auth);
self
}
pub fn github_token(mut self, token: impl Into<String>) -> Self {
if let DockerfileSource::GitHub { token: ref mut t, .. } = &mut self.source {
*t = Some(token.into());
}
self
}
pub fn git_ref(mut self, git_ref: impl Into<String>) -> Self {
if let DockerfileSource::GitHub { git_ref: ref mut r, .. } = &mut self.source {
*r = Some(git_ref.into());
}
self
}
pub fn cache_from(mut self, source: impl Into<String>) -> Self {
self.cache_from.push(source.into());
self
}
pub fn cache_to(mut self, dest: impl Into<String>) -> Self {
self.cache_to.push(dest.into());
self
}
pub fn secret(mut self, id: impl Into<String>, value: impl Into<String>) -> Self {
self.secrets.insert(id.into(), value.into());
self
}
pub fn no_cache(mut self, no_cache: bool) -> Self {
self.no_cache = no_cache;
self
}
pub fn pull(mut self, pull: bool) -> Self {
self.pull = pull;
self
}
}