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 072a079630a9..000000000000 --- a/src/Cli/dotnet/commands/dotnet-workload/InstallType.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -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 9afbb3106206..70772bbed7af 100644 --- a/src/Cli/dotnet/commands/dotnet-workload/WorkloadCommandParser.cs +++ b/src/Cli/dotnet/commands/dotnet-workload/WorkloadCommandParser.cs @@ -78,8 +78,9 @@ internal static void ShowWorkloadsInfo(ParseResult parseResult = null, IWorkload reporter.WriteLine($" {workloadManifest.ManifestPath,align}"); reporter.Write($"{separator}{CommonStrings.WorkloadInstallTypeColumn}:"); - reporter.WriteLine($" {WorkloadInstallerFactory.GetWorkloadInstallType(new SdkFeatureBand(workloadFeatureBand), dotnetPath),align}" + reporter.WriteLine($" {WorkloadInstallType.GetWorkloadInstallType(new SdkFeatureBand(workloadFeatureBand), dotnetPath).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 c2e3f60e498e..67b0734916f9 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) { @@ -62,24 +62,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.WorkloadMSBuildSdkResolver/CachingWorkloadResolver.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadMSBuildSdkResolver/CachingWorkloadResolver.cs index 126b751316b0..15b57a1a9da0 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 9b1073ccce14..85b502f2d1df 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 c09bb13ac569..5974089df81e 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/ReadableWorkloadManifest.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/ReadableWorkloadManifest.cs @@ -13,6 +13,9 @@ namespace Microsoft.NET.Sdk.WorkloadManifestReader public class ReadableWorkloadManifest { public string ManifestId { get; } + + public string ManifestDirectory { get; } + public string ManifestPath { get; } readonly Func _openManifestStreamFunc; @@ -20,10 +23,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.GlobalJsonReader.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.GlobalJsonReader.cs index 2b04bc7e84d5..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)) { @@ -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,115 +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) { } - #if NET8_0_OR_GREATER - [Obsolete(DiagnosticId = "SYSLIB0051")] // add this attribute to the serialization ctor - #endif - 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..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.JsonReader.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.JsonReader.cs new file mode 100644 index 000000000000..79af53599ed1 --- /dev/null +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.JsonReader.cs @@ -0,0 +1,108 @@ +// 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) { } +#if NET8_0_OR_GREATER + [Obsolete(DiagnosticId = "SYSLIB0051")] // add this attribute to the serialization ctor +#endif + 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 866f886de85d..93c07b1e5fa9 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/SdkDirectoryWorkloadManifestProvider.cs @@ -24,6 +24,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) @@ -90,15 +92,29 @@ 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)); + } + } + 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)) { - throw new FileNotFoundException(string.Format(Strings.WorkloadVersionFromGlobalJsonNotFound, globalJsonWorkloadSetVersion, globalJsonPath)); + if (!availableWorkloadSets.TryGetValue(installState.WorkloadSetVersion!, out _workloadSet)) + { + throw new FileNotFoundException(string.Format(Strings.WorkloadVersionFromInstallStateNotFound, installState.WorkloadSetVersion, installStateFilePath)); + } } + _manifestsFromInstallState = installState.Manifests; + _installStateFilePath = installStateFilePath; } } @@ -110,22 +126,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); @@ -178,7 +178,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; } } @@ -208,7 +229,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(); } @@ -285,7 +318,7 @@ private string FallbackForMissingManifest(string manifestId) } } - private string GetManifestDirectoryFromSpecifier(ManifestSpecifier manifestSpecifier) + private string? GetManifestDirectoryFromSpecifier(ManifestSpecifier manifestSpecifier) { foreach (var manifestDirectory in _manifestRoots) { @@ -296,8 +329,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..51881eb4abec 100644 --- a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/Strings.resx +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/Strings.resx @@ -189,11 +189,20 @@ 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. + {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. Error parsing version '{1}' for workload manifest ID '{0}' diff --git a/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/TempDirectoryWorkloadManifestProvider.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/TempDirectoryWorkloadManifestProvider.cs index ccd1fb7af73c..f5aef412d6ca 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/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadInstallType.cs b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadInstallType.cs new file mode 100644 index 000000000000..b484e876c0ad --- /dev/null +++ b/src/Resolvers/Microsoft.NET.Sdk.WorkloadManifestReader/WorkloadInstallType.cs @@ -0,0 +1,66 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +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..87af4878ea91 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. + {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}] 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} @@ -134,7 +139,12 @@ 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. + 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 c211cab0a90d..7957ceca43c1 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. + {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}] 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}. @@ -134,7 +139,12 @@ 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. + 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 a81b23714dda..6d3b75908044 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. + {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}] 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} @@ -134,7 +139,12 @@ 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. + 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 975223208662..06f9d19d3e5c 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. + {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}] 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} @@ -134,7 +139,12 @@ 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. + 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 f8eebe66801c..29b7fc022bc2 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. + {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}] 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} @@ -134,7 +139,12 @@ 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. + 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 36c754938951..e0517c875cf2 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. + {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}] マニフェスト '{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}' があります @@ -134,7 +139,12 @@ 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. + 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 a23e50a04672..f312858ba612 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. + {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}] '{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}'이(가) 있습니다. @@ -134,7 +139,12 @@ 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. + 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 589b7cd190b1..df7e22373be6 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. + {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}] 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} @@ -134,7 +139,12 @@ 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. + 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 f7f493da1649..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 @@ -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. + {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}] 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} @@ -134,7 +139,12 @@ 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. + 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 6aca12538828..0fd5581ea359 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. + {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}] Не удалось найти рабочую нагрузку "{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} @@ -134,7 +139,12 @@ 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. + 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 1810ce450f2b..de15a7251f8b 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. + {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}] '{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 @@ -134,7 +139,12 @@ 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. + 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 9f9941769f32..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 @@ -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. + {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}] 无法找到由清单“{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}” @@ -134,7 +139,12 @@ 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. + 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 cad158599ad2..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 @@ -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. + {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}] 在資訊清單 '{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}' @@ -134,7 +139,12 @@ 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. + Workload version {0}, which was specified in {1}, was not found. diff --git a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/FakeManifestProvider.cs b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/FakeManifestProvider.cs index a07d8cae9afd..bd80153d4b50 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 7bf9545a0d7e..c62436992ae3 100644 --- a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs +++ b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/SdkDirectoryWorkloadManifestProviderTests.cs @@ -519,10 +519,397 @@ 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 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() { @@ -538,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 @@ -550,7 +937,7 @@ var sdkDirectoryWorkloadManifestProvider GetManifestContents(sdkDirectoryWorkloadManifestProvider) .Should() - .BeEquivalentTo("AndroidContent", "iOSContent"); + .BeEquivalentTo("Android: AndroidContent", "iOS: iOSContent"); } [Fact] @@ -568,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"); } @@ -601,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"); } @@ -638,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"); } @@ -655,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] @@ -822,6 +1209,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() { @@ -832,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)!); @@ -843,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 8434b59b2d47..fe6e150cb577 100644 --- a/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/WorkloadPackGroupTests.cs +++ b/src/Tests/Microsoft.NET.Sdk.WorkloadManifestReader.Tests/WorkloadPackGroupTests.cs @@ -27,7 +27,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 9f2cc5bbb393..6a3ef2e0197f 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)