From e4e2c757f0c286c41ad4393b9a547e1ed717f0bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miha=20Marki=C4=8D?= Date: Wed, 7 Feb 2024 20:04:53 +0100 Subject: [PATCH] Removes parser --- .../KubectlParser.Test.csproj | 23 -- .../KubectlParser.Test/ProgramTest.cs | 112 ------- src/KubectlParser/KubectlParser/Exporter.cs | 171 ----------- .../KubectlParser/KubectlParser.csproj | 14 - src/KubectlParser/KubectlParser/Option.cs | 45 --- src/KubectlParser/KubectlParser/Program.cs | 284 ------------------ .../Properties/launchSettings.json | 8 - 7 files changed, 657 deletions(-) delete mode 100644 src/KubectlParser/KubectlParser.Test/KubectlParser.Test.csproj delete mode 100644 src/KubectlParser/KubectlParser.Test/ProgramTest.cs delete mode 100644 src/KubectlParser/KubectlParser/Exporter.cs delete mode 100644 src/KubectlParser/KubectlParser/KubectlParser.csproj delete mode 100644 src/KubectlParser/KubectlParser/Option.cs delete mode 100644 src/KubectlParser/KubectlParser/Program.cs delete mode 100644 src/KubectlParser/KubectlParser/Properties/launchSettings.json diff --git a/src/KubectlParser/KubectlParser.Test/KubectlParser.Test.csproj b/src/KubectlParser/KubectlParser.Test/KubectlParser.Test.csproj deleted file mode 100644 index 961720c..0000000 --- a/src/KubectlParser/KubectlParser.Test/KubectlParser.Test.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - net8.0 - - - - - - - - - - - - - - - PreserveNewest - - - - diff --git a/src/KubectlParser/KubectlParser.Test/ProgramTest.cs b/src/KubectlParser/KubectlParser.Test/ProgramTest.cs deleted file mode 100644 index 4c70f6f..0000000 --- a/src/KubectlParser/KubectlParser.Test/ProgramTest.cs +++ /dev/null @@ -1,112 +0,0 @@ -using NUnit.Framework; -using System.Collections.Generic; -using System.IO; - -namespace KubectlParser.Test -{ - public class ProgramTest - { - [TestFixture] - public class GetGroup - { - public string[] GetSampleContent() - { - return File.ReadAllLines("sample.txt"); - } - [Test] - public void GivenSample_ParsesDescription() - { - var sourceLines = GetSampleContent(); - int index = 0; - - var actual = Program.GetGroup(ref index, sourceLines); - - Assert.That(actual.Value.Caption, Is.EqualTo("Create a resource from a file or from stdin.")); - string[] lines = actual.Value.Lines; - Assert.That(lines.Length, Is.EqualTo(3)); - Assert.That(lines[0], Is.Empty); - Assert.That(lines[1], Is.EqualTo(" JSON and YAML formats are accepted.")); - Assert.That(lines[2], Is.Empty); - } - [Test] - public void GivenSample_ParsesUsageCorrectly() - { - var sourceLines = GetSampleContent(); - int index = 0; - - (string Caption, string[] Lines)? group; - (string Caption, string[] Lines)? lastGroup = null; - while ((group = Program.GetGroup(ref index, sourceLines)).HasValue) - { - lastGroup = group; - } - - Assert.That(lastGroup.Value.Caption, Is.EqualTo("Usage:")); - string[] lines = lastGroup.Value.Lines; - Assert.That(lines.Length, Is.EqualTo(2)); - Assert.That(lines[0], Is.EqualTo(" kubectl create -f FILENAME [options]")); - Assert.That(lines[1], Is.Empty); - } - } - [TestFixture] - public class GetOptionFromText - { - [Test] - public void WhenOptionHasOnlyLongName_ParsesIt() - { - const string text = " --allow-missing-template-keys=true:"; - var description = new List { "If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats." }; - - var option = Program.GetOptionFromText(text, description); - - Assert.That(option.Short, Is.Null); - Assert.That(option.Long, Is.EqualTo("allow-missing-template-keys")); - } - [Test] - public void WhenOptionHasOnlyLongNameAndDefaultIsTrue_ParsesDefault() - { - const string text = " --allow-missing-template-keys=true:"; - var description = new List { "If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats." }; - - var option = Program.GetOptionFromText(text, description); - - Assert.That(option.Default, Is.True); - } - [Test] - public void WhenOptionHasOnlyLongName_ParsesDescription() - { - const string text = " --allow-missing-template-keys=true:"; - var description = new List { "If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats." }; - - var option = Program.GetOptionFromText(text, description); - - Assert.That(option.Description, Is.EqualTo("If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats.")); - } - [Test] - public void WhenOptionHasShortAndLongName_ParsesBoth() - { - const string text = " -f, --filename=[]:"; - var description = new List { "Filename, directory, or URL to files to use to create the resource" }; - - var option = Program.GetOptionFromText(text, description); - - Assert.That(option.Short, Is.EqualTo("f")); - Assert.That(option.Long, Is.EqualTo("filename")); - } - } - - [TestFixture] - public class ExtractNameFromAvailableCommand - { - [Test] - public void GivenAvailableCommand_ExtractsName() - { - const string text = " clusterrole Create a ClusterRole."; - - var actual = Program.ExtractNameFromAvailableCommand(text); - - Assert.That(actual.ToString(), Is.EqualTo("clusterrole")); - } - } - } -} diff --git a/src/KubectlParser/KubectlParser/Exporter.cs b/src/KubectlParser/KubectlParser/Exporter.cs deleted file mode 100644 index 01e4975..0000000 --- a/src/KubectlParser/KubectlParser/Exporter.cs +++ /dev/null @@ -1,171 +0,0 @@ -using System.Collections.Immutable; -using System.IO; -using System.Linq; -using System.Text; - -namespace KubectlParser -{ - public static class Exporter - { - public static void Export(string target, ImmutableArray commands) - { - foreach (var di in Directory.GetDirectories(target)) - { - Directory.Delete(di, recursive: true); - } - foreach (var command in commands) - { - ExportCommand(target, ImmutableArray.Empty, command); - } - } - - public static void ExportCommand(string target, ImmutableArray previousVerbs, Command command) - { - var root = Directory.CreateDirectory(Path.Combine(target, command.PascalCaseVerb)); - CreateSettings(root.FullName, previousVerbs, command); - CreateAlias(root.FullName, previousVerbs, command); - foreach (var c in command.Commands) - { - ExportCommand(root.FullName, previousVerbs.Add(command.Verb), c); - } - } - - public static void CreateSettings(string root, ImmutableArray previousVerbs, Command command) - { - string verbs = string.Join("", previousVerbs.Select(v => Command.PascalizeVerb(v)).ToImmutableArray().Add(command.PascalCaseVerb)); - - StringBuilder builder = new StringBuilder(); - builder.AppendLine("using System.Runtime.CompilerServices;"); - builder.AppendLine(); - builder.AppendLine("namespace Cake.Kubectl"); - builder.AppendLine("{"); - builder.AppendLine("\t/// "); - builder.AppendLine($"\t/// {EncodeComment(command.Short)}"); - builder.AppendLine("\t///"); - foreach (string l in TrimLines(command.Description)) - { - builder.AppendLine($"\t/// {l}"); - } - builder.AppendLine("\t/// "); - if (command.Examples.Length > 0) - { - builder.AppendLine("\t/// "); - foreach (string l in TrimLines(command.Examples)) - { - builder.AppendLine($"\t/// {l}"); - } - builder.AppendLine("\t/// "); - } - builder.AppendLine("\t[CompilerGenerated]"); - builder.AppendLine($"\tpublic sealed class Kubectl{verbs}Settings : AutoToolSettings"); - builder.AppendLine("\t{"); - foreach (var option in command.Options) - { - string name = $"--{option.Long}"; - if (!string.IsNullOrWhiteSpace(option.Short)) - { - name = $"-{option.Short}, {name}"; - } - builder.AppendLine("\t\t/// "); - builder.AppendLine($"\t\t/// {name}"); - builder.AppendLine("\t\t///"); - builder.AppendLine($"\t\t/// {EncodeComment(option.Description)}"); - builder.AppendLine("\t\t/// "); - builder.AppendLine($"\t\tpublic {option.TypeName} {option.PropertyName} {{ get; set; }}"); - } - builder.AppendLine("\t}"); - builder.AppendLine("}"); - string filename = Path.Combine(root, $"Kubectl{verbs}Settings.cs"); - if (File.Exists(filename)) - { - File.Delete(filename); - } - File.WriteAllText(filename, builder.ToString()); - } - - public static void CreateAlias(string root, ImmutableArray previousVerbs, Command command) - { - string verbs = string.Join("", previousVerbs.Select(v => Command.PascalizeVerb(v)).ToImmutableArray().Add(command.PascalCaseVerb)); - string settingsTypeName = $"Kubectl{verbs}Settings"; - StringBuilder builder = new StringBuilder(); - foreach (var u in new string[] { "Cake.Core", "Cake.Core.Annotations", "System", "System.Collections.Generic", "System.Runtime.CompilerServices" } - .OrderBy(u => u)) - { - builder.AppendLine($"using {u};"); - } - builder.AppendLine(); - builder.AppendLine("namespace Cake.Kubectl"); - builder.AppendLine("{"); - builder.AppendLine("\tpartial class KubectlAliases"); - builder.AppendLine("\t{"); - - void AppendMethod(string? methodNamePostfix, string returnType, string runCommand, string? resultTypeMeta) - { - builder.AppendLine("\t\t/// "); - builder.AppendLine($"\t\t/// {EncodeComment(command.Short)}"); - builder.AppendLine("\t\t///"); - foreach (string l in TrimLines(command.Description)) - { - builder.AppendLine($"\t\t/// {l}"); - } - builder.AppendLine("\t\t/// "); - string cmd = $"{string.Join(" ", previousVerbs)} {command.Verb}".Trim(); - builder.AppendLine("\t\t/// The context."); - builder.AppendLine("\t\t/// The settings."); - if (!string.IsNullOrWhiteSpace(resultTypeMeta)) - { - builder.AppendLine($"\t\t/// {resultTypeMeta}"); - } - builder.AppendLine("\t\t[CakeMethodAlias]"); - builder.AppendLine($"\t\tpublic static {returnType} Kubectl{verbs}{methodNamePostfix}(this ICakeContext context, {settingsTypeName} settings)"); - builder.AppendLine($"\t\t{{"); - builder.AppendLine($"\t\t\tif (context == null)"); - builder.AppendLine($"\t\t\t{{"); - builder.AppendLine($"\t\t\t\tthrow new ArgumentNullException(nameof(context));"); - builder.AppendLine($"\t\t\t}}"); - builder.AppendLine($"\t\t\tvar arguments = new string[0];"); - builder.AppendLine($"\t\t\tvar runner = new GenericRunner<{settingsTypeName}>(context.FileSystem, context.Environment, context.ProcessRunner, context.Tools);"); - string? returnKeyword = !string.IsNullOrWhiteSpace(methodNamePostfix) ? "return " : null; - builder.AppendLine($"\t\t\t{returnKeyword}runner.{runCommand}(\"{cmd}\", settings ?? new {settingsTypeName}(), arguments);"); - builder.AppendLine($"\t\t}}"); - } - - AppendMethod(methodNamePostfix: null, "void", "Run", resultTypeMeta: null); - AppendMethod(methodNamePostfix: "WithResult", "IEnumerable", "RunWithResult", "Output lines."); - - builder.AppendLine("\t}"); - builder.AppendLine("}"); - string filename = Path.Combine(root, $"Kubectl.Alias.{verbs}.cs"); - if (File.Exists(filename)) - { - File.Delete(filename); - } - File.WriteAllText(filename, builder.ToString()); - } - - public static string[] TrimLines(string[] lines) - { - int? lastLine = null; - for (int i = lines.Length-1; i >= 0; i--) - { - if (!string.IsNullOrWhiteSpace(lines[i])) - { - lastLine = i; - break; - } - } - if (lastLine.HasValue) - { - return lines.Take(lastLine.Value + 1) - .Select(l => EncodeComment(l)) - .ToArray(); - } - return new string[0]; - } - - internal static string EncodeComment(string line) - { - return line.Replace("<", "<").Replace(">", ">"); - } - } -} diff --git a/src/KubectlParser/KubectlParser/KubectlParser.csproj b/src/KubectlParser/KubectlParser/KubectlParser.csproj deleted file mode 100644 index 18667aa..0000000 --- a/src/KubectlParser/KubectlParser/KubectlParser.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - - Exe - net8.0 - enable - - - - - - - - diff --git a/src/KubectlParser/KubectlParser/Option.cs b/src/KubectlParser/KubectlParser/Option.cs deleted file mode 100644 index 952b55c..0000000 --- a/src/KubectlParser/KubectlParser/Option.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Humanizer; -using System; - -namespace KubectlParser -{ - public class Option - { - public string? Short { get; } - public string Long { get; } - public object Default { get; } - public string Description { get; } - public Type Type { get; } - public Option(string? shortName, string longName, object defaultValue, string description, Type type) - { - Short = shortName; - Long = longName; - Default = defaultValue; - Description = description; - Type = type; - } - public string PropertyName => Long.Replace('-', ' ').Pascalize(); - public string TypeName - { - get - { - if (Type == typeof(bool)) - { - return "bool?"; - } - else if (Type == typeof(string)) - { - return "string?"; - } - else if (Type == typeof(int)) - { - return "int?"; - } - else - { - throw new Exception($"Unknown type {Type.Name}"); - } - } - } - } -} diff --git a/src/KubectlParser/KubectlParser/Program.cs b/src/KubectlParser/KubectlParser/Program.cs deleted file mode 100644 index 7c39adb..0000000 --- a/src/KubectlParser/KubectlParser/Program.cs +++ /dev/null @@ -1,284 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text.RegularExpressions; -using System.Threading; -using static System.Console; - -namespace KubectlParser -{ - public class Program - { - static void Main(string[] args) - { - string target = args[0] ?? throw new ArgumentException("target", "Target directory is required"); - - ImmutableArray commands; - var cache = Persister.Load(); - if (cache.HasValue) - { - WriteLine("Getting commands from cache"); - commands = cache.Value.Commands; - } - else - { - var version = GetVersion(); - WriteLine($"Actual version is {version.Major}.{version.Minor}"); - WriteLine("Getting commands from kubectl"); - var verbs = GetVerbs(); - int allVerbs = verbs.Values.Sum(v => v.Length); - WriteLine($"Got {allVerbs} total verbs"); - var commandInfo = ImmutableArray.Empty; - foreach (string group in verbs.Keys) - { - WriteLine(group); - foreach (string verb in verbs[group]) - { - commandInfo = commandInfo.Add(GetCommandInfo(ImmutableArray.Empty.Add(verb))); - } - } - commands = GetCommandsFromInfo(commandInfo); - Persister.Save(commands, $"{version.Major}.{version.Minor}"); - } - Exporter.Export(target, commands); - if (Debugger.IsAttached) - { - WriteLine("Done"); - //ReadLine(); - } - } - - public static ImmutableArray GetCommandsFromInfo(ImmutableArray info) - { - return info.Select(i => GetCommandFromInfo(i)).ToImmutableArray(); - } - - public static Command GetCommandFromInfo(CommandInfo info) - { - var parsedOptions = ParseOptionLinesForDescription(info.Options); - return new Command( - info.Verb, - info.Short, - info.Description, - info.Examples, - info.SubCommandInfo.Select(i => GetCommandFromInfo(i)).ToImmutableArray(), - options: parsedOptions - .Select(o => GetOptionFromText(o.Command, o.Description)).ToImmutableArray() - ); - } - - public static ImmutableArray<(string Command, ImmutableArray Description)> ParseOptionLinesForDescription(string[] lines) - { - var builder = ImmutableArray.CreateBuilder<(string Command, ImmutableArray Description)>(); - string? command = null; - var description = new List(); - foreach (string line in lines) - { - string trimmed = line.Trim(); - if (command is null) - { - if (trimmed.StartsWith('-')) - { - command = trimmed; - } - } - else - { - if (string.IsNullOrEmpty(trimmed)) - { - builder.Add((command, description.ToImmutableArray())); - command = null; - description.Clear(); - } - else - { - description.Add(trimmed); - } - } - } - if (command is not null) - { - builder.Add((command, description.ToImmutableArray())); - } - return builder.ToImmutableArray(); - } - - public static Option GetOptionFromText(string commandLine, IList descriptionLines) - { - var trimmed = commandLine.AsSpan().Trim(); - string longName; - string? shortName; - if (trimmed[1] == '-') - { - shortName = null; - longName = GetLongName(trimmed); - } - else - { - shortName = GetShortName(trimmed); - trimmed = trimmed.Slice(shortName.Length + 2).Trim(); - longName = GetLongName(trimmed); - } - trimmed = trimmed.Slice(longName.Length + 3); - int column = trimmed.IndexOf(':'); - var defaultValueText = trimmed.Slice(0, column); - object defaultValue = GetDefaultValueFromText(defaultValueText); - string description = string.Join("\n", descriptionLines); - return new Option(shortName, longName, defaultValue, description, defaultValue.GetType()); - } - - public static Regex regex = new Regex("((?\\d+)h)?((?\\d+)m)?((?\\d+)s)?", - RegexOptions.Singleline - | RegexOptions.CultureInvariant - | RegexOptions.Compiled - ); - public static object GetDefaultValueFromText(ReadOnlySpan text) => - text.ToString() switch - { - "true" => true, - "false" => false, - "[]" => string.Empty, - "''" => string.Empty, - "'json'" => string.Empty, - "kubectl" => "kubectl", - //"20s" => "20s", - //"0s" => "0s", - //"1m0s" => "1m0s", - _ when regex.Matches(text.ToString()).Count == 2 => text.ToString(), - "'https" => "https", - _ when text.StartsWith("'") && text.EndsWith("'") => text.ToString(), - "" => string.Empty, - "[localhost]" => text.ToString(), - _ when int.TryParse(text, out int value) => value, - _ => text.ToString(), - //_ => throw new ArgumentException(nameof(text), $"{text.ToString()} is unrecognized default value"), - }; - - public static string GetLongName(ReadOnlySpan text) - { - int index = text.IndexOf('='); - return text.Slice(2, index-2).ToString(); - } - - public static string GetShortName(ReadOnlySpan text) - { - int index = text.IndexOf(','); - return text.Slice(1, index-1).ToString(); - } - - public static ImmutableDictionary GetVerbs() - { - var lines = Retriever.GetCommandOutput("--help"); - - List groups = new List(); - - List group = new List(); - foreach (var line in lines.Skip(4)) - { - bool finished = line.StartsWith("Usage:", StringComparison.Ordinal); - if (finished) - { - break; - } - if (string.IsNullOrWhiteSpace(line)) - { - groups.Add(group.ToArray()); - group.Clear(); - } - else - { - group.Add(line); - } - } - - Dictionary result = new Dictionary(); - foreach (var g in groups) - { - // api-resources Print the supported API resources on the server -> api-resources - result.Add(g[0], g.Skip(1).Select(l => l.TrimStart().Split(' ')[0].Trim()).ToArray()); - } - return result.ToImmutableDictionary(); - } - - static CommandInfo GetCommandInfo(ImmutableArray verbs) - { - WriteLine(string.Join(" ", verbs)); - - var lines = Retriever.GetCommandOutput($"{(string.Join(" ", verbs))} --help"); - - CommandInfo result = new CommandInfo(verbs.Last()); - int index = 0; - var description = GetGroup(ref index, lines)!; - result.Short = description.Value.Caption; - result.Description = description.Value.Lines; - - (string Caption, string[] Lines)? info; - while ((info = GetGroup(ref index, lines)) != null) - { - switch (info.Value.Caption) - { - case "Examples:": - result.Examples = info.Value.Lines; - break; - case "Available Commands:": - result.Commands = info.Value.Lines - .Where(l => !string.IsNullOrWhiteSpace(l)) - .Select(l => ExtractNameFromAvailableCommand(l).ToString()).ToArray(); - break; - case "Options:": - result.Options = info.Value.Lines; - break; - case "Usage:": - result.Usage = info.Value.Lines; - break; - } - } - - var rootVerbs = verbs.ToImmutableArray(); - result.SubCommandInfo = result.Commands.Select(c => GetCommandInfo(rootVerbs.Add(c))).ToImmutableArray(); - return result; - } - - public static ReadOnlySpan ExtractNameFromAvailableCommand(ReadOnlySpan line) - { - var trimmed = line.TrimStart(); - int index = trimmed.IndexOf(' '); - return trimmed.Slice(0, index); - } - - public static (string Caption, string[] Lines)? GetGroup(ref int index, string[] lines) - { - string caption = lines[index]; - if (caption.StartsWith("Use \"", StringComparison.Ordinal)) - { - return null; - } - index++; - var group = new List(); - string line; - while ((line = lines[index]) == string.Empty - || line.StartsWith(" ", StringComparison.Ordinal) - || line.StartsWith("\t", StringComparison.Ordinal)) - { - group.Add(line); - index++; - } - return (caption, group.ToArray()); - } - - static VersionInfo GetVersion() - { - var lines = Retriever.GetCommandOutput("version"); - string line = lines[0]; - int start = line.IndexOf('{'); - int end = line.LastIndexOf('}'); - string json = line.Substring(start, end - start + 1); - var version = JsonConvert.DeserializeObject(json); - return version; - } - } -} diff --git a/src/KubectlParser/KubectlParser/Properties/launchSettings.json b/src/KubectlParser/KubectlParser/Properties/launchSettings.json deleted file mode 100644 index 62edaba..0000000 --- a/src/KubectlParser/KubectlParser/Properties/launchSettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "profiles": { - "KubectlParser": { - "commandName": "Project", - "commandLineArgs": "D:\\GitProjects\\Righthand\\Cake\\Cake.Kubectl\\src\\Cake.Kubectl" - } - } -} \ No newline at end of file