diff --git a/Cargo.lock b/Cargo.lock index 66c5f5e3..14e628ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,6 +18,7 @@ dependencies = [ "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "phf 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)", + "prettytable-rs 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", @@ -589,6 +590,14 @@ dependencies = [ "syn 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "prettytable-rs" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quick-error" version = "1.1.0" @@ -1095,6 +1104,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8cee804ecc7eaf201a4a207241472cc870e825206f6c031e3ee2a72fa425f2fa" "checksum pnacl-build-helper 1.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "61c9231d31aea845007443d62fcbb58bb6949ab9c18081ee1e09920e0cf1118b" "checksum post-expansion 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "31a834a6060acaef74a8d878f6ca37a2b86fefe042bbfe70689ba587e42526f9" +"checksum prettytable-rs 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0157d76bd13c20ed17e085524eba4c0c104a6bb47dafcf5bbe55848230364fe8" "checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c" "checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45" "checksum quote 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1e0c9bc6bfb0a60d539aab6e338207c1a5456e62f5bd5375132cee119aa4b3" diff --git a/Cargo.toml b/Cargo.toml index 39564ac9..2f9c31de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,6 +57,7 @@ itertools = "0.5.6" lazy_static = "0.2.1" log = "0.3.6" phf = "0.7.16" +prettytable-rs = "0.2.0" rand = "0.3.14" rayon = "0.4.2" regex = "0.1.73" diff --git a/src/cmd/source.rs b/src/cmd/source.rs index ea3559b2..1c1d8925 100644 --- a/src/cmd/source.rs +++ b/src/cmd/source.rs @@ -1,11 +1,13 @@ //! The `source` subcommand. -use colored::*; - use command_runner::CommandRunner; use errors::*; use project::Project; +extern crate prettytable; +use self::prettytable::Table; +use self::prettytable::format::FORMAT_BLANK; + /// We implement `source` with a trait so we put it in its own module. pub trait CommandSource { /// List all the source trees associated with a project. @@ -29,9 +31,22 @@ impl CommandSource for Project { fn source_list(&self, _runner: &CR) -> Result<()> where CR: CommandRunner { + let mut table = Table::new(); + table.set_format(FORMAT_BLANK); + + table.add_row(row!["SERVICE", "IMAGE", "STATUS", "LOCAL", "REMOTE"]); + for source in self.sources().iter() { - println!("{:25} {}", source.alias().green(), source.context()); - if source.is_available_locally(self) { + + let available_locally = source.is_available_locally(self); + + let status = if available_locally && source.mounted() { + "mounted" + } else { + "unmounted" + }; + + let local = if available_locally { let canonical = source.path(self).canonicalize()?; // Try to strip the prefix, but this may fail on Windows // or if the source is in a weird location. @@ -39,14 +54,23 @@ impl CommandSource for Project { Ok(stripped) => stripped.to_owned(), Err(_) => canonical.to_owned(), }; - let mounted = if source.mounted() { - "(mounted)".normal() - } else { - "(NOT MOUNTED)".red().bold() - }; - println!(" Available at {} {}", path.display(), mounted); - } + format!("{}", path.display()).to_owned() + } else { + String::from("") + }; + + table.add_row(row![ + source.alias(), + source.image(), + status, + local, + source.context() + ]); + } + + table.printstd(); + Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 3fee5f31..a82d81b5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -89,6 +89,8 @@ extern crate lazy_static; #[macro_use] extern crate log; extern crate phf; +#[macro_use(row)] +extern crate prettytable; #[cfg(test)] extern crate rand; extern crate rayon; diff --git a/src/sources.rs b/src/sources.rs index ca029e82..24e7d31d 100644 --- a/src/sources.rs +++ b/src/sources.rs @@ -50,17 +50,25 @@ impl Sources { /// Add a source tree to a map, keyed by its alias. Returns the alias. fn add_source(sources: &mut BTreeMap, mounted_sources: &BTreeMap, - context: &dc::Context) + context: &dc::Context, + image: Option) -> Result { // Figure out what alias we want to use. let alias = context.human_alias()?; + // Get the fully qualified image name + let fq_image: String = match image { + Some(i) => { format!("{}", i) } + None => { String::from("") } + }; + // Look up whether we've mounted this container or not. let mounted = mounted_sources.get(&alias).cloned().unwrap_or(true); // Build our Source object. let source = Source { alias: alias.clone(), + image: fq_image, context: context.clone(), mounted: mounted, }; @@ -104,7 +112,8 @@ impl Sources { for file in pod.all_files() { for service in file.services.values() { if let Some(context) = service.context()? { - Self::add_source(&mut sources, &mounted, context)?; + let image = format!("{}", service.image.clone().unwrap().to_string()); + Self::add_source(&mut sources, &mounted, context, Some(image))?; } } } @@ -116,7 +125,7 @@ impl Sources { let libs: BTreeMap = load_yaml(&path)?; for (lib_key, lib_info) in &libs { let context = lib_info.context.value()?; - let alias = Self::add_source(&mut sources, &mounted, context)?; + let alias = Self::add_source(&mut sources, &mounted, context, None)?; lib_keys.insert(lib_key.clone(), alias); } } @@ -195,6 +204,8 @@ impl<'a> Iterator for Iter<'a> { pub struct Source { /// A short name for this source tree. alias: String, + /// The fully qualified image used by the services this source maps to + image: String, /// The remote location from which we can clone this source tree, or /// the local directory where we can find it. context: dc::Context, @@ -210,6 +221,11 @@ impl Source { &self.alias } + /// The fully qualified image used by the services this source maps to + pub fn image(&self) -> &str { + &self.image + } + /// The remote git URL from which we can clone this source tree. pub fn context(&self) -> &dc::Context { &self.context @@ -284,6 +300,7 @@ fn are_loaded_with_projects() { assert_eq!(hello.context(), &dc::Context::new(url)); assert_eq!(hello.path(&proj), proj.src_dir().join("dockercloud-hello-world")); + assert_eq!(hello.image(), "dockercloud/hello-world"); } #[test]