use super::*;
pub(super) fn sha256_file(path: &Path) -> Result<String> {
let bytes = fs::read(path).with_context(|| format!("读取文件失败: {}", path.display()))?;
let mut hasher = Sha256::new();
hasher.update(&bytes);
Ok(hasher
.finalize()
.iter()
.map(|byte| format!("{byte:02x}"))
.collect())
}
pub(super) fn build_activate_record(
existing_record: Option<&InstallRecord>,
metadata: &ReleaseMetadata,
operation: &str,
) -> InstallRecord {
let now = now_millis();
let promote_current = existing_record
.and_then(|record| record.current_artifact_id.as_ref())
.is_some_and(|artifact_id| artifact_id != &metadata.artifact_id);
let promoted_record = existing_record.filter(|_| promote_current);
InstallRecord {
install_state: "installed".to_string(),
current_artifact_id: Some(metadata.artifact_id.clone()),
current_version: Some(metadata.version.clone()),
current_build_hash: Some(metadata.build_hash.clone()),
current_sha256: Some(metadata.sha256.clone()),
current_protocol_version: Some(metadata.protocol_version),
current_release_path: Some(metadata.release_root.clone()),
previous_artifact_id: promoted_record
.and_then(|record| record.current_artifact_id.clone())
.or_else(|| existing_record.and_then(|record| record.previous_artifact_id.clone())),
previous_version: promoted_record
.and_then(|record| record.current_version.clone())
.or_else(|| existing_record.and_then(|record| record.previous_version.clone())),
previous_build_hash: promoted_record
.and_then(|record| record.current_build_hash.clone())
.or_else(|| existing_record.and_then(|record| record.previous_build_hash.clone())),
previous_sha256: promoted_record
.and_then(|record| record.current_sha256.clone())
.or_else(|| existing_record.and_then(|record| record.previous_sha256.clone())),
previous_protocol_version: promoted_record
.and_then(|record| record.current_protocol_version)
.or_else(|| existing_record.and_then(|record| record.previous_protocol_version)),
previous_release_path: promoted_record
.and_then(|record| record.current_release_path.clone())
.or_else(|| existing_record.and_then(|record| record.previous_release_path.clone())),
last_operation: Some(operation.to_string()),
last_operation_status: Some("success".to_string()),
last_operation_at_ms: now,
installed_at_ms: existing_record
.map(|record| record.installed_at_ms)
.filter(|value| *value > 0)
.unwrap_or(now),
updated_at_ms: now,
}
}
pub(super) fn build_rollback_record(
existing_record: &InstallRecord,
metadata: &ReleaseMetadata,
) -> InstallRecord {
let now = now_millis();
InstallRecord {
install_state: "installed".to_string(),
current_artifact_id: Some(metadata.artifact_id.clone()),
current_version: Some(metadata.version.clone()),
current_build_hash: Some(metadata.build_hash.clone()),
current_sha256: Some(metadata.sha256.clone()),
current_protocol_version: Some(metadata.protocol_version),
current_release_path: Some(metadata.release_root.clone()),
previous_artifact_id: existing_record.current_artifact_id.clone(),
previous_version: existing_record.current_version.clone(),
previous_build_hash: existing_record.current_build_hash.clone(),
previous_sha256: existing_record.current_sha256.clone(),
previous_protocol_version: existing_record.current_protocol_version,
previous_release_path: existing_record.current_release_path.clone(),
last_operation: Some("rollback".to_string()),
last_operation_status: Some("success".to_string()),
last_operation_at_ms: now,
installed_at_ms: existing_record.installed_at_ms,
updated_at_ms: now,
}
}
fn now_millis() -> i64 {
use std::time::{SystemTime, UNIX_EPOCH};
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as i64
}