Merge pull request #353 from NextTurn/styles

Code Style and Formatting cleanup
pull/363/head
Oleg Nenashev 2020-01-18 19:29:59 +01:00 committed by GitHub
commit 315c43b192
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 871 additions and 932 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,7 +70,7 @@ namespace winsw
eventLogProvider.service = this;
}
public WrapperService() : this (new ServiceDescriptor())
public WrapperService() : this(new ServiceDescriptor())
{
}
@ -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>
@ -151,7 +143,7 @@ namespace winsw
return logAppender;
}
public void LogEvent(String message)
public void LogEvent(string message)
{
if (_systemShuttingdown)
{
@ -170,7 +162,7 @@ namespace winsw
}
}
public void LogEvent(String message, EventLogEntryType type)
public void LogEvent(string message, EventLogEntryType type)
{
if (_systemShuttingdown)
{
@ -199,13 +191,12 @@ namespace winsw
{
LogEvent("envar " + key + '=' + _envs[key]);
}*/
HandleFileCopies();
// handle downloads
foreach (Download d in _descriptor.Downloads)
{
String downloadMsg = "Downloading: " + d.From + " to " + d.To + ". failOnError=" + d.FailOnError;
string downloadMsg = "Downloading: " + d.From + " to " + d.To + ". failOnError=" + d.FailOnError;
LogEvent(downloadMsg);
Log.Info(downloadMsg);
try
@ -217,6 +208,7 @@ 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)
{
@ -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
{
@ -311,7 +303,7 @@ namespace winsw
stoparguments += " " + _descriptor.Arguments;
Process stopProcess = new Process();
String executable = _descriptor.StopExecutable;
string executable = _descriptor.StopExecutable;
if (executable == null)
{
@ -343,11 +335,11 @@ namespace winsw
SignalShutdownPending();
int effectiveProcessWaitSleepTime;
if (_descriptor.SleepTime.TotalMilliseconds > Int32.MaxValue)
if (_descriptor.SleepTime.TotalMilliseconds > int.MaxValue)
{
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;
int.MaxValue + ". The value will be truncated");
effectiveProcessWaitSleepTime = int.MaxValue;
}
else
{
@ -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,28 +361,27 @@ namespace winsw
// already terminated
}
// WriteEvent("WaitForProcessToExit [finished]");
// WriteEvent("WaitForProcessToExit [finished]");
}
private void SignalShutdownPending()
{
int effectiveWaitHint;
if (_descriptor.WaitHint.TotalMilliseconds > Int32.MaxValue)
if (_descriptor.WaitHint.TotalMilliseconds > int.MaxValue)
{
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;
int.MaxValue + ". The value will be truncated");
effectiveWaitHint = int.MaxValue;
}
else
{
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)
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,7 +476,6 @@ namespace winsw
throw new WmiException(ReturnValue.NoSuchService);
}
// ReSharper disable once InconsistentNaming
/// <summary>
/// Runs the wrapper.
@ -498,7 +488,6 @@ namespace winsw
{
bool isCLIMode = _args.Length > 0;
// If descriptor is not specified, initialize the new one (and load configs from there)
var d = descriptor ?? new ServiceDescriptor();
@ -506,7 +495,6 @@ namespace winsw
// 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");
@ -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")
{
@ -584,7 +572,7 @@ namespace winsw
LogonAsAService.AddLogonAsAServiceRight(username);
}
svc.Create (
svc.Create(
d.Id,
d.Caption,
"\"" + d.ExecutablePath + "\"",
@ -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.
@ -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)
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,12 +748,14 @@ namespace winsw
wsvc.OnStop();
return;
}
if (args[0] == "help" || args[0] == "--help" || args[0] == "-h"
|| args[0] == "-?" || args[0] == "/?")
{
printHelp();
return;
}
if (args[0] == "version")
{
printVersion();
@ -759,12 +765,12 @@ namespace winsw
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));
}
@ -784,7 +790,7 @@ namespace winsw
List<IAppender> appenders = new List<IAppender>();
// wrapper.log
String wrapperLogPath = Path.Combine(d.LogDirectory, d.BaseName + ".wrapper.log");
string wrapperLogPath = Path.Combine(d.LogDirectory, d.BaseName + ".wrapper.log");
var wrapperLog = new FileAppender
{
AppendToFile = true,
@ -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,8 +16,9 @@ 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);
private delegate bool ConsoleCtrlDelegate(CtrlTypes CtrlType);
// Enumerated type for the control messages sent to the handler routine
private enum CtrlTypes : uint
@ -43,7 +44,7 @@ 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);

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
@ -42,7 +42,7 @@ namespace winsw.Configuration
// Logging
string LogDirectory { get; }
//TODO: replace by enum
// TODO: replace by enum
string LogMode { get; }
// Environment

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;
@ -44,16 +55,16 @@ namespace winsw
/// <exception cref="InvalidDataException">The required attribute is missing or the configuration is invalid</exception>
internal Download(XmlElement n)
{
From = XmlHelper.SingleAttribute<String>(n, "from");
To = XmlHelper.SingleAttribute<String>(n, "to");
From = XmlHelper.SingleAttribute<string>(n, "from");
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);
Username = XmlHelper.SingleAttribute<String>(n, "user", null);
Password = XmlHelper.SingleAttribute<String>(n, "password", null);
UnsecureAuth = XmlHelper.SingleAttribute<bool>(n, "unsecureAuth", false);
Auth = XmlHelper.EnumAttribute(n, "auth", AuthType.none);
Username = XmlHelper.SingleAttribute<string>(n, "user", null);
Password = XmlHelper.SingleAttribute<string>(n, "password", null);
UnsecureAuth = XmlHelper.SingleAttribute(n, "unsecureAuth", false);
if (Auth == AuthType.basic)
{
@ -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);
@ -77,7 +89,7 @@ namespace winsw
}
// Source: http://stackoverflow.com/questions/2764577/forcing-basic-authentication-in-webrequest
private void SetBasicAuthHeader(WebRequest request, String username, String password)
private void SetBasicAuthHeader(WebRequest request, string username, string password)
{
string authInfo = username + ":" + password;
authInfo = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(authInfo));
@ -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

@ -86,7 +86,7 @@ namespace DynamicProxy
public class ProxyFactory
{
private static ProxyFactory _instance;
private static readonly Object LockObj = new Object();
private static readonly object LockObj = new object();
private readonly Hashtable _typeMap = Hashtable.Synchronized(new Hashtable());
private static readonly Hashtable OpCodeTypeMapper = new Hashtable();
@ -100,14 +100,14 @@ namespace DynamicProxy
// return types, used in the Emit process.
static ProxyFactory()
{
OpCodeTypeMapper.Add(typeof(Boolean), OpCodes.Ldind_I1);
OpCodeTypeMapper.Add(typeof(Int16), OpCodes.Ldind_I2);
OpCodeTypeMapper.Add(typeof(Int32), OpCodes.Ldind_I4);
OpCodeTypeMapper.Add(typeof(Int64), OpCodes.Ldind_I8);
OpCodeTypeMapper.Add(typeof(Double), OpCodes.Ldind_R8);
OpCodeTypeMapper.Add(typeof(Single), OpCodes.Ldind_R4);
OpCodeTypeMapper.Add(typeof(UInt16), OpCodes.Ldind_U2);
OpCodeTypeMapper.Add(typeof(UInt32), OpCodes.Ldind_U4);
OpCodeTypeMapper.Add(typeof(bool), OpCodes.Ldind_I1);
OpCodeTypeMapper.Add(typeof(short), OpCodes.Ldind_I2);
OpCodeTypeMapper.Add(typeof(int), OpCodes.Ldind_I4);
OpCodeTypeMapper.Add(typeof(long), OpCodes.Ldind_I8);
OpCodeTypeMapper.Add(typeof(double), OpCodes.Ldind_R8);
OpCodeTypeMapper.Add(typeof(float), OpCodes.Ldind_R4);
OpCodeTypeMapper.Add(typeof(ushort), OpCodes.Ldind_U2);
OpCodeTypeMapper.Add(typeof(uint), OpCodes.Ldind_U4);
}
private ProxyFactory()
@ -135,7 +135,7 @@ namespace DynamicProxy
}
}
public Object Create(IProxyInvocationHandler handler, Type objType, bool isObjInterface)
public object Create(IProxyInvocationHandler handler, Type objType, bool isObjInterface)
{
string typeName = objType.FullName + PROXY_SUFFIX;
Type type = (Type)_typeMap[typeName];
@ -160,7 +160,7 @@ namespace DynamicProxy
return Activator.CreateInstance(type, new object[] { handler });
}
public Object Create(IProxyInvocationHandler handler, Type objType)
public object Create(IProxyInvocationHandler handler, Type objType)
{
return Create(handler, objType, false);
}
@ -171,7 +171,7 @@ namespace DynamicProxy
if (handler != null && interfaces != null)
{
Type objType = typeof(Object);
Type objType = typeof(object);
Type handlerType = typeof(IProxyInvocationHandler);
AppDomain domain = Thread.GetDomain();
@ -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 });
@ -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,
/*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 );
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.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 );
methodIL.Emit(OpCodes.Callvirt, INVOKE_METHOD);
if ( methodInfo.ReturnType != typeof(void) ) {
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 if (!methodInfo.ReturnType.IsPrimitive)
{
methodIL.Emit(OpCodes.Ldobj, methodInfo.ReturnType);
}
else
{
methodIL.Emit((OpCode)OpCodeTypeMapper[methodInfo.ReturnType]);
}
}
} else {
}
else
{
// pop the return value that Invoke returned from the stack since
// the method's return type is void.
methodIL.Emit( OpCodes.Pop );
methodIL.Emit(OpCodes.Pop);
}
// Return
methodIL.Emit( OpCodes.Ret );
methodIL.Emit(OpCodes.Ret);
#endregion
}
//for (int i = 0; i < props.Length; 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()]);
//}
// }
// 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 String DisplayName { get; }
public abstract string DisplayName { get; }
public WinSWExtensionDescriptor Descriptor { get; set; }
public virtual void Configure(ServiceDescriptor descriptor, XmlNode node)

View File

@ -4,26 +4,20 @@ namespace winsw.Extensions
{
public class ExtensionException : WinSWException
{
public String ExtensionId { get; private set; }
public string ExtensionId { get; private set; }
public ExtensionException(String extensionName, String message)
public ExtensionException(string extensionName, string message)
: base(message)
{
ExtensionId = extensionName;
}
public ExtensionException(String extensionName, String message, Exception innerException)
public ExtensionException(string extensionName, string message, Exception innerException)
: base(message, innerException)
{
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
{
@ -17,7 +16,7 @@ namespace winsw.Extensions
/// <summary>
/// Extension name to be displayed in logs
/// </summary>
String DisplayName { get; }
string DisplayName { get; }
/// <summary>
/// Extension descriptor

View File

@ -15,7 +15,7 @@ namespace winsw.Extensions
/// <summary>
/// Unique extension ID
/// </summary>
public String Id { get; private set; }
public string Id { get; private set; }
/// <summary>
/// Exception is enabled
@ -25,7 +25,7 @@ namespace winsw.Extensions
/// <summary>
/// Extension classname
/// </summary>
public String ClassName { get; private set; }
public string ClassName { get; private set; }
private WinSWExtensionDescriptor(string id, string className, bool enabled)
{

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));
@ -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,34 +157,32 @@ namespace winsw.Extensions
{
Log.Warn("Extension is disabled: " + id);
}
}
private IWinSWExtension CreateExtensionInstance(string id, string className)
{
ActivationContext ac = AppDomain.CurrentDomain.ActivationContext;
Assembly assembly = Assembly.GetCallingAssembly();
Object created;
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;
}

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();
}
}
@ -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)
@ -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,18 +580,18 @@ 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;
}
private int GetNextFileNumber(string ext, string baseDirectory, string baseFileName, DateTime now)
{
var nextFileNumber = 0;
var files = Directory.GetFiles(baseDirectory, String.Format("{0}.{1}.#*{2}", baseFileName, now.ToString(FilePattern), ext));
var files = Directory.GetFiles(baseDirectory, string.Format("{0}.{1}.#*{2}", baseFileName, now.ToString(FilePattern), ext));
if (files.Length == 0)
{
nextFileNumber = 1;
@ -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

@ -17,7 +17,7 @@ namespace winsw.Native
_handle = Advapi32.OpenSCManager(null, null, (uint)SCM_ACCESS.SC_MANAGER_ALL_ACCESS);
if (_handle == IntPtr.Zero)
{
throw new Exception(String.Format("Error connecting to Service Control Manager. Error provided was: 0x{0:X}", Marshal.GetLastWin32Error()));
throw new Exception(string.Format("Error connecting to Service Control Manager. Error provided was: 0x{0:X}", Marshal.GetLastWin32Error()));
}
}
@ -26,8 +26,9 @@ namespace winsw.Native
IntPtr svcHandle = Advapi32.OpenService(_handle, serviceName, (int)SERVICE_ACCESS.SERVICE_ALL_ACCESS);
if (svcHandle == IntPtr.Zero)
{
throw new Exception(String.Format("Error opening service for modifying. Error returned was: 0x{0:X}", Marshal.GetLastWin32Error()));
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;
}
@ -162,34 +164,34 @@ namespace winsw.Native
/// <param name="accountName">Name of an account - "domain\account" or only "account"</param>
/// <param name="privilegeName">Name ofthe privilege</param>
/// <returns>The windows error code returned by LsaAddAccountRights</returns>
private static long SetRight(String accountName, String privilegeName)
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
Advapi32.LookupAccountName(String.Empty, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType);
// 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
bool result = Advapi32.LookupAccountName(String.Empty, accountName, sid, ref sidSize, domainName, ref nameSize,
// 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);
userRights[0].Length = (ushort)(privilegeName.Length * UnicodeEncoding.CharSize);
userRights[0].MaximumLength = (ushort)((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);
}
@ -299,7 +300,7 @@ namespace winsw.Native
public static extern bool SetServiceStatus(IntPtr hServiceStatus, ref SERVICE_STATUS lpServiceStatus);
[DllImport("advapi32.dll", PreserveSig = true)]
internal static extern UInt32 LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, Int32 DesiredAccess,
internal static extern uint LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, int DesiredAccess,
out IntPtr PolicyHandle);
[DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
@ -320,29 +321,28 @@ 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)]
struct LSA_UNICODE_STRING
{
public UInt16 Length;
public UInt16 MaximumLength;
public ushort Length;
public ushort MaximumLength;
public IntPtr Buffer;
}
@ -352,7 +352,7 @@ namespace winsw.Native
public int Length;
public IntPtr RootDirectory;
public LSA_UNICODE_STRING ObjectName;
public UInt32 Attributes;
public uint Attributes;
public IntPtr SecurityDescriptor;
public IntPtr SecurityQualityOfService;
}
@ -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]
@ -537,7 +537,6 @@ namespace winsw.Native
SERVICE_PAUSED = 0x00000007,
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms685126(v=vs.85).aspx
[StructLayout(LayoutKind.Sequential)]
public struct SC_ACTION
@ -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
{
@ -36,20 +36,20 @@ namespace winsw.Native
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STARTUPINFO
{
public Int32 cb;
public int cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwYSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public int dwX;
public int dwY;
public int dwXSize;
public int dwYSize;
public int dwXCountChars;
public int dwYCountChars;
public int dwFillAttribute;
public int dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;

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;
}
@ -89,7 +96,7 @@ namespace winsw
public PeriodicityType periodicityType { get; set; }
public Boolean shouldRoll
public bool shouldRoll
{
get
{
@ -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,8 +19,7 @@ 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?
@ -37,23 +35,19 @@ namespace winsw
/// </summary>
public string BaseName { get; set; }
public virtual string ExecutablePath
{
get
{
// Currently there is no opportunity to alter the executable path
return Defaults.ExecutablePath;
}
}
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> {
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,30 +206,19 @@ 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;
return string.IsNullOrEmpty(wd) ? Defaults.WorkingDirectory : wd;
}
}
@ -257,13 +229,13 @@ 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)
{
XmlElement extension = (XmlElement)e;
String extensionId = XmlHelper.SingleAttribute<string>(extension, "id");
string extensionId = XmlHelper.SingleAttribute<string>(extension, "id");
res.Add(extensionId);
}
}
@ -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
/// 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
/// 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;
}
}
@ -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,21 +624,17 @@ 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)
{
@ -740,47 +650,19 @@ namespace winsw
}
return null;
}
protected string AllowServiceLogon
{
get
{
return GetServiceAccountPart("allowservicelogon");
}
}
protected string AllowServiceLogon => GetServiceAccountPart("allowservicelogon");
// ReSharper disable once InconsistentNaming
protected string serviceAccountDomain
{
get
{
return GetServiceAccountPart("domain");
}
}
protected string serviceAccountDomain => GetServiceAccountPart("domain");
// ReSharper disable once InconsistentNaming
protected string serviceAccountName
{
get
{
return GetServiceAccountPart("user");
}
}
protected string serviceAccountName => GetServiceAccountPart("user");
public string ServiceAccountPassword
{
get
{
return GetServiceAccountPart("password");
}
}
public string ServiceAccountPassword => GetServiceAccountPart("password");
public string ServiceAccountUser
{
get { return (serviceAccountDomain ?? "NULL") + @"\" + (serviceAccountName ?? "NULL"); }
}
public string ServiceAccountUser => (serviceAccountDomain ?? "NULL") + @"\" + (serviceAccountName ?? "NULL");
public bool HasServiceAccount()
{
@ -793,12 +675,12 @@ namespace winsw
{
if (AllowServiceLogon != null)
{
bool parsedvalue;
if (Boolean.TryParse(AllowServiceLogon, out parsedvalue))
if (bool.TryParse(AllowServiceLogon, out bool parsedvalue))
{
return parsedvalue;
}
}
return false;
}
}
@ -806,24 +688,18 @@ namespace winsw
/// <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);
}
}
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
{
@ -25,7 +24,8 @@ namespace winsw.Util
{
var childPids = new List<int>();
try {
try
{
var searcher = new ManagementObjectSearcher("Select * From Win32_Process Where ParentProcessID=" + pid);
foreach (var mo in searcher.Get())
{
@ -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>
@ -131,7 +131,7 @@ namespace winsw.Util
/// <param name="callback">Completion callback. If null, the completion won't be monitored</param>
/// <param name="logHandler">Log handler. If enabled, logs will be redirected to the process and then reported</param>
/// <param name="redirectStdin">Redirect standard input</param>
public static void StartProcessAndCallbackForExit(Process processToStart, String executable = null, string arguments = null, Dictionary<string, string> envVars = null,
public static void StartProcessAndCallbackForExit(Process processToStart, string executable = null, string arguments = null, Dictionary<string, string> envVars = null,
string workingDirectory = null, ProcessPriorityClass? priority = null, ProcessCompletionCallback callback = null, bool redirectStdin = true, LogHandler logHandler = null, bool hideWindow = false)
{
var ps = processToStart.StartInfo;
@ -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,8 +20,9 @@ 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);
private delegate bool ConsoleCtrlDelegate(CtrlTypes CtrlType);
// Enumerated type for the control messages sent to the handler routine
private enum CtrlTypes : uint
@ -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);

View File

@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.Xml;
namespace winsw.Util
{
@ -16,10 +14,12 @@ namespace winsw.Util
/// <param name="optional">If optional, don't throw an exception if the elemen is missing</param>
/// <returns>String value or null</returns>
/// <exception cref="InvalidDataException">The required element is missing</exception>
public static string SingleElement(XmlNode node, string tagName, Boolean optional)
public static string SingleElement(XmlNode node, string tagName, bool 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);
}
@ -31,10 +31,12 @@ namespace winsw.Util
/// <param name="optional">If otional, don't throw an exception if the elemen is missing</param>
/// <returns>String value or null</returns>
/// <exception cref="InvalidDataException">The required element is missing</exception>
public static XmlNode SingleNode(XmlNode node, string tagName, Boolean optional)
public static XmlNode SingleNode(XmlNode node, string tagName, bool 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,7 +66,8 @@ 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);
@ -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);

View File

@ -1,16 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace winsw
{
public class WinSWException : Exception
{
public WinSWException(String message)
public WinSWException(string message)
: base(message)
{ }
public WinSWException(String message, Exception innerException)
public WinSWException(string message, Exception innerException)
: base(message, innerException)
{ }
}

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
@ -98,7 +99,7 @@ namespace WMI
string path;
if (machineName != null)
path = String.Format(@"\\{0}\root\cimv2", machineName);
path = string.Format(@"\\{0}\root\cimv2", machineName);
else
path = @"\root\cimv2";
scope = new ManagementScope(path, options);
@ -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
{
@ -15,7 +15,7 @@ namespace winsw.Plugins.RunawayProcessKiller
/// <summary>
/// Absolute path to the PID file, which stores ID of the previously launched process.
/// </summary>
public String Pidfile { get; private set; }
public string Pidfile { get; private set; }
/// <summary>
/// Defines the process termination timeout in milliseconds.
@ -34,9 +34,9 @@ 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; }
private string ServiceId { get; set; }
private static readonly ILog Logger = LogManager.GetLogger(typeof(RunawayProcessKillerExtension));
@ -45,7 +45,7 @@ namespace winsw.Plugins.RunawayProcessKiller
// Default initializer
}
public RunawayProcessKillerExtension(String pidfile, int stopTimeoutMs = 5000, bool stopParentFirst = false, bool checkWinSWEnvironmentVariable = true)
public RunawayProcessKillerExtension(string pidfile, int stopTimeoutMs = 5000, bool stopParentFirst = false, bool checkWinSWEnvironmentVariable = true)
{
this.Pidfile = pidfile;
this.StopTimeout = TimeSpan.FromMilliseconds(stopTimeoutMs);
@ -58,12 +58,12 @@ namespace winsw.Plugins.RunawayProcessKiller
// We expect the upper logic to process any errors
// TODO: a better parser API for types would be useful
Pidfile = XmlHelper.SingleElement(node, "pidfile", false);
StopTimeout = TimeSpan.FromMilliseconds(Int32.Parse(XmlHelper.SingleElement(node, "stopTimeout", false)));
StopParentProcessFirst = Boolean.Parse(XmlHelper.SingleElement(node, "stopParentFirst", false));
StopTimeout = TimeSpan.FromMilliseconds(int.Parse(XmlHelper.SingleElement(node, "stopTimeout", false)));
StopParentProcessFirst = bool.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;
CheckWinSWEnvironmentVariable = checkWinSWEnvironmentVariable != null ? bool.Parse(checkWinSWEnvironmentVariable) : true;
}
/// <summary>
@ -74,20 +74,22 @@ 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);
pid = int.Parse(pidstring);
}
catch (FormatException e)
{
@ -108,18 +110,18 @@ 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;
}
// Ensure the process references the service
String affiliatedServiceId;
string affiliatedServiceId;
// TODO: This method is not ideal since it works only for vars explicitly mentioned in the start info
// No Windows 10- compatible solution for EnvVars retrieval, see https://blog.gapotchenko.com/eazfuscator.net/reading-environment-variables
StringDictionary previousProcessEnvVars = proc.StartInfo.EnvironmentVariables;
String expectedEnvVarName = WinSWSystem.ENVVAR_NAME_SERVICE_ID;
string expectedEnvVarName = WinSWSystem.ENVVAR_NAME_SERVICE_ID;
if (previousProcessEnvVars.ContainsKey(expectedEnvVarName))
{
// StringDictionary is case-insensitive, hence it will fetch variable definitions in any case
@ -129,12 +131,14 @@ namespace winsw.Plugins.RunawayProcessKiller
{
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
String[] keys = new String[previousProcessEnvVars.Count];
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,7 +83,8 @@ namespace winsw.Plugins.SharedDirectoryMapper
}
}
private void HandleMappingError(SharedDirectoryMapperConfig config, MapperException ex) {
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

@ -10,8 +10,8 @@ namespace winsw.Plugins.SharedDirectoryMapper
public class SharedDirectoryMapperConfig
{
public bool EnableMapping { get; set; }
public String Label { get; set; }
public String UNCPath { get; set; }
public string Label { get; set; }
public string UNCPath { get; set; }
public SharedDirectoryMapperConfig(bool enableMapping, string label, string uncPath)
{

View File

@ -1,6 +1,5 @@
using System;
using System.Diagnostics;
using winsw.Util;
namespace winsw.Plugins.SharedDirectoryMapper
{
@ -13,7 +12,7 @@ namespace winsw.Plugins.SharedDirectoryMapper
/// <param name="command">Command to be executed</param>
/// <param name="args">Command arguments</param>
/// <exception cref="MapperException">Operation failure</exception>
private void InvokeCommand(String command, String args)
private void InvokeCommand(string command, string args)
{
Process p = new Process
{
@ -42,7 +41,7 @@ namespace winsw.Plugins.SharedDirectoryMapper
/// <param name="label">Disk label</param>
/// <param name="uncPath">UNC path to the directory</param>
/// <exception cref="MapperException">Operation failure</exception>
public void MapDirectory(String label, String uncPath)
public void MapDirectory(string label, string uncPath)
{
InvokeCommand("net.exe", " use " + label + " " + uncPath);
}
@ -52,7 +51,7 @@ namespace winsw.Plugins.SharedDirectoryMapper
/// </summary>
/// <param name="label">Disk label</param>
/// <exception cref="MapperException">Operation failure</exception>
public void UnmapDirectory(String label)
public void UnmapDirectory(string label)
{
InvokeCommand("net.exe", " use /DELETE /YES " + label);
}
@ -60,7 +59,7 @@ namespace winsw.Plugins.SharedDirectoryMapper
class MapperException : WinSWException
{
public String Call { get; private set; }
public string Call { get; private set; }
public Process Process { get; private set; }
public MapperException(Process process, string command, string args)

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));
@ -73,23 +71,23 @@ namespace winswTests
[TestCase("file:///")]
[TestCase("jar://")]
[TestCase("\\\\")] // UNC
public void ShouldReject_BasicAuth_with_UnsecureProtocol(String protocolPrefix)
public void ShouldReject_BasicAuth_with_UnsecureProtocol(string protocolPrefix)
{
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);
}
@ -129,12 +127,12 @@ namespace winswTests
[TestCase("SSPI")]
[TestCase("SsPI")]
[TestCase("Sspi")]
public void AuthType_Is_CaseInsensitive(String authType)
public void AuthType_Is_CaseInsensitive(string authType)
{
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,7 +16,7 @@ namespace winswTests.Extensions
{
ServiceDescriptor _testServiceDescriptor;
string testExtension = getExtensionClassNameWithAssembly(typeof(RunawayProcessKillerExtension));
string testExtension = GetExtensionClassNameWithAssembly(typeof(RunawayProcessKillerExtension));
[SetUp]
public void SetUp()
@ -73,7 +72,7 @@ namespace winswTests.Extensions
var tmpDir = FilesystemTestHelper.CreateTmpDirectory();
// Prepare the env var
String varName = WinSWSystem.ENVVAR_NAME_SERVICE_ID;
string varName = WinSWSystem.ENVVAR_NAME_SERVICE_ID;
var env = new Dictionary<string, string>();
env.Add(varName, winswId);

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()
{
@ -26,7 +25,7 @@ namespace winswTests
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,7 +36,7 @@ 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");

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";
@ -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()
{
@ -298,13 +297,13 @@ 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>"
@ -315,6 +314,7 @@ namespace winswTests
var serviceDescriptor = ServiceDescriptor.FromXML(seedXml);
Assert.That(serviceDescriptor.AllowServiceAcountLogonRight, Is.EqualTo(false));
}
[Test]
public void VerifyServiceLogonRightOmitted()
{
@ -438,9 +438,11 @@ namespace winswTests
public void DelayedStart_RoundTrip(bool enabled)
{
var bldr = ConfigXmlBuilder.create();
if (enabled) {
if (enabled)
{
bldr = bldr.WithDelayedAutoStart();
}
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>
@ -32,7 +33,7 @@ namespace winswTests.Util
/// <returns>STDOUT if there's no exceptions</returns>
/// <exception cref="Exception">Command failure</exception>
[NotNull]
public static string CLITest(String[] args, ServiceDescriptor descriptor = null)
public static string CLITest(string[] args, ServiceDescriptor descriptor = null)
{
using (StringWriter sw = new StringWriter())
{
@ -52,7 +53,7 @@ namespace winswTests.Util
/// <param name="descriptor">Optional Service descriptor (will be used for initializationpurposes)</param>
/// <returns>Test results</returns>
[NotNull]
public static CLITestResult CLIErrorTest(String[] args, ServiceDescriptor descriptor = null)
public static CLITestResult CLIErrorTest(string[] args, ServiceDescriptor descriptor = null)
{
StringWriter swOut, swErr;
Exception testEx = null;
@ -61,6 +62,7 @@ namespace winswTests.Util
using (swOut = new StringWriter())
using (swErr = new StringWriter())
{
try
{
Console.SetOut(swOut);
@ -85,6 +87,7 @@ namespace winswTests.Util
Console.WriteLine(testEx);
}
}
}
return new CLITestResult(swOut.ToString(), swErr.ToString(), testEx);
}
@ -96,17 +99,17 @@ namespace winswTests.Util
public class CLITestResult
{
[NotNull]
public String Out { get; private set; }
public string Out { get; private set; }
[NotNull]
public String Err { get; private set; }
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)
public CLITestResult(string output, string err, Exception exception = null)
{
Out = output;
Err = err;

View File

@ -20,7 +20,7 @@ namespace winswTests.Util
public string XMLComment { get; set; }
public List<string> ExtensionXmls { get; private set; }
private List<String> configEntries;
private List<string> configEntries;
// TODO: Switch to the initializer?
private ConfigXmlBuilder()
@ -53,16 +53,18 @@ 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);
str.AppendFormat(" <description>{0}</description>\n", Description);
str.AppendFormat(" <executable>{0}</executable>\n", Executable);
foreach (String entry in configEntries)
foreach (string entry in configEntries)
{
// We do not care much about pretty formatting here
str.AppendFormat(" {0}\n", entry);
@ -76,6 +78,7 @@ namespace winswTests.Util
{
str.Append(xml);
}
str.Append(" </extensions>\n");
}
@ -86,6 +89,7 @@ namespace winswTests.Util
Console.Out.WriteLine("Produced config:");
Console.Out.WriteLine(res);
}
return res;
}
@ -102,19 +106,19 @@ namespace winswTests.Util
public ConfigXmlBuilder WithTag(string tagName, string value)
{
return WithRawEntry(String.Format("<{0}>{1}</{0}>", tagName, 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,7 +127,7 @@ 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)
@ -131,7 +135,7 @@ namespace winswTests.Util
str.AppendFormat(" auth=\"{0}\"", download.Auth);
if (download.Auth == Download.AuthType.basic)
{
str.AppendFormat(" user=\"{0}\" password=\"{1}\"", new Object[] { download.Username, download.Password });
str.AppendFormat(" user=\"{0}\" password=\"{1}\"", new object[] { download.Username, download.Password });
}
if (download.UnsecureAuth)

View File

@ -1,13 +1,11 @@
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Text;
using System;
using NUnit.Framework;
namespace winswTests.Util
{
class ExceptionHelper
{
public static void assertFails(String expectedMessagePart, Type expectedExceptionType, ExceptionHelperExecutionBody body)
public static void assertFails(string expectedMessagePart, Type expectedExceptionType, ExceptionHelperExecutionBody body)
{
try
{
@ -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
{
@ -12,9 +11,9 @@ namespace winswTests.Util
/// Creates a temporary directory for testing.
/// </summary>
/// <returns>tmp Dir</returns>
public static string CreateTmpDirectory(String testName = null)
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.Diagnostics;
using NUnit.Framework;
using winsw;
using System.IO;
using winsw.Util;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using NUnit.Framework;
using winsw.Util;
namespace winswTests.Util
{
[TestFixture]
class ProcessHelperTest
{
@ -21,11 +19,10 @@ namespace winswTests.Util
Environment.SetEnvironmentVariable("TEST_KEY", "TEST_VALUE");
var tmpDir = FilesystemTestHelper.CreateTmpDirectory();
String envFile = Path.Combine(tmpDir, "env.properties");
String scriptFile = Path.Combine(tmpDir, "printenv.bat");
string envFile = Path.Combine(tmpDir, "env.properties");
string scriptFile = Path.Combine(tmpDir, "printenv.bat");
File.WriteAllText(scriptFile, "set > " + envFile);
Process proc = new Process();
var ps = proc.StartInfo;
ps.FileName = scriptFile;
@ -39,9 +36,9 @@ namespace winswTests.Util
// Check several veriables, which are expected to be in Uppercase
var envVars = FilesystemTestHelper.parseSetOutput(envFile);
String[] keys = new String[envVars.Count];
string[] keys = new string[envVars.Count];
envVars.Keys.CopyTo(keys, 0);
String availableVars = "[" + String.Join(",", keys) + "]";
String availableVars = "[" + string.Join(",", keys) + "]";
Assert.That(envVars.ContainsKey("TEST_KEY"), "No TEST_KEY in the injected vars: " + availableVars);
// And just ensure that the parsing logic is case-sensitive
@ -53,8 +50,8 @@ namespace winswTests.Util
public void ShouldNotHangWhenWritingLargeStringToStdOut()
{
var tmpDir = FilesystemTestHelper.CreateTmpDirectory();
String scriptFile = Path.Combine(tmpDir, "print_lots_to_stdout.bat");
var lotsOfStdOut = string.Join("", _Range(1,1000));
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();
@ -72,10 +69,11 @@ namespace winswTests.Util
private string[] _Range(int start, int limit)
{
var range = new List<string>();
for(var i = start; i<limit; i++)
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;
@ -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
}
}
}
}