use std::process::{self, Output, Stdio};
use clap::{Args, Parser};
use termcolor::StandardStream;
use crate::{
api::server::ServerClient,
error::{exit_status_error, Error, Result},
};
use super::ExecuteSubcommand;
#[derive(Debug, Clone, Args)]
pub struct Docker {
#[clap(
default_value = "erikvl87/languagetool",
env = "LANGUAGETOOL_DOCKER_IMAGE"
)]
name: String,
#[clap(
short = 'b',
long,
default_value = "docker",
env = "LANGUAGETOOL_DOCKER_BIN"
)]
bin: String,
#[clap(long, default_value = "languagetool", env = "LANGUAGETOOL_DOCKER_NAME")]
container_name: String,
#[clap(
short = 'p',
long,
default_value = "8010:8010",
env = "LANGUAGETOOL_DOCKER_PORT"
)]
port: String,
#[clap(subcommand)]
action: Action,
}
#[derive(clap::Subcommand, Clone, Debug)]
enum Action {
Pull,
Start,
Stop,
}
impl Docker {
pub fn pull(&self) -> Result<Output> {
let output = process::Command::new(&self.bin)
.args(["pull", &self.name])
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.output()
.map_err(|_| Error::CommandNotFound(self.bin.to_string()))?;
exit_status_error(&output.status)?;
Ok(output)
}
pub fn start(&self) -> Result<Output> {
let output = process::Command::new(&self.bin)
.args([
"run",
"--rm",
"--name",
&self.container_name,
"-d",
"-p",
"8010:8010",
&self.name,
])
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.output()
.map_err(|_| Error::CommandNotFound(self.bin.to_string()))?;
exit_status_error(&output.status)?;
Ok(output)
}
pub fn stop(&self) -> Result<Output> {
let output = process::Command::new(&self.bin)
.args([
"ps",
"-l",
"-f",
&format!("name={}", self.container_name),
"-q",
])
.stderr(Stdio::inherit())
.output()
.map_err(|_| Error::CommandNotFound(self.bin.to_string()))?;
exit_status_error(&output.status)?;
let docker_id: String = String::from_utf8_lossy(&output.stdout)
.chars()
.filter(|c| c.is_alphanumeric()) .collect();
let output = process::Command::new(&self.bin)
.args(["kill", &docker_id])
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.output()?;
exit_status_error(&output.status)?;
Ok(output)
}
pub fn run_action(&self) -> Result<Output> {
match self.action {
Action::Pull => self.pull(),
Action::Start => self.start(),
Action::Stop => self.stop(),
}
}
}
#[derive(Debug, Parser)]
pub struct Command {
#[command(flatten)]
pub docker: Docker,
}
impl ExecuteSubcommand for Command {
async fn execute(self, _stdout: StandardStream, _: ServerClient) -> Result<()> {
self.docker.run_action()?;
Ok(())
}
}