about summary refs log tree commit diff stats
path: root/internal/options/process.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/options/process.go')
-rw-r--r--internal/options/process.go109
1 files changed, 109 insertions, 0 deletions
diff --git a/internal/options/process.go b/internal/options/process.go
new file mode 100644
index 0000000..fde73e4
--- /dev/null
+++ b/internal/options/process.go
@@ -0,0 +1,109 @@
+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
+}