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/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs index 20027af22f33..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,24 +31,11 @@ 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; - ConsumeToken(ref reader, JsonTokenType.StartObject); + JsonReader.ConsumeToken(ref reader, JsonTokenType.StartObject); while (reader.Read()) { switch (reader.TokenType) @@ -57,7 +44,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,113 +55,37 @@ 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); - } - - /// - /// 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(); + throw new JsonFormatException(Strings.IncompleteDocument); } } - - [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.InstallStateReader.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.InstallStateReader.cs new file mode 100644 index 000000000000..32e47f7df400 --- /dev/null +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.InstallStateReader.cs @@ -0,0 +1,96 @@ +// 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); + var reader = JsonReader.CreateReader(fileStream); + + 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.JsonReader.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.JsonReader.cs new file mode 100644 index 000000000000..cd720f834da4 --- /dev/null +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.JsonReader.cs @@ -0,0 +1,123 @@ +// 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 + { + + 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 + /// + 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/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 new file mode 100644 index 000000000000..95d62da17dc9 --- /dev/null +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadInstallType.cs @@ -0,0 +1,68 @@ +// 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; + } + + 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.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "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 diff --git a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs index 593b70fd2ff6..6385b9c20361 100644 --- a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs +++ b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs @@ -519,10 +519,352 @@ public void ItFailsIfGlobalJsonIsMalformed() } """); - var ex = Assert.Throws( + var ex = Assert.Throws( () => 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() {