mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-09-18 08:14:55 +08:00
feat(bat): 完善工作流调度与 dashboard RPC
补全资源拉取、解析、翻译、重打包和本地化发布命令,支持单次、限定次数与周期调度。移除 TUI 计划并通过 schedule.* RPC 暴露给 bat-api dashboard。 Closes #43
This commit is contained in:
@@ -42,6 +42,13 @@ pub struct LocalizedPatchConfig {
|
||||
pub localized_output_root: PathBuf,
|
||||
/// Version identifier shared with the official release.
|
||||
pub release_id: String,
|
||||
/// Optional distinct localized release ID. When omitted, `release_id` is
|
||||
/// used for backward-compatible publication paths.
|
||||
pub localized_release_id: Option<String>,
|
||||
/// Allow publishing a new localized release even when the source release
|
||||
/// already has a localized current release. The caller should normally
|
||||
/// provide a distinct localized release ID.
|
||||
pub force: bool,
|
||||
/// Patch operations to apply.
|
||||
pub patches: Vec<LocalizedTextAssetPatch>,
|
||||
}
|
||||
@@ -58,9 +65,29 @@ impl LocalizedPatchConfig {
|
||||
official_release_root: official_release_root.into(),
|
||||
localized_output_root: localized_output_root.into(),
|
||||
release_id: release_id.into(),
|
||||
localized_release_id: None,
|
||||
force: false,
|
||||
patches,
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets a distinct localized release ID.
|
||||
pub fn with_localized_release_id(mut self, release_id: impl Into<String>) -> Self {
|
||||
self.localized_release_id = Some(release_id.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Enables or disables forced publication.
|
||||
pub fn with_force(mut self, force: bool) -> Self {
|
||||
self.force = force;
|
||||
self
|
||||
}
|
||||
|
||||
fn published_release_id(&self) -> &str {
|
||||
self.localized_release_id
|
||||
.as_deref()
|
||||
.unwrap_or(&self.release_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// Persisted localized release state.
|
||||
@@ -187,7 +214,7 @@ impl LocalizedPatchManifest {
|
||||
}
|
||||
|
||||
/// Result of a successful localized release publication.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
|
||||
pub struct LocalizedPatchReport {
|
||||
/// Published version directory.
|
||||
pub version_path: PathBuf,
|
||||
@@ -217,14 +244,15 @@ impl LocalizedPatchService {
|
||||
|
||||
/// Copies the official release, applies patches in staging and publishes it.
|
||||
pub fn publish(&self, config: &LocalizedPatchConfig) -> anyhow::Result<LocalizedPatchReport> {
|
||||
let published_release_id = config.published_release_id().to_string();
|
||||
let staging = config
|
||||
.localized_output_root
|
||||
.join(LOCALIZED_STAGING_DIR)
|
||||
.join(&config.release_id);
|
||||
.join(&published_release_id);
|
||||
let version_path = config
|
||||
.localized_output_root
|
||||
.join(LOCALIZED_VERSIONS_DIR)
|
||||
.join(&config.release_id);
|
||||
.join(&published_release_id);
|
||||
let current_path = config.localized_output_root.join(LOCALIZED_CURRENT_LINK);
|
||||
let previous_current_target = current_symlink_target(¤t_path).ok().flatten();
|
||||
let version_existed_before = version_path.exists();
|
||||
@@ -257,11 +285,11 @@ impl LocalizedPatchService {
|
||||
let staging = config
|
||||
.localized_output_root
|
||||
.join(LOCALIZED_STAGING_DIR)
|
||||
.join(&config.release_id);
|
||||
.join(config.published_release_id());
|
||||
let version_path = config
|
||||
.localized_output_root
|
||||
.join(LOCALIZED_VERSIONS_DIR)
|
||||
.join(&config.release_id);
|
||||
.join(config.published_release_id());
|
||||
let current_path = config.localized_output_root.join(LOCALIZED_CURRENT_LINK);
|
||||
let state_path = config
|
||||
.localized_output_root
|
||||
@@ -269,10 +297,12 @@ impl LocalizedPatchService {
|
||||
let patch_manifest_path = version_path.join(LOCALIZED_PATCH_MANIFEST_FILE);
|
||||
|
||||
if version_path.exists() {
|
||||
return Err(anyhow::anyhow!(
|
||||
"localized release already exists: {}",
|
||||
version_path.display()
|
||||
));
|
||||
let message = if config.force {
|
||||
"localized release target already exists; forced publication requires a distinct localized release id"
|
||||
} else {
|
||||
"localized release already exists"
|
||||
};
|
||||
return Err(anyhow::anyhow!("{message}: {}", version_path.display()));
|
||||
}
|
||||
remove_owned_staging(&staging)?;
|
||||
fs::create_dir_all(&staging)?;
|
||||
@@ -313,7 +343,7 @@ impl LocalizedPatchService {
|
||||
let manifest = LocalizedPatchManifest {
|
||||
manifest_version: LOCALIZED_PATCH_MANIFEST_VERSION,
|
||||
official_release_id: config.release_id.clone(),
|
||||
localized_release_id: config.release_id.clone(),
|
||||
localized_release_id: config.published_release_id().to_string(),
|
||||
generated_unix_seconds: unix_seconds_now(),
|
||||
file_count: changed_files.len(),
|
||||
text_asset_operation_count: changed_files
|
||||
@@ -339,13 +369,13 @@ impl LocalizedPatchService {
|
||||
switch_current_symlink(
|
||||
&config.localized_output_root,
|
||||
¤t_path,
|
||||
&config.release_id,
|
||||
config.published_release_id(),
|
||||
)?;
|
||||
|
||||
let state = LocalizedVersionState {
|
||||
state_version: 1,
|
||||
official_release_id: config.release_id.clone(),
|
||||
current_release_id: Some(config.release_id.clone()),
|
||||
current_release_id: Some(config.published_release_id().to_string()),
|
||||
status: "localized".to_string(),
|
||||
updated_unix_seconds: unix_seconds_now(),
|
||||
};
|
||||
@@ -623,13 +653,18 @@ fn validate_config(config: &LocalizedPatchConfig) -> Result<(), String> {
|
||||
localized.display()
|
||||
));
|
||||
}
|
||||
if config.release_id.is_empty()
|
||||
|| config.release_id.contains('/')
|
||||
|| config.release_id.contains('\\')
|
||||
|| config.release_id == "."
|
||||
|| config.release_id == ".."
|
||||
{
|
||||
return Err(format!("非法汉化 release id:{}", config.release_id));
|
||||
for (label, release_id) in [
|
||||
("官方", config.release_id.as_str()),
|
||||
("汉化", config.published_release_id()),
|
||||
] {
|
||||
if release_id.is_empty()
|
||||
|| release_id.contains('/')
|
||||
|| release_id.contains('\\')
|
||||
|| release_id == "."
|
||||
|| release_id == ".."
|
||||
{
|
||||
return Err(format!("非法{label} release id:{release_id}"));
|
||||
}
|
||||
}
|
||||
ensure_safe_directory_path(&config.official_release_root, "官方 release")?;
|
||||
ensure_safe_directory_path(&config.localized_output_root, "汉化输出目录")?;
|
||||
|
||||
Reference in New Issue
Block a user