public static IEnumerable <string> EvaluateExpressionAsPaths(ExpressionNode expression, MSBuildRootDocument doc, int skipEndChars = 0) { if (expression == null) { yield return(Path.GetDirectoryName(doc.Filename)); yield break; } if (expression is ListExpression list) { expression = list.Nodes[list.Nodes.Count - 1]; } if (expression is ExpressionText lit) { var path = TrimEndChars(lit.GetUnescapedValue()); //FIXME handle encoding yield return(MSBuildEscaping.FromMSBuildPath(path, Path.GetDirectoryName(doc.Filename))); yield break; } if (!(expression is ConcatExpression expr)) { yield break; } //FIXME evaluate directly without the MSBuildEvaluationContext var sb = new StringBuilder(); for (int i = 0; i < expr.Nodes.Count; i++) { var node = expr.Nodes[i]; if (node is ExpressionText l) { var val = l.GetUnescapedValue(); if (i == expr.Nodes.Count - 1) { val = TrimEndChars(val); } sb.Append(val); } else if (node is ExpressionProperty p) { sb.Append($"$({p.Name})"); } else { yield break; } } foreach (var variant in doc.FileEvaluationContext.EvaluatePathWithPermutation(sb.ToString(), Path.GetDirectoryName(doc.Filename))) { yield return(variant); } string TrimEndChars(string s) => s.Substring(0, Math.Min(s.Length, s.Length - skipEndChars)); }
public static IEnumerable <string> EvaluateExpressionAsPaths(ExpressionNode expression, MSBuildRootDocument doc, int skipEndChars = 0, string baseDir = null) { baseDir = baseDir ?? Path.GetDirectoryName(doc.Filename); if (expression == null) { yield return(baseDir); yield break; } if (expression is ListExpression list) { expression = list.Nodes[list.Nodes.Count - 1]; } if (expression is ExpressionText lit) { if (lit.Length == 0) { yield return(baseDir); yield break; } var path = TrimEndChars(lit.GetUnescapedValue()); if (string.IsNullOrEmpty(path)) { yield return(baseDir); yield break; } //FIXME handle encoding if (MSBuildEscaping.FromMSBuildPath(path, baseDir, out var res)) { yield return(res); } yield break; } if (!(expression is ConcatExpression expr && expr.Nodes.All(n => n is ExpressionText || (n is ExpressionProperty p && p.IsSimpleProperty)))) { yield break; } foreach (var variant in doc.FileEvaluationContext.EvaluatePathWithPermutation(expr, baseDir)) { yield return(variant); } string TrimEndChars(string s) => s.Substring(0, Math.Min(s.Length, s.Length - skipEndChars)); }
// 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? // can we cache the filesystem lookups? public static IEnumerable <string> EvaluatePathWithPermutation( this IMSBuildEvaluationContext context, ExpressionNode pathExpression, string baseDirectory) { foreach (var p in EvaluateWithPermutation(context, null, pathExpression, 0)) { if (p == null) { continue; } yield return(MSBuildEscaping.FromMSBuildPath(p, baseDirectory)); } }
#pragma warning disable 0169 #region Functions // FIXME imported projects static bool Exists(string file, IExpressionContext context) { if (string.IsNullOrEmpty(file)) { return(false); } string directory = context.FullDirectoryName; file = MSBuildEscaping.FromMSBuildPath(file, directory); bool res; lock (context.ExistsEvaluationCache) { if (context.ExistsEvaluationCache.TryGetValue(file, out res)) { return(res); } res = File.Exists(file) || Directory.Exists(file); context.ExistsEvaluationCache [file] = res; } return(res); }
public static string EvaluatePath( this IMSBuildEvaluationContext context, ExpressionNode expression, string baseDirectory) => MSBuildEscaping.FromMSBuildPath(context.Evaluate(expression), baseDirectory);