pipe

Easily chain commands passing the output of each command along as the input for the next

Stars
18
Committers
1

pipe

pipe is a package for chaining exec.Cmds and having the output of each command used as the input for the next.

It has fairy limited uses and isn't as fleshed out as exec is, but I use it every once in a while for chaining several different commands on the same text file. Eg running gofmt and goimports on code that I have generated.

This code was initially released as part of a blog post covering how code generation can be used to make more maintainable code in a world without generics. You can find that post here - https://www.calhoun.io/using-code-generation-to-survive-without-generics-in-go/

Example usage

t := template.Must(template.New("queue").Parse(`
package blah

// Bad formatting intentional
func main() {
      fmt.Println("hello world!");
      }
`))
p, err := pipe.New(
	exec.Command("gofmt"),
	exec.Command("goimports"),
)
if err != nil {
	panic(err)
}
r, w := io.Pipe()
p.Stdin = r
p.Stdout = os.Stdout
if err := p.Start(); err != nil {
	panic(err)
}
// You should probably error check these too
t.Execute(w, nil)
w.Close()
if err := p.Wait(); err != nil {
	panic(err)
}

or you can use the Commands() function

t := template.Must(template.New("queue").Parse(`
package blah

// Bad formatting intentional
func main() {
      fmt.Println("hello world!");
      }
`))
rc, wc, errCh := pipe.Commands(
	exec.Command("gofmt"),
	exec.Command("goimports"),
)
go func() {
	select {
	case err, ok := <-errCh:
		if ok && err != nil {
			panic(err)
		}
	}
}()
t.Execute(wc, d)
wc.Close()
io.Copy(os.Stdout, rc)