選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

124 行
3.0 KiB

  1. // Copyright 2012 Xing Xing <mikespook@gmail.com>.
  2. // All rights reserved.
  3. // Use of this source code is governed by a commercial
  4. // license that can be found in the LICENSE file.
  5. package main
  6. import (
  7. "io"
  8. "bytes"
  9. "os/exec"
  10. "encoding/json"
  11. "github.com/mikespook/golib/log"
  12. "github.com/mikespook/gearman-go/worker"
  13. )
  14. type outData struct {
  15. Numerator, Denominator int
  16. Warning bool
  17. Data []byte
  18. Debug string
  19. }
  20. type ShExec struct {
  21. Name, basedir string
  22. Args []string
  23. *exec.Cmd
  24. job *worker.Job
  25. Logger *log.Logger
  26. }
  27. func NewShExec(basedir string, job *worker.Job) (sh *ShExec, err error) {
  28. sh = &ShExec{
  29. basedir: basedir,
  30. job: job,
  31. Args: make([]string, 0),
  32. }
  33. if err = sh.parse(job.Data); err != nil {
  34. return nil, err
  35. }
  36. return
  37. }
  38. func (sh *ShExec) parse(data []byte) (err error) {
  39. if err = json.Unmarshal(data, sh); err != nil {
  40. return
  41. }
  42. return
  43. }
  44. func (sh *ShExec) Append(args ... string) {
  45. sh.Args = append(sh.Args, args ...)
  46. }
  47. func (sh *ShExec) Prepend(args ... string) {
  48. sh.Args = append(args, sh.Args ...)
  49. }
  50. func (sh *ShExec) Exec() (rslt []byte, err error){
  51. sh.Logger.Debugf("Executing: Handle=%s, Exec=%s, Args=%v",
  52. sh.job.Handle, sh.Name, sh.Args)
  53. sh.Cmd = exec.Command(sh.Name, sh.Args ... )
  54. go func() {
  55. if ok := <-sh.job.Canceled(); ok {
  56. sh.Cmd.Process.Kill()
  57. }
  58. }()
  59. sh.Cmd.Dir = sh.basedir
  60. var buf bytes.Buffer
  61. sh.Cmd.Stdout = &buf
  62. var errPipe io.ReadCloser
  63. if errPipe, err = sh.Cmd.StderrPipe(); err != nil {
  64. return nil, err
  65. }
  66. defer errPipe.Close()
  67. go sh.processErr(errPipe)
  68. if err = sh.Cmd.Run(); err != nil {
  69. return nil, err
  70. }
  71. rslt = buf.Bytes()
  72. return
  73. }
  74. func (sh *ShExec) processErr(pipe io.ReadCloser) {
  75. result := make([]byte, 1024)
  76. var more []byte
  77. for {
  78. n, err := pipe.Read(result)
  79. if err != nil {
  80. if err != io.EOF {
  81. sh.job.UpdateData([]byte(err.Error()), true)
  82. }
  83. return
  84. }
  85. if more != nil {
  86. result = append(more, result[:n]...)
  87. } else {
  88. result = result[:n]
  89. }
  90. if n < 1024 {
  91. var out outData
  92. if err := json.Unmarshal(result, &out); err != nil {
  93. sh.job.UpdateData([]byte(result), true)
  94. return
  95. }
  96. if out.Debug == "" {
  97. if out.Data != nil {
  98. sh.job.UpdateData(out.Data, out.Warning)
  99. }
  100. if out.Numerator != 0 || out.Denominator != 0 {
  101. sh.job.UpdateStatus(out.Numerator, out.Denominator)
  102. }
  103. } else {
  104. sh.Logger.Debugf("Debug: Handle=%s, Exec=%s, Args=%v, Data=%s",
  105. sh.job.Handle, sh.Name, sh.Args, out.Debug)
  106. }
  107. more = nil
  108. } else {
  109. more = result
  110. }
  111. }
  112. }