From 559228e9cf16d1f0c9222ec1a6e86e8aafb3e010 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Thu, 29 Jun 2023 12:48:53 -0400 Subject: [PATCH 01/13] Move install type detection to manifest reader project --- .../commands/dotnet-workload/InstallType.cs | 20 -------- .../dotnet-workload/WorkloadCommandParser.cs | 2 +- .../install/WorkloadInstallerFactory.cs | 20 +------- .../WorkloadInstallType.cs | 50 +++++++++++++++++++ 4 files changed, 52 insertions(+), 40 deletions(-) delete mode 100644 src/Cli/dotnet/commands/dotnet-workload/InstallType.cs create mode 100644 src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadInstallType.cs diff --git a/src/Cli/dotnet/commands/dotnet-workload/InstallType.cs b/src/Cli/dotnet/commands/dotnet-workload/InstallType.cs deleted file mode 100644 index c89d0f6f4937..000000000000 --- a/src/Cli/dotnet/commands/dotnet-workload/InstallType.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -namespace Microsoft.DotNet.Workloads.Workload -{ - /// - /// Describes different workload installation types. - /// - internal enum InstallType - { - /// - /// Workloads are installed as NuGet packages - /// - FileBased = 0, - /// - /// Workloads are installed as MSIs. - /// - Msi = 1 - } -} diff --git a/src/Cli/dotnet/commands/dotnet-workload/WorkloadCommandParser.cs b/src/Cli/dotnet/commands/dotnet-workload/WorkloadCommandParser.cs index aea59e789d2b..ac7cfffaec46 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/WorkloadCommandParser.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/WorkloadCommandParser.cs @@ -65,7 +65,7 @@ internal static void ShowWorkloadsInfo(IWorkloadInfoHelper workloadInfoHelper = reporter.WriteLine($" {workloadManifest.ManifestPath,align}"); reporter.Write($"{separator}{CommonStrings.WorkloadInstallTypeColumn}:"); - reporter.WriteLine($" {WorkloadInstallerFactory.GetWorkloadInstallType(new SdkFeatureBand(workloadFeatureBand), workloadManifest.ManifestPath).ToString(),align}" + reporter.WriteLine($" {WorkloadInstallType.GetWorkloadInstallType(new SdkFeatureBand(workloadFeatureBand), workloadManifest.ManifestPath).ToString(),align}" ); reporter.WriteLine(""); } diff --git a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallerFactory.cs b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallerFactory.cs index 117fa4e342e9..16d45439a117 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallerFactory.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/install/WorkloadInstallerFactory.cs @@ -29,7 +29,7 @@ public static IInstaller GetWorkloadInstaller( bool elevationRequired = true) { dotnetDir = string.IsNullOrWhiteSpace(dotnetDir) ? Path.GetDirectoryName(Environment.ProcessPath) : dotnetDir; - var installType = GetWorkloadInstallType(sdkFeatureBand, dotnetDir); + var installType = WorkloadInstallType.GetWorkloadInstallType(sdkFeatureBand, dotnetDir); if (installType == InstallType.Msi) { @@ -61,24 +61,6 @@ public static IInstaller GetWorkloadInstaller( restoreActionConfig: restoreActionConfig); } - /// - /// Determines the associated with a specific SDK version. - /// - /// The SDK version to check. - /// The associated with the SDK. - public static InstallType GetWorkloadInstallType(SdkFeatureBand sdkFeatureBand, string dotnetDir) - { - string installerTypePath = Path.Combine(dotnetDir, "metadata", - "workloads", $"{sdkFeatureBand.ToStringWithoutPrerelease()}", "installertype"); - - if (File.Exists(Path.Combine(installerTypePath, "msi"))) - { - return InstallType.Msi; - } - - return InstallType.FileBased; - } - private static bool CanWriteToDotnetRoot(string dotnetDir = null) { dotnetDir = dotnetDir ?? Path.GetDirectoryName(Environment.ProcessPath); diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadInstallType.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadInstallType.cs new file mode 100644 index 000000000000..d1de0e595838 --- /dev/null +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadInstallType.cs @@ -0,0 +1,50 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.NET.Sdk.WorkloadManifestReader +{ + /// + /// Describes different workload installation types. + /// + public enum InstallType + { + /// + /// Workloads are installed as NuGet packages + /// + FileBased = 0, + /// + /// Workloads are installed as MSIs. + /// + Msi = 1 + } + + public static class WorkloadInstallType + { + /// + /// Determines the associated with a specific SDK version. + /// + /// The SDK version to check. + /// The associated with the SDK. + public static InstallType GetWorkloadInstallType(SdkFeatureBand sdkFeatureBand, string dotnetDir) + { + string installerTypePath = Path.Combine(dotnetDir, "metadata", + "workloads", $"{sdkFeatureBand.ToStringWithoutPrerelease()}", "installertype"); + + if (File.Exists(Path.Combine(installerTypePath, "msi"))) + { + return InstallType.Msi; + } + + return InstallType.FileBased; + } + } +} From 9fb5ed53b06131c6f969ead936105542b3994f9e Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Thu, 29 Jun 2023 12:52:51 -0400 Subject: [PATCH 02/13] Factor out JsonReader for manifest provider --- ...rkloadManifestProvider.GlobalJsonReader.cs | 92 ++------------- ...toryWorkloadManifestProvider.JsonReader.cs | 105 ++++++++++++++++++ ...kDirectoryWorkloadManifestProviderTests.cs | 2 +- 3 files changed, 114 insertions(+), 85 deletions(-) create mode 100644 src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.JsonReader.cs diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs index 20027af22f33..df0035afedca 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs @@ -48,7 +48,7 @@ static class GlobalJsonReader string? workloadVersion = null; - ConsumeToken(ref reader, JsonTokenType.StartObject); + JsonReader.ConsumeToken(ref reader, JsonTokenType.StartObject); while (reader.Read()) { switch (reader.TokenType) @@ -57,7 +57,7 @@ static class GlobalJsonReader var propName = reader.GetString(); if (string.Equals("sdk", propName, StringComparison.OrdinalIgnoreCase)) { - ConsumeToken(ref reader, JsonTokenType.StartObject); + JsonReader.ConsumeToken(ref reader, JsonTokenType.StartObject); bool readingSdk = true; while (readingSdk && reader.Read()) @@ -68,112 +68,36 @@ static class GlobalJsonReader var sdkPropName = reader.GetString(); if (string.Equals("workloadVersion", sdkPropName, StringComparison.OrdinalIgnoreCase)) { - workloadVersion = ReadString(ref reader); + workloadVersion = JsonReader.ReadString(ref reader); } else { - ConsumeValue(ref reader); + JsonReader.ConsumeValue(ref reader); } break; case JsonTokenType.EndObject: readingSdk = false; break; default: - throw new GlobalJsonFormatException(Strings.UnexpectedTokenAtOffset, reader.TokenType, reader.TokenStartIndex); + throw new JsonFormatException(Strings.UnexpectedTokenAtOffset, reader.TokenType, reader.TokenStartIndex); } } } else { - ConsumeValue(ref reader); + JsonReader.ConsumeValue(ref reader); } break; case JsonTokenType.EndObject: return workloadVersion; default: - throw new GlobalJsonFormatException(Strings.UnexpectedTokenAtOffset, reader.TokenType, reader.TokenStartIndex); + throw new JsonFormatException(Strings.UnexpectedTokenAtOffset, reader.TokenType, reader.TokenStartIndex); } } - throw new GlobalJsonFormatException(Strings.IncompleteDocument); + throw new JsonFormatException(Strings.IncompleteDocument); } - - /// - /// this expects the reader to be before the value token, and leaves it on the last token of the value - /// - private static bool ConsumeValue(ref Utf8JsonStreamReader reader) - { - if (!reader.Read()) - { - return false; - } - - var tokenType = reader.TokenType; - if (tokenType != JsonTokenType.StartArray && tokenType != JsonTokenType.StartObject) - { - return true; - } - - var depth = reader.CurrentDepth; - do - { - if (!reader.Read()) - { - return false; - } - } while (reader.CurrentDepth > depth); - - return true; - } - - private static void ConsumeToken(ref Utf8JsonStreamReader reader, JsonTokenType expected) - { - if (reader.Read() && expected == reader.TokenType) - { - return; - } - ThrowUnexpectedTokenException(ref reader, expected); - } - - private static void ThrowUnexpectedTokenException(ref Utf8JsonStreamReader reader, JsonTokenType expected) - { - string key; - if (expected.IsBool()) - { - key = Strings.ExpectedBoolAtOffset; - } - else if (expected.IsInt()) - { - key = Strings.ExpectedIntegerAtOffset; - } - else if (expected == JsonTokenType.String) - { - key = Strings.ExpectedStringAtOffset; - } - else - { - throw new GlobalJsonFormatException(Strings.ExpectedTokenAtOffset, expected, reader.TokenStartIndex); - } - - throw new GlobalJsonFormatException(key, reader.TokenStartIndex); - } - - private static string ReadString(ref Utf8JsonStreamReader reader) - { - ConsumeToken(ref reader, JsonTokenType.String); - return reader.GetString(); - } - } - - [Serializable] - internal class GlobalJsonFormatException : Exception - { - public GlobalJsonFormatException() { } - public GlobalJsonFormatException(string messageFormat, params object?[] args) : base(string.Format(messageFormat, args)) { } - public GlobalJsonFormatException(string message) : base(message) { } - public GlobalJsonFormatException(string message, Exception inner) : base(message, inner) { } - protected GlobalJsonFormatException(SerializationInfo info, StreamingContext context) : base(info, context) { } } } } diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.JsonReader.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.JsonReader.cs new file mode 100644 index 000000000000..6045ad1e653c --- /dev/null +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.JsonReader.cs @@ -0,0 +1,105 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Microsoft.NET.Sdk.Localization; +using static Microsoft.NET.Sdk.WorkloadManifestReader.WorkloadManifestReader; +using System.Runtime.Serialization; + +#if USE_SYSTEM_TEXT_JSON +using System.Text.Json; +#else +using Newtonsoft.Json; +using JsonTokenType = Newtonsoft.Json.JsonToken; +#endif + +namespace Microsoft.NET.Sdk.WorkloadManifestReader +{ + public partial class SdkDirectoryWorkloadManifestProvider + { + static class JsonReader + { + + /// + /// this expects the reader to be before the value token, and leaves it on the last token of the value + /// + internal static bool ConsumeValue(ref Utf8JsonStreamReader reader) + { + if (!reader.Read()) + { + return false; + } + + var tokenType = reader.TokenType; + if (tokenType != JsonTokenType.StartArray && tokenType != JsonTokenType.StartObject) + { + return true; + } + + var depth = reader.CurrentDepth; + do + { + if (!reader.Read()) + { + return false; + } + } while (reader.CurrentDepth > depth); + + return true; + } + + internal static void ConsumeToken(ref Utf8JsonStreamReader reader, JsonTokenType expected) + { + if (reader.Read() && expected == reader.TokenType) + { + return; + } + ThrowUnexpectedTokenException(ref reader, expected); + } + + private static void ThrowUnexpectedTokenException(ref Utf8JsonStreamReader reader, JsonTokenType expected) + { + string key; + if (expected.IsBool()) + { + key = Strings.ExpectedBoolAtOffset; + } + else if (expected.IsInt()) + { + key = Strings.ExpectedIntegerAtOffset; + } + else if (expected == JsonTokenType.String) + { + key = Strings.ExpectedStringAtOffset; + } + else + { + throw new JsonFormatException(Strings.ExpectedTokenAtOffset, expected, reader.TokenStartIndex); + } + + throw new JsonFormatException(key, reader.TokenStartIndex); + } + + internal static string ReadString(ref Utf8JsonStreamReader reader) + { + ConsumeToken(ref reader, JsonTokenType.String); + return reader.GetString(); + } + } + + [Serializable] + internal class JsonFormatException : Exception + { + public JsonFormatException() { } + public JsonFormatException(string messageFormat, params object?[] args) : base(string.Format(messageFormat, args)) { } + public JsonFormatException(string message) : base(message) { } + public JsonFormatException(string message, Exception inner) : base(message, inner) { } + protected JsonFormatException(SerializationInfo info, StreamingContext context) : base(info, context) { } + } + } +} + diff --git a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs index 593b70fd2ff6..c2f4e38ec800 100644 --- a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs +++ b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs @@ -519,7 +519,7 @@ public void ItFailsIfGlobalJsonIsMalformed() } """); - var ex = Assert.Throws( + var ex = Assert.Throws( () => new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: globalJsonPath)); } From 983cbf53feb1eaf2a52c25f4b4d61327b0e0b235 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Thu, 29 Jun 2023 12:55:22 -0400 Subject: [PATCH 03/13] Use install state in workload manifest provider --- ...loadManifestProvider.InstallStateReader.cs | 109 ++++++++++++++++++ .../SdkDirectoryWorkloadManifestProvider.cs | 47 +++++++- .../Strings.resx | 10 +- .../WorkloadInstallType.cs | 18 +++ .../xlf/Strings.cs.xlf | 20 +++- .../xlf/Strings.de.xlf | 20 +++- .../xlf/Strings.es.xlf | 20 +++- .../xlf/Strings.fr.xlf | 20 +++- .../xlf/Strings.it.xlf | 20 +++- .../xlf/Strings.ja.xlf | 20 +++- .../xlf/Strings.ko.xlf | 20 +++- .../xlf/Strings.pl.xlf | 20 +++- .../xlf/Strings.pt-BR.xlf | 20 +++- .../xlf/Strings.ru.xlf | 20 +++- .../xlf/Strings.tr.xlf | 20 +++- .../xlf/Strings.zh-Hans.xlf | 20 +++- .../xlf/Strings.zh-Hant.xlf | 20 +++- 17 files changed, 373 insertions(+), 71 deletions(-) create mode 100644 src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.InstallStateReader.cs diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.InstallStateReader.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.InstallStateReader.cs new file mode 100644 index 000000000000..903f420b7a2b --- /dev/null +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.InstallStateReader.cs @@ -0,0 +1,109 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Microsoft.NET.Sdk.Localization; +using static Microsoft.NET.Sdk.WorkloadManifestReader.WorkloadManifestReader; +using System.Runtime.Serialization; +using Microsoft.Deployment.DotNet.Releases; + +#if USE_SYSTEM_TEXT_JSON +using System.Text.Json; +#else +using Newtonsoft.Json; +using JsonTokenType = Newtonsoft.Json.JsonToken; +#endif + +namespace Microsoft.NET.Sdk.WorkloadManifestReader +{ + public partial class SdkDirectoryWorkloadManifestProvider + { + class InstallState + { + public string? WorkloadSetVersion { get; set; } + public WorkloadSet? Manifests { get; set; } + } + + static class InstallStateReader + { + public static InstallState ReadInstallState(string installStatePath) + { + using var fileStream = File.OpenRead(installStatePath); + +#if USE_SYSTEM_TEXT_JSON + var readerOptions = new JsonReaderOptions + { + AllowTrailingCommas = true, + CommentHandling = JsonCommentHandling.Skip + }; + var reader = new Utf8JsonStreamReader(fileStream, readerOptions); +#else + using var textReader = new StreamReader(fileStream, System.Text.Encoding.UTF8, true); + using var jsonReader = new JsonTextReader(textReader); + + var reader = new Utf8JsonStreamReader(jsonReader); +#endif + + InstallState installState = new(); + + JsonReader.ConsumeToken(ref reader, JsonTokenType.StartObject); + while (reader.Read()) + { + switch (reader.TokenType) + { + case JsonTokenType.PropertyName: + var propName = reader.GetString(); + if (string.Equals("workloadVersion", propName, StringComparison.OrdinalIgnoreCase)) + { + installState.WorkloadSetVersion = JsonReader.ReadString(ref reader); + } + else if (string.Equals("manifests", propName, StringComparison.OrdinalIgnoreCase)) + { + installState.Manifests = ReadManifests(ref reader); + } + else + { + JsonReader.ConsumeValue(ref reader); + } + break; + + case JsonTokenType.EndObject: + return installState; + default: + throw new JsonFormatException(Strings.UnexpectedTokenAtOffset, reader.TokenType, reader.TokenStartIndex); + } + } + + throw new JsonFormatException(Strings.IncompleteDocument); + } + + static WorkloadSet ReadManifests(ref Utf8JsonStreamReader reader) + { + JsonReader.ConsumeToken(ref reader, JsonTokenType.StartObject); + Dictionary workloadSetDict = new(); + + while (reader.Read()) + { + switch (reader.TokenType) + { + case JsonTokenType.PropertyName: + var propName = reader.GetString(); + var propValue = JsonReader.ReadString(ref reader); + workloadSetDict[propName] = propValue; + break; + case JsonTokenType.EndObject: + return WorkloadSet.FromDictionaryForJson(workloadSetDict, new SdkFeatureBand(new ReleaseVersion(0,0,0))); + default: + throw new JsonFormatException(Strings.UnexpectedTokenAtOffset, reader.TokenType, reader.TokenStartIndex); + } + } + throw new JsonFormatException(Strings.IncompleteDocument); + } + } + } +} + diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs index 20f1ef347ed9..8c188a3a186f 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs @@ -25,6 +25,8 @@ public partial class SdkDirectoryWorkloadManifestProvider : IWorkloadManifestPro private readonly Dictionary? _knownManifestIdsAndOrder; private readonly WorkloadSet? _workloadSet; + private readonly WorkloadSet? _manifestsFromInstallState; + private readonly string? _installStateFilePath; public SdkDirectoryWorkloadManifestProvider(string sdkRootPath, string sdkVersion, string? userProfileDir, string? globalJsonPath) : this(sdkRootPath, sdkVersion, Environment.GetEnvironmentVariable, userProfileDir, globalJsonPath) @@ -102,6 +104,23 @@ internal SdkDirectoryWorkloadManifestProvider(string sdkRootPath, string sdkVers } } } + else + { + var installStateFilePath = Path.Combine(WorkloadInstallType.GetInstallStateFolder(_sdkVersionBand, _sdkRootPath), "default.json"); + if (File.Exists(installStateFilePath)) + { + var installState = InstallStateReader.ReadInstallState(installStateFilePath); + if (!string.IsNullOrEmpty(installState.WorkloadSetVersion)) + { + if (!availableWorkloadSets.TryGetValue(installState.WorkloadSetVersion!, out _workloadSet)) + { + throw new FileNotFoundException(string.Format(Strings.WorkloadVersionFromInstallStateNotFound, installState.WorkloadSetVersion, installStateFilePath)); + } + } + _manifestsFromInstallState = installState.Manifests; + _installStateFilePath = installStateFilePath; + } + } if (_workloadSet == null && availableWorkloadSets.Any()) { @@ -179,7 +198,28 @@ void ProbeDirectory(string manifestDirectory) { foreach (var kvp in _workloadSet.ManifestVersions) { - manifestIdsToDirectories[kvp.Key.ToString()] = GetManifestDirectoryFromSpecifier(new ManifestSpecifier(kvp.Key, kvp.Value.Version, kvp.Value.FeatureBand)); + var manifestSpecifier = new ManifestSpecifier(kvp.Key, kvp.Value.Version, kvp.Value.FeatureBand); + var manifestDirectory = GetManifestDirectoryFromSpecifier(manifestSpecifier); + if (manifestDirectory == null) + { + throw new FileNotFoundException(string.Format(Strings.ManifestFromWorkloadSetNotFound, manifestSpecifier.ToString(), _workloadSet.Version)); + } + manifestIdsToDirectories[kvp.Key.ToString()] = manifestDirectory; + } + } + + // Load manifests from install state + if (_manifestsFromInstallState != null) + { + foreach (var kvp in _manifestsFromInstallState.ManifestVersions) + { + var manifestSpecifier = new ManifestSpecifier(kvp.Key, kvp.Value.Version, kvp.Value.FeatureBand); + var manifestDirectory = GetManifestDirectoryFromSpecifier(manifestSpecifier); + if (manifestDirectory == null) + { + throw new FileNotFoundException(string.Format(Strings.ManifestFromInstallStateNotFound, manifestSpecifier.ToString(), _installStateFilePath)); + } + manifestIdsToDirectories[kvp.Key.ToString()] = manifestDirectory; } } @@ -286,7 +326,7 @@ private string FallbackForMissingManifest(string manifestId) } } - private string GetManifestDirectoryFromSpecifier(ManifestSpecifier manifestSpecifier) + private string? GetManifestDirectoryFromSpecifier(ManifestSpecifier manifestSpecifier) { foreach (var manifestDirectory in _manifestRoots) { @@ -297,8 +337,7 @@ private string GetManifestDirectoryFromSpecifier(ManifestSpecifier manifestSpeci return specifiedManifestDirectory; } } - - throw new FileNotFoundException(string.Format(Strings.SpecifiedManifestNotFound, manifestSpecifier.ToString())); + return null; } /// diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/Strings.resx b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/Strings.resx index c728ad1b1252..0d0bb77d4b8e 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/Strings.resx +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/Strings.resx @@ -189,12 +189,18 @@ Invalid version: {0} - - Specified workload manifest was not found: {0} + + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + + + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. + + Workload version {0}, which was specified in {1}, was not found. + Error parsing version '{1}' for workload manifest ID '{0}' diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadInstallType.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadInstallType.cs index d1de0e595838..19339893a8f4 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadInstallType.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadInstallType.cs @@ -46,5 +46,23 @@ public static InstallType GetWorkloadInstallType(SdkFeatureBand sdkFeatureBand, return InstallType.FileBased; } + + public static string GetInstallStateFolder(SdkFeatureBand sdkFeatureBand, string dotnetDir) + { + var installType = GetWorkloadInstallType(sdkFeatureBand, dotnetDir); + + if (installType == InstallType.FileBased) + { + return Path.Combine(dotnetDir, "metadata", "workloads", sdkFeatureBand.ToString(), "InstallState"); + } + else if (installType == InstallType.Msi) + { + return Path.Combine(Environment.GetEnvironmentVariable("ProgramData")!, "dotnet", "workloads", sdkFeatureBand.ToString(), "InstallState"); + } + else + { + throw new ArgumentException("Unexpected InstallType: " + installType); + } + } } } diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.cs.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.cs.xlf index bf04928a9a37..d239988ced4e 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.cs.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.cs.xlf @@ -77,6 +77,16 @@ Závislost manifestu úlohy {0} verze {1} je nižší než verze {2} požadovaná manifestem {3} [{4}]. + + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + + + + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + + Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] Nepovedlo se najít úlohu {0} rozšířenou podle úlohy {1} v manifestu {2} [{3}]. @@ -102,11 +112,6 @@ Přesměrování úlohy {0} má jiné klíče než redirect-to. - - Specified workload manifest was not found: {0} - Zadaný manifest úlohy se nenašel: {0} - - Unexpected token '{0}' at offset {1} Neočekávaný token {0} u posunu {1} @@ -137,6 +142,11 @@ Verze {0} úlohy, která byla zadána v {1}, nebyla nalezena. Spuštěním příkazu dotnet workload restore nainstalujte tuto verzi úlohy. + + Workload version {0}, which was specified in {1}, was not found. + Workload version {0}, which was specified in {1}, was not found. + + \ No newline at end of file diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.de.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.de.xlf index c211cab0a90d..803ce0de0ac6 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.de.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.de.xlf @@ -77,6 +77,16 @@ Die Workloadmanifestabhängigkeit „{0}“, Version „{1}“, ist niedriger als die Version „{2}“, die vom Manifest „{3}“ [{4}] benötigt wird. + + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + + + + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + + Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] Die Workload „{0}“, die von der Workload „{1}“ im Manifest „{2}“ [{3}] erweitert wurde, konnte nicht gefunden werden. @@ -102,11 +112,6 @@ Die Umleitungsworkload „{0}“ hat andere Schlüssel als „redirect-to“. - - Specified workload manifest was not found: {0} - Das angegebene Workloadmanifest wurde nicht gefunden: {0} - - Unexpected token '{0}' at offset {1} Unerwartetes Token "{0}" bei Offset {1}. @@ -137,6 +142,11 @@ Die Arbeitsauslastungsversion {0}, die in {1} angegeben wurde, wurde nicht gefunden. Führen Sie „dotnet workload restore“ aus, um diese Workloadversion zu installieren. + + Workload version {0}, which was specified in {1}, was not found. + Workload version {0}, which was specified in {1}, was not found. + + \ No newline at end of file diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.es.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.es.xlf index a81b23714dda..e6d9308f9176 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.es.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.es.xlf @@ -77,6 +77,16 @@ La dependencia del manifiesto de carga de trabajo '{0}' versión '{1}' es inferior a la versión '{2}' requerida por el manifiesto '{3}' [{4}] + + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + + + + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + + Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] No se ha encontrado la carga de trabajo '{0}' extendida por la carga de trabajo '{1}' en el manifiesto '{2}' [{3}] @@ -102,11 +112,6 @@ La carga de trabajo de redireccionamiento '{0}' tiene claves distintas que las de 'redirect-to' - - Specified workload manifest was not found: {0} - No se encontró el manifiesto de carga de trabajo especificado: {0} - - Unexpected token '{0}' at offset {1} Token "{0}" inesperado en el desplazamiento {1} @@ -137,6 +142,11 @@ No se encontró la versión de carga de trabajo {0}, que se especificó en {1}. Ejecuta "restauración de carga de trabajo de dotnet" para instalar esta versión de carga de trabajo. + + Workload version {0}, which was specified in {1}, was not found. + Workload version {0}, which was specified in {1}, was not found. + + \ No newline at end of file diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.fr.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.fr.xlf index 975223208662..22a3ac223333 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.fr.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.fr.xlf @@ -77,6 +77,16 @@ La version {0}' de la dépendance du manifeste de charge de travail est inférieure à la version '{1}' requise par {2}le manifeste '{3}' [{4}]. + + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + + + + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + + Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] Impossible de trouver la charge de travail '{0}' prolongée par la charge de travail '{1}' dans le manifeste '{2}' [{3}]. @@ -102,11 +112,6 @@ La charge de travail de redirection « {0} » a des clés autres que « redirection vers ». - - Specified workload manifest was not found: {0} - Le manifeste de charge de travail spécifié est introuvable : {0} - - Unexpected token '{0}' at offset {1} Jeton '{0}' inattendu à l'offset {1} @@ -137,6 +142,11 @@ La version de charge de travail {0}, qui a été spécifiée dans {1}, est introuvable. Exécutez « dotnet workload restore » pour installer cette version de charge de travail. + + Workload version {0}, which was specified in {1}, was not found. + Workload version {0}, which was specified in {1}, was not found. + + \ No newline at end of file diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.it.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.it.xlf index f8eebe66801c..285f79686939 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.it.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.it.xlf @@ -77,6 +77,16 @@ La dipendenza del manifesto del carico di lavoro '{0}' versione '{1}' è inferiore alla versione '{2}' richiesta dal manifesto '{3}' [{4}] + + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + + + + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + + Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] Non è stato possibile trovare il carico di lavoro '{0}' esteso dal carico di lavoro '{1}' nel manifesto '{2}' [{3}] @@ -102,11 +112,6 @@ Il carico di lavoro '{0}' di reindirizzamento ha chiavi diverse da ' Redirect-to ' - - Specified workload manifest was not found: {0} - Il manifesto del carico di lavoro specificato non è stato trovato: {0} - - Unexpected token '{0}' at offset {1} Token '{0}' imprevisto alla posizione di offset {1} @@ -137,6 +142,11 @@ La versione del carico di lavoro {0}, specificata in {1}, non è stata trovata. Eseguire "dotnet workload restore" per installare questa versione del carico di lavoro. + + Workload version {0}, which was specified in {1}, was not found. + Workload version {0}, which was specified in {1}, was not found. + + \ No newline at end of file diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ja.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ja.xlf index 36c754938951..ec4a90479f7c 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ja.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ja.xlf @@ -77,6 +77,16 @@ ワークロード マニフェストの依存関係 '{0}' のバージョン '{1}' は、マニフェスト '{3}' [{4}] で必要とされるバージョン '{2}' 以前のものです + + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + + + + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + + Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] マニフェスト '{2}' [{3}] 内のワークロード '{1}' によって拡張されたワークロード '{0}' が見つかりません @@ -102,11 +112,6 @@ リダイレクト ワークロード '{0}' に 'redirect-to' 以外のキーがあります - - Specified workload manifest was not found: {0} - 指定されたワークロード マニフェストが見つかりませんでした: {0} - - Unexpected token '{0}' at offset {1} オフセット {1} に予期しないトークン '{0}' があります @@ -137,6 +142,11 @@ {1} で指定されたワークロード バージョン {0} が見つかりませんでした。"dotnet ワークロードの復元" を実行して、このワークロード バージョンをインストールします。 + + Workload version {0}, which was specified in {1}, was not found. + Workload version {0}, which was specified in {1}, was not found. + + \ No newline at end of file diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ko.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ko.xlf index a23e50a04672..6991085a28f7 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ko.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ko.xlf @@ -77,6 +77,16 @@ 워크로드 매니페스트 종속성 '{0}' 버전 '{1}'이(가) '{3}' [{4}]에 필요한 버전 '{2}'보다 낮습니다 + + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + + + + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + + Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] '{2}' [{3}] 매니페스트에서 워크로드 '{1}'에 의해 확장된 워크로드 '{0}'을(를) 찾을 수 없습니다 @@ -102,11 +112,6 @@ 리디렉션 워크로드 '{0}'에 'redirect-to' 이외의 다른 키가 있습니다 - - Specified workload manifest was not found: {0} - 지정한 워크로드 매니페스트를 찾을 수 없습니다. {0} - - Unexpected token '{0}' at offset {1} 오프셋 {1}에 예기치 않은 토큰 '{0}'이(가) 있습니다. @@ -137,6 +142,11 @@ {1}에 지정된 워크로드 버전 {0}을(를) 찾을 수 없습니다. "dotnet 워크로드 복원"을 실행하여 이 워크로드 버전을 설치합니다. + + Workload version {0}, which was specified in {1}, was not found. + Workload version {0}, which was specified in {1}, was not found. + + \ No newline at end of file diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.pl.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.pl.xlf index 589b7cd190b1..7c2ff7afd53b 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.pl.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.pl.xlf @@ -77,6 +77,16 @@ Zależność manifestu obciążenia „{0}” w wersji „{1}” jest niższa niż w wersji "{2}" wymaganej przez manifest „{3}”[{4}] + + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + + + + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + + Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] Nie można odnaleźć obciążenia „{0}” rozszerzonego przez obciążenie „{1}" w manifeście „{2}” [{3}] @@ -102,11 +112,6 @@ Obciążenie przekierowania „{0}” ma klucze inne niż „redirect-to” - - Specified workload manifest was not found: {0} - Nie znaleziono określonego manifestu obciążenia: {0} - - Unexpected token '{0}' at offset {1} Nieoczekiwany token „{0}” pod przesunięciem {1} @@ -137,6 +142,11 @@ Nie znaleziono wersji obciążenia {0} określonej w kontenerze {1}. Uruchom polecenie „dotnet workload restore”, aby zainstalować tę wersję obciążenia. + + Workload version {0}, which was specified in {1}, was not found. + Workload version {0}, which was specified in {1}, was not found. + + \ No newline at end of file diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.pt-BR.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.pt-BR.xlf index f7f493da1649..7f26fe23ec1c 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.pt-BR.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.pt-BR.xlf @@ -77,6 +77,16 @@ A dependência do manifesto de carga de trabalho '{0}' versão '{1}' é inferior à versão '{2}' exigida pelo manifesto '{3}' [{4}] + + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + + + + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + + Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] Não foi possível localizar a carga de trabalho '{0}' estendida pela carga de trabalho '{1}' no manifesto '{2}' [{3}] @@ -102,11 +112,6 @@ A carga de trabalho de redirecionamento '{0}' tem chaves diferentes além de 'redirecionar-para' - - Specified workload manifest was not found: {0} - O manifesto de carga de trabalho especificado não foi encontrado: {0} - - Unexpected token '{0}' at offset {1} Token inesperado '{0}' no deslocamento {1} @@ -137,6 +142,11 @@ A versão da carga de trabalho {0}, especificada em {1}, não foi localizada. Execute "dotnet workload restore" para instalar esta versão da carga de trabalho. + + Workload version {0}, which was specified in {1}, was not found. + Workload version {0}, which was specified in {1}, was not found. + + \ No newline at end of file diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ru.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ru.xlf index 6aca12538828..28440f902e82 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ru.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ru.xlf @@ -77,6 +77,16 @@ Зависимость манифеста рабочей нагрузки "{0}" версии "{1}" ниже версии "{2}", необходимой для манифеста "{3}" [{4}] + + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + + + + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + + Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] Не удалось найти рабочую нагрузку "{0}", расширенную рабочей нагрузкой "{1}" в манифесте "{2}" [{3}] @@ -102,11 +112,6 @@ Перенаправление рабочей нагрузки "{0}" содержит ключи, отличные от "redirect-to" - - Specified workload manifest was not found: {0} - Указанный манифест рабочей нагрузки не найден: {0} - - Unexpected token '{0}' at offset {1} Непредвиденный токен "{0}" в смещении {1} @@ -137,6 +142,11 @@ Версия рабочей нагрузки {0}, указанная в {1}, не найдена. Запустите команду "dotnet workload restore", чтобы установить эту версию рабочей нагрузки. + + Workload version {0}, which was specified in {1}, was not found. + Workload version {0}, which was specified in {1}, was not found. + + \ No newline at end of file diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.tr.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.tr.xlf index 1810ce450f2b..d295b82dde51 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.tr.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.tr.xlf @@ -77,6 +77,16 @@ '{0}' iş yükü bildirimi bağımlılığının '{1}' sürümü, '{3}' [{4}] bildirimi için gereken '{2}' sürümünden düşük + + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + + + + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + + Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] '{2}' [{3}] bildirimindeki '{1}' iş yükü tarafından uzatılan '{0}' iş yükü bulunamadı @@ -102,11 +112,6 @@ '{0}' yeniden yönlendirme iş yükünde 'redirect-to' dışında anahtarlar var - - Specified workload manifest was not found: {0} - Belirtilen iş yükü bildirimi bulunamadı: {0} - - Unexpected token '{0}' at offset {1} {1} uzaklığında beklenmeyen '{0}' belirteci @@ -137,6 +142,11 @@ {1} konumunda belirtilen {0} iş yükü sürümü bulunamadı. Bu iş yükü sürümünü yüklemek için "dotnet iş yükü geri yükleme" komutunu çalıştırın. + + Workload version {0}, which was specified in {1}, was not found. + Workload version {0}, which was specified in {1}, was not found. + + \ No newline at end of file diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.zh-Hans.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.zh-Hans.xlf index 9f9941769f32..a43e8f2d6c7f 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.zh-Hans.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.zh-Hans.xlf @@ -77,6 +77,16 @@ 工作负荷清单依赖项“{0}”版本“{1}”低于清单“{2}”所需的版本“{3}”[{4}] + + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + + + + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + + Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] 无法找到由清单“{2}”[{3}] 中的工作负载“{1}”扩展的工作负载“{0}” @@ -102,11 +112,6 @@ 重定向工作负荷“{0}”具有“重定向到”以外的键 - - Specified workload manifest was not found: {0} - 找不到指定的工作负荷清单: {0} - - Unexpected token '{0}' at offset {1} 偏移为 {1} 时意外出现的标记“{0}” @@ -137,6 +142,11 @@ 找不到在 {1} 中指定的工作负载版本 {0}。运行“dotnet 工作负载还原”以安装此工作负载版本。 + + Workload version {0}, which was specified in {1}, was not found. + Workload version {0}, which was specified in {1}, was not found. + + \ No newline at end of file diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.zh-Hant.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.zh-Hant.xlf index cad158599ad2..6dc2664685e6 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.zh-Hant.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.zh-Hant.xlf @@ -77,6 +77,16 @@ 工作負載資訊清單相依性 '{0}' 版本 ' {1} ' 低於資訊清單 '{3}' [{4}] 所需的版本 '{2}' + + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + + + + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + + Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] 在資訊清單 '{2}' [{3}] 中找不到工作負載 '{1}' 延伸的工作負載 '{0}' @@ -102,11 +112,6 @@ 重新導向工作負載 '{0}' 具有 'redirect-to' 以外的其他金鑰 - - Specified workload manifest was not found: {0} - 找不到指定的工作負載資訊清單: {0} - - Unexpected token '{0}' at offset {1} 位移 {1} 有未預期的權杖 '{0}' @@ -137,6 +142,11 @@ 找不到 {1} 中指定的工作負載版本 {0}。執行 "dotnet workload restore" 以安裝此工作負載版本。 + + Workload version {0}, which was specified in {1}, was not found. + Workload version {0}, which was specified in {1}, was not found. + + \ No newline at end of file From 0d9d42f7c0c4cef1f46f1db410d1df7ab33d0b90 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Wed, 28 Jun 2023 17:51:32 -0400 Subject: [PATCH 04/13] Add tests for workload install state --- ...kDirectoryWorkloadManifestProviderTests.cs | 354 ++++++++++++++++++ 1 file changed, 354 insertions(+) diff --git a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs index c2f4e38ec800..6385b9c20361 100644 --- a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs +++ b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs @@ -523,6 +523,348 @@ public void ItFailsIfGlobalJsonIsMalformed() () => new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: globalJsonPath)); } + [Fact] + public void ItUsesWorkloadSetFromInstallState() + { + Initialize("8.0.200"); + + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true); + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true); + CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true); + + CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.201", """ +{ + "ios": "11.0.2/8.0.100" +} +"""); + + CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.202", """ +{ + "ios": "12.0.1/8.0.200" +} +"""); + CreateMockInstallState("8.0.200", + """ + { + "workloadVersion": "8.0.201" + } + """); + + + var sdkDirectoryWorkloadManifestProvider + = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null); + + GetManifestContents(sdkDirectoryWorkloadManifestProvider) + .Should() + .BeEquivalentTo("ios: 11.0.2/8.0.100"); + } + + [Fact] + public void ItFailsIfWorkloadSetFromInstallStateIsNotInstalled() + { + Initialize("8.0.200"); + + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true); + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true); + CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true); + + CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.201", """ +{ + "ios": "11.0.2/8.0.100" +} +"""); + + CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.202", """ +{ + "ios": "12.0.1/8.0.200" +} +"""); + var installStatePath = CreateMockInstallState("8.0.200", + """ + { + "workloadVersion": "8.0.203" + } + """); + + + var ex = Assert.Throws( + () => new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null)); + + ex.Message.Should().Be(string.Format(Strings.WorkloadVersionFromInstallStateNotFound, "8.0.203", installStatePath)); + } + + [Fact] + public void ItFailsIfManifestFromWorkloadSetFromInstallStateIsNotInstalled() + { + Initialize("8.0.200"); + + CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true); + + CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.201", """ +{ + "ios": "11.0.2/8.0.100" +} +"""); + + CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.202", """ +{ + "ios": "12.0.1/8.0.200" +} +"""); + var installStatePath = CreateMockInstallState("8.0.200", + """ + { + "workloadVersion": "8.0.201" + } + """); + + var sdkDirectoryWorkloadManifestProvider + = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null); + + var ex = Assert.Throws(() => sdkDirectoryWorkloadManifestProvider.GetManifests().ToList()); + + ex.Message.Should().Be(string.Format(Strings.ManifestFromWorkloadSetNotFound, "ios: 11.0.2/8.0.100", "8.0.201")); + } + + [Fact] + public void ItUsesWorkloadManifestFromInstallState() + { + Initialize("8.0.200"); + + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true); + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true); + CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true); + + CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.201", """ +{ + "ios": "11.0.2/8.0.100" +} +"""); + + CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.202", """ +{ + "ios": "12.0.1/8.0.200" +} +"""); + CreateMockInstallState("8.0.200", + """ + { + "manifests": { + "ios": "11.0.1/8.0.100", + } + } + """); + + + var sdkDirectoryWorkloadManifestProvider + = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null); + + GetManifestContents(sdkDirectoryWorkloadManifestProvider) + .Should() + .BeEquivalentTo("ios: 11.0.1/8.0.100"); + } + + [Fact] + public void ItFailsIfManifestFromInstallStateIsNotInstalled() + { + Initialize("8.0.200"); + + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true); + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true); + CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true); + + CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.201", """ +{ + "ios": "11.0.2/8.0.100" +} +"""); + + CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.202", """ +{ + "ios": "12.0.1/8.0.200" +} +"""); + var installStatePath = CreateMockInstallState("8.0.200", + """ + { + "manifests": { + "ios": "12.0.2/8.0.200", + } + } + """); + + var sdkDirectoryWorkloadManifestProvider + = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null); + + var ex = Assert.Throws(() => sdkDirectoryWorkloadManifestProvider.GetManifests().ToList()); + + ex.Message.Should().Be(string.Format(Strings.ManifestFromInstallStateNotFound, "ios: 12.0.2/8.0.200", installStatePath)); + } + + [Fact] + public void ItUsesWorkloadSetAndManifestFromInstallState() + { + Initialize("8.0.200"); + + CreateMockManifest(_manifestRoot, "8.0.200", "tizen", "8.0.0", true); + CreateMockManifest(_manifestRoot, "8.0.200", "tizen", "8.0.1", true); + + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true); + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true); + CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true); + + CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.201", """ +{ + "ios": "11.0.2/8.0.100" +} +"""); + + CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.202", """ +{ + "ios": "12.0.1/8.0.200" +} +"""); + CreateMockInstallState("8.0.200", + """ + { + "workloadVersion": "8.0.201", + "manifests": { + "tizen": "8.0.0/8.0.200", + } + } + """); + + + var sdkDirectoryWorkloadManifestProvider + = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null); + + GetManifestContents(sdkDirectoryWorkloadManifestProvider) + .Should() + .BeEquivalentTo("ios: 11.0.2/8.0.100", "tizen: 8.0.0/8.0.200"); + } + + [Fact] + public void WorkloadManifestFromInstallStateOverridesWorkloadSetFromInstallState() + { + Initialize("8.0.200"); + + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true); + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true); + CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true); + + CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.201", """ +{ + "ios": "11.0.2/8.0.100" +} +"""); + + CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.202", """ +{ + "ios": "12.0.1/8.0.200" +} +"""); + CreateMockInstallState("8.0.200", + """ + { + "workloadVersion": "8.0.201", + "manifests": { + "ios": "11.0.1/8.0.100", + } + } + """); + + var sdkDirectoryWorkloadManifestProvider + = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null); + + GetManifestContents(sdkDirectoryWorkloadManifestProvider) + .Should() + .BeEquivalentTo("ios: 11.0.1/8.0.100"); + } + + // Falls back for manifest not in install state + [Fact] + public void ItFallsBackForManifestNotInInstallState() + { + Initialize("8.0.200"); + + var knownWorkloadsFilePath = Path.Combine(_fakeDotnetRootDirectory, "sdk", "8.0.201", "IncludedWorkloadManifests.txt"); + Directory.CreateDirectory(Path.GetDirectoryName(knownWorkloadsFilePath)!); + File.WriteAllText(knownWorkloadsFilePath, "android\nios\nmaui"); + + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true); + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true); + CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true); + + CreateMockManifest(_manifestRoot, "8.0.100", "android", "33.0.1", true); + CreateMockManifest(_manifestRoot, "8.0.100", "android", "33.0.2-rc.1", true); + CreateMockManifest(_manifestRoot, "8.0.100", "android", "33.0.2", true); + + CreateMockInstallState("8.0.200", + """ + { + "manifests": { + "ios": "12.0.1/8.0.200", + } + } + """); + + var sdkDirectoryWorkloadManifestProvider + = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.201", userProfileDir: null, globalJsonPath: null); + + GetManifestContents(sdkDirectoryWorkloadManifestProvider) + .Should() + .BeEquivalentTo("ios: 12.0.1/8.0.200", "android: 33.0.2/8.0.100"); + } + + [Fact] + public void GlobalJsonOverridesInstallState() + { + Initialize("8.0.200"); + + string? globalJsonPath = Path.Combine(_testDirectory, "global.json"); + File.WriteAllText(globalJsonPath, """ + { + "sdk": { + "version": "8.0.200", + "workloadversion": "8.0.201" + }, + "msbuild-sdks": { + "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.23254.2", + } + } + """); + + CreateMockInstallState("8.0.200", + """ + { + "workloadVersion": "8.0.202", + } + """); + + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true); + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true); + CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true); + + CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.201", """ +{ + "ios": "11.0.2/8.0.100" +} +"""); + + CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.202", """ +{ + "ios": "12.0.1/8.0.200" +} +"""); + + var sdkDirectoryWorkloadManifestProvider + = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: globalJsonPath); + + GetManifestContents(sdkDirectoryWorkloadManifestProvider) + .Should() + .BeEquivalentTo("ios: 11.0.2/8.0.100"); + } + [Fact] public void ItShouldReturnManifestsFromTestHook() { @@ -822,6 +1164,18 @@ private void CreateMockWorkloadSet(string manifestRoot, string featureBand, stri File.WriteAllText(Path.Combine(workloadSetDirectory, "workloadset.workloadset.json"), workloadSetContents); } + private string CreateMockInstallState(string featureBand, string installStateContents) + { + var installStateFolder = Path.Combine(_fakeDotnetRootDirectory!, "metadata", "workloads", "8.0.200", "InstallState"); + Directory.CreateDirectory(installStateFolder); + + string installStatePath = Path.Combine(installStateFolder, "default.json"); + + File.WriteAllText(installStatePath, installStateContents); + + return installStatePath; + } + [Fact] public void ItShouldIgnoreManifestsNotFoundInFallback() { From 6973d3627a590c4552b046e75d140e0885008492 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Thu, 29 Jun 2023 13:00:47 -0400 Subject: [PATCH 05/13] Switch to SpecialFolder API to get ProgramData folder --- .../WorkloadInstallType.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadInstallType.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadInstallType.cs index 19339893a8f4..95d62da17dc9 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadInstallType.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadInstallType.cs @@ -57,7 +57,7 @@ public static string GetInstallStateFolder(SdkFeatureBand sdkFeatureBand, string } else if (installType == InstallType.Msi) { - return Path.Combine(Environment.GetEnvironmentVariable("ProgramData")!, "dotnet", "workloads", sdkFeatureBand.ToString(), "InstallState"); + return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "dotnet", "workloads", sdkFeatureBand.ToString(), "InstallState"); } else { From 8ce7dcadf23c51bf53c93416bc37b54acd3bf7ad Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Fri, 30 Jun 2023 13:10:44 -0400 Subject: [PATCH 06/13] Refactor duplicate JSON reader creation code --- ...orkloadManifestProvider.GlobalJsonReader.cs | 17 ++--------------- ...kloadManifestProvider.InstallStateReader.cs | 15 +-------------- ...ctoryWorkloadManifestProvider.JsonReader.cs | 18 ++++++++++++++++++ 3 files changed, 21 insertions(+), 29 deletions(-) diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs index df0035afedca..7cf79facd6f3 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs @@ -23,7 +23,7 @@ public partial class SdkDirectoryWorkloadManifestProvider { static class GlobalJsonReader { - public static string? GetWorkloadVersionFromGlobalJson(string globalJsonPath) + public static string? GetWorkloadVersionFromGlobalJson(string? globalJsonPath) { if (string.IsNullOrEmpty(globalJsonPath)) { @@ -31,20 +31,7 @@ static class GlobalJsonReader } using var fileStream = File.OpenRead(globalJsonPath); - -#if USE_SYSTEM_TEXT_JSON - var readerOptions = new JsonReaderOptions - { - AllowTrailingCommas = true, - CommentHandling = JsonCommentHandling.Skip - }; - var reader = new Utf8JsonStreamReader(fileStream, readerOptions); -#else - using var textReader = new StreamReader(fileStream, System.Text.Encoding.UTF8, true); - using var jsonReader = new JsonTextReader(textReader); - - var reader = new Utf8JsonStreamReader(jsonReader); -#endif + var reader = JsonReader.CreateReader(fileStream); string? workloadVersion = null; diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.InstallStateReader.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.InstallStateReader.cs index 903f420b7a2b..32e47f7df400 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.InstallStateReader.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.InstallStateReader.cs @@ -33,20 +33,7 @@ static class InstallStateReader public static InstallState ReadInstallState(string installStatePath) { using var fileStream = File.OpenRead(installStatePath); - -#if USE_SYSTEM_TEXT_JSON - var readerOptions = new JsonReaderOptions - { - AllowTrailingCommas = true, - CommentHandling = JsonCommentHandling.Skip - }; - var reader = new Utf8JsonStreamReader(fileStream, readerOptions); -#else - using var textReader = new StreamReader(fileStream, System.Text.Encoding.UTF8, true); - using var jsonReader = new JsonTextReader(textReader); - - var reader = new Utf8JsonStreamReader(jsonReader); -#endif + var reader = JsonReader.CreateReader(fileStream); InstallState installState = new(); diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.JsonReader.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.JsonReader.cs index 6045ad1e653c..cd720f834da4 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.JsonReader.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.JsonReader.cs @@ -24,6 +24,24 @@ public partial class SdkDirectoryWorkloadManifestProvider static class JsonReader { + internal static Utf8JsonStreamReader CreateReader(FileStream fileStream) + { +#if USE_SYSTEM_TEXT_JSON + var readerOptions = new JsonReaderOptions + { + AllowTrailingCommas = true, + CommentHandling = JsonCommentHandling.Skip + }; + var reader = new Utf8JsonStreamReader(fileStream, readerOptions); +#else + using var textReader = new StreamReader(fileStream, System.Text.Encoding.UTF8, true); + using var jsonReader = new JsonTextReader(textReader); + + var reader = new Utf8JsonStreamReader(jsonReader); +#endif + return reader; + } + /// /// this expects the reader to be before the value token, and leaves it on the last token of the value /// From 3cf4bbea621fb6798359c55bf6ca102eba973e90 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Fri, 30 Jun 2023 13:11:17 -0400 Subject: [PATCH 07/13] Fix issue where global.json which didn't specify workload version would prevent workload install state from being used --- .../SdkDirectoryWorkloadManifestProvider.cs | 11 ++--- ...kDirectoryWorkloadManifestProviderTests.cs | 45 +++++++++++++++++++ 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs index 8c188a3a186f..e9de7eae89a4 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs @@ -93,15 +93,12 @@ internal SdkDirectoryWorkloadManifestProvider(string sdkRootPath, string sdkVers var availableWorkloadSets = GetAvailableWorkloadSets(); - if (globalJsonPath != null) + string? globalJsonWorkloadSetVersion = GlobalJsonReader.GetWorkloadVersionFromGlobalJson(globalJsonPath); + if (globalJsonWorkloadSetVersion != null) { - string? globalJsonWorkloadSetVersion = GlobalJsonReader.GetWorkloadVersionFromGlobalJson(globalJsonPath); - if (globalJsonWorkloadSetVersion != null) + if (!availableWorkloadSets.TryGetValue(globalJsonWorkloadSetVersion, out _workloadSet)) { - if (!availableWorkloadSets.TryGetValue(globalJsonWorkloadSetVersion, out _workloadSet)) - { - throw new FileNotFoundException(string.Format(Strings.WorkloadVersionFromGlobalJsonNotFound, globalJsonWorkloadSetVersion, globalJsonPath)); - } + throw new FileNotFoundException(string.Format(Strings.WorkloadVersionFromGlobalJsonNotFound, globalJsonWorkloadSetVersion, globalJsonPath)); } } else diff --git a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs index 6385b9c20361..4e825cd99795 100644 --- a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs +++ b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs @@ -865,6 +865,51 @@ var sdkDirectoryWorkloadManifestProvider .BeEquivalentTo("ios: 11.0.2/8.0.100"); } + [Fact] + public void GlobalJsonWithoutWorkloadVersionDoesNotOverrideInstallState() + { + Initialize("8.0.200"); + + string? globalJsonPath = Path.Combine(_testDirectory, "global.json"); + File.WriteAllText(globalJsonPath, "{}"); + + CreateMockInstallState("8.0.200", + """ + { + "workloadVersion": "8.0.200", + } + """); + + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true); + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true); + CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true); + + CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.200", """ +{ + "ios": "11.0.1/8.0.100" +} +"""); + + CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.201", """ +{ + "ios": "11.0.2/8.0.100" +} +"""); + + CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.202", """ +{ + "ios": "12.0.1/8.0.200" +} +"""); + + var sdkDirectoryWorkloadManifestProvider + = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: globalJsonPath); + + GetManifestContents(sdkDirectoryWorkloadManifestProvider) + .Should() + .BeEquivalentTo("ios: 11.0.1/8.0.100"); + } + [Fact] public void ItShouldReturnManifestsFromTestHook() { From a561d2f2e98f34b904915360b114674b2b9e0b62 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Fri, 30 Jun 2023 13:27:43 -0400 Subject: [PATCH 08/13] Add comment to prevent commands in error messages from being translated --- .../Microsoft.NET.Sdk.WorkloadManifestReader/Strings.resx | 3 +++ .../xlf/Strings.cs.xlf | 8 ++++---- .../xlf/Strings.de.xlf | 8 ++++---- .../xlf/Strings.es.xlf | 8 ++++---- .../xlf/Strings.fr.xlf | 8 ++++---- .../xlf/Strings.it.xlf | 8 ++++---- .../xlf/Strings.ja.xlf | 8 ++++---- .../xlf/Strings.ko.xlf | 8 ++++---- .../xlf/Strings.pl.xlf | 8 ++++---- .../xlf/Strings.pt-BR.xlf | 8 ++++---- .../xlf/Strings.ru.xlf | 8 ++++---- .../xlf/Strings.tr.xlf | 8 ++++---- .../xlf/Strings.zh-Hans.xlf | 8 ++++---- .../xlf/Strings.zh-Hant.xlf | 8 ++++---- 14 files changed, 55 insertions(+), 52 deletions(-) diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/Strings.resx b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/Strings.resx index 0d0bb77d4b8e..51881eb4abec 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/Strings.resx +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/Strings.resx @@ -191,12 +191,15 @@ Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. + {Locked="dotnet workload repair"} Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. + {Locked="dotnet workload repair"} Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. + {Locked="dotnet workload restore"} Workload version {0}, which was specified in {1}, was not found. diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.cs.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.cs.xlf index d239988ced4e..87af4878ea91 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.cs.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.cs.xlf @@ -80,12 +80,12 @@ Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] @@ -139,8 +139,8 @@ Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. - Verze {0} úlohy, která byla zadána v {1}, nebyla nalezena. Spuštěním příkazu dotnet workload restore nainstalujte tuto verzi úlohy. - + Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. + {Locked="dotnet workload restore"} Workload version {0}, which was specified in {1}, was not found. diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.de.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.de.xlf index 803ce0de0ac6..7957ceca43c1 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.de.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.de.xlf @@ -80,12 +80,12 @@ Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] @@ -139,8 +139,8 @@ Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. - Die Arbeitsauslastungsversion {0}, die in {1} angegeben wurde, wurde nicht gefunden. Führen Sie „dotnet workload restore“ aus, um diese Workloadversion zu installieren. - + Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. + {Locked="dotnet workload restore"} Workload version {0}, which was specified in {1}, was not found. diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.es.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.es.xlf index e6d9308f9176..6d3b75908044 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.es.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.es.xlf @@ -80,12 +80,12 @@ Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] @@ -139,8 +139,8 @@ Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. - No se encontró la versión de carga de trabajo {0}, que se especificó en {1}. Ejecuta "restauración de carga de trabajo de dotnet" para instalar esta versión de carga de trabajo. - + Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. + {Locked="dotnet workload restore"} Workload version {0}, which was specified in {1}, was not found. diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.fr.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.fr.xlf index 22a3ac223333..06f9d19d3e5c 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.fr.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.fr.xlf @@ -80,12 +80,12 @@ Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] @@ -139,8 +139,8 @@ Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. - La version de charge de travail {0}, qui a été spécifiée dans {1}, est introuvable. Exécutez « dotnet workload restore » pour installer cette version de charge de travail. - + Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. + {Locked="dotnet workload restore"} Workload version {0}, which was specified in {1}, was not found. diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.it.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.it.xlf index 285f79686939..29b7fc022bc2 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.it.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.it.xlf @@ -80,12 +80,12 @@ Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] @@ -139,8 +139,8 @@ Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. - La versione del carico di lavoro {0}, specificata in {1}, non è stata trovata. Eseguire "dotnet workload restore" per installare questa versione del carico di lavoro. - + Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. + {Locked="dotnet workload restore"} Workload version {0}, which was specified in {1}, was not found. diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ja.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ja.xlf index ec4a90479f7c..e0517c875cf2 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ja.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ja.xlf @@ -80,12 +80,12 @@ Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] @@ -139,8 +139,8 @@ Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. - {1} で指定されたワークロード バージョン {0} が見つかりませんでした。"dotnet ワークロードの復元" を実行して、このワークロード バージョンをインストールします。 - + Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. + {Locked="dotnet workload restore"} Workload version {0}, which was specified in {1}, was not found. diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ko.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ko.xlf index 6991085a28f7..f312858ba612 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ko.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ko.xlf @@ -80,12 +80,12 @@ Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] @@ -139,8 +139,8 @@ Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. - {1}에 지정된 워크로드 버전 {0}을(를) 찾을 수 없습니다. "dotnet 워크로드 복원"을 실행하여 이 워크로드 버전을 설치합니다. - + Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. + {Locked="dotnet workload restore"} Workload version {0}, which was specified in {1}, was not found. diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.pl.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.pl.xlf index 7c2ff7afd53b..df7e22373be6 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.pl.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.pl.xlf @@ -80,12 +80,12 @@ Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] @@ -139,8 +139,8 @@ Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. - Nie znaleziono wersji obciążenia {0} określonej w kontenerze {1}. Uruchom polecenie „dotnet workload restore”, aby zainstalować tę wersję obciążenia. - + Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. + {Locked="dotnet workload restore"} Workload version {0}, which was specified in {1}, was not found. diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.pt-BR.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.pt-BR.xlf index 7f26fe23ec1c..2c10ce648957 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.pt-BR.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.pt-BR.xlf @@ -80,12 +80,12 @@ Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] @@ -139,8 +139,8 @@ Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. - A versão da carga de trabalho {0}, especificada em {1}, não foi localizada. Execute "dotnet workload restore" para instalar esta versão da carga de trabalho. - + Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. + {Locked="dotnet workload restore"} Workload version {0}, which was specified in {1}, was not found. diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ru.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ru.xlf index 28440f902e82..0fd5581ea359 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ru.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.ru.xlf @@ -80,12 +80,12 @@ Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] @@ -139,8 +139,8 @@ Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. - Версия рабочей нагрузки {0}, указанная в {1}, не найдена. Запустите команду "dotnet workload restore", чтобы установить эту версию рабочей нагрузки. - + Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. + {Locked="dotnet workload restore"} Workload version {0}, which was specified in {1}, was not found. diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.tr.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.tr.xlf index d295b82dde51..de15a7251f8b 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.tr.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.tr.xlf @@ -80,12 +80,12 @@ Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] @@ -139,8 +139,8 @@ Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. - {1} konumunda belirtilen {0} iş yükü sürümü bulunamadı. Bu iş yükü sürümünü yüklemek için "dotnet iş yükü geri yükleme" komutunu çalıştırın. - + Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. + {Locked="dotnet workload restore"} Workload version {0}, which was specified in {1}, was not found. diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.zh-Hans.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.zh-Hans.xlf index a43e8f2d6c7f..892e1227bb45 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.zh-Hans.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.zh-Hans.xlf @@ -80,12 +80,12 @@ Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] @@ -139,8 +139,8 @@ Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. - 找不到在 {1} 中指定的工作负载版本 {0}。运行“dotnet 工作负载还原”以安装此工作负载版本。 - + Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. + {Locked="dotnet workload restore"} Workload version {0}, which was specified in {1}, was not found. diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.zh-Hant.xlf b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.zh-Hant.xlf index 6dc2664685e6..5cff8edc8f43 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.zh-Hant.xlf +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/xlf/Strings.zh-Hant.xlf @@ -80,12 +80,12 @@ Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. Workload manifest {0}, which was specified in {1}, was not found. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. Workload manifest {0} from workload version {1} was not installed. Running "dotnet workload repair" may resolve this. - + {Locked="dotnet workload repair"} Could not find workload '{0}' extended by workload '{1}' in manifest '{2}' [{3}] @@ -139,8 +139,8 @@ Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. - 找不到 {1} 中指定的工作負載版本 {0}。執行 "dotnet workload restore" 以安裝此工作負載版本。 - + Workload version {0}, which was specified in {1}, was not found. Run "dotnet workload restore" to install this workload version. + {Locked="dotnet workload restore"} Workload version {0}, which was specified in {1}, was not found. From 98221a399da9667232030552957736abde82298a Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Tue, 4 Jul 2023 15:54:23 -0400 Subject: [PATCH 09/13] Revert "Refactor duplicate JSON reader creation code" This reverts commit 8ce7dcadf23c51bf53c93416bc37b54acd3bf7ad. --- ...orkloadManifestProvider.GlobalJsonReader.cs | 17 +++++++++++++++-- ...kloadManifestProvider.InstallStateReader.cs | 15 ++++++++++++++- ...ctoryWorkloadManifestProvider.JsonReader.cs | 18 ------------------ 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs index 7cf79facd6f3..df0035afedca 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs @@ -23,7 +23,7 @@ public partial class SdkDirectoryWorkloadManifestProvider { static class GlobalJsonReader { - public static string? GetWorkloadVersionFromGlobalJson(string? globalJsonPath) + public static string? GetWorkloadVersionFromGlobalJson(string globalJsonPath) { if (string.IsNullOrEmpty(globalJsonPath)) { @@ -31,7 +31,20 @@ static class GlobalJsonReader } using var fileStream = File.OpenRead(globalJsonPath); - var reader = JsonReader.CreateReader(fileStream); + +#if USE_SYSTEM_TEXT_JSON + var readerOptions = new JsonReaderOptions + { + AllowTrailingCommas = true, + CommentHandling = JsonCommentHandling.Skip + }; + var reader = new Utf8JsonStreamReader(fileStream, readerOptions); +#else + using var textReader = new StreamReader(fileStream, System.Text.Encoding.UTF8, true); + using var jsonReader = new JsonTextReader(textReader); + + var reader = new Utf8JsonStreamReader(jsonReader); +#endif string? workloadVersion = null; diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.InstallStateReader.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.InstallStateReader.cs index 32e47f7df400..903f420b7a2b 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.InstallStateReader.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.InstallStateReader.cs @@ -33,7 +33,20 @@ static class InstallStateReader public static InstallState ReadInstallState(string installStatePath) { using var fileStream = File.OpenRead(installStatePath); - var reader = JsonReader.CreateReader(fileStream); + +#if USE_SYSTEM_TEXT_JSON + var readerOptions = new JsonReaderOptions + { + AllowTrailingCommas = true, + CommentHandling = JsonCommentHandling.Skip + }; + var reader = new Utf8JsonStreamReader(fileStream, readerOptions); +#else + using var textReader = new StreamReader(fileStream, System.Text.Encoding.UTF8, true); + using var jsonReader = new JsonTextReader(textReader); + + var reader = new Utf8JsonStreamReader(jsonReader); +#endif InstallState installState = new(); diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.JsonReader.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.JsonReader.cs index cd720f834da4..6045ad1e653c 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.JsonReader.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.JsonReader.cs @@ -24,24 +24,6 @@ public partial class SdkDirectoryWorkloadManifestProvider static class JsonReader { - internal static Utf8JsonStreamReader CreateReader(FileStream fileStream) - { -#if USE_SYSTEM_TEXT_JSON - var readerOptions = new JsonReaderOptions - { - AllowTrailingCommas = true, - CommentHandling = JsonCommentHandling.Skip - }; - var reader = new Utf8JsonStreamReader(fileStream, readerOptions); -#else - using var textReader = new StreamReader(fileStream, System.Text.Encoding.UTF8, true); - using var jsonReader = new JsonTextReader(textReader); - - var reader = new Utf8JsonStreamReader(jsonReader); -#endif - return reader; - } - /// /// this expects the reader to be before the value token, and leaves it on the last token of the value /// From c6f8911588661a206ca54c85b0b7bb6e24324476 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Tue, 4 Jul 2023 20:36:58 -0400 Subject: [PATCH 10/13] Fix build error --- .../SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs index df0035afedca..1b28c9a043b6 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs @@ -23,7 +23,7 @@ public partial class SdkDirectoryWorkloadManifestProvider { static class GlobalJsonReader { - public static string? GetWorkloadVersionFromGlobalJson(string globalJsonPath) + public static string? GetWorkloadVersionFromGlobalJson(string? globalJsonPath) { if (string.IsNullOrEmpty(globalJsonPath)) { From 29f515db4a4e92aa21560ffe3c889fdfb5ba16b2 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Fri, 7 Jul 2023 19:24:16 -0400 Subject: [PATCH 11/13] Fix manifest ID returned for side-by-side workload manifests --- .../CachingWorkloadResolver.cs | 2 +- .../IWorkloadManifestProvider.cs | 2 - .../ReadableWorkloadManifest.cs | 6 ++- .../SdkDirectoryWorkloadManifestProvider.cs | 30 +++++------- .../TempDirectoryWorkloadManifestProvider.cs | 1 + .../FakeManifestProvider.cs | 2 + ...kDirectoryWorkloadManifestProviderTests.cs | 48 +++++++++++-------- .../WorkloadPackGroupTests.cs | 2 +- .../MockManifestProvider.cs | 1 + 9 files changed, 52 insertions(+), 42 deletions(-) diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver/CachingWorkloadResolver.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver/CachingWorkloadResolver.cs index b25b9eb76a5b..60b35d6c8216 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver/CachingWorkloadResolver.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver/CachingWorkloadResolver.cs @@ -139,7 +139,7 @@ private static ResolutionResult Resolve(string sdkReferenceName, IWorkloadManife else if (sdkReferenceName.Equals("Microsoft.NET.SDK.WorkloadManifestTargetsLocator", StringComparison.OrdinalIgnoreCase)) { List workloadManifestPaths = new List(); - foreach (var manifestDirectory in manifestProvider.GetManifestDirectories()) + foreach (var manifestDirectory in manifestProvider.GetManifests().Select(m => m.ManifestDirectory)) { var workloadManifestTargetPath = Path.Combine(manifestDirectory, "WorkloadManifest.targets"); if (File.Exists(workloadManifestTargetPath)) diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/IWorkloadManifestProvider.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/IWorkloadManifestProvider.cs index 473357998678..7aa93f9f998c 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/IWorkloadManifestProvider.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/IWorkloadManifestProvider.cs @@ -15,8 +15,6 @@ public interface IWorkloadManifestProvider { IEnumerable GetManifests(); - IEnumerable GetManifestDirectories(); - string GetSdkFeatureBand(); } } diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/ReadableWorkloadManifest.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/ReadableWorkloadManifest.cs index 512f284019b7..e0a5cf5dd848 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/ReadableWorkloadManifest.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/ReadableWorkloadManifest.cs @@ -14,6 +14,9 @@ namespace Microsoft.NET.Sdk.WorkloadManifestReader public class ReadableWorkloadManifest { public string ManifestId { get; } + + public string ManifestDirectory { get; } + public string ManifestPath { get; } readonly Func _openManifestStreamFunc; @@ -21,10 +24,11 @@ public class ReadableWorkloadManifest readonly Func _openLocalizationStream; - public ReadableWorkloadManifest(string manifestId, string manifestPath, Func openManifestStreamFunc, Func openLocalizationStream) + public ReadableWorkloadManifest(string manifestId, string manifestDirectory, string manifestPath, Func openManifestStreamFunc, Func openLocalizationStream) { ManifestId = manifestId; ManifestPath = manifestPath; + ManifestDirectory = manifestDirectory; _openManifestStreamFunc = openManifestStreamFunc; _openLocalizationStream = openLocalizationStream; } diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs index e9de7eae89a4..f32101243e22 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs @@ -127,22 +127,6 @@ internal SdkDirectoryWorkloadManifestProvider(string sdkRootPath, string sdkVers } public IEnumerable GetManifests() - { - foreach (var workloadManifestDirectory in GetManifestDirectories()) - { - var workloadManifestPath = Path.Combine(workloadManifestDirectory, "WorkloadManifest.json"); - var id = Path.GetFileName(workloadManifestDirectory); - - yield return new( - id, - workloadManifestPath, - () => File.OpenRead(workloadManifestPath), - () => WorkloadManifestReader.TryOpenLocalizationCatalogForManifest(workloadManifestPath) - ); - } - } - - public IEnumerable GetManifestDirectories() { // Scan manifest directories var manifestIdsToDirectories = new Dictionary(StringComparer.OrdinalIgnoreCase); @@ -246,7 +230,19 @@ void ProbeDirectory(string manifestDirectory) return int.MaxValue; }) .ThenBy(kvp => kvp.Key, StringComparer.OrdinalIgnoreCase) - .Select(kvp => kvp.Value) + .Select(kvp => + { + var manifestId = kvp.Key; + var manifestDirectory = kvp.Value; + var workloadManifestPath = Path.Combine(manifestDirectory, "WorkloadManifest.json"); + + return new ReadableWorkloadManifest( + manifestId, + manifestDirectory, + workloadManifestPath, + () => File.OpenRead(workloadManifestPath), + () => WorkloadManifestReader.TryOpenLocalizationCatalogForManifest(workloadManifestPath)); + }) .ToList(); } diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/TempDirectoryWorkloadManifestProvider.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/TempDirectoryWorkloadManifestProvider.cs index 6ae5e948fb6c..ad627cc8676a 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/TempDirectoryWorkloadManifestProvider.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/TempDirectoryWorkloadManifestProvider.cs @@ -35,6 +35,7 @@ public IEnumerable yield return new( manifestId, + workloadManifestDirectory, workloadManifestPath, () => File.OpenRead(workloadManifestPath), () => WorkloadManifestReader.TryOpenLocalizationCatalogForManifest(workloadManifestPath) diff --git a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/FakeManifestProvider.cs b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/FakeManifestProvider.cs index d28b3442fb0b..8776c06327d1 100644 --- a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/FakeManifestProvider.cs +++ b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/FakeManifestProvider.cs @@ -34,6 +34,7 @@ public IEnumerable GetManifests() { yield return new( Path.GetFileNameWithoutExtension(filePath.manifest), + Path.GetDirectoryName(filePath.manifest)!, filePath.manifest, () => new FileStream(filePath.manifest, FileMode.Open, FileAccess.Read), () => filePath.localizationCatalog != null ? new FileStream(filePath.localizationCatalog, FileMode.Open, FileAccess.Read) : null @@ -54,6 +55,7 @@ internal class InMemoryFakeManifestProvider : IWorkloadManifestProvider, IEnumer public IEnumerable GetManifests() => _manifests.Select(m => new ReadableWorkloadManifest( m.id, + $@"C:\fake\{m.id}", $@"C:\fake\{m.id}\WorkloadManifest.json", (Func)(() => new MemoryStream(m.content)), (Func)(() => null) diff --git a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs index 4e825cd99795..0df4511deedf 100644 --- a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs +++ b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs @@ -925,11 +925,11 @@ public void ItShouldReturnManifestsFromTestHook() // Manifest in test hook directory Directory.CreateDirectory(Path.Combine(additionalManifestDirectory, sdkVersion, "Android")); - File.WriteAllText(Path.Combine(additionalManifestDirectory, sdkVersion, "Android", "WorkloadManifest.json"), "AndroidContent"); + File.WriteAllText(Path.Combine(additionalManifestDirectory, sdkVersion, "Android", "WorkloadManifest.json"), "Android: AndroidContent"); // Manifest in default directory Directory.CreateDirectory(Path.Combine(_manifestVersionBandDirectory, "iOS")); - File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "iOS", "WorkloadManifest.json"), "iOSContent"); + File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "iOS", "WorkloadManifest.json"), "iOS: iOSContent"); var sdkDirectoryWorkloadManifestProvider @@ -937,7 +937,7 @@ var sdkDirectoryWorkloadManifestProvider GetManifestContents(sdkDirectoryWorkloadManifestProvider) .Should() - .BeEquivalentTo("AndroidContent", "iOSContent"); + .BeEquivalentTo("Android: AndroidContent", "iOS: iOSContent"); } [Fact] @@ -955,18 +955,18 @@ public void ManifestFromTestHookShouldOverrideDefault() // Manifest in test hook directory Directory.CreateDirectory(Path.Combine(additionalManifestDirectory, sdkVersion, "Android")); - File.WriteAllText(Path.Combine(additionalManifestDirectory, sdkVersion, "Android", "WorkloadManifest.json"), "OverridingAndroidContent"); + File.WriteAllText(Path.Combine(additionalManifestDirectory, sdkVersion, "Android", "WorkloadManifest.json"), "Android: OverridingAndroidContent"); // Manifest in default directory Directory.CreateDirectory(Path.Combine(_manifestVersionBandDirectory, "Android")); - File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "Android", "WorkloadManifest.json"), "OverriddenAndroidContent"); + File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "Android", "WorkloadManifest.json"), "Android: OverriddenAndroidContent"); var sdkDirectoryWorkloadManifestProvider = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: sdkVersion, environmentMock.GetEnvironmentVariable, userProfileDir: null); GetManifestContents(sdkDirectoryWorkloadManifestProvider) .Should() - .BeEquivalentTo("OverridingAndroidContent"); + .BeEquivalentTo("Android: OverridingAndroidContent"); } @@ -988,28 +988,28 @@ public void ItSupportsMultipleTestHookFolders() // Manifests in default directory Directory.CreateDirectory(Path.Combine(_manifestVersionBandDirectory, "iOS")); - File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "iOS", "WorkloadManifest.json"), "iOSContent"); + File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "iOS", "WorkloadManifest.json"), "iOS: iOSContent"); Directory.CreateDirectory(Path.Combine(_manifestVersionBandDirectory, "Android")); - File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "Android", "WorkloadManifest.json"), "DefaultAndroidContent"); + File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "Android", "WorkloadManifest.json"), "Android: DefaultAndroidContent"); // Manifests in first additional directory Directory.CreateDirectory(Path.Combine(additionalManifestDirectory1, sdkVersion, "Android")); - File.WriteAllText(Path.Combine(additionalManifestDirectory1, sdkVersion, "Android", "WorkloadManifest.json"), "AndroidContent1"); + File.WriteAllText(Path.Combine(additionalManifestDirectory1, sdkVersion, "Android", "WorkloadManifest.json"), "Android: AndroidContent1"); // Manifests in second additional directory Directory.CreateDirectory(Path.Combine(additionalManifestDirectory2, sdkVersion, "Android")); - File.WriteAllText(Path.Combine(additionalManifestDirectory2, sdkVersion, "Android", "WorkloadManifest.json"), "AndroidContent2"); + File.WriteAllText(Path.Combine(additionalManifestDirectory2, sdkVersion, "Android", "WorkloadManifest.json"), "Android: AndroidContent2"); Directory.CreateDirectory(Path.Combine(additionalManifestDirectory2, sdkVersion, "Test")); - File.WriteAllText(Path.Combine(additionalManifestDirectory2, sdkVersion, "Test", "WorkloadManifest.json"), "TestContent2"); + File.WriteAllText(Path.Combine(additionalManifestDirectory2, sdkVersion, "Test", "WorkloadManifest.json"), "Test: TestContent2"); var sdkDirectoryWorkloadManifestProvider = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: sdkVersion, environmentMock.GetEnvironmentVariable, userProfileDir: null); GetManifestContents(sdkDirectoryWorkloadManifestProvider) .Should() - .BeEquivalentTo("AndroidContent1", "iOSContent", "TestContent2"); + .BeEquivalentTo("Android: AndroidContent1", "iOS: iOSContent", "Test: TestContent2"); } @@ -1025,14 +1025,14 @@ public void IfTestHookFolderDoesNotExistItShouldBeIgnored() // Manifest in default directory Directory.CreateDirectory(Path.Combine(_manifestVersionBandDirectory, "Android")); - File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "Android", "WorkloadManifest.json"), "AndroidContent"); + File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "Android", "WorkloadManifest.json"), "Android: AndroidContent"); var sdkDirectoryWorkloadManifestProvider = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "5.0.100", environmentMock.GetEnvironmentVariable, userProfileDir: null); GetManifestContents(sdkDirectoryWorkloadManifestProvider) .Should() - .BeEquivalentTo("AndroidContent"); + .BeEquivalentTo("Android: AndroidContent"); } @@ -1042,16 +1042,16 @@ public void ItShouldIgnoreOutdatedManifestIds() Initialize(); Directory.CreateDirectory(Path.Combine(_manifestVersionBandDirectory, "iOS")); - File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "iOS", "WorkloadManifest.json"), "iOSContent"); + File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "iOS", "WorkloadManifest.json"), "iOS: iOSContent"); Directory.CreateDirectory(Path.Combine(_manifestVersionBandDirectory, "Microsoft.NET.Workload.Android")); - File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "Microsoft.NET.Workload.Android", "WorkloadManifest.json"), "iOSContent"); + File.WriteAllText(Path.Combine(_manifestVersionBandDirectory, "Microsoft.NET.Workload.Android", "WorkloadManifest.json"), "Microsoft.NET.Workload.Android: AndroidContent"); var sdkDirectoryWorkloadManifestProvider = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "5.0.100", userProfileDir: null, globalJsonPath: null); GetManifestContents(sdkDirectoryWorkloadManifestProvider) .Should() - .BeEquivalentTo("iOSContent"); + .BeEquivalentTo("iOS: iOSContent"); } [Fact] @@ -1231,7 +1231,7 @@ public void ItShouldIgnoreManifestsNotFoundInFallback() var manifestDirectory6 = Path.Combine(fakeDotnetRootDirectory, "sdk-manifests", "6.0.100"); Directory.CreateDirectory(manifestDirectory6); Directory.CreateDirectory(Path.Combine(manifestDirectory6, "iOS")); - File.WriteAllText(Path.Combine(manifestDirectory6, "iOS", "WorkloadManifest.json"), "iOS-6.0.100"); + File.WriteAllText(Path.Combine(manifestDirectory6, "iOS", "WorkloadManifest.json"), "iOS: iOS-6.0.100"); var knownWorkloadsFilePath = Path.Combine(fakeDotnetRootDirectory, "sdk", "6.0.100", "KnownWorkloadManifests.txt"); Directory.CreateDirectory(Path.GetDirectoryName(knownWorkloadsFilePath)!); @@ -1242,13 +1242,21 @@ var sdkDirectoryWorkloadManifestProvider GetManifestContents(sdkDirectoryWorkloadManifestProvider) .Should() - .BeEquivalentTo("iOS-6.0.100"); + .BeEquivalentTo("iOS: iOS-6.0.100"); } private IEnumerable GetManifestContents(SdkDirectoryWorkloadManifestProvider manifestProvider) { - return manifestProvider.GetManifests().Select(manifest => new StreamReader(manifest.OpenManifestStream()).ReadToEnd()); + return manifestProvider.GetManifests().Select(manifest => + { + var contents = new StreamReader(manifest.OpenManifestStream()).ReadToEnd(); + + string manifestId = contents.Split(':')[0]; + manifest.ManifestId.Should().Be(manifestId); + + return contents; + }); } private class EnvironmentMock diff --git a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/WorkloadPackGroupTests.cs b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/WorkloadPackGroupTests.cs index 5f3cb5d9aba9..23b0b73df154 100644 --- a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/WorkloadPackGroupTests.cs +++ b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/WorkloadPackGroupTests.cs @@ -28,7 +28,7 @@ public void TestGetManifestDirectories() { var manifestProvider = CreateManifestProvider(); - var manifestDirectories = manifestProvider.GetManifestDirectories(); + var manifestDirectories = manifestProvider.GetManifests().Select(m => m.ManifestDirectory); foreach (var manifestDirectory in manifestDirectories) { Log.WriteLine(manifestDirectory); diff --git a/src/Tests/dotnet-workload-install.Tests/MockManifestProvider.cs b/src/Tests/dotnet-workload-install.Tests/MockManifestProvider.cs index 4f5be2bf4f36..6af4f83e25d4 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockManifestProvider.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockManifestProvider.cs @@ -40,6 +40,7 @@ public IEnumerable GetManifests() { yield return new( id, + Path.GetDirectoryName(path), path, () => File.OpenRead(path), () => WorkloadManifestReader.TryOpenLocalizationCatalogForManifest(path) From 7876941e50d4deb8d687bbb5845217bf69990a57 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Wed, 12 Jul 2023 16:58:43 -0400 Subject: [PATCH 12/13] Correctly report manifest feature band for side-by-side manifests in WorkloadResolver.GetInstalledManifests --- .../dotnet-workload/WorkloadCommandParser.cs | 7 +- .../list/WorkloadListCommand.cs | 7 +- .../ReadableWorkloadManifest.cs | 5 +- .../SdkDirectoryWorkloadManifestProvider.cs | 67 ++++++------ .../TempDirectoryWorkloadManifestProvider.cs | 1 + .../WorkloadManifestInfo.cs | 4 +- .../WorkloadResolver.cs | 26 +++-- .../FakeManifestProvider.cs | 5 +- ...kDirectoryWorkloadManifestProviderTests.cs | 101 +++++++++++++++++- .../GivenWorkloadManifestUpdater.cs | 15 ++- .../MockManifestProvider.cs | 19 ++-- .../GivenDotnetWorkloadList.cs | 4 +- 12 files changed, 190 insertions(+), 71 deletions(-) diff --git a/src/Cli/dotnet/commands/dotnet-workload/WorkloadCommandParser.cs b/src/Cli/dotnet/commands/dotnet-workload/WorkloadCommandParser.cs index ac7cfffaec46..7a49de4f4f05 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/WorkloadCommandParser.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/WorkloadCommandParser.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; using System.Collections.Generic; using System.CommandLine; using System.CommandLine.Parsing; @@ -41,14 +42,12 @@ internal static void ShowWorkloadsInfo(IWorkloadInfoHelper workloadInfoHelper = return; } + var manifestInfoDict = workloadInfoHelper.WorkloadResolver.GetInstalledManifests().ToDictionary(info => info.Id, StringComparer.OrdinalIgnoreCase); foreach (var workload in installedWorkloads.AsEnumerable()) { var workloadManifest = workloadInfoHelper.WorkloadResolver.GetManifestFromWorkload(new WorkloadId(workload.Key)); - var workloadFeatureBand = new WorkloadManifestInfo( - workloadManifest.Id, - workloadManifest.Version, - Path.GetDirectoryName(workloadManifest.ManifestPath)!).ManifestFeatureBand; + var workloadFeatureBand = manifestInfoDict[workloadManifest.Id].ManifestFeatureBand; const int align = 10; const string separator = " "; diff --git a/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs b/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs index 298a54f52dfe..9581b7664c5e 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/list/WorkloadListCommand.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; using System.Collections.Generic; using System.CommandLine; using System.CommandLine.Parsing; @@ -79,6 +80,8 @@ public override int Execute() } else { + var manifestInfoDict = _workloadListHelper.WorkloadResolver.GetInstalledManifests().ToDictionary(info => info.Id, StringComparer.OrdinalIgnoreCase); + InstalledWorkloadsCollection installedWorkloads = _workloadListHelper.AddInstalledVsWorkloads(installedList); Reporter.WriteLine(); PrintableTable> table = new(); @@ -86,8 +89,8 @@ public override int Execute() table.AddColumn(InformationStrings.WorkloadManfiestVersionColumn, workload => { var m = _workloadListHelper.WorkloadResolver.GetManifestFromWorkload(new WorkloadId(workload.Key)); - return m.Version + "/" + - new WorkloadManifestInfo(m.Id, m.Version, Path.GetDirectoryName(m.ManifestPath)!).ManifestFeatureBand; + var manifestInfo = manifestInfoDict[m.Id]; + return m.Version + "/" + manifestInfo.ManifestFeatureBand; }); table.AddColumn(InformationStrings.WorkloadSourceColumn, workload => workload.Value); diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/ReadableWorkloadManifest.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/ReadableWorkloadManifest.cs index e0a5cf5dd848..1ce6d96efb15 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/ReadableWorkloadManifest.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/ReadableWorkloadManifest.cs @@ -19,16 +19,19 @@ public class ReadableWorkloadManifest public string ManifestPath { get; } + public string ManifestFeatureBand { get; } + readonly Func _openManifestStreamFunc; readonly Func _openLocalizationStream; - public ReadableWorkloadManifest(string manifestId, string manifestDirectory, string manifestPath, Func openManifestStreamFunc, Func openLocalizationStream) + public ReadableWorkloadManifest(string manifestId, string manifestDirectory, string manifestPath, string manifestFeatureBand, Func openManifestStreamFunc, Func openLocalizationStream) { ManifestId = manifestId; ManifestPath = manifestPath; ManifestDirectory = manifestDirectory; + ManifestFeatureBand = manifestFeatureBand; _openManifestStreamFunc = openManifestStreamFunc; _openLocalizationStream = openLocalizationStream; } diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs index f32101243e22..f153166568e1 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs @@ -129,14 +129,29 @@ internal SdkDirectoryWorkloadManifestProvider(string sdkRootPath, string sdkVers public IEnumerable GetManifests() { // Scan manifest directories - var manifestIdsToDirectories = new Dictionary(StringComparer.OrdinalIgnoreCase); + var manifestIdsToManifests = new Dictionary(StringComparer.OrdinalIgnoreCase); - void ProbeDirectory(string manifestDirectory) + void AddManifest(string manifestId, string manifestDirectory, string featureBand) + { + var workloadManifestPath = Path.Combine(manifestDirectory, "WorkloadManifest.json"); + + var readableManifest = new ReadableWorkloadManifest( + manifestId, + manifestDirectory, + workloadManifestPath, + featureBand, + () => File.OpenRead(workloadManifestPath), + () => WorkloadManifestReader.TryOpenLocalizationCatalogForManifest(workloadManifestPath)); + + manifestIdsToManifests[manifestId] = readableManifest; + } + + void ProbeDirectory(string manifestDirectory, string featureBand) { (string? id, string? finalManifestDirectory) = ResolveManifestDirectory(manifestDirectory); if (id != null && finalManifestDirectory != null) { - manifestIdsToDirectories.Add(id, finalManifestDirectory); + AddManifest(id, finalManifestDirectory, featureBand); } } @@ -148,7 +163,7 @@ void ProbeDirectory(string manifestDirectory) { foreach (var workloadManifestDirectory in Directory.EnumerateDirectories(manifestVersionBandDirectory)) { - ProbeDirectory(workloadManifestDirectory); + ProbeDirectory(workloadManifestDirectory, _sdkVersionBand.ToString()); } } } @@ -170,7 +185,7 @@ void ProbeDirectory(string manifestDirectory) foreach (var workloadManifestDirectory in directoriesWithManifests.Values) { - ProbeDirectory(workloadManifestDirectory); + ProbeDirectory(workloadManifestDirectory, _sdkVersionBand.ToString()); } } @@ -185,7 +200,8 @@ void ProbeDirectory(string manifestDirectory) { throw new FileNotFoundException(string.Format(Strings.ManifestFromWorkloadSetNotFound, manifestSpecifier.ToString(), _workloadSet.Version)); } - manifestIdsToDirectories[kvp.Key.ToString()] = manifestDirectory; + AddManifest(manifestSpecifier.Id.ToString(), manifestDirectory, manifestSpecifier.FeatureBand.ToString()); + } } @@ -200,26 +216,26 @@ void ProbeDirectory(string manifestDirectory) { throw new FileNotFoundException(string.Format(Strings.ManifestFromInstallStateNotFound, manifestSpecifier.ToString(), _installStateFilePath)); } - manifestIdsToDirectories[kvp.Key.ToString()] = manifestDirectory; + AddManifest(manifestSpecifier.Id.ToString(), manifestDirectory, manifestSpecifier.FeatureBand.ToString()); } } - if (_knownManifestIdsAndOrder != null && _knownManifestIdsAndOrder.Keys.Any(id => !manifestIdsToDirectories.ContainsKey(id))) + if (_knownManifestIdsAndOrder != null && _knownManifestIdsAndOrder.Keys.Any(id => !manifestIdsToManifests.ContainsKey(id))) { - var missingManifestIds = _knownManifestIdsAndOrder.Keys.Where(id => !manifestIdsToDirectories.ContainsKey(id)); + var missingManifestIds = _knownManifestIdsAndOrder.Keys.Where(id => !manifestIdsToManifests.ContainsKey(id)); foreach (var missingManifestId in missingManifestIds) { - var manifestDir = FallbackForMissingManifest(missingManifestId); + var (manifestDir, featureBand) = FallbackForMissingManifest(missingManifestId); if (!string.IsNullOrEmpty(manifestDir)) { - manifestIdsToDirectories.Add(missingManifestId, manifestDir); + AddManifest(missingManifestId, manifestDir, featureBand); } } } // Return manifests in a stable order. Manifests in the KnownWorkloadManifests.txt file will be first, and in the same order they appear in that file. // Then the rest of the manifests (if any) will be returned in (ordinal case-insensitive) alphabetical order. - return manifestIdsToDirectories + return manifestIdsToManifests .OrderBy(kvp => { if (_knownManifestIdsAndOrder != null && @@ -230,19 +246,7 @@ void ProbeDirectory(string manifestDirectory) return int.MaxValue; }) .ThenBy(kvp => kvp.Key, StringComparer.OrdinalIgnoreCase) - .Select(kvp => - { - var manifestId = kvp.Key; - var manifestDirectory = kvp.Value; - var workloadManifestPath = Path.Combine(manifestDirectory, "WorkloadManifest.json"); - - return new ReadableWorkloadManifest( - manifestId, - manifestDirectory, - workloadManifestPath, - () => File.OpenRead(workloadManifestPath), - () => WorkloadManifestReader.TryOpenLocalizationCatalogForManifest(workloadManifestPath)); - }) + .Select(kvp => kvp.Value) .ToList(); } @@ -283,13 +287,13 @@ void ProbeDirectory(string manifestDirectory) return (null, null); } - private string FallbackForMissingManifest(string manifestId) + private (string manifestDirectory, string manifestFeatureBand) FallbackForMissingManifest(string manifestId) { // Only use the last manifest root (usually the dotnet folder itself) for fallback var sdkManifestPath = _manifestRoots.Last(); if (!Directory.Exists(sdkManifestPath)) { - return string.Empty; + return (string.Empty, string.Empty); } var candidateFeatureBands = Directory.GetDirectories(sdkManifestPath) @@ -297,7 +301,7 @@ private string FallbackForMissingManifest(string manifestId) .Select(featureBand => new SdkFeatureBand(featureBand)) .Where(featureBand => featureBand < _sdkVersionBand || _sdkVersionBand.ToStringWithoutPrerelease().Equals(featureBand.ToString(), StringComparison.Ordinal)); - var matchingManifestFatureBandsAndResolvedManifestDirectories = candidateFeatureBands + var matchingManifestFeatureBandsAndResolvedManifestDirectories = candidateFeatureBands // Calculate path to \ .Select(featureBand => (featureBand, manifestDirectory: Path.Combine(sdkManifestPath, featureBand.ToString(), manifestId))) // Filter out directories that don't exist @@ -308,14 +312,15 @@ private string FallbackForMissingManifest(string manifestId) .Where(t => t.res.id != null && t.res.manifestDirectory != null) .ToList(); - if (matchingManifestFatureBandsAndResolvedManifestDirectories.Any()) + if (matchingManifestFeatureBandsAndResolvedManifestDirectories.Any()) { - return matchingManifestFatureBandsAndResolvedManifestDirectories.OrderByDescending(t => t.featureBand).First().res.manifestDirectory!; + var selectedFeatureBandAndManifestDirectory = matchingManifestFeatureBandsAndResolvedManifestDirectories.OrderByDescending(t => t.featureBand).First(); + return (selectedFeatureBandAndManifestDirectory.res.manifestDirectory!, selectedFeatureBandAndManifestDirectory.featureBand.ToString()); } else { // Manifest does not exist - return string.Empty; + return (string.Empty, string.Empty); } } diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/TempDirectoryWorkloadManifestProvider.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/TempDirectoryWorkloadManifestProvider.cs index ad627cc8676a..757807105bc6 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/TempDirectoryWorkloadManifestProvider.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/TempDirectoryWorkloadManifestProvider.cs @@ -37,6 +37,7 @@ public IEnumerable manifestId, workloadManifestDirectory, workloadManifestPath, + _sdkVersionBand, () => File.OpenRead(workloadManifestPath), () => WorkloadManifestReader.TryOpenLocalizationCatalogForManifest(workloadManifestPath) ); diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadManifestInfo.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadManifestInfo.cs index 4ebc88bb0fcf..12dfe6fc7737 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadManifestInfo.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadManifestInfo.cs @@ -13,12 +13,12 @@ namespace Microsoft.NET.Sdk.WorkloadManifestReader { public class WorkloadManifestInfo { - public WorkloadManifestInfo(string id, string version, string manifestDirectory) + public WorkloadManifestInfo(string id, string version, string manifestDirectory, string manifestFeatureBand) { Id = id; Version = version; ManifestDirectory = manifestDirectory; - ManifestFeatureBand = Path.GetFileName(Path.GetDirectoryName(manifestDirectory))!; + ManifestFeatureBand = manifestFeatureBand; } public string Id { get; } diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadResolver.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadResolver.cs index d13eb54c6e51..d9b0d4a73334 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadResolver.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadResolver.cs @@ -21,7 +21,7 @@ namespace Microsoft.NET.Sdk.WorkloadManifestReader /// public class WorkloadResolver : IWorkloadResolver { - private readonly Dictionary _manifests = new(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary _manifests = new(StringComparer.OrdinalIgnoreCase); private readonly Dictionary _workloads = new(); private readonly Dictionary _packs = new(); private IWorkloadManifestProvider? _manifestProvider; @@ -118,9 +118,10 @@ private void LoadManifestsFromProvider(IWorkloadManifestProvider manifestProvide using (Stream? localizationStream = readableManifest.OpenLocalizationStream()) { var manifest = WorkloadManifestReader.ReadWorkloadManifest(readableManifest.ManifestId, manifestStream, localizationStream, readableManifest.ManifestPath); - if (!_manifests.TryAdd(readableManifest.ManifestId, manifest)) + var manifestInfo = new WorkloadManifestInfo(manifest.Id, manifest.Version, readableManifest.ManifestDirectory, readableManifest.ManifestFeatureBand); + if (!_manifests.TryAdd(readableManifest.ManifestId, (manifest, manifestInfo))) { - var existingManifest = _manifests[readableManifest.ManifestId]; + var existingManifest = _manifests[readableManifest.ManifestId].manifest; throw new WorkloadManifestCompositionException(Strings.DuplicateManifestID, manifestProvider.GetType().FullName, readableManifest.ManifestId, readableManifest.ManifestPath, existingManifest.ManifestPath); } } @@ -134,14 +135,15 @@ private void ComposeWorkloadManifests() Dictionary? redirects = null; - foreach (var manifest in _manifests.Values) + foreach (var (manifest, info) in _manifests.Values) { if (manifest.DependsOnManifests != null) { foreach (var dependency in manifest.DependsOnManifests) { - if (_manifests.TryGetValue(dependency.Key, out var resolvedDependency)) + if (_manifests.TryGetValue(dependency.Key, out var t)) { + var resolvedDependency = t.manifest; if (FXVersion.Compare(dependency.Value, resolvedDependency.ParsedVersion) > 0) { throw new WorkloadManifestCompositionException(Strings.ManifestDependencyVersionTooLow, dependency.Key, resolvedDependency.Version, dependency.Value, manifest.Id, manifest.ManifestPath); @@ -711,11 +713,17 @@ private bool IsWorkloadPlatformCompatible(WorkloadDefinition workload, WorkloadM private bool IsWorkloadImplicitlyAbstract(WorkloadDefinition workload, WorkloadManifest manifest) => !GetPacksInWorkload(workload, manifest).Any(); - public string GetManifestVersion(string manifestId) => - (_manifests.TryGetValue(manifestId, out WorkloadManifest? value)? value : null)?.Version - ?? throw new Exception($"Manifest with id {manifestId} does not exist."); + public string GetManifestVersion(string manifestId) + { + if (_manifests.TryGetValue(manifestId, out var value)) + { + return value.manifest.Version; + } + throw new Exception($"Manifest with id {manifestId} does not exist."); + } + - public IEnumerable GetInstalledManifests() => _manifests.Select(m => new WorkloadManifestInfo(m.Value.Id, m.Value.Version, Path.GetDirectoryName(m.Value.ManifestPath)!)); + public IEnumerable GetInstalledManifests() => _manifests.Select(t => t.Value.info); } static class DictionaryExtensions diff --git a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/FakeManifestProvider.cs b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/FakeManifestProvider.cs index 8776c06327d1..3a93256d316c 100644 --- a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/FakeManifestProvider.cs +++ b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/FakeManifestProvider.cs @@ -26,8 +26,6 @@ public FakeManifestProvider(params (string manifest, string? localizationCatalog _filePaths = filePaths; } - public IEnumerable GetManifestDirectories() => throw new NotImplementedException(); - public IEnumerable GetManifests() { foreach (var filePath in _filePaths) @@ -36,6 +34,7 @@ public IEnumerable GetManifests() Path.GetFileNameWithoutExtension(filePath.manifest), Path.GetDirectoryName(filePath.manifest)!, filePath.manifest, + "8.0.100", () => new FileStream(filePath.manifest, FileMode.Open, FileAccess.Read), () => filePath.localizationCatalog != null ? new FileStream(filePath.localizationCatalog, FileMode.Open, FileAccess.Read) : null ); @@ -50,13 +49,13 @@ internal class InMemoryFakeManifestProvider : IWorkloadManifestProvider, IEnumer readonly List<(string id, byte[] content)> _manifests = new List<(string, byte[])>(); public void Add(string id, string content) => _manifests.Add((id, Encoding.UTF8.GetBytes(content))); - public IEnumerable GetManifestDirectories() => throw new NotImplementedException(); public IEnumerable GetManifests() => _manifests.Select(m => new ReadableWorkloadManifest( m.id, $@"C:\fake\{m.id}", $@"C:\fake\{m.id}\WorkloadManifest.json", + "8.0.100", (Func)(() => new MemoryStream(m.content)), (Func)(() => null) )); diff --git a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs index 0df4511deedf..10e43e37a685 100644 --- a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs +++ b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs @@ -1183,7 +1183,7 @@ public void ItReturnsManifestsInOrderFromKnownWorkloadManifestsFile() $"NotInIncudedWorkloadsFile: 1/{currentSdkVersion}"); } - private void CreateMockManifest(string manifestRoot, string featureBand, string manifestId, string manifestVersion, bool useVersionFolder = false) + private void CreateMockManifest(string manifestRoot, string featureBand, string manifestId, string manifestVersion, bool useVersionFolder = false, string? manifestContents = null) { var manifestDirectory = Path.Combine(manifestRoot, featureBand, manifestId); if (useVersionFolder) @@ -1196,7 +1196,12 @@ private void CreateMockManifest(string manifestRoot, string featureBand, string Directory.CreateDirectory(manifestDirectory); } - File.WriteAllText(Path.Combine(manifestDirectory, "WorkloadManifest.json"), $"{manifestId}: {manifestVersion}/{featureBand}"); + if (manifestContents == null) + { + manifestContents = $"{manifestId}: {manifestVersion}/{featureBand}"; + } + + File.WriteAllText(Path.Combine(manifestDirectory, "WorkloadManifest.json"), manifestContents); } private void CreateMockWorkloadSet(string manifestRoot, string featureBand, string workloadSetVersion, string workloadSetContents) @@ -1243,7 +1248,99 @@ var sdkDirectoryWorkloadManifestProvider GetManifestContents(sdkDirectoryWorkloadManifestProvider) .Should() .BeEquivalentTo("iOS: iOS-6.0.100"); + } + + [Fact] + public void WorkloadResolverUsesManifestsFromWorkloadSet() + { + Initialize("8.0.200"); + + string manifestContents1 = """ + { + "version": "11.0.1", + "workloads": { + "ios": { + "description": "iOS workload", + "kind": "dev", + "packs": [ "Microsoft.NET.iOS.Workload" ] + }, + }, + "packs": { + "Microsoft.NET.iOS.Workload" : { + "kind": "sdk", + "version": "1" + } + } + } + """; + + string manifestContents2 = """ + { + "version": "11.0.2", + "workloads": { + "ios": { + "description": "iOS workload", + "kind": "dev", + "packs": [ "Microsoft.NET.iOS.Workload" ] + }, + }, + "packs": { + "Microsoft.NET.iOS.Workload" : { + "kind": "sdk", + "version": "2" + } + } + } + """; + + string manifestContents3 = """ + { + "version": "12.0.1", + "workloads": { + "ios": { + "description": "iOS workload", + "kind": "dev", + "packs": [ "Microsoft.NET.iOS.Workload" ] + }, + }, + "packs": { + "Microsoft.NET.iOS.Workload" : { + "kind": "sdk", + "version": "3" + } + } + } + """; + + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.1", true, manifestContents1); + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true, manifestContents2); + CreateMockManifest(_manifestRoot, "8.0.200", "ios", "12.0.1", true, manifestContents3); + + CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.200", """ + { + "ios": "11.0.2/8.0.100" + } + """); + + var sdkDirectoryWorkloadManifestProvider + = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null); + var workloadResolver = WorkloadResolver.CreateForTests(sdkDirectoryWorkloadManifestProvider, _fakeDotnetRootDirectory); + + var workloads = workloadResolver.GetAvailableWorkloads(); + workloads.Count().Should().Be(1); + var expectedPackId = new WorkloadPackId("Microsoft.NET.iOS.Workload"); + workloadResolver.GetPacksInWorkload(workloads.Single().Id).Should().BeEquivalentTo(new[] { expectedPackId }); + var packInfo = workloadResolver.TryGetPackInfo(expectedPackId); + packInfo.Should().NotBeNull(); + packInfo!.Version.Should().Be("2"); + + workloadResolver.GetInstalledManifests().Count().Should().Be(1); + var manifestInfo = workloadResolver.GetInstalledManifests().Single(); + manifestInfo.Id.Should().Be("ios"); + manifestInfo.Version.Should().Be("11.0.2"); + manifestInfo.ManifestFeatureBand.Should().Be("8.0.100"); + manifestInfo.ManifestDirectory.Should().Be(Path.Combine(_manifestRoot, "8.0.100", "ios", "11.0.2")); } private IEnumerable GetManifestContents(SdkDirectoryWorkloadManifestProvider manifestProvider) diff --git a/src/Tests/dotnet-workload-install.Tests/GivenWorkloadManifestUpdater.cs b/src/Tests/dotnet-workload-install.Tests/GivenWorkloadManifestUpdater.cs index 81f35f2b770e..c7c92b3eba10 100644 --- a/src/Tests/dotnet-workload-install.Tests/GivenWorkloadManifestUpdater.cs +++ b/src/Tests/dotnet-workload-install.Tests/GivenWorkloadManifestUpdater.cs @@ -192,10 +192,13 @@ public void GivenAdvertisedManifestsItCalculatesCorrectUpdates() File.WriteAllText(Path.Combine(AdManifestPath, "AdvertisedManifestFeatureBand.txt"), currentFeatureBand); } - var manifestDirs = expectedManifestUpdates.Select(manifest => Path.Combine(testDir, "dotnet", "sdk-manifests", manifest.ExistingFeatureBand, manifest.ManifestId.ToString(), "WorkloadManifest.json")) - .Concat(expectedManifestNotUpdated.Select(manifest => Path.Combine(testDir, "dotnet", "sdk-manifests", currentFeatureBand, manifest.ToString(), "WorkloadManifest.json"))) + var manifestInfo = expectedManifestUpdates.Select( + manifest => (manifest.ManifestId.ToString(), Path.Combine(testDir, "dotnet", "sdk-manifests", manifest.ExistingFeatureBand, manifest.ManifestId.ToString(), "WorkloadManifest.json"), manifest.ExistingFeatureBand)) + .Concat(expectedManifestNotUpdated.Select( + manifestId => (manifestId.ToString(), Path.Combine(testDir, "dotnet", "sdk-manifests", currentFeatureBand, manifestId.ToString(), "WorkloadManifest.json"), currentFeatureBand))) .ToArray(); - var workloadManifestProvider = new MockManifestProvider(manifestDirs); + + var workloadManifestProvider = new MockManifestProvider(manifestInfo); workloadManifestProvider.SdkFeatureBand = new SdkFeatureBand(currentFeatureBand); var nugetDownloader = new MockNuGetPackageDownloader(dotnetRoot); var workloadResolver = WorkloadResolver.CreateForTests(workloadManifestProvider, dotnetRoot); @@ -231,7 +234,9 @@ public void ItCanFallbackAndAdvertiseCorrectUpdate(bool useOfflineCache) Directory.CreateDirectory(Path.Combine(installedManifestDir6_0_200, testManifestName)); File.WriteAllText(Path.Combine(installedManifestDir6_0_200, testManifestName, _manifestFileName), GetManifestContent(new ManifestVersion("1.0.0"))); - var workloadManifestProvider = new MockManifestProvider(Path.Combine(installedManifestDir6_0_200, testManifestName, _manifestFileName)) + string manifestPath = Path.Combine(installedManifestDir6_0_200, testManifestName, _manifestFileName); + + var workloadManifestProvider = new MockManifestProvider((testManifestName, manifestPath, "6.0.200")) { SdkFeatureBand = new SdkFeatureBand(sdkFeatureBand) }; @@ -309,7 +314,7 @@ public void ItCanFallbackWithNoUpdates(bool useOfflineCache) Directory.CreateDirectory(Path.Combine(emptyInstalledManifestsDir, testManifestName)); File.WriteAllText(Path.Combine(emptyInstalledManifestsDir, testManifestName, _manifestFileName), GetManifestContent(new ManifestVersion("1.0.0"))); - var workloadManifestProvider = new MockManifestProvider(Path.Combine(emptyInstalledManifestsDir, testManifestName, _manifestFileName)) + var workloadManifestProvider = new MockManifestProvider((testManifestName, Path.Combine(emptyInstalledManifestsDir, testManifestName, _manifestFileName), "6.0.200")) { SdkFeatureBand = new SdkFeatureBand(sdkFeatureBand) }; diff --git a/src/Tests/dotnet-workload-install.Tests/MockManifestProvider.cs b/src/Tests/dotnet-workload-install.Tests/MockManifestProvider.cs index 6af4f83e25d4..58cd7f47fccd 100644 --- a/src/Tests/dotnet-workload-install.Tests/MockManifestProvider.cs +++ b/src/Tests/dotnet-workload-install.Tests/MockManifestProvider.cs @@ -12,36 +12,35 @@ namespace ManifestReaderTests { internal class MockManifestProvider : IWorkloadManifestProvider { - readonly (string name, string path)[] _manifests; + readonly (string name, string path, string featureBand)[] _manifests; public MockManifestProvider(params string[] manifestPaths) { _manifests = Array.ConvertAll(manifestPaths, mp => { string manifestId = Path.GetFileNameWithoutExtension(Path.GetDirectoryName(mp)); - return (manifestId, mp); + return (manifestId, mp, (string)null); }); SdkFeatureBand = new SdkFeatureBand("6.0.100"); } - public SdkFeatureBand SdkFeatureBand { get; set; } - - public IEnumerable GetManifestDirectories() + public MockManifestProvider(params (string name, string path, string featureBand)[] manifests) { - foreach ((_, var filePath) in _manifests) - { - yield return Path.GetDirectoryName(filePath); - } + _manifests = manifests; + SdkFeatureBand = new SdkFeatureBand("6.0.100"); } + public SdkFeatureBand SdkFeatureBand { get; set; } + public IEnumerable GetManifests() { - foreach ((var id, var path) in _manifests) + foreach ((var id, var path, var featureBand) in _manifests) { yield return new( id, Path.GetDirectoryName(path), path, + featureBand ?? SdkFeatureBand.ToString(), () => File.OpenRead(path), () => WorkloadManifestReader.TryOpenLocalizationCatalogForManifest(path) ); diff --git a/src/Tests/dotnet-workload-list.Tests/GivenDotnetWorkloadList.cs b/src/Tests/dotnet-workload-list.Tests/GivenDotnetWorkloadList.cs index 36a4a10ec650..e61d01dc6bf3 100644 --- a/src/Tests/dotnet-workload-list.Tests/GivenDotnetWorkloadList.cs +++ b/src/Tests/dotnet-workload-list.Tests/GivenDotnetWorkloadList.cs @@ -66,13 +66,13 @@ public void GivenWorkloadsAreInstalledListIsNotEmpty() _reporter.Clear(); var expectedWorkloads = new List() { new WorkloadId("mock-workload-1"), new WorkloadId("mock-workload-2"), new WorkloadId("mock-workload-3") }; var workloadInstaller = new MockWorkloadRecordRepo(expectedWorkloads); - var workloadResolver = WorkloadResolver.CreateForTests(new MockManifestProvider(new[] { _manifestPath }), Directory.GetCurrentDirectory()); + var workloadResolver = WorkloadResolver.CreateForTests(new MockManifestProvider(("SampleManifest", _manifestPath, "6.0.100")), Directory.GetCurrentDirectory()); var command = new WorkloadListCommand(_parseResult, _reporter, workloadInstaller, "6.0.100", workloadResolver: workloadResolver); command.Execute(); foreach (var workload in expectedWorkloads) { - _reporter.Lines.Select(line => line.Trim()).Should().Contain($"{workload} 5.0.0/TestProjects SDK 6.0.100"); + _reporter.Lines.Select(line => line.Trim()).Should().Contain($"{workload} 5.0.0/6.0.100 SDK 6.0.100"); } } From a60bcc93c5b240a4f21a9c0bebd338b8ccee8b76 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Wed, 12 Jul 2023 16:59:02 -0400 Subject: [PATCH 13/13] Allow trailing commas in workload set json --- .../WorkloadSet.cs | 7 ++++- ...kDirectoryWorkloadManifestProviderTests.cs | 26 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadSet.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadSet.cs index ed78e7765c98..2d2606cc1b3f 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadSet.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadSet.cs @@ -71,7 +71,12 @@ public static WorkloadSet FromDictionaryForJson(IDictionary dict public static WorkloadSet FromJson(string json, SdkFeatureBand defaultFeatureBand) { #if USE_SYSTEM_TEXT_JSON - return FromDictionaryForJson(JsonSerializer.Deserialize>(json)!, defaultFeatureBand); + var jsonSerializerOptions = new JsonSerializerOptions() + { + AllowTrailingCommas = true, + ReadCommentHandling = JsonCommentHandling.Skip + }; + return FromDictionaryForJson(JsonSerializer.Deserialize>(json, jsonSerializerOptions)!, defaultFeatureBand); #else return FromDictionaryForJson(JsonConvert.DeserializeObject>(json)!, defaultFeatureBand); #endif diff --git a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs index 10e43e37a685..8393226db7a0 100644 --- a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs +++ b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs @@ -202,6 +202,32 @@ var sdkDirectoryWorkloadManifestProvider .BeEquivalentTo("ios: 11.0.2/8.0.100", "android: 33.0.2-rc.1/8.0.200", "maui: 15.0.1-rc.456/8.0.200-rc.2"); } + + [Fact] + public void WorkloadSetCanHaveTrailingCommasInJson() + { + Initialize("8.0.200"); + + CreateMockManifest(_manifestRoot, "8.0.100", "ios", "11.0.2", true); + CreateMockManifest(_manifestRoot, "8.0.200", "android", "33.0.2-rc.1", true); + CreateMockManifest(_manifestRoot, "8.0.200-rc.2", "maui", "15.0.1-rc.456", true); + + CreateMockWorkloadSet(_manifestRoot, "8.0.200", "8.0.200", """ + { + "ios": "11.0.2/8.0.100", + "android": "33.0.2-rc.1/8.0.200", + "maui": "15.0.1-rc.456/8.0.200-rc.2", + } + """); + + var sdkDirectoryWorkloadManifestProvider + = new SdkDirectoryWorkloadManifestProvider(sdkRootPath: _fakeDotnetRootDirectory, sdkVersion: "8.0.200", userProfileDir: null, globalJsonPath: null); + + GetManifestContents(sdkDirectoryWorkloadManifestProvider) + .Should() + .BeEquivalentTo("ios: 11.0.2/8.0.100", "android: 33.0.2-rc.1/8.0.200", "maui: 15.0.1-rc.456/8.0.200-rc.2"); + } + [Theory] [InlineData(false)] [InlineData(true)]