From 2ef8badef44ba3e2a1c7789f5bb425e1f314ea7f Mon Sep 17 00:00:00 2001 From: Caio Marcelo de Oliveira Filho Date: Wed, 27 Dec 2017 12:21:53 -0800 Subject: [PATCH] swupd: add external reader and writer These types enable using external programs as filters. This will be used to call external compression/decompression programs. Signed-off-by: Caio Marcelo de Oliveira Filho --- swupd/external.go | 74 ++++++++++++++++++++++++++++++++++++++++++ swupd/external_test.go | 73 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 swupd/external.go create mode 100644 swupd/external_test.go diff --git a/swupd/external.go b/swupd/external.go new file mode 100644 index 0000000..5133999 --- /dev/null +++ b/swupd/external.go @@ -0,0 +1,74 @@ +package swupd + +import ( + "io" + "os/exec" +) + +type externalWriter struct { + cmd *exec.Cmd + input io.WriteCloser +} + +// newExternalWriter creates a Writer that will filter the contents in the +// external program and then write to w. +func newExternalWriter(w io.Writer, program string, args ...string) (*externalWriter, error) { + cmd := exec.Command(program, args...) + input, err := cmd.StdinPipe() + if err != nil { + return nil, err + } + cmd.Stdout = w + err = cmd.Start() + if err != nil { + input.Close() + return nil, err + } + return &externalWriter{cmd, input}, nil +} + +func (ew *externalWriter) Write(p []byte) (int, error) { + return ew.input.Write(p) +} + +func (ew *externalWriter) Close() error { + err := ew.input.Close() + if err != nil { + return err + } + return ew.cmd.Wait() +} + +type externalReader struct { + cmd *exec.Cmd + output io.ReadCloser +} + +// newExternalReader creates a Reader that will filter the contents of r in the +// external program before returning it. +func newExternalReader(r io.Reader, program string, args ...string) (*externalReader, error) { + cmd := exec.Command(program, args...) + cmd.Stdin = r + output, err := cmd.StdoutPipe() + if err != nil { + return nil, err + } + err = cmd.Start() + if err != nil { + output.Close() + return nil, err + } + return &externalReader{cmd, output}, nil +} + +func (er *externalReader) Read(p []byte) (int, error) { + return er.output.Read(p) +} + +func (er *externalReader) Close() error { + err := er.output.Close() + if err != nil { + return err + } + return er.cmd.Wait() +} diff --git a/swupd/external_test.go b/swupd/external_test.go new file mode 100644 index 0000000..91af679 --- /dev/null +++ b/swupd/external_test.go @@ -0,0 +1,73 @@ +package swupd + +import ( + "bytes" + "io/ioutil" + "os/exec" + "strings" + "testing" +) + +func TestExternalWriter(t *testing.T) { + tr, err := exec.LookPath("tr") + if err != nil { + if err == exec.ErrNotFound { + t.Skip("couldn't find tr program used for test") + } + t.Fatal(err) + } + + var output bytes.Buffer + w, err := newExternalWriter(&output, tr, "e", "a") + if err != nil { + t.Fatal(err) + } + + input := "Hello, world!" + expected := strings.Replace(input, "e", "a", -1) + + _, err = w.Write([]byte(input)) + if err != nil { + t.Fatal(err) + } + err = w.Close() + if err != nil { + t.Fatal(err) + } + + if output.String() != expected { + t.Fatalf("got %q, but want %q", output.String(), expected) + } +} + +func TestExternalReader(t *testing.T) { + tr, err := exec.LookPath("tr") + if err != nil { + if err == exec.ErrNotFound { + t.Skip("couldn't find tr program used for test") + } + t.Fatal(err) + } + + input := "Hello, world!" + expected := strings.Replace(input, "e", "a", -1) + + r, err := newExternalReader(strings.NewReader(input), tr, "e", "a") + if err != nil { + t.Fatal(err) + } + + output, err := ioutil.ReadAll(r) + if err != nil { + t.Fatal(err) + } + + if string(output) != expected { + t.Fatalf("got %q, but want %q", string(output), expected) + } + + err = r.Close() + if err != nil { + t.Fatal(err) + } +}