diff --git a/implementations/rust/preserves-schema/src/compiler/mod.rs b/implementations/rust/preserves-schema/src/compiler/mod.rs index acf0479..67a9ae0 100644 --- a/implementations/rust/preserves-schema/src/compiler/mod.rs +++ b/implementations/rust/preserves-schema/src/compiler/mod.rs @@ -20,10 +20,9 @@ use preserves::value::Set; use std::convert::TryFrom; use std::fs::DirBuilder; use std::fs::File; +use std::io; use std::io::BufRead; -use std::io::BufReader; -use std::io::Error; -use std::io::ErrorKind; +use std::io::Read; use std::io::Write; use std::path::PathBuf; @@ -52,7 +51,7 @@ impl CompilerConfig { } } - pub fn load_schemas_and_bundles(&mut self, inputs: &Vec) -> Result<(), Error> { + pub fn load_schemas_and_bundles(&mut self, inputs: &Vec) -> io::Result<()> { for i in inputs { let mut f = File::open(&i)?; let mut src = IOBinarySource::new(&mut f); @@ -61,9 +60,11 @@ impl CompilerConfig { if let Ok(s) = Schema::try_from(&blob) { let prefix = i.file_stem().ok_or_else( - || Error::new(ErrorKind::InvalidData, format!("Bad schema file stem: {:?}", i)))? + || io::Error::new(io::ErrorKind::InvalidData, + format!("Bad schema file stem: {:?}", i)))? .to_str().ok_or_else( - || Error::new(ErrorKind::InvalidData, format!("Invalid UTF-8 in schema file name: {:?}", i)))?; + || io::Error::new(io::ErrorKind::InvalidData, + format!("Invalid UTF-8 in schema file name: {:?}", i)))?; self.bundle.insert(vec![prefix.to_owned()], s); continue; } @@ -75,24 +76,38 @@ impl CompilerConfig { continue; } - return Err(Error::new(ErrorKind::InvalidData, - format!("Invalid schema binary blob {:?}", i))); + return Err(io::Error::new(io::ErrorKind::InvalidData, + format!("Invalid schema binary blob {:?}", i))); } Ok(()) } } -pub fn expand_inputs(globs: &Vec) -> Result, Error> { +pub fn expand_inputs(globs: &Vec) -> io::Result> { let mut result = Vec::new(); for g in globs.iter() { - for p in glob(g).map_err(|e| Error::new(ErrorKind::InvalidData, format!("{}", e)))? { + for p in glob(g).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, format!("{}", e)))? { result.push(p.map_err(glob::GlobError::into_error)?) } } Ok(result) } -pub fn compile(config: &CompilerConfig) -> Result<(), std::io::Error> { +fn write_if_changed(output_path: &PathBuf, contents: &[u8]) -> io::Result<()> { + if output_path.exists() { + if let Ok(mut f) = File::open(output_path) { + let mut existing_contents = Vec::new(); + f.read_to_end(&mut existing_contents)?; + if existing_contents == contents { + return Ok(()); + } + } + } + let mut f = File::create(output_path)?; + f.write_all(contents) +} + +pub fn compile(config: &CompilerConfig) -> io::Result<()> { for (k, v) in config.bundle.iter() { let mut output_path = config.output_dir.clone(); output_path.extend(k); @@ -174,10 +189,8 @@ pub fn compile(config: &CompilerConfig) -> Result<(), std::io::Error> { } { - let mut f = File::create(&output_path)?; - for line in lines { - write!(f, "{}\n", line)?; - } + let contents = lines.join("\n"); + write_if_changed(&output_path, contents.as_bytes())?; } { @@ -186,14 +199,12 @@ pub fn compile(config: &CompilerConfig) -> Result<(), std::io::Error> { let mut lines = if !mod_rs.exists() { Set::new() } else { - BufReader::new(File::open(&mod_rs)?) - .lines().collect::, Error>>()? + io::BufReader::new(File::open(&mod_rs)?) + .lines().collect::, _>>()? }; lines.insert(format!("pub mod {};", &module_name)); - let mut f = File::create(mod_rs)?; - for line in lines { - write!(f, "{}\n", line)?; - } + let contents = lines.into_iter().collect::>().join("\n"); + write_if_changed(&mod_rs, contents.as_bytes())?; } } Ok(())