| File: Commands\Package\VirtualProjectPackageReflector.cs | Web Access |
| Project: src\sdk\src\Cli\dotnet\dotnet.csproj (dotnet) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; using Microsoft.Build.Construction; using Microsoft.DotNet.Cli.Commands.Run; using Microsoft.DotNet.FileBasedPrograms; namespace Microsoft.DotNet.Cli.Commands.Package; /// <summary> /// Utility for reflecting changes in a <see cref="ProjectRootElement"/> (modified by NuGet) /// back to <c>#:package</c> directives in a C# source file. /// </summary> internal static class VirtualProjectPackageReflector { /// <summary> /// Reads <c>PackageReference</c> items from the given <paramref name="projectRootElement"/> and /// updates the <c>#:package</c> directives in the source file at <paramref name="entryPointFilePath"/> to match. /// </summary> internal static void ReflectChangesToDirectives(ProjectRootElement projectRootElement, string entryPointFilePath) { // Collect PackageReference items from the modified virtual project. var packageReferences = new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase); foreach (var itemGroup in projectRootElement.ItemGroups) { foreach (var item in itemGroup.Items) { if (string.Equals(item.ItemType, "PackageReference", StringComparison.OrdinalIgnoreCase)) { Debug.Assert(!string.IsNullOrEmpty(item.Include), "Expected only PackageReference Include items in virtual project."); var version = item.Metadata.FirstOrDefault( m => string.Equals(m.Name, "Version", StringComparison.OrdinalIgnoreCase))?.Value; packageReferences[item.Include] = version; } } } // Load the source file and its current directives. var editor = FileBasedAppSourceEditor.Load(SourceFile.Load(entryPointFilePath)); var directives = editor.Directives; // Remove directives for packages that are no longer in the project. // Process in reverse order to avoid invalidating spans. for (int i = directives.Length - 1; i >= 0; i--) { if (directives[i] is CSharpDirective.Package p && !packageReferences.ContainsKey(p.Name)) { editor.Remove(directives[i]); } } // Add or update directives for packages in the project. foreach (var (name, version) in packageReferences) { // Always update existing directives (version might have changed) and add new ones. editor.Add(new CSharpDirective.Package(default) { Name = name, Version = version }); } editor.SourceFile.Save(); } }