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 MSBuildRuntimeEvaluationContext(IRuntimeInformation runtime) { if (runtime is Editor.Completion.NullRuntimeInformation) { return; } string binPath = MSBuildEscaping.ToMSBuildPath(runtime.BinPath); string toolsPath = MSBuildEscaping.ToMSBuildPath(runtime.ToolsPath); Convert("MSBuildExtensionsPath"); Convert("MSBuildExtensionsPath32"); Convert("MSBuildExtensionsPath64"); void Convert(string name) { if (runtime.SearchPaths.TryGetValue(name, out var vals)) { values[name] = new MSBuildPropertyValue(vals.ToArray()); } } values["MSBuildBinPath"] = binPath; values["MSBuildToolsPath"] = toolsPath; values["MSBuildToolsPath32"] = toolsPath; values["MSBuildToolsPath64"] = toolsPath; values["RoslynTargetsPath"] = $"{binPath}\\Roslyn"; values["MSBuildToolsVersion"] = runtime.ToolsVersion; values["VisualStudioVersion"] = "15.0"; values["MSBuildProgramFiles32"] = MSBuildEscaping.ToMSBuildPath(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86)); values["MSBuildProgramFiles64"] = MSBuildEscaping.ToMSBuildPath(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)); var defaultSdksPath = runtime.SdksPath; if (defaultSdksPath != null) { values["MSBuildSDKsPath"] = MSBuildEscaping.ToMSBuildPath(defaultSdksPath, null); } //these are read from a config file and may be described in terms of other properties void Collapse(string name) { if (values.TryGetValue(name, out var val)) { values["name"] = val.Collapse(this); } } Collapse("MSBuildExtensionsPath"); Collapse("MSBuildExtensionsPath32"); Collapse("MSBuildExtensionsPath64"); }
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)); } }
public MSBuildFileEvaluationContext( IMSBuildEvaluationContext runtimeContext, string projectPath, string thisFilePath) { this.runtimeContext = runtimeContext ?? throw new ArgumentNullException(nameof(runtimeContext)); // this file path properties if (thisFilePath != null) { values["MSBuildThisFile"] = MSBuildEscaping.EscapeString(Path.GetFileName(thisFilePath)); values["MSBuildThisFileDirectory"] = MSBuildEscaping.ToMSBuildPath(Path.GetDirectoryName(thisFilePath)) + "\\"; //"MSBuildThisFileDirectoryNoRoot" is this actually used for anything? values["MSBuildThisFileExtension"] = MSBuildEscaping.EscapeString(Path.GetExtension(thisFilePath)); values["MSBuildThisFileFullPath"] = MSBuildEscaping.ToMSBuildPath(Path.GetFullPath(thisFilePath)); values["MSBuildThisFileName"] = MSBuildEscaping.EscapeString(Path.GetFileNameWithoutExtension(thisFilePath)); } if (projectPath == null) { return; } // project path properties string escapedProjectDir = MSBuildEscaping.ToMSBuildPath(Path.GetDirectoryName(projectPath)); values["MSBuildProjectDirectory"] = escapedProjectDir; // "MSBuildProjectDirectoryNoRoot" is this actually used for anything? values["MSBuildProjectExtension"] = MSBuildEscaping.EscapeString(Path.GetExtension(projectPath)); values["MSBuildProjectFile"] = MSBuildEscaping.EscapeString(Path.GetFileName(projectPath)); values["MSBuildProjectFullPath"] = MSBuildEscaping.ToMSBuildPath(Path.GetFullPath(projectPath)); values["MSBuildProjectName"] = MSBuildEscaping.EscapeString(Path.GetFileNameWithoutExtension(projectPath)); //don't have a better value, this is as good as anything values["MSBuildStartupDirectory"] = escapedProjectDir; //HACK: we don't get a usable value for this without real evaluation so hardcode 'obj' var projectExtensionsPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(projectPath), "obj")); values["MSBuildProjectExtensionsPath"] = MSBuildEscaping.ToMSBuildPath(projectExtensionsPath) + "\\"; }
#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);