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.

92 lines
2.0 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
9 years ago
9 years ago
9 years ago
  1. package process
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "os"
  7. "os/exec"
  8. "time"
  9. )
  10. func makeFile(prefix string) (string, *os.File) {
  11. now := time.Now()
  12. path := fmt.Sprintf("%v_%v.out", prefix, now.Format("2006_01_02_15_04_05_MST"))
  13. file, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
  14. if err != nil {
  15. panic(err)
  16. }
  17. return path, file
  18. }
  19. type Process struct {
  20. Label string
  21. ExecPath string
  22. Pid int
  23. StartTime time.Time
  24. EndTime time.Time
  25. OutputPath string
  26. Cmd *exec.Cmd `json:"-"`
  27. ExitState *os.ProcessState `json:"-"`
  28. OutputFile *os.File `json:"-"`
  29. WaitCh chan struct{} `json:"-"`
  30. }
  31. const (
  32. ProcessModeStd = iota
  33. ProcessModeDaemon
  34. )
  35. // execPath: command name
  36. // args: args to command. (should not include name)
  37. func Create(mode int, label string, execPath string, args []string, input string) (*Process, error) {
  38. outPath, outFile := makeFile(label)
  39. cmd := exec.Command(execPath, args...)
  40. switch mode {
  41. case ProcessModeStd:
  42. cmd.Stdout = io.MultiWriter(os.Stdout, outFile)
  43. cmd.Stderr = io.MultiWriter(os.Stderr, outFile)
  44. cmd.Stdin = nil
  45. case ProcessModeDaemon:
  46. cmd.Stdout = outFile
  47. cmd.Stderr = outFile
  48. cmd.Stdin = nil
  49. }
  50. if input != "" {
  51. cmd.Stdin = bytes.NewReader([]byte(input))
  52. }
  53. if err := cmd.Start(); err != nil {
  54. return nil, err
  55. }
  56. proc := &Process{
  57. Label: label,
  58. ExecPath: execPath,
  59. Pid: cmd.Process.Pid,
  60. StartTime: time.Now(),
  61. OutputPath: outPath,
  62. Cmd: cmd,
  63. ExitState: nil,
  64. OutputFile: outFile,
  65. WaitCh: make(chan struct{}),
  66. }
  67. go func() {
  68. err := proc.Cmd.Wait()
  69. if err != nil {
  70. fmt.Printf("Process exit: %v\n", err)
  71. if exitError, ok := err.(*exec.ExitError); ok {
  72. proc.ExitState = exitError.ProcessState
  73. }
  74. }
  75. proc.EndTime = time.Now() // TODO make this goroutine-safe
  76. close(proc.WaitCh)
  77. }()
  78. return proc, nil
  79. }
  80. func Stop(proc *Process, kill bool) error {
  81. if kill {
  82. return proc.Cmd.Process.Kill()
  83. } else {
  84. return proc.Cmd.Process.Signal(os.Interrupt)
  85. }
  86. }