PageRenderTime 54ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/tmp/cmdctrl/lib/cmdctrl/commands/command.rb

https://github.com/oiegorov/expo_improved
Ruby | 130 lines | 84 code | 16 blank | 30 comment | 19 complexity | 7c89c0b4558e894d784e23f072272535 MD5 | raw file
  1. =begin
  2. Copyright (C) 2007 Brice Videau
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License along
  12. with this program; if not, write to the Free Software Foundation, Inc.,
  13. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  14. =end
  15. require 'thread'
  16. require 'date'
  17. module CmdCtrl
  18. module Commands
  19. # Container class representing a command to run or running
  20. class Command
  21. # File descriptors
  22. attr_reader :stdin, :stdout, :stderr
  23. # Command lauched
  24. attr_reader :cmd
  25. # PID of command
  26. attr_reader :pid
  27. # Exit status of command
  28. attr_reader :status
  29. # Creates a command using either a command line to execute or a block
  30. def initialize(cmd = nil, &block)
  31. @cmd = cmd
  32. @block = block
  33. raise "No command nor block passed to Command::new" if @cmd.nil? and @block.nil?
  34. raise "command and block passed to Command::new" if not (@cmd.nil? or @block.nil?)
  35. @status = nil
  36. @pid = nil
  37. end
  38. # Runs the created command
  39. def run
  40. @mystdin, @stdin = IO::pipe
  41. @stdout, @mystdout = IO::pipe
  42. @stderr, @mystderr = IO::pipe
  43. @pid = fork do
  44. close_fds
  45. @mystdout.sync = true
  46. @mystderr.sync = true
  47. STDIN.reopen(@mystdin)
  48. STDOUT.reopen(@mystdout)
  49. STDERR.reopen(@mystderr)
  50. if @cmd
  51. exec(cmd)
  52. else # use the block
  53. v = @block.call
  54. if v.kind_of?(Integer)
  55. exit(v)
  56. else
  57. exit(0)
  58. end
  59. end
  60. end
  61. close_internal_fds
  62. @pid
  63. end
  64. def kill( signal )
  65. raise "Command is not running!" if @pid.nil?
  66. Process::kill( signal, @pid ) if not exited?
  67. end
  68. # Waits for the command to exit end returns [ pid, status ]
  69. def wait
  70. raise "Command is not running!" if @pid.nil?
  71. if not @status
  72. result = Process::waitpid2(@pid)
  73. pid, @status = result
  74. end
  75. [@pid,@status]
  76. end
  77. # Checks if the command exited, returns nil if not and [ pid, status ] if yes
  78. def wait_no_hang
  79. raise "Command is not running!" if @pid.nil?
  80. if not @status
  81. result = Process::waitpid2(@pid,Process::WNOHANG)
  82. if result
  83. pid, @status = result
  84. end
  85. return result
  86. else
  87. [@pid,@status]
  88. end
  89. end
  90. # Returns true if the command exited false unless
  91. def exited?
  92. return wait_no_hang != nil
  93. end
  94. # Close file descriptors. You need to call this when you have finished
  95. # reading all pending data.
  96. def close_fds
  97. @stdin.close unless @stdin.closed? or @stdin == STDIN
  98. @stdout.close unless @stdout.closed? or @stdout == STDOUT
  99. @stderr.close unless @stderr.closed? or @stderr == STDERR
  100. end
  101. private
  102. # Closes the open file descriptors
  103. def close_internal_fds
  104. @mystdin.close unless @mystdin.closed? or @mystdin == STDIN
  105. @mystdout.close unless @mystdout.closed? or @mystdout == STDOUT
  106. @mystderr.close unless @mystderr.closed? or @mystderr == STDERR
  107. self
  108. end
  109. end
  110. end
  111. end