use crate::args::{self, ToArgs};
#[cfg(test)]
use crate::command_runner::TestCommandRunner;
use crate::command_runner::{Command, CommandRunner};
use crate::errors::*;
use crate::ext::service::ServiceExt;
use crate::project::Project;
use crate::util::err;
pub trait CommandExec {
fn exec<CR>(
&self,
runner: &CR,
service_name: &str,
command: &args::Command,
opts: &args::opts::Exec,
) -> Result<()>
where
CR: CommandRunner;
fn shell<CR>(
&self,
runner: &CR,
service_name: &str,
opts: &args::opts::Exec,
) -> Result<()>
where
CR: CommandRunner;
}
impl CommandExec for Project {
fn exec<CR>(
&self,
runner: &CR,
service_name: &str,
command: &args::Command,
opts: &args::opts::Exec,
) -> Result<()>
where
CR: CommandRunner,
{
let (pod, service_name) = self.service_or_err(service_name)?;
runner
.build("docker-compose")
.args(&pod.compose_args(self)?)
.arg("exec")
.args(&opts.to_args())
.arg(service_name)
.args(&command.to_args())
.exec()
}
fn shell<CR>(
&self,
runner: &CR,
service_name: &str,
opts: &args::opts::Exec,
) -> Result<()>
where
CR: CommandRunner,
{
if opts.detached {
return Err(err("Can't run shell in detached mode"));
}
if !opts.allocate_tty {
return Err(err("Can't run shell without a TTY"));
}
let target = self.current_target();
let (pod, service_name) = self.service_or_err(service_name)?;
let service = pod.service_or_err(target, service_name)?;
let shell = service.shell()?;
self.exec(runner, service_name, &args::Command::new(shell), opts)
}
}
#[test]
fn invokes_docker_exec() {
let _ = env_logger::try_init();
let proj = Project::from_example("hello").unwrap();
let runner = TestCommandRunner::new();
proj.output("exec").unwrap();
let command = args::Command::new("true");
let mut opts = args::opts::Exec::default();
opts.allocate_tty = false;
proj.exec(&runner, "web", &command, &opts).unwrap();
assert_ran!(runner, {
[
"docker-compose",
"-p",
"hello",
"-f",
proj.output_dir().join("pods").join("frontend.yml"),
"exec",
"-T",
"web",
"true",
]
});
proj.remove_test_output().unwrap();
}
#[test]
fn runs_shells() {
let _ = env_logger::try_init();
let proj = Project::from_example("hello").unwrap();
let runner = TestCommandRunner::new();
proj.output("exec").unwrap();
proj.shell(&runner, "web", &Default::default()).unwrap();
assert_ran!(runner, {
[
"docker-compose",
"-p",
"hello",
"-f",
proj.output_dir().join("pods").join("frontend.yml"),
"exec",
"web",
"sh",
]
});
proj.remove_test_output().unwrap();
}