Fix linux compiler errors

This commit is contained in:
Caelan Sayler
2025-06-16 22:18:49 +01:00
parent e7f15eef88
commit 48f6afeb9e
11 changed files with 71 additions and 61 deletions

1
Cargo.lock generated
View File

@@ -2365,6 +2365,7 @@ dependencies = [
"ureq",
"url",
"uuid",
"wait-timeout",
"waitpid-any",
"windows",
"xml",

View File

@@ -10,7 +10,7 @@ pub fn apply_package_impl<'a>(locator: &VelopackLocator, pkg: &PathBuf, _runhook
let mut bundle = bundle::load_bundle_from_file(pkg)?;
let manifest = bundle.read_manifest()?;
let temp_path = locator.get_temp_dir_rand16().to_string_lossy().to_string();
let root_path_string = locator.get_root_dir_as_string();
let root_path = locator.get_root_dir().to_string_lossy().to_string();
let script_path = format!("/var/tmp/velopack_update_{}.sh", manifest.id);
let new_locator = locator.clone_self_with_new_manifest(&manifest);
@@ -21,22 +21,22 @@ pub fn apply_package_impl<'a>(locator: &VelopackLocator, pkg: &PathBuf, _runhook
info!("Chmod as executable");
std::fs::set_permissions(&temp_path, fs::Permissions::from_mode(0o755))?;
info!("Moving temp file to target: {}", &root_path_string);
info!("Moving temp file to target: {}", &root_path);
// we use mv instead of fs::rename / fs::copy because rename fails cross-device
// and copy fails if the process is running (presumably because rust opens the file for writing)
// while mv works in both cases.
let mv_args = vec!["-f", &temp_path, &root_path_string];
let mv_args = vec!["-f", &temp_path, &root_path];
let mv_output = Command::new("mv").args(mv_args).output()?;
if mv_output.status.success() {
info!("AppImage moved successfully to: {}", &root_path_string);
info!("AppImage moved successfully to: {}", &root_path);
return Ok(());
}
// if the operation failed, let's try again elevated with pkexec
error!("An error occurred ({:?}), will attempt to elevate permissions and try again...", mv_output);
dialogs::ask_user_to_elevate(&manifest.title, &manifest.version.to_string())?;
let script = format!("#!/bin/sh\nmv -f '{}' '{}'", temp_path, &root_path_string);
let script = format!("#!/bin/sh\nmv -f '{}' '{}'", temp_path, &root_path);
info!("Writing script for elevation: \n{}", script);
fs::write(&script_path, script)?;
std::fs::set_permissions(&script_path, <std::fs::Permissions as std::os::unix::fs::PermissionsExt>::from_mode(0o755))?;
@@ -44,7 +44,7 @@ pub fn apply_package_impl<'a>(locator: &VelopackLocator, pkg: &PathBuf, _runhook
info!("Attempting to elevate: pkexec {:?}", args);
let elev_output = Command::new("pkexec").args(args).output()?;
if elev_output.status.success() {
info!("AppImage moved (elevated) to {}", &root_path_string);
info!("AppImage moved (elevated) to {}", &root_path);
return Ok(());
} else {
bail!("pkexec failed with status: {:?}", elev_output);

View File

@@ -1,5 +1,5 @@
use anyhow::{anyhow, bail, Result};
use std::{process::Command as Process, time::Duration};
use std::{ffi::OsString, process::Command as Process, time::Duration};
use velopack::locator::VelopackLocator;
pub fn wait_for_pid_to_exit(pid: u32, ms_to_wait: u32) -> Result<()> {
@@ -23,7 +23,7 @@ pub fn wait_for_parent_to_exit(ms_to_wait: u32) -> Result<()> {
Ok(())
}
pub fn start_package(locator: &VelopackLocator, exe_args: Option<Vec<&str>>, set_env: Option<&str>) -> Result<()> {
pub fn start_package(locator: &VelopackLocator, exe_args: Option<Vec<OsString>>, set_env: Option<&str>) -> Result<()> {
let root_dir = locator.get_root_dir();
let mut cmd = Process::new(root_dir);
if let Some(args) = exe_args {
@@ -34,4 +34,4 @@ pub fn start_package(locator: &VelopackLocator, exe_args: Option<Vec<&str>>, set
}
cmd.spawn().map_err(|z| anyhow!("Failed to start_package ({}).", z))?;
Ok(())
}
}

View File

@@ -7,13 +7,13 @@ use std::{fs, path::Path, path::PathBuf};
use tempfile::tempdir;
use velopack_bins::*;
use velopack_bins::windows::known_path;
use velopack::bundle::load_bundle_from_file;
use velopack::locator::{auto_locate_app_manifest, LocationContext};
#[cfg(target_os = "windows")]
#[test]
pub fn test_install_apply_uninstall() {
use velopack_bins::windows::known_path;
dialogs::set_silent(true);

View File

@@ -77,4 +77,5 @@ windows = { workspace = true, features = [
[target.'cfg(unix)'.dependencies]
libc.workspace = true
wait-timeout.workspace = true
waitpid-any.workspace = true

View File

@@ -133,7 +133,9 @@ pub mod locator;
/// Sources are abstractions for custom update sources (eg. url, local file, github releases, etc).
pub mod sources;
#[cfg(target_os = "windows")]
maybe_pub!(wide_strings);
maybe_pub!(download, bundle, constants, lockfile, logging, misc);
maybe_pub_os!(process, "process_win.rs", "process_unix.rs");

View File

@@ -407,7 +407,7 @@ pub fn auto_locate_app_manifest(context: LocationContext) -> Result<VelopackLoca
let metadata_path = contents_dir.join("sq.version");
if !update_exe_path.exists() {
return Err(Error::MissingUpdateExe);
return Err(Error::NotInstalled("Update.exe does not exist in the expected path".to_owned()));
}
let appimage_path = match std::env::var("APPIMAGE") {

View File

@@ -56,7 +56,7 @@ pub fn calculate_sha1_sha256<P: AsRef<Path>>(file: P) -> Result<(String, String)
if bytes_read == 0 {
break;
}
sha256.update(&buffer[..bytes_read]);
sha1.update(&buffer[..bytes_read]);
}
@@ -67,6 +67,7 @@ pub fn calculate_sha1_sha256<P: AsRef<Path>>(file: P) -> Result<(String, String)
Ok((sha1_hash, sha256_hash))
}
#[cfg(target_os = "windows")]
pub fn is_directory_writable<P1: AsRef<Path>>(path: P1) -> bool {
use std::os::windows::fs::OpenOptionsExt;
let path = path.as_ref();

View File

@@ -1,44 +1,20 @@
use std::{
collections::HashMap,
ffi::{OsStr, OsString},
ffi::OsString,
io::{Error as IoError, ErrorKind as IoErrorKind, Result as IoResult},
os::{raw::c_void, windows::ffi::OsStrExt},
path::Path,
process::{Child, Command},
time::Duration,
};
use crate::process;
pub fn is_current_process_elevated() -> bool {
false
}
fn string_to_u16<P: AsRef<str>>(input: P) -> Vec<u16> {
let input = input.as_ref();
input.encode_utf16().chain(Some(0)).collect::<Vec<u16>>()
}
pub fn run_process_as_admin(
exe_path: String,
args: Vec<String>,
work_dir: Option<String>,
show_window: bool,
) -> IoResult<SafeProcessHandle> {
// let mut cmd = Command::new(exe_path).args(args);
// if let Some(dir) = work_dir {
// cmd.current_dir(dir);
// }
}
pub fn run_process(
exe_path: String,
args: Vec<String>,
work_dir: Option<String>,
pub fn run_process<P1: AsRef<Path>, P2: AsRef<Path>>(
exe_path: P1,
args: Vec<OsString>,
work_dir: Option<P2>,
_show_window: bool,
set_env: Option<HashMap<String, String>>,
) -> IoResult<Child> {
let exe_path = exe_path.as_ref();
let mut cmd = Command::new(exe_path);
cmd.args(args);
if let Some(dir) = work_dir {
@@ -52,33 +28,60 @@ pub fn run_process(
cmd.spawn()
}
pub fn wait_for_process_exit_with_timeout(process: Child, dur: Duration) -> IoResult<Option<u32>> {
let mut status = process.wait_timeout(dur)?;
if status.is_none() {
return Err(IoError::new(IoErrorKind::TimedOut, "Process timed out"));
}
Ok(status.unwrap().code())
#[derive(Debug)]
pub enum WaitResult {
WaitTimeout,
ExitCode(u32),
NoWaitRequired,
}
pub fn wait_for_pid_to_exit(pid: u32, dur: Duration) -> IoResult<()> {
info!("Waiting {}ms for process ({}) to exit.", ms_to_wait, pid);
let mut handle = waitpid_any::WaitHandle::open(pid.try_into()?)?;
let result = handle.wait_timeout(Duration::from_millis(ms_to_wait as u64))?;
if result.is_some() {
info!("Parent process exited.");
Ok(())
impl WaitResult {
pub fn code(&self) -> Option<u32> {
match self {
WaitResult::WaitTimeout => None,
WaitResult::ExitCode(c) => Some(*c),
WaitResult::NoWaitRequired => None,
}
}
}
pub fn wait_for_process_exit_with_timeout(process: &mut Child, dur: Option<Duration>) -> IoResult<WaitResult> {
if let Some(dur) = dur {
let status = wait_timeout::ChildExt::wait_timeout(process, dur)?;
match status {
Some(status) => Ok(WaitResult::ExitCode(status.code().unwrap_or(0) as u32)),
None => Ok(WaitResult::WaitTimeout),
}
} else {
bail!("Parent process timed out.");
let code = process.wait()?;
Ok(WaitResult::ExitCode(code.code().unwrap_or(0) as u32))
}
}
pub fn wait_for_parent_to_exit(dur: Duration) -> IoResult<()> {
pub fn wait_for_pid_to_exit(pid: u32, dur: Option<Duration>) -> IoResult<WaitResult> {
info!("Waiting {:?} for process ({}) to exit.", dur, pid);
let mut handle = waitpid_any::WaitHandle::open(pid as i32)?;
if let Some(dur) = dur {
let result = handle.wait_timeout(dur)?;
if result.is_some() {
info!("Parent process exited.");
Ok(WaitResult::ExitCode(0))
} else {
Err(IoError::new(IoErrorKind::TimedOut, "Parent process timed out."))
}
} else {
handle.wait()?;
Ok(WaitResult::ExitCode(0))
}
}
pub fn wait_for_parent_to_exit(dur: Option<Duration>) -> IoResult<WaitResult> {
let id = std::os::unix::process::parent_id();
info!("Attempting to wait for parent process ({}) to exit.", id);
if id > 1 {
wait_for_pid_to_exit(id, ms_to_wait)?;
return Ok(wait_for_pid_to_exit(id, dur)?);
}
Ok(())
Ok(WaitResult::NoWaitRequired)
}
pub fn kill_process(mut process: Child) -> IoResult<()> {

View File

@@ -17,7 +17,7 @@ rust-version.workspace = true
path = "src/lib.rs"
crate-type = ["cdylib"]
[dependencies]
[target.'cfg(windows)'.dependencies]
anyhow.workspace = true
velopack.workspace = true
velopack_bins.workspace = true

View File

@@ -1,3 +1,5 @@
#![cfg(windows)]
mod msi;
use msi::*;