Host: fixes from the review, with regression tests
- one live instance per actor: check after the lock; dropping an instance kills it - state snapshots keep target/ and .git/; only source copies skip them - one shutdown deadline; output during shutdown is still routed - deliveries route stdout meanwhile; a stuck stdin kills the instance (no partial lines) and the sender gets undeliverable; control requests are not blocked by a stuck delivery - Host::stop aborts running broker and cargo requests first - compile a version before installing it; roll back if it does not start - unique archive names; a failed archive keeps the actor manageable - commit on close: truncate without create; directory renames - candidates see SAUSAGE_VERSION and the existing state of a new actor - the host publishes PROTOCOL.md at /actor/broker/public/
This commit is contained in:
+20
-4
@@ -227,8 +227,15 @@ pub fn write_atomic(path: &Path, bytes: &[u8]) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Copy a directory tree. Skips `target/` folders and uncommitted files.
|
||||
/// Folders that a copy of a source folder leaves out.
|
||||
const BUILD_DIRS: &[&str] = &["target", ".git"];
|
||||
|
||||
/// Copy a directory tree, except uncommitted files.
|
||||
pub fn copy_tree(from: &Path, to: &Path) -> Result<()> {
|
||||
copy_filtered(from, to, &[])
|
||||
}
|
||||
|
||||
fn copy_filtered(from: &Path, to: &Path, skip: &[&str]) -> Result<()> {
|
||||
std::fs::create_dir_all(to)?;
|
||||
for entry in std::fs::read_dir(from).with_context(|| format!("read {}", from.display()))? {
|
||||
let entry = entry?;
|
||||
@@ -239,8 +246,8 @@ pub fn copy_tree(from: &Path, to: &Path) -> Result<()> {
|
||||
}
|
||||
let dst = to.join(&*name);
|
||||
let ty = entry.file_type()?;
|
||||
if ty.is_dir() && name != "target" && name != ".git" {
|
||||
copy_tree(&entry.path(), &dst)?;
|
||||
if ty.is_dir() && !skip.contains(&&*name) {
|
||||
copy_filtered(&entry.path(), &dst, skip)?;
|
||||
} else if ty.is_file() {
|
||||
std::fs::copy(entry.path(), &dst)?;
|
||||
}
|
||||
@@ -251,6 +258,15 @@ pub fn copy_tree(from: &Path, to: &Path) -> Result<()> {
|
||||
/// Replace the directory `dst` with a copy of `src` (an empty folder if `src`
|
||||
/// does not exist): copy to a sibling, then swap with two renames.
|
||||
pub fn replace_tree(src: &Path, dst: &Path) -> Result<()> {
|
||||
replace_filtered(src, dst, &[])
|
||||
}
|
||||
|
||||
/// Like `replace_tree`, for a source folder: leaves out `target/` and `.git/`.
|
||||
pub fn replace_source(src: &Path, dst: &Path) -> Result<()> {
|
||||
replace_filtered(src, dst, BUILD_DIRS)
|
||||
}
|
||||
|
||||
fn replace_filtered(src: &Path, dst: &Path, skip: &[&str]) -> Result<()> {
|
||||
let parent = dst.parent().context("path has no parent")?;
|
||||
let name = dst.file_name().and_then(|n| n.to_str()).unwrap_or("dir");
|
||||
let fresh = parent.join(format!("{TMP_PREFIX}new-{name}"));
|
||||
@@ -258,7 +274,7 @@ pub fn replace_tree(src: &Path, dst: &Path) -> Result<()> {
|
||||
let _ = std::fs::remove_dir_all(&fresh);
|
||||
let _ = std::fs::remove_dir_all(&old);
|
||||
if src.is_dir() {
|
||||
copy_tree(src, &fresh)?;
|
||||
copy_filtered(src, &fresh, skip)?;
|
||||
} else {
|
||||
std::fs::create_dir_all(&fresh)?;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user