mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
Decouple Spectre from Packaging, refactor command/compat
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Velopack.Packaging;
|
||||
using Velopack.Packaging.Abstractions;
|
||||
using Velopack.Sources;
|
||||
|
||||
namespace Velopack.Deployment;
|
||||
|
||||
public class RepositoryOptions
|
||||
public class RepositoryOptions : IOutputOptions
|
||||
{
|
||||
public string Channel { get; set; } = ReleaseEntryHelper.GetDefaultChannel();
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using ELFSharp.ELF;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Velopack.Packaging.Abstractions;
|
||||
|
||||
namespace Velopack.Packaging.Unix.Commands
|
||||
{
|
||||
@@ -14,8 +15,8 @@ namespace Velopack.Packaging.Unix.Commands
|
||||
{
|
||||
protected string PortablePackagePath { get; set; }
|
||||
|
||||
public LinuxPackCommandRunner(ILogger logger)
|
||||
: base(RuntimeOs.Linux, logger)
|
||||
public LinuxPackCommandRunner(ILogger logger, IFancyConsole console)
|
||||
: base(RuntimeOs.Linux, logger, console)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Velopack.Packaging.Abstractions;
|
||||
|
||||
namespace Velopack.Packaging.Unix.Commands
|
||||
{
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NuGet.Versioning;
|
||||
using Velopack.Packaging.Abstractions;
|
||||
using Velopack.Packaging.Exceptions;
|
||||
|
||||
namespace Velopack.Packaging.Unix.Commands;
|
||||
|
||||
public class OsxBundleCommandRunner
|
||||
public class OsxBundleCommandRunner : ICommand<OsxBundleOptions>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
@@ -14,6 +15,12 @@ public class OsxBundleCommandRunner
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Task Run(OsxBundleOptions options)
|
||||
{
|
||||
Bundle(options);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public string Bundle(OsxBundleOptions options)
|
||||
{
|
||||
var icon = options.Icon;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
namespace Velopack.Packaging.Unix.Commands;
|
||||
using Velopack.Packaging.Abstractions;
|
||||
|
||||
public class OsxBundleOptions
|
||||
namespace Velopack.Packaging.Unix.Commands;
|
||||
|
||||
public class OsxBundleOptions : IOutputOptions
|
||||
{
|
||||
public DirectoryInfo ReleaseDir { get; set; }
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
using System.Runtime.Versioning;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Velopack.Packaging.Abstractions;
|
||||
|
||||
namespace Velopack.Packaging.Unix.Commands;
|
||||
|
||||
[SupportedOSPlatform("osx")]
|
||||
public class OsxPackCommandRunner : PackageBuilder<OsxPackOptions>
|
||||
{
|
||||
public OsxPackCommandRunner(ILogger logger)
|
||||
: base(RuntimeOs.OSX, logger)
|
||||
public OsxPackCommandRunner(ILogger logger, IFancyConsole console)
|
||||
: base(RuntimeOs.OSX, logger, console)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace Velopack.Packaging.Unix.Commands;
|
||||
using Velopack.Packaging.Abstractions;
|
||||
|
||||
namespace Velopack.Packaging.Unix.Commands;
|
||||
|
||||
public class OsxPackOptions : OsxBundleOptions, IPackOptions
|
||||
{
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
using AsmResolver.PE;
|
||||
using AsmResolver.PE.File.Headers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Spectre.Console;
|
||||
using Velopack.Compression;
|
||||
using Velopack.NuGet;
|
||||
using Velopack.Packaging.Abstractions;
|
||||
using Velopack.Packaging.Exceptions;
|
||||
using Velopack.Windows;
|
||||
|
||||
@@ -13,8 +13,8 @@ namespace Velopack.Packaging.Windows.Commands;
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class WindowsPackCommandRunner : PackageBuilder<WindowsPackOptions>
|
||||
{
|
||||
public WindowsPackCommandRunner(ILogger logger)
|
||||
: base(RuntimeOs.Windows, logger)
|
||||
public WindowsPackCommandRunner(ILogger logger, IFancyConsole console)
|
||||
: base(RuntimeOs.Windows, logger, console)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace Velopack.Packaging.Windows.Commands;
|
||||
using Velopack.Packaging.Abstractions;
|
||||
|
||||
namespace Velopack.Packaging.Windows.Commands;
|
||||
|
||||
public class WindowsPackOptions : WindowsReleasifyOptions, INugetPackCommand, IPackOptions
|
||||
{
|
||||
|
||||
9
src/Velopack.Packaging/Abstractions/ICommand.cs
Normal file
9
src/Velopack.Packaging/Abstractions/ICommand.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Velopack.Packaging.Abstractions
|
||||
{
|
||||
public interface ICommand<TOpt> where TOpt : class
|
||||
{
|
||||
Task Run(TOpt options);
|
||||
}
|
||||
}
|
||||
9
src/Velopack.Packaging/Abstractions/IFancyConsole.cs
Normal file
9
src/Velopack.Packaging/Abstractions/IFancyConsole.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Velopack.Packaging.Abstractions
|
||||
{
|
||||
public interface IFancyConsole
|
||||
{
|
||||
Task ExecuteProgressAsync(Func<IFancyConsoleProgress, Task> action);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Velopack.Packaging.Abstractions
|
||||
{
|
||||
public interface IFancyConsoleProgress
|
||||
{
|
||||
Task RunTask(string name, Func<Action<int>, Task> fn);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Velopack.Packaging;
|
||||
namespace Velopack.Packaging.Abstractions;
|
||||
|
||||
public interface INugetPackCommand
|
||||
{
|
||||
13
src/Velopack.Packaging/Abstractions/IOutputOptions.cs
Normal file
13
src/Velopack.Packaging/Abstractions/IOutputOptions.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Velopack.Packaging.Abstractions
|
||||
{
|
||||
public interface IOutputOptions
|
||||
{
|
||||
DirectoryInfo ReleaseDir { get; }
|
||||
}
|
||||
}
|
||||
9
src/Velopack.Packaging/Abstractions/IPackOptions.cs
Normal file
9
src/Velopack.Packaging/Abstractions/IPackOptions.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Velopack.Packaging.Abstractions
|
||||
{
|
||||
public interface IPackOptions : INugetPackCommand, IPlatformOptions
|
||||
{
|
||||
string Channel { get; }
|
||||
DeltaMode DeltaMode { get; }
|
||||
string EntryExecutableName { get; }
|
||||
}
|
||||
}
|
||||
13
src/Velopack.Packaging/Abstractions/IPlatformOptions.cs
Normal file
13
src/Velopack.Packaging/Abstractions/IPlatformOptions.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Velopack.Packaging.Abstractions
|
||||
{
|
||||
public interface IPlatformOptions : IOutputOptions
|
||||
{
|
||||
RID TargetRuntime { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,22 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Velopack.Packaging.Abstractions;
|
||||
|
||||
namespace Velopack.Packaging.Commands
|
||||
{
|
||||
public class DeltaGenCommandRunner : ICommand<DeltaGenOptions>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly IFancyConsole _console;
|
||||
|
||||
public DeltaGenCommandRunner(ILogger logger)
|
||||
public DeltaGenCommandRunner(ILogger logger, IFancyConsole console)
|
||||
{
|
||||
_logger = logger;
|
||||
_console = console;
|
||||
}
|
||||
|
||||
public async Task Run(DeltaGenOptions options)
|
||||
{
|
||||
await Progress.ExecuteAsync(_logger, async (ctx) => {
|
||||
await _console.ExecuteProgressAsync(async (ctx) => {
|
||||
var pold = new ReleasePackage(options.BasePackage);
|
||||
var pnew = new ReleasePackage(options.NewPackage);
|
||||
await ctx.RunTask($"Building delta {pold.Version} -> {pnew.Version}", (progress) => {
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Velopack.Compression;
|
||||
using Velopack.Packaging.Exceptions;
|
||||
using Velopack.Packaging.Abstractions;
|
||||
|
||||
namespace Velopack.Packaging.Commands
|
||||
{
|
||||
public class DeltaPatchCommandRunner : ICommand<DeltaPatchOptions>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly IFancyConsole _console;
|
||||
|
||||
public DeltaPatchCommandRunner(ILogger logger)
|
||||
public DeltaPatchCommandRunner(ILogger logger, IFancyConsole console)
|
||||
{
|
||||
_logger = logger;
|
||||
_console = console;
|
||||
}
|
||||
|
||||
public async Task Run(DeltaPatchOptions options)
|
||||
@@ -31,7 +34,7 @@ namespace Velopack.Packaging.Commands
|
||||
var delta = new DeltaEmbedded(HelperFile.GetZstdPath(), _logger, tmp);
|
||||
EasyZip.ExtractZipToDirectory(_logger, options.BasePackage, workDir);
|
||||
|
||||
await Progress.ExecuteAsync(_logger, async (ctx) => {
|
||||
await _console.ExecuteProgressAsync(async (ctx) => {
|
||||
foreach (var f in options.PatchFiles) {
|
||||
await ctx.RunTask($"Applying {f.Name}", (progress) => {
|
||||
delta.ApplyDeltaPackageFast(workDir, f.FullName, progress);
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Velopack.Packaging
|
||||
{
|
||||
internal interface ICommand<TOpt> where TOpt : class
|
||||
{
|
||||
Task Run(TOpt options);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
namespace Velopack.Packaging
|
||||
{
|
||||
public interface IPackOptions : INugetPackCommand
|
||||
{
|
||||
RID TargetRuntime { get; }
|
||||
DirectoryInfo ReleaseDir { get; }
|
||||
string Channel { get; }
|
||||
DeltaMode DeltaMode { get; }
|
||||
string EntryExecutableName { get; }
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,10 @@ using System.Security;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NuGet.Versioning;
|
||||
using Spectre.Console;
|
||||
using Velopack.Compression;
|
||||
using Velopack.NuGet;
|
||||
using Velopack.Packaging.Exceptions;
|
||||
using Velopack.Packaging.Abstractions;
|
||||
|
||||
namespace Velopack.Packaging
|
||||
{
|
||||
@@ -18,6 +18,8 @@ namespace Velopack.Packaging
|
||||
|
||||
protected ILogger Log { get; }
|
||||
|
||||
protected IFancyConsole Console { get; }
|
||||
|
||||
protected DirectoryInfo TempDir { get; private set; }
|
||||
|
||||
protected T Options { get; private set; }
|
||||
@@ -30,10 +32,11 @@ namespace Velopack.Packaging
|
||||
|
||||
private readonly Regex REGEX_EXCLUDES = new Regex(@".*[\\\/]createdump.*|.*\.vshost\..*|.*\.nupkg$|.*\.pdb$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
|
||||
public PackageBuilder(RuntimeOs supportedOs, ILogger logger)
|
||||
public PackageBuilder(RuntimeOs supportedOs, ILogger logger, IFancyConsole console)
|
||||
{
|
||||
SupportedTargetOs = supportedOs;
|
||||
Log = logger;
|
||||
Console = console;
|
||||
}
|
||||
|
||||
public async Task Run(T options)
|
||||
@@ -90,7 +93,7 @@ namespace Velopack.Packaging
|
||||
return incomplete;
|
||||
}
|
||||
|
||||
await Progress.ExecuteAsync(Log, async (ctx) => {
|
||||
await Console.ExecuteProgressAsync(async (ctx) => {
|
||||
ReleasePackage prev = null;
|
||||
await ctx.RunTask("Pre-process steps", async (progress) => {
|
||||
prev = entryHelper.GetPreviousFullRelease(NuGetVersion.Parse(packVersion));
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Spectre.Console;
|
||||
|
||||
namespace Velopack.Packaging
|
||||
{
|
||||
public class Progress
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly ProgressContext _context;
|
||||
|
||||
public static bool IsEnabled { get; set; }
|
||||
|
||||
private Progress(ILogger logger, ProgressContext context)
|
||||
{
|
||||
_logger = logger;
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public static async Task ExecuteAsync(ILogger logger, Func<Progress, Task> action)
|
||||
{
|
||||
var start = DateTime.UtcNow;
|
||||
if (IsEnabled) {
|
||||
await AnsiConsole.Progress()
|
||||
.AutoRefresh(true)
|
||||
.AutoClear(false)
|
||||
.HideCompleted(false)
|
||||
.Columns(new ProgressColumn[] {
|
||||
new SpinnerColumn(),
|
||||
new TaskDescriptionColumn(),
|
||||
new ProgressBarColumn(),
|
||||
new PercentageColumn(),
|
||||
new ElapsedTimeColumn(),
|
||||
})
|
||||
.StartAsync(async ctx => await action(new Progress(logger, ctx)));
|
||||
} else {
|
||||
await action(new Progress(logger, null));
|
||||
}
|
||||
logger.Info($"[bold]Finished in {DateTime.UtcNow - start}.[/]");
|
||||
}
|
||||
|
||||
public async Task RunTask(string name, Func<Action<int>, Task> fn)
|
||||
{
|
||||
var level = IsEnabled ? LogLevel.Debug : LogLevel.Information;
|
||||
_logger.Log(level, "Starting: " + name);
|
||||
|
||||
if (IsEnabled) {
|
||||
var task = _context.AddTask($"[italic]{name}[/]");
|
||||
task.StartTask();
|
||||
|
||||
void progress(int p)
|
||||
{
|
||||
if (p < 0) {
|
||||
task.IsIndeterminate = true;
|
||||
} else {
|
||||
task.IsIndeterminate = false;
|
||||
task.Value = Math.Min(100, p);
|
||||
}
|
||||
}
|
||||
|
||||
await Task.Run(() => fn(progress)).ConfigureAwait(false);
|
||||
task.IsIndeterminate = false;
|
||||
task.StopTask();
|
||||
} else {
|
||||
await Task.Run(() => fn((_) => { })).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
_logger.Log(level, $"[bold]Complete: {name}[/]");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
|
||||
<PackageReference Include="Spectre.Console" Version="0.48.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
166
src/Velopack.Vpk/CommandMapper.cs
Normal file
166
src/Velopack.Vpk/CommandMapper.cs
Normal file
@@ -0,0 +1,166 @@
|
||||
using AutoMapper;
|
||||
using AutoMapper.Internal;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Velopack.Deployment;
|
||||
using Velopack.Packaging.Abstractions;
|
||||
using Velopack.Packaging.Commands;
|
||||
using Velopack.Packaging.Exceptions;
|
||||
using Velopack.Packaging.Unix.Commands;
|
||||
using Velopack.Packaging.Windows.Commands;
|
||||
using Velopack.Vpk.Commands;
|
||||
using Velopack.Vpk.Updates;
|
||||
|
||||
namespace Velopack.Vpk;
|
||||
|
||||
public static class CommandMapper
|
||||
{
|
||||
private static readonly List<TypePair> RequiredCommandMaps = new();
|
||||
|
||||
public static void Validate()
|
||||
{
|
||||
var config = GetMapperConfig();
|
||||
config.AssertConfigurationIsValid();
|
||||
|
||||
var rootCommand = new CliRootCommand();
|
||||
rootCommand.PopulateVelopackCommands(null);
|
||||
|
||||
var global = (IGlobalConfiguration) config;
|
||||
foreach (var pair in RequiredCommandMaps) {
|
||||
var map = global.FindTypeMapFor(pair);
|
||||
if (map == null) {
|
||||
throw new Exception($"Missing map for {pair.SourceType.Name} -> {pair.DestinationType.Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void PopulateVelopackCommands(this CliRootCommand rootCommand, IServiceProvider provider)
|
||||
{
|
||||
if (VelopackRuntimeInfo.IsWindows) {
|
||||
rootCommand.AddCommand<WindowsPackCommand, WindowsPackCommandRunner, WindowsPackOptions>(provider);
|
||||
} else if (VelopackRuntimeInfo.IsOSX) {
|
||||
rootCommand.AddCommand<OsxBundleCommand, OsxBundleCommandRunner, OsxBundleOptions>(provider);
|
||||
rootCommand.AddCommand<OsxPackCommand, OsxPackCommandRunner, OsxPackOptions>(provider);
|
||||
} else if (VelopackRuntimeInfo.IsLinux) {
|
||||
rootCommand.AddCommand<LinuxPackCommand, LinuxPackCommandRunner, LinuxPackOptions>(provider);
|
||||
} else {
|
||||
throw new NotSupportedException("Unsupported OS platform: " + VelopackRuntimeInfo.SystemOs.GetOsLongName());
|
||||
}
|
||||
|
||||
var downloadCommand = new CliCommand("download", "Download's the latest release from a remote update source.");
|
||||
downloadCommand.AddRepositoryDownload<GitHubDownloadCommand, GitHubRepository, GitHubDownloadOptions>(provider);
|
||||
downloadCommand.AddRepositoryDownload<S3DownloadCommand, S3Repository, S3DownloadOptions>(provider);
|
||||
downloadCommand.AddRepositoryDownload<HttpDownloadCommand, HttpRepository, HttpDownloadOptions>(provider);
|
||||
rootCommand.Add(downloadCommand);
|
||||
|
||||
var uploadCommand = new CliCommand("upload", "Upload local package(s) to a remote update source.");
|
||||
uploadCommand.AddRepositoryUpload<GitHubUploadCommand, GitHubRepository, GitHubUploadOptions>(provider);
|
||||
uploadCommand.AddRepositoryUpload<S3UploadCommand, S3Repository, S3UploadOptions>(provider);
|
||||
rootCommand.Add(uploadCommand);
|
||||
|
||||
var deltaCommand = new CliCommand("delta", "Utilities for creating or applying delta packages.");
|
||||
deltaCommand.AddCommand<DeltaGenCommand, DeltaGenCommandRunner, DeltaGenOptions>(provider);
|
||||
deltaCommand.AddCommand<DeltaPatchCommand, DeltaPatchCommandRunner, DeltaPatchOptions>(provider);
|
||||
rootCommand.Add(deltaCommand);
|
||||
}
|
||||
|
||||
private static MapperConfiguration GetMapperConfig()
|
||||
{
|
||||
return new MapperConfiguration(cfg => {
|
||||
cfg.CreatePlatformMap<OsxPackCommand, OsxPackOptions>();
|
||||
cfg.CreatePlatformMap<WindowsPackCommand, WindowsPackOptions>();
|
||||
cfg.CreatePlatformMap<LinuxPackCommand, LinuxPackOptions>();
|
||||
cfg.CreateOutputMap<OsxBundleCommand, OsxBundleOptions>();
|
||||
cfg.CreateOutputMap<GitHubDownloadCommand, GitHubDownloadOptions>();
|
||||
cfg.CreateOutputMap<GitHubUploadCommand, GitHubUploadOptions>();
|
||||
cfg.CreateOutputMap<HttpDownloadCommand, HttpDownloadOptions>();
|
||||
cfg.CreateOutputMap<S3DownloadCommand, S3DownloadOptions>();
|
||||
cfg.CreateOutputMap<S3UploadCommand, S3UploadOptions>();
|
||||
cfg.CreateMap<DeltaGenCommand, DeltaGenOptions>();
|
||||
cfg.CreateMap<DeltaPatchCommand, DeltaPatchOptions>();
|
||||
});
|
||||
}
|
||||
|
||||
private static CliCommand AddCommand<TCli, TCmd, TOpt>(this CliCommand parent, IServiceProvider provider)
|
||||
where TCli : BaseCommand, new()
|
||||
where TCmd : ICommand<TOpt>
|
||||
where TOpt : class, new()
|
||||
{
|
||||
return parent.Add<TCli, TOpt>(provider, (options) => {
|
||||
var runner = ActivatorUtilities.CreateInstance<TCmd>(provider);
|
||||
return runner.Run(options);
|
||||
});
|
||||
}
|
||||
|
||||
private static CliCommand AddRepositoryDownload<TCli, TCmd, TOpt>(this CliCommand parent, IServiceProvider provider)
|
||||
where TCli : BaseCommand, new()
|
||||
where TCmd : IRepositoryCanDownload<TOpt>
|
||||
where TOpt : RepositoryOptions, new()
|
||||
{
|
||||
return parent.Add<TCli, TOpt>(provider, (options) => {
|
||||
var runner = ActivatorUtilities.CreateInstance<TCmd>(provider);
|
||||
return runner.DownloadLatestFullPackageAsync(options);
|
||||
});
|
||||
}
|
||||
|
||||
private static CliCommand AddRepositoryUpload<TCli, TCmd, TOpt>(this CliCommand parent, IServiceProvider provider)
|
||||
where TCli : BaseCommand, new()
|
||||
where TCmd : IRepositoryCanUpload<TOpt>
|
||||
where TOpt : RepositoryOptions, new()
|
||||
{
|
||||
return parent.Add<TCli, TOpt>(provider, (options) => {
|
||||
var runner = ActivatorUtilities.CreateInstance<TCmd>(provider);
|
||||
return runner.UploadMissingAssetsAsync(options);
|
||||
});
|
||||
}
|
||||
|
||||
private static CliCommand Add<TCli, TOpt>(this CliCommand parent, IServiceProvider provider, Func<TOpt, Task> fn)
|
||||
where TCli : BaseCommand, new()
|
||||
where TOpt : class, new()
|
||||
{
|
||||
RequiredCommandMaps.Add(new TypePair(typeof(TCli), typeof(TOpt)));
|
||||
var command = new TCli();
|
||||
command.SetAction(async (ctx, token) => {
|
||||
var logger = provider.GetRequiredService<ILogger>();
|
||||
logger.LogInformation($"[bold]{Program.INTRO}[/]");
|
||||
var updateCheck = new UpdateChecker(logger);
|
||||
await updateCheck.CheckForUpdates();
|
||||
|
||||
command.SetProperties(ctx);
|
||||
var mapper = GetMapperConfig().CreateMapper();
|
||||
var options = mapper.Map<TOpt>(command);
|
||||
|
||||
try {
|
||||
await fn(options);
|
||||
return 0;
|
||||
} catch (Exception ex) when (ex is ProcessFailedException or UserInfoException) {
|
||||
// some exceptions are just user info / user error, so don't need a stack trace.
|
||||
logger.Fatal($"[bold orange3]{ex.Message}[/]");
|
||||
return -1;
|
||||
} catch (Exception ex) {
|
||||
logger.Fatal(ex, $"Command {typeof(TCli).Name} had an exception.");
|
||||
return -1;
|
||||
}
|
||||
});
|
||||
parent.Subcommands.Add(command);
|
||||
return command;
|
||||
}
|
||||
|
||||
private static IMappingExpression<TSource, TDestination> CreatePlatformMap<TSource, TDestination>(
|
||||
this IMapperConfigurationExpression cfg)
|
||||
where TSource : PlatformCommand
|
||||
where TDestination : IPackOptions
|
||||
{
|
||||
return cfg.CreateMap<TSource, TDestination>()
|
||||
.ForMember(x => x.ReleaseDir, x => x.MapFrom(z => z.GetReleaseDirectory()))
|
||||
.ForMember(x => x.TargetRuntime, x => x.MapFrom(z => z.GetRid()));
|
||||
}
|
||||
|
||||
private static IMappingExpression<TSource, TDestination> CreateOutputMap<TSource, TDestination>(
|
||||
this IMapperConfigurationExpression cfg)
|
||||
where TSource : OutputCommand
|
||||
where TDestination : IOutputOptions
|
||||
{
|
||||
return cfg.CreateMap<TSource, TDestination>()
|
||||
.ForMember(x => x.ReleaseDir, x => x.MapFrom(z => z.GetReleaseDirectory()));
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ namespace Velopack.Vpk.Commands
|
||||
{
|
||||
public class DeltaGenCommand : BaseCommand
|
||||
{
|
||||
public DeltaMode Delta { get; set; }
|
||||
public DeltaMode DeltaMode { get; set; }
|
||||
|
||||
public string BasePackage { get; set; }
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Velopack.Vpk.Commands
|
||||
: base("generate", "Generate a delta patch from two full releases.")
|
||||
|
||||
{
|
||||
AddOption<DeltaMode>((v) => Delta = v, "--mode")
|
||||
AddOption<DeltaMode>((v) => DeltaMode = v, "--mode")
|
||||
.SetDefault(DeltaMode.BestSpeed)
|
||||
.SetDescription("Set the delta generation mode.");
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
|
||||
public class GitHubDownloadCommand : GitHubBaseCommand
|
||||
{
|
||||
public bool Pre { get; private set; }
|
||||
public bool Prerelease { get; private set; }
|
||||
|
||||
public GitHubDownloadCommand()
|
||||
: base("github", "Download latest release from GitHub repository.")
|
||||
{
|
||||
AddOption<bool>((v) => Pre = v, "--pre")
|
||||
AddOption<bool>((v) => Prerelease = v, "--pre")
|
||||
.SetDescription("Get latest pre-release instead of stable.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ public class GitHubUploadCommand : GitHubBaseCommand
|
||||
|
||||
public string TagName { get; private set; }
|
||||
|
||||
public bool Pre { get; private set; }
|
||||
public bool Prerelease { get; private set; }
|
||||
|
||||
public bool Merge { get; private set; }
|
||||
|
||||
@@ -18,7 +18,7 @@ public class GitHubUploadCommand : GitHubBaseCommand
|
||||
AddOption<bool>((v) => Publish = v, "--publish")
|
||||
.SetDescription("Create and publish instead of leaving as draft.");
|
||||
|
||||
AddOption<bool>((v) => Pre = v, "--pre")
|
||||
AddOption<bool>((v) => Prerelease = v, "--pre")
|
||||
.SetDescription("Create as pre-release instead of stable.");
|
||||
|
||||
AddOption<bool>((v) => Merge = v, "--merge")
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Velopack.Vpk.Commands
|
||||
|
||||
public bool PackIsAppDir { get; private set; }
|
||||
|
||||
public DeltaMode Delta { get; set; } = DeltaMode.BestSpeed;
|
||||
public DeltaMode DeltaMode { get; set; } = DeltaMode.BestSpeed;
|
||||
|
||||
public LinuxPackCommand()
|
||||
: this("pack", "Create's a Linux .AppImage bundle from a folder containing application files.")
|
||||
@@ -78,7 +78,7 @@ namespace Velopack.Vpk.Commands
|
||||
.SetArgumentHelpName("PATH")
|
||||
.MustExist();
|
||||
|
||||
AddOption<DeltaMode>((v) => Delta = v, "--delta")
|
||||
AddOption<DeltaMode>((v) => DeltaMode = v, "--delta")
|
||||
.SetDefault(DeltaMode.BestSpeed)
|
||||
.SetDescription("Set the delta generation mode.");
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ public class OsxPackCommand : OsxBundleCommand
|
||||
{
|
||||
public string ReleaseNotes { get; private set; }
|
||||
|
||||
public DeltaMode Delta { get; private set; }
|
||||
public DeltaMode DeltaMode { get; private set; }
|
||||
|
||||
public bool NoPackage { get; private set; }
|
||||
|
||||
@@ -34,7 +34,7 @@ public class OsxPackCommand : OsxBundleCommand
|
||||
.SetArgumentHelpName("PATH")
|
||||
.MustExist();
|
||||
|
||||
AddOption<DeltaMode>((v) => Delta = v, "--delta")
|
||||
AddOption<DeltaMode>((v) => DeltaMode = v, "--delta")
|
||||
.SetDefault(DeltaMode.BestSpeed)
|
||||
.SetDescription("Set the delta generation mode.");
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ public class WindowsReleasifyCommand : WindowsSigningCommand
|
||||
{
|
||||
public string Package { get; set; }
|
||||
|
||||
public DeltaMode Delta { get; private set; }
|
||||
public DeltaMode DeltaMode { get; private set; }
|
||||
|
||||
public string Runtimes { get; private set; }
|
||||
|
||||
@@ -34,7 +34,7 @@ public class WindowsReleasifyCommand : WindowsSigningCommand
|
||||
protected WindowsReleasifyCommand(string name, string description)
|
||||
: base(name, description)
|
||||
{
|
||||
AddOption<DeltaMode>((v) => Delta = v, "--delta")
|
||||
AddOption<DeltaMode>((v) => DeltaMode = v, "--delta")
|
||||
.SetDefault(DeltaMode.BestSpeed)
|
||||
.SetDescription("Set the delta generation mode.");
|
||||
|
||||
|
||||
@@ -1,227 +0,0 @@
|
||||
using System.Runtime.Versioning;
|
||||
using Velopack.Deployment;
|
||||
using Velopack.Packaging.Commands;
|
||||
using Velopack.Packaging.Unix.Commands;
|
||||
using Velopack.Packaging.Windows.Commands;
|
||||
using Velopack.Vpk.Commands;
|
||||
|
||||
namespace Velopack.Vpk.Compat;
|
||||
|
||||
public class EmbeddedRunner : ICommandRunner
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public EmbeddedRunner(ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("osx")]
|
||||
public virtual Task ExecuteBundleOsx(OsxBundleCommand command)
|
||||
{
|
||||
var options = new OsxBundleOptions {
|
||||
BundleId = command.BundleId,
|
||||
PackAuthors = command.PackAuthors,
|
||||
EntryExecutableName = command.EntryExecutableName,
|
||||
Icon = command.Icon,
|
||||
PackDirectory = command.PackDirectory,
|
||||
PackId = command.PackId,
|
||||
PackTitle = command.PackTitle,
|
||||
PackVersion = command.PackVersion,
|
||||
ReleaseDir = command.GetReleaseDirectory(),
|
||||
InfoPlistPath = command.InfoPlistPath,
|
||||
};
|
||||
new OsxBundleCommandRunner(_logger).Bundle(options);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("osx")]
|
||||
public virtual Task ExecutePackOsx(OsxPackCommand command)
|
||||
{
|
||||
var options = new OsxPackOptions {
|
||||
BundleId = command.BundleId,
|
||||
PackAuthors = command.PackAuthors,
|
||||
EntryExecutableName = command.EntryExecutableName,
|
||||
Icon = command.Icon,
|
||||
PackDirectory = command.PackDirectory,
|
||||
PackId = command.PackId,
|
||||
PackTitle = command.PackTitle,
|
||||
Channel = command.Channel,
|
||||
PackVersion = command.PackVersion,
|
||||
TargetRuntime = command.GetRid(),
|
||||
ReleaseDir = command.GetReleaseDirectory(),
|
||||
DeltaMode = command.Delta,
|
||||
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,
|
||||
InfoPlistPath = command.InfoPlistPath,
|
||||
};
|
||||
return new OsxPackCommandRunner(_logger).Run(options);
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
public virtual Task ExecutePackWindows(WindowsPackCommand command)
|
||||
{
|
||||
var options = new WindowsPackOptions {
|
||||
TargetRuntime = command.GetRid(),
|
||||
ReleaseDir = command.GetReleaseDirectory(),
|
||||
Package = command.Package,
|
||||
Icon = command.Icon,
|
||||
DeltaMode = command.Delta,
|
||||
SignParameters = command.SignParameters,
|
||||
EntryExecutableName = command.EntryExecutableName,
|
||||
PackAuthors = command.PackAuthors,
|
||||
PackDirectory = command.PackDirectory,
|
||||
Channel = command.Channel,
|
||||
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,
|
||||
};
|
||||
return new WindowsPackCommandRunner(_logger).Run(options);
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("linux")]
|
||||
public virtual Task ExecutePackLinux(LinuxPackCommand command)
|
||||
{
|
||||
var options = new LinuxPackOptions {
|
||||
TargetRuntime = command.GetRid(),
|
||||
ReleaseDir = command.GetReleaseDirectory(),
|
||||
Icon = command.Icon,
|
||||
DeltaMode = command.Delta,
|
||||
EntryExecutableName = command.EntryExecutableName,
|
||||
PackAuthors = command.PackAuthors,
|
||||
PackDirectory = command.PackDirectory,
|
||||
Channel = command.Channel,
|
||||
PackId = command.PackId,
|
||||
PackTitle = command.PackTitle,
|
||||
PackVersion = command.PackVersion,
|
||||
ReleaseNotes = command.ReleaseNotes,
|
||||
PackIsAppDir = command.PackIsAppDir,
|
||||
};
|
||||
return new LinuxPackCommandRunner(_logger).Run(options);
|
||||
}
|
||||
|
||||
//public virtual Task ExecuteReleasifyWindows(WindowsReleasifyCommand command)
|
||||
//{
|
||||
// var options = new WindowsReleasifyOptions {
|
||||
// TargetRuntime = command.GetRid(),
|
||||
// ReleaseDir = command.GetReleaseDirectory(),
|
||||
// Package = command.Package,
|
||||
// Icon = command.Icon,
|
||||
// DeltaMode = command.Delta,
|
||||
// SignParameters = command.SignParameters,
|
||||
// EntryExecutableName = command.EntryExecutableName,
|
||||
// Runtimes = command.Runtimes,
|
||||
// Channel = command.Channel,
|
||||
// SignParallel = command.SignParallel,
|
||||
// SignSkipDll = command.SignSkipDll,
|
||||
// SignTemplate = command.SignTemplate,
|
||||
// SplashImage = command.SplashImage,
|
||||
// };
|
||||
// new WindowsPackCommandRunner(_logger).Releasify(options);
|
||||
// return Task.CompletedTask;
|
||||
//}
|
||||
|
||||
public virtual Task ExecuteGithubDownload(GitHubDownloadCommand command)
|
||||
{
|
||||
var options = new GitHubDownloadOptions {
|
||||
Prerelease = command.Pre,
|
||||
ReleaseDir = command.GetReleaseDirectory(),
|
||||
RepoUrl = command.RepoUrl,
|
||||
Token = command.Token,
|
||||
Channel = command.Channel,
|
||||
};
|
||||
return new GitHubRepository(_logger).DownloadLatestFullPackageAsync(options);
|
||||
}
|
||||
|
||||
public virtual Task ExecuteGithubUpload(GitHubUploadCommand command)
|
||||
{
|
||||
var options = new GitHubUploadOptions {
|
||||
Prerelease = command.Pre,
|
||||
ReleaseDir = command.GetReleaseDirectory(),
|
||||
RepoUrl = command.RepoUrl,
|
||||
Token = command.Token,
|
||||
Publish = command.Publish,
|
||||
ReleaseName = command.ReleaseName,
|
||||
Channel = command.Channel,
|
||||
Merge = command.Merge,
|
||||
TagName = command.TagName,
|
||||
};
|
||||
return new GitHubRepository(_logger).UploadMissingAssetsAsync(options);
|
||||
}
|
||||
|
||||
public virtual Task ExecuteHttpDownload(HttpDownloadCommand command)
|
||||
{
|
||||
var options = new HttpDownloadOptions {
|
||||
ReleaseDir = command.GetReleaseDirectory(),
|
||||
Url = command.Url,
|
||||
Channel = command.Channel,
|
||||
};
|
||||
return new HttpRepository(_logger).DownloadLatestFullPackageAsync(options);
|
||||
}
|
||||
|
||||
public virtual Task ExecuteS3Download(S3DownloadCommand command)
|
||||
{
|
||||
var options = new S3DownloadOptions {
|
||||
Bucket = command.Bucket,
|
||||
Endpoint = command.Endpoint,
|
||||
Session = command.Session,
|
||||
KeyId = command.KeyId,
|
||||
Region = command.Region,
|
||||
ReleaseDir = command.GetReleaseDirectory(),
|
||||
Secret = command.Secret,
|
||||
Channel = command.Channel,
|
||||
};
|
||||
return new S3Repository(_logger).DownloadLatestFullPackageAsync(options);
|
||||
}
|
||||
|
||||
public virtual Task ExecuteS3Upload(S3UploadCommand command)
|
||||
{
|
||||
var options = new S3UploadOptions {
|
||||
Bucket = command.Bucket,
|
||||
Endpoint = command.Endpoint,
|
||||
KeyId = command.KeyId,
|
||||
Session = command.Session,
|
||||
Region = command.Region,
|
||||
ReleaseDir = command.GetReleaseDirectory(),
|
||||
Secret = command.Secret,
|
||||
Channel = command.Channel,
|
||||
KeepMaxReleases = command.KeepMaxReleases,
|
||||
};
|
||||
return new S3Repository(_logger).UploadMissingAssetsAsync(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(_logger).Run(options);
|
||||
}
|
||||
|
||||
public virtual Task ExecuteDeltaPatch(DeltaPatchCommand command)
|
||||
{
|
||||
var options = new DeltaPatchOptions {
|
||||
BasePackage = command.BasePackage,
|
||||
PatchFiles = command.PatchFiles,
|
||||
OutputFile = command.OutputFile,
|
||||
};
|
||||
return new DeltaPatchCommandRunner(_logger).Run(options);
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using Velopack.Vpk.Commands;
|
||||
|
||||
namespace Velopack.Vpk.Compat;
|
||||
|
||||
public interface ICommandRunner
|
||||
{
|
||||
public Task ExecuteGithubDownload(GitHubDownloadCommand command);
|
||||
public Task ExecuteGithubUpload(GitHubUploadCommand command);
|
||||
public Task ExecuteHttpDownload(HttpDownloadCommand command);
|
||||
public Task ExecuteS3Download(S3DownloadCommand command);
|
||||
public Task ExecuteS3Upload(S3UploadCommand command);
|
||||
public Task ExecuteBundleOsx(OsxBundleCommand command);
|
||||
public Task ExecutePackOsx(OsxPackCommand command);
|
||||
//public Task ExecuteReleasifyWindows(WindowsReleasifyCommand command);
|
||||
public Task ExecutePackWindows(WindowsPackCommand command);
|
||||
public Task ExecutePackLinux(LinuxPackCommand command);
|
||||
public Task ExecuteDeltaGen(DeltaGenCommand command);
|
||||
public Task ExecuteDeltaPatch(DeltaPatchCommand command);
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Velopack.Packaging.Exceptions;
|
||||
using Velopack.Vpk.Commands;
|
||||
using Velopack.Vpk.Updates;
|
||||
|
||||
namespace Velopack.Vpk.Compat;
|
||||
|
||||
public class RunnerFactory
|
||||
{
|
||||
private const string NUGET_PACKAGE_NAME = "Velopack";
|
||||
private readonly ILogger _logger;
|
||||
private readonly IConfiguration _config;
|
||||
|
||||
public RunnerFactory(ILogger logger, IConfiguration config)
|
||||
{
|
||||
_logger = logger;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public async Task<int> CreateAndExecuteAsync<T>(string commandName, T options) where T : BaseCommand
|
||||
{
|
||||
_logger.LogInformation($"[bold]{Program.INTRO}[/]");
|
||||
var runner = await CreateAsync(options);
|
||||
var method = typeof(ICommandRunner).GetMethod(commandName);
|
||||
try {
|
||||
await (Task) method.Invoke(runner, new object[] { options });
|
||||
return 0;
|
||||
} catch (Exception ex) when (ex is ProcessFailedException or UserInfoException) {
|
||||
// some exceptions are just user info / user error, so don't need a stack trace.
|
||||
_logger.Fatal($"[bold orange3]{ex.Message}[/]");
|
||||
return -1;
|
||||
} catch (Exception ex) {
|
||||
_logger.Fatal(ex, $"Command {commandName} had an exception.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<ICommandRunner> CreateAsync<T>(T options)
|
||||
{
|
||||
if (_config.GetValue<bool?>("SKIP_UPDATE_CHECK") != true) {
|
||||
var updateCheck = new UpdateChecker(_logger);
|
||||
await updateCheck.CheckForUpdates();
|
||||
}
|
||||
|
||||
return new EmbeddedRunner(_logger);
|
||||
//if (options is not PlatformCommand) {
|
||||
//}
|
||||
|
||||
//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='.");
|
||||
//}
|
||||
|
||||
//var version = new SdkVersionLocator(_logger).Search(solutionDir, NUGET_PACKAGE_NAME);
|
||||
|
||||
//var myVer = VelopackRuntimeInfo.VelopackNugetVersion;
|
||||
//if (version != myVer) {
|
||||
// _logger.Warn($"Installed SDK is {version}, while vpk is {myVer}, this is not recommended when building packages.");
|
||||
//}
|
||||
|
||||
//return new EmbeddedRunner(_logger);
|
||||
}
|
||||
|
||||
private string FindSolutionDirectory(string slnArgument)
|
||||
{
|
||||
if (!String.IsNullOrWhiteSpace(slnArgument)) {
|
||||
if (File.Exists(slnArgument) && slnArgument.EndsWith(".sln", StringComparison.InvariantCultureIgnoreCase)) {
|
||||
// we were given a sln file as argument
|
||||
return Path.GetDirectoryName(Path.GetFullPath(slnArgument));
|
||||
}
|
||||
|
||||
if (Directory.Exists(slnArgument) && Directory.EnumerateFiles(slnArgument, "*.sln").Any()) {
|
||||
return Path.GetFullPath(slnArgument);
|
||||
}
|
||||
}
|
||||
|
||||
// try to find the solution directory from cwd
|
||||
var cwd = Environment.CurrentDirectory;
|
||||
var slnSearchDirs = new string[] {
|
||||
cwd,
|
||||
Path.Combine(cwd, ".."),
|
||||
Path.Combine(cwd, "..", ".."),
|
||||
};
|
||||
|
||||
return slnSearchDirs.FirstOrDefault(d => Directory.EnumerateFiles(d, "*.sln").Any());
|
||||
}
|
||||
}
|
||||
42
src/Velopack.Vpk/Logging/BasicConsole.cs
Normal file
42
src/Velopack.Vpk/Logging/BasicConsole.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Spectre.Console;
|
||||
using Velopack.Packaging.Abstractions;
|
||||
|
||||
namespace Velopack.Vpk.Logging
|
||||
{
|
||||
public class BasicConsole : IFancyConsole
|
||||
{
|
||||
private readonly ILogger logger;
|
||||
|
||||
public BasicConsole(ILogger logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public async Task ExecuteProgressAsync(Func<IFancyConsoleProgress, Task> action)
|
||||
{
|
||||
await action(new Progress(logger));
|
||||
}
|
||||
|
||||
private class Progress : IFancyConsoleProgress
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public Progress(ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task RunTask(string name, Func<Action<int>, Task> fn)
|
||||
{
|
||||
_logger.Info("Starting: " + name);
|
||||
await Task.Run(() => fn(_ => { }));
|
||||
_logger.Info("Complete: " + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
74
src/Velopack.Vpk/Logging/SpectreConsole.cs
Normal file
74
src/Velopack.Vpk/Logging/SpectreConsole.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Spectre.Console;
|
||||
using Velopack.Packaging.Abstractions;
|
||||
|
||||
namespace Velopack.Vpk.Logging
|
||||
{
|
||||
public class SpectreConsole : IFancyConsole
|
||||
{
|
||||
private readonly ILogger logger;
|
||||
|
||||
public SpectreConsole(ILogger logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public async Task ExecuteProgressAsync(Func<IFancyConsoleProgress, Task> action)
|
||||
{
|
||||
var start = DateTime.UtcNow;
|
||||
await AnsiConsole.Progress()
|
||||
.AutoRefresh(true)
|
||||
.AutoClear(false)
|
||||
.HideCompleted(false)
|
||||
.Columns(new ProgressColumn[] {
|
||||
new SpinnerColumn(),
|
||||
new TaskDescriptionColumn(),
|
||||
new ProgressBarColumn(),
|
||||
new PercentageColumn(),
|
||||
new ElapsedTimeColumn(),
|
||||
})
|
||||
.StartAsync(async ctx => await action(new Progress(logger, ctx)));
|
||||
logger.Info($"[bold]Finished in {DateTime.UtcNow - start}.[/]");
|
||||
}
|
||||
|
||||
private class Progress : IFancyConsoleProgress
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly ProgressContext _context;
|
||||
|
||||
public Progress(ILogger logger, ProgressContext context)
|
||||
{
|
||||
_logger = logger;
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task RunTask(string name, Func<Action<int>, Task> fn)
|
||||
{
|
||||
_logger.Log(LogLevel.Debug, "Starting: " + name);
|
||||
|
||||
var task = _context.AddTask($"[italic]{name}[/]");
|
||||
task.StartTask();
|
||||
|
||||
void progress(int p)
|
||||
{
|
||||
if (p < 0) {
|
||||
task.IsIndeterminate = true;
|
||||
} else {
|
||||
task.IsIndeterminate = false;
|
||||
task.Value = Math.Min(100, p);
|
||||
}
|
||||
}
|
||||
|
||||
await Task.Run(() => fn(progress)).ConfigureAwait(false);
|
||||
task.IsIndeterminate = false;
|
||||
task.StopTask();
|
||||
|
||||
_logger.Log(LogLevel.Debug, $"[bold]Complete: {name}[/]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,8 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Serilog;
|
||||
using Serilog.Events;
|
||||
using Spectre.Console;
|
||||
using Velopack.Packaging;
|
||||
using Velopack.Packaging.Abstractions;
|
||||
using Velopack.Vpk.Commands;
|
||||
using Velopack.Vpk.Compat;
|
||||
using Velopack.Vpk.Logging;
|
||||
|
||||
namespace Velopack.Vpk;
|
||||
@@ -23,8 +21,6 @@ public class Program
|
||||
.SetRecursive(true)
|
||||
.SetDescription("Disable console colors and interactive components.");
|
||||
|
||||
private static RunnerFactory Runner { get; set; }
|
||||
|
||||
public static readonly string INTRO
|
||||
= $"Velopack CLI {VelopackRuntimeInfo.VelopackDisplayVersion} for creating and distributing releases.";
|
||||
|
||||
@@ -49,6 +45,7 @@ public class Program
|
||||
});
|
||||
|
||||
builder.Configuration.AddEnvironmentVariables("VPK_");
|
||||
builder.Services.AddTransient(s => s.GetService<ILoggerFactory>().CreateLogger("vpk"));
|
||||
|
||||
var conf = new LoggerConfiguration()
|
||||
.MinimumLevel.Is(verbose ? LogEventLevel.Debug : LogEventLevel.Information)
|
||||
@@ -57,10 +54,10 @@ public class Program
|
||||
|
||||
if (legacyConsole) {
|
||||
// spectre can have issues with redirected output, so we disable it.
|
||||
Packaging.Progress.IsEnabled = false;
|
||||
builder.Services.AddSingleton<IFancyConsole, BasicConsole>();
|
||||
conf.WriteTo.Console();
|
||||
} else {
|
||||
Packaging.Progress.IsEnabled = true;
|
||||
builder.Services.AddSingleton<IFancyConsole, SpectreConsole>();
|
||||
conf.WriteTo.Spectre();
|
||||
}
|
||||
|
||||
@@ -68,59 +65,16 @@ public class Program
|
||||
builder.Logging.AddSerilog();
|
||||
|
||||
var host = builder.Build();
|
||||
var logFactory = host.Services.GetRequiredService<ILoggerFactory>();
|
||||
var logger = logFactory.CreateLogger("vpk");
|
||||
var logger = host.Services.GetRequiredService<Microsoft.Extensions.Logging.ILogger>();
|
||||
|
||||
Runner = new RunnerFactory(logger, host.Services.GetRequiredService<IConfiguration>());
|
||||
|
||||
CliRootCommand rootCommand = new CliRootCommand(INTRO) {
|
||||
var rootCommand = new CliRootCommand(INTRO) {
|
||||
VerboseOption,
|
||||
LegacyConsole,
|
||||
};
|
||||
|
||||
switch (VelopackRuntimeInfo.SystemOs) {
|
||||
case RuntimeOs.Windows:
|
||||
Add(rootCommand, new WindowsPackCommand(), nameof(ICommandRunner.ExecutePackWindows));
|
||||
break;
|
||||
case RuntimeOs.OSX:
|
||||
Add(rootCommand, new OsxBundleCommand(), nameof(ICommandRunner.ExecuteBundleOsx));
|
||||
Add(rootCommand, new OsxPackCommand(), nameof(ICommandRunner.ExecutePackOsx));
|
||||
break;
|
||||
case RuntimeOs.Linux:
|
||||
Add(rootCommand, new LinuxPackCommand(), nameof(ICommandRunner.ExecutePackLinux));
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException("Unsupported OS platform: " + VelopackRuntimeInfo.SystemOs.GetOsLongName());
|
||||
}
|
||||
|
||||
CliCommand downloadCommand = new CliCommand("download", "Download's the latest release from a remote update source.");
|
||||
Add(downloadCommand, new HttpDownloadCommand(), nameof(ICommandRunner.ExecuteHttpDownload));
|
||||
Add(downloadCommand, new S3DownloadCommand(), nameof(ICommandRunner.ExecuteS3Download));
|
||||
Add(downloadCommand, new GitHubDownloadCommand(), nameof(ICommandRunner.ExecuteGithubDownload));
|
||||
rootCommand.Add(downloadCommand);
|
||||
|
||||
var uploadCommand = new CliCommand("upload", "Upload local package(s) to a remote update source.");
|
||||
Add(uploadCommand, new S3UploadCommand(), nameof(ICommandRunner.ExecuteS3Upload));
|
||||
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);
|
||||
rootCommand.PopulateVelopackCommands(host.Services);
|
||||
|
||||
var cli = new CliConfiguration(rootCommand);
|
||||
return await cli.InvokeAsync(args);
|
||||
}
|
||||
|
||||
private static CliCommand Add<T>(CliCommand parent, T command, string commandName)
|
||||
where T : BaseCommand
|
||||
{
|
||||
command.SetAction((ctx, token) => {
|
||||
command.SetProperties(ctx);
|
||||
return Runner.CreateAndExecuteAsync(commandName, command);
|
||||
});
|
||||
parent.Subcommands.Add(command);
|
||||
return command;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,8 @@
|
||||
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.23407.1" />
|
||||
<PackageReference Include="NuGet.Protocol" Version="6.8.0" />
|
||||
<PackageReference Include="Spectre.Console" Version="0.48.0" />
|
||||
<PackageReference Include="AutoMapper" Version="12.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
18
test/Velopack.CommandLine.Tests/AutoMapperTests.cs
Normal file
18
test/Velopack.CommandLine.Tests/AutoMapperTests.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Velopack.Vpk;
|
||||
|
||||
namespace Velopack.CommandLine.Tests
|
||||
{
|
||||
public class AutoMapperTests
|
||||
{
|
||||
[Fact]
|
||||
public void AutoMapperConfigIsValid()
|
||||
{
|
||||
CommandMapper.Validate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,7 @@ public class GitHubDownloadCommandTests : GitHubCommandTests<GitHubDownloadComma
|
||||
string cli = GetRequiredDefaultOptions() + "--pre";
|
||||
ParseResult parseResult = command.ParseAndApply(cli);
|
||||
|
||||
Assert.True(command.Pre);
|
||||
Assert.True(command.Prerelease);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ public abstract class ReleaseCommandTests<T> : BaseCommandTests<T>
|
||||
string cli = GetRequiredDefaultOptions() + "--delta none";
|
||||
ParseResult parseResult = command.ParseAndApply(cli);
|
||||
|
||||
Assert.True(command.Delta == Packaging.DeltaMode.None);
|
||||
Assert.True(command.DeltaMode == Packaging.DeltaMode.None);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Velopack.Packaging.Unix.Commands;
|
||||
using Velopack.Packaging.Windows.Commands;
|
||||
using Velopack.Vpk.Logging;
|
||||
|
||||
namespace Velopack.Packaging.Tests
|
||||
{
|
||||
@@ -46,7 +47,7 @@ namespace Velopack.Packaging.Tests
|
||||
ReleaseNotes = releaseNotes,
|
||||
Channel = channel,
|
||||
};
|
||||
var runner = new WindowsPackCommandRunner(logger);
|
||||
var runner = new WindowsPackCommandRunner(logger, new BasicConsole(logger));
|
||||
runner.Run(options).GetAwaiterResult();
|
||||
} else if (VelopackRuntimeInfo.IsOSX) {
|
||||
var options = new OsxPackOptions {
|
||||
@@ -60,7 +61,7 @@ namespace Velopack.Packaging.Tests
|
||||
ReleaseNotes = releaseNotes,
|
||||
Channel = channel,
|
||||
};
|
||||
var runner = new OsxPackCommandRunner(logger);
|
||||
var runner = new OsxPackCommandRunner(logger, new BasicConsole(logger));
|
||||
runner.Run(options).GetAwaiterResult();
|
||||
} else if (VelopackRuntimeInfo.IsLinux) {
|
||||
var options = new LinuxPackOptions {
|
||||
@@ -74,7 +75,7 @@ namespace Velopack.Packaging.Tests
|
||||
ReleaseNotes = releaseNotes,
|
||||
Channel = channel,
|
||||
};
|
||||
var runner = new LinuxPackCommandRunner(logger);
|
||||
var runner = new LinuxPackCommandRunner(logger, new BasicConsole(logger));
|
||||
runner.Run(options).GetAwaiterResult();
|
||||
} else {
|
||||
throw new PlatformNotSupportedException();
|
||||
|
||||
@@ -5,9 +5,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Velopack.Deployment\Velopack.Deployment.csproj" />
|
||||
<ProjectReference Include="..\..\src\Velopack.Packaging.Unix\Velopack.Packaging.Unix.csproj" />
|
||||
<ProjectReference Include="..\..\src\Velopack.Packaging.Windows\Velopack.Packaging.Windows.csproj" />
|
||||
<ProjectReference Include="..\..\src\Velopack.Vpk\Velopack.Vpk.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -9,6 +9,7 @@ using Velopack.Compression;
|
||||
using Velopack.Packaging.Commands;
|
||||
using Velopack.Packaging.Exceptions;
|
||||
using Velopack.Packaging.Windows.Commands;
|
||||
using Velopack.Vpk.Logging;
|
||||
using Velopack.Windows;
|
||||
|
||||
namespace Velopack.Packaging.Tests;
|
||||
@@ -55,7 +56,7 @@ public class WindowsPackTests
|
||||
Channel = "asd123"
|
||||
};
|
||||
|
||||
var runner = new WindowsPackCommandRunner(logger);
|
||||
var runner = new WindowsPackCommandRunner(logger, new BasicConsole(logger));
|
||||
runner.Run(options).GetAwaiterResult();
|
||||
|
||||
var nupkgPath = Path.Combine(tmpReleaseDir, $"{id}-{version}-asd123-full.nupkg");
|
||||
@@ -118,7 +119,7 @@ public class WindowsPackTests
|
||||
TargetRuntime = RID.Parse("win"),
|
||||
};
|
||||
|
||||
var runner = new WindowsPackCommandRunner(logger);
|
||||
var runner = new WindowsPackCommandRunner(logger, new BasicConsole(logger));
|
||||
runner.Run(options).GetAwaiterResult();
|
||||
|
||||
Assert.Throws<UserInfoException>(() => runner.Run(options).GetAwaiterResult());
|
||||
@@ -155,7 +156,7 @@ public class WindowsPackTests
|
||||
Channel = "hello",
|
||||
};
|
||||
|
||||
var runner = new WindowsPackCommandRunner(logger);
|
||||
var runner = new WindowsPackCommandRunner(logger, new BasicConsole(logger));
|
||||
runner.Run(options).GetAwaiterResult();
|
||||
|
||||
options.TargetRuntime = RID.Parse("win10.0.19043-x86");
|
||||
@@ -190,7 +191,7 @@ public class WindowsPackTests
|
||||
PackDirectory = tmpOutput,
|
||||
};
|
||||
|
||||
var runner = new WindowsPackCommandRunner(logger);
|
||||
var runner = new WindowsPackCommandRunner(logger, new BasicConsole(logger));
|
||||
runner.Run(options).GetAwaiterResult();
|
||||
|
||||
var setupPath1 = Path.Combine(tmpReleaseDir, $"{id}-win-Setup.exe");
|
||||
@@ -305,7 +306,7 @@ public class WindowsPackTests
|
||||
|
||||
// apply delta and check package
|
||||
var output = Path.Combine(releaseDir, "delta.patched");
|
||||
new DeltaPatchCommandRunner(logger).Run(new DeltaPatchOptions {
|
||||
new DeltaPatchCommandRunner(logger, new BasicConsole(logger)).Run(new DeltaPatchOptions {
|
||||
BasePackage = Path.Combine(releaseDir, $"{id}-1.0.0-full.nupkg"),
|
||||
OutputFile = output,
|
||||
PatchFiles = new[] { new FileInfo(deltaPath) },
|
||||
@@ -679,7 +680,7 @@ public class WindowsPackTests
|
||||
PackDirectory = Path.Combine(projDir, "publish"),
|
||||
};
|
||||
|
||||
var runner = new WindowsPackCommandRunner(logger);
|
||||
var runner = new WindowsPackCommandRunner(logger, new BasicConsole(logger));
|
||||
runner.Run(options).GetAwaiterResult();
|
||||
} finally {
|
||||
File.WriteAllText(testStringFile, oldText);
|
||||
|
||||
Reference in New Issue
Block a user