in src/NuGet.Core/NuGet.CommandLine.XPlat/Commands/PackageReferenceCommands/AddPackageReferenceCommandRunner.cs [31:280]
public async Task<int> ExecuteCommand(PackageReferenceArgs packageReferenceArgs, MSBuildAPIUtility msBuild)
{
packageReferenceArgs.Logger.LogInformation(string.Format(CultureInfo.CurrentCulture,
Strings.Info_AddPkgAddingReference,
packageReferenceArgs.PackageId,
packageReferenceArgs.ProjectPath));
if (packageReferenceArgs.NoRestore)
{
packageReferenceArgs.Logger.LogWarning(string.Format(CultureInfo.CurrentCulture,
Strings.Warn_AddPkgWithoutRestore));
VersionRange versionRange = default;
if (packageReferenceArgs.NoVersion)
{
versionRange = packageReferenceArgs.Prerelease ?
VersionRange.Parse("*-*") :
VersionRange.Parse("*");
}
else
{
versionRange = VersionRange.Parse(packageReferenceArgs.PackageVersion);
}
var libraryDependency = new LibraryDependency()
{
LibraryRange = new LibraryRange(
name: packageReferenceArgs.PackageId,
versionRange: versionRange,
typeConstraint: LibraryDependencyTarget.Package)
};
msBuild.AddPackageReference(packageReferenceArgs.ProjectPath, libraryDependency, packageReferenceArgs.NoVersion);
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.PackageId,
packageReferenceArgs.ProjectPath));
}
// Parse the user specified frameworks once to avoid re-do's
var userSpecifiedFrameworks = new List<NuGetFramework>();
if (packageReferenceArgs.Frameworks?.Any() == true)
{
userSpecifiedFrameworks.AddRange(packageReferenceArgs
.Frameworks
.Select(NuGetFramework.Parse));
}
var originalPackageSpec = matchingPackageSpecs.FirstOrDefault();
// Check if the project files are correct for CPM
if (originalPackageSpec.RestoreMetadata.CentralPackageVersionsEnabled && !MSBuildAPIUtility.AreCentralVersionRequirementsSatisfied(packageReferenceArgs, originalPackageSpec))
{
return 1;
}
// 2. Determine the version
// Setup the Credential Service before making any potential http calls.
DefaultCredentialServiceUtility.SetupDefaultCredentialService(packageReferenceArgs.Logger, !packageReferenceArgs.Interactive);
if (packageReferenceArgs.Sources?.Any() == true)
{
// Convert relative path to absolute path if there is any
List<string> sources = new List<string>();
foreach (string source in packageReferenceArgs.Sources)
{
sources.Add(UriUtility.GetAbsolutePath(Environment.CurrentDirectory, source));
}
originalPackageSpec.RestoreMetadata.Sources =
sources.Where(ns => !string.IsNullOrEmpty(ns))
.Select(ns => new PackageSource(ns))
.ToList();
}
PackageDependency packageDependency = default;
if (packageReferenceArgs.NoVersion)
{
if (originalPackageSpec.RestoreMetadata.CentralPackageVersionsEnabled)
{
var centralVersion = originalPackageSpec
.TargetFrameworks
.Where(tf => tf.CentralPackageVersions.ContainsKey(packageReferenceArgs.PackageId))
.Select(tf => tf.CentralPackageVersions[packageReferenceArgs.PackageId])
.FirstOrDefault();
if (centralVersion != null)
{
packageDependency = new PackageDependency(packageReferenceArgs.PackageId, centralVersion.VersionRange);
}
}
if (packageDependency == null)
{
var latestVersion = await GetLatestVersionAsync(originalPackageSpec, packageReferenceArgs.PackageId, packageReferenceArgs.Logger, packageReferenceArgs.Prerelease);
if (latestVersion == null)
{
if (!packageReferenceArgs.Prerelease)
{
latestVersion = await GetLatestVersionAsync(originalPackageSpec, packageReferenceArgs.PackageId, packageReferenceArgs.Logger, !packageReferenceArgs.Prerelease);
if (latestVersion != null)
{
throw new CommandException(string.Format(CultureInfo.CurrentCulture, Strings.PrereleaseVersionsAvailable, latestVersion));
}
}
throw new CommandException(Messages.Error_NoVersionsAvailable(packageReferenceArgs.PackageId));
}
packageDependency = new PackageDependency(packageReferenceArgs.PackageId, new VersionRange(minVersion: latestVersion, includeMinVersion: true));
}
}
else
{
packageDependency = new PackageDependency(packageReferenceArgs.PackageId, VersionRange.Parse(packageReferenceArgs.PackageVersion));
}
// 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,
packageDependency,
userSpecifiedFrameworks);
}
else
{
PackageSpecOperations.AddOrUpdateDependency(updatedPackageSpec, packageDependency);
}
var updatedDgSpec = dgSpec.WithReplacedSpec(updatedPackageSpec).WithoutRestores();
updatedDgSpec.AddRestore(updatedPackageSpec.RestoreMetadata.ProjectUniqueName);
// 3. Run Restore Preview
packageReferenceArgs.Logger.LogDebug("Running Restore preview");
var restorePreviewResult = await PreviewAddPackageReferenceAsync(packageReferenceArgs,
updatedDgSpec);
packageReferenceArgs.Logger.LogDebug("Restore Review completed");
// 4. Process Restore Result
var compatibleFrameworks = new HashSet<NuGetFramework>(
restorePreviewResult
.Result
.CompatibilityCheckResults
.Where(t => t.Success)
.Select(t => t.Graph.Framework), NuGetFrameworkFullComparer.Instance);
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,
NuGetFrameworkFullComparer.Instance);
compatibleFrameworks.IntersectWith(userSpecifiedFrameworkSet);
}
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.PackageId,
packageReferenceArgs.Frameworks?.Any() == true ? Strings.AddPkg_UserSpecified : Strings.AddPkg_All,
packageReferenceArgs.ProjectPath));
return 1;
}
// 5. Write to Project
if (!TryFindResolvedVersion(userSpecifiedFrameworks, packageDependency.Id, restorePreviewResult.Result, packageReferenceArgs.Logger, out NuGetVersion resolvedVersion))
{
return 1;
}
// Ignore the graphs with RID
if (compatibleFrameworks.Count ==
restorePreviewResult.Result.CompatibilityCheckResults.Count(r => string.IsNullOrEmpty(r.Graph.RuntimeIdentifier)))
{
// 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.PackageId,
packageReferenceArgs.ProjectPath));
// generate a library dependency with all the metadata like Include, Exclude and SuppressParent
var libraryDependency = GenerateLibraryDependency(updatedPackageSpec, packageReferenceArgs.PackageDirectory, packageDependency, resolvedVersion);
msBuild.AddPackageReference(packageReferenceArgs.ProjectPath, libraryDependency, packageReferenceArgs.NoVersion);
}
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.PackageId,
packageReferenceArgs.ProjectPath));
var compatibleOriginalFrameworks = compatibleFrameworks
.Select(e => GetAliasForFramework(originalPackageSpec, e))
.Where(originalFramework => originalFramework != null);
// generate a library dependency with all the metadata like Include, Exlude and SuppressParent
var libraryDependency = GenerateLibraryDependency(updatedPackageSpec, packageReferenceArgs.PackageDirectory, packageDependency, resolvedVersion);
msBuild.AddPackageReferencePerTFM(packageReferenceArgs.ProjectPath,
libraryDependency,
compatibleOriginalFrameworks,
packageReferenceArgs.NoVersion);
}
// 6. Commit restore result
await RestoreRunner.CommitAsync(restorePreviewResult, CancellationToken.None);
return 0;
}