Added parallel computing V2
parent
2195674c08
commit
dfdb8f0c50
|
@ -20,12 +20,15 @@ import "os"
|
|||
import "os/exec"
|
||||
|
||||
func main() {
|
||||
err := shelly.Exec(`
|
||||
_, err := shelly.Exec(`
|
||||
ls -larth &
|
||||
pwd &
|
||||
whoami
|
||||
date`, &shelly.Opts{
|
||||
date`,
|
||||
&shelly.Opts{
|
||||
Await: false,
|
||||
Wd: ".",
|
||||
Debug: true,
|
||||
SetupProc: func(cmd *exec.Cmd) {
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
|
106
lib.go
106
lib.go
|
@ -4,10 +4,11 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Mode int
|
||||
|
@ -40,13 +41,16 @@ const (
|
|||
LINETYPE_SERIAL LineType = iota
|
||||
LINETYPE_PARALLEL
|
||||
LINETYPE_COMMENT
|
||||
LINETYPE_CHANGEWD
|
||||
)
|
||||
|
||||
// Opts tells Exec how to behave
|
||||
// Opts.Await will inform whether its call should wait for all parallel started jobs to finish
|
||||
// Opts.SetupProc will customize the processes before execution - Eg.: setting out and err
|
||||
type Opts struct {
|
||||
Debug bool
|
||||
Await bool
|
||||
Wd string
|
||||
SetupProc func(cmd *exec.Cmd)
|
||||
}
|
||||
|
||||
|
@ -158,28 +162,32 @@ func Lines(str string) ([]Line, error) {
|
|||
Tokens: make([]string, 0),
|
||||
LType: LINETYPE_SERIAL,
|
||||
}
|
||||
for _, tk := range tokens {
|
||||
switch tk {
|
||||
case "\n", ";":
|
||||
if len(line.Tokens) > 0 {
|
||||
|
||||
addLine := func(line Line) {
|
||||
if strings.HasPrefix(line.Tokens[0], "#") {
|
||||
line.LType = LINETYPE_COMMENT
|
||||
} else {
|
||||
line.LType = LINETYPE_SERIAL
|
||||
}
|
||||
|
||||
if line.Tokens[0] == "cd" {
|
||||
line.LType = LINETYPE_CHANGEWD
|
||||
}
|
||||
|
||||
ret = append(ret, line)
|
||||
}
|
||||
|
||||
for _, tk := range tokens {
|
||||
switch tk {
|
||||
case "\n", ";", "&&":
|
||||
if len(line.Tokens) > 0 {
|
||||
addLine(line)
|
||||
}
|
||||
line = Line{
|
||||
Tokens: make([]string, 0),
|
||||
}
|
||||
case "&":
|
||||
if len(line.Tokens) > 0 {
|
||||
if strings.HasPrefix(line.Tokens[0], "#") {
|
||||
line.LType = LINETYPE_COMMENT
|
||||
} else {
|
||||
line.LType = LINETYPE_PARALLEL
|
||||
}
|
||||
ret = append(ret, line)
|
||||
addLine(line)
|
||||
}
|
||||
line = Line{
|
||||
Tokens: make([]string, 0),
|
||||
|
@ -189,15 +197,26 @@ func Lines(str string) ([]Line, error) {
|
|||
}
|
||||
}
|
||||
if len(line.Tokens) > 0 {
|
||||
ret = append(ret, line)
|
||||
addLine(line)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// Exec will call Lines and execute one by one
|
||||
func Exec(str string, opts ...*Opts) error {
|
||||
func Exec(str string, opts ...*Opts) ([]*exec.Cmd, error) {
|
||||
wd, err := os.Getwd()
|
||||
|
||||
var opt *Opts
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := make([]*exec.Cmd, 0)
|
||||
opt := &Opts{
|
||||
Await: false,
|
||||
Wd: wd,
|
||||
SetupProc: func(cmd *exec.Cmd) {
|
||||
|
||||
},
|
||||
}
|
||||
if opts != nil && len(opts) > 0 {
|
||||
opt = opts[0]
|
||||
}
|
||||
|
@ -208,47 +227,74 @@ func Exec(str string, opts ...*Opts) error {
|
|||
}
|
||||
}
|
||||
|
||||
cmdwd := opt.Wd
|
||||
|
||||
prepCmd := func(l Line) *exec.Cmd {
|
||||
cmd := exec.Command(l.Tokens[0], l.Tokens[1:]...)
|
||||
cmd.Stdout = log.Writer()
|
||||
cmd.Stderr = log.Writer()
|
||||
cmd.Dir = cmdwd
|
||||
opt.SetupProc(cmd)
|
||||
ret = append(ret, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
lines, err := Lines(str)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
return ret, err
|
||||
}
|
||||
for _, l := range lines {
|
||||
|
||||
switch l.LType {
|
||||
case LINETYPE_COMMENT:
|
||||
continue
|
||||
case LINETYPE_CHANGEWD:
|
||||
|
||||
if filepath.IsAbs(l.Tokens[1]) {
|
||||
cmdwd = l.Tokens[1]
|
||||
} else {
|
||||
cmdwd, err = filepath.Abs(filepath.Join(wd, l.Tokens[1]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
log.Printf("CMDWD NOW IS: %s", cmdwd)
|
||||
continue
|
||||
case LINETYPE_SERIAL:
|
||||
cmd := prepCmd(l)
|
||||
if opt.Debug {
|
||||
log.Printf("Running %s from dir %s with params %v", cmd.Path, cmd.Dir, cmd.Args)
|
||||
}
|
||||
err = cmd.Run()
|
||||
if opt.Debug {
|
||||
if err != nil {
|
||||
return err
|
||||
log.Printf("Error running: %s: %s", cmd.Path, err.Error())
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
case LINETYPE_PARALLEL:
|
||||
go func(l Line) {
|
||||
cmd := prepCmd(l)
|
||||
wg.Add(1)
|
||||
err = cmd.Run()
|
||||
wg.Done()
|
||||
}(l)
|
||||
|
||||
if opt.Debug {
|
||||
log.Printf("Running %s from dir %s with params %v", cmd.Path, cmd.Dir, cmd.Args)
|
||||
}
|
||||
err = cmd.Start()
|
||||
if opt.Debug {
|
||||
if err != nil {
|
||||
log.Printf("Error running: %s: %s", cmd.Path, err.Error())
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if opt.Await {
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
return nil
|
||||
return ret, err
|
||||
|
||||
}
|
||||
|
||||
|
@ -256,9 +302,11 @@ func Exec(str string, opts ...*Opts) error {
|
|||
func Kill(p int) error {
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
return Exec(fmt.Sprintf("taskkill /T /F /PID %d", p))
|
||||
_, err := Exec(fmt.Sprintf("taskkill /T /F /PID %d", p))
|
||||
return err
|
||||
default:
|
||||
return Exec(fmt.Sprintf("kill -9 %d", p))
|
||||
_, err := Exec(fmt.Sprintf("kill -9 %d", p))
|
||||
return err
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ func TestLines(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestExec(t *testing.T) {
|
||||
err := Exec(`
|
||||
_, err := Exec(`
|
||||
ls -larth &
|
||||
pwd &
|
||||
whoami &
|
||||
|
|
Loading…
Reference in New Issue