Files

107 lines
2.7 KiB
Go

package main
import (
"encoding/json"
"log/slog"
"os"
"sort"
"github.com/hanzoai/o11y-foundry/api/v1alpha1"
installationcasting "github.com/hanzoai/o11y-foundry/internal/casting/installation"
"github.com/hanzoai/o11y-foundry/internal/domain"
"github.com/olekukonko/tablewriter"
"github.com/spf13/cobra"
)
func registerCatalogCmd(rootCmd *cobra.Command) {
catalogCmd := &cobra.Command{
Use: "catalog",
Short: "Show available castings",
RunE: recoverRunE(domain.EventCatalog, func(cmd *cobra.Command, args []string) (domain.Properties, error) {
return runCatalog(rootLogger)
}),
}
catalogCfg.RegisterFlags(catalogCmd)
rootCmd.AddCommand(catalogCmd)
}
type castingEntry struct {
Platform string `json:"platform"`
Mode string `json:"mode"`
Flavor string `json:"flavor"`
Example string `json:"example"`
}
func castingExample(d v1alpha1.TypeDeployment) string {
platform, mode, flavor := d.Platform.String(), d.Mode.String(), d.Flavor.String()
switch {
case platform != "" && mode != "":
return platform + "/" + mode + "/" + flavor
case platform != "":
return platform + "/" + flavor
default:
return mode + "/" + flavor
}
}
// catalogGroup returns a sort key that groups entries:
// 0 = mode + flavor (self-hosted: docker, systemd, kubernetes).
// 1 = mode + flavor + platform (cloud infra: ecs).
// 2 = platform + flavor (managed platforms: coolify, render, railway).
func catalogGroup(e castingEntry) int {
switch {
case e.Platform != "" && e.Mode != "":
return 1
case e.Platform != "":
return 2
default:
return 0
}
}
func runCatalog(logger *slog.Logger) (domain.Properties, error) {
registry := installationcasting.NewRegistry(logger)
var entries []castingEntry
for d := range registry.CastingItems() {
entries = append(entries, castingEntry{
Platform: d.Platform.String(),
Mode: d.Mode.String(),
Flavor: d.Flavor.String(),
Example: castingExample(d),
})
}
sort.Slice(entries, func(i, j int) bool {
gi, gj := catalogGroup(entries[i]), catalogGroup(entries[j])
if gi != gj {
return gi < gj
}
return entries[i].Example < entries[j].Example
})
props := domain.NewProperties()
if commonCfg.Format == "text" {
table := tablewriter.NewWriter(os.Stdout)
table.Header("Mode", "Flavor", "Platform", "Example")
for _, e := range entries {
_ = table.Append(e.Mode, e.Flavor, e.Platform, e.Example)
}
return props, table.Render()
}
data, err := json.MarshalIndent(map[string]any{"Castings": entries}, "", " ")
if err != nil {
return props, err
}
if catalogCfg.OutPath != "" {
err = os.WriteFile(catalogCfg.OutPath, data, 0644)
return props, err
}
_, err = os.Stdout.Write(data)
return props, err
}