Skip to content

Instantly share code, notes, and snippets.

@eumel8
Created October 8, 2023 16:34
Show Gist options
  • Save eumel8/20012c51d6ab83de3e87231932e42c6d to your computer and use it in GitHub Desktop.
Save eumel8/20012c51d6ab83de3e87231932e42c6d to your computer and use it in GitHub Desktop.
Sort Go Types with comments alphabetically
package mystruct
// LoggingSpec defines the desired state of Logging
type MyStruct struct {
// Reference to the logging system. Each of the `loggingRef`s can manage a fluentbit daemonset and a fluentd statefulset.
LoggingRef string `json:"loggingRef,omitempty"`
// Disable configuration check before applying new fluentd configuration.
FlowConfigCheckDisabled bool `json:"flowConfigCheckDisabled,omitempty"`
// Whether to skip invalid Flow and ClusterFlow resources
SkipInvalidResources bool `json:"skipInvalidResources,omitempty"`
// Override generated config. This is a *raw* configuration string for troubleshooting purposes.
FlowConfigOverride string `json:"flowConfigOverride,omitempty"`
// ConfigCheck settings that apply to both fluentd and syslog-ng
ConfigCheck ConfigCheck `json:"configCheck,omitempty"`
// FluentbitAgent daemonset configuration.
// Deprecated, will be removed with next major version
// Migrate to the standalone NodeAgent resource
FluentbitSpec *FluentbitSpec `json:"fluentbit,omitempty"`
// Fluentd statefulset configuration
FluentdSpec *FluentdSpec `json:"fluentd,omitempty"`
// Syslog-NG statefulset configuration
SyslogNGSpec *SyslogNGSpec `json:"syslogNG,omitempty"`
// Default flow for unmatched logs. This Flow configuration collects all logs that didn't matched any other Flow.
DefaultFlowSpec *DefaultFlowSpec `json:"defaultFlow,omitempty"`
// GlobalOutput name to flush ERROR events to
ErrorOutputRef string `json:"errorOutputRef,omitempty"`
// Global filters to apply on logs before any match or filter mechanism.
GlobalFilters []Filter `json:"globalFilters,omitempty"`
// Limit namespaces to watch Flow and Output custom resources.
WatchNamespaces []string `json:"watchNamespaces,omitempty"`
// WatchNamespaceSelector is a LabelSelector to find matching namespaces to watch as in WatchNamespaces
WatchNamespaceSelector *metav1.LabelSelector `json:"watchNamespaceSelector,omitempty"`
// Cluster domain name to be used when templating URLs to services (default: "cluster.local.").
ClusterDomain *string `json:"clusterDomain,omitempty"`
// Namespace for cluster wide configuration resources like CLusterFlow and ClusterOutput.
// This should be a protected namespace from regular users.
// Resources like fluentbit and fluentd will run in this namespace as well.
ControlNamespace string `json:"controlNamespace"`
// Allow configuration of cluster resources from any namespace. Mutually exclusive with ControlNamespace restriction of Cluster resources
AllowClusterResourcesFromAllNamespaces bool `json:"allowClusterResourcesFromAllNamespaces,omitempty"`
// InlineNodeAgent Configuration
// Deprecated, will be removed with next major version
NodeAgents []*InlineNodeAgent `json:"nodeAgents,omitempty"`
// EnableRecreateWorkloadOnImmutableFieldChange enables the operator to recreate the
// fluentbit daemonset and the fluentd statefulset (and possibly other resource in the future)
// in case there is a change in an immutable field
// that otherwise couldn't be managed with a simple update.
EnableRecreateWorkloadOnImmutableFieldChange bool `json:"enableRecreateWorkloadOnImmutableFieldChange,omitempty"`
}
package main
import (
"fmt"
"go/ast"
"go/parser"
"go/token"
"io/ioutil"
"sort"
"strings"
)
type FieldInfo struct {
Name string
Type string
Tag string
Comment string
}
type MyStructInfo struct {
Fields []*FieldInfo
}
func main() {
// Lese den Inhalt der Datei "mystruct.go" ein
content, err := ioutil.ReadFile("mystruct2.go")
if err != nil {
fmt.Println("Fehler beim Lesen der Datei:", err)
return
}
fset := token.NewFileSet()
node, err := parser.ParseFile(fset, "", content, parser.ParseComments)
if err != nil {
fmt.Println("Fehler beim Parsen der Datei:", err)
return
}
// Finde das Struct in der Datei
var myStructInfo *MyStructInfo
for _, decl := range node.Decls {
if gd, ok := decl.(*ast.GenDecl); ok && gd.Tok == token.TYPE {
for _, spec := range gd.Specs {
if ts, ok := spec.(*ast.TypeSpec); ok && ts.Name.Name == "MyStruct" {
myStructInfo = extractFields(ts)
break
}
}
}
}
if myStructInfo == nil {
fmt.Println("Struct 'MyStruct' nicht gefunden")
return
}
// Sortiere die Felder alphabetisch nach Namen
sort.Slice(myStructInfo.Fields, func(i, j int) bool {
return myStructInfo.Fields[i].Name < myStructInfo.Fields[j].Name
})
// Gib die sortierten Felder mit Kommentaren über den Typen aus
for _, field := range myStructInfo.Fields {
fmt.Printf("// %s\n", field.Comment)
fmt.Printf("%s %s %s\n", field.Name, field.Type, field.Tag)
}
}
func extractFields(ts *ast.TypeSpec) *MyStructInfo {
structType, ok := ts.Type.(*ast.StructType)
if !ok {
return nil
}
fields := make([]*FieldInfo, len(structType.Fields.List))
for i, field := range structType.Fields.List {
fieldName := field.Names[0].Name
fieldType := fieldTypeString(field.Type)
fieldTag := ""
if field.Tag != nil {
fieldTag = field.Tag.Value
}
comment := extractComment(field.Doc)
fields[i] = &FieldInfo{Name: fieldName, Type: fieldType, Tag: fieldTag, Comment: comment}
}
return &MyStructInfo{Fields: fields}
}
func fieldTypeString(expr ast.Expr) string {
switch t := expr.(type) {
case *ast.Ident:
return t.Name
case *ast.StarExpr:
return "*" + fieldTypeString(t.X)
}
return ""
}
func extractComment(comments *ast.CommentGroup) string {
if comments != nil {
commentText := comments.Text()
return strings.TrimSpace(commentText)
}
return ""
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment