Clean up styles

pull/353/head
NextTurn 2018-12-07 00:00:00 +08:00
parent 6e9d25a7b5
commit 9808ae88e8
No known key found for this signature in database
GPG Key ID: 17A0D50ADDE1A0C4
41 changed files with 765 additions and 824 deletions

View File

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using winsw.Logging;
using System.Diagnostics;
namespace winsw.Logging
{
@ -11,7 +7,7 @@ namespace winsw.Logging
/// </summary>
public class WrapperServiceEventLogProvider : IServiceEventLogProvider
{
public WrapperService service {get; set;}
public WrapperService service { get; set; }
public EventLog locate()
{

View File

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Management;
using System.Reflection;
using System.Runtime.InteropServices;
using System.ServiceProcess;
using System.Text;
@ -12,15 +12,13 @@ using log4net.Appender;
using log4net.Config;
using log4net.Core;
using log4net.Layout;
using log4net.Repository.Hierarchy;
using Microsoft.Win32;
using winsw.Extensions;
using winsw.Logging;
using winsw.Native;
using winsw.Util;
using WMI;
using ServiceType = WMI.ServiceType;
using winsw.Native;
using System.Reflection;
using winsw.Logging;
namespace winsw
{
@ -32,7 +30,7 @@ namespace winsw
private readonly ServiceDescriptor _descriptor;
private Dictionary<string, string> _envs;
internal WinSWExtensionManager ExtensionManager { private set; get; }
internal WinSWExtensionManager ExtensionManager { get; private set; }
private static readonly ILog Log = LogManager.GetLogger("WinSW");
private static readonly WrapperServiceEventLogProvider eventLogProvider = new WrapperServiceEventLogProvider();
@ -50,17 +48,12 @@ namespace winsw
/// <remarks>
/// The version will be taken from <see cref="AssemblyInfo"/>
/// </remarks>
public static Version Version
{
get { return Assembly.GetExecutingAssembly().GetName().Version; }
}
public static Version Version => Assembly.GetExecutingAssembly().GetName().Version;
/// <summary>
/// Indicates that the system is shutting down.
/// </summary>
public bool IsShuttingDown {
get { return _systemShuttingdown; }
}
public bool IsShuttingDown => _systemShuttingdown;
public WrapperService(ServiceDescriptor descriptor)
{
@ -77,8 +70,8 @@ namespace winsw
eventLogProvider.service = this;
}
public WrapperService() : this (new ServiceDescriptor())
{
public WrapperService() : this(new ServiceDescriptor())
{
}
/// <summary>
@ -93,7 +86,7 @@ namespace winsw
try
{
using (var tr = new StreamReader(file,Encoding.UTF8))
using (var tr = new StreamReader(file, Encoding.UTF8))
{
string line;
while ((line = tr.ReadLine()) != null)
@ -114,7 +107,6 @@ namespace winsw
{
File.Delete(file);
}
}
/// <summary>
@ -199,7 +191,6 @@ namespace winsw
{
LogEvent("envar " + key + '=' + _envs[key]);
}*/
HandleFileCopies();
// handle downloads
@ -217,12 +208,13 @@ namespace winsw
string errorMessage = "Failed to download " + d.From + " to " + d.To;
LogEvent(errorMessage + ". " + e.Message);
Log.Error(errorMessage, e);
// TODO: move this code into the download logic
if (d.FailOnError)
{
throw new IOException(errorMessage, e);
}
// Else just keep going
}
}
@ -254,7 +246,7 @@ namespace winsw
protected override void OnShutdown()
{
// WriteEvent("OnShutdown");
// WriteEvent("OnShutdown");
try
{
@ -269,7 +261,7 @@ namespace winsw
protected override void OnStop()
{
// WriteEvent("OnStop");
// WriteEvent("OnStop");
try
{
@ -318,7 +310,7 @@ namespace winsw
executable = _descriptor.Executable;
}
// TODO: Redirect logging to Log4Net once https://github.com/kohsuke/winsw/pull/213 is integrated
// TODO: Redirect logging to Log4Net once https://github.com/kohsuke/winsw/pull/213 is integrated
StartProcess(stopProcess, stoparguments, executable, null, false);
Log.Debug("WaitForProcessToExit " + _process.Id + "+" + stopProcess.Id);
@ -327,10 +319,10 @@ namespace winsw
SignalShutdownComplete();
}
// Stop extensions
// Stop extensions
ExtensionManager.FireBeforeWrapperStopped();
if (_systemShuttingdown && _descriptor.BeepOnShutdown)
if (_systemShuttingdown && _descriptor.BeepOnShutdown)
{
Console.Beep();
}
@ -341,11 +333,11 @@ namespace winsw
private void WaitForProcessToExit(Process processoWait)
{
SignalShutdownPending();
int effectiveProcessWaitSleepTime;
if (_descriptor.SleepTime.TotalMilliseconds > Int32.MaxValue)
{
Log.Warn("The requested sleep time " + _descriptor.SleepTime.TotalMilliseconds + "is greater that the max value " +
Log.Warn("The requested sleep time " + _descriptor.SleepTime.TotalMilliseconds + "is greater that the max value " +
Int32.MaxValue + ". The value will be truncated");
effectiveProcessWaitSleepTime = Int32.MaxValue;
}
@ -356,12 +348,12 @@ namespace winsw
try
{
// WriteEvent("WaitForProcessToExit [start]");
// WriteEvent("WaitForProcessToExit [start]");
while (!processoWait.WaitForExit(effectiveProcessWaitSleepTime))
{
SignalShutdownPending();
// WriteEvent("WaitForProcessToExit [repeat]");
// WriteEvent("WaitForProcessToExit [repeat]");
}
}
catch (InvalidOperationException)
@ -369,7 +361,7 @@ namespace winsw
// already terminated
}
// WriteEvent("WaitForProcessToExit [finished]");
// WriteEvent("WaitForProcessToExit [finished]");
}
private void SignalShutdownPending()
@ -377,7 +369,7 @@ namespace winsw
int effectiveWaitHint;
if (_descriptor.WaitHint.TotalMilliseconds > Int32.MaxValue)
{
Log.Warn("The requested WaitHint value (" + _descriptor.WaitHint.TotalMilliseconds + " ms) is greater that the max value " +
Log.Warn("The requested WaitHint value (" + _descriptor.WaitHint.TotalMilliseconds + " ms) is greater that the max value " +
Int32.MaxValue + ". The value will be truncated");
effectiveWaitHint = Int32.MaxValue;
}
@ -386,11 +378,10 @@ namespace winsw
effectiveWaitHint = (int)_descriptor.WaitHint.TotalMilliseconds;
}
IntPtr handle = ServiceHandle;
_wrapperServiceStatus.checkPoint++;
_wrapperServiceStatus.waitHint = effectiveWaitHint;
// WriteEvent("SignalShutdownPending " + wrapperServiceStatus.checkPoint + ":" + wrapperServiceStatus.waitHint);
// WriteEvent("SignalShutdownPending " + wrapperServiceStatus.checkPoint + ":" + wrapperServiceStatus.waitHint);
_wrapperServiceStatus.currentState = (int)State.SERVICE_STOP_PENDING;
Advapi32.SetServiceStatus(handle, ref _wrapperServiceStatus);
}
@ -399,16 +390,15 @@ namespace winsw
{
IntPtr handle = ServiceHandle;
_wrapperServiceStatus.checkPoint++;
// WriteEvent("SignalShutdownComplete " + wrapperServiceStatus.checkPoint + ":" + wrapperServiceStatus.waitHint);
// WriteEvent("SignalShutdownComplete " + wrapperServiceStatus.checkPoint + ":" + wrapperServiceStatus.waitHint);
_wrapperServiceStatus.currentState = (int)State.SERVICE_STOPPED;
Advapi32.SetServiceStatus(handle, ref _wrapperServiceStatus);
}
private void StartProcess(Process processToStart, string arguments, String executable, LogHandler logHandler, bool redirectStdin)
{
// Define handler of the completed process
ProcessCompletionCallback processCompletionCallback = delegate(Process proc)
ProcessCompletionCallback processCompletionCallback = proc =>
{
string msg = processToStart.Id + " - " + processToStart.StartInfo.FileName + " " + processToStart.StartInfo.Arguments;
try
@ -425,6 +415,7 @@ namespace winsw
// restart the service automatically
if (proc.ExitCode == 0)
SignalShutdownComplete();
Environment.Exit(proc.ExitCode);
}
}
@ -485,30 +476,27 @@ namespace winsw
throw new WmiException(ReturnValue.NoSuchService);
}
// ReSharper disable once InconsistentNaming
/// <summary>
/// Runs the wrapper.
/// </summary>
/// <param name="_args">Arguments. If empty, WinSW will behave in the service mode. Otherwise - CLI mode</param>
/// <param name="descriptor">Service descriptor. If null, it will be initialized within the method.
/// <param name="descriptor">Service descriptor. If null, it will be initialized within the method.
/// In such case configs will be loaded from the XML Configuration File.</param>
/// <exception cref="Exception">Any unhandled exception</exception>
public static void Run(string[] _args, ServiceDescriptor descriptor = null)
{
bool isCLIMode = _args.Length > 0;
// If descriptor is not specified, initialize the new one (and load configs from there)
var d = descriptor ?? new ServiceDescriptor();
// Configure the wrapper-internal logging.
// STDIN and STDOUT of the child process will be handled independently.
InitLoggers(d, isCLIMode);
if (isCLIMode) // CLI mode, in-service mode otherwise
{
{
Log.Debug("Starting ServiceWrapper in the CLI mode");
// Get service info for the future use
@ -519,7 +507,7 @@ namespace winsw
if (args[0] == "/redirect")
{
// Redirect output
// One might ask why we support this when the caller
// One might ask why we support this when the caller
// can redirect the output easily. The answer is for supporting UAC.
// On UAC-enabled Windows such as Vista, SCM operation requires
// elevated privileges, thus winsw.exe needs to be launched
@ -527,7 +515,7 @@ namespace winsw
// and among other things it makes it difficult for the caller
// to read stdout/stderr. Thus redirection becomes handy.
var f = new FileStream(args[1], FileMode.Create);
var w = new StreamWriter(f) {AutoFlush = true};
var w = new StreamWriter(f) { AutoFlush = true };
Console.SetOut(w);
Console.SetError(w);
@ -551,7 +539,7 @@ namespace winsw
throw new Exception("Installation failure: Service with id '" + d.Id + "' already exists");
}
string username=null, password=null;
string username = null, password = null;
bool setallowlogonasaserviceright = false;
if (args.Count > 1 && args[1] == "/p")
{
@ -578,13 +566,13 @@ namespace winsw
setallowlogonasaserviceright = d.AllowServiceAcountLogonRight;
}
}
if (setallowlogonasaserviceright)
{
LogonAsAService.AddLogonAsAServiceRight(username);
}
svc.Create (
svc.Create(
d.Id,
d.Caption,
"\"" + d.ExecutablePath + "\"",
@ -616,7 +604,7 @@ namespace winsw
using (Service sc = scm.Open(d.Id))
{
// Delayed auto start
if (isDelayedAutoStart)
if (isDelayedAutoStart)
{
sc.SetDelayedAutoStart(true);
}
@ -629,8 +617,10 @@ namespace winsw
}
}
}
return;
}
if (args[0] == "uninstall")
{
Log.Info("Uninstalling the service with id '" + d.Id + "'");
@ -639,6 +629,7 @@ namespace winsw
Log.Warn("The service with id '" + d.Id + "' does not exist. Nothing to uninstall");
return; // there's no such service, so consider it already uninstalled
}
if (s.Started)
{
// We could fail the opeartion here, but it would be an incompatible change.
@ -654,9 +645,9 @@ namespace winsw
{
if (e.ErrorCode == ReturnValue.ServiceMarkedForDeletion)
{
Log.Error("Failed to uninstall the service with id '" + d.Id + "'"
Log.Error("Failed to uninstall the service with id '" + d.Id + "'"
+ ". It has been marked for deletion.");
// TODO: change the default behavior to Error?
return; // it's already uninstalled, so consider it a success
}
@ -664,31 +655,40 @@ namespace winsw
{
Log.Fatal("Failed to uninstall the service with id '" + d.Id + "'. WMI Error code is '" + e.ErrorCode + "'");
}
throw e;
}
return;
}
if (args[0] == "start")
{
Log.Info("Starting the service with id '" + d.Id + "'");
if (s == null) ThrowNoSuchService();
if (s == null)
ThrowNoSuchService();
s.StartService();
return;
}
if (args[0] == "stop")
{
Log.Info("Stopping the service with id '" + d.Id + "'");
if (s == null) ThrowNoSuchService();
if (s == null)
ThrowNoSuchService();
s.StopService();
return;
}
if (args[0] == "restart")
{
Log.Info("Restarting the service with id '" + d.Id + "'");
if (s == null)
if (s == null)
ThrowNoSuchService();
if(s.Started)
if (s.Started)
s.StopService();
while (s.Started)
@ -700,22 +700,24 @@ namespace winsw
s.StartService();
return;
}
if (args[0] == "restart!")
{
Log.Info("Restarting the service with id '" + d.Id + "'");
// run restart from another process group. see README.md for why this is useful.
STARTUPINFO si = new STARTUPINFO();
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
STARTUPINFO si = default;
bool result = Kernel32.CreateProcess(null, d.ExecutablePath+" restart", IntPtr.Zero, IntPtr.Zero, false, 0x200/*CREATE_NEW_PROCESS_GROUP*/, IntPtr.Zero, null, ref si, out pi);
bool result = Kernel32.CreateProcess(null, d.ExecutablePath + " restart", IntPtr.Zero, IntPtr.Zero, false, 0x200/*CREATE_NEW_PROCESS_GROUP*/, IntPtr.Zero, null, ref si, out PROCESS_INFORMATION pi);
if (!result)
{
throw new Exception("Failed to invoke restart: "+Marshal.GetLastWin32Error());
throw new Exception("Failed to invoke restart: " + Marshal.GetLastWin32Error());
}
return;
}
if (args[0] == "status")
{
Log.Debug("User requested the status of the process with id '" + d.Id + "'");
@ -727,6 +729,7 @@ namespace winsw
Console.WriteLine("Stopped");
return;
}
if (args[0] == "test")
{
WrapperService wsvc = new WrapperService(d);
@ -735,6 +738,7 @@ namespace winsw
wsvc.OnStop();
return;
}
if (args[0] == "testwait")
{
WrapperService wsvc = new WrapperService(d);
@ -744,27 +748,29 @@ namespace winsw
wsvc.OnStop();
return;
}
if (args[0] == "help" || args[0] == "--help" || args[0] == "-h"
if (args[0] == "help" || args[0] == "--help" || args[0] == "-h"
|| args[0] == "-?" || args[0] == "/?")
{
printHelp();
return;
}
if (args[0] == "version")
{
printVersion();
return;
}
Console.WriteLine("Unknown command: " + args[0]);
printAvailableCommandsInfo();
throw new Exception("Unknown command: " + args[0]);
}
else
{
Log.Info("Starting ServiceWrapper in the service mode");
}
Run(new WrapperService(d));
}
@ -774,7 +780,7 @@ namespace winsw
Level logLevel = Level.Debug;
// TODO: Debug should not be printed to console by default. Otherwise commands like 'status' will be pollutted
// This is a workaround till there is a better command line parsing, which will allow determining
Level consoleLogLevel = Level.Info;
Level consoleLogLevel = Level.Info;
Level eventLogLevel = Level.Warn;
// Legacy format from winsw-1.x: (DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " - " + message);
@ -812,11 +818,11 @@ namespace winsw
}
// System log
var systemEventLogger = new ServiceEventLogAppender
var systemEventLogger = new ServiceEventLogAppender
{
Name = "System event log",
Threshold = eventLogLevel,
provider = eventLogProvider
provider = eventLogProvider
};
systemEventLogger.ActivateOptions();
appenders.Add(systemEventLogger);
@ -851,21 +857,21 @@ namespace winsw
private static void printHelp()
{
Console.WriteLine("A wrapper binary that can be used to host executables as Windows services");
Console.WriteLine("");
Console.WriteLine();
Console.WriteLine("Usage: winsw [/redirect file] <command> [<args>]");
Console.WriteLine(" Missing arguments trigger the service mode");
Console.WriteLine("");
Console.WriteLine();
printAvailableCommandsInfo();
Console.WriteLine("");
Console.WriteLine();
Console.WriteLine("Extra options:");
Console.WriteLine("- '/redirect' - redirect the wrapper's STDOUT and STDERR to the specified file");
Console.WriteLine("");
Console.WriteLine();
printVersion();
Console.WriteLine("More info: https://github.com/kohsuke/winsw");
Console.WriteLine("Bug tracker: https://github.com/kohsuke/winsw/issues");
}
//TODO: Rework to enum in winsw-2.0
// TODO: Rework to enum in winsw-2.0
private static void printAvailableCommandsInfo()
{
Console.WriteLine("Available commands:");

View File

@ -16,6 +16,7 @@ namespace winsw
[DllImport(KERNEL32)]
private static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add);
// Delegate type to be used as the Handler Routine for SCCH
private delegate Boolean ConsoleCtrlDelegate(CtrlTypes CtrlType);
@ -43,15 +44,15 @@ namespace winsw
{
if (AttachConsole((uint)process.Id))
{
//Disable Ctrl-C handling for our program
// Disable Ctrl-C handling for our program
SetConsoleCtrlHandler(null, true);
GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0);
process.WaitForExit((int)shutdownTimeout.TotalMilliseconds);
return process.HasExited;
return process.HasExited;
}
return false;
}
}

View File

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
using System.Xml;
using WMI;
@ -14,11 +13,11 @@ namespace winsw.Configuration
/// </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 bool HideWindow { get { return false; } }
public string Id => null;
public string Caption => null;
public string Description => null;
public string Executable => null;
public bool HideWindow => false;
public string ExecutablePath
{
@ -32,47 +31,47 @@ namespace winsw.Configuration
}
// 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); } }
public bool AllowServiceAcountLogonRight => false;
public string ServiceAccountPassword => null;
public string ServiceAccountUser => "NULL\\NULL";
public List<Native.SC_ACTION> FailureActions => new List<Native.SC_ACTION>();
public TimeSpan ResetFailureAfter => 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; } }
public string Arguments => string.Empty;
public string Startarguments => null;
public string StopExecutable => null;
public string Stoparguments => null;
public string WorkingDirectory => Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
public ProcessPriorityClass Priority => ProcessPriorityClass.Normal;
public TimeSpan StopTimeout => TimeSpan.FromSeconds(15);
public bool StopParentProcessFirst => false;
// Service management
public StartMode StartMode { get { return StartMode.Automatic; } }
public bool DelayedAutoStart { get { return false; } }
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; } }
public StartMode StartMode => StartMode.Automatic;
public bool DelayedAutoStart => false;
public string[] ServiceDependencies => new string[0];
public TimeSpan WaitHint => TimeSpan.FromSeconds(15);
public TimeSpan SleepTime => TimeSpan.FromSeconds(1);
public bool Interactive => false;
// Logging
public string LogDirectory { get { return Path.GetDirectoryName(ExecutablePath); } }
public string LogMode { get { return "append"; } }
public string LogDirectory => Path.GetDirectoryName(ExecutablePath);
public string LogMode => "append";
public bool OutFileDisabled { get { return false; } }
public bool ErrFileDisabled { get { return false; } }
public string OutFilePattern { get { return ".out.log"; } }
public string ErrFilePattern { get { return ".err.log"; } }
public bool OutFileDisabled => false;
public bool ErrFileDisabled => false;
public string OutFilePattern => ".out.log";
public string ErrFilePattern => ".err.log";
// Environment
public List<Download> Downloads { get { return new List<Download>(); } }
public Dictionary<string, string> EnvironmentVariables { get { return new Dictionary<string, string>(); } }
public List<Download> Downloads => new List<Download>();
public Dictionary<string, string> EnvironmentVariables => new Dictionary<string, string>();
// Misc
public bool BeepOnShutdown { get { return false; } }
public bool BeepOnShutdown => false;
// Extensions
public XmlNode ExtensionsConfiguration { get {return null; } }
public XmlNode ExtensionsConfiguration => null;
}
}

View File

@ -7,7 +7,7 @@ namespace winsw.Configuration
{
public interface IWinSWConfiguration
{
//TODO: Document the parameters && refactor
// TODO: Document the parameters && refactor
string Id { get; }
string Caption { get; }
@ -20,7 +20,7 @@ namespace winsw.Configuration
bool AllowServiceAcountLogonRight { get; }
string ServiceAccountPassword { get; }
string ServiceAccountUser { get; }
List<winsw.Native.SC_ACTION> FailureActions { get; }
List<Native.SC_ACTION> FailureActions { get; }
TimeSpan ResetFailureAfter { get; }
// Executable management
@ -39,16 +39,16 @@ namespace winsw.Configuration
TimeSpan WaitHint { get; }
TimeSpan SleepTime { get; }
bool Interactive { get; }
// Logging
string LogDirectory { get; }
//TODO: replace by enum
// TODO: replace by enum
string LogMode { get; }
// Environment
List<Download> Downloads { get; }
Dictionary<string, string> EnvironmentVariables { get; }
// Misc
bool BeepOnShutdown { get; }

View File

@ -13,7 +13,12 @@ namespace winsw
/// </summary>
public class Download
{
public enum AuthType { none = 0, sspi, basic }
public enum AuthType
{
none = 0,
sspi,
basic
}
public readonly string From;
public readonly string To;
@ -23,10 +28,16 @@ namespace winsw
public readonly bool UnsecureAuth;
public readonly bool FailOnError;
public string ShortId { get { return String.Format("(download from {0})", From); } }
public string ShortId => $"(download from {From})";
public Download(string from, string to, bool failOnError = false, AuthType auth = AuthType.none,
string username = null, string password = null, bool unsecureAuth = false)
public Download(
string from,
string to,
bool failOnError = false,
AuthType auth = AuthType.none,
string username = null,
string password = null,
bool unsecureAuth = false)
{
From = from;
To = to;
@ -48,19 +59,19 @@ namespace winsw
To = XmlHelper.SingleAttribute<String>(n, "to");
// All arguments below are optional
FailOnError = XmlHelper.SingleAttribute<bool>(n, "failOnError", false);
FailOnError = XmlHelper.SingleAttribute(n, "failOnError", false);
Auth = XmlHelper.EnumAttribute<AuthType>(n, "auth", AuthType.none);
Auth = XmlHelper.EnumAttribute(n, "auth", AuthType.none);
Username = XmlHelper.SingleAttribute<String>(n, "user", null);
Password = XmlHelper.SingleAttribute<String>(n, "password", null);
UnsecureAuth = XmlHelper.SingleAttribute<bool>(n, "unsecureAuth", false);
UnsecureAuth = XmlHelper.SingleAttribute(n, "unsecureAuth", false);
if (Auth == AuthType.basic)
{
// Allow it only for HTTPS or for UnsecureAuth
// Allow it only for HTTPS or for UnsecureAuth
if (!From.StartsWith("https:") && !UnsecureAuth)
{
throw new InvalidDataException("Warning: you're sending your credentials in clear text to the server " + ShortId +
throw new InvalidDataException("Warning: you're sending your credentials in clear text to the server " + ShortId +
"If you really want this you must enable 'unsecureAuth' in the configuration");
}
@ -69,6 +80,7 @@ namespace winsw
{
throw new InvalidDataException("Basic Auth is enabled, but username is not specified " + ShortId);
}
if (Password == null)
{
throw new InvalidDataException("Basic Auth is enabled, but password is not specified " + ShortId);
@ -87,7 +99,7 @@ namespace winsw
/// <summary>
/// Downloads the requested file and puts it to the specified target.
/// </summary>
/// <exception cref="System.Net.WebException">
/// <exception cref="WebException">
/// Download failure. FailOnError flag should be processed outside.
/// </exception>
public void Perform()
@ -120,6 +132,7 @@ namespace winsw
// only after we successfully downloaded a file, overwrite the existing one
if (File.Exists(To))
File.Delete(To);
File.Move(To + ".tmp", To);
}
@ -129,9 +142,12 @@ namespace winsw
while (true)
{
int len = i.Read(buf, 0, buf.Length);
if (len <= 0) break;
if (len <= 0)
break;
o.Write(buf, 0, len);
}
i.Close();
o.Close();
}

View File

@ -7,8 +7,8 @@ using System.Threading;
namespace DynamicProxy
{
/// <summary>
/// Interface that a user defined proxy handler needs to implement. This interface
/// defines one method that gets invoked by the generated proxy.
/// Interface that a user defined proxy handler needs to implement. This interface
/// defines one method that gets invoked by the generated proxy.
/// </summary>
public interface IProxyInvocationHandler
{
@ -96,7 +96,7 @@ namespace DynamicProxy
private const string MODULE_NAME = "ProxyModule";
private const string HANDLER_NAME = "handler";
// Initialize the value type mapper. This is needed for methods with intrinsic
// Initialize the value type mapper. This is needed for methods with intrinsic
// return types, used in the Emit process.
static ProxyFactory()
{
@ -182,7 +182,7 @@ namespace DynamicProxy
// create a new assembly for this proxy, one that isn't presisted on the file system
AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly(
assemblyName, AssemblyBuilderAccess.Run);
// assemblyName, AssemblyBuilderAccess.RunAndSave,"."); // to save it to the disk
// assemblyName, AssemblyBuilderAccess.RunAndSave,"."); // to save it to the disk
// create a new module for this proxy
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(MODULE_NAME);
@ -200,9 +200,8 @@ namespace DynamicProxy
FieldBuilder handlerField = typeBuilder.DefineField(
HANDLER_NAME, handlerType, FieldAttributes.Private);
// build a constructor that takes the delegate object as the only argument
//ConstructorInfo defaultObjConstructor = objType.GetConstructor( new Type[0] );
// ConstructorInfo defaultObjConstructor = objType.GetConstructor( new Type[0] );
ConstructorInfo superConstructor = objType.GetConstructor(new Type[0]);
ConstructorBuilder delegateConstructor = typeBuilder.DefineConstructor(
MethodAttributes.Public, CallingConventions.Standard, new Type[] { handlerType });
@ -224,8 +223,8 @@ namespace DynamicProxy
constructorIL.Emit(OpCodes.Ret);
#endregion
// for every method that the interfaces define, build a corresponding
// method in the dynamic type that calls the handlers invoke method.
// for every method that the interfaces define, build a corresponding
// method in the dynamic type that calls the handlers invoke method.
foreach (Type interfaceType in interfaces)
{
GenerateMethod(interfaceType, handlerField, typeBuilder);
@ -242,106 +241,122 @@ namespace DynamicProxy
private static readonly MethodInfo INVOKE_METHOD = typeof(IProxyInvocationHandler).GetMethod("Invoke");
private static readonly MethodInfo GET_METHODINFO_METHOD = typeof(MetaDataFactory).GetMethod("GetMethod", new Type[] { typeof(string), typeof(int) });
private void GenerateMethod( Type interfaceType, FieldBuilder handlerField, TypeBuilder typeBuilder ) {
MetaDataFactory.Add( interfaceType );
private void GenerateMethod(Type interfaceType, FieldBuilder handlerField, TypeBuilder typeBuilder)
{
MetaDataFactory.Add(interfaceType);
MethodInfo[] interfaceMethods = interfaceType.GetMethods();
PropertyInfo[] props = interfaceType.GetProperties();
for ( int i = 0; i < interfaceMethods.Length; i++ ) {
for (int i = 0; i < interfaceMethods.Length; i++)
{
MethodInfo methodInfo = interfaceMethods[i];
// Get the method parameters since we need to create an array
// of parameter types
ParameterInfo[] methodParams = methodInfo.GetParameters();
int numOfParams = methodParams.Length;
Type[] methodParameters = new Type[ numOfParams ];
Type[] methodParameters = new Type[numOfParams];
// convert the ParameterInfo objects into Type
for ( int j = 0; j < numOfParams; j++ ) {
for (int j = 0; j < numOfParams; j++)
{
methodParameters[j] = methodParams[j].ParameterType;
}
// create a new builder for the method in the interface
MethodBuilder methodBuilder = typeBuilder.DefineMethod(
methodInfo.Name,
/*MethodAttributes.Public | MethodAttributes.Virtual | */ methodInfo.Attributes&~MethodAttributes.Abstract,
methodInfo.Name,
/*MethodAttributes.Public | MethodAttributes.Virtual | */ methodInfo.Attributes & ~MethodAttributes.Abstract,
CallingConventions.Standard,
methodInfo.ReturnType, methodParameters );
methodInfo.ReturnType, methodParameters);
#region( "Handler Method IL Code" )
ILGenerator methodIL = methodBuilder.GetILGenerator();
// load "this"
methodIL.Emit( OpCodes.Ldarg_0 );
methodIL.Emit(OpCodes.Ldarg_0);
// load the handler
methodIL.Emit( OpCodes.Ldfld, handlerField );
methodIL.Emit(OpCodes.Ldfld, handlerField);
// load "this" since its needed for the call to invoke
methodIL.Emit( OpCodes.Ldarg_0 );
methodIL.Emit(OpCodes.Ldarg_0);
// load the name of the interface, used to get the MethodInfo object
// from MetaDataFactory
methodIL.Emit( OpCodes.Ldstr, interfaceType.FullName );
// load the index, used to get the MethodInfo object
// from MetaDataFactory
methodIL.Emit( OpCodes.Ldc_I4, i );
methodIL.Emit(OpCodes.Ldstr, interfaceType.FullName);
// load the index, used to get the MethodInfo object
// from MetaDataFactory
methodIL.Emit(OpCodes.Ldc_I4, i);
// invoke GetMethod in MetaDataFactory
methodIL.Emit( OpCodes.Call, GET_METHODINFO_METHOD);
methodIL.Emit(OpCodes.Call, GET_METHODINFO_METHOD);
// load the number of parameters onto the stack
methodIL.Emit( OpCodes.Ldc_I4, numOfParams );
methodIL.Emit(OpCodes.Ldc_I4, numOfParams);
// create a new array, using the size that was just pused on the stack
methodIL.Emit( OpCodes.Newarr, typeof(object) );
methodIL.Emit(OpCodes.Newarr, typeof(object));
// if we have any parameters, then iterate through and set the values
// of each element to the corresponding arguments
for ( int j = 0; j < numOfParams; j++ ) {
methodIL.Emit( OpCodes.Dup ); // this copies the array
methodIL.Emit( OpCodes.Ldc_I4, j );
methodIL.Emit( OpCodes.Ldarg, j + 1 );
if ( methodParameters[j].IsValueType ) {
methodIL.Emit( OpCodes.Box, methodParameters[j] );
for (int j = 0; j < numOfParams; j++)
{
methodIL.Emit(OpCodes.Dup); // this copies the array
methodIL.Emit(OpCodes.Ldc_I4, j);
methodIL.Emit(OpCodes.Ldarg, j + 1);
if (methodParameters[j].IsValueType)
{
methodIL.Emit(OpCodes.Box, methodParameters[j]);
}
methodIL.Emit( OpCodes.Stelem_Ref );
methodIL.Emit(OpCodes.Stelem_Ref);
}
// call the Invoke method
methodIL.Emit( OpCodes.Callvirt, INVOKE_METHOD );
if ( methodInfo.ReturnType != typeof(void) ) {
methodIL.Emit(OpCodes.Callvirt, INVOKE_METHOD);
if (methodInfo.ReturnType != typeof(void))
{
// if the return type if a value type, then unbox the return value
// so that we don't get junk.
if ( methodInfo.ReturnType.IsValueType ) {
methodIL.Emit( OpCodes.Unbox, methodInfo.ReturnType );
if ( methodInfo.ReturnType.IsEnum ) {
methodIL.Emit( OpCodes.Ldind_I4 );
} else if ( !methodInfo.ReturnType.IsPrimitive ) {
methodIL.Emit( OpCodes.Ldobj, methodInfo.ReturnType );
} else {
methodIL.Emit( (OpCode) OpCodeTypeMapper[ methodInfo.ReturnType ] );
if (methodInfo.ReturnType.IsValueType)
{
methodIL.Emit(OpCodes.Unbox, methodInfo.ReturnType);
if (methodInfo.ReturnType.IsEnum)
{
methodIL.Emit(OpCodes.Ldind_I4);
}
}
} else {
// pop the return value that Invoke returned from the stack since
// the method's return type is void.
methodIL.Emit( OpCodes.Pop );
else if (!methodInfo.ReturnType.IsPrimitive)
{
methodIL.Emit(OpCodes.Ldobj, methodInfo.ReturnType);
}
else
{
methodIL.Emit((OpCode)OpCodeTypeMapper[methodInfo.ReturnType]);
}
}
}
else
{
// pop the return value that Invoke returned from the stack since
// the method's return type is void.
methodIL.Emit(OpCodes.Pop);
}
// Return
methodIL.Emit( OpCodes.Ret );
methodIL.Emit(OpCodes.Ret);
#endregion
}
//for (int i = 0; i < props.Length; i++)
//{
// PropertyInfo p = props[i];
// for (int i = 0; i < props.Length; i++)
// {
// PropertyInfo p = props[i];
// PropertyBuilder pb = typeBuilder.DefineProperty(p.Name, p.Attributes, p.PropertyType, new Type[] { p.PropertyType });
// pb.SetGetMethod((MethodBuilder)methodTable[p.GetGetMethod()]);
// pb.SetSetMethod((MethodBuilder)methodTable[p.GetSetMethod()]);
//}
// PropertyBuilder pb = typeBuilder.DefineProperty(p.Name, p.Attributes, p.PropertyType, new Type[] { p.PropertyType });
// pb.SetGetMethod((MethodBuilder)methodTable[p.GetGetMethod()]);
// pb.SetSetMethod((MethodBuilder)methodTable[p.GetSetMethod()]);
// }
// Iterate through the parent interfaces and recursively call this method
foreach ( Type parentType in interfaceType.GetInterfaces() ) {
GenerateMethod( parentType, handlerField, typeBuilder );
foreach (Type parentType in interfaceType.GetInterfaces())
{
GenerateMethod(parentType, handlerField, typeBuilder);
}
}
}

View File

@ -1,12 +1,12 @@
using System;
using System.Xml;
using winsw.Util;
namespace winsw.Extensions
{
public abstract class AbstractWinSWExtension : IWinSWExtension
public abstract class AbstractWinSWExtension : IWinSWExtension
{
public abstract String DisplayName { get; }
public WinSWExtensionDescriptor Descriptor { get; set; }
public virtual void Configure(ServiceDescriptor descriptor, XmlNode node)

View File

@ -18,12 +18,6 @@ namespace winsw.Extensions
ExtensionId = extensionName;
}
public override string Message
{
get
{
return ExtensionId + ": " + base.Message;
}
}
public override string Message => ExtensionId + ": " + base.Message;
}
}

View File

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace winsw.Extensions
namespace winsw.Extensions
{
/// <summary>
/// This attribute is used to identify extension points within the code

View File

@ -1,6 +1,5 @@
using System;
using System.Xml;
using winsw.Util;
namespace winsw.Extensions
{
@ -8,7 +7,7 @@ namespace winsw.Extensions
/// Interface for Win Service Wrapper Extension
/// </summary>
/// <remarks>
/// All implementations should provide the default empty constructor.
/// All implementations should provide the default empty constructor.
/// The initialization will be performed by Init methods.
/// Binary comparibility of the class is not guaranteed in WinSW 2.
/// </remarks>

View File

@ -1,17 +1,16 @@
using System;
using System.Collections.Generic;
using System.Xml;
using System.Reflection;
using System.Diagnostics;
using winsw.Util;
using System.Xml;
using log4net;
namespace winsw.Extensions
{
public class WinSWExtensionManager
{
public Dictionary<string, IWinSWExtension> Extensions { private set; get; }
public ServiceDescriptor ServiceDescriptor { private set; get; }
public Dictionary<string, IWinSWExtension> Extensions { get; private set; }
public ServiceDescriptor ServiceDescriptor { get; private set; }
private static readonly ILog Log = LogManager.GetLogger(typeof(WinSWExtensionManager));
@ -27,7 +26,7 @@ namespace winsw.Extensions
/// If any extensions fails, WinSW startup should be interrupted.
/// </summary>
/// <exception cref="Exception">Start failure</exception>
public void FireOnWrapperStarted()
public void FireOnWrapperStarted()
{
foreach (var ext in Extensions)
{
@ -50,7 +49,7 @@ namespace winsw.Extensions
public void FireBeforeWrapperStopped()
{
foreach (var ext in Extensions)
{
{
try
{
ext.Value.BeforeWrapperStopped();
@ -100,10 +99,9 @@ namespace winsw.Extensions
}
}
//TODO: Implement loading of external extensions. Current version supports internal hack
// TODO: Implement loading of external extensions. Current version supports internal hack
#region Extension load management
/// Loads extensions according to the configuration file.
/// </summary>
/// <param name="logger">Logger</param>
@ -111,7 +109,7 @@ namespace winsw.Extensions
public void LoadExtensions()
{
var extensionIds = ServiceDescriptor.ExtensionIds;
foreach (String extensionId in extensionIds)
foreach (String extensionId in extensionIds)
{
LoadExtension(extensionId);
}
@ -131,7 +129,7 @@ namespace winsw.Extensions
}
var extensionsConfig = ServiceDescriptor.ExtensionsConfiguration;
XmlElement configNode =(extensionsConfig != null) ? extensionsConfig.SelectSingleNode("extension[@id='"+id+"'][1]") as XmlElement : null;
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");
@ -151,6 +149,7 @@ namespace winsw.Extensions
Log.Fatal("Failed to configure the extension " + id, ex);
throw ex;
}
Extensions.Add(id, extension);
Log.Info("Extension loaded: " + id);
}
@ -158,7 +157,6 @@ namespace winsw.Extensions
{
Log.Warn("Extension is disabled: " + id);
}
}
private IWinSWExtension CreateExtensionInstance(string id, string className)
@ -166,29 +164,30 @@ namespace winsw.Extensions
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");
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);
throw new ExtensionException(id, "Cannot load the class by name: " + className, ex);
}
var extension = created as IWinSWExtension;
if (extension == null)
if (!(created is IWinSWExtension extension))
{
throw new ExtensionException(id, "The loaded class is not a WinSW extension: " + className + ". Type is " + created.GetType());
}
return extension;
}
#endregion
#endregion
}
}

View File

@ -2,7 +2,6 @@ using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Timers;
using ICSharpCode.SharpZipLib.Zip;
namespace winsw
@ -11,6 +10,7 @@ namespace winsw
public interface EventLogger
{
void LogEvent(string message);
void LogEvent(string message, EventLogEntryType type);
}
@ -25,7 +25,7 @@ namespace winsw
/// <summary>
/// Error and information about logging should be reported here.
/// </summary>
public EventLogger EventLogger { set; get; }
public EventLogger EventLogger { get; set; }
/// <summary>
/// Convenience method to copy stuff from StreamReader to StreamWriter
@ -36,10 +36,13 @@ namespace winsw
while (true)
{
int sz = i.Read(buf, 0, buf.Length);
if (sz == 0) break;
if (sz == 0)
break;
o.Write(buf, 0, sz);
o.Flush();
}
i.Close();
o.Close();
}
@ -66,11 +69,11 @@ namespace winsw
/// </summary>
public abstract class AbstractFileLogAppender : LogHandler
{
protected string BaseLogFileName { private set; get; }
protected bool OutFileDisabled { private set; get; }
protected bool ErrFileDisabled { private set; get; }
protected string OutFilePattern { private set; get; }
protected string ErrFilePattern { private set; get; }
protected string BaseLogFileName { get; private set; }
protected bool OutFileDisabled { get; private set; }
protected bool ErrFileDisabled { get; private set; }
protected string OutFilePattern { get; private set; }
protected string ErrFilePattern { get; private set; }
protected AbstractFileLogAppender(string logDirectory, string baseName, bool outFileDisabled, bool errFileDisabled, string outFilePattern, string errFilePattern)
{
@ -84,9 +87,9 @@ namespace winsw
public abstract class SimpleLogAppender : AbstractFileLogAppender
{
public FileMode FileMode { private set; get; }
public string OutputLogFileName { private set; get; }
public string ErrorLogFileName { private set; get; }
public FileMode FileMode { get; private set; }
public string OutputLogFileName { get; private set; }
public string ErrorLogFileName { get; private set; }
protected SimpleLogAppender(string logDirectory, string baseName, FileMode fileMode, bool outFileDisabled, bool errFileDisabled, string outFilePattern, string errFilePattern)
: base(logDirectory, baseName, outFileDisabled, errFileDisabled, outFilePattern, errFilePattern)
@ -98,8 +101,11 @@ namespace winsw
public override void log(Stream outputStream, Stream errorStream)
{
if (!OutFileDisabled) new Thread(delegate() { CopyStream(outputStream, new FileStream(OutputLogFileName, FileMode)); }).Start();
if (!ErrFileDisabled) new Thread(delegate() { CopyStream(errorStream, new FileStream(ErrorLogFileName, FileMode)); }).Start();
if (!OutFileDisabled)
new Thread(() => CopyStream(outputStream, new FileStream(OutputLogFileName, FileMode))).Start();
if (!ErrFileDisabled)
new Thread(() => CopyStream(errorStream, new FileStream(ErrorLogFileName, FileMode))).Start();
}
}
@ -118,7 +124,7 @@ namespace winsw
{
}
}
/// <summary>
/// LogHandler that throws away output
/// </summary>
@ -126,8 +132,8 @@ namespace winsw
{
public override void log(Stream outputStream, Stream errorStream)
{
new Thread(delegate() { CopyStream(outputStream, Stream.Null); }).Start();
new Thread(delegate() { CopyStream(errorStream, Stream.Null); }).Start();
new Thread(() => CopyStream(outputStream, Stream.Null)).Start();
new Thread(() => CopyStream(errorStream, Stream.Null)).Start();
}
}
@ -145,8 +151,11 @@ namespace winsw
public override void log(Stream outputStream, Stream errorStream)
{
if (!OutFileDisabled) new Thread(delegate() { CopyStreamWithDateRotation(outputStream, OutFilePattern); }).Start();
if (!ErrFileDisabled) new Thread(delegate() { CopyStreamWithDateRotation(errorStream, ErrFilePattern); }).Start();
if (!OutFileDisabled)
new Thread(() => CopyStreamWithDateRotation(outputStream, OutFilePattern)).Start();
if (!ErrFileDisabled)
new Thread(() => CopyStreamWithDateRotation(errorStream, ErrFilePattern)).Start();
}
/// <summary>
@ -162,16 +171,19 @@ namespace winsw
while (true)
{
int len = data.Read(buf, 0, buf.Length);
if (len == 0) break; // EOF
if (len == 0)
break; // EOF
if (periodicRollingCalendar.shouldRoll)
{// rotate at the line boundary
{
// rotate at the line boundary
int offset = 0;
bool rolled = false;
for (int i = 0; i < len; i++)
{
if (buf[i] == 0x0A)
{// at the line boundary.
{
// at the line boundary.
// time to rotate.
w.Write(buf, offset, i + 1);
w.Close();
@ -189,24 +201,25 @@ namespace winsw
}
if (!rolled)
{// we didn't roll - most likely as we didnt find a line boundary, so we should log what we read and roll anyway.
{
// we didn't roll - most likely as we didnt find a line boundary, so we should log what we read and roll anyway.
w.Write(buf, 0, len);
w.Close();
w = new FileStream(BaseLogFileName + "_" + periodicRollingCalendar.format + ext, FileMode.Create);
}
}
else
{// typical case. write the whole thing into the current file
{
// typical case. write the whole thing into the current file
w.Write(buf, 0, len);
}
w.Flush();
}
data.Close();
w.Close();
}
}
public class SizeBasedRollingLogAppender : AbstractFileLogAppender
@ -220,9 +233,9 @@ namespace winsw
// ReSharper disable once InconsistentNaming
public static int DEFAULT_FILES_TO_KEEP = 8;
public int SizeTheshold { private set; get; }
public int SizeTheshold { get; private set; }
public int FilesToKeep { private set; get; }
public int FilesToKeep { get; private set; }
public SizeBasedRollingLogAppender(string logDirectory, string baseName, bool outFileDisabled, bool errFileDisabled, string outFilePattern, string errFilePattern, int sizeThreshold, int filesToKeep)
: base(logDirectory, baseName, outFileDisabled, errFileDisabled, outFilePattern, errFilePattern)
@ -236,8 +249,11 @@ namespace winsw
public override void log(Stream outputStream, Stream errorStream)
{
if (!OutFileDisabled) new Thread(delegate() { CopyStreamWithRotation(outputStream, OutFilePattern); }).Start();
if (!ErrFileDisabled) new Thread(delegate() { CopyStreamWithRotation(errorStream, ErrFilePattern); }).Start();
if (!OutFileDisabled)
new Thread(() => CopyStreamWithRotation(outputStream, OutFilePattern)).Start();
if (!ErrFileDisabled)
new Thread(() => CopyStreamWithRotation(errorStream, ErrFilePattern)).Start();
}
/// <summary>
@ -252,9 +268,12 @@ namespace winsw
while (true)
{
int len = data.Read(buf, 0, buf.Length);
if (len == 0) break; // EOF
if (len == 0)
break; // EOF
if (sz + len < SizeTheshold)
{// typical case. write the whole thing into the current file
{
// typical case. write the whole thing into the current file
w.Write(buf, 0, len);
sz += len;
}
@ -264,8 +283,11 @@ namespace winsw
int s = 0;
for (int i = 0; i < len; i++)
{
if (buf[i] != 0x0A) continue;
if (sz + i < SizeTheshold) continue;
if (buf[i] != 0x0A)
continue;
if (sz + i < SizeTheshold)
continue;
// at the line boundary and exceeded the rotation unit.
// time to rotate.
@ -281,9 +303,11 @@ namespace winsw
string src = BaseLogFileName + "." + (j - 2) + ext;
if (File.Exists(dst))
File.Delete(dst);
if (File.Exists(src))
File.Move(src, dst);
}
File.Move(BaseLogFileName + ext, BaseLogFileName + ".0" + ext);
}
catch (IOException e)
@ -300,6 +324,7 @@ namespace winsw
w.Flush();
}
data.Close();
w.Close();
}
@ -317,8 +342,12 @@ namespace winsw
public override void log(Stream outputStream, Stream errorStream)
{
if (!OutFileDisabled) CopyFile(OutputLogFileName, OutputLogFileName + ".old");
if (!ErrFileDisabled) CopyFile(ErrorLogFileName, ErrorLogFileName + ".old");
if (!OutFileDisabled)
CopyFile(OutputLogFileName, OutputLogFileName + ".old");
if (!ErrFileDisabled)
CopyFile(ErrorLogFileName, ErrorLogFileName + ".old");
base.log(outputStream, errorStream);
}
}
@ -326,11 +355,11 @@ namespace winsw
public class RollingSizeTimeLogAppender : AbstractFileLogAppender
{
public static int BYTES_PER_KB = 1024;
public int SizeTheshold { private set; get; }
public string FilePattern { private set; get; }
public TimeSpan? AutoRollAtTime { private set; get; }
public int? ZipOlderThanNumDays { private set; get; }
public string ZipDateFormat { private set; get; }
public int SizeTheshold { get; private set; }
public string FilePattern { get; private set; }
public TimeSpan? AutoRollAtTime { get; private set; }
public int? ZipOlderThanNumDays { get; private set; }
public string ZipDateFormat { get; private set; }
public RollingSizeTimeLogAppender(string logDirectory, string baseName, bool outFileDisabled, bool errFileDisabled, string outFilePattern, string errFilePattern, int sizeThreshold, string filePattern, TimeSpan? autoRollAtTime, int? zipolderthannumdays, string zipdateformat)
: base(logDirectory, baseName, outFileDisabled, errFileDisabled, outFilePattern, errFilePattern)
@ -344,8 +373,11 @@ namespace winsw
public override void log(Stream outputStream, Stream errorStream)
{
if (!OutFileDisabled) new Thread(delegate () { CopyStreamWithRotation(outputStream, OutFilePattern); }).Start();
if (!ErrFileDisabled) new Thread(delegate () { CopyStreamWithRotation(errorStream, ErrFilePattern); }).Start();
if (!OutFileDisabled)
new Thread(() => CopyStreamWithRotation(outputStream, OutFilePattern)).Start();
if (!ErrFileDisabled)
new Thread(() => CopyStreamWithRotation(errorStream, ErrFilePattern)).Start();
}
private void CopyStreamWithRotation(Stream data, string ext)
@ -379,7 +411,7 @@ namespace winsw
var now = DateTime.Now.AddDays(-1);
var nextFileNumber = GetNextFileNumber(ext, baseDirectory, baseFileName, now);
var nextFileName = Path.Combine(baseDirectory, string.Format("{0}.{1}.#{2:D4}{3}", baseFileName, now.ToString(FilePattern), nextFileNumber, ext));
var nextFileName = Path.Combine(baseDirectory, string.Format("{0}.{1}.#{2:D4}{3}", baseFileName, now.ToString(FilePattern), nextFileNumber, ext));
File.Move(logFile, nextFileName);
w = new FileStream(logFile, FileMode.Create);
@ -402,10 +434,13 @@ namespace winsw
};
timer.Start();
}
while (true)
{
var len = data.Read(buf, 0, buf.Length);
if (len == 0) break; // EOF
if (len == 0)
break; // EOF
lock (fileLock)
{
if (sz + len < SizeTheshold)
@ -422,8 +457,11 @@ namespace winsw
int s = 0;
for (int i = 0; i < len; i++)
{
if (buf[i] != 0x0A) continue;
if (sz + i < SizeTheshold) continue;
if (buf[i] != 0x0A)
continue;
if (sz + i < SizeTheshold)
continue;
// at the line boundary and exceeded the rotation unit.
// time to rotate.
@ -450,16 +488,19 @@ namespace winsw
EventLogger.LogEvent(string.Format("Failed to roll size time log: {0}", e.Message));
}
}
w.Flush();
}
}
data.Close();
w.Close();
}
private void ZipFiles(string path, string fileExt, string baseZipfilename)
{
if (ZipOlderThanNumDays == null || !(ZipOlderThanNumDays > 0)) return;
if (ZipOlderThanNumDays == null || !(ZipOlderThanNumDays > 0))
return;
try
{
@ -467,7 +508,8 @@ namespace winsw
foreach (var file in files)
{
var fi = new FileInfo(file);
if (fi.LastWriteTimeUtc >= DateTime.UtcNow.AddDays(-ZipOlderThanNumDays.Value)) continue;
if (fi.LastWriteTimeUtc >= DateTime.UtcNow.AddDays(-ZipOlderThanNumDays.Value))
continue;
// lets archive this bugger
ZipTheFile(file, path, fi.LastWriteTimeUtc.ToString(ZipDateFormat), baseZipfilename);
@ -487,7 +529,6 @@ namespace winsw
bool commited = false;
try
{
if (File.Exists(zipfilename))
{
zipFile = new ZipFile(zipfilename);
@ -539,11 +580,11 @@ namespace winsw
{
var nowTime = DateTime.Now;
var scheduledTime = new DateTime(nowTime.Year, nowTime.Month, nowTime.Day, AutoRollAtTime.Value.Hours,
AutoRollAtTime.Value.Minutes, AutoRollAtTime.Value.Seconds, 0); //Specify your time HH,MM,SS
AutoRollAtTime.Value.Minutes, AutoRollAtTime.Value.Seconds, 0); // Specify your time HH,MM,SS
if (nowTime > scheduledTime)
scheduledTime = scheduledTime.AddDays(1);
double tickTime = (double) (scheduledTime - DateTime.Now).TotalMilliseconds;
double tickTime = (scheduledTime - DateTime.Now).TotalMilliseconds;
return tickTime;
}
@ -564,24 +605,29 @@ namespace winsw
var filenameOnly = Path.GetFileNameWithoutExtension(f);
var hashIndex = filenameOnly.IndexOf('#');
var lastNumberAsString = filenameOnly.Substring(hashIndex + 1, 4);
//var lastNumberAsString = filenameOnly.Substring(filenameOnly.Length - 4, 4);
int lastNumber = 0;
if (int.TryParse(lastNumberAsString, out lastNumber))
// var lastNumberAsString = filenameOnly.Substring(filenameOnly.Length - 4, 4);
if (int.TryParse(lastNumberAsString, out int lastNumber))
{
if (lastNumber > nextFileNumber)
nextFileNumber = lastNumber;
}
else
throw new IOException(string.Format("File {0} does not follow the pattern provided",f));
{
throw new IOException(string.Format("File {0} does not follow the pattern provided", f));
}
}
catch (Exception e)
{
throw new IOException(string.Format("Failed to process file {0} due to error {1}",f, e.Message), e);
throw new IOException(string.Format("Failed to process file {0} due to error {1}", f, e.Message), e);
}
}
if (nextFileNumber == 0) throw new IOException("Cannot roll the file because matching pattern not found");
if (nextFileNumber == 0)
throw new IOException("Cannot roll the file because matching pattern not found");
nextFileNumber++;
}
return nextFileNumber;
}
}

View File

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Diagnostics;
namespace winsw.Logging
{

View File

@ -1,9 +1,6 @@
using log4net.Appender;
using System.Diagnostics;
using log4net.Appender;
using log4net.Core;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
namespace winsw.Logging
{
@ -31,6 +28,7 @@ namespace winsw.Logging
{
return EventLogEntryType.Error;
}
if (level.Value >= Level.Warn.Value)
{
return EventLogEntryType.Warning;

View File

@ -28,6 +28,7 @@ namespace winsw.Native
{
throw new Exception(String.Format("Error opening service for modifying. Error returned was: 0x{0:X}", Marshal.GetLastWin32Error()));
}
return new Service(svcHandle);
}
@ -52,9 +53,9 @@ namespace winsw.Native
{
SERVICE_FAILURE_ACTIONS sfa = new SERVICE_FAILURE_ACTIONS
{
dwResetPeriod = (int) failureResetPeriod.TotalSeconds,
lpRebootMsg = "",
lpCommand = ""
dwResetPeriod = (int)failureResetPeriod.TotalSeconds,
lpRebootMsg = string.Empty,
lpCommand = string.Empty
};
// delete message
// delete the command to run
@ -101,7 +102,7 @@ namespace winsw.Native
public void Dispose()
{
if (Handle!=IntPtr.Zero)
if (Handle != IntPtr.Zero)
Advapi32.CloseServiceHandle(Handle);
Handle = IntPtr.Zero;
}
@ -111,14 +112,14 @@ namespace winsw.Native
{
public static void AddLogonAsAServiceRight(string username)
{
//Needs to be at least XP or 2003 server
//https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832%28v=vs.85%29.aspx
// Needs to be at least XP or 2003 server
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832%28v=vs.85%29.aspx
OperatingSystem osInfo = Environment.OSVersion;
if (osInfo.Version.Major >= 5 && osInfo.Version.Minor >= 1)
{
var newuser = GetLocalAccountIfLocalAccount(username);
//Trace.WriteLine("Username for Logon as A Service: " + newuser);
// Trace.WriteLine("Username for Logon as A Service: " + newuser);
long rightexitcode = SetRight(newuser, PrivlegeRights.SeServiceLogonRight.ToString());
if (rightexitcode != 0)
{
@ -155,6 +156,7 @@ namespace winsw.Native
{
return GetLogin(username);
}
return username;
}
@ -164,32 +166,32 @@ namespace winsw.Native
/// <returns>The windows error code returned by LsaAddAccountRights</returns>
private static long SetRight(String accountName, String privilegeName)
{
long winErrorCode = 0; //contains the last error
long winErrorCode; // contains the last error
//pointer an size for the SID
// pointer an size for the SID
IntPtr sid = IntPtr.Zero;
int sidSize = 0;
//StringBuilder and size for the domain name
// StringBuilder and size for the domain name
StringBuilder domainName = new StringBuilder();
int nameSize = 0;
//account-type variable for lookup
// account-type variable for lookup
int accountType = 0;
//get required buffer size
// get required buffer size
Advapi32.LookupAccountName(String.Empty, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType);
//allocate buffers
// allocate buffers
domainName = new StringBuilder(nameSize);
sid = Marshal.AllocHGlobal(sidSize);
//lookup the SID for the account
// lookup the SID for the account
bool result = Advapi32.LookupAccountName(String.Empty, accountName, sid, ref sidSize, domainName, ref nameSize,
ref accountType);
//say what you're doing
//Console.WriteLine("LookupAccountName result = " + result);
//Console.WriteLine("IsValidSid: " + Advapi32.IsValidSid(sid));
//Console.WriteLine("LookupAccountName domainName: " + domainName.ToString());
// say what you're doing
// Console.WriteLine("LookupAccountName result = " + result);
// Console.WriteLine("IsValidSid: " + Advapi32.IsValidSid(sid));
// Console.WriteLine("LookupAccountName domainName: " + domainName.ToString());
if (!result)
{
@ -198,10 +200,9 @@ namespace winsw.Native
}
else
{
//initialize an empty unicode-string
LSA_UNICODE_STRING systemName = new LSA_UNICODE_STRING();
//combine all policies
// initialize an empty unicode-string
LSA_UNICODE_STRING systemName = default;
// combine all policies
const int access = (int)(
LSA_AccessPolicy.POLICY_AUDIT_LOG_ADMIN |
LSA_AccessPolicy.POLICY_CREATE_ACCOUNT |
@ -217,10 +218,9 @@ namespace winsw.Native
LSA_AccessPolicy.POLICY_VIEW_AUDIT_INFORMATION |
LSA_AccessPolicy.POLICY_VIEW_LOCAL_INFORMATION
);
//initialize a pointer for the policy handle
IntPtr policyHandle = IntPtr.Zero;
// initialize a pointer for the policy handle
//these attributes are not used, but LsaOpenPolicy wants them to exists
// these attributes are not used, but LsaOpenPolicy wants them to exists
LSA_OBJECT_ATTRIBUTES objectAttributes = new LSA_OBJECT_ATTRIBUTES
{
Length = 0,
@ -230,8 +230,8 @@ namespace winsw.Native
SecurityQualityOfService = IntPtr.Zero
};
//get a policy handle
uint resultPolicy = Advapi32.LsaOpenPolicy(ref systemName, ref objectAttributes, access, out policyHandle);
// get a policy handle
uint resultPolicy = Advapi32.LsaOpenPolicy(ref systemName, ref objectAttributes, access, out IntPtr policyHandle);
winErrorCode = Advapi32.LsaNtStatusToWinError(resultPolicy);
if (winErrorCode != 0)
@ -240,17 +240,17 @@ namespace winsw.Native
}
else
{
//Now that we have the SID an the policy,
//we can add rights to the account.
// Now that we have the SID an the policy,
// we can add rights to the account.
//initialize an unicode-string for the privilege name
// initialize an unicode-string for the privilege name
LSA_UNICODE_STRING[] userRights = new LSA_UNICODE_STRING[1];
userRights[0] = new LSA_UNICODE_STRING();
userRights[0] = default;
userRights[0].Buffer = Marshal.StringToHGlobalUni(privilegeName);
userRights[0].Length = (UInt16)(privilegeName.Length * UnicodeEncoding.CharSize);
userRights[0].MaximumLength = (UInt16)((privilegeName.Length + 1) * UnicodeEncoding.CharSize);
//add the right to the account
// add the right to the account
uint res = Advapi32.LsaAddAccountRights(policyHandle, sid, userRights, 1);
winErrorCode = Advapi32.LsaNtStatusToWinError(res);
if (winErrorCode != 0)
@ -260,6 +260,7 @@ namespace winsw.Native
Advapi32.LsaClose(policyHandle);
}
Advapi32.FreeSid(sid);
}
@ -290,7 +291,7 @@ namespace winsw.Native
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool CloseServiceHandle(IntPtr hSCObject);
@ -309,7 +310,7 @@ namespace winsw.Native
internal static extern void FreeSid(IntPtr pSid);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, PreserveSig = true)]
internal static extern bool LookupAccountName(string lpSystemName, string lpAccountName, IntPtr psid, ref int cbsid, StringBuilder domainName,
internal static extern bool LookupAccountName(string lpSystemName, string lpAccountName, IntPtr psid, ref int cbsid, StringBuilder domainName,
ref int cbdomainLength, ref int use);
[DllImport("advapi32.dll")]
@ -320,22 +321,21 @@ namespace winsw.Native
[DllImport("advapi32.dll", SetLastError = false)]
internal static extern uint LsaNtStatusToWinError(uint status);
}
//http://msdn.microsoft.com/en-us/library/windows/desktop/bb545671(v=vs.85).aspx
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb545671(v=vs.85).aspx
internal enum PrivlegeRights
{
SeServiceLogonRight, //Required for an account to log on using the service logon type.
SeRemoteInteractiveLogonRight, //Required for an account to log on remotely using the interactive logon type.
SeNetworkLogonRight, //Required for an account to log on using the network logon type.
SeInteractiveLogonRight, //Required for an account to log on using the interactive logon type.
SeDenyServiceLogonRight, //Explicitly denies an account the right to log on using the service logon type.
SeDenyRemoteInteractiveLogonRight, //Explicitly denies an account the right to log on remotely using the interactive logon type.
SeDenyNetworkLogonRight, //Explicitly denies an account the right to log on using the network logon type.
SeDenyInteractiveLogonRight, //Explicitly denies an account the right to log on using the interactive logon type.
SeDenyBatchLogonRight, //Explicitly denies an account the right to log on using the batch logon type.
SeBatchLogonRight //Required for an account to log on using the batch logon type.
SeServiceLogonRight, // Required for an account to log on using the service logon type.
SeRemoteInteractiveLogonRight, // Required for an account to log on remotely using the interactive logon type.
SeNetworkLogonRight, // Required for an account to log on using the network logon type.
SeInteractiveLogonRight, // Required for an account to log on using the interactive logon type.
SeDenyServiceLogonRight, // Explicitly denies an account the right to log on using the service logon type.
SeDenyRemoteInteractiveLogonRight, // Explicitly denies an account the right to log on remotely using the interactive logon type.
SeDenyNetworkLogonRight, // Explicitly denies an account the right to log on using the network logon type.
SeDenyInteractiveLogonRight, // Explicitly denies an account the right to log on using the interactive logon type.
SeDenyBatchLogonRight, // Explicitly denies an account the right to log on using the batch logon type.
SeBatchLogonRight // Required for an account to log on using the batch logon type.
}
[StructLayout(LayoutKind.Sequential)]
@ -381,7 +381,7 @@ namespace winsw.Native
/// <summary>
/// Required to connect to the service control manager.
/// </summary>
SC_MANAGER_CONNECT = 0x00001,
/// <summary>
@ -391,19 +391,19 @@ namespace winsw.Native
SC_MANAGER_CREATE_SERVICE = 0x00002,
/// <summary>
/// Required to call the EnumServicesStatusEx function to list the
/// Required to call the EnumServicesStatusEx function to list the
/// services that are in the database.
/// </summary>
SC_MANAGER_ENUMERATE_SERVICE = 0x00004,
/// <summary>
/// Required to call the LockServiceDatabase function to acquire a
/// Required to call the LockServiceDatabase function to acquire a
/// lock on the database.
/// </summary>
SC_MANAGER_LOCK = 0x00008,
/// <summary>
/// Required to call the QueryServiceLockStatus function to retrieve
/// Required to call the QueryServiceLockStatus function to retrieve
/// the lock status information for the database.
/// </summary>
SC_MANAGER_QUERY_LOCK_STATUS = 0x00010,
@ -414,7 +414,7 @@ namespace winsw.Native
SC_MANAGER_MODIFY_BOOT_CONFIG = 0x00020,
/// <summary>
/// Includes STANDARD_RIGHTS_REQUIRED, in addition to all access
/// Includes STANDARD_RIGHTS_REQUIRED, in addition to all access
/// rights in this table.
/// </summary>
SC_MANAGER_ALL_ACCESS = ACCESS_MASK.STANDARD_RIGHTS_REQUIRED |
@ -452,7 +452,7 @@ namespace winsw.Native
SERVICE_PAUSE_CONTINUE = 0x00040,
SERVICE_INTERROGATE = 0x00080,
SERVICE_USER_DEFINED_CONTROL = 0x00100,
SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED |
SERVICE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
SERVICE_QUERY_CONFIG |
SERVICE_CHANGE_CONFIG |
SERVICE_QUERY_STATUS |
@ -461,7 +461,7 @@ namespace winsw.Native
SERVICE_STOP |
SERVICE_PAUSE_CONTINUE |
SERVICE_INTERROGATE |
SERVICE_USER_DEFINED_CONTROL)
SERVICE_USER_DEFINED_CONTROL
}
[Flags]
@ -536,7 +536,6 @@ namespace winsw.Native
SERVICE_PAUSE_PENDING = 0x00000006,
SERVICE_PAUSED = 0x00000007,
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms685126(v=vs.85).aspx
[StructLayout(LayoutKind.Sequential)]
@ -577,7 +576,7 @@ namespace winsw.Native
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms685939(v=vs.85).aspx
[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Unicode)]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct SERVICE_FAILURE_ACTIONS
{
/// <summary>

View File

@ -1,6 +1,6 @@
using Microsoft.Win32.SafeHandles;
using System;
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace winsw.Native
{
@ -8,7 +8,7 @@ namespace winsw.Native
/// kernel32.dll P/Invoke wrappers
/// </summary>
public class Kernel32
{
{
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetStdHandle(int nStdHandle, SafeFileHandle handle);

View File

@ -29,10 +29,16 @@ namespace winsw
public enum PeriodicityType
{
ERRONEOUS, TOP_OF_MILLISECOND, TOP_OF_SECOND, TOP_OF_MINUTE, TOP_OF_HOUR, TOP_OF_DAY
ERRONEOUS,
TOP_OF_MILLISECOND,
TOP_OF_SECOND,
TOP_OF_MINUTE,
TOP_OF_HOUR,
TOP_OF_DAY
}
private static readonly PeriodicityType[] VALID_ORDERED_LIST = {
private static readonly PeriodicityType[] VALID_ORDERED_LIST =
{
PeriodicityType.TOP_OF_MILLISECOND, PeriodicityType.TOP_OF_SECOND, PeriodicityType.TOP_OF_MINUTE, PeriodicityType.TOP_OF_HOUR, PeriodicityType.TOP_OF_DAY
};
@ -54,6 +60,7 @@ namespace winsw
return i;
}
}
return PeriodicityType.ERRONEOUS;
}
@ -100,17 +107,11 @@ namespace winsw
_nextRoll = nextTriggeringTime(now, _period);
return true;
}
return false;
}
}
public string format
{
get
{
return _currentRoll.ToString(_format);
}
}
public string format => _currentRoll.ToString(_format);
}
}

View File

@ -3,7 +3,6 @@ using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Xml;
using winsw.Configuration;
using winsw.Native;
@ -20,40 +19,35 @@ namespace winsw
// ReSharper disable once InconsistentNaming
protected readonly XmlDocument dom = new XmlDocument();
private static readonly DefaultWinSWSettings defaults = new DefaultWinSWSettings();
public static DefaultWinSWSettings Defaults { get { return defaults; } }
public static DefaultWinSWSettings Defaults { get; } = new DefaultWinSWSettings();
/// <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.
///
///
/// In the above example, this would be "ghi".
/// </summary>
public string BaseName { get; set; }
public virtual string ExecutablePath
{
get
{
// Currently there is no opportunity to alter the executable path
return Defaults.ExecutablePath;
}
}
// Currently there is no opportunity to alter the executable path
public virtual string ExecutablePath => Defaults.ExecutablePath;
public ServiceDescriptor()
{
// find co-located configuration xml. We search up to the ancestor directories to simplify debugging,
// as well as trimming off ".vshost" suffix (which is used during debugging)
//Get the first parent to go into the recursive loop
// Get the first parent to go into the recursive loop
string p = ExecutablePath;
string baseName = Path.GetFileNameWithoutExtension(p);
if (baseName.EndsWith(".vshost")) baseName = baseName.Substring(0, baseName.Length - 7);
if (baseName.EndsWith(".vshost"))
baseName = baseName.Substring(0, baseName.Length - 7);
DirectoryInfo d = new DirectoryInfo(Path.GetDirectoryName(p));
while (true)
{
@ -61,7 +55,7 @@ namespace winsw
break;
if (d.Parent == null)
throw new FileNotFoundException("Unable to locate "+baseName+".xml file within executable directory or any parents");
throw new FileNotFoundException("Unable to locate " + baseName + ".xml file within executable directory or any parents");
d = d.Parent;
}
@ -73,11 +67,13 @@ namespace winsw
// register the base directory as environment variable so that future expansions can refer to this.
Environment.SetEnvironmentVariable("BASE", d.FullName);
// ditto for ID
Environment.SetEnvironmentVariable("SERVICE_ID", Id);
// New name
Environment.SetEnvironmentVariable(WinSWSystem.ENVVAR_NAME_EXECUTABLE_PATH, ExecutablePath);
// Also inject system environment variables
Environment.SetEnvironmentVariable(WinSWSystem.ENVVAR_NAME_SERVICE_ID, Id);
}
@ -106,7 +102,9 @@ namespace winsw
private string SingleElement(string tagName, bool optional)
{
var n = dom.SelectSingleNode("//" + tagName);
if (n == null && !optional) throw new InvalidDataException("<" + tagName + "> is missing in configuration XML");
if (n == null && !optional)
throw new InvalidDataException("<" + tagName + "> is missing in configuration XML");
return n == null ? null : Environment.ExpandEnvironmentVariables(n.InnerText);
}
@ -147,51 +145,36 @@ namespace winsw
return TimeSpan.FromMilliseconds(int.Parse(v.Substring(0, v.Length - s.Key.Length).Trim()) * s.Value);
}
}
return TimeSpan.FromMilliseconds(int.Parse(v));
}
private static readonly Dictionary<string,long> Suffix = new Dictionary<string,long> {
{ "ms", 1 },
private static readonly Dictionary<string, long> Suffix = new Dictionary<string, long>
{
{ "ms", 1 },
{ "sec", 1000L },
{ "secs", 1000L },
{ "min", 1000L*60L },
{ "mins", 1000L*60L },
{ "hr", 1000L*60L*60L },
{ "hrs", 1000L*60L*60L },
{ "hour", 1000L*60L*60L },
{ "hours", 1000L*60L*60L },
{ "day", 1000L*60L*60L*24L },
{ "days", 1000L*60L*60L*24L }
{ "min", 1000L * 60L },
{ "mins", 1000L * 60L },
{ "hr", 1000L * 60L * 60L },
{ "hrs", 1000L * 60L * 60L },
{ "hour", 1000L * 60L * 60L },
{ "hours", 1000L * 60L * 60L },
{ "day", 1000L * 60L * 60L * 24L },
{ "days", 1000L * 60L * 60L * 24L }
};
/// <summary>
/// Path to the executable.
/// </summary>
public string Executable
{
get
{
return SingleElement("executable");
}
}
public string Executable => SingleElement("executable");
public bool HideWindow
{
get {
return SingleBoolElement("hidewindow", Defaults.HideWindow);
}
}
public bool HideWindow => SingleBoolElement("hidewindow", Defaults.HideWindow);
/// <summary>
/// Optionally specify a different Path to an executable to shutdown the service.
/// </summary>
public string StopExecutable
{
get
{
return SingleElement("stopexecutable", true);
}
}
public string StopExecutable => SingleElement("stopexecutable", true);
/// <summary>
/// Arguments or multiple optional argument elements which overrule the arguments element.
@ -223,28 +206,17 @@ namespace winsw
/// <summary>
/// Multiple optional startargument elements.
/// </summary>
public string Startarguments
{
get
{
return AppendTags("startargument", Defaults.Startarguments);
}
}
public string Startarguments => AppendTags("startargument", Defaults.Startarguments);
/// <summary>
/// Multiple optional stopargument elements.
/// </summary>
public string Stoparguments
public string Stoparguments => AppendTags("stopargument", Defaults.Stoparguments);
public string WorkingDirectory
{
get
{
return AppendTags("stopargument", Defaults.Stoparguments);
}
}
public string WorkingDirectory {
get {
var wd = SingleElement("workingdirectory", true);
return String.IsNullOrEmpty(wd) ? Defaults.WorkingDirectory : wd;
}
@ -257,8 +229,8 @@ namespace winsw
List<string> res = new List<string>();
XmlNode argumentNode = ExtensionsConfiguration;
XmlNodeList extensions = argumentNode != null ? argumentNode.SelectNodes("extension") : null;
if ( extensions != null)
XmlNodeList extensions = argumentNode?.SelectNodes("extension");
if (extensions != null)
{
foreach (XmlNode e in extensions)
{
@ -272,14 +244,7 @@ namespace winsw
}
}
public XmlNode ExtensionsConfiguration
{
get
{
XmlNode argumentNode = dom.SelectSingleNode("//extensions");
return argumentNode;
}
}
public XmlNode ExtensionsConfiguration => dom.SelectSingleNode("//extensions");
/// <summary>
/// Combines the contents of all the elements of the given name,
@ -295,7 +260,7 @@ namespace winsw
}
else
{
string arguments = "";
string arguments = string.Empty;
foreach (XmlElement argument in dom.SelectNodes("//" + tagName))
{
@ -314,6 +279,7 @@ namespace winsw
token = '"' + token + '"';
}
}
arguments += " " + token;
}
@ -365,6 +331,7 @@ namespace winsw
{
mode = Defaults.LogMode;
}
return mode;
}
}
@ -379,18 +346,9 @@ namespace winsw
}
}
public bool OutFileDisabled
{
get { return SingleBoolElement("outfiledisabled", Defaults.OutFileDisabled); }
}
public bool OutFileDisabled => SingleBoolElement("outfiledisabled", Defaults.OutFileDisabled);
public bool ErrFileDisabled
{
get
{
return SingleBoolElement("errfiledisabled", Defaults.ErrFileDisabled);
}
}
public bool ErrFileDisabled => SingleBoolElement("errfiledisabled", Defaults.ErrFileDisabled);
public string OutFilePattern
{
@ -414,7 +372,6 @@ namespace winsw
public LogHandler LogHandler
{
get
{
XmlElement e = (XmlElement)dom.SelectSingleNode("//logmode");
@ -423,6 +380,7 @@ namespace winsw
// this is more modern way, to support nested elements as configuration
e = (XmlElement)dom.SelectSingleNode("//log");
}
int sizeThreshold;
switch (LogMode)
{
@ -444,13 +402,14 @@ namespace winsw
{
throw new InvalidDataException("Time Based rolling policy is specified but no pattern can be found in configuration XML.");
}
var pattern = patternNode.InnerText;
int period = SingleIntElement(e,"period",1);
int period = SingleIntElement(e, "period", 1);
return new TimeBasedRollingLogAppender(LogDirectory, LogName, OutFileDisabled, ErrFileDisabled, OutFilePattern, ErrFilePattern, pattern, period);
case "roll-by-size":
sizeThreshold = SingleIntElement(e,"sizeThreshold",10*1024) * SizeBasedRollingLogAppender.BYTES_PER_KB;
int keepFiles = SingleIntElement(e,"keepFiles",SizeBasedRollingLogAppender.DEFAULT_FILES_TO_KEEP);
sizeThreshold = SingleIntElement(e, "sizeThreshold", 10 * 1024) * SizeBasedRollingLogAppender.BYTES_PER_KB;
int keepFiles = SingleIntElement(e, "keepFiles", SizeBasedRollingLogAppender.DEFAULT_FILES_TO_KEEP);
return new SizeBasedRollingLogAppender(LogDirectory, LogName, OutFileDisabled, ErrFileDisabled, OutFilePattern, ErrFilePattern, sizeThreshold, keepFiles);
case "append":
@ -463,29 +422,29 @@ namespace winsw
{
throw new InvalidDataException("Roll-Size-Time Based rolling policy is specified but no pattern can be found in configuration XML.");
}
XmlNode autoRollAtTimeNode = e.SelectSingleNode("autoRollAtTime");
TimeSpan? autoRollAtTime = null;
if (autoRollAtTimeNode != null)
{
TimeSpan autoRollAtTimeValue;
// validate it
if (!TimeSpan.TryParse(autoRollAtTimeNode.InnerText, out autoRollAtTimeValue))
if (!TimeSpan.TryParse(autoRollAtTimeNode.InnerText, out TimeSpan autoRollAtTimeValue))
throw new InvalidDataException("Roll-Size-Time Based rolling policy is specified but autoRollAtTime does not match the TimeSpan format HH:mm:ss found in configuration XML.");
autoRollAtTime = autoRollAtTimeValue;
}
XmlNode zipolderthannumdaysNode = e.SelectSingleNode("zipOlderThanNumDays");
int? zipolderthannumdays = null;
if (zipolderthannumdaysNode != null)
{
int zipolderthannumdaysValue;
// validate it
if (!int.TryParse(zipolderthannumdaysNode.InnerText, out zipolderthannumdaysValue))
if (!int.TryParse(zipolderthannumdaysNode.InnerText, out int zipolderthannumdaysValue))
throw new InvalidDataException("Roll-Size-Time Based rolling policy is specified but zipOlderThanNumDays does not match the int format found in configuration XML.");
zipolderthannumdays = zipolderthannumdaysValue;
}
XmlNode zipdateformatNode = e.SelectSingleNode("zipDateFormat");
string zipdateformat = null;
string zipdateformat;
if (zipdateformatNode == null)
{
zipdateformat = "yyyyMM";
@ -501,7 +460,6 @@ namespace winsw
throw new InvalidDataException("Undefined logging mode: " + LogMode);
}
}
}
/// <summary>
@ -519,35 +477,19 @@ namespace winsw
{
serviceDependencies.Add(depend.InnerText);
}
return (string[])serviceDependencies.ToArray(typeof(string));
}
return Defaults.ServiceDependencies;
}
}
public string Id
{
get
{
return SingleElement("id");
}
}
public string Id => SingleElement("id");
public string Caption
{
get
{
return SingleElement("name");
}
}
public string Caption => SingleElement("name");
public string Description
{
get
{
return SingleElement("description");
}
}
public string Description => SingleElement("description");
/// <summary>
/// Start mode of the Service
@ -557,7 +499,9 @@ namespace winsw
get
{
var p = SingleElement("startmode", true);
if (p == null) return Defaults.StartMode;
if (p == null)
return Defaults.StartMode;
try
{
return (StartMode)Enum.Parse(typeof(StartMode), p, true);
@ -569,6 +513,7 @@ namespace winsw
{
Console.WriteLine(sm);
}
throw;
}
}
@ -578,64 +523,32 @@ namespace winsw
/// True if the service should be installed with the DelayedAutoStart flag.
/// This setting will be applyed only during the install command and only when the Automatic start mode is configured.
/// </summary>
public bool DelayedAutoStart
{
get
{
return dom.SelectSingleNode("//delayedAutoStart") != null;
}
}
public bool DelayedAutoStart => dom.SelectSingleNode("//delayedAutoStart") != null;
/// <summary>
/// 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
{
get
{
return dom.SelectSingleNode("//beeponshutdown") != null;
}
}
public bool BeepOnShutdown => dom.SelectSingleNode("//beeponshutdown") != null;
/// <summary>
/// The estimated time required for a pending stop operation (default 15 secs).
/// Before the specified amount of time has elapsed, the service should make its next call to the SetServiceStatus function
/// Before the specified amount of time has elapsed, the service should make its next call to the SetServiceStatus function
/// with either an incremented checkPoint value or a change in currentState. (see http://msdn.microsoft.com/en-us/library/ms685996.aspx)
/// </summary>
public TimeSpan WaitHint
{
get
{
return SingleTimeSpanElement(dom, "waithint", Defaults.WaitHint);
}
}
public TimeSpan WaitHint => SingleTimeSpanElement(dom, "waithint", Defaults.WaitHint);
/// <summary>
/// The time before the service should make its next call to the SetServiceStatus function
/// The time before the service should make its next call to the SetServiceStatus function
/// with an incremented checkPoint value (default 1 sec).
/// 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.
/// </summary>
public TimeSpan SleepTime
{
get
{
return SingleTimeSpanElement(dom, "sleeptime", Defaults.SleepTime);
}
}
public TimeSpan SleepTime => SingleTimeSpanElement(dom, "sleeptime", Defaults.SleepTime);
/// <summary>
/// True if the service can interact with the desktop.
/// </summary>
public bool Interactive
{
get
{
return dom.SelectSingleNode("//interactive") != null;
}
}
public bool Interactive => dom.SelectSingleNode("//interactive") != null;
/// <summary>
/// Environment variable overrides
@ -653,6 +566,7 @@ namespace winsw
Environment.SetEnvironmentVariable(key, value);
}
return map;
}
}
@ -666,7 +580,7 @@ namespace winsw
get
{
var xmlNodeList = dom.SelectNodes("//download");
if (xmlNodeList == null)
if (xmlNodeList == null)
{
return Defaults.Downloads;
}
@ -674,12 +588,12 @@ namespace winsw
List<Download> r = new List<Download>();
foreach (XmlNode n in xmlNodeList)
{
XmlElement el = n as XmlElement;
if (el != null)
if (n is XmlElement el)
{
r.Add(new Download(el));
}
}
return r;
}
}
@ -710,25 +624,21 @@ namespace winsw
default:
throw new Exception("Invalid failure action: " + action);
}
XmlAttribute delay = n.Attributes["delay"];
r.Add(new SC_ACTION(type, delay != null ? ParseTimeSpan(delay.Value) : TimeSpan.Zero));
}
}
return r;
}
}
public TimeSpan ResetFailureAfter
{
get
{
return SingleTimeSpanElement(dom, "resetfailure", Defaults.ResetFailureAfter);
}
}
public TimeSpan ResetFailureAfter => SingleTimeSpanElement(dom, "resetfailure", Defaults.ResetFailureAfter);
protected string GetServiceAccountPart(string subNodeName)
{
var node = dom.SelectSingleNode("//serviceaccount");
{
var node = dom.SelectSingleNode("//serviceaccount");
if (node != null)
{
@ -736,56 +646,28 @@ namespace winsw
if (subNode != null)
{
return subNode.InnerText;
}
}
}
return null;
}
protected string AllowServiceLogon
{
get
{
return GetServiceAccountPart("allowservicelogon");
}
return null;
}
// ReSharper disable once InconsistentNaming
protected string serviceAccountDomain
{
get
{
return GetServiceAccountPart("domain");
}
}
protected string AllowServiceLogon => GetServiceAccountPart("allowservicelogon");
// ReSharper disable once InconsistentNaming
protected string serviceAccountName
{
get
{
return GetServiceAccountPart("user");
}
}
protected string serviceAccountDomain => GetServiceAccountPart("domain");
public string ServiceAccountPassword
{
get
{
return GetServiceAccountPart("password");
}
}
// ReSharper disable once InconsistentNaming
protected string serviceAccountName => GetServiceAccountPart("user");
public string ServiceAccountUser
{
get { return (serviceAccountDomain ?? "NULL") + @"\" + (serviceAccountName ?? "NULL"); }
}
public string ServiceAccountPassword => GetServiceAccountPart("password");
public bool HasServiceAccount()
{
return !string.IsNullOrEmpty(serviceAccountDomain) && !string.IsNullOrEmpty(serviceAccountName);
}
public string ServiceAccountUser => (serviceAccountDomain ?? "NULL") + @"\" + (serviceAccountName ?? "NULL");
public bool HasServiceAccount()
{
return !string.IsNullOrEmpty(serviceAccountDomain) && !string.IsNullOrEmpty(serviceAccountName);
}
public bool AllowServiceAcountLogonRight
{
@ -793,37 +675,31 @@ namespace winsw
{
if (AllowServiceLogon != null)
{
bool parsedvalue;
if (Boolean.TryParse(AllowServiceLogon, out parsedvalue))
if (Boolean.TryParse(AllowServiceLogon, out bool parsedvalue))
{
return parsedvalue;
}
}
return false;
}
}
/// <summary>
/// Time to wait for the service to gracefully shutdown the executable before we forcibly kill it
/// </summary>
public TimeSpan StopTimeout
{
get
{
return SingleTimeSpanElement(dom, "stoptimeout", Defaults.StopTimeout);
}
}
/// <summary>
/// Time to wait for the service to gracefully shutdown the executable before we forcibly kill it
/// </summary>
public TimeSpan StopTimeout => SingleTimeSpanElement(dom, "stoptimeout", Defaults.StopTimeout);
public bool StopParentProcessFirst
{
get
{
var value = SingleElement("stopparentprocessfirst", true);
bool result;
if (bool.TryParse(value, out result))
if (bool.TryParse(value, out bool result))
{
return result;
}
return Defaults.StopParentProcessFirst;
}
}
@ -835,8 +711,9 @@ namespace winsw
{
get
{
var p = SingleElement("priority",true);
if (p == null) return Defaults.Priority;
var p = SingleElement("priority", true);
if (p == null)
return Defaults.Priority;
return (ProcessPriorityClass)Enum.Parse(typeof(ProcessPriorityClass), p, true);
}

View File

@ -1,10 +1,9 @@
using log4net;
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Management;
using System.Text;
using System.Threading;
using log4net;
namespace winsw.Util
{
@ -24,8 +23,9 @@ namespace winsw.Util
public static List<int> GetChildPids(int pid)
{
var childPids = new List<int>();
try {
try
{
var searcher = new ManagementObjectSearcher("Select * From Win32_Process Where ParentProcessID=" + pid);
foreach (var mo in searcher.Get())
{
@ -38,7 +38,7 @@ namespace winsw.Util
{
Logger.Warn("Failed to locate children of the process with PID=" + pid + ". Child processes won't be terminated", ex);
}
return childPids;
}
@ -87,7 +87,7 @@ namespace winsw.Util
}
}
//TODO: Propagate error if process kill fails? Currently we use the legacy behavior
// TODO: Propagate error if process kill fails? Currently we use the legacy behavior
}
/// <summary>
@ -100,7 +100,7 @@ namespace winsw.Util
public static void StopProcessAndChildren(int pid, TimeSpan stopTimeout, bool stopParentProcessFirst)
{
if (!stopParentProcessFirst)
{
{
foreach (var childPid in GetChildPids(pid))
{
StopProcessAndChildren(childPid, stopTimeout, stopParentProcessFirst);
@ -149,7 +149,7 @@ namespace winsw.Util
foreach (string key in envVars.Keys)
{
Environment.SetEnvironmentVariable(key, envVars[key]);
// DONTDO: ps.EnvironmentVariables[key] = envs[key];
// DONTDO: ps.EnvironmentVariables[key] = envs[key];
// bugged (lower cases all variable names due to StringDictionary being used, see http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=326163)
}
}
@ -157,8 +157,8 @@ namespace winsw.Util
processToStart.Start();
Logger.Info("Started process " + processToStart.Id);
if (priority != null && priority.Value != ProcessPriorityClass.Normal)
{
if (priority != null && priority.Value != ProcessPriorityClass.Normal)
{
processToStart.PriorityClass = priority.Value;
}
@ -172,7 +172,7 @@ namespace winsw.Util
// monitor the completion of the process
if (callback != null)
{
StartThread(delegate
StartThread(() =>
{
processToStart.WaitForExit();
callback(processToStart);
@ -187,7 +187,7 @@ namespace winsw.Util
/// </summary>
public static void StartThread(ThreadStart main)
{
new Thread(delegate()
new Thread(() =>
{
try
{

View File

@ -1,7 +1,7 @@
using log4net;
using System;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using log4net;
using winsw.Native;
namespace winsw.Util
@ -20,6 +20,7 @@ namespace winsw.Util
[DllImport(KERNEL32)]
private static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add);
// Delegate type to be used as the Handler Routine for SCCH
private delegate Boolean ConsoleCtrlDelegate(CtrlTypes CtrlType);
@ -47,7 +48,7 @@ namespace winsw.Util
{
if (AttachConsole((uint)process.Id))
{
//Disable Ctrl-C handling for our program
// Disable Ctrl-C handling for our program
SetConsoleCtrlHandler(null, true);
GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0);
@ -61,9 +62,9 @@ namespace winsw.Util
Logger.Warn("Failed to detach from console. Error code: " + errorCode);
}
return process.HasExited;
return process.HasExited;
}
return false;
}
}

View File

@ -1,15 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.Xml;
namespace winsw.Util
{
public class XmlHelper
{
/// <summary>
/// Retrieves a single string element
/// Retrieves a single string element
/// </summary>
/// <param name="node">Parent node</param>
/// <param name="tagName">Element name</param>
@ -19,7 +17,9 @@ namespace winsw.Util
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");
if (n == null && !optional)
throw new InvalidDataException("<" + tagName + "> is missing in configuration XML");
return n == null ? null : Environment.ExpandEnvironmentVariables(n.InnerText);
}
@ -34,7 +34,9 @@ namespace winsw.Util
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");
if (n == null && !optional)
throw new InvalidDataException("<" + tagName + "> is missing in configuration XML");
return n;
}
@ -45,14 +47,14 @@ namespace winsw.Util
/// <param name="attributeName">Attribute name</param>
/// <returns>Attribute value</returns>
/// <exception cref="InvalidDataException">The required attribute is missing</exception>
public static TAttributeType SingleAttribute <TAttributeType> (XmlElement node, string attributeName)
public static TAttributeType SingleAttribute<TAttributeType>(XmlElement node, string attributeName)
{
if (!node.HasAttribute(attributeName))
{
throw new InvalidDataException("Attribute <" + attributeName + "> is missing in configuration XML");
}
return SingleAttribute<TAttributeType>(node, attributeName, default(TAttributeType));
return SingleAttribute(node, attributeName, default(TAttributeType));
}
/// <summary>
@ -64,12 +66,13 @@ namespace winsw.Util
/// <returns>Attribute value (or default)</returns>
public static TAttributeType SingleAttribute<TAttributeType>(XmlElement node, string attributeName, TAttributeType defaultValue)
{
if (!node.HasAttribute(attributeName)) return 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;
string rawValue = node.GetAttribute(attributeName);
string substitutedValue = Environment.ExpandEnvironmentVariables(rawValue);
var value = (TAttributeType)Convert.ChangeType(substitutedValue, typeof(TAttributeType));
return value;
}
/// <summary>
@ -83,7 +86,8 @@ namespace winsw.Util
/// <exception cref="InvalidDataException">Wrong enum value</exception>
public static TAttributeType EnumAttribute<TAttributeType>(XmlElement node, string attributeName, TAttributeType defaultValue)
{
if (!node.HasAttribute(attributeName)) return defaultValue;
if (!node.HasAttribute(attributeName))
return defaultValue;
string rawValue = node.GetAttribute(attributeName);
string substitutedValue = Environment.ExpandEnvironmentVariables(rawValue);
@ -94,7 +98,7 @@ namespace winsw.Util
}
catch (Exception ex) // Most likely ArgumentException
{
throw new InvalidDataException("Cannot parse <" + attributeName + "> Enum value from string '" + substitutedValue +
throw new InvalidDataException("Cannot parse <" + attributeName + "> Enum value from string '" + substitutedValue +
"'. Enum type: " + typeof(TAttributeType), ex);
}
}

View File

@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace winsw
{

View File

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace winsw
namespace winsw
{
/// <summary>
/// Class, which contains generic information about WinSW runtime.
@ -19,11 +15,11 @@ namespace winsw
/// Variable, which points to the service ID.
/// It may be used to determine runaway processes.
/// </summary>
public static string ENVVAR_NAME_SERVICE_ID { get { return SYSTEM_EVNVVAR_PREFIX + "SERVICE_ID"; } }
public static string ENVVAR_NAME_SERVICE_ID => SYSTEM_EVNVVAR_PREFIX + "SERVICE_ID";
/// <summary>
/// Variable, which specifies path to the executable being launched by WinSW.
/// </summary>
public static string ENVVAR_NAME_EXECUTABLE_PATH { get { return SYSTEM_EVNVVAR_PREFIX + "EXECUTABLE"; } }
public static string ENVVAR_NAME_EXECUTABLE_PATH => SYSTEM_EVNVVAR_PREFIX + "EXECUTABLE";
}
}

View File

@ -5,7 +5,7 @@ using DynamicProxy;
namespace WMI
{
//Reference: http://msdn2.microsoft.com/en-us/library/aa389390(VS.85).aspx
// Reference: http://msdn2.microsoft.com/en-us/library/aa389390(VS.85).aspx
public enum ReturnValue
{
@ -63,13 +63,14 @@ namespace WMI
public class WmiClassName : Attribute
{
public readonly string Name;
public WmiClassName(string name) { Name = name; }
public WmiClassName(string name) => Name = name;
}
/// <summary>
/// Marker interface to denote a collection in WMI.
/// </summary>
public interface IWmiCollection {}
public interface IWmiCollection { }
/// <summary>
/// Marker interface to denote an individual managed object
@ -141,6 +142,7 @@ namespace WMI
_mo[method.Name.Substring(4)] = args[0];
return null;
}
if (method.Name.StartsWith("get_"))
{
return _mo[method.Name.Substring(4)];
@ -180,7 +182,9 @@ namespace WMI
string query = "SELECT * FROM " + _wmiClass + " WHERE ";
for (int i = 0; i < args.Length; i++)
{
if (i != 0) query += " AND ";
if (i != 0)
query += " AND ";
query += ' ' + Capitalize(methodArgs[i].Name) + " = '" + args[i] + "'";
}

View File

@ -1,12 +1,12 @@
using System;
using System.Collections.Generic;
using System.Xml;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml;
using log4net;
using winsw.Extensions;
using winsw.Util;
using log4net;
using System.Collections.Specialized;
using System.Text;
namespace winsw.Plugins.RunawayProcessKiller
{
@ -34,7 +34,7 @@ namespace winsw.Plugins.RunawayProcessKiller
/// </summary>
public bool CheckWinSWEnvironmentVariable { get; private set; }
public override String DisplayName { get { return "Runaway Process Killer"; } }
public override String DisplayName => "Runaway Process Killer";
private String ServiceId { get; set; }
@ -61,7 +61,7 @@ namespace winsw.Plugins.RunawayProcessKiller
StopTimeout = TimeSpan.FromMilliseconds(Int32.Parse(XmlHelper.SingleElement(node, "stopTimeout", false)));
StopParentProcessFirst = Boolean.Parse(XmlHelper.SingleElement(node, "stopParentFirst", false));
ServiceId = descriptor.Id;
//TODO: Consider making it documented
// TODO: Consider making it documented
var checkWinSWEnvironmentVariable = XmlHelper.SingleElement(node, "checkWinSWEnvironmentVariable", true);
CheckWinSWEnvironmentVariable = checkWinSWEnvironmentVariable != null ? Boolean.Parse(checkWinSWEnvironmentVariable) : true;
}
@ -74,17 +74,19 @@ namespace winsw.Plugins.RunawayProcessKiller
{
// Read PID file from the disk
int pid;
if (System.IO.File.Exists(Pidfile)) {
if (File.Exists(Pidfile))
{
string pidstring;
try
{
pidstring = System.IO.File.ReadAllText(Pidfile);
pidstring = File.ReadAllText(Pidfile);
}
catch (Exception ex)
{
Logger.Error("Cannot read PID file from " + Pidfile, ex);
return;
}
try
{
pid = Int32.Parse(pidstring);
@ -108,7 +110,7 @@ namespace winsw.Plugins.RunawayProcessKiller
{
proc = Process.GetProcessById(pid);
}
catch (ArgumentException ex)
catch (ArgumentException)
{
Logger.Debug("No runaway process with PID=" + pid + ". The process has been already stopped.");
return;
@ -127,14 +129,16 @@ namespace winsw.Plugins.RunawayProcessKiller
}
else if (CheckWinSWEnvironmentVariable)
{
Logger.Warn("The process " + pid + " has no " + expectedEnvVarName + " environment variable defined. "
Logger.Warn("The process " + pid + " has no " + expectedEnvVarName + " environment variable defined. "
+ "The process has not been started by WinSW, hence it won't be terminated.");
if (Logger.IsDebugEnabled) {
//TODO replace by String.Join() in .NET 4
if (Logger.IsDebugEnabled)
{
// TODO replace by String.Join() in .NET 4
String[] keys = new String[previousProcessEnvVars.Count];
previousProcessEnvVars.Keys.CopyTo(keys, 0);
Logger.DebugFormat("Env vars of the process with PID={0}: {1}", new Object[] {pid, String.Join(",", keys)});
Logger.DebugFormat("Env vars of the process with PID={0}: {1}", new Object[] { pid, String.Join(",", keys) });
}
return;
}
else
@ -155,11 +159,13 @@ namespace winsw.Plugins.RunawayProcessKiller
StringBuilder bldr = new StringBuilder("Stopping the runaway process (pid=");
bldr.Append(pid);
bldr.Append(") and its children. Environment was ");
if (!CheckWinSWEnvironmentVariable) {
if (!CheckWinSWEnvironmentVariable)
{
bldr.Append("not ");
}
bldr.Append("checked, affiliated service ID: ");
bldr.Append(affiliatedServiceId != null ? affiliatedServiceId : "undefined");
bldr.Append(affiliatedServiceId ?? "undefined");
bldr.Append(", process to kill: ");
bldr.Append(proc);
@ -171,12 +177,12 @@ namespace winsw.Plugins.RunawayProcessKiller
/// Records the started process PID for the future use in OnStart() after the restart.
/// </summary>
/// <param name="process"></param>
public override void OnProcessStarted(System.Diagnostics.Process process)
public override void OnProcessStarted(Process process)
{
Logger.Info("Recording PID of the started process:" + process.Id + ". PID file destination is " + Pidfile);
try
{
System.IO.File.WriteAllText(Pidfile, process.Id.ToString());
File.WriteAllText(Pidfile, process.Id.ToString());
}
catch (Exception ex)
{

View File

@ -1,10 +1,9 @@
using System;
using System.Collections.Generic;
using System.Xml;
using System.Diagnostics;
using log4net;
using winsw.Extensions;
using winsw.Util;
using log4net;
namespace winsw.Plugins.SharedDirectoryMapper
{
@ -13,7 +12,7 @@ namespace winsw.Plugins.SharedDirectoryMapper
private readonly SharedDirectoryMappingHelper _mapper = new SharedDirectoryMappingHelper();
private readonly List<SharedDirectoryMapperConfig> _entries = new List<SharedDirectoryMapperConfig>();
public override String DisplayName { get { return "Shared Directory Mapper"; } }
public override String DisplayName => "Shared Directory Mapper";
private static readonly ILog Logger = LogManager.GetLogger(typeof(SharedDirectoryMapper));
@ -34,8 +33,7 @@ namespace winsw.Plugins.SharedDirectoryMapper
{
foreach (XmlNode mapNode in nodes)
{
var mapElement = mapNode as XmlElement;
if (mapElement != null)
if (mapNode is XmlElement mapElement)
{
var config = SharedDirectoryMapperConfig.FromXml(mapElement);
_entries.Add(config);
@ -85,8 +83,9 @@ namespace winsw.Plugins.SharedDirectoryMapper
}
}
private void HandleMappingError(SharedDirectoryMapperConfig config, MapperException ex) {
Logger.Error("Mapping of " + config.Label + " failed. STDOUT: " + ex.Process.StandardOutput.ReadToEnd()
private void HandleMappingError(SharedDirectoryMapperConfig config, MapperException ex)
{
Logger.Error("Mapping of " + config.Label + " failed. STDOUT: " + ex.Process.StandardOutput.ReadToEnd()
+ " \r\nSTDERR: " + ex.Process.StandardError.ReadToEnd(), ex);
throw new ExtensionException(Descriptor.Id, DisplayName + ": Mapping of " + config.Label + "failed", ex);
}

View File

@ -1,6 +1,5 @@
using System;
using System.Diagnostics;
using winsw.Util;
namespace winsw.Plugins.SharedDirectoryMapper
{

View File

@ -1,9 +1,6 @@
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.IO;
using System.Xml;
using NUnit.Framework;
using winsw;
using winswTests.Util;
@ -16,11 +13,10 @@ namespace winswTests.Configuration
[TestFixture]
class ExamplesTest
{
[Test]
public void allOptionsConfigShouldDeclareDefaults()
public void AllOptionsConfigShouldDeclareDefaults()
{
ServiceDescriptor d = doLoad("allOptions");
ServiceDescriptor d = DoLoad("allOptions");
Assert.AreEqual("myapp", d.Id);
Assert.AreEqual("MyApp Service (powered by WinSW)", d.Caption);
@ -31,9 +27,9 @@ namespace winswTests.Configuration
}
[Test]
public void minimalConfigShouldDeclareDefaults()
public void MinimalConfigShouldDeclareDefaults()
{
ServiceDescriptor d = doLoad("minimal");
ServiceDescriptor d = DoLoad("minimal");
Assert.AreEqual("myapp", d.Id);
Assert.AreEqual("MyApp Service (powered by WinSW)", d.Caption);
@ -43,13 +39,15 @@ namespace winswTests.Configuration
ServiceDescriptorAssert.AssertAllOptionalPropertiesAreDefault(d);
}
private ServiceDescriptor doLoad(string exampleName) {
private ServiceDescriptor DoLoad(string exampleName)
{
var dir = Directory.GetCurrentDirectory();
string path = Path.GetFullPath(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);

View File

@ -1,8 +1,6 @@
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System;
using System.IO;
using System.Text;
using NUnit.Framework;
using winsw;
using winswTests.Util;
@ -22,7 +20,7 @@ namespace winswTests
var sd = ConfigXmlBuilder.create()
.WithDownload(d)
.ToServiceDescriptor(true);
var loaded = getSingleEntry(sd);
var loaded = GetSingleEntry(sd);
// Check default values
Assert.That(loaded.FailOnError, Is.EqualTo(false));
@ -40,7 +38,7 @@ namespace winswTests
var sd = ConfigXmlBuilder.create()
.WithDownload(d)
.ToServiceDescriptor(true);
var loaded = getSingleEntry(sd);
var loaded = GetSingleEntry(sd);
// Check default values
Assert.That(loaded.FailOnError, Is.EqualTo(true));
@ -58,7 +56,7 @@ namespace winswTests
var sd = ConfigXmlBuilder.create()
.WithDownload(d)
.ToServiceDescriptor(true);
var loaded = getSingleEntry(sd);
var loaded = GetSingleEntry(sd);
// Check default values
Assert.That(loaded.FailOnError, Is.EqualTo(false));
@ -67,7 +65,7 @@ namespace winswTests
Assert.That(loaded.Password, Is.Null);
Assert.That(loaded.UnsecureAuth, Is.EqualTo(false));
}
[TestCase("http://")]
[TestCase("ftp://")]
[TestCase("file:///")]
@ -77,19 +75,19 @@ namespace winswTests
{
var d = new Download(protocolPrefix + "myServer.com:8080/file.txt", To,
auth: Download.AuthType.basic, username: "aUser", password: "aPassword");
assertInitializationFails(d, "you're sending your credentials in clear text to the server");
AssertInitializationFails(d, "you're sending your credentials in clear text to the server");
}
public void ShouldRejectBasicAuth_without_username()
{
var d = new Download(From, To, auth: Download.AuthType.basic, username: null, password: "aPassword");
assertInitializationFails(d, "Basic Auth is enabled, but username is not specified");
AssertInitializationFails(d, "Basic Auth is enabled, but username is not specified");
}
public void ShouldRejectBasicAuth_without_password()
{
var d = new Download(From, To, auth: Download.AuthType.basic, username: "aUser", password: null);
assertInitializationFails(d, "Basic Auth is enabled, but password is not specified");
AssertInitializationFails(d, "Basic Auth is enabled, but password is not specified");
}
/// <summary>
@ -105,7 +103,7 @@ namespace winswTests
.WithDownload(d)
.ToServiceDescriptor(true);
var loaded = getSingleEntry(sd);
var loaded = GetSingleEntry(sd);
Assert.That(loaded.From, Is.EqualTo(From));
Assert.That(loaded.To, Is.EqualTo(To));
Assert.That(loaded.FailOnError, Is.EqualTo(failOnError), "Unexpected FailOnError value");
@ -121,7 +119,7 @@ namespace winswTests
.WithRawEntry("<download from=\"http://www.nosuchhostexists.foo.myorg/foo.xml\" to=\"%BASE%\\foo.xml\"/>")
.ToServiceDescriptor(true);
var loaded = getSingleEntry(sd);
var loaded = GetSingleEntry(sd);
Assert.That(loaded.FailOnError, Is.False);
}
@ -134,7 +132,7 @@ namespace winswTests
var sd = ConfigXmlBuilder.create()
.WithRawEntry("<download from=\"http://www.nosuchhostexists.foo.myorg/foo.xml\" to=\"%BASE%\\foo.xml\" auth=\"" + authType + "\"/>")
.ToServiceDescriptor(true);
var loaded = getSingleEntry(sd);
var loaded = GetSingleEntry(sd);
Assert.That(loaded.Auth, Is.EqualTo(Download.AuthType.sspi));
}
@ -146,27 +144,28 @@ namespace winswTests
.WithRawEntry("<download from=\"http://www.nosuchhostexists.foo.myorg/foo.xml\" to=\"%BASE%\\foo.xml\" auth=\"digest\"/>")
.ToServiceDescriptor(true);
ExceptionHelper.assertFails("Cannot parse <auth> Enum value from string 'digest'", typeof(InvalidDataException), delegate {
var d = getSingleEntry(sd);
ExceptionHelper.assertFails("Cannot parse <auth> Enum value from string 'digest'", typeof(InvalidDataException), () =>
{
var d = GetSingleEntry(sd);
});
}
private Download getSingleEntry(ServiceDescriptor sd)
private Download GetSingleEntry(ServiceDescriptor sd)
{
var downloads = sd.Downloads.ToArray();
Assert.That(downloads.Length, Is.EqualTo(1), "Service Descriptor is expected to have only one entry");
return downloads[0];
}
private void assertInitializationFails(Download download, String expectedMessagePart = null, Type expectedExceptionType = null)
private void AssertInitializationFails(Download download, String expectedMessagePart = null, Type expectedExceptionType = null)
{
var sd = ConfigXmlBuilder.create()
.WithDownload(download)
.ToServiceDescriptor(true);
ExceptionHelper.assertFails(expectedMessagePart, expectedExceptionType ?? typeof(InvalidDataException), delegate
ExceptionHelper.assertFails(expectedMessagePart, expectedExceptionType ?? typeof(InvalidDataException), () =>
{
var d = getSingleEntry(sd);
var d = GetSingleEntry(sd);
});
}
}

View File

@ -1,6 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace winswTests.Extensions
{
@ -15,7 +13,7 @@ namespace winswTests.Extensions
/// </summary>
/// <param name="type">Type of the extension</param>
/// <returns>String for Type locator, which includes class and assembly names</returns>
public static String getExtensionClassNameWithAssembly(Type type)
public static String GetExtensionClassNameWithAssembly(Type type)
{
return type.ToString() + ", " + type.Assembly;
}

View File

@ -1,14 +1,13 @@
using winsw;
using NUnit.Framework;
using winsw.Extensions;
using winsw.Plugins.SharedDirectoryMapper;
using winsw.Plugins.RunawayProcessKiller;
using winswTests.Util;
using System.IO;
using System.Diagnostics;
using winsw.Util;
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using NUnit.Framework;
using winsw;
using winsw.Extensions;
using winsw.Plugins.RunawayProcessKiller;
using winsw.Util;
using winswTests.Util;
namespace winswTests.Extensions
{
@ -17,8 +16,8 @@ namespace winswTests.Extensions
{
ServiceDescriptor _testServiceDescriptor;
string testExtension = getExtensionClassNameWithAssembly(typeof(RunawayProcessKillerExtension));
string testExtension = GetExtensionClassNameWithAssembly(typeof(RunawayProcessKillerExtension));
[SetUp]
public void SetUp()
{
@ -71,7 +70,7 @@ namespace winswTests.Extensions
var winswId = "myAppWithRunaway";
var extensionId = "runawayProcessKiller";
var tmpDir = FilesystemTestHelper.CreateTmpDirectory();
// Prepare the env var
String varName = WinSWSystem.ENVVAR_NAME_SERVICE_ID;
var env = new Dictionary<string, string>();
@ -99,7 +98,7 @@ namespace winswTests.Extensions
Assert.IsNotNull(extension, "RunawayProcessKillerExtension should be loaded");
Assert.AreEqual(pidfile, extension.Pidfile, "PidFile should have been retained during the config roundtrip");
// Inject PID
// Inject PID
File.WriteAllText(pidfile, proc.Id.ToString());
// Try to terminate
@ -119,7 +118,7 @@ namespace winswTests.Extensions
Console.Error.WriteLine("Test: ProcessHelper failed to properly terminate process with ID=" + proc.Id);
}
}
}
}
}
}
}

View File

@ -1,5 +1,5 @@
using winsw;
using NUnit.Framework;
using NUnit.Framework;
using winsw;
using winsw.Extensions;
using winsw.Plugins.SharedDirectoryMapper;
@ -10,12 +10,11 @@ namespace winswTests.Extensions
{
ServiceDescriptor _testServiceDescriptor;
string testExtension = getExtensionClassNameWithAssembly(typeof(SharedDirectoryMapper));
string testExtension = GetExtensionClassNameWithAssembly(typeof(SharedDirectoryMapper));
[SetUp]
public void SetUp()
{
string seedXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
+ "<service> "
+ " <id>SERVICE_NAME</id> "

View File

@ -7,7 +7,6 @@ namespace winswTests
[TestFixture]
class MainTest
{
[Test]
public void PrintVersion()
{
@ -21,12 +20,12 @@ namespace winswTests
{
string expectedVersion = WrapperService.Version.ToString();
string cliOut = CLITestHelper.CLITest(new[] { "help" });
StringAssert.Contains(expectedVersion, cliOut, "Expected that help contains " + expectedVersion);
StringAssert.Contains("start", cliOut, "Expected that help refers start command");
StringAssert.Contains("help", cliOut, "Expected that help refers help command");
StringAssert.Contains("version", cliOut, "Expected that help refers version command");
//TODO: check all commands after the migration of ccommands to enum
// TODO: check all commands after the migration of ccommands to enum
// Extra options
StringAssert.Contains("/redirect", cliOut, "Expected that help message refers the redirect message");
@ -37,8 +36,8 @@ namespace winswTests
{
const string commandName = "nonExistentCommand";
string expectedMessage = "Unknown command: " + commandName.ToLower();
CLITestResult res = CLITestHelper.CLIErrorTest(new[] {commandName});
CLITestResult res = CLITestHelper.CLIErrorTest(new[] { commandName });
Assert.True(res.HasException, "Expected an exception due to the wrong command");
StringAssert.Contains(expectedMessage, res.Out, "Expected the message about unknown command");
// ReSharper disable once PossibleNullReferenceException

View File

@ -1,18 +1,16 @@
using System;
using System.Diagnostics;
using System.Diagnostics;
using NUnit.Framework;
using winsw;
namespace winswTests
{
using System;
using WMI;
using winswTests.Util;
using WMI;
[TestFixture]
public class ServiceDescriptorTests
{
private ServiceDescriptor _extendedServiceDescriptor;
private const string ExpectedWorkingDirectory = @"Z:\Path\SubPath";
@ -32,9 +30,9 @@ namespace winswTests
+ "<arguments>My Arguments</arguments>"
+ "<logmode>rotate</logmode>"
+ "<serviceaccount>"
+ "<domain>" + Domain + "</domain>"
+ "<user>" + Username + "</user>"
+ "<password>" + Password + "</password>"
+ "<domain>" + Domain + "</domain>"
+ "<user>" + Username + "</user>"
+ "<password>" + Password + "</password>"
+ "<allowservicelogon>" + AllowServiceAccountLogonRight + "</allowservicelogon>"
+ "</serviceaccount>"
+ "<workingdirectory>"
@ -52,7 +50,7 @@ namespace winswTests
}
[Test]
[ExpectedException(typeof(System.ArgumentException))]
[ExpectedException(typeof(ArgumentException))]
public void IncorrectStartMode()
{
const string SeedXml = "<service>"
@ -105,6 +103,7 @@ namespace winswTests
_extendedServiceDescriptor = ServiceDescriptor.FromXML(SeedXml);
Assert.That(_extendedServiceDescriptor.StartMode, Is.EqualTo(StartMode.Manual));
}
[Test]
public void VerifyWorkingDirectory()
{
@ -154,8 +153,8 @@ namespace winswTests
[Test]
public void CanParseStopParentProcessFirst()
{
const string seedXml = "<service>"
+ "<stopparentprocessfirst>true</stopparentprocessfirst>"
const string seedXml = "<service>"
+ "<stopparentprocessfirst>true</stopparentprocessfirst>"
+ "</service>";
var serviceDescriptor = ServiceDescriptor.FromXML(seedXml);
@ -165,8 +164,8 @@ namespace winswTests
[Test]
public void CanParseStopTimeout()
{
const string seedXml = "<service>"
+ "<stoptimeout>60sec</stoptimeout>"
const string seedXml = "<service>"
+ "<stoptimeout>60sec</stoptimeout>"
+ "</service>";
var serviceDescriptor = ServiceDescriptor.FromXML(seedXml);
@ -176,8 +175,8 @@ namespace winswTests
[Test]
public void CanParseStopTimeoutFromMinutes()
{
const string seedXml = "<service>"
+ "<stoptimeout>10min</stoptimeout>"
const string seedXml = "<service>"
+ "<stoptimeout>10min</stoptimeout>"
+ "</service>";
var serviceDescriptor = ServiceDescriptor.FromXML(seedXml);
@ -242,14 +241,14 @@ namespace winswTests
[Test]
public void LogModeRollBySize()
{
const string seedXml = "<service>"
const string seedXml = "<service>"
+ "<logpath>c:\\</logpath>"
+ "<log mode=\"roll-by-size\">"
+ "<sizeThreshold>112</sizeThreshold>"
+ "<keepFiles>113</keepFiles>"
+ "<sizeThreshold>112</sizeThreshold>"
+ "<keepFiles>113</keepFiles>"
+ "</log>"
+ "</service>";
var serviceDescriptor = ServiceDescriptor.FromXML(seedXml);
serviceDescriptor.BaseName = "service";
@ -265,8 +264,8 @@ namespace winswTests
const string seedXml = "<service>"
+ "<logpath>c:\\</logpath>"
+ "<log mode=\"roll-by-time\">"
+ "<period>7</period>"
+ "<pattern>log pattern</pattern>"
+ "<period>7</period>"
+ "<pattern>log pattern</pattern>"
+ "</log>"
+ "</service>";
@ -298,23 +297,24 @@ namespace winswTests
Assert.NotNull(logHandler);
Assert.That(logHandler.SizeTheshold, Is.EqualTo(10240 * 1024));
Assert.That(logHandler.FilePattern, Is.EqualTo("yyyy-MM-dd"));
Assert.That(logHandler.AutoRollAtTime, Is.EqualTo((TimeSpan?)new TimeSpan(0,0,0)));
Assert.That(logHandler.AutoRollAtTime, Is.EqualTo((TimeSpan?)new TimeSpan(0, 0, 0)));
}
[Test]
public void VerifyServiceLogonRightGraceful()
{
const string seedXml="<service>"
const string seedXml = "<service>"
+ "<serviceaccount>"
+ "<domain>" + Domain + "</domain>"
+ "<user>" + Username + "</user>"
+ "<password>" + Password + "</password>"
+ "<domain>" + Domain + "</domain>"
+ "<user>" + Username + "</user>"
+ "<password>" + Password + "</password>"
+ "<allowservicelogon>true1</allowservicelogon>"
+ "</serviceaccount>"
+ "</serviceaccount>"
+ "</service>";
var serviceDescriptor = ServiceDescriptor.FromXML(seedXml);
Assert.That(serviceDescriptor.AllowServiceAcountLogonRight, Is.EqualTo(false));
}
[Test]
public void VerifyServiceLogonRightOmitted()
{
@ -358,7 +358,7 @@ namespace winswTests
.ToServiceDescriptor(true);
Assert.That(sd.WaitHint, Is.EqualTo(TimeSpan.FromMinutes(22)));
}
[Test]
public void VerifyWaitHint_XMLWithoutVersionAndComment()
{
@ -438,10 +438,12 @@ namespace winswTests
public void DelayedStart_RoundTrip(bool enabled)
{
var bldr = ConfigXmlBuilder.create();
if (enabled) {
if (enabled)
{
bldr = bldr.WithDelayedAutoStart();
}
var sd = bldr.ToServiceDescriptor();
var sd = bldr.ToServiceDescriptor();
Assert.That(sd.DelayedAutoStart, Is.EqualTo(enabled));
}
}

View File

@ -22,6 +22,7 @@ namespace winswTests.Util
+ "</workingdirectory>"
+ @"<logpath>C:\winsw\logs</logpath>"
+ "</service>";
private static readonly ServiceDescriptor DefaultServiceDescriptor = ServiceDescriptor.FromXML(SeedXml);
/// <summary>
@ -61,8 +62,9 @@ namespace winswTests.Util
using (swOut = new StringWriter())
using (swErr = new StringWriter())
{
try
{
{
Console.SetOut(swOut);
Console.SetError(swErr);
WrapperService.Run(args, descriptor ?? DefaultServiceDescriptor);
@ -85,7 +87,8 @@ namespace winswTests.Util
Console.WriteLine(testEx);
}
}
}
return new CLITestResult(swOut.ToString(), swErr.ToString(), testEx);
}
}
@ -97,14 +100,14 @@ namespace winswTests.Util
{
[NotNull]
public String Out { get; private set; }
[NotNull]
public String Err { get; private set; }
[CanBeNull]
public Exception Exception { get; private set; }
public bool HasException { get { return Exception != null; } }
public bool HasException => Exception != null;
public CLITestResult(String output, String err, Exception exception = null)
{

View File

@ -17,7 +17,7 @@ namespace winswTests.Util
public string Description { get; set; }
public string Executable { get; set; }
public bool PrintXMLVersion { get; set; }
public string XMLComment { get; set; }
public string XMLComment { get; set; }
public List<string> ExtensionXmls { get; private set; }
private List<String> configEntries;
@ -29,9 +29,9 @@ namespace winswTests.Util
ExtensionXmls = new List<string>();
}
public static ConfigXmlBuilder create(string id = null, string name = null,
string description = null, string executable = null, bool printXMLVersion = true,
string xmlComment = "")
public static ConfigXmlBuilder create(string id = null, string name = null,
string description = null, string executable = null, bool printXMLVersion = true,
string xmlComment = "")
{
var config = new ConfigXmlBuilder();
config.Id = id ?? "myapp";
@ -39,8 +39,8 @@ namespace winswTests.Util
config.Description = description ?? "MyApp Service (powered by WinSW)";
config.Executable = executable ?? "%BASE%\\myExecutable.exe";
config.PrintXMLVersion = printXMLVersion;
config.XMLComment = (xmlComment != null && xmlComment.Length == 0)
? "Just a sample configuration file generated by the test suite"
config.XMLComment = (xmlComment != null && xmlComment.Length == 0)
? "Just a sample configuration file generated by the test suite"
: xmlComment;
return config;
}
@ -53,10 +53,12 @@ namespace winswTests.Util
// TODO: The encoding is generally wrong
str.Append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
}
if (XMLComment != null)
{
str.AppendFormat("<!--{0}-->\n", XMLComment);
}
str.Append("<service>\n");
str.AppendFormat(" <id>{0}</id>\n", Id);
str.AppendFormat(" <name>{0}</name>\n", Name);
@ -69,13 +71,14 @@ namespace winswTests.Util
}
// Extensions
if (ExtensionXmls.Count > 0)
if (ExtensionXmls.Count > 0)
{
str.Append(" <extensions>\n");
foreach (string xml in ExtensionXmls)
foreach (string xml in ExtensionXmls)
{
str.Append(xml);
}
str.Append(" </extensions>\n");
}
@ -86,13 +89,14 @@ namespace winswTests.Util
Console.Out.WriteLine("Produced config:");
Console.Out.WriteLine(res);
}
return res;
}
public ServiceDescriptor ToServiceDescriptor(bool dumpConfig = false)
{
return ServiceDescriptor.FromXML(ToXMLString(dumpConfig));
}
}
public ConfigXmlBuilder WithRawEntry(string entry)
{
@ -101,20 +105,20 @@ namespace winswTests.Util
}
public ConfigXmlBuilder WithTag(string tagName, string value)
{
{
return WithRawEntry(String.Format("<{0}>{1}</{0}>", tagName, value));
}
public ConfigXmlBuilder WithRunawayProcessKiller(RunawayProcessKillerExtension ext, string extensionId = "killRunawayProcess", bool enabled = true)
{
var fullyQualifiedExtensionName = ExtensionTestBase.getExtensionClassNameWithAssembly(typeof(RunawayProcessKillerExtension));
var fullyQualifiedExtensionName = ExtensionTestBase.GetExtensionClassNameWithAssembly(typeof(RunawayProcessKillerExtension));
StringBuilder str = new StringBuilder();
str.AppendFormat(" <extension enabled=\"{0}\" className=\"{1}\" id=\"{2}\">\n", new Object[] { enabled, fullyQualifiedExtensionName, extensionId});
str.AppendFormat(" <extension enabled=\"{0}\" className=\"{1}\" id=\"{2}\">\n", new Object[] { enabled, fullyQualifiedExtensionName, extensionId });
str.AppendFormat(" <pidfile>{0}</pidfile>\n", ext.Pidfile);
str.AppendFormat(" <stopTimeout>{0}</stopTimeout>\n", ext.StopTimeout.TotalMilliseconds);
str.AppendFormat(" <stopParentFirst>{0}</stopParentFirst>\n", ext.StopParentProcessFirst);
str.AppendFormat(" <checkWinSWEnvironmentVariable>{0}</checkWinSWEnvironmentVariable>\n", ext.CheckWinSWEnvironmentVariable);
str.Append( " </extension>\n");
str.Append(" </extension>\n");
ExtensionXmls.Add(str.ToString());
return this;
@ -123,8 +127,8 @@ namespace winswTests.Util
public ConfigXmlBuilder WithDownload(Download download)
{
StringBuilder str = new StringBuilder();
str.AppendFormat("<download from=\"{0}\" to=\"{1}\" failOnError=\"{2}\"", new Object[] { download.From, download.To, download.FailOnError});
str.AppendFormat("<download from=\"{0}\" to=\"{1}\" failOnError=\"{2}\"", new Object[] { download.From, download.To, download.FailOnError });
// Authentication
if (download.Auth != Download.AuthType.none)
{

View File

@ -1,7 +1,5 @@
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Text;
using System;
using NUnit.Framework;
namespace winswTests.Util
{
@ -28,8 +26,6 @@ namespace winswTests.Util
Assert.Fail("Expected exception " + expectedExceptionType + " to be thrown by the operation");
}
}
public delegate void ExceptionHelperExecutionBody();

View File

@ -1,8 +1,7 @@
using NUnit.Framework;
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using NUnit.Framework;
namespace winswTests.Util
{
@ -14,7 +13,7 @@ namespace winswTests.Util
/// <returns>tmp Dir</returns>
public static string CreateTmpDirectory(String testName = null)
{
string tempDirectory = Path.Combine(Path.GetTempPath(), "winswTests_" + (testName ?? "") + Path.GetRandomFileName());
string tempDirectory = Path.Combine(Path.GetTempPath(), "winswTests_" + (testName ?? string.Empty) + Path.GetRandomFileName());
Directory.CreateDirectory(tempDirectory);
Console.Out.WriteLine("Created the temporary directory: {0}", tempDirectory);
return tempDirectory;
@ -29,7 +28,8 @@ namespace winswTests.Util
{
Dictionary<string, string> res = new Dictionary<string, string>();
var lines = File.ReadAllLines(filePath);
foreach(var line in lines) {
foreach (var line in lines)
{
var parsed = line.Split("=".ToCharArray(), 2);
if (parsed.Length == 2)
{
@ -40,6 +40,7 @@ namespace winswTests.Util
Assert.Fail("Wrong line in the parsed Set output file: " + line);
}
}
return res;
}
}

View File

@ -1,14 +1,12 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using NUnit.Framework;
using winsw;
using System.IO;
using NUnit.Framework;
using winsw.Util;
using System.Collections.Generic;
namespace winswTests.Util
{
namespace winswTests.Util
{
[TestFixture]
class ProcessHelperTest
{
@ -25,7 +23,6 @@ namespace winswTests.Util
String scriptFile = Path.Combine(tmpDir, "printenv.bat");
File.WriteAllText(scriptFile, "set > " + envFile);
Process proc = new Process();
var ps = proc.StartInfo;
ps.FileName = scriptFile;
@ -48,35 +45,36 @@ namespace winswTests.Util
Assert.That(!envVars.ContainsKey("test_key"), "Test error: the environment parsing logic is case-insensitive");
}
[Test]
public void ShouldNotHangWhenWritingLargeStringToStdOut()
{
var tmpDir = FilesystemTestHelper.CreateTmpDirectory();
String scriptFile = Path.Combine(tmpDir, "print_lots_to_stdout.bat");
var lotsOfStdOut = string.Join("", _Range(1,1000));
File.WriteAllText(scriptFile, string.Format("echo \"{0}\"", lotsOfStdOut));
Process proc = new Process();
var ps = proc.StartInfo;
ps.FileName = scriptFile;
ProcessHelper.StartProcessAndCallbackForExit(proc);
var exited = proc.WaitForExit(5000);
if (!exited)
{
Assert.Fail("Process " + proc + " didn't exit after 5 seconds");
}
}
private string[] _Range(int start, int limit)
{
var range = new List<string>();
for(var i = start; i<limit; i++)
{
range.Add(i.ToString());
}
return range.ToArray();
}
}
}
[Test]
public void ShouldNotHangWhenWritingLargeStringToStdOut()
{
var tmpDir = FilesystemTestHelper.CreateTmpDirectory();
String scriptFile = Path.Combine(tmpDir, "print_lots_to_stdout.bat");
var lotsOfStdOut = string.Join(string.Empty, _Range(1, 1000));
File.WriteAllText(scriptFile, string.Format("echo \"{0}\"", lotsOfStdOut));
Process proc = new Process();
var ps = proc.StartInfo;
ps.FileName = scriptFile;
ProcessHelper.StartProcessAndCallbackForExit(proc);
var exited = proc.WaitForExit(5000);
if (!exited)
{
Assert.Fail("Process " + proc + " didn't exit after 5 seconds");
}
}
private string[] _Range(int start, int limit)
{
var range = new List<string>();
for (var i = start; i < limit; i++)
{
range.Add(i.ToString());
}
return range.ToArray();
}
}
}

View File

@ -1,8 +1,6 @@
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using NUnit.Framework;
using winsw;
using winsw.Configuration;
@ -13,7 +11,7 @@ namespace winswTests.Util
// 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)
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);
@ -37,14 +35,17 @@ namespace winswTests.Util
AssertPropertyIsDefault(d, AllOptionalProperties);
}
private static List<string> AllProperties {
get {
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;
}
}
@ -62,6 +63,4 @@ namespace winswTests.Util
}
}
}
}