From 52467ec1b711e3a8edeaba29426ef84c1cffbcfc Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Tue, 26 May 2020 13:08:04 -0400 Subject: [PATCH] Allow for overriding project type What? ===== Because unused may not (by default) be able to determine the best match project type, this opens up a flag to set this by hand. In doing so, this also improves the messaging around project type configuration in standard mode. --- crates/cli/src/cli_configuration.rs | 73 ++++++++++++++++++++++++--- crates/cli/src/flags.rs | 8 +++ crates/cli/src/formatters/standard.rs | 2 +- 3 files changed, 74 insertions(+), 9 deletions(-) diff --git a/crates/cli/src/cli_configuration.rs b/crates/cli/src/cli_configuration.rs index c123c14..f4c3461 100644 --- a/crates/cli/src/cli_configuration.rs +++ b/crates/cli/src/cli_configuration.rs @@ -14,20 +14,40 @@ pub struct CliConfiguration { flags: Flags, token_search_config: TokenSearchConfig, analysis_filter: AnalysisFilter, - project_configuration: ProjectConfiguration, + project_configuration: SelectedProjectConfiguration, outcome: TokenUsageResults, } +enum SelectedProjectConfiguration { + DefaultFromBestMatch(ProjectConfiguration), + DefaultFromProjectType(ProjectConfiguration, String), + ProjectType(ProjectConfiguration), + BestMatch(ProjectConfiguration), +} + +impl SelectedProjectConfiguration { + pub fn project_configuration(&self) -> &ProjectConfiguration { + match self { + Self::DefaultFromBestMatch(config) => config, + Self::DefaultFromProjectType(config, _) => config, + Self::ProjectType(config) => config, + Self::BestMatch(config) => config, + } + } +} + impl CliConfiguration { pub fn new(flags: Flags, tokens: Vec) -> Self { let token_search_config = build_token_search_config(&flags, tokens); let analysis_filter = build_analysis_filter(&flags); let results = TokenSearchResults::generate_with_config(&token_search_config); - let project_configuration = load_and_parse_config() - .best_match(&results) - .unwrap_or(ProjectConfiguration::default()); - let outcome = - TokenUsageResults::calculate(&token_search_config, results, &project_configuration); + + let project_configuration = select_project_configuration(&flags, &results); + let outcome = TokenUsageResults::calculate( + &token_search_config, + results, + project_configuration.project_configuration(), + ); Self { flags, @@ -99,13 +119,25 @@ impl CliConfiguration { } pub fn configuration_name(&self) -> String { - self.project_configuration.name.to_string() + match &self.project_configuration { + SelectedProjectConfiguration::DefaultFromBestMatch(config) => { + format!("{} (unable to find a match)", config.name) + } + SelectedProjectConfiguration::DefaultFromProjectType(config, project_type) => format!( + "{} (unable to find project type '{}')", + config.name, project_type + ), + SelectedProjectConfiguration::ProjectType(config) => format!("{}", config.name), + SelectedProjectConfiguration::BestMatch(config) => { + format!("{} (based on best match)", config.name) + } + } } pub fn low_likelihood_conflicts(&self) -> HashMap> { let mut conflict_results = HashMap::new(); - for ll in self.project_configuration.low_likelihood.iter() { + for ll in self.project_configuration().low_likelihood.iter() { let conflicts = ll.conflicts(); if conflicts.len() > 0 { @@ -115,6 +147,10 @@ impl CliConfiguration { conflict_results } + + pub fn project_configuration(&self) -> &ProjectConfiguration { + self.project_configuration.project_configuration() + } } fn build_token_search_config(cmd: &Flags, token_results: Vec) -> TokenSearchConfig { @@ -138,6 +174,27 @@ fn build_token_search_config(cmd: &Flags, token_results: Vec) -> TokenSea search_config } +fn select_project_configuration( + cmd: &Flags, + results: &TokenSearchResults, +) -> SelectedProjectConfiguration { + match &cmd.project_type { + None => load_and_parse_config() + .best_match(&results) + .map(SelectedProjectConfiguration::BestMatch) + .unwrap_or(SelectedProjectConfiguration::DefaultFromBestMatch( + ProjectConfiguration::default(), + )), + Some(project_type) => load_and_parse_config() + .get(&project_type) + .map(SelectedProjectConfiguration::ProjectType) + .unwrap_or(SelectedProjectConfiguration::DefaultFromProjectType( + ProjectConfiguration::default(), + project_type.clone(), + )), + } +} + fn build_analysis_filter(cmd: &Flags) -> AnalysisFilter { let mut analysis_filter = AnalysisFilter::default(); diff --git a/crates/cli/src/flags.rs b/crates/cli/src/flags.rs index 4ba7f98..63d2291 100644 --- a/crates/cli/src/flags.rs +++ b/crates/cli/src/flags.rs @@ -71,6 +71,14 @@ pub struct Flags { #[structopt(long, use_delimiter = true)] pub ignore: Vec, + /// Project type configuration + /// + /// By default, unused will attempt to detect the type of project you're working on based on + /// heuristics on file or token detection. Setting this will override behavior. If the project + /// type is not found, unused will fallback to default settings (rather than best match). + #[structopt(long)] + pub project_type: Option, + #[structopt(subcommand)] pub cmd: Option, } diff --git a/crates/cli/src/formatters/standard.rs b/crates/cli/src/formatters/standard.rs index 60a3c81..484c3bf 100644 --- a/crates/cli/src/formatters/standard.rs +++ b/crates/cli/src/formatters/standard.rs @@ -65,7 +65,7 @@ fn usage_summary(tokens_count: usize, files_count: usize, cli_config: &CliConfig cli_config.usage_likelihood_filter().join(", ").cyan() ); println!( - " Configuration setting: {}", + " Project type configuration: {}", cli_config.configuration_name().cyan() ); println!("");