use crate::{pattern::Pattern, source::SourceFile, Error};
use glob::glob;
use std::collections::HashSet;
use structopt::StructOpt;
#[derive(Debug, PartialEq, PartialOrd, Eq, Ord, Hash, StructOpt)]
pub struct Project {
#[structopt(long, short = "p")]
package: Option<String>,
#[structopt(long)]
features: Vec<String>,
#[structopt(long)]
workspace: bool,
#[structopt(long = "exclude")]
excludes: Vec<String>,
#[structopt(long = "all-features")]
all_features: bool,
#[structopt(long = "no-default-features")]
no_default_features: bool,
#[structopt(long = "no-cargo")]
no_cargo: bool,
#[structopt(long)]
target: Option<String>,
#[structopt(long = "target-dir", default_value = "target/compliance")]
target_dir: String,
#[structopt(long = "manifest-path")]
manifest_path: Option<String>,
#[structopt(long = "source-pattern")]
source_patterns: Vec<String>,
#[structopt(long = "spec-pattern")]
spec_patterns: Vec<String>,
}
impl Project {
pub fn sources(&self) -> Result<HashSet<SourceFile>, Error> {
let mut sources = HashSet::new();
for pattern in &self.source_patterns {
self.source_file(pattern, &mut sources)?;
}
for pattern in &self.spec_patterns {
self.spec_file(pattern, &mut sources)?;
}
Ok(sources)
}
fn source_file<'a>(
&self,
pattern: &'a str,
files: &mut HashSet<SourceFile<'a>>,
) -> Result<(), Error> {
let (compliance_pattern, file_pattern) = if let Some(pattern) = pattern.strip_prefix('(') {
let mut parts = pattern.splitn(2, ')');
let pattern = parts.next().expect("invalid pattern");
let file_pattern = parts.next().expect("invalid pattern");
let pattern = Pattern::from_arg(pattern)?;
(pattern, file_pattern)
} else {
(Pattern::default(), pattern)
};
for entry in glob(file_pattern)? {
files.insert(SourceFile::Text(compliance_pattern, entry?));
}
Ok(())
}
fn spec_file<'a>(
&self,
pattern: &'a str,
files: &mut HashSet<SourceFile<'a>>,
) -> Result<(), Error> {
for entry in glob(pattern)? {
files.insert(SourceFile::Spec(entry?));
}
Ok(())
}
}