Pergunta

Estou escrevendo um manipulador de URI gráfico para o Git: // Links com Bash e Zenity, e estou usando uma caixa de diálogo 'Text-Info' da Zenity para mostrar a saída do clone do Git enquanto estiver em execução, usando a tubulação FIFO. O script tem cerca de 90 linhas de comprimento, então não vou me incomodar em postá -lo aqui, mas aqui estão as linhas mais importantes:

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

Estou usando o FIFO em vez de um tubo direto para permitir que eles funcionem de forma assíncrona e permitam matar o Git se a janela da zenidade estiver fechada.

O problema é que a única linha que aparece na saída do Git é a primeira:

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

As outras linhas com objetos de contagem, etc. não mostram ou são mostrados no terminal.

Razão atual

O consenso atual sobre por que isso não está funcionando parece ser isso cat é não bloqueando e desiste após a primeira linha, passando apenas para a zenidade e não o resto. Meu objetivo é forçar o bloqueio da leitura e fazer com que a caixa de diálogo Informações sobre texto da Zenity mostre toda a saída progressivamente.

git Saídas Mensagens de progresso (qualquer coisa que não sejam a mensagem "Inicializada") no Stderr, mas no momento em que tento canalizar o stderr em um arquivo ou se fundir com o stdout, as mensagens desaparecem.

Corrigir tentativa 1

Eu tentei escrever duas versões de bloqueio das funções do CAT em C, Bread and Bwrite, como este:

#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);
    }
}

Eles funcionam bem porque bloqueiam e não desistem do EOF, mas ainda não resolveu o problema. No momento, usando um, o outro ou ambos, trabalha em teoria, mas na prática, a zenidade não mostra nada agora.

Corrigir tentativa 2

@mvds sugeriram que o uso de um arquivo regular, em combinação com tail -f ao invés de cat, pode fazer isso. Surpreso com uma solução tão simples (obrigado!) Eu tentei, mas infelizmente, apenas a primeira linha apareceu na zenidade e nada mais.

Corrigir tentativa 3

Depois de fazer alguns strace'ing e inspecionar o código -fonte do Git, percebo que o Git gera todas as suas informações de progresso (qualquer coisa após a mensagem "inicializada") no Stderr, e o fato de que essa é a primeira linha e minha suposição de que é por causa do gato Parar cedo no EOF foi uma suposição de coincidência/equivocada (o Git não é EOF até o término do programa).

A situação parecia se tornar muito mais simples, pois não deveria mudar nada do código original (no início da pergunta) e deve funcionar. Misteriosamente, no entanto, a saída Stderr 'desaparece' quando redirecionada - e isso é apenas algo que acontece no Git.

Caso de teste? Experimente isso e veja se você vê alguma coisa no arquivo (você não fará):

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

Isso vai contra tudo o que sei sobre Stderr e Redirection; Eu até escrevi um pequeno programa C que sai no Stderr e no Stdout para provar a mim mesmo que o redirecionamento simplesmente não funciona para o Git.

Corrigir tentativa 4

De acordo com a resposta de Jakub Narębski, bem como as respostas aos e -mails que enviei para a lista de discussão Git, --progress é a opção de que preciso. Observe que esta opção só funciona após o comando, e não antes clone.

Sucesso!

Muito obrigado por toda sua ajuda. Esta é a linha fixa:

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

Foi útil?

Solução

Eu acho que pelo menos alguns dos relatórios de progresso são silenciados quando a saída é não é um terminal (tty). Não tenho certeza se isso se aplica ao seu caso, mas tente passar --progress opção para 'clone git' (ou seja, use git clone --progress <repository>).

Embora eu não saiba se é o que você queria ter.

Outras dicas

Por um lado, o redirecionamento da saída é analisado da direita para a esquerda, então

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

não é igual a

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

Este último redirecionará o stderr para o stdout e, em seguida, stdout (incluindo stderr) para o arquivo. O primeiro redirecionará o stdout para o arquivo e, em seguida, mostrará o Stderr no stdout.

Quanto à tubulação para zenity (o que eu não sei), acho que você pode estar tornando as coisas excessivamente complicadas com o tubo nomeado. Usando strace Pode lançar alguma luz sobre o funcionamento interno dos processos que você está atirando. Para os inexperientes, os tubos nomeados pioram as coisas em comparação com os tubos normais.

Dado o experimento com o FIFO chamado 'A', acho que o problema está na maneira como a zenidade processa sua entrada. O que acontece se você digitar a zenidade do teclado? (Suspeita: ele se comporta como você gostaria, lendo para o EOF.) No entanto, pode ser que a zenidade lida com a entrada do terminal (entrada TTY) usando a E/S de bloqueio regular, mas use E/S não bloqueador para todos os outros tipos de dispositivos. A E/S não bloqueadora é boa para entrada de arquivos; É menos desejável para a entrada de tubos ou fifos, etc. Se usasse E/S não bloqueando, a zenidade receberá a primeira linha de saída e depois saía do loop pensando que foi feito porque sua segunda tentativa de leitura indicaria que isso Não havia mais nada disponível imediatamente.

Demonstrar que isso é o que está acontecendo (ou não) será complicado. Eu estaria procurando 'treliça' ou 'strace' ou outro monitor de chamadas do sistema para rastrear o que a zenidade está fazendo.

Quanto às soluções alternativas ... se a hipótese estiver correta, você precisará convencer a zenidade de que ela está lendo de um terminal e não um FIFO; portanto, você provavelmente precisará montar um pseudo-tty (ou pty); O primeiro processo escreveria para o extremo mestre do pty e você providencia a zenidade para ler a ponta do escravo do pty. Você ainda pode usar o FIFO também - embora ele faça uma longa cadeia de comando.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top