выход git stderr не может передать - PullRequest
13 голосов
/ 31 октября 2010

Я пишу графический обработчик URI для ссылок git: // с bash и zenity, и я использую диалоговое окно zenity 'text-info', чтобы показать вывод клона git во время его работы, используя трубопровод FIFO. Сценарий длиной около 90 строк, поэтому я не буду публиковать его здесь, но вот самые важные строки:

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

Я использую FIFO вместо прямого канала, чтобы позволить им работать асинхронно и убивать git, если окно zenity закрыто.

Проблема в том, что единственная строка, которая появляется из вывода git, является первой:

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

Другие строки с подсчетом объектов и т. Д. Не отображаются или отображаются на терминале.

Текущая причина

Текущий консенсус относительно того, почему это не работает, похоже, что cat неблокирует и выходит после первой строки, передавая его только zenity, а не остальным. Моя цель состоит в том, чтобы принудительно заблокировать чтение, и чтобы диалоговое окно с текстовой информацией zenity показывало все результаты постепенно.

git выводит сообщения о ходе выполнения (все, кроме сообщения «Initialized») на stderr, но в тот момент, когда я пытаюсь передать stderr в файл или объединить с stdout, сообщения исчезают.

Попытка исправить 1

Я пытался написать две блокирующие версии функций cat на C, bread и bwrite, например:

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

Они хорошо работают, потому что блокируют и не выходят из EOF, но это еще не решило проблему. В настоящее время использование одного, другого или обоих работает в теории, но на практике zenity сейчас вообще ничего не показывает.

Попытка исправить 2

@ mvds предположил, что использование обычного файла в сочетании с tail -f вместо cat может сделать это. Удивленный таким простым решением (спасибо!), Я попробовал его, но, к сожалению, только первая строка показалась в зените и больше ничего.

Попытка исправить 3

После некоторого изучения и проверки исходного кода git я понимаю, что git выводит всю свою информацию о прогрессе (что угодно, кроме сообщения «Initialized») на stderr, и тот факт, что это первая строка, и я предполагаю, что это из-за того, что cat рано выходил из EOF, это было совпадение / ошибочное предположение (git не EOF, пока программа не завершится).

Ситуация, казалось, стала намного проще, поскольку мне не нужно было ничего менять по сравнению с исходным кодом (в начале вопроса), и это должно сработать. Однако при загадочных обстоятельствах вывод stderr «исчезает» при перенаправлении - и это только то, что происходит в git.

контрольный пример? Попробуйте это, и посмотрите, видите ли вы что-нибудь в файле (вы не увидите):

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

Это идет вразрез со всем, что я знаю о stderr и перенаправлении; Я даже написал небольшую C-программу, которая выводит на stderr и stdout, чтобы доказать себе, что перенаправление просто не работает для git.

Попытка исправить 4

В соответствии с ответом Якуба Наребски, а также ответами на электронные письма, которые я отправил в список рассылки git, --progress - это вариант, который мне нужен. Обратите внимание, что этот параметр работает только после команды, а не до clone.

Успех!

Большое спасибо за вашу помощь. Это фиксированная линия:

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

image

Ответы [ 3 ]

18 голосов
/ 31 октября 2010

Я думаю, что, по крайней мере, некоторые отчеты о ходе работы отключаются, когда вывод не является терминалом (tty). Я не уверен, применимо ли это к вашему делу, но попробуйте передать опцию --progress в «git clone» (т.е. использовать git clone --progress <repository>).

Хотя я не знаю, хотел ли ты этого.

6 голосов
/ 31 октября 2010

С одной стороны, перенаправление вывода анализируется справа налево, поэтому

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

не равно

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

Последнее перенаправит stderr на стандартный вывод, изатем стандартный вывод (включая стандартный вывод) в файл.Первый перенаправит stdout в файл, а затем покажет stderr на stdout.

Что касается передачи по трубопроводу на zenity (чего я не знаю), я думаю, вы, возможно, усложняете работу с именованнымтруба.Использование strace может пролить некоторый свет на внутреннюю работу процессов, которые вы запускаете.Для неопытных именованные каналы ухудшают ситуацию по сравнению с обычными.

1 голос
/ 31 октября 2010

Учитывая эксперимент с FIFO под названием «a», я думаю, что проблема заключается в том, как zenity обрабатывает свой вклад. Что произойдет, если вы введете в zenity с клавиатуры? (Подозрение: при чтении в EOF он ведет себя так, как вы хотите.) Однако, возможно, что zenity обрабатывает ввод с терминала (tty-ввод), используя обычный блокирующий ввод / вывод, но использует неблокирующий ввод / вывод для всех других типов устройств. Неблокирующий ввод / вывод хорош для ввода из файлов; это менее желательно для ввода из каналов или FIFO и т. д. Если бы он использовал неблокирующий ввод / вывод, zenity получил бы первую строку вывода, а затем вышел из цикла, думая, что это было сделано, потому что его вторая попытка чтения показала бы, что больше ничего не было доступно сразу.

Демонстрировать, что это происходит (или нет), будет сложно. Я бы посмотрел на 'truss' или 'strace' или другой монитор системных вызовов, чтобы отследить, что делает zenity.

Что касается обходных путей ... если гипотеза верна, то вам нужно будет убедить zenity в том, что она читает с терминала, а не с FIFO, поэтому вам, вероятно, придется настроить псевдо-tty (или псевдотерминал); первый процесс записывает в главный конец pty, и вы организуете чтение с ведомого конца pty. Вы все еще можете использовать FIFO - хотя он создает длинную цепочку команд.

...