Decouple Default Settings to a separate publicly accessible class.

Required for tests.
pull/170/head
Oleg Nenashev 2016-12-23 21:18:59 +01:00
parent 413e24ebeb
commit 14f32cd309
4 changed files with 203 additions and 45 deletions

View File

@ -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; } }
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; } }
}
}

View File

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml;
using WMI;
namespace winsw.Configuration
{
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; }
}
}

View File

@ -5,6 +5,7 @@ using System.Diagnostics;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using System.Xml; using System.Xml;
using winsw.Configuration;
using winsw.Native; using winsw.Native;
using winsw.Util; using winsw.Util;
using WMI; using WMI;
@ -14,17 +15,21 @@ namespace winsw
/// <summary> /// <summary>
/// In-memory representation of the configuration file. /// In-memory representation of the configuration file.
/// </summary> /// </summary>
public class ServiceDescriptor public class ServiceDescriptor : IWinSWConfiguration
{ {
// ReSharper disable once InconsistentNaming // ReSharper disable once InconsistentNaming
protected readonly XmlDocument dom = new XmlDocument(); protected readonly XmlDocument dom = new XmlDocument();
private static readonly DefaultWinSWSettings defaults = new DefaultWinSWSettings();
public static DefaultWinSWSettings Defaults { get { return defaults; } }
/// <summary> /// <summary>
/// Where did we find the configuration file? /// Where did we find the configuration file?
/// ///
/// This string is "c:\abc\def\ghi" when the configuration XML is "c:\abc\def\ghi.xml" /// This string is "c:\abc\def\ghi" when the configuration XML is "c:\abc\def\ghi.xml"
/// </summary> /// </summary>
public string BasePath { get; set; } public string BasePath { get; set; }
/// <summary> /// <summary>
/// The file name portion of the configuration file. /// The file name portion of the configuration file.
/// ///
@ -36,10 +41,8 @@ namespace winsw
{ {
get get
{ {
// this returns the executable name as given by the calling process, so // Currently there is no opportunity to alter the executable path
// it needs to be absolutized. return Defaults.ExecutablePath;
string p = Environment.GetCommandLineArgs()[0];
return Path.GetFullPath(p);
} }
} }
@ -191,7 +194,7 @@ namespace winsw
{ {
get get
{ {
string arguments = AppendTags("argument"); string arguments = AppendTags("argument", Defaults.Arguments);
if (arguments == null) if (arguments == null)
{ {
@ -199,7 +202,7 @@ namespace winsw
if (argumentsNode == null) if (argumentsNode == null)
{ {
return ""; return Defaults.Arguments;
} }
return Environment.ExpandEnvironmentVariables(argumentsNode.InnerText); return Environment.ExpandEnvironmentVariables(argumentsNode.InnerText);
@ -218,7 +221,7 @@ namespace winsw
{ {
get get
{ {
return AppendTags("startargument"); return AppendTags("startargument", Defaults.Startarguments);
} }
} }
@ -229,7 +232,7 @@ namespace winsw
{ {
get get
{ {
return AppendTags("stopargument"); return AppendTags("stopargument", Defaults.Startarguments);
} }
} }
@ -237,7 +240,7 @@ namespace winsw
public string WorkingDirectory { public string WorkingDirectory {
get { get {
var wd = SingleElement("workingdirectory", true); 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, /// Combines the contents of all the elements of the given name,
/// or return null if no element exists. Handles whitespace quotation. /// or return null if no element exists. Handles whitespace quotation.
/// </summary> /// </summary>
private string AppendTags(string tagName) private string AppendTags(string tagName, string defaultValue = null)
{ {
XmlNode argumentNode = dom.SelectSingleNode("//" + tagName); XmlNode argumentNode = dom.SelectSingleNode("//" + tagName);
if (argumentNode == null) if (argumentNode == null)
{ {
return null; return defaultValue;
} }
else else
{ {
@ -327,31 +330,51 @@ namespace winsw
} }
else 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 public LogHandler LogHandler
{ {
get get
{ {
string mode=null;
// first, backward compatibility with older configuration
XmlElement e = (XmlElement)dom.SelectSingleNode("//logmode"); XmlElement e = (XmlElement)dom.SelectSingleNode("//logmode");
if (e!=null) { if (e == null)
mode = e.InnerText; {
} else {
// this is more modern way, to support nested elements as configuration // this is more modern way, to support nested elements as configuration
e = (XmlElement)dom.SelectSingleNode("//log"); e = (XmlElement)dom.SelectSingleNode("//log");
if (e!=null)
mode = e.GetAttribute("mode");
} }
switch (LogMode)
if (mode == null) mode = "append";
switch (mode)
{ {
case "rotate": case "rotate":
return new SizeBasedRollingLogAppender(LogDirectory, BaseName); return new SizeBasedRollingLogAppender(LogDirectory, BaseName);
@ -384,7 +407,7 @@ namespace winsw
return new DefaultLogAppender(LogDirectory, BaseName); return new DefaultLogAppender(LogDirectory, BaseName);
default: default:
throw new InvalidDataException("Undefined logging mode: " + mode); throw new InvalidDataException("Undefined logging mode: " + LogMode);
} }
} }
@ -397,17 +420,18 @@ namespace winsw
{ {
get get
{ {
ArrayList serviceDependencies = new ArrayList();
var xmlNodeList = dom.SelectNodes("//depend"); var xmlNodeList = dom.SelectNodes("//depend");
if (xmlNodeList != null) if (xmlNodeList != null)
{
ArrayList serviceDependencies = new ArrayList();
foreach (XmlNode depend in xmlNodeList) foreach (XmlNode depend in xmlNodeList)
{ {
serviceDependencies.Add(depend.InnerText); serviceDependencies.Add(depend.InnerText);
} }
return (string[])serviceDependencies.ToArray(typeof(string)); return (string[])serviceDependencies.ToArray(typeof(string));
} }
return Defaults.ServiceDependencies;
}
} }
public string Id public string Id
@ -442,7 +466,7 @@ namespace winsw
get get
{ {
var p = SingleElement("startmode", true); var p = SingleElement("startmode", true);
if (p == null) return StartMode.Automatic; // default value if (p == null) return Defaults.StartMode;
try try
{ {
return (StartMode)Enum.Parse(typeof(StartMode), p, true); return (StartMode)Enum.Parse(typeof(StartMode), p, true);
@ -460,7 +484,7 @@ namespace winsw
} }
/// <summary> /// <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 /// This doesn't work on some OSes. See http://msdn.microsoft.com/en-us/library/ms679277%28VS.85%29.aspx
/// </summary> /// </summary>
public bool BeepOnShutdown public bool BeepOnShutdown
@ -481,7 +505,7 @@ namespace winsw
{ {
get get
{ {
return SingleTimeSpanElement(dom.FirstChild, "waithint", TimeSpan.FromSeconds(15)); return SingleTimeSpanElement(dom.FirstChild, "waithint", Defaults.WaitHint);
} }
} }
@ -495,7 +519,7 @@ namespace winsw
{ {
get get
{ {
return SingleTimeSpanElement(dom.FirstChild, "sleeptime", TimeSpan.FromSeconds(1)); return SingleTimeSpanElement(dom.FirstChild, "sleeptime", Defaults.SleepTime);
} }
} }
@ -538,9 +562,13 @@ namespace winsw
{ {
get get
{ {
List<Download> r = new List<Download>();
var xmlNodeList = dom.SelectNodes("//download"); var xmlNodeList = dom.SelectNodes("//download");
if (xmlNodeList != null) if (xmlNodeList == null)
{
return Defaults.Downloads;
}
List<Download> r = new List<Download>();
foreach (XmlNode n in xmlNodeList) foreach (XmlNode n in xmlNodeList)
{ {
r.Add(new Download(n)); r.Add(new Download(n));
@ -587,7 +615,7 @@ namespace winsw
{ {
get get
{ {
return SingleTimeSpanElement(dom.FirstChild, "resetfailure", TimeSpan.FromDays(1)); return SingleTimeSpanElement(dom.FirstChild, "resetfailure", Defaults.ResetFailureAfter);
} }
} }
@ -669,13 +697,13 @@ namespace winsw
} }
/// <summary> /// <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> /// </summary>
public TimeSpan StopTimeout public TimeSpan StopTimeout
{ {
get 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 result;
} }
return false; return Defaults.StopParentProcessFirst;
} }
} }
@ -701,7 +729,7 @@ namespace winsw
get get
{ {
var p = SingleElement("priority",true); 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); return (ProcessPriorityClass)Enum.Parse(typeof(ProcessPriorityClass), p, true);
} }

View File

@ -45,6 +45,7 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Configuration\DefaultSettings.cs" />
<Compile Include="Download.cs" /> <Compile Include="Download.cs" />
<Compile Include="DynamicProxy.cs" /> <Compile Include="DynamicProxy.cs" />
<Compile Include="Extensions\AbstractWinSWExtension.cs" /> <Compile Include="Extensions\AbstractWinSWExtension.cs" />
@ -53,6 +54,7 @@
<Compile Include="Extensions\IWinSWExtension.cs" /> <Compile Include="Extensions\IWinSWExtension.cs" />
<Compile Include="Extensions\WinSWExtensionDescriptor.cs" /> <Compile Include="Extensions\WinSWExtensionDescriptor.cs" />
<Compile Include="Extensions\WinSWExtensionManager.cs" /> <Compile Include="Extensions\WinSWExtensionManager.cs" />
<Compile Include="Configuration\IWinSWConfiguration.cs" />
<Compile Include="LogAppenders.cs" /> <Compile Include="LogAppenders.cs" />
<Compile Include="Logging\ServiceEventLogAppender.cs" /> <Compile Include="Logging\ServiceEventLogAppender.cs" />
<Compile Include="Logging\IServiceEventLogProvider.cs" /> <Compile Include="Logging\IServiceEventLogProvider.cs" />