|
|
|
@ -840,15 +840,9 @@ impl Update {
|
|
|
|
|
/// MacOS
|
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
|
impl Update {
|
|
|
|
|
/// ### Expected structure:
|
|
|
|
|
/// ├── [AppName]_[version]_x64.app.tar.gz # GZ generated by tauri-bundler
|
|
|
|
|
/// │ └──[AppName].app # Main application
|
|
|
|
|
/// │ └── Contents # Application contents...
|
|
|
|
|
/// │ └── ...
|
|
|
|
|
/// └── ...
|
|
|
|
|
fn install_inner(&self, bytes: &[u8]) -> Result<()> {
|
|
|
|
|
use flate2::read::GzDecoder;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let cursor = Cursor::new(bytes);
|
|
|
|
|
let mut extracted_files: Vec<PathBuf> = Vec::new();
|
|
|
|
|
|
|
|
|
@ -856,45 +850,40 @@ impl Update {
|
|
|
|
|
let tmp_backup_dir = tempfile::Builder::new()
|
|
|
|
|
.prefix("tauri_current_app")
|
|
|
|
|
.tempdir()?;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let tmp_extract_dir = tempfile::Builder::new()
|
|
|
|
|
.prefix("tauri_updated_app")
|
|
|
|
|
.tempdir()?
|
|
|
|
|
.into_path();
|
|
|
|
|
.tempdir()?;
|
|
|
|
|
|
|
|
|
|
let decoder = GzDecoder::new(cursor);
|
|
|
|
|
let mut archive = tar::Archive::new(decoder);
|
|
|
|
|
|
|
|
|
|
std::fs::create_dir(&tmp_extract_dir)?;
|
|
|
|
|
|
|
|
|
|
// Extract files to temporary directory
|
|
|
|
|
for entry in archive.entries()? {
|
|
|
|
|
let mut entry = entry?;
|
|
|
|
|
let collected_path: PathBuf = entry.path()?.iter().skip(1).collect();
|
|
|
|
|
let extraction_path = tmp_extract_dir.join(&collected_path);
|
|
|
|
|
let extraction_path = tmp_extract_dir.path().join(&collected_path);
|
|
|
|
|
|
|
|
|
|
// Ensure parent directories exist
|
|
|
|
|
if let Some(parent) = extraction_path.parent() {
|
|
|
|
|
std::fs::create_dir_all(parent)?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Err(err) = entry.unpack(&extraction_path) {
|
|
|
|
|
// Cleanup on error
|
|
|
|
|
for file in &extracted_files {
|
|
|
|
|
if file.is_dir() {
|
|
|
|
|
std::fs::remove_dir(file)?;
|
|
|
|
|
} else {
|
|
|
|
|
std::fs::remove_file(file)?;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
std::fs::remove_dir_all(&tmp_extract_dir).ok();
|
|
|
|
|
std::fs::remove_dir_all(tmp_extract_dir.path()).ok();
|
|
|
|
|
return Err(err.into());
|
|
|
|
|
}
|
|
|
|
|
extracted_files.push(extraction_path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Try to move the current app to backup
|
|
|
|
|
let move_result = std::fs::rename(&self.extract_path, tmp_backup_dir.path());
|
|
|
|
|
let move_result = std::fs::rename(&self.extract_path, tmp_backup_dir.path().join("current_app"));
|
|
|
|
|
let need_authorization = if let Err(err) = move_result {
|
|
|
|
|
if err.kind() == std::io::ErrorKind::PermissionDenied {
|
|
|
|
|
true
|
|
|
|
|
} else {
|
|
|
|
|
std::fs::remove_dir_all(&tmp_extract_dir).ok();
|
|
|
|
|
std::fs::remove_dir_all(tmp_extract_dir.path()).ok();
|
|
|
|
|
return Err(err.into());
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
@ -904,26 +893,29 @@ impl Update {
|
|
|
|
|
if need_authorization {
|
|
|
|
|
// Use AppleScript to perform moves with admin privileges
|
|
|
|
|
let script = format!(
|
|
|
|
|
"do shell script \"mv -f '{src}' '{backup}' && mv -f '{new}' '{src}'\" with administrator privileges",
|
|
|
|
|
"do shell script \"rm -rf '{src}' && mv -f '{new}' '{src}'\" with administrator privileges",
|
|
|
|
|
src = self.extract_path.display(),
|
|
|
|
|
backup = tmp_backup_dir.path().display(),
|
|
|
|
|
new = tmp_extract_dir.display()
|
|
|
|
|
new = tmp_extract_dir.path().display()
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut osascript = std::process::Command::new("osascript");
|
|
|
|
|
osascript.arg("-e").arg(script);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let status = osascript.status()?;
|
|
|
|
|
if !status.success() {
|
|
|
|
|
std::fs::remove_dir_all(&tmp_extract_dir).ok();
|
|
|
|
|
std::fs::remove_dir_all(tmp_extract_dir.path()).ok();
|
|
|
|
|
return Err(Error::Io(std::io::Error::new(
|
|
|
|
|
std::io::ErrorKind::PermissionDenied,
|
|
|
|
|
"Failed to move the new app into place",
|
|
|
|
|
)));
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Move the new app to the target path if we didn't need admin rights
|
|
|
|
|
std::fs::rename(&tmp_extract_dir, &self.extract_path)?;
|
|
|
|
|
// Remove existing directory if it exists
|
|
|
|
|
if self.extract_path.exists() {
|
|
|
|
|
std::fs::remove_dir_all(&self.extract_path)?;
|
|
|
|
|
}
|
|
|
|
|
// Move the new app to the target path
|
|
|
|
|
std::fs::rename(tmp_extract_dir.path(), &self.extract_path)?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let _ = std::process::Command::new("touch")
|
|
|
|
|