Implement rollback-safe tree mutations

This commit is contained in:
Hermes Agent
2026-08-09 22:58:37 +00:00
parent 834df46818
commit 410007c012
6 changed files with 1368 additions and 0 deletions

View File

@@ -631,6 +631,50 @@ impl Repository {
Ok(removed)
}
pub(crate) fn ensure_directory(
&self,
path: &DirectoryPath,
) -> Result<Vec<DirectoryPath>, RepositoryError> {
let (_, created) = self.create_directory_path(path)?;
Ok(created.into_iter().map(DirectoryPath).collect())
}
pub(crate) fn remove_empty_directory(
&self,
directory: &DirectoryPath,
) -> Result<bool, RepositoryError> {
let Some(parent) = directory.parent() else {
return Ok(false);
};
let parent_handle = self.open_directory(parent.as_path())?;
let name = directory
.as_path()
.file_name()
.expect("non-root directory has a file name");
reject_entry_directory_collision(&parent_handle, name, parent.as_path())?;
let Some(metadata) = child_metadata(&parent_handle, name, directory.as_path())? else {
return Ok(false);
};
require_directory(metadata, directory.as_path())?;
match parent_handle.remove_dir(name) {
Ok(()) => {
sync_directory(&parent_handle, parent.as_path()).map_err(|_| {
RepositoryError::DurabilityUncertain {
path: directory.as_path().to_owned(),
}
})?;
Ok(true)
}
Err(error) if error.kind() == io::ErrorKind::DirectoryNotEmpty => Ok(false),
Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false),
Err(error) => Err(io_error(
"remove empty repository directory",
directory.as_path(),
error,
)),
}
}
fn open_entry_parent(&self, path: &EntryPath) -> Result<(Dir, OsString), RepositoryError> {
let mut directory = self
.root