feat(dtmm): Improve deployment after game update
Usually the backup created by the first deployment is used for a clean file to make further deployments from, but when the game is updated, that is reversed, as now the original file is newer than the backup. In such a case, we first copy the new file to our backup before continuing with the deployment. The current implementation is not fool-proof (e.g. it'll do weird stuff if users mess with the files manually) and doesn't cover everything. But it should be enough for the regular use case. Closes #90.
This commit is contained in:
parent
a2814bfd20
commit
f50a97ff16
1 changed files with 58 additions and 31 deletions
|
@ -525,6 +525,7 @@ where
|
||||||
))]
|
))]
|
||||||
pub(crate) async fn deploy_mods(state: ActionState) -> Result<()> {
|
pub(crate) async fn deploy_mods(state: ActionState) -> Result<()> {
|
||||||
let state = Arc::new(state);
|
let state = Arc::new(state);
|
||||||
|
let bundle_dir = state.game_dir.join("bundle");
|
||||||
|
|
||||||
let (_, game_info, deployment_info) = tokio::try_join!(
|
let (_, game_info, deployment_info) = tokio::try_join!(
|
||||||
async {
|
async {
|
||||||
|
@ -565,16 +566,46 @@ pub(crate) async fn deploy_mods(state: ActionState) -> Result<()> {
|
||||||
.map(|i| game_info.last_updated > i.timestamp)
|
.map(|i| game_info.last_updated > i.timestamp)
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
eyre::bail!("Game was updated since last mod deployment. Please reset first.");
|
tracing::warn!(
|
||||||
|
"Game was updated since last mod deployment. \
|
||||||
|
Attempting to reconcile game files."
|
||||||
|
);
|
||||||
|
|
||||||
|
tokio::try_join!(
|
||||||
|
async {
|
||||||
|
let path = bundle_dir.join(BUNDLE_DATABASE_NAME);
|
||||||
|
let backup_path = path.with_extension("data.bak");
|
||||||
|
|
||||||
|
fs::copy(&path, &backup_path)
|
||||||
|
.await
|
||||||
|
.wrap_err("Failed to re-create backup for bundle database.")
|
||||||
|
},
|
||||||
|
async {
|
||||||
|
let path = bundle_dir.join(BOOT_BUNDLE_NAME);
|
||||||
|
let backup_path = path.with_extension("bak");
|
||||||
|
|
||||||
|
fs::copy(&path, &backup_path)
|
||||||
|
.await
|
||||||
|
.wrap_err("Failed to re-create backup for boot bundle")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.with_suggestion(|| {
|
||||||
|
"Reset the game using 'Reset Game', then verify game files.".to_string()
|
||||||
|
})?;
|
||||||
|
|
||||||
|
tracing::info!(
|
||||||
|
"Successfully re-created game file backups. \
|
||||||
|
Continuing mod deployment."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
check_mod_order(&state)?;
|
check_mod_order(&state)?;
|
||||||
|
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
"Deploying {} mods to {}",
|
"Deploying {} mods to '{}'.",
|
||||||
state.mods.iter().filter(|i| i.enabled).count(),
|
state.mods.iter().filter(|i| i.enabled).count(),
|
||||||
state.game_dir.join("bundle").display()
|
bundle_dir.display()
|
||||||
);
|
);
|
||||||
|
|
||||||
tracing::info!("Build mod bundles");
|
tracing::info!("Build mod bundles");
|
||||||
|
@ -589,36 +620,32 @@ pub(crate) async fn deploy_mods(state: ActionState) -> Result<()> {
|
||||||
bundles.append(&mut more_bundles);
|
bundles.append(&mut more_bundles);
|
||||||
|
|
||||||
if let Some(info) = &deployment_info {
|
if let Some(info) = &deployment_info {
|
||||||
let bundle_dir = Arc::new(state.game_dir.join("bundle"));
|
let bundle_dir = Arc::new(bundle_dir);
|
||||||
let tasks = info
|
let tasks = info.bundles.iter().cloned().filter_map(|file_name| {
|
||||||
.bundles
|
let contains = bundles.iter().any(|b2| {
|
||||||
.iter()
|
let name = b2.name().to_murmur64().to_string();
|
||||||
.cloned()
|
file_name == name
|
||||||
.map(|v| (v, bundle_dir.clone()))
|
|
||||||
.filter_map(|(file_name, bundle_dir)| {
|
|
||||||
let contains = bundles.iter().any(|b2| {
|
|
||||||
let name = b2.name().to_murmur64().to_string();
|
|
||||||
file_name == name
|
|
||||||
});
|
|
||||||
|
|
||||||
if !contains {
|
|
||||||
let task = async move {
|
|
||||||
let path = bundle_dir.join(&file_name);
|
|
||||||
|
|
||||||
tracing::debug!("Removing unused bundle '{}'", file_name);
|
|
||||||
|
|
||||||
if let Err(err) = fs::remove_file(&path).await.wrap_err_with(|| {
|
|
||||||
format!("Failed to remove unused bundle '{}'", path.display())
|
|
||||||
}) {
|
|
||||||
tracing::error!("{:?}", err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Some(task)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if !contains {
|
||||||
|
let bundle_dir = bundle_dir.clone();
|
||||||
|
let task = async move {
|
||||||
|
let path = bundle_dir.join(&file_name);
|
||||||
|
|
||||||
|
tracing::debug!("Removing unused bundle '{}'", file_name);
|
||||||
|
|
||||||
|
if let Err(err) = fs::remove_file(&path).await.wrap_err_with(|| {
|
||||||
|
format!("Failed to remove unused bundle '{}'", path.display())
|
||||||
|
}) {
|
||||||
|
tracing::error!("{:?}", err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(task)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
futures::future::join_all(tasks).await;
|
futures::future::join_all(tasks).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue