From 2889455633c11c4df7cf153eba8fe7cb8a8d5909 Mon Sep 17 00:00:00 2001 From: Richard Robert Reitz Date: Sat, 22 Mar 2025 12:55:23 +0100 Subject: [PATCH] added tree, index, onepage and singlepages --- hack/goget/main.go | 292 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 230 insertions(+), 62 deletions(-) diff --git a/hack/goget/main.go b/hack/goget/main.go index 5276e0e..4d47d9f 100644 --- a/hack/goget/main.go +++ b/hack/goget/main.go @@ -4,6 +4,7 @@ import ( "bufio" "fmt" "log" + "os" "sort" "strings" @@ -12,8 +13,12 @@ import ( type field struct { name string + enums string kind string + required bool description []string + fields []field + uuid string } type spec struct { @@ -24,6 +29,8 @@ type spec struct { field []string description []string fields []field + enums string + specs []spec } type index struct { @@ -31,15 +38,11 @@ type index struct { version string key string uuid string + group string } -func getFields(state *int, line string) { - *state++ -} - -func getSpec(specs map[string]spec, specName string) { +func getSpec(level int, specName string) spec { spec := spec{} - spec.uuid = specName out, err := lib.ExecNotFatal(`#!/bin/bash kubectl explain "${SPEC}" @@ -48,19 +51,24 @@ func getSpec(specs map[string]spec, specName string) { if err != nil { if specName == "events.events.k8s.io" { fmt.Println("warning: skipped " + specName + " intentionally, seems substituted by events") - return + return spec } else { log.Fatal("warning, cant lookup "+specName+": ", err) } } - currentField := field{} - fieldsState := 0 + spec.uuid = specName + currentField := field{} scanner := bufio.NewScanner(strings.NewReader(out)) step := 0 + scans := []string{} for scanner.Scan() { - line := scanner.Text() + scans = append(scans, scanner.Text()) + } + //fmt.Println("--- " + specName) + for u := range scans { + line := scans[u] if step == 0 { if strings.HasPrefix(line, "GROUP:") { word := line[6:] @@ -91,13 +99,23 @@ func getSpec(specs map[string]spec, specName string) { if len(strings.TrimSpace(line)) == 0 { step++ } else { - log.Fatal("cant find new line") + log.Fatal("cant find new line 1") + } + } else if step == 8 { + if len(strings.TrimSpace(line)) == 0 { + step = 4 + } else { + spec.enums += ", " + strings.TrimSpace(line) } } else if step == 5 { if len(strings.TrimSpace(line)) == 0 { step = 3 } else { - log.Fatal("cant find new line") + if strings.TrimSpace(line) == "ENUM:" { + step = 8 + } else { + log.Fatal("cant find new line 2 :" + line + ":") + } } } else if step == 4 { if strings.HasPrefix(line, "FIELD:") { @@ -118,15 +136,54 @@ func getSpec(specs map[string]spec, specName string) { step++ } } else if step == 7 { - currentField = field{} - field.name = strings.TrimSpace(line) - spec.fields = append(spec.fields, field) - getFields(&fieldsState, &spec.fieldsstrings.TrimSpace(line)) + runes := []rune(line) + if strings.HasPrefix(strings.TrimSpace(line), "enum:") { + currentField.enums = line[8:] + } else if len(runes) > 0 && runes[0] == 32 && runes[1] == 32 && runes[2] != 32 { + stringSlice := strings.Fields(line) + if !(len(stringSlice) == 2 || len(stringSlice) == 3) { + log.Fatal("wrong object type: " + line) + } + currentField.name = stringSlice[0] + currentField.kind = stringSlice[1][1 : len(stringSlice[1])-1] + if len(stringSlice) == 3 && stringSlice[2] == "-required-" { + currentField.required = true + } + } else { + currentField.uuid = spec.uuid + currentField.description = append(currentField.description, strings.TrimSpace(line)) + if len(strings.TrimSpace(line)) == 0 { + if u >= len(scans)-1 { + if len(strings.TrimSpace(currentField.name)) == 0 { + log.Fatal("field requires a name:" + line) + } + if level > 0 { + subSpec := getSpec(level+1, specName+"."+strings.TrimSpace(currentField.name)) + currentField.fields = append(currentField.fields, subSpec.fields...) + spec.specs = append(spec.specs, subSpec) + } + spec.fields = append(spec.fields, currentField) + currentField = field{} + } else { + localRunes := []rune(scans[u+1]) + if len(localRunes) > 0 && localRunes[0] == 32 && localRunes[1] == 32 && localRunes[2] != 32 { + if len(strings.TrimSpace(currentField.name)) == 0 { + log.Fatal("field requires a name:" + line) + } + if level > 0 { + subSpec := getSpec(level+1, specName+"."+strings.TrimSpace(currentField.name)) + currentField.fields = append(currentField.fields, subSpec.fields...) + spec.specs = append(spec.specs, subSpec) + } + spec.fields = append(spec.fields, currentField) + currentField = field{} + } + } + } + } } } - fmt.Println("fs " + fmt.Sprint(fieldsState)) - if err := scanner.Err(); err != nil { log.Fatal("error: ", err) } @@ -141,66 +198,177 @@ func getSpec(specs map[string]spec, specName string) { } } - specs[specName] = spec + return spec } func main() { - out, err := lib.ExecNotFatal(`#!/bin/bash + specs := make(map[string]spec) + + if len(os.Args) == 1 { + out, err := lib.ExecNotFatal(`#!/bin/bash kubectl api-resources --verbs=list -o name | sort `, []string{}) - if err != nil { - log.Fatal("error: ", err) - } - - specs := make(map[string]spec) - - scanner := bufio.NewScanner(strings.NewReader(out)) - for scanner.Scan() { - getSpec(specs, scanner.Text()) - } - getSpec(specs, "edfbuilders.edfbuilder.crossplane.io") - - if err := scanner.Err(); err != nil { - log.Fatal("error: ", err) - } - - for name, spec := range specs { - fmt.Println("### uuid = " + name) - fmt.Println("group = '" + spec.group + "'") - fmt.Println("kind = '" + spec.kind + "'") - fmt.Println("version = '" + spec.version + "'") - fmt.Println("field[" + fmt.Sprint(len(spec.field)) + "]:") - for i := 0; i < len(spec.field); i++ { - fmt.Println(" " + spec.field[i]) + if err != nil { + log.Fatal("error: ", err) } - fmt.Println("description[" + fmt.Sprint(len(spec.description)) + "]:") - for i := 0; i < len(spec.description); i++ { - fmt.Println(" " + spec.description[i]) + + scanner := bufio.NewScanner(strings.NewReader(out)) + for scanner.Scan() { + spec := getSpec(0, scanner.Text()) + if len(spec.uuid) > 0 { + specs[spec.uuid] = spec + } } - fmt.Println("fields[" + fmt.Sprint(len(spec.fields)) + "]:") - for i := 0; i < len(spec.fields); i++ { - fmt.Println(" " + spec.fields[i].name) + + if err := scanner.Err(); err != nil { + log.Fatal("error: ", err) } + } else { + spec := getSpec(1, os.Args[1]) + specs[spec.uuid] = spec } - objects := []index{} + tree := []spec{} - for name, spec := range specs { - objects = append(objects, index{spec.kind, spec.version, name, spec.uuid}) + for _, spec := range specs { + tree = append(tree, spec) } - sort.SliceStable(objects, func(i, j int) bool { - if objects[i].name == objects[j].name && objects[i].key == objects[j].key { - return objects[i].version < objects[j].version - } else if objects[i].name == objects[j].name { - return objects[i].key < objects[j].key + sort.SliceStable(tree, func(i, j int) bool { + if tree[i].group == tree[j].group { + return tree[i].kind < tree[j].kind } else { - return objects[i].name < objects[j].name + groupA := strings.Fields(strings.Replace(tree[i].group, ".", " ", -1)) + revGroupA := strings.Join(reverse(groupA), ".") + groupB := strings.Fields(strings.Replace(tree[j].group, ".", " ", -1)) + revGroupB := strings.Join(reverse(groupB), ".") + return revGroupA < revGroupB } }) - /*for _, object := range objects { - fmt.Println(object.name + " " + object.version + "." + object.key + " " + object.uuid) - }*/ + if len(os.Args) == 1 { + fmt.Println("") + fmt.Println("tree:") + for _, object := range tree { + if len(object.group) == 0 { + fmt.Println("default, " + object.kind + ", " + object.uuid) + } else { + group := strings.Fields(strings.Replace(object.group, ".", " ", -1)) + revGroup := strings.Join(reverse(group), ".") + fmt.Println(revGroup + ", " + object.kind + ", " + object.uuid) + } + } + + objects := []index{} + + for name, spec := range specs { + objects = append(objects, index{spec.kind, spec.version, name, spec.uuid, spec.group}) + } + + sort.SliceStable(objects, func(i, j int) bool { + groupA := strings.Fields(strings.Replace(objects[i].group, ".", " ", -1)) + revGroupA := strings.Join(reverse(groupA), ".") + groupB := strings.Fields(strings.Replace(objects[j].group, ".", " ", -1)) + revGroupB := strings.Join(reverse(groupB), ".") + //fmt.Println(objects[i].key) + if objects[i].name == objects[j].name && revGroupA == revGroupB { + return objects[i].version < objects[j].version + } else if objects[i].name == objects[j].name { + return revGroupA < revGroupB + } else { + return objects[i].name < objects[j].name + } + }) + + fmt.Println("") + fmt.Println("index:") + for _, object := range objects { + if len(object.group) == 0 { + fmt.Println(object.name + ", default, " + object.uuid) + } else { + group := strings.Fields(strings.Replace(object.group, ".", " ", -1)) + revGroup := strings.Join(reverse(group), ".") + fmt.Println(object.name + ", " + revGroup + ", " + object.uuid) + } + } + } + + if len(os.Args) > 1 { + for _, spec := range tree { + printSpec(spec, true) + } + + for _, spec := range tree { + recurseSpecs(spec) + } + } +} + +func recurseSpecs(spec spec) { + printSpec(spec, false) + for _, subSpec := range spec.specs { + if len(subSpec.specs) > 0 { + recurseSpecs(subSpec) + } + } +} + +func printSpec(spec spec, recurse bool) { + fmt.Println(spec.uuid) + fmt.Println("### uuid = " + spec.uuid) + if len(spec.group) == 0 { + fmt.Println("group = 'default'") + } else { + fmt.Println("group = '" + spec.group + "'") + } + fmt.Println("kind = '" + spec.kind + "'") + fmt.Println("version = '" + spec.version + "'") + fmt.Println("field[" + fmt.Sprint(len(spec.field)) + "]:") + for i := 0; i < len(spec.field); i++ { + fmt.Println(" " + spec.field[i]) + } + fmt.Println("description[" + fmt.Sprint(len(spec.description)) + "]:") + for i := 0; i < len(spec.description); i++ { + fmt.Println(" " + spec.description[i]) + } + fmt.Println("fields[" + fmt.Sprint(len(spec.fields)) + "]:") + printFields(1, spec.fields, len(spec.uuid), strings.ToLower(spec.kind), recurse) +} + +func printFields(level int, fields []field, baseUuidLength int, baseName string, recurse bool) { + fill := "" + for i := 0; i < level; i++ { + fill += " " + } + for i := range fields { + linked := "" + if len(fields[i].fields) > 0 { + linked = ", link" + } + fmt.Println(fill + " " + fields[i].name + ", " + fields[i].kind + ", " + fmt.Sprint(fields[i].required) + ", enums[" + fields[i].enums + "]" + linked) + if len(fields[i].uuid) > baseUuidLength && len(fields[i].uuid[baseUuidLength+1:]) > 0 { + fmt.Println(fill + " " + baseName + "." + fields[i].uuid[baseUuidLength+1:]) + } else if len(fields[i].uuid) == baseUuidLength { + fmt.Println(fill + " " + baseName) + } + for j := range fields[i].description { + fmt.Println(fill + " " + fields[i].description[j]) + } + if recurse { + printFields(level+1, fields[i].fields, baseUuidLength, baseName, recurse) + } + } +} + +func reverse(s []string) []string { + a := make([]string, len(s)) + copy(a, s) + + for i := len(a)/2 - 1; i >= 0; i-- { + opp := len(a) - 1 - i + a[i], a[opp] = a[opp], a[i] + } + + return a }