Merge pull request #532 from NextTurn/args

Support <startarguments> and <stoparguments>
pull/513/head
Oleg Nenashev 2020-05-10 23:00:14 +02:00 committed by GitHub
commit 3ca706678c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 62 additions and 42 deletions

View File

@ -92,9 +92,9 @@ Optionally set a different logging directory with `<logpath>` and startup `<logm
See the [Logging and error reporting](loggingAndErrorReporting.md) page for more info.
### argument
### Arguments
This element specifies the arguments to be passed to the executable.
`<argument>` element specifies the arguments to be passed to the executable.
Winsw will quote each argument if necessary, so do not put quotes in `<argument>` to avoid double quotation.
```xml
@ -107,12 +107,12 @@ Winsw will quote each argument if necessary, so do not put quotes in `<argument>
### stopargument/stopexecutable
When the service is requested to stop, winsw simply calls [TerminateProcess function](https://docs.microsoft.com/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminateprocess) to kill the service instantly.
However, if `<stopargument>` elements are present, winsw will instead launch another process of `<executable>` (or `<stopexecutable>` if that's specified) with the `<stopargument>` arguments, and expects that to initiate the graceful shutdown of the service process.
~~When the service is requested to stop, winsw simply calls [TerminateProcess function](https://docs.microsoft.com/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminateprocess) to kill the service instantly.~~
However, if `<stopargument>`/`<stoparguments>` elements are present, winsw will instead launch another process of `<executable>` (or `<stopexecutable>` if that's specified) with the specified arguments, and expects that to initiate the graceful shutdown of the service process.
Winsw will then wait for the two processes to exit on its own, before reporting back to Windows that the service has terminated.
When you use the `<stopargument>`, you must use `<startargument>` instead of `<argument>`. See the complete example below:
When you use the `<stopargument>`/`<stoparguments>`, you must use `<startargument>`/`<startarguments>` instead of `<argument>`. See the complete example below:
```xml
<executable>catalina.sh</executable>
@ -123,9 +123,6 @@ When you use the `<stopargument>`, you must use `<startargument>` instead of `<a
<stopargument>stop</stopargument>
```
Note that the name of the element is `startargument` and not `startarguments`.
As such, to specify multiple arguments, you'll specify multiple elements.
### stoptimeout
When the service is requested to stop, winsw first attempts to send a Ctrl+C signal,

View File

@ -157,7 +157,7 @@ SECTION: Executable management
This OPTION also enables termination of the executable via stop executable
-->
<!--
<stoparguments>-stop true</stoparguments>-->
<stoparguments>-stop true</stoparguments>
-->
<!--
SECTION: Service management

View File

@ -268,31 +268,31 @@ namespace winsw
}
#endif
string? startarguments = _descriptor.Startarguments;
string? startArguments = _descriptor.StartArguments;
if (startarguments is null)
if (startArguments is null)
{
startarguments = _descriptor.Arguments;
startArguments = _descriptor.Arguments;
}
else
{
startarguments += " " + _descriptor.Arguments;
startArguments += " " + _descriptor.Arguments;
}
// Converting newlines, line returns, tabs into a single
// space. This allows users to provide multi-line arguments
// in the xml for readability.
startarguments = Regex.Replace(startarguments, @"\s*[\n\r]+\s*", " ");
startArguments = Regex.Replace(startArguments, @"\s*[\n\r]+\s*", " ");
LogEvent("Starting " + _descriptor.Executable + ' ' + startarguments);
Log.Info("Starting " + _descriptor.Executable + ' ' + startarguments);
LogEvent("Starting " + _descriptor.Executable + ' ' + startArguments);
Log.Info("Starting " + _descriptor.Executable + ' ' + startArguments);
// Load and start extensions
ExtensionManager.LoadExtensions();
ExtensionManager.FireOnWrapperStarted();
LogHandler executableLogHandler = CreateExecutableLogHandler();
StartProcess(_process, startarguments, _descriptor.Executable, executableLogHandler, true);
StartProcess(_process, startArguments, _descriptor.Executable, executableLogHandler, true);
ExtensionManager.FireOnProcessStarted(_process);
_process.StandardInput.Close(); // nothing for you to read!
@ -332,12 +332,12 @@ namespace winsw
/// </summary>
private void StopIt()
{
string? stoparguments = _descriptor.Stoparguments;
string? stopArguments = _descriptor.StopArguments;
LogEvent("Stopping " + _descriptor.Id);
Log.Info("Stopping " + _descriptor.Id);
_orderlyShutdown = true;
if (stoparguments is null)
if (stopArguments is null)
{
try
{
@ -354,7 +354,7 @@ namespace winsw
{
SignalShutdownPending();
stoparguments += " " + _descriptor.Arguments;
stopArguments += " " + _descriptor.Arguments;
Process stopProcess = new Process();
string? executable = _descriptor.StopExecutable;
@ -362,7 +362,7 @@ namespace winsw
executable ??= _descriptor.Executable;
// TODO: Redirect logging to Log4Net once https://github.com/kohsuke/winsw/pull/213 is integrated
StartProcess(stopProcess, stoparguments, executable, null, false);
StartProcess(stopProcess, stopArguments, executable, null, false);
Log.Debug("WaitForProcessToExit " + _process.Id + "+" + stopProcess.Id);
WaitForProcessToExit(_process);

View File

@ -29,9 +29,9 @@ namespace winsw.Configuration
// Executable management
public string Arguments => string.Empty;
public string? Startarguments => null;
public string? StartArguments => null;
public string? StopExecutable => null;
public string? Stoparguments => null;
public string? StopArguments => null;
public string WorkingDirectory => Path.GetDirectoryName(ExecutablePath)!;
public ProcessPriorityClass Priority => ProcessPriorityClass.Normal;
public TimeSpan StopTimeout => TimeSpan.FromSeconds(15);

View File

@ -26,9 +26,9 @@ namespace winsw.Configuration
// Executable management
string Arguments { get; }
string? Startarguments { get; }
string? StartArguments { get; }
string? StopExecutable { get; }
string? Stoparguments { get; }
string? StopArguments { get; }
string WorkingDirectory { get; }
ProcessPriorityClass Priority { get; }
TimeSpan StopTimeout { get; }

View File

@ -185,7 +185,7 @@ namespace winsw
public string? StopExecutable => SingleElement("stopexecutable", true);
/// <summary>
/// Arguments or multiple optional argument elements which overrule the arguments element.
/// <c>arguments</c> or multiple optional <c>argument</c> elements which overrule the arguments element.
/// </summary>
public string Arguments
{
@ -193,33 +193,56 @@ namespace winsw
{
string? arguments = AppendTags("argument", null);
if (arguments is null)
{
XmlNode? argumentsNode = dom.SelectSingleNode("//arguments");
if (argumentsNode is null)
{
return Defaults.Arguments;
}
return Environment.ExpandEnvironmentVariables(argumentsNode.InnerText);
}
else
if (!(arguments is null))
{
return arguments;
}
XmlNode? argumentsNode = dom.SelectSingleNode("//arguments");
return argumentsNode is null ? Defaults.Arguments : Environment.ExpandEnvironmentVariables(argumentsNode.InnerText);
}
}
/// <summary>
/// Multiple optional startargument elements.
/// <c>startarguments</c> or multiple optional <c>startargument</c> elements.
/// </summary>
public string? Startarguments => AppendTags("startargument", Defaults.Startarguments);
public string? StartArguments
{
get
{
string? startArguments = AppendTags("startargument", null);
if (!(startArguments is null))
{
return startArguments;
}
XmlNode? startArgumentsNode = dom.SelectSingleNode("//startarguments");
return startArgumentsNode is null ? null : Environment.ExpandEnvironmentVariables(startArgumentsNode.InnerText);
}
}
/// <summary>
/// Multiple optional stopargument elements.
/// <c>stoparguments</c> or multiple optional <c>stopargument</c> elements.
/// </summary>
public string? Stoparguments => AppendTags("stopargument", Defaults.Stoparguments);
public string? StopArguments
{
get
{
string? stopArguments = AppendTags("stopargument", null);
if (!(stopArguments is null))
{
return stopArguments;
}
XmlNode? stopArgumentsNode = dom.SelectSingleNode("//stoparguments");
return stopArgumentsNode is null ? null : Environment.ExpandEnvironmentVariables(stopArgumentsNode.InnerText);
}
}
public string WorkingDirectory
{