зеркало из https://github.com/microsoft/PSRule.git
Code quality updates (#533)
This commit is contained in:
Родитель
a1ea08f10e
Коммит
76b184999e
|
@ -0,0 +1,24 @@
|
|||
``` ini
|
||||
|
||||
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.18363.778 (1909/November2018Update/19H2)
|
||||
Intel Core i7-6600U CPU 2.60GHz (Skylake), 1 CPU, 4 logical and 2 physical cores
|
||||
.NET Core SDK=3.1.201
|
||||
[Host] : .NET Core 2.1.17 (CoreCLR 4.6.28619.01, CoreFX 4.6.28619.01), X64 RyuJIT
|
||||
DefaultJob : .NET Core 2.1.17 (CoreCLR 4.6.28619.01, CoreFX 4.6.28619.01), X64 RyuJIT
|
||||
|
||||
|
||||
```
|
||||
| Method | Mean | Error | StdDev | Median | Gen 0 | Gen 1 | Gen 2 | Allocated |
|
||||
|------------------------- |-----------:|----------:|----------:|-----------:|-----------:|------:|------:|------------:|
|
||||
| Invoke | 111.140 ms | 2.1935 ms | 4.5786 ms | 109.312 ms | 8200.0000 | - | - | 16839.42 KB |
|
||||
| InvokeIf | 117.141 ms | 2.2703 ms | 2.2298 ms | 116.398 ms | 9600.0000 | - | - | 19980.62 KB |
|
||||
| InvokeType | 108.648 ms | 0.7983 ms | 0.7467 ms | 108.584 ms | 8200.0000 | - | - | 16870.67 KB |
|
||||
| InvokeSummary | 107.300 ms | 0.8612 ms | 0.8056 ms | 107.115 ms | 8000.0000 | - | - | 16784.76 KB |
|
||||
| Get | 9.003 ms | 0.0643 ms | 0.0602 ms | 9.010 ms | 140.6250 | - | - | 307.96 KB |
|
||||
| GetHelp | 8.902 ms | 0.0831 ms | 0.0649 ms | 8.899 ms | 140.6250 | - | - | 306.34 KB |
|
||||
| Within | 179.522 ms | 1.5483 ms | 1.4483 ms | 179.981 ms | 15666.6667 | - | - | 32400.38 KB |
|
||||
| WithinBulk | 247.883 ms | 2.6279 ms | 2.1944 ms | 248.124 ms | 28500.0000 | - | - | 59306.73 KB |
|
||||
| WithinLike | 238.815 ms | 2.5538 ms | 1.9939 ms | 239.245 ms | 29333.3333 | - | - | 60580.58 KB |
|
||||
| DefaultTargetNameBinding | 2.124 ms | 0.0214 ms | 0.0200 ms | 2.129 ms | 85.9375 | - | - | 179.69 KB |
|
||||
| CustomTargetNameBinding | 2.463 ms | 0.0483 ms | 0.0452 ms | 2.458 ms | 179.6875 | - | - | 375 KB |
|
||||
| NestedTargetNameBinding | 2.433 ms | 0.0370 ms | 0.0328 ms | 2.420 ms | 179.6875 | - | - | 375 KB |
|
|
@ -0,0 +1,24 @@
|
|||
``` ini
|
||||
|
||||
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.450 (2004/?/20H1)
|
||||
Intel Core i7-1065G7 CPU 1.30GHz, 1 CPU, 8 logical and 4 physical cores
|
||||
.NET Core SDK=3.1.401
|
||||
[Host] : .NET Core 3.1.7 (CoreCLR 4.700.20.36602, CoreFX 4.700.20.37001), X64 RyuJIT
|
||||
DefaultJob : .NET Core 3.1.7 (CoreCLR 4.700.20.36602, CoreFX 4.700.20.37001), X64 RyuJIT
|
||||
|
||||
|
||||
```
|
||||
| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|
||||
|------------------------- |-------------:|------------:|------------:|-----------:|---------:|------:|------------:|
|
||||
| Invoke | 40,943.5 μs | 581.23 μs | 515.25 μs | 4000.0000 | 500.0000 | - | 16452.28 KB |
|
||||
| InvokeIf | 42,806.0 μs | 477.29 μs | 423.11 μs | 4500.0000 | 500.0000 | - | 18703.12 KB |
|
||||
| InvokeType | 40,470.1 μs | 484.16 μs | 429.19 μs | 4000.0000 | 538.4615 | - | 16452.27 KB |
|
||||
| InvokeSummary | 39,768.8 μs | 462.14 μs | 385.91 μs | 4000.0000 | 153.8462 | - | 16397.82 KB |
|
||||
| Get | 11,145.4 μs | 402.59 μs | 1,187.03 μs | 46.8750 | - | - | 252.11 KB |
|
||||
| GetHelp | 10,169.1 μs | 625.02 μs | 1,842.88 μs | 46.8750 | - | - | 250.51 KB |
|
||||
| Within | 78,993.5 μs | 799.51 μs | 667.63 μs | 8000.0000 | 400.0000 | - | 32791.83 KB |
|
||||
| WithinBulk | 118,800.8 μs | 1,637.36 μs | 1,531.59 μs | 14333.3333 | 333.3333 | - | 59817.29 KB |
|
||||
| WithinLike | 106,796.3 μs | 2,067.20 μs | 2,538.71 μs | 11333.3333 | - | - | 47311.07 KB |
|
||||
| DefaultTargetNameBinding | 698.2 μs | 7.51 μs | 7.02 μs | 38.0859 | - | - | 156.25 KB |
|
||||
| CustomTargetNameBinding | 884.7 μs | 7.11 μs | 6.65 μs | 85.9375 | - | - | 351.56 KB |
|
||||
| NestedTargetNameBinding | 883.9 μs | 14.44 μs | 12.80 μs | 85.9375 | - | - | 351.56 KB |
|
|
@ -0,0 +1,24 @@
|
|||
``` ini
|
||||
|
||||
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.450 (2004/?/20H1)
|
||||
Intel Core i7-1065G7 CPU 1.30GHz, 1 CPU, 8 logical and 4 physical cores
|
||||
.NET Core SDK=3.1.401
|
||||
[Host] : .NET Core 3.1.7 (CoreCLR 4.700.20.36602, CoreFX 4.700.20.37001), X64 RyuJIT
|
||||
DefaultJob : .NET Core 3.1.7 (CoreCLR 4.700.20.36602, CoreFX 4.700.20.37001), X64 RyuJIT
|
||||
|
||||
|
||||
```
|
||||
| Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Gen 2 | Allocated |
|
||||
|------------------------- |-------------:|------------:|------------:|-----------:|----------:|------:|------------:|
|
||||
| Invoke | 42,162.8 μs | 827.36 μs | 1,263.47 μs | 3833.3333 | - | - | 15952 KB |
|
||||
| InvokeIf | 45,646.4 μs | 912.31 μs | 1,924.38 μs | 4416.6667 | 416.6667 | - | 18202.98 KB |
|
||||
| InvokeType | 41,825.5 μs | 810.73 μs | 901.12 μs | 3833.3333 | - | - | 15952 KB |
|
||||
| InvokeSummary | 41,133.3 μs | 777.97 μs | 895.91 μs | 3833.3333 | 500.0000 | - | 15897.56 KB |
|
||||
| Get | 10,054.3 μs | 396.83 μs | 1,170.07 μs | 46.8750 | - | - | 252.11 KB |
|
||||
| GetHelp | 10,581.4 μs | 448.15 μs | 1,321.38 μs | 46.8750 | - | - | 250.51 KB |
|
||||
| Within | 81,215.1 μs | 1,532.85 μs | 1,433.83 μs | 7750.0000 | 250.0000 | - | 32290.62 KB |
|
||||
| WithinBulk | 123,301.6 μs | 2,451.51 μs | 3,958.73 μs | 14000.0000 | 1000.0000 | - | 59317.29 KB |
|
||||
| WithinLike | 109,738.9 μs | 1,933.95 μs | 1,809.02 μs | 11333.3333 | 1000.0000 | - | 46811.07 KB |
|
||||
| DefaultTargetNameBinding | 696.0 μs | 12.06 μs | 10.69 μs | 38.0859 | - | - | 156.25 KB |
|
||||
| CustomTargetNameBinding | 845.6 μs | 11.75 μs | 10.42 μs | 85.9375 | - | - | 351.56 KB |
|
||||
| NestedTargetNameBinding | 856.0 μs | 12.29 μs | 10.90 μs | 85.9375 | - | - | 351.56 KB |
|
|
@ -294,7 +294,7 @@ task Rules {
|
|||
|
||||
task Benchmark {
|
||||
if ($Benchmark -or $BuildTask -eq 'Benchmark') {
|
||||
dotnet run -p src/PSRule.Benchmark -f netcoreapp2.1 -c Release -- benchmark --output $PWD;
|
||||
dotnet run -p src/PSRule.Benchmark -f netcoreapp3.1 -c Release -- benchmark --output $PWD;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@ using BenchmarkDotNet.Running;
|
|||
#endif
|
||||
|
||||
using Microsoft.Extensions.CommandLineUtils;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace PSRule.Benchmark
|
||||
{
|
||||
|
@ -27,7 +29,8 @@ namespace PSRule.Benchmark
|
|||
|
||||
#if !BENCHMARK
|
||||
// Do profiling
|
||||
DebugProfile();
|
||||
DebugProfile(app);
|
||||
app.Execute(args);
|
||||
#endif
|
||||
|
||||
#if BENCHMARK
|
||||
|
@ -71,34 +74,64 @@ namespace PSRule.Benchmark
|
|||
|
||||
#endif
|
||||
|
||||
private static void DebugProfile()
|
||||
private const int DebugIterations = 100;
|
||||
|
||||
private static void DebugProfile(CommandLineApplication app)
|
||||
{
|
||||
app.Command("benchmark", cmd =>
|
||||
{
|
||||
cmd.OnExecute(() =>
|
||||
{
|
||||
Console.WriteLine("Press ENTER to start.");
|
||||
Console.ReadLine();
|
||||
RunDebug();
|
||||
return 0;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static void RunDebug()
|
||||
{
|
||||
var profile = new PSRule();
|
||||
profile.Prepare();
|
||||
|
||||
for (var i = 0; i < 100; i++)
|
||||
ProfileBlock();
|
||||
for (var i = 0; i < DebugIterations; i++)
|
||||
profile.Invoke();
|
||||
|
||||
for (var i = 0; i < 100; i++)
|
||||
ProfileBlock();
|
||||
for (var i = 0; i < DebugIterations; i++)
|
||||
profile.InvokeIf();
|
||||
|
||||
for (var i = 0; i < 100; i++)
|
||||
ProfileBlock();
|
||||
for (var i = 0; i < DebugIterations; i++)
|
||||
profile.InvokeType();
|
||||
|
||||
for (var i = 0; i < 100; i++)
|
||||
ProfileBlock();
|
||||
for (var i = 0; i < DebugIterations; i++)
|
||||
profile.InvokeSummary();
|
||||
|
||||
for (var i = 0; i < 100; i++)
|
||||
ProfileBlock();
|
||||
for (var i = 0; i < DebugIterations; i++)
|
||||
profile.Get();
|
||||
|
||||
for (var i = 0; i < 100; i++)
|
||||
ProfileBlock();
|
||||
for (var i = 0; i < DebugIterations; i++)
|
||||
profile.DefaultTargetNameBinding();
|
||||
|
||||
for (var i = 0; i < 100; i++)
|
||||
ProfileBlock();
|
||||
for (var i = 0; i < DebugIterations; i++)
|
||||
profile.CustomTargetNameBinding();
|
||||
|
||||
for (var i = 0; i < 100; i++)
|
||||
ProfileBlock();
|
||||
for (var i = 0; i < DebugIterations; i++)
|
||||
profile.NestedTargetNameBinding();
|
||||
}
|
||||
|
||||
[DebuggerStepThrough]
|
||||
private static void ProfileBlock()
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,8 @@
|
|||
// Licensed under the MIT License.
|
||||
|
||||
using PSRule.Pipeline;
|
||||
using PSRule.Resources;
|
||||
using PSRule.Runtime;
|
||||
using System.Management.Automation;
|
||||
using System.Threading;
|
||||
|
||||
namespace PSRule.Commands
|
||||
{
|
||||
|
@ -21,9 +19,9 @@ namespace PSRule.Commands
|
|||
protected override void ProcessRecord()
|
||||
{
|
||||
if (!IsConditionScope())
|
||||
throw new RuleRuntimeException(string.Format(Thread.CurrentThread.CurrentCulture, PSRuleResources.KeywordConditionScope, LanguageKeywords.AllOf));
|
||||
throw ConditionScopeException(LanguageKeywords.AllOf);
|
||||
|
||||
var invokeResult = RuleConditionResult.Create(Body.Invoke());
|
||||
var invokeResult = RuleConditionHelper.Create(Body.Invoke());
|
||||
var result = invokeResult.AllOf();
|
||||
|
||||
RunspaceContext.CurrentThread.VerboseConditionResult(condition: RuleLanguageNouns.AllOf, pass: invokeResult.Pass, count: invokeResult.Count, outcome: result);
|
||||
|
|
|
@ -2,10 +2,8 @@
|
|||
// Licensed under the MIT License.
|
||||
|
||||
using PSRule.Pipeline;
|
||||
using PSRule.Resources;
|
||||
using PSRule.Runtime;
|
||||
using System.Management.Automation;
|
||||
using System.Threading;
|
||||
|
||||
namespace PSRule.Commands
|
||||
{
|
||||
|
@ -21,9 +19,9 @@ namespace PSRule.Commands
|
|||
protected override void ProcessRecord()
|
||||
{
|
||||
if (!IsConditionScope())
|
||||
throw new RuleRuntimeException(string.Format(Thread.CurrentThread.CurrentCulture, PSRuleResources.KeywordConditionScope, LanguageKeywords.AnyOf));
|
||||
throw ConditionScopeException(LanguageKeywords.AnyOf);
|
||||
|
||||
var invokeResult = RuleConditionResult.Create(Body.Invoke());
|
||||
var invokeResult = RuleConditionHelper.Create(Body.Invoke());
|
||||
var result = invokeResult.AnyOf();
|
||||
|
||||
RunspaceContext.CurrentThread.VerboseConditionResult(condition: RuleLanguageNouns.AnyOf, pass: invokeResult.Pass, count: invokeResult.Count, outcome: result);
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace PSRule.Commands
|
|||
protected override void ProcessRecord()
|
||||
{
|
||||
if (!IsRuleScope())
|
||||
throw new RuleRuntimeException(string.Format(Thread.CurrentThread.CurrentCulture, PSRuleResources.KeywordRuleScope, RuleLanguageNouns.Exists));
|
||||
throw RuleScopeException(LanguageKeywords.Exists);
|
||||
|
||||
var targetObject = InputObject ?? GetTargetObject();
|
||||
var foundFields = new List<string>();
|
||||
|
@ -57,7 +57,7 @@ namespace PSRule.Commands
|
|||
|
||||
for (var i = 0; i < Field.Length && found < required; i++)
|
||||
{
|
||||
if (ObjectHelper.GetField(bindingContext: PipelineContext.CurrentThread, targetObject: targetObject, name: Field[i], caseSensitive: CaseSensitive, value: out object fieldValue))
|
||||
if (ObjectHelper.GetField(bindingContext: PipelineContext.CurrentThread, targetObject: targetObject, name: Field[i], caseSensitive: CaseSensitive, value: out _))
|
||||
{
|
||||
RunspaceContext.CurrentThread.VerboseConditionMessage(condition: RuleLanguageNouns.Exists, message: PSRuleResources.ExistsTrue, args: Field[i]);
|
||||
foundFields.Add(Field[i]);
|
||||
|
|
|
@ -59,9 +59,7 @@ namespace PSRule.Commands
|
|||
protected override void ProcessRecord()
|
||||
{
|
||||
if (!IsRuleScope())
|
||||
{
|
||||
throw new RuleRuntimeException(string.Format(Thread.CurrentThread.CurrentCulture, PSRuleResources.KeywordRuleScope, RuleLanguageNouns.Match));
|
||||
}
|
||||
throw RuleScopeException(LanguageKeywords.Match);
|
||||
|
||||
var targetObject = InputObject ?? GetTargetObject();
|
||||
bool expected = !Not;
|
||||
|
|
|
@ -5,6 +5,7 @@ using PSRule.Pipeline;
|
|||
using PSRule.Resources;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
using System.Threading;
|
||||
|
||||
namespace PSRule.Commands
|
||||
{
|
||||
|
@ -26,9 +27,7 @@ namespace PSRule.Commands
|
|||
protected override void ProcessRecord()
|
||||
{
|
||||
if (!IsRuleScope())
|
||||
{
|
||||
throw new RuleRuntimeException(string.Format(PSRuleResources.KeywordRuleScope, RuleLanguageNouns.TypeOf));
|
||||
}
|
||||
throw RuleScopeException(LanguageKeywords.TypeOf);
|
||||
|
||||
var inputObject = InputObject ?? GetTargetObject();
|
||||
var result = false;
|
||||
|
@ -42,7 +41,7 @@ namespace PSRule.Commands
|
|||
RunspaceContext.CurrentThread.VerboseConditionResult(condition: RuleLanguageNouns.TypeOf, outcome: result);
|
||||
if (!(result || TryReason(Reason)))
|
||||
{
|
||||
WriteReason(string.Format(ReasonStrings.TypeOf, string.Join(", ", TypeName)));
|
||||
WriteReason(string.Format(Thread.CurrentThread.CurrentCulture, ReasonStrings.TypeOf, string.Join(", ", TypeName)));
|
||||
}
|
||||
WriteObject(result);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ using PSRule.Resources;
|
|||
using PSRule.Runtime;
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using System.Threading;
|
||||
|
||||
namespace PSRule.Commands
|
||||
{
|
||||
|
@ -59,7 +60,7 @@ namespace PSRule.Commands
|
|||
protected override void ProcessRecord()
|
||||
{
|
||||
if (!IsRuleScope())
|
||||
throw new RuleRuntimeException(string.Format(PSRuleResources.KeywordRuleScope, LanguageKeywords.Within));
|
||||
throw RuleScopeException(LanguageKeywords.Within);
|
||||
|
||||
var targetObject = InputObject ?? GetTargetObject();
|
||||
bool expected = !Not;
|
||||
|
@ -109,7 +110,7 @@ namespace PSRule.Commands
|
|||
RunspaceContext.CurrentThread.VerboseConditionResult(condition: RuleLanguageNouns.Within, outcome: result);
|
||||
if (!(result || TryReason(Reason)))
|
||||
{
|
||||
WriteReason(Not ? string.Format(ReasonStrings.WithinNot, found) : ReasonStrings.Within);
|
||||
WriteReason(Not ? string.Format(Thread.CurrentThread.CurrentCulture, ReasonStrings.WithinNot, found) : ReasonStrings.Within);
|
||||
}
|
||||
WriteObject(result);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the MIT License.
|
||||
|
||||
using PSRule.Pipeline;
|
||||
using PSRule.Resources;
|
||||
using PSRule.Runtime;
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
|
@ -32,7 +33,7 @@ namespace PSRule.Commands
|
|||
// Evalute type pre-condition
|
||||
if (!AcceptsType())
|
||||
{
|
||||
RunspaceContext.CurrentThread.Writer.DebugMessage("Target failed Type precondition");
|
||||
RunspaceContext.CurrentThread.Writer.DebugMessage(PSRuleResources.DebugTargetTypeMismatch);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -40,17 +41,17 @@ namespace PSRule.Commands
|
|||
if (If != null)
|
||||
{
|
||||
PipelineContext.CurrentThread.ExecutionScope = ExecutionScope.Precondition;
|
||||
var ifResult = RuleConditionResult.Create(If.Invoke());
|
||||
var ifResult = RuleConditionHelper.Create(If.Invoke());
|
||||
if (!ifResult.AllOf())
|
||||
{
|
||||
RunspaceContext.CurrentThread.Writer.DebugMessage("Target failed If precondition");
|
||||
RunspaceContext.CurrentThread.Writer.DebugMessage(PSRuleResources.DebugTargetIfMismatch);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Evaluate script block
|
||||
PipelineContext.CurrentThread.ExecutionScope = ExecutionScope.Condition;
|
||||
var invokeResult = RuleConditionResult.Create(Body.Invoke());
|
||||
var invokeResult = RuleConditionHelper.Create(Body.Invoke());
|
||||
WriteObject(invokeResult);
|
||||
}
|
||||
finally
|
||||
|
|
|
@ -15,17 +15,17 @@ namespace PSRule.Commands
|
|||
/// </summary>
|
||||
internal abstract class LanguageBlock : PSCmdlet
|
||||
{
|
||||
protected CommentMetadata GetMetadata(string path, int lineNumber, int offset)
|
||||
protected static CommentMetadata GetMetadata(string path, int lineNumber, int offset)
|
||||
{
|
||||
return HostHelper.GetCommentMeta(path, lineNumber - 2, offset);
|
||||
}
|
||||
|
||||
protected TagSet GetTag(Hashtable hashtable)
|
||||
protected static TagSet GetTag(Hashtable hashtable)
|
||||
{
|
||||
return TagSet.FromHashtable(hashtable);
|
||||
}
|
||||
|
||||
protected bool IsScriptScope()
|
||||
protected static bool IsScriptScope()
|
||||
{
|
||||
return PipelineContext.CurrentThread.ExecutionScope == ExecutionScope.Script;
|
||||
}
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
// Licensed under the MIT License.
|
||||
|
||||
using PSRule.Pipeline;
|
||||
using PSRule.Resources;
|
||||
using PSRule.Rules;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Management.Automation;
|
||||
using System.Threading;
|
||||
|
||||
namespace PSRule.Commands
|
||||
{
|
||||
|
@ -14,12 +16,12 @@ namespace PSRule.Commands
|
|||
/// </summary>
|
||||
internal abstract class RuleKeyword : PSCmdlet
|
||||
{
|
||||
protected RuleRecord GetResult()
|
||||
protected static RuleRecord GetResult()
|
||||
{
|
||||
return RunspaceContext.CurrentThread.RuleRecord;
|
||||
}
|
||||
|
||||
protected PSObject GetTargetObject()
|
||||
protected static PSObject GetTargetObject()
|
||||
{
|
||||
return RunspaceContext.CurrentThread.TargetObject;
|
||||
}
|
||||
|
@ -80,50 +82,52 @@ namespace PSRule.Commands
|
|||
return false;
|
||||
}
|
||||
|
||||
protected object GetBaseObject(object value)
|
||||
protected static object GetBaseObject(object value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (value is PSObject pso)
|
||||
{
|
||||
var baseObject = pso.BaseObject;
|
||||
|
||||
if (baseObject != null)
|
||||
{
|
||||
return baseObject;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
protected void WriteReason(string text)
|
||||
protected static void WriteReason(string text)
|
||||
{
|
||||
RunspaceContext.CurrentThread.WriteReason(text);
|
||||
}
|
||||
|
||||
protected bool TryReason(string text)
|
||||
protected static bool TryReason(string text)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
WriteReason(text);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected bool IsRuleScope()
|
||||
protected static bool IsRuleScope()
|
||||
{
|
||||
return PipelineContext.CurrentThread.ExecutionScope == ExecutionScope.Condition || PipelineContext.CurrentThread.ExecutionScope == ExecutionScope.Precondition;
|
||||
}
|
||||
|
||||
protected bool IsConditionScope()
|
||||
protected static bool IsConditionScope()
|
||||
{
|
||||
return PipelineContext.CurrentThread.ExecutionScope == ExecutionScope.Condition;
|
||||
}
|
||||
|
||||
protected static RuleRuntimeException RuleScopeException(string keyword)
|
||||
{
|
||||
return new RuleRuntimeException(string.Format(Thread.CurrentThread.CurrentCulture, PSRuleResources.KeywordRuleScope, keyword));
|
||||
}
|
||||
|
||||
protected static RuleRuntimeException ConditionScopeException(string keyword)
|
||||
{
|
||||
return new RuleRuntimeException(string.Format(Thread.CurrentThread.CurrentCulture, PSRuleResources.KeywordConditionScope, keyword));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
// Licensed under the MIT License.
|
||||
|
||||
using PSRule.Pipeline;
|
||||
using PSRule.Resources;
|
||||
using System.Management.Automation;
|
||||
|
||||
namespace PSRule.Commands
|
||||
|
@ -19,7 +18,8 @@ namespace PSRule.Commands
|
|||
protected override void ProcessRecord()
|
||||
{
|
||||
if (!IsConditionScope())
|
||||
throw new RuleRuntimeException(string.Format(PSRuleResources.KeywordConditionScope, LanguageKeywords.Reason));
|
||||
throw ConditionScopeException(LanguageKeywords.Reason);
|
||||
|
||||
|
||||
if (MyInvocation.BoundParameters.ContainsKey(nameof(Text)))
|
||||
RunspaceContext.CurrentThread.WriteReason(text: Text);
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using PSRule.Pipeline;
|
||||
using PSRule.Resources;
|
||||
using System.Management.Automation;
|
||||
|
||||
namespace PSRule.Commands
|
||||
|
@ -20,9 +18,7 @@ namespace PSRule.Commands
|
|||
protected override void ProcessRecord()
|
||||
{
|
||||
if (!IsConditionScope())
|
||||
{
|
||||
throw new RuleRuntimeException(string.Format(PSRuleResources.KeywordConditionScope, LanguageKeywords.Recommend));
|
||||
}
|
||||
throw ConditionScopeException(LanguageKeywords.Recommend);
|
||||
|
||||
var result = GetResult();
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ using System.Security;
|
|||
|
||||
namespace PSRule
|
||||
{
|
||||
internal sealed class EnvironmentHelper
|
||||
internal static class EnvironmentHelper
|
||||
{
|
||||
private const char UNDERSCORE = '_';
|
||||
|
|
@ -12,7 +12,7 @@ namespace PSRule.Host
|
|||
private readonly DependencyTarget[] _Targets;
|
||||
|
||||
// Track whether Dispose has been called.
|
||||
private bool _Disposed = false;
|
||||
private bool _Disposed;
|
||||
|
||||
public DependencyGraph(T[] targets)
|
||||
{
|
||||
|
@ -40,12 +40,12 @@ namespace PSRule.Host
|
|||
DependencyFail = 3
|
||||
}
|
||||
|
||||
public sealed class DependencyTarget
|
||||
internal sealed class DependencyTarget
|
||||
{
|
||||
public readonly DependencyGraph<T> Graph;
|
||||
public readonly T Value;
|
||||
|
||||
internal DependencyTargetState State;
|
||||
private DependencyTargetState State;
|
||||
|
||||
public DependencyTarget(DependencyGraph<T> graph, T value)
|
||||
{
|
||||
|
@ -58,6 +58,16 @@ namespace PSRule.Host
|
|||
get { return State == DependencyTargetState.DependencyFail; }
|
||||
}
|
||||
|
||||
public bool Failed
|
||||
{
|
||||
get { return State == DependencyTargetState.Fail || State == DependencyTargetState.DependencyFail; }
|
||||
}
|
||||
|
||||
public bool Passed
|
||||
{
|
||||
get { return State == DependencyTargetState.Pass; }
|
||||
}
|
||||
|
||||
public void Pass()
|
||||
{
|
||||
State = DependencyTargetState.Pass;
|
||||
|
@ -67,34 +77,38 @@ namespace PSRule.Host
|
|||
{
|
||||
State = DependencyTargetState.Fail;
|
||||
}
|
||||
|
||||
public void DependencyFail()
|
||||
{
|
||||
State = DependencyTargetState.DependencyFail;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<DependencyTarget> GetSingleTarget()
|
||||
{
|
||||
foreach (var target in _Targets)
|
||||
for (var t = 0; t < _Targets.Length; t++)
|
||||
{
|
||||
var target = _Targets[t];
|
||||
if (target.Value.DependsOn != null && target.Value.DependsOn.Length > 0)
|
||||
{
|
||||
// Process each dependency
|
||||
foreach (var d in target.Value.DependsOn)
|
||||
for (var d = 0; d < target.Value.DependsOn.Length; d++)
|
||||
{
|
||||
var dTarget = _Index[d];
|
||||
var dTarget = _Index[target.Value.DependsOn[d]];
|
||||
|
||||
// Check if dependency was already completed
|
||||
if (dTarget.State == DependencyTargetState.Pass)
|
||||
if (dTarget.Passed)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (dTarget.State == DependencyTargetState.Fail || dTarget.State == DependencyTargetState.DependencyFail)
|
||||
else if (dTarget.Failed)
|
||||
{
|
||||
target.State = DependencyTargetState.DependencyFail;
|
||||
target.DependencyFail();
|
||||
break;
|
||||
}
|
||||
|
||||
yield return dTarget;
|
||||
}
|
||||
}
|
||||
|
||||
yield return target;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ using PSRule.Resources;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace PSRule.Host
|
||||
{
|
||||
|
@ -32,7 +33,7 @@ namespace PSRule.Host
|
|||
foreach (var item in items)
|
||||
{
|
||||
if (index.ContainsKey(item.RuleId))
|
||||
throw new RuleRuntimeException(message: string.Format(PSRuleResources.DuplicateRuleId, item.RuleId));
|
||||
throw new RuleRuntimeException(string.Format(Thread.CurrentThread.CurrentCulture, PSRuleResources.DuplicateRuleId, item.RuleId));
|
||||
|
||||
index.Add(item.RuleId, item);
|
||||
}
|
||||
|
@ -63,7 +64,7 @@ namespace PSRule.Host
|
|||
|
||||
// Check for circular dependencies
|
||||
if (_Stack.Contains(value: ruleId, comparer: _Comparer))
|
||||
throw new RuleRuntimeException(message: string.Format(PSRuleResources.DependencyCircularReference, parentId, ruleId));
|
||||
throw new RuleRuntimeException(string.Format(Thread.CurrentThread.CurrentCulture, PSRuleResources.DependencyCircularReference, parentId, ruleId));
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -76,7 +77,7 @@ namespace PSRule.Host
|
|||
foreach (var d in item.DependsOn)
|
||||
{
|
||||
if (!index.ContainsKey(d))
|
||||
throw new RuleRuntimeException(message: string.Format(PSRuleResources.DependencyNotFound, d, ruleId));
|
||||
throw new RuleRuntimeException(string.Format(Thread.CurrentThread.CurrentCulture, PSRuleResources.DependencyNotFound, d, ruleId));
|
||||
|
||||
// Handle dependencies
|
||||
if (!_Targets.ContainsKey(d))
|
||||
|
|
|
@ -88,10 +88,10 @@ namespace PSRule.Host
|
|||
{
|
||||
foreach (var comment in comments)
|
||||
{
|
||||
if (comment.StartsWith("# Description: "))
|
||||
if (comment.StartsWith("# Description: ", StringComparison.OrdinalIgnoreCase))
|
||||
metadata.Synopsis = comment.Substring(15);
|
||||
|
||||
if (comment.StartsWith("# Synopsis: "))
|
||||
if (comment.StartsWith("# Synopsis: ", StringComparison.OrdinalIgnoreCase))
|
||||
metadata.Synopsis = comment.Substring(12);
|
||||
}
|
||||
}
|
||||
|
@ -156,15 +156,12 @@ namespace PSRule.Host
|
|||
|
||||
foreach (var ir in invokeResults)
|
||||
{
|
||||
if (ir.BaseObject is RuleBlock)
|
||||
{
|
||||
var block = ir.BaseObject as RuleBlock;
|
||||
if (ir.BaseObject is RuleBlock block)
|
||||
results.Add(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
context.Writer.ExitScope();
|
||||
|
@ -250,7 +247,7 @@ namespace PSRule.Host
|
|||
{
|
||||
ruleRecord.OutcomeReason = RuleOutcomeReason.Inconclusive;
|
||||
ruleRecord.Outcome = RuleOutcome.Fail;
|
||||
context.WarnRuleInconclusive(ruleId: ruleRecord.RuleId);
|
||||
context.WarnRuleInconclusive(ruleRecord.RuleId);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -9,10 +9,8 @@ namespace PSRule.Parser
|
|||
{
|
||||
public Dictionary<string, string> Process(TokenStream stream)
|
||||
{
|
||||
stream.MoveTo(0);
|
||||
|
||||
// Look for yaml header
|
||||
|
||||
stream.MoveTo(0);
|
||||
return YamlHeader(stream);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ using PSRule.Resources;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace PSRule.Parser
|
||||
{
|
||||
|
@ -26,11 +27,9 @@ namespace PSRule.Parser
|
|||
|
||||
public RuleDocument Process(TokenStream stream)
|
||||
{
|
||||
stream.MoveTo(0);
|
||||
|
||||
// Look for yaml header
|
||||
stream.MoveTo(0);
|
||||
var metadata = YamlHeader(stream);
|
||||
|
||||
RuleDocument doc = null;
|
||||
|
||||
// Process sections
|
||||
|
@ -151,7 +150,7 @@ namespace PSRule.Parser
|
|||
return true;
|
||||
}
|
||||
|
||||
private TextBlock TextBlock(TokenStream stream)
|
||||
private static TextBlock TextBlock(TokenStream stream)
|
||||
{
|
||||
var useBreak = stream.Current.IsDoubleLineEnding();
|
||||
stream.Next();
|
||||
|
@ -177,7 +176,7 @@ namespace PSRule.Parser
|
|||
AppendEnding(sb, stream.Peak(-1));
|
||||
sb.Append(stream.Current.Meta);
|
||||
if (!string.IsNullOrEmpty(stream.Current.Text))
|
||||
sb.AppendFormat(" ({0})", stream.Current.Text);
|
||||
sb.AppendFormat(Thread.CurrentThread.CurrentCulture, " ({0})", stream.Current.Text);
|
||||
}
|
||||
else if (stream.IsTokenType(MarkdownTokenType.LinkReference))
|
||||
{
|
||||
|
|
|
@ -127,16 +127,14 @@ namespace PSRule.Pipeline
|
|||
internal GetTargetPipeline(PipelineContext context, PipelineReader reader, PipelineWriter writer)
|
||||
: base(context, null, reader, writer) { }
|
||||
|
||||
public override void Process(PSObject targetObject)
|
||||
public override void Process(PSObject sourceObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
Reader.Enqueue(targetObject);
|
||||
Reader.Enqueue(sourceObject);
|
||||
while (Reader.TryDequeue(out PSObject next))
|
||||
{
|
||||
Writer.WriteObject(next, false);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
End();
|
||||
|
|
|
@ -25,9 +25,7 @@ namespace PSRule.Pipeline
|
|||
if (commandRuntime != null)
|
||||
ShouldProcess = commandRuntime.ShouldProcess;
|
||||
|
||||
InSession = executionContext == null ? false : executionContext.SessionState.PSVariable.GetValue("PSSenderInfo") != null;
|
||||
InSession = executionContext != null && executionContext.SessionState.PSVariable.GetValue("PSSenderInfo") != null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -179,7 +179,7 @@ namespace PSRule.Pipeline
|
|||
private readonly RuleSuppressionFilter _SuppressionFilter;
|
||||
|
||||
// Track whether Dispose has been called.
|
||||
private bool _Disposed = false;
|
||||
private bool _Disposed;
|
||||
|
||||
internal InvokeRulePipeline(PipelineContext context, Source[] source, PipelineReader reader, PipelineWriter writer, RuleOutcome outcome)
|
||||
: base(context, source, reader, writer)
|
||||
|
@ -199,11 +199,11 @@ namespace PSRule.Pipeline
|
|||
|
||||
public int RuleCount { get; private set; }
|
||||
|
||||
public override void Process(PSObject targetObject)
|
||||
public override void Process(PSObject sourceObject)
|
||||
{
|
||||
try
|
||||
{
|
||||
Reader.Enqueue(targetObject);
|
||||
Reader.Enqueue(sourceObject);
|
||||
while (Reader.TryDequeue(out PSObject next))
|
||||
{
|
||||
var result = ProcessTargetObject(next);
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace PSRule.Pipeline
|
|||
private readonly string _DefaultSearchPattern;
|
||||
private readonly PathFilter _GlobalFilter;
|
||||
|
||||
internal PathBuilder(ILogger logger, string basePath, string searchPattern, PathFilter filter)
|
||||
protected PathBuilder(ILogger logger, string basePath, string searchPattern, PathFilter filter)
|
||||
{
|
||||
_Logger = logger;
|
||||
_Files = new List<InputFileInfo>();
|
||||
|
@ -171,11 +171,6 @@ namespace PSRule.Pipeline
|
|||
if (string.IsNullOrEmpty(searchPattern))
|
||||
searchPattern = _DefaultSearchPattern;
|
||||
|
||||
// If a path separator is within the pattern use a resursive search
|
||||
//if (relativeAnchor || !string.IsNullOrEmpty(pathLiteral))
|
||||
//if (relativeAnchor && string.IsNullOrEmpty(searchPattern))
|
||||
// searchOption = SearchOption.TopDirectoryOnly;
|
||||
|
||||
return GetRootedPath(pathLiteral);
|
||||
}
|
||||
|
||||
|
|
|
@ -62,12 +62,9 @@ namespace PSRule.Pipeline
|
|||
private const char Hash = '#'; // Comment
|
||||
private const char Exclamation = '!'; // Include a previously excluded path
|
||||
|
||||
private const string GitIgnoreFileName = ".gitignore";
|
||||
|
||||
private readonly string _BasePath;
|
||||
private readonly PathFilterExpression[] _Expression;
|
||||
|
||||
private bool _MatchResult;
|
||||
private readonly bool _MatchResult;
|
||||
|
||||
private PathFilter(string basePath, PathFilterExpression[] expression, bool matchResult)
|
||||
{
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace PSRule.Pipeline
|
|||
protected readonly PipelineWriter Writer;
|
||||
|
||||
// Track whether Dispose has been called.
|
||||
private bool _Disposed = false;
|
||||
private bool _Disposed;
|
||||
|
||||
protected RulePipeline(PipelineContext context, Source[] source, PipelineReader reader, PipelineWriter writer)
|
||||
{
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace PSRule.Pipeline
|
|||
private readonly OutcomeLogStream _FailStream;
|
||||
private readonly OutcomeLogStream _PassStream;
|
||||
|
||||
private bool _RaisedUsingInvariantCulture = false;
|
||||
private bool _RaisedUsingInvariantCulture;
|
||||
|
||||
// Pipeline logging
|
||||
private string _LogPrefix;
|
||||
|
@ -53,7 +53,7 @@ namespace PSRule.Pipeline
|
|||
private readonly List<string> _Reason;
|
||||
|
||||
// Track whether Dispose has been called.
|
||||
private bool _Disposed = false;
|
||||
private bool _Disposed;
|
||||
|
||||
internal RunspaceContext(PipelineContext pipeline, PipelineWriter writer)
|
||||
{
|
||||
|
@ -77,13 +77,13 @@ namespace PSRule.Pipeline
|
|||
return;
|
||||
|
||||
if (_PassStream == OutcomeLogStream.Warning && Writer.ShouldWriteWarning())
|
||||
Writer.WriteWarning(string.Format(PSRuleResources.OutcomeRulePass, RuleRecord.RuleName, Pipeline.Binder.TargetName));
|
||||
Writer.WriteWarning(PSRuleResources.OutcomeRulePass, RuleRecord.RuleName, Pipeline.Binder.TargetName);
|
||||
|
||||
if (_PassStream == OutcomeLogStream.Error && Writer.ShouldWriteError())
|
||||
Writer.WriteError(new ErrorRecord(new RuleRuntimeException(string.Format(PSRuleResources.OutcomeRulePass, RuleRecord.RuleName, Pipeline.Binder.TargetName)), SOURCE_OUTCOME_PASS, ErrorCategory.InvalidData, null));
|
||||
Writer.WriteError(new ErrorRecord(new RuleRuntimeException(string.Format(Thread.CurrentThread.CurrentCulture, PSRuleResources.OutcomeRulePass, RuleRecord.RuleName, Pipeline.Binder.TargetName)), SOURCE_OUTCOME_PASS, ErrorCategory.InvalidData, null));
|
||||
|
||||
if (_PassStream == OutcomeLogStream.Information && Writer.ShouldWriteInformation())
|
||||
Writer.WriteInformation(new InformationRecord(messageData: string.Format(PSRuleResources.OutcomeRulePass, RuleRecord.RuleName, Pipeline.Binder.TargetName), source: SOURCE_OUTCOME_PASS));
|
||||
Writer.WriteInformation(new InformationRecord(messageData: string.Format(Thread.CurrentThread.CurrentCulture, PSRuleResources.OutcomeRulePass, RuleRecord.RuleName, Pipeline.Binder.TargetName), source: SOURCE_OUTCOME_PASS));
|
||||
}
|
||||
|
||||
public void Fail()
|
||||
|
@ -92,13 +92,13 @@ namespace PSRule.Pipeline
|
|||
return;
|
||||
|
||||
if (_FailStream == OutcomeLogStream.Warning && Writer.ShouldWriteWarning())
|
||||
Writer.WriteWarning(string.Format(PSRuleResources.OutcomeRuleFail, RuleRecord.RuleName, Pipeline.Binder.TargetName));
|
||||
Writer.WriteWarning(PSRuleResources.OutcomeRuleFail, RuleRecord.RuleName, Pipeline.Binder.TargetName);
|
||||
|
||||
if (_FailStream == OutcomeLogStream.Error && Writer.ShouldWriteError())
|
||||
Writer.WriteError(new ErrorRecord(new RuleRuntimeException(string.Format(PSRuleResources.OutcomeRuleFail, RuleRecord.RuleName, Pipeline.Binder.TargetName)), SOURCE_OUTCOME_FAIL, ErrorCategory.InvalidData, null));
|
||||
Writer.WriteError(new ErrorRecord(new RuleRuntimeException(string.Format(Thread.CurrentThread.CurrentCulture, PSRuleResources.OutcomeRuleFail, RuleRecord.RuleName, Pipeline.Binder.TargetName)), SOURCE_OUTCOME_FAIL, ErrorCategory.InvalidData, null));
|
||||
|
||||
if (_FailStream == OutcomeLogStream.Information && Writer.ShouldWriteInformation())
|
||||
Writer.WriteInformation(new InformationRecord(messageData: string.Format(PSRuleResources.OutcomeRuleFail, RuleRecord.RuleName, Pipeline.Binder.TargetName), source: SOURCE_OUTCOME_FAIL));
|
||||
Writer.WriteInformation(new InformationRecord(messageData: string.Format(Thread.CurrentThread.CurrentCulture, PSRuleResources.OutcomeRuleFail, RuleRecord.RuleName, Pipeline.Binder.TargetName), source: SOURCE_OUTCOME_FAIL));
|
||||
}
|
||||
|
||||
public void WarnRuleInconclusive(string ruleId)
|
||||
|
@ -106,7 +106,7 @@ namespace PSRule.Pipeline
|
|||
if (Writer == null || !Writer.ShouldWriteWarning() || !_InconclusiveWarning)
|
||||
return;
|
||||
|
||||
Writer.WriteWarning(string.Format(PSRuleResources.RuleInconclusive, ruleId, Pipeline.Binder.TargetName));
|
||||
Writer.WriteWarning(PSRuleResources.RuleInconclusive, ruleId, Pipeline.Binder.TargetName);
|
||||
}
|
||||
|
||||
public void WarnObjectNotProcessed()
|
||||
|
@ -114,7 +114,7 @@ namespace PSRule.Pipeline
|
|||
if (Writer == null || !Writer.ShouldWriteWarning() || !_NotProcessedWarning)
|
||||
return;
|
||||
|
||||
Writer.WriteWarning(string.Format(PSRuleResources.ObjectNotProcessed, Pipeline.Binder.TargetName));
|
||||
Writer.WriteWarning(PSRuleResources.ObjectNotProcessed, Pipeline.Binder.TargetName);
|
||||
}
|
||||
|
||||
public void WarnRuleNotFound()
|
||||
|
@ -335,7 +335,7 @@ namespace PSRule.Pipeline
|
|||
return string.Concat(
|
||||
record.ScriptStackTrace,
|
||||
Environment.NewLine,
|
||||
string.Format(PSRuleResources.RuleStackTrace, RuleBlock.RuleName, RuleBlock.Extent.File, RuleBlock.Extent.StartLineNumber)
|
||||
string.Format(Thread.CurrentThread.CurrentCulture, PSRuleResources.RuleStackTrace, RuleBlock.RuleName, RuleBlock.Extent.File, RuleBlock.Extent.StartLineNumber)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -385,7 +385,7 @@ namespace PSRule.Pipeline
|
|||
{
|
||||
_ObjectNumber++;
|
||||
TargetObject = targetObject;
|
||||
Pipeline.Binder.Bind(Pipeline.Baseline, targetObject);
|
||||
Pipeline.Binder.Bind(Pipeline.Baseline, TargetObject);
|
||||
if (Pipeline.ContentCache.Count > 0)
|
||||
Pipeline.ContentCache.Clear();
|
||||
}
|
||||
|
@ -395,7 +395,6 @@ namespace PSRule.Pipeline
|
|||
/// </summary>
|
||||
public RuleRecord EnterRuleBlock(RuleBlock ruleBlock)
|
||||
{
|
||||
Pipeline.Binder.Bind(Pipeline.Baseline, TargetObject);
|
||||
RuleBlock = ruleBlock;
|
||||
RuleRecord = new RuleRecord(
|
||||
ruleId: ruleBlock.RuleId,
|
||||
|
|
|
@ -119,10 +119,10 @@ namespace PSRule.Pipeline
|
|||
/// </summary>
|
||||
private void BindField(FieldMap[] map, bool caseSensitive, PSObject targetObject)
|
||||
{
|
||||
var hashtable = new ImmutableHashtable();
|
||||
if (map == null || map.Length == 0)
|
||||
return;
|
||||
|
||||
var hashtable = new ImmutableHashtable();
|
||||
for (var i = 0; i < map.Length; i++)
|
||||
{
|
||||
if (map[i] == null || map[i].Count == 0)
|
||||
|
|
|
@ -78,6 +78,24 @@ namespace PSRule.Resources {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Target failed If precondition.
|
||||
/// </summary>
|
||||
internal static string DebugTargetIfMismatch {
|
||||
get {
|
||||
return ResourceManager.GetString("DebugTargetIfMismatch", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Target failed Type precondition.
|
||||
/// </summary>
|
||||
internal static string DebugTargetTypeMismatch {
|
||||
get {
|
||||
return ResourceManager.GetString("DebugTargetTypeMismatch", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to A circular rule dependency was detected. The rule '{0}' depends on '{1}' which also depend on '{0}'..
|
||||
/// </summary>
|
||||
|
|
|
@ -124,6 +124,12 @@
|
|||
<data name="ConstrainedTargetBinding" xml:space="preserve">
|
||||
<value>Binding functions are not supported in this language mode.</value>
|
||||
</data>
|
||||
<data name="DebugTargetIfMismatch" xml:space="preserve">
|
||||
<value>Target failed If precondition</value>
|
||||
</data>
|
||||
<data name="DebugTargetTypeMismatch" xml:space="preserve">
|
||||
<value>Target failed Type precondition</value>
|
||||
</data>
|
||||
<data name="DependencyCircularReference" xml:space="preserve">
|
||||
<value>A circular rule dependency was detected. The rule '{0}' depends on '{1}' which also depend on '{0}'.</value>
|
||||
<comment>Occurs when rules interdepend on each other.</comment>
|
||||
|
|
|
@ -34,7 +34,8 @@ namespace PSRule.Rules
|
|||
if (field != null && field.Count > 0)
|
||||
Field = field;
|
||||
|
||||
Data = new Hashtable();
|
||||
// Limit allocations for most scenarios. Runtime calls GetData().
|
||||
Data = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -143,5 +144,16 @@ namespace PSRule.Rules
|
|||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Safe call to Data.
|
||||
/// </summary>
|
||||
internal Hashtable GetData()
|
||||
{
|
||||
if (Data == null)
|
||||
Data = new Hashtable();
|
||||
|
||||
return Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -286,7 +286,6 @@ namespace PSRule.Runtime
|
|||
value = null;
|
||||
var bindingFlags = caseSensitive ? BindingFlags.Default : BindingFlags.IgnoreCase;
|
||||
var fieldInfo = baseType.GetField(fieldName, bindingAttr: bindingFlags | BindingFlags.Instance | BindingFlags.Public);
|
||||
|
||||
if (fieldInfo == null)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace PSRule.Runtime
|
|||
{
|
||||
get
|
||||
{
|
||||
return _Context.RuleRecord.Data;
|
||||
return _Context.RuleRecord.GetData();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,13 +7,76 @@ using System.Management.Automation;
|
|||
|
||||
namespace PSRule.Runtime
|
||||
{
|
||||
internal static class RuleConditionHelper
|
||||
{
|
||||
private readonly static RuleConditionResult Empty = new RuleConditionResult(pass: 0, count: 0, hadErrors: false);
|
||||
|
||||
internal static RuleConditionResult Create(IEnumerable<object> value)
|
||||
{
|
||||
if (value == null)
|
||||
return Empty;
|
||||
|
||||
var count = 0;
|
||||
var pass = 0;
|
||||
var hasErrors = false;
|
||||
foreach (var v in value)
|
||||
{
|
||||
count++;
|
||||
if (v == null)
|
||||
continue;
|
||||
|
||||
var baseObject = GetBaseObject(v);
|
||||
if (!(TryAssertResult(baseObject, out bool result) || TryBoolean(baseObject, out result)))
|
||||
{
|
||||
RunspaceContext.CurrentThread.ErrorInvaildRuleResult();
|
||||
hasErrors = true;
|
||||
}
|
||||
else if (result)
|
||||
{
|
||||
pass++;
|
||||
}
|
||||
}
|
||||
return new RuleConditionResult(pass, count, hasErrors);
|
||||
}
|
||||
|
||||
private static object GetBaseObject(object o)
|
||||
{
|
||||
return o is PSObject pso ? pso.BaseObject : o;
|
||||
}
|
||||
|
||||
private static bool TryBoolean(object o, out bool result)
|
||||
{
|
||||
result = false;
|
||||
if (o == null || !(o is bool bresult))
|
||||
return false;
|
||||
|
||||
result = bresult;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool TryAssertResult(object o, out bool result)
|
||||
{
|
||||
result = false;
|
||||
if (o == null || !(o is AssertResult assert))
|
||||
return false;
|
||||
|
||||
result = assert.Result;
|
||||
|
||||
// Complete results
|
||||
if (PipelineContext.CurrentThread.ExecutionScope == ExecutionScope.Condition)
|
||||
assert.Complete();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class RuleConditionResult
|
||||
{
|
||||
public readonly int Pass;
|
||||
public readonly int Count;
|
||||
public readonly bool HadErrors;
|
||||
|
||||
private RuleConditionResult(int pass, int count, bool hadErrors)
|
||||
internal RuleConditionResult(int pass, int count, bool hadErrors)
|
||||
{
|
||||
Pass = pass;
|
||||
Count = count;
|
||||
|
@ -29,65 +92,5 @@ namespace PSRule.Runtime
|
|||
{
|
||||
return Pass > 0;
|
||||
}
|
||||
|
||||
internal static RuleConditionResult Create(IEnumerable<object> value)
|
||||
{
|
||||
if (value == null)
|
||||
return new RuleConditionResult(pass: 0, count: 0, hadErrors: false);
|
||||
|
||||
var count = 0;
|
||||
var pass = 0;
|
||||
var hasError = false;
|
||||
foreach (var v in value)
|
||||
{
|
||||
count++;
|
||||
if (v == null)
|
||||
continue;
|
||||
|
||||
if (!(TryAssertResult(v, out bool result) || TryBoolean(v, out result)))
|
||||
{
|
||||
RunspaceContext.CurrentThread.ErrorInvaildRuleResult();
|
||||
hasError = true;
|
||||
}
|
||||
else if (result)
|
||||
{
|
||||
pass++;
|
||||
}
|
||||
}
|
||||
return new RuleConditionResult(pass: pass, count: count, hadErrors: hasError);
|
||||
}
|
||||
|
||||
private static bool TryBoolean(object o, out bool result)
|
||||
{
|
||||
result = false;
|
||||
if (o == null)
|
||||
return false;
|
||||
|
||||
var baseObject = o is PSObject pso ? pso.BaseObject : o;
|
||||
if (!(baseObject is bool bresult))
|
||||
return false;
|
||||
|
||||
result = bresult;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool TryAssertResult(object o, out bool result)
|
||||
{
|
||||
result = false;
|
||||
if (o == null)
|
||||
return false;
|
||||
|
||||
var baseObject = o is PSObject pso ? pso.BaseObject : o;
|
||||
if (!(baseObject is AssertResult assert))
|
||||
return false;
|
||||
|
||||
result = assert.Result;
|
||||
|
||||
// Complete results
|
||||
if (PipelineContext.CurrentThread.ExecutionScope == ExecutionScope.Condition)
|
||||
assert.Complete();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,11 +47,11 @@ namespace PSRule
|
|||
{
|
||||
SetContext();
|
||||
var assert = GetAssertionHelper();
|
||||
var actual1 = PSRule.Runtime.RuleConditionResult.Create(new object[] { PSObject.AsPSObject(assert.Create(true, "Test reason")), PSObject.AsPSObject(assert.Create(false, "Test reason")) });
|
||||
var actual1 = PSRule.Runtime.RuleConditionHelper.Create(new object[] { PSObject.AsPSObject(assert.Create(true, "Test reason")), PSObject.AsPSObject(assert.Create(false, "Test reason")) });
|
||||
Assert.True(actual1.AnyOf());
|
||||
Assert.False(actual1.AllOf());
|
||||
|
||||
var actual2 = PSRule.Runtime.RuleConditionResult.Create(new object[] { assert.Create(true, "Test reason"), assert.Create(false, "Test reason") });
|
||||
var actual2 = PSRule.Runtime.RuleConditionHelper.Create(new object[] { assert.Create(true, "Test reason"), assert.Create(false, "Test reason") });
|
||||
Assert.True(actual2.AnyOf());
|
||||
Assert.False(actual2.AllOf());
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче