You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
99 lines
2.0 KiB
Go
99 lines
2.0 KiB
Go
11 months ago
|
package main
|
||
|
|
||
|
import (
|
||
|
"encoding/csv"
|
||
|
"encoding/json"
|
||
|
"errors"
|
||
|
"flag"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"os"
|
||
|
"sync"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
FormatCSV = "csv"
|
||
|
FormatJSON = "json"
|
||
|
FormatStream = "stream"
|
||
|
)
|
||
|
|
||
|
type UnknownFormatError struct{ Format string }
|
||
|
|
||
|
func (e UnknownFormatError) Error() string {
|
||
|
return "unknown format: '" + e.Format + "'"
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
if err := run(); err != nil {
|
||
|
_, _ = os.Stderr.WriteString("ERROR: " + err.Error())
|
||
|
os.Exit(1)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func run() error {
|
||
|
var in string
|
||
|
var out string
|
||
|
var format string
|
||
|
var width int
|
||
|
|
||
|
flag.StringVar(&in, "in", "", "input file")
|
||
|
flag.StringVar(&out, "out", "", "output file")
|
||
|
flag.StringVar(&format, "format", "csv", "output format (csv,json,stream)")
|
||
|
flag.IntVar(&width, "width", DefaultTabWidth, "spaces per tab")
|
||
|
flag.Parse()
|
||
|
|
||
|
var input io.ReadCloser = os.Stdin
|
||
|
var output io.WriteCloser = os.Stdout
|
||
|
|
||
|
if in != "" {
|
||
|
var err error
|
||
|
if input, err = os.Open(in); err != nil {
|
||
|
return fmt.Errorf("failed to get input %s: %w", in, err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if out != "" {
|
||
|
var err error
|
||
|
if output, err = os.Create(out); err != nil {
|
||
|
return fmt.Errorf("failed to get output %s: %w", out, err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
p := Parser{Width: width}
|
||
|
var err error
|
||
|
switch format {
|
||
|
case FormatCSV:
|
||
|
var once sync.Once
|
||
|
writer := csv.NewWriter(output)
|
||
|
err = p.IterSlice(input, func(headers []string, values []string) error {
|
||
|
var err error
|
||
|
once.Do(func() { err = writer.Write(headers) })
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return writer.Write(values)
|
||
|
})
|
||
|
writer.Flush()
|
||
|
|
||
|
case FormatStream:
|
||
|
enc := json.NewEncoder(output)
|
||
|
err = p.IterMap(input, func(values map[string]string) error {
|
||
|
return enc.Encode(values)
|
||
|
})
|
||
|
|
||
|
case FormatJSON:
|
||
|
var doc Document
|
||
|
doc, err = p.Parse(input)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to parse input: %w",
|
||
|
errors.Join(err, input.Close(), output.Close()))
|
||
|
}
|
||
|
err = json.NewEncoder(output).Encode(doc)
|
||
|
|
||
|
default:
|
||
|
err = UnknownFormatError{Format: format}
|
||
|
}
|
||
|
|
||
|
return errors.Join(err, input.Close(), output.Close())
|
||
|
}
|