Vastly simplify windows update for now

This commit is contained in:
Caelan Sayler
2024-12-01 22:18:54 +00:00
committed by Caelan
parent ddc10a2599
commit 36e80fc8fb
5 changed files with 88 additions and 106 deletions

View File

@@ -105,7 +105,7 @@ webview2-com = "0.33"
libloading.workspace = true
strsim.workspace = true
same-file.workspace = true
filelocksmith.workspace = true
# filelocksmith.workspace = true
[dev-dependencies]
tempfile.workspace = true

View File

@@ -1,46 +1,46 @@
use crate::{
dialogs,
shared::{self},
windows::locksmith,
// windows::locksmith,
windows::splash,
};
use anyhow::{bail, Result};
use anyhow::{bail, Context, Result};
use std::sync::mpsc;
use std::{
fs,
path::{Path, PathBuf},
};
use velopack::{bundle::load_bundle_from_file, locator::VelopackLocator, constants};
use velopack::{bundle::load_bundle_from_file, constants, locator::VelopackLocator};
fn ropycopy<P1: AsRef<Path>, P2: AsRef<Path>>(source: &P1, dest: &P2) -> Result<()> {
let source = source.as_ref();
let dest = dest.as_ref();
// fn ropycopy<P1: AsRef<Path>, P2: AsRef<Path>>(source: &P1, dest: &P2) -> Result<()> {
// let source = source.as_ref();
// let dest = dest.as_ref();
// robocopy C:\source\something.new C:\destination\something /MIR /ZB /W:5 /R:5 /MT:8 /LOG:C:\logs\copy_log.txt
let cmd = std::process::Command::new("robocopy")
.arg(source)
.arg(dest)
.arg("/MIR")
.arg("/IS")
.arg("/W:1")
.arg("/R:5")
.arg("/MT:2")
.output()?;
// // robocopy C:\source\something.new C:\destination\something /MIR /ZB /W:5 /R:5 /MT:8 /LOG:C:\logs\copy_log.txt
// let cmd = std::process::Command::new("robocopy")
// .arg(source)
// .arg(dest)
// .arg("/MIR")
// .arg("/IS")
// .arg("/W:1")
// .arg("/R:5")
// .arg("/MT:2")
// .output()?;
let stdout = String::from_utf8_lossy(&cmd.stdout);
let stderr = String::from_utf8_lossy(&cmd.stderr);
// let stdout = String::from_utf8_lossy(&cmd.stdout);
// let stderr = String::from_utf8_lossy(&cmd.stderr);
let exit_code = cmd.status.code().unwrap_or(-9999);
if (0..7).contains(&exit_code) {
info!("{stdout}");
info!("Robocopy completed successfully.");
} else {
error!("{stdout}");
error!("{stderr}");
bail!("Robocopy failed with code: {:?}", exit_code);
}
Ok(())
}
// let exit_code = cmd.status.code().unwrap_or(-9999);
// if (0..7).contains(&exit_code) {
// info!("{stdout}");
// info!("Robocopy completed successfully.");
// } else {
// error!("{stdout}");
// error!("{stderr}");
// bail!("Robocopy failed with code: {:?}", exit_code);
// }
// Ok(())
// }
pub fn apply_package_impl(old_locator: &VelopackLocator, package: &PathBuf, run_hooks: bool) -> Result<VelopackLocator> {
let mut bundle = load_bundle_from_file(package)?;
@@ -87,49 +87,55 @@ pub fn apply_package_impl(old_locator: &VelopackLocator, package: &PathBuf, run_
// third, we try _REALLY HARD_ to stop the package
let _ = shared::force_stop_package(root_path);
if winsafe::IsWindows10OrGreater() == Ok(true) && !locksmith::close_processes_locking_dir(&old_locator) {
bail!("Failed to close processes locking directory / user cancelled.");
}
// if winsafe::IsWindows10OrGreater() == Ok(true) && !locksmith::close_processes_locking_dir(&old_locator) {
// bail!("Failed to close processes locking directory / user cancelled.");
// }
// fourth, we make as backup of the current dir to temp_path_old
info!("Backing up current dir to {}", &temp_path_old.to_string_lossy());
let mut requires_robocopy = false;
if let Err(e) = fs::rename(&current_dir, &temp_path_old) {
warn!("Failed to rename current_dir to temp_path_old ({}). Retrying with robocopy...", e);
ropycopy(&current_dir, &temp_path_old)?;
requires_robocopy = true;
}
shared::retry_io_ex(|| fs::rename(&current_dir, &temp_path_old), 1000, 10)
.context("Unable to start the update, because one or more running processes prevented it.")?;
// let mut requires_robocopy = false;
// if let Err(e) = fs::rename(&current_dir, &temp_path_old) {
// warn!("Failed to rename current_dir to temp_path_old ({}). Retrying with robocopy...", e);
// ropycopy(&current_dir, &temp_path_old)?;
// requires_robocopy = true;
// }
// fifth, we try to replace the current dir with temp_path_new
// if this fails we will yolo a rollback...
info!("Replacing current dir with {}", &temp_path_new.to_string_lossy());
shared::retry_io_ex(|| fs::rename(&temp_path_new, &current_dir), 1000, 30)
.context("Unable to complete the update, and the app was left in a broken state. You may need to re-install")?;
if !requires_robocopy {
// if we didn't need robocopy for the backup, we don't need it for the deploy hopefully
if let Err(e1) = fs::rename(&temp_path_new, &current_dir) {
warn!("Failed to rename temp_path_new to current_dir ({}). Retrying with robocopy...", e1);
requires_robocopy = true;
}
}
// if !requires_robocopy {
// // if we didn't need robocopy for the backup, we don't need it for the deploy hopefully
// if let Err(e1) = fs::rename(&temp_path_new, &current_dir) {
// warn!("Failed to rename temp_path_new to current_dir ({}). Retrying with robocopy...", e1);
// requires_robocopy = true;
// }
// }
if requires_robocopy {
if let Err(e2) = ropycopy(&temp_path_new, &current_dir) {
error!("Failed to robocopy temp_path_new to current_dir ({}). Will attempt a rollback...", e2);
let _ = ropycopy(&temp_path_old, &current_dir);
let _ = tx.send(splash::MSG_CLOSE);
// if requires_robocopy {
// if let Err(e2) = ropycopy(&temp_path_new, &current_dir) {
// error!("Failed to robocopy temp_path_new to current_dir ({}). Will attempt a rollback...", e2);
// let _ = ropycopy(&temp_path_old, &current_dir);
// let _ = tx.send(splash::MSG_CLOSE);
info!("Showing error dialog...");
let title = format!("{} Update", &new_locator.get_manifest_title());
let header = "Failed to update";
let body =
format!("Failed to update {} to version {}. Please check the logs for more details.",
&new_locator.get_manifest_title(),
&new_locator.get_manifest_version_full_string());
dialogs::show_error(&title, Some(header), &body);
// info!("Showing error dialog...");
// let title = format!("{} Update", &new_locator.get_manifest_title());
// let header = "Failed to update";
// let body = format!(
// "Failed to update {} to version {}. Please check the logs for more details.",
// &new_locator.get_manifest_title(),
// &new_locator.get_manifest_version_full_string()
// );
// dialogs::show_error(&title, Some(header), &body);
bail!("Fatal error performing update.");
}
}
// bail!("Fatal error performing update.");
// }
// }
// from this point on, we're past the point of no return and should not bail
// sixth, we write the uninstall entry
@@ -146,7 +152,7 @@ pub fn apply_package_impl(old_locator: &VelopackLocator, package: &PathBuf, run_
} else {
info!("Skipping uninstall entry for portable app.");
}
// seventh, we run the post-install hooks
if run_hooks {
crate::windows::run_hook(&new_locator, constants::HOOK_CLI_UPDATED, 15);

View File

@@ -29,39 +29,25 @@ where
F: Fn() -> Result<T, E>,
E: std::fmt::Debug,
{
let res = op();
if res.is_ok() {
return Ok(res.unwrap());
retry_io_ex(op, 1000, 4)
}
pub fn retry_io_ex<F, T, E>(op: F, delay_ms: i32, count: i32) -> Result<T, E>
where
F: Fn() -> Result<T, E>,
E: std::fmt::Debug,
{
let mut res = op();
for _ in 0..count {
if res.is_ok() {
return Ok(res.unwrap());
}
warn!("Retrying operation in {}ms... (error was: {:?})", delay_ms, res.err());
thread::sleep(Duration::from_millis(delay_ms as u64));
res = op();
}
warn!("Retrying operation in 1000ms... (error was: {:?})", res.err());
thread::sleep(Duration::from_millis(1000));
let res = op();
if res.is_ok() {
return Ok(res.unwrap());
}
warn!("Retrying operation in 1000ms... (error was: {:?})", res.err());
thread::sleep(Duration::from_millis(1000));
let res = op();
if res.is_ok() {
return Ok(res.unwrap());
}
warn!("Retrying operation in 1000ms... (error was: {:?})", res.err());
thread::sleep(Duration::from_millis(1000));
let res = op();
if res.is_ok() {
return Ok(res.unwrap());
}
warn!("Last retry in 1000ms... (error was: {:?})", res.err());
thread::sleep(Duration::from_millis(1000));
op()
res
}
pub fn random_string(len: usize) -> String {

View File

@@ -1,4 +1,4 @@
pub mod locksmith;
// pub mod locksmith;
pub mod mitigate;
pub mod prerequisite;
pub mod runtimes;