public static MSBuildEvaluationContext Create(IRuntimeInformation runtime, string projectPath, string thisFilePath) { // MSBuildEvaluationContext can only populate these properties from an MSBuildProject and we don't have one // OTOH this isn't a full evaluation anyway. Just set up a bunch of properties commonly used for imports. // TODO: add more commonly used properties var ctx = new MSBuildEvaluationContext(); string tvString = MSBuildToolsVersion.Unknown.ToVersionString(); string binPath = MSBuildProjectService.ToMSBuildPath(null, runtime.GetBinPath()); string toolsPath = MSBuildProjectService.ToMSBuildPath(null, runtime.GetToolsPath()); var extPaths = runtime.GetExtensionsPaths(); ctx.extensionPaths = new List <string> (extPaths); AddReadOnlyProp("MSBuildBinPath", binPath); AddReadOnlyProp("MSBuildToolsPath", toolsPath); AddReadOnlyProp("MSBuildToolsPath32", toolsPath); AddReadOnlyProp("MSBuildToolsPath64", toolsPath); AddReadOnlyProp("RoslynTargetsPath", $"{binPath}\\Roslyn"); AddReadOnlyProp("MSBuildToolsVersion", tvString); var extPath = MSBuildProjectService.ToMSBuildPath(null, extPaths.First()); AddReadOnlyProp("MSBuildExtensionsPath", extPath); AddReadOnlyProp("MSBuildExtensionsPath32", extPath); AddReadOnlyProp("VisualStudioVersion", "15.0"); var defaultSdksPath = runtime.GetSdksPath(); if (defaultSdksPath != null) { AddReadOnlyProp("MSBuildSDKsPath", MSBuildProjectService.ToMSBuildPath(null, defaultSdksPath)); } // project path properties string escapedProjectDir = MSBuildProjectService.ToMSBuildPath(null, Path.GetDirectoryName(projectPath)); AddReadOnlyProp("MSBuildProjectDirectory", escapedProjectDir); // "MSBuildProjectDirectoryNoRoot" is this actually used for anything? AddReadOnlyProp("MSBuildProjectExtension", MSBuildProjectService.EscapeString(Path.GetExtension(projectPath))); AddReadOnlyProp("MSBuildProjectFile", MSBuildProjectService.EscapeString(Path.GetFileName(projectPath))); AddReadOnlyProp("MSBuildProjectFullPath", MSBuildProjectService.ToMSBuildPath(null, Path.GetFullPath(projectPath))); AddReadOnlyProp("MSBuildProjectName", MSBuildProjectService.EscapeString(Path.GetFileNameWithoutExtension(projectPath))); //don't have a better value, this is as good as anything AddReadOnlyProp("MSBuildStartupDirectory", escapedProjectDir); // this file path properties AddReadOnlyProp("MSBuildThisFile", MSBuildProjectService.EscapeString(Path.GetFileName(thisFilePath))); AddReadOnlyProp("MSBuildThisFileDirectory", MSBuildProjectService.ToMSBuildPath(null, Path.GetDirectoryName(thisFilePath)) + "\\"); //"MSBuildThisFileDirectoryNoRoot" is this actually used for anything? AddReadOnlyProp("MSBuildThisFileExtension", MSBuildProjectService.EscapeString(Path.GetExtension(thisFilePath))); AddReadOnlyProp("MSBuildThisFileFullPath", MSBuildProjectService.ToMSBuildPath(null, Path.GetFullPath(thisFilePath))); AddReadOnlyProp("MSBuildThisFileName", MSBuildProjectService.EscapeString(Path.GetFileNameWithoutExtension(thisFilePath))); //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")); AddReadOnlyProp("MSBuildProjectExtensionsPath", MSBuildProjectService.ToMSBuildPath(null, projectExtensionsPath) + "\\"); return(ctx); void AddReadOnlyProp(string key, string val) { ctx.SetPropertyValue(key, val); readonlyProps.Add(key); } }
//TODO: guard against excessive permutation //TODO: return a new context instead of altering this one? static IEnumerable <MSBuildEvaluationContext> PermuteProperties(MSBuildEvaluationContext evalCtx, List <(string, List <string>)> multivaluedProperties, int idx = 0)