Increase code coverage

pull/642/head
NextTurn 2020-08-08 00:00:00 +08:00
parent 4414e36f6b
commit b85593eb11
No known key found for this signature in database
GPG Key ID: 17A0D50ADDE1A0C4
18 changed files with 466 additions and 123 deletions

View File

@ -4,6 +4,15 @@
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<DebugType>full</DebugType>
<ArtifactsDir>$(MSBuildThisFileDirectory)artifacts\</ArtifactsDir>
<ArtifactsBinDir>$(ArtifactsDir)bin\</ArtifactsBinDir>
<ArtifactsObjDir>$(ArtifactsDir)obj\</ArtifactsObjDir>
<ArtifactsPublishDir>$(ArtifactsDir)publish\</ArtifactsPublishDir>
<RunSettingsFilePath>$(MSBuildThisFileDirectory)src\.runsettings</RunSettingsFilePath>
</PropertyGroup>
<PropertyGroup>
<BaseOutputPath>$(ArtifactsBinDir)$(MSBuildProjectName)\</BaseOutputPath>
<BaseIntermediateOutputPath>$(ArtifactsObjDir)$(MSBuildProjectName)\</BaseIntermediateOutputPath>
</PropertyGroup>
<ItemGroup>

View File

@ -25,7 +25,7 @@ More info about the wrapper is available in the projects GitHub repository.
</dependencies>
</metadata>
<files>
<file src="artifacts\WinSW.NET461.exe" target="lib\net461\WinSW.NET461.exe" />
<file src="artifacts\publish\WinSW.NET461.exe" target="lib\net461\WinSW.NET461.exe" />
<file src="samples\sample-complete.xml" target="lib\net461\WinSW.NET461.xml" />
</files>
</package>

View File

@ -50,7 +50,7 @@ jobs:
inputs:
command: test
projects: src\WinSW.Tests\WinSW.Tests.csproj
arguments: -c $(BuildConfiguration) --no-build
arguments: -c $(BuildConfiguration) --collect "XPlat Code Coverage" --no-build
- task: NuGetToolInstaller@1
displayName: Install Nuget
inputs:
@ -62,19 +62,19 @@ jobs:
packagesToPack: WinSW.nuspec
versioningScheme: byEnvVar
versionEnvVar: BuildVersion
- publish: artifacts\WinSW.NET461.exe
- publish: artifacts\publish\WinSW.NET461.exe
artifact: WinSW.NET461.exe_$(BuildConfiguration)
displayName: Publish .NET 4.6.1
- publish: artifacts\WinSW.NETCore.x64.zip
- publish: artifacts\publish\WinSW.NETCore.x64.zip
artifact: WinSW.NETCore.x64.zip_$(BuildConfiguration)
displayName: Publish .NET Core x64 .zip
- publish: artifacts\WinSW.NETCore.x86.zip
- publish: artifacts\publish\WinSW.NETCore.x86.zip
artifact: WinSW.NETCore.x86.zip_$(BuildConfiguration)
displayName: Publish .NET Core x86 .zip
- publish: artifacts\WinSW.NETCore.x64.exe
- publish: artifacts\publish\WinSW.NETCore.x64.exe
artifact: WinSW.NETCore.x64.exe_$(BuildConfiguration)
displayName: Publish .NET Core x64 .exe
- publish: artifacts\WinSW.NETCore.x86.exe
- publish: artifacts\publish\WinSW.NETCore.x86.exe
artifact: WinSW.NETCore.x86.exe_$(BuildConfiguration)
displayName: Publish .NET Core x86 .exe
- publish: $(Build.ArtifactStagingDirectory)\WinSW.$(BuildVersion).nupkg

6
src/.runsettings Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
<RunConfiguration>
<TargetPlatform>x64</TargetPlatform>
</RunConfiguration>
</RunSettings>

View File

@ -22,7 +22,7 @@ namespace WinSW.Configuration
public abstract string Executable { get; }
public string ExecutablePath => Process.GetCurrentProcess().MainModule.FileName;
public virtual string ExecutablePath => Process.GetCurrentProcess().MainModule.FileName;
public virtual bool HideWindow => false;

View File

@ -30,14 +30,14 @@ namespace WinSW
///
/// This string is "c:\abc\def\ghi" when the configuration XML is "c:\abc\def\ghi.xml"
/// </summary>
public string BasePath { get; set; }
public virtual string BasePath { get; }
/// <summary>
/// The file name portion of the configuration file.
///
/// In the above example, this would be "ghi".
/// </summary>
public string BaseName { get; set; }
public virtual string BaseName { get; set; }
/// <exception cref="FileNotFoundException" />
public XmlServiceConfig(string path)

View File

@ -0,0 +1,113 @@
using System;
using System.Diagnostics;
using System.IO;
using System.ServiceProcess;
using WinSW.Tests.Util;
using Xunit;
using Helper = WinSW.Tests.Util.CommandLineTestHelper;
namespace WinSW.Tests
{
public class CommandLineTests
{
[ElevatedFact]
public void Install_Start_Stop_Uninstall_Console_App()
{
using var config = Helper.TestXmlServiceConfig.FromXml(Helper.SeedXml);
try
{
_ = Helper.Test(new[] { "install", config.FullPath }, config);
using var controller = new ServiceController(Helper.Name);
Assert.Equal(Helper.DisplayName, controller.DisplayName);
Assert.False(controller.CanStop);
Assert.False(controller.CanShutdown);
Assert.False(controller.CanPauseAndContinue);
Assert.Equal(ServiceControllerStatus.Stopped, controller.Status);
Assert.Equal(ServiceType.Win32OwnProcess, controller.ServiceType);
#if NETFRAMEWORK
InterProcessCodeCoverageSession session = null;
try
{
try
{
_ = Helper.Test(new[] { "start", config.FullPath }, config);
controller.Refresh();
Assert.Equal(ServiceControllerStatus.Running, controller.Status);
Assert.True(controller.CanStop);
if (Environment.GetEnvironmentVariable("System.DefinitionId") != null)
{
session = new InterProcessCodeCoverageSession(Helper.Name);
}
}
finally
{
_ = Helper.Test(new[] { "stop", config.FullPath }, config);
controller.Refresh();
Assert.Equal(ServiceControllerStatus.Stopped, controller.Status);
}
}
finally
{
session?.Wait();
}
#endif
}
finally
{
_ = Helper.Test(new[] { "uninstall", config.FullPath }, config);
}
}
[Fact]
public void FailOnUnknownCommand()
{
const string commandName = "unknown";
CommandLineTestResult result = Helper.ErrorTest(new[] { commandName });
Assert.Equal($"Unrecognized command or argument '{commandName}'\r\n\r\n", result.Error);
}
/// <summary>
/// https://github.com/kohsuke/winsw/issues/206
/// </summary>
[Fact(Skip = "unknown")]
public void ShouldNotPrintLogsForStatusCommand()
{
string cliOut = Helper.Test(new[] { "status" });
Assert.Equal("NonExistent" + Environment.NewLine, cliOut);
}
[Fact]
public void Customize()
{
const string OldCompanyName = "CloudBees, Inc.";
const string NewCompanyName = "CLOUDBEES, INC.";
string inputPath = Layout.WinSWExe;
Assert.Equal(OldCompanyName, FileVersionInfo.GetVersionInfo(inputPath).CompanyName);
// deny write access
using FileStream file = File.OpenRead(inputPath);
string outputPath = Path.GetTempFileName();
Program.TestExecutablePath = inputPath;
try
{
_ = Helper.Test(new[] { "customize", "-o", outputPath, "--manufacturer", NewCompanyName });
Assert.Equal(NewCompanyName, FileVersionInfo.GetVersionInfo(outputPath).CompanyName);
}
finally
{
Program.TestExecutablePath = null;
File.Delete(outputPath);
}
}
}
}

View File

@ -1,83 +0,0 @@
using System;
using System.Diagnostics;
using System.IO;
using System.ServiceProcess;
using WinSW.Tests.Util;
using Xunit;
namespace WinSW.Tests
{
public class MainTest
{
[ElevatedFact]
public void TestInstall()
{
try
{
_ = CommandLineTestHelper.Test(new[] { "install" });
using ServiceController controller = new ServiceController(CommandLineTestHelper.Id);
Assert.Equal(CommandLineTestHelper.Name, controller.DisplayName);
Assert.False(controller.CanStop);
Assert.False(controller.CanShutdown);
Assert.False(controller.CanPauseAndContinue);
Assert.Equal(ServiceControllerStatus.Stopped, controller.Status);
Assert.Equal(ServiceType.Win32OwnProcess, controller.ServiceType);
}
finally
{
_ = CommandLineTestHelper.Test(new[] { "uninstall" });
}
}
[Fact]
public void FailOnUnknownCommand()
{
const string commandName = "unknown";
CommandLineTestResult result = CommandLineTestHelper.ErrorTest(new[] { commandName });
Assert.Equal($"Unrecognized command or argument '{commandName}'\r\n\r\n", result.Error);
}
/// <summary>
/// https://github.com/kohsuke/winsw/issues/206
/// </summary>
[Fact(Skip = "unknown")]
public void ShouldNotPrintLogsForStatusCommand()
{
string cliOut = CommandLineTestHelper.Test(new[] { "status" });
Assert.Equal("NonExistent" + Environment.NewLine, cliOut);
}
#if NET461
[Fact]
public void Customize()
{
const string OldCompanyName = "CloudBees, Inc.";
const string NewCompanyName = "CLOUDBEES, INC.";
string inputPath = Path.Combine(Layout.ArtifactsDirectory, "WinSW.NET461.exe");
Assert.Equal(OldCompanyName, FileVersionInfo.GetVersionInfo(inputPath).CompanyName);
// deny write access
using FileStream file = File.OpenRead(inputPath);
string outputPath = Path.GetTempFileName();
Program.TestExecutablePath = inputPath;
try
{
_ = CommandLineTestHelper.Test(new[] { "customize", "-o", outputPath, "--manufacturer", NewCompanyName });
Assert.Equal(NewCompanyName, FileVersionInfo.GetVersionInfo(outputPath).CompanyName);
}
finally
{
Program.TestExecutablePath = null;
File.Delete(outputPath);
}
}
#endif
}
}

View File

@ -1,4 +1,4 @@
#if NET461
#if NETFRAMEWORK
using System;
using System.IO;
using System.Reflection.Metadata;
@ -15,8 +15,7 @@ namespace WinSW.Tests
{
var version = new Version(4, 0, 0, 0);
using var file = File.OpenRead(Path.Combine(Layout.ArtifactsDirectory, "WinSW.NET461.exe"));
using var peReader = new PEReader(file);
using var peReader = new PEReader(File.OpenRead(Layout.NET461Exe));
var metadataReader = peReader.GetMetadataReader();
foreach (var handle in metadataReader.AssemblyReferences)
{

View File

@ -0,0 +1,9 @@
using Xunit;
namespace WinSW.Tests.Util
{
internal static class AssertEx
{
internal static void Succeeded(int hr) => Assert.InRange(hr, 0, int.MaxValue);
}
}

View File

@ -1,5 +1,7 @@
using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Xml;
using Xunit;
namespace WinSW.Tests.Util
@ -9,22 +11,18 @@ namespace WinSW.Tests.Util
/// </summary>
public static class CommandLineTestHelper
{
public const string Id = "WinSW.Tests";
public const string Name = "WinSW Test Service";
public const string Name = "WinSW.Tests";
public const string DisplayName = "WinSW Test Service";
private static readonly string SeedXml =
internal static readonly string SeedXml =
$@"<service>
<id>{Id}</id>
<name>{Name}</name>
<description>The service.</description>
<executable>node.exe</executable>
<arguments>My Arguments</arguments>
<log mode=""roll""></log>
<workingdirectory>C:\winsw\workdir</workingdirectory>
<logpath>C:\winsw\logs</logpath>
<id>{Name}</id>
<name>{DisplayName}</name>
<executable>cmd.exe</executable>
<arguments>/c timeout /t -1 /nobreak</arguments>
</service>";
public static readonly XmlServiceConfig DefaultServiceConfig = XmlServiceConfig.FromXml(SeedXml);
private static readonly XmlServiceConfig DefaultServiceConfig = XmlServiceConfig.FromXml(SeedXml);
/// <summary>
/// Runs a simle test, which returns the output CLI
@ -97,6 +95,69 @@ $@"<service>
return new CommandLineTestResult(swOut.ToString(), swError.ToString(), exception);
}
internal sealed class TestXmlServiceConfig : XmlServiceConfig, IDisposable
{
private readonly string directory;
private bool disposed;
internal TestXmlServiceConfig(XmlDocument document, string name)
: base(document)
{
string directory = this.directory = Path.Combine(Path.GetTempPath(), name);
_ = Directory.CreateDirectory(directory);
try
{
string path = this.FullPath = Path.Combine(directory, "config.xml");
using (var file = File.CreateText(path))
{
file.Write(SeedXml);
}
this.BaseName = name;
this.BasePath = Path.Combine(directory, name);
}
catch
{
Directory.Delete(directory, true);
throw;
}
}
~TestXmlServiceConfig() => this.Dispose(false);
public override string FullPath { get; }
public override string BasePath { get; }
public override string BaseName { get; set; }
public override string ExecutablePath => Layout.WinSWExe;
internal static TestXmlServiceConfig FromXml(string xml, [CallerMemberName] string name = null)
{
var document = new XmlDocument();
document.LoadXml(xml);
return new TestXmlServiceConfig(document, name);
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool _)
{
if (!disposed)
{
Directory.Delete(this.directory, true);
disposed = true;
}
}
}
}
/// <summary>

View File

@ -0,0 +1,191 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.Diagnostics.Runtime;
using Microsoft.Diagnostics.Runtime.Interop;
using WinSW.Native;
using Xunit;
namespace WinSW.Tests.Util
{
internal sealed class InterProcessCodeCoverageSession : IDebugEventCallbacks
{
private readonly Type trackerType;
private readonly FieldInfo hitsField;
private readonly IDebugControl control;
private readonly DataTarget target;
private readonly Thread thread;
private List<Exception> exceptions;
private bool exited;
internal InterProcessCodeCoverageSession(string serviceName)
{
var trackerType = this.trackerType = typeof(Program).Assembly.GetTypes().Single(type => type.Namespace == "Coverlet.Core.Instrumentation.Tracker");
var hitsField = this.hitsField = trackerType.GetField("HitsArray", BindingFlags.Public | BindingFlags.Static);
Assert.NotNull(hitsField);
using var scm = ServiceManager.Open();
using var sc = scm.OpenService(serviceName, ServiceApis.ServiceAccess.QUERY_STATUS);
int processId = sc.ProcessId;
Assert.True(processId >= 0);
var guid = new Guid("27fe5639-8407-4f47-8364-ee118fb08ac8");
int hr = Native.DebugCreate(guid, out object unknown);
AssertEx.Succeeded(hr);
var client = (IDebugClient)unknown;
this.control = (IDebugControl)unknown;
hr = client.AttachProcess(0, (uint)processId, DEBUG_ATTACH.DEFAULT);
AssertEx.Succeeded(hr);
hr = client.SetEventCallbacks(this);
AssertEx.Succeeded(hr);
IntPtr pointer = Marshal.GetIUnknownForObject(client);
Assert.Equal(1, Marshal.Release(pointer));
target = DataTarget.CreateFromDbgEng(pointer);
var thread = this.thread = new Thread(() =>
{
try
{
using (this.target)
{
do
{
int hr = this.control.WaitForEvent(DEBUG_WAIT.DEFAULT, 0xffffffff);
AssertEx.Succeeded(hr);
}
while (!this.exited);
}
}
catch (Exception e)
{
(this.exceptions ??= new List<Exception>()).Add(e);
}
});
thread.Start();
}
/// <exception cref="AggregateException" />
internal void Wait()
{
this.thread.Join();
if (this.exceptions != null)
{
throw new AggregateException(this.exceptions);
}
}
int IDebugEventCallbacks.GetInterestMask(out DEBUG_EVENT Mask)
{
Mask = DEBUG_EVENT.EXIT_PROCESS;
return 0;
}
int IDebugEventCallbacks.Breakpoint(IDebugBreakpoint Bp)
{
throw new NotImplementedException();
}
int IDebugEventCallbacks.Exception(in EXCEPTION_RECORD64 Exception, uint FirstChance)
{
throw new NotImplementedException();
}
int IDebugEventCallbacks.CreateThread(ulong Handle, ulong DataOffset, ulong StartOffset)
{
throw new NotImplementedException();
}
int IDebugEventCallbacks.ExitThread(uint ExitCode)
{
throw new NotImplementedException();
}
int IDebugEventCallbacks.CreateProcess(ulong ImageFileHandle, ulong Handle, ulong BaseOffset, uint ModuleSize, string ModuleName, string ImageName, uint CheckSum, uint TimeDateStamp, ulong InitialThreadHandle, ulong ThreadDataOffset, ulong StartOffset)
{
throw new NotImplementedException();
}
int IDebugEventCallbacks.ExitProcess(uint ExitCode)
{
this.exited = true;
try
{
using var runtime = this.target.ClrVersions.Single().CreateRuntime();
var module = runtime.EnumerateModules().First(module => module.Name == typeof(Program).Assembly.Location);
var type = module.GetTypeByName(this.trackerType.FullName);
var field = type.GetStaticFieldByName(this.hitsField.Name);
var array = field.ReadObject(runtime.AppDomains.Single()).AsArray();
int[] hits = (int[])this.hitsField.GetValue(null);
int[] values = array.ReadValues<int>(0, hits.Length);
for (int i = 0; i < hits.Length; i++)
{
hits[i] += values[i];
}
}
catch (Exception e)
{
(this.exceptions ??= new List<Exception>()).Add(e);
}
return (int)DEBUG_STATUS.BREAK;
}
int IDebugEventCallbacks.LoadModule(ulong ImageFileHandle, ulong BaseOffset, uint ModuleSize, string ModuleName, string ImageName, uint CheckSum, uint TimeDateStamp)
{
throw new NotImplementedException();
}
int IDebugEventCallbacks.UnloadModule(string ImageBaseName, ulong BaseOffset)
{
throw new NotImplementedException();
}
int IDebugEventCallbacks.SystemError(uint Error, uint Level)
{
throw new NotImplementedException();
}
int IDebugEventCallbacks.SessionStatus(DEBUG_SESSION Status)
{
throw new NotImplementedException();
}
int IDebugEventCallbacks.ChangeDebuggeeState(DEBUG_CDS Flags, ulong Argument)
{
throw new NotImplementedException();
}
int IDebugEventCallbacks.ChangeEngineState(DEBUG_CES Flags, ulong Argument)
{
throw new NotImplementedException();
}
int IDebugEventCallbacks.ChangeSymbolState(DEBUG_CSS Flags, ulong Argument)
{
throw new NotImplementedException();
}
private static class Native
{
[DllImport("dbgeng.dll")]
internal static extern int DebugCreate(in Guid InterfaceId, [MarshalAs(UnmanagedType.IUnknown)] out object Interface);
}
}
}

View File

@ -35,5 +35,14 @@ namespace WinSW.Tests.Util
}
internal static string ArtifactsDirectory => artifactsDirectory ??= Path.Combine(RepositoryRoot, "artifacts");
internal static string NET461Exe => Path.Combine(ArtifactsDirectory, "publish", "WinSW.NET461.exe");
internal static string WinSWExe =>
#if NETCOREAPP
Path.ChangeExtension(typeof(Program).Assembly.Location, ".exe");
#else
typeof(Program).Assembly.Location;
#endif
}
}

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net461;netcoreapp5.0</TargetFrameworks>
<TargetFrameworks>net471;netcoreapp5.0</TargetFrameworks>
<LangVersion>latest</LangVersion>
</PropertyGroup>
@ -10,6 +10,8 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.Diagnostics.Runtime" Version="2.0.137201" />
<PackageReference Include="Microsoft.Diagnostics.Runtime.Utilities" Version="2.0.0-rc.20303.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.2">
@ -29,4 +31,24 @@
<ProjectReference Include="..\WinSW.Plugins\WinSW.Plugins.csproj" />
</ItemGroup>
<ItemGroup>
<Content Include="xunit.runner.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Target Name="Copy" BeforeTargets="AfterBuild">
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp5.0'">
<_FilesToCopy Include="$(ArtifactsBinDir)WinSW\$(Configuration)\netcoreapp3.1\WinSW.runtimeconfig*.json" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'netcoreapp5.0'">
<_FilesToCopy Include="$(ArtifactsBinDir)WinSW\$(Configuration)\net461\System.ValueTuple.dll" />
</ItemGroup>
<Copy SourceFiles="@(_FilesToCopy)" DestinationFolder="$(OutputPath)" />
</Target>
</Project>

View File

@ -0,0 +1,4 @@
{
"$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
"shadowCopy": false
}

View File

@ -16,6 +16,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4975DCF4-C32C-43ED-A731-8FCC1F7E6746}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.runsettings = .runsettings
EndProjectSection
EndProject
Global

View File

@ -991,16 +991,16 @@ namespace WinSW
/// <exception cref="FileNotFoundException" />
private static XmlServiceConfig CreateConfig(string? path)
{
if (path != null)
{
return new XmlServiceConfig(path);
}
if (TestConfig != null)
{
return TestConfig;
}
if (path != null)
{
return new XmlServiceConfig(path);
}
path = Path.ChangeExtension(ExecutablePath, ".xml");
if (!File.Exists(path))
{

View File

@ -38,20 +38,22 @@
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' != 'netcoreapp3.1'">
<ProjectReference Include="..\WinSW.Tasks\WinSW.Tasks.csproj" />
<ProjectReference Include="..\WinSW.Tasks\WinSW.Tasks.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
<Target Name="PublishCoreZip" AfterTargets="Publish" Condition="'$(TargetFramework)' == 'netcoreapp3.1' and '$(PublishSingleFile)' != 'true'">
<MakeDir Directories="$(ArtifactsDir)" />
<ZipDirectory SourceDirectory="$(PublishDir)" DestinationFile="$(ArtifactsDir)WinSW.NETCore.$(PlatformTarget).zip" Overwrite="true" />
<MakeDir Directories="$(ArtifactsPublishDir)" />
<ZipDirectory SourceDirectory="$(PublishDir)" DestinationFile="$(ArtifactsPublishDir)WinSW.NETCore.$(PlatformTarget).zip" Overwrite="true" />
</Target>
<Target Name="PublishCoreExe" AfterTargets="Publish" Condition="'$(TargetFramework)' == 'netcoreapp3.1' and '$(PublishSingleFile)' == 'true'">
<MakeDir Directories="$(ArtifactsDir)" />
<Copy SourceFiles="$(PublishDir)$(TargetName).exe" DestinationFiles="$(ArtifactsDir)WinSW.NETCore.$(PlatformTarget).exe" />
<MakeDir Directories="$(ArtifactsPublishDir)" />
<Copy SourceFiles="$(PublishDir)$(TargetName).exe" DestinationFiles="$(ArtifactsPublishDir)WinSW.NETCore.$(PlatformTarget).exe" />
</Target>
@ -73,7 +75,7 @@
<InputAssemblies>$(InputAssemblies) "$(OutDir)System.Numerics.Vectors.dll"</InputAssemblies>
<InputAssemblies>$(InputAssemblies) "$(OutDir)System.Runtime.CompilerServices.Unsafe.dll"</InputAssemblies>
<InputAssemblies>$(InputAssemblies) "$(OutDir)System.ValueTuple.dll"</InputAssemblies>
<OutputAssembly>"$(ArtifactsDir)WinSW.$(TargetFrameworkSuffix).exe"</OutputAssembly>
<OutputAssembly>"$(ArtifactsPublishDir)WinSW.$(TargetFrameworkSuffix).exe"</OutputAssembly>
</PropertyGroup>
<PropertyGroup>
@ -82,14 +84,14 @@
<ILMergeCommand>"$(ILMerge)" $(ILMergeArgs)</ILMergeCommand>
</PropertyGroup>
<MakeDir Directories="$(ArtifactsDir)" />
<MakeDir Directories="$(ArtifactsPublishDir)" />
<Exec Command="$(ILMergeCommand)" />
</Target>
<UsingTask TaskName="WinSW.Tasks.Trim" AssemblyFile="..\WinSW.Tasks\bin\$(Configuration)\net461\WinSW.Tasks.dll" />
<UsingTask TaskName="WinSW.Tasks.Trim" AssemblyFile="$(ArtifactsBinDir)WinSW.Tasks\$(Configuration)\net461\WinSW.Tasks.dll" />
<Target Name="Trim" AfterTargets="Merge" Condition="'$(TargetFramework)' != 'netcoreapp3.1'">
<Trim Path="$(ArtifactsDir)WinSW.$(TargetFrameworkSuffix).exe" />
<Trim Path="$(ArtifactsPublishDir)WinSW.$(TargetFrameworkSuffix).exe" />
</Target>
</Project>