mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
Refactor the rest of the command classes
This commit is contained in:
@@ -4,10 +4,6 @@ public class WindowsReleasifyCommand : WindowsSigningCommand
|
||||
{
|
||||
public string Package { get; set; }
|
||||
|
||||
public string BaseUrl { get; private set; }
|
||||
|
||||
public string DebugSetupExe { get; private set; }
|
||||
|
||||
public bool NoDelta { get; private set; }
|
||||
|
||||
public string Runtimes { get; private set; }
|
||||
@@ -16,9 +12,7 @@ public class WindowsReleasifyCommand : WindowsSigningCommand
|
||||
|
||||
public string Icon { get; private set; }
|
||||
|
||||
public string[] SquirrelAwareExecutableNames { get; private set; }
|
||||
|
||||
public string AppIcon { get; private set; }
|
||||
public string EntryExecutableName { get; private set; }
|
||||
|
||||
public WindowsReleasifyCommand()
|
||||
: this("releasify", "Take an existing nuget package and convert it into a Squirrel release.")
|
||||
@@ -38,19 +32,6 @@ public class WindowsReleasifyCommand : WindowsSigningCommand
|
||||
protected WindowsReleasifyCommand(string name, string description)
|
||||
: base(name, description)
|
||||
{
|
||||
AddOption<Uri>((v) => BaseUrl = v.ToAbsoluteOrNull(), "-b", "--baseUrl")
|
||||
.SetDescription("Provides a base URL to prefix the RELEASES file packages with.")
|
||||
.SetHidden()
|
||||
.MustBeValidHttpUri();
|
||||
|
||||
AddOption<FileInfo>((v) => DebugSetupExe = v.ToFullNameOrNull(), "--debugSetupExe")
|
||||
.SetDescription("Uses the Setup.exe at this {PATH} to create the bundle, and then replaces it with the bundle. " +
|
||||
"Used for locally debugging Setup.exe with a real bundle attached.")
|
||||
.SetArgumentHelpName("PATH")
|
||||
.SetHidden()
|
||||
.AcceptExistingOnly()
|
||||
.RequiresExtension(".exe");
|
||||
|
||||
AddOption<bool>((v) => NoDelta = v, "--noDelta")
|
||||
.SetDescription("Skip the generation of delta packages.");
|
||||
|
||||
@@ -70,14 +51,9 @@ public class WindowsReleasifyCommand : WindowsSigningCommand
|
||||
.AcceptExistingOnly()
|
||||
.RequiresExtension(".ico");
|
||||
|
||||
AddOption<string[]>((v) => SquirrelAwareExecutableNames = v ?? new string[0], "-e", "--mainExe")
|
||||
.SetDescription("Name of one or more SquirrelAware executables.")
|
||||
.SetArgumentHelpName("NAME");
|
||||
|
||||
AddOption<FileInfo>((v) => AppIcon = v.ToFullNameOrNull(), "--appIcon")
|
||||
.SetDescription("Path to .ico for 'Apps and Features' list.")
|
||||
.SetArgumentHelpName("PATH")
|
||||
.AcceptExistingOnly()
|
||||
.RequiresExtension(".ico");
|
||||
AddOption<string>((v) => EntryExecutableName = v, "-e", "--mainExe")
|
||||
.SetDescription("The file name of the main/entry executable.")
|
||||
.SetArgumentHelpName("NAME")
|
||||
.SetRequired();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
using System.Runtime.Versioning;
|
||||
using Squirrel.Csq.Commands;
|
||||
using Squirrel.Deployment;
|
||||
using Squirrel.Packaging.OSX;
|
||||
using Squirrel.Packaging.OSX.Commands;
|
||||
using Squirrel.Packaging.Windows.Commands;
|
||||
|
||||
namespace Squirrel.Csq.Compat;
|
||||
|
||||
@@ -17,7 +18,7 @@ public class EmbeddedRunner : ICommandRunner
|
||||
[SupportedOSPlatform("osx")]
|
||||
public Task ExecuteBundleOsx(OsxBundleCommand command)
|
||||
{
|
||||
var options = new BundleOsxOptions {
|
||||
var options = new OsxBundleOptions {
|
||||
BundleId = command.BundleId,
|
||||
PackAuthors = command.PackAuthors,
|
||||
EntryExecutableName = command.EntryExecutableName,
|
||||
@@ -28,7 +29,78 @@ public class EmbeddedRunner : ICommandRunner
|
||||
PackVersion = command.PackVersion,
|
||||
ReleaseDir = command.GetReleaseDirectory(),
|
||||
};
|
||||
new OsxCommands(_logger).Bundle(options);
|
||||
new OsxBundleCommandRunner(_logger).Bundle(options);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("osx")]
|
||||
public Task ExecuteReleasifyOsx(OsxReleasifyCommand command)
|
||||
{
|
||||
var options = new OsxReleasifyOptions {
|
||||
ReleaseDir = command.GetReleaseDirectory(),
|
||||
BundleDirectory = command.BundleDirectory,
|
||||
IncludePdb = command.IncludePdb,
|
||||
NoDelta = command.NoDelta,
|
||||
NoPackage = command.NoPackage,
|
||||
NotaryProfile = command.NotaryProfile,
|
||||
PackageConclusion = command.PackageConclusion,
|
||||
PackageLicense = command.PackageLicense,
|
||||
PackageReadme = command.PackageReadme,
|
||||
PackageWelcome = command.PackageWelcome,
|
||||
ReleaseNotes = command.ReleaseNotes,
|
||||
SigningAppIdentity = command.SigningAppIdentity,
|
||||
SigningEntitlements = command.SigningEntitlements,
|
||||
SigningInstallIdentity = command.SigningInstallIdentity,
|
||||
TargetRuntime = command.TargetRuntime,
|
||||
};
|
||||
new OsxReleasifyCommandRunner(_logger).Releasify(options);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task ExecutePackWindows(WindowsPackCommand command)
|
||||
{
|
||||
var options = new WindowsPackOptions {
|
||||
TargetRuntime = command.TargetRuntime,
|
||||
ReleaseDir = command.GetReleaseDirectory(),
|
||||
Package = command.Package,
|
||||
Icon = command.Icon,
|
||||
NoDelta = command.NoDelta,
|
||||
IncludePdb = command.IncludePdb,
|
||||
SignParameters = command.SignParameters,
|
||||
EntryExecutableName = command.EntryExecutableName,
|
||||
PackAuthors = command.PackAuthors,
|
||||
PackDirectory = command.PackDirectory,
|
||||
PackId = command.PackId,
|
||||
PackTitle = command.PackTitle,
|
||||
PackVersion = command.PackVersion,
|
||||
ReleaseNotes = command.ReleaseNotes,
|
||||
Runtimes = command.Runtimes,
|
||||
SignParallel = command.SignParallel,
|
||||
SignSkipDll = command.SignSkipDll,
|
||||
SignTemplate = command.SignTemplate,
|
||||
SplashImage = command.SplashImage,
|
||||
};
|
||||
new WindowsPackCommandRunner(_logger).Pack(options);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task ExecuteReleasifyWindows(WindowsReleasifyCommand command)
|
||||
{
|
||||
var options = new WindowsReleasifyOptions {
|
||||
TargetRuntime = command.TargetRuntime,
|
||||
ReleaseDir = command.GetReleaseDirectory(),
|
||||
Package = command.Package,
|
||||
Icon = command.Icon,
|
||||
NoDelta = command.NoDelta,
|
||||
SignParameters = command.SignParameters,
|
||||
EntryExecutableName = command.EntryExecutableName,
|
||||
Runtimes = command.Runtimes,
|
||||
SignParallel = command.SignParallel,
|
||||
SignSkipDll = command.SignSkipDll,
|
||||
SignTemplate = command.SignTemplate,
|
||||
SplashImage = command.SplashImage,
|
||||
};
|
||||
new WindowsReleasifyCommandRunner(_logger).Releasify(options);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -64,22 +136,6 @@ public class EmbeddedRunner : ICommandRunner
|
||||
return new SimpleWebRepository(_logger).DownloadRecentPackages(options);
|
||||
}
|
||||
|
||||
public Task ExecutePackWindows(WindowsPackCommand command)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("osx")]
|
||||
public Task ExecuteReleasifyOsx(OsxReleasifyCommand command)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task ExecuteReleasifyWindows(WindowsReleasifyCommand command)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Task ExecuteS3Download(S3DownloadCommand command)
|
||||
{
|
||||
var options = new S3Options {
|
||||
|
||||
@@ -25,11 +25,9 @@ public class V2CompatRunner : ICommandRunner
|
||||
var options = new PackOptions {
|
||||
releaseDir = command.GetReleaseDirectory().FullName,
|
||||
package = command.Package,
|
||||
baseUrl = command.BaseUrl,
|
||||
framework = command.Runtimes,
|
||||
splashImage = command.SplashImage,
|
||||
icon = command.Icon,
|
||||
appIcon = command.AppIcon,
|
||||
noDelta = command.NoDelta,
|
||||
allowUnaware = false,
|
||||
signParams = command.SignParameters,
|
||||
@@ -58,11 +56,9 @@ public class V2CompatRunner : ICommandRunner
|
||||
var options = new ReleasifyOptions {
|
||||
releaseDir = command.GetReleaseDirectory().FullName,
|
||||
package = command.Package,
|
||||
baseUrl = command.BaseUrl,
|
||||
framework = command.Runtimes,
|
||||
splashImage = command.SplashImage,
|
||||
icon = command.Icon,
|
||||
appIcon = command.AppIcon,
|
||||
noDelta = command.NoDelta,
|
||||
allowUnaware = false,
|
||||
signParams = command.SignParameters,
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NuGet.Versioning;
|
||||
|
||||
namespace Squirrel.Packaging.OSX.Commands;
|
||||
|
||||
public class OsxBundleCommandRunner
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public OsxBundleCommandRunner(ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Bundle(OsxBundleOptions options)
|
||||
{
|
||||
var icon = options.Icon;
|
||||
var packId = options.PackId;
|
||||
var packDirectory = options.PackDirectory;
|
||||
var packVersion = options.PackVersion;
|
||||
var exeName = options.EntryExecutableName;
|
||||
var packAuthors = options.PackAuthors;
|
||||
var packTitle = options.PackTitle;
|
||||
var releaseDir = options.ReleaseDir;
|
||||
|
||||
_logger.Info("Generating new '.app' bundle from a directory of application files.");
|
||||
|
||||
var mainExePath = Path.Combine(packDirectory, exeName);
|
||||
if (!File.Exists(mainExePath))// || !PlatformUtil.IsMachOImage(mainExePath))
|
||||
throw new ArgumentException($"--exeName '{mainExePath}' does not exist or is not a mach-o executable.");
|
||||
|
||||
var appleId = $"com.{packAuthors ?? packId}.{packId}";
|
||||
var escapedAppleId = Regex.Replace(appleId, @"[^\w\.]", "_");
|
||||
var appleSafeVersion = NuGetVersion.Parse(packVersion).Version.ToString();
|
||||
|
||||
var info = new AppInfo {
|
||||
SQPackId = packId,
|
||||
SQPackAuthors = packAuthors,
|
||||
CFBundleName = packTitle ?? packId,
|
||||
//CFBundleDisplayName = packTitle ?? packId,
|
||||
CFBundleExecutable = exeName,
|
||||
CFBundleIdentifier = options.BundleId ?? escapedAppleId,
|
||||
CFBundlePackageType = "APPL",
|
||||
CFBundleShortVersionString = appleSafeVersion,
|
||||
CFBundleVersion = packVersion,
|
||||
CFBundleSignature = "????",
|
||||
NSPrincipalClass = "NSApplication",
|
||||
NSHighResolutionCapable = true,
|
||||
CFBundleIconFile = Path.GetFileName(icon),
|
||||
};
|
||||
|
||||
_logger.Info("Creating '.app' directory structure");
|
||||
var builder = new StructureBuilder(packId, releaseDir.FullName);
|
||||
if (Directory.Exists(builder.AppDirectory)) {
|
||||
_logger.Warn(builder.AppDirectory + " already exists, deleting...");
|
||||
Utility.DeleteFileOrDirectoryHard(builder.AppDirectory);
|
||||
}
|
||||
|
||||
builder.Build();
|
||||
|
||||
_logger.Info("Writing Info.plist");
|
||||
var plist = new PlistWriter(_logger, info, builder.ContentsDirectory);
|
||||
plist.Write();
|
||||
|
||||
_logger.Info("Copying resources into new '.app' bundle");
|
||||
File.Copy(icon, Path.Combine(builder.ResourcesDirectory, Path.GetFileName(icon)));
|
||||
|
||||
_logger.Info("Copying application files into new '.app' bundle");
|
||||
Utility.CopyFiles(new DirectoryInfo(packDirectory), new DirectoryInfo(builder.MacosDirectory));
|
||||
|
||||
_logger.Info("Bundle created successfully: " + builder.AppDirectory);
|
||||
}
|
||||
}
|
||||
22
src/Squirrel.Packaging.OSX/Commands/OsxBundleOptions.cs
Normal file
22
src/Squirrel.Packaging.OSX/Commands/OsxBundleOptions.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace Squirrel.Packaging.OSX.Commands;
|
||||
|
||||
public class OsxBundleOptions
|
||||
{
|
||||
public DirectoryInfo ReleaseDir { get; set; }
|
||||
|
||||
public string PackId { get; set; }
|
||||
|
||||
public string PackVersion { get; set; }
|
||||
|
||||
public string PackDirectory { get; set; }
|
||||
|
||||
public string PackAuthors { get; set; }
|
||||
|
||||
public string PackTitle { get; set; }
|
||||
|
||||
public string EntryExecutableName { get; set; }
|
||||
|
||||
public string Icon { get; set; }
|
||||
|
||||
public string BundleId { get; set; }
|
||||
}
|
||||
148
src/Squirrel.Packaging.OSX/Commands/OsxReleasifyCommandRunner.cs
Normal file
148
src/Squirrel.Packaging.OSX/Commands/OsxReleasifyCommandRunner.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NuGet.Versioning;
|
||||
|
||||
namespace Squirrel.Packaging.OSX.Commands;
|
||||
|
||||
public class OsxReleasifyCommandRunner
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public OsxReleasifyCommandRunner(ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Releasify(OsxReleasifyOptions options)
|
||||
{
|
||||
var releaseDir = options.ReleaseDir;
|
||||
|
||||
var appBundlePath = options.BundleDirectory;
|
||||
_logger.Info("Creating Squirrel application from app bundle at: " + appBundlePath);
|
||||
|
||||
_logger.Info("Parsing app Info.plist");
|
||||
var contentsDir = Path.Combine(appBundlePath, "Contents");
|
||||
|
||||
if (!Directory.Exists(contentsDir))
|
||||
throw new Exception("Invalid bundle structure (missing Contents dir)");
|
||||
|
||||
var plistPath = Path.Combine(contentsDir, "Info.plist");
|
||||
if (!File.Exists(plistPath))
|
||||
throw new Exception("Invalid bundle structure (missing Info.plist)");
|
||||
|
||||
var rootDict = (NSDictionary) PropertyListParser.Parse(plistPath);
|
||||
var packId = rootDict.ObjectForKey(nameof(AppInfo.SQPackId))?.ToString();
|
||||
if (string.IsNullOrWhiteSpace(packId))
|
||||
packId = rootDict.ObjectForKey(nameof(AppInfo.CFBundleIdentifier))?.ToString();
|
||||
|
||||
var packAuthors = rootDict.ObjectForKey(nameof(AppInfo.SQPackAuthors))?.ToString();
|
||||
if (string.IsNullOrWhiteSpace(packAuthors))
|
||||
packAuthors = packId;
|
||||
|
||||
var packTitle = rootDict.ObjectForKey(nameof(AppInfo.CFBundleName))?.ToString();
|
||||
var packVersion = rootDict.ObjectForKey(nameof(AppInfo.CFBundleVersion))?.ToString();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(packId))
|
||||
throw new InvalidOperationException($"Invalid CFBundleIdentifier in Info.plist: '{packId}'");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(packTitle))
|
||||
throw new InvalidOperationException($"Invalid CFBundleName in Info.plist: '{packTitle}'");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(packVersion) || !NuGetVersion.TryParse(packVersion, out var _))
|
||||
throw new InvalidOperationException($"Invalid CFBundleVersion in Info.plist: '{packVersion}'");
|
||||
|
||||
_logger.Info($"Package valid: '{packId}', Name: '{packTitle}', Version: {packVersion}");
|
||||
|
||||
_logger.Info("Adding Squirrel resources to bundle.");
|
||||
var nuspecText = NugetConsole.CreateNuspec(
|
||||
packId, packTitle, packAuthors, packVersion, options.ReleaseNotes, options.IncludePdb);
|
||||
var nuspecPath = Path.Combine(contentsDir, Utility.SpecVersionFileName);
|
||||
|
||||
var helper = new HelperExe(_logger);
|
||||
|
||||
// nuspec and UpdateMac need to be in contents dir or this package can't update
|
||||
File.WriteAllText(nuspecPath, nuspecText);
|
||||
File.Copy(helper.UpdateMacPath, Path.Combine(contentsDir, "UpdateMac"), true);
|
||||
|
||||
var zipPath = Path.Combine(releaseDir.FullName, $"{packId}-{options.TargetRuntime.StringWithNoVersion}.zip");
|
||||
if (File.Exists(zipPath)) File.Delete(zipPath);
|
||||
|
||||
// code signing all mach-o binaries
|
||||
if (!string.IsNullOrEmpty(options.SigningAppIdentity) && !string.IsNullOrEmpty(options.NotaryProfile)) {
|
||||
helper.CodeSign(options.SigningAppIdentity, options.SigningEntitlements, appBundlePath);
|
||||
helper.CreateDittoZip(appBundlePath, zipPath);
|
||||
helper.Notarize(zipPath, options.NotaryProfile);
|
||||
helper.Staple(appBundlePath);
|
||||
helper.SpctlAssessCode(appBundlePath);
|
||||
File.Delete(zipPath);
|
||||
} else {
|
||||
_logger.Warn("Package will not be signed or notarized. Requires the --signAppIdentity and --notaryProfile options.");
|
||||
}
|
||||
|
||||
// create a portable zip package from signed/notarized bundle
|
||||
_logger.Info("Creating final application artifact (zip)");
|
||||
helper.CreateDittoZip(appBundlePath, zipPath);
|
||||
|
||||
// create release / delta from notarized .app
|
||||
_logger.Info("Creating Squirrel Release");
|
||||
using var _ = Utility.GetTempDirectory(out var tmp);
|
||||
var nuget = new NugetConsole(_logger);
|
||||
var nupkgPath = nuget.CreatePackageFromNuspecPath(tmp, appBundlePath, nuspecPath);
|
||||
|
||||
var releaseFilePath = Path.Combine(releaseDir.FullName, "RELEASES");
|
||||
var releases = new Dictionary<string, ReleaseEntry>();
|
||||
|
||||
ReleaseEntry.BuildReleasesFile(releaseDir.FullName);
|
||||
foreach (var rel in ReleaseEntry.ParseReleaseFile(File.ReadAllText(releaseFilePath, Encoding.UTF8))) {
|
||||
releases[rel.Filename] = rel;
|
||||
}
|
||||
|
||||
var rp = new ReleasePackageBuilder(_logger, nupkgPath);
|
||||
var suggestedName = ReleasePackageBuilder.GetSuggestedFileName(packId, packVersion, options.TargetRuntime.StringWithNoVersion);
|
||||
var newPkgPath = rp.CreateReleasePackage((i, pkg) => Path.Combine(releaseDir.FullName, suggestedName));
|
||||
|
||||
_logger.Info("Creating Delta Packages");
|
||||
var prev = ReleasePackageBuilder.GetPreviousRelease(_logger, releases.Values, rp, releaseDir.FullName, options.TargetRuntime);
|
||||
if (prev != null && !options.NoDelta) {
|
||||
var deltaBuilder = new DeltaPackageBuilder(_logger);
|
||||
var deltaFile = rp.ReleasePackageFile.Replace("-full", "-delta");
|
||||
var dp = deltaBuilder.CreateDeltaPackage(prev, rp, deltaFile);
|
||||
var deltaEntry = ReleaseEntry.GenerateFromFile(deltaFile);
|
||||
releases[deltaEntry.Filename] = deltaEntry;
|
||||
}
|
||||
|
||||
var fullEntry = ReleaseEntry.GenerateFromFile(newPkgPath);
|
||||
releases[fullEntry.Filename] = fullEntry;
|
||||
|
||||
ReleaseEntry.WriteReleaseFile(releases.Values, releaseFilePath);
|
||||
|
||||
// create installer package, sign and notarize
|
||||
if (!options.NoPackage) {
|
||||
if (SquirrelRuntimeInfo.IsOSX) {
|
||||
var pkgPath = Path.Combine(releaseDir.FullName, $"{packId}-{options.TargetRuntime.StringWithNoVersion}.pkg");
|
||||
|
||||
Dictionary<string, string> pkgContent = new() {
|
||||
{"welcome", options.PackageWelcome },
|
||||
{"license", options.PackageLicense },
|
||||
{"readme", options.PackageReadme },
|
||||
{"conclusion", options.PackageConclusion },
|
||||
};
|
||||
|
||||
helper.CreateInstallerPkg(appBundlePath, packTitle, pkgContent, pkgPath, options.SigningInstallIdentity);
|
||||
if (!string.IsNullOrEmpty(options.SigningInstallIdentity) && !string.IsNullOrEmpty(options.NotaryProfile)) {
|
||||
helper.Notarize(pkgPath, options.NotaryProfile);
|
||||
helper.Staple(pkgPath);
|
||||
helper.SpctlAssessInstaller(pkgPath);
|
||||
} else {
|
||||
_logger.Warn("Package installer (.pkg) will not be Notarized. " +
|
||||
"This is supported with the --signInstallIdentity and --notaryProfile arguments.");
|
||||
}
|
||||
} else {
|
||||
_logger.Warn("Package installer (.pkg) will not be created - this is only supported on OSX.");
|
||||
}
|
||||
}
|
||||
|
||||
_logger.Info("Done.");
|
||||
}
|
||||
}
|
||||
34
src/Squirrel.Packaging.OSX/Commands/OsxReleasifyOptions.cs
Normal file
34
src/Squirrel.Packaging.OSX/Commands/OsxReleasifyOptions.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
namespace Squirrel.Packaging.OSX.Commands;
|
||||
|
||||
public class OsxReleasifyOptions
|
||||
{
|
||||
public DirectoryInfo ReleaseDir { get; set; }
|
||||
|
||||
public RID TargetRuntime { get; set; }
|
||||
|
||||
public string BundleDirectory { get; set; }
|
||||
|
||||
public bool IncludePdb { get; set; }
|
||||
|
||||
public string ReleaseNotes { get; set; }
|
||||
|
||||
public bool NoDelta { get; set; }
|
||||
|
||||
public bool NoPackage { get; set; }
|
||||
|
||||
public string PackageWelcome { get; set; }
|
||||
|
||||
public string PackageReadme { get; set; }
|
||||
|
||||
public string PackageLicense { get; set; }
|
||||
|
||||
public string PackageConclusion { get; set; }
|
||||
|
||||
public string SigningAppIdentity { get; set; }
|
||||
|
||||
public string SigningInstallIdentity { get; set; }
|
||||
|
||||
public string SigningEntitlements { get; set; }
|
||||
|
||||
public string NotaryProfile { get; set; }
|
||||
}
|
||||
@@ -1,262 +0,0 @@
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NuGet.Versioning;
|
||||
|
||||
namespace Squirrel.Packaging.OSX;
|
||||
|
||||
public class BundleOsxOptions
|
||||
{
|
||||
public DirectoryInfo ReleaseDir { get; set; }
|
||||
|
||||
public string PackId { get; set; }
|
||||
|
||||
public string PackVersion { get; set; }
|
||||
|
||||
public string PackDirectory { get; set; }
|
||||
|
||||
public string PackAuthors { get; set; }
|
||||
|
||||
public string PackTitle { get; set; }
|
||||
|
||||
public string EntryExecutableName { get; set; }
|
||||
|
||||
public string Icon { get; set; }
|
||||
|
||||
public string BundleId { get; set; }
|
||||
}
|
||||
|
||||
public class ReleasifyOsxOptions
|
||||
{
|
||||
public DirectoryInfo ReleaseDir { get; set; }
|
||||
|
||||
public RID TargetRuntime { get; set; }
|
||||
|
||||
public string BundleDirectory { get; set; }
|
||||
|
||||
public bool IncludePdb { get; set; }
|
||||
|
||||
public string ReleaseNotes { get; set; }
|
||||
|
||||
public bool NoDelta { get; set; }
|
||||
|
||||
public bool NoPackage { get; set; }
|
||||
|
||||
public string PackageWelcome { get; set; }
|
||||
|
||||
public string PackageReadme { get; set; }
|
||||
|
||||
public string PackageLicense { get; set; }
|
||||
|
||||
public string PackageConclusion { get; set; }
|
||||
|
||||
public string SigningAppIdentity { get; set; }
|
||||
|
||||
public string SigningInstallIdentity { get; set; }
|
||||
|
||||
public string SigningEntitlements { get; set; }
|
||||
|
||||
public string NotaryProfile { get; set; }
|
||||
}
|
||||
|
||||
public class OsxCommands
|
||||
{
|
||||
public ILogger Log { get; }
|
||||
|
||||
public OsxCommands(ILogger logger)
|
||||
{
|
||||
Log = logger;
|
||||
}
|
||||
|
||||
|
||||
public void Bundle(BundleOsxOptions options)
|
||||
{
|
||||
var icon = options.Icon;
|
||||
var packId = options.PackId;
|
||||
var packDirectory = options.PackDirectory;
|
||||
var packVersion = options.PackVersion;
|
||||
var exeName = options.EntryExecutableName;
|
||||
var packAuthors = options.PackAuthors;
|
||||
var packTitle = options.PackTitle;
|
||||
var releaseDir = options.ReleaseDir;
|
||||
|
||||
Log.Info("Generating new '.app' bundle from a directory of application files.");
|
||||
|
||||
var mainExePath = Path.Combine(packDirectory, exeName);
|
||||
if (!File.Exists(mainExePath))// || !PlatformUtil.IsMachOImage(mainExePath))
|
||||
throw new ArgumentException($"--exeName '{mainExePath}' does not exist or is not a mach-o executable.");
|
||||
|
||||
var appleId = $"com.{packAuthors ?? packId}.{packId}";
|
||||
var escapedAppleId = Regex.Replace(appleId, @"[^\w\.]", "_");
|
||||
var appleSafeVersion = NuGetVersion.Parse(packVersion).Version.ToString();
|
||||
|
||||
var info = new AppInfo {
|
||||
SQPackId = packId,
|
||||
SQPackAuthors = packAuthors,
|
||||
CFBundleName = packTitle ?? packId,
|
||||
//CFBundleDisplayName = packTitle ?? packId,
|
||||
CFBundleExecutable = exeName,
|
||||
CFBundleIdentifier = options.BundleId ?? escapedAppleId,
|
||||
CFBundlePackageType = "APPL",
|
||||
CFBundleShortVersionString = appleSafeVersion,
|
||||
CFBundleVersion = packVersion,
|
||||
CFBundleSignature = "????",
|
||||
NSPrincipalClass = "NSApplication",
|
||||
NSHighResolutionCapable = true,
|
||||
CFBundleIconFile = Path.GetFileName(icon),
|
||||
};
|
||||
|
||||
Log.Info("Creating '.app' directory structure");
|
||||
var builder = new StructureBuilder(packId, releaseDir.FullName);
|
||||
if (Directory.Exists(builder.AppDirectory)) {
|
||||
Log.Warn(builder.AppDirectory + " already exists, deleting...");
|
||||
Utility.DeleteFileOrDirectoryHard(builder.AppDirectory);
|
||||
}
|
||||
|
||||
builder.Build();
|
||||
|
||||
Log.Info("Writing Info.plist");
|
||||
var plist = new PlistWriter(Log, info, builder.ContentsDirectory);
|
||||
plist.Write();
|
||||
|
||||
Log.Info("Copying resources into new '.app' bundle");
|
||||
File.Copy(icon, Path.Combine(builder.ResourcesDirectory, Path.GetFileName(icon)));
|
||||
|
||||
Log.Info("Copying application files into new '.app' bundle");
|
||||
Utility.CopyFiles(new DirectoryInfo(packDirectory), new DirectoryInfo(builder.MacosDirectory));
|
||||
|
||||
Log.Info("Bundle created successfully: " + builder.AppDirectory);
|
||||
}
|
||||
|
||||
public void Releasify(ReleasifyOsxOptions options)
|
||||
{
|
||||
var releaseDir = options.ReleaseDir;
|
||||
|
||||
var appBundlePath = options.BundleDirectory;
|
||||
Log.Info("Creating Squirrel application from app bundle at: " + appBundlePath);
|
||||
|
||||
Log.Info("Parsing app Info.plist");
|
||||
var contentsDir = Path.Combine(appBundlePath, "Contents");
|
||||
|
||||
if (!Directory.Exists(contentsDir))
|
||||
throw new Exception("Invalid bundle structure (missing Contents dir)");
|
||||
|
||||
var plistPath = Path.Combine(contentsDir, "Info.plist");
|
||||
if (!File.Exists(plistPath))
|
||||
throw new Exception("Invalid bundle structure (missing Info.plist)");
|
||||
|
||||
NSDictionary rootDict = (NSDictionary) PropertyListParser.Parse(plistPath);
|
||||
var packId = rootDict.ObjectForKey(nameof(AppInfo.SQPackId))?.ToString();
|
||||
if (String.IsNullOrWhiteSpace(packId))
|
||||
packId = rootDict.ObjectForKey(nameof(AppInfo.CFBundleIdentifier))?.ToString();
|
||||
|
||||
var packAuthors = rootDict.ObjectForKey(nameof(AppInfo.SQPackAuthors))?.ToString();
|
||||
if (String.IsNullOrWhiteSpace(packAuthors))
|
||||
packAuthors = packId;
|
||||
|
||||
var packTitle = rootDict.ObjectForKey(nameof(AppInfo.CFBundleName))?.ToString();
|
||||
var packVersion = rootDict.ObjectForKey(nameof(AppInfo.CFBundleVersion))?.ToString();
|
||||
|
||||
if (String.IsNullOrWhiteSpace(packId))
|
||||
throw new InvalidOperationException($"Invalid CFBundleIdentifier in Info.plist: '{packId}'");
|
||||
|
||||
if (String.IsNullOrWhiteSpace(packTitle))
|
||||
throw new InvalidOperationException($"Invalid CFBundleName in Info.plist: '{packTitle}'");
|
||||
|
||||
if (String.IsNullOrWhiteSpace(packVersion) || !NuGetVersion.TryParse(packVersion, out var _))
|
||||
throw new InvalidOperationException($"Invalid CFBundleVersion in Info.plist: '{packVersion}'");
|
||||
|
||||
Log.Info($"Package valid: '{packId}', Name: '{packTitle}', Version: {packVersion}");
|
||||
|
||||
Log.Info("Adding Squirrel resources to bundle.");
|
||||
var nuspecText = NugetConsole.CreateNuspec(
|
||||
packId, packTitle, packAuthors, packVersion, options.ReleaseNotes, options.IncludePdb);
|
||||
var nuspecPath = Path.Combine(contentsDir, Utility.SpecVersionFileName);
|
||||
|
||||
var helper = new HelperExe(Log);
|
||||
|
||||
// nuspec and UpdateMac need to be in contents dir or this package can't update
|
||||
File.WriteAllText(nuspecPath, nuspecText);
|
||||
File.Copy(helper.UpdateMacPath, Path.Combine(contentsDir, "UpdateMac"), true);
|
||||
|
||||
var zipPath = Path.Combine(releaseDir.FullName, $"{packId}-{options.TargetRuntime.StringWithNoVersion}.zip");
|
||||
if (File.Exists(zipPath)) File.Delete(zipPath);
|
||||
|
||||
// code signing all mach-o binaries
|
||||
if (!String.IsNullOrEmpty(options.SigningAppIdentity) && !String.IsNullOrEmpty(options.NotaryProfile)) {
|
||||
helper.CodeSign(options.SigningAppIdentity, options.SigningEntitlements, appBundlePath);
|
||||
helper.CreateDittoZip(appBundlePath, zipPath);
|
||||
helper.Notarize(zipPath, options.NotaryProfile);
|
||||
helper.Staple(appBundlePath);
|
||||
helper.SpctlAssessCode(appBundlePath);
|
||||
File.Delete(zipPath);
|
||||
} else {
|
||||
Log.Warn("Package will not be signed or notarized. Requires the --signAppIdentity and --notaryProfile options.");
|
||||
}
|
||||
|
||||
// create a portable zip package from signed/notarized bundle
|
||||
Log.Info("Creating final application artifact (zip)");
|
||||
helper.CreateDittoZip(appBundlePath, zipPath);
|
||||
|
||||
// create release / delta from notarized .app
|
||||
Log.Info("Creating Squirrel Release");
|
||||
using var _ = Utility.GetTempDirectory(out var tmp);
|
||||
var nuget = new NugetConsole(Log);
|
||||
var nupkgPath = nuget.CreatePackageFromNuspecPath(tmp, appBundlePath, nuspecPath);
|
||||
|
||||
var releaseFilePath = Path.Combine(releaseDir.FullName, "RELEASES");
|
||||
var releases = new Dictionary<string, ReleaseEntry>();
|
||||
|
||||
ReleaseEntry.BuildReleasesFile(releaseDir.FullName);
|
||||
foreach (var rel in ReleaseEntry.ParseReleaseFile(File.ReadAllText(releaseFilePath, Encoding.UTF8))) {
|
||||
releases[rel.Filename] = rel;
|
||||
}
|
||||
|
||||
var rp = new ReleasePackageBuilder(Log, nupkgPath);
|
||||
var suggestedName = ReleasePackageBuilder.GetSuggestedFileName(packId, packVersion, options.TargetRuntime.StringWithNoVersion);
|
||||
var newPkgPath = rp.CreateReleasePackage((i, pkg) => Path.Combine(releaseDir.FullName, suggestedName));
|
||||
|
||||
Log.Info("Creating Delta Packages");
|
||||
var prev = ReleasePackageBuilder.GetPreviousRelease(Log, releases.Values, rp, releaseDir.FullName, options.TargetRuntime);
|
||||
if (prev != null && !options.NoDelta) {
|
||||
var deltaBuilder = new DeltaPackageBuilder(Log);
|
||||
var deltaFile = rp.ReleasePackageFile.Replace("-full", "-delta");
|
||||
var dp = deltaBuilder.CreateDeltaPackage(prev, rp, deltaFile);
|
||||
var deltaEntry = ReleaseEntry.GenerateFromFile(deltaFile);
|
||||
releases[deltaEntry.Filename] = deltaEntry;
|
||||
}
|
||||
|
||||
var fullEntry = ReleaseEntry.GenerateFromFile(newPkgPath);
|
||||
releases[fullEntry.Filename] = fullEntry;
|
||||
|
||||
ReleaseEntry.WriteReleaseFile(releases.Values, releaseFilePath);
|
||||
|
||||
// create installer package, sign and notarize
|
||||
if (!options.NoPackage) {
|
||||
if (SquirrelRuntimeInfo.IsOSX) {
|
||||
var pkgPath = Path.Combine(releaseDir.FullName, $"{packId}-{options.TargetRuntime.StringWithNoVersion}.pkg");
|
||||
|
||||
Dictionary<string, string> pkgContent = new() {
|
||||
{"welcome", options.PackageWelcome },
|
||||
{"license", options.PackageLicense },
|
||||
{"readme", options.PackageReadme },
|
||||
{"conclusion", options.PackageConclusion },
|
||||
};
|
||||
|
||||
helper.CreateInstallerPkg(appBundlePath, packTitle, pkgContent, pkgPath, options.SigningInstallIdentity);
|
||||
if (!String.IsNullOrEmpty(options.SigningInstallIdentity) && !String.IsNullOrEmpty(options.NotaryProfile)) {
|
||||
helper.Notarize(pkgPath, options.NotaryProfile);
|
||||
helper.Staple(pkgPath);
|
||||
helper.SpctlAssessInstaller(pkgPath);
|
||||
} else {
|
||||
Log.Warn("Package installer (.pkg) will not be Notarized. " +
|
||||
"This is supported with the --signInstallIdentity and --notaryProfile arguments.");
|
||||
}
|
||||
} else {
|
||||
Log.Warn("Package installer (.pkg) will not be created - this is only supported on OSX.");
|
||||
}
|
||||
}
|
||||
|
||||
Log.Info("Done.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System.Drawing;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Squirrel.NuGet;
|
||||
using FileMode = System.IO.FileMode;
|
||||
|
||||
namespace Squirrel.Packaging.Windows.Commands;
|
||||
|
||||
public class WindowsPackCommandRunner
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public WindowsPackCommandRunner(ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Pack(WindowsPackOptions options)
|
||||
{
|
||||
using (Utility.GetTempDirectory(out var tmp)) {
|
||||
var nupkgPath = new NugetConsole(_logger).CreatePackageFromOptions(tmp, options);
|
||||
options.Package = nupkgPath;
|
||||
var runner = new WindowsReleasifyCommandRunner(_logger);
|
||||
runner.Releasify(options);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace Squirrel.Packaging.Windows.Commands;
|
||||
|
||||
public class WindowsPackOptions : WindowsReleasifyOptions, INugetPackCommand
|
||||
{
|
||||
public string PackId { get; set; }
|
||||
|
||||
public string PackVersion { get; set; }
|
||||
|
||||
public string PackDirectory { get; set; }
|
||||
|
||||
public string PackAuthors { get; set; }
|
||||
|
||||
public string PackTitle { get; set; }
|
||||
|
||||
public bool IncludePdb { get; set; }
|
||||
|
||||
public string ReleaseNotes { get; set; }
|
||||
}
|
||||
@@ -4,87 +4,24 @@ using Microsoft.Extensions.Logging;
|
||||
using Squirrel.NuGet;
|
||||
using FileMode = System.IO.FileMode;
|
||||
|
||||
namespace Squirrel.Packaging.Windows;
|
||||
namespace Squirrel.Packaging.Windows.Commands;
|
||||
|
||||
public class SigningOptions
|
||||
public class WindowsReleasifyCommandRunner
|
||||
{
|
||||
public string SignParameters { get; set; }
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public bool SignSkipDll { get; set; }
|
||||
|
||||
public int SignParallel { get; set; }
|
||||
|
||||
public string SignTemplate { get; set; }
|
||||
}
|
||||
|
||||
public class ReleasifyWindowsOptions : SigningOptions
|
||||
{
|
||||
public DirectoryInfo ReleaseDir { get; set; }
|
||||
|
||||
public RID TargetRuntime { get; set; }
|
||||
|
||||
public string Package { get; set; }
|
||||
|
||||
public string BaseUrl { get; set; }
|
||||
|
||||
public string DebugSetupExe { get; set; }
|
||||
|
||||
public bool NoDelta { get; set; }
|
||||
|
||||
public string Runtimes { get; set; }
|
||||
|
||||
public string SplashImage { get; set; }
|
||||
|
||||
public string Icon { get; set; }
|
||||
|
||||
public string[] MainExe { get; set; }
|
||||
|
||||
public string AppIcon { get; set; }
|
||||
}
|
||||
|
||||
public class PackWindowsOptions : ReleasifyWindowsOptions, INugetPackCommand
|
||||
{
|
||||
public string PackId { get; set; }
|
||||
|
||||
public string PackVersion { get; set; }
|
||||
|
||||
public string PackDirectory { get; set; }
|
||||
|
||||
public string PackAuthors { get; set; }
|
||||
|
||||
public string PackTitle { get; set; }
|
||||
|
||||
public bool IncludePdb { get; set; }
|
||||
|
||||
public string ReleaseNotes { get; set; }
|
||||
}
|
||||
|
||||
public class WindowsCommands
|
||||
{
|
||||
private readonly ILogger Log;
|
||||
|
||||
public WindowsCommands(ILogger logger)
|
||||
public WindowsReleasifyCommandRunner(ILogger logger)
|
||||
{
|
||||
Log = logger;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Pack(PackWindowsOptions options)
|
||||
{
|
||||
using (Utility.GetTempDirectory(out var tmp)) {
|
||||
var nupkgPath = new NugetConsole(Log).CreatePackageFromOptions(tmp, options);
|
||||
options.Package = nupkgPath;
|
||||
Releasify(options);
|
||||
}
|
||||
}
|
||||
|
||||
public void Releasify(ReleasifyWindowsOptions options)
|
||||
public void Releasify(WindowsReleasifyOptions options)
|
||||
{
|
||||
var targetDir = options.ReleaseDir.FullName;
|
||||
var package = options.Package;
|
||||
var baseUrl = options.BaseUrl;
|
||||
var generateDeltas = !options.NoDelta;
|
||||
var backgroundGif = options.SplashImage;
|
||||
var setupIcon = options.Icon ?? options.AppIcon;
|
||||
var setupIcon = options.Icon;
|
||||
|
||||
// normalize and validate that the provided frameworks are supported
|
||||
var requiredFrameworks = options.Runtimes
|
||||
@@ -97,14 +34,14 @@ public class WindowsCommands
|
||||
using var ud = Utility.GetTempDirectory(out var tempDir);
|
||||
|
||||
// update icon for Update.exe if requested
|
||||
var helper = new HelperExe(Log);
|
||||
var helper = new HelperExe(_logger);
|
||||
var updatePath = Path.Combine(tempDir, "Update.exe");
|
||||
File.Copy(HelperExe.UpdatePath, updatePath, true);
|
||||
|
||||
if (setupIcon != null && SquirrelRuntimeInfo.IsWindows) {
|
||||
helper.SetExeIcon(updatePath, setupIcon);
|
||||
} else if (setupIcon != null) {
|
||||
Log.Warn("Unable to set icon for Update.exe (only supported on windows).");
|
||||
_logger.Warn("Unable to set icon for Update.exe (only supported on windows).");
|
||||
}
|
||||
|
||||
// copy input package to target output directory
|
||||
@@ -123,9 +60,9 @@ public class WindowsCommands
|
||||
}
|
||||
|
||||
foreach (var file in toProcess) {
|
||||
Log.Info("Creating release for package: " + file.FullName);
|
||||
_logger.Info("Creating release for package: " + file.FullName);
|
||||
|
||||
var rp = new ReleasePackageBuilder(Log, file.FullName);
|
||||
var rp = new ReleasePackageBuilder(_logger, file.FullName);
|
||||
rp.CreateReleasePackage(contentsPostProcessHook: (pkgPath, zpkg) => {
|
||||
var nuspecPath = Directory.GetFiles(pkgPath, "*.nuspec", SearchOption.TopDirectoryOnly)
|
||||
.ContextualSingle("package", "*.nuspec", "top level directory");
|
||||
@@ -140,7 +77,7 @@ public class WindowsCommands
|
||||
Directory.EnumerateFiles(libDir, "*", SearchOption.AllDirectories)
|
||||
.Select(f => f.Substring(libDir.Length).Trim(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar))
|
||||
.Where(f => f.Length >= 200)
|
||||
.ForEach(f => Log.Warn($"File path in package exceeds 200 characters ({f.Length}) and may cause issues on Windows: '{f}'."));
|
||||
.ForEach(f => _logger.Warn($"File path in package exceeds 200 characters ({f.Length}) and may cause issues on Windows: '{f}'."));
|
||||
|
||||
// fail the release if this is a clickonce application
|
||||
if (Directory.EnumerateFiles(libDir, "*.application").Any(f => File.ReadAllText(f).Contains("clickonce"))) {
|
||||
@@ -149,7 +86,7 @@ public class WindowsCommands
|
||||
"Please publish your application to a folder without ClickOnce.");
|
||||
}
|
||||
|
||||
ZipPackage.SetMetadata(nuspecPath, requiredFrameworks.Select(r => r.Id), options.TargetRuntime);
|
||||
NuspecManifest.SetMetadata(nuspecPath, requiredFrameworks.Select(r => r.Id), options.TargetRuntime);
|
||||
|
||||
// copy Update.exe into package, so it can also be updated in both full/delta packages
|
||||
// and do it before signing so that Update.exe will also be signed. It is renamed to
|
||||
@@ -164,33 +101,6 @@ public class WindowsCommands
|
||||
|
||||
signFiles(options, libDir, filesToSign);
|
||||
|
||||
// copy app icon to 'lib/fx/app.ico'
|
||||
var iconTarget = Path.Combine(libDir, "app.ico");
|
||||
if (options.AppIcon != null) {
|
||||
// icon was specified on the command line
|
||||
Log.Info("Using app icon from command line arguments");
|
||||
File.Copy(options.AppIcon, iconTarget, true);
|
||||
} else if (!File.Exists(iconTarget) && zpkg.IconUrl != null) {
|
||||
// icon was provided in the nuspec. download it and possibly convert it from a different image format
|
||||
Log.Info($"Downloading app icon from '{zpkg.IconUrl}'.");
|
||||
var fd = Utility.CreateDefaultDownloader();
|
||||
var imgBytes = fd.DownloadBytes(zpkg.IconUrl.ToString()).Result;
|
||||
if (zpkg.IconUrl.AbsolutePath.EndsWith(".ico")) {
|
||||
File.WriteAllBytes(iconTarget, imgBytes);
|
||||
} else {
|
||||
if (SquirrelRuntimeInfo.IsWindows) {
|
||||
using var imgStream = new MemoryStream(imgBytes);
|
||||
using var bmp = (Bitmap) Image.FromStream(imgStream);
|
||||
using var ico = Icon.FromHandle(bmp.GetHicon());
|
||||
using var fs = File.Open(iconTarget, FileMode.Create, FileAccess.Write);
|
||||
ico.Save(fs);
|
||||
} else {
|
||||
Log.Warn($"App icon is currently {Path.GetExtension(zpkg.IconUrl.AbsolutePath)} and can not be automatically " +
|
||||
$"converted to .ico (only supported on windows). Supply a .ico image instead.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// copy other images to root (used by setup)
|
||||
if (setupIcon != null) File.Copy(setupIcon, Path.Combine(pkgPath, "setup.ico"), true);
|
||||
if (backgroundGif != null) File.Copy(backgroundGif, Path.Combine(pkgPath, "splashimage" + Path.GetExtension(backgroundGif)));
|
||||
@@ -200,9 +110,9 @@ public class WindowsCommands
|
||||
|
||||
processed.Add(rp.ReleasePackageFile);
|
||||
|
||||
var prev = ReleasePackageBuilder.GetPreviousRelease(Log, previousReleases, rp, targetDir, options.TargetRuntime);
|
||||
var prev = ReleasePackageBuilder.GetPreviousRelease(_logger, previousReleases, rp, targetDir, options.TargetRuntime);
|
||||
if (prev != null && generateDeltas) {
|
||||
var deltaBuilder = new DeltaPackageBuilder(Log);
|
||||
var deltaBuilder = new DeltaPackageBuilder(_logger);
|
||||
var deltaOutputPath = rp.ReleasePackageFile.Replace("-full", "-delta");
|
||||
var dp = deltaBuilder.CreateDeltaPackage(prev, rp, deltaOutputPath);
|
||||
processed.Insert(0, dp.InputPackageFile);
|
||||
@@ -214,7 +124,7 @@ public class WindowsCommands
|
||||
}
|
||||
|
||||
var newReleaseEntries = processed
|
||||
.Select(packageFilename => ReleaseEntry.GenerateFromFile(packageFilename, baseUrl))
|
||||
.Select(packageFilename => ReleaseEntry.GenerateFromFile(packageFilename))
|
||||
.ToList();
|
||||
var distinctPreviousReleases = previousReleases
|
||||
.Where(x => !newReleaseEntries.Select(e => e.Version).Contains(x.Version));
|
||||
@@ -224,48 +134,42 @@ public class WindowsCommands
|
||||
|
||||
var bundledzp = new ZipPackage(package);
|
||||
var targetSetupExe = Path.Combine(targetDir, $"{bundledzp.Id}Setup-{options.TargetRuntime.StringWithNoVersion}.exe");
|
||||
File.Copy(options.DebugSetupExe ?? HelperExe.SetupPath, targetSetupExe, true);
|
||||
File.Copy(HelperExe.SetupPath, targetSetupExe, true);
|
||||
|
||||
if (SquirrelRuntimeInfo.IsWindows) {
|
||||
helper.SetPEVersionBlockFromPackageInfo(targetSetupExe, bundledzp, setupIcon);
|
||||
} else {
|
||||
Log.Warn("Unable to set Setup.exe icon (only supported on windows)");
|
||||
_logger.Warn("Unable to set Setup.exe icon (only supported on windows)");
|
||||
}
|
||||
|
||||
var newestFullRelease = Squirrel.EnumerableExtensions.MaxBy(releaseEntries, x => x.Version).Where(x => !x.IsDelta).First();
|
||||
var newestFullRelease = releaseEntries.MaxBy(x => x.Version).Where(x => !x.IsDelta).First();
|
||||
var newestReleasePath = Path.Combine(targetDir, newestFullRelease.Filename);
|
||||
|
||||
Log.Info($"Creating Setup bundle");
|
||||
_logger.Info($"Creating Setup bundle");
|
||||
var bundleOffset = SetupBundle.CreatePackageBundle(targetSetupExe, newestReleasePath);
|
||||
Log.Info("Signing Setup bundle");
|
||||
_logger.Info("Signing Setup bundle");
|
||||
signFiles(options, targetDir, targetSetupExe);
|
||||
Log.Info("Bundle package offset is " + bundleOffset);
|
||||
_logger.Info("Bundle package offset is " + bundleOffset);
|
||||
|
||||
Log.Info($"Setup bundle created at '{targetSetupExe}'.");
|
||||
_logger.Info($"Setup bundle created at '{targetSetupExe}'.");
|
||||
|
||||
// this option is used for debugging a local Setup.exe
|
||||
if (options.DebugSetupExe != null) {
|
||||
File.Copy(targetSetupExe, options.DebugSetupExe, true);
|
||||
Log.Warn($"DEBUG OPTION: Setup bundle copied on top of '{options.DebugSetupExe}'. Recompile before creating a new bundle.");
|
||||
}
|
||||
|
||||
Log.Info("Done");
|
||||
_logger.Info("Done");
|
||||
}
|
||||
|
||||
private void signFiles(SigningOptions options, string rootDir, params string[] filePaths)
|
||||
private void signFiles(WindowsSigningOptions options, string rootDir, params string[] filePaths)
|
||||
{
|
||||
var signParams = options.SignParameters;
|
||||
var signTemplate = options.SignTemplate;
|
||||
var signParallel = options.SignParallel;
|
||||
var helper = new HelperExe(Log);
|
||||
var helper = new HelperExe(_logger);
|
||||
|
||||
if (String.IsNullOrEmpty(signParams) && String.IsNullOrEmpty(signTemplate)) {
|
||||
Log.Debug($"No signing paramaters provided, {filePaths.Length} file(s) will not be signed.");
|
||||
if (string.IsNullOrEmpty(signParams) && string.IsNullOrEmpty(signTemplate)) {
|
||||
_logger.Debug($"No signing paramaters provided, {filePaths.Length} file(s) will not be signed.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(signTemplate)) {
|
||||
Log.Info($"Preparing to sign {filePaths.Length} files with custom signing template");
|
||||
if (!string.IsNullOrEmpty(signTemplate)) {
|
||||
_logger.Info($"Preparing to sign {filePaths.Length} files with custom signing template");
|
||||
foreach (var f in filePaths) {
|
||||
helper.SignPEFileWithTemplate(f, signTemplate);
|
||||
}
|
||||
@@ -275,8 +179,8 @@ public class WindowsCommands
|
||||
// signtool.exe does not work if we're not on windows.
|
||||
if (!SquirrelRuntimeInfo.IsWindows) return;
|
||||
|
||||
if (!String.IsNullOrEmpty(signParams)) {
|
||||
Log.Info($"Preparing to sign {filePaths.Length} files with embedded signtool.exe with parallelism of {signParallel}");
|
||||
if (!string.IsNullOrEmpty(signParams)) {
|
||||
_logger.Info($"Preparing to sign {filePaths.Length} files with embedded signtool.exe with parallelism of {signParallel}");
|
||||
helper.SignPEFilesWithSignTool(rootDir, filePaths, signParams, signParallel);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
namespace Squirrel.Packaging.Windows.Commands;
|
||||
|
||||
public class WindowsReleasifyOptions : WindowsSigningOptions
|
||||
{
|
||||
public DirectoryInfo ReleaseDir { get; set; }
|
||||
|
||||
public RID TargetRuntime { get; set; }
|
||||
|
||||
public string Package { get; set; }
|
||||
|
||||
public bool NoDelta { get; set; }
|
||||
|
||||
public string Runtimes { get; set; }
|
||||
|
||||
public string SplashImage { get; set; }
|
||||
|
||||
public string Icon { get; set; }
|
||||
|
||||
public string EntryExecutableName { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace Squirrel.Packaging.Windows.Commands;
|
||||
|
||||
public class WindowsSigningOptions
|
||||
{
|
||||
public string SignParameters { get; set; }
|
||||
|
||||
public bool SignSkipDll { get; set; }
|
||||
|
||||
public int SignParallel { get; set; }
|
||||
|
||||
public string SignTemplate { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user