public PackageSpecReferenceDependencyProvider(
     IPackageSpecResolver projectResolver,
     ExternalProjectReference projectReference)
 {
     _resolver         = projectResolver;
     _projectReference = projectReference;
 }
 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);
        }
Ejemplo n.º 7
0
        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);
        }