only run formatters if there are files to format

Add more debugging. Take the baseline from ~500millis to ~60millis.
This commit is contained in:
zimbatm 2021-02-25 18:42:33 +01:00
parent fd7d6e2396
commit c9bc5c63c9
No known key found for this signature in database
GPG Key ID: 71BAF6D40C1D63D7
6 changed files with 95 additions and 53 deletions

View File

@ -6,6 +6,11 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[profile.release]
lto = true
codegen-units = 1
panic = "abort"
[dependencies]
anyhow = "1.0"
console = "0.13"

View File

@ -40,7 +40,8 @@ fn cwd() -> PathBuf {
}
/// Returns an absolute path to the treefmt.toml file. From the current folder, and up.
#[must_use] pub fn lookup(dir: &PathBuf) -> Option<PathBuf> {
#[must_use]
pub fn lookup(dir: &PathBuf) -> Option<PathBuf> {
let mut cwd = dir.clone();
loop {
let config_file = cwd.join(FILENAME);

View File

@ -48,7 +48,8 @@ pub struct CustomLogOutput {
impl CustomLogOutput {
/// Returns a new CustomLogOutput
#[must_use] pub const fn new() -> Self {
#[must_use]
pub const fn new() -> Self {
Self {
quiet: AtomicBool::new(false),
log_level: AtomicU8::new(LogLevel::Info as u8),

View File

@ -49,6 +49,11 @@ pub fn run_treefmt(
// Load the treefmt.toml file
let project_config = config::from_path(&treefmt_toml)?;
CLOG.debug(&format!(
"load config: {}",
start_time.elapsed().as_millis()
));
// Load all the formatter instances from the config. Ignore the ones that failed.
let formatters =
project_config
@ -67,9 +72,14 @@ pub fn run_treefmt(
sum
});
CLOG.debug(&format!(
"load formatters: {}",
start_time.elapsed().as_millis()
));
// Load the eval cache
let cache = CacheManifest::load(&cache_dir, &treefmt_toml);
CLOG.debug(&format!("load cache: {}", start_time.elapsed().as_millis()));
// Insert the new formatter configs
let cache = cache.update_formatters(formatters.clone());
@ -126,10 +136,16 @@ pub fn run_treefmt(
}
}
}
CLOG.debug(&format!("tree walk: {}", start_time.elapsed().as_millis()));
// Filter out all of the paths that were already in the cache
let matches = cache.clone().filter_matches(matches);
CLOG.debug(&format!(
"filter_matches: {}",
start_time.elapsed().as_millis()
));
// Start another collection of formatter names to path to mtime.
//
// This time to collect the new paths that have been formatted.
@ -141,62 +157,77 @@ pub fn run_treefmt(
let paths: Vec<PathBuf> = path_mtime.keys().cloned().collect();
let formatter = formatters.get(&formatter_name).unwrap();
// Keep track of the paths that are actually going to be formatted
filtered_files += paths.len();
if !paths.is_empty() {
// Keep track of the paths that are actually going to be formatted
filtered_files += paths.len();
match formatter.clone().fmt(&paths.clone()) {
// FIXME: do we care about the output?
Ok(_) => {
// Get the new mtimes and compare them to the original ones
let new_paths = paths.into_iter().fold(BTreeMap::new(), |mut sum, path| {
let mtime = get_path_mtime(&path).unwrap();
sum.insert(path, mtime);
sum
});
new_matches.insert(formatter_name.clone(), new_paths);
}
Err(err) => {
// FIXME: What is the right behaviour if a formatter has failed running?
CLOG.error(&format!("{} failed: {}", &formatter, err));
let start_time = Instant::now();
match formatter.clone().fmt(&paths.clone()) {
// FIXME: do we care about the output?
Ok(_) => {
CLOG.info(&format!(
"{}: {} files formatted in {} millis",
formatter.name,
paths.len(),
start_time.elapsed().as_millis()
));
// Get the new mtimes and compare them to the original ones
let new_paths = paths.into_iter().fold(BTreeMap::new(), |mut sum, path| {
let mtime = get_path_mtime(&path).unwrap();
sum.insert(path, mtime);
sum
});
new_matches.insert(formatter_name.clone(), new_paths);
}
Err(err) => {
// FIXME: What is the right behaviour if a formatter has failed running?
CLOG.error(&format!("{} failed: {}", &formatter, err));
}
}
}
}
CLOG.debug(&format!("format: {}", start_time.elapsed().as_millis()));
// Record the new matches in the cache
let cache = cache.add_results(new_matches.clone());
// And write to disk
cache.write(cache_dir, treefmt_toml);
CLOG.debug(&format!(
"write cache: {}",
start_time.elapsed().as_millis()
));
// Diff the old matches with the new matches
let changed_matches: BTreeMap<FormatterName, Vec<PathBuf>> = new_matches
.into_iter()
.fold(BTreeMap::new(), |mut sum, (name, new_paths)| {
let old_paths = matches.get(&name).unwrap().clone();
let filtered = new_paths
.iter()
.filter_map(|(k, v)| {
if old_paths.get(k).unwrap() == v {
None
} else {
Some(k.clone())
}
})
.collect();
let changed_matches: BTreeMap<FormatterName, Vec<PathBuf>> =
new_matches
.into_iter()
.fold(BTreeMap::new(), |mut sum, (name, new_paths)| {
let old_paths = matches.get(&name).unwrap().clone();
let filtered = new_paths
.iter()
.filter_map(|(k, v)| {
if old_paths.get(k).unwrap() == v {
None
} else {
Some(k.clone())
}
})
.collect();
sum.insert(name, filtered);
sum
});
sum.insert(name, filtered);
sum
});
// Finally display all the paths that have been formatted
for (_name, paths) in changed_matches {
// Keep track of how many files were reformatted
reformatted_files += paths.len();
println!("{}:", name);
for path in paths {
println!("- {}", path.display());
}
// println!("{}:", name);
// for path in paths {
// println!("- {}", path.display());
// }
}
println!(

View File

@ -68,7 +68,8 @@ impl CacheManifest {
}
/// Always loads the manifest. If an error occured, log and return an empty manifest.
#[must_use] pub fn load(cache_dir: &PathBuf, treefmt_toml: &PathBuf) -> Self {
#[must_use]
pub fn load(cache_dir: &PathBuf, treefmt_toml: &PathBuf) -> Self {
match Self::try_load(cache_dir, treefmt_toml) {
Ok(manifest) => manifest,
Err(err) => {
@ -107,7 +108,8 @@ impl CacheManifest {
/// Checks and inserts the formatter info into the cache.
/// If the formatter info has changed, invalidate all the old paths.
#[must_use] pub fn update_formatters(self, formatters: BTreeMap<FormatterName, Formatter>) -> Self {
#[must_use]
pub fn update_formatters(self, formatters: BTreeMap<FormatterName, Formatter>) -> Self {
let mut new_formatters = BTreeMap::new();
let mut new_paths = self.matches.clone();
for (name, fmt) in formatters {
@ -145,12 +147,12 @@ impl CacheManifest {
}
/// Returns a new map with all the paths that haven't changed
#[must_use] pub fn filter_matches(
#[must_use]
pub fn filter_matches(
self,
matches: BTreeMap<FormatterName, BTreeMap<PathBuf, Mtime>>,
) -> BTreeMap<FormatterName, BTreeMap<PathBuf, Mtime>> {
matches
.into_iter()
.fold(BTreeMap::new(), |mut sum, (key, path_infos)| {
let new_path_infos = match self.matches.get(&key) {
@ -175,10 +177,8 @@ impl CacheManifest {
}
/// Merge recursively the new matches with the existing entries in the cache
#[must_use] pub fn add_results(
self,
matches: BTreeMap<FormatterName, BTreeMap<PathBuf, Mtime>>,
) -> Self {
#[must_use]
pub fn add_results(self, matches: BTreeMap<FormatterName, BTreeMap<PathBuf, Mtime>>) -> Self {
// Get a copy of the old matches
let mut new_matches = self.matches.to_owned();
// This is really ugly. Get a second copy to work around lifetime issues.
@ -187,7 +187,9 @@ impl CacheManifest {
// Merge all the new matches into it
for (name, path_infos) in matches {
let mut def = BTreeMap::new();
let merged_path_infos = new_matches_cmp.get_mut(&name).unwrap_or_else(|| def.borrow_mut());
let merged_path_infos = new_matches_cmp
.get_mut(&name)
.unwrap_or_else(|| def.borrow_mut());
for (path, mtime) in path_infos {
merged_path_infos.insert(path.clone(), mtime);
}

View File

@ -37,13 +37,15 @@ pub fn get_path_mtime(path: &PathBuf) -> Result<Mtime> {
}
/// Small utility that stat() and retrieve the mtime of a file metadata
#[must_use] pub fn get_meta_mtime(metadata: &Metadata) -> Mtime {
#[must_use]
pub fn get_meta_mtime(metadata: &Metadata) -> Mtime {
Mtime(FileTime::from_last_modification_time(metadata).unix_seconds())
}
/// Returns an absolute path. If the path is absolute already, leave it alone. Otherwise join it to the reference path.
/// Then clean all superfluous ../
#[must_use] pub fn expand_path(path: &PathBuf, reference: &PathBuf) -> PathBuf {
#[must_use]
pub fn expand_path(path: &PathBuf, reference: &PathBuf) -> PathBuf {
let new_path = if path.is_absolute() {
path.clone()
} else {