add QProcess::Forwarded{Output,Error}Channel
Change-Id: Ifc5ed20c38f3228ef25c28681f296d0456b61abe Reviewed-by: Simon Hausmann <simon.hausmann@digia.com> Reviewed-by: Lars Knoll <lars.knoll@digia.com> Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
This commit is contained in:
parent
dd9d6b3d5b
commit
fba0a30791
@ -533,7 +533,11 @@ void QProcessPrivate::Channel::clear()
|
||||
MergedChannels before starting the process to activative
|
||||
this feature. You also have the option of forwarding the output of
|
||||
the running process to the calling, main process, by passing
|
||||
ForwardedChannels as the argument.
|
||||
ForwardedChannels as the argument. It is also possible to forward
|
||||
only one of the output channels - typically one would use
|
||||
ForwardedErrorChannel, but ForwardedOutputChannel also exists.
|
||||
Note that using channel forwarding is typically a bad idea in GUI
|
||||
applications - you should present errors graphically instead.
|
||||
|
||||
Certain processes need special environment settings in order to
|
||||
operate. You can set environment variables for your process by
|
||||
@ -625,6 +629,17 @@ void QProcessPrivate::Channel::clear()
|
||||
writes to its standard output and standard error will be written
|
||||
to the standard output and standard error of the main process.
|
||||
|
||||
\value ForwardedErrorChannel QProcess manages the standard output
|
||||
of the running process, but forwards its standard error onto the
|
||||
main process. This reflects the typical use of command line tools
|
||||
as filters, where the standard output is redirected to another
|
||||
process or a file, while standard error is printed to the console
|
||||
for diagnostic purposes.
|
||||
(This value was introduced in Qt 5.2.)
|
||||
|
||||
\value ForwardedOutputChannel Complementary to ForwardedErrorChannel.
|
||||
(This value was introduced in Qt 5.2.)
|
||||
|
||||
\note Windows intentionally suppresses output from GUI-only
|
||||
applications to inherited consoles.
|
||||
This does \e not apply to output redirected to files or pipes.
|
||||
|
@ -124,7 +124,9 @@ public:
|
||||
enum ProcessChannelMode {
|
||||
SeparateChannels,
|
||||
MergedChannels,
|
||||
ForwardedChannels
|
||||
ForwardedChannels,
|
||||
ForwardedOutputChannel,
|
||||
ForwardedErrorChannel
|
||||
};
|
||||
enum ExitStatus {
|
||||
NormalExit,
|
||||
|
@ -813,6 +813,16 @@ pid_t QProcessPrivate::spawnChild(const char *workingDir, char **argv, char **en
|
||||
fd_map[1] = QT_FILENO(stdout);
|
||||
fd_map[2] = QT_FILENO(stderr);
|
||||
break;
|
||||
case QProcess::ForwardedOutputChannel:
|
||||
fd_map[0] = stdinChannel.pipe[0];
|
||||
fd_map[1] = QT_FILENO(stdout);
|
||||
fd_map[2] = stderrChannel.pipe[1];
|
||||
break;
|
||||
case QProcess::ForwardedErrorChannel:
|
||||
fd_map[0] = stdinChannel.pipe[0];
|
||||
fd_map[1] = stdoutChannel.pipe[1];
|
||||
fd_map[2] = QT_FILENO(stderr);
|
||||
break;
|
||||
case QProcess::MergedChannels:
|
||||
fd_map[0] = stdinChannel.pipe[0];
|
||||
fd_map[1] = stdoutChannel.pipe[1];
|
||||
@ -850,12 +860,13 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv
|
||||
|
||||
// copy the stdout and stderr if asked to
|
||||
if (processChannelMode != QProcess::ForwardedChannels) {
|
||||
qt_safe_dup2(stdoutChannel.pipe[1], fileno(stdout), 0);
|
||||
if (processChannelMode != QProcess::ForwardedOutputChannel)
|
||||
qt_safe_dup2(stdoutChannel.pipe[1], fileno(stdout), 0);
|
||||
|
||||
// merge stdout and stderr if asked to
|
||||
if (processChannelMode == QProcess::MergedChannels) {
|
||||
qt_safe_dup2(fileno(stdout), fileno(stderr), 0);
|
||||
} else {
|
||||
} else if (processChannelMode != QProcess::ForwardedErrorChannel) {
|
||||
qt_safe_dup2(stderrChannel.pipe[1], fileno(stderr), 0);
|
||||
}
|
||||
}
|
||||
|
@ -160,7 +160,8 @@ bool QProcessPrivate::createChannel(Channel &channel)
|
||||
} else {
|
||||
QWindowsPipeReader *pipeReader = 0;
|
||||
if (&channel == &stdoutChannel) {
|
||||
if (processChannelMode != QProcess::ForwardedChannels) {
|
||||
if (processChannelMode != QProcess::ForwardedChannels
|
||||
&& processChannelMode != QProcess::ForwardedOutputChannel) {
|
||||
if (!stdoutReader) {
|
||||
stdoutReader = new QWindowsPipeReader(q);
|
||||
q->connect(stdoutReader, SIGNAL(readyRead()), SLOT(_q_canReadStandardOutput()));
|
||||
@ -170,7 +171,8 @@ bool QProcessPrivate::createChannel(Channel &channel)
|
||||
duplicateStdWriteChannel(channel.pipe, STD_OUTPUT_HANDLE);
|
||||
}
|
||||
} else /* if (&channel == &stderrChannel) */ {
|
||||
if (processChannelMode != QProcess::ForwardedChannels) {
|
||||
if (processChannelMode != QProcess::ForwardedChannels
|
||||
&& processChannelMode != QProcess::ForwardedErrorChannel) {
|
||||
if (!stderrReader) {
|
||||
stderrReader = new QWindowsPipeReader(q);
|
||||
q->connect(stderrReader, SIGNAL(readyRead()), SLOT(_q_canReadStandardError()));
|
||||
|
@ -42,30 +42,41 @@
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QProcess>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
|
||||
if (argc < 2)
|
||||
return 13;
|
||||
|
||||
#ifndef QT_NO_PROCESS
|
||||
QProcess process;
|
||||
process.setProcessChannelMode(QProcess::ForwardedChannels);
|
||||
if (process.processChannelMode() != QProcess::ForwardedChannels)
|
||||
|
||||
QProcess::ProcessChannelMode mode = (QProcess::ProcessChannelMode)atoi(argv[1]);
|
||||
process.setProcessChannelMode(mode);
|
||||
if (process.processChannelMode() != mode)
|
||||
return 1;
|
||||
|
||||
process.start("testProcessEcho/testProcessEcho");
|
||||
process.start("testProcessEcho2/testProcessEcho2");
|
||||
|
||||
if (!process.waitForStarted(5000))
|
||||
return 2;
|
||||
|
||||
if (process.write("forwarded\n") != 10)
|
||||
if (process.write("forwarded") != 9)
|
||||
return 3;
|
||||
|
||||
process.closeWriteChannel();
|
||||
if (!process.waitForFinished(5000))
|
||||
return 4;
|
||||
|
||||
if (process.bytesAvailable() != 0)
|
||||
if ((mode == QProcess::ForwardedOutputChannel || mode == QProcess::ForwardedChannels)
|
||||
&& !process.readAllStandardOutput().isEmpty())
|
||||
return 5;
|
||||
if ((mode == QProcess::ForwardedErrorChannel || mode == QProcess::ForwardedChannels)
|
||||
&& !process.readAllStandardError().isEmpty())
|
||||
return 6;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -107,6 +107,7 @@ private slots:
|
||||
void softExitInSlots_data();
|
||||
void softExitInSlots();
|
||||
void mergedChannels();
|
||||
void forwardedChannels_data();
|
||||
void forwardedChannels();
|
||||
void atEnd();
|
||||
void atEnd2();
|
||||
@ -1089,10 +1090,31 @@ void tst_QProcess::mergedChannels()
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef Q_OS_WINCE
|
||||
// Reading and writing to a process is not supported on Qt/CE
|
||||
|
||||
void tst_QProcess::forwardedChannels_data()
|
||||
{
|
||||
QTest::addColumn<int>("mode");
|
||||
QTest::addColumn<QByteArray>("outdata");
|
||||
QTest::addColumn<QByteArray>("errdata");
|
||||
|
||||
QTest::newRow("separate") << int(QProcess::SeparateChannels)
|
||||
<< QByteArray() << QByteArray();
|
||||
QTest::newRow("forwarded") << int(QProcess::ForwardedChannels)
|
||||
<< QByteArray("forwarded") << QByteArray("forwarded");
|
||||
QTest::newRow("stdout") << int(QProcess::ForwardedOutputChannel)
|
||||
<< QByteArray("forwarded") << QByteArray();
|
||||
QTest::newRow("stderr") << int(QProcess::ForwardedErrorChannel)
|
||||
<< QByteArray() << QByteArray("forwarded");
|
||||
}
|
||||
|
||||
void tst_QProcess::forwardedChannels()
|
||||
{
|
||||
QFETCH(int, mode);
|
||||
QFETCH(QByteArray, outdata);
|
||||
QFETCH(QByteArray, errdata);
|
||||
|
||||
QProcess process;
|
||||
process.start("testForwarding/testForwarding");
|
||||
process.start("testForwarding/testForwarding", QStringList() << QString::number(mode));
|
||||
QVERIFY(process.waitForStarted(5000));
|
||||
QVERIFY(process.waitForFinished(5000));
|
||||
const char *err;
|
||||
@ -1103,12 +1125,13 @@ void tst_QProcess::forwardedChannels()
|
||||
case 3: err = "failed to write"; break;
|
||||
case 4: err = "did not finish"; break;
|
||||
case 5: err = "unexpected stdout"; break;
|
||||
case 6: err = "unexpected stderr"; break;
|
||||
case 13: err = "parameter error"; break;
|
||||
default: err = "unknown exit code"; break;
|
||||
}
|
||||
QVERIFY2(!process.exitCode(), err);
|
||||
QByteArray data = process.readAll();
|
||||
QVERIFY(!data.isEmpty());
|
||||
QVERIFY(data.contains("forwarded"));
|
||||
QCOMPARE(process.readAllStandardOutput(), outdata);
|
||||
QCOMPARE(process.readAllStandardError(), errdata);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user