package format import ( "encoding/json" "fmt" "path/filepath" "gopkg.in/yaml.v3" ) type DataFormat string const ( List DataFormat = "list" JSON DataFormat = "json" YAML DataFormat = "yaml" ) func (df DataFormat) String() string { return string(df) } func (df *DataFormat) Set(v string) error { switch DataFormat(v) { case List, JSON, YAML: *df = DataFormat(v) return nil default: return fmt.Errorf("must be one of %v", []DataFormat{ List, JSON, 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 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 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 YAML } return defaultFmt }