fix(release): 修复发布一致性与并发边界
bat-rust / Build and test Rust (push) Canceled after 0s
bat-rust / Build and test Go API (push) Canceled after 0s

This commit is contained in:
2026-09-12 16:35:55 +08:00
parent 8d57a63697
commit 30d1cd77e8
20 changed files with 1100 additions and 102 deletions
+60 -1
View File
@@ -3224,7 +3224,15 @@ fn copy_tree_no_symlink(
continue;
}
}
if let Err(_error) = fs::hard_link(&source_path, &destination_path) {
if is_release_local_mutable_state(&source_path) {
fs::copy(&source_path, &destination_path).map_err(|copy_error| {
format!(
"复制官方 release mutable state 失败 {} -> {}{copy_error}",
source_path.display(),
destination_path.display()
)
})?;
} else if let Err(_error) = fs::hard_link(&source_path, &destination_path) {
fs::copy(&source_path, &destination_path).map_err(|copy_error| {
format!(
"复制官方资源到 staging 失败 {} -> {}{copy_error}",
@@ -3243,6 +3251,17 @@ fn copy_tree_no_symlink(
Ok(())
}
fn is_release_local_mutable_state(path: &Path) -> bool {
matches!(
path.file_name().and_then(|name| name.to_str()),
Some(
"translation-tasks.sqlite"
| "translation-tasks.sqlite-wal"
| "translation-tasks.sqlite-shm"
)
)
}
#[cfg(unix)]
fn switch_current_symlink(
root: &Path,
@@ -4415,6 +4434,46 @@ fn process_exists(_pid: u32) -> bool {
mod tests {
use super::*;
#[cfg(unix)]
#[test]
fn staging_copy_does_not_hard_link_mutable_translation_state() {
use std::os::unix::fs::MetadataExt;
let temp = tempfile::TempDir::new().unwrap();
let source = temp.path().join("old");
let destination = temp.path().join("new");
fs::create_dir_all(&source).unwrap();
fs::write(source.join("translation-tasks.sqlite"), b"old-db").unwrap();
fs::write(source.join("translation-tasks.sqlite-wal"), b"old-wal").unwrap();
fs::write(source.join("immutable.bundle"), b"payload").unwrap();
copy_tree_no_symlink(&source, &destination, false).unwrap();
let old_db_inode = fs::metadata(source.join("translation-tasks.sqlite"))
.unwrap()
.ino();
let new_db_inode = fs::metadata(destination.join("translation-tasks.sqlite"))
.unwrap()
.ino();
assert_ne!(old_db_inode, new_db_inode);
fs::write(destination.join("translation-tasks.sqlite"), b"new-db").unwrap();
fs::write(destination.join("translation-tasks.sqlite-wal"), b"new-wal").unwrap();
assert_eq!(
fs::read(source.join("translation-tasks.sqlite")).unwrap(),
b"old-db"
);
assert_eq!(
fs::read(source.join("translation-tasks.sqlite-wal")).unwrap(),
b"old-wal"
);
assert_eq!(
fs::metadata(source.join("immutable.bundle")).unwrap().ino(),
fs::metadata(destination.join("immutable.bundle"))
.unwrap()
.ino()
);
}
#[test]
fn missing_app_version_carries_input_error_code() {
// 未启用 auto-discover 且未传 app-version:配置校验失败应携带