You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

105 lines
2.3 KiB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  1. package process
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "io/ioutil"
  7. "os"
  8. "os/exec"
  9. "time"
  10. . "github.com/tendermint/tendermint/common"
  11. )
  12. type Process struct {
  13. Label string
  14. ExecPath string
  15. Args []string
  16. Pid int
  17. StartTime time.Time
  18. EndTime time.Time
  19. OutputPath string
  20. Cmd *exec.Cmd `json:"-"`
  21. ExitState *os.ProcessState `json:"-"`
  22. OutputFile *AutoFile `json:"-"`
  23. WaitCh chan struct{} `json:"-"`
  24. }
  25. const (
  26. ProcessModeStd = iota
  27. ProcessModeDaemon
  28. )
  29. // execPath: command name
  30. // args: args to command. (should not include name)
  31. func Create(mode int, label string, execPath string, args []string, input string, outPath string) (*Process, error) {
  32. outFile, err := OpenAutoFile(outPath)
  33. if err != nil {
  34. return nil, err
  35. }
  36. cmd := exec.Command(execPath, args...)
  37. switch mode {
  38. case ProcessModeStd:
  39. cmd.Stdout = io.MultiWriter(os.Stdout, outFile)
  40. cmd.Stderr = io.MultiWriter(os.Stderr, outFile)
  41. cmd.Stdin = nil
  42. case ProcessModeDaemon:
  43. cmd.Stdout = outFile
  44. cmd.Stderr = outFile
  45. cmd.Stdin = nil
  46. }
  47. if input != "" {
  48. cmd.Stdin = bytes.NewReader([]byte(input))
  49. }
  50. if err := cmd.Start(); err != nil {
  51. return nil, err
  52. }
  53. proc := &Process{
  54. Label: label,
  55. ExecPath: execPath,
  56. Args: args,
  57. Pid: cmd.Process.Pid,
  58. StartTime: time.Now(),
  59. OutputPath: outPath,
  60. Cmd: cmd,
  61. ExitState: nil,
  62. OutputFile: outFile,
  63. WaitCh: make(chan struct{}),
  64. }
  65. go func() {
  66. err := proc.Cmd.Wait()
  67. if err != nil {
  68. fmt.Printf("Process exit: %v\n", err)
  69. if exitError, ok := err.(*exec.ExitError); ok {
  70. proc.ExitState = exitError.ProcessState
  71. }
  72. }
  73. proc.EndTime = time.Now() // TODO make this goroutine-safe
  74. err = proc.OutputFile.Close()
  75. if err != nil {
  76. fmt.Printf("Error closing output file for %v: %v\n", proc.Label, err)
  77. }
  78. close(proc.WaitCh)
  79. }()
  80. return proc, nil
  81. }
  82. func ReadOutput(proc *Process) string {
  83. output, err := ioutil.ReadFile(proc.OutputPath)
  84. if err != nil {
  85. return fmt.Sprintf("ERROR READING OUTPUT: %v", err)
  86. }
  87. return string(output)
  88. }
  89. func Stop(proc *Process, kill bool) error {
  90. defer proc.OutputFile.Close()
  91. if kill {
  92. fmt.Printf("Killing process %v\n", proc.Cmd.Process)
  93. return proc.Cmd.Process.Kill()
  94. } else {
  95. fmt.Printf("Stopping process %v\n", proc.Cmd.Process)
  96. return proc.Cmd.Process.Signal(os.Interrupt)
  97. }
  98. }