diff --git a/build.ps1 b/build.ps1
index 364b50c7..9f47e073 100644
--- a/build.ps1
+++ b/build.ps1
@@ -37,7 +37,7 @@ Copy-Item "$In\Win32\WriteZipToSetup.exe" -Destination "$Out"
Copy-Item "$In\Win32\WriteZipToSetup.pdb" -Destination "$Out"
Copy-Item -Path "$PSScriptRoot\vendor\7zip\*" -Destination "$Out" -Recurse
-Copy-Item -Path "$PSScriptRoot\vendor\wix\*" -Destination "$Out" -Recurse
+# Copy-Item -Path "$PSScriptRoot\vendor\wix\*" -Destination "$Out" -Recurse
Copy-Item "$PSScriptRoot\vendor\NuGet.exe" -Destination "$Out"
Copy-Item "$PSScriptRoot\vendor\rcedit.exe" -Destination "$Out"
Copy-Item "$PSScriptRoot\vendor\signtool.exe" -Destination "$Out"
diff --git a/src/SquirrelCli/squirrel.ico b/squirrel.ico
similarity index 100%
rename from src/SquirrelCli/squirrel.ico
rename to squirrel.ico
diff --git a/src/Squirrel/Squirrel.csproj b/src/Squirrel/Squirrel.csproj
index 620bdb9c..660e9444 100644
--- a/src/Squirrel/Squirrel.csproj
+++ b/src/Squirrel/Squirrel.csproj
@@ -7,8 +7,7 @@
Squirrel
Squirrel
true
- 9
- Squirrel.Lib
+ SquirrelLib
diff --git a/src/SquirrelCli/SquirrelCli.csproj b/src/SquirrelCli/SquirrelCli.csproj
index a21e0244..2094c921 100644
--- a/src/SquirrelCli/SquirrelCli.csproj
+++ b/src/SquirrelCli/SquirrelCli.csproj
@@ -1,22 +1,21 @@
- Exe
net6.0
+ Exe
+ 9
+ Squirrel
+ ..\..\squirrel.ico
+ en
+
+
true
true
true
- true
win-x86
- squirrel.ico
- Squirrel
- en
+ true
-
-
-
-
diff --git a/src/Squirrel/Lib/ValidatedOptionSet.cs b/src/SquirrelCli/ValidatedOptionSet.cs
similarity index 100%
rename from src/Squirrel/Lib/ValidatedOptionSet.cs
rename to src/SquirrelCli/ValidatedOptionSet.cs
diff --git a/src/SquirrelCli/app.manifest b/src/SquirrelCli/app.manifest
deleted file mode 100644
index 532ca1ee..00000000
--- a/src/SquirrelCli/app.manifest
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Update/CopStache.cs b/src/Update/CopStache.cs
deleted file mode 100644
index 82e1b5e7..00000000
--- a/src/Update/CopStache.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Security;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Squirrel.Update
-{
- public static class CopStache
- {
- public static string Render(string template, Dictionary identifiers)
- {
- var buf = new StringBuilder();
-
- foreach (var line in template.Split('\n')) {
- identifiers["RandomGuid"] = (Guid.NewGuid()).ToString();
-
- foreach (var key in identifiers.Keys) {
- buf.Replace("{{" + key + "}}", SecurityElement.Escape(identifiers[key]));
- }
-
- buf.AppendLine(line);
- }
-
- return buf.ToString();
- }
- }
-}
diff --git a/src/Update/Program.cs b/src/Update/Program.cs
index 7cf0deeb..8e131040 100644
--- a/src/Update/Program.cs
+++ b/src/Update/Program.cs
@@ -17,21 +17,15 @@ using Squirrel.Lib;
namespace Squirrel.Update
{
- enum UpdateAction
- {
- Unset = 0, Install, Uninstall, Download, Update, Releasify, Shortcut,
- Deshortcut, ProcessStart, UpdateSelf, CheckForUpdate
- }
-
class Program : IEnableLogger
{
static StartupOption opt;
+ static IFullLogger Log => SquirrelLocator.Current.GetService().GetLogger(typeof(Program));
public static int Main(string[] args)
{
- var pg = new Program();
try {
- return pg.main(args);
+ return main(args);
} catch (Exception ex) {
// NB: Normally this is a terrible idea but we want to make
// sure Setup.exe above us gets the nonzero error code
@@ -40,7 +34,7 @@ namespace Squirrel.Update
}
}
- int main(string[] args)
+ static int main(string[] args)
{
try {
opt = new StartupOption(args);
@@ -68,9 +62,9 @@ namespace Squirrel.Update
}
}
- int executeCommandLine(string[] args)
+ static int executeCommandLine(string[] args)
{
- this.Log().Info("Starting Squirrel Updater: " + String.Join(" ", args));
+ Log.Info("Starting Squirrel Updater: " + String.Join(" ", args));
if (args.Any(x => x.StartsWith("/squirrel", StringComparison.OrdinalIgnoreCase))) {
// NB: We're marked as Squirrel-aware, but we don't want to do
@@ -84,7 +78,6 @@ namespace Squirrel.Update
}
switch (opt.updateAction) {
-#if !MONO
case UpdateAction.Install:
var progressSource = new ProgressSource();
Install(opt.silentInstall, progressSource, Path.GetFullPath(opt.target)).Wait();
@@ -105,7 +98,7 @@ namespace Squirrel.Update
UpdateSelf().Wait();
break;
case UpdateAction.Shortcut:
- Shortcut(opt.target, opt.shortcutArgs, opt.processStartArgs, opt.setupIcon, opt.onlyUpdateShortcuts);
+ Shortcut(opt.target, opt.shortcutArgs, opt.processStartArgs, opt.icon, opt.onlyUpdateShortcuts);
break;
case UpdateAction.Deshortcut:
Deshortcut(opt.target, opt.shortcutArgs);
@@ -113,22 +106,18 @@ namespace Squirrel.Update
case UpdateAction.ProcessStart:
ProcessStart(opt.processStart, opt.processStartArgs, opt.shouldWait);
break;
-#endif
- case UpdateAction.Releasify:
- Releasify(opt.target, opt.releaseDir, opt.bootstrapperExe, opt.backgroundGif, opt.signingParameters, opt.baseUrl, opt.setupIcon, !opt.noMsi, opt.packageAs64Bit, opt.frameworkVersion, !opt.noDelta);
- break;
}
- this.Log().Info("Finished Squirrel Updater");
+ Log.Info("Finished Squirrel Updater");
return 0;
}
- public async Task Install(bool silentInstall, ProgressSource progressSource, string sourceDirectory = null)
+ static async Task Install(bool silentInstall, ProgressSource progressSource, string sourceDirectory = null)
{
sourceDirectory = sourceDirectory ?? AssemblyRuntimeInfo.BaseDirectory;
var releasesPath = Path.Combine(sourceDirectory, "RELEASES");
- this.Log().Info("Starting install, writing to {0}", sourceDirectory);
+ Log.Info("Starting install, writing to {0}", sourceDirectory);
if (!AssemblyRuntimeInfo.IsSingleFile) {
// when doing a standard build, our executable has multiple files/dependencies.
@@ -138,7 +127,7 @@ namespace Squirrel.Update
}
if (!File.Exists(releasesPath)) {
- this.Log().Info("RELEASES doesn't exist, creating it at " + releasesPath);
+ Log.Info("RELEASES doesn't exist, creating it at " + releasesPath);
var nupkgs = (new DirectoryInfo(sourceDirectory)).GetFiles()
.Where(x => x.Name.EndsWith(".nupkg", StringComparison.OrdinalIgnoreCase))
.Select(x => ReleaseEntry.GenerateFromFile(x.FullName));
@@ -150,42 +139,42 @@ namespace Squirrel.Update
.First().PackageName;
using (var mgr = new UpdateManager(sourceDirectory, ourAppName)) {
- this.Log().Info("About to install to: " + mgr.RootAppDirectory);
+ Log.Info("About to install to: " + mgr.RootAppDirectory);
if (Directory.Exists(mgr.RootAppDirectory)) {
- this.Log().Warn("Install path {0} already exists, burning it to the ground", mgr.RootAppDirectory);
+ Log.Warn("Install path {0} already exists, burning it to the ground", mgr.RootAppDirectory);
mgr.KillAllExecutablesBelongingToPackage();
await Task.Delay(500);
- await this.ErrorIfThrows(() => Utility.DeleteDirectory(mgr.RootAppDirectory),
+ await Log.ErrorIfThrows(() => Utility.DeleteDirectory(mgr.RootAppDirectory),
"Failed to remove existing directory on full install, is the app still running???");
- this.ErrorIfThrows(() => Utility.Retry(() => Directory.CreateDirectory(mgr.RootAppDirectory), 3),
+ Log.ErrorIfThrows(() => Utility.Retry(() => Directory.CreateDirectory(mgr.RootAppDirectory), 3),
"Couldn't recreate app directory, perhaps Antivirus is blocking it");
}
Directory.CreateDirectory(mgr.RootAppDirectory);
var updateTarget = Path.Combine(mgr.RootAppDirectory, "Update.exe");
- this.ErrorIfThrows(() => File.Copy(AssemblyRuntimeInfo.EntryExePath, updateTarget, true),
+ Log.ErrorIfThrows(() => File.Copy(AssemblyRuntimeInfo.EntryExePath, updateTarget, true),
"Failed to copy Update.exe to " + updateTarget);
await mgr.FullInstall(silentInstall, progressSource.Raise);
- await this.ErrorIfThrows(() => mgr.CreateUninstallerRegistryEntry(),
+ await Log.ErrorIfThrows(() => mgr.CreateUninstallerRegistryEntry(),
"Failed to create uninstaller registry entry");
}
}
- public async Task Update(string updateUrl, string appName = null)
+ static async Task Update(string updateUrl, string appName = null)
{
appName = appName ?? getAppNameFromDirectory();
- this.Log().Info("Starting update, downloading from " + updateUrl);
+ Log.Info("Starting update, downloading from " + updateUrl);
using (var mgr = new UpdateManager(updateUrl, appName)) {
bool ignoreDeltaUpdates = false;
- this.Log().Info("About to update to: " + mgr.RootAppDirectory);
+ Log.Info("About to update to: " + mgr.RootAppDirectory);
retry:
try {
@@ -199,24 +188,24 @@ namespace Squirrel.Update
await mgr.ApplyReleases(updateInfo, x => Console.WriteLine(UpdateManager.CalculateProgress(x, 30, 100)));
} catch (Exception ex) {
if (ignoreDeltaUpdates) {
- this.Log().ErrorException("Really couldn't apply updates!", ex);
+ Log.ErrorException("Really couldn't apply updates!", ex);
throw;
}
- this.Log().WarnException("Failed to apply updates, falling back to full updates", ex);
+ Log.WarnException("Failed to apply updates, falling back to full updates", ex);
ignoreDeltaUpdates = true;
goto retry;
}
var updateTarget = Path.Combine(mgr.RootAppDirectory, "Update.exe");
- await this.ErrorIfThrows(() =>
+ await Log.ErrorIfThrows(() =>
mgr.CreateUninstallerRegistryEntry(),
"Failed to create uninstaller registry entry");
}
}
- public async Task UpdateSelf()
+ static async Task UpdateSelf()
{
waitForParentToExit();
var src = AssemblyRuntimeInfo.EntryExePath;
@@ -229,11 +218,11 @@ namespace Squirrel.Update
});
}
- public async Task Download(string updateUrl, string appName = null)
+ static async Task Download(string updateUrl, string appName = null)
{
appName = appName ?? getAppNameFromDirectory();
- this.Log().Info("Fetching update information, downloading from " + updateUrl);
+ Log.Info("Fetching update information, downloading from " + updateUrl);
using (var mgr = new UpdateManager(updateUrl, appName)) {
var updateInfo = await mgr.CheckForUpdate(intention: UpdaterIntention.Update, progress: x => Console.WriteLine(x / 3));
await mgr.DownloadReleases(updateInfo.ReleasesToApply, x => Console.WriteLine(33 + x / 3));
@@ -253,11 +242,11 @@ namespace Squirrel.Update
}
}
- public async Task CheckForUpdate(string updateUrl, string appName = null)
+ static async Task CheckForUpdate(string updateUrl, string appName = null)
{
appName = appName ?? getAppNameFromDirectory();
- this.Log().Info("Fetching update information, downloading from " + updateUrl);
+ Log.Info("Fetching update information, downloading from " + updateUrl);
using (var mgr = new UpdateManager(updateUrl, appName)) {
var updateInfo = await mgr.CheckForUpdate(intention: UpdaterIntention.Update, progress: x => Console.WriteLine(x));
var releaseNotes = updateInfo.FetchReleaseNotes();
@@ -275,9 +264,9 @@ namespace Squirrel.Update
}
}
- public async Task Uninstall(string appName = null)
+ static async Task Uninstall(string appName = null)
{
- this.Log().Info("Starting uninstall for app: " + appName);
+ Log.Info("Starting uninstall for app: " + appName);
appName = appName ?? getAppNameFromDirectory();
using (var mgr = new UpdateManager("", appName)) {
@@ -294,172 +283,7 @@ namespace Squirrel.Update
}
}
- public void Releasify(string package, string targetDir = null, string bootstrapperExe = null, string backgroundGif = null, string signingOpts = null, string baseUrl = null, string setupIcon = null, bool generateMsi = true, bool packageAs64Bit = false, string frameworkVersion = null, bool generateDeltas = true)
- {
- ensureConsole();
-
- if (baseUrl != null) {
- if (!Utility.IsHttpUrl(baseUrl)) {
- throw new Exception(string.Format("Invalid --baseUrl '{0}'. A base URL must start with http or https and be a valid URI.", baseUrl));
- }
-
- if (!baseUrl.EndsWith("/")) {
- baseUrl += "/";
- }
- }
-
- targetDir = targetDir ?? Path.Combine(".", "Releases");
- bootstrapperExe = bootstrapperExe ?? Path.Combine(".", "Setup.exe");
-
- if (!Directory.Exists(targetDir)) {
- Directory.CreateDirectory(targetDir);
- }
-
- if (!File.Exists(bootstrapperExe)) {
- bootstrapperExe = Path.Combine(
- AssemblyRuntimeInfo.BaseDirectory,
- "Setup.exe");
- }
-
- if (!File.Exists(bootstrapperExe)) {
- this.Log().Error("Could not find Bootstrapper EXE. Please place it in the directory next to me, or use the bootstrapperExe command line option.");
- throw new ArgumentException();
- }
-
- this.Log().Info("Bootstrapper EXE found at:" + bootstrapperExe);
-
- // validate that the provided "frameworkVersion" is supported by Setup.exe
- if (!String.IsNullOrWhiteSpace(frameworkVersion)) {
- var chkFrameworkResult = Utility.InvokeProcessAsync(bootstrapperExe, "--checkFramework " + frameworkVersion, CancellationToken.None).Result;
- if (chkFrameworkResult.Item1 != 0) {
- this.Log().Error($"Unsupported FrameworkVersion: '{frameworkVersion}'. {chkFrameworkResult.Item2}");
- throw new ArgumentException();
- }
- }
-
- // copy input package to target output directory
- var di = new DirectoryInfo(targetDir);
- File.Copy(package, Path.Combine(di.FullName, Path.GetFileName(package)), true);
-
- var allNuGetFiles = di.EnumerateFiles()
- .Where(x => x.Name.EndsWith(".nupkg", StringComparison.OrdinalIgnoreCase));
-
- var toProcess = allNuGetFiles.Where(x => !x.Name.Contains("-delta") && !x.Name.Contains("-full"));
- var processed = new List();
-
- var releaseFilePath = Path.Combine(di.FullName, "RELEASES");
- var previousReleases = new List();
- if (File.Exists(releaseFilePath)) {
- previousReleases.AddRange(ReleaseEntry.ParseReleaseFile(File.ReadAllText(releaseFilePath, Encoding.UTF8)));
- }
-
- foreach (var file in toProcess) {
- this.Log().Info("Creating release package: " + file.FullName);
-
- var rp = new ReleasePackage(file.FullName);
- rp.CreateReleasePackage(Path.Combine(di.FullName, rp.SuggestedReleaseFileName), contentsPostProcessHook: pkgPath => {
-
- // create sub executable for all exe's in this package (except Squirrel!)
- new DirectoryInfo(pkgPath).GetAllFilesRecursively()
- .Where(x => x.Name.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase))
- .Where(x => !x.Name.Contains("squirrel.exe", StringComparison.InvariantCultureIgnoreCase))
- .Where(x => Utility.IsFileTopLevelInPackage(x.FullName, pkgPath))
- .Where(x => Utility.ExecutableUsesWin32Subsystem(x.FullName))
- .ForEachAsync(x => createExecutableStubForExe(x.FullName))
- .Wait();
-
- // copy myself into the package so Squirrel can also be updated
- // how we find the lib dir is a huge hack here, but 'ReleasePackage' verifies there can only be one of these so it should be fine.
- var re = new Regex(@"lib[\\\/][^\\\/]*[\\\/]?", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
- var libDir = Directory
- .EnumerateDirectories(pkgPath, "*", SearchOption.AllDirectories)
- .Where(d => re.IsMatch(d))
- .OrderBy(d => d.Length)
- .FirstOrDefault();
- File.Copy(getUpdateExePath(), Path.Combine(libDir, "Squirrel.exe"));
-
- // sign all exe's in this package
- if (signingOpts == null) return;
- new DirectoryInfo(pkgPath).GetAllFilesRecursively()
- .Where(x => Utility.FileIsLikelyPEImage(x.Name))
- .ForEachAsync(async x => {
- if (isPEFileSigned(x.FullName)) {
- this.Log().Info("{0} is already signed, skipping", x.FullName);
- return;
- }
-
- this.Log().Info("About to sign {0}", x.FullName);
- await signPEFile(x.FullName, signingOpts);
- }, 1)
- .Wait();
- });
-
- processed.Add(rp.ReleasePackageFile);
-
- var prev = ReleaseEntry.GetPreviousRelease(previousReleases, rp, targetDir);
- if (prev != null && generateDeltas) {
- var deltaBuilder = new DeltaPackageBuilder(null);
-
- var dp = deltaBuilder.CreateDeltaPackage(prev, rp,
- Path.Combine(di.FullName, rp.SuggestedReleaseFileName.Replace("full", "delta")));
- processed.Insert(0, dp.InputPackageFile);
- }
- }
-
- foreach (var file in toProcess) { File.Delete(file.FullName); }
-
- var newReleaseEntries = processed
- .Select(packageFilename => ReleaseEntry.GenerateFromFile(packageFilename, baseUrl))
- .ToList();
- var distinctPreviousReleases = previousReleases
- .Where(x => !newReleaseEntries.Select(e => e.Version).Contains(x.Version));
- var releaseEntries = distinctPreviousReleases.Concat(newReleaseEntries).ToList();
-
- ReleaseEntry.WriteReleaseFile(releaseEntries, releaseFilePath);
-
- var targetSetupExe = Path.Combine(di.FullName, "Setup.exe");
- var newestFullRelease = releaseEntries.MaxBy(x => x.Version).Where(x => !x.IsDelta).First();
-
- File.Copy(bootstrapperExe, targetSetupExe, true);
- var zipPath = createSetupEmbeddedZip(Path.Combine(di.FullName, newestFullRelease.Filename), di.FullName, signingOpts, setupIcon).Result;
-
- var writeZipToSetup = Utility.FindHelperExecutable("WriteZipToSetup.exe");
-
- try {
- string arguments = $"\"{targetSetupExe}\" \"{zipPath}\"";
- if (!String.IsNullOrWhiteSpace(frameworkVersion)) {
- arguments += $" --set-required-framework \"{frameworkVersion}\"";
- }
- if (!String.IsNullOrWhiteSpace(backgroundGif)) {
- arguments += $" --set-splash \"{Path.GetFullPath(backgroundGif)}\"";
- }
-
- var result = Utility.InvokeProcessAsync(writeZipToSetup, arguments, CancellationToken.None).Result;
- if (result.Item1 != 0) throw new Exception("Failed to write Zip to Setup.exe!\n\n" + result.Item2);
- } catch (Exception ex) {
- this.Log().ErrorException("Failed to update Setup.exe with new Zip file", ex);
- throw;
- } finally {
- File.Delete(zipPath);
- }
-
- Utility.Retry(() =>
- setPEVersionInfoAndIcon(targetSetupExe, new ZipPackage(package), setupIcon).Wait());
-
- if (signingOpts != null) {
- signPEFile(targetSetupExe, signingOpts).Wait();
- }
-
- if (generateMsi) {
- createMsiPackage(targetSetupExe, new ZipPackage(package), packageAs64Bit).Wait();
-
- if (signingOpts != null) {
- signPEFile(targetSetupExe.Replace(".exe", ".msi"), signingOpts).Wait();
- }
- }
- }
-
- public void Shortcut(string exeName, string shortcutArgs, string processStartArgs, string icon, bool onlyUpdate)
+ static void Shortcut(string exeName, string shortcutArgs, string processStartArgs, string icon, bool onlyUpdate)
{
if (String.IsNullOrWhiteSpace(exeName)) {
ShowHelp();
@@ -475,7 +299,7 @@ namespace Squirrel.Update
}
}
- public void Deshortcut(string exeName, string shortcutArgs)
+ static void Deshortcut(string exeName, string shortcutArgs)
{
if (String.IsNullOrWhiteSpace(exeName)) {
ShowHelp();
@@ -491,7 +315,7 @@ namespace Squirrel.Update
}
}
- public void ProcessStart(string exeName, string arguments, bool shouldWait)
+ static void ProcessStart(string exeName, string arguments, bool shouldWait)
{
if (String.IsNullOrWhiteSpace(exeName)) {
ShowHelp();
@@ -519,7 +343,7 @@ namespace Squirrel.Update
// Check for the EXE name they want
var targetExe = new FileInfo(Path.Combine(latestAppDir, exeName.Replace("%20", " ")));
- this.Log().Info("Want to launch '{0}'", targetExe);
+ Log.Info("Want to launch '{0}'", targetExe);
// Check for path canonicalization attacks
if (!targetExe.FullName.StartsWith(latestAppDir, StringComparison.Ordinal)) {
@@ -527,27 +351,27 @@ namespace Squirrel.Update
}
if (!targetExe.Exists) {
- this.Log().Error("File {0} doesn't exist in current release", targetExe);
+ Log.Error("File {0} doesn't exist in current release", targetExe);
throw new ArgumentException();
}
if (shouldWait) waitForParentToExit();
try {
- this.Log().Info("About to launch: '{0}': {1}", targetExe.FullName, arguments ?? "");
+ Log.Info("About to launch: '{0}': {1}", targetExe.FullName, arguments ?? "");
Process.Start(new ProcessStartInfo(targetExe.FullName, arguments ?? "") { WorkingDirectory = Path.GetDirectoryName(targetExe.FullName) });
} catch (Exception ex) {
- this.Log().ErrorException("Failed to start process", ex);
+ Log.ErrorException("Failed to start process", ex);
}
}
- public void ShowHelp()
+ static void ShowHelp()
{
ensureConsole();
opt.WriteOptionDescriptions();
}
- void waitForParentToExit()
+ static void waitForParentToExit()
{
// Grab a handle the parent process
var parentPid = NativeMethods.GetParentProcessId();
@@ -557,242 +381,16 @@ namespace Squirrel.Update
try {
handle = NativeMethods.OpenProcess(ProcessAccess.Synchronize, false, parentPid);
if (handle != IntPtr.Zero) {
- this.Log().Info("About to wait for parent PID {0}", parentPid);
+ Log.Info("About to wait for parent PID {0}", parentPid);
NativeMethods.WaitForSingleObject(handle, 0xFFFFFFFF /*INFINITE*/);
} else {
- this.Log().Info("Parent PID {0} no longer valid - ignoring", parentPid);
+ Log.Info("Parent PID {0} no longer valid - ignoring", parentPid);
}
} finally {
if (handle != IntPtr.Zero) NativeMethods.CloseHandle(handle);
}
}
- string getUpdateExePath()
- {
- //if (selfContained) {
- // var selfPath = Path.Combine(AssemblyRuntimeInfo.BaseDirectory, "UpdateSelfContained.exe");
- // if (!File.Exists(selfPath)) {
- // this.Log().Error("Could not find UpdateSelfContained.exe in base directory. Am I published?");
- // }
- // return selfPath;
- //}
- return AssemblyRuntimeInfo.EntryExePath;
- }
-
- async Task createSetupEmbeddedZip(string fullPackage, string releasesDir, string signingOpts, string setupIcon)
- {
- string tempPath;
-
- this.Log().Info("Building embedded zip file for Setup.exe");
- using (Utility.WithTempDirectory(out tempPath, null)) {
- this.ErrorIfThrows(() => {
- File.Copy(getUpdateExePath(), Path.Combine(tempPath, "Update.exe"));
- File.Copy(fullPackage, Path.Combine(tempPath, Path.GetFileName(fullPackage)));
- }, "Failed to write package files to temp dir: " + tempPath);
-
- if (!String.IsNullOrWhiteSpace(setupIcon)) {
- this.ErrorIfThrows(() => {
- File.Copy(setupIcon, Path.Combine(tempPath, "setupIcon.ico"));
- }, "Failed to write icon to temp dir: " + tempPath);
- }
-
- var releases = new[] { ReleaseEntry.GenerateFromFile(fullPackage) };
- ReleaseEntry.WriteReleaseFile(releases, Path.Combine(tempPath, "RELEASES"));
-
- var target = Path.GetTempFileName();
- File.Delete(target);
-
- // Sign Update.exe so that virus scanners don't think we're
- // pulling one over on them
- if (signingOpts != null) {
- var di = new DirectoryInfo(tempPath);
-
- var files = di.EnumerateFiles()
- .Where(x => x.Name.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase))
- .Select(x => x.FullName);
-
- await files.ForEachAsync(x => signPEFile(x, signingOpts));
- }
-
- this.ErrorIfThrows(() =>
- ZipFile.CreateFromDirectory(tempPath, target, CompressionLevel.Optimal, false),
- "Failed to create Zip file from directory: " + tempPath);
-
- return target;
- }
- }
-
- static async Task signPEFile(string exePath, string signingOpts)
- {
- // Try to find SignTool.exe
- var exe = @".\signtool.exe";
- if (!File.Exists(exe)) {
- exe = Path.Combine(AssemblyRuntimeInfo.BaseDirectory, "signtool.exe");
-
- // Run down PATH and hope for the best
- if (!File.Exists(exe)) exe = "signtool.exe";
- }
-
- var processResult = await Utility.InvokeProcessAsync(exe,
- String.Format("sign {0} \"{1}\"", signingOpts, exePath), CancellationToken.None);
-
- if (processResult.Item1 != 0) {
- var optsWithPasswordHidden = new Regex(@"/p\s+\w+").Replace(signingOpts, "/p ********");
- var msg = String.Format("Failed to sign, command invoked was: '{0} sign {1} {2}'",
- exe, optsWithPasswordHidden, exePath);
-
- throw new Exception(msg);
- } else {
- Console.WriteLine(processResult.Item2);
- }
- }
- bool isPEFileSigned(string path)
- {
-#if MONO
- return Path.GetExtension(path).Equals(".exe", StringComparison.OrdinalIgnoreCase);
-#else
- try {
- return AuthenticodeTools.IsTrusted(path);
- } catch (Exception ex) {
- this.Log().ErrorException("Failed to determine signing status for " + path, ex);
- return false;
- }
-#endif
- }
-
- async Task createExecutableStubForExe(string fullName)
- {
- var exe = Utility.FindHelperExecutable(@"StubExecutable.exe");
-
- var target = Path.Combine(
- Path.GetDirectoryName(fullName),
- Path.GetFileNameWithoutExtension(fullName) + "_ExecutionStub.exe");
-
- await Utility.CopyToAsync(exe, target);
-
- await Utility.InvokeProcessAsync(
- Utility.FindHelperExecutable("WriteZipToSetup.exe"),
- String.Format("--copy-stub-resources \"{0}\" \"{1}\"", fullName, target),
- CancellationToken.None);
- }
-
- static async Task setPEVersionInfoAndIcon(string exePath, IPackage package, string iconPath = null)
- {
- var realExePath = Path.GetFullPath(exePath);
- var company = String.Join(",", package.Authors);
- var verStrings = new Dictionary() {
- { "CompanyName", company },
- { "LegalCopyright", package.Copyright ?? "Copyright © " + DateTime.Now.Year.ToString() + " " + company },
- { "FileDescription", package.Summary ?? package.Description ?? "Installer for " + package.Id },
- { "ProductName", package.Description ?? package.Summary ?? package.Id },
- };
-
- var args = verStrings.Aggregate(new StringBuilder("\"" + realExePath + "\""), (acc, x) => { acc.AppendFormat(" --set-version-string \"{0}\" \"{1}\"", x.Key, x.Value); return acc; });
- args.AppendFormat(" --set-file-version {0} --set-product-version {0}", package.Version.ToString());
- if (iconPath != null) {
- args.AppendFormat(" --set-icon \"{0}\"", Path.GetFullPath(iconPath));
- }
-
- // Try to find rcedit.exe
- string exe = Utility.FindHelperExecutable("rcedit.exe");
-
- var processResult = await Utility.InvokeProcessAsync(exe, args.ToString(), CancellationToken.None);
-
- if (processResult.Item1 != 0) {
- var msg = String.Format(
- "Failed to modify resources, command invoked was: '{0} {1}'\n\nOutput was:\n{2}",
- exe, args, processResult.Item2);
-
- throw new Exception(msg);
- } else {
- Console.WriteLine(processResult.Item2);
- }
- }
-
- static async Task createMsiPackage(string setupExe, IPackage package, bool packageAs64Bit)
- {
- var pathToWix = pathToWixTools();
- var setupExeDir = Path.GetDirectoryName(setupExe);
- var company = String.Join(",", package.Authors);
-
- var culture = CultureInfo.GetCultureInfo(package.Language ?? "").TextInfo.ANSICodePage;
-
-
- var templateText = File.ReadAllText(Path.Combine(pathToWix, "template.wxs"));
- var templateData = new Dictionary {
- { "Id", package.Id },
- { "Title", package.Title },
- { "Author", company },
- { "Version", Regex.Replace(package.Version.ToString(), @"-.*$", "") },
- { "Summary", package.Summary ?? package.Description ?? package.Id },
- { "Codepage", $"{culture}" },
- { "Platform", packageAs64Bit ? "x64" : "x86" },
- { "ProgramFilesFolder", packageAs64Bit ? "ProgramFiles64Folder" : "ProgramFilesFolder" },
- { "Win64YesNo", packageAs64Bit ? "yes" : "no" }
- };
-
- // NB: We need some GUIDs that are based on the package ID, but unique (i.e.
- // "Unique but consistent").
- for (int i = 1; i <= 10; i++) {
- templateData[String.Format("IdAsGuid{0}", i)] = Utility.CreateGuidFromHash(String.Format("{0}:{1}", package.Id, i)).ToString();
- }
-
- var templateResult = CopStache.Render(templateText, templateData);
-
- var wxsTarget = Path.Combine(setupExeDir, "Setup.wxs");
- File.WriteAllText(wxsTarget, templateResult, Encoding.UTF8);
-
- var candleParams = String.Format("-nologo -ext WixNetFxExtension -out \"{0}\" \"{1}\"", wxsTarget.Replace(".wxs", ".wixobj"), wxsTarget);
- var processResult = await Utility.InvokeProcessAsync(
- Path.Combine(pathToWix, "candle.exe"), candleParams, CancellationToken.None, setupExeDir);
-
- if (processResult.Item1 != 0) {
- var msg = String.Format(
- "Failed to compile WiX template, command invoked was: '{0} {1}'\n\nOutput was:\n{2}",
- "candle.exe", candleParams, processResult.Item2);
-
- throw new Exception(msg);
- }
-
- var lightParams = String.Format("-ext WixNetFxExtension -sval -out \"{0}\" \"{1}\"", wxsTarget.Replace(".wxs", ".msi"), wxsTarget.Replace(".wxs", ".wixobj"));
- processResult = await Utility.InvokeProcessAsync(
- Path.Combine(pathToWix, "light.exe"), lightParams, CancellationToken.None, setupExeDir);
-
- if (processResult.Item1 != 0) {
- var msg = String.Format(
- "Failed to link WiX template, command invoked was: '{0} {1}'\n\nOutput was:\n{2}",
- "light.exe", lightParams, processResult.Item2);
-
- throw new Exception(msg);
- }
-
- var toDelete = new[] {
- wxsTarget,
- wxsTarget.Replace(".wxs", ".wixobj"),
- wxsTarget.Replace(".wxs", ".wixpdb"),
- };
-
- await Utility.ForEachAsync(toDelete, x => Utility.DeleteFileHarder(x));
- }
-
- static string pathToWixTools()
- {
- var ourPath = AssemblyRuntimeInfo.BaseDirectory;
-
- // Same Directory? (i.e. released)
- if (File.Exists(Path.Combine(ourPath, "candle.exe"))) {
- return ourPath;
- }
-
- // Debug Mode (i.e. in vendor)
- var debugPath = Path.Combine(ourPath, "..", "..", "..", "vendor", "wix", "candle.exe");
- if (File.Exists(debugPath)) {
- return Path.GetFullPath(debugPath);
- }
-
- throw new Exception("WiX tools can't be found");
- }
-
static string getAppNameFromDirectory(string path = null)
{
path = path ?? AssemblyRuntimeInfo.BaseDirectory;
diff --git a/src/Update/StartupOption.cs b/src/Update/StartupOption.cs
index 0fe90b68..5cba0b01 100644
--- a/src/Update/StartupOption.cs
+++ b/src/Update/StartupOption.cs
@@ -3,28 +3,24 @@ using System;
namespace Squirrel.Update
{
+ enum UpdateAction
+ {
+ Unset = 0, Install, Uninstall, Download, Update, Shortcut,
+ Deshortcut, ProcessStart, UpdateSelf, CheckForUpdate
+ }
+
internal class StartupOption
{
private readonly OptionSet optionSet;
-
internal bool silentInstall { get; private set; } = false;
internal UpdateAction updateAction { get; private set; } = default(UpdateAction);
internal string target { get; private set; } = default(string);
- internal string releaseDir { get; private set; } = default(string);
- internal string bootstrapperExe { get; private set; } = default(string);
- internal string backgroundGif { get; private set; } = default(string);
- internal string signingParameters { get; private set; } = default(string);
- internal string baseUrl { get; private set; } = default(string);
+ //internal string baseUrl { get; private set; } = default(string);
internal string processStart { get; private set; } = default(string);
internal string processStartArgs { get; private set; } = default(string);
- internal string setupIcon { get; private set; } = default(string);
internal string icon { get; private set; } = default(string);
internal string shortcutArgs { get; private set; } = default(string);
- internal string frameworkVersion { get; private set; }
internal bool shouldWait { get; private set; } = false;
- internal bool noMsi { get; private set; } = (Environment.OSVersion.Platform != PlatformID.Win32NT); // NB: WiX doesn't work under Mono / Wine
- internal bool packageAs64Bit { get; private set; } = false;
- internal bool noDelta { get; private set; } = false;
internal bool onlyUpdateShortcuts { get; private set; } = false;
public StartupOption(string[] args)
@@ -44,7 +40,6 @@ namespace Squirrel.Update
{ "download=", "Download the releases specified by the URL and write new results to stdout as JSON", v => { updateAction = UpdateAction.Download; target = v; } },
{ "checkForUpdate=", "Check for one available update and writes new results to stdout as JSON", v => { updateAction = UpdateAction.CheckForUpdate; target = v; } },
{ "update=", "Update the application to the latest remote version specified by URL", v => { updateAction = UpdateAction.Update; target = v; } },
- { "releasify=", "Update or generate a releases directory with a given NuGet package", v => { updateAction = UpdateAction.Releasify; target = v; } },
{ "createShortcut=", "Create a shortcut for the given executable name", v => { updateAction = UpdateAction.Shortcut; target = v; } },
{ "removeShortcut=", "Remove a shortcut for the given executable name", v => { updateAction = UpdateAction.Deshortcut; target = v; } },
{ "updateSelf=", "Copy the currently executing Update.exe into the default location", v => { updateAction = UpdateAction.UpdateSelf; target = v; } },
@@ -53,29 +48,16 @@ namespace Squirrel.Update
"",
"Options:",
{ "h|?|help", "Display Help and exit", _ => {} },
- { "r=|releaseDir=", "Path to a release directory to use with releasify", v => releaseDir = v},
- { "bootstrapperExe=", "Path to the Setup.exe to use as a template", v => bootstrapperExe = v},
- { "g=|loadingGif=|splashImage=", "Path to an animated GIF to be displayed during installation", v => backgroundGif = v},
{ "i=|icon", "Path to an ICO file that will be used for icon shortcuts", v => icon = v},
- { "setupIcon=", "Path to an ICO file that will be used for the Setup executable's icon", v => setupIcon = v},
- { "n=|signWithParams=", "Sign the installer via SignTool.exe with the parameters given", v => signingParameters = v},
{ "s|silent", "Silent install", _ => silentInstall = true},
- { "b=|baseUrl=", "Provides a base URL to prefix the RELEASES file packages with", v => baseUrl = v, true},
+ //{ "b=|baseUrl=", "Provides a base URL to prefix the RELEASES file packages with", v => baseUrl = v, true},
{ "a=|process-start-args=", "Arguments that will be used when starting executable", v => processStartArgs = v, true},
{ "l=|shortcut-locations=", "Comma-separated string of shortcut locations, e.g. 'Desktop,StartMenu'", v => shortcutArgs = v},
- { "no-msi", "Don't generate an MSI package", v => noMsi = true},
- { "no-delta", "Don't generate delta packages to save time", v => noDelta = true},
- { "framework-version=", "Set the required .NET framework version, e.g. net461", v => frameworkVersion = v },
- { "msi-win64", "Mark the MSI as 64-bit, which is useful in Enterprise deployment scenarios", _ => packageAs64Bit = true},
{ "updateOnly", "Update shortcuts that already exist, rather than creating new ones", _ => onlyUpdateShortcuts = true},
};
opts.Parse(args);
- // NB: setupIcon and icon are just aliases for compatibility
- // reasons, because of a dumb breaking rename I made in 1.0.1
- setupIcon = setupIcon ?? icon;
-
return opts;
}
diff --git a/src/Update/Update.csproj b/src/Update/Update.csproj
index 8743edc6..10566f38 100644
--- a/src/Update/Update.csproj
+++ b/src/Update/Update.csproj
@@ -1,29 +1,30 @@
-
-
+
-
- net6.0
- WinExe
- 9
- Squirrel.Update
- app.manifest
- squirrel.ico
- CA1416
- en
- true
- true
- true
- win-x86
- true
-
+
+ net6.0
+ WinExe
+ 9
+ Squirrel.Update
+ app.manifest
+ ..\..\squirrel.ico
+ CA1416
+ en
+
+
+ true
+ true
+ true
+ win-x86
+ true
+
-
-
- update.ico
-
+
+
+ update.ico
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/src/Update/squirrel.ico b/src/Update/squirrel.ico
deleted file mode 100644
index d9bd2a75..00000000
Binary files a/src/Update/squirrel.ico and /dev/null differ