mirror of
https://seed.radicle.dev/rad:zwTxygwuz5LDGBq255RA2CbNGrz8.git
synced 2026-10-18 19:30:29 +08:00
feat: when writing HTML report pages, write temp file and rename
This avoids creating an empty file if the disk is full.
This commit is contained in:
+4
-4
@@ -9,7 +9,6 @@
|
||||
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
fs::write,
|
||||
path::{Path, PathBuf},
|
||||
sync::mpsc::RecvTimeoutError,
|
||||
};
|
||||
@@ -33,7 +32,7 @@ use crate::{
|
||||
msg::{RunId, RunResult},
|
||||
notif::NotificationReceiver,
|
||||
run::{Run, RunState, Whence},
|
||||
util::{parse_timestamp, rfc822_timestamp},
|
||||
util::{parse_timestamp, rfc822_timestamp, safely_overwrite},
|
||||
worker::Worker,
|
||||
};
|
||||
|
||||
@@ -53,7 +52,7 @@ pub enum PageError {
|
||||
Timeformat(#[from] time::error::Format),
|
||||
|
||||
#[error("failed to write status page to {0}")]
|
||||
Write(PathBuf, #[source] std::io::Error),
|
||||
Write(PathBuf, #[source] crate::util::UtilError),
|
||||
|
||||
#[error("no node alias has been set for builder")]
|
||||
NoAlias,
|
||||
@@ -972,7 +971,8 @@ impl StatusPage {
|
||||
}
|
||||
|
||||
fn write_file(filename: &Path, text: &str) -> Result<(), PageError> {
|
||||
write(filename, text).map_err(|e| PageError::Write(filename.into(), e))?;
|
||||
safely_overwrite(filename, text.as_bytes())
|
||||
.map_err(|err| PageError::Write(filename.into(), err))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
+28
@@ -1,8 +1,10 @@
|
||||
use std::{
|
||||
io::Write,
|
||||
path::{Path, PathBuf},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use tempfile::NamedTempFile;
|
||||
use time::{
|
||||
format_description::{well_known::Rfc2822, FormatItem},
|
||||
macros::format_description,
|
||||
@@ -138,6 +140,20 @@ pub fn read_file_as_objectid(filename: &Path) -> Result<ObjectId, UtilError> {
|
||||
ObjectId::from_str(s.trim()).map_err(|err| UtilError::ReadObjectId(filename.into(), err))
|
||||
}
|
||||
|
||||
pub fn safely_overwrite<P: AsRef<Path>>(filename: P, data: &[u8]) -> Result<(), UtilError> {
|
||||
let filename = filename.as_ref();
|
||||
let dirname = filename
|
||||
.parent()
|
||||
.ok_or(UtilError::NoParent(filename.to_path_buf()))?;
|
||||
let mut tmp = NamedTempFile::new_in(dirname)
|
||||
.map_err(|err| UtilError::CreateTemp(dirname.to_path_buf(), err))?;
|
||||
tmp.write_all(data)
|
||||
.map_err(|err| UtilError::WriteTemp(dirname.to_path_buf(), err))?;
|
||||
tmp.persist(filename)
|
||||
.map_err(|err| UtilError::RenameTemp(filename.to_path_buf(), err))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum UtilError {
|
||||
#[error("failed to look up node profile")]
|
||||
@@ -178,4 +194,16 @@ pub enum UtilError {
|
||||
|
||||
#[error("failed to read object id from {0}")]
|
||||
ReadObjectId(PathBuf, #[source] radicle::cob::object::ParseObjectId),
|
||||
|
||||
#[error("file name to write to doesn't have a parent directory: {0}")]
|
||||
NoParent(PathBuf),
|
||||
|
||||
#[error("failed to create temporary file in directory {0}")]
|
||||
CreateTemp(PathBuf, #[source] std::io::Error),
|
||||
|
||||
#[error("failed to write to temporary file in {0}")]
|
||||
WriteTemp(PathBuf, #[source] std::io::Error),
|
||||
|
||||
#[error("failed to rename temporary file to {0}")]
|
||||
RenameTemp(PathBuf, #[source] tempfile::PersistError),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user