/// <summary> /// Initializes the in memory project. Sets BuildEnabled on the project to true. /// </summary> /// <param name="buildEngine">The build engine to use to create a build project.</param> /// <param name="fullProjectPath">The full path of the project.</param> /// <returns>A loaded msbuild project.</returns> public static Microsoft.Build.Evaluation.Project InitializeMsBuildProject(Microsoft.Build.Evaluation.ProjectCollection buildEngine, string fullProjectPath) { if (buildEngine == null) { throw new ArgumentNullException("buildEngine"); } if (String.IsNullOrEmpty(fullProjectPath)) { throw new ArgumentException(SR.GetString(SR.InvalidParameter, CultureInfo.CurrentUICulture), "fullProjectPath"); } // Check if the project already has been loaded with the fullProjectPath. If yes return the build project associated to it. var prjs = new List <Microsoft.Build.Evaluation.Project>(buildEngine.GetLoadedProjects(fullProjectPath)); System.Diagnostics.Debug.Assert(prjs.Count <= 1, string.Format("more than one loaded project with same filename '{0}'", fullProjectPath)); Microsoft.Build.Evaluation.Project buildProject = prjs.Count == 0 ? null : prjs[0]; if (buildProject == null) { var globalProperties = new Dictionary <string, string>() { { "FSharpCompilerPath", Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) } }; buildProject = buildEngine.LoadProject(fullProjectPath, globalProperties, null); buildProject.IsBuildEnabled = true; } return(buildProject); }
private static async Task <(MSB.Evaluation.Project?project, DiagnosticLog log)> LoadProjectAsync( string path, MSB.Evaluation.ProjectCollection?projectCollection, CancellationToken cancellationToken) { var log = new DiagnosticLog(); try { var loadedProjects = projectCollection?.GetLoadedProjects(path); if (loadedProjects != null && loadedProjects.Count > 0) { Debug.Assert(loadedProjects.Count == 1); return(loadedProjects.First(), log); } using var stream = FileUtilities.OpenAsyncRead(path); using var readStream = await SerializableBytes.CreateReadableStreamAsync(stream, cancellationToken).ConfigureAwait(false); using var xmlReader = XmlReader.Create(readStream, s_xmlReaderSettings); var xml = MSB.Construction.ProjectRootElement.Create(xmlReader, projectCollection); // When constructing a project from an XmlReader, MSBuild cannot determine the project file path. Setting the // path explicitly is necessary so that the reserved properties like $(MSBuildProjectDirectory) will work. xml.FullPath = path; var project = new MSB.Evaluation.Project(xml, globalProperties: null, toolsVersion: null, projectCollection); return(project, log); } catch (Exception e) { log.Add(e, path); return(project : null, log); } }
private static MSB.Evaluation.Project FindProject( string path, IDictionary <string, string> globalProperties, MSB.Evaluation.ProjectCollection projectCollection, CancellationToken cancellationToken) { var loadedProjects = projectCollection.GetLoadedProjects(path); if (loadedProjects == null || loadedProjects.Count == 0) { return(null); } // We need to walk through all of the projects that have been previously loaded from this path and // find the one that has the given set of global properties, plus the default global properties that // we load every project with. globalProperties = globalProperties ?? ImmutableDictionary <string, string> .Empty; var totalGlobalProperties = projectCollection.GlobalProperties.Count + globalProperties.Count; foreach (var loadedProject in loadedProjects) { cancellationToken.ThrowIfCancellationRequested(); // If this project has a different number of global properties than we expect, it's not the // one we're looking for. if (loadedProject.GlobalProperties.Count != totalGlobalProperties) { continue; } // Since we loaded all of them, the projects in this collection should all have the default // global properties (i.e. the ones in _projectCollection.GlobalProperties). So, we just need to // check the extra global properties. var found = true; foreach (var(key, value) in globalProperties) { // MSBuild escapes the values of a project's global properties, so we must too. var escapedValue = MSB.Evaluation.ProjectCollection.Escape(value); if (!loadedProject.GlobalProperties.TryGetValue(key, out var actualValue) || !string.Equals(actualValue, escapedValue, StringComparison.Ordinal)) { found = false; break; } } if (found) { return(loadedProject); } } // We couldn't find a project with this path and the set of global properties we expect. return(null); }