mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
Fixing bugs in full integration test
This commit is contained in:
@@ -139,9 +139,9 @@ impl BundleInfo<'_> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn extract_zip_idx_to_path<T: AsRef<str>>(&self, index: usize, path: T) -> Result<()> {
|
||||
pub fn extract_zip_idx_to_path<T: AsRef<Path>>(&self, index: usize, path: T) -> Result<()> {
|
||||
let path = path.as_ref();
|
||||
debug!("Extracting zip file to path: {}", path);
|
||||
debug!("Extracting zip file to path: {}", path.to_string_lossy());
|
||||
let p = PathBuf::from(path);
|
||||
let parent = p.parent().unwrap();
|
||||
|
||||
@@ -160,7 +160,7 @@ impl BundleInfo<'_> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn extract_zip_predicate_to_path<F, T: AsRef<str>>(&self, predicate: F, path: T) -> Result<usize>
|
||||
pub fn extract_zip_predicate_to_path<F, T: AsRef<Path>>(&self, predicate: F, path: T) -> Result<usize>
|
||||
where
|
||||
F: Fn(&str) -> bool,
|
||||
{
|
||||
@@ -183,6 +183,11 @@ impl BundleInfo<'_> {
|
||||
let stub_regex = Regex::new("_ExecutionStub.exe$").unwrap();
|
||||
let updater_idx = self.find_zip_file(|name| name.ends_with("Squirrel.exe"));
|
||||
|
||||
let nuspec_path = current_path.join("sq.version");
|
||||
let _ = self
|
||||
.extract_zip_predicate_to_path(|name| name.ends_with(".nuspec"), nuspec_path)
|
||||
.map_err(|_| anyhow!("This package is missing a nuspec manifest."))?;
|
||||
|
||||
for (i, key) in files.iter().enumerate() {
|
||||
if Some(i) == updater_idx || !re.is_match(key) || key.ends_with("/") || key.ends_with("\\") {
|
||||
info!(" {} Skipped '{}'", i, key);
|
||||
|
||||
@@ -185,6 +185,10 @@ fn apply<'a>(matches: &ArgMatches) -> Result<()> {
|
||||
info!(" Exe Name: {:?}", exe_name);
|
||||
info!(" Exe Args: {:?}", exe_args);
|
||||
|
||||
if wait_for_parent {
|
||||
let _ = platform::wait_for_parent_to_exit(60_000); // 1 minute
|
||||
}
|
||||
|
||||
if let Err(e) = apply_package(package) {
|
||||
error!("Error applying package: {}", e);
|
||||
if !restart {
|
||||
@@ -193,7 +197,7 @@ fn apply<'a>(matches: &ArgMatches) -> Result<()> {
|
||||
}
|
||||
|
||||
if restart {
|
||||
_start(wait_for_parent, exe_name, exe_args, None)?;
|
||||
_start(false, exe_name, exe_args, None)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -240,6 +244,8 @@ fn apply_package<'a>(package: Option<&PathBuf>) -> Result<()> {
|
||||
bail!("Latest package found is {}, which is not newer than current version {}.", found_version, app.version);
|
||||
}
|
||||
|
||||
info!("Applying package to current: {}", found_version);
|
||||
|
||||
let current_dir = app.get_current_path(&root_path);
|
||||
replace_dir_with_rollback(current_dir.clone(), || {
|
||||
if let Some(bundle) = package_bundle.take() {
|
||||
|
||||
115
src/Squirrel/Internal/ProcessArgumentListPolyfill.cs
Normal file
115
src/Squirrel/Internal/ProcessArgumentListPolyfill.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Squirrel
|
||||
{
|
||||
internal static class ProcessArgumentListPolyfill
|
||||
{
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
public static void AppendArgumentListSafe(this ProcessStartInfo psi, IEnumerable<string> args, out string debug)
|
||||
{
|
||||
foreach (var a in args) {
|
||||
psi.ArgumentList.Add(a);
|
||||
}
|
||||
var sb = new StringBuilder();
|
||||
AppendArgumentsTo(sb, args);
|
||||
debug = sb.ToString();
|
||||
}
|
||||
|
||||
#else
|
||||
public static void AppendArgumentListSafe(this ProcessStartInfo psi, IEnumerable<string> args, out string debug)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
AppendArgumentsTo(sb, args);
|
||||
psi.Arguments = sb.ToString();
|
||||
debug = psi.Arguments;
|
||||
}
|
||||
#endif
|
||||
// https://source.dot.net/#System.Diagnostics.Process/System/Diagnostics/ProcessStartInfo.cs,204
|
||||
private static void AppendArgumentsTo(StringBuilder stringBuilder, IEnumerable<string> args)
|
||||
{
|
||||
if (args != null && args.Any()) {
|
||||
foreach (string argument in args) {
|
||||
AppendArgument(stringBuilder, argument);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// https://source.dot.net/#System.Diagnostics.Process/src/libraries/System.Private.CoreLib/src/System/PasteArguments.cs,624678ba1465e776
|
||||
private static void AppendArgument(StringBuilder stringBuilder, string argument)
|
||||
{
|
||||
if (stringBuilder.Length != 0) {
|
||||
stringBuilder.Append(' ');
|
||||
}
|
||||
|
||||
// Parsing rules for non-argv[0] arguments:
|
||||
// - Backslash is a normal character except followed by a quote.
|
||||
// - 2N backslashes followed by a quote ==> N literal backslashes followed by unescaped quote
|
||||
// - 2N+1 backslashes followed by a quote ==> N literal backslashes followed by a literal quote
|
||||
// - Parsing stops at first whitespace outside of quoted region.
|
||||
// - (post 2008 rule): A closing quote followed by another quote ==> literal quote, and parsing remains in quoting mode.
|
||||
if (argument.Length != 0 && ContainsNoWhitespaceOrQuotes(argument)) {
|
||||
// Simple case - no quoting or changes needed.
|
||||
stringBuilder.Append(argument);
|
||||
} else {
|
||||
stringBuilder.Append(Quote);
|
||||
int idx = 0;
|
||||
while (idx < argument.Length) {
|
||||
char c = argument[idx++];
|
||||
if (c == Backslash) {
|
||||
int numBackSlash = 1;
|
||||
while (idx < argument.Length && argument[idx] == Backslash) {
|
||||
idx++;
|
||||
numBackSlash++;
|
||||
}
|
||||
|
||||
if (idx == argument.Length) {
|
||||
// We'll emit an end quote after this so must double the number of backslashes.
|
||||
stringBuilder.Append(Backslash, numBackSlash * 2);
|
||||
} else if (argument[idx] == Quote) {
|
||||
// Backslashes will be followed by a quote. Must double the number of backslashes.
|
||||
stringBuilder.Append(Backslash, numBackSlash * 2 + 1);
|
||||
stringBuilder.Append(Quote);
|
||||
idx++;
|
||||
} else {
|
||||
// Backslash will not be followed by a quote, so emit as normal characters.
|
||||
stringBuilder.Append(Backslash, numBackSlash);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == Quote) {
|
||||
// Escape the quote so it appears as a literal. This also guarantees that we won't end up generating a closing quote followed
|
||||
// by another quote (which parses differently pre-2008 vs. post-2008.)
|
||||
stringBuilder.Append(Backslash);
|
||||
stringBuilder.Append(Quote);
|
||||
continue;
|
||||
}
|
||||
|
||||
stringBuilder.Append(c);
|
||||
}
|
||||
|
||||
stringBuilder.Append(Quote);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ContainsNoWhitespaceOrQuotes(string s)
|
||||
{
|
||||
for (int i = 0; i < s.Length; i++) {
|
||||
char c = s[i];
|
||||
if (char.IsWhiteSpace(c) || c == Quote) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private const char Quote = '\"';
|
||||
private const char Backslash = '\\';
|
||||
}
|
||||
}
|
||||
@@ -215,12 +215,7 @@ namespace Squirrel
|
||||
WorkingDirectory = Path.GetDirectoryName(Locator.UpdateExePath),
|
||||
};
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
var args = psi.ArgumentList;
|
||||
#else
|
||||
var args = new List<string>();
|
||||
#endif
|
||||
|
||||
if (silent) args.Add("--silent");
|
||||
args.Add("apply");
|
||||
args.Add("--wait");
|
||||
@@ -239,9 +234,8 @@ namespace Squirrel
|
||||
}
|
||||
}
|
||||
|
||||
#if !NET5_0_OR_GREATER
|
||||
psi.Arguments = String.Join(" ", args);
|
||||
#endif
|
||||
psi.AppendArgumentListSafe(args, out var debugArgs);
|
||||
Log.Debug($"Restarting app to apply updates. Running: {psi.FileName} {debugArgs}");
|
||||
|
||||
var p = Process.Start(psi);
|
||||
Thread.Sleep(300);
|
||||
@@ -251,6 +245,7 @@ namespace Squirrel
|
||||
if (p.HasExited) {
|
||||
throw new Exception($"Update.exe process exited too soon ({p.ExitCode}).");
|
||||
}
|
||||
Log.Info("Update.exe apply triggered successfully.");
|
||||
}
|
||||
|
||||
protected virtual async Task DownloadAndApplyDeltaUpdates(string extractedBasePackage, UpdateInfo updates, Action<int> progress)
|
||||
|
||||
@@ -280,10 +280,11 @@ public class WindowsPackTests
|
||||
// check app installed correctly
|
||||
var appPath = Path.Combine(installDir, "current", "TestApp.exe");
|
||||
Assert.True(File.Exists(appPath));
|
||||
var argsPath = Path.Combine(installDir, "current", "args.txt");
|
||||
var argsPath = Path.Combine(installDir, "args.txt");
|
||||
Assert.True(File.Exists(argsPath));
|
||||
var argsContent = File.ReadAllText(argsPath).Trim();
|
||||
Assert.Equal("--squirrel-install 1.0.0", argsContent);
|
||||
logger.Info("TEST: v1 installed");
|
||||
|
||||
// check app output
|
||||
var chk1test = RunProcess(appPath, new string[] { "test" }, installDir, logger);
|
||||
@@ -292,6 +293,7 @@ public class WindowsPackTests
|
||||
Assert.EndsWith(Environment.NewLine + "1.0.0", chk1version);
|
||||
var chk1check = RunProcess(appPath, new string[] { "check", releaseDir }, installDir, logger);
|
||||
Assert.EndsWith(Environment.NewLine + "no updates", chk1check);
|
||||
logger.Info("TEST: v1 output verified");
|
||||
|
||||
// pack v2
|
||||
PackTestApp("2.0.0", "version 2 test", releaseDir, logger);
|
||||
@@ -299,15 +301,17 @@ public class WindowsPackTests
|
||||
// check can find v2 update
|
||||
var chk2check = RunProcess(appPath, new string[] { "check", releaseDir }, installDir, logger);
|
||||
Assert.EndsWith(Environment.NewLine + "update: 2.0.0", chk2check);
|
||||
logger.Info("TEST: found v2 update");
|
||||
|
||||
// pack v3
|
||||
PackTestApp("3.0.0", "version 3 test", releaseDir, logger);
|
||||
|
||||
// perform full update, check that we get v3
|
||||
// apply should fail if there's not an update downloaded
|
||||
RunProcess(appPath, new string[] { "apply", releaseDir }, installDir, logger, -1);
|
||||
RunProcess(appPath, new string[] { "apply", releaseDir }, installDir, logger, exitCode: -1);
|
||||
RunProcess(appPath, new string[] { "download", releaseDir }, installDir, logger);
|
||||
RunProcess(appPath, new string[] { "apply", releaseDir }, installDir, logger);
|
||||
RunProcess(appPath, new string[] { "apply", releaseDir }, installDir, logger, exitCode: null);
|
||||
logger.Info("TEST: v3 applied");
|
||||
|
||||
// check app output
|
||||
var chk3test = RunProcess(appPath, new string[] { "test" }, installDir, logger);
|
||||
@@ -316,12 +320,15 @@ public class WindowsPackTests
|
||||
Assert.EndsWith(Environment.NewLine + "3.0.0", chk3version);
|
||||
var ch3check2 = RunProcess(appPath, new string[] { "check", releaseDir }, installDir, logger);
|
||||
Assert.EndsWith(Environment.NewLine + "no updates", ch3check2);
|
||||
logger.Info("TEST: v3 output verified");
|
||||
|
||||
|
||||
// check new obsoleted/updated hooks have run
|
||||
var argsContentv3 = File.ReadAllText(argsPath).Trim();
|
||||
Assert.Contains("--squirrel-install 1.0.0", argsContent);
|
||||
Assert.Contains("--squirrel-obsoleted 1.0.0", argsContent);
|
||||
Assert.Contains("--squirrel-updated 3.0.0", argsContent);
|
||||
logger.Info("TEST: hooks verified");
|
||||
|
||||
|
||||
|
||||
@@ -339,11 +346,12 @@ public class WindowsPackTests
|
||||
// uninstall
|
||||
var updatePath = Path.Combine(installDir, "Update.exe");
|
||||
RunProcess(updatePath, new string[] { "--nocolor", "--silent", "--uninstall" }, Environment.CurrentDirectory, logger);
|
||||
logger.Info("TEST: uninstalled / complete");
|
||||
}
|
||||
|
||||
const string TEST_APP_ID = "Test.Squirrel-App";
|
||||
|
||||
private string RunProcess(string exe, string[] args, string workingDir, ILogger logger, int exitCode = 0)
|
||||
private string RunProcess(string exe, string[] args, string workingDir, ILogger logger, int? exitCode = 0)
|
||||
{
|
||||
var psi = new ProcessStartInfo(exe);
|
||||
psi.WorkingDirectory = workingDir;
|
||||
@@ -360,7 +368,9 @@ public class WindowsPackTests
|
||||
p.ErrorDataReceived += (s, e) => { sb.AppendLine(e.Data); logger.Debug(e.Data); };
|
||||
p.WaitForExit();
|
||||
|
||||
Assert.Equal(exitCode, p.ExitCode);
|
||||
if (exitCode != null)
|
||||
Assert.Equal(exitCode, p.ExitCode);
|
||||
|
||||
return sb.ToString().Trim();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,18 +4,18 @@ using Squirrel.Locators;
|
||||
try {
|
||||
if (args.Length >= 1 && args[0].StartsWith("--squirrel")) {
|
||||
// squirrel hooks
|
||||
File.AppendAllText(Path.Combine(AppContext.BaseDirectory, "args.txt"), String.Join(" ", args) + Environment.NewLine);
|
||||
File.AppendAllText(Path.Combine(AppContext.BaseDirectory, "..", "args.txt"), String.Join(" ", args) + Environment.NewLine);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (args.Length == 1 && args[0] == "version") {
|
||||
var locator = SquirrelLocator.GetDefault(new ConsoleLogger());
|
||||
Console.WriteLine(locator.CurrentlyInstalledVersion);
|
||||
Console.WriteLine(locator.CurrentlyInstalledVersion?.ToString() ?? "unknown_version");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (args.Length == 1 && args[0] == "test") {
|
||||
Console.WriteLine(Const.TEST_STRING);
|
||||
Console.WriteLine(Const.TEST_STRING ?? "no_test_string");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user