github.com/informationsea/shellflow@v0.1.3/execute_local_single.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os"
     7  	"os/exec"
     8  	"path"
     9  	"syscall"
    10  )
    11  
    12  var localRunPidFile = "local-run-pid.txt"
    13  
    14  type executationError struct {
    15  	message   string
    16  	exitCode  int
    17  	jobRoot   string
    18  	shellTask *ShellTask
    19  }
    20  
    21  func (s *executationError) Error() string {
    22  	return s.message
    23  }
    24  
    25  func IsExecutionError(err error) bool {
    26  	_, ok := err.(*executationError)
    27  	return ok
    28  }
    29  
    30  func FollowUpLocalSingle(jobLogRoot string) (bool, error) {
    31  	rc, err := os.Open(path.Join(jobLogRoot, "rc"))
    32  	if err == nil {
    33  		defer rc.Close()
    34  		return false, nil
    35  	} else if os.IsNotExist(err) {
    36  		pidFile, err := os.Open(path.Join(jobLogRoot, localRunPidFile))
    37  		if err == nil {
    38  			var pid int
    39  			i, err := fmt.Fscanf(pidFile, "%d", &pid)
    40  			if err != nil {
    41  				return false, err
    42  			}
    43  			if i != 1 {
    44  				return false, fmt.Errorf("Cannot read pid: %d", i)
    45  			}
    46  			process, err := os.FindProcess(pid)
    47  			if err != nil {
    48  				return false, err
    49  			}
    50  			err = process.Signal(syscall.Signal(0))
    51  			if err != nil {
    52  				rc, err = os.OpenFile(path.Join(jobLogRoot, "rc"), os.O_CREATE|os.O_WRONLY, 0644)
    53  				if err != nil {
    54  					return false, err
    55  				}
    56  				defer rc.Close()
    57  				_, err = fmt.Fprintf(rc, "1000")
    58  				if err != nil {
    59  					return false, err
    60  				}
    61  			}
    62  			return true, nil
    63  		} else if os.IsNotExist(err) {
    64  			return false, nil
    65  		} else {
    66  			return false, err
    67  		}
    68  	} else {
    69  		return false, err
    70  	}
    71  }
    72  
    73  // ExecuteLocalSingle runs tasks in local machine and single thread
    74  func ExecuteLocalSingle(ge *TaskScripts) error {
    75  	originalWorkDir, err := os.Getwd()
    76  	if err != nil {
    77  		return err
    78  	}
    79  	err = os.Chdir(ge.env.workDir)
    80  	if err != nil {
    81  		return err
    82  	}
    83  	defer os.Chdir(originalWorkDir)
    84  
    85  	var finalErr error
    86  
    87  	for _, v := range ge.builder.Tasks {
    88  		if finalErr != nil {
    89  			scriptInfo := ge.scripts[v.ID]
    90  			rc, err := os.OpenFile(path.Join(scriptInfo.JobRoot, "rc"), os.O_CREATE|os.O_WRONLY, 0644)
    91  			if err != nil {
    92  				return err
    93  			}
    94  			defer rc.Close()
    95  			fmt.Fprintf(rc, "2000")
    96  			continue
    97  		}
    98  
    99  		if v.ShouldSkip {
   100  			fmt.Printf("skipping: %s\n", v.ShellScript)
   101  			continue
   102  		}
   103  
   104  		err := ExecuteLocalSingleOneTask(ge, v)
   105  		if err != nil {
   106  			finalErr = err
   107  		}
   108  	}
   109  
   110  	return finalErr
   111  }
   112  
   113  func ExecuteLocalSingleOneTask(ge *TaskScripts, v *ShellTask) error {
   114  	scriptInfo := ge.scripts[v.ID]
   115  	args := []string{scriptInfo.RunScriptPath}
   116  
   117  	fmt.Printf("%s\n", v.ShellScript)
   118  
   119  	cmd := exec.Command("/bin/bash", args...)
   120  
   121  	stdout, err := os.OpenFile(path.Join(scriptInfo.JobRoot, "run.stdout"), os.O_CREATE|os.O_WRONLY, 0644)
   122  	if err != nil {
   123  		return err
   124  	}
   125  	defer stdout.Close()
   126  
   127  	stderr, err := os.OpenFile(path.Join(scriptInfo.JobRoot, "run.stderr"), os.O_CREATE|os.O_WRONLY, 0644)
   128  	if err != nil {
   129  		return err
   130  	}
   131  	defer stderr.Close()
   132  
   133  	pid, err := os.OpenFile(path.Join(scriptInfo.JobRoot, localRunPidFile), os.O_CREATE|os.O_WRONLY, 0644)
   134  	if err != nil {
   135  		return err
   136  	}
   137  	defer pid.Close()
   138  
   139  	stdoutPipe, err := cmd.StdoutPipe()
   140  	if err != nil {
   141  		return err
   142  	}
   143  
   144  	stderrPipe, err := cmd.StderrPipe()
   145  	if err != nil {
   146  		return err
   147  	}
   148  
   149  	err = cmd.Start()
   150  	if err != nil {
   151  		return err
   152  	}
   153  
   154  	if _, err = fmt.Fprintf(pid, "%d", cmd.Process.Pid); err != nil {
   155  		return err
   156  	}
   157  
   158  	if _, err = io.Copy(stdout, stdoutPipe); err != nil {
   159  		return err
   160  	}
   161  
   162  	if _, err = io.Copy(stderr, stderrPipe); err != nil {
   163  		return err
   164  	}
   165  
   166  	if err = cmd.Wait(); err != nil {
   167  		exitCode := 1000
   168  		status, ok := cmd.ProcessState.Sys().(syscall.WaitStatus)
   169  		if ok {
   170  			exitCode = status.ExitStatus()
   171  		}
   172  
   173  		return &executationError{
   174  			message:   fmt.Sprintf("exit status %d: %s", exitCode, scriptInfo.RunScriptPath),
   175  			exitCode:  exitCode,
   176  			jobRoot:   scriptInfo.JobRoot,
   177  			shellTask: v,
   178  		}
   179  	}
   180  
   181  	return nil
   182  }