Download files to *.partial before renaming to final location

This commit is contained in:
Caelan Sayler
2024-11-02 13:45:16 +00:00
committed by Caelan
parent c07f9842f0
commit 36e87c0e7d
2 changed files with 45 additions and 38 deletions

View File

@@ -23,7 +23,7 @@ pub fn default_log_location(context: LocationContext) -> PathBuf {
if let Ok(locator) = auto_locate_app_manifest(context) {
return locator.get_root_dir().join("Velopack.log");
}
warn!("Could not auto-locate app manifest, writing log to current directory.");
// If we can't locate the current app, we write to the current directory.
@@ -149,7 +149,7 @@ impl VelopackLocator {
pub fn get_temp_dir_root(&self) -> PathBuf {
self.paths.PackagesDir.join("VelopackTemp")
}
/// Get the name of a new temporary directory inside get_temp_dir_root() with a random 16-character suffix.
pub fn get_temp_dir_rand16(&self) -> PathBuf {
self.get_temp_dir_root().join("tmp_".to_string() + &util::random_string(16))
@@ -199,7 +199,7 @@ impl VelopackLocator {
pub fn get_current_bin_dir_as_string(&self) -> String {
Self::path_as_string(&self.paths.CurrentBinaryDir)
}
/// Returns a clone of the current app's manifest.
pub fn get_manifest(&self) -> Manifest {
self.manifest.clone()
@@ -221,7 +221,7 @@ impl VelopackLocator {
let ver = &self.manifest.version;
format!("{}.{}.{}", ver.major, ver.minor, ver.patch)
}
/// Returns the current app package channel.
pub fn get_manifest_channel(&self) -> String {
self.manifest.channel.clone()
@@ -391,7 +391,7 @@ pub fn auto_locate_app_manifest(context: LocationContext) -> Result<VelopackLoca
match context {
LocationContext::FromSpecifiedRootDir(dir) => search_path = dir.join("dummy"),
LocationContext::FromSpecifiedAppExecutable(exe) => search_path = exe,
_ => {},
_ => {}
}
let search_string = search_path.to_string_lossy();
@@ -431,9 +431,9 @@ pub fn auto_locate_app_manifest(context: LocationContext) -> Result<VelopackLoca
match context {
LocationContext::FromSpecifiedRootDir(dir) => search_path = dir.join("dummy"),
LocationContext::FromSpecifiedAppExecutable(exe) => search_path = exe,
_ => {},
_ => {}
}
let search_string = search_path.to_string_lossy();
let idx = search_string.rfind(".app/");
if idx.is_none() {
@@ -469,14 +469,14 @@ pub fn auto_locate_app_manifest(context: LocationContext) -> Result<VelopackLoca
CurrentBinaryDir: contents_dir,
IsPortable: true,
};
config_to_locator(&config)
}
fn read_current_manifest(nuspec_path: &PathBuf) -> Result<Manifest, Error> {
if nuspec_path.exists() {
if let Ok(nuspec) = util::retry_io(|| std::fs::read_to_string(&nuspec_path)) {
return Ok(bundle::read_manifest_from_string(&nuspec)?);
if let Ok(nuspec) = util::retry_io(|| std::fs::read_to_string(nuspec_path)) {
return bundle::read_manifest_from_string(&nuspec);
}
}
Err(Error::MissingNuspec)
@@ -489,16 +489,15 @@ pub fn find_latest_full_package(packages_dir: &PathBuf) -> Option<(PathBuf, Mani
info!("Attempting to auto-detect package in: {}", packages_dir);
let mut package: Option<(PathBuf, Manifest)> = None;
if let Ok(paths) = glob::glob(format!("{}/*.nupkg", packages_dir).as_str()) {
for path in paths {
if let Ok(path) = path {
trace!("Checking package: '{}'", path.to_string_lossy());
if let Ok(mut bun) = bundle::load_bundle_from_file(&path) {
if let Ok(mani) = bun.read_manifest() {
if package.is_none() || mani.version > package.clone().unwrap().1.version {
info!("Found {}: '{}'", mani.version, path.to_string_lossy());
package = Some((path, mani));
}
let search_glob = format!("{}/*.nupkg", packages_dir);
if let Ok(paths) = glob::glob(search_glob.as_str()) {
for path in paths.into_iter().flatten() {
trace!("Checking package: '{}'", path.to_string_lossy());
if let Ok(mut bun) = bundle::load_bundle_from_file(&path) {
if let Ok(mani) = bun.read_manifest() {
if package.is_none() || mani.version > package.clone()?.1.version {
info!("Found {}: '{}'", mani.version, path.to_string_lossy());
package = Some((path, mani));
}
}
}

View File

@@ -299,36 +299,44 @@ impl UpdateManager {
let packages_dir = &self.locator.get_packages_dir();
fs::create_dir_all(packages_dir)?;
let target_file = packages_dir.join(name);
let final_target_file = packages_dir.join(name);
let partial_file = packages_dir.join(format!("{}.partial", name));
if target_file.exists() {
info!("Package already exists on disk, skipping download: '{}'", target_file.to_string_lossy());
if final_target_file.exists() {
info!("Package already exists on disk, skipping download: '{}'", final_target_file.to_string_lossy());
return Ok(());
}
let g = format!("{}/*.nupkg", packages_dir.to_string_lossy());
info!("Searching for packages to clean in: '{}'", g);
let old_nupkg_pattern = format!("{}/*.nupkg", packages_dir.to_string_lossy());
let old_partial_pattern = format!("{}/*.partial", packages_dir.to_string_lossy());
let mut to_delete = Vec::new();
match glob::glob(&g) {
Ok(paths) => {
for path in paths {
if let Ok(path) = path {
to_delete.push(path.clone());
debug!("Will delete: '{}'", path.to_string_lossy());
fn find_files_to_delete(pattern: &str, to_delete: &mut Vec<String>) {
info!("Searching for packages to clean: '{}'", pattern);
match glob::glob(pattern) {
Ok(paths) => {
for path in paths.into_iter().flatten() {
to_delete.push(path.to_string_lossy().to_string());
}
}
}
Err(e) => {
error!("Error while searching for packages to clean: {}", e);
Err(e) => {
error!("Error while searching for packages to clean: {}", e);
}
}
}
find_files_to_delete(&old_nupkg_pattern, &mut to_delete);
find_files_to_delete(&old_partial_pattern, &mut to_delete);
self.source.download_release_entry(&update.TargetFullRelease, &target_file.to_string_lossy(), progress)?;
info!("Successfully placed file: '{}'", target_file.to_string_lossy());
self.source.download_release_entry(&update.TargetFullRelease, &partial_file.to_string_lossy(), progress)?;
info!("Successfully placed file: '{}'", partial_file.to_string_lossy());
info!("Renaming partial file to final target: '{}'", final_target_file.to_string_lossy());
fs::rename(&partial_file, &final_target_file)?;
// extract new Update.exe on Windows only
#[cfg(target_os = "windows")]
match crate::bundle::load_bundle_from_file(&target_file) {
match crate::bundle::load_bundle_from_file(&final_target_file) {
Ok(bundle) => {
info!("Bundle loaded successfully.");
let update_exe_path = self.locator.get_update_path();
@@ -342,7 +350,7 @@ impl UpdateManager {
}
for path in to_delete {
info!("Cleaning up old package: '{}'", path.to_string_lossy());
info!("Deleting up old package: '{}'", path);
let _ = fs::remove_file(&path);
}