mirror of https://github.com/winsw/winsw
Merge pull request #170 from oleg-nenashev/sample-config-file
Provide WinSW configuration samplespull/177/head
commit
ece313e28e
|
@ -45,6 +45,10 @@ artifacts:
|
|||
name: WinSW.NET4.exe
|
||||
- path: 'WinSW.$(appveyor_build_version).nupkg'
|
||||
name: WinSW.nupkg
|
||||
- path: 'examples/sample-allOptions.xml'
|
||||
name: 'sample-allOptions.xml'
|
||||
- path: 'examples/sample-minimal.xml'
|
||||
name: 'sample-minimal.xml'
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -3,6 +3,9 @@ WinSW XML Configuration File
|
|||
|
||||
This page describes the configuration file, which controls the behavior of the Jenkins service.
|
||||
|
||||
You can find configuration file samples in the `examples` directory of the source code repository.
|
||||
Actual samples are being also published as a part of releases in GitHub and NuGet.
|
||||
|
||||
## File structure
|
||||
|
||||
The root element of this XML file must be `<service>`, and it supports the following child element.
|
||||
|
|
|
@ -0,0 +1,288 @@
|
|||
<!--
|
||||
Copyright (c) 2016 Oleg Nenashev and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
software and associated documentation files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
-->
|
||||
|
||||
<!--
|
||||
This is a sample configuration of the Windows Service Wrapper.
|
||||
This configuration file should be placed near the WinSW executable, the name should be the same.
|
||||
E.g. for myapp.exe the configuration file name should be myapp.xml
|
||||
|
||||
You can find more information about configuration options here: https://github.com/kohsuke/winsw/blob/master/doc/xmlConfigFile.md
|
||||
-->
|
||||
<configuration>
|
||||
|
||||
<!--
|
||||
SECTION: Mandatory options
|
||||
All options in other sections are optional
|
||||
-->
|
||||
|
||||
<!-- ID of the service. It should be unique accross the Windows system-->
|
||||
<id>myapp</id>
|
||||
<!-- Display name of the service -->
|
||||
<name>MyApp Service (powered by WinSW)</name>
|
||||
<!-- Service description -->
|
||||
<description>This service is a service cratead from a sample configuration</description>
|
||||
|
||||
<!-- Path to the executable, which should be started -->
|
||||
<executable>%BASE%\myExecutable.exe</executable>
|
||||
|
||||
<!--
|
||||
SECTION: Installation
|
||||
These options are being used during the installation only.
|
||||
Their modification will not take affect without the service re-installation.
|
||||
-->
|
||||
|
||||
<!--
|
||||
OPTION: serviceaccount
|
||||
Defines account, under which the service should run.
|
||||
-->
|
||||
<!--
|
||||
<serviceaccount>
|
||||
<domain>YOURDOMAIN</domain>
|
||||
<user>useraccount</user>
|
||||
<password>Pa55w0rd</password>
|
||||
<allowservicelogon>true</allowservicelogon>
|
||||
</serviceaccount>
|
||||
-->
|
||||
|
||||
<!--
|
||||
OPTION: onfailure
|
||||
Defines a sequence of actions, which should be performed if the managed executable fails.
|
||||
Supported actions: restart, reboot, none
|
||||
-->
|
||||
<!--
|
||||
<onfailure action="restart" delay="10 sec"/>
|
||||
<onfailure action="restart" delay="20 sec"/>
|
||||
<onfailure action="reboot" />
|
||||
-->
|
||||
|
||||
<!--
|
||||
OPTION: resetfailure
|
||||
Time, after which the Windows service resets the failure status.
|
||||
Default value: 1 day
|
||||
-->
|
||||
<!--
|
||||
<resetfailure>1 hour</resetfailure>
|
||||
-->
|
||||
|
||||
<!--
|
||||
SECTION: Executable management
|
||||
-->
|
||||
|
||||
<!--
|
||||
OPTION: arguments
|
||||
Arguments, which should be passed to the executable
|
||||
-->
|
||||
<!--
|
||||
<arguments>-classpath c:\cygwin\home\kohsuke\ws\hello-world\out\production\hello-world test.Main</arguments>
|
||||
-->
|
||||
|
||||
<!--
|
||||
OPTION: startarguments
|
||||
Arguments, which should be passed to the executable when it starts
|
||||
If specified, overrides 'arguments'.
|
||||
-->
|
||||
<!--
|
||||
<startarguments></startarguments>
|
||||
-->
|
||||
|
||||
<!--
|
||||
OPTION: workingdirectory
|
||||
If specified, sets the default working directory of the executable
|
||||
Default value: Directory of the service wrapper executable.
|
||||
-->
|
||||
<!--
|
||||
<workingdirectory>C:\myApp\work</workingdirectory>
|
||||
-->
|
||||
|
||||
<!--
|
||||
OPTION: priority
|
||||
Desired process priority.
|
||||
Possible values: Normal, Idle, High, RealTime, BelowNormal, AboveNormal
|
||||
Default value: Normal
|
||||
-->
|
||||
<priority>Normal</priority>
|
||||
|
||||
<!--
|
||||
OPTION: stoptimeout
|
||||
Time to wait for the service to gracefully shutdown the executable before we forcibly kill it
|
||||
Default value: 15 seconds
|
||||
-->
|
||||
<stoptimeout>15 sec</stoptimeout>
|
||||
|
||||
<!--
|
||||
OPTION: stopparentprocessfirst
|
||||
If set, WinSW will terminate the parent process before stopping the children.
|
||||
Default value: false
|
||||
-->
|
||||
<stopparentprocessfirst>false</stopparentprocessfirst>
|
||||
|
||||
|
||||
<!--
|
||||
OPTION: stopexecutable
|
||||
Path to an optional executable, which performs shutdown of the service.
|
||||
This executable will be used if and only if 'stoparguments' are specified.
|
||||
If 'stoparguments' are defined without this option, 'executable' will be used as a stop executable
|
||||
-->
|
||||
<!--
|
||||
<stopexecutable>%BASE%\stop.exe</stopexecutable>
|
||||
-->
|
||||
|
||||
<!--
|
||||
OPTION: stoparguments
|
||||
Additional arguments, which should be passed to the stop executable during termination.
|
||||
This OPTION also enables termination of the executable via stop executable
|
||||
-->
|
||||
<!--
|
||||
<stoparguments>-stop true</stoparguments>-->
|
||||
-->
|
||||
<!--
|
||||
SECTION: Service management
|
||||
-->
|
||||
<!--
|
||||
OPTION: startmode
|
||||
Defines start mode of the service.
|
||||
Supported modes: Automatic, Manual, Boot, System (latter ones are supported for driver services only)
|
||||
Default mode: Automatic
|
||||
-->
|
||||
<startmode>Automatic</startmode>
|
||||
|
||||
<!--
|
||||
OPTION: depend
|
||||
Optionally specifies services that must start before this service starts.
|
||||
-->
|
||||
<!--
|
||||
<depend>Eventlog</depend>
|
||||
<depend>W32Time</depend>
|
||||
-->
|
||||
|
||||
<!--
|
||||
OPTION: waithint
|
||||
The estimated time required for a pending stop operation.
|
||||
Before the specified amount of time has elapsed, the service should make its next call to the SetServiceStatus function.
|
||||
Otherwise the service will be marked as non-responding
|
||||
Default value: 15 seconds
|
||||
-->
|
||||
<waithint>15 sec</waithint>
|
||||
|
||||
<!--
|
||||
OPTION: sleeptime
|
||||
The time before the service should make its next call to the SetServiceStatus function.
|
||||
Do not wait longer than the wait hint. A good interval is one-tenth of the wait hint but not less than 1 second and not more than 10 seconds.
|
||||
Default value: 1 second
|
||||
-->
|
||||
<sleeptime>1 sec</sleeptime>
|
||||
|
||||
<!--
|
||||
OPTION: interactive
|
||||
Indicates the service can interactwith the desktop.
|
||||
-->
|
||||
<!--
|
||||
<interactive/>
|
||||
-->
|
||||
|
||||
<!--
|
||||
SECTION:Logging
|
||||
-->
|
||||
|
||||
<!--
|
||||
OPTION: logpath
|
||||
Sets a custom logging directory for all logs being produced by the service wrapper
|
||||
Default value: Directory, which contains the executor
|
||||
-->
|
||||
<!--
|
||||
<logpath>%BASE%\logs</logpath>
|
||||
-->
|
||||
|
||||
<!--
|
||||
OPTION: log
|
||||
Defines logging mode for logs produced by the executable.
|
||||
Supported modes:
|
||||
* append - Rust update the existing log
|
||||
* none - Do not save executable logs to the disk
|
||||
* reset - Wipe the log files on startup
|
||||
* roll - Rotate logs based on size
|
||||
* roll-by-time - Rotate logs based on time
|
||||
* rotate - Rotate logs based on size, (8 logs, 10MB each). This mode is deprecated, use "roll"
|
||||
Default mode: append
|
||||
|
||||
Each mode has different settings.
|
||||
See https://github.com/kohsuke/winsw/blob/master/doc/loggingAndErrorReporting.md for more details
|
||||
-->
|
||||
<log mode="append">
|
||||
<!--
|
||||
<setting1/>
|
||||
<setting2/>
|
||||
-->
|
||||
</log>
|
||||
|
||||
<!--
|
||||
SECTION: Environment setup
|
||||
-->
|
||||
<!--
|
||||
OPTION: env
|
||||
Sets or overrides environment variables.
|
||||
There may be multiple entries configured on the top level.
|
||||
-->
|
||||
<!--
|
||||
<env name="MY_TOOL_HOME" value="C:\etc\tools\myTool" />
|
||||
<env name="LM_LICENSE_FILE" value="host1;host2" />
|
||||
-->
|
||||
|
||||
|
||||
<!--
|
||||
OPTION: download
|
||||
List of downloads to be performed by the wrapper before starting
|
||||
-->
|
||||
<!--
|
||||
<download from="http://www.google.com/" to="%BASE%\index.html" />
|
||||
<download from="http://www.nosuchhostexists.com/" to="%BASE%\dummy.html" />
|
||||
-->
|
||||
|
||||
<!--
|
||||
SECTION: Other options
|
||||
-->
|
||||
|
||||
<!--
|
||||
OPTION: beeponshutdown
|
||||
Indicates the service should beep when finished on shutdown (if it's supported by OS).
|
||||
-->
|
||||
<!--
|
||||
<beeponshutdown/>
|
||||
-->
|
||||
|
||||
<!--
|
||||
SECTION: Extensions
|
||||
This configuration section allows specifying custom extensions.
|
||||
More info is available here: https://github.com/kohsuke/winsw/blob/master/doc/extensions/extensions.md
|
||||
-->
|
||||
|
||||
<!--
|
||||
<extensions>
|
||||
Extension 1: id values must be unique
|
||||
<extension enabled="true" id="extension1" className="winsw.Plugins.SharedDirectoryMapper.SharedDirectoryMapper">
|
||||
<mapping>
|
||||
<map enabled="false" label="N:" uncpath="\\UNC"/>
|
||||
<map enabled="false" label="M:" uncpath="\\UNC2"/>
|
||||
</mapping>
|
||||
</extension>
|
||||
...
|
||||
</extensions>
|
||||
-->
|
||||
|
||||
</configuration>
|
|
@ -0,0 +1,41 @@
|
|||
<!--
|
||||
Copyright (c) 2016 Oleg Nenashev and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
software and associated documentation files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or
|
||||
substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
-->
|
||||
|
||||
<!--
|
||||
This is an example of a minimal Windows Service Wrapper configuration, which includes only mandatiory options.
|
||||
|
||||
This configuration file should be placed near the WinSW executable, the name should be the same.
|
||||
E.g. for myapp.exe the configuration file name should be myapp.xml
|
||||
|
||||
You can find more information about the configuration options here: https://github.com/kohsuke/winsw/blob/master/doc/xmlConfigFile.md
|
||||
Full example: https://github.com/kohsuke/winsw/blob/sample-config-file/examples/allOptions.xml
|
||||
-->
|
||||
<configuration>
|
||||
|
||||
<!-- ID of the service. It should be unique accross the Windows system-->
|
||||
<id>myapp</id>
|
||||
<!-- Display name of the service -->
|
||||
<name>MyApp Service (powered by WinSW)</name>
|
||||
<!-- Service description -->
|
||||
<description>This service is a service cratead from a minimal configuration</description>
|
||||
|
||||
<!-- Path to the executable, which should be started -->
|
||||
<executable>%BASE%\myExecutable.exe</executable>
|
||||
|
||||
</configuration>
|
|
@ -83,12 +83,6 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="manifest.xml" />
|
||||
<Content Include="pom.xml">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<Content Include="winsw.xml">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config">
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
<configuration>
|
||||
<id>winsw</id>
|
||||
<name>Winsw test service(2)</name>
|
||||
<description>This service is a do-nothing test app. Really.</description>
|
||||
<download from="http://www.google.com/" to="%BASE%\index.html" />
|
||||
<download from="http://www.nosuchhostexists.com/" to="%BASE%\dummy.html" />
|
||||
|
||||
<executable>C:\development\jdk6u7\bin\java.exe</executable>
|
||||
<arguments>-classpath c:\cygwin\home\kohsuke\ws\hello-world\out\production\hello-world test.Main</arguments>
|
||||
</configuration>
|
|
@ -0,0 +1,71 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using WMI;
|
||||
|
||||
namespace winsw.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// Default WinSW settings
|
||||
/// </summary>
|
||||
public sealed class DefaultWinSWSettings : IWinSWConfiguration
|
||||
{
|
||||
public string Id { get { return null; } }
|
||||
public string Caption { get { return null; } }
|
||||
public string Description { get { return null; } }
|
||||
public string Executable { get { return null; } }
|
||||
|
||||
public string ExecutablePath
|
||||
{
|
||||
get
|
||||
{
|
||||
// this returns the executable name as given by the calling process, so
|
||||
// it needs to be absolutized.
|
||||
string p = Environment.GetCommandLineArgs()[0];
|
||||
return Path.GetFullPath(p);
|
||||
}
|
||||
}
|
||||
|
||||
// Installation
|
||||
public bool AllowServiceAcountLogonRight { get { return false; } }
|
||||
public string ServiceAccountPassword { get { return null; } }
|
||||
public string ServiceAccountUser { get { return "NULL\\NULL"; } }
|
||||
public List<winsw.Native.SC_ACTION> FailureActions { get { return new List<winsw.Native.SC_ACTION>(); } }
|
||||
public TimeSpan ResetFailureAfter { get { return TimeSpan.FromDays(1); } }
|
||||
|
||||
// Executable management
|
||||
public string Arguments { get { return ""; } }
|
||||
public string Startarguments { get { return null; } }
|
||||
public string StopExecutable { get { return null; } }
|
||||
public string Stoparguments { get { return null; } }
|
||||
public string WorkingDirectory { get { return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); } }
|
||||
public ProcessPriorityClass Priority { get { return ProcessPriorityClass.Normal; } }
|
||||
public TimeSpan StopTimeout { get { return TimeSpan.FromSeconds(15); } }
|
||||
public bool StopParentProcessFirst { get { return false; } }
|
||||
|
||||
// Service management
|
||||
public StartMode StartMode { get { return StartMode.Automatic; } }
|
||||
public string[] ServiceDependencies { get { return new string[0]; } }
|
||||
public TimeSpan WaitHint { get { return TimeSpan.FromSeconds(15); } }
|
||||
public TimeSpan SleepTime { get { return TimeSpan.FromSeconds(1); } }
|
||||
public bool Interactive { get { return false; } }
|
||||
|
||||
// Logging
|
||||
public string LogDirectory { get { return Path.GetDirectoryName(ExecutablePath); } }
|
||||
public string LogMode { get { return "append"; } }
|
||||
|
||||
// Environment
|
||||
public List<Download> Downloads { get { return new List<Download>(); } }
|
||||
public Dictionary<string, string> EnvironmentVariables { get { return new Dictionary<string, string>(); } }
|
||||
|
||||
// Misc
|
||||
public bool BeepOnShutdown { get { return false; } }
|
||||
|
||||
// Extensions
|
||||
public XmlNode ExtensionsConfiguration { get {return null; } }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Xml;
|
||||
using WMI;
|
||||
namespace winsw.Configuration
|
||||
{
|
||||
public interface IWinSWConfiguration
|
||||
{
|
||||
//TODO: Document the parameters && refactor
|
||||
|
||||
string Id { get; }
|
||||
string Caption { get; }
|
||||
string Description { get; }
|
||||
string Executable { get; }
|
||||
string ExecutablePath { get; }
|
||||
|
||||
// Installation
|
||||
bool AllowServiceAcountLogonRight { get; }
|
||||
string ServiceAccountPassword { get; }
|
||||
string ServiceAccountUser { get; }
|
||||
List<winsw.Native.SC_ACTION> FailureActions { get; }
|
||||
TimeSpan ResetFailureAfter { get; }
|
||||
|
||||
// Executable management
|
||||
string Arguments { get; }
|
||||
string Startarguments { get; }
|
||||
string StopExecutable { get; }
|
||||
string Stoparguments { get; }
|
||||
string WorkingDirectory { get; }
|
||||
ProcessPriorityClass Priority { get; }
|
||||
TimeSpan StopTimeout { get; }
|
||||
bool StopParentProcessFirst { get; }
|
||||
|
||||
// Service management
|
||||
StartMode StartMode { get; }
|
||||
string[] ServiceDependencies { get; }
|
||||
TimeSpan WaitHint { get; }
|
||||
TimeSpan SleepTime { get; }
|
||||
bool Interactive { get; }
|
||||
|
||||
// Logging
|
||||
string LogDirectory { get; }
|
||||
//TODO: replace by enum
|
||||
string LogMode { get; }
|
||||
|
||||
// Environment
|
||||
List<Download> Downloads { get; }
|
||||
Dictionary<string, string> EnvironmentVariables { get; }
|
||||
|
||||
// Misc
|
||||
bool BeepOnShutdown { get; }
|
||||
|
||||
// Extensions
|
||||
XmlNode ExtensionsConfiguration { get; }
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ using System.Diagnostics;
|
|||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Xml;
|
||||
using winsw.Configuration;
|
||||
using winsw.Native;
|
||||
using winsw.Util;
|
||||
using WMI;
|
||||
|
@ -14,17 +15,21 @@ namespace winsw
|
|||
/// <summary>
|
||||
/// In-memory representation of the configuration file.
|
||||
/// </summary>
|
||||
public class ServiceDescriptor
|
||||
public class ServiceDescriptor : IWinSWConfiguration
|
||||
{
|
||||
// ReSharper disable once InconsistentNaming
|
||||
protected readonly XmlDocument dom = new XmlDocument();
|
||||
|
||||
private static readonly DefaultWinSWSettings defaults = new DefaultWinSWSettings();
|
||||
public static DefaultWinSWSettings Defaults { get { return defaults; } }
|
||||
|
||||
/// <summary>
|
||||
/// Where did we find the configuration file?
|
||||
///
|
||||
/// This string is "c:\abc\def\ghi" when the configuration XML is "c:\abc\def\ghi.xml"
|
||||
/// </summary>
|
||||
public string BasePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The file name portion of the configuration file.
|
||||
///
|
||||
|
@ -36,10 +41,8 @@ namespace winsw
|
|||
{
|
||||
get
|
||||
{
|
||||
// this returns the executable name as given by the calling process, so
|
||||
// it needs to be absolutized.
|
||||
string p = Environment.GetCommandLineArgs()[0];
|
||||
return Path.GetFullPath(p);
|
||||
// Currently there is no opportunity to alter the executable path
|
||||
return Defaults.ExecutablePath;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,7 +183,7 @@ namespace winsw
|
|||
{
|
||||
get
|
||||
{
|
||||
return SingleElement("stopexecutable");
|
||||
return SingleElement("stopexecutable", true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,7 +194,7 @@ namespace winsw
|
|||
{
|
||||
get
|
||||
{
|
||||
string arguments = AppendTags("argument");
|
||||
string arguments = AppendTags("argument", Defaults.Arguments);
|
||||
|
||||
if (arguments == null)
|
||||
{
|
||||
|
@ -199,7 +202,7 @@ namespace winsw
|
|||
|
||||
if (argumentsNode == null)
|
||||
{
|
||||
return "";
|
||||
return Defaults.Arguments;
|
||||
}
|
||||
|
||||
return Environment.ExpandEnvironmentVariables(argumentsNode.InnerText);
|
||||
|
@ -218,7 +221,7 @@ namespace winsw
|
|||
{
|
||||
get
|
||||
{
|
||||
return AppendTags("startargument");
|
||||
return AppendTags("startargument", Defaults.Startarguments);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -229,7 +232,7 @@ namespace winsw
|
|||
{
|
||||
get
|
||||
{
|
||||
return AppendTags("stopargument");
|
||||
return AppendTags("stopargument", Defaults.Startarguments);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,7 +240,7 @@ namespace winsw
|
|||
public string WorkingDirectory {
|
||||
get {
|
||||
var wd = SingleElement("workingdirectory", true);
|
||||
return String.IsNullOrEmpty(wd) ? Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) : wd;
|
||||
return String.IsNullOrEmpty(wd) ? Defaults.WorkingDirectory : wd;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -276,13 +279,13 @@ namespace winsw
|
|||
/// Combines the contents of all the elements of the given name,
|
||||
/// or return null if no element exists. Handles whitespace quotation.
|
||||
/// </summary>
|
||||
private string AppendTags(string tagName)
|
||||
private string AppendTags(string tagName, string defaultValue = null)
|
||||
{
|
||||
XmlNode argumentNode = dom.SelectSingleNode("//" + tagName);
|
||||
|
||||
if (argumentNode == null)
|
||||
{
|
||||
return null;
|
||||
return defaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -327,31 +330,51 @@ namespace winsw
|
|||
}
|
||||
else
|
||||
{
|
||||
return Path.GetDirectoryName(ExecutablePath);
|
||||
return Defaults.LogDirectory;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string LogMode
|
||||
{
|
||||
get
|
||||
{
|
||||
string mode = null;
|
||||
|
||||
// first, backward compatibility with older configuration
|
||||
XmlElement e = (XmlElement)dom.SelectSingleNode("//logmode");
|
||||
if (e != null)
|
||||
{
|
||||
mode = e.InnerText;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is more modern way, to support nested elements as configuration
|
||||
e = (XmlElement)dom.SelectSingleNode("//log");
|
||||
if (e != null)
|
||||
mode = e.GetAttribute("mode");
|
||||
}
|
||||
|
||||
if (mode == null)
|
||||
{
|
||||
mode = Defaults.LogMode;
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
}
|
||||
|
||||
public LogHandler LogHandler
|
||||
{
|
||||
|
||||
get
|
||||
{
|
||||
string mode=null;
|
||||
|
||||
// first, backward compatibility with older configuration
|
||||
XmlElement e = (XmlElement)dom.SelectSingleNode("//logmode");
|
||||
if (e!=null) {
|
||||
mode = e.InnerText;
|
||||
} else {
|
||||
if (e == null)
|
||||
{
|
||||
// this is more modern way, to support nested elements as configuration
|
||||
e = (XmlElement)dom.SelectSingleNode("//log");
|
||||
if (e!=null)
|
||||
mode = e.GetAttribute("mode");
|
||||
}
|
||||
|
||||
if (mode == null) mode = "append";
|
||||
|
||||
switch (mode)
|
||||
switch (LogMode)
|
||||
{
|
||||
case "rotate":
|
||||
return new SizeBasedRollingLogAppender(LogDirectory, BaseName);
|
||||
|
@ -384,7 +407,7 @@ namespace winsw
|
|||
return new DefaultLogAppender(LogDirectory, BaseName);
|
||||
|
||||
default:
|
||||
throw new InvalidDataException("Undefined logging mode: " + mode);
|
||||
throw new InvalidDataException("Undefined logging mode: " + LogMode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -397,16 +420,17 @@ namespace winsw
|
|||
{
|
||||
get
|
||||
{
|
||||
ArrayList serviceDependencies = new ArrayList();
|
||||
|
||||
var xmlNodeList = dom.SelectNodes("//depend");
|
||||
if (xmlNodeList != null)
|
||||
{
|
||||
ArrayList serviceDependencies = new ArrayList();
|
||||
foreach (XmlNode depend in xmlNodeList)
|
||||
{
|
||||
serviceDependencies.Add(depend.InnerText);
|
||||
}
|
||||
|
||||
return (string[])serviceDependencies.ToArray(typeof(string));
|
||||
return (string[])serviceDependencies.ToArray(typeof(string));
|
||||
}
|
||||
return Defaults.ServiceDependencies;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -442,7 +466,7 @@ namespace winsw
|
|||
get
|
||||
{
|
||||
var p = SingleElement("startmode", true);
|
||||
if (p == null) return StartMode.Automatic; // default value
|
||||
if (p == null) return Defaults.StartMode;
|
||||
try
|
||||
{
|
||||
return (StartMode)Enum.Parse(typeof(StartMode), p, true);
|
||||
|
@ -460,7 +484,7 @@ namespace winsw
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if the service should when finished on shutdown.
|
||||
/// True if the service should beep when finished on shutdown.
|
||||
/// This doesn't work on some OSes. See http://msdn.microsoft.com/en-us/library/ms679277%28VS.85%29.aspx
|
||||
/// </summary>
|
||||
public bool BeepOnShutdown
|
||||
|
@ -481,7 +505,7 @@ namespace winsw
|
|||
{
|
||||
get
|
||||
{
|
||||
return SingleTimeSpanElement(dom.FirstChild, "waithint", TimeSpan.FromSeconds(15));
|
||||
return SingleTimeSpanElement(dom.FirstChild, "waithint", Defaults.WaitHint);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -495,7 +519,7 @@ namespace winsw
|
|||
{
|
||||
get
|
||||
{
|
||||
return SingleTimeSpanElement(dom.FirstChild, "sleeptime", TimeSpan.FromSeconds(1));
|
||||
return SingleTimeSpanElement(dom.FirstChild, "sleeptime", Defaults.SleepTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -538,13 +562,17 @@ namespace winsw
|
|||
{
|
||||
get
|
||||
{
|
||||
List<Download> r = new List<Download>();
|
||||
var xmlNodeList = dom.SelectNodes("//download");
|
||||
if (xmlNodeList != null)
|
||||
foreach (XmlNode n in xmlNodeList)
|
||||
{
|
||||
r.Add(new Download(n));
|
||||
}
|
||||
if (xmlNodeList == null)
|
||||
{
|
||||
return Defaults.Downloads;
|
||||
}
|
||||
|
||||
List<Download> r = new List<Download>();
|
||||
foreach (XmlNode n in xmlNodeList)
|
||||
{
|
||||
r.Add(new Download(n));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
@ -587,7 +615,7 @@ namespace winsw
|
|||
{
|
||||
get
|
||||
{
|
||||
return SingleTimeSpanElement(dom.FirstChild, "resetfailure", TimeSpan.FromDays(1));
|
||||
return SingleTimeSpanElement(dom.FirstChild, "resetfailure", Defaults.ResetFailureAfter);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -669,13 +697,13 @@ namespace winsw
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Time to wait for the service to gracefully shutdown before we forcibly kill it
|
||||
/// Time to wait for the service to gracefully shutdown the executable before we forcibly kill it
|
||||
/// </summary>
|
||||
public TimeSpan StopTimeout
|
||||
{
|
||||
get
|
||||
{
|
||||
return SingleTimeSpanElement(dom.FirstChild, "stoptimeout", TimeSpan.FromSeconds(15));
|
||||
return SingleTimeSpanElement(dom.FirstChild, "stoptimeout", Defaults.StopTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -689,7 +717,7 @@ namespace winsw
|
|||
{
|
||||
return result;
|
||||
}
|
||||
return false;
|
||||
return Defaults.StopParentProcessFirst;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -701,7 +729,7 @@ namespace winsw
|
|||
get
|
||||
{
|
||||
var p = SingleElement("priority",true);
|
||||
if (p == null) return ProcessPriorityClass.Normal; // default value
|
||||
if (p == null) return Defaults.Priority;
|
||||
|
||||
return (ProcessPriorityClass)Enum.Parse(typeof(ProcessPriorityClass), p, true);
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Configuration\DefaultSettings.cs" />
|
||||
<Compile Include="Download.cs" />
|
||||
<Compile Include="DynamicProxy.cs" />
|
||||
<Compile Include="Extensions\AbstractWinSWExtension.cs" />
|
||||
|
@ -53,6 +54,7 @@
|
|||
<Compile Include="Extensions\IWinSWExtension.cs" />
|
||||
<Compile Include="Extensions\WinSWExtensionDescriptor.cs" />
|
||||
<Compile Include="Extensions\WinSWExtensionManager.cs" />
|
||||
<Compile Include="Configuration\IWinSWConfiguration.cs" />
|
||||
<Compile Include="LogAppenders.cs" />
|
||||
<Compile Include="Logging\ServiceEventLogAppender.cs" />
|
||||
<Compile Include="Logging\IServiceEventLogProvider.cs" />
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using winsw;
|
||||
using winswTests.Util;
|
||||
|
||||
namespace winswTests.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests example configuration files.
|
||||
/// The test uses a relative path to example files, which is based on the current project structure.
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
class ExamplesTest
|
||||
{
|
||||
|
||||
[Test]
|
||||
public void allOptionsConfigShouldDeclareDefaults()
|
||||
{
|
||||
ServiceDescriptor d = doLoad("allOptions");
|
||||
|
||||
Assert.AreEqual("myapp", d.Id);
|
||||
Assert.AreEqual("MyApp Service (powered by WinSW)", d.Caption);
|
||||
Assert.AreEqual("This service is a service cratead from a sample configuration", d.Description);
|
||||
Assert.AreEqual("%BASE%\\myExecutable.exe", d.Executable);
|
||||
|
||||
ServiceDescriptorAssert.AssertAllOptionalPropertiesAreDefault(d);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void minimalConfigShouldDeclareDefaults()
|
||||
{
|
||||
ServiceDescriptor d = doLoad("minimal");
|
||||
|
||||
Assert.AreEqual("myapp", d.Id);
|
||||
Assert.AreEqual("MyApp Service (powered by WinSW)", d.Caption);
|
||||
Assert.AreEqual("This service is a service cratead from a minimal configuration", d.Description);
|
||||
Assert.AreEqual("%BASE%\\myExecutable.exe", d.Executable);
|
||||
|
||||
ServiceDescriptorAssert.AssertAllOptionalPropertiesAreDefault(d);
|
||||
}
|
||||
|
||||
private ServiceDescriptor doLoad(string exampleName) {
|
||||
var dir = Directory.GetCurrentDirectory();
|
||||
string path = dir + "\\..\\..\\..\\..\\..\\examples\\sample-" + exampleName + ".xml";
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
throw new FileNotFoundException("Cannot find the XML file " + path, path);
|
||||
}
|
||||
XmlDocument dom = new XmlDocument();
|
||||
dom.Load(path);
|
||||
return new ServiceDescriptor(dom);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using winsw;
|
||||
using winsw.Configuration;
|
||||
|
||||
namespace winswTests.Util
|
||||
{
|
||||
public static class ServiceDescriptorAssert
|
||||
{
|
||||
// TODO: convert to Extension attributes once the .NET dependency is upgraded
|
||||
// BTW there is a way to get them working in .NET2, but KISS
|
||||
|
||||
public static void AssertPropertyIsDefault(ServiceDescriptor d, string property)
|
||||
{
|
||||
PropertyInfo actualProperty = typeof(ServiceDescriptor).GetProperty(property);
|
||||
Assert.IsNotNull(actualProperty, "Cannot find property " + property + " in the service descriptor" + d);
|
||||
PropertyInfo defaultProperty = typeof(DefaultWinSWSettings).GetProperty(property);
|
||||
Assert.IsNotNull(defaultProperty, "Cannot find property " + property + " in the default settings");
|
||||
|
||||
Assert.AreEqual(defaultProperty.GetValue(ServiceDescriptor.Defaults, null), actualProperty.GetValue(d, null),
|
||||
"Value of property " + property + " does not equal to the default one");
|
||||
}
|
||||
|
||||
public static void AssertPropertyIsDefault(ServiceDescriptor d, List<string> properties)
|
||||
{
|
||||
foreach (var prop in properties)
|
||||
{
|
||||
AssertPropertyIsDefault(d, prop);
|
||||
}
|
||||
}
|
||||
|
||||
public static void AssertAllOptionalPropertiesAreDefault(ServiceDescriptor d)
|
||||
{
|
||||
AssertPropertyIsDefault(d, AllOptionalProperties);
|
||||
}
|
||||
|
||||
private static List<string> AllProperties {
|
||||
get {
|
||||
var res = new List<string>();
|
||||
var properties = typeof(IWinSWConfiguration).GetProperties();
|
||||
foreach (var prop in properties)
|
||||
{
|
||||
res.Add(prop.Name);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<string> AllOptionalProperties
|
||||
{
|
||||
get
|
||||
{
|
||||
var properties = AllProperties;
|
||||
properties.Remove("Id");
|
||||
properties.Remove("Caption");
|
||||
properties.Remove("Description");
|
||||
properties.Remove("Executable");
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -55,6 +55,7 @@
|
|||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Configuration\ExamplesTest.cs" />
|
||||
<Compile Include="Extensions\ExtensionTestBase.cs" />
|
||||
<Compile Include="Extensions\RunawayProcessKillerTest.cs" />
|
||||
<Compile Include="Extensions\SharedDirectoryMapperTest.cs" />
|
||||
|
@ -62,6 +63,7 @@
|
|||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ServiceDescriptorTests.cs" />
|
||||
<Compile Include="Util\CLITestHelper.cs" />
|
||||
<Compile Include="Util\ServiceDescriptorAssert.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Core\ServiceWrapper\winsw.csproj">
|
||||
|
|
|
@ -33,6 +33,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RunawayProcessKiller", "Plu
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "winsw_dotNET4", "Core\ServiceWrapper_dotNET4\winsw_dotNET4.csproj", "{419AEEA7-E7DE-4A76-B001-76DB5F98C838}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{AA414F46-B863-473A-A0E0-C2971B3396AE}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
..\examples\sample-allOptions.xml = ..\examples\sample-allOptions.xml
|
||||
..\examples\sample-minimal.xml = ..\examples\sample-minimal.xml
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
Loading…
Reference in New Issue