package main import ( "encoding/json" "errors" "flag" "fmt" "os" "path/filepath" "strings" "github.com/pelletier/go-toml/v2" "github.com/philandstuff/dhall-golang/v6" "github.com/tailscale/hujson" "go.jolheiser.com/nixfig" "gopkg.in/yaml.v3" ) func maine() error { var unmarshal func([]byte, any) error var marshal func(any) ([]byte, error) fs := flag.NewFlagSet("cfg", flag.ExitOnError) fromFunc := func(s string) error { switch strings.ToLower(s) { case "json", "jsonc": unmarshal = func(b []byte, a any) error { b, err := hujson.Standardize(b) if err != nil { return err } return json.Unmarshal(b, a) } case "yaml": unmarshal = yaml.Unmarshal case "toml": unmarshal = toml.Unmarshal case "dhall": unmarshal = dhall.Unmarshal case "nix": unmarshal = nixfig.Unmarshal default: return fmt.Errorf("unknown format %q", s) } return nil } fs.Func("from", "The format to convert from", fromFunc) fs.Func("f", "--from", fromFunc) toFunc := func(s string) error { switch strings.ToLower(s) { case "json", "jsonc": marshal = func(a any) ([]byte, error) { return json.MarshalIndent(a, "", "\t") } case "yaml": marshal = yaml.Marshal case "toml": marshal = toml.Marshal case "nix": marshal = nixfig.Marshal default: return fmt.Errorf("unknown format %q", s) } return nil } fs.Func("to", "The format to convert to", toFunc) fs.Func("t", "--to", toFunc) if err := fs.Parse(os.Args[1:]); err != nil { return err } if fs.NArg() < 1 { return errors.New("cfg requires at least an input file") } in := fs.Arg(0) if unmarshal == nil { if err := fromFunc(strings.TrimPrefix(filepath.Ext(fs.Arg(0)), ".")); err != nil { return err } } out := os.Stdout if fs.NArg() > 1 { fi, err := os.Create(fs.Arg(1)) if err != nil { return err } defer fi.Close() out = fi if marshal == nil { if err := toFunc(strings.TrimPrefix(filepath.Ext(fs.Arg(1)), ".")); err != nil { return err } } } else if marshal == nil { marshal = json.Marshal } var data any inData, err := os.ReadFile(in) if err != nil { return err } if err := unmarshal(inData, &data); err != nil { return err } outData, err := marshal(data) if err != nil { return err } if _, err := out.Write(outData); err != nil { return err } return nil } func main() { if err := maine(); err != nil { fmt.Println(err) os.Exit(1) } }