2010-10-31 11 views
13

Escribo un controlador URI gráfico para git: // enlaces con bash y zenity, y estoy usando un cuadro de diálogo zenity 'text-info' para mostrar la salida de clonación de git mientras se ejecuta , utilizando tuberías FIFO. El guión es de aproximadamente 90 líneas de largo, por lo que no se molestará en publicar aquí, pero aquí es las líneas más importantes:git stderr output no pipe

git clone "$1" "$target" 2>&1 | cat >> /tmp/githandler-fifo & 
cat /tmp/githandler-fifo | zenity --text-info --text='Cloning git repository' & 

que estoy usando FIFO en lugar de una tubería directa para permitir que se ejecuten de forma asincrónica y permiten por matar a git si la ventana de zenity está cerrada.

El problema es que la única línea que aparece a partir de la salida de Git es el primero:

Initialized empty Git repository in /home/delan/a/.git/ 

Las otras líneas con contar objetos, etc. no muestran o se muestran en el terminal.

razón actual

El consenso actual de por qué esto no está funcionando parece ser que cat es no bloqueante y se cierra después de la primera línea, sólo el paso, que a Zenity y no el resto. Mi objetivo es forzar el bloqueo de la lectura y hacer que el cuadro de diálogo de texto de zenity muestre todos los resultados de forma progresiva.

git salidas de mensajes de progreso (que no sea el mensaje "iniciada" nada) en stderr, pero en el momento que intento stderr tubería a un archivo o fusionarse con la salida estándar, los mensajes desaparecen.

intento Fix 1

He tratado de escribir dos versiones de bloqueo de funciones de gato en C, pan y bwrite, así:

#include <stdio.h> 
main(int argc, char **argv) { 
    int c; 
    for (;;) { 
     freopen(argv[1], "r", stdin); 
     while ((c = getchar()) != EOF) 
      putchar(c); 
    } 
} 

#include <stdio.h> 
main(int argc, char **argv) { 
    int c; 
    for (;;) { 
     freopen(argv[1], "w", stdout); 
     while ((c = getchar()) != EOF) 
      putchar(c), fputs("writing", stderr); 
    } 
} 

Ellos trabajan muy bien porque bloquean y don 'Salir en EOF, pero aún no ha resuelto el problema. Por el momento, usar uno, el otro o ambos funciona en teoría, pero en la práctica, el zenity no muestra nada ahora.

intento Fix 2

@mvds sugirieron que el uso de un archivo normal, en combinación con tail -f en lugar de cat, puede hacer esto. Sorprendido por una solución tan simple (¡gracias!) Lo intenté, pero desafortunadamente, solo la primera línea apareció en zenity y nada más.

intento Fix 3

Después de hacer algunas strace'ing e inspeccionar el código fuente de Git, que se dan cuenta de que las salidas git toda su información de progreso (cualquier cosa más allá del mensaje "iniciada") en stderr, y el hecho de que esta es la primera línea y mi suposición de que es debido a que el gato dejó de fumar temprano en EOF fue una suposición de coincidencia/equivocada (git no EOF hasta que finaliza el programa).

La situación parecía ser mucho más simple, ya que no debería tener que cambiar nada del código original (al comienzo de la pregunta) y debería funcionar. Misteriosamente, sin embargo, la salida stderr 'desaparece' cuando se redirige, y esto es solo algo que sucede en git.

¿Estuche de prueba?Prueba de esto, y ver si ves algo en el archivo (que no lo hará):

git clone git://anongit.freedesktop.org/xorg/proto/dri2proto 2> hurr 

Esto va en contra de todo lo que sé sobre stderr y la redirección; Incluso he escrito un pequeño programa de C que da salida en stderr y stdout para probarme a mí mismo que la redirección simplemente no funciona para git.

intento Fix 4

De acuerdo con la respuesta de Jakub Narębski, así como las respuestas a mensajes de correo electrónico que he enviado a la lista de correo de git, --progress es la opción que necesito. Tenga en cuenta que esta opción solo funciona después del comando, y no antes de clone.

¡Éxito!

Muchas gracias por toda su ayuda. Esta es la línea fija:

git clone "$1" "$target" --progress > /tmp/githandler-fifo 2>&1 & 

+1

Dios mío ... me has salvado la vida .... ha tenido el mismo problema – KnF

+0

¡Éxito! Gracias por eso. --progreso fue la pieza que faltaba del rompecabezas para mí. – Form

Respuesta

18

Creo que al menos algunos de los informes de progreso se silencian cuando la salida es no es un terminal (tty). No estoy seguro de si se aplica a su caso, pero intente pasar la opción --progress a 'git clone' (es decir, use git clone --progress <repository>).

Aunque no sé si es lo que quería tener.

+0

Sospecho que podría ser. También es fácil de probar: solo redirija a un archivo normal en lugar de un FIFO y toque hasta que sepa que tiene el resultado que desea. – Cascabel

+0

Desafortunadamente, git genera "Opción desconocida: --progreso", luego un salto de línea, luego el resumen de sintaxis/uso. Curiosamente, esta vez, todo se imprime en zenity, y el FIFO funciona. Además, las salidas de git son totalmente válidas para un archivo; es probable que las lecturas sin bloqueo de zenity sean las culpables. –

+0

@Delan: Ah, entonces esto no. (En cuanto a la opción '--progress', presumiblemente eso significa que estás usando una versión de git demasiado vieja - esa característica se agregó en v1.7.1.) – Cascabel

6

Por un lado, la redirección de la salida se analiza de derecha a izquierda, por lo

git clone "$1" "$target" 2>&1 > /tmp/githandler-fifo & 

no es igual a

git clone "$1" "$target" > /tmp/githandler-fifo 2>&1 & 

Este último redireccionará stderr a stdout, y luego stdout (incluido stderr) al archivo. El primero redireccionará stdout al archivo y luego mostrará stderr en stdout.

En cuanto a la tubería de zenity (que no sé), creo que puede estar haciendo las cosas demasiado complicadas con la tubería con nombre. El uso de strace puede arrojar algo de luz sobre el funcionamiento interno de los procesos que está activando. Para los inexpertos, las tuberías nombradas empeoran las cosas en comparación con las tuberías normales.

+0

Estoy usando un tubo con nombre por el mero propósito de poder hacer un fondo de git y zenity, lo que me permite comprobar si zenity ha dejado de funcionar antes de git, y matar a git si eso sucede. Gracias por informarme sobre el análisis de redirección de derecha a izquierda. Lo he intentado, pero no soluciona el problema aquí. Ahora, la primera línea aparece en zenity, y el resto no se muestra en ninguna parte (ni siquiera en la terminal). –

+0

como una alternativa con menos complicaciones, es posible que desee redireccionar a un archivo y luego pipe 'tail -f'. Esto evita problemas típicos de tuberías con nombre. – mvds

+2

Con respecto a la ejecución de redirección de derecha a izquierda, esto es simplemente ** incorrecto **. Las redirecciones se ejecutan en orden natural. Las redirecciones '2> & 1> archivo' se manejan de la siguiente manera: después de la primera redirección, fd 2 apunta al mismo archivo que fd 1 (es decir, qué fue stdout, por ejemplo, la terminal). Después de la segunda redirección, fd 1 apunta al 'archivo', y fd 2 todavía apunta al terminal, porque la redirección se realizó * antes de que * fd 1 cambiara. –

1

Dado el experimento con el FIFO llamado 'a', creo que el problema radica en la forma en que zenity procesa su entrada. ¿Qué sucede si escribe en zenity desde el teclado? (Sospecha: se comporta como lo desearía, leyendo a EOF). Sin embargo, podría ser que zenity maneje la entrada del terminal (entrada tty) usando E/S de bloqueo regular, pero usa E/S sin bloqueo para todos los demás tipos de dispositivos. La E/S sin bloqueo está bien para la entrada de archivos; es menos deseable para la entrada de tuberías o FIFO, etc. Si utilizara E/S sin bloqueo, zenity obtendría la primera línea de salida, y luego saldría del bucle pensando que estaba hecho porque su segundo intento de lectura indicaría que no había nada más disponible de inmediato.

Demostrar que esto es lo que está sucediendo (o no) será complicado. Yo buscaría 'truss' o 'strace' u otro monitor de llamada al sistema para rastrear lo que está haciendo zenity.

En cuanto a soluciones ...si la hipótesis es correcta, deberá persuadir al zenity de que está leyendo desde un terminal y no desde un FIFO, por lo que probablemente necesite instalar un pseudo-tty (o pty); el primer proceso escribiría en el extremo maestro de la pty y usted se encargaría de leer el zenity desde el extremo esclavo de la pty. También podría usar el FIFO también, aunque tenga una larga cadena de comando.