package options import ( "encoding/json" "io" "os" "github.com/bcicen/jstream" "github.com/mitchellh/mapstructure" "github.com/pkg/errors" ) func ValueTypeToString(valueType jstream.ValueType) string { switch valueType { case jstream.Unknown: return "unknown" case jstream.Null: return "null" case jstream.String: return "string" case jstream.Number: return "number" case jstream.Boolean: return "boolean" case jstream.Array: return "array" case jstream.Object: return "object" } return "very strange" } func Process(inpath string, outpath string) error { infile, err := os.Open(inpath) if err != nil { return errors.WithMessagef(err, "failed to open input file %s", inpath) } defer infile.Close() outfile, err := os.Create(outpath) if err != nil { return errors.WithMessagef(err, "failed to open output file %s", outpath) } if outpath != "/dev/stdout" { defer outfile.Close() } dec := jstream.NewDecoder(infile, 1).EmitKV() var opt NixOption ms, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ ErrorUnused: true, Result: &opt, Squash: true, DecodeHook: mapstructure.TextUnmarshallerHookFunc(), }) if err != nil { return errors.WithMessage(err, "could not create mapstructure decoder") } _, err = outfile.WriteString("[\n") if err != nil { return errors.WithMessage(err, "could not write to output") } for mv := range dec.Stream() { if err := dec.Err(); err != nil { return errors.WithMessage(err, "could not decode JSON") } if mv.ValueType != jstream.Object { return errors.Errorf("unexpected object type %s", ValueTypeToString(mv.ValueType)) } kv := mv.Value.(jstream.KV) if kv.Key == "_module.args" { continue } x := kv.Value.(map[string]interface{}) x["option"] = kv.Key err = ms.Decode(x) if err != nil { return errors.WithMessagef(err, "failed to decode option %#v", x) } b, err := json.MarshalIndent(opt, "", " ") if err != nil { return errors.WithMessagef(err, "failed to encode option %#v", opt) } _, err = outfile.Write(b) if err != nil { return errors.WithMessage(err, "failed to write to output") } _, err = outfile.WriteString(",\n") if err != nil { return errors.WithMessage(err, "failed to write to output") } } _, err = outfile.Seek(-2, io.SeekCurrent) if err != nil { return errors.WithMessage(err, "could not write to output") } _, err = outfile.WriteString("]\n") if err != nil { return errors.WithMessage(err, "could not write to output") } return nil }