#[derive(Debug, Clone, Default)]
pub struct ImageBuildOptions {
pub tag: Option<String>,
pub dockerfile: Option<String>,
pub build_args: Vec<(String, String)>,
pub labels: Vec<(String, String)>,
pub platform: Option<String>,
pub target: Option<String>,
pub no_cache: bool,
pub pull: bool,
pub force_rm: bool,
}
#[derive(Debug, Clone, Default)]
pub struct ImageCommitOptions {
pub container: Option<String>,
pub repo: Option<String>,
pub tag: Option<String>,
pub comment: Option<String>,
pub author: Option<String>,
pub pause: Option<bool>,
pub changes: Option<String>,
}
use foundation_netio::shared::http::{SendSafeBody, SimpleHeader};
use foundation_netio::PreparedRequestBuilder;
use crate::client::body::{ByteBody, ProgressStream};
use crate::client::build_context::ContextTar;
use crate::error::DockerError;
use crate::generated::build::{image_build_request, ImageBuildArgs};
use crate::generated::commit::{image_commit_request, ContainerConfig, ImageCommitArgs};
use crate::generated::create::{image_create_request, CreateImageInfo, ImageCreateArgs};
use crate::generated::get::{image_get_all_request, image_get_request, ImageGetAllArgs, ImageGetArgs};
use crate::generated::history::{image_history_request, ImageHistoryArgs};
use crate::generated::images::{image_delete_request, ImageDeleteArgs};
use crate::generated::json::{image_inspect_request, image_list_request, ImageInspect, ImageInspectArgs, ImageListArgs};
use crate::generated::load::{image_load_request, ImageLoadArgs};
use crate::generated::prune::{image_prune_request, ImagePruneArgs};
use crate::generated::push::{image_push_request, ImagePushArgs, PushImageInfo};
use crate::generated::search::{image_search_request, ImageSearchArgs};
use crate::generated::shared::{BuildInfo, IDResponse};
use crate::generated::tag::{image_tag_request, ImageTagArgs};
use crate::DockerClient;
impl DockerClient {
pub async fn image_list(
&self,
all: Option<bool>,
filters: Option<&str>,
shared_size: Option<bool>,
digests: Option<bool>,
) -> Result<serde_json::Value, DockerError> {
let args = ImageListArgs {
all: all.map(|v| v.to_string()),
filters: filters.map(str::to_string),
shared_size: shared_size.map(|v| v.to_string()),
digests: digests.map(|v| v.to_string()),
manifests: None,
};
let response =
image_list_request(self.api(), &args, &self.api_url().await?, None::<super::NoMod>).await?;
Ok(response.body)
}
pub async fn image_inspect(&self, name: &str) -> Result<ImageInspect, DockerError> {
let args = ImageInspectArgs {
name: name.to_string(),
manifests: None,
platform: None,
};
let response =
image_inspect_request(self.api(), &args, &self.api_url().await?, None::<super::NoMod>).await?;
Ok(response.body)
}
pub async fn image_history(&self, name: &str) -> Result<serde_json::Value, DockerError> {
let args = ImageHistoryArgs {
name: name.to_string(),
platform: None,
};
let response =
image_history_request(self.api(), &args, &self.api_url().await?, None::<super::NoMod>).await?;
Ok(response.body)
}
pub async fn image_tag(
&self,
name: &str,
repo: Option<&str>,
tag: Option<&str>,
) -> Result<(), DockerError> {
let args = ImageTagArgs {
name: name.to_string(),
repo: repo.map(str::to_string),
tag: tag.map(str::to_string),
};
image_tag_request(self.api(), &args, &self.api_url().await?, None::<super::NoMod>).await?;
Ok(())
}
pub async fn image_delete(
&self,
name: &str,
force: Option<bool>,
noprune: Option<bool>,
) -> Result<serde_json::Value, DockerError> {
let args = ImageDeleteArgs {
name: name.to_string(),
force: force.map(|v| v.to_string()),
noprune: noprune.map(|v| v.to_string()),
platforms: Vec::new(),
};
let response =
image_delete_request(self.api(), &args, &self.api_url().await?, None::<super::NoMod>).await?;
Ok(response.body)
}
pub async fn image_search(
&self,
term: Option<&str>,
limit: Option<u32>,
filters: Option<&str>,
) -> Result<serde_json::Value, DockerError> {
let args = ImageSearchArgs {
term: term.map(str::to_string),
limit: limit.map(|v| v.to_string()),
filters: filters.map(str::to_string),
};
let response =
image_search_request(self.api(), &args, &self.api_url().await?, None::<super::NoMod>).await?;
Ok(response.body)
}
pub async fn image_load(
&self,
tarball: SendSafeBody,
quiet: Option<bool>,
) -> Result<ProgressStream<BuildInfo>, DockerError> {
let args = ImageLoadArgs {
quiet: quiet.map(|v| v.to_string()),
platform: Vec::new(),
};
let response = image_load_request(
self.api(),
&args,
&self.api_url().await?,
Some(tarball),
None::<super::NoMod>,
)
.await?;
Ok(ProgressStream::new(response.body, DockerError::LoadFailed))
}
pub async fn image_commit(&self, opts: &ImageCommitOptions) -> Result<IDResponse, DockerError> {
let args = ImageCommitArgs {
container: opts.container.clone(),
repo: opts.repo.clone(),
tag: opts.tag.clone(),
comment: opts.comment.clone(),
author: opts.author.clone(),
pause: opts.pause.map(|v| v.to_string()),
changes: opts.changes.clone(),
body: ContainerConfig::default(),
};
let response =
image_commit_request(self.api(), &args, &self.api_url().await?, None::<super::NoMod>).await?;
Ok(response.body)
}
pub async fn image_prune(&self, filters: Option<&str>) -> Result<(), DockerError> {
let args = ImagePruneArgs {
filters: filters.map(str::to_string),
};
image_prune_request(self.api(), &args, &self.api_url().await?, None::<super::NoMod>).await?;
Ok(())
}
pub async fn image_build(
&self,
context: &ContextTar,
opts: &ImageBuildOptions,
) -> Result<ProgressStream<BuildInfo>, DockerError> {
let json_map = |what: &str, pairs: &[(String, String)]| {
if pairs.is_empty() {
return Ok(None);
}
let map: std::collections::HashMap<&str, &str> =
pairs.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect();
serde_json::to_string(&map)
.map(Some)
.map_err(|e| DockerError::JsonParse(format!("{what}: {e}")))
};
let args = ImageBuildArgs {
dockerfile: opts.dockerfile.clone(),
t: opts.tag.clone(),
target: opts.target.clone(),
platform: opts.platform.clone(),
nocache: Some(opts.no_cache.to_string()),
pull: Some(opts.pull.to_string()),
rm: Some("true".to_string()),
forcerm: opts.force_rm.then(|| "true".to_string()),
buildargs: json_map("buildargs", &opts.build_args)?,
labels: json_map("labels", &opts.labels)?,
..ImageBuildArgs::default()
};
let response = image_build_request(
self.api(),
&args,
&self.api_url().await?,
Some(SendSafeBody::Bytes(context.as_bytes().to_vec())),
Some(|b: &mut PreparedRequestBuilder| {
b.set_header(SimpleHeader::CONTENT_TYPE, "application/x-tar");
}),
)
.await?;
Ok(ProgressStream::new(response.body, DockerError::BuildFailed))
}
pub async fn image_push(
&self,
name: &str,
tag: Option<&str>,
x_registry_auth: Option<&str>,
) -> Result<ProgressStream<PushImageInfo>, DockerError> {
let args = ImagePushArgs {
name: name.to_string(),
tag: tag.map(str::to_string),
platform: None,
};
let auth = x_registry_auth.map(str::to_string);
let response = image_push_request(
self.api(),
&args,
&self.api_url().await?,
Some(move |b: &mut PreparedRequestBuilder| {
if let Some(auth) = auth {
b.set_header(SimpleHeader::custom("X-Registry-Auth"), auth);
}
}),
)
.await?;
Ok(ProgressStream::new(response.body, DockerError::PushFailed))
}
pub async fn image_pull(
&self,
from_image: Option<&str>,
from_src: Option<&str>,
repo: Option<&str>,
tag: Option<&str>,
message: Option<&str>,
platform: Option<&str>,
) -> Result<ProgressStream<CreateImageInfo>, DockerError> {
let args = ImageCreateArgs {
from_image: from_image.map(str::to_string),
from_src: from_src.map(str::to_string),
repo: repo.map(str::to_string),
tag: tag.map(str::to_string),
message: message.map(str::to_string),
changes: Vec::new(),
platform: platform.map(str::to_string),
};
let response = image_create_request(
self.api(),
&args,
&self.api_url().await?,
None,
None::<super::NoMod>,
)
.await?;
Ok(ProgressStream::new(response.body, DockerError::PullFailed))
}
pub async fn image_save(&self, name: &str) -> Result<ByteBody, DockerError> {
let args = ImageGetArgs {
name: name.to_string(),
platform: Vec::new(),
};
let response =
image_get_request(self.api(), &args, &self.api_url().await?, None::<super::NoMod>).await?;
Ok(ByteBody::new(response.body))
}
pub async fn distribution_inspect(
&self,
name: &str,
) -> Result<crate::generated::json::DistributionInspect, DockerError> {
use crate::generated::json::{distribution_inspect_request, DistributionInspectArgs};
let args = DistributionInspectArgs {
name: name.to_string(),
};
let response = distribution_inspect_request(self.api(), &args, &self.api_url().await?, None::<super::NoMod>).await?;
Ok(response.body)
}
pub async fn build_prune(
&self,
reserved_space: Option<u32>,
max_used_space: Option<u32>,
all: Option<bool>,
filters: Option<&str>,
) -> Result<(), DockerError> {
use crate::generated::prune::{build_prune_request, BuildPruneArgs};
let args = BuildPruneArgs {
reserved_space: reserved_space.map(|v| v.to_string()),
max_used_space: max_used_space.map(|v| v.to_string()),
min_free_space: None,
all: all.map(|v| v.to_string()),
filters: filters.map(str::to_string),
};
build_prune_request(self.api(), &args, &self.api_url().await?, None::<super::NoMod>).await?;
Ok(())
}
pub async fn export_images(&self, names: &[&str]) -> Result<ByteBody, DockerError> {
let args = ImageGetAllArgs {
names: names.iter().map(|n| (*n).to_string()).collect(),
platform: Vec::new(),
};
let response =
image_get_all_request(self.api(), &args, &self.api_url().await?, None::<super::NoMod>).await?;
Ok(ByteBody::new(response.body))
}
}