Exemplo n.º 1
0
            private async Task <ResolvedReferences> ResolveReferencesAsync(ProjectId id, ProjectFileInfo projectFileInfo, CommandLineArguments commandLineArgs, CancellationToken cancellationToken)
            {
                // First, gather all of the metadata references from the command-line arguments.
                var resolvedMetadataReferences = commandLineArgs.ResolveMetadataReferences(
                    new WorkspaceMetadataFileReferenceResolver(
                        metadataService: GetWorkspaceService <IMetadataService>(),
                        pathResolver: new RelativePathResolver(commandLineArgs.ReferencePaths, commandLineArgs.BaseDirectory)));

                var builder = new ResolvedReferencesBuilder(resolvedMetadataReferences);

                var projectDirectory = Path.GetDirectoryName(projectFileInfo.FilePath);

                // Next, iterate through all project references in the file and create project references.
                foreach (var projectFileReference in projectFileInfo.ProjectReferences)
                {
                    var aliases = projectFileReference.Aliases;

                    if (_pathResolver.TryGetAbsoluteProjectPath(projectFileReference.Path, baseDirectory: projectDirectory, _discoveredProjectOptions.OnPathFailure, out var projectReferencePath))
                    {
                        // The easiest case is to add a reference to a project we already know about.
                        if (TryAddReferenceToKnownProject(id, projectReferencePath, aliases, builder))
                        {
                            continue;
                        }

                        // If we don't know how to load a project (that is, it's not a language we support), we can still
                        // attempt to verify that its output exists on disk and is included in our set of metadata references.
                        // If it is, we'll just leave it in place.
                        if (!IsProjectLoadable(projectReferencePath) &&
                            await VerifyUnloadableProjectOutputExistsAsync(projectReferencePath, builder, cancellationToken).ConfigureAwait(false))
                        {
                            continue;
                        }

                        // If metadata is preferred, see if the project reference's output exists on disk and is included
                        // in our metadata references. If it is, don't create a project reference; we'll just use the metadata.
                        if (_preferMetadataForReferencesOfDiscoveredProjects &&
                            await VerifyProjectOutputExistsAsync(projectReferencePath, builder, cancellationToken).ConfigureAwait(false))
                        {
                            continue;
                        }

                        // Finally, we'll try to load and reference the project.
                        if (await TryLoadAndAddReferenceAsync(id, projectReferencePath, aliases, builder, cancellationToken).ConfigureAwait(false))
                        {
                            continue;
                        }
                    }

                    // We weren't able to handle this project reference, so add it without further processing.
                    var unknownProjectId    = _projectMap.GetOrCreateProjectId(projectFileReference.Path);
                    var newProjectReference = CreateProjectReference(from: id, to: unknownProjectId, aliases);
                    builder.AddProjectReference(newProjectReference);
                }

                // Are there still any unresolved metadata references? If so, remove them and report diagnostics.
                foreach (var unresolvedMetadataReference in builder.GetUnresolvedMetadataReferences())
                {
                    var filePath = unresolvedMetadataReference.Reference;

                    builder.Remove(filePath);

                    _diagnosticReporter.Report(new ProjectDiagnostic(
                                                   WorkspaceDiagnosticKind.Warning,
                                                   string.Format(WorkspaceMSBuildResources.Unresolved_metadata_reference_removed_from_project_0, filePath),
                                                   id));
                }

                return(builder.ToResolvedReferences());
            }
Exemplo n.º 2
0
            private async Task <bool> VerifyProjectOutputExistsAsync(string projectPath, ResolvedReferencesBuilder builder, CancellationToken cancellationToken)
            {
                // Note: Load the project, but don't report failures.
                var projectFileInfos = await LoadProjectFileInfosAsync(projectPath, DiagnosticReportingOptions.IgnoreAll, cancellationToken).ConfigureAwait(false);

                foreach (var projectFileInfo in projectFileInfos)
                {
                    var outputFilePath    = projectFileInfo.OutputFilePath;
                    var outputRefFilePath = projectFileInfo.OutputRefFilePath;

                    if ((builder.Contains(outputFilePath) && File.Exists(outputFilePath)) ||
                        (builder.Contains(outputRefFilePath) && File.Exists(outputRefFilePath)))
                    {
                        return(true);
                    }
                }

                return(false);
            }
Exemplo n.º 3
0
            private async Task <bool> TryLoadAndAddReferenceAsync(ProjectId id, string projectReferencePath, ImmutableArray <string> aliases, ResolvedReferencesBuilder builder, CancellationToken cancellationToken)
            {
                var projectReferenceInfos = await LoadProjectInfosFromPathAsync(projectReferencePath, _discoveredProjectOptions, cancellationToken).ConfigureAwait(false);

                if (projectReferenceInfos.IsEmpty)
                {
                    return(false);
                }

                // Find the project reference info whose output we have a metadata reference for.
                ProjectInfo projectReferenceInfo = null;

                foreach (var info in projectReferenceInfos)
                {
                    if (builder.Contains(info.OutputFilePath) ||
                        builder.Contains(info.OutputRefFilePath))
                    {
                        projectReferenceInfo = info;
                        break;
                    }
                }

                if (projectReferenceInfo == null)
                {
                    // We didn't find the project reference info that matches any of our metadata references.
                    // In this case, we'll go ahead and use the first project reference info that was found,
                    // but report a warning because this likely means that either a metadata reference path
                    // or a project output path is incorrect.

                    projectReferenceInfo = projectReferenceInfos[0];

                    _diagnosticReporter.Report(new ProjectDiagnostic(
                                                   WorkspaceDiagnosticKind.Warning,
                                                   string.Format(WorkspaceMSBuildResources.Found_project_reference_without_a_matching_metadata_reference_0, projectReferencePath),
                                                   id));
                }

                if (!ProjectReferenceExists(to: id, from: projectReferenceInfo))
                {
                    var newProjectReference = CreateProjectReference(from: id, to: projectReferenceInfo.Id, aliases);
                    builder.SwapMetadataReferenceForProjectReference(newProjectReference, projectReferenceInfo.OutputRefFilePath, projectReferenceInfo.OutputFilePath);
                }
                else
                {
                    // This project already has a reference on us. Don't introduce a circularity by referencing it.
                    // However, if the project's output doesn't exist on disk, we need to remove from our list of
                    // metadata references to avoid failures later. Essentially, the concern here is that the metadata
                    // reference is an UnresolvedMetadataReference, which will throw when we try to create a
                    // Compilation with it.

                    if (!File.Exists(projectReferenceInfo.OutputRefFilePath))
                    {
                        builder.Remove(projectReferenceInfo.OutputRefFilePath);
                    }

                    if (!File.Exists(projectReferenceInfo.OutputFilePath))
                    {
                        builder.Remove(projectReferenceInfo.OutputFilePath);
                    }
                }

                // Note that we return true even if we don't actually add a reference due to a circularity because,
                // in that case, we've still handled everything.
                return(true);
            }
Exemplo n.º 4
0
            private async Task <bool> VerifyUnloadableProjectOutputExistsAsync(string projectPath, ResolvedReferencesBuilder builder, CancellationToken cancellationToken)
            {
                var outputFilePath = await _buildManager.TryGetOutputFilePathAsync(projectPath, cancellationToken).ConfigureAwait(false);

                return(builder.Contains(outputFilePath) &&
                       File.Exists(outputFilePath));
            }
            private async Task <bool> TryLoadAndAddReferenceAsync(ProjectId id, string projectReferencePath, ImmutableArray <string> aliases, ResolvedReferencesBuilder builder, CancellationToken cancellationToken)
            {
                var projectReferenceInfos = await LoadProjectInfosFromPathAsync(projectReferencePath, _discoveredProjectOptions, cancellationToken).ConfigureAwait(false);

                // Find the project reference info whose output we have a metadata reference for.
                ProjectInfo projectReferenceInfo = null;

                foreach (var info in projectReferenceInfos)
                {
                    if (builder.Contains(info.OutputFilePath) ||
                        builder.Contains(info.OutputRefFilePath))
                    {
                        projectReferenceInfo = info;
                        break;
                    }
                }

                if (projectReferenceInfo == null)
                {
                    return(false);
                }

                if (!ProjectReferenceExists(to: id, from: projectReferenceInfo))
                {
                    var newProjectReference = CreateProjectReference(from: id, to: projectReferenceInfo.Id, aliases);
                    builder.SwapMetadataReferenceForProjectReference(newProjectReference, projectReferenceInfo.OutputRefFilePath, projectReferenceInfo.OutputFilePath);
                }
                else
                {
                    // This project already has a reference on us. Don't introduce a circularity by referencing it.
                    // However, if the project's output doesn't exist on disk, we need to remove from our list of
                    // metadata references to avoid failures later. Essentially, the concern here is that the metadata
                    // reference is an UnresolvedMetadataReference, which will throw when we try to create a
                    // Compilation with it.

                    if (!File.Exists(projectReferenceInfo.OutputRefFilePath))
                    {
                        builder.Remove(projectReferenceInfo.OutputRefFilePath);
                    }

                    if (!File.Exists(projectReferenceInfo.OutputFilePath))
                    {
                        builder.Remove(projectReferenceInfo.OutputFilePath);
                    }
                }

                // Note that we return true even if we don't actually add a reference due to a circularity because,
                // in that case, we've still handled everything.
                return(true);
            }