diff --git a/src/libs/utils/synchronousprocess.cpp b/src/libs/utils/synchronousprocess.cpp index 0367eb484255c1a962ed5fedc1113eb40f2ecd3d..23d524f969df37d321f59ad4a7fc7f561f4cfd52 100644 --- a/src/libs/utils/synchronousprocess.cpp +++ b/src/libs/utils/synchronousprocess.cpp @@ -28,6 +28,7 @@ **************************************************************************/ #include "synchronousprocess.h" +#include <qtcassert.h> #include <QtCore/QDebug> #include <QtCore/QTimer> @@ -41,6 +42,7 @@ #include <limits.h> enum { debug = 0 }; +enum { syncDebug = 0 }; enum { defaultMaxHangTimerCount = 10 }; @@ -403,25 +405,39 @@ void SynchronousProcess::processStdErr(bool emitSignals) bool SynchronousProcess::readDataFromProcess(QProcess &p, int timeOutMS, QByteArray *stdOut, QByteArray *stdErr) { + if (syncDebug) + qDebug() << ">readDataFromProcess" << timeOutMS; if (p.state() != QProcess::Running) { qWarning("readDataFromProcess: Process in non-running state passed in."); return false; } + QTC_ASSERT(p.readChannel() == QProcess::StandardOutput, return false) + // Keep the process running until it has no longer has data bool finished = false; bool hasData = false; do { finished = p.waitForFinished(timeOutMS); - if ( (hasData = p.bytesAvailable()) ) { + hasData = false; + // First check 'stdout' + if (p.bytesAvailable()) { // applies to readChannel() only + hasData = true; const QByteArray newStdOut = p.readAllStandardOutput(); - const QByteArray newStdErr = p.readAllStandardError(); if (stdOut) stdOut->append(newStdOut); + } + // Check 'stderr' separately. This is a special handling + // for 'git pull' and the like which prints its progress on stderr. + const QByteArray newStdErr = p.readAllStandardError(); + if (!newStdErr.isEmpty()) { + hasData = true; if (stdErr) stdErr->append(newStdErr); } } while (hasData && !finished); + if (syncDebug) + qDebug() << "<readDataFromProcess" << finished; return finished; } diff --git a/tests/manual/process/main.cpp b/tests/manual/process/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..01efb7daf6acf40c49c299f42c8cf8f8e9ed87a5 --- /dev/null +++ b/tests/manual/process/main.cpp @@ -0,0 +1,92 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "mainwindow.h" + +#include <utils/synchronousprocess.h> +#include <QtGui/QApplication> +#include <QtCore/QDebug> +#include <QtCore/QTimer> + +#include <cstdio> + +static const char usage[] = +"Tests timeout behaviour of Utils:SynchronousProcess.\n" +"Usage:\n" +" 1) Test Utils:SynchronousProcess (graphically)\n" +" process <cmd> <args>\n" +" 2) Test synchronous helpers of Utils:SynchronousProcess (tty)\n" +" process -s <cmd> <args>\n\n" +"slowprocess.sh is provided as an example script that produces slow\n" +"output. It takes an option -e to switch to stderr\n" +"No timeout should occur.\n"; + +static int testSynchronous(const QString &cmd, const QStringList &args) +{ + std::fprintf(stdout, "testSynchronous %s %s\n", qPrintable(cmd), + qPrintable(args.join(QLatin1String(" ")))); + QProcess p; + p.start(cmd, args); + if (!p.waitForStarted()) + return -2; + p.closeWriteChannel(); + + QByteArray stdOut; + QByteArray stdErr; + if (!Utils::SynchronousProcess::readDataFromProcess(p, 2000, &stdOut, &stdErr)) { + std::fputs("Timeout", stderr); + return -3; + } + std::fputs(stdOut, stdout); + std::fputs(stdErr, stderr); + return p.exitCode(); +} + +int main(int argc, char *argv[]) +{ + if (argc < 2) { + std::fputs(usage, stdout); + return -1; + } + const bool synchronous = argc > 1 && !qstrcmp(argv[1], "-s"); + int ex = 0; + if (synchronous) { + const QString cmd = QString::fromLocal8Bit(argv[2]); + QStringList args; + for (int i = 3; i < argc; i++) + args += QString::fromLocal8Bit(argv[i]); + ex = testSynchronous(cmd, args); + } else { + QApplication app(argc, argv); + MainWindow mw; + mw.show(); + ex = app.exec(); + } + return ex; +} diff --git a/tests/manual/process/mainwindow.cpp b/tests/manual/process/mainwindow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f3e5959c716fb77cf3fe0a36e18c6838980f03f6 --- /dev/null +++ b/tests/manual/process/mainwindow.cpp @@ -0,0 +1,65 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +*************************************************************************/ + +#include "mainwindow.h" + +#include <utils/synchronousprocess.h> + +#include <QtGui/QPlainTextEdit> +#include <QtGui/QApplication> +#include <QtCore/QDebug> +#include <QtCore/QTimer> + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + m_logWindow(new QPlainTextEdit) +{ + setCentralWidget(m_logWindow); + QTimer::singleShot(200, this, SLOT(test())); +} + +void MainWindow::append(const QByteArray &a) +{ + m_logWindow->appendPlainText(QString::fromLocal8Bit(a)); +} + +void MainWindow::test() +{ + QStringList args = QApplication::arguments(); + args.pop_front(); + const QString cmd = args.front(); + args.pop_front(); + Utils::SynchronousProcess process; + process.setTimeout(2000); + qDebug() << "Async: " << cmd << args; + connect(&process, SIGNAL(stdOut(QByteArray,bool)), this, SLOT(append(QByteArray))); + connect(&process, SIGNAL(stdErr(QByteArray,bool)), this, SLOT(append(QByteArray))); + const Utils::SynchronousProcessResponse resp = process.run(cmd, args); + qDebug() << resp; +} diff --git a/tests/manual/process/mainwindow.h b/tests/manual/process/mainwindow.h new file mode 100644 index 0000000000000000000000000000000000000000..ec276f18e5e9d438553b37362367e06161d55339 --- /dev/null +++ b/tests/manual/process/mainwindow.h @@ -0,0 +1,53 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <QtGui/QMainWindow> + +class QPlainTextEdit; + +class MainWindow : public QMainWindow +{ +Q_OBJECT +public: + explicit MainWindow(QWidget *parent = 0); + +signals: + +public slots: + void test(); + void append(const QByteArray &a); + +private: + QPlainTextEdit *m_logWindow; +}; + +#endif // MAINWINDOW_H diff --git a/tests/manual/process/process.pro b/tests/manual/process/process.pro new file mode 100644 index 0000000000000000000000000000000000000000..05c5e4a48c24f75a526d84ab32766939ba7494f5 --- /dev/null +++ b/tests/manual/process/process.pro @@ -0,0 +1,27 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2010-03-01T11:08:57 +# +#------------------------------------------------- + +# Utils lib requires gui, too. +QT += core +QT += gui + +# -- Add creator 'utils' lib +CREATOR_LIB_LIB = ../../../lib/qtcreator +LIBS *= -L$$CREATOR_LIB_LIB +LIBS *= -l$$qtLibraryTarget(Utils) +QMAKE_RPATHDIR*=$$CREATOR_LIB_LIB +CREATOR_LIB_SRC = ../../../src/libs +INCLUDEPATH *= $$CREATOR_LIB_SRC + +TARGET = process +CONFIG += console +CONFIG -= app_bundle +TEMPLATE = app +SOURCES += main.cpp \ + mainwindow.cpp + +HEADERS += \ + mainwindow.h