mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
Detect VelopackApp.Run() in any method in main module
This commit is contained in:
@@ -85,4 +85,9 @@ public class MSBuildLogger(TaskLoggingHelper loggingHelper) : ILogger, IFancyCon
|
||||
{
|
||||
Log(LogLevel.Information, 0, null, null, (object? state, Exception? exception) => text);
|
||||
}
|
||||
|
||||
public string EscapeMarkup(string text)
|
||||
{
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,11 +33,12 @@ public class WindowsPackCommandRunner : PackageBuilder<WindowsPackOptions>
|
||||
if (Directory.EnumerateFiles(packDir, "*.application").Any(f => File.ReadAllText(f).Contains("clickonce"))) {
|
||||
throw new ArgumentException(
|
||||
"Velopack does not support building releases for ClickOnce applications. " +
|
||||
"Please publish your application to a folder without ClickOnce.");
|
||||
"Please remove all ClickOnce properties from your .csproj before continuing.");
|
||||
}
|
||||
|
||||
if (!Options.SkipVelopackAppCheck) {
|
||||
DotnetUtil.VerifyVelopackApp(MainExePath, Log);
|
||||
var compat = new CompatUtil(Log, Console);
|
||||
compat.Verify(MainExePath);
|
||||
} else {
|
||||
Log.Info("Skipping VelopackApp.Build.Run() check.");
|
||||
}
|
||||
|
||||
241
src/Velopack.Packaging.Windows/CompatUtil.cs
Normal file
241
src/Velopack.Packaging.Windows/CompatUtil.cs
Normal file
@@ -0,0 +1,241 @@
|
||||
using AsmResolver.DotNet;
|
||||
using AsmResolver.DotNet.Bundles;
|
||||
using AsmResolver.DotNet.Serialized;
|
||||
using AsmResolver.PE;
|
||||
using AsmResolver.PE.DotNet.Cil;
|
||||
using AsmResolver.PE.Win32Resources.Version;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NuGet.Versioning;
|
||||
using Velopack.Packaging.Abstractions;
|
||||
using Velopack.Packaging.Exceptions;
|
||||
|
||||
namespace Velopack.Packaging.Windows;
|
||||
|
||||
public class CompatUtil
|
||||
{
|
||||
private readonly ILogger _log;
|
||||
private readonly IFancyConsole _console;
|
||||
|
||||
public CompatUtil(ILogger logger, IFancyConsole console)
|
||||
{
|
||||
_log = logger;
|
||||
_console = console;
|
||||
}
|
||||
|
||||
public NuGetVersion Verify(string exeFile)
|
||||
{
|
||||
VerifyVelopackApp(exeFile);
|
||||
return VerifyVelopackVersion(exeFile);
|
||||
}
|
||||
|
||||
public void VerifyVelopackApp(string exeFile)
|
||||
{
|
||||
try {
|
||||
AssemblyDefinition mainAssy = LoadDotnetAssembly(exeFile);
|
||||
if (mainAssy == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ModuleDefinition mainModule = mainAssy.Modules.Single();
|
||||
var result = SearchAssemblyForVelopackApp(mainModule);
|
||||
if (result == null) {
|
||||
// if we've iterated the whole main assembly and not found the call, then the velopack builder is missing
|
||||
throw new UserInfoException($"Unable to verify VelopackApp is called. " +
|
||||
"Please ensure that 'VelopackApp.Build().Run()' is present in your Program.Main().");
|
||||
}
|
||||
|
||||
result = _console.EscapeMarkup(result);
|
||||
|
||||
// could be regular Program.Main or async Main which has a slightly different signature.
|
||||
if (result.Contains("Program") && result.Contains("Main")) {
|
||||
_log.Info($"[green underline]Verified VelopackApp.Run()[/] in '{result}'.");
|
||||
} else {
|
||||
_log.Warn($"VelopackApp.Run() was found in method '{result}', which does not look like your application's entry point." +
|
||||
$"It is [underline yellow]strongly recommended[/] that you move this to the very beginning of your Main() method. ");
|
||||
}
|
||||
|
||||
} catch (Exception ex) when (ex is not UserInfoException) {
|
||||
_log.Error("Unable to verify VelopackApp: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public NuGetVersion VerifyVelopackVersion(string exeFile)
|
||||
{
|
||||
var rawVersion = GetVelopackVersion(exeFile);
|
||||
if (rawVersion == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var dllVersion = new Version(rawVersion.ToString("V", VersionFormatter.Instance));
|
||||
var myVersion = new Version(VelopackRuntimeInfo.VelopackNugetVersion.ToString("V", VersionFormatter.Instance));
|
||||
if (dllVersion == myVersion) {
|
||||
return new NuGetVersion(dllVersion);
|
||||
}
|
||||
|
||||
if (dllVersion > myVersion) {
|
||||
throw new UserInfoException($"Velopack library version is greater than vpk version ({dllVersion} > {myVersion}). This can cause compatibility issues, please update vpk first.");
|
||||
}
|
||||
|
||||
_log.Warn($"Velopack library version is lower than vpk version ({dllVersion} < {myVersion}). This can occasionally cause compatibility issues.");
|
||||
return new NuGetVersion(dllVersion);
|
||||
}
|
||||
|
||||
private string SearchAssemblyForVelopackApp(ModuleDefinition mainModule)
|
||||
{
|
||||
MethodDefinition entryPoint = mainModule.ManagedEntryPointMethod;
|
||||
|
||||
string SearchMethod(MethodDefinition method)
|
||||
{
|
||||
foreach (var instr in method.CilMethodBody.Instructions) {
|
||||
if (instr.OpCode.Code is CilCode.Call or CilCode.Callvirt or CilCode.Calli) {
|
||||
var operand = instr.Operand as SerializedMemberReference;
|
||||
if (operand != null) {
|
||||
if (operand.Name == "Run" && operand.DeclaringType.FullName == "Velopack.VelopackApp") {
|
||||
// success!
|
||||
return method.FullName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
string SearchType(TypeDefinition type)
|
||||
{
|
||||
// search all methods in type
|
||||
foreach (var method in type.Methods) {
|
||||
if (method.HasMethodBody) {
|
||||
var result = SearchMethod(method);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// then, search all nested types
|
||||
foreach (var nestedType in type.NestedTypes) {
|
||||
var result = SearchType(nestedType);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// search entry point first
|
||||
string result;
|
||||
if ((result = SearchMethod(entryPoint)) != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// then, iterate all methods in the main module
|
||||
foreach (var topType in mainModule.TopLevelTypes) {
|
||||
if ((result = SearchType(topType)) != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public NuGetVersion GetVelopackVersion(string exeFile)
|
||||
{
|
||||
try {
|
||||
var velopackDll = FindVelopackDll(exeFile);
|
||||
if (velopackDll == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var versionInfo = VersionInfoResource.FromDirectory(velopackDll.Resources);
|
||||
var actualInfo = versionInfo.GetChild<StringFileInfo>(StringFileInfo.StringFileInfoKey);
|
||||
var versionTable = actualInfo.Tables[0];
|
||||
var productVersion = versionTable.Where(v => v.Key == StringTable.ProductVersionKey).FirstOrDefault();
|
||||
return NuGetVersion.Parse(productVersion.Value);
|
||||
} catch (Exception ex) {
|
||||
// don't really care
|
||||
_log.Debug(ex, "Unable to read Velopack.dll version info.");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private IPEImage FindVelopackDll(string exeFile)
|
||||
{
|
||||
var versionFile = Path.Combine(Path.GetDirectoryName(exeFile), "Velopack.dll");
|
||||
if (File.Exists(versionFile)) {
|
||||
_log.Debug(exeFile + " has Velopack.dll in the same directory.");
|
||||
return PEImage.FromFile(versionFile);
|
||||
}
|
||||
|
||||
try {
|
||||
var bundle = BundleManifest.FromFile(exeFile);
|
||||
IList<BundleFile> embeddedFiles = bundle.Files;
|
||||
var velopackEmbedded = embeddedFiles.SingleOrDefault(f => f.Type == BundleFileType.Assembly && f.RelativePath == "Velopack.dll");
|
||||
if (velopackEmbedded != null && velopackEmbedded.TryGetReader(out var readerVel)) {
|
||||
_log.Debug(exeFile + " has Velopack.dll embedded in a SingleFileHost.");
|
||||
return PEImage.FromReader(readerVel);
|
||||
}
|
||||
} catch (BadImageFormatException) {
|
||||
// not an AppHost / SingleFileHost binary
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private AssemblyDefinition LoadDotnetAssembly(string exeFile)
|
||||
{
|
||||
try {
|
||||
var assy = AssemblyDefinition.FromFile(exeFile);
|
||||
return assy;
|
||||
} catch (BadImageFormatException) {
|
||||
// not a .Net Framework binary
|
||||
}
|
||||
|
||||
try {
|
||||
var bundle = BundleManifest.FromFile(exeFile);
|
||||
IList<BundleFile> embeddedFiles = null;
|
||||
|
||||
try {
|
||||
embeddedFiles = bundle.Files;
|
||||
} catch {
|
||||
// not a SingleFileHost binary, so we'll search on disk
|
||||
var parentDir = Path.GetDirectoryName(exeFile);
|
||||
var diskFile = Path.Combine(parentDir, Path.GetFileNameWithoutExtension(exeFile) + ".dll");
|
||||
if (File.Exists(diskFile)) {
|
||||
return AssemblyDefinition.FromFile(diskFile);
|
||||
}
|
||||
|
||||
var runtimeConfigFile = Directory.EnumerateFiles(parentDir, "*.runtimeconfig.json").SingleOrDefault();
|
||||
var possNameRuntime = Path.Combine(parentDir,
|
||||
Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(runtimeConfigFile)) + ".dll");
|
||||
if (File.Exists(possNameRuntime)) {
|
||||
return AssemblyDefinition.FromFile(possNameRuntime);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var runtimeConfig = embeddedFiles.SingleOrDefault(f => f.Type == BundleFileType.RuntimeConfigJson);
|
||||
if (runtimeConfig != null) {
|
||||
var possName1 = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(runtimeConfig.RelativePath)) + ".dll";
|
||||
var file = embeddedFiles.SingleOrDefault(f => f.Type == BundleFileType.Assembly && f.RelativePath == possName1);
|
||||
if (file != null && file.TryGetReader(out var reader)) {
|
||||
return AssemblyDefinition.FromReader(reader);
|
||||
}
|
||||
}
|
||||
|
||||
var possName2 = Path.GetFileNameWithoutExtension(exeFile) + ".dll";
|
||||
var file2 = embeddedFiles.SingleOrDefault(f => f.Type == BundleFileType.Assembly && f.RelativePath == possName2);
|
||||
if (file2 != null && file2.TryGetReader(out var reader2)) {
|
||||
return AssemblyDefinition.FromReader(reader2);
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (BadImageFormatException) {
|
||||
// not an AppHost / SingleFileHost binary
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
using AsmResolver.DotNet;
|
||||
using AsmResolver.DotNet.Bundles;
|
||||
using AsmResolver.DotNet.Serialized;
|
||||
using AsmResolver.PE;
|
||||
using AsmResolver.PE.DotNet.Cil;
|
||||
using AsmResolver.PE.Win32Resources.Version;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NuGet.Versioning;
|
||||
using Velopack.Packaging.Exceptions;
|
||||
|
||||
namespace Velopack.Packaging.Windows;
|
||||
|
||||
public class DotnetUtil
|
||||
{
|
||||
public static NuGetVersion VerifyVelopackApp(string exeFile, ILogger log)
|
||||
{
|
||||
try {
|
||||
NuGetVersion velopackVersion = null;
|
||||
IPEImage velopackDll = null;
|
||||
AssemblyDefinition mainAssy = null;
|
||||
mainAssy ??= LoadFullFramework(exeFile, ref velopackDll);
|
||||
mainAssy ??= LoadDncBundle(exeFile, ref velopackDll);
|
||||
|
||||
if (mainAssy == null) {
|
||||
// not a dotnet binary
|
||||
return null;
|
||||
}
|
||||
|
||||
if (velopackDll != null) {
|
||||
try {
|
||||
var versionInfo = VersionInfoResource.FromDirectory(velopackDll.Resources);
|
||||
var actualInfo = versionInfo.GetChild<StringFileInfo>(StringFileInfo.StringFileInfoKey);
|
||||
var versionTable = actualInfo.Tables[0];
|
||||
var productVersion = versionTable.Where(v => v.Key == StringTable.ProductVersionKey).FirstOrDefault();
|
||||
velopackVersion = NuGetVersion.Parse(productVersion.Value);
|
||||
} catch (Exception ex) {
|
||||
// don't really care
|
||||
log.Debug(ex, "Unable to read Velopack.dll version info.");
|
||||
}
|
||||
}
|
||||
|
||||
var mainModule = mainAssy.Modules.Single();
|
||||
var entryPoint = mainModule.ManagedEntryPointMethod;
|
||||
|
||||
foreach (var instr in entryPoint.CilMethodBody.Instructions) {
|
||||
if (instr.OpCode.Code is CilCode.Call or CilCode.Callvirt or CilCode.Calli) {
|
||||
SerializedMemberReference operand = instr.Operand as SerializedMemberReference;
|
||||
if (operand != null && operand.IsMethod) {
|
||||
if (operand.Name == "Run" && operand.DeclaringType.FullName == "Velopack.VelopackApp") {
|
||||
// success!
|
||||
if (velopackVersion != null) {
|
||||
log.Info($"Verified VelopackApp.Run() in '{entryPoint.FullName}', version {velopackVersion}.");
|
||||
if (velopackVersion != VelopackRuntimeInfo.VelopackProductVersion) {
|
||||
log.Warn(exeFile + " was built with a different version of Velopack than this tool. " +
|
||||
$"This may cause compatibility issues. Expected {VelopackRuntimeInfo.VelopackProductVersion}, " +
|
||||
$"but found {velopackVersion}.");
|
||||
}
|
||||
return velopackVersion;
|
||||
} else {
|
||||
log.Warn("VelopackApp verified at entry point, but ProductVersion could not be checked.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we've iterated the whole main method and not found the call, then the velopack builder is missing
|
||||
throw new UserInfoException($"Unable to verify VelopackApp, in application main method '{entryPoint.FullName}'. " +
|
||||
"Please ensure that 'VelopackApp.Build().Run()' is present in your Program.Main().");
|
||||
|
||||
} catch (Exception ex) when (ex is not UserInfoException) {
|
||||
log.Error("Unable to verify VelopackApp: " + ex.Message);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static AssemblyDefinition LoadFullFramework(string exeFile, ref IPEImage velopackDll)
|
||||
{
|
||||
try {
|
||||
var assy = AssemblyDefinition.FromFile(exeFile);
|
||||
var versionFile = Path.Combine(Path.GetDirectoryName(exeFile), "Velopack.dll");
|
||||
if (File.Exists(versionFile)) {
|
||||
velopackDll = PEImage.FromFile(versionFile);
|
||||
}
|
||||
return assy;
|
||||
} catch (BadImageFormatException) {
|
||||
// not a .Net Framework binary
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static AssemblyDefinition LoadDncBundle(string exeFile, ref IPEImage velopackDll)
|
||||
{
|
||||
try {
|
||||
var bundle = BundleManifest.FromFile(exeFile);
|
||||
IList<BundleFile> embeddedFiles = null;
|
||||
|
||||
try {
|
||||
embeddedFiles = bundle.Files;
|
||||
} catch {
|
||||
// not a SingleFileHost binary, so we'll search on disk
|
||||
var parentDir = Path.GetDirectoryName(exeFile);
|
||||
var versionFile = Path.Combine(parentDir, "Velopack.dll");
|
||||
if (File.Exists(versionFile)) {
|
||||
velopackDll = PEImage.FromFile(versionFile);
|
||||
}
|
||||
|
||||
var diskFile = Path.Combine(parentDir, Path.GetFileNameWithoutExtension(exeFile) + ".dll");
|
||||
if (File.Exists(diskFile)) {
|
||||
return AssemblyDefinition.FromFile(diskFile);
|
||||
}
|
||||
|
||||
var runtimeConfigFile = Directory.EnumerateFiles(parentDir, "*.runtimeconfig.json").SingleOrDefault();
|
||||
var possNameRuntime = Path.Combine(parentDir,
|
||||
Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(runtimeConfigFile)) + ".dll");
|
||||
if (File.Exists(possNameRuntime)) {
|
||||
return AssemblyDefinition.FromFile(possNameRuntime);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var velopackEmbedded = embeddedFiles.SingleOrDefault(f => f.Type == BundleFileType.Assembly && f.RelativePath == "Velopack.dll");
|
||||
if (velopackEmbedded != null && velopackEmbedded.TryGetReader(out var readerVel)) {
|
||||
velopackDll = PEImage.FromReader(readerVel);
|
||||
}
|
||||
|
||||
var runtimeConfig = embeddedFiles.SingleOrDefault(f => f.Type == BundleFileType.RuntimeConfigJson);
|
||||
if (runtimeConfig != null) {
|
||||
var possName1 = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(runtimeConfig.RelativePath)) + ".dll";
|
||||
var file = embeddedFiles.SingleOrDefault(f => f.Type == BundleFileType.Assembly && f.RelativePath == possName1);
|
||||
if (file != null && file.TryGetReader(out var reader)) {
|
||||
return AssemblyDefinition.FromReader(reader);
|
||||
}
|
||||
}
|
||||
|
||||
var possName2 = Path.GetFileNameWithoutExtension(exeFile) + ".dll";
|
||||
var file2 = embeddedFiles.SingleOrDefault(f => f.Type == BundleFileType.Assembly && f.RelativePath == possName2);
|
||||
if (file2 != null && file2.TryGetReader(out var reader2)) {
|
||||
return AssemblyDefinition.FromReader(reader2);
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (BadImageFormatException) {
|
||||
// not an AppHost / SingleFileHost binary
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,4 +7,6 @@ public interface IFancyConsole : IConsole
|
||||
void WriteTable(string tableName, IEnumerable<IEnumerable<string>> rows, bool hasHeaderRow = true);
|
||||
|
||||
Task<bool> PromptYesNo(string prompt, bool? defaultValue = null, TimeSpan? timeout = null);
|
||||
|
||||
string EscapeMarkup(string text);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,11 @@ public class BasicConsole : IFancyConsole
|
||||
this.defaultFactory = defaultFactory;
|
||||
}
|
||||
|
||||
public string EscapeMarkup(string text)
|
||||
{
|
||||
return text;
|
||||
}
|
||||
|
||||
public async Task ExecuteProgressAsync(Func<IFancyConsoleProgress, Task> action)
|
||||
{
|
||||
var start = DateTime.UtcNow;
|
||||
|
||||
@@ -15,6 +15,11 @@ public class SpectreConsole : IFancyConsole
|
||||
this.defaultFactory = defaultFactory;
|
||||
}
|
||||
|
||||
public string EscapeMarkup(string text)
|
||||
{
|
||||
return Markup.Escape(text);
|
||||
}
|
||||
|
||||
public async Task ExecuteProgressAsync(Func<IFancyConsoleProgress, Task> action)
|
||||
{
|
||||
var start = DateTime.UtcNow;
|
||||
|
||||
@@ -7,6 +7,10 @@ try {
|
||||
bool shouldExit = false;
|
||||
bool shouldAutoUpdate = args.Any(a => a.Equals("--autoupdate", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
#if USE_ASYNC_MAIN
|
||||
await Task.Delay(10).ConfigureAwait(false);
|
||||
#endif
|
||||
|
||||
#if !NO_VELO_BUILDER
|
||||
VelopackApp.Build()
|
||||
.SetAutoApplyOnStartup(shouldAutoUpdate)
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
<DefineConstants>NO_VELO_BUILDER</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" $(UseAsyncMain) != '' ">
|
||||
<DefineConstants>USE_ASYNC_MAIN</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Velopack\Velopack.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,30 +1,39 @@
|
||||
using Velopack.Packaging.Exceptions;
|
||||
using Divergic.Logging.Xunit;
|
||||
using Velopack.Packaging.Exceptions;
|
||||
using Velopack.Packaging.Windows;
|
||||
using Velopack.Vpk.Logging;
|
||||
|
||||
namespace Velopack.Packaging.Tests;
|
||||
|
||||
public class DotnetUtilTests
|
||||
public class CompatUtilTests
|
||||
{
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
public DotnetUtilTests(ITestOutputHelper output)
|
||||
public CompatUtilTests(ITestOutputHelper output)
|
||||
{
|
||||
_output = output;
|
||||
}
|
||||
|
||||
private ICacheLogger<CompatUtilTests> GetCompat(out CompatUtil compat)
|
||||
{
|
||||
var logger = _output.BuildLoggerFor<CompatUtilTests>();
|
||||
compat = new CompatUtil(logger, new BasicConsole(logger, new DefaultPromptValueFactory(true)));
|
||||
return logger;
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public void NonDotnetBinaryPasses()
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
using var logger = _output.BuildLoggerFor<DotnetUtilTests>();
|
||||
Assert.Null(DotnetUtil.VerifyVelopackApp(PathHelper.GetRustAsset("testapp.exe"), logger));
|
||||
using var logger = GetCompat(out var compat);
|
||||
Assert.Null(compat.Verify(PathHelper.GetRustAsset("testapp.exe")));
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public void PublishSingleFilePasses()
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
using var logger = _output.BuildLoggerFor<DotnetUtilTests>();
|
||||
using var logger = GetCompat(out var compat);
|
||||
using var _1 = Utility.GetTempDirectory(out var dir);
|
||||
var sample = PathHelper.GetAvaloniaSample();
|
||||
Exe.InvokeAndThrowIfNonZero(
|
||||
@@ -34,18 +43,18 @@ public class DotnetUtilTests
|
||||
sample);
|
||||
|
||||
var path = Path.Combine(dir, "AvaloniaCrossPlat.exe");
|
||||
Assert.Equal(VelopackRuntimeInfo.VelopackProductVersion, DotnetUtil.VerifyVelopackApp(path, logger));
|
||||
Assert.Equal(VelopackRuntimeInfo.VelopackProductVersion, compat.Verify(path));
|
||||
|
||||
var newPath = Path.Combine(dir, "AvaloniaCrossPlat-asd2.exe");
|
||||
File.Move(path, newPath);
|
||||
Assert.Equal(VelopackRuntimeInfo.VelopackProductVersion, DotnetUtil.VerifyVelopackApp(newPath, logger));
|
||||
Assert.Equal(VelopackRuntimeInfo.VelopackProductVersion, compat.Verify(newPath));
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public void PublishDotnet6Passes()
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
using var logger = _output.BuildLoggerFor<DotnetUtilTests>();
|
||||
using var logger = GetCompat(out var compat);
|
||||
using var _1 = Utility.GetTempDirectory(out var dir);
|
||||
var sample = PathHelper.GetAvaloniaSample();
|
||||
Exe.InvokeAndThrowIfNonZero(
|
||||
@@ -55,18 +64,18 @@ public class DotnetUtilTests
|
||||
sample);
|
||||
|
||||
var path = Path.Combine(dir, "AvaloniaCrossPlat.exe");
|
||||
Assert.Equal(VelopackRuntimeInfo.VelopackProductVersion, DotnetUtil.VerifyVelopackApp(path, logger));
|
||||
Assert.Equal(VelopackRuntimeInfo.VelopackProductVersion, compat.Verify(path));
|
||||
|
||||
var newPath = Path.Combine(dir, "AvaloniaCrossPlat-asd2.exe");
|
||||
File.Move(path, newPath);
|
||||
Assert.Equal(VelopackRuntimeInfo.VelopackProductVersion, DotnetUtil.VerifyVelopackApp(newPath, logger));
|
||||
Assert.Equal(VelopackRuntimeInfo.VelopackProductVersion, compat.Verify(newPath));
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public void PublishNet48Passes()
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
using var logger = _output.BuildLoggerFor<DotnetUtilTests>();
|
||||
using var logger = GetCompat(out var compat);
|
||||
using var _1 = Utility.GetTempDirectory(out var dir);
|
||||
var sample = PathHelper.GetWpfSample();
|
||||
Exe.InvokeAndThrowIfNonZero(
|
||||
@@ -75,18 +84,18 @@ public class DotnetUtilTests
|
||||
sample);
|
||||
|
||||
var path = Path.Combine(dir, "VeloWpfSample.exe");
|
||||
Assert.NotNull(DotnetUtil.VerifyVelopackApp(path, logger));
|
||||
Assert.NotNull(compat.Verify(path));
|
||||
|
||||
var newPath = Path.Combine(dir, "VeloWpfSample-asd2.exe");
|
||||
File.Move(path, newPath);
|
||||
Assert.NotNull(DotnetUtil.VerifyVelopackApp(newPath, logger));
|
||||
Assert.NotNull(compat.Verify(newPath));
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public void UnawareDotnetAppFails()
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
using var logger = _output.BuildLoggerFor<DotnetUtilTests>();
|
||||
using var logger = GetCompat(out var compat);
|
||||
using var _1 = Utility.GetTempDirectory(out var dir);
|
||||
var sample = PathHelper.GetTestRootPath("TestApp");
|
||||
Exe.InvokeAndThrowIfNonZero(
|
||||
@@ -96,6 +105,27 @@ public class DotnetUtilTests
|
||||
sample);
|
||||
|
||||
var path = Path.Combine(dir, "TestApp.exe");
|
||||
Assert.Throws<UserInfoException>(() => DotnetUtil.VerifyVelopackApp(path, logger));
|
||||
Assert.Throws<UserInfoException>(() => compat.Verify(path));
|
||||
}
|
||||
|
||||
[SkippableFact]
|
||||
public void PublishAsyncMainPasses()
|
||||
{
|
||||
Skip.IfNot(VelopackRuntimeInfo.IsWindows);
|
||||
using var logger = GetCompat(out var compat);
|
||||
using var _1 = Utility.GetTempDirectory(out var dir);
|
||||
var sample = PathHelper.GetTestRootPath("TestApp");
|
||||
Exe.InvokeAndThrowIfNonZero(
|
||||
"dotnet",
|
||||
new string[] { "publish", "--no-self-contained", "-r", "win-x64", "-o", dir,
|
||||
"-p:UseAsyncMain=true" },
|
||||
sample);
|
||||
|
||||
var path = Path.Combine(dir, "TestApp.exe");
|
||||
Assert.NotNull(compat.Verify(path));
|
||||
|
||||
var newPath = Path.Combine(dir, "VeloWpfSample-asd2.exe");
|
||||
File.Move(path, newPath);
|
||||
Assert.NotNull(compat.Verify(newPath));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user