json.go 1.48 KB
Newer Older
protolambda's avatar
protolambda committed
1 2 3
package cmd

import (
4
	"compress/gzip"
protolambda's avatar
protolambda committed
5
	"encoding/json"
6
	"errors"
protolambda's avatar
protolambda committed
7 8 9
	"fmt"
	"io"
	"os"
10
	"strings"
protolambda's avatar
protolambda committed
11 12 13
)

func loadJSON[X any](inputPath string) (*X, error) {
14 15 16
	if inputPath == "" {
		return nil, errors.New("no path specified")
	}
17
	var f io.ReadCloser
protolambda's avatar
protolambda committed
18 19 20 21 22
	f, err := os.OpenFile(inputPath, os.O_RDONLY, 0)
	if err != nil {
		return nil, fmt.Errorf("failed to open file %q: %w", inputPath, err)
	}
	defer f.Close()
23 24 25 26 27 28 29
	if isGzip(inputPath) {
		f, err = gzip.NewReader(f)
		if err != nil {
			return nil, fmt.Errorf("create gzip reader: %w", err)
		}
		defer f.Close()
	}
protolambda's avatar
protolambda committed
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
	var state X
	if err := json.NewDecoder(f).Decode(&state); err != nil {
		return nil, fmt.Errorf("failed to decode file %q: %w", inputPath, err)
	}
	return &state, nil
}

func writeJSON[X any](outputPath string, value X, outIfEmpty bool) error {
	var out io.Writer
	if outputPath != "" {
		f, err := os.OpenFile(outputPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
		if err != nil {
			return fmt.Errorf("failed to open output file: %w", err)
		}
		defer f.Close()
		out = f
46 47 48 49 50
		if isGzip(outputPath) {
			g := gzip.NewWriter(f)
			defer g.Close()
			out = g
		}
protolambda's avatar
protolambda committed
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
	} else if outIfEmpty {
		out = os.Stdout
	} else {
		return nil
	}
	enc := json.NewEncoder(out)
	if err := enc.Encode(value); err != nil {
		return fmt.Errorf("failed to encode to JSON: %w", err)
	}
	_, err := out.Write([]byte{'\n'})
	if err != nil {
		return fmt.Errorf("failed to append new-line: %w", err)
	}
	return nil
}
66 67 68 69

func isGzip(path string) bool {
	return strings.HasSuffix(path, ".gz")
}