public void PropertyCollectorEvaluationContextTest() { var collector = new PropertyValueCollector(false); collector.Mark("Hello"); collector.Collect("Hello", new ExpressionText(0, "One", true)); collector.Collect("Hello", new ExpressionText(0, "Two", true)); var ctx = new MSBuildCollectedValuesEvaluationContext( new TestEvaluationContext(), collector ); var vals = ctx.EvaluateWithPermutation("$(Hello)").ToList(); Assert.AreEqual(2, vals.Count); Assert.AreEqual("One", vals[0]); Assert.AreEqual("Two", vals[1]); }
// FIXME: need to make this more efficient. can we ignore results where a property was simply not found? // can we tokenize it and check each level of the path exists before drilling down? internal IEnumerable <string> EvaluatePathWithPermutation(string path, string basePath, PropertyValueCollector propVals) { //fast path for imports without properties, will generally be true for SDK imports if (path.IndexOf('$') < 0) { yield return(EvaluatePath(path, basePath)); yield break; } if (propVals != null) { //ensure each of the properties is fully evaluated //FIXME this is super hacky, use real MSBuild evaluation foreach (var p in propVals) { if (p.Value != null && !readonlyProps.Contains(p.Key)) { for (int i = 0; i < p.Value.Count; i++) { var val = p.Value [i]; int recDepth = 0; try { while (val.IndexOf('$') > -1 && (recDepth++ < 10)) { val = Evaluate(val); } if (val != null && val.IndexOf('$') < 0) { SetPropertyValue(p.Key, val); } if (string.IsNullOrEmpty(val)) { p.Value.RemoveAt(i); i--; } else { p.Value [i] = val; } } catch { //this happens a lot with things like property functions that //index into null values, so make it quiet //LoggingService.LogDebug ($"Error evaluating property {p.Key}={val}"); //FIXME stop ignoring these errors } } } } //TODO: use a new context instead of altering this one? foreach (var p in propVals) { if (p.Value != null && p.Value.Count > 0 && !readonlyProps.Contains(p.Key)) { SetPropertyValue(p.Key, p.Value [0]); } } } //permute on properties for which we have multiple values var expr = ExpressionParser.Parse(path, ExpressionOptions.None); var propsToPermute = new List <(string, List <string>)> (); foreach (var prop in expr.WithAllDescendants().OfType <ExpressionProperty> ()) { if (readonlyProps.Contains(prop.Name)) { continue; } if (propVals != null && propVals.TryGetValues(prop.Name, out List <string> values) && values != null) { if (values.Count > 1) { propsToPermute.Add((prop.Name, values)); } } else if (extensionPaths != null && string.Equals(prop.Name, "MSBuildExtensionsPath", StringComparison.OrdinalIgnoreCase) || string.Equals(prop.Name, "MSBuildExtensionsPath32", StringComparison.OrdinalIgnoreCase)) { propsToPermute.Add((prop.Name, extensionPaths)); } } if (propsToPermute.Count == 0) { yield return(EvaluatePath(path, basePath)); } else { foreach (var ctx in PermuteProperties(this, propsToPermute)) { yield return(EvaluatePath(path, basePath)); } } }
public MSBuildCollectedValuesEvaluationContext(IMSBuildEvaluationContext fileContext, PropertyValueCollector collector) { this.collector = collector; this.fileContext = fileContext; }