public PackageSpecReferenceDependencyProvider( IPackageSpecResolver projectResolver, ExternalProjectReference projectReference) { _resolver = projectResolver; _projectReference = projectReference; }
/// <summary> /// UWP Project.json /// </summary> private List <LibraryDependency> GetDependenciesFromExternalReference( ExternalProjectReference externalReference, PackageSpec packageSpec, NuGetFramework targetFramework) { var dependencies = GetSpecDependencies(packageSpec, targetFramework); if (externalReference != null) { var childReferences = GetChildReferences(externalReference); var childReferenceNames = childReferences.Select(reference => reference.ProjectName).ToList(); // External references are created without pivoting on the TxM. Here we need to account for this // and filter out references except the nearest TxM. var filteredExternalDependencies = new HashSet <string>( childReferenceNames, StringComparer.OrdinalIgnoreCase); // Set all dependencies from project.json to external if an external match was passed in // This is viral and keeps p2ps from looking into directories when we are going down // a path already resolved by msbuild. foreach (var dependency in dependencies.Where(d => IsProject(d) && filteredExternalDependencies.Contains(d.Name))) { dependency.LibraryRange.TypeConstraint = LibraryDependencyTarget.ExternalProject; } // Add dependencies passed in externally // These are usually msbuild references which have less metadata, they have // the lowest priority. // Note: Only add in dependencies that are in the filtered list to avoid getting the wrong TxM dependencies.AddRange(childReferences .Where(reference => filteredExternalDependencies.Contains(reference.ProjectName)) .Select(reference => new LibraryDependency { LibraryRange = new LibraryRange { Name = reference.ProjectName, VersionRange = VersionRange.Parse("1.0.0"), TypeConstraint = LibraryDependencyTarget.ExternalProject } })); } return(dependencies); }
private List <ExternalProjectReference> GetChildReferences(ExternalProjectReference parent) { var children = new List <ExternalProjectReference>(parent.ExternalProjectReferences.Count); foreach (var reference in parent.ExternalProjectReferences) { ExternalProjectReference childReference; if (!_externalProjectsByUniqueName.TryGetValue(reference, out childReference)) { // Create a reference to mark that this project is unresolved here childReference = new ExternalProjectReference( uniqueName: reference, packageSpec: null, msbuildProjectPath: null, projectReferences: Enumerable.Empty <string>()); } children.Add(childReference); } return(children); }
public Library GetLibrary(LibraryRange libraryRange, NuGetFramework targetFramework) { Library library = null; var name = libraryRange.Name; ExternalProjectReference externalReference = null; PackageSpec packageSpec = null; // This must exist in the external references if (_externalProjectsByUniqueName.TryGetValue(name, out externalReference)) { packageSpec = externalReference.PackageSpec; } if (externalReference == null && packageSpec == null) { // unable to find any projects return(null); } // create a dictionary of dependencies to make sure that no duplicates exist var dependencies = new List <LibraryDependency>(); var projectStyle = packageSpec?.RestoreMetadata?.ProjectStyle ?? ProjectStyle.Unknown; // Read references from external project - we don't care about dotnettool projects, since they don't have project refs if (projectStyle == ProjectStyle.PackageReference) { // NETCore dependencies.AddRange(GetDependenciesFromSpecRestoreMetadata(packageSpec, targetFramework)); } else { // UWP dependencies.AddRange(GetDependenciesFromExternalReference(externalReference, packageSpec, targetFramework)); } // Remove duplicate dependencies. A reference can exist both in csproj and project.json // dependencies is already ordered by importance here var uniqueDependencies = new List <LibraryDependency>(dependencies.Count); var projectNames = new HashSet <string>(StringComparer.OrdinalIgnoreCase); foreach (var project in dependencies) { if (projectNames.Add(project.Name)) { uniqueDependencies.Add(project); } } library = new Library { LibraryRange = libraryRange, Identity = new LibraryIdentity { Name = externalReference?.ProjectName ?? packageSpec.Name, Version = packageSpec?.Version ?? new NuGetVersion(1, 0, 0), Type = LibraryType.Project, }, Path = packageSpec?.FilePath, Dependencies = uniqueDependencies, Resolved = true }; // Add msbuild path var msbuildPath = externalReference?.MSBuildProjectPath; if (msbuildPath != null) { library[KnownLibraryProperties.MSBuildProjectPath] = msbuildPath; } if (packageSpec != null) { // Additional library properties AddLibraryProperties(library, packageSpec, targetFramework, msbuildPath); } return(library); }
public Library GetLibrary(LibraryRange libraryRange, NuGetFramework targetFramework, string rootPath) { Library library = null; var name = libraryRange.Name; ExternalProjectReference externalReference = null; PackageSpec packageSpec = null; bool resolvedUsingDirectory = false; // Check the external references first if (_externalProjectsByName.TryGetValue(name, out externalReference)) { packageSpec = externalReference.PackageSpec; } else if (libraryRange.TypeConstraintAllows(LibraryDependencyTarget.Project)) { // Find the package spec resolver for this root path. var specResolver = GetPackageSpecResolver(rootPath); // Allow directory look ups unless this constrained to external resolvedUsingDirectory = specResolver.TryResolvePackageSpec(name, out packageSpec); } if (externalReference == null && packageSpec == null) { // unable to find any projects return(null); } // create a dictionary of dependencies to make sure that no duplicates exist var dependencies = new List <LibraryDependency>(); TargetFrameworkInformation targetFrameworkInfo = null; if (packageSpec != null) { // Add dependencies section dependencies.AddRange(packageSpec.Dependencies); // Add framework specific dependencies targetFrameworkInfo = packageSpec.GetTargetFramework(targetFramework); dependencies.AddRange(targetFrameworkInfo.Dependencies); // Remove all framework assemblies dependencies.RemoveAll(d => d.LibraryRange.TypeConstraint == LibraryDependencyTarget.Reference); // Disallow projects (resolved by directory) for non-xproj msbuild projects. // If there is no msbuild path then resolving by directory is allowed. // CSProj does not allow directory to directory look up. if (XProjUtility.IsMSBuildBasedProject(externalReference?.MSBuildProjectPath)) { foreach (var dependency in dependencies) { // Remove "project" from the allowed types for this dependency // This will require that projects referenced by an msbuild project // must be external projects. dependency.LibraryRange.TypeConstraint &= ~LibraryDependencyTarget.Project; } } } if (externalReference != null) { var childReferences = GetChildReferences(externalReference); var childReferenceNames = childReferences.Select(reference => reference.ProjectName).ToList(); // External references are created without pivoting on the TxM. Here we need to account for this // and filter out references except the nearest TxM. var filteredExternalDependencies = new HashSet <string>( childReferenceNames, StringComparer.OrdinalIgnoreCase); // Non-Xproj projects may only have one TxM, all external references should be // included if this is an msbuild based project. if (packageSpec != null && !XProjUtility.IsMSBuildBasedProject(externalReference.MSBuildProjectPath)) { // Create an exclude list of all references from the non-selected TxM // Start with all framework specific references var allFrameworkDependencies = GetProjectNames( packageSpec.TargetFrameworks.SelectMany(info => info.Dependencies)); var excludedDependencies = new HashSet <string>( allFrameworkDependencies, StringComparer.OrdinalIgnoreCase); // Then clear out excluded dependencies that are found in the good dependency list foreach (var dependency in GetProjectNames(dependencies)) { excludedDependencies.Remove(dependency); } // Remove excluded dependencies from the external list foreach (var excluded in excludedDependencies) { filteredExternalDependencies.Remove(excluded); } } // Set all dependencies from project.json to external if an external match was passed in // This is viral and keeps p2ps from looking into directories when we are going down // a path already resolved by msbuild. foreach (var dependency in dependencies.Where(d => IsProject(d) && filteredExternalDependencies.Contains(d.Name))) { dependency.LibraryRange.TypeConstraint = LibraryDependencyTarget.ExternalProject; } // Add dependencies passed in externally // These are usually msbuild references which have less metadata, they have // the lowest priority. // Note: Only add in dependencies that are in the filtered list to avoid getting the wrong TxM dependencies.AddRange(childReferences .Where(reference => filteredExternalDependencies.Contains(reference.ProjectName)) .Select(reference => new LibraryDependency { LibraryRange = new LibraryRange { Name = reference.ProjectName, VersionRange = VersionRange.Parse("1.0.0"), TypeConstraint = LibraryDependencyTarget.ExternalProject } })); } // Remove duplicate dependencies. A reference can exist both in csproj and project.json // dependencies is already ordered by importance here var uniqueDependencies = new List <LibraryDependency>(dependencies.Count); var projectNames = new HashSet <string>(StringComparer.OrdinalIgnoreCase); foreach (var project in dependencies) { if (projectNames.Add(project.Name)) { uniqueDependencies.Add(project); } } library = new Library { LibraryRange = libraryRange, Identity = new LibraryIdentity { Name = externalReference?.ProjectName ?? packageSpec.Name, Version = packageSpec?.Version ?? NuGetVersion.Parse("1.0.0"), Type = LibraryType.Project, }, Path = packageSpec?.FilePath, Dependencies = uniqueDependencies, Resolved = true }; if (packageSpec != null) { library[KnownLibraryProperties.PackageSpec] = packageSpec; } string msbuildPath = null; if (externalReference == null) { // Build the path to the .xproj file // If it exists add it to the library properties for the lock file var projectDir = Path.GetDirectoryName(packageSpec.FilePath); var xprojPath = Path.Combine(projectDir, packageSpec.Name + ".xproj"); if (File.Exists(xprojPath)) { msbuildPath = xprojPath; } } else { msbuildPath = externalReference.MSBuildProjectPath; } if (msbuildPath != null) { library[KnownLibraryProperties.MSBuildProjectPath] = msbuildPath; } if (packageSpec != null) { // Record all frameworks in the project library[KnownLibraryProperties.ProjectFrameworks] = new List <NuGetFramework>( packageSpec.TargetFrameworks.Select(fw => fw.FrameworkName)); } if (targetFrameworkInfo != null) { library[KnownLibraryProperties.TargetFrameworkInformation] = targetFrameworkInfo; // Add framework references var frameworkReferences = targetFrameworkInfo.Dependencies .Where(d => d.LibraryRange.TypeConstraint == LibraryDependencyTarget.Reference) .Select(d => d.Name) .Distinct(StringComparer.OrdinalIgnoreCase) .ToList(); library[KnownLibraryProperties.FrameworkAssemblies] = frameworkReferences; // Add a compile asset for msbuild to xproj projects if (targetFrameworkInfo.FrameworkName != null && msbuildPath?.EndsWith(".xproj", StringComparison.OrdinalIgnoreCase) == true) { var tfmFolder = targetFrameworkInfo.FrameworkName.GetShortFolderName(); // Projects under solution folders will have names such as src\\MyProject // For the purpose of finding the output assembly just take the last part of the name var projectName = packageSpec.Name.Split( new char[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries) .Last(); // Currently the assembly name cannot be changed for xproj, we can construct the path to where // the output should be. var asset = $"{tfmFolder}/{projectName}.dll"; library[KnownLibraryProperties.CompileAsset] = asset; library[KnownLibraryProperties.RuntimeAsset] = asset; } } return(library); }
public async Task<RestoreResult> ExecuteAsync(RestoreRequest request) { if (request.Project.TargetFrameworks.Count == 0) { _log.LogError("The project does not specify any target frameworks!"); return new RestoreResult(success: false, restoreGraphs: Enumerable.Empty<RestoreTargetGraph>()); } var projectLockFilePath = string.IsNullOrEmpty(request.LockFilePath) ? Path.Combine(request.Project.BaseDirectory, LockFileFormat.LockFileName) : request.LockFilePath; _log.LogInformation($"Restoring packages for '{request.Project.FilePath}'"); _log.LogWarning("TODO: Read and use lock file"); // Load repositories var projectResolver = new PackageSpecResolver(request.Project); var nugetRepository = Repository.Factory.GetCoreV3(request.PackagesDirectory); var context = new RemoteWalkContext(); ExternalProjectReference exterenalProjectReference = null; if (request.ExternalProjects.Any()) { exterenalProjectReference = new ExternalProjectReference( request.Project.Name, request.Project.FilePath, request.ExternalProjects.Select(p => p.Name)); } context.ProjectLibraryProviders.Add( new LocalDependencyProvider( new PackageSpecReferenceDependencyProvider(projectResolver, exterenalProjectReference))); if (request.ExternalProjects != null) { context.ProjectLibraryProviders.Add( new LocalDependencyProvider( new ExternalProjectReferenceDependencyProvider(request.ExternalProjects))); } context.LocalLibraryProviders.Add( new SourceRepositoryDependencyProvider(nugetRepository, _log)); foreach (var provider in request.Sources.Select(s => CreateProviderFromSource(s, request.NoCache))) { context.RemoteLibraryProviders.Add(provider); } var remoteWalker = new RemoteDependencyWalker(context); var projectRange = new LibraryRange() { Name = request.Project.Name, VersionRange = new VersionRange(request.Project.Version), TypeConstraint = LibraryTypes.Project }; // Resolve dependency graphs var frameworks = request.Project.TargetFrameworks.Select(f => f.FrameworkName).ToList(); var graphs = new List<RestoreTargetGraph>(); var frameworkTasks = new List<Task<RestoreTargetGraph>>(); foreach (var framework in frameworks) { frameworkTasks.Add(WalkDependencies(projectRange, framework, remoteWalker, context)); } graphs.AddRange(await Task.WhenAll(frameworkTasks)); if (graphs.Any(g => g.InConflict)) { _log.LogError("Failed to resolve conflicts"); return new RestoreResult(success: false, restoreGraphs: graphs); } // Install the runtime-agnostic packages var allInstalledPackages = new HashSet<LibraryIdentity>(); var localRepository = new NuGetv3LocalRepository(request.PackagesDirectory, checkPackageIdCase: false); await InstallPackages(graphs, request.PackagesDirectory, allInstalledPackages, request.MaxDegreeOfConcurrency); // Resolve runtime dependencies var runtimeGraphs = new List<RestoreTargetGraph>(); if (request.Project.RuntimeGraph.Runtimes.Count > 0) { var runtimeTasks = new List<Task<RestoreTargetGraph[]>>(); foreach (var graph in graphs) { runtimeTasks.Add(WalkRuntimeDependencies(projectRange, graph, request.Project.RuntimeGraph, remoteWalker, context, localRepository)); } foreach (var runtimeSpecificGraphs in await Task.WhenAll(runtimeTasks)) { runtimeGraphs.AddRange(runtimeSpecificGraphs); } graphs.AddRange(runtimeGraphs); if (runtimeGraphs.Any(g => g.InConflict)) { _log.LogError("Failed to resolve conflicts"); return new RestoreResult(success: false, restoreGraphs: graphs); } // Install runtime-specific packages await InstallPackages(runtimeGraphs, request.PackagesDirectory, allInstalledPackages, request.MaxDegreeOfConcurrency); } else { _log.LogVerbose("Skipping runtime dependency walk, no runtimes defined in project.json"); } // Build the lock file var repository = new NuGetv3LocalRepository(request.PackagesDirectory, checkPackageIdCase: false); var lockFile = CreateLockFile(request.Project, graphs, repository); var lockFileFormat = new LockFileFormat(); lockFileFormat.Write(projectLockFilePath, lockFile); // Generate Targets/Props files WriteTargetsAndProps(request.Project, graphs, repository); return new RestoreResult(true, graphs, lockFile); }