Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
286 changes: 273 additions & 13 deletions cmdTools/lowLevelCmd.tmpl
Original file line number Diff line number Diff line change
@@ -1,54 +1,293 @@

{{ $operationId := .operationId }}
{{ $isGet := hasPrefix $operationId "Get" }}
{{ $isList := hasPrefix $operationId "List" }}
{{ $isCreate := hasPrefix $operationId "Create" }}

var (
{{ $operationId := .operationId }}
{{if not .requiredFlags}}
{{else}}
{{- range .requiredFlags}}
{{ $operationId }}{{ . }} string
{{ end }}
{{end}}
{{ if or $isGet $isList }}
{{ $operationId }}BackupDir string
{{ end }}
{{ if $isCreate }}
{{ $operationId }}RestoreFile string
{{ end }}
{{ if $isList }}
{{ $operationId }}Limit int32
{{ $operationId }}Page string
{{ $operationId }}FetchAll bool
{{ end }}
{{ $operationId }}Quiet bool
)

func New{{ .operationId }}Cmd() *cobra.Command {
cmd := &cobra.Command{
Use: "{{ .subCommand }}",
Long: "{{ .summary }}",
PreRunE: func(cmd *cobra.Command, args []string) error {
{{ if or $isGet $isList }}
isBackupRequested := cmd.Flags().Changed("backup") || cmd.Flags().Changed("batch-backup")
if isBackupRequested && !cmd.Flags().Changed("backup-dir") {
return fmt.Errorf("--backup-dir is required when using backup functionality")
}
{{ end }}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
{{ $operationId := .operationId }}
{{ $newParam := "" }}

{{ if $isCreate }}
if {{ $operationId }}RestoreFile != "" {
{{ if .data }}
jsonData, err := os.ReadFile({{ $operationId }}RestoreFile)
if err != nil {
return fmt.Errorf("failed to read restore file: %w", err)
}

processedData, err := utils.PrepareDataForRestore(jsonData)
if err != nil {
return fmt.Errorf("failed to process restore data: %w", err)
}

{{ $operationId }}data = string(processedData)
{{ else }}
fmt.Println("Warning: This Create operation doesn't support data input. Cannot restore from file.")
return fmt.Errorf("restore from file not supported for this operation that doesn't accept data input")
{{ end }}

if !{{ $operationId }}Quiet {
fmt.Println("Restoring {{ .name }} from:", {{ $operationId }}RestoreFile)
}
}
{{ end }}

{{if not .pathParams}}
req := apiClient.{{ .name }}API.{{ .operationId }}(apiClient.GetConfig().Context)
{{else}}
req := apiClient.{{ .name }}API.{{ .operationId }}(apiClient.GetConfig().Context, {{join .pathParams ", "}})
{{end}}

{{if .data}}
if {{ .operationId }}data != "" {
req = req.Data({{ .operationId }}data)
}
{{else}}
{{end}}

{{ if $isList }}
var allItems []map[string]interface{}
var pageCount int

for {
resp, err := req.Execute()
if err != nil {
if resp != nil && resp.Body != nil {
d, err := io.ReadAll(resp.Body)
if err == nil && !{{ $operationId }}Quiet {
utils.PrettyPrintByte(d)
}
}
return err
}

d, err := io.ReadAll(resp.Body)
if err != nil {
return err
}

var items []map[string]interface{}
if err := json.Unmarshal(d, &items); err != nil {
if !{{ $operationId }}Quiet {
utils.PrettyPrintByte(d)
}
return nil
}

allItems = append(allItems, items...)
pageCount++

if !{{ $operationId }}FetchAll || len(items) == 0 {
break
}

nextURL := ""
if resp != nil {
links := resp.Header["Link"]
for _, link := range links {
if strings.Contains(link, `rel="next"`) {
parts := strings.Split(link, ";")
if len(parts) > 0 {
urlPart := strings.TrimSpace(parts[0])
urlPart = strings.TrimPrefix(urlPart, "<")
urlPart = strings.TrimSuffix(urlPart, ">")
nextURL = urlPart
break
}
}
}
}

if nextURL == "" {
break
}

nextReq, err := http.NewRequest("GET", nextURL, nil)
if err != nil {
break
}

token := ""
cfg := apiClient.GetConfig()
if cfg != nil {
apiKeys, ok := cfg.Context.Value(sdk.ContextAPIKeys).(map[string]sdk.APIKey)
if ok {
apiKey, exists := apiKeys["API_Token"]
if exists {
token = apiKey.Prefix + " " + apiKey.Key
}
}
}

if token != "" {
nextReq.Header.Add("Authorization", token)
}

nextReq.Header.Add("Accept", "application/json")

respNext, err := http.DefaultClient.Do(nextReq)
if err != nil {
break
}

dNext, err := io.ReadAll(respNext.Body)
respNext.Body.Close()
if err != nil {
break
}

var nextItems []map[string]interface{}
if err := json.Unmarshal(dNext, &nextItems); err != nil {
break
}

allItems = append(allItems, nextItems...)
pageCount++
}

if {{ $operationId }}FetchAll && pageCount > 1 && !{{ $operationId }}Quiet {
fmt.Printf("Retrieved %d items across %d pages\n", len(allItems), pageCount)
}

combinedJSON, err := json.Marshal(allItems)
if err != nil {
return fmt.Errorf("error combining results: %w", err)
}

if cmd.Flags().Changed("batch-backup") {
dirPath := filepath.Join({{ $operationId }}BackupDir, "{{ .name | lower }}", "{{ .subCommand }}")

if err := os.MkdirAll(dirPath, 0o755); err != nil {
return fmt.Errorf("failed to create backup directory: %w", err)
}

if !{{ $operationId }}Quiet {
fmt.Printf("Backing up {{ .name }}s to %s\n", dirPath)
}

success := 0
for _, item := range allItems {
id, ok := item["id"].(string)
if !ok {
if !{{ $operationId }}Quiet {
fmt.Println("Warning: item missing ID field, skipping")
}
continue
}

itemJSON, err := json.MarshalIndent(item, "", " ")
if err != nil {
if !{{ $operationId }}Quiet {
fmt.Printf("Error marshaling item %s: %v\n", id, err)
}
continue
}

filePath := filepath.Join(dirPath, id+".json")
if err := os.WriteFile(filePath, itemJSON, 0o644); err != nil {
if !{{ $operationId }}Quiet {
fmt.Printf("Error writing file for %s: %v\n", id, err)
}
continue
}

success++
}

if !{{ $operationId }}Quiet {
fmt.Printf("Successfully backed up %d/%d {{ .name }}s\n", success, len(allItems))
}
return nil
} else {
if !{{ $operationId }}Quiet {
return utils.PrettyPrintByte(combinedJSON)
}
return nil
}
{{ else }}
resp, err := req.Execute()
if err != nil {
if resp != nil && resp.Body != nil {
d, err := io.ReadAll(resp.Body)
if err == nil {
if err == nil && !{{ $operationId }}Quiet {
utils.PrettyPrintByte(d)
}
}
return err
}
d, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
utils.PrettyPrintByte(d)
// cmd.Println(string(d))
return nil
d, err := io.ReadAll(resp.Body)
if err != nil {
return err
}

{{ if $isGet }}
if cmd.Flags().Changed("backup") {
dirPath := filepath.Join({{ $operationId }}BackupDir, "{{ .name | lower }}", "{{ .subCommand }}")
if err := os.MkdirAll(dirPath, 0o755); err != nil {
return fmt.Errorf("failed to create backup directory: %w", err)
}

{{if .pathParams}}
idParam := {{index .pathParams 0}}
fileName := fmt.Sprintf("%s.json", idParam)
{{else}}
fileName := "{{ .name | lower }}.json"
{{end}}

filePath := filepath.Join(dirPath, fileName)

if err := os.WriteFile(filePath, d, 0o644); err != nil {
return fmt.Errorf("failed to write backup file: %w", err)
}

if !{{ $operationId }}Quiet {
fmt.Printf("Backup completed successfully to %s\n", filePath)
}
return nil
}
{{ end }}

if !{{ $operationId }}Quiet {
utils.PrettyPrintByte(d)
}
return nil
{{ end }}
},
}

{{ $operationId := .operationId }}
{{if not .requiredFlags}}
{{else}}
{{- range .requiredFlags}}
Expand All @@ -57,10 +296,31 @@ func New{{ .operationId }}Cmd() *cobra.Command {
{{ end }}
{{end}}

{{ if $isList }}
cmd.Flags().Int32VarP(&{{ $operationId }}Limit, "limit", "l", 0, "Maximum number of items to return per page")
cmd.Flags().StringVarP(&{{ $operationId }}Page, "page", "p", "", "Page to fetch (if supported)")
cmd.Flags().BoolVarP(&{{ $operationId }}FetchAll, "all", "", false, "Fetch all items by following pagination automatically")
cmd.Flags().BoolP("batch-backup", "b", false, "Backup multiple {{ .name }}s to a directory")
{{ end }}

{{ if $isGet }}
cmd.Flags().BoolP("backup", "b", false, "Backup the {{ .name }} to a file")
{{ end }}

{{ if or $isGet $isList }}
cmd.Flags().StringVarP(&{{ $operationId }}BackupDir, "backup-dir", "d", "", "Directory to save backups")
{{ end }}

{{ if $isCreate }}
cmd.Flags().StringVarP(&{{ $operationId }}RestoreFile, "restore-from", "r", "", "Restore {{ .name }} from a JSON backup file")
{{ end }}

cmd.Flags().BoolVarP(&{{ $operationId }}Quiet, "quiet", "q", false, "Suppress normal output")

return cmd
}

func init() {
{{ .operationId }}Cmd := New{{ .operationId }}Cmd()
{{ .name }}Cmd.AddCommand({{ .operationId }}Cmd)
}
}
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
Loading