Created
January 29, 2020 20:01
-
-
Save bored-engineer/70283f03f83f6105e1a67144287bd95f to your computer and use it in GitHub Desktop.
jq but for MessagePack: go build mq.go -o mq
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"fmt" | |
"io" | |
"io/ioutil" | |
"log" | |
"os" | |
"os/exec" | |
"strings" | |
"github.com/tinylib/msgp/msgp" | |
) | |
// usage invokes jq but replaced jq with mq | |
func usage() { | |
out, err := exec.Command("jq", "--help").CombinedOutput() | |
if err != nil { | |
log.Fatalf("failed to execute jq: %v", err) | |
} | |
out = bytes.ReplaceAll(out, []byte("jq"), []byte("mq")) | |
out = bytes.ReplaceAll(out, []byte("JSON"), []byte("MessagePack")) | |
fmt.Print(string(out)) | |
os.Exit(0) | |
} | |
// convert takes a input converts to json and returns the path | |
func convert(inputPath string) (string, error) { | |
output, err := ioutil.TempFile("", "mq*") | |
if err != nil { | |
return output.Name(), err | |
} | |
defer output.Close() | |
input, err := os.Open(inputPath) | |
if err != nil { | |
return output.Name(), err | |
} | |
defer input.Close() | |
if _, err := msgp.CopyToJSON(output, input); err != nil { | |
return output.Name(), err | |
} | |
return output.Name(), nil | |
} | |
// Entry point | |
func main() { | |
// Extract the jq args from the filenames | |
var files []string | |
var args []string | |
flags := true | |
for _, arg := range os.Args[1:] { | |
switch { | |
case arg == "--": | |
flags = false | |
case arg == "--help" || arg == "-h": | |
usage() | |
case flags && strings.HasPrefix(arg, "-"): | |
args = append(args, arg) | |
default: | |
files = append(files, arg) | |
} | |
} | |
cmd := exec.Command("jq", files[0]) | |
files = files[1:] | |
// If 1 or less files, use stdin to pipe | |
if len(files) <= 1 { | |
src := os.Stdin | |
if len(files) == 1 { | |
f, err := os.Open(files[0]) | |
if err != nil { | |
log.Fatalf("failed to open file: %v", err) | |
} | |
defer f.Close() | |
src = f | |
} | |
// Use a pipe for minimal i/o | |
var dst io.WriteCloser | |
cmd.Stdin, dst = io.Pipe() | |
go func() { | |
defer dst.Close() | |
if _, err := msgp.CopyToJSON(dst, src); err != nil { | |
log.Fatalf("failed to decode msgpack: %v", err) | |
} | |
}() | |
} else { | |
// Convert the files on disk with temporary files blocking until done | |
for _, file := range files { | |
tmp, err := convert(file) | |
defer os.Remove(tmp) | |
if err != nil { | |
log.Fatalf("failed to convert file: %v", err) | |
} | |
cmd.Args = append(cmd.Args, tmp) | |
} | |
} | |
cmd.Args = append(cmd.Args, args...) | |
cmd.Stdout = os.Stdout | |
cmd.Stderr = os.Stderr | |
if err := cmd.Run(); err != nil { | |
if exitError, ok := err.(*exec.ExitError); ok { | |
os.Exit(exitError.ExitCode()) | |
} else { | |
log.Fatalf("failed to execute jq: %v", err) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment