From a240062eeebc4d04e019af4557e9e188691b2b31 Mon Sep 17 00:00:00 2001 From: "Jonatan Gonzalez (HE/HIM) (from Dev Box)" Date: Wed, 10 Jan 2024 17:31:13 -0800 Subject: [PATCH] Caching the parsed NugetVersion and VersionRange objects. --- ...nPackageSpecReader.Utf8JsonStreamReader.cs | 12 +++---- .../JsonPackageSpecReader.cs | 12 +++---- .../NuGet.ProjectModel/JsonUtility.cs | 36 ++++++++++++++++++- .../LockFile/LockFileFormat.cs | 6 ++-- .../Utf8JsonStreamLockFileLibraryConverter.cs | 2 +- ...sonStreamLockFileTargetLibraryConverter.cs | 4 +-- .../NuGet.ProjectModel/PackageSpecUtility.cs | 4 +-- .../LockFileFormatTests.cs | 2 +- .../LockFileParsingEnvironmentVariable.cs | 31 ++++++++-------- 9 files changed, 72 insertions(+), 37 deletions(-) diff --git a/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.Utf8JsonStreamReader.cs b/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.Utf8JsonStreamReader.cs index 5f59fde6c4d..6eedcb5c10c 100644 --- a/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.Utf8JsonStreamReader.cs +++ b/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.Utf8JsonStreamReader.cs @@ -316,7 +316,7 @@ private static LibraryDependency ReadLibraryDependency(ref Utf8JsonStreamReader { try { - dependencyVersionRange = VersionRange.Parse(dependencyVersionValue); + dependencyVersionRange = JsonUtility.ParseVersionRange(dependencyVersionValue); } catch (Exception ex) { @@ -486,7 +486,7 @@ private static void ReadDependencies( var versionPropValue = jsonReader.GetString(); try { - versionOverride = VersionRange.Parse(versionPropValue); + versionOverride = JsonUtility.ParseVersionRange(versionPropValue); } catch (Exception ex) { @@ -515,7 +515,7 @@ private static void ReadDependencies( { try { - dependencyVersionRange = VersionRange.Parse(dependencyVersionValue); + dependencyVersionRange = JsonUtility.ParseVersionRange(dependencyVersionValue); } catch (Exception ex) { @@ -625,7 +625,7 @@ private static void ReadCentralPackageVersions( throw FileFormatException.Create("The version cannot be null or empty.", filePath); } - centralPackageVersions[propertyName] = new CentralPackageVersion(propertyName, VersionRange.Parse(version)); + centralPackageVersions[propertyName] = new CentralPackageVersion(propertyName, JsonUtility.ParseVersionRange(version)); } } } @@ -732,7 +732,7 @@ private static void ReadDownloadDependencies( try { - VersionRange version = VersionRange.Parse(singleVersionValue); + VersionRange version = JsonUtility.ParseVersionRange(singleVersionValue); downloadDependencies.Add(new DownloadDependency(name, version)); } @@ -1489,7 +1489,7 @@ private static RuntimeDependencySet ReadRuntimeDependencySet(ref Utf8JsonStreamR var propertyName = jsonReader.GetString(); dependencies ??= []; - var dependency = new RuntimePackageDependency(propertyName, VersionRange.Parse(jsonReader.ReadNextTokenAsString())); + var dependency = new RuntimePackageDependency(propertyName, JsonUtility.ParseVersionRange(jsonReader.ReadNextTokenAsString())); dependencies.Add(dependency); } diff --git a/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.cs b/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.cs index 70074621110..9ee659896ad 100644 --- a/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.cs +++ b/src/NuGet.Core/NuGet.ProjectModel/JsonPackageSpecReader.cs @@ -306,7 +306,7 @@ private static void ReadCentralPackageVersions( filePath); } - centralPackageVersions[propertyName] = new CentralPackageVersion(propertyName, VersionRange.Parse(version)); + centralPackageVersions[propertyName] = new CentralPackageVersion(propertyName, JsonUtility.ParseVersionRange(version)); }); } @@ -449,7 +449,7 @@ private static void ReadDependencies( { try { - versionOverride = VersionRange.Parse((string)jsonReader.Value); + versionOverride = JsonUtility.ParseVersionRange((string)jsonReader.Value); } catch (Exception ex) { @@ -478,7 +478,7 @@ private static void ReadDependencies( { try { - dependencyVersionRange = VersionRange.Parse(dependencyVersionValue); + dependencyVersionRange = JsonUtility.ParseVersionRange(dependencyVersionValue); } catch (Exception ex) { @@ -620,7 +620,7 @@ internal static void ReadCentralTransitiveDependencyGroup( { try { - dependencyVersionRange = VersionRange.Parse(dependencyVersionValue); + dependencyVersionRange = JsonUtility.ParseVersionRange(dependencyVersionValue); } catch (Exception ex) { @@ -737,7 +737,7 @@ private static void ReadDownloadDependencies( { try { - VersionRange version = VersionRange.Parse(singleVersionValue); + VersionRange version = JsonUtility.ParseVersionRange(singleVersionValue); downloadDependencies.Add(new DownloadDependency(name, version)); } @@ -1502,7 +1502,7 @@ static RuntimeDependencySet ReadRuntimeDependencySet(JsonTextReader jsonReader, { dependencies ??= new List(); - var dependency = new RuntimePackageDependency(propertyName, VersionRange.Parse(jsonReader.ReadNextTokenAsString())); + var dependency = new RuntimePackageDependency(propertyName, JsonUtility.ParseVersionRange(jsonReader.ReadNextTokenAsString())); dependencies.Add(dependency); }); diff --git a/src/NuGet.Core/NuGet.ProjectModel/JsonUtility.cs b/src/NuGet.Core/NuGet.ProjectModel/JsonUtility.cs index 657a231c0ec..8012bf5b075 100644 --- a/src/NuGet.Core/NuGet.ProjectModel/JsonUtility.cs +++ b/src/NuGet.Core/NuGet.ProjectModel/JsonUtility.cs @@ -14,6 +14,9 @@ namespace NuGet.ProjectModel { internal static class JsonUtility { + private static readonly Dictionary NuGetVersionCache = new(); + private static readonly Dictionary VersionRangeCache = new(); + internal const string NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING = nameof(NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING); internal static bool? UseNewtonsoftJson = null; internal static readonly char[] PathSplitChars = new[] { LockFile.DirectorySeparatorChar }; @@ -57,7 +60,7 @@ internal static PackageDependency ReadPackageDependency(string property, JToken var versionStr = json.Value(); return new PackageDependency( property, - versionStr == null ? null : VersionRange.Parse(versionStr)); + versionStr == null ? null : JsonUtility.ParseVersionRange(versionStr)); } internal static bool UseNewstonSoftJsonForParsing(IEnvironmentVariableReader environmentVariableReader, bool bypassCache) @@ -167,5 +170,36 @@ internal static JToken WriteString(string item) { return item != null ? new JValue(item) : JValue.CreateNull(); } + + internal static NuGetVersion ParseNugetVersion(string value) + { + if (!NuGetVersionCache.ContainsKey(value)) + { + var result = NuGetVersion.Parse(value); + NuGetVersionCache[value] = result; + } + return NuGetVersionCache[value]; + } + + internal static bool TryParseNugetVersion(string value, out NuGetVersion version) + { + if (!NuGetVersionCache.ContainsKey(value)) + { + _ = NuGetVersion.TryParse(value, out version); + NuGetVersionCache[value] = version; + } + version = NuGetVersionCache[value]; + return version is not null; + } + + internal static VersionRange ParseVersionRange(string value) + { + if (!VersionRangeCache.ContainsKey(value)) + { + var result = VersionRange.Parse(value); + VersionRangeCache[value] = result; + } + return VersionRangeCache[value]; + } } } diff --git a/src/NuGet.Core/NuGet.ProjectModel/LockFile/LockFileFormat.cs b/src/NuGet.Core/NuGet.ProjectModel/LockFile/LockFileFormat.cs index 562d78bee52..6633df719c1 100644 --- a/src/NuGet.Core/NuGet.ProjectModel/LockFile/LockFileFormat.cs +++ b/src/NuGet.Core/NuGet.ProjectModel/LockFile/LockFileFormat.cs @@ -93,7 +93,7 @@ public LockFile Read(Stream stream, ILogger log, string path) internal LockFile Read(Stream stream, ILogger log, string path, IEnvironmentVariableReader environmentVariableReader, bool bypassCache = false) { - if (JsonUtility.UseNewstonSoftJsonForParsing(environmentVariableReader, bypassCache)) + if (!JsonUtility.UseNewstonSoftJsonForParsing(environmentVariableReader, bypassCache)) { return Utf8JsonRead(stream, log, path); } @@ -284,7 +284,7 @@ private static LockFileLibrary ReadLibrary(string property, JToken json) library.Name = parts[0]; if (parts.Length == 2) { - library.Version = NuGetVersion.Parse(parts[1]); + library.Version = JsonUtility.ParseNugetVersion(parts[1]); } library.Type = ReadString(json[TypeProperty]); @@ -560,7 +560,7 @@ private static LockFileTargetLibrary ReadTargetLibrary(string property, JToken j else { library.Name = property.Substring(0, slashIndex); - library.Version = NuGetVersion.Parse(property.Substring(slashIndex + 1)); + library.Version = JsonUtility.ParseNugetVersion(property.Substring(slashIndex + 1)); } var jObject = json as JObject; diff --git a/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileLibraryConverter.cs b/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileLibraryConverter.cs index 96e146202f4..f3ba5216716 100644 --- a/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileLibraryConverter.cs +++ b/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileLibraryConverter.cs @@ -35,7 +35,7 @@ public LockFileLibrary Read(ref Utf8JsonStreamReader reader) lockFileLibrary.Name = name; if (!string.IsNullOrWhiteSpace(version)) { - lockFileLibrary.Version = NuGetVersion.Parse(version); + lockFileLibrary.Version = JsonUtility.ParseNugetVersion(version); } reader.Read(); diff --git a/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileTargetLibraryConverter.cs b/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileTargetLibraryConverter.cs index f8187886061..743e41d3fa3 100644 --- a/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileTargetLibraryConverter.cs +++ b/src/NuGet.Core/NuGet.ProjectModel/LockFile/Utf8JsonStreamLockFileTargetLibraryConverter.cs @@ -44,7 +44,7 @@ public LockFileTargetLibrary Read(ref Utf8JsonStreamReader reader) var propertyName = reader.GetString(); var (targetLibraryName, version) = propertyName.SplitInTwo('/'); lockFileTargetLibrary.Name = targetLibraryName; - lockFileTargetLibrary.Version = version is null ? null : NuGetVersion.Parse(version); + lockFileTargetLibrary.Version = version is null ? null : JsonUtility.ParseNugetVersion(version); reader.Read(); if (reader.TokenType != JsonTokenType.StartObject) @@ -151,7 +151,7 @@ private IList ReadPackageDependencyList(ref Utf8JsonStreamRea packageDependencies.Add(new PackageDependency( propertyName, - versionString == null ? null : VersionRange.Parse(versionString))); + versionString == null ? null : JsonUtility.ParseVersionRange(versionString))); } return packageDependencies; } diff --git a/src/NuGet.Core/NuGet.ProjectModel/PackageSpecUtility.cs b/src/NuGet.Core/NuGet.ProjectModel/PackageSpecUtility.cs index 11ff892913f..2fd415315ad 100644 --- a/src/NuGet.Core/NuGet.ProjectModel/PackageSpecUtility.cs +++ b/src/NuGet.Core/NuGet.ProjectModel/PackageSpecUtility.cs @@ -27,7 +27,7 @@ public static NuGetVersion SpecifySnapshot(string version, string snapshotValue) } } - return NuGetVersion.Parse(version); + return JsonUtility.ParseNugetVersion(version); } /// @@ -44,7 +44,7 @@ public static bool IsSnapshotVersion(string version) { // Verify the version is valid NuGetVersion parsed = null; - return NuGetVersion.TryParse(version.Substring(0, version.Length - 2), out parsed); + return JsonUtility.TryParseNugetVersion(version.Substring(0, version.Length - 2), out parsed); } return false; diff --git a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileFormatTests.cs b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileFormatTests.cs index 67a3b192a42..9dd76c69a68 100644 --- a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileFormatTests.cs +++ b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileFormatTests.cs @@ -2384,7 +2384,7 @@ public void LockFileFormat_WritesCentralTransitiveDependencyGroups() Assert.Equal(expected.ToString(), output.ToString()); } - private LockFile Read(string filePath, IEnvironmentVariableReader environmentVariableReader) + public static LockFile Read(string filePath, IEnvironmentVariableReader environmentVariableReader) { var reader = new LockFileFormat(); using (var stream = File.OpenRead(filePath)) diff --git a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileParsingEnvironmentVariable.cs b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileParsingEnvironmentVariable.cs index b29c06de105..50dce830d50 100644 --- a/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileParsingEnvironmentVariable.cs +++ b/test/NuGet.Core.Tests/NuGet.ProjectModel.Test/LockFileParsingEnvironmentVariable.cs @@ -2,12 +2,25 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; +using NuGet.Common; using Test.Utility; -namespace NuGet.ProjectModel +namespace NuGet.ProjectModel.Test { public class LockFileParsingEnvironmentVariable { + public static readonly IEnvironmentVariableReader UseNjForProcessingEnvironmentVariable = new TestEnvironmentVariableReader( + new Dictionary() + { + ["NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING"] = bool.TrueString + }, "NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING: true"); + + public static readonly IEnvironmentVariableReader UseStjForProcessingEnvironmentVariable = new TestEnvironmentVariableReader( + new Dictionary() + { + ["NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING"] = bool.FalseString + }, "NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING: false"); + public static IEnumerable TestEnvironmentVariableReader() { return GetTestEnvironmentVariableReader(); @@ -30,20 +43,8 @@ public static IEnumerable TestEnvironmentVariableReader(object value1, private static IEnumerable GetTestEnvironmentVariableReader(params object[] objects) { - var UseNjForFileTrue = new List { - new TestEnvironmentVariableReader( - new Dictionary() - { - ["NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING"] = bool.TrueString - }, "NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING: true") - }; - var UseNjForFileFalse = new List { - new TestEnvironmentVariableReader( - new Dictionary() - { - ["NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING"] = bool.FalseString - }, "NUGET_EXPERIMENTAL_USE_NJ_FOR_FILE_PARSING: false") - }; + var UseNjForFileTrue = new List { UseNjForProcessingEnvironmentVariable }; + var UseNjForFileFalse = new List { UseStjForProcessingEnvironmentVariable }; if (objects != null) {