summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/containerexec.rs13
-rw-r--r--src/builder.rs23
-rw-r--r--src/lib.rs27
-rw-r--r--src/tty.rs34
4 files changed, 78 insertions, 19 deletions
diff --git a/examples/containerexec.rs b/examples/containerexec.rs
index fe542f2..b41d1ac 100644
--- a/examples/containerexec.rs
+++ b/examples/containerexec.rs
@@ -6,14 +6,17 @@ use std::env;
fn main() {
let docker = Docker::new();
let options = ExecContainerOptions::builder()
- .cmd(vec!["ls"])
+ .cmd(vec!["bash", "-c", "echo -n \"echo VAR=$VAR on stdout\"; echo -n \"echo VAR=$VAR on stderr\" >&2"])
.env(vec!["VAR=value"])
+ .attach_stdout(true)
+ .attach_stderr(true)
.build();
if let Some(id) = env::args().nth(1) {
- match docker.containers()
- .get(&id)
- .exec(&options) {
- Ok(res) => println!("Success: {:?}", res),
+ match docker.containers().get(&id).exec(&options) {
+ Ok(res) => {
+ println!("Stdout: {}", res.stdout);
+ println!("Stderr: {}", res.stderr);
+ }
Err(err) => println!("An error occured: {:?}", err),
}
}
diff --git a/src/builder.rs b/src/builder.rs
index aa5b7df..fac07d1 100644
--- a/src/builder.rs
+++ b/src/builder.rs
@@ -454,6 +454,7 @@ impl ContainerOptionsBuilder {
pub struct ExecContainerOptions {
params: HashMap<&'static str, Vec<String>>,
+ params_bool: HashMap<&'static str, bool>,
}
impl ExecContainerOptions {
@@ -469,6 +470,9 @@ impl ExecContainerOptions {
for (k, v) in &self.params {
body.insert(k.to_string(), v.to_json());
}
+ for (k, v) in &self.params_bool {
+ body.insert(k.to_string(), v.to_json());
+ }
let json_obj: Json = body.to_json();
Ok(try!(json::encode(&json_obj)))
@@ -478,11 +482,13 @@ impl ExecContainerOptions {
#[derive(Default)]
pub struct ExecContainerOptionsBuilder {
params: HashMap<&'static str, Vec<String>>,
+ params_bool: HashMap<&'static str, bool>,
}
impl ExecContainerOptionsBuilder {
pub fn new() -> ExecContainerOptionsBuilder {
- ExecContainerOptionsBuilder { params: HashMap::new() }
+ ExecContainerOptionsBuilder { params: HashMap::new(),
+ params_bool: HashMap::new() }
}
/// Command to run, as an array of strings
@@ -501,8 +507,21 @@ impl ExecContainerOptionsBuilder {
self
}
+/// Attach to stdout of the exec command
+ pub fn attach_stdout(&mut self, stdout: bool) -> &mut ExecContainerOptionsBuilder {
+ self.params_bool.insert("AttachStdout", stdout);
+ self
+ }
+
+/// Attach to stderr of the exec command
+ pub fn attach_stderr(&mut self, stderr: bool) -> &mut ExecContainerOptionsBuilder {
+ self.params_bool.insert("AttachStderr", stderr);
+ self
+ }
+
pub fn build(&self) -> ExecContainerOptions {
- ExecContainerOptions { params: self.params.clone() }
+ ExecContainerOptions { params: self.params.clone(),
+ params_bool: self.params_bool.clone() }
}
}
diff --git a/src/lib.rs b/src/lib.rs
index bc5a794..12e0cdf 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -29,6 +29,7 @@ pub mod builder;
pub mod rep;
pub mod transport;
pub mod errors;
+pub mod tty;
mod tarball;
@@ -50,6 +51,7 @@ use rep::{NetworkDetails as NetworkInfo, NetworkCreateInfo};
use rep::{Output, PullInfo, Change, ContainerCreateInfo, ContainerDetails,
Container as ContainerRep, Event, Exit, History, ImageDetails, Info, SearchResult,
Stats, Status, Top, Version};
+use tty::Tty;
use rustc_serialize::json::{self, Json};
use std::borrow::Cow;
use std::env::{self, VarError};
@@ -419,26 +421,27 @@ impl<'a, 'b> Container<'a, 'b> {
}
/// Exec the specified command in the container
- pub fn exec(&self, opts: &ExecContainerOptions) -> Result<()> {
+ pub fn exec(&self, opts: &ExecContainerOptions) -> Result<Tty> {
let data = try!(opts.serialize());
let mut bytes = data.as_bytes();
match self.docker
- .post(&format!("/containers/{}/exec", self.id)[..],
- Some((&mut bytes, ContentType::json()))) {
+ .post(&format!("/containers/{}/exec", self.id)[..],
+ Some((&mut bytes, ContentType::json()))) {
Err(e) => Err(e),
Ok(res) => {
let data = "{}";
let mut bytes = data.as_bytes();
self.docker
- .post(&format!("/exec/{}/start",
- Json::from_str(res.as_str())
- .unwrap()
- .search("Id")
- .unwrap()
- .as_string()
- .unwrap())[..],
- Some((&mut bytes, ContentType::json())))
- .map(|_| ())
+ .stream_post(&format!("/exec/{}/start",
+ Json::from_str(res.as_str())
+ .unwrap()
+ .search("Id")
+ .unwrap()
+ .as_string()
+ .unwrap())
+ [..],
+ Some((&mut bytes, ContentType::json())))
+ .map(|stream| Tty::new(stream))
}
}
}
diff --git a/src/tty.rs b/src/tty.rs
new file mode 100644
index 0000000..446ab26
--- /dev/null
+++ b/src/tty.rs
@@ -0,0 +1,34 @@
+use std::io::Read;
+pub struct Tty {
+ pub stdout: String,
+ pub stderr: String,
+}
+
+impl Tty {
+ pub fn new(mut stream: Box<Read>) -> Tty {
+ let mut stdout: Vec<u8> = vec![];
+ let mut stderr: Vec<u8> = vec![];
+ loop {
+ let mut header = [0; 8];
+ match stream.read(&mut header) {
+ Ok(0) => break,
+ Ok(_) => {
+ let mut body: Vec<u8> = vec![0; header[7] as usize];
+ if let Ok(_) = stream.read(&mut body) {
+ if header[0] == 1 {
+ stdout.append(&mut body);
+ }
+ if header[0] == 2 {
+ stderr.append(&mut body);
+ }
+ };
+ }
+ Err(_) => break,
+ }
+ }
+ Tty {
+ stdout: String::from_utf8_lossy(&stdout).to_string(),
+ stderr: String::from_utf8_lossy(&stderr).to_string(),
+ }
+ }
+}