private void ResolveDependencies(Dictionary <LibraryKey, LibraryDescription> libraries, ReferenceAssemblyDependencyResolver referenceAssemblyDependencyResolver, out bool requiresFrameworkAssemblies) { // Remark: the LibraryType in the key of the given dictionary are all "Unspecified" at the beginning. requiresFrameworkAssemblies = false; foreach (var pair in libraries.ToList()) { var library = pair.Value; // The System.* packages provide placeholders on any non netstandard platform // To make them work seamlessly on those platforms, we fill the gap with a reference // assembly (if available) var package = library as PackageDescription; if (package != null && package.Resolved && package.HasCompileTimePlaceholder && !TargetFramework.IsPackageBased) { // requiresFrameworkAssemblies is true whenever we find a CompileTimePlaceholder in a non-package based framework, even if // the reference is unresolved. This ensures the best error experience when someone is building on a machine without // the target framework installed. requiresFrameworkAssemblies = true; var newKey = new LibraryKey(library.Identity.Name, LibraryType.Reference); var dependency = new ProjectLibraryDependency { LibraryRange = new LibraryRange(library.Identity.Name, LibraryDependencyTarget.Reference) }; var replacement = referenceAssemblyDependencyResolver.GetDescription(dependency, TargetFramework); // If the reference is unresolved, just skip it. Don't replace the package dependency if (replacement == null) { continue; } // Remove the original package reference libraries.Remove(pair.Key); // Insert a reference assembly key if there isn't one if (!libraries.ContainsKey(newKey)) { libraries[newKey] = replacement; } } } foreach (var pair in libraries.ToList()) { var library = pair.Value; library.Framework = library.Framework ?? TargetFramework; foreach (var dependency in library.Dependencies) { var keyType = dependency.LibraryRange.TypeConstraint == LibraryDependencyTarget.Reference ? LibraryType.Reference : (LibraryType?)null; var key = new LibraryKey(dependency.Name, keyType); LibraryDescription dependencyDescription; if (!libraries.TryGetValue(key, out dependencyDescription)) { if (keyType == LibraryType.Reference) { // a dependency is specified to be reference assembly but fail to match // then add a unresolved dependency dependencyDescription = referenceAssemblyDependencyResolver.GetDescription(dependency, TargetFramework) ?? UnresolvedDependencyProvider.GetDescription(dependency, TargetFramework); libraries[key] = dependencyDescription; } else if (!libraries.TryGetValue(new LibraryKey(dependency.Name, LibraryType.Reference), out dependencyDescription)) { // a dependency which type is unspecified fails to match, then try to find a // reference assembly type dependency dependencyDescription = UnresolvedDependencyProvider.GetDescription(dependency, TargetFramework); libraries[key] = dependencyDescription; } } dependencyDescription.RequestedRanges.Add(dependency); dependencyDescription.Parents.Add(library); } } // Deduplicate libraries with the same name // Priority list is backwards so not found -1 would be last when sorting by descending var priorities = new[] { LibraryType.Package, LibraryType.Project, LibraryType.Reference }; var nameGroups = libraries.Keys.ToLookup(libraryKey => libraryKey.Name); foreach (var nameGroup in nameGroups) { var librariesToRemove = nameGroup .OrderByDescending(libraryKey => Array.IndexOf(priorities, libraryKey.LibraryType)) .Skip(1); foreach (var library in librariesToRemove) { libraries.Remove(library); } } }
public ProjectContext Build() { var diagnostics = new List <DiagnosticMessage>(); ProjectDirectory = Project?.ProjectDirectory ?? ProjectDirectory; GlobalSettings globalSettings = null; if (ProjectDirectory != null) { RootDirectory = ProjectRootResolver.ResolveRootDirectory(ProjectDirectory); GlobalSettings.TryGetGlobalSettings(RootDirectory, out globalSettings); } RootDirectory = globalSettings?.DirectoryPath ?? RootDirectory; FrameworkReferenceResolver frameworkReferenceResolver; if (string.IsNullOrEmpty(ReferenceAssembliesPath)) { // Use the default static resolver frameworkReferenceResolver = FrameworkReferenceResolver.Default; } else { frameworkReferenceResolver = new FrameworkReferenceResolver(ReferenceAssembliesPath); } LockFileLookup lockFileLookup = null; EnsureProjectLoaded(); ReadLockFile(diagnostics); // some callers only give ProjectContextBuilder a LockFile ProjectDirectory = ProjectDirectory ?? TryGetProjectDirectoryFromLockFile(); INuGetPathContext nugetPathContext = null; if (ProjectDirectory != null) { nugetPathContext = NuGetPathContext.Create(ProjectDirectory); } PackagesDirectory = PackagesDirectory ?? nugetPathContext?.UserPackageFolder; var validLockFile = true; string lockFileValidationMessage = null; if (LockFile != null) { if (Project != null) { validLockFile = LockFile.IsValidForProject(Project, out lockFileValidationMessage); } lockFileLookup = new LockFileLookup(LockFile); } var libraries = new Dictionary <LibraryKey, LibraryDescription>(); var projectResolver = new ProjectDependencyProvider(ProjectResolver); ProjectDescription mainProject = null; if (Project != null) { mainProject = projectResolver.GetDescription(TargetFramework, Project, targetLibrary: null); // Add the main project libraries.Add(new LibraryKey(mainProject.Identity.Name), mainProject); } ProjectLibraryDependency platformDependency = null; if (mainProject != null) { platformDependency = mainProject.Dependencies .Where(d => d.Type.Equals(LibraryDependencyType.Platform)) .Cast <ProjectLibraryDependency>() .FirstOrDefault(); } bool isPortable = platformDependency != null; LockFileTarget target = null; LibraryDescription platformLibrary = null; if (lockFileLookup != null) { target = SelectTarget(LockFile, isPortable); if (target != null) { var nugetPackageResolver = new PackageDependencyProvider(nugetPathContext, frameworkReferenceResolver); var msbuildProjectResolver = new MSBuildDependencyProvider(Project, ProjectResolver); ScanLibraries(target, lockFileLookup, libraries, msbuildProjectResolver, nugetPackageResolver, projectResolver); if (platformDependency != null) { libraries.TryGetValue(new LibraryKey(platformDependency.Name), out platformLibrary); } } } string runtime = target?.RuntimeIdentifier; if (string.IsNullOrEmpty(runtime) && TargetFramework.IsDesktop()) { // we got a ridless target for desktop so turning portable mode on isPortable = true; var legacyRuntime = RuntimeEnvironmentRidExtensions.GetLegacyRestoreRuntimeIdentifier(); if (RuntimeIdentifiers.Contains(legacyRuntime)) { runtime = legacyRuntime; } else { runtime = RuntimeIdentifiers.FirstOrDefault(); } } var referenceAssemblyDependencyResolver = new ReferenceAssemblyDependencyResolver(frameworkReferenceResolver); bool requiresFrameworkAssemblies; // Resolve the dependencies ResolveDependencies(libraries, referenceAssemblyDependencyResolver, out requiresFrameworkAssemblies); // REVIEW: Should this be in NuGet (possibly stored in the lock file?) if (LockFile == null) { diagnostics.Add(new DiagnosticMessage( ErrorCodes.NU1009, $"The expected lock file doesn't exist. Please run \"dotnet restore\" to generate a new lock file.", Path.Combine(Project.ProjectDirectory, LockFileFormat.LockFileName), DiagnosticMessageSeverity.Error)); } if (!validLockFile) { diagnostics.Add(new DiagnosticMessage( ErrorCodes.NU1006, $"{lockFileValidationMessage}. Please run \"dotnet restore\" to generate a new lock file.", Path.Combine(Project.ProjectDirectory, LockFileFormat.LockFileName), DiagnosticMessageSeverity.Warning)); } if (requiresFrameworkAssemblies) { var frameworkInfo = Project.GetTargetFramework(TargetFramework); if (frameworkReferenceResolver == null || string.IsNullOrEmpty(frameworkReferenceResolver.ReferenceAssembliesPath)) { // If there was an attempt to use reference assemblies but they were not installed // report an error diagnostics.Add(new DiagnosticMessage( ErrorCodes.DOTNET1012, $"The reference assemblies directory was not specified. You can set the location using the DOTNET_REFERENCE_ASSEMBLIES_PATH environment variable.", filePath: Project.ProjectFilePath, severity: DiagnosticMessageSeverity.Error, startLine: frameworkInfo.Line, startColumn: frameworkInfo.Column )); } else if (!frameworkReferenceResolver.IsInstalled(TargetFramework)) { // If there was an attempt to use reference assemblies but they were not installed // report an error diagnostics.Add(new DiagnosticMessage( ErrorCodes.DOTNET1011, $"Framework not installed: {TargetFramework.DotNetFrameworkName} in {ReferenceAssembliesPath}", filePath: Project.ProjectFilePath, severity: DiagnosticMessageSeverity.Error, startLine: frameworkInfo.Line, startColumn: frameworkInfo.Column )); } } List <DiagnosticMessage> allDiagnostics = new List <DiagnosticMessage>(diagnostics); if (Project != null) { allDiagnostics.AddRange(Project.Diagnostics); } // Create a library manager var libraryManager = new LibraryManager(libraries.Values.ToList(), allDiagnostics, Project?.ProjectFilePath); return(new ProjectContext( globalSettings, mainProject, platformLibrary, TargetFramework, isPortable, runtime, PackagesDirectory, libraryManager, LockFile, diagnostics)); }