summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2021-03-07 20:25:35 +0100
committerMatthias Beyer <mail@beyermatthias.de>2021-03-07 21:50:29 +0100
commitf0a223a5c78fb5e7b534f0595899af42b296e0d5 (patch)
treeaed10434bf251dcd8d3d27d1da7290a4bced55e2
parente010cb9e9ec4a23ef46ac302e0b1a5c198b5859f (diff)
Implement container exec subcommand
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
-rw-r--r--src/cli.rs2
-rw-r--r--src/commands/endpoint.rs37
2 files changed, 38 insertions, 1 deletions
diff --git a/src/cli.rs b/src/cli.rs
index 044acbe..fef7957 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -988,7 +988,7 @@ pub fn cli<'a>() -> App<'a> {
.version(crate_version!())
.about("Execute commands in the container")
.arg(Arg::new("commands")
- .required(false)
+ .required(true)
.multiple(true)
.index(1)
.takes_value(true)
diff --git a/src/commands/endpoint.rs b/src/commands/endpoint.rs
index 240770e..7dd7c27 100644
--- a/src/commands/endpoint.rs
+++ b/src/commands/endpoint.rs
@@ -193,6 +193,7 @@ async fn container(endpoint_names: Vec<String>,
Some(("delete", _)) => container_delete(relevant_endpoint, container_id).await,
Some(("start", _)) => container_start(relevant_endpoint, container_id).await,
Some(("stop", matches)) => container_stop(matches, relevant_endpoint, container_id).await,
+ Some(("exec", matches)) => container_exec(matches, relevant_endpoint, container_id).await,
Some((other, _)) => Err(anyhow!("Unknown subcommand: {}", other)),
None => Err(anyhow!("No subcommand")),
}
@@ -288,6 +289,42 @@ async fn container_stop(
.map_err(Error::from)
}
+async fn container_exec(
+ matches: &ArgMatches,
+ endpoint: &Endpoint,
+ container_id: &str,
+) -> Result<()> {
+ use std::io::Write;
+ use futures::TryStreamExt;
+
+ let commands = matches.values_of("commands").unwrap().collect::<Vec<&str>>();
+ let prompt = format!("Really run '{}' in {}?", commands.join(" "), container_id);
+ dialoguer::Confirm::new().with_prompt(prompt).interact()?;
+
+ let execopts = shiplift::builder::ExecContainerOptions::builder()
+ .cmd(commands)
+ .attach_stdout(true)
+ .attach_stderr(true)
+ .build();
+
+ endpoint
+ .get_container_by_id(container_id)
+ .await?
+ .ok_or_else(|| anyhow!("Cannot find container {} on {}", container_id, endpoint.name()))?
+ .exec(&execopts)
+ .map_err(Error::from)
+ .try_for_each(|chunk| async {
+ let mut stdout = std::io::stdout();
+ let mut stderr = std::io::stderr();
+ match chunk {
+ shiplift::tty::TtyChunk::StdIn(_) => Err(anyhow!("Cannot handle STDIN TTY chunk")),
+ shiplift::tty::TtyChunk::StdOut(v) => stdout.write(&v).map_err(Error::from).map(|_| ()),
+ shiplift::tty::TtyChunk::StdErr(v) => stderr.write(&v).map_err(Error::from).map(|_| ()),
+ }
+ })
+ .await
+}
+
async fn containers(endpoint_names: Vec<String>,
matches: &ArgMatches,