moved the enforcing of some invariants to be done on save

This commit is contained in:
aaron-jack-manning
2022-09-10 16:14:05 +10:00
parent 5bb20e6166
commit 5361ea4630
4 changed files with 37 additions and 40 deletions

View File

@@ -85,10 +85,6 @@ pub fn edit_raw(id : Id, vault_folder : path::PathBuf, editor : &str, state : &m
if edited_task.data.id != task.data.id {
Err(error::Error::Generic(String::from("You cannot change the ID of a task in a direct edit")))
}
// Enforce non numeric name invariant.
else if edited_task.data.name.chars().all(|c| c.is_numeric()) {
Err(error::Error::Generic(String::from("Name must not be purely numeric")))
}
else {
// Dependencies were edited so the graph needs to be updated.
if edited_task.data.dependencies != task.data.dependencies {

View File

@@ -119,8 +119,8 @@ fn program() -> Result<(), error::Error> {
match command {
Command::New { name, info, tag, dependency, priority, due } => {
let task = tasks::Task::new(name, info, tag, dependency, priority, due, vault_folder, &mut state)?;
println!("Created task {} (ID: {})", format::task(&task.data.name), format::id(task.data.id));
let id = tasks::Task::new(name.clone(), info, tag, dependency, priority, due, vault_folder, &mut state)?;
println!("Created task {} (ID: {})", format::task(&name), format::id(id));
},
Command::Delete { id_or_name } => {
let id = state.data.index.lookup(&id_or_name)?;

View File

@@ -16,7 +16,8 @@ pub type Id = u64;
pub struct Task {
pub path : path::PathBuf,
file : fs::File,
// This should only be None for a new task, in which case it should be written from the path.
file : Option<fs::File>,
pub data : InternalTask,
}
@@ -223,12 +224,7 @@ impl TimeEntry {
impl Task {
/// Creates a new task from the input data.
pub fn new(name : String, info : Option<String>, tags : Vec<String>, dependencies : Vec<Id>, priority : Option<Priority>, due : Option<chrono::NaiveDateTime>, vault_folder : &path::Path, state : &mut state::State) -> Result<Self, error::Error> {
// Exclude numeric names in the interest of allowing commands that take in ID or name.
if name.chars().all(|c| c.is_numeric()) {
return Err(error::Error::Generic(String::from("Name must not be purely numeric")));
};
pub fn new(name : String, info : Option<String>, tags : Vec<String>, dependencies : Vec<Id>, priority : Option<Priority>, due : Option<chrono::NaiveDateTime>, vault_folder : &path::Path, state : &mut state::State) -> Result<Id, error::Error> {
// Update the state with the new next Id.
let id = state.data.next_id;
@@ -236,11 +232,6 @@ impl Task {
let path = vault_folder.join("tasks").join(&format!("{}.toml", id));
let mut file = fs::File::options()
.write(true)
.create(true)
.open(&path)?;
// Adding to dependency graph appropriately.
state.data.deps.insert_node(id);
if !dependencies.is_empty() {
@@ -267,19 +258,17 @@ impl Task {
completed : None,
};
let file_contents = toml::to_string(&data)?;
file.set_len(0)?;
file.seek(io::SeekFrom::Start(0))?;
file.write_all(file_contents.as_bytes())?;
state.data.index.insert(data.name.clone(), id);
Ok(Task {
let task = Task {
path,
file,
file : None,
data,
})
};
task.save()?;
Ok(id)
}
/// Loads a task directly from its path, for use with the temporary edit file.
@@ -300,7 +289,7 @@ impl Task {
Ok(Self {
path,
file,
file : Some(file),
data,
})
}
@@ -360,17 +349,36 @@ impl Task {
/// Saves the in memory task data to the corresponding file.
pub fn save(self) -> Result<(), error::Error> {
// Enforce any additional invariants which need to be checked for both edits and now tasks
// at the point of save.
{
// Exclude numeric names in the interest of allowing commands that take in ID or name.
if self.data.name.chars().all(|c| c.is_numeric()) {
return Err(error::Error::Generic(String::from("Name must not be purely numeric")));
};
}
let Self {
path : _,
mut file,
path,
file,
data,
} = self;
let file_contents = toml::to_string(&data)?;
file.set_len(0)?;
file.seek(io::SeekFrom::Start(0))?;
file.write_all(file_contents.as_bytes())?;
// Check if the file exists, if not it is a new task and the file must be written from the
// path.
match file {
Some(mut file) => {
file.set_len(0)?;
file.seek(io::SeekFrom::Start(0))?;
file.write_all(file_contents.as_bytes())?;
},
None => {
fs::write(path, file_contents.as_bytes())?;
}
}
Ok(())
}