use crate::verbose::Verbosity;
use colored::Colorize;
use std::env::var;
use std::io::Write;
use std::process::{Command, Output, Stdio};
use std::{io, process};
pub struct DockerCommand {
pub docker_bin: String,
pub verbosity: Verbosity,
}
impl DockerCommand {
pub fn new(verbosity: Verbosity) -> Self {
Self {
docker_bin: var("DOCKER_BIN").unwrap_or("docker".to_string()),
verbosity,
}
}
pub fn call_to_string(&self, args: &[&str]) -> String {
format!(
"{} {}",
self.docker_bin,
args.iter()
.map(|s| {
if s.contains(' ') {
format!("\"{s}\"")
} else {
s.to_string()
}
})
.collect::<Vec<_>>()
.join(" ")
)
}
pub fn call_cmd(
&self,
args: &[&str],
output_stdout: bool,
output_stderr: bool,
) -> io::Result<Output> {
if matches!(self.verbosity, Verbosity::Verbose) {
eprintln!("{}: {}", "DEBUG".green(), self.call_to_string(args));
}
let mut binding = Command::new(&self.docker_bin);
let mut command = binding.args(args);
command = command.stdout(Stdio::piped()).stderr(Stdio::piped());
let output = command.output()?; if output_stdout {
self.write_stdout(&output.stdout);
}
if output_stderr {
self.write_stderr(&output.stderr);
}
Ok(output)
}
pub fn call_compose_cmd(
&self,
cmd: &str,
filenames: &[&str],
args: &[&str],
cmd_args: &[&str],
output_stdout: bool,
output_stderr: bool,
) -> io::Result<Output> {
let mut docker_args = vec!["compose"];
for filename in filenames {
docker_args.push("-f");
docker_args.push(filename);
}
for arg in args {
docker_args.push(arg);
}
docker_args.push(cmd);
for arg in cmd_args {
docker_args.push(arg);
}
self.call_cmd(&docker_args, output_stdout, output_stderr)
}
pub fn call_compose_config(
&self,
filenames: &[&str],
no_consistency: bool,
no_interpolate: bool,
no_normalize: bool,
output_stdout: bool,
output_stderr: bool,
) -> io::Result<Output> {
let mut cmd_args = Vec::new();
if no_consistency {
cmd_args.push("--no-consistency");
}
if no_interpolate {
cmd_args.push("--no-interpolate");
}
if no_normalize {
cmd_args.push("--no-normalize");
}
self.call_compose_cmd(
"config",
filenames,
&Vec::default(),
&cmd_args,
output_stdout,
output_stderr,
)
}
pub fn get_manifest_inspect(&self, image: &str) -> io::Result<Output> {
self.call_cmd(&["manifest", "inspect", "--insecure", image], false, false)
}
pub fn write_stderr(&self, stderr: &[u8]) {
io::stderr().write_all(stderr).unwrap_or_else(|e| {
eprintln!(
"{}: writing {} stderr: {}",
"ERROR".red(),
self.docker_bin,
e
);
process::exit(151);
});
}
pub fn write_stdout(&self, stdout: &[u8]) {
io::stdout().write_all(stdout).unwrap_or_else(|e| {
eprintln!(
"{}: writing {} stdout: {}",
"ERROR".red(),
self.docker_bin,
e
);
process::exit(151);
});
}
pub fn exit_code(&self, output: &Output) -> i32 {
output.status.code().unwrap_or_else(|| {
eprintln!(
"{}: {} process terminated by signal",
"ERROR".red(),
self.docker_bin
);
process::exit(10)
})
}
}