Golang script: Difference between revisions
From wikinotes
No edit summary |
|||
Line 19: | Line 19: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
</blockquote><!-- Usage --> | </blockquote><!-- Usage --> | ||
= How it Works = | |||
<blockquote> | |||
It implements railroad-style programming pipes asynchronously/interchangeably between functions/subprocesses.<br> | |||
This is done using a Reader/Writer representing STDIN/STDOUT.<br> | |||
Similar to unix pipes, | |||
* when the Reader is closed, the pipes stop processing information | |||
* when any of the Filter() methods returns err, the pipes following it stop processing information | |||
Here's an oversimplification of the flow: | |||
<syntaxhighlight lang="go"> | |||
type Pipe struct { | |||
Reader ReadAutoCloser | |||
stdout io.Writer | |||
mu *sync.Mutex | |||
Err error | |||
} | |||
fun NewPipe() *Pipe {...} | |||
// https://github.com/bitfield/script/blob/master/script.go#L473 | |||
func (p *Pipe) Filter(filter func(io.Reader, io.Writer) error) *Pipe { | |||
if p.Err() != nil { | |||
return p | |||
} | |||
pr, pw := io.Pipe() | |||
filter(p.Reader, pw) | |||
} | |||
</syntaxhighlight> | |||
<syntaxhighlight lang="go"> | |||
pipe := NewPipe() | |||
pipe\ | |||
.Filter( | |||
func (r io.Reader, w io.Writer) error { | |||
w.Write(...) // write result | |||
return err := errors.New("some error") // flag an error | |||
} | |||
)\ | |||
.Filter(func (r io.Reader, w io.Writer) error { ... })\ | |||
.Filter(func (r io.Reader, w io.Writer) error { ... })\ | |||
.Filter(func (r io.Reader, w io.Writer) error { ... }) | |||
.Stdout() | |||
</syntaxhighlight> | |||
</blockquote><!-- How it Works --> |
Revision as of 04:06, 15 December 2022
A collection of shellscript inspired utility functions,
with stream-like asynchronous piping. Very clever.
Documentation
github https://github.com/bitfield/script
Example
import "script" script.Exec("ping 127.0.0.1").Stdout()
How it Works
It implements railroad-style programming pipes asynchronously/interchangeably between functions/subprocesses.
This is done using a Reader/Writer representing STDIN/STDOUT.
Similar to unix pipes,
- when the Reader is closed, the pipes stop processing information
- when any of the Filter() methods returns err, the pipes following it stop processing information
Here's an oversimplification of the flow:
type Pipe struct { Reader ReadAutoCloser stdout io.Writer mu *sync.Mutex Err error } fun NewPipe() *Pipe {...} // https://github.com/bitfield/script/blob/master/script.go#L473 func (p *Pipe) Filter(filter func(io.Reader, io.Writer) error) *Pipe { if p.Err() != nil { return p } pr, pw := io.Pipe() filter(p.Reader, pw) }pipe := NewPipe() pipe\ .Filter( func (r io.Reader, w io.Writer) error { w.Write(...) // write result return err := errors.New("some error") // flag an error } )\ .Filter(func (r io.Reader, w io.Writer) error { ... })\ .Filter(func (r io.Reader, w io.Writer) error { ... })\ .Filter(func (r io.Reader, w io.Writer) error { ... }) .Stdout()