2012-04-19 11 views
12

Estoy escribiendo un código que toma un archivo, pasa ese archivo a uno de varios binarios para su procesamiento y supervisa el proceso de conversión para detectar errores. He escrito y probado la siguiente rutina en OSX, pero Linux falla por razones sobre las cuales no estoy seguro.Ruby en Linux PTY desaparece sin EOF, aumenta Errno :: EIO

#run the command, capture the output so it doesn't display 
PTY.spawn(command) {|r,w,pid| 
    until r.eof? do 
     ##mark 
     puts r.readline 
    end 
} 

El comando que se ejecuta varía mucho y el código en la marca de ## se ha simplificado en un eco local en un intento de depurar el problema. El comando se ejecuta y el script imprime el resultado esperado en el terminal y luego lanza una excepción.

El error se produce en sistemas Debian es: Errno::EIO (Input/output error - /dev/pts/0):

Todas las cadenas de comandos que puede llegar a producir ese error, y cuando corro el código sin el bloque de eco local que funciona muy bien:

PTY.spawn(command) {|r,w,pid|} 

En cualquier caso, el comando se ejecuta correctamente, pero parece que debian linux no está enviando eof hasta el pty. Las páginas de doc para PTY y IO en ruby-doc no parecen prestar ninguna ayuda aquí.

¿Alguna sugerencia? Gracias.

-vox-

+0

Esto es solo una suposición, pero ¿las readlines están compiladas correctamente en la versión Debian ruby? Si ese es el problema y utiliza rvm, sus notas sobre el problema pueden ser de ayuda: [http://beginrescueend.com/packages/readline/] (http://beginrescueend.com/packages/readline/) – forforf

+0

Eso es un buen pensamiento. No estoy usando rvm en esos servidores, pero sí compilé ruby1.9.3 desde el origen (y en otro servidor 1.9.2). No había considerado que cambiar la readline lib podría ordenarlo. Gracias por la sugerencia. – voxobscuro

+0

libreadline está relacionado con la edición de línea de comandos, historial, etc. (por ejemplo, en irb). No afecta el método IO # readline. Puede compilar Ruby sin soporte de libreadline e IO funcionará como se espera (pero irb será desagradable de usar). –

Respuesta

15

Así que tuve que ir tan lejos como para leer la fuente C de la biblioteca PTY para estar realmente satisfecho con lo que está sucediendo aquí.

El documento Ruby PTY en realidad no dice lo que dicen los comentarios in the source code.

Mi solución fue armar un método envoltorio y llamarlo desde mi script donde sea necesario. También he encasillados en el método de espera en el proceso para asegurarse de salida y el Acceso del estado de salida de $?:

# file: lib/safe_pty.rb 

require 'pty' 
module SafePty 
    def self.spawn command, &block 

    PTY.spawn(command) do |r,w,p| 
     begin 
     yield r,w,p 
     rescue Errno::EIO 
     ensure 
     Process.wait p 
     end 
    end 

    $?.exitstatus 
    end 
end 

Esto se utiliza básicamente el mismo que PTY.spawn:

require 'safe_pty' 
exit_status = SafePty.spawn(command) do |r,w,pid| 
    until r.eof? do 
    logger.debug r.readline 
    end 
end 

#test exit_status for zeroness 

Estaba más que un poco frustrado al descubrir que esta es una respuesta válida, ya que estaba completamente indocumentada en ruby-doc.

+0

Interesante. Al navegar por el src, me encontré con esto en los comentarios para pty_open: "El resultado de la operación de lectura cuando pty slave está cerrado depende de la plataforma". Eso también está en el rdoc, pero me lo perdí. –

+0

@RichDrummond Sí, ese es el comentario del que estaba hablando. También me lo perdí en el rdoc, pero eso es porque estaba mirando las notas para .spawn y no realmente nada más. : - / – voxobscuro

5

Parece válida para Errno :: EEI que se planteó aquí (esto simplemente significa que el proceso hijo ha terminado y cerrado la corriente), por lo que debe esperar eso y atraparlo.

Por ejemplo, ver la respuesta seleccionada en Continuously read from STDOUT of external process in Ruby y http://www.shanison.com/2010/09/11/ptychildexited-exception-and-ptys-exit-status/

Por cierto, hice algunas pruebas. En Ruby 1.8.7 en Ubuntu 10.04, no obtengo un error. Con Ruby 1.9.3, lo hago. Con JRuby 1.6.4 en Ubuntu en los modos 1.8 y 1.9, no me da error. En OS X, con 1.8.7, 1.9.2 y 1.9.3, no obtengo un error. El comportamiento depende obviamente de su versión y plataforma de Ruby.

+0

Bounty premiada por ser la única persona que tenía idea de lo que estaba hablando! Si no hubiera descubierto la solución en la fuente C unos 15 minutos antes de publicar esto, estoy bastante seguro de que me hubiera llevado a eso de todos modos. ¡Aclamaciones! – voxobscuro

Cuestiones relacionadas