From 26f18e521ba3916f878623d37e1b493cea5fab2e Mon Sep 17 00:00:00 2001 From: Mavdol Date: Fri, 23 Jan 2026 12:31:13 +0100 Subject: [PATCH 1/3] add fingerprint manage via blake3 --- crates/capsule-cli/Cargo.lock | 33 +++ crates/capsule-core/Cargo.lock | 33 +++ crates/capsule-core/Cargo.toml | 1 + crates/capsule-core/src/config/fingerprint.rs | 204 ++++++++++++++++++ crates/capsule-core/src/config/mod.rs | 1 + .../src/wasm/compiler/javascript.rs | 78 ++----- .../capsule-core/src/wasm/compiler/python.rs | 77 ++----- 7 files changed, 310 insertions(+), 117 deletions(-) create mode 100644 crates/capsule-core/src/config/fingerprint.rs diff --git a/crates/capsule-cli/Cargo.lock b/crates/capsule-cli/Cargo.lock index 81b1c33..c31895e 100644 --- a/crates/capsule-cli/Cargo.lock +++ b/crates/capsule-cli/Cargo.lock @@ -115,6 +115,18 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "ast_node" version = "5.0.0" @@ -176,6 +188,20 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +[[package]] +name = "blake3" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2468ef7d57b3fb7e16b576e8377cdbde2320c60e1491e961d11da40fc4f02a2d" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "cpufeatures", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -299,6 +325,7 @@ name = "capsule-core" version = "0.4.0" dependencies = [ "anyhow", + "blake3", "chrono", "colored", "humantime", @@ -444,6 +471,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + [[package]] name = "core-foundation-sys" version = "0.8.7" diff --git a/crates/capsule-core/Cargo.lock b/crates/capsule-core/Cargo.lock index 21b14d6..4fa3355 100644 --- a/crates/capsule-core/Cargo.lock +++ b/crates/capsule-core/Cargo.lock @@ -74,6 +74,18 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "ast_node" version = "5.0.0" @@ -156,6 +168,20 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +[[package]] +name = "blake3" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2468ef7d57b3fb7e16b576e8377cdbde2320c60e1491e961d11da40fc4f02a2d" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "cpufeatures", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -279,6 +305,7 @@ name = "capsule-core" version = "0.4.0" dependencies = [ "anyhow", + "blake3", "chrono", "colored", "humantime", @@ -378,6 +405,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + [[package]] name = "core-foundation-sys" version = "0.8.7" diff --git a/crates/capsule-core/Cargo.toml b/crates/capsule-core/Cargo.toml index f2450a5..288d9ff 100644 --- a/crates/capsule-core/Cargo.toml +++ b/crates/capsule-core/Cargo.toml @@ -28,6 +28,7 @@ indicatif = "0.17" chrono = "0.4" colored = "2.1" toml = "0.9.11" +blake3 = "1" rustpython-parser = "0.4" swc_ecma_parser = "33.0" diff --git a/crates/capsule-core/src/config/fingerprint.rs b/crates/capsule-core/src/config/fingerprint.rs new file mode 100644 index 0000000..934b7b9 --- /dev/null +++ b/crates/capsule-core/src/config/fingerprint.rs @@ -0,0 +1,204 @@ +use std::collections::BTreeMap; +use std::fs; +use std::path::{Path, PathBuf}; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Default)] +pub struct SourceFingerprint { + pub files: BTreeMap, +} + +impl SourceFingerprint { + const MANIFEST_FILENAME: &'static str = ".capsule_fingerprint.json"; + + pub fn load(cache_dir: &Path) -> Self { + let fingerprint_path = cache_dir.join(Self::MANIFEST_FILENAME); + + if fingerprint_path.exists() { + if let Ok(content) = fs::read_to_string(&fingerprint_path) { + if let Ok(fingerprint) = serde_json::from_str(&content) { + return fingerprint; + } + } + } + + Self::default() + } + + pub fn save(&self, cache_dir: &Path) -> std::io::Result<()> { + let fingerprint_path = cache_dir.join(Self::MANIFEST_FILENAME); + let content = serde_json::to_string_pretty(self)?; + fs::write(fingerprint_path, content) + } + + pub fn hash_file(path: &Path) -> Option { + let contents = fs::read(path).ok()?; + Some(blake3::hash(&contents).to_hex().to_string()) + } + + pub fn collect_source_files( + base_dir: &Path, + extensions: &[&str], + ignored_dirs: &[&str], + ) -> Vec { + let mut files = Vec::new(); + Self::collect_files_recursive(base_dir, extensions, ignored_dirs, &mut files); + files + } + + fn collect_files_recursive( + dir: &Path, + extensions: &[&str], + ignored_dirs: &[&str], + files: &mut Vec, + ) { + let Ok(entries) = fs::read_dir(dir) else { + return; + }; + + for entry in entries.flatten() { + let path = entry.path(); + + if path.is_dir() { + let dir_name = path.file_name().and_then(|n| n.to_str()).unwrap_or(""); + + if dir_name.starts_with('.') || ignored_dirs.contains(&dir_name) { + continue; + } + + Self::collect_files_recursive(&path, extensions, ignored_dirs, files); + } else if let Some(ext) = path.extension().and_then(|e| e.to_str()) { + if extensions.contains(&ext) { + files.push(path); + } + } + } + } + + pub fn build( + base_dir: &Path, + extensions: &[&str], + ignored_dirs: &[&str], + ) -> Self { + let files = Self::collect_source_files(base_dir, extensions, ignored_dirs); + let mut fingerprint = Self::default(); + + for file_path in files { + if let Some(hash) = Self::hash_file(&file_path) { + + let relative = file_path + .strip_prefix(base_dir) + .unwrap_or(&file_path) + .to_string_lossy() + .to_string(); + fingerprint.files.insert(relative, hash); + } + } + + fingerprint + } + + pub fn has_changes(&self, other: &SourceFingerprint) -> bool { + if self.files.len() != other.files.len() { + return true; + } + + for (path, hash) in &self.files { + match other.files.get(path) { + Some(other_hash) if hash == other_hash => continue, + _ => return true, + } + } + + false + } + + pub fn needs_rebuild( + cache_dir: &Path, + source_dir: &Path, + output_path: &Path, + extensions: &[&str], + ignored_dirs: &[&str], + ) -> bool { + if !output_path.exists() { + return true; + } + let previous = Self::load(cache_dir); + + let current = Self::build(source_dir, extensions, ignored_dirs); + + current.has_changes(&previous) + } + + pub fn update_after_build( + cache_dir: &Path, + source_dir: &Path, + extensions: &[&str], + ignored_dirs: &[&str], + ) -> std::io::Result<()> { + let fingerprint = Self::build(source_dir, extensions, ignored_dirs); + fingerprint.save(cache_dir) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_hash_consistency() { + let hash1 = blake3::hash(b"hello world").to_hex().to_string(); + let hash2 = blake3::hash(b"hello world").to_hex().to_string(); + assert_eq!(hash1, hash2); + + let hash3 = blake3::hash(b"goodbye world").to_hex().to_string(); + assert_ne!(hash1, hash3); + } + + #[test] + fn test_fingerprint_no_changes() { + let mut fingerprint1 = SourceFingerprint::default(); + fingerprint1.files.insert("main.py".to_string(), "abc123".to_string()); + + let mut fingerprint2 = SourceFingerprint::default(); + fingerprint2.files.insert("main.py".to_string(), "abc123".to_string()); + + assert!(!fingerprint1.has_changes(&fingerprint2)); + } + + #[test] + fn test_fingerprint_content_changed() { + let mut fingerprint1 = SourceFingerprint::default(); + fingerprint1.files.insert("main.py".to_string(), "abc123".to_string()); + + let mut fingerprint2 = SourceFingerprint::default(); + fingerprint2.files.insert("main.py".to_string(), "xyz789".to_string()); + + assert!(fingerprint1.has_changes(&fingerprint2)); + } + + #[test] + fn test_fingerprint_file_added() { + let mut fingerprint1 = SourceFingerprint::default(); + fingerprint1.files.insert("main.py".to_string(), "abc123".to_string()); + + let mut fingerprint2 = SourceFingerprint::default(); + fingerprint2.files.insert("main.py".to_string(), "abc123".to_string()); + fingerprint2.files.insert("helper.py".to_string(), "def456".to_string()); + + assert!(fingerprint1.has_changes(&fingerprint2)); + } + + #[test] + fn test_fingerprint_file_deleted() { + let mut fingerprint1 = SourceFingerprint::default(); + fingerprint1.files.insert("main.py".to_string(), "abc123".to_string()); + fingerprint1.files.insert("helper.py".to_string(), "def456".to_string()); + + let mut fingerprint2 = SourceFingerprint::default(); + fingerprint2.files.insert("main.py".to_string(), "abc123".to_string()); + + assert!(fingerprint1.has_changes(&fingerprint2)); + } +} diff --git a/crates/capsule-core/src/config/mod.rs b/crates/capsule-core/src/config/mod.rs index bf23c6b..85d3be3 100644 --- a/crates/capsule-core/src/config/mod.rs +++ b/crates/capsule-core/src/config/mod.rs @@ -1,3 +1,4 @@ pub mod database; pub mod log; pub mod manifest; +pub mod fingerprint; diff --git a/crates/capsule-core/src/wasm/compiler/javascript.rs b/crates/capsule-core/src/wasm/compiler/javascript.rs index f021120..f214d4b 100644 --- a/crates/capsule-core/src/wasm/compiler/javascript.rs +++ b/crates/capsule-core/src/wasm/compiler/javascript.rs @@ -5,6 +5,7 @@ use std::process::{Command, Stdio}; use crate::wasm::utilities::introspection::javascript; use crate::wasm::utilities::wit_manager::WitManager; +use crate::config::fingerprint::SourceFingerprint; #[derive(Debug)] pub enum JavascriptWasmCompilerError { @@ -97,7 +98,17 @@ impl JavascriptWasmCompiler { } pub fn compile_wasm(&self) -> Result { - if !self.needs_rebuild(&self.source_path, &self.output_wasm)? { + let source_dir = self.source_path.parent().ok_or_else(|| { + JavascriptWasmCompilerError::FsError("Cannot determine source directory".to_string()) + })?; + + if !SourceFingerprint::needs_rebuild( + &self.cache_dir, + source_dir, + &self.output_wasm, + &["js", "ts", "toml"], + &["node_modules", "dist"], + ) { return Ok(self.output_wasm.clone()); } @@ -190,6 +201,13 @@ export const taskRunner = exports; ))); } + let _ = SourceFingerprint::update_after_build( + &self.cache_dir, + source_dir, + &["js", "ts", "toml"], + &["node_modules", "dist"], + ); + Ok(self.output_wasm.clone()) } @@ -244,64 +262,6 @@ export const taskRunner = exports; )) } - fn needs_rebuild( - &self, - source: &Path, - output: &Path, - ) -> Result { - if !output.exists() { - return Ok(true); - } - - let output_time = fs::metadata(output).and_then(|m| m.modified())?; - - let source_time = fs::metadata(source).and_then(|m| m.modified())?; - if source_time > output_time { - return Ok(true); - } - - if let Some(source_dir) = source.parent() - && Self::check_dir_modified(source_dir, source, output_time)? - { - return Ok(true); - } - - Ok(false) - } - - fn check_dir_modified( - dir: &Path, - source: &Path, - wasm_time: std::time::SystemTime, - ) -> Result { - if let Ok(entries) = fs::read_dir(dir) { - for entry in entries.flatten() { - let path = entry.path(); - - if path.is_dir() { - let dir_name = path.file_name().and_then(|n| n.to_str()).unwrap_or(""); - if dir_name.starts_with('.') || dir_name == "node_modules" { - continue; - } - - if Self::check_dir_modified(&path, source, wasm_time)? { - return Ok(true); - } - } else if let Some(ext) = path.extension() - && (ext == "js" || ext == "ts") - && path != source - && let Ok(metadata) = fs::metadata(&path) - && let Ok(modified) = metadata.modified() - && modified > wasm_time - { - return Ok(true); - } - } - } - - Ok(false) - } - fn transpile_typescript(&self) -> Result { let output_path = self.cache_dir.join( self.source_path diff --git a/crates/capsule-core/src/wasm/compiler/python.rs b/crates/capsule-core/src/wasm/compiler/python.rs index b16bb50..b88756d 100644 --- a/crates/capsule-core/src/wasm/compiler/python.rs +++ b/crates/capsule-core/src/wasm/compiler/python.rs @@ -7,6 +7,7 @@ use std::process::Stdio; use crate::wasm::utilities::introspection::python; use crate::wasm::utilities::wit_manager::WitManager; +use crate::config::fingerprint::SourceFingerprint; pub enum PythonWasmCompilerError { CompileFailed(String), @@ -90,7 +91,17 @@ impl PythonWasmCompiler { } pub fn compile_wasm(&self) -> Result { - if !self.needs_rebuild(&self.source_path, &self.output_wasm)? { + let source_dir = self.source_path.parent().ok_or_else(|| { + PythonWasmCompilerError::FsError("Cannot determine source directory".to_string()) + })?; + + if !SourceFingerprint::needs_rebuild( + &self.cache_dir, + source_dir, + &self.output_wasm, + &["py", "toml"], + &["__pycache__"], + ) { return Ok(self.output_wasm.clone()); } @@ -177,64 +188,14 @@ from capsule.app import TaskRunner, exports self.cleanup_pycache(python_path); - Ok(self.output_wasm.clone()) - } - - fn needs_rebuild( - &self, - source: &Path, - wasm_path: &Path, - ) -> Result { - if !wasm_path.exists() { - return Ok(true); - } - - let wasm_time = fs::metadata(wasm_path).and_then(|m| m.modified())?; - - let source_time = fs::metadata(source).and_then(|m| m.modified())?; - if source_time > wasm_time { - return Ok(true); - } - - if let Some(source_dir) = source.parent() - && Self::check_dir_modified(source_dir, source, wasm_time)? - { - return Ok(true); - } - - Ok(false) - } - - fn check_dir_modified( - dir: &Path, - source: &Path, - wasm_time: std::time::SystemTime, - ) -> Result { - if let Ok(entries) = fs::read_dir(dir) { - for entry in entries.flatten() { - let path = entry.path(); - - if path.is_dir() { - let dir_name = path.file_name().and_then(|n| n.to_str()).unwrap_or(""); - if dir_name.starts_with('.') || dir_name == "__pycache__" { - continue; - } - - if Self::check_dir_modified(&path, source, wasm_time)? { - return Ok(true); - } - } else if path.extension().is_some_and(|ext| ext == "py") - && path != source - && let Ok(metadata) = fs::metadata(&path) - && let Ok(modified) = metadata.modified() - && modified > wasm_time - { - return Ok(true); - } - } - } + let _ = SourceFingerprint::update_after_build( + &self.cache_dir, + source_dir, + &["py", "toml"], + &["__pycache__"], + ); - Ok(false) + Ok(self.output_wasm.clone()) } fn get_wit_path(&self) -> Result { From 6760d9433a284125b4e629a43f503509c73806e7 Mon Sep 17 00:00:00 2001 From: Mavdol Date: Fri, 23 Jan 2026 12:43:13 +0100 Subject: [PATCH 2/3] fmt check --- crates/capsule-core/src/config/fingerprint.rs | 47 ++++++++++++------- crates/capsule-core/src/config/mod.rs | 2 +- .../src/wasm/compiler/javascript.rs | 2 +- .../capsule-core/src/wasm/compiler/python.rs | 2 +- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/crates/capsule-core/src/config/fingerprint.rs b/crates/capsule-core/src/config/fingerprint.rs index 934b7b9..5f07269 100644 --- a/crates/capsule-core/src/config/fingerprint.rs +++ b/crates/capsule-core/src/config/fingerprint.rs @@ -76,17 +76,12 @@ impl SourceFingerprint { } } - pub fn build( - base_dir: &Path, - extensions: &[&str], - ignored_dirs: &[&str], - ) -> Self { + pub fn build(base_dir: &Path, extensions: &[&str], ignored_dirs: &[&str]) -> Self { let files = Self::collect_source_files(base_dir, extensions, ignored_dirs); let mut fingerprint = Self::default(); for file_path in files { if let Some(hash) = Self::hash_file(&file_path) { - let relative = file_path .strip_prefix(base_dir) .unwrap_or(&file_path) @@ -159,10 +154,14 @@ mod tests { #[test] fn test_fingerprint_no_changes() { let mut fingerprint1 = SourceFingerprint::default(); - fingerprint1.files.insert("main.py".to_string(), "abc123".to_string()); + fingerprint1 + .files + .insert("main.py".to_string(), "abc123".to_string()); let mut fingerprint2 = SourceFingerprint::default(); - fingerprint2.files.insert("main.py".to_string(), "abc123".to_string()); + fingerprint2 + .files + .insert("main.py".to_string(), "abc123".to_string()); assert!(!fingerprint1.has_changes(&fingerprint2)); } @@ -170,10 +169,14 @@ mod tests { #[test] fn test_fingerprint_content_changed() { let mut fingerprint1 = SourceFingerprint::default(); - fingerprint1.files.insert("main.py".to_string(), "abc123".to_string()); + fingerprint1 + .files + .insert("main.py".to_string(), "abc123".to_string()); let mut fingerprint2 = SourceFingerprint::default(); - fingerprint2.files.insert("main.py".to_string(), "xyz789".to_string()); + fingerprint2 + .files + .insert("main.py".to_string(), "xyz789".to_string()); assert!(fingerprint1.has_changes(&fingerprint2)); } @@ -181,11 +184,17 @@ mod tests { #[test] fn test_fingerprint_file_added() { let mut fingerprint1 = SourceFingerprint::default(); - fingerprint1.files.insert("main.py".to_string(), "abc123".to_string()); + fingerprint1 + .files + .insert("main.py".to_string(), "abc123".to_string()); let mut fingerprint2 = SourceFingerprint::default(); - fingerprint2.files.insert("main.py".to_string(), "abc123".to_string()); - fingerprint2.files.insert("helper.py".to_string(), "def456".to_string()); + fingerprint2 + .files + .insert("main.py".to_string(), "abc123".to_string()); + fingerprint2 + .files + .insert("helper.py".to_string(), "def456".to_string()); assert!(fingerprint1.has_changes(&fingerprint2)); } @@ -193,11 +202,17 @@ mod tests { #[test] fn test_fingerprint_file_deleted() { let mut fingerprint1 = SourceFingerprint::default(); - fingerprint1.files.insert("main.py".to_string(), "abc123".to_string()); - fingerprint1.files.insert("helper.py".to_string(), "def456".to_string()); + fingerprint1 + .files + .insert("main.py".to_string(), "abc123".to_string()); + fingerprint1 + .files + .insert("helper.py".to_string(), "def456".to_string()); let mut fingerprint2 = SourceFingerprint::default(); - fingerprint2.files.insert("main.py".to_string(), "abc123".to_string()); + fingerprint2 + .files + .insert("main.py".to_string(), "abc123".to_string()); assert!(fingerprint1.has_changes(&fingerprint2)); } diff --git a/crates/capsule-core/src/config/mod.rs b/crates/capsule-core/src/config/mod.rs index 85d3be3..46745de 100644 --- a/crates/capsule-core/src/config/mod.rs +++ b/crates/capsule-core/src/config/mod.rs @@ -1,4 +1,4 @@ pub mod database; +pub mod fingerprint; pub mod log; pub mod manifest; -pub mod fingerprint; diff --git a/crates/capsule-core/src/wasm/compiler/javascript.rs b/crates/capsule-core/src/wasm/compiler/javascript.rs index f214d4b..0e3167d 100644 --- a/crates/capsule-core/src/wasm/compiler/javascript.rs +++ b/crates/capsule-core/src/wasm/compiler/javascript.rs @@ -3,9 +3,9 @@ use std::fs; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; +use crate::config::fingerprint::SourceFingerprint; use crate::wasm::utilities::introspection::javascript; use crate::wasm::utilities::wit_manager::WitManager; -use crate::config::fingerprint::SourceFingerprint; #[derive(Debug)] pub enum JavascriptWasmCompilerError { diff --git a/crates/capsule-core/src/wasm/compiler/python.rs b/crates/capsule-core/src/wasm/compiler/python.rs index b88756d..157c33c 100644 --- a/crates/capsule-core/src/wasm/compiler/python.rs +++ b/crates/capsule-core/src/wasm/compiler/python.rs @@ -5,9 +5,9 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::process::Stdio; +use crate::config::fingerprint::SourceFingerprint; use crate::wasm::utilities::introspection::python; use crate::wasm::utilities::wit_manager::WitManager; -use crate::config::fingerprint::SourceFingerprint; pub enum PythonWasmCompilerError { CompileFailed(String), From 2e31c6d321ea62afdd4bdcc77d4c2f8e2393d9ac Mon Sep 17 00:00:00 2001 From: Mavdol Date: Fri, 23 Jan 2026 13:14:00 +0100 Subject: [PATCH 3/3] avoid nested if --- crates/capsule-core/src/config/fingerprint.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/crates/capsule-core/src/config/fingerprint.rs b/crates/capsule-core/src/config/fingerprint.rs index 5f07269..59a9daf 100644 --- a/crates/capsule-core/src/config/fingerprint.rs +++ b/crates/capsule-core/src/config/fingerprint.rs @@ -15,12 +15,11 @@ impl SourceFingerprint { pub fn load(cache_dir: &Path) -> Self { let fingerprint_path = cache_dir.join(Self::MANIFEST_FILENAME); - if fingerprint_path.exists() { - if let Ok(content) = fs::read_to_string(&fingerprint_path) { - if let Ok(fingerprint) = serde_json::from_str(&content) { - return fingerprint; - } - } + if fingerprint_path.exists() + && let Ok(content) = fs::read_to_string(&fingerprint_path) + && let Ok(fingerprint) = serde_json::from_str(&content) + { + return fingerprint; } Self::default() @@ -68,10 +67,10 @@ impl SourceFingerprint { } Self::collect_files_recursive(&path, extensions, ignored_dirs, files); - } else if let Some(ext) = path.extension().and_then(|e| e.to_str()) { - if extensions.contains(&ext) { - files.push(path); - } + } else if let Some(ext) = path.extension().and_then(|e| e.to_str()) + && extensions.contains(&ext) + { + files.push(path); } } }