diff options
42 files changed, 1097 insertions, 1153 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b4ad43..8e72e8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.7.0 + +* async-await support [#229](https://github.com/softprops/shiplift/pull/229) + # 0.6.0 * add chrono as an optional feature, enabled by default [#190](https://github.com/softprops/shiplift/pull/190) @@ -18,28 +18,31 @@ coveralls = { repository = "softprops/shipflit" } maintenance = { status = "actively-developed" } [dependencies] -log = "0.4" -mime = "0.3" base64 = "0.11" byteorder = "1.3" bytes = "0.4" chrono = { version = "0.4", optional = true, features = ["serde"] } flate2 = "1.0" -futures = "0.1" -hyper = "0.12" -hyper-openssl = { version = "0.7", optional = true } -hyperlocal = { version = "0.6", optional = true } +futures-util = "0.3" +futures_codec = "0.3" +hyper = "0.13" +hyper-openssl = { version = "0.8", optional = true } +hyperlocal = { version = "0.7", optional = true } +log = "0.4" +mime = "0.3" openssl = { version = "0.10", optional = true } +pin-project = "0.4" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" tar = "0.4" -tokio = "0.1" -tokio-codec = "0.1" -tokio-io = "0.1" +tokio = "0.2" url = "2.1" [dev-dependencies] env_logger = "0.7" +# Required for examples to run +futures = "0.3.1" +tokio = { version = "0.2.6", features = ["macros"] } [features] default = ["chrono", "unix-socket", "tls"] diff --git a/examples/attach.rs b/examples/attach.rs new file mode 100644 index 0000000..e4ed637 --- /dev/null +++ b/examples/attach.rs @@ -0,0 +1,32 @@ +use futures::StreamExt; +use shiplift::{tty::TtyChunk, Docker}; +use std::env; + +#[tokio::main] +async fn main() -> Result<(), Box<dyn std::error::Error>> { + let docker = Docker::new(); + let id = env::args() + .nth(1) + .expect("You need to specify a container id"); + + let tty_multiplexer = docker.containers().get(&id).attach().await?; + + let (mut reader, _writer) = tty_multiplexer.split(); + + while let Some(tty_result) = reader.next().await { + match tty_result { + Ok(chunk) => print_chunk(chunk), + Err(e) => eprintln!("Error: {}", e), + } + } + + Ok(()) +} + +fn print_chunk(chunk: TtyChunk) { + match chunk { + TtyChunk::StdOut(bytes) => println!("Stdout: {}", std::str::from_utf8(&bytes).unwrap()), + TtyChunk::StdErr(bytes) => eprintln!("Stdout: {}", std::str::from_utf8(&bytes).unwrap()), + TtyChunk::StdIn(_) => unreachable!(), + } +} diff --git a/examples/containercopyfrom.rs b/examples/containercopyfrom.rs index 2ebeccf..acbfa19 100644 --- a/examples/containercopyfrom.rs +++ b/examples/containercopyfrom.rs @@ -1,8 +1,10 @@ +use futures::TryStreamExt; use shiplift::Docker; use std::{env, path}; -use tokio::prelude::{Future, Stream}; +use tar::Archive; -fn main() { +#[tokio::main] +async fn main() -> Result<(), Box<dyn std::error::Error>> { let docker = Docker::new(); let id = env::args() .nth(1) @@ -10,17 +12,16 @@ fn main() { let path = env::args() .nth(2) .expect("Usage: cargo run --example containercopyfrom -- <container> <path in container>"); - let fut = docker + + let bytes = docker .containers() .get(&id) .copy_from(path::Path::new(&path)) - .collect() - .and_then(|stream| { - let tar = stream.concat(); - let mut archive = tar::Archive::new(tar.as_slice()); - archive.unpack(env::current_dir()?)?; - Ok(()) - }) - .map_err(|e| eprintln!("Error: {}", e)); - tokio::run(fut); + .try_concat() + .await?; + + let mut archive = Archive::new(&bytes[..]); + archive.unpack(env::current_dir()?)?; + + Ok(()) } diff --git a/examples/containercopyinto.rs b/examples/containercopyinto.rs index 63f0a2d..689e7af 100644 --- a/examples/containercopyinto.rs +++ b/examples/containercopyinto.rs @@ -1,8 +1,8 @@ use shiplift::Docker; -use std::env; -use tokio::prelude::Future; +use std::{env, fs::File, io::Read}; -fn main() { +#[tokio::main] +async fn main() { let docker = Docker::new(); let path = env::args() .nth(1) @@ -11,17 +11,17 @@ fn main() { .nth(2) .expect("Usage: cargo run --example containercopyinto -- <local path> <container>"); - use std::{fs::File, io::prelude::*}; - let mut file = File::open(&path).unwrap(); let mut bytes = Vec::new(); file.read_to_end(&mut bytes) .expect("Cannot read file on the localhost."); - let fut = docker + if let Err(e) = docker .containers() .get(&id) - .copy_file_into(path, &bytes[..]) - .map_err(|e| eprintln!("Error: {}", e)); - tokio::run(fut); + .copy_file_into(path, &bytes) + .await + { + eprintln!("Error: {}", e) + } } diff --git a/examples/containercreate.rs b/examples/containercreate.rs index d061f70..ef579a6 100644 --- a/examples/containercreate.rs +++ b/examples/containercreate.rs @@ -1,16 +1,19 @@ use shiplift::{ContainerOptions, Docker}; use std::env; -use tokio::prelude::Future; -fn main() { +#[tokio::main] +async fn main() { let docker = Docker::new(); let image = env::args() .nth(1) .expect("You need to specify an image name"); - let fut = docker + + match docker .containers() .create(&ContainerOptions::builder(image.as_ref()).build()) - .map(|info| println!("{:?}", info)) - .map_err(|e| eprintln!("Error: {}", e)); - tokio::run(fut); + .await + { + Ok(info) => println!("{:?}", info), + Err(e) => eprintln!("Error: {}", e), + } } diff --git a/examples/containerdelete.rs b/examples/containerdelete.rs index e3c2036..86bd9c5 100644 --- a/examples/containerdelete.rs +++ b/examples/containerdelete.rs @@ -1,16 +1,14 @@ use shiplift::Docker; use std::env; -use tokio::prelude::Future; -fn main() { +#[tokio::main] +async fn main() { let docker = Docker::new(); let id = env::args() .nth(1) .expect("You need to specify an container id"); - let fut = docker - .containers() - .get(&id) - .delete() - .map_err(|e| eprintln!("Error: {}", e)); - tokio::run(fut); + + if let Err(e) = docker.containers().get(&id).delete().await { + eprintln!("Error: {}", e) + } } diff --git a/examples/containerexec.rs b/examples/containerexec.rs index 7f12f88..6c545a7 100644 --- a/examples/containerexec.rs +++ b/examples/containerexec.rs @@ -1,8 +1,9 @@ -use shiplift::{tty::StreamType, Docker, ExecContainerOptions}; -use std::env; -use tokio::prelude::{Future, Stream}; +use futures::StreamExt; +use shiplift::{tty::TtyChunk, Docker, ExecContainerOptions}; +use std::{env, str::from_utf8}; -fn main() { +#[tokio::main] +async fn main() { let docker = Docker::new(); let id = env::args() .nth(1) @@ -18,19 +19,19 @@ fn main() { .attach_stdout(true) .attach_stderr(true) .build(); - let fut = docker - .containers() - .get(&id) - .exec(&options) - .for_each(|chunk| { - match chunk.stream_type { - StreamType::StdOut => println!("Stdout: {}", chunk.as_string_lossy()), - StreamType::StdErr => eprintln!("Stderr: {}", chunk.as_string_lossy()), - StreamType::StdIn => unreachable!(), - } - Ok(()) - }) - .map_err(|e| eprintln!("Error: {}", e)); - tokio::run(fut); + while let Some(exec_result) = docker.containers().get(&id).exec(&options).next().await { + match exec_result { + Ok(chunk) => print_chunk(chunk), + Err(e) => eprintln!("Error: {}", e), + } + } +} + +fn print_chunk(chunk: TtyChunk) { + match chunk { + TtyChunk::StdOut(bytes) => println!("Stdout: {}", from_utf8(&bytes).unwrap()), + TtyChunk::StdErr(bytes) => eprintln!("Stdout: {}", from_utf8(&bytes).unwrap()), + TtyChunk::StdIn(_) => unreachable!(), + } } diff --git a/examples/containerinspect.rs b/examples/containerinspect.rs index 0f853bc..8de2a67 100644 --- a/examples/containerinspect.rs +++ b/examples/containerinspect.rs @@ -1,17 +1,15 @@ use shiplift::Docker; use std::env; -use tokio::prelude::Future; -fn main() { +#[tokio::main] +async fn main() { let docker = Docker::new(); let id = env::args() .nth(1) .expect("Usage: cargo run --example containerinspect -- <container>"); - let fut = docker - .containers() - .get(&id) - .inspect() - .map(|container| println!("{:#?}", container)) - .map_err(|e| eprintln!("Error: {}", e)); - tokio::run(fut); + + match docker.containers().get(&id).inspect().await { + Ok(container) => println!("{:#?}", container), + Err(e) => eprintln!("Error: {}", e), + } } diff --git a/examples/containers.rs b/examples/containers.rs index 0eb51af..72de140 100644 --- a/examples/containers.rs +++ b/examples/containers.rs @@ -1,18 +1,15 @@ use shiplift::Docker; -use tokio::prelude::Future; -fn main() { +#[tokio::main] +async fn main() { env_logger::init(); let docker = Docker::new(); - let fut = docker - .containers() - .list(&Default::default()) - .map(|containers| { + match docker.containers().list(&Default::default()).await { + Ok(containers) => { for c in containers { println!("container -> {:#?}", c) } - }) - .map_err(|e| eprintln!("Error: {}", e)); - - tokio::run(fut); + } + Err(e) => eprintln!("Error: {}", e), + } } diff --git a/examples/custom_host.rs b/examples/custom_host.rs index 3b1fd3e..8b06eae 100644 --- a/examples/custom_host.rs +++ b/examples/custom_host.rs @@ -1,13 +1,10 @@ -use futures::Future; use shiplift::Docker; -fn main() { +#[tokio::main] +async fn main() { let docker = Docker::host("http://yourhost".parse().unwrap()); - - let fut = docker - .ping() - .map(|pong| println!("Ping: {}", pong)) - .map_err(|e| eprintln!("Error: {}", e)); - - tokio::run(fut); + match docker.ping().await { + Ok(pong) => println!("Ping: {}", pong), + Err(e) => eprintln!("Error: {}", e), + } } diff --git a/examples/events.rs b/examples/events.rs index 0e35860..e44d68f 100644 --- a/examples/events.rs +++ b/examples/events.rs @@ -1,16 +1,15 @@ +use futures::StreamExt; use shiplift::Docker; -use tokio::prelude::{Future, Stream}; -fn main() { +#[tokio::main] +async fn main() { let docker = Docker::new(); println!("listening for events"); - let fut = docker - .events(&Default::default()) - .for_each(|e| { - println!("event -> {:?}", e); - Ok(()) - }) - .map_err(|e| eprintln!("Error: {}", e)); - tokio::run(fut); + while let Some(event_result) = docker.events(&Default::default()).next().await { + match event_result { + Ok(event) => println!("event -> {:?}", event), + Err(e) => eprintln!("Error: {}", e), + } + } } diff --git a/examples/export.rs b/examples/export.rs index 55d1b7b..34f460d 100644 --- a/examples/export.rs +++ b/examples/export.rs @@ -1,8 +1,10 @@ -use shiplift::{errors::Error, Docker}; +use futures::StreamExt; use std::{env, fs::OpenOptions, io::Write}; -use tokio::prelude::{Future, Stream}; -fn main() { +use shiplift::{errors::Error, Docker}; + +#[tokio::main] +async fn main() { let docker = Docker::new(); let id = env::args().nth(1).expect("You need to specify an image id"); @@ -11,17 +13,13 @@ fn main() { .create(true) .open(format!("{}.tar", &id)) .unwrap(); + let images = docker.images(); - let fut = images - .get(&id) - .export() - .for_each(move |bytes| { - export_file - .write(&bytes[..]) - .map(|n| println!("copied {} bytes", n)) - .map_err(Error::IO) - }) - .map_err(|e| eprintln!("Error: {}", e)); - tokio::run(fut) + while let Some(export_result) = images.get(&id).export().next().await { + match export_result.and_then(|bytes| export_file.write(&bytes).map_err(Error::from)) { + Ok(n) => println!("copied {} bytes", n), + Err(e) => eprintln!("Error: {}", e), + } + } } diff --git a/examples/imagebuild.rs b/examples/imagebuild.rs index 6dbea78..80d825c 100644 --- a/examples/imagebuild.rs +++ b/examples/imagebuild.rs @@ -1,19 +1,22 @@ +use futures::StreamExt; use shiplift::{BuildOptions, Docker}; use std::env; -use tokio::prelude::{Future, Stream}; -fn main() { +#[tokio::main] +async fn main() { let docker = Docker::new(); let path = env::args().nth(1).expect("You need to specify a path"); - let fut = docker - .images() - .build(&BuildOptions::builder(path).tag("shiplift_test").build()) - .for_each(|output| { - println!("{:?}", output); - Ok(()) - }) - .map_err(|e| eprintln!("Error: {}", e)); + let options = BuildOptions::builder(path).tag("shiplift_test").build(); - tokio::run(fut); + let images = docker.images(); + + let mut stream = images.build(&options); + + while let Some(build_result) = stream.next().await { + match build_result { + Ok(output) => println!("{:?}", output), + Err(e) => eprintln!("Error: {}", e), + } + } } diff --git a/examples/imagedelete.rs b/examples/imagedelete.rs index efa763c..3b9bc60 100644 --- a/examples/imagedelete.rs +++ b/examples/imagedelete.rs @@ -1,21 +1,18 @@ use shiplift::Docker; use std::env; -use tokio::prelude::Future; -fn main() { +#[tokio::main] +async fn main() { let docker = Docker::new(); let img = env::args() .nth(1) .expect("You need to specify an image name"); - let fut = docker - .images() - .get(&img[..]) - .delete() - .map(|statuses| { + match docker.images().get(&img).delete().await { + Ok(statuses) => { for status in statuses { println!("{:?}", status); } - }) - .map_err(|e| eprintln!("Error: {}", e)); - tokio::run(fut); + } + Err(e) => eprintln!("Error: {}", e), + } } diff --git a/examples/imageinspect.rs b/examples/imageinspect.rs index 494480a..b7d2f9a 100644 --- a/examples/imageinspect.rs +++ b/examples/imageinspect.rs @@ -1,17 +1,15 @@ use shiplift::Docker; use std::env; -use tokio::prelude::Future; -fn main() { +#[tokio::main] +async fn main() { let docker = Docker::new(); let id = env::args() .nth(1) .expect("Usage: cargo run --example imageinspect -- <image>"); - let fut = docker - .images() - .get(&id) - .inspect() - .map(|image| println!("{:#?}", image)) - .map_err(|e| eprintln!("Error: {}", e)); - tokio::run(fut); + + match docker.images().get(&id).inspect().await { + Ok(image) => println!("{:#?}", image), + Err(e) => eprintln!("Error: {}", e), + } } diff --git a/examples/imagepull.rs b/examples/imagepull.rs index 84a6149..5b3fbf4 100644 --- a/examples/imagepull.rs +++ b/examples/imagepull.rs @@ -1,22 +1,25 @@ // cargo run --example imagepull busybox +use futures::StreamExt; use shiplift::{Docker, PullOptions}; use std::env; -use tokio::prelude::{Future, Stream}; -fn main() { +#[tokio::main] +async fn main() { env_logger::init(); let docker = Docker::new(); let img = env::args() .nth(1) .expect("You need to specify an image name"); - let fut = docker + + let mut stream = docker .images() - .pull(&PullOptions::builder().image(img).build()) - .for_each(|output| { - println!("{:?}", output); - Ok(()) - }) - .map_err(|e| eprintln!("Error: {}", e)); - tokio::run(fut); + .pull(&PullOptions::builder().image(img).build()); + + while let Some(pull_result) = stream.next().await { + match pull_result { + Ok(output) => println!("{:?}", output), + Err(e) => eprintln!("Error: {}", e), + } + } } diff --git a/examples/imagepull_auth.rs b/examples/imagepull_auth.rs index 1c559c7..6f0ceec 100644 --- a/examples/imagepull_auth.rs +++ b/examples/imagepull_auth.rs @@ -1,10 +1,11 @@ // cargo run --example imagepull_auth busybox username password +use futures::StreamExt; use shiplift::{Docker, PullOptions, RegistryAuth}; use std::env; -use tokio::prelude::{Future, Stream}; -fn main() { +#[tokio::main] +async fn main() { env_logger::init(); let docker = Docker::new(); let img = env::args() @@ -16,13 +17,15 @@ fn main() { .username(username) .password(password) .build(); - let fut = docker + + let mut stream = docker .images() - .pull(&PullOptions::builder().image(img).auth(auth).build()) - .for_each(|output| { - println!("{:?}", output); - Ok(()) - }) - .map_err(|e| eprintln!("Error: {}", e)); - tokio::run(fut); + .pull(&PullOptions::builder().image(img).auth(auth).build()); + + while let Some(pull_result) = stream.next().await { + match pull_result { + Ok(output) => println!("{:?}", output), + Err(e) => eprintln!("{}", e), + } + } } diff --git a/examples/images.rs b/examples/images.rs index 7a8a094..1c0852e 100644 --- a/examples/images.rs +++ b/examples/images.rs @@ -1,13 +1,14 @@ use shiplift::Docker; -use tokio::prelude::Future; -fn main() { +#[tokio::main] +async fn main() { let docker = Docker::new(); println!("docker images in stock"); - let fut = docker - .images() - .list(&Default::default()) - .map(|images| { + + let result = docker.images().list(&Default::default()).await; + + match result { + Ok(images) => { for i in images { println!( "{} {} {:?}", @@ -16,7 +17,7 @@ fn main() { i.repo_tags.unwrap_or_else(|| vec!["none".into()]) ); } - }) - .map_err(|e| eprintln!("Error: {}", e)); - tokio::run(fut); + } + Err(e) => eprintln!("Error: {}", e), + } } diff --git a/examples/imagesearch.rs b/examples/imagesearch.rs index a6d6e52..e2fd110 100644 --- a/examples/imagesearch.rs +++ b/examples/imagesearch.rs @@ -1,17 +1,16 @@ use shiplift::Docker; -use tokio::prelude::Future; -fn main() { +#[tokio::main] +async fn main() { let docker = Docker::new(); println!("remote docker images in stock"); - let fut = docker - .images() - .search("rust") - .map(|results| { + + match docker.images().search("rust").await { + Ok(results) => { for result in results { println!("{} - {}", result.name, result.description); } - }) - .map_err(|e| eprintln!("Error: {}", e)); - tokio::run(fut); + } + Err(e) => eprintln!("Error: {}", e), + } } diff --git a/examples/imagetag.rs b/examples/imagetag.rs index 7ae78dd..e36af76 100644 --- a/examples/imagetag.rs +++ b/examples/imagetag.rs @@ -2,9 +2,9 @@ use shiplift::{Docker, Image, TagOptions}; use std::env; -use tokio::prelude::Future; -fn main() { +#[tokio::main] +async fn main() { env_logger::init(); let docker = Docker::new(); let img = env::args() @@ -21,7 +21,7 @@ fn main() { let image = Image::new(&docker, img); - let fut = image.tag(&tag_opts).map_err(|e| eprintln!("Error: {}", e)); - - tokio::run(fut); + if let Err(e) = image.tag(&tag_opts).await { + eprintln!("Error: {}", e) + } } diff --git a/examples/import.rs b/examples/import.rs index 20c61e6..7ea35bd 100644 --- a/examples/import.rs +++ b/examples/import.rs @@ -1,8 +1,9 @@ +use futures::StreamExt; use shiplift::Docker; use std::{env, fs::File}; -use tokio::prelude::{Future, Stream}; -fn main() { +#[tokio::main] +async fn main() { let docker = Docker::new(); let path = env::args() .nth(1) @@ -11,14 +12,12 @@ fn main() { let reader = Box::from(f); - let fut = docker - .images() - .import(reader) - .for_each(|output| { - println!("{:?}", output); - Ok(()) - }) - .map_err(|e| eprintln!("Error: {}", e)); + let mut stream = docker.images().import(reader); - tokio::run(fut); + while let Some(import_result) = stream.next().await { + match import_result { + Ok(output) => println!("{:?}", output), + Err(e) => eprintln!("Error: {}", e), + } + } } diff --git a/examples/info.rs b/examples/info.rs index 05fdede..76036e6 100644 --- a/examples/info.rs +++ b/examples/info.rs @@ -1,12 +1,11 @@ use shiplift::Docker; -use tokio::prelude::Future; -fn main() { +#[tokio::main] +async fn main() { let docker = Docker::new(); - tokio::run( - docker - .info() - .map(|info| println!("info {:?}", info)) - .map_err |