Rework Build Parser handling

* Rework IBuildParser:
    * Remove name() method.
    * Remove enterDirectory and leaveDirectory signals.
    * Allow chaining of parsers.
 * Rename IBuildParser to IOutputParser.
 * Implement GnuMakeParser.
    * Remove entering/leaving directory related code from all other parsers
    * Move filename fixup heuristic based on entering/leaving directory
      massages from gnumake here from AbstractMakeStep.
 * Add outputParser method to ToolChain: This removes the need to map
   toolchains to BuildParser names in the BuildSteps.
 * Enhance AbstractProcessStep to accept a IOutputParser to parse its output.
 * Remove AbstractMakeStep.
 * Set the appropriate Parsers in all classes deriving from AbstractProcessStep
   and append the ToolChain's parser to the parser chain.
 * Remove BuildParserFactories: There is no more need for them.
 * Remove constants used to identify the BuildParsers.
 * Clean up some names:
    * Replace stdOut with stdOutput.
    * Replace addToTaskWindow with addTask and addToOutputWindow with
      addOutput. Do this wherever it is not yet clear that this will end up
      in the Task/Output window.

Reviewed-by: dt
This commit is contained in:
Tobias Hunger
2009-12-09 13:54:46 +01:00
parent a0abde6306
commit ec025c6dbf
54 changed files with 635 additions and 1035 deletions

View File

@@ -28,29 +28,45 @@
**************************************************************************/
#include "abstractprocessstep.h"
#include "buildconfiguration.h"
#include "buildstep.h"
#include "ioutputparser.h"
#include "project.h"
#include <utils/qtcassert.h>
#include <QtCore/QProcess>
#include <QtCore/QEventLoop>
#include <QtCore/QDebug>
#include <QtCore/QTimer>
#include <QtGui/QTextDocument>
using namespace ProjectExplorer;
AbstractProcessStep::AbstractProcessStep(BuildConfiguration *bc)
: BuildStep(bc), m_timer(0), m_futureInterface(0), m_process(0), m_eventLoop(0)
AbstractProcessStep::AbstractProcessStep(BuildConfiguration *bc) :
BuildStep(bc), m_timer(0), m_futureInterface(0),
m_enabled(true), m_ignoreReturnValue(false),
m_process(0), m_eventLoop(0), m_outputParserChain(0)
{
}
AbstractProcessStep::AbstractProcessStep(AbstractProcessStep *bs, BuildConfiguration *bc)
: BuildStep(bs, bc), m_timer(0), m_futureInterface(0), m_process(0), m_eventLoop(0)
AbstractProcessStep::AbstractProcessStep(AbstractProcessStep *bs,
BuildConfiguration *bc) :
BuildStep(bs, bc), m_timer(0), m_futureInterface(0),
m_enabled(bs->m_enabled), m_ignoreReturnValue(bs->m_ignoreReturnValue),
m_process(0), m_eventLoop(0), m_outputParserChain(0)
{
}
AbstractProcessStep::~AbstractProcessStep()
{
delete m_process;
delete m_timer;
// do not delete m_futureInterface, we do not own it.
delete m_outputParserChain;
}
void AbstractProcessStep::setCommand(const QString &cmd)
{
m_command = cmd;
@@ -61,6 +77,34 @@ QString AbstractProcessStep::workingDirectory() const
return m_workingDirectory;
}
void AbstractProcessStep::setOutputParser(ProjectExplorer::IOutputParser *parser)
{
delete m_outputParserChain;
m_outputParserChain = parser;
if (m_outputParserChain) {
connect(parser, SIGNAL(addOutput(QString)),
this, SLOT(outputAdded(QString)));
connect(parser, SIGNAL(addTask(ProjectExplorer::TaskWindow::Task)),
this, SLOT(taskAdded(ProjectExplorer::TaskWindow::Task)));
}
}
void AbstractProcessStep::appendOutputParser(ProjectExplorer::IOutputParser *parser)
{
if (!parser)
return;
QTC_ASSERT(m_outputParserChain, return);
m_outputParserChain->appendOutputParser(parser);
return;
}
ProjectExplorer::IOutputParser *AbstractProcessStep::outputParser() const
{
return m_outputParserChain;
}
void AbstractProcessStep::setWorkingDirectory(const QString &workingDirectory)
{
m_workingDirectory = workingDirectory;
@@ -96,7 +140,7 @@ bool AbstractProcessStep::init()
return true;
}
void AbstractProcessStep::run(QFutureInterface<bool> & fi)
void AbstractProcessStep::run(QFutureInterface<bool> &fi)
{
m_futureInterface = &fi;
if (!m_enabled) {
@@ -155,23 +199,22 @@ void AbstractProcessStep::run(QFutureInterface<bool> & fi)
void AbstractProcessStep::processStarted()
{
emit addToOutputWindow(tr("<font color=\"#0000ff\">Starting: %1 %2</font>\n").arg(m_command, Qt::escape(m_arguments.join(" "))));
emit addOutput(tr("<font color=\"#0000ff\">Starting: %1 %2</font>\n").arg(m_command, Qt::escape(m_arguments.join(" "))));
}
bool AbstractProcessStep::processFinished(int exitCode, QProcess::ExitStatus status)
{
const bool ok = status == QProcess::NormalExit && (exitCode == 0 || m_ignoreReturnValue);
if (ok) {
emit addToOutputWindow(tr("<font color=\"#0000ff\">Exited with code %1.</font>").arg(m_process->exitCode()));
} else {
emit addToOutputWindow(tr("<font color=\"#ff0000\"><b>Exited with code %1.</b></font>").arg(m_process->exitCode()));
}
if (ok)
emit addOutput(tr("<font color=\"#0000ff\">Exited with code %1.</font>").arg(m_process->exitCode()));
else
emit addOutput(tr("<font color=\"#ff0000\"><b>Exited with code %1.</b></font>").arg(m_process->exitCode()));
return ok;
}
void AbstractProcessStep::processStartupFailed()
{
emit addToOutputWindow(tr("<font color=\"#ff0000\">Could not start process %1 </b></font>").arg(m_command));
emit addOutput(tr("<font color=\"#ff0000\">Could not start process %1 </b></font>").arg(m_command));
}
void AbstractProcessStep::processReadyReadStdOutput()
@@ -179,13 +222,15 @@ void AbstractProcessStep::processReadyReadStdOutput()
m_process->setReadChannel(QProcess::StandardOutput);
while (m_process->canReadLine()) {
QString line = QString::fromLocal8Bit(m_process->readLine()).trimmed();
stdOut(line);
stdOutput(line);
}
}
void AbstractProcessStep::stdOut(const QString &line)
void AbstractProcessStep::stdOutput(const QString &line)
{
emit addToOutputWindow(Qt::escape(line));
if (m_outputParserChain)
m_outputParserChain->stdOutput(line);
emit addOutput(Qt::escape(line));
}
void AbstractProcessStep::processReadyReadStdError()
@@ -199,7 +244,10 @@ void AbstractProcessStep::processReadyReadStdError()
void AbstractProcessStep::stdError(const QString &line)
{
emit addToOutputWindow(QLatin1String("<font color=\"#ff0000\">") + Qt::escape(line) + QLatin1String("</font>"));
if (m_outputParserChain)
m_outputParserChain->stdError(line);
else
emit addOutput(QLatin1String("<font color=\"#ff0000\">") + Qt::escape(line) + QLatin1String("</font>"));
}
void AbstractProcessStep::checkForCancel()
@@ -212,6 +260,54 @@ void AbstractProcessStep::checkForCancel()
}
}
void AbstractProcessStep::taskAdded(const ProjectExplorer::TaskWindow::Task &task)
{
TaskWindow::Task editable(task);
QString filePath = QDir::cleanPath(task.file.trimmed());
if (!filePath.isEmpty() && !QDir::isAbsolutePath(filePath)) {
// We have no save way to decide which file in which subfolder
// is meant. Therefore we apply following heuristics:
// 1. Check if file is unique in whole project
// 2. Otherwise try again without any ../
// 3. give up.
QList<QFileInfo> possibleFiles;
QString fileName = QFileInfo(filePath).fileName();
foreach (const QString &file, buildConfiguration()->project()->files(ProjectExplorer::Project::AllFiles)) {
QFileInfo candidate(file);
if (candidate.fileName() == fileName)
possibleFiles << candidate;
}
if (possibleFiles.count() == 1) {
editable.file = possibleFiles.first().filePath();
} else {
// More then one filename, so do a better compare
// Chop of any "../"
while (filePath.startsWith("../"))
filePath = filePath.mid(3);
int count = 0;
QString possibleFilePath;
foreach(const QFileInfo &fi, possibleFiles) {
if (fi.filePath().endsWith(filePath)) {
possibleFilePath = fi.filePath();
++count;
}
}
if (count == 1)
editable.file = possibleFilePath;
else
qWarning() << "Could not find absolute location of file " << filePath;
}
}
emit addTask(editable);
}
void AbstractProcessStep::outputAdded(const QString &string)
{
emit addOutput(string);
}
void AbstractProcessStep::slotProcessFinished(int, QProcess::ExitStatus)
{
QString line = QString::fromLocal8Bit(m_process->readAllStandardError()).trimmed();
@@ -220,7 +316,7 @@ void AbstractProcessStep::slotProcessFinished(int, QProcess::ExitStatus)
line = QString::fromLocal8Bit(m_process->readAllStandardOutput()).trimmed();
if (!line.isEmpty())
stdOut(line);
stdOutput(line);
m_eventLoop->exit(0);
}