diff --git a/internal/format/format.go b/internal/format/format.go new file mode 100644 index 0000000..d38aa3e --- /dev/null +++ b/internal/format/format.go @@ -0,0 +1,104 @@ +package format + +import ( + "encoding/json" + "fmt" + "path/filepath" + + "gopkg.in/yaml.v3" +) + +type DataFormat string + +const ( + List DataFormat = "list" + JSON DataFormat = "json" + FORMAT_YAML DataFormat = "yaml" +) + +func (df DataFormat) String() string { + return string(df) +} + +func (df *DataFormat) Set(v string) error { + switch DataFormat(v) { + case List, JSON, FORMAT_YAML: + *df = DataFormat(v) + return nil + default: + return fmt.Errorf("must be one of %v", []DataFormat{ + List, JSON, FORMAT_YAML, + }) + } +} + +func (df DataFormat) Type() string { + return "DataFormat" +} + +// MarshalData marshals arbitrary data into a byte slice formatted as outFormat. +// If a marshalling error occurs or outFormat is unknown, an error is returned. +// +// Supported values are: json, list, yaml +func Marshal(data interface{}, outFormat DataFormat) ([]byte, error) { + switch outFormat { + case JSON: + if bytes, err := json.MarshalIndent(data, "", " "); err != nil { + return nil, fmt.Errorf("failed to marshal data into JSON: %w", err) + } else { + return bytes, nil + } + case FORMAT_YAML: + if bytes, err := yaml.Marshal(data); err != nil { + return nil, fmt.Errorf("failed to marshal data into YAML: %w", err) + } else { + return bytes, nil + } + case List: + return nil, fmt.Errorf("this data format cannot be marshaled") + default: + return nil, fmt.Errorf("unknown data format: %s", outFormat) + } +} + +// UnmarshalData unmarshals a byte slice formatted as inFormat into an interface +// v. If an unmarshalling error occurs or inFormat is unknown, an error is +// returned. +// +// Supported values are: json, list, yaml +func Unmarshal(data []byte, v interface{}, inFormat DataFormat) error { + switch inFormat { + case JSON: + if err := json.Unmarshal(data, v); err != nil { + return fmt.Errorf("failed to unmarshal data into JSON: %w", err) + } + case FORMAT_YAML: + if err := yaml.Unmarshal(data, v); err != nil { + return fmt.Errorf("failed to unmarshal data into YAML: %w", err) + } + case List: + return fmt.Errorf("this data format cannot be unmarshaled") + default: + return fmt.Errorf("unknown data format: %s", inFormat) + } + + return nil +} + +// DataFormatFromFileExt determines the type of the contents +// (JSON or YAML) based on the filname extension. The default +// format is passed in, so if it doesn't match one of the cases, +// that's what we will use. The defaultFmt value takes into account +// both the standard default format (JSON) and any command line +// change to that provided by options. +func DataFormatFromFileExt(path string, defaultFmt DataFormat) DataFormat { + switch filepath.Ext(path) { + case ".json", ".JSON": + // The file is a JSON file + return JSON + case ".yaml", ".yml", ".YAML", ".YML": + // The file is a YAML file + return FORMAT_YAML + } + return defaultFmt +}