From a6ba41681d84d84d95eb7a377c369d709e32225b Mon Sep 17 00:00:00 2001 From: Next Turn <45985406+nxtn@users.noreply.github.com> Date: Sun, 29 Jan 2023 00:27:45 +0800 Subject: [PATCH] Upgrade to .NET 7 (#1001) --- eng/build.yml | 13 +- src/WinSW.Core/AssemblyInfo.cs | 4 +- src/WinSW.Core/WinSW.Core.csproj | 10 +- src/WinSW.Core/WrapperService.cs | 1 - src/WinSW.Plugins/WinSW.Plugins.csproj | 2 +- src/WinSW.Tasks/Trim.cs | 11 +- src/WinSW.Tasks/WinSW.Tasks.csproj | 2 +- src/WinSW.Tests/CommandLineTests.cs | 2 +- src/WinSW.Tests/WinSW.Tests.csproj | 14 +- src/WinSW/AssemblyInfo.cs | 4 +- src/WinSW/CommandExtensions.cs | 41 +++++ src/WinSW/Program.cs | 222 +++++++++++++------------ src/WinSW/WinSW.csproj | 29 ++-- 13 files changed, 206 insertions(+), 149 deletions(-) create mode 100644 src/WinSW/CommandExtensions.cs diff --git a/eng/build.yml b/eng/build.yml index a7417d3..0727edf 100644 --- a/eng/build.yml +++ b/eng/build.yml @@ -25,11 +25,6 @@ strategy: Release: BuildConfiguration: Release steps: -- task: UseDotNet@2 - displayName: Install .NET SDK - inputs: - packageType: sdk - version: 6.x - task: DotNetCoreCLI@2 displayName: Build inputs: @@ -37,9 +32,9 @@ steps: projects: src\WinSW.sln arguments: -c $(BuildConfiguration) -p:Version=$(BuildVersion) - script: | - dotnet publish src\WinSW\WinSW.csproj -c $(BuildConfiguration) -f net6.0-windows -r win-x64 -p:Version=$(BuildVersion) - dotnet publish src\WinSW\WinSW.csproj -c $(BuildConfiguration) -f net6.0-windows -r win-x86 -p:Version=$(BuildVersion) - dotnet publish src\WinSW\WinSW.csproj -c $(BuildConfiguration) -f net6.0-windows -r win-arm64 -p:Version=$(BuildVersion) + dotnet publish src\WinSW\WinSW.csproj -c $(BuildConfiguration) -f net7.0-windows -r win-x64 --sc -p:Version=$(BuildVersion) + dotnet publish src\WinSW\WinSW.csproj -c $(BuildConfiguration) -f net7.0-windows -r win-x86 --sc -p:Version=$(BuildVersion) + dotnet publish src\WinSW\WinSW.csproj -c $(BuildConfiguration) -f net7.0-windows -r win-arm64 --sc -p:Version=$(BuildVersion) displayName: Build - task: DotNetCoreCLI@2 displayName: Test @@ -73,7 +68,7 @@ steps: - publish: artifacts\publish\WinSW-arm64.exe artifact: WinSW-arm64.exe_$(BuildConfiguration) - displayName: Publish .NET arm64 .exe + displayName: Publish .NET Arm64 .exe - publish: $(Build.ArtifactStagingDirectory)\WinSW.$(BuildVersion).nupkg artifact: WinSW.nupkg_$(BuildConfiguration) diff --git a/src/WinSW.Core/AssemblyInfo.cs b/src/WinSW.Core/AssemblyInfo.cs index 3b0a125..7bd9500 100644 --- a/src/WinSW.Core/AssemblyInfo.cs +++ b/src/WinSW.Core/AssemblyInfo.cs @@ -1,4 +1,6 @@ -using System.Runtime.CompilerServices; +using System.Reflection; +using System.Runtime.CompilerServices; +[assembly: AssemblyMetadata("IsTrimmable", "True")] [assembly: InternalsVisibleTo("WinSW")] [assembly: InternalsVisibleTo("WinSW.Tests")] diff --git a/src/WinSW.Core/WinSW.Core.csproj b/src/WinSW.Core/WinSW.Core.csproj index e2caa00..768022c 100644 --- a/src/WinSW.Core/WinSW.Core.csproj +++ b/src/WinSW.Core/WinSW.Core.csproj @@ -1,8 +1,8 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFrameworks>net461;net6.0-windows</TargetFrameworks> - <LangVersion>preview</LangVersion> + <TargetFrameworks>net461;net7.0-windows</TargetFrameworks> + <LangVersion>latest</LangVersion> <Nullable>enable</Nullable> <AllowUnsafeBlocks>true</AllowUnsafeBlocks> </PropertyGroup> @@ -15,13 +15,13 @@ </PackageReference> </ItemGroup> - <ItemGroup Condition="'$(TargetFramework)' == 'net6.0-windows'"> + <ItemGroup Condition="'$(TargetFramework)' == 'net7.0-windows'"> <PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" /> <PackageReference Include="System.Security.AccessControl" Version="6.0.0" /> - <PackageReference Include="System.ServiceProcess.ServiceController" Version="5.0.0" /> + <PackageReference Include="System.ServiceProcess.ServiceController" Version="7.0.0" /> </ItemGroup> - <ItemGroup Condition="'$(TargetFramework)' != 'net6.0-windows'"> + <ItemGroup Condition="'$(TargetFramework)' != 'net7.0-windows'"> <PackageReference Include="System.Memory" Version="4.5.5" /> <PackageReference Include="System.ValueTuple" Version="4.5.0" /> <Reference Include="System.ServiceProcess" /> diff --git a/src/WinSW.Core/WrapperService.cs b/src/WinSW.Core/WrapperService.cs index 7a97721..33bf83a 100644 --- a/src/WinSW.Core/WrapperService.cs +++ b/src/WinSW.Core/WrapperService.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; diff --git a/src/WinSW.Plugins/WinSW.Plugins.csproj b/src/WinSW.Plugins/WinSW.Plugins.csproj index 3fdb8be..9971e51 100644 --- a/src/WinSW.Plugins/WinSW.Plugins.csproj +++ b/src/WinSW.Plugins/WinSW.Plugins.csproj @@ -1,7 +1,7 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFrameworks>net461;net6.0-windows</TargetFrameworks> + <TargetFrameworks>net461;net7.0-windows</TargetFrameworks> <LangVersion>latest</LangVersion> <Nullable>enable</Nullable> </PropertyGroup> diff --git a/src/WinSW.Tasks/Trim.cs b/src/WinSW.Tasks/Trim.cs index 1895189..62883ab 100644 --- a/src/WinSW.Tasks/Trim.cs +++ b/src/WinSW.Tasks/Trim.cs @@ -17,13 +17,18 @@ namespace WinSW.Tasks { using var module = ModuleDefinition.ReadModule(this.Path, new() { ReadWrite = true, ReadSymbols = true }); + foreach (var t in module.CustomAttributeTypes()) + { + this.WalkType(t); + } + this.WalkType(module.EntryPoint.DeclaringType); var types = module.Types; for (int i = types.Count - 1; i >= 0; i--) { var type = types[i]; - if (type.FullName.Contains("WinSW.Plugins")) + if (type.FullName.StartsWith("WinSW.Plugins")) { this.WalkType(type); } @@ -64,6 +69,10 @@ namespace WinSW.Tasks this.WalkType(genericArg); } } + else if (typeRef is IModifierType modifierType) + { + this.WalkType(modifierType.ModifierType); + } return; } diff --git a/src/WinSW.Tasks/WinSW.Tasks.csproj b/src/WinSW.Tasks/WinSW.Tasks.csproj index 874eb83..d19e91d 100644 --- a/src/WinSW.Tasks/WinSW.Tasks.csproj +++ b/src/WinSW.Tasks/WinSW.Tasks.csproj @@ -7,7 +7,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.Build.Utilities.Core" Version="17.2.0" /> + <PackageReference Include="Microsoft.Build.Utilities.Core" Version="17.4.0" /> <PackageReference Include="Mono.Cecil" Version="0.11.4" /> </ItemGroup> diff --git a/src/WinSW.Tests/CommandLineTests.cs b/src/WinSW.Tests/CommandLineTests.cs index fa7eff3..3c711b2 100644 --- a/src/WinSW.Tests/CommandLineTests.cs +++ b/src/WinSW.Tests/CommandLineTests.cs @@ -77,7 +77,7 @@ namespace WinSW.Tests var result = Helper.ErrorTest(new[] { commandName }); - Assert.Equal($"Unrecognized command or argument '{commandName}'\r\n\r\n", result.Error); + Assert.Equal($"Unrecognized command or argument '{commandName}'.\r\n\r\n", result.Error); } /// <summary> diff --git a/src/WinSW.Tests/WinSW.Tests.csproj b/src/WinSW.Tests/WinSW.Tests.csproj index a3a88fc..6288ec4 100644 --- a/src/WinSW.Tests/WinSW.Tests.csproj +++ b/src/WinSW.Tests/WinSW.Tests.csproj @@ -1,7 +1,7 @@ <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> - <TargetFrameworks>net471;net6.0-windows</TargetFrameworks> + <TargetFrameworks>net471;net7.0-windows</TargetFrameworks> <LangVersion>latest</LangVersion> </PropertyGroup> @@ -12,15 +12,15 @@ </PackageReference> <PackageReference Include="Microsoft.Diagnostics.Runtime" Version="2.0.226801" /> <PackageReference Include="Microsoft.Diagnostics.Runtime.Utilities" Version="2.0.0-rc.20303.3" /> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.0" /> - <PackageReference Include="xunit" Version="2.4.1" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" /> + <PackageReference Include="xunit" Version="2.4.2" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <PrivateAssets>all</PrivateAssets> </PackageReference> </ItemGroup> - <ItemGroup Condition="'$(TargetFramework)' != 'net6.0-windows'"> + <ItemGroup Condition="'$(TargetFramework)' != 'net7.0-windows'"> <PackageReference Include="System.Reflection.Metadata" Version="5.0.0" /> <Reference Include="System.ServiceProcess" /> </ItemGroup> @@ -39,11 +39,11 @@ <Target Name="Copy" BeforeTargets="AfterBuild"> - <ItemGroup Condition="'$(TargetFramework)' == 'net6.0-windows'"> - <_FilesToCopy Include="$(ArtifactsBinDir)WinSW\$(Configuration)\net6.0-windows\WinSW.runtimeconfig*.json" /> + <ItemGroup Condition="'$(TargetFramework)' == 'net7.0-windows'"> + <_FilesToCopy Include="$(ArtifactsBinDir)WinSW\$(Configuration)\net7.0-windows\WinSW.runtimeconfig*.json" /> </ItemGroup> - <ItemGroup Condition="'$(TargetFramework)' != 'net6.0-windows'"> + <ItemGroup Condition="'$(TargetFramework)' != 'net7.0-windows'"> <_FilesToCopy Include="$(ArtifactsBinDir)WinSW\$(Configuration)\net461\System.ValueTuple.dll" /> </ItemGroup> diff --git a/src/WinSW/AssemblyInfo.cs b/src/WinSW/AssemblyInfo.cs index 790f54e..3916c1f 100644 --- a/src/WinSW/AssemblyInfo.cs +++ b/src/WinSW/AssemblyInfo.cs @@ -1,3 +1,5 @@ -using System.Runtime.CompilerServices; +using System.Reflection; +using System.Runtime.CompilerServices; +[assembly: AssemblyMetadata("IsTrimmable", "True")] [assembly: InternalsVisibleTo("WinSW.Tests")] diff --git a/src/WinSW/CommandExtensions.cs b/src/WinSW/CommandExtensions.cs new file mode 100644 index 0000000..f5537fa --- /dev/null +++ b/src/WinSW/CommandExtensions.cs @@ -0,0 +1,41 @@ +using System; +using System.CommandLine; +using System.CommandLine.Invocation; + +namespace WinSW +{ + internal static class CommandExtensions + { + internal static void SetHandler<T>(this Command command, Action<T, InvocationContext> handle, Argument<T> symbol) + { + command.SetHandler(context => + { + var value = context.ParseResult.GetValueForArgument(symbol); + handle(value!, context); + }); + } + + internal static void SetHandler<T1, T2, T3>(this Command command, Action<T1, T2, T3, InvocationContext> handle, Argument<T1> symbol1, Option<T2> symbol2, Option<T3> symbol3) + { + command.SetHandler(context => + { + var value1 = context.ParseResult.GetValueForArgument(symbol1); + var value2 = context.ParseResult.GetValueForOption(symbol2); + var value3 = context.ParseResult.GetValueForOption(symbol3); + handle(value1!, value2!, value3!, context); + }); + } + + internal static void SetHandler<T1, T2, T3, T4>(this Command command, Action<T1, T2, T3, T4, InvocationContext> handle, Argument<T1> symbol1, Option<T2> symbol2, Option<T3> symbol3, Option<T4> symbol4) + { + command.SetHandler(context => + { + var value1 = context.ParseResult.GetValueForArgument(symbol1); + var value2 = context.ParseResult.GetValueForOption(symbol2); + var value3 = context.ParseResult.GetValueForOption(symbol3); + var value4 = context.ParseResult.GetValueForOption(symbol4); + handle(value1!, value2!, value3!, value4!, context); + }); + } + } +} diff --git a/src/WinSW/Program.cs b/src/WinSW/Program.cs index f085eb0..ecc203f 100644 --- a/src/WinSW/Program.cs +++ b/src/WinSW/Program.cs @@ -13,7 +13,6 @@ using System.Reflection; using System.Security.AccessControl; using System.Security.Principal; using System.ServiceProcess; -using System.Threading; using log4net; using log4net.Appender; using log4net.Config; @@ -107,36 +106,14 @@ namespace WinSW elevated = IsProcessElevated(); } - var root = new RootCommand("A wrapper binary that can be used to host executables as Windows services. https://github.com/winsw/winsw") + var serviceConfig = new Argument<string?>("path-to-config") { - Handler = CommandHandler.Create((string? pathToConfig) => - { - XmlServiceConfig config = null!; - try - { - config = LoadConfigAndInitLoggers(pathToConfig, false); - } - catch (FileNotFoundException) - { - Throw.Command.Exception("The specified command or file was not found."); - } - - Log.Debug("Starting WinSW in service mode."); - - AutoRefresh(config); - - using var service = new WrapperService(config); - try - { - ServiceBase.Run(service); - } - catch - { - // handled in OnStart - } - }), + Arity = ArgumentArity.ZeroOrOne, + IsHidden = true, }; + var root = new RootCommand("A wrapper binary that can be used to host executables as Windows services. https://github.com/winsw/winsw"); + using (var identity = WindowsIdentity.GetCurrent()) { var principal = new WindowsPrincipal(identity); @@ -145,31 +122,31 @@ namespace WinSW principal.IsInRole(new SecurityIdentifier(WellKnownSidType.LocalServiceSid, null)) || principal.IsInRole(new SecurityIdentifier(WellKnownSidType.NetworkServiceSid, null))) { - root.Add(new Argument<string?>("path-to-config") - { - Arity = ArgumentArity.ZeroOrOne, - IsHidden = true, - }); + root.Add(serviceConfig); } } + root.SetHandler(Run, serviceConfig); + var config = new Argument<string?>("path-to-config", "The path to the configuration file.") { Arity = ArgumentArity.ZeroOrOne, }; - var noElevate = new Option("--no-elevate", "Doesn't automatically trigger a UAC prompt."); + var noElevate = new Option<bool>("--no-elevate", "Doesn't automatically trigger a UAC prompt."); { + var username = new Option<string?>(new[] { "--username", "--user" }, "Specifies the user name of the service account."); + var password = new Option<string?>(new[] { "--password", "--pass" }, "Specifies the password of the service account."); + var install = new Command("install", "Installs the service.") { - Handler = CommandHandler.Create<string?, bool, string?, string?>(Install), + config, + noElevate, + username, + password, }; - - install.Add(config); - install.Add(noElevate); - install.Add(new Option<string?>(new[] { "--username", "--user" }, "Specifies the user name of the service account.")); - install.Add(new Option<string?>(new[] { "--password", "--pass" }, "Specifies the password of the service account.")); + install.SetHandler(Install, config, noElevate, username, password); root.Add(install); } @@ -177,51 +154,54 @@ namespace WinSW { var uninstall = new Command("uninstall", "Uninstalls the service.") { - Handler = CommandHandler.Create<string?, bool>(Uninstall), + config, + noElevate, }; - - uninstall.Add(config); - uninstall.Add(noElevate); + uninstall.SetHandler(Uninstall, config, noElevate); root.Add(uninstall); } { + var noWait = new Option<bool>("--no-wait", "Doesn't wait for the service to actually start."); + var start = new Command("start", "Starts the service.") { - Handler = CommandHandler.Create<string?, bool, bool, CancellationToken>(Start), + config, + noElevate, + noWait, }; - - start.Add(config); - start.Add(noElevate); - start.Add(new Option("--no-wait", "Doesn't wait for the service to actually start.")); + start.SetHandler(Start, config, noElevate, noWait); root.Add(start); } { + var noWait = new Option<bool>("--no-wait", "Doesn't wait for the service to actually stop."); + var force = new Option<bool>("--force", "Stops the service even if it has started dependent services."); + var stop = new Command("stop", "Stops the service.") { - Handler = CommandHandler.Create<string?, bool, bool, bool, CancellationToken>(Stop), + config, + noElevate, + noWait, + force, }; - - stop.Add(config); - stop.Add(noElevate); - stop.Add(new Option("--no-wait", "Doesn't wait for the service to actually stop.")); - stop.Add(new Option("--force", "Stops the service even if it has started dependent services.")); + stop.SetHandler(Stop, config, noElevate, noWait, force); root.Add(stop); } { + var force = new Option<bool>("--force", "Restarts the service even if it has started dependent services."); + var restart = new Command("restart", "Stops and then starts the service.") { - Handler = CommandHandler.Create<string?, bool, bool, CancellationToken>(Restart), + config, + noElevate, + force, }; - - restart.Add(config); - restart.Add(noElevate); - restart.Add(new Option("--force", "Restarts the service even if it has started dependent services.")); + restart.SetHandler(Restart, config, noElevate, force); root.Add(restart); } @@ -229,10 +209,9 @@ namespace WinSW { var restartSelf = new Command("restart!", "self-restart (can be called from child processes)") { - Handler = CommandHandler.Create<string?>(RestartSelf), + config, }; - - restartSelf.Add(config); + restartSelf.SetHandler(RestartSelf, config); root.Add(restartSelf); } @@ -240,10 +219,9 @@ namespace WinSW { var status = new Command("status", "Checks the status of the service.") { - Handler = CommandHandler.Create<string?>(Status), + config, }; - - status.Add(config); + status.SetHandler(Status, config); root.Add(status); } @@ -251,44 +229,43 @@ namespace WinSW { var refresh = new Command("refresh", "Refreshes the service properties without reinstallation.") { - Handler = CommandHandler.Create<string?, bool>(Refresh), + config, + noElevate, }; - - refresh.Add(config); - refresh.Add(noElevate); + refresh.SetHandler(Refresh, config, noElevate); root.Add(refresh); } { - var customize = new Command("customize", "Customizes the wrapper executable.") + var output = new Option<string>(new[] { "--output", "-o" }) { - Handler = CommandHandler.Create<string, string>(Customize), + IsRequired = true, }; - customize.Add(new Option<string>(new[] { "--output", "-o" }) - { - Required = true, - }); - var manufacturer = new Option<string>("--manufacturer") { - Required = true, + IsRequired = true, }; - manufacturer.Argument.AddValidator(argument => + manufacturer.AddValidator(result => { const int minLength = 12; const int maxLength = 15; - string token = argument.Tokens.Single().Value; + string token = result.Tokens.Single().Value; int length = token.Length; - return + result.ErrorMessage = length < minLength ? $"The length of argument '{token}' must be greater than or equal to {minLength}." : length > maxLength ? $"The length of argument '{token}' must be less than or equal to {maxLength}." : null; }); - customize.Add(manufacturer); + var customize = new Command("customize", "Customizes the wrapper executable.") + { + output, + manufacturer, + }; + customize.SetHandler(Customize, output, manufacturer); root.Add(customize); } @@ -299,14 +276,14 @@ namespace WinSW root.Add(dev); { + var all = new Option<bool>(new[] { "--all", "-a" }); + var ps = new Command("ps", "Draws the process tree associated with the service.") { - Handler = CommandHandler.Create<string?, bool>(DevPs), + config, + all, }; - - ps.Add(config); - - ps.Add(new Option(new[] { "--all", "-a" })); + ps.SetHandler(DevPs, config, all); dev.Add(ps); } @@ -314,20 +291,17 @@ namespace WinSW { var kill = new Command("kill", "Terminates the service if it has stopped responding.") { - Handler = CommandHandler.Create<string?, bool>(DevKill), + config, + noElevate, }; - - kill.Add(config); - kill.Add(noElevate); + kill.SetHandler(DevKill, config, noElevate); dev.Add(kill); } { - var list = new Command("list", "Lists services managed by the current executable.") - { - Handler = CommandHandler.Create(DevList), - }; + var list = new Command("list", "Lists services managed by the current executable."); + list.SetHandler(DevList); dev.Add(list); } @@ -346,16 +320,13 @@ namespace WinSW static void OnException(Exception exception, InvocationContext context) { - Debug.Assert(exception is TargetInvocationException); - Debug.Assert(exception.InnerException != null); - exception = exception.InnerException!; switch (exception) { case InvalidDataException e: { string message = "The configuration file could not be loaded. " + e.Message; Log.Fatal(message, e); - context.ResultCode = -1; + context.ExitCode = -1; break; } @@ -363,7 +334,7 @@ namespace WinSW { Debug.Assert(e.CancellationToken == context.GetCancellationToken()); Log.Fatal(e.Message); - context.ResultCode = -1; + context.ExitCode = -1; break; } @@ -371,7 +342,7 @@ namespace WinSW { string message = e.Message; Log.Fatal(message); - context.ResultCode = e.InnerException is Win32Exception inner ? inner.NativeErrorCode : -1; + context.ExitCode = e.InnerException is Win32Exception inner ? inner.NativeErrorCode : -1; break; } @@ -379,7 +350,7 @@ namespace WinSW { string message = e.Message; Log.Fatal(message); - context.ResultCode = inner.NativeErrorCode; + context.ExitCode = inner.NativeErrorCode; break; } @@ -387,19 +358,46 @@ namespace WinSW { string message = e.Message; Log.Fatal(message, e); - context.ResultCode = e.NativeErrorCode; + context.ExitCode = e.NativeErrorCode; break; } default: { Log.Fatal("Unhandled exception", exception); - context.ResultCode = -1; + context.ExitCode = -1; break; } } } + static void Run(string? pathToConfig) + { + XmlServiceConfig config = null!; + try + { + config = LoadConfigAndInitLoggers(pathToConfig, false); + } + catch (FileNotFoundException) + { + Throw.Command.Exception("The specified command or file was not found."); + } + + Log.Debug("Starting WinSW in service mode."); + + AutoRefresh(config); + + using var service = new WrapperService(config); + try + { + ServiceBase.Run(service); + } + catch + { + // handled in OnStart + } + } + void Install(string? pathToConfig, bool noElevate, string? username, string? password) { var config = LoadConfigAndInitLoggers(pathToConfig, true); @@ -557,7 +555,7 @@ namespace WinSW } } - void Start(string? pathToConfig, bool noElevate, bool noWait, CancellationToken ct) + void Start(string? pathToConfig, bool noElevate, bool noWait, InvocationContext context) { var config = LoadConfigAndInitLoggers(pathToConfig, true); @@ -580,6 +578,7 @@ namespace WinSW { try { + var ct = context.GetCancellationToken(); svc.WaitForStatus(ServiceControllerStatus.Running, ServiceControllerStatus.StartPending, ct); } catch (TimeoutException) @@ -602,7 +601,7 @@ namespace WinSW } } - void Stop(string? pathToConfig, bool noElevate, bool noWait, bool force, CancellationToken ct) + void Stop(string? pathToConfig, bool noElevate, bool noWait, bool force, InvocationContext context) { var config = LoadConfigAndInitLoggers(pathToConfig, true); @@ -633,6 +632,7 @@ namespace WinSW { try { + var ct = context.GetCancellationToken(); svc.WaitForStatus(ServiceControllerStatus.Stopped, ServiceControllerStatus.StopPending, ct); } catch (TimeoutException) @@ -655,7 +655,7 @@ namespace WinSW } } - void Restart(string? pathToConfig, bool noElevate, bool force, CancellationToken ct) + void Restart(string? pathToConfig, bool noElevate, bool force, InvocationContext context) { var config = LoadConfigAndInitLoggers(pathToConfig, true); @@ -688,6 +688,7 @@ namespace WinSW try { + var ct = context.GetCancellationToken(); svc.WaitForStatus(ServiceControllerStatus.Stopped, ServiceControllerStatus.StopPending, ct); } catch (TimeoutException) @@ -710,6 +711,7 @@ namespace WinSW try { + var ct = context.GetCancellationToken(); svc.WaitForStatus(ServiceControllerStatus.Running, ServiceControllerStatus.StartPending, ct); } catch (TimeoutException) @@ -763,7 +765,7 @@ namespace WinSW _ = HandleApis.CloseHandle(processInfo.ThreadHandle); } - static int Status(string? pathToConfig) + static void Status(string? pathToConfig, InvocationContext context) { var config = LoadConfigAndInitLoggers(pathToConfig, true); @@ -781,7 +783,7 @@ namespace WinSW _ => "Inactive (stopped)" }); - return svc.Status switch + context.ExitCode = svc.Status switch { ServiceControllerStatus.Stopped => 0, _ => 1 @@ -791,7 +793,7 @@ namespace WinSW when (e.InnerException is Win32Exception inner && inner.NativeErrorCode == Errors.ERROR_SERVICE_DOES_NOT_EXIST) { Console.WriteLine("NonExistent"); - return Errors.ERROR_SERVICE_DOES_NOT_EXIST; + context.ExitCode = Errors.ERROR_SERVICE_DOES_NOT_EXIST; } } diff --git a/src/WinSW/WinSW.csproj b/src/WinSW/WinSW.csproj index 0c3b021..19bdada 100644 --- a/src/WinSW/WinSW.csproj +++ b/src/WinSW/WinSW.csproj @@ -2,11 +2,10 @@ <PropertyGroup> <OutputType>Exe</OutputType> - <TargetFrameworks>net461;net6.0-windows</TargetFrameworks> - <LangVersion>preview</LangVersion> + <TargetFrameworks>net461;net7.0-windows</TargetFrameworks> + <LangVersion>latest</LangVersion> <Nullable>enable</Nullable> <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - <PublishTrimmed>true</PublishTrimmed> <AssemblyTitle>Windows Service Wrapper</AssemblyTitle> <Description>Allows arbitrary process to run as a Windows service by wrapping it.</Description> @@ -15,19 +14,27 @@ <Copyright>Copyright (c) 2008-2020 Kohsuke Kawaguchi, Sun Microsystems, Inc., CloudBees, Inc., Oleg Nenashev and other contributors</Copyright> </PropertyGroup> - <PropertyGroup Condition="'$(TargetFramework)' == 'net6.0-windows' AND '$(RuntimeIdentifier)' != ''"> + <PropertyGroup> + <PublishTrimmed>true</PublishTrimmed> + <TrimMode>partial</TrimMode> + <DebuggerSupport>false</DebuggerSupport> + <NullabilityInfoContextSupport>false</NullabilityInfoContextSupport> + <_AggressiveAttributeTrimming>true</_AggressiveAttributeTrimming> + </PropertyGroup> + + <PropertyGroup Condition="'$(TargetFramework)' == 'net7.0-windows' AND '$(RuntimeIdentifier)' != ''"> <PublishSingleFile>true</PublishSingleFile> </PropertyGroup> - <PropertyGroup Condition="'$(TargetFramework)' != 'net6.0-windows'"> + <PropertyGroup Condition="'$(TargetFramework)' != 'net7.0-windows'"> <ILMergeVersion>3.0.41</ILMergeVersion> </PropertyGroup> <ItemGroup> - <PackageReference Include="System.CommandLine" Version="2.0.0-beta1.20303.1" /> + <PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" /> </ItemGroup> - <ItemGroup Condition="'$(TargetFramework)' != 'net6.0-windows'"> + <ItemGroup Condition="'$(TargetFramework)' != 'net7.0-windows'"> <PackageReference Include="ilmerge" Version="$(ILMergeVersion)" /> <Reference Include="System.ServiceProcess" /> </ItemGroup> @@ -37,11 +44,11 @@ <ProjectReference Include="..\WinSW.Plugins\WinSW.Plugins.csproj" /> </ItemGroup> - <ItemGroup Condition="'$(TargetFramework)' != 'net6.0-windows'"> + <ItemGroup Condition="'$(TargetFramework)' != 'net7.0-windows'"> <ProjectReference Include="..\WinSW.Tasks\WinSW.Tasks.csproj" ReferenceOutputAssembly="false" /> </ItemGroup> - <Target Name="PublishCoreExe" AfterTargets="Publish" Condition="'$(TargetFramework)' == 'net6.0-windows'"> + <Target Name="PublishCoreExe" AfterTargets="Publish" Condition="'$(TargetFramework)' == 'net7.0-windows'"> <MakeDir Directories="$(ArtifactsPublishDir)" /> <Copy SourceFiles="$(PublishDir)$(TargetName).exe" DestinationFiles="$(ArtifactsPublishDir)WinSW-$(PlatformTarget).exe" /> @@ -49,7 +56,7 @@ </Target> <!-- Merge plugins and other DLLs into the executable --> - <Target Name="Merge" BeforeTargets="AfterBuild" Condition="'$(TargetFramework)' != 'net6.0-windows'"> + <Target Name="Merge" BeforeTargets="AfterBuild" Condition="'$(TargetFramework)' != 'net7.0-windows'"> <PropertyGroup> <InputAssemblies>"$(OutDir)$(TargetFileName)"</InputAssemblies> @@ -77,7 +84,7 @@ </Target> <UsingTask TaskName="WinSW.Tasks.Trim" AssemblyFile="$(ArtifactsBinDir)WinSW.Tasks\$(Configuration)\net461\WinSW.Tasks.dll" /> - <Target Name="Trim" AfterTargets="Merge" Condition="'$(TargetFramework)' != 'net6.0-windows'"> + <Target Name="Trim" AfterTargets="Merge" Condition="'$(TargetFramework)' != 'net7.0-windows'"> <Trim Path="$(ArtifactsPublishDir)WinSW-$(TargetFramework).exe" /> </Target>