| use std::fmt; |
| |
| use anyhow::{Error, bail}; |
| |
| use self::parse::{Parser, RawChunk}; |
| use super::{Graph, Node, NodeId}; |
| |
| mod parse; |
| |
| enum Chunk { |
| Raw(String), |
| Package, |
| License, |
| Repository, |
| Features, |
| LibName, |
| } |
| |
| pub struct Pattern(Vec<Chunk>); |
| |
| impl Pattern { |
| pub fn new(format: &str) -> Result<Pattern, Error> { |
| let mut chunks = vec![]; |
| |
| for raw in Parser::new(format) { |
| let chunk = match raw { |
| RawChunk::Text(text) => Chunk::Raw(text.to_owned()), |
| RawChunk::Argument("package") | RawChunk::Argument("p") => Chunk::Package, |
| RawChunk::Argument("license") | RawChunk::Argument("l") => Chunk::License, |
| RawChunk::Argument("repository") | RawChunk::Argument("r") => Chunk::Repository, |
| RawChunk::Argument("features") | RawChunk::Argument("f") => Chunk::Features, |
| RawChunk::Argument("lib") => Chunk::LibName, |
| RawChunk::Argument(a) => { |
| bail!("unsupported pattern `{}`", a); |
| } |
| RawChunk::Error(err) => bail!("{}", err), |
| }; |
| chunks.push(chunk); |
| } |
| |
| Ok(Pattern(chunks)) |
| } |
| |
| pub fn display<'a>(&'a self, graph: &'a Graph<'a>, node_index: NodeId) -> Display<'a> { |
| Display { |
| pattern: self, |
| graph, |
| node_index, |
| } |
| } |
| } |
| |
| pub struct Display<'a> { |
| pattern: &'a Pattern, |
| graph: &'a Graph<'a>, |
| node_index: NodeId, |
| } |
| |
| impl<'a> fmt::Display for Display<'a> { |
| fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
| let node = self.graph.node(self.node_index); |
| match node { |
| Node::Package { |
| package_id, |
| features, |
| .. |
| } => { |
| let package = self.graph.package_for_id(*package_id); |
| for chunk in &self.pattern.0 { |
| match chunk { |
| Chunk::Raw(s) => fmt.write_str(s)?, |
| Chunk::Package => { |
| let proc_macro_suffix = if package.proc_macro() { |
| " (proc-macro)" |
| } else { |
| "" |
| }; |
| write!( |
| fmt, |
| "{} v{}{}", |
| package.name(), |
| package.version(), |
| proc_macro_suffix |
| )?; |
| |
| let source_id = package.package_id().source_id(); |
| if !source_id.is_crates_io() { |
| write!(fmt, " ({})", source_id)?; |
| } |
| } |
| Chunk::License => { |
| if let Some(license) = &package.manifest().metadata().license { |
| write!(fmt, "{}", license)?; |
| } |
| } |
| Chunk::Repository => { |
| if let Some(repository) = &package.manifest().metadata().repository { |
| write!(fmt, "{}", repository)?; |
| } |
| } |
| Chunk::Features => { |
| write!(fmt, "{}", features.join(","))?; |
| } |
| Chunk::LibName => { |
| if let Some(target) = package |
| .manifest() |
| .targets() |
| .iter() |
| .find(|target| target.is_lib()) |
| { |
| write!(fmt, "{}", target.crate_name())?; |
| } |
| } |
| } |
| } |
| } |
| Node::Feature { name, node_index } => { |
| let for_node = self.graph.node(*node_index); |
| match for_node { |
| Node::Package { package_id, .. } => { |
| write!(fmt, "{} feature \"{}\"", package_id.name(), name)?; |
| if self.graph.is_cli_feature(self.node_index) { |
| write!(fmt, " (command-line)")?; |
| } |
| } |
| // The node_index in Node::Feature must point to a package |
| // node, see `add_feature`. |
| _ => panic!("unexpected feature node {:?}", for_node), |
| } |
| } |
| } |
| |
| Ok(()) |
| } |
| } |