Refactor cli and add delta commands

This commit is contained in:
Caelan Sayler
2023-12-30 17:30:10 +00:00
parent 66b214252e
commit 1ad0b01eda
30 changed files with 378 additions and 148 deletions

View File

@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Octokit;
using Squirrel.Packaging;
namespace Squirrel.Csq.Commands
{
public class DeltaGenCommand : BaseCommand
{
public DeltaMode Delta { get; set; }
public string BasePackage { get; set; }
public string NewPackage { get; set; }
public string OutputFile { get; set; }
public DeltaGenCommand()
: base("generate", "Generate a delta patch from two full releases.")
{
AddOption<DeltaMode>((v) => Delta = v, "--mode")
.SetDefault(DeltaMode.BestSpeed)
.SetDescription("Set the delta generation mode.");
AddOption<FileInfo>((v) => BasePackage = v.ToFullNameOrNull(), "--base", "-b")
.SetDescription("The base package for the created patch.")
.SetArgumentHelpName("PATH")
.RequiresExtension(".nupkg")
.MustExist()
.SetRequired();
AddOption<FileInfo>((v) => NewPackage = v.ToFullNameOrNull(), "--new", "-n")
.SetDescription("The resulting package for the created patch.")
.SetArgumentHelpName("PATH")
.RequiresExtension(".nupkg")
.MustExist()
.SetRequired();
AddOption<FileInfo>((v) => OutputFile = v.ToFullNameOrNull(), "--output", "-o")
.SetDescription("The output file path for the created patch.")
.SetArgumentHelpName("PATH")
.SetRequired();
}
}
}

View File

@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Squirrel.Packaging;
namespace Squirrel.Csq.Commands
{
public class DeltaPatchCommand : BaseCommand
{
public string BasePackage { get; set; }
public FileInfo[] PatchFiles { get; set; }
public string OutputFile { get; set; }
public DeltaPatchCommand()
: base("patch", "Patch a base package and retrieve the original new package.")
{
AddOption<FileInfo>((v) => BasePackage = v.ToFullNameOrNull(), "--base", "-b")
.SetDescription("The base package for the created patch.")
.SetArgumentHelpName("PATH")
.RequiresExtension(".nupkg")
.MustExist()
.SetRequired();
AddMultipleTokenOption<FileInfo[]>((v) => PatchFiles = v, "--patch", "-p")
.SetDescription("The resulting package for the created patch.")
.SetArgumentHelpName("PATH");
AddOption<FileInfo>((v) => OutputFile = v.ToFullNameOrNull(), "--output", "-o")
.SetDescription("The output file path for the created patch.")
.SetArgumentHelpName("PATH")
.SetRequired();
}
}
}

View File

@@ -1,6 +1,6 @@
namespace Squirrel.Csq.Commands;
public abstract class GitHubBaseCommand : BaseCommand
public abstract class GitHubBaseCommand : OutputCommand
{
public string RepoUrl { get; private set; }

View File

@@ -1,6 +1,6 @@
namespace Squirrel.Csq.Commands;
public class HttpDownloadCommand : BaseCommand
public class HttpDownloadCommand : OutputCommand
{
public string Url { get; private set; }

View File

@@ -1,6 +1,6 @@
namespace Squirrel.Csq.Commands;
public class OsxBundleCommand : BaseCommand
public class OsxBundleCommand : OutputCommand
{
public string PackId { get; private set; }

View File

@@ -2,7 +2,7 @@
namespace Squirrel.Csq.Commands;
public class OsxReleasifyCommand : BaseCommand
public class OsxReleasifyCommand : PlatformCommand
{
public string BundleDirectory { get; private set; }

View File

@@ -1,7 +1,7 @@

namespace Squirrel.Csq.Commands;
public class S3BaseCommand : BaseCommand
public class S3BaseCommand : OutputCommand
{
public string KeyId { get; private set; }

View File

@@ -3,7 +3,7 @@ using Squirrel.Packaging;
namespace Squirrel.Csq.Commands;
public class WindowsSigningCommand : BaseCommand
public class WindowsSigningCommand : PlatformCommand
{
public string SignParameters { get; private set; }

View File

@@ -2,33 +2,23 @@
public class BaseCommand : CliCommand
{
public RID TargetRuntime { get; set; }
public string ReleaseDirectory { get; private set; }
protected CliOption<DirectoryInfo> ReleaseDirectoryOption { get; private set; }
private Dictionary<CliOption, Action<ParseResult>> _setters = new();
protected BaseCommand(string name, string description)
: base(name, description)
{
ReleaseDirectoryOption = AddOption<DirectoryInfo>((v) => ReleaseDirectory = v.ToFullNameOrNull(), "-o", "--outputDir")
.SetDescription("Output directory for Squirrel packages.")
.SetArgumentHelpName("DIR")
.SetDefault(new DirectoryInfo(".\\Releases"));
}
public DirectoryInfo GetReleaseDirectory()
{
var di = new DirectoryInfo(ReleaseDirectory);
if (!di.Exists) di.Create();
return di;
}
protected virtual CliOption<T> AddOption<T>(Action<T> setValue, params string[] aliases)
{
return AddOption(setValue, new CliOption<T>(aliases.OrderBy(a => a.Length).First(), aliases));
return AddOption(setValue, new CliOption<T>(aliases.OrderByDescending(a => a.Length).First(), aliases));
}
protected virtual CliOption<T> AddMultipleTokenOption<T>(Action<T> setValue, params string[] aliases)
{
var opt = new CliOption<T>(aliases.OrderByDescending(a => a.Length).First(), aliases);
opt.AllowMultipleArgumentsPerToken = true;
return AddOption(setValue, opt);
}
protected virtual CliOption<T> AddOption<T>(Action<T> setValue, CliOption<T> opt)

View File

@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Squirrel.Csq.Commands
{
public class OutputCommand : BaseCommand
{
public string ReleaseDirectory { get; private set; }
protected CliOption<DirectoryInfo> ReleaseDirectoryOption { get; private set; }
protected OutputCommand(string name, string description)
: base(name, description)
{
ReleaseDirectoryOption = AddOption<DirectoryInfo>((v) => ReleaseDirectory = v.ToFullNameOrNull(), "-o", "--outputDir")
.SetDescription("Output directory for Squirrel packages.")
.SetArgumentHelpName("DIR")
.SetDefault(new DirectoryInfo(".\\Releases"));
}
public DirectoryInfo GetReleaseDirectory()
{
var di = new DirectoryInfo(ReleaseDirectory);
if (!di.Exists) di.Create();
return di;
}
}
}

View File

@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Squirrel.Csq.Commands
{
public class PlatformCommand : OutputCommand
{
public string TargetRuntime { get; set; }
public FileSystemInfo SolutionDir { get; set; }
protected PlatformCommand(string name, string description) : base(name, description)
{
TargetRuntime = SquirrelRuntimeInfo.SystemOs.GetOsShortName();
AddOption<string>((v) => TargetRuntime = v, "-r", "--runtime")
.SetDescription("The target runtime to build packages for.")
.SetArgumentHelpName("RID")
.MustBeSupportedRid();
AddOption<FileSystemInfo>((v) => SolutionDir = v, "--sln")
.SetDescription("Explicit path to project solution (.sln)")
.AcceptExistingOnly();
}
public RID GetRid() => RID.Parse(TargetRuntime ?? SquirrelRuntimeInfo.SystemOs.GetOsShortName());
public RuntimeOs GetRuntimeOs() => GetRid().BaseRID;
}
}

View File

@@ -1,6 +1,7 @@
using System.Runtime.Versioning;
using Squirrel.Csq.Commands;
using Squirrel.Deployment;
using Squirrel.Packaging.Commands;
using Squirrel.Packaging.OSX.Commands;
using Squirrel.Packaging.Windows.Commands;
@@ -16,7 +17,7 @@ public class EmbeddedRunner : ICommandRunner
}
[SupportedOSPlatform("osx")]
public Task ExecuteBundleOsx(OsxBundleCommand command)
public virtual Task ExecuteBundleOsx(OsxBundleCommand command)
{
var options = new OsxBundleOptions {
BundleId = command.BundleId,
@@ -34,9 +35,10 @@ public class EmbeddedRunner : ICommandRunner
}
[SupportedOSPlatform("osx")]
public Task ExecuteReleasifyOsx(OsxReleasifyCommand command)
public virtual Task ExecuteReleasifyOsx(OsxReleasifyCommand command)
{
var options = new OsxReleasifyOptions {
TargetRuntime = command.GetRid(),
ReleaseDir = command.GetReleaseDirectory(),
BundleDirectory = command.BundleDirectory,
IncludePdb = command.IncludePdb,
@@ -51,16 +53,15 @@ public class EmbeddedRunner : ICommandRunner
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)
public virtual Task ExecutePackWindows(WindowsPackCommand command)
{
var options = new WindowsPackOptions {
TargetRuntime = command.TargetRuntime,
TargetRuntime = command.GetRid(),
ReleaseDir = command.GetReleaseDirectory(),
Package = command.Package,
Icon = command.Icon,
@@ -84,10 +85,10 @@ public class EmbeddedRunner : ICommandRunner
return Task.CompletedTask;
}
public Task ExecuteReleasifyWindows(WindowsReleasifyCommand command)
public virtual Task ExecuteReleasifyWindows(WindowsReleasifyCommand command)
{
var options = new WindowsReleasifyOptions {
TargetRuntime = command.TargetRuntime,
TargetRuntime = command.GetRid(),
ReleaseDir = command.GetReleaseDirectory(),
Package = command.Package,
Icon = command.Icon,
@@ -104,7 +105,7 @@ public class EmbeddedRunner : ICommandRunner
return Task.CompletedTask;
}
public Task ExecuteGithubDownload(GitHubDownloadCommand command)
public virtual Task ExecuteGithubDownload(GitHubDownloadCommand command)
{
var options = new GitHubDownloadOptions {
Pre = command.Pre,
@@ -115,7 +116,7 @@ public class EmbeddedRunner : ICommandRunner
return new GitHubRepository(_logger).DownloadRecentPackages(options);
}
public Task ExecuteGithubUpload(GitHubUploadCommand command)
public virtual Task ExecuteGithubUpload(GitHubUploadCommand command)
{
var options = new GitHubUploadOptions {
ReleaseDir = command.GetReleaseDirectory(),
@@ -127,7 +128,7 @@ public class EmbeddedRunner : ICommandRunner
return new GitHubRepository(_logger).UploadMissingPackages(options);
}
public Task ExecuteHttpDownload(HttpDownloadCommand command)
public virtual Task ExecuteHttpDownload(HttpDownloadCommand command)
{
var options = new HttpDownloadOptions {
ReleaseDir = command.GetReleaseDirectory(),
@@ -136,7 +137,7 @@ public class EmbeddedRunner : ICommandRunner
return new SimpleWebRepository(_logger).DownloadRecentPackages(options);
}
public Task ExecuteS3Download(S3DownloadCommand command)
public virtual Task ExecuteS3Download(S3DownloadCommand command)
{
var options = new S3Options {
Bucket = command.Bucket,
@@ -151,7 +152,7 @@ public class EmbeddedRunner : ICommandRunner
return new S3Repository(_logger).DownloadRecentPackages(options);
}
public Task ExecuteS3Upload(S3UploadCommand command)
public virtual Task ExecuteS3Upload(S3UploadCommand command)
{
var options = new S3UploadOptions {
Bucket = command.Bucket,
@@ -166,4 +167,25 @@ public class EmbeddedRunner : ICommandRunner
};
return new S3Repository(_logger).UploadMissingPackages(options);
}
public virtual Task ExecuteDeltaGen(DeltaGenCommand command)
{
var options = new DeltaGenOptions {
BasePackage = command.BasePackage,
NewPackage = command.NewPackage,
OutputFile = command.OutputFile,
DeltaMode = command.Delta,
};
return new DeltaGenCommandRunner().Run(options, _logger);
}
public virtual Task ExecuteDeltaPatch(DeltaPatchCommand command)
{
var options = new DeltaPatchOptions {
BasePackage = command.BasePackage,
PatchFiles = command.PatchFiles,
OutputFile = command.OutputFile,
};
return new DeltaPatchCommandRunner().Run(options, _logger);
}
}

View File

@@ -14,4 +14,6 @@ public interface ICommandRunner
public Task ExecuteReleasifyOsx(OsxReleasifyCommand command);
public Task ExecuteReleasifyWindows(WindowsReleasifyCommand command);
public Task ExecutePackWindows(WindowsPackCommand command);
public Task ExecuteDeltaGen(DeltaGenCommand command);
public Task ExecuteDeltaPatch(DeltaPatchCommand command);
}

View File

@@ -1,9 +0,0 @@
using Squirrel.Csq.Commands;
namespace Squirrel.Csq.Compat;
public interface IRunnerFactory
{
public Task CreateAndExecuteAsync<T>(string commandName, T options) where T : BaseCommand;
public Task<ICommandRunner> CreateAsync();
}

View File

@@ -4,35 +4,38 @@ using Squirrel.Csq.Updates;
namespace Squirrel.Csq.Compat;
public class RunnerFactory : IRunnerFactory
public class RunnerFactory
{
private const string CLOWD_PACKAGE_NAME = "Clowd.Squirrel";
private readonly ILogger _logger;
private readonly FileSystemInfo _solution;
private readonly IConfiguration _config;
public RunnerFactory(ILogger logger, FileSystemInfo solution, IConfiguration config)
public RunnerFactory(ILogger logger, IConfiguration config)
{
_logger = logger;
_solution = solution;
this._config = config;
_config = config;
}
public async Task CreateAndExecuteAsync<T>(string commandName, T options) where T : BaseCommand
{
var runner = await CreateAsync();
var runner = await CreateAsync(options);
var method = typeof(ICommandRunner).GetMethod(commandName);
await (Task) method.Invoke(runner, new object[] { options });
}
public async Task<ICommandRunner> CreateAsync()
private async Task<ICommandRunner> CreateAsync<T>(T options)
{
if (_config.GetValue<bool?>("SKIP_UPDATE_CHECK") != true) {
var updateCheck = new UpdateChecker(_logger);
await updateCheck.CheckForUpdates();
}
var solutionDir = FindSolutionDirectory(_solution?.FullName);
if (options is not PlatformCommand) {
return new EmbeddedRunner(_logger);
}
var cmd = (PlatformCommand) (object) options;
var solutionDir = FindSolutionDirectory(cmd.SolutionDir?.FullName);
if (solutionDir is null) {
throw new Exception($"Could not find '.sln'. Specify solution or solution directory with '--solution='.");
@@ -76,7 +79,7 @@ public class RunnerFactory : IRunnerFactory
return new V2CompatRunner(_logger, squirrelExe);
}
throw new NotSupportedException($"Squirrel {version} is installed in this project, but not supported by this version of Csq. Supported versions are [> v2.8] and [> v4.0]");
throw new NotSupportedException($"Squirrel {version} is installed in this project, but not supported by this version of Csq. Supported versions are [>= v2.8] and [>= v4.0]");
}
private string FindSolutionDirectory(string slnArgument)

View File

@@ -3,22 +3,21 @@ using Squirrel.Csq.Commands;
namespace Squirrel.Csq.Compat;
public class V2CompatRunner : ICommandRunner
public class V2CompatRunner : EmbeddedRunner
{
private readonly ILogger _logger;
private readonly string _squirrelExePath;
private readonly EmbeddedRunner _embedded;
public V2CompatRunner(ILogger logger, string squirrelExePath)
: base(logger)
{
_logger = logger;
_squirrelExePath = squirrelExePath;
_embedded = new EmbeddedRunner(logger);
}
public async Task ExecutePackWindows(WindowsPackCommand command)
public override async Task ExecutePackWindows(WindowsPackCommand command)
{
if (!SquirrelRuntimeInfo.IsWindows || command.TargetRuntime.BaseRID != RuntimeOs.Windows) {
if (!SquirrelRuntimeInfo.IsWindows || command.GetRuntimeOs() != RuntimeOs.Windows) {
throw new NotSupportedException("Squirrel v2.x is only supported on/for Windows.");
}
@@ -47,9 +46,9 @@ public class V2CompatRunner : ICommandRunner
await Process.Start(_squirrelExePath, args).WaitForExitAsync();
}
public async Task ExecuteReleasifyWindows(WindowsReleasifyCommand command)
public override async Task ExecuteReleasifyWindows(WindowsReleasifyCommand command)
{
if (!SquirrelRuntimeInfo.IsWindows || command.TargetRuntime.BaseRID != RuntimeOs.Windows) {
if (!SquirrelRuntimeInfo.IsWindows || command.GetRuntimeOs() != RuntimeOs.Windows) {
throw new NotSupportedException("Squirrel v2.x is only supported on/for Windows.");
}
@@ -71,41 +70,16 @@ public class V2CompatRunner : ICommandRunner
await Process.Start(_squirrelExePath, args).WaitForExitAsync();
}
public Task ExecuteBundleOsx(OsxBundleCommand command)
public override Task ExecuteBundleOsx(OsxBundleCommand command)
{
throw new NotSupportedException("Squirrel v2.x is only supported on/for Windows.");
}
public Task ExecuteReleasifyOsx(OsxReleasifyCommand command)
public override Task ExecuteReleasifyOsx(OsxReleasifyCommand command)
{
throw new NotSupportedException("Squirrel v2.x is only supported on/for Windows.");
}
public Task ExecuteGithubDownload(GitHubDownloadCommand command)
{
return ((ICommandRunner) _embedded).ExecuteGithubDownload(command);
}
public Task ExecuteGithubUpload(GitHubUploadCommand command)
{
return ((ICommandRunner) _embedded).ExecuteGithubUpload(command);
}
public Task ExecuteHttpDownload(HttpDownloadCommand command)
{
return ((ICommandRunner) _embedded).ExecuteHttpDownload(command);
}
public Task ExecuteS3Download(S3DownloadCommand command)
{
return ((ICommandRunner) _embedded).ExecuteS3Download(command);
}
public Task ExecuteS3Upload(S3UploadCommand command)
{
return ((ICommandRunner) _embedded).ExecuteS3Upload(command);
}
private abstract class BaseOptions
{
public string releaseDir { get; set; }

View File

@@ -6,41 +6,25 @@ using Squirrel.Csq.Commands;
using Microsoft.Extensions.DependencyInjection;
using Squirrel.Csq.Updates;
using Squirrel.Csq.Compat;
using System.CommandLine.Help;
namespace Squirrel.Csq;
public class Program
{
public static CliOption<string> TargetRuntime { get; }
= new CliOption<string>("--runtime", "-r")
.SetDescription("The target runtime to build packages for.")
.SetArgumentHelpName("RID")
.MustBeSupportedRid()
.SetRequired();
public static CliOption<bool> VerboseOption { get; }
= new CliOption<bool>("--verbose")
.SetDescription("Print diagnostic messages.");
private static CliOption<FileSystemInfo> CsqSolutionPath { get; }
= new CliOption<FileSystemInfo>("--solution")
.SetDescription("Explicit path to project solution (.sln)")
.AcceptExistingOnly();
private static IServiceProvider Provider { get; set; }
private static RunnerFactory Runner { get; set; }
public static async Task<int> Main(string[] args)
{
CliRootCommand platformRootCommand = new CliRootCommand() {
TargetRuntime,
VerboseOption,
CsqSolutionPath,
};
platformRootCommand.TreatUnmatchedTokensAsErrors = false;
ParseResult parseResult = platformRootCommand.Parse(args);
var runtime = RID.Parse(parseResult.GetValue(TargetRuntime) ?? SquirrelRuntimeInfo.SystemOs.GetOsShortName());
var solutionPath = parseResult.GetValue(CsqSolutionPath);
bool verbose = parseResult.GetValue(VerboseOption);
var builder = Host.CreateEmptyApplicationBuilder(new HostApplicationBuilderSettings {
@@ -50,7 +34,6 @@ public class Program
Configuration = new ConfigurationManager(),
});
builder.Services.AddSingleton<IRunnerFactory>(s => new RunnerFactory(s.GetRequiredService<Microsoft.Extensions.Logging.ILogger>(), solutionPath, s.GetRequiredService<IConfiguration>()));
builder.Configuration.AddEnvironmentVariables("CSQ_");
var minLevel = verbose ? LogEventLevel.Debug : LogEventLevel.Information;
@@ -63,30 +46,26 @@ public class Program
builder.Logging.AddSerilog();
var host = builder.Build();
var logger = host.Services.GetRequiredService<ILogger<Program>>();
Provider = host.Services;
var logFactory = host.Services.GetRequiredService<ILoggerFactory>();
var logger = logFactory.CreateLogger("csq");
Runner = new RunnerFactory(logger, host.Services.GetRequiredService<IConfiguration>());
CliRootCommand rootCommand = new CliRootCommand($"Squirrel {SquirrelRuntimeInfo.SquirrelDisplayVersion} for creating and distributing Squirrel releases.") {
TargetRuntime,
CliRootCommand rootCommand = new CliRootCommand(
$"Squirrel {SquirrelRuntimeInfo.SquirrelDisplayVersion} for creating and distributing Squirrel releases.") {
VerboseOption,
CsqSolutionPath,
};
switch (runtime.BaseRID) {
switch (SquirrelRuntimeInfo.SystemOs) {
case RuntimeOs.Windows:
if (!SquirrelRuntimeInfo.IsWindows)
logger.Warn("Cross-compiling will cause some commands and options of Squirrel to be unavailable.");
Add(rootCommand, new WindowsPackCommand(), nameof(ICommandRunner.ExecutePackWindows));
Add(rootCommand, new WindowsReleasifyCommand(), nameof(ICommandRunner.ExecuteReleasifyWindows));
break;
case RuntimeOs.OSX:
if (!SquirrelRuntimeInfo.IsOSX)
throw new NotSupportedException("Cannot create OSX packages on non-OSX platforms.");
Add(rootCommand, new OsxBundleCommand(), nameof(ICommandRunner.ExecuteBundleOsx));
Add(rootCommand, new OsxReleasifyCommand(), nameof(ICommandRunner.ExecuteReleasifyOsx));
break;
default:
throw new NotSupportedException("Unsupported OS platform: " + runtime.BaseRID.GetOsLongName());
throw new NotSupportedException("Unsupported OS platform: " + SquirrelRuntimeInfo.SystemOs.GetOsLongName());
}
CliCommand downloadCommand = new CliCommand("download", "Download's the latest release from a remote update source.");
@@ -100,6 +79,11 @@ public class Program
Add(uploadCommand, new GitHubUploadCommand(), nameof(ICommandRunner.ExecuteGithubUpload));
rootCommand.Add(uploadCommand);
var deltaCommand = new CliCommand("delta", "Utilities for creating or applying delta packages.");
Add(deltaCommand, new DeltaGenCommand(), nameof(ICommandRunner.ExecuteDeltaGen));
Add(deltaCommand, new DeltaPatchCommand(), nameof(ICommandRunner.ExecuteDeltaPatch));
rootCommand.Add(deltaCommand);
var cli = new CliConfiguration(rootCommand);
return await cli.InvokeAsync(args);
}
@@ -109,9 +93,7 @@ public class Program
{
command.SetAction((ctx, token) => {
command.SetProperties(ctx);
command.TargetRuntime = RID.Parse(ctx.GetValue(TargetRuntime));
var factory = Provider.GetRequiredService<IRunnerFactory>();
return factory.CreateAndExecuteAsync(commandName, command);
return Runner.CreateAndExecuteAsync(commandName, command);
});
parent.Subcommands.Add(command);
return command;

View File

@@ -20,7 +20,9 @@ public class UpdateChecker
var dl = new NugetDownloader(new NugetLoggingWrapper(_logger));
var package = await dl.GetPackageMetadata("csq", (myVer.IsPrerelease || myVer.HasMetadata) ? "pre" : "latest", cancel.Token).ConfigureAwait(false);
if (package.Identity.Version > myVer)
_logger.Warn($"There is a new version of csq available ({package.Identity.Version})");
_logger.Warn($"There is a newer version of csq available ({package.Identity.Version})");
else
_logger.Debug($"csq is up to date (latest online = {package.Identity.Version})");
} catch (Exception ex) {
_logger.Debug(ex, "Failed to check for updates.");
}

View File

@@ -13,8 +13,6 @@ public class HelperExe : HelperFile
{
}
public string UpdateMacPath => FindHelperFile("UpdateMac");
public string SquirrelEntitlements => FindHelperFile("Squirrel.entitlements");
[SupportedOSPlatform("osx")]

View File

@@ -58,7 +58,7 @@ public class WindowsReleasifyCommandRunner
var helper = new HelperExe(_logger);
var updatePath = Path.Combine(tempDir, "Update.exe");
File.Copy(HelperExe.UpdatePath, updatePath, true);
File.Copy(helper.UpdatePath, updatePath, true);
// update icon for Update.exe if requested
if (setupIcon != null && SquirrelRuntimeInfo.IsWindows) {
@@ -148,7 +148,7 @@ public class WindowsReleasifyCommandRunner
var bundledzp = new ZipPackage(package);
var targetSetupExe = Path.Combine(targetDir, $"{bundledzp.Id}-Setup-[{options.TargetRuntime.ToDisplay(RidDisplayType.NoVersion)}].exe");
File.Copy(HelperExe.SetupPath, targetSetupExe, true);
File.Copy(helper.SetupPath, targetSetupExe, true);
if (SquirrelRuntimeInfo.IsWindows) {
helper.SetPEVersionBlockFromPackageInfo(targetSetupExe, bundledzp, setupIcon);

View File

@@ -13,15 +13,13 @@ public class HelperExe : HelperFile
{
}
public static string SetupPath => FindHelperFile("Setup.exe");
public string SetupPath => FindHelperFile("Setup.exe");
public static string UpdatePath => FindHelperFile("Update.exe");
public string StubExecutablePath => FindHelperFile("StubExecutable.exe");
public static string StubExecutablePath => FindHelperFile("StubExecutable.exe");
private string SignToolPath => FindHelperFile("signtool.exe");
private static string SignToolPath => FindHelperFile("signtool.exe");
private static string RceditPath => FindHelperFile("rcedit.exe");
private string RceditPath => FindHelperFile("rcedit.exe");
[SupportedOSPlatform("windows")]
private bool CheckIsAlreadySigned(string filePath)

View File

@@ -0,0 +1,16 @@
using Microsoft.Extensions.Logging;
namespace Squirrel.Packaging.Commands
{
public class DeltaGenCommandRunner : ICommand<DeltaGenOptions>
{
public Task Run(DeltaGenOptions options, ILogger logger)
{
var pold = new ReleasePackageBuilder(logger, options.BasePackage);
var pnew = new ReleasePackageBuilder(logger, options.NewPackage);
var delta = new DeltaPackageBuilder(logger);
delta.CreateDeltaPackage(pnew, pold, options.OutputFile, options.DeltaMode);
return Task.CompletedTask;
}
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Squirrel.Packaging.Commands
{
public class DeltaGenOptions
{
public DeltaMode DeltaMode { get; set; }
public string BasePackage { get; set; }
public string NewPackage { get; set; }
public string OutputFile { get; set; }
}
}

View File

@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Squirrel.Compression;
namespace Squirrel.Packaging.Commands
{
public class DeltaPatchCommandRunner : ICommand<DeltaPatchOptions>
{
public Task Run(DeltaPatchOptions options, ILogger logger)
{
if (options.PatchFiles.Length == 0) {
throw new ArgumentException("Must specify at least one patch file.");
}
if (options.PatchFiles.Any(x => x == null || !x.Exists)) {
throw new ArgumentException("One or more patch files do not exist.");
}
var tmp = Utility.GetDefaultTempBaseDirectory();
using var _1 = Utility.GetTempDirectory(out var workDir);
var helper = new HelperFile(logger);
string updateExe;
if (SquirrelRuntimeInfo.IsWindows)
updateExe = helper.UpdatePath;
else if (SquirrelRuntimeInfo.IsOSX)
updateExe = helper.UpdateMacPath;
else
throw new NotSupportedException("This platform is not supported.");
var delta = new DeltaPackage(logger, tmp, updateExe);
EasyZip.ExtractZipToDirectory(logger, options.BasePackage, workDir);
foreach (var f in options.PatchFiles) {
logger.Info($"Applying delta patch {f.Name}");
delta.ApplyDeltaPackageFast(workDir, f.FullName);
}
return Task.CompletedTask;
}
}
}

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Squirrel.Packaging.Commands
{
public class DeltaPatchOptions
{
public string BasePackage { get; set; }
public FileInfo[] PatchFiles { get; set; }
public string OutputFile { get; set; }
}
}

View File

@@ -18,6 +18,10 @@ public enum DeltaMode
public class HelperFile
{
public string UpdatePath => FindHelperFile("Update.exe");
public string UpdateMacPath => FindHelperFile("UpdateMac");
private static List<string> _searchPaths = new List<string>();
protected readonly ILogger Log;

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace Squirrel.Packaging
{
internal interface ICommand<TOpt> where TOpt : class
{
Task Run(TOpt options, ILogger logger);
}
}

View File

@@ -21,11 +21,11 @@ namespace Squirrel.Compression
private readonly string _baseTempDir;
private static Regex DIFF_SUFFIX = new Regex(@"\.(bs|zs)?diff$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public DeltaPackage(ILogger logger, ISquirrelLocator locator)
public DeltaPackage(ILogger logger, string baseTmpDir, string updateExePath)
{
_log = logger;
_baseTempDir = locator.AppTempDir;
_updatePath = locator.UpdateExePath;
_baseTempDir = baseTmpDir;
_updatePath = updateExePath;
}
public void ApplyDeltaPackageFast(string workingPath, string deltaPackageZip, Action<int> progress = null)

View File

@@ -228,7 +228,7 @@ namespace Squirrel
} catch (Exception ex) {
Log.Warn(ex, "Unable to apply delta updates, falling back to full update.");
if (SquirrelRuntimeInfo.InUnitTestRunner) {
throw ex;
throw;
}
}
@@ -345,7 +345,7 @@ namespace Squirrel
// applying deltas accounts for 50%-100% of progress
double progressStepSize = 100d / releasesToDownload.Length;
var builder = new DeltaPackage(Log, Locator);
var builder = new DeltaPackage(Log, Locator.AppTempDir, Locator.UpdateExePath);
for (var i = 0; i < releasesToDownload.Length; i++) {
var rel = releasesToDownload[i];
double baseProgress = i * progressStepSize;

View File

@@ -7,21 +7,21 @@ public abstract class BaseCommandTests<T> : TempFileTestBase
{
public virtual bool ShouldBeNonEmptyReleaseDir => false;
[Fact]
public void ReleaseDirectory_WithDirectory_ParsesValue()
{
var releaseDirectory = CreateTempDirectory();
//[Fact]
//public void ReleaseDirectory_WithDirectory_ParsesValue()
//{
// var releaseDirectory = CreateTempDirectory();
if (ShouldBeNonEmptyReleaseDir)
CreateTempFile(releaseDirectory, "anything");
// if (ShouldBeNonEmptyReleaseDir)
// CreateTempFile(releaseDirectory, "anything");
BaseCommand command = new T();
// BaseCommand command = new T();
var cli = GetRequiredDefaultOptions() + $"--outputDir \"{releaseDirectory.FullName}\"";
var parseResult = command.ParseAndApply(cli);
// var cli = GetRequiredDefaultOptions() + $"--outputDir \"{releaseDirectory.FullName}\"";
// var parseResult = command.ParseAndApply(cli);
Assert.Equal(releaseDirectory.FullName, command.ReleaseDirectory);
}
// Assert.Equal(releaseDirectory.FullName, command.ReleaseDirectory);
//}
protected virtual string GetRequiredDefaultOptions() => "";
}