예제 #1
0
 public Worker(
     HostWorkspaceServices services,
     DiagnosticReporter diagnosticReporter,
     PathResolver pathResolver,
     ProjectFileLoaderRegistry projectFileLoaderRegistry,
     ProjectBuildManager buildManager,
     ImmutableArray <string> requestedProjectPaths,
     string baseDirectory,
     ImmutableDictionary <string, string> globalProperties,
     ProjectMap projectMap,
     IProgress <ProjectLoadProgress> progress,
     DiagnosticReportingOptions requestedProjectOptions,
     DiagnosticReportingOptions discoveredProjectOptions,
     bool preferMetadataForReferencesOfDiscoveredProjects)
 {
     _workspaceServices         = services;
     _diagnosticReporter        = diagnosticReporter;
     _pathResolver              = pathResolver;
     _projectFileLoaderRegistry = projectFileLoaderRegistry;
     _buildManager              = buildManager;
     _baseDirectory             = baseDirectory;
     _requestedProjectPaths     = requestedProjectPaths;
     _globalProperties          = globalProperties;
     _projectMap = projectMap ?? ProjectMap.Create();
     _progress   = progress;
     _requestedProjectOptions  = requestedProjectOptions;
     _discoveredProjectOptions = discoveredProjectOptions;
     _preferMetadataForReferencesOfDiscoveredProjects = preferMetadataForReferencesOfDiscoveredProjects;
     _projectIdToFileInfoMap          = new Dictionary <ProjectId, ProjectFileInfo>();
     _pathToDiscoveredProjectInfosMap = new Dictionary <string, ImmutableArray <ProjectInfo> >(PathUtilities.Comparer);
     _projectIdToProjectReferencesMap = new Dictionary <ProjectId, List <ProjectReference> >();
 }
예제 #2
0
            private async Task <ImmutableArray <ProjectInfo> > LoadProjectInfosFromPathAsync(
                string projectPath, DiagnosticReportingOptions reportingOptions, CancellationToken cancellationToken)
            {
                if (_projectMap.TryGetProjectInfosByProjectPath(projectPath, out var results) ||
                    _pathToDiscoveredProjectInfosMap.TryGetValue(projectPath, out results))
                {
                    return(results);
                }

                var builder = ImmutableArray.CreateBuilder <ProjectInfo>();

                var projectFileInfos = await LoadProjectFileInfosAsync(projectPath, reportingOptions, cancellationToken).ConfigureAwait(false);

                var idsAndFileInfos = new List <(ProjectId id, ProjectFileInfo fileInfo)>();

                foreach (var projectFileInfo in projectFileInfos)
                {
                    var projectId = _projectMap.GetOrCreateProjectId(projectFileInfo);

                    if (_projectIdToFileInfoMap.ContainsKey(projectId))
                    {
                        // There are multiple projects with the same project path and output path. This can happen
                        // if a multi-TFM project does not have unique output file paths for each TFM. In that case,
                        // we'll create a new ProjectId to ensure that the project is added to the workspace.

                        _diagnosticReporter.Report(
                            DiagnosticReportingMode.Log,
                            string.Format(WorkspaceMSBuildResources.Found_project_with_the_same_file_path_and_output_path_as_another_project_0, projectFileInfo.FilePath));

                        projectId = ProjectId.CreateNewId(debugName: projectFileInfo.FilePath);
                    }

                    idsAndFileInfos.Add((projectId, projectFileInfo));
                    _projectIdToFileInfoMap.Add(projectId, projectFileInfo);
                }

                // If this project resulted in more than a single project, a discrimator (e.g. TFM) should be
                // added to the project name.
                var addDiscriminator = idsAndFileInfos.Count > 1;

                foreach (var(id, fileInfo) in idsAndFileInfos)
                {
                    var projectInfo = await CreateProjectInfoAsync(fileInfo, id, addDiscriminator, cancellationToken).ConfigureAwait(false);

                    builder.Add(projectInfo);
                    _projectMap.AddProjectInfo(projectInfo);
                }

                results = builder.ToImmutable();

                _pathToDiscoveredProjectInfosMap.Add(projectPath, results);

                return(results);
            }
예제 #3
0
            private async Task <ImmutableArray <ProjectFileInfo> > LoadProjectFileInfosAsync(string projectPath, DiagnosticReportingOptions reportingOptions, CancellationToken cancellationToken)
            {
                if (!_projectFileLoaderRegistry.TryGetLoaderFromProjectPath(projectPath, reportingOptions.OnLoaderFailure, out var loader))
                {
                    return(ImmutableArray <ProjectFileInfo> .Empty); // Failure should already be reported.
                }

                var projectFile = await DoOperationAndReportProgressAsync(
                    ProjectLoadOperation.Evaluate,
                    projectPath,
                    targetFramework : null,
                    () => loader.LoadProjectFileAsync(projectPath, _buildManager, cancellationToken)
                    ).ConfigureAwait(false);

                // If there were any failures during load, we won't be able to build the project. So, bail early with an empty project.
                if (projectFile.Log.HasFailure)
                {
                    _diagnosticReporter.Report(projectFile.Log);

                    return(ImmutableArray.Create(
                               ProjectFileInfo.CreateEmpty(loader.Language, projectPath, projectFile.Log)));
                }

                var projectFileInfos = await DoOperationAndReportProgressAsync(
                    ProjectLoadOperation.Build,
                    projectPath,
                    targetFramework : null,
                    () => projectFile.GetProjectFileInfosAsync(cancellationToken)
                    ).ConfigureAwait(false);

                var results = ImmutableArray.CreateBuilder <ProjectFileInfo>(projectFileInfos.Length);

                foreach (var projectFileInfo in projectFileInfos)
                {
                    // If any diagnostics were logged during build, we'll carry on and try to produce a meaningful project.
                    if (!projectFileInfo.Log.IsEmpty)
                    {
                        _diagnosticReporter.Report(projectFileInfo.Log);
                    }

                    results.Add(projectFileInfo);
                }

                return(results.MoveToImmutable());
            }
예제 #4
0
        /// <summary>
        /// Loads the <see cref="SolutionInfo"/> for the specified solution file, including all projects referenced by the solution file and
        /// all the projects referenced by the project files.
        /// </summary>
        /// <param name="solutionFilePath">The path to the solution file to be loaded. This may be an absolute path or a path relative to the
        /// current working directory.</param>
        /// <param name="progress">An optional <see cref="IProgress{T}"/> that will receive updates as the solution is loaded.</param>
        /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> to allow cancellation of this operation.</param>
        public async Task <SolutionInfo> LoadSolutionInfoAsync(
            string solutionFilePath,
            IProgress <ProjectLoadProgress> progress = null,
            CancellationToken cancellationToken      = default)
        {
            if (solutionFilePath == null)
            {
                throw new ArgumentNullException(nameof(solutionFilePath));
            }

            if (!_pathResolver.TryGetAbsoluteSolutionPath(solutionFilePath, baseDirectory: Directory.GetCurrentDirectory(), DiagnosticReportingMode.Throw, out var absoluteSolutionPath))
            {
                // TryGetAbsoluteSolutionPath should throw before we get here.
                return(null);
            }

            using (_dataGuard.DisposableWait(cancellationToken))
            {
                this.SetSolutionProperties(absoluteSolutionPath);
            }

            var solutionFile = MSB.Construction.SolutionFile.Parse(absoluteSolutionPath);

            var reportingMode = GetReportingModeForUnrecognizedProjects();

            var reportingOptions = new DiagnosticReportingOptions(
                onPathFailure: reportingMode,
                onLoaderFailure: reportingMode);

            var projectPaths = ImmutableArray.CreateBuilder <string>();

            // load all the projects
            foreach (var project in solutionFile.ProjectsInOrder)
            {
                cancellationToken.ThrowIfCancellationRequested();

                if (project.ProjectType != MSB.Construction.SolutionProjectType.SolutionFolder)
                {
                    projectPaths.Add(project.RelativePath);
                }
            }

            var buildManager = new ProjectBuildManager(_properties);

            var worker = new Worker(
                _workspaceServices,
                _diagnosticReporter,
                _pathResolver,
                _projectFileLoaderRegistry,
                buildManager,
                projectPaths.ToImmutable(),
                baseDirectory: Path.GetDirectoryName(absoluteSolutionPath),
                _properties,
                projectMap: null,
                progress,
                requestedProjectOptions: reportingOptions,
                discoveredProjectOptions: reportingOptions,
                preferMetadataForReferencesOfDiscoveredProjects: false);

            var projects = await worker.LoadAsync(cancellationToken).ConfigureAwait(false);

            // construct workspace from loaded project infos
            return(SolutionInfo.Create(
                       SolutionId.CreateNewId(debugName: absoluteSolutionPath),
                       version: default,