forked from qt-creator/qt-creator
OutputParser: Allow to flush pending tasks.
Add a way to flush out tasks from the outputparsers. This is necessary to make parsers that keep state more robust. Flush parsers (once) before adding any new task. This keeps the sequence intact. Flush all parsers once the parsing is done to make sure there is no task queued somewhere. Task-number: QTCREATORBUG-9195 Change-Id: Icd37df1f470cb73123ad286d6900ad1047a1d512 Reviewed-by: Tobias Hunger <tobias.hunger@digia.com>
This commit is contained in:
@@ -88,7 +88,7 @@ using namespace ProjectExplorer;
|
|||||||
AbstractProcessStep::AbstractProcessStep(BuildStepList *bsl, const Core::Id id) :
|
AbstractProcessStep::AbstractProcessStep(BuildStepList *bsl, const Core::Id id) :
|
||||||
BuildStep(bsl, id), m_timer(0), m_futureInterface(0),
|
BuildStep(bsl, id), m_timer(0), m_futureInterface(0),
|
||||||
m_ignoreReturnValue(false), m_process(0),
|
m_ignoreReturnValue(false), m_process(0),
|
||||||
m_outputParserChain(0)
|
m_outputParserChain(0), m_skipFlush(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ AbstractProcessStep::AbstractProcessStep(BuildStepList *bsl,
|
|||||||
AbstractProcessStep *bs) :
|
AbstractProcessStep *bs) :
|
||||||
BuildStep(bsl, bs), m_timer(0), m_futureInterface(0),
|
BuildStep(bsl, bs), m_timer(0), m_futureInterface(0),
|
||||||
m_ignoreReturnValue(bs->m_ignoreReturnValue),
|
m_ignoreReturnValue(bs->m_ignoreReturnValue),
|
||||||
m_process(0), m_outputParserChain(0)
|
m_process(0), m_outputParserChain(0), m_skipFlush(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,6 +261,9 @@ void AbstractProcessStep::processStarted()
|
|||||||
|
|
||||||
void AbstractProcessStep::processFinished(int exitCode, QProcess::ExitStatus status)
|
void AbstractProcessStep::processFinished(int exitCode, QProcess::ExitStatus status)
|
||||||
{
|
{
|
||||||
|
if (m_outputParserChain)
|
||||||
|
m_outputParserChain->flush();
|
||||||
|
|
||||||
QString command = QDir::toNativeSeparators(m_param.effectiveCommand());
|
QString command = QDir::toNativeSeparators(m_param.effectiveCommand());
|
||||||
if (status == QProcess::NormalExit && exitCode == 0) {
|
if (status == QProcess::NormalExit && exitCode == 0) {
|
||||||
emit addOutput(tr("The process \"%1\" exited normally.").arg(command),
|
emit addOutput(tr("The process \"%1\" exited normally.").arg(command),
|
||||||
@@ -367,6 +370,13 @@ void AbstractProcessStep::taskAdded(const ProjectExplorer::Task &task)
|
|||||||
if (m_ignoreReturnValue)
|
if (m_ignoreReturnValue)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// flush out any pending tasks before proceeding:
|
||||||
|
if (!m_skipFlush && m_outputParserChain) {
|
||||||
|
m_skipFlush = true;
|
||||||
|
m_outputParserChain->flush();
|
||||||
|
m_skipFlush = false;
|
||||||
|
}
|
||||||
|
|
||||||
Task editable(task);
|
Task editable(task);
|
||||||
QString filePath = task.file.toString();
|
QString filePath = task.file.toString();
|
||||||
if (!filePath.isEmpty() && !QDir::isAbsolutePath(filePath)) {
|
if (!filePath.isEmpty() && !QDir::isAbsolutePath(filePath)) {
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ private:
|
|||||||
QEventLoop *m_eventLoop;
|
QEventLoop *m_eventLoop;
|
||||||
ProjectExplorer::IOutputParser *m_outputParserChain;
|
ProjectExplorer::IOutputParser *m_outputParserChain;
|
||||||
bool m_killProcess;
|
bool m_killProcess;
|
||||||
|
bool m_skipFlush;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ProjectExplorer
|
} // namespace ProjectExplorer
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ void ClangParser::stdError(const QString &line)
|
|||||||
{
|
{
|
||||||
const QString lne = rightTrimmed(line);
|
const QString lne = rightTrimmed(line);
|
||||||
if (m_summaryRegExp.indexIn(lne) > -1) {
|
if (m_summaryRegExp.indexIn(lne) > -1) {
|
||||||
emitTask();
|
doFlush();
|
||||||
m_expectSnippet = false;
|
m_expectSnippet = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -74,11 +74,11 @@ void ClangParser::stdError(const QString &line)
|
|||||||
|
|
||||||
if (m_inLineRegExp.indexIn(lne) > -1) {
|
if (m_inLineRegExp.indexIn(lne) > -1) {
|
||||||
m_expectSnippet = true;
|
m_expectSnippet = true;
|
||||||
newTask(Task::Unknown,
|
newTask(Task(Task::Unknown,
|
||||||
lne.trimmed(),
|
lne.trimmed(),
|
||||||
Utils::FileName::fromUserInput(m_inLineRegExp.cap(2)), /* filename */
|
Utils::FileName::fromUserInput(m_inLineRegExp.cap(2)), /* filename */
|
||||||
m_inLineRegExp.cap(3).toInt(), /* line */
|
m_inLineRegExp.cap(3).toInt(), /* line */
|
||||||
Core::Id(Constants::TASK_CATEGORY_COMPILE));
|
Core::Id(Constants::TASK_CATEGORY_COMPILE)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,11 +60,6 @@ GccParser::GccParser()
|
|||||||
appendOutputParser(new LdParser);
|
appendOutputParser(new LdParser);
|
||||||
}
|
}
|
||||||
|
|
||||||
GccParser::~GccParser()
|
|
||||||
{
|
|
||||||
emitTask();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GccParser::stdError(const QString &line)
|
void GccParser::stdError(const QString &line)
|
||||||
{
|
{
|
||||||
QString lne = rightTrimmed(line);
|
QString lne = rightTrimmed(line);
|
||||||
@@ -79,11 +74,11 @@ void GccParser::stdError(const QString &line)
|
|||||||
// Handle misc issues:
|
// Handle misc issues:
|
||||||
if (lne.startsWith(QLatin1String("ERROR:")) ||
|
if (lne.startsWith(QLatin1String("ERROR:")) ||
|
||||||
lne == QLatin1String("* cpp failed")) {
|
lne == QLatin1String("* cpp failed")) {
|
||||||
newTask(Task::Error,
|
newTask(Task(Task::Error,
|
||||||
lne /* description */,
|
lne /* description */,
|
||||||
Utils::FileName() /* filename */,
|
Utils::FileName() /* filename */,
|
||||||
-1 /* linenumber */,
|
-1 /* linenumber */,
|
||||||
Core::Id(Constants::TASK_CATEGORY_COMPILE));
|
Core::Id(Constants::TASK_CATEGORY_COMPILE)));
|
||||||
return;
|
return;
|
||||||
} else if (m_regExpGccNames.indexIn(lne) > -1) {
|
} else if (m_regExpGccNames.indexIn(lne) > -1) {
|
||||||
QString description = lne.mid(m_regExpGccNames.matchedLength());
|
QString description = lne.mid(m_regExpGccNames.matchedLength());
|
||||||
@@ -121,44 +116,40 @@ void GccParser::stdError(const QString &line)
|
|||||||
newTask(task);
|
newTask(task);
|
||||||
return;
|
return;
|
||||||
} else if (m_regExpIncluded.indexIn(lne) > -1) {
|
} else if (m_regExpIncluded.indexIn(lne) > -1) {
|
||||||
newTask(Task::Unknown,
|
newTask(Task(Task::Unknown,
|
||||||
lne.trimmed() /* description */,
|
lne.trimmed() /* description */,
|
||||||
Utils::FileName::fromUserInput(m_regExpIncluded.cap(1)) /* filename */,
|
Utils::FileName::fromUserInput(m_regExpIncluded.cap(1)) /* filename */,
|
||||||
m_regExpIncluded.cap(3).toInt() /* linenumber */,
|
m_regExpIncluded.cap(3).toInt() /* linenumber */,
|
||||||
Core::Id(Constants::TASK_CATEGORY_COMPILE));
|
Core::Id(Constants::TASK_CATEGORY_COMPILE)));
|
||||||
return;
|
return;
|
||||||
} else if (lne.startsWith(QLatin1Char(' '))) {
|
} else if (lne.startsWith(QLatin1Char(' '))) {
|
||||||
amendDescription(lne, true);
|
amendDescription(lne, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emitTask();
|
doFlush();
|
||||||
IOutputParser::stdError(line);
|
IOutputParser::stdError(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GccParser::stdOutput(const QString &line)
|
void GccParser::stdOutput(const QString &line)
|
||||||
{
|
{
|
||||||
emitTask();
|
doFlush();
|
||||||
IOutputParser::stdOutput(line);
|
IOutputParser::stdOutput(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GccParser::newTask(const Task &task)
|
void GccParser::newTask(const Task &task)
|
||||||
{
|
{
|
||||||
emitTask();
|
doFlush();
|
||||||
m_currentTask = task;
|
m_currentTask = task;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GccParser::newTask(Task::TaskType type_, const QString &description_,
|
void GccParser::doFlush()
|
||||||
const Utils::FileName &file_, int line_, const Core::Id &category_)
|
|
||||||
{
|
{
|
||||||
newTask(Task(type_, description_, file_, line_, category_));
|
if (m_currentTask.isNull())
|
||||||
}
|
return;
|
||||||
|
Task t = m_currentTask;
|
||||||
void GccParser::emitTask()
|
m_currentTask.clear();
|
||||||
{
|
emit addTask(t);
|
||||||
if (!m_currentTask.isNull())
|
|
||||||
emit addTask(m_currentTask);
|
|
||||||
m_currentTask = Task();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GccParser::amendDescription(const QString &desc, bool monospaced)
|
void GccParser::amendDescription(const QString &desc, bool monospaced)
|
||||||
|
|||||||
@@ -44,15 +44,13 @@ class GccParser : public ProjectExplorer::IOutputParser
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
GccParser();
|
GccParser();
|
||||||
~GccParser();
|
|
||||||
void stdError(const QString &line);
|
void stdError(const QString &line);
|
||||||
void stdOutput(const QString &line);
|
void stdOutput(const QString &line);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void newTask(const Task &task);
|
void newTask(const Task &task);
|
||||||
void newTask(Task::TaskType type_, const QString &description_,
|
void doFlush();
|
||||||
const Utils::FileName &file_, int line_, const Core::Id &category_);
|
|
||||||
void emitTask();
|
|
||||||
|
|
||||||
void amendDescription(const QString &desc, bool monospaced);
|
void amendDescription(const QString &desc, bool monospaced);
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ void GnuMakeParser::stdError(const QString &line)
|
|||||||
++m_fatalErrorCount;
|
++m_fatalErrorCount;
|
||||||
if (!m_suppressIssues) {
|
if (!m_suppressIssues) {
|
||||||
m_suppressIssues = true;
|
m_suppressIssues = true;
|
||||||
addTask(Task(Task::Error,
|
emit addTask(Task(Task::Error,
|
||||||
m_makefileError.cap(3),
|
m_makefileError.cap(3),
|
||||||
Utils::FileName::fromUserInput(m_makefileError.cap(1)),
|
Utils::FileName::fromUserInput(m_makefileError.cap(1)),
|
||||||
m_makefileError.cap(2).toInt(),
|
m_makefileError.cap(2).toInt(),
|
||||||
@@ -110,7 +110,7 @@ void GnuMakeParser::stdError(const QString &line)
|
|||||||
type = Task::Warning;
|
type = Task::Warning;
|
||||||
}
|
}
|
||||||
|
|
||||||
addTask(Task(type, description,
|
emit addTask(Task(type, description,
|
||||||
Utils::FileName() /* filename */,
|
Utils::FileName() /* filename */,
|
||||||
-1, /* line */
|
-1, /* line */
|
||||||
Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)));
|
Core::Id(Constants::TASK_CATEGORY_BUILDSYSTEM)));
|
||||||
|
|||||||
@@ -108,6 +108,17 @@
|
|||||||
This method can be overwritten to change the task.
|
This method can be overwritten to change the task.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn void ProjectExplorer::IOutputParser::doFlush()
|
||||||
|
|
||||||
|
\brief This method is called whenever a parser is supposed to flush his state.
|
||||||
|
Parsers may have state (e.g. because they need to aggregate several lines into one task). This
|
||||||
|
method is called when this state needs to be flushed out to be visible.
|
||||||
|
|
||||||
|
doFlush() is called by flush(). flush() is called on childparsers whenever a new task is added.
|
||||||
|
It is also called once when all input has been parsed.
|
||||||
|
*/
|
||||||
|
|
||||||
namespace ProjectExplorer {
|
namespace ProjectExplorer {
|
||||||
|
|
||||||
IOutputParser::IOutputParser() : m_parser(0)
|
IOutputParser::IOutputParser() : m_parser(0)
|
||||||
@@ -180,6 +191,9 @@ void IOutputParser::taskAdded(const ProjectExplorer::Task &task)
|
|||||||
emit addTask(task);
|
emit addTask(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IOutputParser::doFlush()
|
||||||
|
{ }
|
||||||
|
|
||||||
bool IOutputParser::hasFatalErrors() const
|
bool IOutputParser::hasFatalErrors() const
|
||||||
{
|
{
|
||||||
return false || (m_parser && m_parser->hasFatalErrors());
|
return false || (m_parser && m_parser->hasFatalErrors());
|
||||||
@@ -191,6 +205,13 @@ void IOutputParser::setWorkingDirectory(const QString &workingDirectory)
|
|||||||
m_parser->setWorkingDirectory(workingDirectory);
|
m_parser->setWorkingDirectory(workingDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IOutputParser::flush()
|
||||||
|
{
|
||||||
|
doFlush();
|
||||||
|
if (m_parser)
|
||||||
|
m_parser->flush();
|
||||||
|
}
|
||||||
|
|
||||||
QString IOutputParser::rightTrimmed(const QString &in)
|
QString IOutputParser::rightTrimmed(const QString &in)
|
||||||
{
|
{
|
||||||
int pos = in.length();
|
int pos = in.length();
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class PROJECTEXPLORER_EXPORT IOutputParser : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
IOutputParser();
|
IOutputParser();
|
||||||
virtual ~IOutputParser();
|
~IOutputParser();
|
||||||
|
|
||||||
virtual void appendOutputParser(IOutputParser *parser);
|
virtual void appendOutputParser(IOutputParser *parser);
|
||||||
|
|
||||||
@@ -60,6 +60,8 @@ public:
|
|||||||
// For GnuMakeParser
|
// For GnuMakeParser
|
||||||
virtual void setWorkingDirectory(const QString &workingDirectory);
|
virtual void setWorkingDirectory(const QString &workingDirectory);
|
||||||
|
|
||||||
|
void flush(); // flush out pending tasks
|
||||||
|
|
||||||
static QString rightTrimmed(const QString &in);
|
static QString rightTrimmed(const QString &in);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@@ -71,6 +73,8 @@ public slots:
|
|||||||
virtual void taskAdded(const ProjectExplorer::Task &task);
|
virtual void taskAdded(const ProjectExplorer::Task &task);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
virtual void doFlush();
|
||||||
|
|
||||||
IOutputParser *m_parser;
|
IOutputParser *m_parser;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -58,12 +58,6 @@ LinuxIccParser::LinuxIccParser()
|
|||||||
appendOutputParser(new LdParser);
|
appendOutputParser(new LdParser);
|
||||||
}
|
}
|
||||||
|
|
||||||
LinuxIccParser::~LinuxIccParser()
|
|
||||||
{
|
|
||||||
if (!m_temporary.isNull())
|
|
||||||
addTask(m_temporary);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LinuxIccParser::stdError(const QString &line)
|
void LinuxIccParser::stdError(const QString &line)
|
||||||
{
|
{
|
||||||
if (m_expectFirstLine && m_firstLine.indexIn(line) != -1) {
|
if (m_expectFirstLine && m_firstLine.indexIn(line) != -1) {
|
||||||
@@ -107,6 +101,15 @@ void LinuxIccParser::stdError(const QString &line)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LinuxIccParser::doFlush()
|
||||||
|
{
|
||||||
|
if (m_temporary.isNull())
|
||||||
|
return;
|
||||||
|
Task t = m_temporary;
|
||||||
|
m_temporary.clear();
|
||||||
|
emit addTask(t);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef WITH_TESTS
|
#ifdef WITH_TESTS
|
||||||
# include <QTest>
|
# include <QTest>
|
||||||
# include "projectexplorer.h"
|
# include "projectexplorer.h"
|
||||||
|
|||||||
@@ -43,11 +43,12 @@ class LinuxIccParser : public ProjectExplorer::IOutputParser
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
LinuxIccParser();
|
LinuxIccParser();
|
||||||
~LinuxIccParser();
|
|
||||||
|
|
||||||
void stdError(const QString &line);
|
void stdError(const QString &line);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void doFlush();
|
||||||
|
|
||||||
QRegExp m_firstLine;
|
QRegExp m_firstLine;
|
||||||
QRegExp m_continuationLines;
|
QRegExp m_continuationLines;
|
||||||
QRegExp m_caretLine;
|
QRegExp m_caretLine;
|
||||||
|
|||||||
@@ -69,11 +69,6 @@ MsvcParser::MsvcParser()
|
|||||||
m_additionalInfoRegExp.setMinimal(true);
|
m_additionalInfoRegExp.setMinimal(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
MsvcParser::~MsvcParser()
|
|
||||||
{
|
|
||||||
sendQueuedTask();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MsvcParser::stdOutput(const QString &line)
|
void MsvcParser::stdOutput(const QString &line)
|
||||||
{
|
{
|
||||||
int infoPos = m_additionalInfoRegExp.indexIn(line);
|
int infoPos = m_additionalInfoRegExp.indexIn(line);
|
||||||
@@ -141,7 +136,7 @@ void MsvcParser::stdError(const QString &line)
|
|||||||
|
|
||||||
bool MsvcParser::processCompileLine(const QString &line)
|
bool MsvcParser::processCompileLine(const QString &line)
|
||||||
{
|
{
|
||||||
sendQueuedTask();
|
doFlush();
|
||||||
|
|
||||||
if (m_compileRegExp.indexIn(line) > -1) {
|
if (m_compileRegExp.indexIn(line) > -1) {
|
||||||
QPair<Utils::FileName, int> position = parseFileName( m_compileRegExp.cap(1));
|
QPair<Utils::FileName, int> position = parseFileName( m_compileRegExp.cap(1));
|
||||||
@@ -159,13 +154,14 @@ bool MsvcParser::processCompileLine(const QString &line)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MsvcParser::sendQueuedTask()
|
void MsvcParser::doFlush()
|
||||||
{
|
{
|
||||||
if (m_lastTask.isNull())
|
if (m_lastTask.isNull())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
addTask(m_lastTask);
|
Task t = m_lastTask;
|
||||||
m_lastTask = Task();
|
m_lastTask.clear();
|
||||||
|
emit addTask(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unit tests:
|
// Unit tests:
|
||||||
|
|||||||
@@ -44,14 +44,12 @@ class MsvcParser : public ProjectExplorer::IOutputParser
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
MsvcParser();
|
MsvcParser();
|
||||||
~MsvcParser();
|
|
||||||
|
|
||||||
void stdOutput(const QString &line);
|
void stdOutput(const QString &line);
|
||||||
void stdError(const QString &line);
|
void stdError(const QString &line);
|
||||||
void flush();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void sendQueuedTask();
|
void doFlush();
|
||||||
bool processCompileLine(const QString &line);
|
bool processCompileLine(const QString &line);
|
||||||
|
|
||||||
QRegExp m_compileRegExp;
|
QRegExp m_compileRegExp;
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ void OutputParserTester::testParsing(const QString &lines,
|
|||||||
else
|
else
|
||||||
childParser()->stdError(input + QLatin1Char('\n'));
|
childParser()->stdError(input + QLatin1Char('\n'));
|
||||||
}
|
}
|
||||||
|
childParser()->flush();
|
||||||
|
|
||||||
// first disconnect ourselves from the end of the parser chain again
|
// first disconnect ourselves from the end of the parser chain again
|
||||||
IOutputParser * parser = this;
|
IOutputParser * parser = this;
|
||||||
|
|||||||
Reference in New Issue
Block a user