From 2546168ed395ab992ca357dddd02d861cf885cf5 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Sat, 31 Jan 2015 19:50:42 +0300 Subject: [PATCH 1/6] Integrate changes in WinSW core and SharedDirectoryMapper from #42 The code is compilable, the SharedDirectoryMapper won't be included into WinSW Signed-off-by: Oleg Nenashev Conflicts: src/Core/ServiceWrapper/Main.cs Conflicts: src/Core/ServiceWrapper/ServiceDescriptor.cs src/Test/winswTests/winswTests.csproj src/winsw.sln --- .../Extensions/AbstractWinSWExtension.cs | 27 ++++ .../Extensions/ExtensionException.cs | 30 +++++ .../Extensions/IWinSWExtension.cs | 44 +++++++ .../Extensions/WinSWExtensionDescriptor.cs | 39 ++++++ .../Extensions/WinSWExtensionManager.cs | 123 ++++++++++++++++++ src/Core/ServiceWrapper/IEventWriter.cs | 13 ++ src/Core/ServiceWrapper/Main.cs | 34 ++++- src/Core/ServiceWrapper/ServiceDescriptor.cs | 36 ++++- src/Core/ServiceWrapper/Util/IEventWriter.cs | 13 ++ .../ServiceWrapper/Util/WinSWException.cs | 15 +++ src/Core/ServiceWrapper/Util/XmlHelper.cs | 73 +++++++++++ src/Core/ServiceWrapper/WinSWException.cs | 17 +++ src/Core/ServiceWrapper/XmlHelper.cs | 75 +++++++++++ src/Core/ServiceWrapper/winsw.csproj | 9 ++ .../Properties/AssemblyInfo.cs | 36 +++++ .../SharedDirectoryMapper.cs | 93 +++++++++++++ .../SharedDirectoryMapper.csproj | 57 ++++++++ .../SharedDirectoryMapperConfig.cs | 31 +++++ .../SharedDirectoryMapperHelper.cs | 73 +++++++++++ .../SharedDirectoryMapper/sampleConfig.xml | 18 +++ .../Extensions/WinSWExtensionManagerTest.cs | 62 +++++++++ src/Test/winswTests/NunitTest.nunit | 7 + src/Test/winswTests/Util/TestLogger.cs | 19 +++ src/Test/winswTests/winswTests.csproj | 7 + src/winsw.sln | 45 +++++++ src/winsw.sln.DotSettings | 3 + 26 files changed, 995 insertions(+), 4 deletions(-) create mode 100644 src/Core/ServiceWrapper/Extensions/AbstractWinSWExtension.cs create mode 100644 src/Core/ServiceWrapper/Extensions/ExtensionException.cs create mode 100644 src/Core/ServiceWrapper/Extensions/IWinSWExtension.cs create mode 100644 src/Core/ServiceWrapper/Extensions/WinSWExtensionDescriptor.cs create mode 100644 src/Core/ServiceWrapper/Extensions/WinSWExtensionManager.cs create mode 100644 src/Core/ServiceWrapper/IEventWriter.cs create mode 100644 src/Core/ServiceWrapper/Util/IEventWriter.cs create mode 100644 src/Core/ServiceWrapper/Util/WinSWException.cs create mode 100644 src/Core/ServiceWrapper/Util/XmlHelper.cs create mode 100644 src/Core/ServiceWrapper/WinSWException.cs create mode 100644 src/Core/ServiceWrapper/XmlHelper.cs create mode 100644 src/Plugins/SharedDirectoryMapper/Properties/AssemblyInfo.cs create mode 100644 src/Plugins/SharedDirectoryMapper/SharedDirectoryMapper.cs create mode 100644 src/Plugins/SharedDirectoryMapper/SharedDirectoryMapper.csproj create mode 100644 src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperConfig.cs create mode 100644 src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperHelper.cs create mode 100644 src/Plugins/SharedDirectoryMapper/sampleConfig.xml create mode 100644 src/Test/winswTests/Extensions/WinSWExtensionManagerTest.cs create mode 100644 src/Test/winswTests/NunitTest.nunit create mode 100644 src/Test/winswTests/Util/TestLogger.cs create mode 100644 src/winsw.sln.DotSettings diff --git a/src/Core/ServiceWrapper/Extensions/AbstractWinSWExtension.cs b/src/Core/ServiceWrapper/Extensions/AbstractWinSWExtension.cs new file mode 100644 index 0000000..acba93c --- /dev/null +++ b/src/Core/ServiceWrapper/Extensions/AbstractWinSWExtension.cs @@ -0,0 +1,27 @@ +using System; +using System.Xml; +using winsw.Util; + +namespace winsw.Extensions +{ + public abstract class AbstractWinSWExtension : IWinSWExtension + { + public abstract String DisplayName { get; } + public WinSWExtensionDescriptor Descriptor { get; set; } + + public virtual void Configure(ServiceDescriptor descriptor, XmlNode node, IEventWriter logger) + { + // Do nothing + } + + public virtual void OnStart(IEventWriter eventWriter) + { + // Do nothing + } + + public virtual void OnStop(IEventWriter eventWriter) + { + // Do nothing + } + } +} diff --git a/src/Core/ServiceWrapper/Extensions/ExtensionException.cs b/src/Core/ServiceWrapper/Extensions/ExtensionException.cs new file mode 100644 index 0000000..563c5ed --- /dev/null +++ b/src/Core/ServiceWrapper/Extensions/ExtensionException.cs @@ -0,0 +1,30 @@ +using System; +using winsw.Util; + +namespace winsw.Extensions +{ + public class ExtensionException : WinSWException + { + public String ExtensionId { get; private set; } + + public ExtensionException(String extensionName, String message) + : base(message) + { + ExtensionId = extensionName; + } + + public ExtensionException(String extensionName, String message, Exception innerException) + : base(message, innerException) + { + ExtensionId = extensionName; + } + + public override string Message + { + get + { + return ExtensionId + ": " + base.Message; + } + } + } +} diff --git a/src/Core/ServiceWrapper/Extensions/IWinSWExtension.cs b/src/Core/ServiceWrapper/Extensions/IWinSWExtension.cs new file mode 100644 index 0000000..23f1b80 --- /dev/null +++ b/src/Core/ServiceWrapper/Extensions/IWinSWExtension.cs @@ -0,0 +1,44 @@ +using System; +using System.Xml; +using winsw.Util; + +namespace winsw.Extensions +{ + /// + /// Interface for Win Service Wrapper Extension + /// + /// All implementations should provide the default empty constructor. The initialization will be performed by Init methods + public interface IWinSWExtension + { + /// + /// Extension name to be displayed in logs + /// + String DisplayName { get; } + + /// + /// Extension descriptor + /// + WinSWExtensionDescriptor Descriptor { get; set; } + + /// + /// Init handler. Extension should load it's config during that step + /// + /// Service descriptor + /// Configuration node + void Configure(ServiceDescriptor descriptor, XmlNode node, IEventWriter logger); + + /// + /// Start handler. Called during start of the service + /// + /// Logger + /// Any error during execution + void OnStart(IEventWriter logger); + + /// + /// Stop handler. Called during stop of the service + /// + /// Logger + /// Any error during execution + void OnStop(IEventWriter logger); + } +} diff --git a/src/Core/ServiceWrapper/Extensions/WinSWExtensionDescriptor.cs b/src/Core/ServiceWrapper/Extensions/WinSWExtensionDescriptor.cs new file mode 100644 index 0000000..b659fee --- /dev/null +++ b/src/Core/ServiceWrapper/Extensions/WinSWExtensionDescriptor.cs @@ -0,0 +1,39 @@ +using System; +using System.Xml; +using winsw.Util; + +namespace winsw.Extensions +{ + public class WinSWExtensionDescriptor + { + /// + /// Unique extension ID + /// + public String Id { get; private set; } + + /// + /// Exception is enabled + /// + public bool Enabled { get; private set; } + + /// + /// Extension classname + /// + public String ClassName { get; private set; } + + private WinSWExtensionDescriptor(string id, string className, bool enabled) + { + Id = id; + Enabled = enabled; + ClassName = className; + } + + public static WinSWExtensionDescriptor FromXml(XmlElement node) + { + bool enabled = XmlHelper.SingleAttribute(node, "enabled", true); + string className = XmlHelper.SingleAttribute(node, "className"); + string id = XmlHelper.SingleAttribute(node, "id"); + return new WinSWExtensionDescriptor(id, className, enabled); + } + } +} diff --git a/src/Core/ServiceWrapper/Extensions/WinSWExtensionManager.cs b/src/Core/ServiceWrapper/Extensions/WinSWExtensionManager.cs new file mode 100644 index 0000000..c305409 --- /dev/null +++ b/src/Core/ServiceWrapper/Extensions/WinSWExtensionManager.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.Xml; +using System.Reflection; +using System.Diagnostics; +using winsw.Util; + +namespace winsw.Extensions +{ + public class WinSWExtensionManager + { + public Dictionary Extensions { private set; get; } + public ServiceDescriptor ServiceDescriptor { private set; get; } + + public WinSWExtensionManager(ServiceDescriptor serviceDescriptor) + { + ServiceDescriptor = serviceDescriptor; + Extensions = new Dictionary(); + } + + /// + /// Starts all extensions + /// + /// Start failure + public void OnStart(IEventWriter logger) + { + foreach (var ext in Extensions) + { + ext.Value.OnStart(logger); + } + } + + /// + /// Stops all extensions + /// + /// Stop failure + public void OnStop(IEventWriter logger) + { + foreach (var ext in Extensions) + { + ext.Value.OnStop(logger); + } + } + + //TODO: Implement loading of external extensions. Current version supports internal hack + #region Extension load management + + public void LoadExtensions(IEventWriter logger) + { + var extensionIds = ServiceDescriptor.ExtensionIds; + foreach (String extensionId in extensionIds) + { + LoadExtension(extensionId, logger); + } + } + + /// + /// Loads extensions from the configuration file + /// + /// Extension ID + /// Logger + /// Loading failure + private void LoadExtension(string id, IEventWriter logger) + { + if (Extensions.ContainsKey(id)) + { + throw new ExtensionException(id, "Extension has been already loaded"); + } + + var extensionsConfig = ServiceDescriptor.ExtensionsConfiguration; + XmlElement configNode =(extensionsConfig != null) ? extensionsConfig.SelectSingleNode("extension[@id='"+id+"'][1]") as XmlElement : null; + if (configNode == null) + { + throw new ExtensionException(id, "Cannot get the configuration entry"); + } + + var descriptor = WinSWExtensionDescriptor.FromXml(configNode); + if (descriptor.Enabled) + { + IWinSWExtension extension = CreateExtensionInstance(descriptor.Id, descriptor.ClassName); + extension.Descriptor = descriptor; + extension.Configure(ServiceDescriptor, configNode, logger); + Extensions.Add(id, extension); + logger.LogEvent("Extension loaded: "+id, EventLogEntryType.Information); + } + else + { + logger.LogEvent("Extension is disabled: " + id, EventLogEntryType.Warning); + } + + } + + private IWinSWExtension CreateExtensionInstance(string id, string className) + { + ActivationContext ac = AppDomain.CurrentDomain.ActivationContext; + Assembly assembly = Assembly.GetCallingAssembly(); + Object created; + + try + { + Type t = Type.GetType(className); + if (t == null) + { + throw new ExtensionException(id, "Class "+className+" does not exist"); + } + created = Activator.CreateInstance(t); + } + catch (Exception ex) + { + throw new ExtensionException(id, "Cannot load the class by name: "+className, ex); + } + + var extension = created as IWinSWExtension; + if (extension == null) + { + throw new ExtensionException(id, "The loaded class is not a WinSW extension: " + className + ". Type is " + created.GetType()); + } + return extension; + } + + #endregion + } +} diff --git a/src/Core/ServiceWrapper/IEventWriter.cs b/src/Core/ServiceWrapper/IEventWriter.cs new file mode 100644 index 0000000..a09421f --- /dev/null +++ b/src/Core/ServiceWrapper/IEventWriter.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; + +namespace winsw.util +{ + public interface IEventWriter + { + void LogEvent(String message); + void LogEvent(String message, EventLogEntryType type); + } +} diff --git a/src/Core/ServiceWrapper/Main.cs b/src/Core/ServiceWrapper/Main.cs index bf29bbf..f9de0cb 100644 --- a/src/Core/ServiceWrapper/Main.cs +++ b/src/Core/ServiceWrapper/Main.cs @@ -14,13 +14,15 @@ using log4net.Core; using log4net.Layout; using log4net.Repository.Hierarchy; using Microsoft.Win32; +using winsw.Extensions; +using winsw.Util; using WMI; using ServiceType = WMI.ServiceType; using System.Reflection; namespace winsw { - public class WrapperService : ServiceBase, EventLogger + public class WrapperService : ServiceBase, EventLogger, IEventWriter { private SERVICE_STATUS _wrapperServiceStatus; @@ -28,6 +30,8 @@ namespace winsw private readonly ServiceDescriptor _descriptor; private Dictionary _envs; + internal WinSWExtensionManager ExtensionManager { private set; get; } + private static readonly ILog Log = LogManager.GetLogger("WinSW"); /// @@ -52,6 +56,7 @@ namespace winsw { _descriptor = descriptor; ServiceName = _descriptor.Id; + ExtensionManager = new WinSWExtensionManager(_descriptor); CanShutdown = true; CanStop = true; CanPauseAndContinue = false; @@ -246,6 +251,22 @@ namespace winsw LogEvent("Starting " + _descriptor.Executable + ' ' + startarguments); WriteEvent("Starting " + _descriptor.Executable + ' ' + startarguments); + // Load and start extensions + ExtensionManager.LoadExtensions(this); + try + { + ExtensionManager.OnStart(this); + } + catch (ExtensionException ex) + { + LogEvent("Failed to start extension " + ex.ExtensionId + "\n" + ex.Message, EventLogEntryType.Error); + WriteEvent("Failed to start extension " + ex.ExtensionId, ex); + //TODO: Exit on error? + } + + LogEvent("Starting " + _descriptor.Executable + ' ' + startarguments); + WriteEvent("Starting " + _descriptor.Executable + ' ' + startarguments); + StartProcess(_process, startarguments, _descriptor.Executable); // send stdout and stderr to its respective output file. @@ -327,6 +348,17 @@ namespace winsw SignalShutdownComplete(); } + // Stop extensions + try + { + ExtensionManager.OnStop(this); + } + catch (ExtensionException ex) + { + LogEvent("Failed to stop extension " + ex.ExtensionId + "\n" + ex.Message, EventLogEntryType.Error); + WriteEvent("Failed to stop extension " + ex.ExtensionId, ex); + } + if (_systemShuttingdown && _descriptor.BeepOnShutdown) { Console.Beep(); diff --git a/src/Core/ServiceWrapper/ServiceDescriptor.cs b/src/Core/ServiceWrapper/ServiceDescriptor.cs index 1263087..8e161ba 100755 --- a/src/Core/ServiceWrapper/ServiceDescriptor.cs +++ b/src/Core/ServiceWrapper/ServiceDescriptor.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.IO; using System.Reflection; using System.Xml; +using winsw.Util; using WMI; namespace winsw @@ -227,9 +228,7 @@ namespace winsw } } - /// - /// Optional working directory. - /// + public string WorkingDirectory { get { var wd = SingleElement("workingdirectory", true); @@ -237,6 +236,37 @@ namespace winsw } } + public List ExtensionIds + { + get + { + List res = new List(); + + XmlNode argumentNode = ExtensionsConfiguration; + XmlNodeList extensions = argumentNode != null ? argumentNode.SelectNodes("extension") : null; + if ( extensions != null) + { + foreach (XmlNode e in extensions) + { + XmlElement extension = (XmlElement)e; + String extensionId = XmlHelper.SingleAttribute(extension, "id"); + res.Add(extensionId); + } + } + + return res; + } + } + + public XmlNode ExtensionsConfiguration + { + get + { + XmlNode argumentNode = dom.SelectSingleNode("//extensions"); + return argumentNode; + } + } + /// /// Combines the contents of all the elements of the given name, /// or return null if no element exists. Handles whitespace quotation. diff --git a/src/Core/ServiceWrapper/Util/IEventWriter.cs b/src/Core/ServiceWrapper/Util/IEventWriter.cs new file mode 100644 index 0000000..7f49dfa --- /dev/null +++ b/src/Core/ServiceWrapper/Util/IEventWriter.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; + +namespace winsw.Util +{ + public interface IEventWriter + { + void LogEvent(String message); + void LogEvent(String message, EventLogEntryType type); + } +} diff --git a/src/Core/ServiceWrapper/Util/WinSWException.cs b/src/Core/ServiceWrapper/Util/WinSWException.cs new file mode 100644 index 0000000..3d1c8c4 --- /dev/null +++ b/src/Core/ServiceWrapper/Util/WinSWException.cs @@ -0,0 +1,15 @@ +using System; + +namespace winsw.Util +{ + public class WinSWException : Exception + { + public WinSWException(String message) + : base(message) + { } + + public WinSWException(String message, Exception innerException) + : base(message, innerException) + { } + } +} diff --git a/src/Core/ServiceWrapper/Util/XmlHelper.cs b/src/Core/ServiceWrapper/Util/XmlHelper.cs new file mode 100644 index 0000000..6269976 --- /dev/null +++ b/src/Core/ServiceWrapper/Util/XmlHelper.cs @@ -0,0 +1,73 @@ +using System; +using System.IO; +using System.Xml; + +namespace winsw.Util +{ + public class XmlHelper + { + /// + /// Retrieves a single string element + /// + /// Parent node + /// Element name + /// If otional, don't throw an exception if the elemen is missing + /// String value or null + /// The required element is missing + public static string SingleElement(XmlNode node, string tagName, Boolean optional) + { + var n = node.SelectSingleNode(tagName); + if (n == null && !optional) throw new InvalidDataException("<" + tagName + "> is missing in configuration XML"); + return n == null ? null : Environment.ExpandEnvironmentVariables(n.InnerText); + } + + /// + /// Retrieves a single node + /// + /// Parent node + /// Element name + /// If otional, don't throw an exception if the elemen is missing + /// String value or null + /// The required element is missing + public static XmlNode SingleNode(XmlNode node, string tagName, Boolean optional) + { + var n = node.SelectSingleNode(tagName); + if (n == null && !optional) throw new InvalidDataException("<" + tagName + "> is missing in configuration XML"); + return n; + } + + /// + /// Retrieves a single mandatory attribute + /// + /// Parent node + /// Attribute name + /// Attribute value + /// The required attribute is missing + public static TAttributeType SingleAttribute (XmlElement node, string attributeName) + { + if (!node.HasAttribute(attributeName)) + { + throw new InvalidDataException("Attribute <" + attributeName + "> is missing in configuration XML"); + } + + return SingleAttribute(node, attributeName, default(TAttributeType)); + } + + /// + /// Retrieves a single optional attribute + /// + /// Parent node + /// Attribute name + /// Default value + /// Attribute value (or default) + public static TAttributeType SingleAttribute(XmlElement node, string attributeName, TAttributeType defaultValue) + { + if (!node.HasAttribute(attributeName)) return defaultValue; + + string rawValue = node.GetAttribute(attributeName); + string substitutedValue = Environment.ExpandEnvironmentVariables(rawValue); + var value = (TAttributeType)Convert.ChangeType(substitutedValue, typeof(TAttributeType)); + return value; + } + } +} diff --git a/src/Core/ServiceWrapper/WinSWException.cs b/src/Core/ServiceWrapper/WinSWException.cs new file mode 100644 index 0000000..9db697f --- /dev/null +++ b/src/Core/ServiceWrapper/WinSWException.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace winsw.extensions +{ + public class WinSWException : Exception + { + public WinSWException(String message) + : base(message) + { } + + public WinSWException(String message, Exception innerException) + : base(message, innerException) + { } + } +} diff --git a/src/Core/ServiceWrapper/XmlHelper.cs b/src/Core/ServiceWrapper/XmlHelper.cs new file mode 100644 index 0000000..2d6155b --- /dev/null +++ b/src/Core/ServiceWrapper/XmlHelper.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml; +using System.IO; + +namespace winsw.Utils +{ + internal class XmlHelper + { + /// + /// Retrieves a single string element + /// + /// Parent node + /// Element name + /// If otional, don't throw an exception if the elemen is missing + /// String value or null + /// The required element is missing + public static string SingleElement(XmlNode node, string tagName, Boolean optional) + { + var n = node.SelectSingleNode(tagName); + if (n == null && !optional) throw new InvalidDataException("<" + tagName + "> is missing in configuration XML"); + return n == null ? null : Environment.ExpandEnvironmentVariables(n.InnerText); + } + + /// + /// Retrieves a single node + /// + /// Parent node + /// Element name + /// If otional, don't throw an exception if the elemen is missing + /// String value or null + /// The required element is missing + public static XmlNode SingleNode(XmlNode node, string tagName, Boolean optional) + { + var n = node.SelectSingleNode(tagName); + if (n == null && !optional) throw new InvalidDataException("<" + tagName + "> is missing in configuration XML"); + return n; + } + + /// + /// Retrieves a single mandatory attribute + /// + /// Parent node + /// Attribute name + /// Attribute value + /// The required attribute is missing + public static TAttributeType SingleAttribute (XmlElement node, string attributeName) + { + if (!node.HasAttribute(attributeName)) + { + throw new InvalidDataException("Attribute <" + attributeName + "> is missing in configuration XML"); + } + + return SingleAttribute(node, attributeName, default(TAttributeType)); + } + + /// + /// Retrieves a single optional attribute + /// + /// Parent node + /// Attribute name + /// Default value + /// Attribute value (or default) + public static TAttributeType SingleAttribute(XmlElement node, string attributeName, TAttributeType defaultValue) + { + if (!node.HasAttribute(attributeName)) return defaultValue; + + string rawValue = node.GetAttribute(attributeName); + string substitutedValue = Environment.ExpandEnvironmentVariables(rawValue); + var value = (TAttributeType)Convert.ChangeType(substitutedValue, typeof(TAttributeType)); + return value; + } + } +} diff --git a/src/Core/ServiceWrapper/winsw.csproj b/src/Core/ServiceWrapper/winsw.csproj index 0844ff4..eb2754a 100644 --- a/src/Core/ServiceWrapper/winsw.csproj +++ b/src/Core/ServiceWrapper/winsw.csproj @@ -77,6 +77,11 @@ + + + + + @@ -86,6 +91,9 @@ + + + @@ -114,6 +122,7 @@ true + + \ No newline at end of file diff --git a/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperConfig.cs b/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperConfig.cs new file mode 100644 index 0000000..0a6387e --- /dev/null +++ b/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperConfig.cs @@ -0,0 +1,31 @@ +using System; +using System.Xml; +using winsw.Util; + +namespace winsw.Plugins.SharedDirectoryMapper +{ + /// + /// Stores configuration entries for SharedDirectoryMapper extension. + /// + internal class SharedDirectoryMapperConfig + { + public bool EnableMapping { get; set; } + public String Label { get; set; } + public String UNCPath { get; set; } + + public SharedDirectoryMapperConfig(bool enableMapping, string label, string uncPath) + { + EnableMapping = enableMapping; + Label = label; + UNCPath = uncPath; + } + + public static SharedDirectoryMapperConfig FromXml(XmlElement node) + { + bool enableMapping = XmlHelper.SingleAttribute(node, "enabled", true); + string label = XmlHelper.SingleAttribute(node, "label"); + string uncPath = XmlHelper.SingleAttribute(node, "uncpath"); + return new SharedDirectoryMapperConfig(enableMapping, label, uncPath); + } + } +} diff --git a/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperHelper.cs b/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperHelper.cs new file mode 100644 index 0000000..8016a93 --- /dev/null +++ b/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperHelper.cs @@ -0,0 +1,73 @@ +using System; +using System.Diagnostics; +using winsw.Util; + +namespace winsw.Plugins.SharedDirectoryMapper +{ + class SharedDirectoryMappingHelper + { + /// + /// Invokes a system command + /// + /// + /// Command to be executed + /// Command arguments + /// Operation failure + private void InvokeCommand(String command, String args) + { + Process p = new Process + { + StartInfo = + { + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardError = true, + RedirectStandardOutput = true, + FileName = command, + Arguments = args + } + }; + + p.Start(); + p.WaitForExit(); + if (p.ExitCode != 0) + { + throw new MapperException(p, command, args); + } + } + + /// + /// Maps the remote directory + /// + /// Disk label + /// UNC path to the directory + /// Operation failure + public void MapDirectory(String label, String uncPath) + { + InvokeCommand("net.exe", " use " + label + " " + uncPath); + } + + /// + /// Unmaps the label + /// + /// Disk label + /// Operation failure + public void UnmapDirectory(String label) + { + InvokeCommand("net.exe", " use /DELETE /YES " + label); + } + } + + class MapperException : WinSWException + { + public String Call { get; private set; } + public Process Process { get; private set; } + + public MapperException(Process process, string command, string args) + : base("Command " + command + " " + args + " failed with code " + process.ExitCode) + { + Call = command + " " + args; + Process = process; + } + } +} diff --git a/src/Plugins/SharedDirectoryMapper/sampleConfig.xml b/src/Plugins/SharedDirectoryMapper/sampleConfig.xml new file mode 100644 index 0000000..8cf5907 --- /dev/null +++ b/src/Plugins/SharedDirectoryMapper/sampleConfig.xml @@ -0,0 +1,18 @@ + + + SERVICE_NAME + Jenkins Slave + This service runs a slave for Jenkins continuous integration system. + C:\Program Files\Java\jre7\bin\java.exe + -Xrs -jar "%BASE%\slave.jar" -jnlpUrl ... + rotate + + + + + + + + + + \ No newline at end of file diff --git a/src/Test/winswTests/Extensions/WinSWExtensionManagerTest.cs b/src/Test/winswTests/Extensions/WinSWExtensionManagerTest.cs new file mode 100644 index 0000000..5ccd638 --- /dev/null +++ b/src/Test/winswTests/Extensions/WinSWExtensionManagerTest.cs @@ -0,0 +1,62 @@ +using winsw; +using NUnit.Framework; +using winsw.Extensions; +using winsw.Plugins.SharedDirectoryMapper; +using winswTests.util; + +namespace winswTests.extensions +{ + [TestFixture] + class WinSWExtensionManagerTest + { + ServiceDescriptor _testServiceDescriptor; + readonly TestLogger _logger = new TestLogger(); + + [SetUp] + public void SetUp() + { + string testExtension = typeof (SharedDirectoryMapper).ToString(); + string seedXml = "" + + " " + + " SERVICE_NAME " + + " Jenkins Slave " + + " This service runs a slave for Jenkins continuous integration system. " + + " C:\\Program Files\\Java\\jre7\\bin\\java.exe " + + " -Xrs -jar \\\"%BASE%\\slave.jar\\\" -jnlpUrl ... " + + " rotate " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + ""; + _testServiceDescriptor = ServiceDescriptor.FromXML(seedXml); + } + + [Test] + public void LoadExtensions() + { + WinSWExtensionManager manager = new WinSWExtensionManager(_testServiceDescriptor); + manager.LoadExtensions(_logger); + Assert.AreEqual(2, manager.Extensions.Count, "Two extensions should be loaded"); + } + + [Test] + public void StartStopExtension() + { + WinSWExtensionManager manager = new WinSWExtensionManager(_testServiceDescriptor); + manager.LoadExtensions(_logger); + manager.OnStart(_logger); + manager.OnStop(_logger); + } + } +} diff --git a/src/Test/winswTests/NunitTest.nunit b/src/Test/winswTests/NunitTest.nunit new file mode 100644 index 0000000..3eaf587 --- /dev/null +++ b/src/Test/winswTests/NunitTest.nunit @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/Test/winswTests/Util/TestLogger.cs b/src/Test/winswTests/Util/TestLogger.cs new file mode 100644 index 0000000..d73ffab --- /dev/null +++ b/src/Test/winswTests/Util/TestLogger.cs @@ -0,0 +1,19 @@ +using System; +using System.Diagnostics; +using winsw.Util; + +namespace winswTests.util +{ + class TestLogger : IEventWriter + { + public void LogEvent(String message) + { + Console.WriteLine(message); + } + + public void LogEvent(String message, EventLogEntryType type) + { + Console.WriteLine("[" + type + "]" + message); + } + } +} diff --git a/src/Test/winswTests/winswTests.csproj b/src/Test/winswTests/winswTests.csproj index 83bddf7..0bf6911 100644 --- a/src/Test/winswTests/winswTests.csproj +++ b/src/Test/winswTests/winswTests.csproj @@ -52,9 +52,11 @@ + + @@ -62,10 +64,15 @@ {0DE77F55-ADE5-43C1-999A-0BC81153B039} winsw + + {ca5c71db-c5a8-4c27-bf83-8e6daed9d6b5} + SharedDirectoryMapper + + diff --git a/src/winsw.sln b/src/winsw.sln index 15d09bd..4bb2cad 100644 --- a/src/winsw.sln +++ b/src/winsw.sln @@ -6,6 +6,9 @@ MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "winsw", "Core\ServiceWrapper\winsw.csproj", "{0DE77F55-ADE5-43C1-999A-0BC81153B039}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "winswTests", "Test\winswTests\winswTests.csproj", "{93843402-842B-44B4-B303-AEE829BE0B43}" + ProjectSection(ProjectDependencies) = postProject + {CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5} = {CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5} + EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{6BDF4025-D46C-4C69-BDB2-5CE434C857AA}" ProjectSection(SolutionItems) = preProject @@ -14,22 +17,64 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{6BDF40 .nuget\NuGet.targets = .nuget\NuGet.targets EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedDirectoryMapper", "Plugins\SharedDirectoryMapper\SharedDirectoryMapper.csproj", "{CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{077C2CEC-B687-4B53-86E9-C1A1BF5554E5}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{BC4AD891-E87E-4F30-867C-FD8084A29E5D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms Debug|Win32 = Debug|Win32 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Win32.ActiveCfg = Debug|Any CPU {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Win32.Build.0 = Debug|Any CPU + {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Release|Any CPU.Build.0 = Release|Any CPU + {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Release|Mixed Platforms.Build.0 = Release|Any CPU {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Release|Win32.ActiveCfg = Release|Any CPU {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Release|Win32.Build.0 = Release|Any CPU + {93843402-842B-44B4-B303-AEE829BE0B43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {93843402-842B-44B4-B303-AEE829BE0B43}.Debug|Any CPU.Build.0 = Debug|Any CPU + {93843402-842B-44B4-B303-AEE829BE0B43}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {93843402-842B-44B4-B303-AEE829BE0B43}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {93843402-842B-44B4-B303-AEE829BE0B43}.Debug|Win32.ActiveCfg = Debug|Any CPU {93843402-842B-44B4-B303-AEE829BE0B43}.Debug|Win32.Build.0 = Debug|Any CPU + {93843402-842B-44B4-B303-AEE829BE0B43}.Release|Any CPU.ActiveCfg = Release|Any CPU + {93843402-842B-44B4-B303-AEE829BE0B43}.Release|Any CPU.Build.0 = Release|Any CPU + {93843402-842B-44B4-B303-AEE829BE0B43}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {93843402-842B-44B4-B303-AEE829BE0B43}.Release|Mixed Platforms.Build.0 = Release|Any CPU {93843402-842B-44B4-B303-AEE829BE0B43}.Release|Win32.ActiveCfg = Release|Any CPU {93843402-842B-44B4-B303-AEE829BE0B43}.Release|Win32.Build.0 = Release|Any CPU + {CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Debug|Win32.ActiveCfg = Debug|Any CPU + {CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Debug|Win32.Build.0 = Debug|Any CPU + {CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Release|Any CPU.Build.0 = Release|Any CPU + {CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Release|Win32.ActiveCfg = Release|Any CPU + {CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Release|Win32.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {93843402-842B-44B4-B303-AEE829BE0B43} = {077C2CEC-B687-4B53-86E9-C1A1BF5554E5} + {CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5} = {BC4AD891-E87E-4F30-867C-FD8084A29E5D} + EndGlobalSection EndGlobal diff --git a/src/winsw.sln.DotSettings b/src/winsw.sln.DotSettings new file mode 100644 index 0000000..45d451a --- /dev/null +++ b/src/winsw.sln.DotSettings @@ -0,0 +1,3 @@ + + SW + UNC \ No newline at end of file From 3af1f726583aa3a0c5d751d02aa36a947b89670d Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Sun, 1 Feb 2015 01:41:22 +0300 Subject: [PATCH 2/6] Support merging plugins into winsw.exe executable * Decouple Core components into WinSWCore projects. * Use ILMerge to merge everything (inc. Plugins) into a single executable TODO: API Should be refactored before the publishing TODO: check signing procedure Signed-off-by: Oleg Nenashev Conflicts: src/Core/ServiceWrapper/winsw.csproj Conflicts: src/Core/ServiceWrapper/Main.cs src/winsw.sln --- .gitignore | 2 + src/.nuget/packages.config | 4 + src/Core/ServiceWrapper/IEventWriter.cs | 13 ---- src/Core/ServiceWrapper/Main.cs | 1 + .../ServiceWrapper/Util/WinSWException.cs | 15 ---- src/Core/ServiceWrapper/Util/XmlHelper.cs | 73 ------------------ src/Core/ServiceWrapper/winsw.csproj | 47 ++++++------ .../{ServiceWrapper => WinSWCore}/Download.cs | 0 .../DynamicProxy.cs | 0 .../Extensions/AbstractWinSWExtension.cs | 0 .../Extensions/ExtensionException.cs | 1 - .../Extensions/IWinSWExtension.cs | 0 .../Extensions/WinSWExtensionDescriptor.cs | 0 .../Extensions/WinSWExtensionManager.cs | 0 .../LogAppenders.cs | 0 .../Native}/Advapi32.cs | 12 +-- .../Native}/Kernel32.cs | 14 ++-- .../PeriodicRollingCalendar.cs | 0 src/Core/WinSWCore/Properties/AssemblyInfo.cs | 36 +++++++++ .../ServiceDescriptor.cs | 1 + .../Util/IEventWriter.cs | 0 .../Util}/XmlHelper.cs | 4 +- src/Core/WinSWCore/WinSWCore.csproj | 75 +++++++++++++++++++ .../WinSWException.cs | 2 +- src/Core/{ServiceWrapper => WinSWCore}/Wmi.cs | 0 .../WmiSchema.cs | 0 .../SharedDirectoryMapper.csproj | 6 +- .../SharedDirectoryMapperConfig.cs | 2 +- src/Test/winswTests/winswTests.csproj | 4 + src/winsw.sln | 27 +++++-- 30 files changed, 188 insertions(+), 151 deletions(-) create mode 100644 src/.nuget/packages.config delete mode 100644 src/Core/ServiceWrapper/IEventWriter.cs delete mode 100644 src/Core/ServiceWrapper/Util/WinSWException.cs delete mode 100644 src/Core/ServiceWrapper/Util/XmlHelper.cs rename src/Core/{ServiceWrapper => WinSWCore}/Download.cs (100%) rename src/Core/{ServiceWrapper => WinSWCore}/DynamicProxy.cs (100%) rename src/Core/{ServiceWrapper => WinSWCore}/Extensions/AbstractWinSWExtension.cs (100%) rename src/Core/{ServiceWrapper => WinSWCore}/Extensions/ExtensionException.cs (97%) rename src/Core/{ServiceWrapper => WinSWCore}/Extensions/IWinSWExtension.cs (100%) rename src/Core/{ServiceWrapper => WinSWCore}/Extensions/WinSWExtensionDescriptor.cs (100%) rename src/Core/{ServiceWrapper => WinSWCore}/Extensions/WinSWExtensionManager.cs (100%) rename src/Core/{ServiceWrapper => WinSWCore}/LogAppenders.cs (100%) rename src/Core/{ServiceWrapper => WinSWCore/Native}/Advapi32.cs (96%) rename src/Core/{ServiceWrapper => WinSWCore/Native}/Kernel32.cs (79%) rename src/Core/{ServiceWrapper => WinSWCore}/PeriodicRollingCalendar.cs (100%) create mode 100644 src/Core/WinSWCore/Properties/AssemblyInfo.cs rename src/Core/{ServiceWrapper => WinSWCore}/ServiceDescriptor.cs (96%) rename src/Core/{ServiceWrapper => WinSWCore}/Util/IEventWriter.cs (100%) rename src/Core/{ServiceWrapper => WinSWCore/Util}/XmlHelper.cs (98%) create mode 100644 src/Core/WinSWCore/WinSWCore.csproj rename src/Core/{ServiceWrapper => WinSWCore}/WinSWException.cs (92%) rename src/Core/{ServiceWrapper => WinSWCore}/Wmi.cs (100%) rename src/Core/{ServiceWrapper => WinSWCore}/WmiSchema.cs (100%) diff --git a/.gitignore b/.gitignore index 52acab8..a5c19de 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ obj /winsw.csproj.user /winsw_cert.pfx *.user +/src/packages/NUnit.2.6.4 +/src/packages/ILMerge.MSBuild.Tasks.1.0.0.3 diff --git a/src/.nuget/packages.config b/src/.nuget/packages.config new file mode 100644 index 0000000..e1e92a3 --- /dev/null +++ b/src/.nuget/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/Core/ServiceWrapper/IEventWriter.cs b/src/Core/ServiceWrapper/IEventWriter.cs deleted file mode 100644 index a09421f..0000000 --- a/src/Core/ServiceWrapper/IEventWriter.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Diagnostics; - -namespace winsw.util -{ - public interface IEventWriter - { - void LogEvent(String message); - void LogEvent(String message, EventLogEntryType type); - } -} diff --git a/src/Core/ServiceWrapper/Main.cs b/src/Core/ServiceWrapper/Main.cs index f9de0cb..dd18771 100644 --- a/src/Core/ServiceWrapper/Main.cs +++ b/src/Core/ServiceWrapper/Main.cs @@ -18,6 +18,7 @@ using winsw.Extensions; using winsw.Util; using WMI; using ServiceType = WMI.ServiceType; +using winsw.Native; using System.Reflection; namespace winsw diff --git a/src/Core/ServiceWrapper/Util/WinSWException.cs b/src/Core/ServiceWrapper/Util/WinSWException.cs deleted file mode 100644 index 3d1c8c4..0000000 --- a/src/Core/ServiceWrapper/Util/WinSWException.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace winsw.Util -{ - public class WinSWException : Exception - { - public WinSWException(String message) - : base(message) - { } - - public WinSWException(String message, Exception innerException) - : base(message, innerException) - { } - } -} diff --git a/src/Core/ServiceWrapper/Util/XmlHelper.cs b/src/Core/ServiceWrapper/Util/XmlHelper.cs deleted file mode 100644 index 6269976..0000000 --- a/src/Core/ServiceWrapper/Util/XmlHelper.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using System.IO; -using System.Xml; - -namespace winsw.Util -{ - public class XmlHelper - { - /// - /// Retrieves a single string element - /// - /// Parent node - /// Element name - /// If otional, don't throw an exception if the elemen is missing - /// String value or null - /// The required element is missing - public static string SingleElement(XmlNode node, string tagName, Boolean optional) - { - var n = node.SelectSingleNode(tagName); - if (n == null && !optional) throw new InvalidDataException("<" + tagName + "> is missing in configuration XML"); - return n == null ? null : Environment.ExpandEnvironmentVariables(n.InnerText); - } - - /// - /// Retrieves a single node - /// - /// Parent node - /// Element name - /// If otional, don't throw an exception if the elemen is missing - /// String value or null - /// The required element is missing - public static XmlNode SingleNode(XmlNode node, string tagName, Boolean optional) - { - var n = node.SelectSingleNode(tagName); - if (n == null && !optional) throw new InvalidDataException("<" + tagName + "> is missing in configuration XML"); - return n; - } - - /// - /// Retrieves a single mandatory attribute - /// - /// Parent node - /// Attribute name - /// Attribute value - /// The required attribute is missing - public static TAttributeType SingleAttribute (XmlElement node, string attributeName) - { - if (!node.HasAttribute(attributeName)) - { - throw new InvalidDataException("Attribute <" + attributeName + "> is missing in configuration XML"); - } - - return SingleAttribute(node, attributeName, default(TAttributeType)); - } - - /// - /// Retrieves a single optional attribute - /// - /// Parent node - /// Attribute name - /// Default value - /// Attribute value (or default) - public static TAttributeType SingleAttribute(XmlElement node, string attributeName, TAttributeType defaultValue) - { - if (!node.HasAttribute(attributeName)) return defaultValue; - - string rawValue = node.GetAttribute(attributeName); - string substitutedValue = Environment.ExpandEnvironmentVariables(rawValue); - var value = (TAttributeType)Convert.ChangeType(substitutedValue, typeof(TAttributeType)); - return value; - } - } -} diff --git a/src/Core/ServiceWrapper/winsw.csproj b/src/Core/ServiceWrapper/winsw.csproj index eb2754a..bcae52a 100644 --- a/src/Core/ServiceWrapper/winsw.csproj +++ b/src/Core/ServiceWrapper/winsw.csproj @@ -9,7 +9,7 @@ Exe Properties winsw - winsw + WindowsService v2.0 512 @@ -62,9 +62,6 @@ - - ..\..\packages\log4net.2.0.3\lib\net20-full\log4net.dll - @@ -74,28 +71,11 @@ - - - - - - - - - - Component - - - - - - - @@ -108,7 +88,6 @@ - @@ -122,6 +101,16 @@ true + + + {ca5c71db-c5a8-4c27-bf83-8e6daed9d6b5} + SharedDirectoryMapper + + + {9d0c63e2-b6ff-4a85-bd36-b3e5d7f27d06} + WinSWCore + + + + + + + + + + + $(ProjectDir)$(OutDir)winsw.exe + + + + \ No newline at end of file diff --git a/src/Core/ServiceWrapper/Download.cs b/src/Core/WinSWCore/Download.cs similarity index 100% rename from src/Core/ServiceWrapper/Download.cs rename to src/Core/WinSWCore/Download.cs diff --git a/src/Core/ServiceWrapper/DynamicProxy.cs b/src/Core/WinSWCore/DynamicProxy.cs similarity index 100% rename from src/Core/ServiceWrapper/DynamicProxy.cs rename to src/Core/WinSWCore/DynamicProxy.cs diff --git a/src/Core/ServiceWrapper/Extensions/AbstractWinSWExtension.cs b/src/Core/WinSWCore/Extensions/AbstractWinSWExtension.cs similarity index 100% rename from src/Core/ServiceWrapper/Extensions/AbstractWinSWExtension.cs rename to src/Core/WinSWCore/Extensions/AbstractWinSWExtension.cs diff --git a/src/Core/ServiceWrapper/Extensions/ExtensionException.cs b/src/Core/WinSWCore/Extensions/ExtensionException.cs similarity index 97% rename from src/Core/ServiceWrapper/Extensions/ExtensionException.cs rename to src/Core/WinSWCore/Extensions/ExtensionException.cs index 563c5ed..5ac682a 100644 --- a/src/Core/ServiceWrapper/Extensions/ExtensionException.cs +++ b/src/Core/WinSWCore/Extensions/ExtensionException.cs @@ -1,5 +1,4 @@ using System; -using winsw.Util; namespace winsw.Extensions { diff --git a/src/Core/ServiceWrapper/Extensions/IWinSWExtension.cs b/src/Core/WinSWCore/Extensions/IWinSWExtension.cs similarity index 100% rename from src/Core/ServiceWrapper/Extensions/IWinSWExtension.cs rename to src/Core/WinSWCore/Extensions/IWinSWExtension.cs diff --git a/src/Core/ServiceWrapper/Extensions/WinSWExtensionDescriptor.cs b/src/Core/WinSWCore/Extensions/WinSWExtensionDescriptor.cs similarity index 100% rename from src/Core/ServiceWrapper/Extensions/WinSWExtensionDescriptor.cs rename to src/Core/WinSWCore/Extensions/WinSWExtensionDescriptor.cs diff --git a/src/Core/ServiceWrapper/Extensions/WinSWExtensionManager.cs b/src/Core/WinSWCore/Extensions/WinSWExtensionManager.cs similarity index 100% rename from src/Core/ServiceWrapper/Extensions/WinSWExtensionManager.cs rename to src/Core/WinSWCore/Extensions/WinSWExtensionManager.cs diff --git a/src/Core/ServiceWrapper/LogAppenders.cs b/src/Core/WinSWCore/LogAppenders.cs similarity index 100% rename from src/Core/ServiceWrapper/LogAppenders.cs rename to src/Core/WinSWCore/LogAppenders.cs diff --git a/src/Core/ServiceWrapper/Advapi32.cs b/src/Core/WinSWCore/Native/Advapi32.cs similarity index 96% rename from src/Core/ServiceWrapper/Advapi32.cs rename to src/Core/WinSWCore/Native/Advapi32.cs index ae6ea7a..cc2ed32 100755 --- a/src/Core/ServiceWrapper/Advapi32.cs +++ b/src/Core/WinSWCore/Native/Advapi32.cs @@ -6,9 +6,9 @@ using System.Text; // ReSharper disable InconsistentNaming -namespace winsw +namespace winsw.Native { - class ServiceManager : IDisposable + public class ServiceManager : IDisposable { private IntPtr _handle; @@ -39,7 +39,7 @@ namespace winsw } } - class Service : IDisposable + public class Service : IDisposable { internal IntPtr Handle; @@ -87,7 +87,7 @@ namespace winsw } } - static class LogonAsAService + public static class LogonAsAService { public static void AddLogonAsAServiceRight(string username) { @@ -251,7 +251,7 @@ namespace winsw /// Advapi32.dll wrapper for performing additional service related operations that are not /// available in WMI. /// - internal class Advapi32 + public class Advapi32 { [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] [return: MarshalAs(UnmanagedType.Bool)] @@ -272,7 +272,7 @@ namespace winsw internal static extern bool CloseServiceHandle(IntPtr hSCObject); [DllImport("advapi32.DLL")] - internal static extern bool SetServiceStatus(IntPtr hServiceStatus, ref SERVICE_STATUS lpServiceStatus); + public static extern bool SetServiceStatus(IntPtr hServiceStatus, ref SERVICE_STATUS lpServiceStatus); [DllImport("advapi32.dll", PreserveSig = true)] internal static extern UInt32 LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, Int32 DesiredAccess, diff --git a/src/Core/ServiceWrapper/Kernel32.cs b/src/Core/WinSWCore/Native/Kernel32.cs similarity index 79% rename from src/Core/ServiceWrapper/Kernel32.cs rename to src/Core/WinSWCore/Native/Kernel32.cs index 29b20ae..3d57a9a 100755 --- a/src/Core/ServiceWrapper/Kernel32.cs +++ b/src/Core/WinSWCore/Native/Kernel32.cs @@ -1,18 +1,18 @@ using System; using System.Runtime.InteropServices; -namespace winsw +namespace winsw.Native { /// /// kernel32.dll P/Invoke wrappers /// - internal class Kernel32 + public class Kernel32 { [DllImport("Kernel32.dll", SetLastError = true)] - internal static extern int SetStdHandle(int device, IntPtr handle); + public static extern int SetStdHandle(int device, IntPtr handle); [DllImport("kernel32.dll", SetLastError = true)] - internal static extern bool CreateProcess(string lpApplicationName, + public static extern bool CreateProcess(string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, @@ -20,11 +20,11 @@ namespace winsw out PROCESS_INFORMATION lpProcessInformation); [DllImport("kernel32.dll")] - internal static extern int GetLastError(); + public static extern int GetLastError(); } [StructLayout(LayoutKind.Sequential)] - internal struct PROCESS_INFORMATION + public struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; @@ -33,7 +33,7 @@ namespace winsw } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - struct STARTUPINFO + public struct STARTUPINFO { public Int32 cb; public string lpReserved; diff --git a/src/Core/ServiceWrapper/PeriodicRollingCalendar.cs b/src/Core/WinSWCore/PeriodicRollingCalendar.cs similarity index 100% rename from src/Core/ServiceWrapper/PeriodicRollingCalendar.cs rename to src/Core/WinSWCore/PeriodicRollingCalendar.cs diff --git a/src/Core/WinSWCore/Properties/AssemblyInfo.cs b/src/Core/WinSWCore/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..5cb6f2a --- /dev/null +++ b/src/Core/WinSWCore/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("WinSWCore")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("WinSWCore")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("8f845354-ba20-455d-82d1-9b6ec4e0e517")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Core/ServiceWrapper/ServiceDescriptor.cs b/src/Core/WinSWCore/ServiceDescriptor.cs similarity index 96% rename from src/Core/ServiceWrapper/ServiceDescriptor.cs rename to src/Core/WinSWCore/ServiceDescriptor.cs index 8e161ba..8d770fe 100755 --- a/src/Core/ServiceWrapper/ServiceDescriptor.cs +++ b/src/Core/WinSWCore/ServiceDescriptor.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.IO; using System.Reflection; using System.Xml; +using winsw.Native; using winsw.Util; using WMI; diff --git a/src/Core/ServiceWrapper/Util/IEventWriter.cs b/src/Core/WinSWCore/Util/IEventWriter.cs similarity index 100% rename from src/Core/ServiceWrapper/Util/IEventWriter.cs rename to src/Core/WinSWCore/Util/IEventWriter.cs diff --git a/src/Core/ServiceWrapper/XmlHelper.cs b/src/Core/WinSWCore/Util/XmlHelper.cs similarity index 98% rename from src/Core/ServiceWrapper/XmlHelper.cs rename to src/Core/WinSWCore/Util/XmlHelper.cs index 2d6155b..687a8d2 100644 --- a/src/Core/ServiceWrapper/XmlHelper.cs +++ b/src/Core/WinSWCore/Util/XmlHelper.cs @@ -4,9 +4,9 @@ using System.Text; using System.Xml; using System.IO; -namespace winsw.Utils +namespace winsw.Util { - internal class XmlHelper + public class XmlHelper { /// /// Retrieves a single string element diff --git a/src/Core/WinSWCore/WinSWCore.csproj b/src/Core/WinSWCore/WinSWCore.csproj new file mode 100644 index 0000000..e26b0be --- /dev/null +++ b/src/Core/WinSWCore/WinSWCore.csproj @@ -0,0 +1,75 @@ + + + + + Debug + AnyCPU + {9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06} + Library + Properties + winsw + WinSWCore + v2.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + ..\..\..\winsw_cert.pfx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Core/ServiceWrapper/WinSWException.cs b/src/Core/WinSWCore/WinSWException.cs similarity index 92% rename from src/Core/ServiceWrapper/WinSWException.cs rename to src/Core/WinSWCore/WinSWException.cs index 9db697f..870660e 100644 --- a/src/Core/ServiceWrapper/WinSWException.cs +++ b/src/Core/WinSWCore/WinSWException.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace winsw.extensions +namespace winsw { public class WinSWException : Exception { diff --git a/src/Core/ServiceWrapper/Wmi.cs b/src/Core/WinSWCore/Wmi.cs similarity index 100% rename from src/Core/ServiceWrapper/Wmi.cs rename to src/Core/WinSWCore/Wmi.cs diff --git a/src/Core/ServiceWrapper/WmiSchema.cs b/src/Core/WinSWCore/WmiSchema.cs similarity index 100% rename from src/Core/ServiceWrapper/WmiSchema.cs rename to src/Core/WinSWCore/WmiSchema.cs diff --git a/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapper.csproj b/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapper.csproj index 4b27b75..6552879 100644 --- a/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapper.csproj +++ b/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapper.csproj @@ -41,9 +41,9 @@ - - {0de77f55-ade5-43c1-999a-0bc81153b039} - winsw + + {9d0c63e2-b6ff-4a85-bd36-b3e5d7f27d06} + WinSWCore diff --git a/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperConfig.cs b/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperConfig.cs index 0a6387e..59276e8 100644 --- a/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperConfig.cs +++ b/src/Plugins/SharedDirectoryMapper/SharedDirectoryMapperConfig.cs @@ -7,7 +7,7 @@ namespace winsw.Plugins.SharedDirectoryMapper /// /// Stores configuration entries for SharedDirectoryMapper extension. /// - internal class SharedDirectoryMapperConfig + public class SharedDirectoryMapperConfig { public bool EnableMapping { get; set; } public String Label { get; set; } diff --git a/src/Test/winswTests/winswTests.csproj b/src/Test/winswTests/winswTests.csproj index 0bf6911..4818a3c 100644 --- a/src/Test/winswTests/winswTests.csproj +++ b/src/Test/winswTests/winswTests.csproj @@ -64,6 +64,10 @@ {0DE77F55-ADE5-43C1-999A-0BC81153B039} winsw + + {9d0c63e2-b6ff-4a85-bd36-b3e5d7f27d06} + WinSWCore + {ca5c71db-c5a8-4c27-bf83-8e6daed9d6b5} SharedDirectoryMapper diff --git a/src/winsw.sln b/src/winsw.sln index 4bb2cad..6f2dd5d 100644 --- a/src/winsw.sln +++ b/src/winsw.sln @@ -1,4 +1,3 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.31101.0 @@ -6,15 +5,11 @@ MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "winsw", "Core\ServiceWrapper\winsw.csproj", "{0DE77F55-ADE5-43C1-999A-0BC81153B039}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "winswTests", "Test\winswTests\winswTests.csproj", "{93843402-842B-44B4-B303-AEE829BE0B43}" - ProjectSection(ProjectDependencies) = postProject - {CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5} = {CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5} - EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{6BDF4025-D46C-4C69-BDB2-5CE434C857AA}" ProjectSection(SolutionItems) = preProject .nuget\NuGet.Config = .nuget\NuGet.Config .nuget\NuGet.exe = .nuget\NuGet.exe - .nuget\NuGet.targets = .nuget\NuGet.targets EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedDirectoryMapper", "Plugins\SharedDirectoryMapper\SharedDirectoryMapper.csproj", "{CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}" @@ -23,6 +18,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{077C2CEC EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{BC4AD891-E87E-4F30-867C-FD8084A29E5D}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{5297623A-1A95-4F89-9AAE-DA634081EC86}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinSWCore", "Core\WinSWCore\WinSWCore.csproj", "{9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -35,8 +34,8 @@ Global GlobalSection(ProjectConfigurationPlatforms) = postSolution {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Mixed Platforms.ActiveCfg = Release|Any CPU + {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Mixed Platforms.Build.0 = Release|Any CPU {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Win32.ActiveCfg = Debug|Any CPU {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Debug|Win32.Build.0 = Debug|Any CPU {0DE77F55-ADE5-43C1-999A-0BC81153B039}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -69,12 +68,26 @@ Global {CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Release|Mixed Platforms.Build.0 = Release|Any CPU {CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Release|Win32.ActiveCfg = Release|Any CPU {CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5}.Release|Win32.Build.0 = Release|Any CPU + {9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Debug|Win32.ActiveCfg = Debug|Any CPU + {9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Debug|Win32.Build.0 = Debug|Any CPU + {9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Release|Any CPU.Build.0 = Release|Any CPU + {9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Release|Win32.ActiveCfg = Release|Any CPU + {9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}.Release|Win32.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution + {0DE77F55-ADE5-43C1-999A-0BC81153B039} = {5297623A-1A95-4F89-9AAE-DA634081EC86} {93843402-842B-44B4-B303-AEE829BE0B43} = {077C2CEC-B687-4B53-86E9-C1A1BF5554E5} {CA5C71DB-C5A8-4C27-BF83-8E6DAED9D6B5} = {BC4AD891-E87E-4F30-867C-FD8084A29E5D} + {9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06} = {5297623A-1A95-4F89-9AAE-DA634081EC86} EndGlobalSection EndGlobal From 8a5a1dd10d01212eae5db2bff890319da6a4a12c Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Mon, 2 Feb 2015 10:56:18 +0300 Subject: [PATCH 3/6] Integrate log4net dependency into WinSWCore Signed-off-by: Oleg Nenashev --- src/Core/ServiceWrapper/winsw.csproj | 4 ++++ src/Core/WinSWCore/WinSWCore.csproj | 13 +++++++++++++ src/packages/repositories.config | 1 + 3 files changed, 18 insertions(+) diff --git a/src/Core/ServiceWrapper/winsw.csproj b/src/Core/ServiceWrapper/winsw.csproj index bcae52a..66e95ae 100644 --- a/src/Core/ServiceWrapper/winsw.csproj +++ b/src/Core/ServiceWrapper/winsw.csproj @@ -62,6 +62,9 @@ + + ..\..\packages\log4net.2.0.3\lib\net20-full\log4net.dll + @@ -88,6 +91,7 @@ + diff --git a/src/Core/WinSWCore/WinSWCore.csproj b/src/Core/WinSWCore/WinSWCore.csproj index e26b0be..18970be 100644 --- a/src/Core/WinSWCore/WinSWCore.csproj +++ b/src/Core/WinSWCore/WinSWCore.csproj @@ -11,6 +11,8 @@ WinSWCore v2.0 512 + ..\..\ + true true @@ -36,6 +38,9 @@ ..\..\..\winsw_cert.pfx + + ..\..\packages\log4net.2.0.3\lib\net20-full\log4net.dll + @@ -63,8 +68,16 @@ + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + - - - - @@ -135,8 +134,8 @@ - - + + @@ -146,8 +145,35 @@ $(ProjectDir)$(OutDir)winsw.exe + $(AssemblyOriginatorKeyFile) + + + $(OutputPath)sn-path.txt + + + + + + + + + + + + $([System.Text.RegularExpressions.Regex]::Replace('$(SNPath)', ';.*', '')) + + + + + + $(SolutionDir)packages\ilmerge.2.14.1208\tools + $(OutputPath)winsw_cert.pub + + + - + + \ No newline at end of file diff --git a/src/winsw.sln b/src/winsw.sln index 6f2dd5d..95098b0 100644 --- a/src/winsw.sln +++ b/src/winsw.sln @@ -22,6 +22,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{5297623A-1 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinSWCore", "Core\WinSWCore\WinSWCore.csproj", "{9D0C63E2-B6FF-4A85-BD36-B3E5D7F27D06}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".build", ".build", "{D8806424-4640-440C-952D-37790B603C27}" + ProjectSection(SolutionItems) = preProject + Build.proj = Build.proj + .build\MSBuild.Community.Tasks.dll = .build\MSBuild.Community.Tasks.dll + .build\MSBuild.Community.Tasks.targets = .build\MSBuild.Community.Tasks.targets + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU