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 22:22:11 +08:00
parent f2c20367a6
commit 786b739f99
17 changed files with 835 additions and 124 deletions
+32 -11
View File
@@ -13,6 +13,7 @@ use crate::official_changes::{
write_official_resource_change_handoff, OfficialResourceChangeHandoffReport,
OfficialResourceChangeSummary,
};
use crate::official_download::OFFICIAL_CAS_REUSE_REFERENCES_FILE;
use crate::official_game_main_config::{
resolve_game_main_config_source, OfficialGameMainConfigSelectedSource,
OfficialGameMainConfigSourceKind,
@@ -1128,7 +1129,20 @@ impl OfficialPublishLayout {
if !path_exists_no_follow(active_root)? {
return Ok(());
}
copy_tree_no_symlink(active_root, staging_root, active_root == self.root)
copy_tree_no_symlink(active_root, staging_root, active_root == self.root)?;
if active_root != self.root {
let cas_references = staging_root.join(OFFICIAL_CAS_REUSE_REFERENCES_FILE);
if path_exists_no_follow(&cas_references)? {
ensure_safe_file_target(staging_root, &cas_references, "staging CAS 引用清单")?;
fs::remove_file(&cas_references).map_err(|error| {
format!(
"清理 active release CAS ownership 清单失败 {}{error}",
cas_references.display()
)
})?;
}
}
Ok(())
}
fn legacy_manifest_exists(&self) -> Result<bool, String> {
@@ -4309,21 +4323,22 @@ fn required_platform(endpoint: &YostarJpResourceEndpoint) -> anyhow::Result<Patc
}
#[derive(Debug)]
struct OfficialUpdateLock {
pub(crate) struct OfficialUpdateLock {
path: PathBuf,
}
impl OfficialUpdateLock {
fn acquire(config: &OfficialUpdateConfig) -> anyhow::Result<Self> {
validate_output_root(&config.output_root).map_err(anyhow::Error::msg)?;
ensure_safe_directory_path(&config.output_root, "资源输出目录")
.map_err(anyhow::Error::msg)?;
fs::create_dir_all(&config.output_root)?;
ensure_safe_directory_path(&config.output_root, "资源输出目录")
.map_err(anyhow::Error::msg)?;
let path = config.lock_path();
ensure_safe_file_target(&config.output_root, &path, "官方同步锁")
.map_err(anyhow::Error::msg)?;
Self::acquire_output_root(&config.output_root)
}
pub(crate) fn acquire_output_root(output_root: &Path) -> anyhow::Result<Self> {
validate_output_root(output_root).map_err(anyhow::Error::msg)?;
ensure_safe_directory_path(output_root, "资源输出目录").map_err(anyhow::Error::msg)?;
fs::create_dir_all(output_root)?;
ensure_safe_directory_path(output_root, "资源输出目录").map_err(anyhow::Error::msg)?;
let path = output_root.join(".official-sync.lock");
ensure_safe_file_target(output_root, &path, "官方同步锁").map_err(anyhow::Error::msg)?;
for attempt in 0..=1 {
let mut options = OpenOptions::new();
options.write(true).create_new(true);
@@ -4361,6 +4376,12 @@ impl OfficialUpdateLock {
}
}
pub(crate) fn acquire_official_output_lock(
output_root: &Path,
) -> anyhow::Result<OfficialUpdateLock> {
OfficialUpdateLock::acquire_output_root(output_root)
}
impl Drop for OfficialUpdateLock {
fn drop(&mut self) {
let expected = std::process::id().to_string();