cmdsync

package
v0.5.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 2, 2021 License: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Overview

Package cmdsync has logic for synchronizing multiple shell comands. Commands can depend on the completion or readiness of other commands where readiness can be determined by the output matching some regular expression.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Group

type Group struct {
	// contains filtered or unexported fields
}

Group manages scheduling concurrent ShellCmds

func NewGroup

func NewGroup(commands ...*ShellCmd) *Group

NewGroup makes a new Group it can be optionally initialized with commands or they can be added later via AddCommands

func (*Group) AddCommands

func (g *Group) AddCommands(commands ...*ShellCmd) error

AddCommands will add ShellCmds to the commands slice It will return an error if called after Group.Run()

func (*Group) Run

func (g *Group) Run() error

Run will run all of the group's ShellCmds and block until they have all finished running or an interrupt signal is sent (ctrl + c). Internally it relays the first interrupt signal to all underlying ShellCmds. Additional interrupt commands will return to normal behavior.

It checks for each ShellCmd's prerequisites before starting. See ShellCmd for details on ready regexp.

The returned error is the first error returned from any of the Group's ShellCmds, if any.

Example
package main

import (
	"log"

	"github.com/alexchao26/oneterminal/cmdsync"
)

func main() {
	cmd1, _ := cmdsync.NewShellCmd("bash", "echo logging into vault && sleep 0.5 && echo logged in",
		cmdsync.Name("setup"),
		// a regexp pattern that must match the command's outputs for it to be deemed "ready", and
		// for its dependents to start executing
		cmdsync.ReadyPattern("logged in"),
	)
	cmd2, _ := cmdsync.NewShellCmd("bash", "echo starting some api...",
		cmdsync.Name("second"),
		// will not start until the "setup" command is "ready"
		cmdsync.DependsOn("setup"),
	)
	cmd3, _ := cmdsync.NewShellCmd("bash", "echo sweep sweep",
		cmdsync.Name("cleanup"),
		// will happen last
		cmdsync.DependsOn("second"),
	)

	group := cmdsync.NewGroup(cmd1, cmd2, cmd3)
	err := group.Run()
	if err != nil {
		log.Fatal(err)
	}
}
Output:

setup | logging into vault
setup | logged in
second | starting some api...
cleanup | sweep sweep

func (*Group) RunContext added in v0.4.0

func (g *Group) RunContext(ctx context.Context) error

RunContext is the same as Run but does not setup singal notifying internally. This means callers can only interrupt the Group's ShellCmds by cancelling the context.

To cancel the context via an interrupt signal from the terminal (ctrl + c), use signal.NotifyContext.

ctx, done := signal.NotifyContext(context.Background(), os.Interrupt)
// ensure done() is called to restore normal SIGINT behavior
go func() {
    <- ctx.Done()
    done()
}()
err := group.Run(ctx)
// handle error
Example (Notify)
package main

import (
	"context"
	"log"
	"os"
	"os/signal"

	"github.com/alexchao26/oneterminal/cmdsync"
)

func main() {
	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
	// RunContext might hang even when interrupted, so reset the signal behavior
	// in a goroutine to ensure subsequent interrupt signals behave "normally".
	go func() {
		<-ctx.Done()
		stop()
	}()

	cmd1, _ := cmdsync.NewShellCmd("bash", "echo potatoes", cmdsync.Name("first"))
	cmd2, _ := cmdsync.NewShellCmd("bash", "echo are", cmdsync.Name("second"), cmdsync.DependsOn("first"))
	cmd3, _ := cmdsync.NewShellCmd("bash", "echo great", cmdsync.Name("third"), cmdsync.DependsOn("second"))

	group := cmdsync.NewGroup(cmd1, cmd2, cmd3)
	err := group.RunContext(ctx)
	if err != nil {
		log.Fatal(err)
	}
}
Output:

first | potatoes
second | are
third | great

func (*Group) SendInterrupts

func (g *Group) SendInterrupts()

SendInterrupts relays an interrupt signal to all underlying commands

type ShellCmd added in v0.4.0

type ShellCmd struct {
	// contains filtered or unexported fields
}

ShellCmd is a wrapper around exec.Cmd that eases syncing to other ShellCmd's via Group.

Its implementation calls the shell directly (through zsh/bash)

ShellCmd can indicate that the underlying process has reached a "ready state" by

  1. Its stdout/stderr outputs matching a given regexp.
  2. Its underlying process completing/exiting with a non-zero code.

An interrupt signal can be sent to the underlying process via Interrupt().

func NewShellCmd added in v0.4.0

func NewShellCmd(shell, command string, options ...ShellCmdOption) (*ShellCmd, error)

NewShellCmd defaults to using zsh. bash and sh are also supported

func (*ShellCmd) Interrupt added in v0.4.0

func (s *ShellCmd) Interrupt() error

Interrupt will send an interrupt signal to the process

func (*ShellCmd) IsReady added in v0.4.0

func (s *ShellCmd) IsReady() bool

IsReady is a simple getter for the ready state of a monitored command

func (*ShellCmd) Run added in v0.4.0

func (s *ShellCmd) Run() error

Run the underlying command. This function blocks until the command exits

Example (Options)
package main

import (
	"log"

	"github.com/alexchao26/oneterminal/cmdsync"
)

func main() {
	cmd, err := cmdsync.NewShellCmd("bash",
		"echo potato && echo loves $FAV_FOOD",
		cmdsync.Name("monkey"),
		cmdsync.Environment(map[string]string{
			"FAV_FOOD": "cheeseburgers",
		}),
	)
	if err != nil {
		log.Fatal(err)
	}
	err = cmd.Run()
	if err != nil {
		log.Fatal(err)
	}
}
Output:

monkey | potato
monkey | loves cheeseburgers
Example (Simple)
package main

import (
	"log"

	"github.com/alexchao26/oneterminal/cmdsync"
)

func main() {
	cmd, err := cmdsync.NewShellCmd("bash", "echo hello potato")
	if err != nil {
		log.Fatal(err)
	}
	err = cmd.Run()
	if err != nil {
		log.Fatal(err)
	}
}
Output:

hello potato

func (*ShellCmd) RunContext added in v0.4.0

func (s *ShellCmd) RunContext(ctx context.Context) error

RunContext is the same as Run but cancels if the ctx cancels

func (*ShellCmd) Write added in v0.4.0

func (s *ShellCmd) Write(in []byte) (int, error)

Write implements io.Writer, so that ShellCmd itself can be used for exec.ShellCmd.Stdout and Stderr Write "intercepts" writes to Stdout/Stderr to check if the outputs match a regexp and determines if a command has reached its "ready state" the ready state is used by Orchestrator to coordinate dependent commands

type ShellCmdOption added in v0.4.0

type ShellCmdOption func(*ShellCmd) error

func CmdDir

func CmdDir(dir string) ShellCmdOption

CmdDir is a functional option that modifies the Dir property of the underlying exec.ShellCmd which is the directory to execute the Command from

func Color added in v0.4.0

func Color(c color.Color) ShellCmdOption

Color is a functional option that sets the ansiColor for the outputs

func DependsOn

func DependsOn(cmdNames ...string) ShellCmdOption

DependsOn is a functional option that sets a slice of dependencies for this command. The dependencies are names of commands that need to have completed or reached a ready state prior to this command starting.

Note that there is no validation that the cmdNames are valid/match other ShellCmd's configs (because it would cause a circular dependency). Some, but not all possible config errors are checked at runtime.

func Environment

func Environment(envMap map[string]string) ShellCmdOption

Environment is a functional option that adds export commands to the start of a command. This is a bit of a hacky workaround to maintain exec.ShellCmd's default environment, while being able to set additional variables

func Name added in v0.4.0

func Name(name string) ShellCmdOption

Name is a functional option that sets a monitored command's name, which is used to prefix each line written to Stdout

func ReadyPattern

func ReadyPattern(pattern string) ShellCmdOption

ReadyPattern is a functional option that takes in a pattern string that must compile into a valid regexp and sets it to monitored command's readyPattern field

func SilenceOutput

func SilenceOutput() ShellCmdOption

SilenceOutput sets the command's Stdout and Stderr to nil so no output will be seen in the terminal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL