mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
Fix Squirrel CLI migrations by adding --updateSelf
This commit is contained in:
@@ -56,6 +56,13 @@ fn root_command() -> Command {
|
||||
.about("Remove all app shortcuts, files, and registry entries.")
|
||||
.long_flag_alias("uninstall")
|
||||
);
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
let cmd = cmd.subcommand(Command::new("update-self")
|
||||
.about("Copy the currently executing Update.exe into the default location.")
|
||||
.long_flag_alias("updateSelf")
|
||||
.hide(true)
|
||||
);
|
||||
cmd
|
||||
}
|
||||
|
||||
@@ -155,6 +162,8 @@ fn main() -> Result<()> {
|
||||
let result = match subcommand {
|
||||
#[cfg(target_os = "windows")]
|
||||
"uninstall" => uninstall(subcommand_matches).map_err(|e| anyhow!("Uninstall error: {}", e)),
|
||||
#[cfg(target_os = "windows")]
|
||||
"update-self" => update_self(subcommand_matches).map_err(|e| anyhow!("Update-self error: {}", e)),
|
||||
"start" => start(subcommand_matches).map_err(|e| anyhow!("Start error: {}", e)),
|
||||
"apply" => apply(subcommand_matches).map_err(|e| anyhow!("Apply error: {}", e)),
|
||||
"patch" => patch(subcommand_matches).map_err(|e| anyhow!("Patch error: {}", e)),
|
||||
@@ -243,6 +252,47 @@ fn uninstall(_matches: &ArgMatches) -> Result<()> {
|
||||
commands::uninstall(&locator, true)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn update_self(_matches: &ArgMatches) -> Result<()> {
|
||||
info!("Command: Update Self");
|
||||
let my_path = env::current_exe()?;
|
||||
const RETRY_DELAY: i32 = 500;
|
||||
const RETRY_COUNT: i32 = 20;
|
||||
match auto_locate_app_manifest(LocationContext::IAmUpdateExe) {
|
||||
Ok(locator) => {
|
||||
let target_update_path = locator.get_update_path();
|
||||
if same_file::is_same_file(&target_update_path, &my_path)? {
|
||||
bail!("Update.exe is already in the default location. No need to update.");
|
||||
} else {
|
||||
info!("Copying Update.exe to the default location: {:?}", target_update_path);
|
||||
shared::retry_io_ex(|| std::fs::copy(&my_path, &target_update_path), RETRY_DELAY, RETRY_COUNT)?;
|
||||
info!("Update.exe copied successfully.");
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Failed to initialise locator: {}", e);
|
||||
// search for an Update.exe in parent directories (at least 2 levels up)
|
||||
let mut current_dir = env::current_dir()?;
|
||||
let mut found = false;
|
||||
for _ in 0..2 {
|
||||
current_dir.pop();
|
||||
let target_update_path = current_dir.join("Update.exe");
|
||||
if target_update_path.exists() {
|
||||
info!("Found Update.exe in parent directory: {:?}", target_update_path);
|
||||
shared::retry_io_ex(|| std::fs::copy(&my_path, &target_update_path), RETRY_DELAY, RETRY_COUNT)?;
|
||||
info!("Update.exe copied successfully.");
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
bail!("Failed to locate Update.exe in parent directories, so it could not be updated.");
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[test]
|
||||
fn test_cli_parse_handles_equals_spaces() {
|
||||
|
||||
@@ -253,7 +253,7 @@ public class WindowsPackTests
|
||||
Assert.False(File.Exists(appPath));
|
||||
|
||||
using var key2 = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default)
|
||||
.OpenSubKey(uninstallRegSubKey + "\\" + id, RegistryKeyPermissionCheck.ReadSubTree);
|
||||
.OpenSubKey(uninstallRegSubKey + "\\" + id, RegistryKeyPermissionCheck.ReadSubTree);
|
||||
Assert.Null(key2);
|
||||
}
|
||||
|
||||
@@ -508,12 +508,74 @@ public class WindowsPackTests
|
||||
logger.Info("TEST: uninstalled / complete");
|
||||
}
|
||||
|
||||
[SkippableTheory]
|
||||
[InlineData("LegacyTestApp-ClowdV2-Setup.exe", "app-1.0.0")]
|
||||
[InlineData("LegacyTestApp-SquirrelWinV2-Setup.exe", "app-1.0.0")]
|
||||
public void LegacyAppCanMigrateUsingCli(string fixture, string origDirName)
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
using var logger = _output.BuildLoggerFor<WindowsPackTests>();
|
||||
|
||||
var rootDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "LegacyTestApp");
|
||||
if (Directory.Exists(rootDir)) {
|
||||
IoUtil.Retry(() => IoUtil.DeleteFileOrDirectoryHard(rootDir), 10, 1000);
|
||||
}
|
||||
|
||||
var setup = PathHelper.GetFixture(fixture);
|
||||
var p = Process.Start(setup);
|
||||
p!.WaitForExit();
|
||||
|
||||
var currentDir = Path.Combine(rootDir, origDirName);
|
||||
var appExe = Path.Combine(currentDir, "LegacyTestApp.exe");
|
||||
var stubExe = Path.Combine(rootDir, "LegacyTestApp.exe");
|
||||
var updateExe = Path.Combine(rootDir, "Update.exe");
|
||||
|
||||
var assertAppExe = appExe;
|
||||
IoUtil.Retry(
|
||||
() => {
|
||||
Assert.True(File.Exists(assertAppExe));
|
||||
Assert.True(File.Exists(updateExe));
|
||||
},
|
||||
retries: 10,
|
||||
retryDelay: 1000);
|
||||
|
||||
using var _1 = TempUtil.GetTempDirectory(out var releaseDir);
|
||||
PackTestApp("LegacyTestApp", "2.0.0", "hello!", releaseDir, logger, assemblyNameOverride: "LegacyTestApp");
|
||||
|
||||
RunNoCoverage(updateExe, ["--update", releaseDir], currentDir, logger, exitCode: 0);
|
||||
Thread.Sleep(2000); // update.exe does a self update after
|
||||
|
||||
RunNoCoverage(stubExe, [], currentDir, logger, exitCode: 0);
|
||||
Thread.Sleep(8000); // update.exe will do migration here
|
||||
|
||||
string logContents = ReadFileWithRetry(Path.Combine(rootDir, "Velopack.log"), logger);
|
||||
logger.Info("Velopack.log:" + Environment.NewLine + logContents);
|
||||
|
||||
if (origDirName != "current") {
|
||||
Assert.False(Directory.Exists(currentDir));
|
||||
currentDir = Path.Combine(rootDir, "current");
|
||||
}
|
||||
|
||||
Assert.True(Directory.Exists(currentDir));
|
||||
appExe = Path.Combine(currentDir, "LegacyTestApp.exe");
|
||||
Assert.True(File.Exists(appExe));
|
||||
|
||||
Assert.False(Directory.EnumerateDirectories(rootDir, "app-*").Any());
|
||||
Assert.False(Directory.Exists(Path.Combine(rootDir, "staging")));
|
||||
|
||||
// this is the file written by TestApp when it's detected the squirrel restart. if this is here, everything went smoothly.
|
||||
Assert.True(File.Exists(Path.Combine(rootDir, "restarted")));
|
||||
|
||||
var chk3version = RunNoCoverage(appExe, ["version"], currentDir, logger);
|
||||
Assert.EndsWith(Environment.NewLine + "2.0.0", chk3version);
|
||||
}
|
||||
|
||||
[SkippableTheory]
|
||||
[InlineData("LegacyTestApp-ClowdV2-Setup.exe", "app-1.0.0")]
|
||||
[InlineData("LegacyTestApp-ClowdV3-Setup.exe", "current")]
|
||||
[InlineData("LegacyTestApp-SquirrelWinV2-Setup.exe", "app-1.0.0")]
|
||||
[InlineData("LegacyTestApp-Velopack0084-Setup.exe", "current")]
|
||||
public void LegacyAppCanSuccessfullyMigrate(string fixture, string origDirName)
|
||||
public void LegacyAppCanMigrate(string fixture, string origDirName)
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
using var logger = _output.BuildLoggerFor<WindowsPackTests>();
|
||||
@@ -807,7 +869,8 @@ public class WindowsPackTests
|
||||
return RunImpl(psi, logger, exitCode);
|
||||
}
|
||||
|
||||
private static void PackTestApp(string id, string version, string testString, string releaseDir, ILogger logger, bool addNewFile = false)
|
||||
private static void PackTestApp(string id, string version, string testString, string releaseDir, ILogger logger,
|
||||
bool addNewFile = false, string assemblyNameOverride = null)
|
||||
{
|
||||
var projDir = PathHelper.GetTestRootPath("TestApp");
|
||||
var testStringFile = Path.Combine(projDir, "Const.cs");
|
||||
@@ -815,7 +878,10 @@ public class WindowsPackTests
|
||||
|
||||
try {
|
||||
File.WriteAllText(testStringFile, $"class Const {{ public const string TEST_STRING = \"{testString}\"; }}");
|
||||
var args = new string[] { "publish", "--no-self-contained", "-c", "Release", "-r", "win-x64", "-o", "publish" };
|
||||
var args = new string[] {
|
||||
"publish", "--no-self-contained", "-c", "Release", "-r", "win-x64", "-o", "publish",
|
||||
$"-p:PublishSingleFile=true", "--tl:off"
|
||||
};
|
||||
|
||||
var psi = new ProcessStartInfo("dotnet");
|
||||
psi.WorkingDirectory = projDir;
|
||||
@@ -839,10 +905,20 @@ public class WindowsPackTests
|
||||
}
|
||||
}
|
||||
|
||||
var publishDir = Path.Combine(projDir, "publish");
|
||||
|
||||
if (assemblyNameOverride != null) {
|
||||
var targetExe = Path.Combine(publishDir, assemblyNameOverride + ".exe");
|
||||
if (File.Exists(targetExe)) {
|
||||
File.Delete(targetExe);
|
||||
}
|
||||
File.Move(Path.Combine(publishDir, "TestApp.exe"), targetExe);
|
||||
}
|
||||
|
||||
//RunNoCoverage("dotnet", args, projDir, logger);
|
||||
|
||||
var options = new WindowsPackOptions {
|
||||
EntryExecutableName = "TestApp.exe",
|
||||
EntryExecutableName = assemblyNameOverride + ".exe",
|
||||
ReleaseDir = new DirectoryInfo(releaseDir),
|
||||
PackId = id,
|
||||
PackVersion = version,
|
||||
|
||||
Reference in New Issue
Block a user