Refactor util into separate classes

This commit is contained in:
Caelan
2024-09-21 12:48:05 -06:00
parent cb9447821d
commit 8347f29309
83 changed files with 1104 additions and 1048 deletions

View File

@@ -5,6 +5,7 @@ using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Logging;
using Velopack.Util;
namespace Velopack.Compression
{
@@ -29,7 +30,7 @@ namespace Velopack.Compression
Log.Info($"Applying delta package from {deltaPackageZip} to delta staging directory.");
using var _1 = Utility.GetTempDirectory(out var deltaPath, BaseTempDir);
using var _1 = TempUtil.GetTempDirectory(out var deltaPath, BaseTempDir);
EasyZip.ExtractZipToDirectory(Log, deltaPackageZip, deltaPath);
progress(10);
@@ -51,7 +52,7 @@ namespace Velopack.Compression
pathsVisited.Add(DIFF_SUFFIX.Replace(file, "").ToLowerInvariant());
applyDiffToFile(deltaPath, file, workingPath);
var perc = (index + 1) / (double) files.Length * 100;
progress(Utility.CalculateProgress((int) perc, 10, 90));
progress(CoreUtil.CalculateProgress((int) perc, 10, 90));
}
progress(80);
@@ -118,7 +119,7 @@ namespace Velopack.Compression
var inputFile = Path.Combine(deltaPath, relativeFilePath);
var finalTarget = Path.Combine(workingDirectory, DIFF_SUFFIX.Replace(relativeFilePath, ""));
using var _d = Utility.GetTempFileName(out var tempTargetFile, BaseTempDir);
using var _d = TempUtil.GetTempFileName(out var tempTargetFile, BaseTempDir);
// NB: Zero-length diffs indicate the file hasn't actually changed
if (new FileInfo(inputFile).Length == 0) {

View File

@@ -1,6 +1,7 @@
using System;
using System.Diagnostics;
using Microsoft.Extensions.Logging;
using Velopack.Util;
namespace Velopack.Compression
{

View File

@@ -7,6 +7,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Velopack.Util;
namespace Velopack.Compression
{
@@ -17,7 +18,7 @@ namespace Velopack.Compression
public static void ExtractZipToDirectory(ILogger logger, string inputFile, string outputDirectory, bool expandSymlinks = false)
{
logger.Debug($"Extracting '{inputFile}' to '{outputDirectory}' using System.IO.Compression...");
Utility.DeleteFileOrDirectoryHard(outputDirectory);
IoUtil.DeleteFileOrDirectoryHard(outputDirectory);
List<ZipArchiveEntry> symlinks = new();
using (ZipArchive archive = ZipFile.Open(inputFile, ZipArchiveMode.Read)) {
@@ -58,7 +59,7 @@ namespace Velopack.Compression
using (var reader = new StreamReader(source.Open())) {
var targetPath = reader.ReadToEnd();
var absolute = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(fileDestinationPath)!, targetPath));
if (!Utility.IsFileInDirectory(absolute, destinationDirectoryName)) {
if (!PathUtil.IsFileInDirectory(absolute, destinationDirectoryName)) {
throw new IOException("IO_SymlinkTargetNotInDirectory");
}
@@ -127,7 +128,7 @@ namespace Velopack.Compression
// if dir is a symlink, write it as a file containing path to target
if (SymbolicLink.Exists(dir.FullName)) {
if (!Utility.IsFileInDirectory(SymbolicLink.GetTarget(dir.FullName, relative: false), sourceDirectoryName)) {
if (!PathUtil.IsFileInDirectory(SymbolicLink.GetTarget(dir.FullName, relative: false), sourceDirectoryName)) {
throw new IOException("IO_SymlinkTargetNotInDirectory");
}
@@ -169,7 +170,7 @@ namespace Velopack.Compression
if (SymbolicLink.Exists(fileInfo.FullName)) {
// Handle symlink: Store the symlink target instead of its content
if (!Utility.IsFileInDirectory(SymbolicLink.GetTarget(fileInfo.FullName, relative: false), sourceDirectoryName)) {
if (!PathUtil.IsFileInDirectory(SymbolicLink.GetTarget(fileInfo.FullName, relative: false), sourceDirectoryName)) {
throw new IOException("IO_SymlinkTargetNotInDirectory");
}

View File

@@ -1,711 +0,0 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace Velopack
{
internal static class Utility
{
public const string SpecVersionFileName = "sq.version";
/// <summary>
/// Calculates the total percentage of a specific step that should report within a specific range.
/// <para />
/// If a step needs to report between 50 -> 75 %, this method should be used as CalculateProgress(percentage, 50, 75).
/// </summary>
/// <param name="percentageOfCurrentStep">The percentage of the current step, a value between 0 and 100.</param>
/// <param name="stepStartPercentage">The start percentage of the range the current step represents.</param>
/// <param name="stepEndPercentage">The end percentage of the range the current step represents.</param>
/// <returns>The calculated percentage that can be reported about the total progress.</returns>
public static int CalculateProgress(int percentageOfCurrentStep, int stepStartPercentage, int stepEndPercentage)
{
// Ensure we are between 0 and 100
percentageOfCurrentStep = Math.Max(Math.Min(percentageOfCurrentStep, 100), 0);
var range = stepEndPercentage - stepStartPercentage;
var singleValue = range / 100d;
var totalPercentage = (singleValue * percentageOfCurrentStep) + stepStartPercentage;
return (int) totalPercentage;
}
public static Action<int> CreateProgressDelegate(Action<int> rootProgress, int stepStartPercentage, int stepEndPercentage)
{
return percentage => {
rootProgress(CalculateProgress(percentage, stepStartPercentage, stepEndPercentage));
};
}
public static string RemoveByteOrderMarkerIfPresent(string content)
{
return string.IsNullOrEmpty(content)
? string.Empty
: RemoveByteOrderMarkerIfPresent(Encoding.UTF8.GetBytes(content));
}
public static string RemoveByteOrderMarkerIfPresent(byte[] content)
{
byte[] output = { };
Func<byte[], byte[], bool> matches = (bom, src) => {
if (src.Length < bom.Length) return false;
return !bom.Where((chr, index) => src[index] != chr).Any();
};
var utf32Be = new byte[] { 0x00, 0x00, 0xFE, 0xFF };
var utf32Le = new byte[] { 0xFF, 0xFE, 0x00, 0x00 };
var utf16Be = new byte[] { 0xFE, 0xFF };
var utf16Le = new byte[] { 0xFF, 0xFE };
var utf8 = new byte[] { 0xEF, 0xBB, 0xBF };
if (matches(utf32Be, content)) {
output = new byte[content.Length - utf32Be.Length];
} else if (matches(utf32Le, content)) {
output = new byte[content.Length - utf32Le.Length];
} else if (matches(utf16Be, content)) {
output = new byte[content.Length - utf16Be.Length];
} else if (matches(utf16Le, content)) {
output = new byte[content.Length - utf16Le.Length];
} else if (matches(utf8, content)) {
output = new byte[content.Length - utf8.Length];
} else {
output = content;
}
if (output.Length > 0) {
Buffer.BlockCopy(content, content.Length - output.Length, output, 0, output.Length);
}
return Encoding.UTF8.GetString(output);
}
public static bool TryParseEnumU16<TEnum>(ushort enumValue, out TEnum? retVal)
{
retVal = default;
bool success = Enum.IsDefined(typeof(TEnum), enumValue);
if (success) {
retVal = (TEnum) Enum.ToObject(typeof(TEnum), enumValue);
}
return success;
}
public static bool FullPathEquals(string path1, string path2)
{
return NormalizePath(path1).Equals(NormalizePath(path2), VelopackRuntimeInfo.PathStringComparison);
}
public static bool PathPartEquals(string part1, string part2)
{
return part1.Equals(part2, VelopackRuntimeInfo.PathStringComparison);
}
public static bool PathPartStartsWith(string part1, string startsWith)
{
return part1.StartsWith(startsWith, VelopackRuntimeInfo.PathStringComparison);
}
public static bool PathPartEndsWith(string part1, string endsWith)
{
return part1.EndsWith(endsWith, VelopackRuntimeInfo.PathStringComparison);
}
public static bool FileHasExtension(string filePath, string extension)
{
var ext = Path.GetExtension(filePath);
if (!extension.StartsWith(".")) extension = "." + extension;
return PathPartEquals(ext, extension);
}
public static string NormalizePath(string path)
{
var fullPath = Path.GetFullPath(path);
var normalized = new Uri(fullPath, UriKind.Absolute).LocalPath;
return normalized.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
}
public static bool IsFileInDirectory(string file, string directory)
{
var normalizedDir = NormalizePath(directory) + Path.DirectorySeparatorChar;
var normalizedFile = NormalizePath(file);
return normalizedFile.StartsWith(normalizedDir, VelopackRuntimeInfo.PathStringComparison);
}
public static IEnumerable<FileInfo> GetAllFilesRecursively(this DirectoryInfo rootPath)
{
if (rootPath == null) return Enumerable.Empty<FileInfo>();
return rootPath.EnumerateFiles("*", SearchOption.AllDirectories);
}
public static string CalculateFileSHA1(string filePath)
{
var bufferSize = 1000000; // 1mb
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize)) {
return CalculateStreamSHA1(stream);
}
}
public static string CalculateStreamSHA1(Stream file)
{
using (var sha1 = SHA1.Create()) {
return BitConverter.ToString(sha1.ComputeHash(file)).Replace("-", String.Empty);
}
}
/// <inheritdoc cref="CalculateStreamSHA256"/>
public static string CalculateFileSHA256(string filePath)
{
var bufferSize = 1000000; // 1mb
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize)) {
return CalculateStreamSHA256(stream);
}
}
/// <summary>
/// Get SHA256 hash of the specified file and returns the result as a base64 encoded string (with length 44)
/// </summary>
public static string CalculateStreamSHA256(Stream file)
{
using (var sha256 = SHA256.Create()) {
return BitConverter.ToString(sha256.ComputeHash(file)).Replace("-", String.Empty);
}
}
public static Sources.IFileDownloader CreateDefaultDownloader()
{
return new Sources.HttpClientFileDownloader();
}
public static string GetVeloReleaseIndexName(string channel)
{
return $"releases.{channel ?? VelopackRuntimeInfo.SystemOs.GetOsShortName()}.json";
}
[Obsolete]
public static string GetReleasesFileName(string channel)
{
if (channel == null) {
// default RELEASES file name for each platform.
if (VelopackRuntimeInfo.IsOSX) return "RELEASES-osx";
if (VelopackRuntimeInfo.IsLinux) return "RELEASES-linux";
return "RELEASES";
} else {
// if the channel is an empty string or "win", we use the default RELEASES file name.
if (String.IsNullOrWhiteSpace(channel) || channel.ToLower() == "win") {
return "RELEASES";
}
// all other cases the RELEASES file includes the channel name.
return $"RELEASES-{channel.ToLower()}";
}
}
public static void Retry(this Action block, int retries = 4, int retryDelay = 250, ILogger? logger = null)
{
Retry(
() => {
block();
return true;
},
retries,
retryDelay,
logger);
}
public static T Retry<T>(this Func<T> block, int retries = 4, int retryDelay = 250, ILogger? logger = null)
{
Contract.Requires(retries > 0);
while (true) {
try {
T ret = block();
return ret;
} catch (Exception ex) {
if (retries == 0) throw;
logger?.Warn($"Operation failed ({ex.Message}). Retrying {retries} more times...");
retries--;
Thread.Sleep(retryDelay);
}
}
}
public static Task RetryAsync(this Func<Task> block, int retries = 4, int retryDelay = 250, ILogger? logger = null)
{
return RetryAsync(
async () => {
await block().ConfigureAwait(false);
return true;
},
retries,
retryDelay,
logger);
}
public static async Task<T> RetryAsync<T>(this Func<Task<T>> block, int retries = 4, int retryDelay = 250, ILogger? logger = null)
{
while (true) {
try {
return await block().ConfigureAwait(false);
} catch (Exception ex) {
if (retries == 0) throw;
logger?.Warn($"Operation failed ({ex.Message}). Retrying {retries} more times...");
retries--;
await Task.Delay(retryDelay).ConfigureAwait(false);
}
}
}
public static T GetAwaiterResult<T>(this Task<T> task)
{
return task.ConfigureAwait(false).GetAwaiter().GetResult();
}
public static void GetAwaiterResult(this Task task)
{
task.ConfigureAwait(false).GetAwaiter().GetResult();
}
public static Task ForEachAsync<T>(this IEnumerable<T> source, Action<T> body, int degreeOfParallelism = 4)
{
return ForEachAsync(source, x => Task.Run(() => body(x)), degreeOfParallelism);
}
public static Task ForEachAsync<T>(this IEnumerable<T> source, Func<T, Task> body, int degreeOfParallelism = 4)
{
return Task.WhenAll(
from partition in Partitioner.Create(source).GetPartitions(degreeOfParallelism)
select Task.Run(
async () => {
using (partition)
while (partition.MoveNext())
await body(partition.Current).ConfigureAwait(false);
}));
}
/// <summary>
/// Escapes file name such that the file name is safe for writing to disk in the packages folder
/// </summary>
public static string GetSafeFilename(string fileName)
{
string safeFileName = Path.GetFileName(fileName);
char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
if (safeFileName.IndexOfAny(invalidFileNameChars) != -1) {
StringBuilder safeName = new();
foreach (char ch in safeFileName) {
if (Array.IndexOf(invalidFileNameChars, ch) == -1)
safeName.Append(ch);
else
safeName.Append('_');
}
safeFileName = safeName.ToString();
}
return safeFileName;
}
public static string GetDefaultTempBaseDirectory()
{
string tempDir;
if (VelopackRuntimeInfo.IsOSX || VelopackRuntimeInfo.IsLinux) {
tempDir = "/tmp/velopack";
} else if (VelopackRuntimeInfo.IsWindows) {
tempDir = Path.Combine(Path.GetTempPath(), "Velopack");
} else {
throw new PlatformNotSupportedException();
}
if (Environment.GetEnvironmentVariable("VELOPACK_TEMP") is var squirrlTmp
&& !string.IsNullOrWhiteSpace(squirrlTmp))
tempDir = squirrlTmp;
var di = new DirectoryInfo(tempDir);
if (!di.Exists) di.Create();
return di.FullName;
}
private static string GetNextTempName(string tempDir)
{
for (int i = 1; i < 1000; i++) {
string name = "temp." + i;
var target = Path.Combine(tempDir, name);
FileSystemInfo? info = null;
if (Directory.Exists(target)) info = new DirectoryInfo(target);
else if (File.Exists(target)) info = new FileInfo(target);
// this dir/file does not exist, lets use it.
if (info == null) {
return target;
}
// this dir/file exists, but it is old, let's re-use it.
// this shouldn't generally happen, but crashes do exist.
if (DateTime.UtcNow - info.LastWriteTimeUtc > TimeSpan.FromDays(1)) {
if (DeleteFileOrDirectoryHard(target, false, true)) {
// the dir/file was deleted successfully.
return target;
}
}
}
throw new Exception(
"Unable to find free temp path. Has the temp directory exceeded it's maximum number of items? (1000)");
}
public static IDisposable GetTempDirectory(out string newTempDirectory)
{
return GetTempDirectory(out newTempDirectory, GetDefaultTempBaseDirectory());
}
public static IDisposable GetTempDirectory(out string newTempDirectory, string rootTempDir)
{
var disp = GetTempFileName(out newTempDirectory, rootTempDir);
Directory.CreateDirectory(newTempDirectory);
return disp;
}
public static IDisposable GetTempFileName(out string newTempFile)
{
return GetTempFileName(out newTempFile, GetDefaultTempBaseDirectory());
}
public static IDisposable GetTempFileName(out string newTempFile, string rootTempDir)
{
var path = GetNextTempName(rootTempDir);
newTempFile = path;
return Disposable.Create(() => DeleteFileOrDirectoryHard(path, throwOnFailure: false));
}
/// <summary>
/// Repeatedly tries various methods to delete a file system object. Optionally renames the directory first.
/// Optionally ignores errors.
/// </summary>
/// <param name="path">The path of the file system entity to delete.</param>
/// <param name="throwOnFailure">Whether this function should throw if the delete fails.</param>
/// <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)
{
logger ??= NullLogger.Instance;
Contract.Requires(!String.IsNullOrEmpty(path));
logger.Debug($"Starting to delete: {path}");
try {
if (File.Exists(path)) {
DeleteFsiVeryHard(new FileInfo(path), logger);
} else if (Directory.Exists(path)) {
if (renameFirst) {
// if there are locked files in a directory, we will not attempt to delte it
var oldPath = path + ".old";
Directory.Move(path, oldPath);
path = oldPath;
}
DeleteFsiTree(new DirectoryInfo(path), logger);
} else {
if (throwOnFailure)
logger?.Warn($"Cannot delete '{path}' if it does not exist.");
}
return true;
} catch (Exception ex) {
logger.Error(ex, $"Unable to delete '{path}'");
if (throwOnFailure)
throw;
return false;
}
}
private static void DeleteFsiTree(FileSystemInfo fileSystemInfo, ILogger logger)
{
// if junction / symlink, don't iterate, just delete it.
if (fileSystemInfo.Attributes.HasFlag(FileAttributes.ReparsePoint)) {
DeleteFsiVeryHard(fileSystemInfo, logger);
return;
}
// recursively delete children
try {
var directoryInfo = fileSystemInfo as DirectoryInfo;
if (directoryInfo != null) {
foreach (FileSystemInfo childInfo in directoryInfo.GetFileSystemInfos()) {
DeleteFsiTree(childInfo, logger);
}
}
} catch (Exception ex) {
logger.Warn(ex, $"Unable to traverse children of '{fileSystemInfo.FullName}'");
}
// finally, delete myself, we should try this even if deleting children failed
// because Directory.Delete can also be recursive
DeleteFsiVeryHard(fileSystemInfo, logger);
}
private static void DeleteFsiVeryHard(FileSystemInfo fileSystemInfo, ILogger logger)
{
// don't try to delete the running process
if (FullPathEquals(fileSystemInfo.FullName, VelopackRuntimeInfo.EntryExePath))
return;
// try to remove "ReadOnly" attributes
try { fileSystemInfo.Attributes = FileAttributes.Normal; } catch { }
try { fileSystemInfo.Refresh(); } catch { }
// use this instead of fsi.Delete() because it is more resilient/aggressive
Action deleteMe = fileSystemInfo is DirectoryInfo
? () => Directory.Delete(fileSystemInfo.FullName, true)
: () => File.Delete(fileSystemInfo.FullName);
// retry a few times. if a directory in this tree is open in Windows Explorer,
// it might be locked for a little while WE cleans up handles
try {
Retry(
() => {
try {
deleteMe();
} catch (DirectoryNotFoundException) {
return; // good!
}
},
retries: 4,
retryDelay: 50);
} catch (Exception ex) {
logger?.Warn(ex, $"Unable to delete child '{fileSystemInfo.FullName}'");
throw;
}
}
//public static string PackageDirectoryForAppDir(string rootAppDirectory)
//{
// return Path.Combine(rootAppDirectory, "packages");
//}
//public static string LocalReleaseFileForAppDir(string rootAppDirectory)
//{
// return Path.Combine(PackageDirectoryForAppDir(rootAppDirectory), "RELEASES");
//}
//public static IEnumerable<ReleaseEntry> LoadLocalReleases(string localReleaseFile)
//{
// var file = File.OpenRead(localReleaseFile);
// // NB: sr disposes file
// using (var sr = new StreamReader(file, Encoding.UTF8)) {
// return ReleaseEntry.ParseReleaseFile(sr.ReadToEnd());
// }
//}
//public static ReleaseEntry FindLatestFullVersion(IEnumerable<ReleaseEntry> localReleases, RID compatibleRid)
//{
// return FindCompatibleVersions(localReleases, compatibleRid).FirstOrDefault(f => !f.IsDelta);
//}
//public static IEnumerable<ReleaseEntry> FindCompatibleVersions(IEnumerable<ReleaseEntry> localReleases, RID compatibleRid)
//{
// if (!localReleases.Any()) {
// return null;
// }
// if (compatibleRid == null || !compatibleRid.IsValid) {
// return localReleases.OrderByDescending(x => x.Version);
// }
// return localReleases
// .Where(r => r.Rid.BaseRID == compatibleRid.BaseRID)
// .Where(r => r.Rid.Architecture == compatibleRid.Architecture)
// .OrderByDescending(x => x.Version);
//}
public static string GetAppUserModelId(string packageId)
{
return $"velopack.{packageId}";
}
public static bool IsHttpUrl(string urlOrPath)
{
if (!Uri.TryCreate(urlOrPath, UriKind.Absolute, out Uri? uri)) {
return false;
}
return uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps;
}
public static Uri AppendPathToUri(Uri uri, string path)
{
var builder = new UriBuilder(uri);
if (!builder.Path.EndsWith("/")) {
builder.Path += "/";
}
builder.Path += path;
return builder.Uri;
}
public static Uri EnsureTrailingSlash(Uri uri)
{
return AppendPathToUri(uri, "");
}
public static async Task<int> GetExitCodeAsync(this Process p)
{
#if NET5_0_OR_GREATER
await p.WaitForExitAsync().ConfigureAwait(false);
return p.ExitCode;
#else
var tcs = new TaskCompletionSource<int>();
var thread = new Thread(() => {
try {
p.WaitForExit();
tcs.SetResult(p.ExitCode);
} catch (Exception ex) {
tcs.SetException(ex);
}
});
thread.IsBackground = true;
thread.Start();
await tcs.Task.ConfigureAwait(false);
return p.ExitCode;
#endif
}
public static Uri AddQueryParamsToUri(Uri uri, IEnumerable<KeyValuePair<string, string>> newQuery)
{
var query = System.Web.HttpUtility.ParseQueryString(uri.Query);
foreach (var entry in newQuery) {
query[entry.Key] = entry.Value;
}
var builder = new UriBuilder(uri);
builder.Query = query.ToString();
return builder.Uri;
}
readonly static string[] peExtensions = new[] { ".exe", ".dll", ".node" };
public static bool FileIsLikelyPEImage(string name)
{
var ext = Path.GetExtension(name);
return peExtensions.Any(x => ext.Equals(x, StringComparison.OrdinalIgnoreCase));
}
public static Guid CreateGuidFromHash(string text)
{
return CreateGuidFromHash(text, Utility.IsoOidNamespace);
}
public static Guid CreateGuidFromHash(byte[] data)
{
return CreateGuidFromHash(data, Utility.IsoOidNamespace);
}
public static Guid CreateGuidFromHash(string text, Guid namespaceId)
{
return CreateGuidFromHash(Encoding.UTF8.GetBytes(text), namespaceId);
}
public static Guid CreateGuidFromHash(byte[] nameBytes, Guid namespaceId)
{
// convert the namespace UUID to network order (step 3)
byte[] namespaceBytes = namespaceId.ToByteArray();
SwapByteOrder(namespaceBytes);
// comput the hash of the name space ID concatenated with the
// name (step 4)
byte[] hash;
using (var algorithm = SHA1.Create()) {
algorithm.TransformBlock(namespaceBytes, 0, namespaceBytes.Length, null, 0);
algorithm.TransformFinalBlock(nameBytes, 0, nameBytes.Length);
hash = algorithm.Hash!;
}
// most bytes from the hash are copied straight to the bytes of
// the new GUID (steps 5-7, 9, 11-12)
var newGuid = new byte[16];
Array.Copy(hash, 0, newGuid, 0, 16);
// set the four most significant bits (bits 12 through 15) of
// the time_hi_and_version field to the appropriate 4-bit
// version number from Section 4.1.3 (step 8)
newGuid[6] = (byte) ((newGuid[6] & 0x0F) | (5 << 4));
// set the two most significant bits (bits 6 and 7) of the
// clock_seq_hi_and_reserved to zero and one, respectively
// (step 10)
newGuid[8] = (byte) ((newGuid[8] & 0x3F) | 0x80);
// convert the resulting UUID to local byte order (step 13)
SwapByteOrder(newGuid);
return new Guid(newGuid);
}
/// <summary>
/// The namespace for fully-qualified domain names (from RFC 4122, Appendix C).
/// </summary>
public static readonly Guid DnsNamespace = new Guid("6ba7b810-9dad-11d1-80b4-00c04fd430c8");
/// <summary>
/// The namespace for URLs (from RFC 4122, Appendix C).
/// </summary>
public static readonly Guid UrlNamespace = new Guid("6ba7b811-9dad-11d1-80b4-00c04fd430c8");
/// <summary>
/// The namespace for ISO OIDs (from RFC 4122, Appendix C).
/// </summary>
public static readonly Guid IsoOidNamespace = new Guid("6ba7b812-9dad-11d1-80b4-00c04fd430c8");
// Converts a GUID (expressed as a byte array) to/from network order (MSB-first).
static void SwapByteOrder(byte[] guid)
{
SwapBytes(guid, 0, 3);
SwapBytes(guid, 1, 2);
SwapBytes(guid, 4, 5);
SwapBytes(guid, 6, 7);
}
static void SwapBytes(byte[] guid, int left, int right)
{
byte temp = guid[left];
guid[left] = guid[right];
guid[right] = temp;
}
public static void MoveFile(string source, string dest, bool overwrite)
{
#if NET6_0_OR_GREATER
File.Move(source, dest, overwrite);
#else
if (!File.Exists(source)) throw new FileNotFoundException("File not found", source);
if (overwrite) File.Delete(dest);
File.Move(source, dest);
#endif
}
public static TEnum[] GetEnumValues<TEnum>() where TEnum : struct, Enum
{
#if NET6_0_OR_GREATER
return Enum.GetValues<TEnum>();
#else
return Enum.GetValues(typeof(TEnum)).Cast<TEnum>().ToArray();
#endif
}
}
}

View File

@@ -4,6 +4,7 @@ using System.Runtime.Versioning;
using Microsoft.Extensions.Logging;
using NuGet.Versioning;
using Velopack.NuGet;
using Velopack.Util;
namespace Velopack.Locators
{
@@ -33,7 +34,7 @@ namespace Velopack.Locators
public override string? Channel { get; }
/// <inheritdoc />
public override string? AppTempDir => CreateSubDirIfDoesNotExist(Utility.GetDefaultTempBaseDirectory(), AppId);
public override string? AppTempDir => CreateSubDirIfDoesNotExist(TempUtil.GetDefaultTempBaseDirectory(), AppId);
/// <inheritdoc />
public override string? PackagesDir => CreateSubDirIfDoesNotExist(PersistentTempDir, "packages");
@@ -70,7 +71,7 @@ namespace Velopack.Locators
var rootDir = ourPath.Substring(0, ix);
var contentsDir = Path.Combine(rootDir, "usr", "bin");
var updateExe = Path.Combine(contentsDir, "UpdateNix");
var metadataPath = Path.Combine(contentsDir, Utility.SpecVersionFileName);
var metadataPath = Path.Combine(contentsDir, CoreUtil.SpecVersionFileName);
if (!String.IsNullOrEmpty(AppImagePath) && File.Exists(AppImagePath)) {
if (File.Exists(updateExe) && PackageManifest.TryParseFromFile(metadataPath, out var manifest)) {

View File

@@ -4,6 +4,7 @@ using System.Runtime.Versioning;
using Microsoft.Extensions.Logging;
using NuGet.Versioning;
using Velopack.NuGet;
using Velopack.Util;
namespace Velopack.Locators
{
@@ -30,7 +31,7 @@ namespace Velopack.Locators
public override string? AppContentDir => RootAppDir;
/// <inheritdoc />
public override string? AppTempDir => CreateSubDirIfDoesNotExist(Utility.GetDefaultTempBaseDirectory(), AppId);
public override string? AppTempDir => CreateSubDirIfDoesNotExist(TempUtil.GetDefaultTempBaseDirectory(), AppId);
/// <inheritdoc />
public override string? PackagesDir => CreateSubDirIfDoesNotExist(CachesAppDir, "packages");
@@ -68,7 +69,7 @@ namespace Velopack.Locators
var contentsDir = Path.Combine(appPath, "Contents");
var macosDir = Path.Combine(contentsDir, "MacOS");
var updateExe = Path.Combine(macosDir, "UpdateMac");
var metadataPath = Path.Combine(macosDir, Utility.SpecVersionFileName);
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);

View File

@@ -6,6 +6,7 @@ using System.Text;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using NuGet.Versioning;
using Velopack.Util;
namespace Velopack.Locators
{
@@ -162,7 +163,7 @@ namespace Velopack.Locators
var buf = new byte[4096];
prng.NextBytes(buf);
ret = Utility.CreateGuidFromHash(buf);
ret = GuidUtil.CreateGuidFromHash(buf);
try {
File.WriteAllText(stagedUserIdFile, ret.ToString(), Encoding.UTF8);
Log.Info($"Generated new staging userId: {ret}");

View File

@@ -1,4 +1,5 @@
using System.IO;
using Velopack.Util;
namespace Velopack.Locators
{
@@ -13,7 +14,7 @@ namespace Velopack.Locators
/// </summary>
public static string GetLocalPackagePath(this IVelopackLocator locator, VelopackAsset velopackAsset)
{
return Path.Combine(locator.PackagesDir!, Utility.GetSafeFilename(velopackAsset.FileName));
return Path.Combine(locator.PackagesDir!, PathUtil.GetSafeFilename(velopackAsset.FileName));
}
}

View File

@@ -4,6 +4,7 @@ using System.Runtime.Versioning;
using Microsoft.Extensions.Logging;
using NuGet.Versioning;
using Velopack.NuGet;
using Velopack.Util;
namespace Velopack.Locators
{
@@ -69,7 +70,7 @@ namespace Velopack.Locators
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, Utility.SpecVersionFileName);
var manifestFile = Path.Combine(myDirPath, CoreUtil.SpecVersionFileName);
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);
@@ -79,7 +80,7 @@ namespace Velopack.Locators
UpdateExePath = possibleUpdateExe;
AppContentDir = myDirPath;
Channel = manifest.Channel;
} else if (Utility.PathPartStartsWith(myDirName, "app-") && NuGetVersion.TryParse(myDirName.Substring(4), out var version)) {
} 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.");
AppId = Path.GetFileName(Path.GetDirectoryName(possibleUpdateExe));
@@ -92,7 +93,7 @@ namespace Velopack.Locators
// this is an attempt to handle the case where we are running in a nested current directory.
var rootDir = ourExePath.Substring(0, ixCurrent);
var currentDir = Path.Combine(rootDir, "current");
var manifestFile = Path.Combine(currentDir, Utility.SpecVersionFileName);
var manifestFile = Path.Combine(currentDir, CoreUtil.SpecVersionFileName);
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)) {

View File

@@ -11,6 +11,7 @@ using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using NuGet.Versioning;
using Velopack.Util;
namespace Velopack
{
@@ -225,7 +226,7 @@ namespace Velopack
string baseUrl = null;
string query = null;
if (Utility.IsHttpUrl(filename)) {
if (HttpUtil.IsHttpUrl(filename)) {
var uri = new Uri(filename);
var path = uri.LocalPath;
var authority = uri.GetLeftPart(UriPartial.Authority);
@@ -281,7 +282,7 @@ namespace Velopack
return new ReleaseEntry[0];
}
fileContents = Utility.RemoveByteOrderMarkerIfPresent(fileContents);
fileContents = CoreUtil.RemoveByteOrderMarkerIfPresent(fileContents);
var ret = fileContents.Split('\n')
.Where(x => !String.IsNullOrWhiteSpace(x))
@@ -302,7 +303,7 @@ namespace Velopack
return new ReleaseEntry[0];
}
fileContents = Utility.RemoveByteOrderMarkerIfPresent(fileContents);
fileContents = CoreUtil.RemoveByteOrderMarkerIfPresent(fileContents);
var ret = fileContents.Split('\n')
.Where(x => !String.IsNullOrWhiteSpace(x))
@@ -350,7 +351,7 @@ namespace Velopack
Contract.Requires(file != null && file.CanRead);
Contract.Requires(!String.IsNullOrEmpty(filename));
var hash = Utility.CalculateStreamSHA1(file);
var hash = IoUtil.CalculateStreamSHA1(file);
return new ReleaseEntry(hash, filename, file.Length, baseUrl);
}
@@ -387,7 +388,7 @@ namespace Velopack
var entries = entriesQueue.ToList();
if (writeToDisk) {
using var _ = Utility.GetTempFileName(out var tempFile);
using var _ = TempUtil.GetTempFileName(out var tempFile);
using (var of = File.OpenWrite(tempFile)) {
if (entries.Count > 0) WriteReleaseFile(entries, of);
}

View File

@@ -4,6 +4,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Velopack.Util;
namespace Velopack.Sources
{
@@ -44,7 +45,7 @@ namespace Velopack.Sources
RepoUri = new Uri(repoUrl.TrimEnd('/'));
AccessToken = accessToken;
Prerelease = prerelease;
Downloader = downloader ?? Utility.CreateDefaultDownloader();
Downloader = downloader ?? HttpUtil.CreateDefaultDownloader();
}
/// <inheritdoc />
@@ -69,7 +70,7 @@ namespace Velopack.Sources
return new VelopackAssetFeed();
}
var releasesFileName = Utility.GetVeloReleaseIndexName(channel);
var releasesFileName = CoreUtil.GetVeloReleaseIndexName(channel);
List<GitBaseAsset> entries = new List<GitBaseAsset>();
foreach (var r in releases) {
@@ -83,7 +84,7 @@ namespace Velopack.Sources
continue;
}
var releaseBytes = await Downloader.DownloadBytes(assetUrl, Authorization, "application/octet-stream").ConfigureAwait(false);
var txt = Utility.RemoveByteOrderMarkerIfPresent(releaseBytes);
var txt = CoreUtil.RemoveByteOrderMarkerIfPresent(releaseBytes);
var feed = VelopackAssetFeed.FromJson(txt);
foreach (var f in feed.Assets) {
entries.Add(new GitBaseAsset(f, r));

View File

@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Velopack.Json;
using Velopack.Util;
namespace Velopack.Sources
{
/// <summary> Describes a Gitea release, including attached assets. </summary>

View File

@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Velopack.Json;
using Velopack.Util;
namespace Velopack.Sources
{

View File

@@ -2,7 +2,7 @@
using System.Linq;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Velopack.Json;
using Velopack.Util;
namespace Velopack.Sources
{

View File

@@ -5,6 +5,7 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Velopack.NuGet;
using Velopack.Util;
namespace Velopack.Sources
{
@@ -32,7 +33,7 @@ namespace Velopack.Sources
}
// if a feed exists in the folder, let's use that.
var feedLoc = Path.Combine(BaseDirectory.FullName, Utility.GetVeloReleaseIndexName(channel));
var feedLoc = Path.Combine(BaseDirectory.FullName, CoreUtil.GetVeloReleaseIndexName(channel));
if (File.Exists(feedLoc)) {
logger.Debug($"Found local file feed at '{feedLoc}'.");
return Task.FromResult(VelopackAssetFeed.FromJson(File.ReadAllText(feedLoc)));

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Velopack.Util;
namespace Velopack.Sources
{
@@ -28,14 +29,14 @@ namespace Velopack.Sources
public SimpleWebSource(Uri baseUri, IFileDownloader? downloader = null)
{
BaseUri = baseUri;
Downloader = downloader ?? Utility.CreateDefaultDownloader();
Downloader = downloader ?? HttpUtil.CreateDefaultDownloader();
}
/// <inheritdoc />
public async virtual Task<VelopackAssetFeed> GetReleaseFeed(ILogger logger, string channel, Guid? stagingId = null, VelopackAsset? latestLocalRelease = null)
{
var releaseFilename = Utility.GetVeloReleaseIndexName(channel);
var uri = Utility.AppendPathToUri(BaseUri, releaseFilename);
var releaseFilename = CoreUtil.GetVeloReleaseIndexName(channel);
var uri = HttpUtil.AppendPathToUri(BaseUri, releaseFilename);
var args = new Dictionary<string, string>();
if (VelopackRuntimeInfo.SystemArch != RuntimeCpu.Unknown) {
@@ -52,7 +53,7 @@ namespace Velopack.Sources
args.Add("localVersion", latestLocalRelease.Version.ToString());
}
var uriAndQuery = Utility.AddQueryParamsToUri(uri, args);
var uriAndQuery = HttpUtil.AddQueryParamsToUri(uri, args);
logger.Info($"Downloading release file '{releaseFilename}' from '{uriAndQuery}'.");
@@ -68,11 +69,11 @@ namespace Velopack.Sources
// releaseUri can be a relative url (eg. "MyPackage.nupkg") or it can be an
// absolute url (eg. "https://example.com/MyPackage.nupkg"). In the former case
var sourceBaseUri = Utility.EnsureTrailingSlash(BaseUri);
var sourceBaseUri = HttpUtil.EnsureTrailingSlash(BaseUri);
var source = Utility.IsHttpUrl(releaseEntry.FileName)
var source = HttpUtil.IsHttpUrl(releaseEntry.FileName)
? releaseEntry.FileName
: Utility.AppendPathToUri(sourceBaseUri, releaseEntry.FileName).ToString();
: HttpUtil.AppendPathToUri(sourceBaseUri, releaseEntry.FileName).ToString();
logger.Info($"Downloading '{releaseEntry.FileName}' from '{source}'.");
await Downloader.DownloadFile(source, localFile, progress, cancelToken: cancelToken).ConfigureAwait(false);

View File

@@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Velopack.Json;
using Velopack.Util;
using Velopack.Locators;
namespace Velopack.Sources
@@ -19,7 +19,7 @@ namespace Velopack.Sources
IFileDownloader? downloader = null)
{
BaseUri = new Uri(baseUri);
Downloader = downloader ?? Utility.CreateDefaultDownloader();
Downloader = downloader ?? HttpUtil.CreateDefaultDownloader();
}
/// <summary> The URL of the server hosting packages to update to. </summary>
@@ -33,7 +33,7 @@ namespace Velopack.Sources
VelopackAsset? latestLocalRelease = null)
{
Uri baseUri = new(BaseUri, $"v1.0/manifest/");
var uri = Utility.AppendPathToUri(baseUri, Utility.GetVeloReleaseIndexName(channel));
var uri = HttpUtil.AppendPathToUri(baseUri, CoreUtil.GetVeloReleaseIndexName(channel));
var args = new Dictionary<string, string>();
if (VelopackRuntimeInfo.SystemArch != RuntimeCpu.Unknown) {
@@ -52,7 +52,7 @@ namespace Velopack.Sources
args.Add("id", VelopackLocator.GetDefault(logger).AppId ?? "");
}
var uriAndQuery = Utility.AddQueryParamsToUri(uri, args);
var uriAndQuery = HttpUtil.AddQueryParamsToUri(uri, args);
logger.LogInformation("Downloading releases from '{Uri}'.", uriAndQuery);
@@ -73,7 +73,7 @@ namespace Velopack.Sources
}
if (localFile is null) throw new ArgumentNullException(nameof(localFile));
Uri sourceBaseUri = Utility.EnsureTrailingSlash(BaseUri);
Uri sourceBaseUri = HttpUtil.EnsureTrailingSlash(BaseUri);
Uri downloadUri = new(sourceBaseUri, $"v1.0/download/{velopackRelease.Id}");

View File

@@ -9,6 +9,7 @@ using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Velopack.Locators;
using Velopack.Util;
namespace Velopack
{

View File

@@ -11,6 +11,7 @@ using Velopack.Compression;
using Velopack.Locators;
using Velopack.NuGet;
using Velopack.Sources;
using Velopack.Util;
namespace Velopack
{
@@ -126,7 +127,7 @@ namespace Velopack
var feedObj = await Source.GetReleaseFeed(Log, Channel, betaId, latestLocalFull).ConfigureAwait(false);
var feed = feedObj.Assets;
var latestRemoteFull = feed.Where(r => r.Type == VelopackAssetType.Full).MaxBy(x => x.Version).FirstOrDefault();
var latestRemoteFull = feed.Where(r => r.Type == VelopackAssetType.Full).MaxByPolyfill(x => x.Version).FirstOrDefault();
if (latestRemoteFull == null) {
Log.Info("No remote full releases found.");
return null;
@@ -264,20 +265,20 @@ namespace Velopack
Log.Info($"There are too many delta's ({deltasCount} > 10) or the sum of their size ({deltasSize} > {targetRelease.Size}) is too large. " +
$"Only full update will be available.");
} else {
using var _1 = Utility.GetTempDirectory(out var deltaStagingDir, appTempDir);
using var _1 = TempUtil.GetTempDirectory(out var deltaStagingDir, appTempDir);
string basePackagePath = Locator.GetLocalPackagePath(updates.BaseRelease);
if (!File.Exists(basePackagePath))
throw new Exception($"Unable to find base package {basePackagePath} for delta update.");
EasyZip.ExtractZipToDirectory(Log, basePackagePath, deltaStagingDir);
reportProgress(10);
await DownloadAndApplyDeltaUpdates(deltaStagingDir, updates, x => reportProgress(Utility.CalculateProgress(x, 10, 80)), cancelToken)
await DownloadAndApplyDeltaUpdates(deltaStagingDir, updates, x => reportProgress(CoreUtil.CalculateProgress(x, 10, 80)), cancelToken)
.ConfigureAwait(false);
reportProgress(80);
Log.Info("Delta updates completed, creating final update package.");
File.Delete(incompleteFile);
await EasyZip.CreateZipFromDirectoryAsync(Log, incompleteFile, deltaStagingDir, x => reportProgress(Utility.CalculateProgress(x, 80, 100)),
await EasyZip.CreateZipFromDirectoryAsync(Log, incompleteFile, deltaStagingDir, x => reportProgress(CoreUtil.CalculateProgress(x, 80, 100)),
cancelToken: cancelToken).ConfigureAwait(false);
File.Delete(completeFile);
File.Move(incompleteFile, completeFile);
@@ -297,7 +298,7 @@ namespace Velopack
Log.Info("Verifying package checksum...");
VerifyPackageChecksum(targetRelease, incompleteFile);
Utility.MoveFile(incompleteFile, completeFile, true);
IoUtil.MoveFile(incompleteFile, completeFile, true);
Log.Info("Full release download complete. Package moved to: " + completeFile);
reportProgress(100);
} finally {
@@ -310,7 +311,7 @@ namespace Velopack
if (zip.UpdateExeBytes == null) {
Log.Error("Update.exe not found in package, skipping extraction.");
} else {
await Utility.RetryAsync(async () => {
await IoUtil.RetryAsync(async () => {
using var ms = new MemoryStream(zip.UpdateExeBytes);
using var fs = File.Create(updateExe);
await ms.CopyToAsync(fs).ConfigureAwait(false);
@@ -352,7 +353,7 @@ namespace Velopack
current -= component;
component = toIncrement / 100.0 * p;
var progressOfStep = (int) Math.Round(current += component);
progress(Utility.CalculateProgress(progressOfStep, 0, 50));
progress(CoreUtil.CalculateProgress(progressOfStep, 0, 50));
}
}, cancelToken).ConfigureAwait(false);
VerifyPackageChecksum(x, targetFile);
@@ -372,7 +373,7 @@ namespace Velopack
var packageFile = Locator.GetLocalPackagePath(rel);
builder.ApplyDeltaPackageFast(extractedBasePackage, packageFile, x => {
var progressOfStep = (int) (baseProgress + (progressStepSize * (x / 100d)));
progress(Utility.CalculateProgress(progressOfStep, 50, 100));
progress(CoreUtil.CalculateProgress(progressOfStep, 50, 100));
});
}
@@ -391,11 +392,11 @@ namespace Velopack
var appPackageDir = Locator.PackagesDir!;
foreach (var l in Directory.EnumerateFiles(appPackageDir, "*.nupkg").ToArray()) {
try {
if (assetToKeep != null && Utility.FullPathEquals(l, assetToKeep)) {
if (assetToKeep != null && PathUtil.FullPathEquals(l, assetToKeep)) {
continue;
}
Utility.DeleteFileOrDirectoryHard(l);
IoUtil.DeleteFileOrDirectoryHard(l);
Log.Trace(l + " deleted.");
} catch (Exception ex) {
Log.Warn(ex, "Failed to delete partial package: " + l);
@@ -404,7 +405,7 @@ namespace Velopack
foreach (var l in Directory.EnumerateFiles(appPackageDir, "*.partial").ToArray()) {
try {
Utility.DeleteFileOrDirectoryHard(l);
IoUtil.DeleteFileOrDirectoryHard(l);
Log.Trace(l + " deleted.");
} catch (Exception ex) {
Log.Warn(ex, "Failed to delete partial package: " + l);
@@ -433,12 +434,12 @@ namespace Velopack
}
if (!string.IsNullOrEmpty(release.SHA256)) {
var hash = Utility.CalculateFileSHA256(targetPackage.FullName);
var hash = IoUtil.CalculateFileSHA256(targetPackage.FullName);
if (!hash.Equals(release.SHA256, StringComparison.Ordinal)) {
throw new ChecksumFailedException(targetPackage.FullName, $"SHA256 doesn't match ({release.SHA256} != {hash}).");
}
} else {
var hash = Utility.CalculateFileSHA1(targetPackage.FullName);
var hash = IoUtil.CalculateFileSHA1(targetPackage.FullName);
if (!hash.Equals(release.SHA1, StringComparison.OrdinalIgnoreCase)) {
throw new ChecksumFailedException(targetPackage.FullName, $"SHA1 doesn't match ({release.SHA1} != {hash}).");
}
@@ -479,8 +480,8 @@ namespace Velopack
if (String.IsNullOrWhiteSpace(urlOrPath)) {
throw new ArgumentException("Must pass a valid URL or file path to UpdateManager", nameof(urlOrPath));
}
if (Utility.IsHttpUrl(urlOrPath)) {
return new SimpleWebSource(urlOrPath, Utility.CreateDefaultDownloader());
if (HttpUtil.IsHttpUrl(urlOrPath)) {
return new SimpleWebSource(urlOrPath, HttpUtil.CreateDefaultDownloader());
} else {
return new SimpleFileSource(new DirectoryInfo(urlOrPath));
}

View File

@@ -22,7 +22,7 @@ namespace System.Text.Json.Serialization
}
#endif
namespace Velopack.Json
namespace Velopack.Util
{
#if NET6_0_OR_GREATER

View File

@@ -0,0 +1,142 @@
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Velopack.Util
{
internal static class CoreUtil
{
public const string SpecVersionFileName = "sq.version";
public static string GetVeloReleaseIndexName(string channel)
{
return $"releases.{channel ?? VelopackRuntimeInfo.SystemOs.GetOsShortName()}.json";
}
public static string GetReleasesFileName(string? channel)
{
if (channel == null) {
// default RELEASES file name for each platform.
if (VelopackRuntimeInfo.IsOSX) return "RELEASES-osx";
if (VelopackRuntimeInfo.IsLinux) return "RELEASES-linux";
return "RELEASES";
} else {
// if the channel is an empty string or "win", we use the default RELEASES file name.
if (String.IsNullOrWhiteSpace(channel) || channel.ToLower() == "win") {
return "RELEASES";
}
// all other cases the RELEASES file includes the channel name.
return $"RELEASES-{channel.ToLower()}";
}
}
public static string GetAppUserModelId(string packageId)
{
return $"velopack.{packageId}";
}
/// <summary>
/// Calculates the total percentage of a specific step that should report within a specific range.
/// <para />
/// If a step needs to report between 50 -> 75 %, this method should be used as CalculateProgress(percentage, 50, 75).
/// </summary>
/// <param name="percentageOfCurrentStep">The percentage of the current step, a value between 0 and 100.</param>
/// <param name="stepStartPercentage">The start percentage of the range the current step represents.</param>
/// <param name="stepEndPercentage">The end percentage of the range the current step represents.</param>
/// <returns>The calculated percentage that can be reported about the total progress.</returns>
public static int CalculateProgress(int percentageOfCurrentStep, int stepStartPercentage, int stepEndPercentage)
{
// Ensure we are between 0 and 100
percentageOfCurrentStep = Math.Max(Math.Min(percentageOfCurrentStep, 100), 0);
var range = stepEndPercentage - stepStartPercentage;
var singleValue = range / 100d;
var totalPercentage = (singleValue * percentageOfCurrentStep) + stepStartPercentage;
return (int) totalPercentage;
}
public static Action<int> CreateProgressDelegate(Action<int> rootProgress, int stepStartPercentage, int stepEndPercentage)
{
return percentage => {
rootProgress(CalculateProgress(percentage, stepStartPercentage, stepEndPercentage));
};
}
public static string RemoveByteOrderMarkerIfPresent(string content)
{
return string.IsNullOrEmpty(content)
? string.Empty
: RemoveByteOrderMarkerIfPresent(Encoding.UTF8.GetBytes(content));
}
public static string RemoveByteOrderMarkerIfPresent(byte[] content)
{
byte[] output = { };
Func<byte[], byte[], bool> matches = (bom, src) => {
if (src.Length < bom.Length) return false;
return !bom.Where((chr, index) => src[index] != chr).Any();
};
var utf32Be = new byte[] { 0x00, 0x00, 0xFE, 0xFF };
var utf32Le = new byte[] { 0xFF, 0xFE, 0x00, 0x00 };
var utf16Be = new byte[] { 0xFE, 0xFF };
var utf16Le = new byte[] { 0xFF, 0xFE };
var utf8 = new byte[] { 0xEF, 0xBB, 0xBF };
if (matches(utf32Be, content)) {
output = new byte[content.Length - utf32Be.Length];
} else if (matches(utf32Le, content)) {
output = new byte[content.Length - utf32Le.Length];
} else if (matches(utf16Be, content)) {
output = new byte[content.Length - utf16Be.Length];
} else if (matches(utf16Le, content)) {
output = new byte[content.Length - utf16Le.Length];
} else if (matches(utf8, content)) {
output = new byte[content.Length - utf8.Length];
} else {
output = content;
}
if (output.Length > 0) {
Buffer.BlockCopy(content, content.Length - output.Length, output, 0, output.Length);
}
return Encoding.UTF8.GetString(output);
}
public static T GetAwaiterResult<T>(this Task<T> task)
{
return task.ConfigureAwait(false).GetAwaiter().GetResult();
}
public static void GetAwaiterResult(this Task task)
{
task.ConfigureAwait(false).GetAwaiter().GetResult();
}
public static bool TryParseEnumU16<TEnum>(ushort enumValue, out TEnum? retVal)
{
retVal = default;
bool success = Enum.IsDefined(typeof(TEnum), enumValue);
if (success) {
retVal = (TEnum) Enum.ToObject(typeof(TEnum), enumValue);
}
return success;
}
public static TEnum[] GetEnumValues<TEnum>() where TEnum : struct, Enum
{
#if NET6_0_OR_GREATER
return Enum.GetValues<TEnum>();
#else
return Enum.GetValues(typeof(TEnum)).Cast<TEnum>().ToArray();
#endif
}
}
}

View File

@@ -2,7 +2,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Threading;
namespace Velopack
namespace Velopack.Util
{
[ExcludeFromCodeCoverage]
internal static class Disposable

View File

@@ -1,10 +1,13 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading.Tasks;
namespace Velopack
namespace Velopack.Util
{
[ExcludeFromCodeCoverage]
internal static class EnumerableExtensions
@@ -45,6 +48,7 @@ namespace Velopack
$" There were 2 or more.");
}
}
return result;
}
@@ -72,14 +76,14 @@ namespace Velopack
/// <param name="source">Source sequence.</param>
/// <param name="keySelector">Key selector used to extract the key for each element in the sequence.</param>
/// <returns>List with the elements that share the same maximum key value.</returns>
public static IList<TSource> MaxBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
public static IList<TSource> MaxByPolyfill<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
if (source == null)
throw new ArgumentNullException("source");
if (keySelector == null)
throw new ArgumentNullException("keySelector");
return MaxBy(source, keySelector, Comparer<TKey>.Default);
return MaxByPolyfill(source, keySelector, Comparer<TKey>.Default);
}
/// <summary>
@@ -91,7 +95,7 @@ namespace Velopack
/// <param name="keySelector">Key selector used to extract the key for each element in the sequence.</param>
/// <param name="comparer">Comparer used to determine the maximum key value.</param>
/// <returns>List with the elements that share the same maximum key value.</returns>
public static IList<TSource> MaxBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
public static IList<TSource> MaxByPolyfill<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IComparer<TKey> comparer)
{
if (source == null) throw new ArgumentNullException("source");
if (keySelector == null) throw new ArgumentNullException("keySelector");
@@ -127,5 +131,22 @@ namespace Velopack
return result;
}
public static Task ForEachAsync<T>(this IEnumerable<T> source, Action<T> body, int degreeOfParallelism = 4)
{
return ForEachAsync(source, x => Task.Run(() => body(x)), degreeOfParallelism);
}
public static Task ForEachAsync<T>(this IEnumerable<T> source, Func<T, Task> body, int degreeOfParallelism = 4)
{
return Task.WhenAll(
from partition in Partitioner.Create(source).GetPartitions(degreeOfParallelism)
select Task.Run(
async () => {
using (partition)
while (partition.MoveNext())
await body(partition.Current).ConfigureAwait(false);
}));
}
}
}

View File

@@ -0,0 +1,88 @@
using System;
using System.Security.Cryptography;
using System.Text;
namespace Velopack.Util
{
internal static class GuidUtil
{
public static Guid CreateGuidFromHash(string text)
{
return CreateGuidFromHash(text, IsoOidNamespace);
}
public static Guid CreateGuidFromHash(byte[] data)
{
return CreateGuidFromHash(data, IsoOidNamespace);
}
public static Guid CreateGuidFromHash(string text, Guid namespaceId)
{
return CreateGuidFromHash(Encoding.UTF8.GetBytes(text), namespaceId);
}
public static Guid CreateGuidFromHash(byte[] nameBytes, Guid namespaceId)
{
// convert the namespace UUID to network order (step 3)
byte[] namespaceBytes = namespaceId.ToByteArray();
SwapByteOrder(namespaceBytes);
// comput the hash of the name space ID concatenated with the
// name (step 4)
byte[] hash;
using (var algorithm = SHA1.Create()) {
algorithm.TransformBlock(namespaceBytes, 0, namespaceBytes.Length, null, 0);
algorithm.TransformFinalBlock(nameBytes, 0, nameBytes.Length);
hash = algorithm.Hash!;
}
// most bytes from the hash are copied straight to the bytes of
// the new GUID (steps 5-7, 9, 11-12)
var newGuid = new byte[16];
Array.Copy(hash, 0, newGuid, 0, 16);
// set the four most significant bits (bits 12 through 15) of
// the time_hi_and_version field to the appropriate 4-bit
// version number from Section 4.1.3 (step 8)
newGuid[6] = (byte) ((newGuid[6] & 0x0F) | (5 << 4));
// set the two most significant bits (bits 6 and 7) of the
// clock_seq_hi_and_reserved to zero and one, respectively
// (step 10)
newGuid[8] = (byte) ((newGuid[8] & 0x3F) | 0x80);
// convert the resulting UUID to local byte order (step 13)
SwapByteOrder(newGuid);
return new Guid(newGuid);
}
/// <summary>
/// The namespace for fully-qualified domain names (from RFC 4122, Appendix C).
/// </summary>
public static readonly Guid DnsNamespace = new Guid("6ba7b810-9dad-11d1-80b4-00c04fd430c8");
/// <summary>
/// The namespace for URLs (from RFC 4122, Appendix C).
/// </summary>
public static readonly Guid UrlNamespace = new Guid("6ba7b811-9dad-11d1-80b4-00c04fd430c8");
/// <summary>
/// The namespace for ISO OIDs (from RFC 4122, Appendix C).
/// </summary>
public static readonly Guid IsoOidNamespace = new Guid("6ba7b812-9dad-11d1-80b4-00c04fd430c8");
// Converts a GUID (expressed as a byte array) to/from network order (MSB-first).
static void SwapByteOrder(byte[] guid)
{
SwapBytes(guid, 0, 3);
SwapBytes(guid, 1, 2);
SwapBytes(guid, 4, 5);
SwapBytes(guid, 6, 7);
}
static void SwapBytes(byte[] guid, int left, int right)
{
(guid[left], guid[right]) = (guid[right], guid[left]);
}
}
}

View File

@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
namespace Velopack.Util
{
internal static class HttpUtil
{
public static Uri AddQueryParamsToUri(Uri uri, IEnumerable<KeyValuePair<string, string>> newQuery)
{
var query = System.Web.HttpUtility.ParseQueryString(uri.Query);
foreach (var entry in newQuery) {
query[entry.Key] = entry.Value;
}
var builder = new UriBuilder(uri);
builder.Query = query.ToString();
return builder.Uri;
}
public static bool IsHttpUrl(string urlOrPath)
{
if (!Uri.TryCreate(urlOrPath, UriKind.Absolute, out Uri? uri)) {
return false;
}
return uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps;
}
public static Sources.IFileDownloader CreateDefaultDownloader()
{
return new Sources.HttpClientFileDownloader();
}
public static Uri AppendPathToUri(Uri uri, string path)
{
var builder = new UriBuilder(uri);
if (!builder.Path.EndsWith("/")) {
builder.Path += "/";
}
builder.Path += path;
return builder.Uri;
}
public static Uri EnsureTrailingSlash(Uri uri)
{
return AppendPathToUri(uri, "");
}
}
}

View File

@@ -0,0 +1,218 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
namespace Velopack.Util
{
internal static class IoUtil
{
public static IEnumerable<FileInfo> GetAllFilesRecursively(this DirectoryInfo? rootPath)
{
if (rootPath == null) return Enumerable.Empty<FileInfo>();
return rootPath.EnumerateFiles("*", SearchOption.AllDirectories);
}
public static string CalculateFileSHA1(string filePath)
{
var bufferSize = 1000000; // 1mb
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize)) {
return CalculateStreamSHA1(stream);
}
}
public static string CalculateStreamSHA1(Stream file)
{
using (var sha1 = SHA1.Create()) {
return BitConverter.ToString(sha1.ComputeHash(file)).Replace("-", String.Empty);
}
}
/// <inheritdoc cref="CalculateStreamSHA256"/>
public static string CalculateFileSHA256(string filePath)
{
var bufferSize = 1000000; // 1mb
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize)) {
return CalculateStreamSHA256(stream);
}
}
/// <summary>
/// Get SHA256 hash of the specified file and returns the result as a base64 encoded string (with length 44)
/// </summary>
public static string CalculateStreamSHA256(Stream file)
{
using (var sha256 = SHA256.Create()) {
return BitConverter.ToString(sha256.ComputeHash(file)).Replace("-", String.Empty);
}
}
public static void MoveFile(string source, string dest, bool overwrite)
{
#if NET6_0_OR_GREATER
File.Move(source, dest, overwrite);
#else
if (!File.Exists(source)) throw new FileNotFoundException("File not found", source);
if (overwrite) File.Delete(dest);
File.Move(source, dest);
#endif
}
/// <summary>
/// Repeatedly tries various methods to delete a file system object. Optionally renames the directory first.
/// Optionally ignores errors.
/// </summary>
/// <param name="path">The path of the file system entity to delete.</param>
/// <param name="throwOnFailure">Whether this function should throw if the delete fails.</param>
/// <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)
{
logger ??= NullLogger.Instance;
logger.Debug($"Starting to delete: {path}");
try {
if (File.Exists(path)) {
DeleteFsiVeryHard(new FileInfo(path), logger);
} else if (Directory.Exists(path)) {
if (renameFirst) {
// if there are locked files in a directory, we will not attempt to delte it
var oldPath = path + ".old";
Directory.Move(path, oldPath);
path = oldPath;
}
DeleteFsiTree(new DirectoryInfo(path), logger);
} else {
if (throwOnFailure)
logger?.Warn($"Cannot delete '{path}' if it does not exist.");
}
return true;
} catch (Exception ex) {
logger.Error(ex, $"Unable to delete '{path}'");
if (throwOnFailure)
throw;
return false;
}
}
private static void DeleteFsiTree(FileSystemInfo fileSystemInfo, ILogger logger)
{
// if junction / symlink, don't iterate, just delete it.
if (fileSystemInfo.Attributes.HasFlag(FileAttributes.ReparsePoint)) {
DeleteFsiVeryHard(fileSystemInfo, logger);
return;
}
// recursively delete children
try {
if (fileSystemInfo is DirectoryInfo directoryInfo) {
foreach (FileSystemInfo childInfo in directoryInfo.GetFileSystemInfos()) {
DeleteFsiTree(childInfo, logger);
}
}
} catch (Exception ex) {
logger.Warn(ex, $"Unable to traverse children of '{fileSystemInfo.FullName}'");
}
// finally, delete myself, we should try this even if deleting children failed
// because Directory.Delete can also be recursive
DeleteFsiVeryHard(fileSystemInfo, logger);
}
private static void DeleteFsiVeryHard(FileSystemInfo fileSystemInfo, ILogger logger)
{
// don't try to delete the running process
if (PathUtil.FullPathEquals(fileSystemInfo.FullName, VelopackRuntimeInfo.EntryExePath))
return;
// try to remove "ReadOnly" attributes
try { fileSystemInfo.Attributes = FileAttributes.Normal; } catch { }
try { fileSystemInfo.Refresh(); } catch { }
// use this instead of fsi.Delete() because it is more resilient/aggressive
Action deleteMe = fileSystemInfo is DirectoryInfo
? () => Directory.Delete(fileSystemInfo.FullName, true)
: () => File.Delete(fileSystemInfo.FullName);
// retry a few times. if a directory in this tree is open in Windows Explorer,
// it might be locked for a little while WE cleans up handles
try {
Retry(
() => {
try {
deleteMe();
} catch (DirectoryNotFoundException) {
return; // good!
}
},
retries: 4,
retryDelay: 50);
} catch (Exception ex) {
logger?.Warn(ex, $"Unable to delete child '{fileSystemInfo.FullName}'");
throw;
}
}
public static void Retry(this Action block, int retries = 4, int retryDelay = 250, ILogger? logger = null)
{
Retry(
() => {
block();
return true;
},
retries,
retryDelay,
logger);
}
public static T Retry<T>(this Func<T> block, int retries = 4, int retryDelay = 250, ILogger? logger = null)
{
while (true) {
try {
T ret = block();
return ret;
} catch (Exception ex) {
if (retries == 0) throw;
logger?.Warn($"Operation failed ({ex.Message}). Retrying {retries} more times...");
retries--;
Thread.Sleep(retryDelay);
}
}
}
public static Task RetryAsync(this Func<Task> block, int retries = 4, int retryDelay = 250, ILogger? logger = null)
{
return RetryAsync(
async () => {
await block().ConfigureAwait(false);
return true;
},
retries,
retryDelay,
logger);
}
public static async Task<T> RetryAsync<T>(this Func<Task<T>> block, int retries = 4, int retryDelay = 250, ILogger? logger = null)
{
while (true) {
try {
return await block().ConfigureAwait(false);
} catch (Exception ex) {
if (retries == 0) throw;
logger?.Warn($"Operation failed ({ex.Message}). Retrying {retries} more times...");
retries--;
await Task.Delay(retryDelay).ConfigureAwait(false);
}
}
}
}
}

View File

@@ -2,7 +2,7 @@
using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Logging;
namespace Velopack
namespace Velopack.Util
{
[ExcludeFromCodeCoverage]
internal static class LoggerExtensions

View File

@@ -0,0 +1,154 @@
using System;
using System.IO;
using System.Linq;
using System.Text;
namespace Velopack.Util
{
internal static class PathUtil
{
public static string MakePathRelativeTo(string relativeTo, string thePath)
{
#if NETFRAMEWORK || NETSTANDARD
relativeTo = Path.GetFullPath(relativeTo);
thePath = Path.GetFullPath(thePath);
return ToggleRelative(relativeTo, thePath);
#else
return Path.GetRelativePath(relativeTo, thePath);
#endif
}
public static bool FullPathEquals(string path1, string path2)
{
return NormalizePath(path1).Equals(NormalizePath(path2), VelopackRuntimeInfo.PathStringComparison);
}
public static bool PathPartEquals(string part1, string part2)
{
return part1.Equals(part2, VelopackRuntimeInfo.PathStringComparison);
}
public static bool PathPartStartsWith(string part1, string startsWith)
{
return part1.StartsWith(startsWith, VelopackRuntimeInfo.PathStringComparison);
}
public static bool PathPartEndsWith(string part1, string endsWith)
{
return part1.EndsWith(endsWith, VelopackRuntimeInfo.PathStringComparison);
}
public static bool FileHasExtension(string filePath, string extension)
{
var ext = Path.GetExtension(filePath);
if (!extension.StartsWith(".")) extension = "." + extension;
return PathPartEquals(ext, extension);
}
public static string NormalizePath(string path)
{
var fullPath = Path.GetFullPath(path);
var normalized = new Uri(fullPath, UriKind.Absolute).LocalPath;
return normalized.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
}
public static bool IsFileInDirectory(string file, string directory)
{
var normalizedDir = NormalizePath(directory) + Path.DirectorySeparatorChar;
var normalizedFile = NormalizePath(file);
return normalizedFile.StartsWith(normalizedDir, VelopackRuntimeInfo.PathStringComparison);
}
/// <summary>
/// Escapes file name such that the file name is safe for writing to disk in the packages folder
/// </summary>
public static string GetSafeFilename(string fileName)
{
string safeFileName = Path.GetFileName(fileName);
char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
if (safeFileName.IndexOfAny(invalidFileNameChars) != -1) {
StringBuilder safeName = new();
foreach (char ch in safeFileName) {
if (Array.IndexOf(invalidFileNameChars, ch) == -1)
safeName.Append(ch);
else
safeName.Append('_');
}
safeFileName = safeName.ToString();
}
return safeFileName;
}
readonly static string[] peExtensions = new[] { ".exe", ".dll", ".node" };
public static bool FileIsLikelyPEImage(string name)
{
var ext = Path.GetExtension(name);
return peExtensions.Any(x => ext.Equals(x, StringComparison.OrdinalIgnoreCase));
}
private static string ToggleRelative(string basePath, string toggledPath)
{
// from https://github.com/RT-Projects/RT.Util/blob/master/RT.Util.Core/Paths/PathUtil.cs#L297
if (basePath.Length == 0)
throw new Exception("InvalidBasePath");
if (toggledPath.Length == 0)
throw new Exception("InvalidToggledPath");
if (!Path.IsPathRooted(basePath))
throw new Exception("BasePathNotAbsolute");
try { basePath = Path.GetFullPath(basePath + "\\"); } catch { throw new Exception("InvalidBasePath"); }
if (!Path.IsPathRooted(toggledPath)) {
try {
return StripTrailingSeparator(Path.GetFullPath(Path.Combine(basePath, toggledPath)));
} catch {
throw new Exception("InvalidToggledPath");
}
}
// Both basePath and toggledPath are absolute. Need to relativize toggledPath.
try { toggledPath = Path.GetFullPath(toggledPath + "\\"); } catch { throw new Exception("InvalidToggledPath"); }
int prevPos = -1;
int pos = toggledPath.IndexOf(Path.DirectorySeparatorChar);
while (pos != -1 && pos < basePath.Length &&
basePath.Substring(0, pos + 1).Equals(toggledPath.Substring(0, pos + 1), StringComparison.OrdinalIgnoreCase)) {
prevPos = pos;
pos = toggledPath.IndexOf(Path.DirectorySeparatorChar, pos + 1);
}
if (prevPos == -1)
throw new Exception("PathsOnDifferentDrives");
var piece = basePath.Substring(prevPos + 1);
var result = StripTrailingSeparator(
(".." + Path.DirectorySeparatorChar).Repeat(piece.Count(ch => ch == Path.DirectorySeparatorChar))
+ toggledPath.Substring(prevPos + 1));
return result.Length == 0 ? "." : result;
}
private static string Repeat(this string input, int numTimes)
{
if (numTimes == 0) return "";
if (numTimes == 1) return input;
if (numTimes == 2) return input + input;
var sb = new StringBuilder();
for (int i = 0; i < numTimes; i++)
sb.Append(input);
return sb.ToString();
}
private static string StripTrailingSeparator(string path)
{
if (path.Length < 1)
return path;
if (path[path.Length - 1] == '/' || path[path.Length - 1] == '\\')
return (path.Length == 3 && path[1] == ':') ? path : path.Substring(0, path.Length - 1);
else
return path;
}
}
}

View File

@@ -4,13 +4,37 @@ using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace Velopack
namespace Velopack.Util
{
[ExcludeFromCodeCoverage]
internal static class ProcessStartExtensions
{
public static async Task<int> GetExitCodeAsync(this Process p)
{
#if NET5_0_OR_GREATER
await p.WaitForExitAsync().ConfigureAwait(false);
return p.ExitCode;
#else
var tcs = new TaskCompletionSource<int>();
var thread = new Thread(
() => {
try {
p.WaitForExit();
tcs.SetResult(p.ExitCode);
} catch (Exception ex) {
tcs.SetException(ex);
}
});
thread.IsBackground = true;
thread.Start();
await tcs.Task.ConfigureAwait(false);
return p.ExitCode;
#endif
}
#if NET5_0_OR_GREATER
public static void AppendArgumentListSafe(this ProcessStartInfo psi, IEnumerable<string> args, out string debug)

View File

@@ -1,12 +1,11 @@
using System;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles;
namespace Velopack
namespace Velopack.Util
{
internal static class SymbolicLink
{
@@ -28,14 +27,14 @@ namespace Velopack
if (Directory.Exists(linkPath) || File.Exists(linkPath)) {
if (overwrite) {
Utility.DeleteFileOrDirectoryHard(linkPath);
IoUtil.DeleteFileOrDirectoryHard(linkPath);
} else {
throw new IOException("Junction / symlink path already exists and overwrite parameter is false.");
}
}
var finalTarget = relative
? GetRelativePath(Path.GetDirectoryName(linkPath)!, targetPath)
? PathUtil.MakePathRelativeTo(Path.GetDirectoryName(linkPath)!, targetPath)
: targetPath;
if (Directory.Exists(targetPath)) {
@@ -106,7 +105,7 @@ namespace Velopack
var target = GetUnresolvedTarget(linkPath);
if (relative) {
if (Path.IsPathRooted(target)) {
return GetRelativePath(Path.GetDirectoryName(linkPath)!, target);
return PathUtil.MakePathRelativeTo(Path.GetDirectoryName(linkPath)!, target);
} else {
return target;
}
@@ -150,79 +149,8 @@ namespace Velopack
return fsi != null && (fsi.Attributes & FileAttributes.ReparsePoint) != 0;
}
private static string GetRelativePath(string relativeTo, string path)
{
#if NETFRAMEWORK || NETSTANDARD
relativeTo = Path.GetFullPath(relativeTo);
path = Path.GetFullPath(path);
return ToggleRelative(relativeTo, path);
#else
return Path.GetRelativePath(relativeTo, path);
#endif
}
#if NETFRAMEWORK || NETSTANDARD
private static string ToggleRelative(string basePath, string toggledPath)
{
// from https://github.com/RT-Projects/RT.Util/blob/master/RT.Util.Core/Paths/PathUtil.cs#L297
if (basePath.Length == 0)
throw new Exception("InvalidBasePath");
if (toggledPath.Length == 0)
throw new Exception("InvalidToggledPath");
if (!Path.IsPathRooted(basePath))
throw new Exception("BasePathNotAbsolute");
try { basePath = Path.GetFullPath(basePath + "\\"); } catch { throw new Exception("InvalidBasePath"); }
if (!Path.IsPathRooted(toggledPath)) {
try {
return StripTrailingSeparator(Path.GetFullPath(Path.Combine(basePath, toggledPath)));
} catch {
throw new Exception("InvalidToggledPath");
}
}
// Both basePath and toggledPath are absolute. Need to relativize toggledPath.
try { toggledPath = Path.GetFullPath(toggledPath + "\\"); } catch { throw new Exception("InvalidToggledPath"); }
int prevPos = -1;
int pos = toggledPath.IndexOf(Path.DirectorySeparatorChar);
while (pos != -1 && pos < basePath.Length &&
basePath.Substring(0, pos + 1).Equals(toggledPath.Substring(0, pos + 1), StringComparison.OrdinalIgnoreCase)) {
prevPos = pos;
pos = toggledPath.IndexOf(Path.DirectorySeparatorChar, pos + 1);
}
if (prevPos == -1)
throw new Exception("PathsOnDifferentDrives");
var piece = basePath.Substring(prevPos + 1);
var result = StripTrailingSeparator(
(".." + Path.DirectorySeparatorChar).Repeat(piece.Count(ch => ch == Path.DirectorySeparatorChar))
+ toggledPath.Substring(prevPos + 1));
return result.Length == 0 ? "." : result;
}
private static string Repeat(this string input, int numTimes)
{
if (numTimes == 0) return "";
if (numTimes == 1) return input;
if (numTimes == 2) return input + input;
var sb = new StringBuilder();
for (int i = 0; i < numTimes; i++)
sb.Append(input);
return sb.ToString();
}
private static string StripTrailingSeparator(string path)
{
if (path.Length < 1)
return path;
if (path[path.Length - 1] == '/' || path[path.Length - 1] == '\\')
return (path.Length == 3 && path[1] == ':') ? path : path.Substring(0, path.Length - 1);
else
return path;
}
[Flags]
private enum EFileAttributes : uint
{

View File

@@ -0,0 +1,83 @@
using System;
using System.IO;
namespace Velopack.Util
{
internal static class TempUtil
{
public static string GetDefaultTempBaseDirectory()
{
string tempDir;
if (VelopackRuntimeInfo.IsOSX || VelopackRuntimeInfo.IsLinux) {
tempDir = "/tmp/velopack";
} else if (VelopackRuntimeInfo.IsWindows) {
tempDir = Path.Combine(Path.GetTempPath(), "Velopack");
} else {
throw new PlatformNotSupportedException();
}
if (Environment.GetEnvironmentVariable("VELOPACK_TEMP") is var squirrlTmp
&& !string.IsNullOrWhiteSpace(squirrlTmp))
tempDir = squirrlTmp;
var di = new DirectoryInfo(tempDir);
if (!di.Exists) di.Create();
return di.FullName;
}
private static string GetNextTempName(string tempDir)
{
for (int i = 1; i < 1000; i++) {
string name = "temp." + i;
var target = Path.Combine(tempDir, name);
FileSystemInfo? info = null;
if (Directory.Exists(target)) info = new DirectoryInfo(target);
else if (File.Exists(target)) info = new FileInfo(target);
// this dir/file does not exist, lets use it.
if (info == null) {
return target;
}
// this dir/file exists, but it is old, let's re-use it.
// this shouldn't generally happen, but crashes do exist.
if (DateTime.UtcNow - info.LastWriteTimeUtc > TimeSpan.FromDays(1)) {
if (IoUtil.DeleteFileOrDirectoryHard(target, false, true)) {
// the dir/file was deleted successfully.
return target;
}
}
}
throw new Exception(
"Unable to find free temp path. Has the temp directory exceeded it's maximum number of items? (1000)");
}
public static IDisposable GetTempDirectory(out string newTempDirectory)
{
return GetTempDirectory(out newTempDirectory, GetDefaultTempBaseDirectory());
}
public static IDisposable GetTempDirectory(out string newTempDirectory, string rootTempDir)
{
var disp = GetTempFileName(out newTempDirectory, rootTempDir);
Directory.CreateDirectory(newTempDirectory);
return disp;
}
public static IDisposable GetTempFileName(out string newTempFile)
{
return GetTempFileName(out newTempFile, GetDefaultTempBaseDirectory());
}
public static IDisposable GetTempFileName(out string newTempFile, string rootTempDir)
{
var path = GetNextTempName(rootTempDir);
newTempFile = path;
return Disposable.Create(() => IoUtil.DeleteFileOrDirectoryHard(path, throwOnFailure: false));
}
}
}

View File

@@ -7,6 +7,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using NuGet.Versioning;
using Velopack.Locators;
using Velopack.Util;
namespace Velopack
{
@@ -170,7 +171,7 @@ namespace Velopack
log.Info("Starting Velopack App (Run).");
if (VelopackRuntimeInfo.IsWindows && locator.AppId != null) {
var appUserModelId = Utility.GetAppUserModelId(locator.AppId);
var appUserModelId = CoreUtil.GetAppUserModelId(locator.AppId);
log.Info($"Setting current process explicit AppUserModelID to '{appUserModelId}'");
SetCurrentProcessExplicitAppUserModelID(appUserModelId);
}

View File

@@ -2,7 +2,7 @@
using System;
using System.IO;
using NuGet.Versioning;
using Velopack.Json;
using Velopack.Util;
using Velopack.NuGet;
namespace Velopack
@@ -81,8 +81,8 @@ namespace Velopack
NotesMarkdown = zip.ReleaseNotes,
NotesHTML = zip.ReleaseNotesHtml,
Size = new FileInfo(filePath).Length,
SHA1 = Utility.CalculateFileSHA1(filePath),
SHA256 = Utility.CalculateFileSHA256(filePath),
SHA1 = IoUtil.CalculateFileSHA1(filePath),
SHA256 = IoUtil.CalculateFileSHA256(filePath),
FileName = Path.GetFileName(filePath),
Type = IsDeltaFile(filePath) ? VelopackAssetType.Delta : VelopackAssetType.Full,
};

View File

@@ -5,6 +5,7 @@ using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using NuGet.Versioning;
using Velopack.Util;
#if !NETFRAMEWORK
using InteropArchitecture = System.Runtime.InteropServices.Architecture;
@@ -221,7 +222,7 @@ namespace Velopack
try {
if (IsWow64Process2(GetCurrentProcess(), out var _, out var nativeMachine)) {
if (Utility.TryParseEnumU16<RuntimeCpu>(nativeMachine, out var val)) {
if (CoreUtil.TryParseEnumU16<RuntimeCpu>(nativeMachine, out var val)) {
SystemArch = val;
}
}

View File

@@ -11,6 +11,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.Win32;
using NuGet.Versioning;
using Velopack.Sources;
using Velopack.Util;
namespace Velopack.Windows
{
@@ -77,7 +78,7 @@ namespace Velopack.Windows
{
var url = await GetDownloadUrl().ConfigureAwait(false);
log?.Info($"Downloading {Id} from {url} to {localPath}");
downloader = downloader ?? Utility.CreateDefaultDownloader();
downloader = downloader ?? HttpUtil.CreateDefaultDownloader();
await downloader.DownloadFile(url, localPath, progress).ConfigureAwait(false);
}
@@ -319,7 +320,7 @@ namespace Velopack.Windows
var archValid = Enum.TryParse<RuntimeCpu>(String.IsNullOrWhiteSpace(archstr) ? "x64" : archstr, true, out var cpu);
if (!archValid) {
throw new ArgumentException($"Invalid machine architecture '{archstr}'. " +
$"Valid values: {String.Join(", ", Utility.GetEnumValues<RuntimeCpu>())}");
$"Valid values: {String.Join(", ", CoreUtil.GetEnumValues<RuntimeCpu>())}");
}
var type = DotnetRuntimeType.WindowsDesktop;
@@ -404,7 +405,7 @@ namespace Velopack.Windows
_ => throw new NotImplementedException(),
};
downloader = downloader ?? Utility.CreateDefaultDownloader();
downloader = downloader ?? HttpUtil.CreateDefaultDownloader();
try {
return await downloader.DownloadString($"{UncachedDotNetFeed}/{runtime}/{channel}/latest.version").ConfigureAwait(false);

View File

@@ -9,6 +9,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Velopack.Locators;
using Velopack.NuGet;
using Velopack.Util;
namespace Velopack.Windows
{
@@ -165,7 +166,7 @@ namespace Velopack.Windows
Log.Info($"Creating shortcut for {relativeExeName} => {file}");
ShellLink sl;
Utility.Retry(() => {
IoUtil.Retry(() => {
File.Delete(file);
var target = Path.Combine(currentDir, relativeExeName);
@@ -280,7 +281,7 @@ namespace Velopack.Windows
private ShortcutLocation[] GetLocations(ShortcutLocation flag)
{
var locations = Utility.GetEnumValues<ShortcutLocation>();
var locations = CoreUtil.GetEnumValues<ShortcutLocation>();
return locations
.Where(x => x != ShortcutLocation.None)
.Where(x => flag.HasFlag(x))

View File

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

View File

@@ -5,6 +5,7 @@ using Velopack.NuGet;
using Velopack.Packaging;
using Velopack.Packaging.Exceptions;
using Velopack.Sources;
using Velopack.Util;
namespace Velopack.Deployment;
@@ -103,7 +104,7 @@ public class GitHubRepository(ILogger logger) : SourceRepository<GitHubDownloadO
}
// check if there is an existing releasesFile to merge
var releasesFileName = Utility.GetVeloReleaseIndexName(options.Channel);
var releasesFileName = CoreUtil.GetVeloReleaseIndexName(options.Channel);
var releaseAsset = release.Assets.FirstOrDefault(a => a.Name == releasesFileName);
if (releaseAsset != null) {
throw new UserInfoException($"There is already a remote asset named '{releasesFileName}', and merging release files on GitHub is not supported.");

View File

@@ -8,6 +8,7 @@ using Velopack.NuGet;
using Velopack.Packaging;
using Velopack.Packaging.Exceptions;
using Velopack.Sources;
using Velopack.Util;
namespace Velopack.Deployment;
@@ -132,7 +133,7 @@ public class GiteaRepository : SourceRepository<GiteaDownloadOptions, GiteaSourc
}
// check if there is an existing releasesFile to merge
var releasesFileName = Utility.GetVeloReleaseIndexName(options.Channel);
var releasesFileName = CoreUtil.GetVeloReleaseIndexName(options.Channel);
var releaseAsset = release.Assets.FirstOrDefault(a => a.Name == releasesFileName);
if (releaseAsset != null) {
throw new UserInfoException($"There is already a remote asset named '{releasesFileName}', and merging release files on Gitea is not supported.");

View File

@@ -1,6 +1,7 @@
using Microsoft.Extensions.Logging;
using Velopack.Packaging;
using Velopack.Sources;
using Velopack.Util;
namespace Velopack.Deployment;
@@ -26,7 +27,7 @@ public class LocalRepository(ILogger logger) : ObjectRepository<LocalDownloadOpt
{
var target = Path.Combine(client.FullName, key);
Log.Info("Deleting: " + target);
Utility.DeleteFileOrDirectoryHard(target);
IoUtil.DeleteFileOrDirectoryHard(target);
return Task.CompletedTask;
}

View File

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

View File

@@ -1,6 +1,7 @@
using System.Text;
using Microsoft.Extensions.Logging;
using Velopack.Packaging;
using Velopack.Util;
namespace Velopack.Deployment;
@@ -37,7 +38,7 @@ public abstract class ObjectRepository<TDown, TUp, TClient> : DownRepository<TDo
protected override async Task<VelopackAssetFeed> GetReleasesAsync(TDown options)
{
var releasesName = Utility.GetVeloReleaseIndexName(options.Channel);
var releasesName = CoreUtil.GetVeloReleaseIndexName(options.Channel);
var client = CreateClient(options);
var bytes = await GetObjectBytes(client, releasesName);
if (bytes == null || bytes.Length == 0) {
@@ -87,15 +88,15 @@ public abstract class ObjectRepository<TDown, TUp, TClient> : DownRepository<TDo
var newReleaseFeed = new VelopackAssetFeed { Assets = releaseEntries };
using var _1 = Utility.GetTempFileName(out var tmpReleases);
using var _1 = TempUtil.GetTempFileName(out var tmpReleases);
File.WriteAllText(tmpReleases, ReleaseEntryHelper.GetAssetFeedJson(newReleaseFeed));
var releasesName = Utility.GetVeloReleaseIndexName(options.Channel);
var releasesName = CoreUtil.GetVeloReleaseIndexName(options.Channel);
await UploadObject(client, releasesName, new FileInfo(tmpReleases), true, noCache: true);
#pragma warning disable CS0612 // Type or member is obsolete
var legacyKey = Utility.GetReleasesFileName(options.Channel);
var legacyKey = CoreUtil.GetReleasesFileName(options.Channel);
#pragma warning restore CS0612 // Type or member is obsolete
using var _2 = Utility.GetTempFileName(out var tmpReleases2);
using var _2 = TempUtil.GetTempFileName(out var tmpReleases2);
File.WriteAllText(tmpReleases2, ReleaseEntryHelper.GetLegacyMigrationReleaseFeedString(newReleaseFeed));
await UploadObject(client, legacyKey, new FileInfo(tmpReleases2), true, noCache: true);

View File

@@ -3,6 +3,7 @@ using Microsoft.Extensions.Logging;
using Velopack.Packaging;
using Velopack.Packaging.Abstractions;
using Velopack.Sources;
using Velopack.Util;
namespace Velopack.Deployment;
@@ -83,8 +84,8 @@ public abstract class DownRepository<TDown> : IRepositoryCanDownload<TDown>
Log.Warn($"File '{path}' already exists on disk. Verifying checksum...");
bool hashMatch = (latest.SHA256 != null)
? latest.SHA256 == Utility.CalculateFileSHA256(path)
: latest.SHA1 == Utility.CalculateFileSHA1(path);
? latest.SHA256 == IoUtil.CalculateFileSHA256(path)
: latest.SHA1 == IoUtil.CalculateFileSHA1(path);
if (hashMatch) {
Log.Info("Checksum matches. Finished.");
@@ -99,12 +100,12 @@ public abstract class DownRepository<TDown> : IRepositoryCanDownload<TDown>
Log.Info("Verifying checksum...");
string newHash;
if (!string.IsNullOrEmpty(latest.SHA256)) {
if (latest.SHA256 != (newHash = Utility.CalculateFileSHA256(incomplete))) {
if (latest.SHA256 != (newHash = IoUtil.CalculateFileSHA256(incomplete))) {
Log.Error($"Checksum mismatch, expected {latest.SHA256}, got {newHash}");
return;
}
}
else if (latest.SHA1 != (newHash = Utility.CalculateFileSHA1(incomplete))) {
else if (latest.SHA1 != (newHash = IoUtil.CalculateFileSHA1(incomplete))) {
Log.Error($"Checksum mismatch, expected {latest.SHA1}, got {newHash}");
return;
}

View File

@@ -1,6 +1,7 @@
using ICSharpCode.SharpZipLib.Tar;
using ICSharpCode.SharpZipLib.Tar;
using Microsoft.Extensions.Logging;
using Velopack.Compression;
using Velopack.Util;
namespace Velopack.Packaging.Unix;
@@ -81,8 +82,8 @@ public class AppImageTool
Chmod.ChmodFileAsExecutable(outputFile);
} finally {
Utility.DeleteFileOrDirectoryHard(tmpSquashFile);
Utility.DeleteFileOrDirectoryHard(tmpTarFile);
IoUtil.DeleteFileOrDirectoryHard(tmpSquashFile);
IoUtil.DeleteFileOrDirectoryHard(tmpTarFile);
}
}
}

View File

@@ -1,6 +1,7 @@
using ELFSharp.ELF;
using Microsoft.Extensions.Logging;
using Velopack.Packaging.Abstractions;
using Velopack.Util;
namespace Velopack.Packaging.Unix.Commands;

View File

@@ -4,6 +4,7 @@ using Microsoft.Extensions.Logging;
using NuGet.Versioning;
using Velopack.Packaging.Abstractions;
using Velopack.Packaging.Exceptions;
using Velopack.Util;
namespace Velopack.Packaging.Unix.Commands;
@@ -69,7 +70,7 @@ public class OsxBundleCommandRunner : ICommand<OsxBundleOptions>
var builder = new OsxStructureBuilder(packId, releaseDir.FullName);
if (Directory.Exists(builder.AppDirectory)) {
_logger.Warn(builder.AppDirectory + " already exists, deleting...");
Utility.DeleteFileOrDirectoryHard(builder.AppDirectory);
IoUtil.DeleteFileOrDirectoryHard(builder.AppDirectory);
}
builder.Build();

View File

@@ -1,6 +1,7 @@
using System.Runtime.Versioning;
using Microsoft.Extensions.Logging;
using Velopack.Packaging.Abstractions;
using Velopack.Util;
namespace Velopack.Packaging.Unix.Commands;
@@ -27,7 +28,7 @@ public class OsxPackCommandRunner : PackageBuilder<OsxPackOptions>
if (deleteAppBundle) {
Log.Debug("Removing temporary .app bundle.");
Utility.DeleteFileOrDirectoryHard(appBundlePath);
IoUtil.DeleteFileOrDirectoryHard(appBundlePath);
}
var structure = new OsxStructureBuilder(dir.FullName);
@@ -98,7 +99,7 @@ public class OsxPackCommandRunner : PackageBuilder<OsxPackOptions>
var packId = Options.PackId;
if (!string.IsNullOrEmpty(Options.SignInstallIdentity) && !string.IsNullOrEmpty(Options.NotaryProfile)) {
helper.CreateInstallerPkg(packDir, packTitle, packId, pkgContent, pkgPath, Options.SignInstallIdentity, Utility.CreateProgressDelegate(progress, 0, 60));
helper.CreateInstallerPkg(packDir, packTitle, packId, pkgContent, pkgPath, Options.SignInstallIdentity, CoreUtil.CreateProgressDelegate(progress, 0, 60));
progress(-1); // indeterminate
helper.Notarize(pkgPath, Options.NotaryProfile, Options.Keychain);
progress(80);

View File

@@ -1,7 +1,7 @@
using System.Runtime.Versioning;
using System.Security;
using Microsoft.Extensions.Logging;
using Velopack.Json;
using Velopack.Util;
namespace Velopack.Packaging.Unix;
@@ -97,11 +97,11 @@ public class OsxBuildTools
if (File.Exists(pkgOutputPath)) File.Delete(pkgOutputPath);
using var _1 = Utility.GetTempDirectory(out var tmp);
using var _2 = Utility.GetTempDirectory(out var tmpPayload1);
using var _3 = Utility.GetTempDirectory(out var tmpPayload2);
using var _4 = Utility.GetTempDirectory(out var tmpScripts);
using var _5 = Utility.GetTempDirectory(out var tmpResources);
using var _1 = TempUtil.GetTempDirectory(out var tmp);
using var _2 = TempUtil.GetTempDirectory(out var tmpPayload1);
using var _3 = TempUtil.GetTempDirectory(out var tmpPayload2);
using var _4 = TempUtil.GetTempDirectory(out var tmpScripts);
using var _5 = TempUtil.GetTempDirectory(out var tmpResources);
// copy .app to tmp folder
var bundleName = Path.GetFileName(appBundlePath);

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.Util;
namespace Velopack.Packaging.Unix;

View File

@@ -2,6 +2,7 @@
using System.Text.RegularExpressions;
using Microsoft.Extensions.Logging;
using Velopack.Packaging.Exceptions;
using Velopack.Util;
namespace Velopack.Packaging.Windows;
@@ -45,13 +46,13 @@ public class CodeSign
if (String.IsNullOrEmpty(rootDir)) {
pendingSign.Enqueue(f);
} else {
var partialPath = Utility.NormalizePath(f).Substring(Utility.NormalizePath(rootDir).Length).Trim('/', '\\');
var partialPath = PathUtil.NormalizePath(f).Substring(PathUtil.NormalizePath(rootDir).Length).Trim('/', '\\');
pendingSign.Enqueue(partialPath);
}
}
}
using var _1 = Utility.GetTempFileName(out var signLogFile);
using var _1 = TempUtil.GetTempFileName(out var signLogFile);
var totalToSign = pendingSign.Count;
if (signAsTemplate) {

View File

@@ -3,6 +3,7 @@ using Velopack.Compression;
using Velopack.NuGet;
using Velopack.Packaging.Abstractions;
using Velopack.Packaging.Exceptions;
using Velopack.Util;
using Velopack.Windows;
namespace Velopack.Packaging.Windows.Commands;
@@ -17,7 +18,7 @@ public class WindowsPackCommandRunner : PackageBuilder<WindowsPackOptions>
protected override Task CodeSign(Action<int> progress, string packDir)
{
var filesToSign = new DirectoryInfo(packDir).GetAllFilesRecursively()
.Where(x => Options.SignSkipDll ? Utility.PathPartEndsWith(x.Name, ".exe") : Utility.FileIsLikelyPEImage(x.Name))
.Where(x => Options.SignSkipDll ? PathUtil.PathPartEndsWith(x.Name, ".exe") : PathUtil.FileIsLikelyPEImage(x.Name))
.Select(x => x.FullName)
.ToArray();
@@ -37,7 +38,7 @@ public class WindowsPackCommandRunner : PackageBuilder<WindowsPackOptions>
// add nuspec metadata
ExtraNuspecMetadata["runtimeDependencies"] = GetRuntimeDependencies();
ExtraNuspecMetadata["shortcutLocations"] = GetShortcutLocations();
ExtraNuspecMetadata["shortcutAmuid"] = Utility.GetAppUserModelId(Options.PackId);
ExtraNuspecMetadata["shortcutAmuid"] = CoreUtil.GetAppUserModelId(Options.PackId);
// copy files to temp dir, so we can modify them
var dir = TempDir.CreateSubdirectory("PreprocessPackDirWin");
@@ -173,7 +174,7 @@ public class WindowsPackCommandRunner : PackageBuilder<WindowsPackOptions>
protected override Task CreateSetupPackage(Action<int> progress, string releasePkg, string packDir, string targetSetupExe)
{
var bundledZip = new ZipPackage(releasePkg);
Utility.Retry(() => File.Copy(HelperFile.SetupPath, targetSetupExe, true));
IoUtil.Retry(() => File.Copy(HelperFile.SetupPath, targetSetupExe, true));
progress(10);
var editor = new ResourceEdit(targetSetupExe, Log);
@@ -189,7 +190,7 @@ public class WindowsPackCommandRunner : PackageBuilder<WindowsPackOptions>
progress(50);
Log.Debug("Signing Setup bundle");
var targetDir = Path.GetDirectoryName(targetSetupExe);
SignFilesImpl(Options, targetDir, Utility.CreateProgressDelegate(progress, 50, 100), targetSetupExe);
SignFilesImpl(Options, targetDir, CoreUtil.CreateProgressDelegate(progress, 50, 100), targetSetupExe);
Log.Debug($"Setup bundle created '{Path.GetFileName(targetSetupExe)}'.");
progress(100);
return Task.CompletedTask;
@@ -201,7 +202,7 @@ public class WindowsPackCommandRunner : PackageBuilder<WindowsPackOptions>
File.Copy(Path.Combine(packDir, "Squirrel.exe"), Path.Combine(dir.FullName, "Update.exe"), true);
var current = dir.CreateSubdirectory("current");
CopyFiles(new DirectoryInfo(packDir), current, Utility.CreateProgressDelegate(progress, 0, 30));
CopyFiles(new DirectoryInfo(packDir), current, CoreUtil.CreateProgressDelegate(progress, 0, 30));
File.Delete(Path.Combine(current.FullName, "Squirrel.exe"));
@@ -214,7 +215,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, Utility.CreateProgressDelegate(progress, 40, 100));
await EasyZip.CreateZipFromDirectoryAsync(Log, outputPath, dir.FullName, CoreUtil.CreateProgressDelegate(progress, 40, 100));
progress(100);
}
@@ -233,7 +234,7 @@ public class WindowsPackCommandRunner : PackageBuilder<WindowsPackOptions>
}
try {
Utility.Retry(() => File.Copy(HelperFile.StubExecutablePath, targetStubPath, true));
IoUtil.Retry(() => File.Copy(HelperFile.StubExecutablePath, targetStubPath, true));
var edit = new ResourceEdit(targetStubPath, Log);
edit.CopyResourcesFrom(exeToCopy);
edit.Commit();

View File

@@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging;
using NuGet.Versioning;
using Velopack.Packaging.Abstractions;
using Velopack.Packaging.Exceptions;
using Velopack.Util;
namespace Velopack.Packaging.Windows;

View File

@@ -7,6 +7,7 @@ using AsmResolver.PE.Win32Resources.Icon;
using AsmResolver.PE.Win32Resources.Version;
using Microsoft.Extensions.Logging;
using Velopack.NuGet;
using Velopack.Util;
namespace Velopack.Packaging.Windows;
@@ -181,7 +182,7 @@ public class ResourceEdit
_file.OptionalHeader.SetDataDirectory(DataDirectoryIndex.ResourceDirectory,
new DataDirectory(resourceBuffer.Rva, resourceBuffer.GetPhysicalSize()));
Utility.Retry(() => {
IoUtil.Retry(() => {
using var fs = File.Create(_exePath);
_file.Write(fs);
});

View File

@@ -1,4 +1,5 @@
using System.IO.MemoryMappedFiles;
using Velopack.Util;
namespace Velopack.Packaging.Windows;
@@ -31,7 +32,7 @@ public static class SetupBundle
length = accessor.ReadInt64(position - 8);
}
Utility.Retry(FindBundleHeader);
IoUtil.Retry(FindBundleHeader);
bundleOffset = offset;
bundleLength = length;
@@ -45,8 +46,8 @@ public static class SetupBundle
Stream pkgStream = null, setupStream = null;
try {
pkgStream = Utility.Retry(() => File.OpenRead(packagePath), retries: 10);
setupStream = Utility.Retry(() => File.Open(setupPath, FileMode.Append, FileAccess.Write), retries: 10);
pkgStream = IoUtil.Retry(() => File.OpenRead(packagePath), retries: 10);
setupStream = IoUtil.Retry(() => File.Open(setupPath, FileMode.Append, FileAccess.Write), retries: 10);
bundleOffset = setupStream.Position;
bundleLength = pkgStream.Length;
pkgStream.CopyTo(setupStream);

View File

@@ -1,5 +1,4 @@
using Velopack.Json;
using Velopack.Packaging.Exceptions;
using Velopack.Packaging.Exceptions;
namespace Velopack.Packaging;

View File

@@ -2,6 +2,7 @@
using Velopack.Compression;
using Velopack.Packaging.Exceptions;
using Velopack.Packaging.Abstractions;
using Velopack.Util;
namespace Velopack.Packaging.Commands;
@@ -28,8 +29,8 @@ public class DeltaPatchCommandRunner : ICommand<DeltaPatchOptions>
}
}
var tmp = Utility.GetDefaultTempBaseDirectory();
using var _1 = Utility.GetTempDirectory(out var workDir);
var tmp = TempUtil.GetDefaultTempBaseDirectory();
using var _1 = TempUtil.GetTempDirectory(out var workDir);
var delta = new DeltaEmbedded(HelperFile.GetZstdPath(), _logger, tmp);
EasyZip.ExtractZipToDirectory(_logger, options.BasePackage, workDir);

View File

@@ -3,6 +3,7 @@ using System.Text;
using Microsoft.Extensions.Logging;
using Velopack.Compression;
using Velopack.Packaging.Exceptions;
using Velopack.Util;
namespace Velopack.Packaging;
@@ -61,8 +62,8 @@ public class DeltaPackageBuilder
int fNew = 0, fSame = 0, fChanged = 0, fWarnings = 0, fProcessed = 0, fRemoved = 0;
using (Utility.GetTempDirectory(out var baseTempPath))
using (Utility.GetTempDirectory(out var tempPath)) {
using (TempUtil.GetTempDirectory(out var baseTempPath))
using (TempUtil.GetTempDirectory(out var tempPath)) {
var baseTempInfo = new DirectoryInfo(baseTempPath);
var tempInfo = new DirectoryInfo(tempPath);
@@ -139,12 +140,12 @@ public class DeltaPackageBuilder
targetFile.Delete();
baseLibFiles.Remove(relativePath);
var p = Interlocked.Increment(ref fProcessed);
progress(Utility.CalculateProgress((int) ((double) p / numNewFiles * 100), 0, 70));
progress(CoreUtil.CalculateProgress((int) ((double) p / numNewFiles * 100), 0, 70));
} catch (Exception ex) {
_logger.Debug(ex, String.Format("Failed to create a delta for {0}", targetFile.Name));
Utility.DeleteFileOrDirectoryHard(targetFile.FullName + ".bsdiff", throwOnFailure: false);
Utility.DeleteFileOrDirectoryHard(targetFile.FullName + ".diff", throwOnFailure: false);
Utility.DeleteFileOrDirectoryHard(targetFile.FullName + ".shasum", throwOnFailure: false);
IoUtil.DeleteFileOrDirectoryHard(targetFile.FullName + ".bsdiff", throwOnFailure: false);
IoUtil.DeleteFileOrDirectoryHard(targetFile.FullName + ".diff", throwOnFailure: false);
IoUtil.DeleteFileOrDirectoryHard(targetFile.FullName + ".shasum", throwOnFailure: false);
Interlocked.Increment(ref fWarnings);
throw;
}
@@ -179,7 +180,7 @@ public class DeltaPackageBuilder
throw new UserInfoException("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, Utility.CreateProgressDelegate(progress, 70, 100)).GetAwaiterResult();
EasyZip.CreateZipFromDirectoryAsync(_logger, outputFile, tempInfo.FullName, CoreUtil.CreateProgressDelegate(progress, 70, 100)).GetAwaiterResult();
progress(100);
fRemoved = baseLibFiles.Count;

View File

@@ -1,6 +1,7 @@
using System.Diagnostics;
using System.Text;
using Velopack.Packaging.Exceptions;
using Velopack.Util;
namespace Velopack.Packaging;
@@ -38,7 +39,7 @@ public static class Exe
public static string RunHostedCommand(string command, string workDir = null)
{
using var _1 = Utility.GetTempFileName(out var outputFile);
using var _1 = TempUtil.GetTempFileName(out var outputFile);
File.Create(outputFile).Close();
var fileName = "cmd.exe";
@@ -64,7 +65,7 @@ public static class Exe
process.WaitForExit();
var stdout = Utility.Retry(() => File.ReadAllText(outputFile).Trim(), 10, 1000);
var stdout = IoUtil.Retry(() => File.ReadAllText(outputFile).Trim(), 10, 1000);
var result = (process.ExitCode, stdout, "", command);
ProcessFailedException.ThrowIfNonZero(result);
return result.Item2;
@@ -72,7 +73,7 @@ public static class Exe
public static void RunHostedCommandNoWait(string command, string workDir = null)
{
using var _1 = Utility.GetTempFileName(out var outputFile);
using var _1 = TempUtil.GetTempFileName(out var outputFile);
File.Create(outputFile).Close();
var fileName = "cmd.exe";

View File

@@ -8,6 +8,7 @@ using Velopack.Compression;
using Velopack.NuGet;
using Velopack.Packaging.Abstractions;
using Velopack.Packaging.Exceptions;
using Velopack.Util;
namespace Velopack.Packaging;
@@ -90,7 +91,7 @@ public abstract class PackageBuilder<T> : ICommand<T>
MainExePath = mainExePath;
options.EntryExecutableName = Path.GetFileName(mainExePath);
using var _1 = Utility.GetTempDirectory(out var pkgTempDir);
using var _1 = TempUtil.GetTempDirectory(out var pkgTempDir);
TempDir = new DirectoryInfo(pkgTempDir);
Options = options;
@@ -158,7 +159,7 @@ public abstract class PackageBuilder<T> : ICommand<T>
await ctx.RunTask("Post-process steps", (progress) => {
foreach (var f in filesToCopy) {
Utility.MoveFile(f.from, f.to, true);
IoUtil.MoveFile(f.from, f.to, true);
}
ReleaseEntryHelper.UpdateReleaseFiles(releaseDir.FullName, Log);
@@ -261,7 +262,7 @@ public abstract class PackageBuilder<T> : ICommand<T>
File.WriteAllText(nuspecPath, GenerateNuspecContent());
var appDir = stagingDir.CreateSubdirectory("lib").CreateSubdirectory("app");
CopyFiles(new DirectoryInfo(packDir), appDir, Utility.CreateProgressDelegate(progress, 0, 30));
CopyFiles(new DirectoryInfo(packDir), appDir, CoreUtil.CreateProgressDelegate(progress, 0, 30));
var metadataFiles = GetReleaseMetadataFiles();
foreach (var kvp in metadataFiles) {
@@ -270,7 +271,7 @@ public abstract class PackageBuilder<T> : ICommand<T>
AddContentTypesAndRel(nuspecPath);
await EasyZip.CreateZipFromDirectoryAsync(Log, outputPath, stagingDir.FullName, Utility.CreateProgressDelegate(progress, 30, 100));
await EasyZip.CreateZipFromDirectoryAsync(Log, outputPath, stagingDir.FullName, CoreUtil.CreateProgressDelegate(progress, 30, 100));
progress(100);
}

View File

@@ -1,8 +1,8 @@
using System.Text;
using Microsoft.Extensions.Logging;
using NuGet.Versioning;
using Velopack.Json;
using Velopack.NuGet;
using Velopack.Util;
namespace Velopack.Packaging;
@@ -64,7 +64,7 @@ public class ReleaseEntryHelper
{
var releases = _releases.ContainsKey(_channel) ? _releases[_channel] : null;
if (releases == null || !releases.Any()) return null;
return releases.Where(z => z.Type == VelopackAssetType.Full).MaxBy(z => z.Version).First();
return releases.Where(z => z.Type == VelopackAssetType.Full).MaxByPolyfill(z => z.Version).First();
}
public IEnumerable<VelopackAsset> GetLatestAssets()
@@ -72,7 +72,7 @@ public class ReleaseEntryHelper
if (!_releases.ContainsKey(_channel) || !_releases[_channel].Any())
return Enumerable.Empty<VelopackAsset>();
var latest = _releases[_channel].MaxBy(x => x.Version).First();
var latest = _releases[_channel].MaxByPolyfill(x => x.Version).First();
_logger.Info($"Latest release: {latest.FileName}");
var assets = _releases[_channel]
@@ -102,9 +102,8 @@ public class ReleaseEntryHelper
}
// We write a legacy RELEASES file to allow older applications to update to velopack
#pragma warning disable CS0612 // Type or member is obsolete
#pragma warning disable CS0618 // Type or member is obsolete
var name = Utility.GetReleasesFileName(kvp.Key);
var name = CoreUtil.GetReleasesFileName(kvp.Key);
var path = Path.Combine(outputDir, name);
ReleaseEntry.WriteReleaseFile(
@@ -114,9 +113,8 @@ public class ReleaseEntryHelper
.Where(entry => !entry.IsDelta),
path);
#pragma warning restore CS0618 // Type or member is obsolete
#pragma warning restore CS0612 // Type or member is obsolete
var indexPath = Path.Combine(outputDir, Utility.GetVeloReleaseIndexName(kvp.Key));
var indexPath = Path.Combine(outputDir, CoreUtil.GetVeloReleaseIndexName(kvp.Key));
var feed = new VelopackAssetFeed() {
Assets = kvp.Value.OrderByDescending(v => v.Version).ThenBy(v => v.Type).ToArray(),
};

View File

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

View File

@@ -1,6 +1,7 @@
using System.Threading;
using Spectre.Console;
using Velopack.Packaging.Abstractions;
using Velopack.Util;
namespace Velopack.Vpk.Logging;

View File

@@ -1,4 +1,4 @@
using System.ComponentModel;
using System.ComponentModel;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
@@ -12,6 +12,7 @@ using Velopack.Packaging.Exceptions;
using Velopack.Packaging.Flow;
using Velopack.Packaging.Unix.Commands;
using Velopack.Packaging.Windows.Commands;
using Velopack.Util;
using Velopack.Vpk.Commands;
using Velopack.Vpk.Commands.Deployment;
using Velopack.Vpk.Commands.Flow;

View File

@@ -1,5 +1,6 @@
using System.Threading;
using NuGet.Protocol.Core.Types;
using Velopack.Util;
namespace Velopack.Vpk.Updates;

View File

@@ -1,4 +1,5 @@
using System.CommandLine;
using Velopack.Util;
using Velopack.Vpk.Commands.Deployment;
namespace Velopack.CommandLine.Tests.Commands;
@@ -9,7 +10,7 @@ public class LocalDownloadCommandTests : BaseCommandTests<LocalDownloadCommand>
{
var command = new LocalDownloadCommand();
using var _1 = Utility.GetTempDirectory(out var releaseDir);
using var _1 = TempUtil.GetTempDirectory(out var releaseDir);
File.Create(Path.Combine(releaseDir, "test.txt")).Close();
ParseResult parseResult = command.ParseAndApply($"--path {releaseDir}");
@@ -22,7 +23,7 @@ public class LocalDownloadCommandTests : BaseCommandTests<LocalDownloadCommand>
public void Path_WithEmptyPath_ParsesValue()
{
var command = new LocalDownloadCommand();
using var _1 = Utility.GetTempDirectory(out var releaseDir);
using var _1 = TempUtil.GetTempDirectory(out var releaseDir);
ParseResult parseResult = command.ParseAndApply($"--path {releaseDir}");

View File

@@ -1,6 +1,7 @@
using NuGet.Versioning;
using Velopack.Deployment;
using Velopack.Sources;
using Velopack.Util;
namespace Velopack.Packaging.Tests;
@@ -23,7 +24,7 @@ public class AzureDeploymentTests
{
Skip.If(String.IsNullOrWhiteSpace(AZ_KEY), "VELOPACK_AZ_TEST_TOKEN is not set.");
using var logger = _output.BuildLoggerFor<S3DeploymentTests>();
using var _1 = Utility.GetTempDirectory(out var releaseDir);
using var _1 = TempUtil.GetTempDirectory(out var releaseDir);
string channel = String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("CI"))
? VelopackRuntimeInfo.SystemOs.GetOsShortName()

View File

@@ -1,6 +1,7 @@
using Neovolve.Logging.Xunit;
using Velopack.Packaging.Exceptions;
using Velopack.Packaging.Windows;
using Velopack.Util;
using Velopack.Vpk;
using Velopack.Vpk.Logging;
@@ -35,7 +36,7 @@ public class CompatUtilTests
{
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
using var logger = GetCompat(out var compat);
using var _1 = Utility.GetTempDirectory(out var dir);
using var _1 = TempUtil.GetTempDirectory(out var dir);
var sample = PathHelper.GetAvaloniaSample();
Exe.InvokeAndThrowIfNonZero(
"dotnet",
@@ -56,7 +57,7 @@ public class CompatUtilTests
{
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
using var logger = GetCompat(out var compat);
using var _1 = Utility.GetTempDirectory(out var dir);
using var _1 = TempUtil.GetTempDirectory(out var dir);
var sample = PathHelper.GetAvaloniaSample();
Exe.InvokeAndThrowIfNonZero(
"dotnet",
@@ -77,7 +78,7 @@ public class CompatUtilTests
{
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
using var logger = GetCompat(out var compat);
using var _1 = Utility.GetTempDirectory(out var dir);
using var _1 = TempUtil.GetTempDirectory(out var dir);
var sample = PathHelper.GetWpfSample();
Exe.InvokeAndThrowIfNonZero(
"dotnet",
@@ -97,7 +98,7 @@ public class CompatUtilTests
{
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
using var logger = GetCompat(out var compat);
using var _1 = Utility.GetTempDirectory(out var dir);
using var _1 = TempUtil.GetTempDirectory(out var dir);
var sample = PathHelper.GetTestRootPath("TestApp");
Exe.InvokeAndThrowIfNonZero(
"dotnet",
@@ -114,7 +115,7 @@ public class CompatUtilTests
{
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
using var logger = GetCompat(out var compat);
using var _1 = Utility.GetTempDirectory(out var dir);
using var _1 = TempUtil.GetTempDirectory(out var dir);
var sample = PathHelper.GetTestRootPath("TestApp");
Exe.InvokeAndThrowIfNonZero(
"dotnet",

View File

@@ -1,4 +1,5 @@
using Velopack.Packaging.Unix;
using Velopack.Util;
namespace Velopack.Packaging.Tests;
@@ -20,7 +21,7 @@ public class CrossCompile
var rid = RID.Parse(target);
string id = $"from-{VelopackRuntimeInfo.SystemOs.GetOsShortName()}-targets-{rid.BaseRID.GetOsShortName()}";
using var _1 = Utility.GetTempDirectory(out var tempDir);
using var _1 = TempUtil.GetTempDirectory(out var tempDir);
TestApp.PackTestApp(id, "1.0.0", id, tempDir, logger, targetRid: rid);
var artifactsDir = PathHelper.GetTestRootPath("artifacts");
@@ -84,7 +85,7 @@ public class CrossCompile
var appExe = Path.Combine(appRoot, "current", "TestApp.exe");
var appUpdate = Path.Combine(appRoot, "Update.exe");
Utility.DeleteFileOrDirectoryHard(appRoot);
IoUtil.DeleteFileOrDirectoryHard(appRoot);
Assert.False(File.Exists(appExe));
@@ -102,6 +103,6 @@ public class CrossCompile
Assert.False(File.Exists(appExe));
Assert.True(File.Exists(Path.Combine(appRoot, ".dead")));
Utility.DeleteFileOrDirectoryHard(appRoot);
IoUtil.DeleteFileOrDirectoryHard(appRoot);
}
}

View File

@@ -2,6 +2,7 @@
using Velopack.Sources;
using Octokit;
using Velopack.Packaging.Exceptions;
using Velopack.Util;
namespace Velopack.Packaging.Tests;
@@ -22,8 +23,8 @@ public class GithubDeploymentTests
{
Skip.If(String.IsNullOrWhiteSpace(GITHUB_TOKEN), "VELOPACK_GITHUB_TEST_TOKEN is not set.");
using var logger = _output.BuildLoggerFor<GithubDeploymentTests>();
using var _1 = Utility.GetTempDirectory(out var releaseDir);
using var _2 = Utility.GetTempDirectory(out var releaseDir2);
using var _1 = TempUtil.GetTempDirectory(out var releaseDir);
using var _2 = TempUtil.GetTempDirectory(out var releaseDir2);
using var ghvar = GitHubReleaseTest.Create("nomerge", logger);
var id = "GithubUpdateTest";
TestApp.PackTestApp(id, $"0.0.1-{ghvar.UniqueSuffix}", "t1", releaseDir, logger);
@@ -51,8 +52,8 @@ public class GithubDeploymentTests
{
Skip.If(String.IsNullOrWhiteSpace(GITHUB_TOKEN), "VELOPACK_GITHUB_TEST_TOKEN is not set.");
using var logger = _output.BuildLoggerFor<GithubDeploymentTests>();
using var _1 = Utility.GetTempDirectory(out var releaseDir);
using var _2 = Utility.GetTempDirectory(out var releaseDir2);
using var _1 = TempUtil.GetTempDirectory(out var releaseDir);
using var _2 = TempUtil.GetTempDirectory(out var releaseDir2);
using var ghvar = GitHubReleaseTest.Create("mixmatched", logger);
var id = "GithubUpdateTest";
TestApp.PackTestApp(id, $"0.0.1-{ghvar.UniqueSuffix}", "t1", releaseDir, logger);
@@ -81,8 +82,8 @@ public class GithubDeploymentTests
{
Skip.If(String.IsNullOrWhiteSpace(GITHUB_TOKEN), "VELOPACK_GITHUB_TEST_TOKEN is not set.");
using var logger = _output.BuildLoggerFor<GithubDeploymentTests>();
using var _1 = Utility.GetTempDirectory(out var releaseDir);
using var _2 = Utility.GetTempDirectory(out var releaseDir2);
using var _1 = TempUtil.GetTempDirectory(out var releaseDir);
using var _2 = TempUtil.GetTempDirectory(out var releaseDir2);
using var ghvar = GitHubReleaseTest.Create("yesmerge", logger);
var id = "GithubUpdateTest";
TestApp.PackTestApp(id, $"0.0.1-{ghvar.UniqueSuffix}", "t1", releaseDir, logger);
@@ -114,7 +115,7 @@ public class GithubDeploymentTests
Skip.If(String.IsNullOrWhiteSpace(GITHUB_TOKEN), "VELOPACK_GITHUB_TEST_TOKEN is not set.");
using var logger = _output.BuildLoggerFor<GithubDeploymentTests>();
var id = "GithubUpdateTest";
using var _1 = Utility.GetTempDirectory(out var releaseDir);
using var _1 = TempUtil.GetTempDirectory(out var releaseDir);
var (repoOwner, repoName) = GitHubRepository.GetOwnerAndRepo(GITHUB_REPOURL);
using var ghvar = GitHubReleaseTest.Create("integration", logger);
var releaseName = ghvar.ReleaseName;
@@ -172,7 +173,7 @@ This is just a _test_!
Assert.Equal(newVer, r.Version.ToNormalizedString());
}
using var _2 = Utility.GetTempDirectory(out var releaseDirNew);
using var _2 = TempUtil.GetTempDirectory(out var releaseDirNew);
gh.DownloadLatestFullPackageAsync(new GitHubDownloadOptions {
Token = GITHUB_TOKEN,
RepoUrl = GITHUB_REPOURL,
@@ -189,7 +190,7 @@ This is just a _test_!
{
Skip.If(String.IsNullOrWhiteSpace(GITHUB_TOKEN), "VELOPACK_GITHUB_TEST_TOKEN is not set.");
using var logger = _output.BuildLoggerFor<GithubDeploymentTests>();
using var _1 = Utility.GetTempDirectory(out var releaseDir);
using var _1 = TempUtil.GetTempDirectory(out var releaseDir);
using var ghvar = GitHubReleaseTest.Create("targetCommitish", logger, true);
var (repoOwner, repoName) = GitHubRepository.GetOwnerAndRepo(GITHUB_REPOURL);
var id = "GithubUpdateTest";
@@ -225,7 +226,7 @@ This is just a _test_!
{
Skip.If(String.IsNullOrWhiteSpace(GITHUB_TOKEN), "VELOPACK_GITHUB_TEST_TOKEN is not set.");
using var logger = _output.BuildLoggerFor<GithubDeploymentTests>();
using var _1 = Utility.GetTempDirectory(out var releaseDir);
using var _1 = TempUtil.GetTempDirectory(out var releaseDir);
using var ghvar = GitHubReleaseTest.Create("targetCommitish", logger, true);
var (repoOwner, repoName) = GitHubRepository.GetOwnerAndRepo(GITHUB_REPOURL);
var id = "GithubUpdateTest";

View File

@@ -1,5 +1,6 @@
using System.Runtime.Versioning;
using Velopack.Compression;
using Velopack.Util;
namespace Velopack.Packaging.Tests;
@@ -20,9 +21,9 @@ public class OsxPackTests
using var logger = _output.BuildLoggerFor<OsxPackTests>();
using var _1 = Utility.GetTempDirectory(out var tmpOutput);
using var _2 = Utility.GetTempDirectory(out var tmpReleaseDir);
using var _3 = Utility.GetTempDirectory(out var unzipDir);
using var _1 = TempUtil.GetTempDirectory(out var tmpOutput);
using var _2 = TempUtil.GetTempDirectory(out var tmpReleaseDir);
using var _3 = TempUtil.GetTempDirectory(out var unzipDir);
const string id = "MyAppId";
const string title = "MyAppTitle";

View File

@@ -8,6 +8,7 @@ using AsmResolver.PE.Win32Resources.Icon;
using AsmResolver.PE.Win32Resources.Version;
using Velopack.NuGet;
using Velopack.Packaging.Windows;
using Velopack.Util;
namespace Velopack.Packaging.Tests;
@@ -37,7 +38,7 @@ public class ResourceEditTests
public void CommitResourcesInCorrectOrder()
{
using var logger = _output.BuildLoggerFor<ResourceEditTests>();
using var _1 = Utility.GetTempFileName(out var tempFile);
using var _1 = TempUtil.GetTempFileName(out var tempFile);
var exe = PathHelper.GetRustAsset("setup.exe");
File.Copy(exe, tempFile);
@@ -65,7 +66,7 @@ public class ResourceEditTests
{
using var logger = _output.BuildLoggerFor<ResourceEditTests>();
using var _1 = Utility.GetTempFileName(out var tempFile);
using var _1 = TempUtil.GetTempFileName(out var tempFile);
CreateTestPEFileWithoutRsrc(tempFile);
var edit = new ResourceEdit(tempFile, logger);
@@ -81,7 +82,7 @@ public class ResourceEditTests
{
using var logger = _output.BuildLoggerFor<ResourceEditTests>();
using var _1 = Utility.GetTempFileName(out var tempFile);
using var _1 = TempUtil.GetTempFileName(out var tempFile);
var exe = PathHelper.GetFixture("SquirrelAwareTweakedNetCoreApp.exe");
File.Copy(exe, tempFile);
@@ -98,7 +99,7 @@ public class ResourceEditTests
{
using var logger = _output.BuildLoggerFor<ResourceEditTests>();
using var _1 = Utility.GetTempFileName(out var tempFile);
using var _1 = TempUtil.GetTempFileName(out var tempFile);
var exe = PathHelper.GetFixture("atom.exe");
File.Copy(exe, tempFile);
@@ -125,7 +126,7 @@ public class ResourceEditTests
{
using var logger = _output.BuildLoggerFor<ResourceEditTests>();
using var _1 = Utility.GetTempFileName(out var tempFile);
using var _1 = TempUtil.GetTempFileName(out var tempFile);
CreateTestPEFileWithoutRsrc(tempFile);
var beforeRsrc = PEImage.FromFile(PEFile.FromFile(tempFile)).Resources;
@@ -146,7 +147,7 @@ public class ResourceEditTests
public void SetVersionInfoWithPreExistingRsrc()
{
using var logger = _output.BuildLoggerFor<ResourceEditTests>();
using var _1 = Utility.GetTempFileName(out var tempFile);
using var _1 = TempUtil.GetTempFileName(out var tempFile);
var exe = PathHelper.GetFixture("atom.exe");
File.Copy(exe, tempFile);
@@ -165,7 +166,7 @@ public class ResourceEditTests
public void SetVersionInfoWithoutRsrc()
{
using var logger = _output.BuildLoggerFor<ResourceEditTests>();
using var _1 = Utility.GetTempFileName(out var tempFile);
using var _1 = TempUtil.GetTempFileName(out var tempFile);
CreateTestPEFileWithoutRsrc(tempFile);
var nuspec = PathHelper.GetFixture("FullNuspec.nuspec");

View File

@@ -1,6 +1,7 @@
using NuGet.Versioning;
using Velopack.Deployment;
using Velopack.Sources;
using Velopack.Util;
namespace Velopack.Packaging.Tests;
@@ -23,7 +24,7 @@ public class S3DeploymentTests
{
Skip.If(String.IsNullOrWhiteSpace(B2_SECRET), "VELOPACK_B2_TEST_TOKEN is not set.");
using var logger = _output.BuildLoggerFor<S3DeploymentTests>();
using var _1 = Utility.GetTempDirectory(out var releaseDir);
using var _1 = TempUtil.GetTempDirectory(out var releaseDir);
string channel = String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("CI"))
? VelopackRuntimeInfo.SystemOs.GetOsShortName()

View File

@@ -1,7 +1,6 @@
using System.Text.Json.Serialization;
using System.Text.Json;
using NuGet.Versioning;
using Velopack.Json;
using Velopack.Packaging;
using Velopack.Sources;
using JsonPropertyNameAttribute = System.Text.Json.Serialization.JsonPropertyNameAttribute;

View File

@@ -1,6 +1,7 @@
using System.Diagnostics;
using Velopack.Packaging.Unix.Commands;
using Velopack.Packaging.Windows.Commands;
using Velopack.Util;
using Velopack.Vpk;
using Velopack.Vpk.Logging;

View File

@@ -8,6 +8,7 @@ using Velopack.Compression;
using Velopack.Packaging.Commands;
using Velopack.Packaging.Exceptions;
using Velopack.Packaging.Windows.Commands;
using Velopack.Util;
using Velopack.Vpk;
using Velopack.Vpk.Logging;
using Velopack.Windows;
@@ -37,9 +38,9 @@ public class WindowsPackTests
using var logger = _output.BuildLoggerFor<WindowsPackTests>();
using var _1 = Utility.GetTempDirectory(out var tmpOutput);
using var _2 = Utility.GetTempDirectory(out var tmpReleaseDir);
using var _3 = Utility.GetTempDirectory(out var unzipDir);
using var _1 = TempUtil.GetTempDirectory(out var tmpOutput);
using var _2 = TempUtil.GetTempDirectory(out var tmpReleaseDir);
using var _3 = TempUtil.GetTempDirectory(out var unzipDir);
var exe = "testapp.exe";
var pdb = Path.ChangeExtension(exe, ".pdb");
@@ -106,8 +107,8 @@ public class WindowsPackTests
using var logger = _output.BuildLoggerFor<WindowsPackTests>();
using var _1 = Utility.GetTempDirectory(out var tmpOutput);
using var _2 = Utility.GetTempDirectory(out var tmpReleaseDir);
using var _1 = TempUtil.GetTempDirectory(out var tmpOutput);
using var _2 = TempUtil.GetTempDirectory(out var tmpReleaseDir);
var exe = "testapp.exe";
var pdb = Path.ChangeExtension(exe, ".pdb");
@@ -139,8 +140,8 @@ public class WindowsPackTests
using var logger = _output.BuildLoggerFor<WindowsPackTests>();
using var _1 = Utility.GetTempDirectory(out var tmpOutput);
using var _2 = Utility.GetTempDirectory(out var tmpReleaseDir);
using var _1 = TempUtil.GetTempDirectory(out var tmpOutput);
using var _2 = TempUtil.GetTempDirectory(out var tmpReleaseDir);
var exe = "testapp.exe";
var pdb = Path.ChangeExtension(exe, ".pdb");
@@ -177,9 +178,9 @@ public class WindowsPackTests
using var logger = _output.BuildLoggerFor<WindowsPackTests>();
using var _1 = Utility.GetTempDirectory(out var tmpOutput);
using var _2 = Utility.GetTempDirectory(out var tmpReleaseDir);
using var _3 = Utility.GetTempDirectory(out var tmpInstallDir);
using var _1 = TempUtil.GetTempDirectory(out var tmpOutput);
using var _2 = TempUtil.GetTempDirectory(out var tmpReleaseDir);
using var _3 = TempUtil.GetTempDirectory(out var tmpInstallDir);
var exe = "testapp.exe";
var pdb = Path.ChangeExtension(exe, ".pdb");
@@ -260,8 +261,8 @@ public class WindowsPackTests
{
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
using var logger = _output.BuildLoggerFor<WindowsPackTests>();
using var _1 = Utility.GetTempDirectory(out var releaseDir);
using var _2 = Utility.GetTempDirectory(out var installDir);
using var _1 = TempUtil.GetTempDirectory(out var releaseDir);
using var _2 = TempUtil.GetTempDirectory(out var installDir);
string id = "SquirrelAutoUpdateTest";
var appPath = Path.Combine(installDir, "current", "TestApp.exe");
@@ -293,7 +294,7 @@ public class WindowsPackTests
[SkippableFact]
public void TestPackGeneratesValidDelta()
{
using var _1 = Utility.GetTempDirectory(out var releaseDir);
using var _1 = TempUtil.GetTempDirectory(out var releaseDir);
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
using var logger = _output.BuildLoggerFor<WindowsPackTests>();
string id = "SquirrelDeltaTest";
@@ -304,7 +305,7 @@ public class WindowsPackTests
// did a zsdiff get created for our v2 update?
var deltaPath = Path.Combine(releaseDir, $"{id}-2.0.0-delta.nupkg");
Assert.True(File.Exists(deltaPath));
using var _2 = Utility.GetTempDirectory(out var extractDir);
using var _2 = TempUtil.GetTempDirectory(out var extractDir);
EasyZip.ExtractZipToDirectory(logger, deltaPath, extractDir);
var extractDllDiff = Path.Combine(extractDir, "lib", "app", "testapp.dll.zsdiff");
var extractDllShasum = Path.Combine(extractDir, "lib", "app", "testapp.dll.shasum");
@@ -366,8 +367,8 @@ public class WindowsPackTests
{
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
using var logger = _output.BuildLoggerFor<WindowsPackTests>();
using var _1 = Utility.GetTempDirectory(out var releaseDir);
using var _2 = Utility.GetTempDirectory(out var installDir);
using var _1 = TempUtil.GetTempDirectory(out var releaseDir);
using var _2 = TempUtil.GetTempDirectory(out var installDir);
string id = "SquirrelHookTest";
var appPath = Path.Combine(installDir, "current", "TestApp.exe");
@@ -415,8 +416,8 @@ public class WindowsPackTests
{
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
using var logger = _output.BuildLoggerFor<WindowsPackTests>();
using var _1 = Utility.GetTempDirectory(out var releaseDir);
using var _2 = Utility.GetTempDirectory(out var installDir);
using var _1 = TempUtil.GetTempDirectory(out var releaseDir);
using var _2 = TempUtil.GetTempDirectory(out var installDir);
string id = "SquirrelIntegrationTest";
@@ -507,7 +508,7 @@ public class WindowsPackTests
var rootDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "LegacyTestApp");
if (Directory.Exists(rootDir)) {
Utility.Retry(() => Utility.DeleteFileOrDirectoryHard(rootDir), 10, 1000);
IoUtil.Retry(() => IoUtil.DeleteFileOrDirectoryHard(rootDir), 10, 1000);
}
var setup = PathHelper.GetFixture(fixture);
@@ -520,7 +521,7 @@ public class WindowsPackTests
Assert.True(File.Exists(appExe));
Assert.True(File.Exists(updateExe));
using var _1 = Utility.GetTempDirectory(out var releaseDir);
using var _1 = TempUtil.GetTempDirectory(out var releaseDir);
PackTestApp("LegacyTestApp", "2.0.0", "hello!", releaseDir, logger);
RunNoCoverage(appExe, new string[] { "download", releaseDir }, currentDir, logger, exitCode: 0);
@@ -612,7 +613,7 @@ public class WindowsPackTests
logger.Info($"TEST: Process exited with code {p.ExitCode} in {elapsed.TotalSeconds}s");
using var fs = Utility.Retry(() => {
using var fs = IoUtil.Retry(() => {
return File.Open(outputFile, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}, 10, 1000, logger);

View File

@@ -1,5 +1,6 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using Velopack.Util;
namespace Velopack.Tests;

View File

@@ -1,6 +1,7 @@
#pragma warning disable CS0618 // Type or member is obsolete
using System.Runtime.Versioning;
using Velopack.Locators;
using Velopack.Util;
using Velopack.Windows;
namespace Velopack.Tests;
@@ -21,7 +22,7 @@ public class ShortcutTests
using var logger = _output.BuildLoggerFor<ShortcutTests>();
string exeName = "NotSquirrelAwareApp.exe";
using var _1 = Utility.GetTempDirectory(out var rootDir);
using var _1 = TempUtil.GetTempDirectory(out var rootDir);
var packages = Directory.CreateDirectory(Path.Combine(rootDir, "packages"));
var current = Directory.CreateDirectory(Path.Combine(rootDir, "current"));

View File

@@ -1,5 +1,6 @@
using System.IO.Compression;
using Velopack.Compression;
using Velopack.Util;
namespace Velopack.Tests;
@@ -8,14 +9,14 @@ public class SymbolicLinkTests
[Fact]
public void Exists_NoSuchFile()
{
using var _1 = Utility.GetTempDirectory(out var tempFolder);
using var _1 = TempUtil.GetTempDirectory(out var tempFolder);
Assert.False(SymbolicLink.Exists(Path.Combine(tempFolder, "$$$NoSuchFolder$$$")));
}
[Fact]
public void Exists_IsADirectory()
{
using var _1 = Utility.GetTempDirectory(out var tempFolder);
using var _1 = TempUtil.GetTempDirectory(out var tempFolder);
File.Create(Path.Combine(tempFolder, "AFile")).Close();
Assert.False(SymbolicLink.Exists(Path.Combine(tempFolder, "AFile")));
@@ -24,7 +25,7 @@ public class SymbolicLinkTests
[Fact]
public void CreateDirectory_VerifyExists_GetTarget_Delete()
{
using var _1 = Utility.GetTempDirectory(out var tempFolder);
using var _1 = TempUtil.GetTempDirectory(out var tempFolder);
string targetFolder = Path.Combine(tempFolder, "ADirectory");
string junctionPoint = Path.Combine(tempFolder, "SymLink");
@@ -64,7 +65,7 @@ public class SymbolicLinkTests
[Fact]
public void CreateFile_VerifyExists_GetTarget_Delete()
{
using var _1 = Utility.GetTempDirectory(out var tempFolder);
using var _1 = TempUtil.GetTempDirectory(out var tempFolder);
var tmpFile = Path.Combine(tempFolder, "AFile");
var symFile = Path.Combine(tempFolder, "SymFile");
File.Create(tmpFile).Close();
@@ -92,7 +93,7 @@ public class SymbolicLinkTests
[Fact]
public void CreateFile_RelativePath()
{
using var _1 = Utility.GetTempDirectory(out var tempFolder);
using var _1 = TempUtil.GetTempDirectory(out var tempFolder);
var subDir = Directory.CreateDirectory(Path.Combine(tempFolder, "SubDir")).FullName;
var tmpFile = Path.Combine(tempFolder, "AFile");
@@ -122,7 +123,7 @@ public class SymbolicLinkTests
[Fact]
public void CreateDirectory_RelativePath()
{
using var _1 = Utility.GetTempDirectory(out var tempFolder);
using var _1 = TempUtil.GetTempDirectory(out var tempFolder);
var subDir = Directory.CreateDirectory(Path.Combine(tempFolder, "SubDir")).FullName;
var subSubDir = Directory.CreateDirectory(Path.Combine(subDir, "SubSub")).FullName;
var subDir2 = Directory.CreateDirectory(Path.Combine(tempFolder, "SubDir2")).FullName;
@@ -145,7 +146,7 @@ public class SymbolicLinkTests
[Fact]
public void Create_ThrowsIfOverwriteNotSpecifiedAndDirectoryExists()
{
using var _1 = Utility.GetTempDirectory(out var tempFolder);
using var _1 = TempUtil.GetTempDirectory(out var tempFolder);
string targetFolder = Path.Combine(tempFolder, "ADirectory");
string junctionPoint = Path.Combine(tempFolder, "SymLink");
@@ -156,7 +157,7 @@ public class SymbolicLinkTests
[Fact]
public void Create_OverwritesIfSpecifiedAndDirectoryExists()
{
using var _1 = Utility.GetTempDirectory(out var tempFolder);
using var _1 = TempUtil.GetTempDirectory(out var tempFolder);
string targetFolder = Path.Combine(tempFolder, "ADirectory");
string junctionPoint = Path.Combine(tempFolder, "SymLink");
@@ -171,7 +172,7 @@ public class SymbolicLinkTests
[Fact]
public void Create_ThrowsIfTargetDirectoryDoesNotExist()
{
using var _1 = Utility.GetTempDirectory(out var tempFolder);
using var _1 = TempUtil.GetTempDirectory(out var tempFolder);
string targetFolder = Path.Combine(tempFolder, "ADirectory");
string junctionPoint = Path.Combine(tempFolder, "SymLink");
Assert.Throws<IOException>(() => SymbolicLink.Create(junctionPoint, targetFolder, false));
@@ -180,21 +181,21 @@ public class SymbolicLinkTests
[Fact]
public void GetTarget_NonExistentJunctionPoint()
{
using var _1 = Utility.GetTempDirectory(out var tempFolder);
using var _1 = TempUtil.GetTempDirectory(out var tempFolder);
Assert.Throws<IOException>(() => SymbolicLink.GetTarget(Path.Combine(tempFolder, "SymLink")));
}
[Fact]
public void GetTarget_CalledOnADirectoryThatIsNotAJunctionPoint()
{
using var _1 = Utility.GetTempDirectory(out var tempFolder);
using var _1 = TempUtil.GetTempDirectory(out var tempFolder);
Assert.Throws<IOException>(() => SymbolicLink.GetTarget(tempFolder));
}
[Fact]
public void GetTarget_CalledOnAFile()
{
using var _1 = Utility.GetTempDirectory(out var tempFolder);
using var _1 = TempUtil.GetTempDirectory(out var tempFolder);
File.Create(Path.Combine(tempFolder, "AFile")).Close();
Assert.Throws<IOException>(() => SymbolicLink.GetTarget(Path.Combine(tempFolder, "AFile")));
@@ -204,21 +205,21 @@ public class SymbolicLinkTests
public void Delete_NonExistentJunctionPoint()
{
// Should do nothing.
using var _1 = Utility.GetTempDirectory(out var tempFolder);
using var _1 = TempUtil.GetTempDirectory(out var tempFolder);
SymbolicLink.Delete(Path.Combine(tempFolder, "SymLink"));
}
[Fact]
public void Delete_CalledOnADirectoryThatIsNotAJunctionPoint()
{
using var _1 = Utility.GetTempDirectory(out var tempFolder);
using var _1 = TempUtil.GetTempDirectory(out var tempFolder);
Assert.Throws<IOException>(() => SymbolicLink.Delete(tempFolder));
}
[Fact]
public void Delete_CalledOnAFile()
{
using var _1 = Utility.GetTempDirectory(out var tempFolder);
using var _1 = TempUtil.GetTempDirectory(out var tempFolder);
File.Create(Path.Combine(tempFolder, "AFile")).Close();
Assert.Throws<IOException>(() => SymbolicLink.Delete(Path.Combine(tempFolder, "AFile")));
@@ -227,7 +228,7 @@ public class SymbolicLinkTests
[Fact]
public async Task ComplexSymlinkDirGetsZippedCorrectly()
{
using var _1 = Utility.GetTempDirectory(out var tempFolder);
using var _1 = TempUtil.GetTempDirectory(out var tempFolder);
var temp = new DirectoryInfo(tempFolder);
var versions = temp.CreateSubdirectory("Versions");
var a = versions.CreateSubdirectory("A");
@@ -238,7 +239,7 @@ public class SymbolicLinkTests
SymbolicLink.Create(Path.Combine(temp.FullName, "Resources"), Path.Combine(versions.FullName, "Current", "Resources"), false, true);
SymbolicLink.Create(Path.Combine(temp.FullName, "App"), Path.Combine(versions.FullName, "Current", "App"), false, true);
using var _2 = Utility.GetTempDirectory(out var tempOutput);
using var _2 = TempUtil.GetTempDirectory(out var tempOutput);
var output = Path.Combine(tempOutput, "output.zip");
await EasyZip.CreateZipFromDirectoryAsync(NullLogger.Instance, output, tempFolder);

View File

@@ -3,6 +3,7 @@
using System.Text;
using Velopack.Packaging;
using Velopack.Sources;
using Velopack.Util;
namespace Velopack.Tests.TestHelpers;
@@ -16,8 +17,8 @@ internal class FakeFixtureRepository : Sources.IFileDownloader
public FakeFixtureRepository(string pkgId, bool mockLatestFullVer, string channel = null)
{
_releasesName = Utility.GetReleasesFileName(channel);
_releasesNameNew = Utility.GetVeloReleaseIndexName(channel);
_releasesName = CoreUtil.GetReleasesFileName(channel);
_releasesNameNew = CoreUtil.GetVeloReleaseIndexName(channel);
_pkgId = pkgId;
var releases = ReleaseEntry.BuildReleasesFile(PathHelper.GetFixturesDir(), false)
.Where(r => r.OriginalFilename.StartsWith(_pkgId))

View File

@@ -1,5 +1,6 @@
using System.Net;
using System.Text;
using Velopack.Util;
namespace Velopack.Tests;

View File

@@ -5,6 +5,7 @@ using Velopack.Packaging;
using Velopack.Locators;
using Velopack.Sources;
using Velopack.Tests.TestHelpers;
using Velopack.Util;
namespace Velopack.Tests;
@@ -107,7 +108,7 @@ public class UpdateManagerTests
var fixture = PathHelper.GetFixture("AvaloniaCrossPlat-1.0.11-win-full.nupkg");
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = Utility.GetTempDirectory(out var tempPath);
using var _1 = TempUtil.GetTempDirectory(out var tempPath);
var dl = new FakeDownloader() {
MockedResponseBytes = Encoding.UTF8.GetBytes(SimpleJson.SerializeObject(
new VelopackAssetFeed {
@@ -117,7 +118,7 @@ public class UpdateManagerTests
Version = new SemanticVersion(1, 0, 11),
Type = VelopackAssetType.Full,
FileName = $"https://mysite.com/releases/AvaloniaCrossPlat$-1.1.0.nupkg",
SHA1 = Utility.CalculateFileSHA1(fixture),
SHA1 = IoUtil.CalculateFileSHA1(fixture),
Size = new FileInfo(fixture).Length,
} }
}))
@@ -145,7 +146,7 @@ public class UpdateManagerTests
public void CheckFromLocal()
{
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = Utility.GetTempDirectory(out var tempPath);
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);
@@ -162,7 +163,7 @@ public class UpdateManagerTests
public void CheckFromLocalWithChannel()
{
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = Utility.GetTempDirectory(out var tempPath);
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);
@@ -180,7 +181,7 @@ public class UpdateManagerTests
public void CheckForSameAsInstalledVersion()
{
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = Utility.GetTempDirectory(out var tempPath);
using var _1 = TempUtil.GetTempDirectory(out var tempPath);
var dl = GetMockDownloaderWith2Delta();
var myVer = new VelopackAsset() {
PackageId = "MyCoolApp",
@@ -220,7 +221,7 @@ public class UpdateManagerTests
public void CheckForLowerThanInstalledVersion()
{
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = Utility.GetTempDirectory(out var tempPath);
using var _1 = TempUtil.GetTempDirectory(out var tempPath);
var dl = GetMockDownloaderWith2Delta();
var myVer = new VelopackAsset() {
PackageId = "MyCoolApp",
@@ -254,7 +255,7 @@ public class UpdateManagerTests
public void CheckFromLocalWithDelta()
{
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = Utility.GetTempDirectory(out var tempPath);
using var _1 = TempUtil.GetTempDirectory(out var tempPath);
var dl = GetMockDownloaderWith2Delta();
var myVer = new VelopackAsset() {
PackageId = "MyCoolApp",
@@ -282,7 +283,7 @@ public class UpdateManagerTests
string version = "3.4.287";
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = Utility.GetTempDirectory(out var packagesDir);
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);
@@ -316,7 +317,7 @@ public class UpdateManagerTests
string version = "3.4.287";
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = Utility.GetTempDirectory(out var packagesDir);
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);
@@ -347,7 +348,7 @@ public class UpdateManagerTests
public void NoDeltaIfNoBasePackage()
{
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = Utility.GetTempDirectory(out var tempPath);
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);
@@ -363,7 +364,7 @@ public class UpdateManagerTests
public void CheckFromLocalWithDeltaNoLocalPackage()
{
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = Utility.GetTempDirectory(out var tempPath);
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);
@@ -380,7 +381,7 @@ public class UpdateManagerTests
{
// https://github.com/caesay/SquirrelCustomLauncherTestApp
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = Utility.GetTempDirectory(out var tempPath);
using var _1 = TempUtil.GetTempDirectory(out var tempPath);
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger);
var source = new GithubSource("https://github.com/caesay/SquirrelCustomLauncherTestApp", null, false);
var um = new UpdateManager(source, null, logger, locator);
@@ -394,7 +395,7 @@ public class UpdateManagerTests
{
// https://github.com/caesay/SquirrelCustomLauncherTestApp
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = Utility.GetTempDirectory(out var tempPath);
using var _1 = TempUtil.GetTempDirectory(out var tempPath);
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger);
var source = new GithubSource("https://github.com/caesay/SquirrelCustomLauncherTestApp", null, false);
var opt = new UpdateOptions { ExplicitChannel = "hello" };
@@ -406,7 +407,7 @@ public class UpdateManagerTests
{
// https://github.com/caesay/SquirrelCustomLauncherTestApp
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = Utility.GetTempDirectory(out var tempPath);
using var _1 = TempUtil.GetTempDirectory(out var tempPath);
var locator = new TestVelopackLocator("MyCoolApp", "1.0.0", tempPath, logger);
var source = new GiteaSource("https://gitea.com/remco1271/VeloPackTest", null, false);
var um = new UpdateManager(source, null, logger, locator);
@@ -419,7 +420,7 @@ public class UpdateManagerTests
public void CheckFromEmptyFileSource()
{
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = Utility.GetTempDirectory(out var tempPath);
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);
@@ -431,7 +432,7 @@ public class UpdateManagerTests
public void NoUpdatesIfCurrentEqualsRemoteVersion()
{
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = Utility.GetTempDirectory(out var tempPath);
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);
@@ -444,7 +445,7 @@ public class UpdateManagerTests
public void NoUpdatesIfCurrentGreaterThanRemoteVersion()
{
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = Utility.GetTempDirectory(out var tempPath);
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);
@@ -459,7 +460,7 @@ public class UpdateManagerTests
public void DownloadsLatestFullVersion(string id, string version)
{
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = Utility.GetTempDirectory(out var packagesDir);
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);
@@ -484,7 +485,7 @@ public class UpdateManagerTests
{
Skip.If(VelopackRuntimeInfo.IsLinux);
using var logger = _output.BuildLoggerFor<UpdateManagerTests>();
using var _1 = Utility.GetTempDirectory(out var packagesDir);
using var _1 = TempUtil.GetTempDirectory(out var packagesDir);
var repo = new FakeFixtureRepository(id, true);
var source = new SimpleWebSource("http://any.com", repo);

View File

@@ -2,6 +2,7 @@
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using Velopack.Util;
using Velopack.Windows;
namespace Velopack.Tests;
@@ -26,7 +27,7 @@ public class UtilityTests
{
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
var exp = Path.GetFullPath(expected);
var normal = Utility.NormalizePath(input);
var normal = PathUtil.NormalizePath(input);
Assert.Equal(exp, normal);
}
@@ -43,7 +44,7 @@ public class UtilityTests
public void FileIsInDirectory(string directory, string file, bool isIn)
{
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
var fileInDir = Utility.IsFileInDirectory(file, directory);
var fileInDir = PathUtil.IsFileInDirectory(file, directory);
Assert.Equal(isIn, fileInDir);
}
@@ -84,24 +85,24 @@ public class UtilityTests
var emptyString = string.Empty;
string nullString = null;
byte[] nullByteArray = { };
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(emptyString));
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(nullString));
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(nullByteArray));
Assert.Equal(string.Empty, CoreUtil.RemoveByteOrderMarkerIfPresent(emptyString));
Assert.Equal(string.Empty, CoreUtil.RemoveByteOrderMarkerIfPresent(nullString));
Assert.Equal(string.Empty, CoreUtil.RemoveByteOrderMarkerIfPresent(nullByteArray));
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(utf32Be));
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(utf32Le));
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(utf16Be));
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(utf16Le));
Assert.Equal(string.Empty, Utility.RemoveByteOrderMarkerIfPresent(utf8));
Assert.Equal(string.Empty, CoreUtil.RemoveByteOrderMarkerIfPresent(utf32Be));
Assert.Equal(string.Empty, CoreUtil.RemoveByteOrderMarkerIfPresent(utf32Le));
Assert.Equal(string.Empty, CoreUtil.RemoveByteOrderMarkerIfPresent(utf16Be));
Assert.Equal(string.Empty, CoreUtil.RemoveByteOrderMarkerIfPresent(utf16Le));
Assert.Equal(string.Empty, CoreUtil.RemoveByteOrderMarkerIfPresent(utf8));
Assert.Equal("hello world", Utility.RemoveByteOrderMarkerIfPresent(utf32BeHelloWorld));
Assert.Equal("hello world", Utility.RemoveByteOrderMarkerIfPresent(utf32LeHelloWorld));
Assert.Equal("hello world", Utility.RemoveByteOrderMarkerIfPresent(utf16BeHelloWorld));
Assert.Equal("hello world", Utility.RemoveByteOrderMarkerIfPresent(utf16LeHelloWorld));
Assert.Equal("hello world", Utility.RemoveByteOrderMarkerIfPresent(utf8HelloWorld));
Assert.Equal("hello world", CoreUtil.RemoveByteOrderMarkerIfPresent(utf32BeHelloWorld));
Assert.Equal("hello world", CoreUtil.RemoveByteOrderMarkerIfPresent(utf32LeHelloWorld));
Assert.Equal("hello world", CoreUtil.RemoveByteOrderMarkerIfPresent(utf16BeHelloWorld));
Assert.Equal("hello world", CoreUtil.RemoveByteOrderMarkerIfPresent(utf16LeHelloWorld));
Assert.Equal("hello world", CoreUtil.RemoveByteOrderMarkerIfPresent(utf8HelloWorld));
Assert.Equal("hello world", Utility.RemoveByteOrderMarkerIfPresent(asciiMultipleChars));
Assert.Equal("A", Utility.RemoveByteOrderMarkerIfPresent(asciiSingleChar));
Assert.Equal("hello world", CoreUtil.RemoveByteOrderMarkerIfPresent(asciiMultipleChars));
Assert.Equal("A", CoreUtil.RemoveByteOrderMarkerIfPresent(asciiSingleChar));
}
[Fact]
@@ -110,7 +111,7 @@ public class UtilityTests
var sha1FromExternalTool = "75255cfd229a1ed1447abe1104f5635e69975d30";
var inputPackage = PathHelper.GetFixture("Squirrel.Core.1.0.0.0.nupkg");
var stream = File.OpenRead(inputPackage);
var sha1 = Utility.CalculateStreamSHA1(stream);
var sha1 = IoUtil.CalculateStreamSHA1(stream);
Assert.NotEqual(sha1FromExternalTool, sha1);
Assert.Equal(sha1FromExternalTool, sha1, StringComparer.OrdinalIgnoreCase);
@@ -121,7 +122,7 @@ public class UtilityTests
{
using var logger = _output.BuildLoggerFor<UtilityTests>();
string tempDir;
using (Utility.GetTempDirectory(out tempDir)) {
using (TempUtil.GetTempDirectory(out tempDir)) {
for (var i = 0; i < 50; i++) {
var directory = Path.Combine(tempDir, newId());
CreateSampleDirectory(directory);
@@ -135,7 +136,7 @@ public class UtilityTests
var sw = new Stopwatch();
sw.Start();
Utility.DeleteFileOrDirectoryHard(tempDir);
IoUtil.DeleteFileOrDirectoryHard(tempDir);
sw.Stop();
logger.Info($"Delete took {sw.ElapsedMilliseconds}ms");
@@ -147,7 +148,7 @@ public class UtilityTests
//public void CreateFakePackageSmokeTest()
//{
// string path;
// using (Utility.GetTempDirectory(out path)) {
// using (TempUtil.GetTempDirectory(out path)) {
// var output = IntegrationTestHelper.CreateFakeInstalledApp("0.3.0", path);
// Assert.True(File.Exists(output));
// }
@@ -161,7 +162,7 @@ public class UtilityTests
[InlineData(".rels", false)]
public void FileIsLikelyPEImageTest(string input, bool result)
{
Assert.Equal(result, Utility.FileIsLikelyPEImage(input));
Assert.Equal(result, PathUtil.FileIsLikelyPEImage(input));
}
[Fact(Skip = "Only really need to run this test after changes to FileDownloader")]
@@ -170,10 +171,10 @@ public class UtilityTests
// this probably should use a local http server instead.
const string testUrl = "http://speedtest.tele2.net/1MB.zip";
var dl = Utility.CreateDefaultDownloader();
var dl = HttpUtil.CreateDefaultDownloader();
List<int> prog = new List<int>();
using (Utility.GetTempFileName(out var tempPath))
using (TempUtil.GetTempFileName(out var tempPath))
await dl.DownloadFile(testUrl, tempPath, prog.Add);
Assert.True(prog.Count > 10);

View File

@@ -2,6 +2,7 @@
using NuGet.Versioning;
using Velopack.NuGet;
using Velopack.Tests.TestHelpers;
using Velopack.Util;
using ZipPackage = Velopack.NuGet.ZipPackage;
namespace Velopack.Tests;
@@ -19,9 +20,9 @@ public class ZipPackageTests
{
using var logger = _output.BuildLoggerFor<ZipPackageTests>();
using var _1 = Utility.GetTempDirectory(out var tempDir);
using var _2 = Utility.GetTempDirectory(out var zipDir);
using var _3 = Utility.GetTempDirectory(out var extractedDir);
using var _1 = TempUtil.GetTempDirectory(out var tempDir);
using var _2 = TempUtil.GetTempDirectory(out var zipDir);
using var _3 = TempUtil.GetTempDirectory(out var extractedDir);
var actual = Path.Combine(tempDir, "actual");
var actualFile = Path.Combine(actual, "file.txt");
@@ -56,7 +57,7 @@ public class ZipPackageTests
[Fact]
public void HasSameFilesAndDependenciesAsPackaging()
{
using var _1 = Utility.GetTempDirectory(out var tempDir);
using var _1 = TempUtil.GetTempDirectory(out var tempDir);
var inputPackage = PathHelper.GetFixture("slack-1.1.8-full.nupkg");
var copyPackage = Path.Combine(tempDir, "slack-1.1.8-full.nupkg");
File.Copy(inputPackage, copyPackage);