Skip to content

Commit

Permalink
List now goes via a Dependencies struct
Browse files Browse the repository at this point in the history
Preliminary work to expose the APIs needed for a future `cargo upgrade`
(killercup#74)
  • Loading branch information
bjgill committed Jun 26, 2017
1 parent c371689 commit 8a8c4a8
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 20 deletions.
74 changes: 55 additions & 19 deletions src/bin/list/list.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,69 @@

use std::fmt;

use cargo_edit::Manifest;
use list_error::ListError;
use pad::{Alignment, PadStr};
use toml;

/// List the dependencies for manifest section
#[allow(deprecated)] // connect -> join
pub fn list_section(manifest: &Manifest, section: &str) -> Result<String, ListError> {
let mut output = vec![];
enum Source {
Version(String),
Git(String),
Path(String),
}

impl fmt::Display for Source {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", match *self {
Source::Version(ref v) => v.to_owned(),
Source::Git(ref g) => format!("git: {}", g),
Source::Path(ref g) => format!("path: {}", g),
})
}
}

struct Dependency {
name: String,
version: Source,
optional: bool,
}

/// A set of dependencies parsed
pub struct Dependencies(Vec<Dependency>, usize);

impl fmt::Display for Dependencies {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let output: Vec<_> = self.0.iter().map(|dep| {
format!("{name} {version}{optional}",
name = dep.name.pad_to_width_with_alignment(self.1, Alignment::Left),
version = dep.version,
optional = if dep.optional { " (optional)" } else { "" })
}).collect();

write!(f, "{}", output.join("\n"))
}
}

/// Parse the manifest to extract the dependencies.
pub fn list_section(manifest: &Manifest, section: &str) -> Result<Dependencies, ListError> {
let list = try!(manifest.data
.get(section)
.and_then(|field| field.as_table())
.ok_or_else(|| ListError::SectionMissing(String::from(section))));

let name_max_len = list.keys().map(|k| k.len()).max().unwrap_or(0);
let name_max_len = list.keys().map(String::len).max().unwrap_or(0);

for (name, val) in list {
let deps = list.iter().map(|(name, val)| {
let version = match *val {
toml::Value::String(ref version) => version.clone(),
toml::Value::String(ref version) => Source::Version(version.to_owned()),
toml::Value::Table(_) => {
try!(val.get("version")
.and_then(|field| field.as_str().map(|s| s.to_owned()))
.or_else(|| val.get("git").map(|repo| format!("git: {}", repo)))
.or_else(|| val.get("path").map(|path| format!("path: {}", path)))
.and_then(|field| field.as_str().map(|s| Source::Version(s.to_owned())))
.or_else(|| val.get("git").map(|g| Source::Git(g.to_string())))
.or_else(|| val.get("path").map(|p| Source::Path(p.to_string())))
.ok_or_else(|| ListError::VersionMissing(name.clone(), section.to_owned())))
}
_ => String::from(""),
_ => Source::Version(String::new()),
};

let optional = if let toml::Value::Table(_) = *val {
Expand All @@ -38,14 +74,14 @@ pub fn list_section(manifest: &Manifest, section: &str) -> Result<String, ListEr
false
};

output.push(format!("{name} {version}{optional}",
name =
name.pad_to_width_with_alignment(name_max_len, Alignment::Left),
version = version,
optional = if optional { " (optional)" } else { "" }));
}
Ok(Dependency {
name: name.to_owned(),
version,
optional,
})
}).collect::<Result<Vec<Dependency>, ListError>>()?;

Ok(output.connect("\n"))
Ok(Dependencies(deps, name_max_len))
}

#[cfg(test)]
Expand All @@ -66,7 +102,7 @@ lorem-ipsum = "0.4.2""#;
fn basic_listing() {
let manifile: Manifest = DEFAULT_CARGO_TOML.parse().unwrap();

assert_eq!(list_section(&manifile, "dependencies").unwrap(),
assert_eq!(list_section(&manifile, "dependencies").unwrap().to_string(),
"\
foo-bar 0.1
lorem-ipsum 0.4.2");
Expand Down
2 changes: 1 addition & 1 deletion src/bin/list/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ fn handle_list(args: &Args) -> Result<String, Box<Error>> {
list_tree(&manifest)
} else {
let manifest = try!(Manifest::open(&args.flag_manifest_path.as_ref().map(|s| &s[..])));
list_section(&manifest, args.get_section()).or_else(|err| match err {
list_section(&manifest, args.get_section()).map(|a| a.to_string()).or_else(|err| match err {
ListError::SectionMissing(..) => Ok("".into()),
_ => Err(err),
})
Expand Down

0 comments on commit 8a8c4a8

Please sign in to comment.