From 49df1746174cbf5791f92423540de9b3d79eb072 Mon Sep 17 00:00:00 2001 From: David Schmitt Date: Tue, 29 Dec 2009 12:15:39 +0100 Subject: [PATCH] Implement process priority property on exec tasks --- UnitTests/Core/Tasks/ExecutableTaskTest.cs | 4 +++ UnitTests/Core/Tasks/MsBuildTaskTest.cs | 5 +++- UnitTests/Core/Util/ProcessExecutorTest.cs | 8 +++--- UnitTests/Core/Util/ProcessInfoTest.cs | 2 +- core/sourcecontrol/RobocopySourceControl.cs | 5 ++- core/tasks/BaseExecutableTask.cs | 4 ++- core/tasks/DevenvTask.cs | 12 ++++++++++- core/tasks/DupFinderTask.cs | 28 +++++++++++++++++++++++++- core/tasks/ExecutableTask.cs | 16 ++++++++++++++- core/tasks/GendarmeTask.cs | 15 ++++++++++++++ core/tasks/MsBuildTask.cs | 24 +++++++++++++++++++++- core/tasks/NAntTask.cs | 17 ++++++++++++++++ core/tasks/NCoverProfileTask.cs | 23 +++++++++++++++++++++- core/tasks/NCoverReportTask.cs | 23 +++++++++++++++++++++- core/tasks/NDependTask.cs | 26 ++++++++++++++++++++++++- core/tasks/NUnitTask.cs | 13 +++++++++++- core/tasks/PowerShellTask.cs | 11 +++++++++- core/tasks/RakeTask.cs | 15 ++++++++++++++ core/util/ProcessExecutor.cs | 24 ++++++++++++++++++++++- core/util/ProcessInfo.cs | 15 ++++++++++--- 20 files changed, 265 insertions(+), 25 deletions(-) diff --git a/UnitTests/Core/Tasks/ExecutableTaskTest.cs b/UnitTests/Core/Tasks/ExecutableTaskTest.cs index 056791a..9d19fb5 100644 --- a/UnitTests/Core/Tasks/ExecutableTaskTest.cs +++ b/UnitTests/Core/Tasks/ExecutableTaskTest.cs @@ -1,3 +1,4 @@ +using System.Diagnostics; using System.IO; using Exortech.NetReflector; using NMock.Constraints; @@ -42,6 +43,7 @@ namespace ThoughtWorks.CruiseControl.UnitTests.Core.Tasks name2 value3 + BelowNormal 0,1,3,5 "; @@ -58,6 +60,7 @@ namespace ThoughtWorks.CruiseControl.UnitTests.Core.Tasks Assert.AreEqual("name3", task.EnvironmentVariables[2].name, "Checking name3 environment variable."); Assert.AreEqual("value3", task.EnvironmentVariables[2].value, "Checking name3 environment value."); Assert.AreEqual("0,1,3,5", task.SuccessExitCodes); + Assert.AreEqual(ProcessPriorityClass.BelowNormal, task.Priority); Verify(); } @@ -75,6 +78,7 @@ namespace ThoughtWorks.CruiseControl.UnitTests.Core.Tasks Assert.AreEqual("", task.BuildArgs, "Checking BuildArgs property."); Assert.AreEqual(0, task.EnvironmentVariables.Length, "Checking environment variable array size."); Assert.AreEqual("", task.SuccessExitCodes); + Assert.AreEqual(ProcessPriorityClass.Normal, task.Priority); Verify(); } diff --git a/UnitTests/Core/Tasks/MsBuildTaskTest.cs b/UnitTests/Core/Tasks/MsBuildTaskTest.cs index 797e697..3d93906 100644 --- a/UnitTests/Core/Tasks/MsBuildTaskTest.cs +++ b/UnitTests/Core/Tasks/MsBuildTaskTest.cs @@ -1,12 +1,13 @@ +using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using Exortech.NetReflector; using NUnit.Framework; +using Rhino.Mocks; using ThoughtWorks.CruiseControl.Core; using ThoughtWorks.CruiseControl.Core.Tasks; using ThoughtWorks.CruiseControl.Core.Util; using ThoughtWorks.CruiseControl.Remote; -using Rhino.Mocks; namespace ThoughtWorks.CruiseControl.UnitTests.Core.Tasks { @@ -178,6 +179,7 @@ namespace ThoughtWorks.CruiseControl.UnitTests.Core.Tasks Build;Test 15 Kobush.Build.Logging.XmlLogger,Kobush.MSBuild.dll;buildresult.xml + BelowNormal "; task = (MsBuildTask) NetReflector.Read(xml); Assert.AreEqual(@"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50215\MSBuild.exe", task.Executable); @@ -187,6 +189,7 @@ namespace ThoughtWorks.CruiseControl.UnitTests.Core.Tasks Assert.AreEqual("/p:Configuration=Debug /v:diag", task.BuildArgs); Assert.AreEqual(15, task.Timeout); Assert.AreEqual("Kobush.Build.Logging.XmlLogger,Kobush.MSBuild.dll;buildresult.xml", task.Logger); + Assert.AreEqual(ProcessPriorityClass.BelowNormal, task.Priority); } [Test] diff --git a/UnitTests/Core/Util/ProcessExecutorTest.cs b/UnitTests/Core/Util/ProcessExecutorTest.cs index b9f57fb..d9f954a 100644 --- a/UnitTests/Core/Util/ProcessExecutorTest.cs +++ b/UnitTests/Core/Util/ProcessExecutorTest.cs @@ -184,28 +184,28 @@ namespace ThoughtWorks.CruiseControl.UnitTests.Core.Util { int[] successExitCodes = { 1, 3, 5 }; - ProcessInfo processInfo1 = new ProcessInfo("cmd.exe", "/C @echo Hello World & exit 1", null, successExitCodes); + ProcessInfo processInfo1 = new ProcessInfo("cmd.exe", "/C @echo Hello World & exit 1", null, ProcessPriorityClass.AboveNormal, successExitCodes); ProcessResult result1 = executor.Execute(processInfo1); Assert.AreEqual("Hello World", result1.StandardOutput.Trim()); Assert.AreEqual(1, result1.ExitCode, "Process did not exit successfully"); AssertFalse("process should not return an error", result1.Failed); - ProcessInfo processInfo2 = new ProcessInfo("cmd.exe", "/C @echo Hello World & exit 3", null, successExitCodes); + ProcessInfo processInfo2 = new ProcessInfo("cmd.exe", "/C @echo Hello World & exit 3", null, ProcessPriorityClass.AboveNormal, successExitCodes); ProcessResult result2 = executor.Execute(processInfo2); Assert.AreEqual("Hello World", result2.StandardOutput.Trim()); Assert.AreEqual(3, result2.ExitCode, "Process did not exit successfully"); AssertFalse("process should not return an error", result2.Failed); - ProcessInfo processInfo3 = new ProcessInfo("cmd.exe", "/C @echo Hello World & exit 5", null, successExitCodes); + ProcessInfo processInfo3 = new ProcessInfo("cmd.exe", "/C @echo Hello World & exit 5", null, ProcessPriorityClass.AboveNormal, successExitCodes); ProcessResult result3 = executor.Execute(processInfo3); Assert.AreEqual("Hello World", result3.StandardOutput.Trim()); Assert.AreEqual(5, result3.ExitCode, "Process did not exit successfully"); AssertFalse("process should not return an error", result3.Failed); - ProcessInfo processInfo4 = new ProcessInfo("cmd.exe", "/C @echo Hello World", null, successExitCodes); + ProcessInfo processInfo4 = new ProcessInfo("cmd.exe", "/C @echo Hello World", null, ProcessPriorityClass.AboveNormal, successExitCodes); ProcessResult result4 = executor.Execute(processInfo4); Assert.AreEqual("Hello World", result4.StandardOutput.Trim()); diff --git a/UnitTests/Core/Util/ProcessInfoTest.cs b/UnitTests/Core/Util/ProcessInfoTest.cs index d1fafe3..d27f346 100644 --- a/UnitTests/Core/Util/ProcessInfoTest.cs +++ b/UnitTests/Core/Util/ProcessInfoTest.cs @@ -52,7 +52,7 @@ namespace ThoughtWorks.CruiseControl.UnitTests.Core.Util { int[] successExitCodes = { 1, 3, 5 }; - ProcessInfo info = new ProcessInfo(@"""c:\nant\nant.exe""", null, string.Format(@"""{0}""", Path.GetTempPath()), successExitCodes); + ProcessInfo info = new ProcessInfo(@"""c:\nant\nant.exe""", null, string.Format(@"""{0}""", Path.GetTempPath()), ProcessPriorityClass.Normal, successExitCodes); Assert.IsFalse(info.ProcessSuccessful(0)); Assert.IsTrue(info.ProcessSuccessful(1)); diff --git a/core/sourcecontrol/RobocopySourceControl.cs b/core/sourcecontrol/RobocopySourceControl.cs index de81703..851294c 100644 --- a/core/sourcecontrol/RobocopySourceControl.cs +++ b/core/sourcecontrol/RobocopySourceControl.cs @@ -1,3 +1,4 @@ +using System.Diagnostics; using Exortech.NetReflector; using ThoughtWorks.CruiseControl.Core.Util; @@ -97,7 +98,7 @@ namespace ThoughtWorks.CruiseControl.Core.Sourcecontrol builder.AddArgument("/L"); - Modification[] modifications = GetModifications(new ProcessInfo(Executable, builder.ToString(), null, successExitCodes), from.StartTime, to.StartTime); + Modification[] modifications = GetModifications(new ProcessInfo(Executable, builder.ToString(), null, ProcessPriorityClass.Normal, successExitCodes), from.StartTime, to.StartTime); return modifications; } @@ -115,7 +116,7 @@ namespace ThoughtWorks.CruiseControl.Core.Sourcecontrol AddStandardArguments(builder, destinationDirectory); - Execute(new ProcessInfo(Executable, builder.ToString(), null, successExitCodes)); + Execute(new ProcessInfo(Executable, builder.ToString(), null, ProcessPriorityClass.Normal, successExitCodes)); } } diff --git a/core/tasks/BaseExecutableTask.cs b/core/tasks/BaseExecutableTask.cs index 2f80361..5f09927 100644 --- a/core/tasks/BaseExecutableTask.cs +++ b/core/tasks/BaseExecutableTask.cs @@ -1,4 +1,5 @@ using System.Collections; +using System.Diagnostics; using System.IO; using ThoughtWorks.CruiseControl.Core.Util; @@ -12,6 +13,7 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks protected abstract string GetProcessFilename(); protected abstract string GetProcessArguments(IIntegrationResult result); protected abstract string GetProcessBaseDirectory(IIntegrationResult result); + protected abstract ProcessPriorityClass GetProcessPriorityClass(); protected abstract int GetProcessTimeout(); protected virtual int[] GetProcessSuccessCodes() @@ -21,7 +23,7 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks protected virtual ProcessInfo CreateProcessInfo(IIntegrationResult result) { - ProcessInfo info = new ProcessInfo(GetProcessFilename(), GetProcessArguments(result), GetProcessBaseDirectory(result), GetProcessSuccessCodes()); + ProcessInfo info = new ProcessInfo(GetProcessFilename(), GetProcessArguments(result), GetProcessBaseDirectory(result),GetProcessPriorityClass(), GetProcessSuccessCodes()); info.TimeOut = GetProcessTimeout(); IDictionary properties = result.IntegrationProperties; diff --git a/core/tasks/DevenvTask.cs b/core/tasks/DevenvTask.cs index ff876d0..d3c8def 100644 --- a/core/tasks/DevenvTask.cs +++ b/core/tasks/DevenvTask.cs @@ -2,6 +2,7 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks { using System; using System.Collections; + using System.Diagnostics; using System.IO; using System.Text; using Exortech.NetReflector; @@ -61,6 +62,7 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks public const int DEFAULT_BUILD_TIMEOUT = 600; public const string DEFAULT_BUILDTYPE = "rebuild"; public const string DEFAULT_PROJECT = ""; + public const ProcessPriorityClass DEFAULT_PRIORITY = ProcessPriorityClass.Normal; private readonly IRegistry registry; private readonly ProcessExecutor executor; @@ -231,6 +233,14 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks [ReflectorProperty("project", Required = false)] public string Project = DEFAULT_PROJECT; + /// + /// The priority class of the spawned process. + /// + /// 1.5 + /// Normal + [ReflectorProperty("priority", Required = false)] + public ProcessPriorityClass Priority = DEFAULT_PRIORITY; + protected override bool Execute(IIntegrationResult result) { result.BuildProgressInformation.SignalStartRunTask(!string.IsNullOrEmpty(Description) ? Description : string.Format("Executing Devenv :{0}", GetArguments())); @@ -246,7 +256,7 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks private ProcessResult TryToRun(IIntegrationResult result) { - ProcessInfo processInfo = new ProcessInfo(Executable, GetArguments(), result.WorkingDirectory); + ProcessInfo processInfo = new ProcessInfo(Executable, GetArguments(), result.WorkingDirectory, Priority); processInfo.TimeOut = BuildTimeoutSeconds * 1000; IDictionary properties = result.IntegrationProperties; diff --git a/core/tasks/DupFinderTask.cs b/core/tasks/DupFinderTask.cs index 9a30e24..fce6d66 100644 --- a/core/tasks/DupFinderTask.cs +++ b/core/tasks/DupFinderTask.cs @@ -7,12 +7,13 @@ using System; namespace ThoughtWorks.CruiseControl.Core.Tasks { + using System.Collections.Generic; + using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; + using System.Xml; using Exortech.NetReflector; using ThoughtWorks.CruiseControl.Core.Util; - using System.Xml; - using System.Collections.Generic; /// /// @@ -69,6 +70,9 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks #region Private consts [SuppressMessage("Microsoft.StyleCop.CSharp.DocumentationRules", "SA1600:ElementsMustBeDocumented", Justification = "Private constant")] private const string DefaultExecutable = "dupfinder"; + + /// Default priority class + private const ProcessPriorityClass DefaultPriority = ProcessPriorityClass.Normal; #endregion #region Private fields @@ -109,6 +113,16 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks public string Executable { get; set; } #endregion + #region Priority + /// + /// The priority class of the spawned process. + /// + /// 1.5 + /// Normal + [ReflectorProperty("priority", Required = false)] + public ProcessPriorityClass Priority = ProcessPriorityClass.Normal; + #endregion + #region InputDir /// /// The input directory to scan. If relative, this will be relative to the project working directory. @@ -369,6 +383,16 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks } #endregion + #region GetProcessPriorityClass() + /// + /// Gets the requested priority class value for this Task. + /// + protected override ProcessPriorityClass GetProcessPriorityClass() + { + return this.Priority; + } + #endregion + #region RemoveInputDir() /// /// Removes the input directory from the filenames. diff --git a/core/tasks/ExecutableTask.cs b/core/tasks/ExecutableTask.cs index 35a3be8..1dc9011 100644 --- a/core/tasks/ExecutableTask.cs +++ b/core/tasks/ExecutableTask.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; +using System.Diagnostics; using Exortech.NetReflector; using ThoughtWorks.CruiseControl.Core.Util; -using System.Diagnostics; namespace ThoughtWorks.CruiseControl.Core.Tasks { @@ -82,6 +82,7 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks : BaseExecutableTask { public const int DEFAULT_BUILD_TIMEOUT = 600; + public const ProcessPriorityClass DEFAULT_PRIORITY = ProcessPriorityClass.Normal; public ExecutableTask() : this(new ProcessExecutor()) {} @@ -102,6 +103,14 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks public string Executable = string.Empty; /// + /// The priority class of the spawned process. + /// + /// 1.5 + /// Normal + [ReflectorProperty("priority", Required = false)] + public ProcessPriorityClass Priority = DEFAULT_PRIORITY; + + /// /// The directory to run the process in. If relative, is a subdirectory of the Project Working /// Directory. /// @@ -239,6 +248,11 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks return BuildTimeoutSeconds*1000; } + protected override ProcessPriorityClass GetProcessPriorityClass() + { + return this.Priority; + } + public override string ToString() { return string.Format(@" BaseDirectory: {0}, Executable: {1}", ConfiguredBaseDirectory, Executable); diff --git a/core/tasks/GendarmeTask.cs b/core/tasks/GendarmeTask.cs index 8a6525a..e21d490 100644 --- a/core/tasks/GendarmeTask.cs +++ b/core/tasks/GendarmeTask.cs @@ -1,3 +1,4 @@ +using System.Diagnostics; using System.IO; using System.Text; using Exortech.NetReflector; @@ -56,6 +57,7 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks public const bool defaultVerbose = false; public const bool defaultFailBuildOnFoundDefects = false; public const int defaultVerifyTimeout = 0; + public const ProcessPriorityClass defaultPriority = ProcessPriorityClass.Normal; private readonly IFileDirectoryDeleter fileDirectoryDeleter = new IoService(); @@ -86,6 +88,14 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks public string ConfiguredBaseDirectory = string.Empty; /// + /// The priority class of the spawned process. + /// + /// 1.5 + /// Normal + [ReflectorProperty("priority", Required = false)] + public ProcessPriorityClass Priority = defaultPriority; + + /// /// Specify the configuration file. /// /// 1.4.3 @@ -238,6 +248,11 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks return VerifyTimeoutSeconds * 1000; } + protected override ProcessPriorityClass GetProcessPriorityClass() + { + return this.Priority; + } + protected override bool Execute(IIntegrationResult result) { string gendarmeOutputFile = GetGendarmeOutputFile(result); diff --git a/core/tasks/MsBuildTask.cs b/core/tasks/MsBuildTask.cs index aec661d..201cdbf 100644 --- a/core/tasks/MsBuildTask.cs +++ b/core/tasks/MsBuildTask.cs @@ -1,12 +1,13 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks { + using System; using System.Collections; + using System.Diagnostics; using System.IO; + using System.Reflection; using System.Text; using Exortech.NetReflector; using ThoughtWorks.CruiseControl.Core.Util; - using System.Reflection; - using System; /// /// @@ -136,6 +137,17 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks [ReflectorProperty("timeout", Required = false)] public int Timeout = DefaultTimeout; #endregion + + #region Priority + /// + /// The priority class of the spawned process. + /// + /// 1.5 + /// Normal + [ReflectorProperty("priority", Required = false)] + public string Priority = ProcessPriorityClass.Normal.ToString(); + #endregion + #endregion protected override string GetProcessFilename() @@ -179,6 +191,14 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks return Timeout * 1000; } + /// + /// Gets the requested priority class value for this Task. + /// + protected override ProcessPriorityClass GetProcessPriorityClass() + { + return (ProcessPriorityClass)Enum.Parse(typeof(ProcessPriorityClass), this.Priority); + } + protected override bool Execute(IIntegrationResult result) { result.BuildProgressInformation.SignalStartRunTask(!string.IsNullOrEmpty(Description) ? Description : diff --git a/core/tasks/NAntTask.cs b/core/tasks/NAntTask.cs index 8612ce8..1ece0f3 100644 --- a/core/tasks/NAntTask.cs +++ b/core/tasks/NAntTask.cs @@ -1,5 +1,6 @@ using System; using System.Collections; +using System.Diagnostics; using System.IO; using Exortech.NetReflector; using ThoughtWorks.CruiseControl.Core.Util; @@ -119,6 +120,7 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks public const string DefaultLogger = "NAnt.Core.XmlLogger"; public const string DefaultListener = "NAnt.Core.DefaultLogger"; public const bool DefaultNoLogo = true; + public const ProcessPriorityClass DefaultPriority = ProcessPriorityClass.Normal; private readonly IFileDirectoryDeleter fileDirectoryDeleter = new IoService(); @@ -154,6 +156,16 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks public string Executable = defaultExecutable; #endregion + #region Priority + /// + /// The priority class of the spawned process. + /// + /// 1.5 + /// Normal + [ReflectorProperty("priority", Required = false)] + public ProcessPriorityClass Priority = DefaultPriority; + #endregion + #region BuildFile /// /// The name of the build file to run, relative to the baseDirectory. @@ -284,6 +296,11 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks return result.BaseFromWorkingDirectory(ConfiguredBaseDirectory); } + protected override ProcessPriorityClass GetProcessPriorityClass() + { + return this.Priority; + } + private static void AppendIntegrationResultProperties(ProcessArgumentBuilder buffer, IIntegrationResult result) { // We have to sort this alphabetically, else the unit tests diff --git a/core/tasks/NCoverProfileTask.cs b/core/tasks/NCoverProfileTask.cs index 41262d4..8536c34 100644 --- a/core/tasks/NCoverProfileTask.cs +++ b/core/tasks/NCoverProfileTask.cs @@ -1,9 +1,10 @@ using System; using System.Collections.Generic; +using System.Diagnostics; +using System.IO; using System.Text; using Exortech.NetReflector; using ThoughtWorks.CruiseControl.Core.Util; -using System.IO; namespace ThoughtWorks.CruiseControl.Core.Tasks { @@ -114,6 +115,16 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks public string Executable { get; set; } #endregion + #region Priority + /// + /// The priority class of the spawned process. + /// + /// 1.5 + /// Normal + [ReflectorProperty("priority", Required = false)] + public ProcessPriorityClass Priority = ProcessPriorityClass.Normal; + #endregion + #region TimeOut /// /// The time-out period in seconds. If the task does no finish running in this time it will be terminated. @@ -613,6 +624,16 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks return buffer.ToString(); } #endregion + + #region GetProcessPriorityClass() + /// + /// Gets the requested priority class value for this Task. + /// + protected override ProcessPriorityClass GetProcessPriorityClass() + { + return this.Priority; + } + #endregion #endregion #region Private methods diff --git a/core/tasks/NCoverReportTask.cs b/core/tasks/NCoverReportTask.cs index 3a2d9c9..b7f4c06 100644 --- a/core/tasks/NCoverReportTask.cs +++ b/core/tasks/NCoverReportTask.cs @@ -1,9 +1,10 @@ using System; using System.Collections.Generic; +using System.Diagnostics; +using System.IO; using System.Text; using Exortech.NetReflector; using ThoughtWorks.CruiseControl.Core.Util; -using System.IO; namespace ThoughtWorks.CruiseControl.Core.Tasks { @@ -122,6 +123,16 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks public string WorkingDirectory { get; set; } #endregion + #region Priority + /// + /// The priority class of the spawned process. + /// + /// 1.5 + /// Normal + [ReflectorProperty("priority", Required = false)] + public ProcessPriorityClass Priority = ProcessPriorityClass.Normal; + #endregion + #region CoverageFile /// /// The location to read the coverage date from. If relative, this will be relative to baseDir. @@ -499,6 +510,16 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks return buffer.ToString(); } #endregion + + #region GetProcessPriorityClass() + /// + /// Gets the requested priority class value for this Task. + /// + protected override ProcessPriorityClass GetProcessPriorityClass() + { + return this.Priority; + } + #endregion #endregion #region Private methods diff --git a/core/tasks/NDependTask.cs b/core/tasks/NDependTask.cs index d750cb8..afc87d9 100644 --- a/core/tasks/NDependTask.cs +++ b/core/tasks/NDependTask.cs @@ -1,9 +1,10 @@ using System; using System.Collections.Generic; +using System.Diagnostics; +using System.IO; using System.Text; using Exortech.NetReflector; using ThoughtWorks.CruiseControl.Core.Util; -using System.IO; namespace ThoughtWorks.CruiseControl.Core.Tasks { @@ -79,6 +80,9 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks { #region Private consts private const string defaultExecutable = "NDepend.Console"; + + /// Default priority class + private const ProcessPriorityClass DefaultPriority = ProcessPriorityClass.Normal; #endregion #region Private fields @@ -131,6 +135,16 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks public string Executable { get; set; } #endregion + #region Priority + /// + /// The priority class of the spawned process. + /// + /// 1.5 + /// Normal + [ReflectorProperty("priority", Required = false)] + public ProcessPriorityClass Priority = ProcessPriorityClass.Normal; + #endregion + #region EmitXml /// /// Whether to emit the XML report data or not. @@ -358,6 +372,16 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks return buffer.ToString(); } #endregion + + #region GetProcessPriorityClass() + /// + /// Gets the requested priority class value for this Task. + /// + protected override ProcessPriorityClass GetProcessPriorityClass() + { + return this.Priority; + } + #endregion #endregion #region Private methods diff --git a/core/tasks/NUnitTask.cs b/core/tasks/NUnitTask.cs index 15ada36..e16ff3a 100644 --- a/core/tasks/NUnitTask.cs +++ b/core/tasks/NUnitTask.cs @@ -1,3 +1,4 @@ +using System.Diagnostics; using System.IO; using Exortech.NetReflector; using ThoughtWorks.CruiseControl.Core.Util; @@ -101,6 +102,16 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks public int Timeout = DefaultTimeout; #endregion + #region Priority + /// + /// The priority class of the spawned process. + /// + /// 1.5 + /// Normal + [ReflectorProperty("priority", Required = false)] + public ProcessPriorityClass Priority = ProcessPriorityClass.Normal; + #endregion + #region ExcludedCategories /// /// List of the test categories to be excluded from the NUnit run. The tests need to have the CategoryAttribute set. @@ -150,7 +161,7 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks Log.Debug(string.Format("Running unit tests: {0} {1}", NUnitPath, args)); - ProcessInfo info = new ProcessInfo(NUnitPath, args, result.WorkingDirectory); + ProcessInfo info = new ProcessInfo(NUnitPath, args, result.WorkingDirectory, Priority); info.TimeOut = Timeout * 1000; return info; } diff --git a/core/tasks/PowerShellTask.cs b/core/tasks/PowerShellTask.cs index 9900a5b..4c22940 100644 --- a/core/tasks/PowerShellTask.cs +++ b/core/tasks/PowerShellTask.cs @@ -3,6 +3,7 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks using System; using System.Collections; using System.Collections.Specialized; + using System.Diagnostics; using System.IO; using System.Text; using System.Text.RegularExpressions; @@ -92,6 +93,14 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks } /// + /// The priority class of the spawned process. + /// + /// 1.5 + /// Normal + [ReflectorProperty("priority", Required = false)] + public ProcessPriorityClass Priority = ProcessPriorityClass.Normal; + + /// /// The directory that the PowerShell scripts are stored in. /// /// 1.5 @@ -206,7 +215,7 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks private ProcessInfo NewProcessInfoFrom(IIntegrationResult result) { - ProcessInfo info = new ProcessInfo( executable, Args(result), BaseDirectory(result), successExitCodes); + ProcessInfo info = new ProcessInfo( executable, Args(result), BaseDirectory(result), this.Priority, successExitCodes); info.TimeOut = BuildTimeoutSeconds*1000; SetConfiguredEnvironmentVariables(info.EnvironmentVariables, this.EnvironmentVariables); IDictionary properties = result.IntegrationProperties; diff --git a/core/tasks/RakeTask.cs b/core/tasks/RakeTask.cs index 542b2da..c4324a6 100644 --- a/core/tasks/RakeTask.cs +++ b/core/tasks/RakeTask.cs @@ -1,5 +1,6 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks { + using System.Diagnostics; using Exortech.NetReflector; using ThoughtWorks.CruiseControl.Core.Util; @@ -61,6 +62,7 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks { public const int DefaultBuildTimeout = 600; public const string DefaultExecutable = @"rake"; + public const ProcessPriorityClass DefaultPriority = ProcessPriorityClass.Normal; /// /// Any arguments to pass through to Rake (e.g to specify build properties). @@ -105,6 +107,14 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks public string Executable = DefaultExecutable; /// + /// The priority class of the spawned process. + /// + /// 1.5 + /// Normal + [ReflectorProperty("priority", Required = false)] + public ProcessPriorityClass Priority = DefaultPriority; + + /// /// The name of the Rakefile to run, relative to the baseDirectory. /// /// None @@ -215,6 +225,11 @@ namespace ThoughtWorks.CruiseControl.Core.Tasks return Executable; } + protected override ProcessPriorityClass GetProcessPriorityClass() + { + return this.Priority; + } + public string TargetsForPresentation { get diff --git a/core/util/ProcessExecutor.cs b/core/util/ProcessExecutor.cs index 99d90e8..e5bc50d 100644 --- a/core/util/ProcessExecutor.cs +++ b/core/util/ProcessExecutor.cs @@ -142,14 +142,36 @@ namespace ThoughtWorks.CruiseControl.Core.Util process.EnableRaisingEvents = true; supervisingThread = Thread.CurrentThread; + string filename = Path.Combine(process.StartInfo.WorkingDirectory, process.StartInfo.FileName); + try { bool isNewProcess = process.Start(); if (!isNewProcess) Log.Warning("Reusing existing process..."); + + // avoid useless setting of the default + if (processInfo.Priority != System.Diagnostics.Process.GetCurrentProcess().PriorityClass) + { + try + { + Log.Debug(string.Format("Setting PriorityClass on [{0}] to {1}", filename, processInfo.Priority)); + process.PriorityClass = processInfo.Priority; + } + catch (Exception ex) + { + if (!process.HasExited) + { + Log.Info(string.Format("Unable to set PriorityClass on [{0}]: {1}", filename, ex.ToString())); + } + } + } + else + { + Log.Debug(string.Format("Not setting PriorityClass on [{0}] to default {1}", filename, processInfo.Priority)); + } } catch (Win32Exception e) { - string filename = Path.Combine(process.StartInfo.WorkingDirectory, process.StartInfo.FileName); string msg = string.Format("Unable to execute file [{0}]. The file may not exist or may not be executable.", filename); throw new IOException(msg, e); } diff --git a/core/util/ProcessInfo.cs b/core/util/ProcessInfo.cs index ab08024..651389b 100644 --- a/core/util/ProcessInfo.cs +++ b/core/util/ProcessInfo.cs @@ -11,6 +11,9 @@ namespace ThoughtWorks.CruiseControl.Core.Util public const int DefaultTimeout = 120000; public const int InfiniteTimeout = 0; + public const ProcessPriorityClass DEFAULT_PRIORITY = ProcessPriorityClass.Normal; + public ProcessPriorityClass Priority; + private readonly PrivateArguments arguments; private readonly ProcessStartInfo startInfo = new ProcessStartInfo(); private string standardInputContent; @@ -19,17 +22,21 @@ namespace ThoughtWorks.CruiseControl.Core.Util private readonly int[] successExitCodes; public ProcessInfo(string filename) : - this(filename, null, null, null){} + this(filename, null){} public ProcessInfo(string filename, PrivateArguments arguments) : - this(filename, arguments, null, null){} + this(filename, arguments, null){} public ProcessInfo(string filename, PrivateArguments arguments, string workingDirectory) : - this(filename, arguments, workingDirectory, null){} + this(filename, arguments, workingDirectory, DEFAULT_PRIORITY){} + + public ProcessInfo(string filename, PrivateArguments arguments, string workingDirectory, ProcessPriorityClass priority) : + this(filename, arguments, workingDirectory, priority, null){} - public ProcessInfo(string filename, PrivateArguments arguments, string workingDirectory, int[] successExitCodes) + public ProcessInfo(string filename, PrivateArguments arguments, string workingDirectory, ProcessPriorityClass priority, int[] successExitCodes) { this.arguments = arguments; + this.Priority = priority; startInfo.FileName = StringUtil.StripQuotes(filename); startInfo.Arguments = arguments == null ? null : arguments.ToString(SecureDataMode.Private); startInfo.WorkingDirectory = StringUtil.StripQuotes(workingDirectory); -- 1.6.4.msysgit.0