use std::path::{Path, PathBuf};
use crate::error::SaveError;
use crate::view::SaveResult;
use super::Workspace;
impl Workspace {
pub fn save(&mut self) -> Result<SaveResult, SaveError> {
let new_root_toml = crate::toml_writer::render_apimock_toml(&self.config);
let mut rule_set_renders: Vec<(PathBuf, String)> = Vec::new();
for rule_set in self.config.service.rule_sets.iter() {
let path = PathBuf::from(rule_set.file_path.as_str());
let text = crate::toml_writer::render_rule_set_toml(rule_set);
rule_set_renders.push((path, text));
}
let mut to_write: Vec<(PathBuf, String)> = Vec::new();
let baseline_root = self.baseline_files.get(&self.root_path);
if baseline_root.map(String::as_str) != Some(new_root_toml.as_str()) {
to_write.push((self.root_path.clone(), new_root_toml.clone()));
}
for (path, text) in rule_set_renders.iter() {
let baseline = self.baseline_files.get(path);
if baseline.map(String::as_str) != Some(text.as_str()) {
to_write.push((path.clone(), text.clone()));
}
}
let mut written: Vec<PathBuf> = Vec::with_capacity(to_write.len());
for (path, text) in &to_write {
atomic_write(path, text)?;
written.push(path.clone());
}
let diff_summary = self.compute_diff_summary();
for (path, text) in to_write.into_iter() {
self.baseline_files.insert(path, text);
}
let listener_changed = written.contains(&self.root_path);
let requires_reload = listener_changed || !written.is_empty();
Ok(SaveResult {
changed_files: written,
diff_summary,
requires_reload,
})
}
pub fn has_unsaved_changes(&self) -> bool {
let root_text = crate::toml_writer::render_apimock_toml(&self.config);
if self
.baseline_files
.get(&self.root_path)
.map(|s| s.as_str())
!= Some(root_text.as_str())
{
return true;
}
for rule_set in self.config.service.rule_sets.iter() {
let path = PathBuf::from(rule_set.file_path.as_str());
let text = crate::toml_writer::render_rule_set_toml(rule_set);
if self
.baseline_files
.get(&path)
.map(|s| s.as_str())
!= Some(text.as_str())
{
return true;
}
}
false
}
}
fn atomic_write(path: &Path, text: &str) -> Result<(), SaveError> {
let parent = path
.parent()
.filter(|p| !p.as_os_str().is_empty())
.map(Path::to_path_buf)
.unwrap_or_else(|| PathBuf::from("."));
let mut tmp =
tempfile::NamedTempFile::new_in(&parent).map_err(|e| SaveError::Write {
path: path.to_path_buf(),
source: e,
})?;
use std::io::Write;
tmp.write_all(text.as_bytes())
.map_err(|e| SaveError::Write {
path: path.to_path_buf(),
source: e,
})?;
tmp.flush().map_err(|e| SaveError::Write {
path: path.to_path_buf(),
source: e,
})?;
tmp.persist(path).map_err(|persist_err| SaveError::Write {
path: path.to_path_buf(),
source: persist_err.error,
})?;
Ok(())
}