use anyhow::bail;
use anyhow::Result;
use std::borrow::Cow;
use std::collections::HashMap;
use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Instant;
use crate::environment::Environment;
use crate::incremental::IncrementalFile;
use crate::paths::PluginNames;
use crate::plugins::do_batch_format;
use crate::plugins::PluginAndPoolMutRef;
use crate::plugins::PluginPools;
use crate::plugins::TakePluginResult;
use crate::utils::ErrorCountLogger;
use crate::utils::FileText;
pub fn format_with_plugin_pools<'a, TEnvironment: Environment>(
file_name: &Path,
file_text: &'a str,
environment: &TEnvironment,
plugin_pools: &Arc<PluginPools<TEnvironment>>,
) -> Result<Cow<'a, str>> {
let plugin_names = plugin_pools.get_plugin_names_from_file_name(file_name);
let mut file_text = Cow::Borrowed(file_text);
for plugin_name in plugin_names {
let plugin_pool = plugin_pools.get_pool(&plugin_name).unwrap();
let error_logger = ErrorCountLogger::from_environment(environment);
match plugin_pool.take_or_create_checking_config_diagnostics(&error_logger)? {
TakePluginResult::Success(mut initialized_plugin) => {
let result = initialized_plugin.format_text(file_name, &file_text, &HashMap::new());
plugin_pool.release(initialized_plugin);
file_text = Cow::Owned(result?); }
TakePluginResult::HadDiagnostics => {
bail!("Had {} configuration errors.", error_logger.get_error_count());
}
}
}
Ok(file_text)
}
pub fn run_parallelized<F, TEnvironment: Environment>(
file_paths_by_plugins: HashMap<PluginNames, Vec<PathBuf>>,
environment: &TEnvironment,
plugin_pools: Arc<PluginPools<TEnvironment>>,
incremental_file: Option<Arc<IncrementalFile<TEnvironment>>>,
f: F,
) -> Result<()>
where
F: Fn(&Path, &str, String, bool, Instant, &TEnvironment) -> Result<()> + Send + 'static + Clone,
{
let error_logger = ErrorCountLogger::from_environment(environment);
do_batch_format(environment, &error_logger, &plugin_pools, file_paths_by_plugins, {
let environment = environment.clone();
let error_logger = error_logger.clone();
move |plugins, file_path| {
let result = run_for_file_path(&environment, &incremental_file, plugins, file_path, f.clone());
if let Err(err) = result {
error_logger.log_error(&format!("Error formatting {}. Message: {}", file_path.display(), err));
}
}
})?;
let error_count = error_logger.get_error_count();
return if error_count == 0 {
Ok(())
} else {
bail!("Had {0} error(s) formatting.", error_count)
};
#[inline]
fn run_for_file_path<F, TEnvironment: Environment>(
environment: &TEnvironment,
incremental_file: &Option<Arc<IncrementalFile<TEnvironment>>>,
mut plugins: Vec<PluginAndPoolMutRef<TEnvironment>>,
file_path: &Path,
f: F,
) -> Result<()>
where
F: Fn(&Path, &str, String, bool, Instant, &TEnvironment) -> Result<()> + Send + 'static + Clone,
{
let file_text = FileText::new(environment.read_file(&file_path)?);
if let Some(incremental_file) = incremental_file {
if incremental_file.is_file_same(file_path, file_text.as_str()) {
log_verbose!(environment, "No change: {}", file_path.display());
return Ok(());
}
}
let (start_instant, formatted_text) = {
let start_instant = Instant::now();
let mut file_text = Cow::Borrowed(file_text.as_str());
let plugins_len = plugins.len();
for (i, plugin) in plugins.iter_mut().enumerate() {
let start_instant = Instant::now();
let format_text_result = plugin
.pool
.format_measuring_time(|| plugin.plugin.format_text(file_path, &file_text, &HashMap::new()));
log_verbose!(
environment,
"Formatted file: {} in {}ms{}",
file_path.display(),
start_instant.elapsed().as_millis(),
if plugins_len > 1 {
format!(" (Plugin {}/{})", i + 1, plugins_len)
} else {
String::new()
},
);
file_text = Cow::Owned(format_text_result?);
}
(start_instant, file_text.into_owned())
};
if let Some(incremental_file) = incremental_file {
incremental_file.update_file(file_path, &formatted_text);
}
f(file_path, file_text.as_str(), formatted_text, file_text.has_bom(), start_instant, environment)?;
Ok(())
}
}