From f99a0d6b8ede14605fbc1f2c932348b78b6ea976 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Sat, 18 Mar 2017 10:23:21 -0700 Subject: [PATCH] Pin DotNetCliToolReferences Fixes #491 --- tools/PinVersions/PinVersionUtility.cs | 120 +++++++++++++++++++------ tools/PinVersions/PinVersions.csproj | 1 + 2 files changed, 94 insertions(+), 27 deletions(-) diff --git a/tools/PinVersions/PinVersionUtility.cs b/tools/PinVersions/PinVersionUtility.cs index 84e0a284a8..42d1e90176 100644 --- a/tools/PinVersions/PinVersionUtility.cs +++ b/tools/PinVersions/PinVersionUtility.cs @@ -39,33 +39,84 @@ namespace PinVersions } public void Execute() + { + var solutionPinMetadata = GetPinVersionMetadata(); + foreach (var item in solutionPinMetadata) + { + var projectPinMetadata = item.Value; + var specProject = projectPinMetadata.PackageSpec; + + if (!(projectPinMetadata.Packages.Any() || projectPinMetadata.CLIToolReferences.Any())) + { + Console.WriteLine($"No package or tool references to pin for {specProject.FilePath}."); + continue; + } + + var projectFileInfo = new FileInfo(specProject.FilePath); + var pinnedReferencesFile = Path.Combine( + specProject.RestoreMetadata.OutputPath, + projectFileInfo.Name + ".pinnedversions.targets"); + + Directory.CreateDirectory(Path.GetDirectoryName(pinnedReferencesFile)); + + Console.WriteLine($"Pinning package versions for {specProject.FilePath}."); + var pinnedReferences = new XElement("ItemGroup"); + foreach (var packageReference in projectPinMetadata.Packages) + { + (var tfm, var libraryRange, var exactVersion) = packageReference; + Console.WriteLine($"Pinning reference {libraryRange.Name}({libraryRange.VersionRange} to {exactVersion}."); + var metadata = new List + { + new XAttribute("Update", libraryRange.Name), + new XAttribute("Version", exactVersion.ToNormalizedString()), + }; + + if (tfm != NuGetFramework.AnyFramework) + { + metadata.Add(new XAttribute("Condition", $"'$(TargetFramework)'=='{tfm.GetShortFolderName()}'")); + } + + pinnedReferences.Add(new XElement("PackageReference", metadata)); + } + + foreach (var toolReference in projectPinMetadata.CLIToolReferences) + { + (var libraryRange, var exactVersion) = toolReference; + Console.WriteLine($"Pinning CLI Tool {libraryRange.Name}({libraryRange.VersionRange} to {exactVersion}."); + var metadata = new List + { + new XAttribute("Update", libraryRange.Name), + new XAttribute("Version", exactVersion.ToNormalizedString()), + }; + + pinnedReferences.Add(new XElement("DotNetCliToolReference", metadata)); + } + + var pinnedVersionRoot = new XElement("Project", pinnedReferences); + File.WriteAllText(pinnedReferencesFile, pinnedVersionRoot.ToString()); + } + } + + private IDictionary GetPinVersionMetadata() { var repositoryDirectoryInfo = new DirectoryInfo(_repositoryRoot); - var knownProjects = new HashSet(StringComparer.OrdinalIgnoreCase); + var projects = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (var slnFile in repositoryDirectoryInfo.EnumerateFiles("*.sln")) { var graphSpec = _provider.GetDependencyGraphSpec(repositoryDirectoryInfo.Name, slnFile.FullName); foreach (var specProject in graphSpec.Projects) { - if (!knownProjects.Add(specProject.FilePath) || - specProject.RestoreMetadata.ProjectStyle != ProjectStyle.PackageReference) + if (!projects.TryGetValue(specProject.FilePath, out var pinMetadata)) { - continue; + pinMetadata = new PinVersionMetadata(specProject); + projects[specProject.FilePath] = pinMetadata; } - var projectFileInfo = new FileInfo(specProject.FilePath); - var pinnedReferencesFile = Path.Combine( - specProject.RestoreMetadata.OutputPath, - projectFileInfo.Name + ".pinnedversions.targets"); - - Directory.CreateDirectory(Path.GetDirectoryName(pinnedReferencesFile)); - var allDependencies = specProject.Dependencies.Select(dependency => new { Dependency = dependency, FrameworkName = NuGetFramework.AnyFramework }) .Concat(specProject.TargetFrameworks.SelectMany(tfm => tfm.Dependencies.Select(dependency => new { Dependency = dependency, tfm.FrameworkName }))) .Where(d => d.Dependency.LibraryRange.TypeConstraintAllows(LibraryDependencyTarget.Package)); - Console.WriteLine($"Pinning package versions for {specProject.FilePath}."); - var packageReferencesItemGroup = new XElement("ItemGroup"); foreach (var dependency in allDependencies) { var reference = dependency.Dependency; @@ -81,25 +132,24 @@ namespace PinVersions continue; } - Console.WriteLine($"Pinning reference {reference.Name}({reference.LibraryRange.VersionRange} to {exactVersion}."); - var metadata = new List + var projectStyle = specProject.RestoreMetadata.ProjectStyle; + if (projectStyle == ProjectStyle.PackageReference) { - new XAttribute("Update", reference.Name), - new XAttribute("Version", exactVersion.ToNormalizedString()), - }; - - if (dependency.FrameworkName != NuGetFramework.AnyFramework) - { - metadata.Add(new XAttribute("Condition", $"'$(TargetFramework)'=='{dependency.FrameworkName.GetShortFolderName()}'")); + pinMetadata.Packages.Add((dependency.FrameworkName, reference.LibraryRange, exactVersion)); + } + else if (projectStyle == ProjectStyle.DotnetCliTool) + { + pinMetadata.CLIToolReferences.Add((reference.LibraryRange, exactVersion)); + } + else + { + throw new NotSupportedException($"Unknown project style '{projectStyle}'."); } - - packageReferencesItemGroup.Add(new XElement("PackageReference", metadata)); } - - var pinnedVersionRoot = new XElement("Project", packageReferencesItemGroup); - File.WriteAllText(pinnedReferencesFile, pinnedVersionRoot.ToString()); } } + + return projects; } private NuGetVersion GetExactVersion(string name, VersionRange range) @@ -137,5 +187,21 @@ namespace PinVersions return null; } + + private struct PinVersionMetadata + { + public PinVersionMetadata(PackageSpec packageSpec) + { + PackageSpec = packageSpec; + Packages = new List<(NuGetFramework, LibraryRange, NuGetVersion)>(); + CLIToolReferences = new List<(LibraryRange, NuGetVersion)>(); + } + + public PackageSpec PackageSpec { get; } + + public List<(NuGetFramework, LibraryRange, NuGetVersion)> Packages { get; } + + public List<(LibraryRange, NuGetVersion)> CLIToolReferences { get; } + } } } diff --git a/tools/PinVersions/PinVersions.csproj b/tools/PinVersions/PinVersions.csproj index c10400b42a..f52efb6b1c 100644 --- a/tools/PinVersions/PinVersions.csproj +++ b/tools/PinVersions/PinVersions.csproj @@ -12,5 +12,6 @@ + \ No newline at end of file