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); }
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)); msBuild.AddPackageReference(packageReferenceArgs.ProjectPath, packageReferenceArgs.PackageDependency); return(0); } // 1. Get project dg file packageReferenceArgs.Logger.LogDebug("Reading project Dependency Graph"); var dgSpec = ReadProjectDependencyGraph(packageReferenceArgs); if (dgSpec == null) { throw new Exception(Strings.Error_NoDgSpec); } packageReferenceArgs.Logger.LogDebug("Project Dependency Graph Read"); var projectName = dgSpec.Restore.FirstOrDefault(); var originalPackageSpec = dgSpec.GetProjectSpec(projectName); // Create a copy to avoid modifying the original spec which may be shared. var updatedPackageSpec = originalPackageSpec.Clone(); PackageSpecOperations.AddOrUpdateDependency(updatedPackageSpec, packageReferenceArgs.PackageDependency); var updatedDgSpec = dgSpec.WithReplacedSpec(updatedPackageSpec).WithoutRestores(); updatedDgSpec.AddRestore(updatedPackageSpec.RestoreMetadata.ProjectUniqueName); // 2. Run Restore Preview packageReferenceArgs.Logger.LogDebug("Running Restore preview"); var restorePreviewResult = await PreviewAddPackageReference(packageReferenceArgs, updatedDgSpec, updatedPackageSpec); 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)); if (packageReferenceArgs.Frameworks?.Any() == true) { // If the user has specified frameworks then we intersect that with the compatible frameworks. var userSpecifiedFrameworks = new HashSet <NuGetFramework>( packageReferenceArgs .Frameworks .Select(f => NuGetFramework.Parse(f))); compatibleFrameworks.IntersectWith(userSpecifiedFrameworks); } // 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); } else if (compatibleFrameworks.Count == restorePreviewResult.Result.CompatibilityCheckResults.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)); // If the user did not specify a version then update the version to resolved version UpdatePackageVersionIfNeeded(restorePreviewResult, packageReferenceArgs); msBuild.AddPackageReference(packageReferenceArgs.ProjectPath, packageReferenceArgs.PackageDependency); } 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))); // If the user did not specify a version then update the version to resolved version UpdatePackageVersionIfNeeded(restorePreviewResult, packageReferenceArgs); msBuild.AddPackageReferencePerTFM(packageReferenceArgs.ProjectPath, packageReferenceArgs.PackageDependency, compatibleOriginalFrameworks); } return(0); }