| File: GetPackageDirectory.cs | Web Access |
| Project: src\sdk\src\Tasks\Microsoft.NET.Build.Tasks\Microsoft.NET.Build.Tasks.csproj (Microsoft.NET.Build.Tasks) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #nullable disable using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using NuGet.Versioning; namespace Microsoft.NET.Build.Tasks { // Locates the root NuGet package directory for each of the input items that has PackageName and PackageVersion, // but not PackageDirectory metadata specified [MSBuildMultiThreadableTask] public class GetPackageDirectory : TaskBase, IMultiThreadableTask { public TaskEnvironment TaskEnvironment { get; set; } = TaskEnvironment.Fallback; public ITaskItem[] Items { get; set; } = Array.Empty<ITaskItem>(); public string[] PackageFolders { get; set; } = Array.Empty<string>(); public string AssetsFileWithAdditionalPackageFolders { get; set; } [Output] public ITaskItem[] Output { get; set; } protected override void ExecuteCore() { if (Items.Length == 0 || (PackageFolders.Length == 0 && string.IsNullOrEmpty(AssetsFileWithAdditionalPackageFolders))) { Output = Items; return; } // The package folder paths (PackageFolders and those read from the assets file) are already // absolute, as they originate from NuGet restore. Likewise, the package directory resolved // below is an absolute on-disk path. These paths are intentionally not wrapped in AbsolutePath: // doing so would not change behavior and would only complicate this code. if (!string.IsNullOrEmpty(AssetsFileWithAdditionalPackageFolders)) { AbsolutePath assetsFilePath = TaskEnvironment.GetAbsolutePath(AssetsFileWithAdditionalPackageFolders); var lockFileCache = new LockFileCache(this); var lockFile = lockFileCache.GetLockFile(assetsFilePath); PackageFolders = PackageFolders.Concat(lockFile.PackageFolders.Select(p => p.Path)).ToArray(); } string[] absolutePackageFolders = PackageFolders .Select(p => string.IsNullOrEmpty(p) ? p : (string)TaskEnvironment.GetAbsolutePath(p)) .ToArray(); var originalByAbsolute = new Dictionary<string, string>(PackageFolders.Length, StringComparer.Ordinal); for (int i = 0; i < PackageFolders.Length; i++) { if (!string.IsNullOrEmpty(absolutePackageFolders[i])) { originalByAbsolute[absolutePackageFolders[i]] = PackageFolders[i]; } } var packageResolver = NuGetPackageResolver.CreateResolver(absolutePackageFolders); int index = 0; var updatedItems = new ITaskItem[Items.Length]; foreach (var item in Items) { string packageName = item.GetMetadata(MetadataKeys.NuGetPackageId); string packageVersion = item.GetMetadata(MetadataKeys.NuGetPackageVersion); if (string.IsNullOrEmpty(packageName) || string.IsNullOrEmpty(packageVersion) || !string.IsNullOrEmpty(item.GetMetadata(MetadataKeys.PackageDirectory))) { updatedItems[index++] = item; continue; } var parsedPackageVersion = NuGetVersion.Parse(packageVersion); string packageDirectory = packageResolver.GetPackageDirectory(packageName, parsedPackageVersion, out string packageRoot); if (packageDirectory == null) { updatedItems[index++] = item; continue; } // Restore the caller's original (possibly relative) folder prefix so the // PackageDirectory metadata is unchanged from before absolutization. if (packageRoot != null && originalByAbsolute.TryGetValue(packageRoot, out string originalRoot) && !string.Equals(originalRoot, packageRoot, StringComparison.Ordinal)) { packageDirectory = originalRoot + packageDirectory.Substring(packageRoot.Length); } var newItem = new TaskItem(item); newItem.SetMetadata(MetadataKeys.PackageDirectory, packageDirectory); updatedItems[index++] = newItem; } Output = updatedItems; } } }