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.

94 lines
2.1 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 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. fmt.Printf("Killing process %v\n", proc.Cmd.Process)
  83. return proc.Cmd.Process.Kill()
  84. } else {
  85. fmt.Printf("Stopping process %v\n", proc.Cmd.Process)
  86. return proc.Cmd.Process.Signal(os.Interrupt)
  87. }
  88. }