mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
Add ability to wait for a specific process (instead of the current one)
This commit is contained in:
@@ -179,7 +179,7 @@ private:
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
updateManager->WaitExitThenApplyUpdate(updateInfo.value());
|
updateManager->WaitExitThenApplyUpdates(updateInfo.value());
|
||||||
wxTheApp->ExitMainLoop();
|
wxTheApp->ExitMainLoop();
|
||||||
}
|
}
|
||||||
catch (...) { /* exception will print in log */ }
|
catch (...) { /* exception will print in log */ }
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|||||||
MessageBoxCentered(hWnd, L"Download an update first.", szTitle, MB_OK);
|
MessageBoxCentered(hWnd, L"Download an update first.", szTitle, MB_OK);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
manager->WaitExitThenApplyUpdate(updInfo.value());
|
manager->WaitExitThenApplyUpdates(updInfo.value());
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -294,13 +294,27 @@ bool vpkc_download_updates(vpkc_update_manager_t *p_manager,
|
|||||||
* You should then clean up any state and exit your app. The updater will apply updates and then
|
* You should then clean up any state and exit your app. The updater will apply updates and then
|
||||||
* optionally restart your app. The updater will only wait for 60 seconds before giving up.
|
* optionally restart your app. The updater will only wait for 60 seconds before giving up.
|
||||||
*/
|
*/
|
||||||
bool vpkc_wait_exit_then_apply_update(vpkc_update_manager_t *p_manager,
|
bool vpkc_wait_exit_then_apply_updates(vpkc_update_manager_t *p_manager,
|
||||||
struct vpkc_asset_t *p_asset,
|
struct vpkc_asset_t *p_asset,
|
||||||
bool b_silent,
|
bool b_silent,
|
||||||
bool b_restart,
|
bool b_restart,
|
||||||
char **p_restart_args,
|
char **p_restart_args,
|
||||||
size_t c_restart_args);
|
size_t c_restart_args);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will launch the Velopack updater and optionally wait for a program to exit gracefully.
|
||||||
|
* This method is unsafe because it does not necessarily wait for any / the correct process to exit
|
||||||
|
* before applying updates. The `vpkc_wait_exit_then_apply_updates` method is recommended for most use cases.
|
||||||
|
* If dw_wait_pid is 0, the updater will not wait for any process to exit before applying updates (Not Recommended).
|
||||||
|
*/
|
||||||
|
bool vpkc_unsafe_apply_updates(vpkc_update_manager_t *p_manager,
|
||||||
|
struct vpkc_asset_t *p_asset,
|
||||||
|
bool b_silent,
|
||||||
|
uint32_t dw_wait_pid,
|
||||||
|
bool b_restart,
|
||||||
|
char **p_restart_args,
|
||||||
|
size_t c_restart_args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Frees a vpkc_update_manager_t instance.
|
* Frees a vpkc_update_manager_t instance.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -583,10 +583,19 @@ public:
|
|||||||
* You should then clean up any state and exit your app. The updater will apply updates and then
|
* You should then clean up any state and exit your app. The updater will apply updates and then
|
||||||
* optionally restart your app. The updater will only wait for 60 seconds before giving up.
|
* optionally restart your app. The updater will only wait for 60 seconds before giving up.
|
||||||
*/
|
*/
|
||||||
void WaitExitThenApplyUpdate(const VelopackAsset& asset, bool silent = false, bool restart = true, std::vector<std::string> restartArgs = {}) {
|
void WaitExitThenApplyUpdates(const UpdateInfo& asset, bool silent = false, bool restart = true, std::vector<std::string> restartArgs = {}) {
|
||||||
|
this->WaitExitThenApplyUpdates(asset.TargetFullRelease, silent, restart, restartArgs);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This will launch the Velopack updater and tell it to wait for this program to exit gracefully.
|
||||||
|
* You should then clean up any state and exit your app. The updater will apply updates and then
|
||||||
|
* optionally restart your app. The updater will only wait for 60 seconds before giving up.
|
||||||
|
*/
|
||||||
|
void WaitExitThenApplyUpdates(const VelopackAsset& asset, bool silent = false, bool restart = true, std::vector<std::string> restartArgs = {}) {
|
||||||
char** pRestartArgs = allocate_cstring_array(restartArgs);
|
char** pRestartArgs = allocate_cstring_array(restartArgs);
|
||||||
vpkc_asset_t vpkc_asset = to_c(asset);
|
vpkc_asset_t vpkc_asset = to_c(asset);
|
||||||
bool result = vpkc_wait_exit_then_apply_update(m_pManager, &vpkc_asset, silent, restart, pRestartArgs, restartArgs.size());
|
bool result = vpkc_wait_exit_then_apply_updates(m_pManager, &vpkc_asset, silent, restart, pRestartArgs, restartArgs.size());
|
||||||
free_cstring_array(pRestartArgs, restartArgs.size());
|
free_cstring_array(pRestartArgs, restartArgs.size());
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
@@ -595,12 +604,20 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This will launch the Velopack updater and tell it to wait for this program to exit gracefully.
|
* This will launch the Velopack updater and optionally wait for a program to exit gracefully.
|
||||||
* You should then clean up any state and exit your app. The updater will apply updates and then
|
* This method is unsafe because it does not necessarily wait for any / the correct process to exit
|
||||||
* optionally restart your app. The updater will only wait for 60 seconds before giving up.
|
* before applying updates. The `WaitExitThenApplyUpdates` method is recommended for most use cases.
|
||||||
|
* If waitPid is 0, the updater will not wait for any process to exit before applying updates (Not Recommended).
|
||||||
*/
|
*/
|
||||||
void WaitExitThenApplyUpdate(const UpdateInfo& asset, bool silent = false, bool restart = true, std::vector<std::string> restartArgs = {}) {
|
void UnsafeApplyUpdates(const VelopackAsset& asset, bool silent, uint32_t waitPid, bool restart, std::vector<std::string> restartArgs) {
|
||||||
this->WaitExitThenApplyUpdate(asset.TargetFullRelease, silent, restart, restartArgs);
|
char** pRestartArgs = allocate_cstring_array(restartArgs);
|
||||||
|
vpkc_asset_t vpkc_asset = to_c(asset);
|
||||||
|
bool result = vpkc_unsafe_apply_updates(m_pManager, &vpkc_asset, silent, waitPid, restart, pRestartArgs, restartArgs.size());
|
||||||
|
free_cstring_array(pRestartArgs, restartArgs.size());
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
throw_last_error();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use anyhow::{anyhow, bail};
|
|||||||
use libc::{c_char, c_void, size_t};
|
use libc::{c_char, c_void, size_t};
|
||||||
use log_derive::{logfn, logfn_inputs};
|
use log_derive::{logfn, logfn_inputs};
|
||||||
use std::{ffi::CString, ptr};
|
use std::{ffi::CString, ptr};
|
||||||
use velopack::{sources, Error as VelopackError, UpdateCheck, UpdateManager, VelopackApp};
|
use velopack::{sources, ApplyWaitMode, Error as VelopackError, UpdateCheck, UpdateManager, VelopackApp};
|
||||||
|
|
||||||
/// Create a new FileSource update source for a given file path.
|
/// Create a new FileSource update source for a given file path.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@@ -295,7 +295,7 @@ pub extern "C" fn vpkc_download_updates(
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[logfn(Trace)]
|
#[logfn(Trace)]
|
||||||
#[logfn_inputs(Trace)]
|
#[logfn_inputs(Trace)]
|
||||||
pub extern "C" fn vpkc_wait_exit_then_apply_update(
|
pub extern "C" fn vpkc_wait_exit_then_apply_updates(
|
||||||
p_manager: *mut vpkc_update_manager_t,
|
p_manager: *mut vpkc_update_manager_t,
|
||||||
p_asset: *mut vpkc_asset_t,
|
p_asset: *mut vpkc_asset_t,
|
||||||
b_silent: bool,
|
b_silent: bool,
|
||||||
@@ -316,6 +316,36 @@ pub extern "C" fn vpkc_wait_exit_then_apply_update(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This will launch the Velopack updater and optionally wait for a program to exit gracefully.
|
||||||
|
/// This method is unsafe because it does not necessarily wait for any / the correct process to exit
|
||||||
|
/// before applying updates. The `vpkc_wait_exit_then_apply_updates` method is recommended for most use cases.
|
||||||
|
/// If dw_wait_pid is 0, the updater will not wait for any process to exit before applying updates (Not Recommended).
|
||||||
|
#[no_mangle]
|
||||||
|
#[logfn(Trace)]
|
||||||
|
#[logfn_inputs(Trace)]
|
||||||
|
pub extern "C" fn vpkc_unsafe_apply_updates(
|
||||||
|
p_manager: *mut vpkc_update_manager_t,
|
||||||
|
p_asset: *mut vpkc_asset_t,
|
||||||
|
b_silent: bool,
|
||||||
|
dw_wait_pid: u32,
|
||||||
|
b_restart: bool,
|
||||||
|
p_restart_args: *mut *mut c_char,
|
||||||
|
c_restart_args: size_t,
|
||||||
|
) -> bool {
|
||||||
|
wrap_error(|| {
|
||||||
|
let manager = match p_manager.to_opaque_ref() {
|
||||||
|
Some(manager) => manager,
|
||||||
|
None => bail!("pManager must not be null"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let asset = c_to_velopackasset_opt(p_asset).ok_or(anyhow!("pAsset must not be null"))?;
|
||||||
|
let restart_args = c_to_string_array_opt(p_restart_args, c_restart_args).unwrap_or_default();
|
||||||
|
let wait_mode = if dw_wait_pid > 0 { ApplyWaitMode::WaitPid(dw_wait_pid) } else { ApplyWaitMode::NoWait };
|
||||||
|
manager.unsafe_apply_updates(&asset, b_silent, wait_mode, b_restart, &restart_args)?;
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Frees a vpkc_update_manager_t instance.
|
/// Frees a vpkc_update_manager_t instance.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[logfn(Trace)]
|
#[logfn(Trace)]
|
||||||
|
|||||||
@@ -58,11 +58,11 @@ namespace Velopack
|
|||||||
/// Runs Update.exe in the current working directory with the 'start' command which will simply start the application.
|
/// Runs Update.exe in the current working directory with the 'start' command which will simply start the application.
|
||||||
/// Combined with the `waitForExit` parameter, this can be used to gracefully restart the application.
|
/// Combined with the `waitForExit` parameter, this can be used to gracefully restart the application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="waitForExit">If true, Update.exe will wait for the current process to exit before re-starting the application.</param>
|
/// <param name="waitPid">Optionally wait for the specified process to exit before continuing.</param>
|
||||||
/// <param name="locator">The locator to use to find the path to Update.exe and the packages directory.</param>
|
/// <param name="locator">The locator to use to find the path to Update.exe and the packages directory.</param>
|
||||||
/// <param name="startArgs">The arguments to pass to the application when it is restarted.</param>
|
/// <param name="startArgs">The arguments to pass to the application when it is restarted.</param>
|
||||||
/// <param name="logger">The logger to use for diagnostic messages</param>
|
/// <param name="logger">The logger to use for diagnostic messages</param>
|
||||||
public static void Start(IVelopackLocator? locator = null, bool waitForExit = true, string[]? startArgs = null, ILogger? logger = null)
|
public static void Start(IVelopackLocator? locator = null, uint waitPid = 0, string[]? startArgs = null, ILogger? logger = null)
|
||||||
{
|
{
|
||||||
logger ??= NullLogger.Instance;
|
logger ??= NullLogger.Instance;
|
||||||
locator ??= VelopackLocator.GetDefault(logger);
|
locator ??= VelopackLocator.GetDefault(logger);
|
||||||
@@ -70,9 +70,9 @@ namespace Velopack
|
|||||||
var args = new List<string>();
|
var args = new List<string>();
|
||||||
args.Add("start");
|
args.Add("start");
|
||||||
|
|
||||||
if (waitForExit) {
|
if (waitPid > 0) {
|
||||||
args.Add("--waitPid");
|
args.Add("--waitPid");
|
||||||
args.Add(Process.GetCurrentProcess().Id.ToString());
|
args.Add(waitPid.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (startArgs != null && startArgs.Length > 0) {
|
if (startArgs != null && startArgs.Length > 0) {
|
||||||
@@ -85,8 +85,8 @@ namespace Velopack
|
|||||||
StartUpdateExe(logger, locator, args);
|
StartUpdateExe(logger, locator, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Process ApplyImpl(IVelopackLocator? locator, VelopackAsset? toApply, bool silent, bool restart, string[]? restartArgs = null,
|
private static Process ApplyImpl(IVelopackLocator? locator, VelopackAsset? toApply, bool silent, uint waitPid, bool restart,
|
||||||
ILogger? logger = null)
|
string[]? restartArgs = null, ILogger? logger = null)
|
||||||
{
|
{
|
||||||
logger ??= NullLogger.Instance;
|
logger ??= NullLogger.Instance;
|
||||||
locator ??= VelopackLocator.GetDefault(logger);
|
locator ??= VelopackLocator.GetDefault(logger);
|
||||||
@@ -104,8 +104,10 @@ namespace Velopack
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (waitPid > 0) {
|
||||||
args.Add("--waitPid");
|
args.Add("--waitPid");
|
||||||
args.Add(Process.GetCurrentProcess().Id.ToString());
|
args.Add(waitPid.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
if (!restart) args.Add("--norestart"); // restarting is now the default Update.exe behavior
|
if (!restart) args.Add("--norestart"); // restarting is now the default Update.exe behavior
|
||||||
|
|
||||||
@@ -128,13 +130,14 @@ namespace Velopack
|
|||||||
/// <param name="restart">If true, restarts the application after updates are applied (or if they failed)</param>
|
/// <param name="restart">If true, restarts the application after updates are applied (or if they failed)</param>
|
||||||
/// <param name="locator">The locator to use to find the path to Update.exe and the packages directory.</param>
|
/// <param name="locator">The locator to use to find the path to Update.exe and the packages directory.</param>
|
||||||
/// <param name="toApply">The update package you wish to apply, can be left null.</param>
|
/// <param name="toApply">The update package you wish to apply, can be left null.</param>
|
||||||
|
/// <param name="waitPid">Optionally wait for the specified process to exit before continuing.</param>
|
||||||
/// <param name="restartArgs">The arguments to pass to the application when it is restarted.</param>
|
/// <param name="restartArgs">The arguments to pass to the application when it is restarted.</param>
|
||||||
/// <param name="logger">The logger to use for diagnostic messages</param>
|
/// <param name="logger">The logger to use for diagnostic messages</param>
|
||||||
/// <exception cref="Exception">Thrown if Update.exe does not initialize properly.</exception>
|
/// <exception cref="Exception">Thrown if Update.exe does not initialize properly.</exception>
|
||||||
public static void Apply(IVelopackLocator? locator, VelopackAsset? toApply, bool silent, bool restart, string[]? restartArgs = null,
|
public static void Apply(IVelopackLocator? locator, VelopackAsset? toApply, bool silent, uint waitPid, bool restart,
|
||||||
ILogger? logger = null)
|
string[]? restartArgs = null, ILogger? logger = null)
|
||||||
{
|
{
|
||||||
var process = ApplyImpl(locator, toApply, silent, restart, restartArgs, logger);
|
var process = ApplyImpl(locator, toApply, silent, waitPid, restart, restartArgs, logger);
|
||||||
Thread.Sleep(500);
|
Thread.Sleep(500);
|
||||||
|
|
||||||
if (process.HasExited) {
|
if (process.HasExited) {
|
||||||
@@ -143,10 +146,10 @@ namespace Velopack
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="Apply"/>
|
/// <inheritdoc cref="Apply"/>
|
||||||
public static async Task ApplyAsync(IVelopackLocator? locator, VelopackAsset? toApply, bool silent, bool restart, string[]? restartArgs = null,
|
public static async Task ApplyAsync(IVelopackLocator? locator, VelopackAsset? toApply, bool silent, uint waitPid, bool restart, string[]? restartArgs = null,
|
||||||
ILogger? logger = null)
|
ILogger? logger = null)
|
||||||
{
|
{
|
||||||
var process = ApplyImpl(locator, toApply, silent, restart, restartArgs, logger);
|
var process = ApplyImpl(locator, toApply, silent, waitPid, restart, restartArgs, logger);
|
||||||
await Task.Delay(500).ConfigureAwait(false);
|
await Task.Delay(500).ConfigureAwait(false);
|
||||||
|
|
||||||
if (process.HasExited) {
|
if (process.HasExited) {
|
||||||
|
|||||||
@@ -45,13 +45,13 @@ namespace Velopack
|
|||||||
/// <param name="restartArgs">The arguments to pass to the application when it is restarted.</param>
|
/// <param name="restartArgs">The arguments to pass to the application when it is restarted.</param>
|
||||||
public void WaitExitThenApplyUpdates(VelopackAsset? toApply, bool silent = false, bool restart = true, string[]? restartArgs = null)
|
public void WaitExitThenApplyUpdates(VelopackAsset? toApply, bool silent = false, bool restart = true, string[]? restartArgs = null)
|
||||||
{
|
{
|
||||||
UpdateExe.Apply(Locator, toApply, silent, restart, restartArgs, Log);
|
UpdateExe.Apply(Locator, toApply, silent, VelopackRuntimeInfo.ProcessId, restart, restartArgs, Log);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="WaitExitThenApplyUpdates"/>
|
/// <inheritdoc cref="WaitExitThenApplyUpdates"/>
|
||||||
public async Task WaitExitThenApplyUpdatesAsync(VelopackAsset? toApply, bool silent = false, bool restart = true, string[]? restartArgs = null)
|
public async Task WaitExitThenApplyUpdatesAsync(VelopackAsset? toApply, bool silent = false, bool restart = true, string[]? restartArgs = null)
|
||||||
{
|
{
|
||||||
await UpdateExe.ApplyAsync(Locator, toApply, silent, restart, restartArgs, Log).ConfigureAwait(false);
|
await UpdateExe.ApplyAsync(Locator, toApply, silent, VelopackRuntimeInfo.ProcessId, restart, restartArgs, Log).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ namespace Velopack
|
|||||||
log.Info($"Launching app is out-dated. Current: {myVersion}, Newest Local Available: {latestLocal.Version}");
|
log.Info($"Launching app is out-dated. Current: {myVersion}, Newest Local Available: {latestLocal.Version}");
|
||||||
if (!restarted && _autoApply) {
|
if (!restarted && _autoApply) {
|
||||||
log.Info("Auto apply is true, so restarting to apply update...");
|
log.Info("Auto apply is true, so restarting to apply update...");
|
||||||
UpdateExe.Apply(locator, latestLocal, false, true, args, log);
|
UpdateExe.Apply(locator, latestLocal, false, VelopackRuntimeInfo.ProcessId, true, args, log);
|
||||||
Exit(0);
|
Exit(0);
|
||||||
} else {
|
} else {
|
||||||
log.Info("Pre-condition failed, we will not restart to apply updates. (restarted: " + restarted + ", autoApply: " + _autoApply + ")");
|
log.Info("Pre-condition failed, we will not restart to apply updates. (restarted: " + restarted + ", autoApply: " + _autoApply + ")");
|
||||||
|
|||||||
@@ -91,6 +91,9 @@ namespace Velopack
|
|||||||
/// <summary> The path on disk of the entry assembly. </summary>
|
/// <summary> The path on disk of the entry assembly. </summary>
|
||||||
public static string EntryExePath { get; }
|
public static string EntryExePath { get; }
|
||||||
|
|
||||||
|
/// <summary> The current executing process ID. </summary>
|
||||||
|
public static uint ProcessId { get; }
|
||||||
|
|
||||||
/// <summary> The current machine architecture, ignoring the current process / pe architecture. </summary>
|
/// <summary> The current machine architecture, ignoring the current process / pe architecture. </summary>
|
||||||
public static RuntimeCpu SystemArch { get; private set; }
|
public static RuntimeCpu SystemArch { get; private set; }
|
||||||
|
|
||||||
@@ -122,7 +125,9 @@ namespace Velopack
|
|||||||
|
|
||||||
static VelopackRuntimeInfo()
|
static VelopackRuntimeInfo()
|
||||||
{
|
{
|
||||||
EntryExePath = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
|
var currentProcess = System.Diagnostics.Process.GetCurrentProcess();
|
||||||
|
EntryExePath = currentProcess.MainModule.FileName;
|
||||||
|
ProcessId = (uint)currentProcess.Id;
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
InUnitTestRunner = CheckForUnitTestRunner();
|
InUnitTestRunner = CheckForUnitTestRunner();
|
||||||
|
|||||||
@@ -6,24 +6,36 @@ use std::{
|
|||||||
sync::mpsc::Sender,
|
sync::mpsc::Sender,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use semver::Version;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
use async_std::channel::Sender as AsyncSender;
|
use async_std::channel::Sender as AsyncSender;
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
use async_std::task::JoinHandle;
|
use async_std::task::JoinHandle;
|
||||||
use semver::Version;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
locator::{self, VelopackLocatorConfig, LocationContext, VelopackLocator},
|
locator::{self, LocationContext, VelopackLocator, VelopackLocatorConfig},
|
||||||
sources::UpdateSource,
|
sources::UpdateSource,
|
||||||
Error,
|
util, Error,
|
||||||
util,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Configure how the update process should wait before applying updates.
|
||||||
|
pub enum ApplyWaitMode {
|
||||||
|
/// NOT RECOMMENDED: Will not wait for any process before continuing. This could result in the update process being
|
||||||
|
/// killed, or the update process itself failing.
|
||||||
|
NoWait,
|
||||||
|
/// Will wait for the current process to exit before continuing. This is the default and recommended mode.
|
||||||
|
WaitCurrentProcess,
|
||||||
|
/// Wait for the specified process ID to exit before continuing. This is useful if you are updating a program
|
||||||
|
/// different from the one that is currently running.
|
||||||
|
WaitPid(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A feed of Velopack assets, usually retrieved from a remote location.
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
/// A feed of Velopack assets, usually retrieved from a remote location.
|
|
||||||
pub struct VelopackAssetFeed {
|
pub struct VelopackAssetFeed {
|
||||||
/// The list of assets in the (probably remote) update feed.
|
/// The list of assets in the (probably remote) update feed.
|
||||||
pub Assets: Vec<VelopackAsset>,
|
pub Assets: Vec<VelopackAsset>,
|
||||||
@@ -36,11 +48,11 @@ impl VelopackAssetFeed {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An individual Velopack asset, could refer to an asset on-disk or in a remote package feed.
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
/// An individual Velopack asset, could refer to an asset on-disk or in a remote package feed.
|
|
||||||
pub struct VelopackAsset {
|
pub struct VelopackAsset {
|
||||||
/// The name or Id of the package containing this release.
|
/// The name or Id of the package containing this release.
|
||||||
pub PackageId: String,
|
pub PackageId: String,
|
||||||
@@ -62,11 +74,11 @@ pub struct VelopackAsset {
|
|||||||
pub NotesHtml: String,
|
pub NotesHtml: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Holds information about the current version and pending updates, such as how many there are, and access to release notes.
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
/// Holds information about the current version and pending updates, such as how many there are, and access to release notes.
|
|
||||||
pub struct UpdateInfo {
|
pub struct UpdateInfo {
|
||||||
/// The available version that we are updating to.
|
/// The available version that we are updating to.
|
||||||
pub TargetFullRelease: VelopackAsset,
|
pub TargetFullRelease: VelopackAsset,
|
||||||
@@ -88,11 +100,11 @@ impl AsRef<VelopackAsset> for VelopackAsset {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Options to customise the behaviour of UpdateManager.
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
||||||
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "typescript", derive(ts_rs::TS))]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
/// Options to customise the behaviour of UpdateManager.
|
|
||||||
pub struct UpdateOptions {
|
pub struct UpdateOptions {
|
||||||
/// Allows UpdateManager to update to a version that's lower than the current version (i.e. downgrading).
|
/// Allows UpdateManager to update to a version that's lower than the current version (i.e. downgrading).
|
||||||
/// This could happen if a release has bugs and was retracted from the release feed, or if you're using
|
/// This could happen if a release has bugs and was retracted from the release feed, or if you're using
|
||||||
@@ -166,11 +178,7 @@ impl UpdateManager {
|
|||||||
} else {
|
} else {
|
||||||
locator::auto_locate_app_manifest(LocationContext::FromCurrentExe)?
|
locator::auto_locate_app_manifest(LocationContext::FromCurrentExe)?
|
||||||
};
|
};
|
||||||
Ok(UpdateManager {
|
Ok(UpdateManager { options: options.unwrap_or_default(), source, locator })
|
||||||
options: options.unwrap_or_default(),
|
|
||||||
source,
|
|
||||||
locator,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_practical_channel(&self) -> String {
|
fn get_practical_channel(&self) -> String {
|
||||||
@@ -235,10 +243,9 @@ impl UpdateManager {
|
|||||||
self.source.get_release_feed(&channel, &self.locator.get_manifest())
|
self.source.get_release_feed(&channel, &self.locator.get_manifest())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
|
||||||
/// Get a list of available remote releases from the package source.
|
/// Get a list of available remote releases from the package source.
|
||||||
pub fn get_release_feed_async(&self) -> JoinHandle<Result<VelopackAssetFeed, Error>>
|
#[cfg(feature = "async")]
|
||||||
{
|
pub fn get_release_feed_async(&self) -> JoinHandle<Result<VelopackAssetFeed, Error>> {
|
||||||
let self_clone = self.clone();
|
let self_clone = self.clone();
|
||||||
async_std::task::spawn_blocking(move || self_clone.get_release_feed())
|
async_std::task::spawn_blocking(move || self_clone.get_release_feed())
|
||||||
}
|
}
|
||||||
@@ -299,11 +306,10 @@ impl UpdateManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
|
||||||
/// Checks for updates, returning None if there are none available. If there are updates available, this method will return an
|
/// Checks for updates, returning None if there are none available. If there are updates available, this method will return an
|
||||||
/// UpdateInfo object containing the latest available release, and any delta updates that can be applied if they are available.
|
/// UpdateInfo object containing the latest available release, and any delta updates that can be applied if they are available.
|
||||||
pub fn check_for_updates_async(&self) -> JoinHandle<Result<UpdateCheck, Error>>
|
#[cfg(feature = "async")]
|
||||||
{
|
pub fn check_for_updates_async(&self) -> JoinHandle<Result<UpdateCheck, Error>> {
|
||||||
let self_clone = self.clone();
|
let self_clone = self.clone();
|
||||||
async_std::task::spawn_blocking(move || self_clone.check_for_updates())
|
async_std::task::spawn_blocking(move || self_clone.check_for_updates())
|
||||||
}
|
}
|
||||||
@@ -378,13 +384,13 @@ impl UpdateManager {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "async")]
|
|
||||||
/// Downloads the specified updates to the local app packages directory. Progress is reported back to the caller via an optional Sender.
|
/// Downloads the specified updates to the local app packages directory. Progress is reported back to the caller via an optional Sender.
|
||||||
/// This function will acquire a global update lock so may fail if there is already another update operation in progress.
|
/// This function will acquire a global update lock so may fail if there is already another update operation in progress.
|
||||||
/// - If the update contains delta packages and the delta feature is enabled
|
/// - If the update contains delta packages and the delta feature is enabled
|
||||||
/// this method will attempt to unpack and prepare them.
|
/// this method will attempt to unpack and prepare them.
|
||||||
/// - If there is no delta update available, or there is an error preparing delta
|
/// - If there is no delta update available, or there is an error preparing delta
|
||||||
/// packages, this method will fall back to downloading the full version of the update.
|
/// packages, this method will fall back to downloading the full version of the update.
|
||||||
|
#[cfg(feature = "async")]
|
||||||
pub fn download_updates_async(&self, update: &UpdateInfo, progress: Option<AsyncSender<i16>>) -> JoinHandle<Result<(), Error>> {
|
pub fn download_updates_async(&self, update: &UpdateInfo, progress: Option<AsyncSender<i16>>) -> JoinHandle<Result<(), Error>> {
|
||||||
let mut sync_progress: Option<Sender<i16>> = None;
|
let mut sync_progress: Option<Sender<i16>> = None;
|
||||||
|
|
||||||
@@ -424,7 +430,7 @@ impl UpdateManager {
|
|||||||
where
|
where
|
||||||
A: AsRef<VelopackAsset>,
|
A: AsRef<VelopackAsset>,
|
||||||
S: AsRef<str>,
|
S: AsRef<str>,
|
||||||
C: IntoIterator<Item=S>,
|
C: IntoIterator<Item = S>,
|
||||||
{
|
{
|
||||||
self.wait_exit_then_apply_updates(to_apply, false, true, restart_args)?;
|
self.wait_exit_then_apply_updates(to_apply, false, true, restart_args)?;
|
||||||
exit(0);
|
exit(0);
|
||||||
@@ -449,7 +455,27 @@ impl UpdateManager {
|
|||||||
where
|
where
|
||||||
A: AsRef<VelopackAsset>,
|
A: AsRef<VelopackAsset>,
|
||||||
S: AsRef<str>,
|
S: AsRef<str>,
|
||||||
C: IntoIterator<Item=S>,
|
C: IntoIterator<Item = S>,
|
||||||
|
{
|
||||||
|
self.unsafe_apply_updates(to_apply, silent, ApplyWaitMode::WaitCurrentProcess, restart, restart_args)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This will launch the Velopack updater and optionally wait for a program to exit gracefully.
|
||||||
|
/// This method is unsafe because it does not necessarily wait for any / the correct process to exit
|
||||||
|
/// before applying updates. The `wait_exit_then_apply_updates` method is recommended for most use cases.
|
||||||
|
pub fn unsafe_apply_updates<A, C, S>(
|
||||||
|
&self,
|
||||||
|
to_apply: A,
|
||||||
|
silent: bool,
|
||||||
|
wait_mode: ApplyWaitMode,
|
||||||
|
restart: bool,
|
||||||
|
restart_args: C,
|
||||||
|
) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
A: AsRef<VelopackAsset>,
|
||||||
|
S: AsRef<str>,
|
||||||
|
C: IntoIterator<Item = S>,
|
||||||
{
|
{
|
||||||
let to_apply = to_apply.as_ref();
|
let to_apply = to_apply.as_ref();
|
||||||
let pkg_path = self.locator.get_packages_dir().join(&to_apply.FileName);
|
let pkg_path = self.locator.get_packages_dir().join(&to_apply.FileName);
|
||||||
@@ -457,10 +483,26 @@ impl UpdateManager {
|
|||||||
|
|
||||||
let mut args = Vec::new();
|
let mut args = Vec::new();
|
||||||
args.push("apply".to_string());
|
args.push("apply".to_string());
|
||||||
|
|
||||||
|
args.push("--package".to_string());
|
||||||
|
args.push(pkg_path_str.to_string());
|
||||||
|
|
||||||
|
if !pkg_path.exists() {
|
||||||
|
error!("Package does not exist on disk: '{}'", &pkg_path_str);
|
||||||
|
return Err(Error::FileNotFound(pkg_path_str.to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
match wait_mode {
|
||||||
|
ApplyWaitMode::NoWait => {}
|
||||||
|
ApplyWaitMode::WaitCurrentProcess => {
|
||||||
args.push("--waitPid".to_string());
|
args.push("--waitPid".to_string());
|
||||||
args.push(format!("{}", std::process::id()));
|
args.push(format!("{}", std::process::id()));
|
||||||
args.push("--package".to_string());
|
}
|
||||||
args.push(pkg_path_str.into_owned());
|
ApplyWaitMode::WaitPid(pid) => {
|
||||||
|
args.push("--waitPid".to_string());
|
||||||
|
args.push(format!("{}", pid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if silent {
|
if silent {
|
||||||
args.push("--silent".to_string());
|
args.push("--silent".to_string());
|
||||||
|
|||||||
Reference in New Issue
Block a user