private ITaskItem AssignNearestFrameworkForSingleReference( ITaskItem project, NuGetFramework projectNuGetFramework, IList <NuGetFramework> fallbackNuGetFrameworks, MSBuildLogger logger) { var itemWithProperties = new TaskItem(project); var referencedProjectFrameworkString = project.GetMetadata(TARGET_FRAMEWORKS); var referenceTargetFrameworkMonikers = project.GetMetadata(TARGET_FRAMEWORK_MONIKERS); var referencedProjectPlatformString = project.GetMetadata(TARGET_PLATFORM_MONIKERS); var referencedProjectFile = project.GetMetadata(MSBUILD_SOURCE_PROJECT_FILE); if (string.IsNullOrEmpty(referencedProjectFrameworkString)) { // No target frameworks set, nothing to do. return(itemWithProperties); } var referencedProjectFrameworks = MSBuildStringUtility.Split(referencedProjectFrameworkString); var referencedProjectTargetFrameworkMonikers = MSBuildStringUtility.Split(referenceTargetFrameworkMonikers); var referencedProjectTargetPlatformMonikers = MSBuildStringUtility.Split(referencedProjectPlatformString); if (referencedProjectTargetFrameworkMonikers.Length > 0 && (referencedProjectTargetFrameworkMonikers.Length != referencedProjectTargetPlatformMonikers.Length || referencedProjectTargetFrameworkMonikers.Length != referencedProjectFrameworks.Length)) { logger.LogError($"Internal error for {CurrentProjectName}." + $" Expected {TARGET_FRAMEWORKS}:{referencedProjectFrameworks}, " + $"{TARGET_FRAMEWORK_MONIKERS}:{referenceTargetFrameworkMonikers}, " + $"{TARGET_PLATFORM_MONIKERS}:{referencedProjectPlatformString} to have the same number of elements."); return(itemWithProperties); } // TargetFrameworks, TargetFrameworkMoniker, TargetPlatforMoniker var targetFrameworkInformations = new List <TargetFrameworkInformation>(); var useTargetMonikers = referencedProjectTargetFrameworkMonikers.Length > 0; for (int i = 0; i < referencedProjectFrameworks.Length; i++) { targetFrameworkInformations.Add(new TargetFrameworkInformation( referencedProjectFrameworks[i], useTargetMonikers ? referencedProjectTargetFrameworkMonikers[i] : null, useTargetMonikers ? referencedProjectTargetPlatformMonikers[i] : null)); } // try project framework var nearestNuGetFramework = NuGetFrameworkUtility.GetNearest(targetFrameworkInformations, projectNuGetFramework, GetNuGetFramework); if (nearestNuGetFramework != null) { itemWithProperties.SetMetadata(NEAREST_TARGET_FRAMEWORK, nearestNuGetFramework._targetFrameworkAlias); return(itemWithProperties); } // try project fallback frameworks foreach (var currentProjectTargetFramework in fallbackNuGetFrameworks) { nearestNuGetFramework = NuGetFrameworkUtility.GetNearest(targetFrameworkInformations, currentProjectTargetFramework, GetNuGetFramework); if (nearestNuGetFramework != null) { var message = string.Format(CultureInfo.CurrentCulture, Strings.ImportsFallbackWarning, referencedProjectFile, currentProjectTargetFramework.DotNetFrameworkName, projectNuGetFramework.DotNetFrameworkName); var warning = RestoreLogMessage.CreateWarning(NuGetLogCode.NU1702, message); warning.LibraryId = referencedProjectFile; warning.ProjectPath = CurrentProjectName; // log NU1702 for ATF on project reference logger.Log(warning); itemWithProperties.SetMetadata(NEAREST_TARGET_FRAMEWORK, nearestNuGetFramework._targetFrameworkAlias); return(itemWithProperties); } } // no match found logger.LogError(string.Format(CultureInfo.CurrentCulture, Strings.NoCompatibleTargetFramework, project.ItemSpec, projectNuGetFramework.DotNetFrameworkName, referencedProjectFrameworkString)); return(itemWithProperties); }
public LockFile CreateLockFile(LockFile previousLockFile, PackageSpec project, IEnumerable <RestoreTargetGraph> targetGraphs, IReadOnlyList <NuGetv3LocalRepository> localRepositories, RemoteWalkContext context) { var lockFile = new LockFile() { Version = _lockFileVersion }; var previousLibraries = previousLockFile?.Libraries.ToDictionary(l => Tuple.Create(l.Name, l.Version)); if (project.RestoreMetadata?.ProjectStyle == ProjectStyle.PackageReference || project.RestoreMetadata?.ProjectStyle == ProjectStyle.DotnetToolReference) { AddProjectFileDependenciesForPackageReference(project, lockFile, targetGraphs); } else { AddProjectFileDependenciesForSpec(project, lockFile); } // Record all libraries used foreach (var item in targetGraphs.SelectMany(g => g.Flattened).Distinct() .OrderBy(x => x.Data.Match.Library)) { var library = item.Data.Match.Library; if (project.Name.Equals(library.Name, StringComparison.OrdinalIgnoreCase)) { // Do not include the project itself as a library. continue; } if (library.Type == LibraryType.Project || library.Type == LibraryType.ExternalProject) { // Project var localMatch = (LocalMatch)item.Data.Match; var projectLib = new LockFileLibrary() { Name = library.Name, Version = library.Version, Type = LibraryType.Project, }; // Set the relative path if a path exists // For projects without project.json this will be empty if (!string.IsNullOrEmpty(localMatch.LocalLibrary.Path)) { projectLib.Path = PathUtility.GetRelativePath( project.FilePath, localMatch.LocalLibrary.Path, '/'); } // The msbuild project path if it exists object msbuildPath; if (localMatch.LocalLibrary.Items.TryGetValue(KnownLibraryProperties.MSBuildProjectPath, out msbuildPath)) { var msbuildRelativePath = PathUtility.GetRelativePath( project.FilePath, (string)msbuildPath, '/'); projectLib.MSBuildProject = msbuildRelativePath; } lockFile.Libraries.Add(projectLib); } else if (library.Type == LibraryType.Package) { // Packages var packageInfo = NuGetv3LocalRepositoryUtility.GetPackage(localRepositories, library.Name, library.Version); // Add the library if it was resolved, unresolved packages are not added to the assets file. if (packageInfo != null) { var package = packageInfo.Package; var resolver = packageInfo.Repository.PathResolver; var sha512 = package.Sha512; var path = PathUtility.GetPathWithForwardSlashes(resolver.GetPackageDirectory(package.Id, package.Version)); LockFileLibrary lockFileLib = null; LockFileLibrary previousLibrary = null; if (previousLibraries?.TryGetValue(Tuple.Create(package.Id, package.Version), out previousLibrary) == true) { // Check that the previous library is still valid if (previousLibrary != null && StringComparer.Ordinal.Equals(path, previousLibrary.Path) && StringComparer.Ordinal.Equals(sha512, previousLibrary.Sha512)) { // We mutate this previous library so we must take a clone of it. This is // important because later, when deciding whether the lock file has changed, // we compare the new lock file to the previous (in-memory) lock file. lockFileLib = previousLibrary.Clone(); } } // Create a new lock file library if one doesn't exist already. if (lockFileLib == null) { lockFileLib = CreateLockFileLibrary(package, sha512, path); } // Create a new lock file library lockFile.Libraries.Add(lockFileLib); } } } var libraries = lockFile.Libraries.ToDictionary(lib => Tuple.Create(lib.Name, lib.Version)); var librariesWithWarnings = new HashSet <LibraryIdentity>(); var rootProjectStyle = project.RestoreMetadata?.ProjectStyle ?? ProjectStyle.Unknown; // Cache package data and selection criteria across graphs. var builderCache = new LockFileBuilderCache(); // Add the targets foreach (var targetGraph in targetGraphs .OrderBy(graph => graph.Framework.ToString(), StringComparer.Ordinal) .ThenBy(graph => graph.RuntimeIdentifier, StringComparer.Ordinal)) { var target = new LockFileTarget { TargetFramework = targetGraph.Framework, RuntimeIdentifier = targetGraph.RuntimeIdentifier }; var flattenedFlags = IncludeFlagUtils.FlattenDependencyTypes(_includeFlagGraphs, project, targetGraph); // Check if warnings should be displayed for the current framework. var tfi = project.GetTargetFramework(targetGraph.Framework); var warnForImportsOnGraph = tfi.Warn && (target.TargetFramework is FallbackFramework || target.TargetFramework is AssetTargetFallbackFramework); foreach (var graphItem in targetGraph.Flattened.OrderBy(x => x.Key)) { var library = graphItem.Key; // include flags LibraryIncludeFlags includeFlags; if (!flattenedFlags.TryGetValue(library.Name, out includeFlags)) { includeFlags = ~LibraryIncludeFlags.ContentFiles; } if (library.Type == LibraryType.Project || library.Type == LibraryType.ExternalProject) { if (project.Name.Equals(library.Name, StringComparison.OrdinalIgnoreCase)) { // Do not include the project itself as a library. continue; } var projectLib = LockFileUtils.CreateLockFileTargetProject( graphItem, library, includeFlags, targetGraph, rootProjectStyle); target.Libraries.Add(projectLib); continue; } else if (library.Type == LibraryType.Package) { var packageInfo = NuGetv3LocalRepositoryUtility.GetPackage(localRepositories, library.Name, library.Version); if (packageInfo == null) { continue; } var package = packageInfo.Package; var developmentDependency = package.Nuspec.GetDevelopmentDependency(); // check if package is development dependency and include flags are not overwritten if (developmentDependency && includeFlags == LibraryIncludeFlags.All) { var dependency = tfi.Dependencies.FirstOrDefault(dep => dep.Name.Equals(package.Id, StringComparison.OrdinalIgnoreCase)); // make sure new resolved dependency still have default PrivateAssets as well as IncludeAssets if (dependency?.SuppressParent == LibraryIncludeFlagUtils.DefaultSuppressParent && dependency?.IncludeType == LibraryIncludeFlags.All) { includeFlags = LibraryIncludeFlags.All & ~LibraryIncludeFlags.Compile; } } var targetLibrary = LockFileUtils.CreateLockFileTargetLibrary( libraries[Tuple.Create(library.Name, library.Version)], package, targetGraph, dependencyType: includeFlags, targetFrameworkOverride: null, dependencies: graphItem.Data.Dependencies, cache: builderCache); target.Libraries.Add(targetLibrary); // Log warnings if the target library used the fallback framework if (warnForImportsOnGraph && !librariesWithWarnings.Contains(library)) { var nonFallbackFramework = new NuGetFramework(target.TargetFramework); var targetLibraryWithoutFallback = LockFileUtils.CreateLockFileTargetLibrary( libraries[Tuple.Create(library.Name, library.Version)], package, targetGraph, targetFrameworkOverride: nonFallbackFramework, dependencyType: includeFlags, dependencies: graphItem.Data.Dependencies, cache: builderCache); if (!targetLibrary.Equals(targetLibraryWithoutFallback)) { var libraryName = DiagnosticUtility.FormatIdentity(library); var message = string.Format(CultureInfo.CurrentCulture, Strings.Log_ImportsFallbackWarning, libraryName, GetFallbackFrameworkString(target.TargetFramework), nonFallbackFramework); var logMessage = RestoreLogMessage.CreateWarning( NuGetLogCode.NU1701, message, library.Name, targetGraph.TargetGraphName); _logger.Log(logMessage); // only log the warning once per library librariesWithWarnings.Add(library); } } } } lockFile.Targets.Add(target); } PopulatePackageFolders(localRepositories.Select(repo => repo.RepositoryRoot).Distinct(), lockFile); // Add the original package spec to the lock file. lockFile.PackageSpec = project; return(lockFile); }
/// <summary> /// This method verifies that the assets files, props/targets files and all the packages written out in the assets file are present on disk /// When the project has opted into packages lock file, it also verified that the lock file is present on disk. /// This does not account if the files were manually modified since the last restore /// </summary> internal static bool VerifyRestoreOutput(RestoreRequest request, CacheFile cacheFile) { if (!string.IsNullOrWhiteSpace(request.LockFilePath) && !File.Exists(request.LockFilePath)) { request.Log.LogVerbose(string.Format(CultureInfo.CurrentCulture, Strings.Log_AssetsFileNotOnDisk, request.Project.Name)); return(false); } if (request.ProjectStyle == ProjectStyle.PackageReference || request.ProjectStyle == ProjectStyle.Standalone) { var targetsFilePath = BuildAssetsUtils.GetMSBuildFilePath(request.Project, BuildAssetsUtils.TargetsExtension); if (!File.Exists(targetsFilePath)) { request.Log.LogVerbose(string.Format(CultureInfo.CurrentCulture, Strings.Log_TargetsFileNotOnDisk, request.Project.Name, targetsFilePath)); return(false); } var propsFilePath = BuildAssetsUtils.GetMSBuildFilePath(request.Project, BuildAssetsUtils.PropsExtension); if (!File.Exists(propsFilePath)) { request.Log.LogVerbose(string.Format(CultureInfo.CurrentCulture, Strings.Log_PropsFileNotOnDisk, request.Project.Name, propsFilePath)); return(false); } if (PackagesLockFileUtilities.IsNuGetLockFileEnabled(request.Project)) { var packageLockFilePath = PackagesLockFileUtilities.GetNuGetLockFilePath(request.Project); if (!File.Exists(packageLockFilePath)) { request.Log.LogVerbose(string.Format(CultureInfo.CurrentCulture, Strings.Log_LockFileNotOnDisk, request.Project.Name, packageLockFilePath)); return(false); } } } if (cacheFile.HasAnyMissingPackageFiles) { request.Log.LogVerbose(string.Format(CultureInfo.CurrentCulture, Strings.Log_MissingPackagesOnDisk, request.Project.Name)); return(false); } if (request.UpdatePackageLastAccessTime) { foreach (var package in cacheFile.ExpectedPackageFilePaths) { if (!package.StartsWith(request.PackagesDirectory, StringComparison.OrdinalIgnoreCase)) { continue; } var packageDirectory = Path.GetDirectoryName(package); var metadataFile = Path.Combine(packageDirectory, PackagingCoreConstants.NupkgMetadataFileExtension); try { request.DependencyProviders.PackageFileCache.UpdateLastAccessTime(metadataFile); } catch (Exception ex) { request.Log.Log(RestoreLogMessage.CreateWarning(NuGetLogCode.NU1802, string.Format(CultureInfo.InvariantCulture, Strings.Error_CouldNotUpdateMetadataLastAccessTime, metadataFile, ex.Message))); } } } return(true); }
private async Task <IEnumerable <RestoreTargetGraph> > ExecuteRestoreAsync( NuGetv3LocalRepository userPackageFolder, IReadOnlyList <NuGetv3LocalRepository> fallbackPackageFolders, RemoteWalkContext context, CancellationToken token, TelemetryActivity telemetryActivity) { if (_request.Project.TargetFrameworks.Count == 0) { var message = string.Format(CultureInfo.CurrentCulture, Strings.Log_ProjectDoesNotSpecifyTargetFrameworks, _request.Project.Name, _request.Project.FilePath); await _logger.LogAsync(RestoreLogMessage.CreateError(NuGetLogCode.NU1001, message)); _success = false; return(Enumerable.Empty <RestoreTargetGraph>()); } _logger.LogMinimal(string.Format(CultureInfo.CurrentCulture, Strings.Log_RestoringPackages, _request.Project.FilePath)); // Get external project references // If the top level project already exists, update the package spec provided // with the RestoreRequest spec. var updatedExternalProjects = GetProjectReferences(context); // Determine if the targets and props files should be written out. context.IsMsBuildBased = _request.ProjectStyle != ProjectStyle.DotnetCliTool; // Load repositories // the external project provider is specific to the current restore project context.ProjectLibraryProviders.Add( new PackageSpecReferenceDependencyProvider(updatedExternalProjects, _logger)); var remoteWalker = new RemoteDependencyWalker(context); var projectRange = new LibraryRange() { Name = _request.Project.Name, VersionRange = new VersionRange(_request.Project.Version), TypeConstraint = LibraryDependencyTarget.Project | LibraryDependencyTarget.ExternalProject }; // Resolve dependency graphs var allGraphs = new List <RestoreTargetGraph>(); var runtimeIds = RequestRuntimeUtility.GetRestoreRuntimes(_request); var projectFrameworkRuntimePairs = CreateFrameworkRuntimePairs(_request.Project, runtimeIds); var hasSupports = _request.Project.RuntimeGraph.Supports.Count > 0; var projectRestoreRequest = new ProjectRestoreRequest( _request, _request.Project, _request.ExistingLockFile, _logger) { ParentId = _operationId }; var projectRestoreCommand = new ProjectRestoreCommand(projectRestoreRequest); Tuple <bool, List <RestoreTargetGraph>, RuntimeGraph> result = null; using (var tryRestoreTelemetry = TelemetryActivity.CreateTelemetryActivityWithNewOperationIdAndEvent(telemetryActivity.OperationId, CreateRestoreTargetGraph)) { result = await projectRestoreCommand.TryRestoreAsync( projectRange, projectFrameworkRuntimePairs, userPackageFolder, fallbackPackageFolders, remoteWalker, context, forceRuntimeGraphCreation : hasSupports, token : token, telemetryActivity : tryRestoreTelemetry); } var success = result.Item1; allGraphs.AddRange(result.Item2); _success = success; // Calculate compatibility profiles to check by merging those defined in the project with any from the command line foreach (var profile in _request.Project.RuntimeGraph.Supports) { var runtimes = result.Item3; CompatibilityProfile compatProfile; if (profile.Value.RestoreContexts.Any()) { // Just use the contexts from the project definition compatProfile = profile.Value; } else if (!runtimes.Supports.TryGetValue(profile.Value.Name, out compatProfile)) { // No definition of this profile found, so just continue to the next one var message = string.Format(CultureInfo.CurrentCulture, Strings.Log_UnknownCompatibilityProfile, profile.Key); await _logger.LogAsync(RestoreLogMessage.CreateWarning(NuGetLogCode.NU1502, message)); continue; } foreach (var pair in compatProfile.RestoreContexts) { _logger.LogDebug($" {profile.Value.Name} -> +{pair}"); _request.CompatibilityProfiles.Add(pair); } } // Walk additional runtime graphs for supports checks if (_success && _request.CompatibilityProfiles.Any()) { Tuple <bool, List <RestoreTargetGraph>, RuntimeGraph> compatibilityResult = null; using (var runtimeTryRestoreTelemetry = TelemetryActivity.CreateTelemetryActivityWithNewOperationIdAndEvent(telemetryActivity.OperationId, RestoreAdditionalCompatCheck)) { compatibilityResult = await projectRestoreCommand.TryRestoreAsync( projectRange, _request.CompatibilityProfiles, userPackageFolder, fallbackPackageFolders, remoteWalker, context, forceRuntimeGraphCreation : true, token : token, telemetryActivity : runtimeTryRestoreTelemetry); } _success = compatibilityResult.Item1; // TryRestore may contain graphs that are already in allGraphs if the // supports section contains the same TxM as the project framework. var currentGraphs = new HashSet <KeyValuePair <NuGetFramework, string> >( allGraphs.Select(graph => new KeyValuePair <NuGetFramework, string>( graph.Framework, graph.RuntimeIdentifier)) ); foreach (var graph in compatibilityResult.Item2) { var key = new KeyValuePair <NuGetFramework, string>( graph.Framework, graph.RuntimeIdentifier); if (currentGraphs.Add(key)) { allGraphs.Add(graph); } } } return(allGraphs); }
/// <summary> /// Asynchronously gets a package downloader. /// </summary> /// <param name="packageIdentity">A package identity.</param> /// <param name="cacheContext">A source cache context.</param> /// <param name="logger">A logger.</param> /// <param name="cancellationToken">A cancellation token.</param> /// <returns>A task that represents the asynchronous operation. /// The task result (<see cref="Task{TResult}.Result" />) returns a <see cref="IPackageDownloader" /> /// instance.</returns> /// <exception cref="ArgumentNullException">Thrown if <paramref name="packageIdentity" /> /// is either <c>null</c> or empty.</exception> /// <exception cref="ArgumentNullException">Thrown if <paramref name="cacheContext" /> /// is either <c>null</c> or empty.</exception> /// <exception cref="ArgumentNullException">Thrown if <paramref name="logger" /> /// is either <c>null</c> or empty.</exception> /// <exception cref="OperationCanceledException">Thrown if <paramref name="cancellationToken" /> /// is cancelled.</exception> public async Task <IPackageDownloader> GetPackageDownloaderAsync( PackageIdentity packageIdentity, SourceCacheContext cacheContext, ILogger logger, CancellationToken cancellationToken) { if (packageIdentity == null) { throw new ArgumentNullException(nameof(packageIdentity)); } if (cacheContext == null) { throw new ArgumentNullException(nameof(cacheContext)); } if (logger == null) { throw new ArgumentNullException(nameof(logger)); } cancellationToken.ThrowIfCancellationRequested(); await EnsureResource(); try { if (_throttle != null) { await _throttle.WaitAsync(); } cancellationToken.ThrowIfCancellationRequested(); var packageDownloader = await _findPackagesByIdResource.GetPackageDownloaderAsync( packageIdentity, cacheContext, logger, cancellationToken); packageDownloader.SetThrottle(_throttle); packageDownloader.SetExceptionHandler(async exception => { if (exception is FatalProtocolException && _ignoreFailedSources) { if (!_ignoreWarning) { await _logger.LogAsync( RestoreLogMessage.CreateWarning( NuGetLogCode.NU1801, exception.Message, packageIdentity.Id)); } return(true); } return(false); }); return(packageDownloader); } catch (FatalProtocolException e) when(_ignoreFailedSources) { if (!_ignoreWarning) { await _logger.LogAsync(RestoreLogMessage.CreateWarning(NuGetLogCode.NU1801, e.Message, packageIdentity.Id)); } } finally { _throttle?.Release(); } return(null); }