diff --git a/src/Cli/dotnet/Commands/CliCommandStrings.resx b/src/Cli/dotnet/Commands/CliCommandStrings.resx index 6ca03e2f5fe6..95113e71d016 100644 --- a/src/Cli/dotnet/Commands/CliCommandStrings.resx +++ b/src/Cli/dotnet/Commands/CliCommandStrings.resx @@ -2047,6 +2047,33 @@ Your project targets multiple frameworks. Specify which framework to run using ' Install or manage tools that extend the .NET experience. + + Manage tools using Microsoft Desired State Configuration (DSC). + + + Get the current state of installed tools. + + + Set the desired state of tools by installing or updating them. + + + Test if the current state matches the desired state. + + + Export the current state of all installed tools. + + + Get the JSON schema for DSC tool state. + + + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + + + JSON input representing the desired or requested tool state. + + + JSON + Add an additional NuGet package source to use during installation. diff --git a/src/Cli/dotnet/Commands/Tool/Dsc/DscModels.cs b/src/Cli/dotnet/Commands/Tool/Dsc/DscModels.cs new file mode 100644 index 000000000000..22205ddaa99d --- /dev/null +++ b/src/Cli/dotnet/Commands/Tool/Dsc/DscModels.cs @@ -0,0 +1,97 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.Json.Serialization; +using NuGet.Versioning; + +namespace Microsoft.DotNet.Cli.Commands.Tool.Dsc; + +internal record DscToolsState +{ + [JsonPropertyName("tools")] + public List Tools { get; set; } = new List(); +} + +internal record DscToolState +{ + [JsonPropertyName("packageId")] + public string? PackageId { get; set; } + + [JsonPropertyName("version")] + public string? Version { get; set; } + + [JsonPropertyName("commands")] + public List? Commands { get; set; } + + [JsonPropertyName("scope")] + [JsonConverter(typeof(JsonStringEnumConverter))] + public DscToolScope? Scope { get; set; } + + [JsonPropertyName("toolPath")] + public string? ToolPath { get; set; } + + [JsonPropertyName("manifestPath")] + public string? ManifestPath { get; set; } + + [JsonPropertyName("_exist")] + public bool? Exist { get; set; } + + /// + /// Parses packageId and version from the PackageId property. + /// Supports format: "packageId" or "packageId@version" + /// + public (string PackageId, VersionRange? VersionRange) ParsePackageIdentity() + { + if (string.IsNullOrEmpty(PackageId)) + { + return (string.Empty, null); + } + + string[] parts = PackageId.Split('@'); + string packageId = parts[0]; + + if (parts.Length > 1 && !string.IsNullOrEmpty(parts[1])) + { + // packageId@version format + if (VersionRange.TryParse(parts[1], out var versionRange)) + { + return (packageId, versionRange); + } + } + else if (!string.IsNullOrEmpty(Version)) + { + // Use separate Version property if available + if (VersionRange.TryParse(Version, out var versionRange)) + { + return (packageId, versionRange); + } + } + + return (packageId, null); + } +} + +internal enum DscToolScope +{ + Global, + Local, + ToolPath +} + +internal record DscErrorMessage +{ + [JsonPropertyName("error")] + public string Error { get; set; } = string.Empty; +} + +internal record DscDebugMessage +{ + [JsonPropertyName("debug")] + public string Debug { get; set; } = string.Empty; +} + +internal record DscTraceMessage +{ + [JsonPropertyName("trace")] + public string Trace { get; set; } = string.Empty; +} diff --git a/src/Cli/dotnet/Commands/Tool/Dsc/DscWriter.cs b/src/Cli/dotnet/Commands/Tool/Dsc/DscWriter.cs new file mode 100644 index 000000000000..d381692988fe --- /dev/null +++ b/src/Cli/dotnet/Commands/Tool/Dsc/DscWriter.cs @@ -0,0 +1,219 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.Json; +using Microsoft.DotNet.Cli.ToolPackage; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.Extensions.EnvironmentAbstractions; + +namespace Microsoft.DotNet.Cli.Commands.Tool.Dsc; + +internal static class DscWriter +{ + /// + /// Writes an error message to stderr in DSC JSON format. + /// + public static void WriteError(string message) + { + var errorMessage = new DscErrorMessage { Error = message }; + string json = JsonSerializer.Serialize(errorMessage); + Reporter.Error.WriteLine(json); + } + + /// + /// Writes a debug message to stderr in DSC JSON format. + /// + public static void WriteDebug(string message) + { + var debugMessage = new DscDebugMessage { Debug = message }; + string json = JsonSerializer.Serialize(debugMessage); + Reporter.Error.WriteLine(json); + } + + /// + /// Writes a trace message to stderr in DSC JSON format. + /// + public static void WriteTrace(string message) + { + var traceMessage = new DscTraceMessage { Trace = message }; + string json = JsonSerializer.Serialize(traceMessage); + Reporter.Error.WriteLine(json); + } + + /// + /// Writes the result state to stdout in DSC JSON format. + /// + public static void WriteResult(DscToolsState state) + { + var options = new JsonSerializerOptions + { + DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull, + WriteIndented = false + }; + + string json = JsonSerializer.Serialize(state, options); + Reporter.Output.WriteLine(json); + } + + /// + /// Writes any object to stdout in JSON format. + /// + public static void WriteJson(object obj, bool writeIndented = false) + { + var options = new JsonSerializerOptions + { + WriteIndented = writeIndented + }; + + string json = JsonSerializer.Serialize(obj, options); + Reporter.Output.WriteLine(json); + } + + /// + /// Reads input from either stdin (if input is "-") or from a file. + /// + public static string ReadInput(string input) + { + if (input == "-") + { + return Console.In.ReadToEnd(); + } + else + { + return File.ReadAllText(input); + } + } + + /// + /// Reads and deserializes DSC tool state from input (file or stdin). + /// Returns null if input is not provided. + /// Exits with code 1 if deserialization fails. + /// + public static DscToolsState? ReadAndDeserializeInput(string? input) + { + if (string.IsNullOrEmpty(input)) + { + return null; + } + + try + { + string jsonInput = ReadInput(input); + var inputState = JsonSerializer.Deserialize(jsonInput); + return inputState; + } + catch (JsonException ex) + { + WriteError($"Failed to deserialize JSON: {ex.Message}"); + Environment.Exit(1); + return null; // Unreachable, but satisfies compiler + } + } + + /// + /// Queries the actual state of a tool from the package store. + /// + public static DscToolState QueryToolState(DscToolState requestedState) + { + // Parse packageId to handle packageId@version syntax + var (packageIdString, _) = requestedState.ParsePackageIdentity(); + + if (string.IsNullOrEmpty(packageIdString)) + { + packageIdString = requestedState.PackageId ?? string.Empty; + } + + // Determine the scope and tool path based on the requested tool + DirectoryPath? toolPath = null; + DscToolScope scope = requestedState.Scope ?? DscToolScope.Global; + + if (scope == DscToolScope.ToolPath && !string.IsNullOrWhiteSpace(requestedState.ToolPath)) + { + toolPath = new DirectoryPath(requestedState.ToolPath); + } + else if (scope == DscToolScope.Global) + { + // Global tools, use default location (null) + toolPath = null; + } + else if (scope == DscToolScope.Local) + { + // TODO: Local tools require querying dotnet-tools.json in current directory + // For now, return not found for local tools + WriteDebug($"Local tool scope not yet implemented for {packageIdString}"); + return new DscToolState + { + PackageId = packageIdString, + Version = null, + Commands = null, + Scope = DscToolScope.Local, + ToolPath = null, + ManifestPath = null, + Exist = false + }; + } + + // Query the tool package store + var packageStoreQuery = ToolPackageFactory.CreateToolPackageStoreQuery(toolPath); + var packageId = new PackageId(packageIdString); + + try + { + // Find the tool package + var installedPackages = packageStoreQuery.EnumeratePackages() + .Where(p => p.Id.Equals(packageId)) + .ToList(); + + if (installedPackages.Any()) + { + // Tool exists, get its details from the first (or only) matching package + var package = installedPackages.First(); + + WriteDebug($"Found tool {package.Id} version {package.Version.ToNormalizedString()}"); + + return new DscToolState + { + PackageId = package.Id.ToString(), + Version = package.Version.ToNormalizedString(), + Commands = package.Command != null ? new List { package.Command.Name.Value } : null, + Scope = scope, + ToolPath = scope == DscToolScope.ToolPath ? requestedState.ToolPath : null, + ManifestPath = null, + Exist = true + }; + } + else + { + // Tool not found + WriteDebug($"Tool {packageIdString} not found in {scope} scope"); + + return new DscToolState + { + PackageId = packageIdString, + Version = null, + Commands = null, + Scope = scope, + ToolPath = scope == DscToolScope.ToolPath ? requestedState.ToolPath : null, + ManifestPath = null, + Exist = false + }; + } + } + catch (Exception ex) + { + // If there's an error querying the tool, return it as not found + WriteError($"Error querying tool {packageIdString}: {ex.Message}"); + + return new DscToolState + { + PackageId = packageIdString, + Version = null, + Commands = null, + Scope = scope, + ToolPath = scope == DscToolScope.ToolPath ? requestedState.ToolPath : null, + ManifestPath = null, + Exist = false + }; + } + } +} diff --git a/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscCommandParser.cs new file mode 100644 index 000000000000..8cc5054004ad --- /dev/null +++ b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscCommandParser.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.CommandLine; +using Microsoft.DotNet.Cli.Extensions; + +namespace Microsoft.DotNet.Cli.Commands.Tool.Dsc; + +internal static class ToolDscCommandParser +{ + public static readonly string DocsLink = "https://aka.ms/dotnet-tool-dsc"; + + private static readonly Command Command = ConstructCommand(); + + public static Command GetCommand() + { + return Command; + } + + private static Command ConstructCommand() + { + DocumentedCommand command = new("dsc", DocsLink, CliCommandStrings.ToolDscCommandDescription); + + command.Subcommands.Add(ToolDscGetCommandParser.GetCommand()); + command.Subcommands.Add(ToolDscSetCommandParser.GetCommand()); + command.Subcommands.Add(ToolDscTestCommandParser.GetCommand()); + command.Subcommands.Add(ToolDscExportCommandParser.GetCommand()); + command.Subcommands.Add(ToolDscSchemaCommandParser.GetCommand()); + command.Subcommands.Add(ToolDscManifestCommandParser.GetCommand()); + + command.SetAction((parseResult) => parseResult.HandleMissingCommand()); + + return command; + } +} diff --git a/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscExportCommand.cs b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscExportCommand.cs new file mode 100644 index 000000000000..577b2bd13f20 --- /dev/null +++ b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscExportCommand.cs @@ -0,0 +1,95 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable disable + +using System.CommandLine; +using System.Text.Json; +using Microsoft.DotNet.Cli.ToolPackage; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.Extensions.EnvironmentAbstractions; + +namespace Microsoft.DotNet.Cli.Commands.Tool.Dsc; + +internal class ToolDscExportCommand : CommandBase +{ + public ToolDscExportCommand(ParseResult parseResult) + : base(parseResult) + { + } + + public override int Execute() + { + try + { + var state = new DscToolsState(); + + // Enumerate all global tools + DscWriter.WriteTrace("Enumerating global tools"); + var globalTools = EnumerateGlobalTools(); + foreach (var tool in globalTools) + { + state.Tools.Add(tool); + } + + DscWriter.WriteTrace($"Found {state.Tools.Count} global tools"); + + // TODO: Add support for local tools (requires scanning for dotnet-tools.json files) + // TODO: Add support for tool-path tools (requires configuration of tool paths to scan) + + DscWriter.WriteResult(state); + + return 0; + } + catch (Exception ex) + { + DscWriter.WriteError($"Unexpected error: {ex.Message}"); + return 1; + } + } + + private List EnumerateGlobalTools() + { + var tools = new List(); + + // Query the global tool package store (null = default global location) + var packageStoreQuery = ToolPackageFactory.CreateToolPackageStoreQuery(null); + + try + { + var packages = packageStoreQuery.EnumeratePackages(); + + foreach (var package in packages) + { + try + { + // Only include packages that have commands + if (package.Command != null) + { + tools.Add(new DscToolState + { + PackageId = package.Id.ToString(), + Version = package.Version.ToNormalizedString(), + Commands = new List { package.Command.Name.Value }, + Scope = DscToolScope.Global, + ToolPath = null, + ManifestPath = null, + Exist = true + }); + } + } + catch (Exception ex) + { + // If we can't read a specific package, log a warning and continue + DscWriter.WriteError($"Warning: Could not read tool {package.Id}: {ex.Message}"); + } + } + } + catch (Exception ex) + { + DscWriter.WriteError($"Error enumerating global tools: {ex.Message}"); + } + + return tools; + } +} diff --git a/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscExportCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscExportCommandParser.cs new file mode 100644 index 000000000000..03a3b0d27016 --- /dev/null +++ b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscExportCommandParser.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.CommandLine; + +namespace Microsoft.DotNet.Cli.Commands.Tool.Dsc; + +internal static class ToolDscExportCommandParser +{ + private static readonly Command Command = ConstructCommand(); + + public static Command GetCommand() + { + return Command; + } + + private static Command ConstructCommand() + { + Command command = new("export", CliCommandStrings.ToolDscExportCommandDescription); + + command.SetAction((parseResult) => new ToolDscExportCommand(parseResult).Execute()); + + return command; + } +} diff --git a/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscGetCommand.cs b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscGetCommand.cs new file mode 100644 index 000000000000..13cb49986589 --- /dev/null +++ b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscGetCommand.cs @@ -0,0 +1,48 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable disable + +using System.CommandLine; +using System.Text.Json; +using Microsoft.DotNet.Cli.Utils; + +namespace Microsoft.DotNet.Cli.Commands.Tool.Dsc; + +internal class ToolDscGetCommand : CommandBase +{ + private readonly string _input; + + public ToolDscGetCommand(ParseResult parseResult) + : base(parseResult) + { + _input = parseResult.GetValue(ToolDscGetCommandParser.InputOption); + } + + public override int Execute() + { + try + { + var inputState = DscWriter.ReadAndDeserializeInput(_input); + var resultState = new DscToolsState(); + + foreach (var tool in inputState?.Tools ?? Enumerable.Empty()) + { + var actualState = DscWriter.QueryToolState(tool); + if (actualState != null) + { + resultState.Tools.Add(actualState); + } + } + + DscWriter.WriteResult(resultState); + + return 0; + } + catch (Exception ex) + { + DscWriter.WriteError($"Unexpected error: {ex.Message}"); + return 1; + } + } +} diff --git a/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscGetCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscGetCommandParser.cs new file mode 100644 index 000000000000..88dd47a3e7fe --- /dev/null +++ b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscGetCommandParser.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.CommandLine; +using Microsoft.DotNet.Cli.Extensions; + +namespace Microsoft.DotNet.Cli.Commands.Tool.Dsc; + +internal static class ToolDscGetCommandParser +{ + public static readonly Option InputOption = new("--input", "-i") + { + Description = CliCommandStrings.ToolDscInputOptionDescription, + HelpName = CliCommandStrings.ToolDscInputOptionName + }; + + private static readonly Command Command = ConstructCommand(); + + public static Command GetCommand() + { + return Command; + } + + private static Command ConstructCommand() + { + Command command = new("get", CliCommandStrings.ToolDscGetCommandDescription); + command.Options.Add(InputOption); + + command.SetAction((parseResult) => new ToolDscGetCommand(parseResult).Execute()); + + return command; + } +} diff --git a/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscManifestCommand.cs b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscManifestCommand.cs new file mode 100644 index 000000000000..5df59cbfd0ab --- /dev/null +++ b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscManifestCommand.cs @@ -0,0 +1,103 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.CommandLine; +using System.Text.Json; +using Microsoft.DotNet.Cli.Utils; + +namespace Microsoft.DotNet.Cli.Commands.Tool.Dsc; + +internal class ToolDscManifestCommand : CommandBase +{ + public ToolDscManifestCommand(ParseResult parseResult) + : base(parseResult) + { + } + + public override int Execute() + { + try + { + var manifest = new Dictionary + { + ["$schema"] = "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json", + ["type"] = "Microsoft.DotNet.Sdk/Tool", + ["description"] = "Manage .NET tools using Microsoft Desired State Configuration (DSC).", + ["version"] = "1.0.0", + ["tags"] = new[] { "dotnet", "tool", "sdk" }, + ["exitCodes"] = new Dictionary + { + ["0"] = "Success", + ["1"] = "Error" + }, + ["schema"] = new Dictionary + { + ["command"] = new Dictionary + { + ["executable"] = "dotnet", + ["args"] = new object[] { "tool", "dsc", "schema" } + } + }, + ["get"] = new Dictionary + { + ["executable"] = "dotnet", + ["args"] = new object[] + { + "tool", + "dsc", + "get", + new Dictionary + { + ["jsonInputArg"] = "--input", + ["mandatory"] = true + } + } + }, + ["set"] = new Dictionary + { + ["executable"] = "dotnet", + ["args"] = new object[] + { + "tool", + "dsc", + "set", + new Dictionary + { + ["jsonInputArg"] = "--input", + ["mandatory"] = true + } + } + }, + ["test"] = new Dictionary + { + ["executable"] = "dotnet", + ["args"] = new object[] + { + "tool", + "dsc", + "test", + new Dictionary + { + ["jsonInputArg"] = "--input", + ["mandatory"] = true + } + } + }, + ["export"] = new Dictionary + { + ["executable"] = "dotnet", + ["args"] = new object[] { "tool", "dsc", "export" } + } + }; + + DscWriter.WriteJson(manifest); + + return 0; + } + catch (Exception ex) + { + DscWriter.WriteError($"Error generating manifest: {ex.Message}"); + return 1; + } + } +} diff --git a/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscManifestCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscManifestCommandParser.cs new file mode 100644 index 000000000000..f597dfe9a3f3 --- /dev/null +++ b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscManifestCommandParser.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.CommandLine; + +namespace Microsoft.DotNet.Cli.Commands.Tool.Dsc; + +internal static class ToolDscManifestCommandParser +{ + private static readonly Command Command = ConstructCommand(); + + public static Command GetCommand() + { + return Command; + } + + private static Command ConstructCommand() + { + Command command = new("manifest", CliCommandStrings.ToolDscManifestCommandDescription); + + command.SetAction((parseResult) => new ToolDscManifestCommand(parseResult).Execute()); + + return command; + } +} diff --git a/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscSchemaCommand.cs b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscSchemaCommand.cs new file mode 100644 index 000000000000..6de2f631e07d --- /dev/null +++ b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscSchemaCommand.cs @@ -0,0 +1,108 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable disable + +using System.CommandLine; +using System.Reflection; +using System.Text.Json; +using System.Text.Json.Serialization; +using Microsoft.DotNet.Cli.Utils; + +namespace Microsoft.DotNet.Cli.Commands.Tool.Dsc; + +internal class ToolDscSchemaCommand : CommandBase +{ + public ToolDscSchemaCommand(ParseResult parseResult) + : base(parseResult) + { + } + + public override int Execute() + { + try + { + // Generate schema dynamically from DscToolState model + var toolProperties = new Dictionary(); + var requiredProperties = new List(); + + foreach (var prop in typeof(DscToolState).GetProperties()) + { + var jsonPropertyAttr = prop.GetCustomAttribute(); + if (jsonPropertyAttr == null) continue; + + string propertyName = jsonPropertyAttr.Name; + var propertySchema = GetPropertySchema(prop); + + toolProperties[propertyName] = propertySchema; + + // packageId is required + if (propertyName == "packageId") + { + requiredProperties.Add(propertyName); + } + } + + var schema = new + { + type = "object", + properties = new + { + tools = new + { + type = "array", + items = new + { + type = "object", + properties = toolProperties, + required = requiredProperties.ToArray() + } + } + } + }; + + DscWriter.WriteJson(schema, writeIndented: true); + + return 0; + } + catch (Exception ex) + { + DscWriter.WriteError($"Unexpected error: {ex.Message}"); + return 1; + } + } + + private static object GetPropertySchema(PropertyInfo prop) + { + var underlyingType = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType; + + // Check for enum + if (underlyingType.IsEnum) + { + var enumValues = Enum.GetNames(underlyingType); + return new { type = "string", @enum = enumValues }; + } + + // Check for List + if (underlyingType.IsGenericType && underlyingType.GetGenericTypeDefinition() == typeof(List<>)) + { + var itemType = underlyingType.GetGenericArguments()[0]; + if (itemType == typeof(string)) + { + return new { type = "array", items = new { type = "string" } }; + } + } + + // Map CLR types to JSON schema types + if (underlyingType == typeof(string)) + return new { type = "string" }; + if (underlyingType == typeof(bool)) + return new { type = "boolean" }; + if (underlyingType == typeof(int) || underlyingType == typeof(long)) + return new { type = "integer" }; + if (underlyingType == typeof(double) || underlyingType == typeof(float)) + return new { type = "number" }; + + return new { type = "string" }; + } +} diff --git a/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscSchemaCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscSchemaCommandParser.cs new file mode 100644 index 000000000000..3743cb502f23 --- /dev/null +++ b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscSchemaCommandParser.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.CommandLine; + +namespace Microsoft.DotNet.Cli.Commands.Tool.Dsc; + +internal static class ToolDscSchemaCommandParser +{ + private static readonly Command Command = ConstructCommand(); + + public static Command GetCommand() + { + return Command; + } + + private static Command ConstructCommand() + { + Command command = new("schema", CliCommandStrings.ToolDscSchemaCommandDescription); + + command.SetAction((parseResult) => new ToolDscSchemaCommand(parseResult).Execute()); + + return command; + } +} diff --git a/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscSetCommand.cs b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscSetCommand.cs new file mode 100644 index 000000000000..31848e5b3fb1 --- /dev/null +++ b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscSetCommand.cs @@ -0,0 +1,118 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable disable + +using System.CommandLine; +using System.Text.Json; +using Microsoft.DotNet.Cli.Commands.Tool.Install; +using Microsoft.DotNet.Cli.ToolPackage; +using Microsoft.DotNet.Cli.Utils; +using Microsoft.Extensions.EnvironmentAbstractions; +using NuGet.Versioning; + +namespace Microsoft.DotNet.Cli.Commands.Tool.Dsc; + +internal class ToolDscSetCommand : CommandBase +{ + private readonly string _input; + + public ToolDscSetCommand(ParseResult parseResult) + : base(parseResult) + { + _input = parseResult.GetValue(ToolDscSetCommandParser.InputOption); + } + + public override int Execute() + { + try + { + var inputState = DscWriter.ReadAndDeserializeInput(_input); + var resultState = new DscToolsState(); + bool hasFailures = false; + + foreach (var tool in inputState?.Tools ?? Enumerable.Empty()) + { + // Skip tools that should not exist (Exist == false) + if (tool.Exist == false) + { + DscWriter.WriteDebug($"Skipping tool {tool.PackageId}: _exist is false (tool removal not supported)"); + continue; + } + + // Only support Global scope for now + var scope = tool.Scope ?? DscToolScope.Global; + if (scope != DscToolScope.Global) + { + DscWriter.WriteDebug($"Skipping tool {tool.PackageId}: only Global scope is currently supported"); + continue; + } + + DscWriter.WriteDebug($"Setting desired state for tool: {tool.PackageId}"); + + // Parse packageId and version + var (packageId, versionRange) = tool.ParsePackageIdentity(); + + if (string.IsNullOrEmpty(packageId)) + { + DscWriter.WriteError($"Invalid packageId: {tool.PackageId}"); + continue; + } + + // Install or update the tool + try + { + string installArgs = $"tool install -g {packageId}"; + if (versionRange != null) + { + installArgs += $" --version \"{versionRange.OriginalString}\""; + } + + var installParseResult = Parser.Parse($"dotnet {installArgs}"); + + var installCommand = new ToolInstallGlobalOrToolPathCommand( + installParseResult, + packageId: new PackageId(packageId), + createToolPackageStoreDownloaderUninstaller: null, + createShellShimRepository: null, + environmentPathInstruction: null, + reporter: null); + + int exitCode = installCommand.Execute(); + + if (exitCode != 0) + { + DscWriter.WriteError($"Failed to install/update tool {packageId}"); + hasFailures = true; + continue; + } + + DscWriter.WriteDebug($"Tool {packageId} is at desired state"); + } + catch (Exception ex) + { + DscWriter.WriteError($"Error installing/updating tool {packageId}: {ex.Message}"); + hasFailures = true; + continue; + } + + // Query final state after installation + var finalState = DscWriter.QueryToolState(new DscToolState + { + PackageId = packageId, + Scope = scope + }); + + resultState.Tools.Add(finalState); + } + + DscWriter.WriteResult(resultState); + return hasFailures ? 1 : 0; + } + catch (Exception ex) + { + DscWriter.WriteError($"Unexpected error: {ex.Message}"); + return 1; + } + } +} diff --git a/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscSetCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscSetCommandParser.cs new file mode 100644 index 000000000000..6ae4331d9444 --- /dev/null +++ b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscSetCommandParser.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.CommandLine; +using Microsoft.DotNet.Cli.Extensions; + +namespace Microsoft.DotNet.Cli.Commands.Tool.Dsc; + +internal static class ToolDscSetCommandParser +{ + public static readonly Option InputOption = new("--input", "-i") + { + Description = CliCommandStrings.ToolDscInputOptionDescription, + HelpName = CliCommandStrings.ToolDscInputOptionName + }; + + private static readonly Command Command = ConstructCommand(); + + public static Command GetCommand() + { + return Command; + } + + private static Command ConstructCommand() + { + Command command = new("set", CliCommandStrings.ToolDscSetCommandDescription); + command.Options.Add(InputOption); + + command.SetAction((parseResult) => new ToolDscSetCommand(parseResult).Execute()); + + return command; + } +} diff --git a/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscTestCommand.cs b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscTestCommand.cs new file mode 100644 index 000000000000..741fa5378dee --- /dev/null +++ b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscTestCommand.cs @@ -0,0 +1,172 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable disable + +using System.CommandLine; +using System.Text.Json; +using Microsoft.DotNet.Cli.Utils; +using NuGet.Versioning; + +namespace Microsoft.DotNet.Cli.Commands.Tool.Dsc; + +internal class ToolDscTestCommand : CommandBase +{ + private readonly string _input; + + public ToolDscTestCommand(ParseResult parseResult) + : base(parseResult) + { + _input = parseResult.GetValue(ToolDscTestCommandParser.InputOption); + } + + public override int Execute() + { + try + { + var inputState = DscWriter.ReadAndDeserializeInput(_input); + var resultState = new DscToolsState(); + bool allMatch = true; + + foreach (var tool in inputState?.Tools ?? Enumerable.Empty()) + { + var actualState = DscWriter.QueryToolState(tool); + bool matches = CompareToolStates(tool, actualState); + + actualState.Exist = matches; + + if (!matches) + { + allMatch = false; + } + + resultState.Tools.Add(actualState); + } + + DscWriter.WriteResult(resultState); + + // Return exit code 0 if all tools match desired state, 1 if any don't match + return allMatch ? 0 : 1; + } + catch (Exception ex) + { + DscWriter.WriteError($"Unexpected error: {ex.Message}"); + return 1; + } + } + + /// + /// Compares desired state with actual state to determine if they match. + /// + private bool CompareToolStates(DscToolState desired, DscToolState actual) + { + // Parse packageId to handle packageId@version syntax + var (packageId, versionRange) = desired.ParsePackageIdentity(); + + // Check _exist property first + bool desiredExist = desired.Exist ?? true; // Default to true if not specified + bool actualExist = actual.Exist ?? false; + + if (desiredExist != actualExist) + { + DscWriter.WriteDebug($"Tool {packageId}: Exist mismatch (desired: {desiredExist}, actual: {actualExist})"); + return false; + } + + // If tool should not exist and doesn't exist, that's a match + if (!desiredExist && !actualExist) + { + DscWriter.WriteDebug($"Tool {packageId}: Correctly does not exist"); + return true; + } + + // If tool should exist but doesn't, already caught above + // Now check version if specified + if (versionRange != null) + { + // packageId@version syntax or Version property specified + if (string.IsNullOrEmpty(actual.Version)) + { + DscWriter.WriteDebug($"Tool {packageId}: Version mismatch (desired: {versionRange.OriginalString}, actual: none)"); + return false; + } + + // Check if actual version satisfies the version range + if (NuGetVersion.TryParse(actual.Version, out var actualVersion)) + { + if (!versionRange.Satisfies(actualVersion)) + { + DscWriter.WriteDebug($"Tool {packageId}: Version mismatch (desired: {versionRange.OriginalString}, actual: {actual.Version})"); + return false; + } + } + else + { + DscWriter.WriteDebug($"Tool {packageId}: Failed to parse actual version {actual.Version}"); + return false; + } + } + else if (!string.IsNullOrEmpty(desired.Version)) + { + // Fallback to string comparison for Version property (shouldn't happen if ParsePackageIdentity works) + if (string.IsNullOrEmpty(actual.Version)) + { + DscWriter.WriteDebug($"Tool {packageId}: Version mismatch (desired: {desired.Version}, actual: none)"); + return false; + } + + if (NuGetVersion.TryParse(desired.Version, out var desiredVersion) && + NuGetVersion.TryParse(actual.Version, out var actualVersion)) + { + if (!desiredVersion.Equals(actualVersion)) + { + DscWriter.WriteDebug($"Tool {packageId}: Version mismatch (desired: {desired.Version}, actual: {actual.Version})"); + return false; + } + } + else if (!string.Equals(desired.Version, actual.Version, StringComparison.OrdinalIgnoreCase)) + { + DscWriter.WriteDebug($"Tool {packageId}: Version mismatch (desired: {desired.Version}, actual: {actual.Version})"); + return false; + } + } + + // Check commands if specified + if (desired.Commands != null && desired.Commands.Any()) + { + if (actual.Commands == null || !actual.Commands.Any()) + { + DscWriter.WriteDebug($"Tool {desired.PackageId}: Commands mismatch (desired commands specified, actual: none)"); + return false; + } + + // Check if all desired commands are present in actual + var missingCommands = desired.Commands.Except(actual.Commands, StringComparer.OrdinalIgnoreCase).ToList(); + if (missingCommands.Any()) + { + DscWriter.WriteDebug($"Tool {desired.PackageId}: Missing commands: {string.Join(", ", missingCommands)}"); + return false; + } + } + + // Check scope if specified + if (desired.Scope.HasValue && actual.Scope.HasValue) + { + if (desired.Scope.Value != actual.Scope.Value) + { + DscWriter.WriteDebug($"Tool {desired.PackageId}: Scope mismatch (desired: {desired.Scope.Value}, actual: {actual.Scope.Value})"); + return false; + } + } + + if (!string.IsNullOrEmpty(desired.ToolPath) && !string.IsNullOrEmpty(actual.ToolPath)) + { + if (!string.Equals(desired.ToolPath, actual.ToolPath, StringComparison.OrdinalIgnoreCase)) + { + DscWriter.WriteDebug($"Tool {desired.PackageId}: ToolPath mismatch (desired: {desired.ToolPath}, actual: {actual.ToolPath})"); + return false; + } + } + return true; + } +} diff --git a/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscTestCommandParser.cs b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscTestCommandParser.cs new file mode 100644 index 000000000000..572e73b4abc2 --- /dev/null +++ b/src/Cli/dotnet/Commands/Tool/Dsc/ToolDscTestCommandParser.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.CommandLine; +using Microsoft.DotNet.Cli.Extensions; + +namespace Microsoft.DotNet.Cli.Commands.Tool.Dsc; + +internal static class ToolDscTestCommandParser +{ + public static readonly Option InputOption = new("--input", "-i") + { + Description = CliCommandStrings.ToolDscInputOptionDescription, + HelpName = CliCommandStrings.ToolDscInputOptionName + }; + + private static readonly Command Command = ConstructCommand(); + + public static Command GetCommand() + { + return Command; + } + + private static Command ConstructCommand() + { + Command command = new("test", CliCommandStrings.ToolDscTestCommandDescription); + command.Options.Add(InputOption); + + command.SetAction((parseResult) => new ToolDscTestCommand(parseResult).Execute()); + + return command; + } +} diff --git a/src/Cli/dotnet/Commands/Tool/ToolCommandParser.cs b/src/Cli/dotnet/Commands/Tool/ToolCommandParser.cs index 0392bde15d3f..b0e93ef1a58d 100644 --- a/src/Cli/dotnet/Commands/Tool/ToolCommandParser.cs +++ b/src/Cli/dotnet/Commands/Tool/ToolCommandParser.cs @@ -4,6 +4,7 @@ #nullable disable using System.CommandLine; +using Microsoft.DotNet.Cli.Commands.Tool.Dsc; using Microsoft.DotNet.Cli.Commands.Tool.Execute; using Microsoft.DotNet.Cli.Commands.Tool.Install; using Microsoft.DotNet.Cli.Commands.Tool.List; @@ -39,6 +40,7 @@ private static Command ConstructCommand() command.Subcommands.Add(ToolSearchCommandParser.GetCommand()); command.Subcommands.Add(ToolRestoreCommandParser.GetCommand()); command.Subcommands.Add(ToolExecuteCommandParser.GetCommand()); + command.Subcommands.Add(ToolDscCommandParser.GetCommand()); command.SetAction((parseResult) => parseResult.HandleMissingCommand()); diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf index d1d8709624e6..ef306e017851 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.cs.xlf @@ -3218,6 +3218,51 @@ Chcete pokračovat? Stažení balíčku nástroje vyžaduje potvrzení. Spusťte v interaktivním režimu nebo potvrďte akci pomocí možnosti příkazového řádku --yes. {Locked="--yes"} + + Manage tools using Microsoft Desired State Configuration (DSC). + Manage tools using Microsoft Desired State Configuration (DSC). + + + + Export the current state of all installed tools. + Export the current state of all installed tools. + + + + Get the current state of installed tools. + Get the current state of installed tools. + + + + JSON input representing the desired or requested tool state. + JSON input representing the desired or requested tool state. + + + + JSON + JSON + + + + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + + + + Get the JSON schema for DSC tool state. + Get the JSON schema for DSC tool state. + + + + Set the desired state of tools by installing or updating them. + Set the desired state of tools by installing or updating them. + + + + Test if the current state matches the desired state. + Test if the current state matches the desired state. + + Executes a tool from source without permanently installing it. Spustí nástroj ze zdroje bez trvalé instalace. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf index 2a39befb9d3c..c24bfaf3c3f9 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.de.xlf @@ -3218,6 +3218,51 @@ Vorgang fortsetzen? Der Download des Toolpakets muss bestätigt werden. Führen Sie den Vorgang im interaktiven Modus aus oder verwenden Sie zur Bestätigung die Befehlszeilenoption "--yes". {Locked="--yes"} + + Manage tools using Microsoft Desired State Configuration (DSC). + Manage tools using Microsoft Desired State Configuration (DSC). + + + + Export the current state of all installed tools. + Export the current state of all installed tools. + + + + Get the current state of installed tools. + Get the current state of installed tools. + + + + JSON input representing the desired or requested tool state. + JSON input representing the desired or requested tool state. + + + + JSON + JSON + + + + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + + + + Get the JSON schema for DSC tool state. + Get the JSON schema for DSC tool state. + + + + Set the desired state of tools by installing or updating them. + Set the desired state of tools by installing or updating them. + + + + Test if the current state matches the desired state. + Test if the current state matches the desired state. + + Executes a tool from source without permanently installing it. Führt ein Tool aus der Quelle aus, ohne es dauerhaft zu installieren. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf index 84f4aabb9069..353f5071c26c 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.es.xlf @@ -3218,6 +3218,51 @@ Proceed? La descarga del paquete de herramientas necesita confirmación. Ejecute en modo interactivo o use la opción de línea de comandos "--yes" para confirmar. {Locked="--yes"} + + Manage tools using Microsoft Desired State Configuration (DSC). + Manage tools using Microsoft Desired State Configuration (DSC). + + + + Export the current state of all installed tools. + Export the current state of all installed tools. + + + + Get the current state of installed tools. + Get the current state of installed tools. + + + + JSON input representing the desired or requested tool state. + JSON input representing the desired or requested tool state. + + + + JSON + JSON + + + + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + + + + Get the JSON schema for DSC tool state. + Get the JSON schema for DSC tool state. + + + + Set the desired state of tools by installing or updating them. + Set the desired state of tools by installing or updating them. + + + + Test if the current state matches the desired state. + Test if the current state matches the desired state. + + Executes a tool from source without permanently installing it. Ejecuta una herramienta desde el origen sin instalarla permanentemente. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf index 6a637323a60e..3935070ab2a8 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.fr.xlf @@ -3218,6 +3218,51 @@ Voulez-vous continuer ? Le téléchargement du package d’outils doit être confirmé. Exécutez en mode interactif ou utilisez l’option de ligne de commande « --yes » pour confirmer. {Locked="--yes"} + + Manage tools using Microsoft Desired State Configuration (DSC). + Manage tools using Microsoft Desired State Configuration (DSC). + + + + Export the current state of all installed tools. + Export the current state of all installed tools. + + + + Get the current state of installed tools. + Get the current state of installed tools. + + + + JSON input representing the desired or requested tool state. + JSON input representing the desired or requested tool state. + + + + JSON + JSON + + + + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + + + + Get the JSON schema for DSC tool state. + Get the JSON schema for DSC tool state. + + + + Set the desired state of tools by installing or updating them. + Set the desired state of tools by installing or updating them. + + + + Test if the current state matches the desired state. + Test if the current state matches the desired state. + + Executes a tool from source without permanently installing it. Exécute un outil à partir de la source sans l’installer définitivement. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf index 1f255f43c794..050cc5eb7117 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.it.xlf @@ -3218,6 +3218,51 @@ Procedere? Il download del pacchetto dello strumento richiede conferma. Esegui in modalità interattiva o usa l'opzione della riga di comando "--yes" per confermare. {Locked="--yes"} + + Manage tools using Microsoft Desired State Configuration (DSC). + Manage tools using Microsoft Desired State Configuration (DSC). + + + + Export the current state of all installed tools. + Export the current state of all installed tools. + + + + Get the current state of installed tools. + Get the current state of installed tools. + + + + JSON input representing the desired or requested tool state. + JSON input representing the desired or requested tool state. + + + + JSON + JSON + + + + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + + + + Get the JSON schema for DSC tool state. + Get the JSON schema for DSC tool state. + + + + Set the desired state of tools by installing or updating them. + Set the desired state of tools by installing or updating them. + + + + Test if the current state matches the desired state. + Test if the current state matches the desired state. + + Executes a tool from source without permanently installing it. Esegue uno strumento dall'origine senza installarlo permanentemente. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf index 7aa8108b6954..1a4b8d6972e8 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ja.xlf @@ -3218,6 +3218,51 @@ Proceed? ツール パッケージのダウンロードには確認が必要です。対話モードで実行するか、"--yes" コマンド ライン オプションを使用して確認してください。 {Locked="--yes"} + + Manage tools using Microsoft Desired State Configuration (DSC). + Manage tools using Microsoft Desired State Configuration (DSC). + + + + Export the current state of all installed tools. + Export the current state of all installed tools. + + + + Get the current state of installed tools. + Get the current state of installed tools. + + + + JSON input representing the desired or requested tool state. + JSON input representing the desired or requested tool state. + + + + JSON + JSON + + + + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + + + + Get the JSON schema for DSC tool state. + Get the JSON schema for DSC tool state. + + + + Set the desired state of tools by installing or updating them. + Set the desired state of tools by installing or updating them. + + + + Test if the current state matches the desired state. + Test if the current state matches the desired state. + + Executes a tool from source without permanently installing it. ツールを永続的にインストールすることなく、ソースから実行します。 diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf index 6544ed0d7051..98c3a6edc685 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ko.xlf @@ -3218,6 +3218,51 @@ Proceed? 도구 패키지 다운로드를 확인해야 합니다. 대화형 모드에서 실행하거나 "--yes" 명령줄 옵션을 사용하여 확인하세요. {Locked="--yes"} + + Manage tools using Microsoft Desired State Configuration (DSC). + Manage tools using Microsoft Desired State Configuration (DSC). + + + + Export the current state of all installed tools. + Export the current state of all installed tools. + + + + Get the current state of installed tools. + Get the current state of installed tools. + + + + JSON input representing the desired or requested tool state. + JSON input representing the desired or requested tool state. + + + + JSON + JSON + + + + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + + + + Get the JSON schema for DSC tool state. + Get the JSON schema for DSC tool state. + + + + Set the desired state of tools by installing or updating them. + Set the desired state of tools by installing or updating them. + + + + Test if the current state matches the desired state. + Test if the current state matches the desired state. + + Executes a tool from source without permanently installing it. 영구적으로 설치하지 않고 원본에서 도구를 실행합니다. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf index 6e7de9021244..8aace083331a 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pl.xlf @@ -3218,6 +3218,51 @@ Kontynuować? Pobieranie pakietu narzędzi wymaga potwierdzenia. Uruchom w trybie interakcyjnym lub użyj opcji wiersza polecenia „--yes”, aby potwierdzić. {Locked="--yes"} + + Manage tools using Microsoft Desired State Configuration (DSC). + Manage tools using Microsoft Desired State Configuration (DSC). + + + + Export the current state of all installed tools. + Export the current state of all installed tools. + + + + Get the current state of installed tools. + Get the current state of installed tools. + + + + JSON input representing the desired or requested tool state. + JSON input representing the desired or requested tool state. + + + + JSON + JSON + + + + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + + + + Get the JSON schema for DSC tool state. + Get the JSON schema for DSC tool state. + + + + Set the desired state of tools by installing or updating them. + Set the desired state of tools by installing or updating them. + + + + Test if the current state matches the desired state. + Test if the current state matches the desired state. + + Executes a tool from source without permanently installing it. Wykonuje narzędzie ze źródła bez trwałego instalowania go. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf index 032d2caf149f..8813374a1da0 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.pt-BR.xlf @@ -3218,6 +3218,51 @@ Continuar? O download do pacote de ferramentas precisa de confirmação. Execute no modo interativo ou use a opção de linha de comando "--yes" para confirmar. {Locked="--yes"} + + Manage tools using Microsoft Desired State Configuration (DSC). + Manage tools using Microsoft Desired State Configuration (DSC). + + + + Export the current state of all installed tools. + Export the current state of all installed tools. + + + + Get the current state of installed tools. + Get the current state of installed tools. + + + + JSON input representing the desired or requested tool state. + JSON input representing the desired or requested tool state. + + + + JSON + JSON + + + + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + + + + Get the JSON schema for DSC tool state. + Get the JSON schema for DSC tool state. + + + + Set the desired state of tools by installing or updating them. + Set the desired state of tools by installing or updating them. + + + + Test if the current state matches the desired state. + Test if the current state matches the desired state. + + Executes a tool from source without permanently installing it. Executa uma ferramenta da origem sem instalá-la permanentemente. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf index 05edfdd693ef..1d0d54365e3e 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.ru.xlf @@ -3218,6 +3218,51 @@ Proceed? Для скачивания пакета инструмента требуется подтверждение. Запустите в интерактивном режиме или используйте параметр командной строки "--yes" для подтверждения. {Locked="--yes"} + + Manage tools using Microsoft Desired State Configuration (DSC). + Manage tools using Microsoft Desired State Configuration (DSC). + + + + Export the current state of all installed tools. + Export the current state of all installed tools. + + + + Get the current state of installed tools. + Get the current state of installed tools. + + + + JSON input representing the desired or requested tool state. + JSON input representing the desired or requested tool state. + + + + JSON + JSON + + + + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + + + + Get the JSON schema for DSC tool state. + Get the JSON schema for DSC tool state. + + + + Set the desired state of tools by installing or updating them. + Set the desired state of tools by installing or updating them. + + + + Test if the current state matches the desired state. + Test if the current state matches the desired state. + + Executes a tool from source without permanently installing it. Выполняет инструмент из источника без его постоянной установки. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf index 228d3a11bd02..a0c8dac403a0 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.tr.xlf @@ -3218,6 +3218,51 @@ Devam edilsin mi? Araç paketinin indirilmesi için onay gerekiyor. Etkileşimli modda çalıştırın veya onaylamak için "--yes" komut satırı seçeneğini kullanın. {Locked="--yes"} + + Manage tools using Microsoft Desired State Configuration (DSC). + Manage tools using Microsoft Desired State Configuration (DSC). + + + + Export the current state of all installed tools. + Export the current state of all installed tools. + + + + Get the current state of installed tools. + Get the current state of installed tools. + + + + JSON input representing the desired or requested tool state. + JSON input representing the desired or requested tool state. + + + + JSON + JSON + + + + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + + + + Get the JSON schema for DSC tool state. + Get the JSON schema for DSC tool state. + + + + Set the desired state of tools by installing or updating them. + Set the desired state of tools by installing or updating them. + + + + Test if the current state matches the desired state. + Test if the current state matches the desired state. + + Executes a tool from source without permanently installing it. Aracı kalıcı olarak yüklemeden kaynaktan yürütür. diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf index 8dce87da752d..5215b467d3ea 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hans.xlf @@ -3218,6 +3218,51 @@ Proceed? 工具包下载需要确认。在交互模式下运行,或使用 “--yes” 命令行选项进行确认。 {Locked="--yes"} + + Manage tools using Microsoft Desired State Configuration (DSC). + Manage tools using Microsoft Desired State Configuration (DSC). + + + + Export the current state of all installed tools. + Export the current state of all installed tools. + + + + Get the current state of installed tools. + Get the current state of installed tools. + + + + JSON input representing the desired or requested tool state. + JSON input representing the desired or requested tool state. + + + + JSON + JSON + + + + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + + + + Get the JSON schema for DSC tool state. + Get the JSON schema for DSC tool state. + + + + Set the desired state of tools by installing or updating them. + Set the desired state of tools by installing or updating them. + + + + Test if the current state matches the desired state. + Test if the current state matches the desired state. + + Executes a tool from source without permanently installing it. 从源执行工具,而无需永久安装它。 diff --git a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf index 4402fa7bc229..d0cb397abbb9 100644 --- a/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf +++ b/src/Cli/dotnet/Commands/xlf/CliCommandStrings.zh-Hant.xlf @@ -3218,6 +3218,51 @@ Proceed? 工具套件下載需要確認。請以互動模式執行,或使用 "--yes" 命令列選項來確認。 {Locked="--yes"} + + Manage tools using Microsoft Desired State Configuration (DSC). + Manage tools using Microsoft Desired State Configuration (DSC). + + + + Export the current state of all installed tools. + Export the current state of all installed tools. + + + + Get the current state of installed tools. + Get the current state of installed tools. + + + + JSON input representing the desired or requested tool state. + JSON input representing the desired or requested tool state. + + + + JSON + JSON + + + + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + Get the Microsoft Desired State Configuration (DSC) resource manifest for dotnet tool. + + + + Get the JSON schema for DSC tool state. + Get the JSON schema for DSC tool state. + + + + Set the desired state of tools by installing or updating them. + Set the desired state of tools by installing or updating them. + + + + Test if the current state matches the desired state. + Test if the current state matches the desired state. + + Executes a tool from source without permanently installing it. 從來源執行工具,但不永久性地安裝。 diff --git a/src/Cli/dotnet/dotnet.csproj b/src/Cli/dotnet/dotnet.csproj index 2e63f9a3c5a8..9a45aeb11d75 100644 --- a/src/Cli/dotnet/dotnet.csproj +++ b/src/Cli/dotnet/dotnet.csproj @@ -107,4 +107,17 @@ OverwriteReadOnlyFiles="true" /> + + + + $(TargetName).dsc.resource.json + $(RepoRoot).dotnet\dotnet$([System.IO.Path]::GetExtension('$(DotnetToolCommand)')) + + + + + + +