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