public static async Task <RestoreResult> RestoreProjectAsync( ISolutionManager solutionManager, BuildIntegratedNuGetProject project, DependencyGraphCacheContext context, RestoreCommandProvidersCache providerCache, Action <SourceCacheContext> cacheContextModifier, IEnumerable <SourceRepository> sources, Guid parentId, ILogger log, CancellationToken token) { if (project == null) { throw new ArgumentNullException(nameof(project)); } // Restore var specs = await project.GetPackageSpecsAsync(context); var spec = specs.Single(e => e.RestoreMetadata.ProjectStyle == ProjectStyle.PackageReference || e.RestoreMetadata.ProjectStyle == ProjectStyle.ProjectJson); // Do not restore global tools Project Style in VS. var result = await PreviewRestoreAsync( solutionManager, project, spec, context, providerCache, cacheContextModifier, sources, parentId, token); // Throw before writing if this has been canceled token.ThrowIfCancellationRequested(); // Write out the lock file and msbuild files var summary = await RestoreRunner.CommitAsync(result, token); RestoreSummary.Log(log, new[] { summary }); return(result.Result); }
public async Task <int> ExecuteCommand(PackageReferenceArgs packageReferenceArgs, MSBuildAPIUtility msBuild) { packageReferenceArgs.Logger.LogInformation(string.Format(CultureInfo.CurrentCulture, Strings.Info_AddPkgAddingReference, packageReferenceArgs.PackageDependency.Id, packageReferenceArgs.ProjectPath)); if (packageReferenceArgs.NoRestore) { packageReferenceArgs.Logger.LogWarning(string.Format(CultureInfo.CurrentCulture, Strings.Warn_AddPkgWithoutRestore)); var libraryDependency = new LibraryDependency { LibraryRange = new LibraryRange( name: packageReferenceArgs.PackageDependency.Id, versionRange: packageReferenceArgs.PackageDependency.VersionRange, typeConstraint: LibraryDependencyTarget.Package) }; msBuild.AddPackageReference(packageReferenceArgs.ProjectPath, libraryDependency); return(0); } // 1. Get project dg file packageReferenceArgs.Logger.LogDebug("Reading project Dependency Graph"); var dgSpec = ReadProjectDependencyGraph(packageReferenceArgs); if (dgSpec == null) { // Logging non localized error on debug stream. packageReferenceArgs.Logger.LogDebug(Strings.Error_NoDgSpec); throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.Error_NoDgSpec)); } packageReferenceArgs.Logger.LogDebug("Project Dependency Graph Read"); var projectFullPath = Path.GetFullPath(packageReferenceArgs.ProjectPath); var matchingPackageSpecs = dgSpec .Projects .Where(p => p.RestoreMetadata.ProjectStyle == ProjectStyle.PackageReference && PathUtility.GetStringComparerBasedOnOS().Equals(Path.GetFullPath(p.RestoreMetadata.ProjectPath), projectFullPath)) .ToArray(); // This ensures that the DG specs generated in previous steps contain exactly 1 project with the same path as the project requesting add package. // Throw otherwise since we cannot proceed further. if (matchingPackageSpecs.Length != 1) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.Error_UnsupportedProject, packageReferenceArgs.PackageDependency.Id, packageReferenceArgs.ProjectPath)); } // Parse the user specified frameworks once to avoid re-do's var userSpecifiedFrameworks = Enumerable.Empty <NuGetFramework>(); if (packageReferenceArgs.Frameworks?.Any() == true) { userSpecifiedFrameworks = packageReferenceArgs .Frameworks .Select(f => NuGetFramework.Parse(f)); } var originalPackageSpec = matchingPackageSpecs.FirstOrDefault(); // Create a copy to avoid modifying the original spec which may be shared. var updatedPackageSpec = originalPackageSpec.Clone(); if (packageReferenceArgs.Frameworks?.Any() == true) { // If user specified frameworks then just use them to add the dependency PackageSpecOperations.AddOrUpdateDependency(updatedPackageSpec, packageReferenceArgs.PackageDependency, userSpecifiedFrameworks); } else { // If the user has not specified a framework, then just add it to all frameworks PackageSpecOperations.AddOrUpdateDependency(updatedPackageSpec, packageReferenceArgs.PackageDependency, updatedPackageSpec.TargetFrameworks.Select(e => e.FrameworkName)); } var updatedDgSpec = dgSpec.WithReplacedSpec(updatedPackageSpec).WithoutRestores(); updatedDgSpec.AddRestore(updatedPackageSpec.RestoreMetadata.ProjectUniqueName); // 2. Run Restore Preview packageReferenceArgs.Logger.LogDebug("Running Restore preview"); var restorePreviewResult = await PreviewAddPackageReferenceAsync(packageReferenceArgs, updatedDgSpec); packageReferenceArgs.Logger.LogDebug("Restore Review completed"); // 3. Process Restore Result var compatibleFrameworks = new HashSet <NuGetFramework>( restorePreviewResult .Result .CompatibilityCheckResults .Where(t => t.Success) .Select(t => t.Graph.Framework), new NuGetFrameworkFullComparer()); if (packageReferenceArgs.Frameworks?.Any() == true) { // If the user has specified frameworks then we intersect that with the compatible frameworks. var userSpecifiedFrameworkSet = new HashSet <NuGetFramework>( userSpecifiedFrameworks, new NuGetFrameworkFullComparer()); compatibleFrameworks.IntersectWith(userSpecifiedFrameworkSet); } // 4. Write to Project if (compatibleFrameworks.Count == 0) { // Package is compatible with none of the project TFMs // Do not add a package reference, throw appropriate error packageReferenceArgs.Logger.LogError(string.Format(CultureInfo.CurrentCulture, Strings.Error_AddPkgIncompatibleWithAllFrameworks, packageReferenceArgs.PackageDependency.Id, packageReferenceArgs.Frameworks?.Any() == true ? Strings.AddPkg_UserSpecified : Strings.AddPkg_All, packageReferenceArgs.ProjectPath)); return(1); } // Ignore the graphs with RID else if (compatibleFrameworks.Count == restorePreviewResult.Result.CompatibilityCheckResults.Where(r => string.IsNullOrEmpty(r.Graph.RuntimeIdentifier)).Count()) { // Package is compatible with all the project TFMs // Add an unconditional package reference to the project packageReferenceArgs.Logger.LogInformation(string.Format(CultureInfo.CurrentCulture, Strings.Info_AddPkgCompatibleWithAllFrameworks, packageReferenceArgs.PackageDependency.Id, packageReferenceArgs.ProjectPath)); // generate a library dependency with all the metadata like Include, Exlude and SuppressParent var libraryDependency = GenerateLibraryDependency(updatedPackageSpec, packageReferenceArgs, restorePreviewResult, userSpecifiedFrameworks); msBuild.AddPackageReference(packageReferenceArgs.ProjectPath, libraryDependency); } else { // Package is compatible with some of the project TFMs // Add conditional package references to the project for the compatible TFMs packageReferenceArgs.Logger.LogInformation(string.Format(CultureInfo.CurrentCulture, Strings.Info_AddPkgCompatibleWithSubsetFrameworks, packageReferenceArgs.PackageDependency.Id, packageReferenceArgs.ProjectPath)); var compatibleOriginalFrameworks = originalPackageSpec.RestoreMetadata .OriginalTargetFrameworks .Where(s => compatibleFrameworks.Contains(NuGetFramework.Parse(s))); // generate a library dependency with all the metadata like Include, Exlude and SuppressParent var libraryDependency = GenerateLibraryDependency(updatedPackageSpec, packageReferenceArgs, restorePreviewResult, userSpecifiedFrameworks); msBuild.AddPackageReferencePerTFM(packageReferenceArgs.ProjectPath, libraryDependency, compatibleOriginalFrameworks); } // 5. Commit restore result await RestoreRunner.CommitAsync(restorePreviewResult, CancellationToken.None); return(0); }