use containers_api::opts::{Filter, FilterItem};
use containers_api::{
impl_filter_func, impl_map_field, impl_opts_builder, impl_opts_required_builder,
impl_url_bool_field, impl_url_enum_field, impl_url_field, impl_url_str_field,
impl_url_vec_field,
};
use serde::Serialize;
use base64::engine::Engine;
use std::collections::HashMap;
use std::fmt;
impl_opts_required_builder!(url =>
ImageBuild,
path => "path"
);
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Default)]
pub enum NetworkMode {
#[default]
Bridge,
Host,
None,
Container,
Custom(String),
}
impl AsRef<str> for NetworkMode {
fn as_ref(&self) -> &str {
match self {
NetworkMode::Bridge => "bridge",
NetworkMode::Host => "host",
NetworkMode::None => "none",
NetworkMode::Container => "container",
NetworkMode::Custom(custom) => custom,
}
}
}
impl fmt::Display for NetworkMode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_ref())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Platform {
os: String,
arch: Option<String>,
version: Option<String>,
}
impl Platform {
pub fn new(os: impl Into<String>) -> Self {
Self {
os: os.into(),
arch: None,
version: None,
}
}
pub fn arch(mut self, arch: impl Into<String>) -> Self {
self.arch = Some(arch.into());
self
}
pub fn version(mut self, version: impl Into<String>) -> Self {
self.version = Some(version.into());
self
}
}
impl fmt::Display for Platform {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(arch) = &self.arch {
if let Some(vers) = &self.version {
write!(f, "{}/{}/{}", self.os, arch, vers)
} else {
write!(f, "{}/{}", self.os, arch)
}
} else {
write!(f, "{}", self.os)
}
}
}
impl ImageBuildOptsBuilder {
impl_url_bool_field!(
all_platforms => "allplatforms"
);
impl_map_field!(url
build_args => "buildargs"
);
pub fn cache_from<S>(mut self, images: impl IntoIterator<Item = S>) -> Self
where
S: Into<String>,
{
self.params.insert(
"cachefrom",
serde_json::to_string(&images.into_iter().map(|i| i.into()).collect::<Vec<_>>())
.unwrap_or_default(),
);
self
}
impl_url_field!(
cpu_period: isize => "cpuperiod"
);
impl_url_field!(
cpu_quota: isize => "cpuquota"
);
impl_url_field!(
cpu_set_cpus: isize => "cpusetcpus"
);
impl_url_field!(
cpu_shares: isize => "cpushares"
);
impl_url_str_field!(
dockerfile => "dockerfile"
);
impl_url_str_field!(
extra_hosts => "extrahosts"
);
impl_url_bool_field!(
force_rm => "forcerm"
);
impl_url_bool_field!(
http_proxy => "httpproxy"
);
impl_map_field!(url
labels => "labels"
);
impl_url_bool_field!(
layers => "layers"
);
impl_url_field!(
memory: usize => "memory"
);
impl_url_field!(
memswap: usize => "memswap"
);
impl_url_enum_field!(
network_mode: NetworkMode => "networkmode"
);
impl_url_bool_field!(
no_cache => "nocache"
);
impl_url_str_field!(
outputs => "outputs"
);
pub fn platform(mut self, platform: Platform) -> Self {
self.params.insert("platform", platform.to_string());
self
}
impl_url_bool_field!(
pull => "pull"
);
impl_url_bool_field!(
quiet => "q"
);
impl_url_str_field!(
remote => "remote"
);
impl_url_bool_field!(
remove => "rm"
);
impl_url_field!(
shared_mem_size: usize => "shmsize"
);
impl_url_bool_field!(
squash => "squash"
);
impl_url_str_field!(
tag => "t"
);
impl_url_str_field!(
target => "target"
);
impl_url_vec_field!(
unset_env => "unsetenv"
);
}
impl_opts_builder!(url =>
ImageList
);
#[derive(Debug, Clone)]
pub enum ImageOpt {
Name(crate::Id),
Tag(crate::Id, String),
Digest(crate::Id, String),
}
impl fmt::Display for ImageOpt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use ImageOpt::*;
match self {
Name(id) => write!(f, "{id}"),
Tag(id, tag) => write!(f, "{id}:{tag}"),
Digest(id, digest) => write!(f, "{id}@{digest}"),
}
}
}
#[derive(Debug)]
pub enum ImageListFilter {
Before(ImageOpt),
Dangling(bool),
LabelKey(String),
LabelKeyVal(String, String),
NoLabelKey(String),
NoLabelKeyVal(String, String),
Reference(crate::Id, Option<String>),
Id(crate::Id),
Since(ImageOpt),
}
impl Filter for ImageListFilter {
fn query_item(&self) -> FilterItem {
use ImageListFilter::*;
match &self {
Before(image) => FilterItem::new("before", image.to_string()),
Dangling(dangling) => FilterItem::new("dangling", dangling.to_string()),
LabelKey(key) => FilterItem::new("label", key.clone()),
LabelKeyVal(key, val) => FilterItem::new("label", format!("{key}={val}")),
NoLabelKey(key) => FilterItem::new("label!", key.clone()),
NoLabelKeyVal(key, val) => FilterItem::new("label!", format!("{key}={val}")),
Reference(image, tag) => FilterItem::new(
"reference",
if let Some(tag) = tag {
format!("{image}:{tag}")
} else {
image.to_string()
},
),
Id(id) => FilterItem::new("id", id.to_string()),
Since(image) => FilterItem::new("since", image.to_string()),
}
}
}
impl ImageListOptsBuilder {
impl_filter_func!(ImageListFilter);
impl_url_bool_field!(
all => "all"
);
}
impl_opts_builder!(url =>
ImageTag
);
impl ImageTagOptsBuilder {
impl_url_str_field!(
repo => "repo"
);
impl_url_str_field!(
tag => "tag"
);
}
#[derive(Clone, Serialize, Debug)]
#[serde(untagged)]
pub enum RegistryAuth {
Password {
username: String,
password: String,
#[serde(skip_serializing_if = "Option::is_none")]
email: Option<String>,
#[serde(rename = "serveraddress")]
#[serde(skip_serializing_if = "Option::is_none")]
server_address: Option<String>,
},
Token {
#[serde(rename = "identitytoken")]
identity_token: String,
},
}
impl RegistryAuth {
pub fn token(token: impl Into<String>) -> RegistryAuth {
RegistryAuth::Token {
identity_token: token.into(),
}
}
pub fn builder() -> RegistryAuthBuilder {
RegistryAuthBuilder::default()
}
pub fn serialize(&self) -> String {
serde_json::to_string(self)
.map(|c| base64::engine::general_purpose::URL_SAFE.encode(c))
.unwrap_or_default()
}
}
#[derive(Default)]
pub struct RegistryAuthBuilder {
username: Option<String>,
password: Option<String>,
email: Option<String>,
server_address: Option<String>,
}
impl RegistryAuthBuilder {
pub fn username(&mut self, username: impl Into<String>) -> &mut Self {
self.username = Some(username.into());
self
}
pub fn password(&mut self, password: impl Into<String>) -> &mut Self {
self.password = Some(password.into());
self
}
pub fn email(&mut self, email: impl Into<String>) -> &mut Self {
self.email = Some(email.into());
self
}
pub fn server_address(&mut self, server_address: impl Into<String>) -> &mut Self {
self.server_address = Some(server_address.into());
self
}
pub fn build(&self) -> RegistryAuth {
RegistryAuth::Password {
username: self.username.clone().unwrap_or_default(),
password: self.password.clone().unwrap_or_default(),
email: self.email.clone(),
server_address: self.server_address.clone(),
}
}
}
#[derive(Default, Debug)]
pub struct PullOpts {
auth: Option<RegistryAuth>,
params: HashMap<&'static str, String>,
}
impl PullOpts {
pub fn builder() -> PullOptsBuilder {
PullOptsBuilder::default()
}
pub fn serialize(&self) -> Option<String> {
if self.params.is_empty() {
None
} else {
Some(containers_api::url::encoded_pairs(
self.params.iter().map(|(k, v)| (k, v)),
))
}
}
pub(crate) fn auth_header(&self) -> Option<String> {
self.auth.clone().map(|a| a.serialize())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Default)]
pub enum PullPolicy {
#[default]
Always,
Missing,
Newer,
Never,
}
impl AsRef<str> for PullPolicy {
fn as_ref(&self) -> &str {
match self {
PullPolicy::Always => "always",
PullPolicy::Missing => "missing",
PullPolicy::Newer => "newer",
PullPolicy::Never => "never",
}
}
}
impl fmt::Display for PullPolicy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_ref())
}
}
#[derive(Debug, Default)]
pub struct PullOptsBuilder {
auth: Option<RegistryAuth>,
params: HashMap<&'static str, String>,
}
impl PullOptsBuilder {
impl_url_bool_field!(
all_tags => "allTags"
);
impl_url_str_field!(
arch => "Arch"
);
impl_url_str_field!(
credentials => "credentials"
);
impl_url_str_field!(
os => "OS"
);
impl_url_enum_field!(
policy: PullPolicy => "policy"
);
impl_url_bool_field!(
quiet => "quiet"
);
impl_url_str_field!(
reference => "reference"
);
impl_url_bool_field!(
tls_verify => "tlsVerify"
);
impl_url_str_field!(
variant => "Variant"
);
pub fn auth(&mut self, auth: RegistryAuth) -> &mut Self {
self.auth = Some(auth);
self
}
pub fn build(&mut self) -> PullOpts {
PullOpts {
auth: self.auth.take(),
params: self.params.clone(),
}
}
}
impl_opts_builder!(url =>
ImageExport
);
impl ImageExportOptsBuilder {
impl_url_bool_field!(
compress => "compress"
);
impl_url_str_field!(
format => "format"
);
}
impl_opts_builder!(url =>
ImageImport
);
impl ImageImportOptsBuilder {
impl_url_vec_field!(
changes => "changes"
);
impl_url_str_field!(
message => "message"
);
impl_url_str_field!(
reference => "reference"
);
impl_url_str_field!(
url => "url"
);
}
impl_opts_builder!(url =>
ImageTree
);
impl ImageTreeOptsBuilder {
impl_url_bool_field!(
what_requires => "whatrequires"
);
}
impl_opts_builder!(url =>
ImagesRemove
);
impl ImagesRemoveOptsBuilder {
impl_url_bool_field!(
all => "all"
);
impl_url_bool_field!(
force => "force"
);
impl_url_bool_field!(
ignore => "ignore"
);
impl_url_vec_field!(
images => "images"
);
impl_url_bool_field!(
lookup_manifest => "lookupManifest"
);
}
#[derive(Default, Debug)]
pub struct ImagePushOpts {
auth: Option<RegistryAuth>,
params: HashMap<&'static str, String>,
}
impl ImagePushOpts {
pub fn builder() -> ImagePushOptsBuilder {
ImagePushOptsBuilder::default()
}
pub fn serialize(&self) -> Option<String> {
if self.params.is_empty() {
None
} else {
Some(containers_api::url::encoded_pairs(
self.params.iter().map(|(k, v)| (k, v)),
))
}
}
pub(crate) fn auth_header(&self) -> Option<String> {
self.auth.clone().map(|a| a.serialize())
}
}
#[derive(Debug, Default)]
pub struct ImagePushOptsBuilder {
auth: Option<RegistryAuth>,
params: HashMap<&'static str, String>,
}
impl ImagePushOptsBuilder {
impl_url_str_field!(
destination => "destination"
);
impl_url_bool_field!(
quiet => "quiet"
);
impl_url_bool_field!(
tls_verify => "tlsVerify"
);
pub fn auth(mut self, auth: RegistryAuth) -> Self {
self.auth = Some(auth);
self
}
pub fn build(self) -> ImagePushOpts {
ImagePushOpts {
auth: self.auth,
params: self.params,
}
}
}
#[derive(Debug)]
pub enum ImagePruneFilter {
Dangling(bool),
Until(String),
LabelKey(String),
LabelKeyVal(String, String),
NoLabelKey(String),
NoLabelKeyVal(String, String),
}
impl Filter for ImagePruneFilter {
fn query_item(&self) -> FilterItem {
use ImagePruneFilter::*;
match &self {
Dangling(dangling) => FilterItem::new("dangling", dangling.to_string()),
Until(until) => FilterItem::new("until", until.to_string()),
LabelKey(key) => FilterItem::new("label", key.clone()),
LabelKeyVal(key, val) => FilterItem::new("label", format!("{key}={val}")),
NoLabelKey(key) => FilterItem::new("label!", key.clone()),
NoLabelKeyVal(key, val) => FilterItem::new("label!", format!("{key}={val}")),
}
}
}
impl_opts_builder!(url =>
ImagePrune
);
impl ImagePruneOptsBuilder {
impl_filter_func!(
ImagePruneFilter
);
impl_url_bool_field!(
all => "all"
);
impl_url_bool_field!(
external => "external"
);
}
#[derive(Debug)]
pub enum ImageSearchFilter {
IsAutomated(bool),
IsOfficial(bool),
Stars(usize),
}
impl Filter for ImageSearchFilter {
fn query_item(&self) -> FilterItem {
use ImageSearchFilter::*;
match &self {
IsAutomated(is_automated) => FilterItem::new("is-automated", is_automated.to_string()),
IsOfficial(is_official) => FilterItem::new("is-official", is_official.to_string()),
Stars(stars) => FilterItem::new("stars", stars.to_string()),
}
}
}
impl_opts_builder!(url =>
ImageSearch
);
impl ImageSearchOptsBuilder {
impl_filter_func!(
ImageSearchFilter
);
impl_url_field!(
limit: usize => "limit"
);
impl_url_bool_field!(
list_tags => "listTags"
);
impl_url_str_field!(
term => "term"
);
impl_url_bool_field!(
tls_verify => "tlsVerify"
);
}
impl_opts_builder!(url =>
ImagesExport
);
impl ImagesExportOptsBuilder {
impl_url_bool_field!(
compress => "compress"
);
impl_url_str_field!(
format => "format"
);
impl_url_bool_field!(
oci_accept_uncompressed_layers => "ociAcceptUncompressedLayers"
);
impl_url_vec_field!(
references => "references"
);
}