Remove Msft.Logging from C# lib

This commit is contained in:
Caelan Sayler
2025-03-03 10:46:36 +00:00
committed by Caelan
parent fd96504ff4
commit 60890b7bba
63 changed files with 789 additions and 395 deletions

View File

@@ -4,20 +4,20 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Logging;
using Velopack.Exceptions;
using Velopack.Logging;
using Velopack.Util;
namespace Velopack.Compression
{
internal abstract class DeltaPackage
{
protected readonly ILogger Log;
protected readonly IVelopackLogger Log;
protected readonly string BaseTempDir;
private static Regex DIFF_SUFFIX = new Regex(@"\.(bs|zs)?diff$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public DeltaPackage(ILogger logger, string baseTmpDir)
public DeltaPackage(IVelopackLogger logger, string baseTmpDir)
{
Log = logger;
BaseTempDir = baseTmpDir;

View File

@@ -1,6 +1,6 @@
using System;
using System.Diagnostics;
using Microsoft.Extensions.Logging;
using Velopack.Logging;
using Velopack.Util;
namespace Velopack.Compression
@@ -9,7 +9,7 @@ namespace Velopack.Compression
{
private readonly string _updateExePath;
public DeltaUpdateExe(ILogger logger, string baseTmpDir, string updateExePath) : base(logger, baseTmpDir)
public DeltaUpdateExe(IVelopackLogger logger, string baseTmpDir, string updateExePath) : base(logger, baseTmpDir)
{
_updateExePath = updateExePath;
}
@@ -19,11 +19,12 @@ namespace Velopack.Compression
var psi = new ProcessStartInfo(_updateExePath);
psi.AppendArgumentListSafe(new string[] { "patch", "--old", baseFile, "--patch", patchFile, "--output", outputFile }, out var _);
psi.CreateNoWindow = true;
var p = psi.StartRedirectOutputToILogger(Log, LogLevel.Debug);
var p = psi.StartRedirectOutputToILogger(Log, VelopackLogLevel.Debug);
if (!p.WaitForExit(30_000)) {
p.Kill();
throw new TimeoutException("zstd patch process timed out (30s).");
}
if (p.ExitCode != 0) {
throw new Exception($"zstd patch process failed with exit code {p.ExitCode}.");
}

View File

@@ -6,7 +6,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Velopack.Logging;
using Velopack.Util;
namespace Velopack.Compression
@@ -15,7 +15,7 @@ namespace Velopack.Compression
{
private const string SYMLINK_EXT = ".__symlink";
public static void ExtractZipToDirectory(ILogger logger, string inputFile, string outputDirectory, bool expandSymlinks = false)
public static void ExtractZipToDirectory(IVelopackLogger logger, string inputFile, string outputDirectory, bool expandSymlinks = false)
{
logger.Debug($"Extracting '{inputFile}' to '{outputDirectory}' using System.IO.Compression...");
IoUtil.DeleteFileOrDirectoryHard(outputDirectory);
@@ -85,7 +85,7 @@ namespace Velopack.Compression
internal static string SanitizeEntryFilePath(string entryPath) => entryPath.Replace('\0', '_');
public static async Task CreateZipFromDirectoryAsync(ILogger logger, string outputFile, string directoryToCompress, Action<int>? progress = null,
public static async Task CreateZipFromDirectoryAsync(IVelopackLogger logger, string outputFile, string directoryToCompress, Action<int>? progress = null,
CompressionLevel compressionLevel = CompressionLevel.Optimal, CancellationToken cancelToken = default)
{
progress ??= (x => { });

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using NuGet.Versioning;
using Velopack.Logging;
namespace Velopack.Locators
{
@@ -38,7 +39,10 @@ namespace Velopack.Locators
/// <summary> The release channel this package was built for. </summary>
public string? Channel { get; }
/// <summary> The logging interface to use for Velopack diagnostic messages. </summary>
public IVelopackLogger Log { get; }
/// <summary>
/// A flag indicating if this is a portable build, and that the settings should be self-contained in the package.
/// On Windows, this is true for portable builds, and false for non-portable builds which were installed by Setup.exe

View File

@@ -1,8 +1,8 @@
using System;
using System;
using System.IO;
using System.Runtime.Versioning;
using Microsoft.Extensions.Logging;
using NuGet.Versioning;
using Velopack.Logging;
using Velopack.NuGet;
using Velopack.Util;
@@ -33,6 +33,9 @@ namespace Velopack.Locators
/// <inheritdoc />
public override string? Channel { get; }
/// <inheritdoc />
public override IVelopackLogger Log { get; }
/// <inheritdoc />
public override string? AppTempDir => CreateSubDirIfDoesNotExist(TempUtil.GetDefaultTempBaseDirectory(), AppId);
@@ -58,8 +61,7 @@ namespace Velopack.Locators
/// Creates a new <see cref="OsxVelopackLocator"/> and auto-detects the
/// app information from metadata embedded in the .app.
/// </summary>
public LinuxVelopackLocator(string currentProcessPath, uint currentProcessId, ILogger logger)
: base(logger)
public LinuxVelopackLocator(string currentProcessPath, uint currentProcessId, IVelopackLogger? logger)
{
if (!VelopackRuntimeInfo.IsLinux)
throw new NotSupportedException("Cannot instantiate LinuxVelopackLocator on a non-linux system.");
@@ -67,12 +69,16 @@ namespace Velopack.Locators
ProcessId = currentProcessId;
var ourPath = ProcessExePath = currentProcessPath;
Log.Info($"Initialising {nameof(LinuxVelopackLocator)}");
logger ??= new FileVelopackLogger("/tmp/velopack.log", currentProcessId);
logger.Info($"Initialising {nameof(LinuxVelopackLocator)}");
Log = logger;
// are we inside a mounted .AppImage?
var ix = ourPath.IndexOf("/usr/bin/", StringComparison.InvariantCultureIgnoreCase);
if (ix <= 0) {
Log.Warn($"Unable to locate .AppImage root from '{ourPath}'. This warning indicates that the application is not running from a mounted .AppImage, for example during development.");
logger.Warn(
$"Unable to locate .AppImage root from '{ourPath}'. " +
$"This warning indicates that the application is not running from a mounted .AppImage, for example during development.");
return;
}
@@ -83,7 +89,7 @@ namespace Velopack.Locators
if (!String.IsNullOrEmpty(AppImagePath) && File.Exists(AppImagePath)) {
if (File.Exists(updateExe) && PackageManifest.TryParseFromFile(metadataPath, out var manifest)) {
Log.Info("Located valid manifest file at: " + metadataPath);
logger.Info("Located valid manifest file at: " + metadataPath);
AppId = manifest.Id;
RootAppDir = rootDir;
AppContentDir = contentsDir;
@@ -98,4 +104,4 @@ namespace Velopack.Locators
}
}
}
}
}

View File

@@ -1,8 +1,8 @@
using System;
using System;
using System.IO;
using System.Runtime.Versioning;
using Microsoft.Extensions.Logging;
using NuGet.Versioning;
using Velopack.Logging;
using Velopack.NuGet;
using Velopack.Util;
@@ -36,6 +36,9 @@ namespace Velopack.Locators
/// <inheritdoc />
public override string? PackagesDir => CreateSubDirIfDoesNotExist(CachesAppDir, "packages");
/// <inheritdoc />
public override IVelopackLogger Log { get; }
private string? CachesAppDir => CreateSubDirIfDoesNotExist(CachesVelopackDir, AppId);
private string? CachesVelopackDir => CreateSubDirIfDoesNotExist(CachesDir, "velopack");
private string? CachesDir => CreateSubDirIfDoesNotExist(LibraryDir, "Caches");
@@ -55,8 +58,7 @@ namespace Velopack.Locators
/// Creates a new <see cref="OsxVelopackLocator"/> and auto-detects the
/// app information from metadata embedded in the .app.
/// </summary>
public OsxVelopackLocator(string currentProcessPath, uint currentProcessId, ILogger logger)
: base(logger)
public OsxVelopackLocator(string currentProcessPath, uint currentProcessId, IVelopackLogger? logger)
{
if (!VelopackRuntimeInfo.IsOSX)
throw new NotSupportedException("Cannot instantiate OsxLocator on a non-osx system.");
@@ -64,12 +66,16 @@ namespace Velopack.Locators
ProcessId = currentProcessId;
var ourPath = ProcessExePath = currentProcessPath;
Log.Info($"Initialising {nameof(OsxVelopackLocator)}");
var userLogDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Logs");
var logPath = Directory.Exists(userLogDir) ? Path.Combine(userLogDir, "velopack.log") : "/tmp/velopack.log";
logger ??= new FileVelopackLogger(logPath, currentProcessId);
logger.Info($"Initialising {nameof(OsxVelopackLocator)}");
Log = logger;
// are we inside a .app?
var ix = ourPath.IndexOf(".app/", StringComparison.InvariantCultureIgnoreCase);
if (ix <= 0) {
Log.Warn($"Unable to locate .app root from '{ourPath}'");
logger.Warn($"Unable to locate .app root from '{ourPath}'");
return;
}
@@ -80,7 +86,7 @@ namespace Velopack.Locators
var metadataPath = Path.Combine(macosDir, CoreUtil.SpecVersionFileName);
if (File.Exists(updateExe) && PackageManifest.TryParseFromFile(metadataPath, out var manifest)) {
Log.Info("Located valid manifest file at: " + metadataPath);
logger.Info("Located valid manifest file at: " + metadataPath);
AppId = manifest.Id;
RootAppDir = appPath;
UpdateExePath = updateExe;

View File

@@ -1,7 +1,8 @@
using System;
using System;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Logging;
using NuGet.Versioning;
using Velopack.Logging;
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace Velopack.Locators
@@ -19,6 +20,7 @@ namespace Velopack.Locators
if (_id == null) {
throw new NotSupportedException("AppId is not supported in this test implementation.");
}
return _id;
}
}
@@ -28,6 +30,7 @@ namespace Velopack.Locators
if (_root == null) {
throw new NotSupportedException("RootAppDir is not supported in this test implementation.");
}
return _root;
}
}
@@ -37,6 +40,7 @@ namespace Velopack.Locators
if (_packages == null) {
throw new NotSupportedException("PackagesDir is not supported in this test implementation.");
}
return _packages;
}
}
@@ -46,6 +50,7 @@ namespace Velopack.Locators
if (_updatePath == null) {
throw new NotSupportedException("UpdateExePath is not supported in this test implementation.");
}
return _updatePath;
}
}
@@ -55,6 +60,7 @@ namespace Velopack.Locators
if (_version == null) {
throw new NotSupportedException("CurrentlyInstalledVersion is not supported in this test implementation.");
}
return _version;
}
}
@@ -64,6 +70,7 @@ namespace Velopack.Locators
if (_appContent == null) {
throw new NotSupportedException("AppContentDir is not supported in this test implementation.");
}
return _appContent;
}
}
@@ -74,11 +81,14 @@ namespace Velopack.Locators
}
}
public override IVelopackLogger Log { get; }
public override VelopackAsset? GetLatestLocalFullPackage()
{
if (_asset != null) {
return _asset;
}
return base.GetLatestLocalFullPackage();
}
@@ -96,15 +106,14 @@ namespace Velopack.Locators
private readonly VelopackAsset? _asset;
/// <inheritdoc cref="TestVelopackLocator" />
public TestVelopackLocator(string appId, string version, string packagesDir, ILogger? logger = null)
public TestVelopackLocator(string appId, string version, string packagesDir, IVelopackLogger? logger = null)
: this(appId, version, packagesDir, null, null, null, null, logger)
{
}
/// <inheritdoc cref="TestVelopackLocator" />
public TestVelopackLocator(string appId, string version, string packagesDir, string? appDir,
string? rootDir, string? updateExe, string? channel = null, ILogger? logger = null, VelopackAsset? localPackage = null, string processPath = null!)
: base(logger)
string? rootDir, string? updateExe, string? channel = null, IVelopackLogger? logger = null, VelopackAsset? localPackage = null, string processPath = null!)
{
_id = appId;
_packages = packagesDir;
@@ -115,6 +124,7 @@ namespace Velopack.Locators
_channel = channel;
_asset = localPackage;
ProcessExePath = processPath;
Log = logger ?? new NullVelopackLogger();
}
}
}
}

View File

@@ -1,13 +1,11 @@
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using NuGet.Versioning;
using Velopack.Util;
using Velopack.Logging;
namespace Velopack.Locators
{
@@ -16,34 +14,57 @@ namespace Velopack.Locators
/// </summary>
public abstract class VelopackLocator : IVelopackLocator
{
private static VelopackLocator? _current;
private static IVelopackLocator? _current;
/// <summary>
/// Auto-detect the platform from the current operating system.
/// Check if a VelopackLocator has been set for the current process.
/// </summary>
public static VelopackLocator GetDefault(ILogger? logger)
{
var log = logger ?? NullLogger.Instance;
public static bool IsCurrentSet => _current != null;
if (_current != null)
/// <summary>
/// Get the current locator in use, this process-wide locator can be set/overriden during VelopackApp.Build().
/// Alternatively, most methods which use locators also accept an IVelopackLocator as a parameter.
/// </summary>
public static IVelopackLocator Current {
get {
if (_current == null)
throw new InvalidOperationException(
"No VelopackLocator has been set. Either call VelopackApp.Build() or provide IVelopackLocator as a method parameter.");
return _current;
}
}
/// <summary> Create a new default locator based on the current operating system. </summary>
public static IVelopackLocator CreateDefaultForPlatform(IVelopackLogger? logger = null)
{
var process = Process.GetCurrentProcess();
var processExePath = process.MainModule?.FileName ?? throw new InvalidOperationException("Could not determine process path.");
var processId = (uint)process.Id;
var processExePath = process.MainModule?.FileName
?? throw new InvalidOperationException("Could not determine process path, please construct IVelopackLocator manually.");
var processId = (uint) process.Id;
if (VelopackRuntimeInfo.IsWindows)
return _current = new WindowsVelopackLocator(processExePath, processId, log);
return _current = new WindowsVelopackLocator(processExePath, processId, logger);
if (VelopackRuntimeInfo.IsOSX)
return _current = new OsxVelopackLocator(processExePath, processId, log);
return _current = new OsxVelopackLocator(processExePath, processId, logger);
if (VelopackRuntimeInfo.IsLinux)
return _current = new LinuxVelopackLocator(processExePath, processId, log);
return _current = new LinuxVelopackLocator(processExePath, processId, logger);
throw new PlatformNotSupportedException($"OS platform '{VelopackRuntimeInfo.SystemOs.GetOsLongName()}' is not supported.");
}
internal static void SetCurrentLocator(IVelopackLocator locator)
{
_current = locator;
}
internal static IVelopackLocator GetCurrentOrCreateDefault(IVelopackLogger? logger = null)
{
_current ??= CreateDefaultForPlatform(logger);
return _current;
}
/// <inheritdoc/>
public abstract string? AppId { get; }
@@ -65,12 +86,15 @@ namespace Velopack.Locators
/// <inheritdoc/>
public abstract string? Channel { get; }
/// <inheritdoc/>
public abstract IVelopackLogger Log { get; }
/// <inheritdoc/>
public abstract uint ProcessId { get; }
/// <inheritdoc/>
public abstract string ProcessExePath { get; }
/// <inheritdoc/>
public virtual bool IsPortable => false;
@@ -90,15 +114,6 @@ namespace Velopack.Locators
/// <inheritdoc/>
public abstract SemanticVersion? CurrentlyInstalledVersion { get; }
/// <summary> The log interface to use for diagnostic messages. </summary>
protected ILogger Log { get; }
/// <inheritdoc cref="VelopackLocator"/>
protected VelopackLocator(ILogger? logger)
{
Log = logger ?? NullLogger.Instance;
}
/// <inheritdoc/>
public virtual List<VelopackAsset> GetLocalPackages()
{
@@ -119,6 +134,7 @@ namespace Velopack.Locators
}
}
}
return list;
} catch (Exception ex) {
Log.Error(ex, "Error while reading local packages.");
@@ -131,8 +147,7 @@ namespace Velopack.Locators
{
return GetLocalPackages()
.OrderByDescending(x => x.Version)
.Where(a => a.Type == VelopackAssetType.Full)
.FirstOrDefault();
.FirstOrDefault(a => a.Type == VelopackAssetType.Full);
}
/// <summary>
@@ -161,6 +176,7 @@ namespace Velopack.Locators
if (!Guid.TryParse(File.ReadAllText(stagedUserIdFile, Encoding.UTF8), out ret)) {
throw new Exception("File was read but contents were invalid");
}
Log.Info($"Loaded existing staging userId: {ret}");
return ret;
} catch (Exception ex) {

View File

@@ -1,8 +1,9 @@
using System;
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.Versioning;
using Microsoft.Extensions.Logging;
using NuGet.Versioning;
using Velopack.Logging;
using Velopack.NuGet;
using Velopack.Util;
@@ -32,6 +33,9 @@ namespace Velopack.Locators
/// <inheritdoc />
public override string? PackagesDir => CreateSubDirIfDoesNotExist(RootAppDir, "packages");
/// <inheritdoc />
public override IVelopackLogger Log { get; }
/// <inheritdoc />
public override bool IsPortable => RootAppDir != null && File.Exists(Path.Combine(RootAppDir, ".portable"));
@@ -40,13 +44,12 @@ namespace Velopack.Locators
/// <inheritdoc />
public override uint ProcessId { get; }
/// <inheritdoc />
public override string ProcessExePath { get; }
/// <inheritdoc cref="WindowsVelopackLocator" />
public WindowsVelopackLocator(string currentProcessPath, uint currentProcessId, ILogger logger)
: base(logger)
public WindowsVelopackLocator(string currentProcessPath, uint currentProcessId, IVelopackLogger? logger)
{
if (!VelopackRuntimeInfo.IsWindows)
throw new NotSupportedException("Cannot instantiate WindowsLocator on a non-Windows system.");
@@ -66,29 +69,31 @@ namespace Velopack.Locators
var possibleUpdateExe = Path.GetFullPath(Path.Combine(myDirPath, "..", "Update.exe"));
var ixCurrent = ourPath.LastIndexOf("/current/", StringComparison.InvariantCultureIgnoreCase);
Log.Info($"Initializing {nameof(WindowsVelopackLocator)}");
if (File.Exists(possibleUpdateExe)) {
Log.Info("Update.exe found in parent directory");
// we're running in a directory with an Update.exe in the parent directory
var manifestFile = Path.Combine(myDirPath, CoreUtil.SpecVersionFileName);
var rootDir = Path.GetDirectoryName(possibleUpdateExe)!;
logger ??= new FileVelopackLogger(Path.Combine(rootDir, "velopack.log"), currentProcessId);
Log = logger;
if (PackageManifest.TryParseFromFile(manifestFile, out var manifest)) {
// ideal, the info we need is in a manifest file.
Log.Info("Located valid manifest file at: " + manifestFile);
logger.Info($"{nameof(WindowsVelopackLocator)}: Update.exe in parent dir, Located valid manifest file at: " + manifestFile);
AppId = manifest.Id;
CurrentlyInstalledVersion = manifest.Version;
RootAppDir = Path.GetDirectoryName(possibleUpdateExe);
RootAppDir = rootDir;
UpdateExePath = possibleUpdateExe;
AppContentDir = myDirPath;
Channel = manifest.Channel;
} else if (PathUtil.PathPartStartsWith(myDirName, "app-") && NuGetVersion.TryParse(myDirName.Substring(4), out var version)) {
// this is a legacy case, where we're running in an 'root/app-*/' directory, and there is no manifest.
Log.Warn("Legacy app-* directory detected, sq.version not found. Using directory name for AppId and Version.");
logger.Warn("Update.exe in parent dir, Legacy app-* directory detected, sq.version not found. Using directory name for AppId and Version.");
AppId = Path.GetFileName(Path.GetDirectoryName(possibleUpdateExe));
CurrentlyInstalledVersion = version;
RootAppDir = Path.GetDirectoryName(possibleUpdateExe);
RootAppDir = rootDir;
UpdateExePath = possibleUpdateExe;
AppContentDir = myDirPath;
} else {
logger.Error("Update.exe in parent dir, but unable to locate a valid manifest file at: " + manifestFile);
}
} else if (ixCurrent > 0) {
// this is an attempt to handle the case where we are running in a nested current directory.
@@ -98,8 +103,10 @@ namespace Velopack.Locators
possibleUpdateExe = Path.GetFullPath(Path.Combine(rootDir, "Update.exe"));
// we only support parsing a manifest when we're in a nested current directory. no legacy fallback.
if (File.Exists(possibleUpdateExe) && PackageManifest.TryParseFromFile(manifestFile, out var manifest)) {
Log.Warn("Running in deeply nested directory. This is not an advised use-case.");
Log.Info("Located valid manifest file at: " + manifestFile);
logger ??= new FileVelopackLogger(Path.Combine(rootDir, "velopack.log"), currentProcessId);
Log = logger;
logger.Warn("Running in deeply nested directory. This is not an advised use-case.");
logger.Info("Located valid manifest file at: " + manifestFile);
RootAppDir = Path.GetDirectoryName(possibleUpdateExe);
UpdateExePath = possibleUpdateExe;
AppId = manifest.Id;
@@ -108,6 +115,15 @@ namespace Velopack.Locators
Channel = manifest.Channel;
}
}
if (Log == null) {
try {
Log = new FileVelopackLogger(Path.Combine(AppContext.BaseDirectory, "velopack.log"), currentProcessId);
} catch (Exception ex) {
Debug.WriteLine("Error creating Velopack logger: " + ex);
Log = new NullVelopackLogger();
}
}
}
}
}

View File

@@ -0,0 +1,18 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
namespace Velopack.Logging
{
public class ConsoleVelopackLogger : IVelopackLogger
{
public void Log(VelopackLogLevel logLevel, string? message, Exception? exception)
{
var logMessage = $"[{DateTime.Now.ToShortTimeString()}] [{logLevel}] {message}";
if (exception != null) {
logMessage += Environment.NewLine + exception;
}
Console.WriteLine(logMessage);
}
}
}

View File

@@ -0,0 +1,51 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
using System.Diagnostics;
using System.IO;
namespace Velopack.Logging
{
public class FileVelopackLogger : IVelopackLogger, IDisposable
{
public uint ProcessId { get; }
private readonly object _lock = new();
private readonly StreamWriter _writer;
private readonly FileStream _fileStream;
public FileVelopackLogger(string filePath, uint processId)
{
ProcessId = processId;
_fileStream = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
_writer = new StreamWriter(_fileStream);
}
public void Log(VelopackLogLevel logLevel, string? message, Exception? exception)
{
try {
lock (_lock) {
var logMessage = $"[lib-csharp:{ProcessId}] [{DateTime.Now.ToShortTimeString()}] [{logLevel}] {message}";
if (exception != null) {
logMessage += Environment.NewLine + exception;
}
_writer.WriteLine(logMessage);
}
} catch (Exception ex) {
Debug.WriteLine($"Error writing to log file: {ex}");
}
}
public void Dispose()
{
try {
lock (_lock) {
_writer.Flush();
_writer.Dispose();
_fileStream.Dispose();
}
} catch (Exception ex) {
Debug.WriteLine($"Error disposing log file: {ex}");
}
}
}
}

View File

@@ -0,0 +1,11 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
namespace Velopack.Logging
{
public interface IVelopackLogger
{
void Log(VelopackLogLevel logLevel, string? message, Exception? exception);
}
}

View File

@@ -0,0 +1,166 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
using System.Diagnostics.CodeAnalysis;
namespace Velopack.Logging
{
[ExcludeFromCodeCoverage]
public static class LoggerExtensions
{
public static void Log(this IVelopackLogger logger, VelopackLogLevel logLevel, string message)
{
logger.Log(logLevel, message, null);
}
public static void LogTrace(this IVelopackLogger logger, string message)
{
logger.Log(VelopackLogLevel.Trace, message, null);
}
public static void LogTrace(this IVelopackLogger logger, Exception ex, string message)
{
logger.Log(VelopackLogLevel.Trace, message, ex);
}
public static void LogDebug(this IVelopackLogger logger, string message)
{
logger.Log(VelopackLogLevel.Debug, message, null);
}
public static void LogDebug(this IVelopackLogger logger, Exception ex, string message)
{
logger.Log(VelopackLogLevel.Debug, message, ex);
}
public static void LogInformation(this IVelopackLogger logger, string message)
{
logger.Log(VelopackLogLevel.Information, message, null);
}
public static void LogInformation(this IVelopackLogger logger, Exception ex, string message)
{
logger.Log(VelopackLogLevel.Information, message, ex);
}
public static void LogWarning(this IVelopackLogger logger, string message)
{
logger.Log(VelopackLogLevel.Warning, message, null);
}
public static void LogWarning(this IVelopackLogger logger, Exception ex, string message)
{
logger.Log(VelopackLogLevel.Warning, message, ex);
}
public static void LogError(this IVelopackLogger logger, string message)
{
logger.Log(VelopackLogLevel.Error, message, null);
}
public static void LogError(this IVelopackLogger logger, Exception ex, string message)
{
logger.Log(VelopackLogLevel.Error, message, ex);
}
public static void LogCritical(this IVelopackLogger logger, string message)
{
logger.Log(VelopackLogLevel.Critical, message, null);
}
public static void LogCritical(this IVelopackLogger logger, Exception ex, string message)
{
logger.Log(VelopackLogLevel.Critical, message, ex);
}
public static void Trace(this IVelopackLogger logger, string message)
{
logger.LogTrace(message);
}
public static void Trace(this IVelopackLogger logger, Exception ex, string message)
{
logger.LogTrace(ex, message);
}
public static void Trace(this IVelopackLogger logger, Exception ex)
{
logger.LogTrace(ex, ex.Message);
}
public static void Debug(this IVelopackLogger logger, string message)
{
logger.LogDebug(message);
}
public static void Debug(this IVelopackLogger logger, Exception ex, string message)
{
logger.LogDebug(ex, message);
}
public static void Debug(this IVelopackLogger logger, Exception ex)
{
logger.LogDebug(ex, ex.Message);
}
public static void Info(this IVelopackLogger logger, string message)
{
logger.LogInformation(message);
}
public static void Info(this IVelopackLogger logger, Exception ex, string message)
{
logger.LogInformation(ex, message);
}
public static void Info(this IVelopackLogger logger, Exception ex)
{
logger.LogInformation(ex, ex.Message);
}
public static void Warn(this IVelopackLogger logger, string message)
{
logger.LogWarning(message);
}
public static void Warn(this IVelopackLogger logger, Exception ex, string message)
{
logger.LogWarning(ex, message);
}
public static void Warn(this IVelopackLogger logger, Exception ex)
{
logger.LogWarning(ex, ex.Message);
}
public static void Error(this IVelopackLogger logger, string message)
{
logger.LogError(message);
}
public static void Error(this IVelopackLogger logger, Exception ex, string message)
{
logger.LogError(ex, message);
}
public static void Error(this IVelopackLogger logger, Exception ex)
{
logger.LogError(ex, ex.Message);
}
public static void Fatal(this IVelopackLogger logger, string message)
{
logger.LogCritical(message);
}
public static void Fatal(this IVelopackLogger logger, Exception ex, string message)
{
logger.LogCritical(ex, message);
}
public static void Fatal(this IVelopackLogger logger, Exception ex)
{
logger.LogCritical(ex, ex.Message);
}
}
}

View File

@@ -0,0 +1,15 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
using System;
namespace Velopack.Logging
{
public class NullVelopackLogger : IVelopackLogger
{
public static readonly NullVelopackLogger Instance = new();
public void Log(VelopackLogLevel logLevel, string? message, Exception? exception)
{
// Do nothing
}
}
}

View File

@@ -0,0 +1,14 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace Velopack.Logging
{
public enum VelopackLogLevel
{
Trace = 0,
Debug = 1,
Information = 2,
Warning = 3,
Error = 4,
Critical = 5,
}
}

View File

@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Velopack.Logging;
using Velopack.Util;
namespace Velopack.Sources
@@ -49,7 +49,7 @@ namespace Velopack.Sources
}
/// <inheritdoc />
public virtual Task DownloadReleaseEntry(ILogger logger, VelopackAsset releaseEntry, string localFile, Action<int> progress, CancellationToken cancelToken)
public virtual Task DownloadReleaseEntry(IVelopackLogger logger, VelopackAsset releaseEntry, string localFile, Action<int> progress, CancellationToken cancelToken)
{
if (releaseEntry is GitBaseAsset githubEntry) {
// this might be a browser url or an api url (depending on whether we have a AccessToken or not)
@@ -62,7 +62,8 @@ namespace Velopack.Sources
}
/// <inheritdoc />
public virtual async Task<VelopackAssetFeed> GetReleaseFeed(ILogger logger, string channel, Guid? stagingId = null, VelopackAsset? latestLocalRelease = null)
public virtual async Task<VelopackAssetFeed> GetReleaseFeed(IVelopackLogger logger, string? appId, string channel, Guid? stagingId = null,
VelopackAsset? latestLocalRelease = null)
{
var releases = await GetReleases(Prerelease).ConfigureAwait(false);
if (releases == null || releases.Length == 0) {

View File

@@ -1,7 +1,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Velopack.Logging;
namespace Velopack.Sources
{
@@ -14,21 +14,22 @@ namespace Velopack.Sources
{
/// <summary>
/// Retrieve the list of available remote releases from the package source. These releases
/// can subsequently be downloaded with <see cref="DownloadReleaseEntry(ILogger, VelopackAsset, string, Action{int}, CancellationToken)"/>.
/// can subsequently be downloaded with <see cref="DownloadReleaseEntry(IVelopackLogger, VelopackAsset, string, Action{int}, CancellationToken)"/>.
/// </summary>
/// <param name="channel">Release channel to filter packages by. Can be null, which is the
/// default channel for this operating system.</param>
/// <param name="stagingId">A persistent user-id, used for calculating whether a specific
/// release should be available to this user or not. (eg, for the purposes of rolling out
/// an update to only a small portion of users at a time).</param>
/// <param name="latestLocalRelease">The latest / current local release. If specified,
/// metadata from this package may be provided to the remote server (such as package id,
/// or cpu architecture) to ensure that the correct package is downloaded for this user.
/// </param>
/// <param name="logger">The logger to use for any diagnostic messages.</param>
/// <param name="appId"></param>
/// <param name="channel">Release channel to filter packages by. Can be null, which is the
/// default channel for this operating system.</param>
/// <param name="stagingId">A persistent user-id, used for calculating whether a specific
/// release should be available to this user or not. (eg, for the purposes of rolling out
/// an update to only a small portion of users at a time).</param>
/// <param name="latestLocalRelease">The latest / current local release. If specified,
/// metadata from this package may be provided to the remote server (such as package id,
/// or cpu architecture) to ensure that the correct package is downloaded for this user.
/// </param>
/// <returns>An array of <see cref="ReleaseEntry"/> objects that are available for download
/// and are applicable to this user.</returns>
Task<VelopackAssetFeed> GetReleaseFeed(ILogger logger, string channel, Guid? stagingId = null, VelopackAsset? latestLocalRelease = null);
Task<VelopackAssetFeed> GetReleaseFeed(IVelopackLogger logger, string? appId, string channel, Guid? stagingId = null, VelopackAsset? latestLocalRelease = null);
/// <summary>
/// Download the specified <see cref="VelopackAsset"/> to the provided local file path.
@@ -40,6 +41,6 @@ namespace Velopack.Sources
/// download is being processed.</param>
/// <param name="logger">The logger to use for any diagnostic messages.</param>
/// <param name="cancelToken">A token to use to cancel the request.</param>
Task DownloadReleaseEntry(ILogger logger, VelopackAsset releaseEntry, string localFile, Action<int> progress, CancellationToken cancelToken = default);
Task DownloadReleaseEntry(IVelopackLogger logger, VelopackAsset releaseEntry, string localFile, Action<int> progress, CancellationToken cancelToken = default);
}
}

View File

@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Velopack.Logging;
using Velopack.NuGet;
using Velopack.Util;
@@ -25,7 +25,8 @@ namespace Velopack.Sources
}
/// <inheritdoc />
public virtual Task<VelopackAssetFeed> GetReleaseFeed(ILogger logger, string channel, Guid? stagingId = null, VelopackAsset? latestLocalRelease = null)
public virtual Task<VelopackAssetFeed> GetReleaseFeed(IVelopackLogger logger, string? appId, string channel, Guid? stagingId = null,
VelopackAsset? latestLocalRelease = null)
{
if (!BaseDirectory.Exists) {
logger.Error($"The local update directory '{BaseDirectory.FullName}' does not exist.");
@@ -65,7 +66,7 @@ namespace Velopack.Sources
}
/// <inheritdoc />
public virtual Task DownloadReleaseEntry(ILogger logger, VelopackAsset releaseEntry, string localFile, Action<int> progress, CancellationToken cancelToken)
public virtual Task DownloadReleaseEntry(IVelopackLogger logger, VelopackAsset releaseEntry, string localFile, Action<int> progress, CancellationToken cancelToken)
{
var releasePath = Path.Combine(BaseDirectory.FullName, releaseEntry.FileName);
if (!File.Exists(releasePath))

View File

@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Velopack.Logging;
using Velopack.Util;
namespace Velopack.Sources
@@ -37,7 +37,8 @@ namespace Velopack.Sources
}
/// <inheritdoc />
public async virtual Task<VelopackAssetFeed> GetReleaseFeed(ILogger logger, string channel, Guid? stagingId = null, VelopackAsset? latestLocalRelease = null)
public async virtual Task<VelopackAssetFeed> GetReleaseFeed(IVelopackLogger logger, string? appId, string channel, Guid? stagingId = null,
VelopackAsset? latestLocalRelease = null)
{
var releaseFilename = CoreUtil.GetVeloReleaseIndexName(channel);
var uri = HttpUtil.AppendPathToUri(BaseUri, releaseFilename);
@@ -66,7 +67,7 @@ namespace Velopack.Sources
}
/// <inheritdoc />
public async virtual Task DownloadReleaseEntry(ILogger logger, VelopackAsset releaseEntry, string localFile, Action<int> progress, CancellationToken cancelToken)
public async virtual Task DownloadReleaseEntry(IVelopackLogger logger, VelopackAsset releaseEntry, string localFile, Action<int> progress, CancellationToken cancelToken)
{
if (releaseEntry == null) throw new ArgumentNullException(nameof(releaseEntry));
if (localFile == null) throw new ArgumentNullException(nameof(localFile));

View File

@@ -1,20 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Velopack.Util;
using Velopack.Locators;
using Velopack.Logging;
namespace Velopack.Sources
{
/// <summary>
/// Retrieves updates from the hosted Velopack service.
/// </summary>
public sealed class VelopackFlowUpdateSource : IUpdateSource
public sealed class VelopackFlowSource : IUpdateSource
{
/// <inheritdoc cref="SimpleWebSource" />
public VelopackFlowUpdateSource(
public VelopackFlowSource(
string baseUri = "https://api.velopack.io/",
IFileDownloader? downloader = null)
{
@@ -29,17 +29,13 @@ namespace Velopack.Sources
public IFileDownloader Downloader { get; }
/// <inheritdoc />
public async Task<VelopackAssetFeed> GetReleaseFeed(ILogger logger, string channel, Guid? stagingId = null,
public async Task<VelopackAssetFeed> GetReleaseFeed(IVelopackLogger logger, string? appId, string channel, Guid? stagingId = null,
VelopackAsset? latestLocalRelease = null)
{
string? packageId = latestLocalRelease?.PackageId ?? VelopackLocator.GetDefault(logger).AppId;
if (string.IsNullOrWhiteSpace(packageId)) {
//Without a package id, we can't get a feed.
return new VelopackAssetFeed();
}
if (appId is null) return new VelopackAssetFeed(); // without an appId, we can't get any releases.
Uri baseUri = new(BaseUri, $"v1.0/manifest/");
Uri uri = HttpUtil.AppendPathToUri(baseUri, $"{packageId}/{channel}");
Uri uri = HttpUtil.AppendPathToUri(baseUri, $"{appId}/{channel}");
var args = new Dictionary<string, string>();
if (VelopackRuntimeInfo.SystemArch != RuntimeCpu.Unknown) {
@@ -61,30 +57,37 @@ namespace Velopack.Sources
var uriAndQuery = HttpUtil.AddQueryParamsToUri(uri, args);
logger.LogInformation("Downloading releases from '{Uri}'.", uriAndQuery);
logger.LogInformation($"Downloading releases from '{uriAndQuery}'.");
var json = await Downloader.DownloadString(uriAndQuery.ToString()).ConfigureAwait(false);
var releaseAssets = CompiledJson.DeserializeVelopackFlowAssetArray(json);
if (releaseAssets is null) {
return new VelopackAssetFeed();
}
return new VelopackAssetFeed() {
Assets = releaseAssets
Assets = releaseAssets.Cast<VelopackAsset>().ToArray()
};
}
/// <inheritdoc />
public async Task DownloadReleaseEntry(ILogger logger, VelopackAsset releaseEntry, string localFile, Action<int> progress, CancellationToken cancelToken = default)
public async Task DownloadReleaseEntry(IVelopackLogger logger, VelopackAsset releaseEntry, string localFile, Action<int> progress,
CancellationToken cancelToken = default)
{
if (releaseEntry is null) throw new ArgumentNullException(nameof(releaseEntry));
if (releaseEntry is not VelopackFlowReleaseAsset velopackRelease) {
throw new ArgumentException($"Expected {nameof(releaseEntry)} to be {nameof(VelopackFlowReleaseAsset)} but was {releaseEntry.GetType().FullName}");
throw new ArgumentException(
$"Expected {nameof(releaseEntry)} to be {nameof(VelopackFlowReleaseAsset)} but was {releaseEntry.GetType().FullName}");
}
if (localFile is null) throw new ArgumentNullException(nameof(localFile));
Uri sourceBaseUri = HttpUtil.EnsureTrailingSlash(BaseUri);
Uri downloadUri = new(sourceBaseUri, $"v1.0/download/{velopackRelease.Id}");
logger.LogInformation("Downloading '{ReleaseFileName}' from '{Uri}'.", releaseEntry.FileName, downloadUri);
logger.LogInformation($"Downloading '{releaseEntry.FileName}' from '{downloadUri}'.");
await Downloader.DownloadFile(downloadUri.AbsoluteUri, localFile, progress, cancelToken: cancelToken).ConfigureAwait(false);
}
}
@@ -93,4 +96,4 @@ namespace Velopack.Sources
{
public string? Id { get; set; }
}
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
@@ -6,9 +6,8 @@ using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Velopack.Locators;
using Velopack.Logging;
using Velopack.Util;
namespace Velopack
@@ -24,7 +23,7 @@ namespace Velopack
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool AllowSetForegroundWindow(int dwProcessId);
private static Process StartUpdateExe(ILogger logger, IVelopackLocator locator, IEnumerable<string> args)
private static Process StartUpdateExe(IVelopackLogger logger, IVelopackLocator locator, IEnumerable<string> args)
{
var psi = new ProcessStartInfo() {
CreateNoWindow = true,
@@ -61,11 +60,9 @@ namespace Velopack
/// <param name="waitPid">Optionally wait for the specified process to exit before continuing.</param>
/// <param name="locator">The locator to use to find the path to Update.exe and the packages directory.</param>
/// <param name="startArgs">The arguments to pass to the application when it is restarted.</param>
/// <param name="logger">The logger to use for diagnostic messages</param>
public static void Start(IVelopackLocator? locator = null, uint waitPid = 0, string[]? startArgs = null, ILogger? logger = null)
public static void Start(IVelopackLocator? locator = null, uint waitPid = 0, string[]? startArgs = null)
{
logger ??= NullLogger.Instance;
locator ??= VelopackLocator.GetDefault(logger);
locator ??= VelopackLocator.Current;
var args = new List<string>();
args.Add("start");
@@ -82,14 +79,13 @@ namespace Velopack
}
}
StartUpdateExe(logger, locator, args);
StartUpdateExe(locator.Log, locator, args);
}
private static Process ApplyImpl(IVelopackLocator? locator, VelopackAsset? toApply, bool silent, uint waitPid, bool restart,
string[]? restartArgs = null, ILogger? logger = null)
string[]? restartArgs = null)
{
logger ??= NullLogger.Instance;
locator ??= VelopackLocator.GetDefault(logger);
locator ??= VelopackLocator.Current;
var args = new List<string>();
if (silent) args.Add("--silent");
@@ -118,7 +114,7 @@ namespace Velopack
}
}
return StartUpdateExe(logger, locator, args);
return StartUpdateExe(locator.Log, locator, args);
}
/// <summary>
@@ -132,12 +128,11 @@ namespace Velopack
/// <param name="toApply">The update package you wish to apply, can be left null.</param>
/// <param name="waitPid">Optionally wait for the specified process to exit before continuing.</param>
/// <param name="restartArgs">The arguments to pass to the application when it is restarted.</param>
/// <param name="logger">The logger to use for diagnostic messages</param>
/// <exception cref="Exception">Thrown if Update.exe does not initialize properly.</exception>
public static void Apply(IVelopackLocator? locator, VelopackAsset? toApply, bool silent, uint waitPid, bool restart,
string[]? restartArgs = null, ILogger? logger = null)
public static void Apply(IVelopackLocator? locator, VelopackAsset? toApply, bool silent, uint waitPid, bool restart,
string[]? restartArgs = null)
{
var process = ApplyImpl(locator, toApply, silent, waitPid, restart, restartArgs, logger);
var process = ApplyImpl(locator, toApply, silent, waitPid, restart, restartArgs);
Thread.Sleep(500);
if (process.HasExited) {
@@ -146,10 +141,10 @@ namespace Velopack
}
/// <inheritdoc cref="Apply"/>
public static async Task ApplyAsync(IVelopackLocator? locator, VelopackAsset? toApply, bool silent, uint waitPid, bool restart, string[]? restartArgs = null,
ILogger? logger = null)
public static async Task ApplyAsync(IVelopackLocator? locator, VelopackAsset? toApply, bool silent, uint waitPid, bool restart,
string[]? restartArgs = null)
{
var process = ApplyImpl(locator, toApply, silent, waitPid, restart, restartArgs, logger);
var process = ApplyImpl(locator, toApply, silent, waitPid, restart, restartArgs);
await Task.Delay(500).ConfigureAwait(false);
if (process.HasExited) {

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.ComponentModel;
using System.Threading.Tasks;
@@ -45,13 +45,13 @@ namespace Velopack
/// <param name="restartArgs">The arguments to pass to the application when it is restarted.</param>
public void WaitExitThenApplyUpdates(VelopackAsset? toApply, bool silent = false, bool restart = true, string[]? restartArgs = null)
{
UpdateExe.Apply(Locator, toApply, silent, Locator.ProcessId, restart, restartArgs, Log);
UpdateExe.Apply(Locator, toApply, silent, Locator.ProcessId, restart, restartArgs);
}
/// <inheritdoc cref="WaitExitThenApplyUpdates"/>
public async Task WaitExitThenApplyUpdatesAsync(VelopackAsset? toApply, bool silent = false, bool restart = true, string[]? restartArgs = null)
{
await UpdateExe.ApplyAsync(Locator, toApply, silent, Locator.ProcessId, restart, restartArgs, Log).ConfigureAwait(false);
await UpdateExe.ApplyAsync(Locator, toApply, silent, Locator.ProcessId, restart, restartArgs).ConfigureAwait(false);
}
}
}
}

View File

@@ -1,15 +1,14 @@
using System;
using System;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using NuGet.Versioning;
using Velopack.Compression;
using Velopack.Exceptions;
using Velopack.Locators;
using Velopack.Logging;
using Velopack.NuGet;
using Velopack.Sources;
using Velopack.Util;
@@ -52,7 +51,7 @@ namespace Velopack
protected IUpdateSource Source { get; }
/// <summary> The logger to use for diagnostic messages. </summary>
protected ILogger Log { get; }
protected IVelopackLogger Log { get; }
/// <summary> The locator to use when searching for local file paths. </summary>
protected IVelopackLocator Locator { get; }
@@ -74,12 +73,10 @@ namespace Velopack
/// </summary>
/// <param name="urlOrPath">A basic URL or file path to use when checking for updates.</param>
/// <param name="options">Override / configure default update behaviors.</param>
/// <param name="logger">The logger to use for diagnostic messages. If one was provided to <see cref="VelopackApp.Run(ILogger)"/> but is null here,
/// it will be cached and used again.</param>
/// <param name="locator">This should usually be left null. Providing an <see cref="IVelopackLocator" /> allows you to mock up certain application paths.
/// For example, if you wanted to test that updates are working in a unit test, you could provide an instance of <see cref="TestVelopackLocator"/>. </param>
public UpdateManager(string urlOrPath, UpdateOptions? options = null, ILogger? logger = null, IVelopackLocator? locator = null)
: this(CreateSimpleSource(urlOrPath), options, logger, locator)
public UpdateManager(string urlOrPath, UpdateOptions? options = null, IVelopackLocator? locator = null)
: this(CreateSimpleSource(urlOrPath), options, locator)
{
}
@@ -89,19 +86,13 @@ namespace Velopack
/// <param name="source">The source describing where to search for updates. This can be a custom source, if you are integrating with some private resource,
/// or it could be one of the predefined sources. (eg. <see cref="SimpleWebSource"/> or <see cref="GithubSource"/>, etc).</param>
/// <param name="options">Override / configure default update behaviors.</param>
/// <param name="logger">The logger to use for diagnostic messages. If one was provided to <see cref="VelopackApp.Run(ILogger)"/> but is null here,
/// it will be cached and used again.</param>
/// <param name="locator">This should usually be left null. Providing an <see cref="IVelopackLocator" /> allows you to mock up certain application paths.
/// For example, if you wanted to test that updates are working in a unit test, you could provide an instance of <see cref="TestVelopackLocator"/>. </param>
public UpdateManager(IUpdateSource source, UpdateOptions? options = null, ILogger? logger = null, IVelopackLocator? locator = null)
public UpdateManager(IUpdateSource source, UpdateOptions? options = null, IVelopackLocator? locator = null)
{
if (source == null) {
throw new ArgumentNullException(nameof(source));
}
Source = source;
Log = logger ?? VelopackApp.DefaultLogger ?? NullLogger.Instance;
Locator = locator ?? VelopackApp.DefaultLocator ?? VelopackLocator.GetDefault(Log);
Source = source ?? throw new ArgumentNullException(nameof(source));
Locator = locator ?? VelopackLocator.Current;
Log = Locator.Log;
Channel = options?.ExplicitChannel ?? DefaultChannel;
ShouldAllowVersionDowngrade = options?.AllowVersionDowngrade ?? false;
}
@@ -126,7 +117,7 @@ namespace Velopack
var latestLocalFull = Locator.GetLatestLocalFullPackage();
Log.Debug("Retrieving latest release feed.");
var feedObj = await Source.GetReleaseFeed(Log, Channel, stagedUserId, latestLocalFull).ConfigureAwait(false);
var feedObj = await Source.GetReleaseFeed(Log, AppId, Channel, stagedUserId, latestLocalFull).ConfigureAwait(false);
var feed = feedObj.Assets;
var latestRemoteFull = feed.Where(r => r.Type == VelopackAssetType.Full).MaxByPolyfill(x => x.Version).FirstOrDefault();

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@@ -6,8 +6,7 @@ using System.Linq;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Velopack.Logging;
namespace Velopack.Util
{
@@ -73,9 +72,9 @@ namespace Velopack.Util
/// <param name="renameFirst">Try to rename this object first before deleting. Can help prevent partial delete of folders.</param>
/// <param name="logger">Logger for diagnostic messages.</param>
/// <returns>True if the file system object was deleted, false otherwise.</returns>
public static bool DeleteFileOrDirectoryHard(string path, bool throwOnFailure = true, bool renameFirst = false, ILogger? logger = null)
public static bool DeleteFileOrDirectoryHard(string path, bool throwOnFailure = true, bool renameFirst = false, IVelopackLogger? logger = null)
{
logger ??= NullLogger.Instance;
logger ??= NullVelopackLogger.Instance;
logger.Debug($"Starting to delete: {path}");
string? currentExePath = null;
@@ -111,7 +110,7 @@ namespace Velopack.Util
}
}
private static void DeleteFsiTree(FileSystemInfo fileSystemInfo, string? currentExePath, ILogger logger)
private static void DeleteFsiTree(FileSystemInfo fileSystemInfo, string? currentExePath, IVelopackLogger logger)
{
// if junction / symlink, don't iterate, just delete it.
if (fileSystemInfo.Attributes.HasFlag(FileAttributes.ReparsePoint)) {
@@ -135,7 +134,7 @@ namespace Velopack.Util
DeleteFsiVeryHard(fileSystemInfo, currentExePath, logger);
}
private static void DeleteFsiVeryHard(FileSystemInfo fileSystemInfo, string? currentExePath, ILogger logger)
private static void DeleteFsiVeryHard(FileSystemInfo fileSystemInfo, string? currentExePath, IVelopackLogger logger)
{
// don't try to delete the running process
if (currentExePath != null && PathUtil.FullPathEquals(fileSystemInfo.FullName, currentExePath)) {
@@ -171,7 +170,7 @@ namespace Velopack.Util
}
}
public static void Retry(this Action block, int retries = 4, int retryDelay = 250, ILogger? logger = null)
public static void Retry(this Action block, int retries = 4, int retryDelay = 250, IVelopackLogger? logger = null)
{
Retry(
() => {
@@ -183,7 +182,7 @@ namespace Velopack.Util
logger);
}
public static T Retry<T>(this Func<T> block, int retries = 4, int retryDelay = 250, ILogger? logger = null)
public static T Retry<T>(this Func<T> block, int retries = 4, int retryDelay = 250, IVelopackLogger? logger = null)
{
while (true) {
try {
@@ -198,7 +197,7 @@ namespace Velopack.Util
}
}
public static Task RetryAsync(this Func<Task> block, int retries = 4, int retryDelay = 250, ILogger? logger = null)
public static Task RetryAsync(this Func<Task> block, int retries = 4, int retryDelay = 250, IVelopackLogger? logger = null)
{
return RetryAsync(
async () => {
@@ -210,7 +209,7 @@ namespace Velopack.Util
logger);
}
public static async Task<T> RetryAsync<T>(this Func<Task<T>> block, int retries = 4, int retryDelay = 250, ILogger? logger = null)
public static async Task<T> RetryAsync<T>(this Func<Task<T>> block, int retries = 4, int retryDelay = 250, IVelopackLogger? logger = null)
{
while (true) {
try {

View File

@@ -6,7 +6,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Velopack.Logging;
namespace Velopack.Util
{
@@ -56,7 +56,7 @@ namespace Velopack.Util
}
#endif
public static Process StartRedirectOutputToILogger(this ProcessStartInfo psi, ILogger log, LogLevel outputLevel)
public static Process StartRedirectOutputToILogger(this ProcessStartInfo psi, IVelopackLogger log, VelopackLogLevel outputLevel)
{
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;

View File

@@ -24,26 +24,15 @@
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="[2.2.0,)" />
</ItemGroup>
<ItemGroup Condition=" $(TargetFramework.StartsWith('netstandard2')) ">
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="[2.2.0,)" />
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
</ItemGroup>
<ItemGroup Condition=" $(TargetFramework) == 'net6.0' ">
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="[6.0.0,)" />
</ItemGroup>
<ItemGroup Condition=" $(TargetFramework) == 'net8.0' ">
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="[8.0.0,)" />
</ItemGroup>
<ItemGroup Condition=" $(TargetFramework) == 'net9.0' ">
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="[9.0.0,)" />
</ItemGroup>
</Project>

View File

@@ -1,12 +1,11 @@
using System;
using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using NuGet.Versioning;
using Velopack.Locators;
using Velopack.Logging;
using Velopack.Util;
namespace Velopack
@@ -27,18 +26,15 @@ namespace Velopack
[DllImport("shell32.dll", SetLastError = true)]
private static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID);
internal static ILogger DefaultLogger { get; private set; } = NullLogger.Instance;
internal static IVelopackLocator? DefaultLocator { get; private set; }
VelopackHook? _install;
VelopackHook? _update;
VelopackHook? _obsolete;
VelopackHook? _uninstall;
VelopackHook? _firstrun;
VelopackHook? _restarted;
string[]? _args;
bool _autoApply = true;
private VelopackHook? _install;
private VelopackHook? _update;
private VelopackHook? _obsolete;
private VelopackHook? _uninstall;
private VelopackHook? _firstrun;
private VelopackHook? _restarted;
private string[]? _args;
private bool _autoApply = true;
private IVelopackLocator? _customLocator;
private VelopackApp()
{
@@ -47,7 +43,7 @@ namespace Velopack
/// <summary>
/// Creates and returns a new Velopack application builder.
/// </summary>
public static VelopackApp Build() => new VelopackApp();
public static VelopackApp Build() => new();
/// <summary>
/// Override the command line arguments used to determine the Velopack hook to run.
@@ -74,14 +70,14 @@ namespace Velopack
/// </summary>
public VelopackApp SetLocator(IVelopackLocator locator)
{
DefaultLocator = locator;
_customLocator = locator;
return this;
}
/// <summary>
/// This hook is triggered when the application is started for the first time after installation.
/// </summary>
public VelopackApp WithFirstRun(VelopackHook hook)
public VelopackApp OnFirstRun(VelopackHook hook)
{
_firstrun += hook;
return this;
@@ -90,7 +86,7 @@ namespace Velopack
/// <summary>
/// This hook is triggered when the application is restarted by Velopack after installing updates.
/// </summary>
public VelopackApp WithRestarted(VelopackHook hook)
public VelopackApp OnRestarted(VelopackHook hook)
{
_restarted += hook;
return this;
@@ -103,7 +99,7 @@ namespace Velopack
/// Only supported on windows; On other operating systems, this will never be called.
/// </summary>
[SupportedOSPlatform("windows")]
public VelopackApp WithAfterInstallFastCallback(VelopackHook hook)
public VelopackApp OnAfterInstallFastCallback(VelopackHook hook)
{
_install += hook;
return this;
@@ -116,7 +112,7 @@ namespace Velopack
/// Only supported on windows; On other operating systems, this will never be called.
/// </summary>
[SupportedOSPlatform("windows")]
public VelopackApp WithAfterUpdateFastCallback(VelopackHook hook)
public VelopackApp OnAfterUpdateFastCallback(VelopackHook hook)
{
_update += hook;
return this;
@@ -129,7 +125,7 @@ namespace Velopack
/// Only supported on windows; On other operating systems, this will never be called.
/// </summary>
[SupportedOSPlatform("windows")]
public VelopackApp WithBeforeUpdateFastCallback(VelopackHook hook)
public VelopackApp OnBeforeUpdateFastCallback(VelopackHook hook)
{
_obsolete += hook;
return this;
@@ -142,7 +138,7 @@ namespace Velopack
/// Only supported on windows; On other operating systems, this will never be called.
/// </summary>
[SupportedOSPlatform("windows")]
public VelopackApp WithBeforeUninstallFastCallback(VelopackHook hook)
public VelopackApp OnBeforeUninstallFastCallback(VelopackHook hook)
{
_uninstall += hook;
return this;
@@ -151,9 +147,7 @@ namespace Velopack
/// <summary>
/// Runs the Velopack application startup code and triggers any configured hooks.
/// </summary>
/// <param name="logger">A logging interface for diagnostic messages. This will be
/// cached and potentially re-used throughout the lifetime of the application.</param>
public void Run(ILogger? logger = null)
public void Run()
{
var args = _args ?? Environment.GetCommandLineArgs().Skip(1).ToArray();
@@ -164,11 +158,19 @@ namespace Velopack
return;
}
var log = logger ?? NullLogger.Instance;
var locator = DefaultLocator ?? VelopackLocator.GetDefault(log);
DefaultLogger = log;
if (VelopackLocator.IsCurrentSet) {
VelopackLocator.Current.Log.Error(
"VelopackApp.Build().Run() was called more than once. This is not allowed and can lead to unexpected behaviour.");
}
log.Info("Starting Velopack App (Run).");
if (_customLocator != null) {
VelopackLocator.SetCurrentLocator(_customLocator);
}
var locator = VelopackLocator.GetCurrentOrCreateDefault();
var log = locator.Log;
log.Info($"Starting VelopackApp.Run (library version {VelopackRuntimeInfo.VelopackNugetVersion}).");
if (VelopackRuntimeInfo.IsWindows && locator.AppId != null) {
var appUserModelId = CoreUtil.GetAppUserModelId(locator.AppId);
@@ -224,7 +226,7 @@ namespace Velopack
log.Info($"Launching app is out-dated. Current: {myVersion}, Newest Local Available: {latestLocal.Version}");
if (!restarted && _autoApply) {
log.Info("Auto apply is true, so restarting to apply update...");
UpdateExe.Apply(locator, latestLocal, false, locator.ProcessId, true, args, log);
UpdateExe.Apply(locator, latestLocal, false, locator.ProcessId, true, args);
Exit(0);
} else {
log.Info("Pre-condition failed, we will not restart to apply updates. (restarted: " + restarted + ", autoApply: " + _autoApply + ")");

View File

@@ -1,4 +1,4 @@
#nullable disable
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq;

View File

@@ -7,9 +7,9 @@ using System.Linq;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Win32;
using NuGet.Versioning;
using Velopack.Logging;
using Velopack.Sources;
using Velopack.Util;
@@ -76,7 +76,7 @@ namespace Velopack.Windows
public abstract Task<bool> CheckIsSupported();
/// <summary> Download the latest installer for this runtime to the specified file </summary>
public virtual async Task DownloadToFile(string localPath, Action<int> progress = null, IFileDownloader downloader = null, ILogger log = null)
public virtual async Task DownloadToFile(string localPath, Action<int> progress = null, IFileDownloader downloader = null, IVelopackLogger log = null)
{
var url = await GetDownloadUrl().ConfigureAwait(false);
log?.Info($"Downloading {Id} from {url} to {localPath}");
@@ -86,7 +86,7 @@ namespace Velopack.Windows
/// <summary> Execute a runtime installer at a local file path. Typically used after <see cref="DownloadToFile"/> </summary>
[SupportedOSPlatform("windows")]
public virtual async Task<RuntimeInstallResult> InvokeInstaller(string pathToInstaller, bool isQuiet, ILogger log = null)
public virtual async Task<RuntimeInstallResult> InvokeInstaller(string pathToInstaller, bool isQuiet, IVelopackLogger log = null)
{
var args = new string[] { "/passive", "/norestart", "/showrmui" };
var quietArgs = new string[] { "/q", "/norestart" };

View File

@@ -5,9 +5,8 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.Versioning;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Velopack.Locators;
using Velopack.Logging;
using Velopack.NuGet;
using Velopack.Util;
@@ -58,16 +57,16 @@ namespace Velopack.Windows
public class Shortcuts
{
/// <summary> Log for diagnostic messages. </summary>
protected ILogger Log { get; }
protected IVelopackLogger Log { get; }
/// <summary> Locator to use for finding important application paths. </summary>
protected IVelopackLocator Locator { get; }
/// <inheritdoc cref="Shortcuts"/>
public Shortcuts(ILogger logger = null, IVelopackLocator locator = null)
public Shortcuts(IVelopackLocator locator = null)
{
Log = logger ?? NullLogger.Instance;
Locator = locator ?? VelopackLocator.GetDefault(Log);
Locator = locator ?? VelopackLocator.Current;
Log = Locator.Log;
}
/// <summary>
@@ -80,7 +79,7 @@ namespace Velopack.Windows
Locator.ThisExeRelativePath,
location,
false,
null, // shortcut arguments
null, // shortcut arguments
null); // shortcut icon
}
@@ -166,30 +165,31 @@ namespace Velopack.Windows
Log.Info($"Creating shortcut for {relativeExeName} => {file}");
ShellLink sl;
IoUtil.Retry(() => {
File.Delete(file);
IoUtil.Retry(
() => {
File.Delete(file);
var target = Path.Combine(currentDir, relativeExeName);
sl = new ShellLink {
Target = target,
IconPath = icon ?? target,
IconIndex = 0,
WorkingDirectory = Path.GetDirectoryName(exePath),
Description = zf.ProductDescription,
};
var target = Path.Combine(currentDir, relativeExeName);
sl = new ShellLink {
Target = target,
IconPath = icon ?? target,
IconIndex = 0,
WorkingDirectory = Path.GetDirectoryName(exePath),
Description = zf.ProductDescription,
};
if (!String.IsNullOrWhiteSpace(programArguments)) {
sl.Arguments += String.Format(" -a \"{0}\"", programArguments);
}
if (!String.IsNullOrWhiteSpace(programArguments)) {
sl.Arguments += String.Format(" -a \"{0}\"", programArguments);
}
//var appUserModelId = Utility.GetAppUserModelId(zf.Id, exeName);
//var toastActivatorCLSID = Utility.CreateGuidFromHash(appUserModelId).ToString();
//sl.SetAppUserModelId(appUserModelId);
//sl.SetToastActivatorCLSID(toastActivatorCLSID);
//var appUserModelId = Utility.GetAppUserModelId(zf.Id, exeName);
//var toastActivatorCLSID = Utility.CreateGuidFromHash(appUserModelId).ToString();
//sl.SetAppUserModelId(appUserModelId);
//sl.SetToastActivatorCLSID(toastActivatorCLSID);
Log.Info($"About to save shortcut: {file} (target {sl.Target}, workingDir {sl.WorkingDirectory}, args {sl.Arguments})");
sl.Save(file);
});
Log.Info($"About to save shortcut: {file} (target {sl.Target}, workingDir {sl.WorkingDirectory}, args {sl.Arguments})");
sl.Save(file);
});
}
}
@@ -230,16 +230,16 @@ namespace Velopack.Windows
protected virtual string LinkPathForVersionInfo(ShortcutLocation location, ZipPackage package, FileVersionInfo versionInfo, string rootdir)
{
var possibleProductNames = new[] {
versionInfo.ProductName,
package.ProductName,
versionInfo.FileDescription,
Path.GetFileNameWithoutExtension(versionInfo.FileName)
};
versionInfo.ProductName,
package.ProductName,
versionInfo.FileDescription,
Path.GetFileNameWithoutExtension(versionInfo.FileName)
};
var possibleCompanyNames = new[] {
versionInfo.CompanyName,
package.ProductCompany,
};
versionInfo.CompanyName,
package.ProductCompany,
};
var prodName = possibleCompanyNames.First(x => !String.IsNullOrWhiteSpace(x));
var pkgName = possibleProductNames.First(x => !String.IsNullOrWhiteSpace(x));
@@ -250,7 +250,8 @@ namespace Velopack.Windows
/// <summary>
/// Given the application info, return the shortcut target path.
/// </summary>
protected virtual string GetLinkPath(ShortcutLocation location, string title, string applicationName, string rootdir, bool createDirectoryIfNecessary = true)
protected virtual string GetLinkPath(ShortcutLocation location, string title, string applicationName, string rootdir,
bool createDirectoryIfNecessary = true)
{
var dir = default(string);
@@ -288,4 +289,4 @@ namespace Velopack.Windows
.ToArray();
}
}
}
}

View File

@@ -1,12 +1,45 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Logging;
using Velopack.Logging;
namespace Velopack.Util
namespace Velopack.Core
{
[ExcludeFromCodeCoverage]
internal static class LoggerExtensions
public static class LoggerExtensions
{
public static IVelopackLogger ToVelopackLogger(this ILogger logger)
{
return new MicrosoftExtensionsLoggerAdapter(logger);
}
private class MicrosoftExtensionsLoggerAdapter(ILogger logger) : IVelopackLogger
{
public void Log(VelopackLogLevel logLevel, string? message, Exception? exception)
{
switch (logLevel) {
case VelopackLogLevel.Trace:
logger.LogTrace(exception, message);
break;
case VelopackLogLevel.Debug:
logger.LogDebug(exception, message);
break;
case VelopackLogLevel.Information:
logger.LogInformation(exception, message);
break;
case VelopackLogLevel.Warning:
logger.LogWarning(exception, message);
break;
case VelopackLogLevel.Error:
logger.LogError(exception, message);
break;
case VelopackLogLevel.Critical:
logger.LogCritical(exception, message);
break;
}
}
}
public static void Trace(this ILogger logger, string message)
{
logger.LogTrace(message);
@@ -16,6 +49,7 @@ namespace Velopack.Util
{
logger.LogTrace(ex, message);
}
public static void Trace(this ILogger logger, Exception ex)
{
logger.LogTrace(ex, ex.Message);

View File

@@ -15,6 +15,7 @@
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
</ItemGroup>
</Project>

View File

@@ -3,6 +3,7 @@ using Azure.Storage;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Microsoft.Extensions.Logging;
using Velopack.Core;
using Velopack.Util;
namespace Velopack.Deployment;

View File

@@ -1,4 +1,5 @@
using Microsoft.Extensions.Logging;
using Velopack.Core;
using Velopack.Packaging;
using Velopack.Sources;
using Velopack.Util;
@@ -68,12 +69,12 @@ public class LocalRepository(ILogger logger) : ObjectRepository<LocalDownloadOpt
protected override Task SaveEntryToFileAsync(LocalDownloadOptions options, VelopackAsset entry, string filePath)
{
var source = new SimpleFileSource(options.TargetPath);
return source.DownloadReleaseEntry(Log, entry, filePath, (i) => { }, default);
return source.DownloadReleaseEntry(Log.ToVelopackLogger(), entry, filePath, (i) => { }, default);
}
protected override Task<VelopackAssetFeed> GetReleasesAsync(LocalDownloadOptions options)
{
var source = new SimpleFileSource(options.TargetPath);
return source.GetReleaseFeed(channel: options.Channel, logger: Log);
return source.GetReleaseFeed(Log.ToVelopackLogger(), null, options.Channel);
}
}

View File

@@ -3,6 +3,7 @@ using Amazon.Runtime;
using Amazon.S3;
using Amazon.S3.Model;
using Microsoft.Extensions.Logging;
using Velopack.Core;
using Velopack.Util;
namespace Velopack.Deployment;

View File

@@ -32,25 +32,20 @@ public interface IRepositoryCanDownload<TDown> where TDown : RepositoryOptions
Task DownloadLatestFullPackageAsync(TDown options);
}
public abstract class SourceRepository<TDown, TSource> : DownRepository<TDown>
public abstract class SourceRepository<TDown, TSource>(ILogger logger) : DownRepository<TDown>(logger)
where TDown : RepositoryOptions
where TSource : IUpdateSource
{
public SourceRepository(ILogger logger)
: base(logger)
{
}
protected override Task<VelopackAssetFeed> GetReleasesAsync(TDown options)
{
var source = CreateSource(options);
return source.GetReleaseFeed(channel: options.Channel, logger: Log);
return source.GetReleaseFeed(Log.ToVelopackLogger(), null, options.Channel);
}
protected override Task SaveEntryToFileAsync(TDown options, VelopackAsset entry, string filePath)
{
var source = CreateSource(options);
return source.DownloadReleaseEntry(Log, entry, filePath, (i) => { });
return source.DownloadReleaseEntry(Log.ToVelopackLogger(), entry, filePath, (i) => { });
}
public abstract TSource CreateSource(TDown options);

View File

@@ -1,6 +1,7 @@
using ICSharpCode.SharpZipLib.Tar;
using Microsoft.Extensions.Logging;
using Velopack.Compression;
using Velopack.Core;
using Velopack.Util;
namespace Velopack.Packaging.Unix;

View File

@@ -1,5 +1,6 @@
using System.Runtime.Versioning;
using Microsoft.Extensions.Logging;
using Velopack.Core;
using Velopack.Core.Abstractions;
using Velopack.Util;

View File

@@ -1,6 +1,7 @@
// https://raw.githubusercontent.com/egramtel/dotnet-bundle/master/DotNet.Bundle/PlistWriter.cs
using System.Xml;
using Microsoft.Extensions.Logging;
using Velopack.Core;
using Velopack.Util;
namespace Velopack.Packaging.Unix;

View File

@@ -248,7 +248,7 @@ public class WindowsPackCommandRunner : PackageBuilder<WindowsPackOptions>
// create a .portable file to indicate this is a portable package
File.Create(Path.Combine(dir.FullName, ".portable")).Close();
await EasyZip.CreateZipFromDirectoryAsync(Log, outputPath, dir.FullName, CoreUtil.CreateProgressDelegate(progress, 40, 100));
await EasyZip.CreateZipFromDirectoryAsync(Log.ToVelopackLogger(), outputPath, dir.FullName, CoreUtil.CreateProgressDelegate(progress, 40, 100));
progress(100);
}
@@ -301,7 +301,8 @@ public class WindowsPackCommandRunner : PackageBuilder<WindowsPackOptions>
Log.Info($"Use Azure Trusted Signing service for code signing. Metadata file path: {trustedSignMetadataPath}");
string dlibPath = GetDlibPath(CancellationToken.None);
signParams = $"/fd SHA256 /tr http://timestamp.acs.microsoft.com /v /debug /td SHA256 /dlib {HelperFile.AzureDlibFileName} /dmdf \"{trustedSignMetadataPath}\"";
signParams =
$"/fd SHA256 /tr http://timestamp.acs.microsoft.com /v /debug /td SHA256 /dlib {HelperFile.AzureDlibFileName} /dmdf \"{trustedSignMetadataPath}\"";
helper.Sign(filePaths, signParams, signParallel, progress, false);
} else if (!string.IsNullOrEmpty(signParams)) {
helper.Sign(filePaths, signParams, signParallel, progress, false);

View File

@@ -33,7 +33,8 @@ public class DeltaPatchCommandRunner : ICommand<DeltaPatchOptions>
using var _1 = TempUtil.GetTempDirectory(out var workDir);
var delta = new DeltaEmbedded(HelperFile.GetZstdPath(), _logger, tmp);
EasyZip.ExtractZipToDirectory(_logger, options.BasePackage, workDir);
var veloLogger = _logger.ToVelopackLogger();
EasyZip.ExtractZipToDirectory(veloLogger, options.BasePackage, workDir);
await _console.ExecuteProgressAsync(
async (ctx) => {
@@ -50,7 +51,7 @@ public class DeltaPatchCommandRunner : ICommand<DeltaPatchOptions>
await ctx.RunTask(
$"Building {Path.GetFileName(options.OutputFile)}",
async (progress) => {
await EasyZip.CreateZipFromDirectoryAsync(_logger, options.OutputFile, workDir, progress);
await EasyZip.CreateZipFromDirectoryAsync(veloLogger, options.OutputFile, workDir, progress);
progress(100);
});
});

View File

@@ -1,5 +1,6 @@
using Microsoft.Extensions.Logging;
using Velopack.Compression;
using Velopack.Core;
namespace Velopack.Packaging;
@@ -21,7 +22,7 @@ public class DeltaEmbedded
{
private readonly Zstd _zstd;
public DeltaImpl(string zstdPath, ILogger logger, string baseTmpDir) : base(logger, baseTmpDir)
public DeltaImpl(string zstdPath, ILogger logger, string baseTmpDir) : base(logger.ToVelopackLogger(), baseTmpDir)
{
_zstd = new Zstd(zstdPath);
}

View File

@@ -76,8 +76,9 @@ public class DeltaPackageBuilder
_logger.Info($"Creating delta for {basePackage.Version} -> {newPackage.Version} with {numParallel} parallel threads.");
_logger.Debug($"Extracting {Path.GetFileName(basePackage.PackageFile)} and {Path.GetFileName(newPackage.PackageFile)} into {tempPath}");
EasyZip.ExtractZipToDirectory(_logger, basePackage.PackageFile, baseTempInfo.FullName);
EasyZip.ExtractZipToDirectory(_logger, newPackage.PackageFile, tempInfo.FullName);
var veloLogger = _logger.ToVelopackLogger();
EasyZip.ExtractZipToDirectory(veloLogger, basePackage.PackageFile, baseTempInfo.FullName);
EasyZip.ExtractZipToDirectory(veloLogger, newPackage.PackageFile, tempInfo.FullName);
// Collect a list of relative paths under 'lib' and map them
// to their full name. We'll use this later to determine in
@@ -191,7 +192,7 @@ public class DeltaPackageBuilder
"Delta creation failed for one or more files. See log for details. To skip delta generation, use the '--delta none' argument.");
}
EasyZip.CreateZipFromDirectoryAsync(_logger, outputFile, tempInfo.FullName, CoreUtil.CreateProgressDelegate(progress, 70, 100)).GetAwaiterResult();
EasyZip.CreateZipFromDirectoryAsync(_logger.ToVelopackLogger(), outputFile, tempInfo.FullName, CoreUtil.CreateProgressDelegate(progress, 70, 100)).GetAwaiterResult();
progress(100);
fRemoved = baseLibFiles.Count;

View File

@@ -2,10 +2,6 @@
using System.Text;
using Microsoft.Extensions.Logging;
#if !DEBUG
using Velopack.Util;
#endif
namespace Velopack.Packaging;
public static class HelperFile
@@ -23,7 +19,7 @@ public static class HelperFile
#else
case RuntimeOs.Linux:
if (!target.HasArchitecture) {
log.Warn("No architecture specified with --runtime, defaulting to x64. If this was not intended please specify via the --runtime parameter");
log.LogWarning("No architecture specified with --runtime, defaulting to x64. If this was not intended please specify via the --runtime parameter");
return FindHelperFile("UpdateNix_x64");
}

View File

@@ -293,7 +293,7 @@ public abstract class PackageBuilder<T> : ICommand<T>
AddContentTypesAndRel(nuspecPath);
await EasyZip.CreateZipFromDirectoryAsync(Log, outputPath, stagingDir.FullName, CoreUtil.CreateProgressDelegate(progress, 30, 100));
await EasyZip.CreateZipFromDirectoryAsync(Log.ToVelopackLogger(), outputPath, stagingDir.FullName, CoreUtil.CreateProgressDelegate(progress, 30, 100));
progress(100);
}

View File

@@ -1,4 +1,5 @@
using Velopack.Core.Abstractions;
using Velopack.Core;
using Velopack.Core.Abstractions;
using Velopack.Util;
namespace Velopack.Vpk.Logging;

View File

@@ -1,5 +1,6 @@
using System.Threading;
using Spectre.Console;
using Velopack.Core;
using Velopack.Core.Abstractions;
using Velopack.Util;

View File

@@ -1,5 +1,6 @@
using System.Threading;
using NuGet.Protocol.Core.Types;
using Velopack.Core;
using Velopack.Packaging.NuGet;
using Velopack.Util;
@@ -21,7 +22,6 @@ public class UpdateChecker
{
if (_defaults.SkipUpdates) return false;
try {
var myVer = VelopackRuntimeInfo.VelopackNugetVersion;
var isPre = myVer.IsPrerelease || myVer.HasMetadata;
@@ -38,6 +38,7 @@ public class UpdateChecker
} else {
_logger.Warn($"[bold]There is a newer version of vpk available. Run 'dotnet tool update -g vpk --version {cacheVersion}'[/]");
}
return true;
} else {
_logger.Debug($"vpk is up to date (latest online = {cacheVersion})");
@@ -45,6 +46,7 @@ public class UpdateChecker
} catch (Exception ex) {
_logger.Debug(ex, "Failed to check for updates.");
}
return false;
}
}
}

View File

@@ -1,19 +0,0 @@
using Microsoft.Extensions.Logging;
class ConsoleLogger : ILogger
{
public IDisposable BeginScope<TState>(TState state) where TState : notnull
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return true;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
Console.WriteLine(formatter(state, exception));
}
}

View File

@@ -2,6 +2,9 @@
using System.Diagnostics;
using Velopack;
using Velopack.Locators;
using Velopack.Logging;
var locator = VelopackLocator.CreateDefaultForPlatform(new ConsoleVelopackLogger());
try {
bool shouldExit = false;
@@ -14,21 +17,24 @@ try {
#if !NO_VELO_BUILDER
VelopackApp.Build()
.SetAutoApplyOnStartup(shouldAutoUpdate)
.WithFirstRun((v) => {
debugFile("firstrun", v.ToString());
Console.WriteLine("was first run");
shouldExit = true;
})
.WithRestarted((v) => {
debugFile("restarted", v.ToString() + "," + String.Join(",", args));
Console.WriteLine("app just restarted");
shouldExit = true;
})
.WithAfterInstallFastCallback((v) => debugFile("args.txt", String.Join(" ", args)))
.WithBeforeUpdateFastCallback((v) => debugFile("args.txt", String.Join(" ", args)))
.WithAfterUpdateFastCallback((v) => debugFile("args.txt", String.Join(" ", args)))
.WithBeforeUninstallFastCallback((v) => debugFile("args.txt", String.Join(" ", args)))
.Run(new ConsoleLogger());
.OnFirstRun(
(v) => {
debugFile("firstrun", v.ToString());
Console.WriteLine("was first run");
shouldExit = true;
})
.OnRestarted(
(v) => {
debugFile("restarted", v.ToString() + "," + String.Join(",", args));
Console.WriteLine("app just restarted");
shouldExit = true;
})
.SetLocator(locator)
.OnAfterInstallFastCallback((v) => debugFile("args.txt", String.Join(" ", args)))
.OnBeforeUpdateFastCallback((v) => debugFile("args.txt", String.Join(" ", args)))
.OnAfterUpdateFastCallback((v) => debugFile("args.txt", String.Join(" ", args)))
.OnBeforeUninstallFastCallback((v) => debugFile("args.txt", String.Join(" ", args)))
.Run();
if (shouldAutoUpdate) {
// this shouldn't be reached
@@ -41,7 +47,6 @@ try {
#endif
if (args.Length == 1 && args[0] == "version") {
var locator = VelopackLocator.GetDefault(new ConsoleLogger());
Console.WriteLine(locator.CurrentlyInstalledVersion?.ToString() ?? "unknown_version");
return 0;
}
@@ -53,7 +58,7 @@ try {
if (args.Length == 2) {
if (args[0] == "check") {
var um = new UpdateManager(args[1], null, new ConsoleLogger());
var um = new UpdateManager(args[1], null, locator);
var info = um.CheckForUpdates();
if (info == null) {
Console.WriteLine("no updates");
@@ -65,28 +70,29 @@ try {
}
if (args[0] == "download") {
var um = new UpdateManager(args[1], null, new ConsoleLogger());
var um = new UpdateManager(args[1], null, locator);
var info = um.CheckForUpdates();
if (info == null) {
Console.WriteLine("no updates");
return -1;
}
um.DownloadUpdates(info, (x) => Console.WriteLine(x));
return 0;
}
if (args[0] == "apply") {
var um = new UpdateManager(args[1], null, new ConsoleLogger());
var um = new UpdateManager(args[1], null, locator);
if (um.UpdatePendingRestart == null) {
Console.WriteLine("not pending restart");
return -1;
}
Console.WriteLine("applying...");
um.ApplyUpdatesAndRestart((VelopackAsset) null, new[] { "test", "args !!" });
return 0;
}
}
} catch (Exception ex) {
Console.WriteLine("exception: " + ex.ToString());
if (Debugger.IsAttached) throw;
@@ -100,4 +106,4 @@ void debugFile(string name, string message)
{
var path = Path.Combine(AppContext.BaseDirectory, "..", name);
File.AppendAllText(path, message + Environment.NewLine);
}
}

View File

@@ -1,6 +1,8 @@
using Azure.Storage.Blobs;
using NuGet.Versioning;
using Velopack.Core;
using Velopack.Deployment;
using Velopack.Locators;
using Velopack.Sources;
using Velopack.Util;
@@ -92,8 +94,9 @@ public class DeploymentTests
// get the latest
var source = new SimpleWebSource(updateUrl);
VelopackAssetFeed feed = new VelopackAssetFeed();
try {
feed = await source.GetReleaseFeed(logger, CHANNEL);
feed = await source.GetReleaseFeed(logger.ToVelopackLogger(), null, CHANNEL);
} catch (Exception ex) {
logger.Warn(ex, "Failed to fetch release feed.");
}
@@ -116,7 +119,7 @@ public class DeploymentTests
await repo.UploadMissingAssetsAsync(options);
// verify that new version has been uploaded
feed = await source.GetReleaseFeed(logger, CHANNEL);
feed = await source.GetReleaseFeed(logger.ToVelopackLogger(), null, CHANNEL);
latestOnline = feed.Assets.Where(a => a.Version != null && a.Type == VelopackAssetType.Full).MaxBy(a => a.Version);
Assert.True(latestOnline != null, "No latest version found.");

View File

@@ -173,7 +173,7 @@ This is just a _test_!
// update
var source = new GiteaSource(GITEA_REPOURL, GITEA_TOKEN, false);
var releases = source.GetReleaseFeed(channel: uniqueSuffix, logger: logger).GetAwaiterResult();
var releases = source.GetReleaseFeed(logger.ToVelopackLogger(), null, channel: uniqueSuffix).GetAwaiterResult();
var ghrel = releases.Assets.Select(r => (GiteaSource.GitBaseAsset) r).ToArray();
foreach (var g in ghrel) {

View File

@@ -2,6 +2,7 @@
using Velopack.Sources;
using Octokit;
using Velopack.Core;
using Velopack.Locators;
using Velopack.Packaging.Exceptions;
using Velopack.Util;
@@ -167,7 +168,7 @@ public class GithubDeploymentTests
// update
var source = new GithubSource(GITHUB_REPOURL, GITHUB_TOKEN, false);
var releases = source.GetReleaseFeed(channel: uniqueSuffix, logger: logger).GetAwaiterResult();
var releases = source.GetReleaseFeed(logger.ToVelopackLogger(), null, channel: uniqueSuffix).GetAwaiterResult();
var ghrel = releases.Assets.Select(r => (GithubSource.GitBaseAsset) r).ToArray();
foreach (var g in ghrel) {

View File

@@ -1,5 +1,6 @@
using System.Runtime.Versioning;
using Velopack.Compression;
using Velopack.Core;
using Velopack.Util;
namespace Velopack.Packaging.Tests;
@@ -32,7 +33,7 @@ public class OsxPackTests
TestApp.PackTestApp(id, "0.0.1", string.Empty, tmpReleaseDir, logger, channel: channel, packTitle: title);
var portablePath = Path.Combine(tmpReleaseDir, $"{id}-{channel}-Portable.zip");
EasyZip.ExtractZipToDirectory(logger, portablePath, unzipDir);
EasyZip.ExtractZipToDirectory(logger.ToVelopackLogger(), portablePath, unzipDir);
var bundlePath = Path.Combine(unzipDir, $"{title}.app");
Assert.True(Directory.Exists(bundlePath));

View File

@@ -1,5 +1,6 @@
#nullable enable
using System.Diagnostics;
using Velopack.Core;
using Velopack.Packaging.Unix.Commands;
using Velopack.Packaging.Windows.Commands;
using Velopack.Util;

View File

@@ -79,7 +79,7 @@ public class WindowsPackTests
var releasesPath2 = Path.Combine(tmpReleaseDir, $"releases.asd123.json");
Assert.True(File.Exists(releasesPath2));
EasyZip.ExtractZipToDirectory(logger, nupkgPath, unzipDir);
EasyZip.ExtractZipToDirectory(logger.ToVelopackLogger(), nupkgPath, unzipDir);
// does nuspec exist and is it valid
var nuspecPath = Path.Combine(unzipDir, $"{id}.nuspec");
@@ -310,7 +310,7 @@ public class WindowsPackTests
var deltaPath = Path.Combine(releaseDir, $"{id}-2.0.0-delta.nupkg");
Assert.True(File.Exists(deltaPath));
using var _2 = TempUtil.GetTempDirectory(out var extractDir);
EasyZip.ExtractZipToDirectory(logger, deltaPath, extractDir);
EasyZip.ExtractZipToDirectory(logger.ToVelopackLogger(), deltaPath, extractDir);
var extractDllDiff = Path.Combine(extractDir, "lib", "app", "testapp.dll.zsdiff");
var extractDllShasum = Path.Combine(extractDir, "lib", "app", "testapp.dll.shasum");
Assert.True(File.Exists(extractDllDiff));
@@ -659,7 +659,7 @@ public class WindowsPackTests
() => {
return File.ReadAllText(path);
},
logger: logger,
logger: logger.ToVelopackLogger(),
retries: 10,
retryDelay: 1000);
}
@@ -730,7 +730,7 @@ public class WindowsPackTests
},
10,
1000,
logger);
logger.ToVelopackLogger());
using var reader = new StreamReader(fs);
var output = reader.ReadToEnd();

View File

@@ -1,5 +1,6 @@
#pragma warning disable CS0618 // Type or member is obsolete
using System.Runtime.Versioning;
using Velopack.Core;
using Velopack.Locators;
using Velopack.Util;
using Velopack.Windows;
@@ -29,8 +30,16 @@ public class ShortcutTests
PathHelper.CopyFixtureTo("AvaloniaCrossPlat-1.0.15-win-full.nupkg", packages.FullName);
PathHelper.CopyFixtureTo(exeName, current.FullName);
var locator = new TestVelopackLocator("AvaloniaCrossPlat", "1.0.0", packages.FullName, current.FullName, rootDir, null, null, logger);
var sh = new Shortcuts(logger, locator);
var locator = new TestVelopackLocator(
"AvaloniaCrossPlat",
"1.0.0",
packages.FullName,
current.FullName,
rootDir,
null,
null,
logger.ToVelopackLogger());
var sh = new Shortcuts(locator);
var flag = ShortcutLocation.StartMenuRoot | ShortcutLocation.Desktop;
sh.DeleteShortcuts(exeName, flag);
sh.CreateShortcut(exeName, flag, false, "");
@@ -54,4 +63,4 @@ public class ShortcutTests
var after = sh.FindShortcuts(exeName, flag);
Assert.Equal(0, after.Keys.Count);
}
}
}

View File

@@ -2,6 +2,7 @@
using System.IO.Compression;
using NCode.ReparsePoints;
using Velopack.Compression;
using Velopack.Logging;
using Velopack.Util;
namespace Velopack.Tests;
@@ -247,7 +248,7 @@ public class SymbolicLinkTests
using var _2 = TempUtil.GetTempDirectory(out var tempOutput);
var output = Path.Combine(tempOutput, "output.zip");
await EasyZip.CreateZipFromDirectoryAsync(NullLogger.Instance, output, tempFolder);
await EasyZip.CreateZipFromDirectoryAsync(NullVelopackLogger.Instance, output, tempFolder);
ZipFile.ExtractToDirectory(output, tempOutput);
var appSym = Path.Combine(tempOutput, "App.__symlink");

View File

@@ -2,6 +2,7 @@
#pragma warning disable CS0612 // Type or member is obsolete
using System.Text;
using Velopack.Core;
using Velopack.Logging;
using Velopack.Sources;
using Velopack.Util;
@@ -25,7 +26,7 @@ internal class FakeFixtureRepository : IFileDownloader
.ToList();
var releasesNew = new SimpleFileSource(new DirectoryInfo(PathHelper.GetFixturesDir()))
.GetReleaseFeed(NullLogger.Instance, null).GetAwaiterResult().Assets
.GetReleaseFeed(NullVelopackLogger.Instance, null, null).GetAwaiterResult().Assets
.Where(r => r.FileName.StartsWith(_pkgId))
.ToList();

View File

@@ -49,7 +49,7 @@ public class UpdateManagerTests
{
var feed = new VelopackAssetFeed {
Assets = new VelopackAsset[] {
new VelopackAsset() {
new VelopackAsset() {
PackageId = "MyCoolApp",
Version = new SemanticVersion(1, 1, 0),
Type = VelopackAssetType.Full,
@@ -81,7 +81,7 @@ public class UpdateManagerTests
SHA1 = "14db31d2647c6d2284882a2e101924a9c409ee67",
Size = 80396,
},
new VelopackAsset() {
new VelopackAsset() {
PackageId = "MyCoolApp",
Version = new SemanticVersion(1, 2, 0),
Type = VelopackAssetType.Delta,
@@ -111,22 +111,24 @@ public class UpdateManagerTests
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = TempUtil.GetTempDirectory(out var tempPath);
var dl = new FakeDownloader() {
MockedResponseBytes = Encoding.UTF8.GetBytes(SimpleJson.SerializeObject(
new VelopackAssetFeed {
Assets = new VelopackAsset[] {
new VelopackAsset() {
PackageId = "AvaloniaCrossPlat",
Version = new SemanticVersion(1, 0, 11),
Type = VelopackAssetType.Full,
FileName = $"https://mysite.com/releases/AvaloniaCrossPlat$-1.1.0.nupkg",
SHA1 = IoUtil.CalculateFileSHA1(fixture),
Size = new FileInfo(fixture).Length,
} }
}))
MockedResponseBytes = Encoding.UTF8.GetBytes(
SimpleJson.SerializeObject(
new VelopackAssetFeed {
Assets = new VelopackAsset[] {
new VelopackAsset() {
PackageId = "AvaloniaCrossPlat",
Version = new SemanticVersion(1, 0, 11),
Type = VelopackAssetType.Full,
FileName = $"https://mysite.com/releases/AvaloniaCrossPlat$-1.1.0.nupkg",
SHA1 = IoUtil.CalculateFileSHA1(fixture),
Size = new FileInfo(fixture).Length,
}
}
}))
};
var source = new SimpleWebSource("http://any.com", dl);
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger);
var um = new UpdateManager(source, null, logger, locator);
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger.ToVelopackLogger());
var um = new UpdateManager(source, null, locator);
var info = um.CheckForUpdates();
Assert.NotNull(info);
Assert.True(new SemanticVersion(1, 0, 11) == info.TargetFullRelease.Version);
@@ -150,8 +152,8 @@ public class UpdateManagerTests
using var _1 = TempUtil.GetTempDirectory(out var tempPath);
var dl = GetMockDownloaderNoDelta();
var source = new SimpleWebSource("http://any.com", dl);
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger);
var um = new UpdateManager(source, null, logger, locator);
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger.ToVelopackLogger());
var um = new UpdateManager(source, null, locator);
var info = um.CheckForUpdates();
Assert.NotNull(info);
Assert.True(new SemanticVersion(1, 1, 0) == info.TargetFullRelease.Version);
@@ -167,9 +169,9 @@ public class UpdateManagerTests
using var _1 = TempUtil.GetTempDirectory(out var tempPath);
var dl = GetMockDownloaderNoDelta();
var source = new SimpleWebSource("http://any.com", dl);
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger);
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger.ToVelopackLogger());
var opt = new UpdateOptions { ExplicitChannel = "experimental" };
var um = new UpdateManager(source, opt, logger, locator);
var um = new UpdateManager(source, opt, locator);
var info = um.CheckForUpdates();
Assert.NotNull(info);
Assert.True(new SemanticVersion(1, 1, 0) == info.TargetFullRelease.Version);
@@ -193,23 +195,32 @@ public class UpdateManagerTests
Size = 1040561,
};
var source = new SimpleWebSource("http://any.com", dl);
var locator = new TestVelopackLocator("MyCoolApp", "1.2.0", tempPath, null, null, null, logger: logger, localPackage: myVer, channel: "stable");
var locator = new TestVelopackLocator(
"MyCoolApp",
"1.2.0",
tempPath,
null,
null,
null,
logger: logger.ToVelopackLogger(),
localPackage: myVer,
channel: "stable");
// checking for same version should return null
var um = new UpdateManager(source, null, logger, locator);
var um = new UpdateManager(source, null, locator);
var info = um.CheckForUpdates();
Assert.Null(info);
Assert.StartsWith("http://any.com/releases.stable.json?", dl.LastUrl);
// checking for same version WITHOUT explicit channel should return null
var opt = new UpdateOptions { AllowVersionDowngrade = true };
um = new UpdateManager(source, opt, logger, locator);
um = new UpdateManager(source, opt, locator);
Assert.Null(info);
Assert.StartsWith("http://any.com/releases.stable.json?", dl.LastUrl);
// checking for same version with explicit channel & downgrade allowed should return version
opt = new UpdateOptions { ExplicitChannel = "experimental", AllowVersionDowngrade = true };
um = new UpdateManager(source, opt, logger, locator);
um = new UpdateManager(source, opt, locator);
info = um.CheckForUpdates();
Assert.True(info.IsDowngrade);
Assert.NotNull(info);
@@ -233,17 +244,26 @@ public class UpdateManagerTests
Size = 1040561,
};
var source = new SimpleWebSource("http://any.com", dl);
var locator = new TestVelopackLocator("MyCoolApp", "2.0.0", tempPath, null, null, null, logger: logger, localPackage: myVer, channel: "stable");
var locator = new TestVelopackLocator(
"MyCoolApp",
"2.0.0",
tempPath,
null,
null,
null,
logger: logger.ToVelopackLogger(),
localPackage: myVer,
channel: "stable");
// checking for lower version should return null
var um = new UpdateManager(source, null, logger, locator);
var um = new UpdateManager(source, null, locator);
var info = um.CheckForUpdates();
Assert.Null(info);
Assert.StartsWith("http://any.com/releases.stable.json?", dl.LastUrl);
// checking for lower version with downgrade allowed should return lower version
var opt = new UpdateOptions { AllowVersionDowngrade = true };
um = new UpdateManager(source, opt, logger, locator);
um = new UpdateManager(source, opt, locator);
info = um.CheckForUpdates();
Assert.True(info.IsDowngrade);
Assert.NotNull(info);
@@ -268,8 +288,8 @@ public class UpdateManagerTests
};
var source = new SimpleWebSource("http://any.com", dl);
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, null, null, null, logger: logger, localPackage: myVer);
var um = new UpdateManager(source, null, logger, locator);
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, null, null, null, logger: logger.ToVelopackLogger(), localPackage: myVer);
var um = new UpdateManager(source, null, locator);
var info = um.CheckForUpdates();
Assert.False(info.IsDowngrade);
Assert.NotNull(info);
@@ -287,8 +307,8 @@ public class UpdateManagerTests
using var _1 = TempUtil.GetTempDirectory(out var packagesDir);
var repo = new FakeFixtureRepository(id, false);
var source = new SimpleWebSource("http://any.com", repo);
var locator = new TestVelopackLocator(id, "1.0.0", packagesDir, logger);
var um = new UpdateManager(source, null, logger, locator);
var locator = new TestVelopackLocator(id, "1.0.0", packagesDir, logger.ToVelopackLogger());
var um = new UpdateManager(source, null, locator);
var info = um.CheckForUpdates();
Assert.NotNull(info);
@@ -298,7 +318,7 @@ public class UpdateManagerTests
string actualHash = info.TargetFullRelease.SHA256;
string modifiedHash = info.TargetFullRelease.SHA256.ToLowerInvariant();
info.TargetFullRelease.SHA256 = modifiedHash;
var ex = Assert.Throws<ChecksumFailedException>(() => um.DownloadUpdates(info));
Assert.Contains("SHA256 doesn't match", ex.Message);
@@ -321,8 +341,8 @@ public class UpdateManagerTests
using var _1 = TempUtil.GetTempDirectory(out var packagesDir);
var repo = new FakeFixtureRepository(id, false);
var source = new SimpleWebSource("http://any.com", repo);
var locator = new TestVelopackLocator(id, "1.0.0", packagesDir, logger);
var um = new UpdateManager(source, null, logger, locator);
var locator = new TestVelopackLocator(id, "1.0.0", packagesDir, logger.ToVelopackLogger());
var um = new UpdateManager(source, null, locator);
var info = um.CheckForUpdates();
Assert.NotNull(info);
@@ -352,8 +372,8 @@ public class UpdateManagerTests
using var _1 = TempUtil.GetTempDirectory(out var tempPath);
var dl = GetMockDownloaderWith2Delta();
var source = new SimpleWebSource("http://any.com", dl);
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger: logger);
var um = new UpdateManager(source, null, logger, locator);
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger: logger.ToVelopackLogger());
var um = new UpdateManager(source, null, locator);
var info = um.CheckForUpdates();
Assert.NotNull(info);
Assert.False(info.IsDowngrade);
@@ -368,8 +388,8 @@ public class UpdateManagerTests
using var _1 = TempUtil.GetTempDirectory(out var tempPath);
var dl = GetMockDownloaderWith2Delta();
var source = new SimpleWebSource("http://any.com", dl);
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger: logger);
var um = new UpdateManager(source, null, logger, locator);
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger: logger.ToVelopackLogger());
var um = new UpdateManager(source, null, locator);
var info = um.CheckForUpdates();
Assert.NotNull(info);
Assert.False(info.IsDowngrade);
@@ -383,48 +403,51 @@ public class UpdateManagerTests
// https://github.com/caesay/SquirrelCustomLauncherTestApp
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = TempUtil.GetTempDirectory(out var tempPath);
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger);
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger.ToVelopackLogger());
var source = new GithubSource("https://github.com/caesay/SquirrelCustomLauncherTestApp", null, false);
var um = new UpdateManager(source, null, logger, locator);
var um = new UpdateManager(source, null, locator);
var info = um.CheckForUpdates();
Assert.NotNull(info);
Assert.True(new SemanticVersion(1, 0, 1) == info.TargetFullRelease.Version);
Assert.Equal(0, info.DeltasToTarget.Count());
}
[Fact(Skip = "Consumes API Quota")]
public void CheckGithubWithNonExistingChannel()
{
// https://github.com/caesay/SquirrelCustomLauncherTestApp
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = TempUtil.GetTempDirectory(out var tempPath);
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger);
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger.ToVelopackLogger());
var source = new GithubSource("https://github.com/caesay/SquirrelCustomLauncherTestApp", null, false);
var opt = new UpdateOptions { ExplicitChannel = "hello" };
var um = new UpdateManager(source, opt, logger, locator);
var um = new UpdateManager(source, opt, locator);
Assert.Throws<ArgumentException>(() => um.CheckForUpdates());
}
[Fact(Skip = "Consumes API Quota")]
public void CheckGitea()
{
// https://github.com/caesay/SquirrelCustomLauncherTestApp
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = TempUtil.GetTempDirectory(out var tempPath);
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger);
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger.ToVelopackLogger());
var source = new GiteaSource("https://gitea.com/remco1271/VeloPackTest", null, false);
var um = new UpdateManager(source, null, logger, locator);
var um = new UpdateManager(source, null, locator);
var info = um.CheckForUpdates();
Assert.NotNull(info);
Assert.True(new SemanticVersion(1, 0, 1) == info.TargetFullRelease.Version);
Assert.Equal(0, info.DeltasToTarget.Count());
}
[Fact]
public void CheckFromEmptyFileSource()
{
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = TempUtil.GetTempDirectory(out var tempPath);
var source = new SimpleFileSource(new DirectoryInfo(tempPath));
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger);
var um = new UpdateManager(source, null, logger, locator);
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger.ToVelopackLogger());
var um = new UpdateManager(source, null, locator);
var info = um.CheckForUpdates();
Assert.Null(info);
}
@@ -436,8 +459,8 @@ public class UpdateManagerTests
using var _1 = TempUtil.GetTempDirectory(out var tempPath);
var dl = GetMockDownloaderNoDelta();
var source = new SimpleWebSource("http://any.com", dl);
var locator = new TestVelopackLocator("MyCoolApp", "1.1.0", tempPath, logger);
var um = new UpdateManager(source, null, logger, locator);
var locator = new TestVelopackLocator("MyCoolApp", "1.1.0", tempPath, logger.ToVelopackLogger());
var um = new UpdateManager(source, null, locator);
var info = um.CheckForUpdates();
Assert.Null(info);
}
@@ -449,8 +472,8 @@ public class UpdateManagerTests
using var _1 = TempUtil.GetTempDirectory(out var tempPath);
var dl = GetMockDownloaderNoDelta();
var source = new SimpleWebSource("http://any.com", dl);
var locator = new TestVelopackLocator("MyCoolApp", "1.2.0", tempPath, logger);
var um = new UpdateManager(source, null, logger, locator);
var locator = new TestVelopackLocator("MyCoolApp", "1.2.0", tempPath, logger.ToVelopackLogger());
var um = new UpdateManager(source, null, locator);
var info = um.CheckForUpdates();
Assert.Null(info);
}
@@ -464,8 +487,8 @@ public class UpdateManagerTests
using var _1 = TempUtil.GetTempDirectory(out var packagesDir);
var repo = new FakeFixtureRepository(id, false);
var source = new SimpleWebSource("http://any.com", repo);
var locator = new TestVelopackLocator(id, "1.0.0", packagesDir, logger);
var um = new UpdateManager(source, null, logger, locator);
var locator = new TestVelopackLocator(id, "1.0.0", packagesDir, logger.ToVelopackLogger());
var um = new UpdateManager(source, null, locator);
var info = um.CheckForUpdates();
Assert.NotNull(info);
@@ -490,7 +513,7 @@ public class UpdateManagerTests
var repo = new FakeFixtureRepository(id, true);
var source = new SimpleWebSource("http://any.com", repo);
var feed = await source.GetReleaseFeed(logger, VelopackRuntimeInfo.SystemOs.GetOsShortName());
var feed = await source.GetReleaseFeed(logger.ToVelopackLogger(), id, VelopackRuntimeInfo.SystemOs.GetOsShortName());
var basePkg = feed.Assets
.Where(x => x.Type == VelopackAssetType.Full)
.Single(x => x.Version == SemanticVersion.Parse(fromVersion));
@@ -499,9 +522,16 @@ public class UpdateManagerTests
File.Copy(basePkgFixturePath, basePkgPath);
var updateExe = PathHelper.CopyUpdateTo(packagesDir);
var locator = new TestVelopackLocator(id, fromVersion,
packagesDir, null, null, updateExe, null, logger);
var um = new UpdateManager(source, null, logger, locator);
var locator = new TestVelopackLocator(
id,
fromVersion,
packagesDir,
null,
null,
updateExe,
null,
logger.ToVelopackLogger());
var um = new UpdateManager(source, null, locator);
var info = await um.CheckForUpdatesAsync();
Assert.NotNull(info);
@@ -513,4 +543,4 @@ public class UpdateManagerTests
var target = Path.Combine(packagesDir, $"{id}-{toVersion}-full.nupkg");
Assert.True(File.Exists(target));
}
}
}

View File

@@ -2,6 +2,7 @@
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using Velopack.Core;
using Velopack.Util;
using Velopack.Windows;

View File

@@ -19,11 +19,11 @@
</Choose>
<ItemGroup>
<Compile Include="..\..\src\vpk\Velopack.Core\SimpleJson.cs" Link="SimpleJson.cs" />
<PackageReference Include="System.IO.Packaging" Version="9.0.2"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.IO.Packaging" Version="9.0.2"/>
<ProjectReference Include="..\..\src\vpk\Velopack.Core\Velopack.Core.csproj"/>
</ItemGroup>
<ItemGroup Condition=" $(TargetFramework.StartsWith('net4')) ">
@@ -45,5 +45,5 @@
</ItemGroup>
</Otherwise>
</Choose>
</Project>

View File

@@ -1,5 +1,6 @@
using System.IO.Packaging;
using NuGet.Versioning;
using Velopack.Core;
using Velopack.NuGet;
using Velopack.Tests.TestHelpers;
using Velopack.Util;
@@ -38,8 +39,8 @@ public class ZipPackageTests
SymbolicLink.Create(symlink, actual);
SymbolicLink.Create(symfile, actualFile);
Compression.EasyZip.CreateZipFromDirectoryAsync(logger, zipFile, tempDir).GetAwaiterResult();
Compression.EasyZip.ExtractZipToDirectory(logger, zipFile, extractedDir, expandSymlinks: true);
Compression.EasyZip.CreateZipFromDirectoryAsync(logger.ToVelopackLogger(), zipFile, tempDir).GetAwaiterResult();
Compression.EasyZip.ExtractZipToDirectory(logger.ToVelopackLogger(), zipFile, extractedDir, expandSymlinks: true);
Assert.True(File.Exists(Path.Combine(extractedDir, "actual", "file.txt")));
Assert.Equal("hello", File.ReadAllText(Path.Combine(extractedDir, "actual", "file.txt")));