conf/adapters.go

177 lines
3.7 KiB
Go
Raw Normal View History

package conf
import (
"encoding/json"
2025-01-15 01:49:44 +01:00
"errors"
"fmt"
"strings"
2025-01-15 01:49:44 +01:00
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/gohcl"
"github.com/hashicorp/hcl/v2/hclsimple"
"github.com/hashicorp/hcl/v2/hclwrite"
"github.com/pelletier/go-toml/v2"
2025-01-15 15:06:02 +01:00
"gopkg.in/yaml.v3"
)
type filetype int
const (
typeInvalid filetype = iota
typeJSON
typeTOML
2025-01-15 01:49:44 +01:00
typeHCL
2025-01-15 15:06:02 +01:00
typeYAML
)
2025-01-14 01:06:47 +01:00
// getType returns the type of the config file.
func getType(filename string) filetype {
switch {
case strings.HasSuffix(filename, ".json"):
return typeJSON
case strings.HasSuffix(filename, ".toml"):
return typeTOML
2025-01-15 01:49:44 +01:00
case strings.HasSuffix(filename, ".hcl"):
return typeHCL
2025-01-15 15:06:02 +01:00
case strings.HasSuffix(filename, ".yml") ||
strings.HasSuffix(filename, ".yaml"):
return typeYAML
default:
return typeInvalid
}
}
2025-01-14 01:06:47 +01:00
// unmarshal unmarshals the given data to the given struct.
2025-01-15 01:49:44 +01:00
func unmarshal(filepath string, data []byte, v any) error {
ft := getType(filepath)
switch ft {
case typeJSON:
return unmarshalJSON(data, v)
case typeTOML:
return unmarshalTOML(data, v)
2025-01-15 01:49:44 +01:00
case typeHCL:
return unmarshalHCL(filepath, data, v)
2025-01-15 15:06:02 +01:00
case typeYAML:
return unmarshalYAML(data, v)
default:
return ErrUnsupportedFileType
}
}
2025-01-14 01:06:47 +01:00
// marshal marshals the given struct to bytes.
func marshal(ft filetype, v any) ([]byte, error) {
switch ft {
case typeJSON:
return marshalJSON(v)
case typeTOML:
return marshalTOML(v)
2025-01-15 01:49:44 +01:00
case typeHCL:
return marshalHCL(v)
2025-01-15 15:06:02 +01:00
case typeYAML:
return marshalYAML(v)
default:
return nil, ErrUnsupportedFileType
}
}
2025-01-14 01:06:47 +01:00
// unmarshalJSON unmarshals the given data to the given struct.
func unmarshalJSON(data []byte, v any) error {
err := json.Unmarshal(data, v)
if err != nil {
return fmt.Errorf("cannot parse config file: %w", err)
}
return nil
}
2025-01-14 01:06:47 +01:00
// marshalJSON marshals the given struct to bytes.
func marshalJSON(v any) ([]byte, error) {
data, err := json.MarshalIndent(v, "", " ")
if err != nil {
return nil, fmt.Errorf("cannot generate config content: %w", err)
}
return data, nil
}
2025-01-14 01:06:47 +01:00
// unmarshalTOML unmarshals the given data to the given struct.
func unmarshalTOML(data []byte, v any) error {
err := toml.Unmarshal(data, v)
if err != nil {
return fmt.Errorf("cannot parse config file: %w", err)
}
return nil
}
2025-01-14 01:06:47 +01:00
// marshalTOML marshals the given struct to bytes.
func marshalTOML(v any) ([]byte, error) {
data, err := toml.Marshal(v)
if err != nil {
return nil, fmt.Errorf("cannot generate config content: %w", err)
}
return data, nil
}
2025-01-15 01:49:44 +01:00
// unmarshalHCL unmarshals the given data to the given struct.
func unmarshalHCL(filepath string, data []byte, v any) error {
err := hclsimple.Decode(filepath, data, nil, v)
var diags hcl.Diagnostics
errors.As(err, &diags)
newDiags := hclFilterDiagnostics(diags)
if len(newDiags) > 0 {
return fmt.Errorf("cannot parse config file: %w", newDiags)
}
return nil
}
// marshalHCL marshals the given struct to bytes.
2025-01-15 15:06:02 +01:00
func marshalHCL(v any) ([]byte, error) {
2025-01-15 01:49:44 +01:00
f := hclwrite.NewEmptyFile()
gohcl.EncodeIntoBody(v, f.Body())
return f.Bytes(), nil
}
func hclFilterDiagnostics(diags hcl.Diagnostics) hcl.Diagnostics {
var newDiags hcl.Diagnostics
for _, diag := range diags {
if diag.Summary != "Unsupported argument" {
newDiags = append(newDiags, diag)
}
}
if len(newDiags) > 0 {
return newDiags
}
return nil
}
2025-01-15 15:06:02 +01:00
// unmarshalYAML unmarshals the given data to the given struct.
func unmarshalYAML(data []byte, v any) error {
err := yaml.Unmarshal(data, v)
if err != nil {
return fmt.Errorf("cannot parse config file: %w", err)
}
return nil
}
// marshalYAML marshals the given struct to bytes.
func marshalYAML(v any) ([]byte, error) {
data, err := yaml.Marshal(v)
if err != nil {
return nil, fmt.Errorf("cannot generate config content: %w", err)
}
return data, nil
}