Documentation
¶
Overview ¶
Package script makes it easy to write declarative scripts in go.
The core abstraction is a Task. A shell command is an example of a task and this can be created and executed via:
task := script.Cmd("echo", "hello")
err := script.Run(context.Background(), task)
A pure Go task can be created via script.Func:
task := script.Func(func(ctx context.Context, r io.Reader, w io.Writer) error {
...
_, err := io.Copy(w, r)
return err
})
err := script.Run(context.Background(), task)
Tasks can be composed in sequence:
task := script.Sequence(
script.Cmd("echo", "hello"),
script.Cmd("echo", "world"),
)
err := script.Run(context.Background(), task)
This type of composition allows for expressions without having to constantly check for errors. A sequential task stops with an error when one of its tasks fails.
The other types of control flow structures are "Parallel", "Or" and "If".
Tasks can also be "Piped" in a chain via `Pipe`:
task := script.Pipe(
script.Cmd("echo", "hello"),
script.Cmd("sed", "s/hello/world"),
script.Cmd("grep", "world"),
)
err := script.Run(context.Background(), task)
Tasks can also be piped to a file (or piped from a file) by just using a file task `File(path)` in a pipe.
Non shell tasks can be mingled within via the `Func(...)` method. When the Func task is used in a Pipe, its input and output are provided via the reader and writer arg.
Index ¶
- func Run(ctx context.Context, t Task) error
- type Logger
- type Task
- func Cmd(program string, args ...string) Task
- func CmdWithLog(logger Logger, program string, args ...string) Task
- func File(path string) Task
- func Func(f func(ctx context.Context, r io.Reader, w io.Writer) error) Task
- func If(condition, thenTask, elseTask Task) Task
- func IgnoreError(t Task) Task
- func Or(tasks ...Task) Task
- func Parallel(tasks ...Task) Task
- func Pipe(tasks ...Task) Task
- func Sequence(tasks ...Task) Task
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Task ¶
type Task interface {
// Start starts a task asynchronously.
Start(ctx context.Context) error
// Wait waits for the task to finish.
// Wait can be called before the task is started. In this
// case, it should do nothing and return nil.
Wait(ctx context.Context) error
// Stdin redirects input.
// This is immutable returning a new task.
Stdin(r io.Reader) Task
// Stdout redirects output.
// This is immutable returning a new task.
Stdout(w io.Writer) Task
}
Task defines a task that can be run.
func CmdWithLog ¶
CmdWithLog runs a program with the provided args and also logs output.
func File ¶
File runs a task which allows either input to be piped to it or for the file to be piped into another task.
Example (Redirect) ¶
package main
import (
"context"
"fmt"
"github.com/tvastar/gotools/pkg/script"
)
func main() {
spec := script.Sequence(
// echo hello > /tmp/hello.txt
script.Pipe(
script.Cmd("echo", "hello"),
script.File("/tmp/hello.txt"),
),
// cat < /tmp/hello.txt
script.Pipe(
script.File("/tmp/hello.txt"),
script.Cmd("cat"),
),
// script.Cmd("rm", "/tmp/hello.txt"),
)
err := script.Run(context.Background(), spec)
if err != nil {
fmt.Println("error", err)
}
}
Output: hello
func Func ¶
Func runs a task function.
Example ¶
package main
import (
"context"
"fmt"
"io"
"github.com/tvastar/gotools/pkg/script"
)
func main() {
spec := script.Pipe(
script.Cmd("echo", "hello"),
script.Func(func(ctx context.Context, r io.Reader, w io.Writer) error {
_, err := io.Copy(w, r)
return err
}),
script.Cmd("cat"),
)
err := script.Run(context.Background(), spec)
if err != nil {
fmt.Println("error", err)
}
}
Output: hello
func If ¶
If runs the "then" task if the "condition" succeeds. It runs the else task if the "condition" fails. It is legal for thenTask and elseTask to be nil. If either of them are nil, the result of the condition is propagated.
Example ¶
package main
import (
"context"
"fmt"
"github.com/tvastar/gotools/pkg/script"
)
func main() {
spec := script.If(
script.Cmd("false"),
script.Cmd("echo", "wrongly succeeded"),
script.Cmd("echo", "rightly failed"),
)
err := script.Run(context.Background(), spec)
if err != nil {
fmt.Println("error", err)
}
spec = script.If(
script.IgnoreError(script.Cmd("false")),
script.Cmd("echo", "rightly succeeded"),
script.Cmd("echo", "wrongly failed"),
)
err = script.Run(context.Background(), spec)
if err != nil {
fmt.Println("error", err)
}
}
Output: rightly failed rightly succeeded
func Or ¶
Or runs a sequence of commands until one succeeds.
Example ¶
package main
import (
"context"
"fmt"
"github.com/tvastar/gotools/pkg/script"
)
func main() {
spec := script.Or(
script.Cmd("false"),
script.Cmd("false"),
script.Cmd("echo", "hello"),
)
err := script.Run(context.Background(), spec)
if err != nil {
fmt.Println("error", err)
}
}
Output: hello
func Parallel ¶
Parallel runs all tasks in parallel. If any tasks fail, it returns one of the errors.
func Pipe ¶
Pipe runs all tasks in a "pipe" chaining their input and outputs.
Example (If) ¶
package main
import (
"context"
"fmt"
"github.com/tvastar/gotools/pkg/script"
)
func main() {
spec := script.If(
script.Pipe(
script.Cmd("echo", "hello"),
script.Cmd("sed", "s/hello/world/"),
),
script.Cmd("echo", "rightly succeeded"),
script.Cmd("echo", "wrongly failed"),
)
err := script.Run(context.Background(), spec)
if err != nil {
fmt.Println("error", err)
}
}
Output: world rightly succeeded
func Sequence ¶
Sequence chains a sequence of tasks together. If any task fails, the sequence is aborted.
Example ¶
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/tvastar/gotools/pkg/script"
)
func main() {
logger := log.New(os.Stdout, "", 0)
spec := script.Sequence(
script.CmdWithLog(logger, "echo", "hello"),
script.CmdWithLog(logger, "echo", "world"),
)
err := script.Run(context.Background(), spec)
if err != nil {
fmt.Println("error", err)
}
}
Output: > echo hello hello > echo world world