Commit ec025c6d authored by Tobias Hunger's avatar Tobias Hunger
Browse files

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
parent a0abde63
......@@ -136,21 +136,6 @@ QString CMakeBuildConfiguration::buildDirectory() const
return buildDirectory;
}
QString CMakeBuildConfiguration::buildParser() const
{
if (!m_toolChain)
return QString::null;
if (m_toolChain->type() == ProjectExplorer::ToolChain::GCC
//|| m_toolChain->type() == ProjectExplorer::ToolChain::LinuxICC
|| m_toolChain->type() == ProjectExplorer::ToolChain::MinGW) {
return ProjectExplorer::Constants::BUILD_PARSER_GCC;
} else if (m_toolChain->type() == ProjectExplorer::ToolChain::MSVC
|| m_toolChain->type() == ProjectExplorer::ToolChain::WINCE) {
return ProjectExplorer::Constants::BUILD_PARSER_MSVC;
}
return QString::null;
}
ProjectExplorer::ToolChain::ToolChainType CMakeBuildConfiguration::toolChainType() const
{
if (m_toolChain)
......
......@@ -57,7 +57,6 @@ public:
void setUseSystemEnvironment(bool b);
virtual QString buildDirectory() const;
QString buildParser() const;
ProjectExplorer::ToolChain::ToolChainType toolChainType() const;
ProjectExplorer::ToolChain *toolChain() const;
......
......@@ -32,6 +32,7 @@
#include "cmakebuildconfiguration.h"
#include <projectexplorer/projectexplorer.h>
#include <projectexplorer/gnumakeparser.h>
#include <QtGui/QFormLayout>
#include <QtGui/QGroupBox>
......@@ -43,14 +44,14 @@ using namespace CMakeProjectManager;
using namespace CMakeProjectManager::Internal;
using namespace ProjectExplorer;
MakeStep::MakeStep(BuildConfiguration *bc)
: AbstractMakeStep(bc), m_clean(false), m_futureInterface(0)
MakeStep::MakeStep(BuildConfiguration *bc) :
AbstractProcessStep(bc), m_clean(false), m_futureInterface(0)
{
m_percentProgress = QRegExp("^\\[\\s*(\\d*)%\\]");
}
MakeStep::MakeStep(MakeStep *bs, BuildConfiguration *bc)
: AbstractMakeStep(bs, bc),
MakeStep::MakeStep(MakeStep *bs, BuildConfiguration *bc) :
AbstractProcessStep(bs, bc),
m_clean(bs->m_clean),
m_futureInterface(0),
m_buildTargets(bs->m_buildTargets),
......@@ -78,7 +79,7 @@ void MakeStep::restoreFromGlobalMap(const QMap<QString, QVariant> &map)
{
if (map.value("clean").isValid() && map.value("clean").toBool())
m_clean = true;
AbstractMakeStep::restoreFromGlobalMap(map);
AbstractProcessStep::restoreFromGlobalMap(map);
}
void MakeStep::restoreFromLocalMap(const QMap<QString, QVariant> &map)
......@@ -87,7 +88,7 @@ void MakeStep::restoreFromLocalMap(const QMap<QString, QVariant> &map)
m_additionalArguments = map["additionalArguments"].toStringList();
if (map.value("clean").isValid() && map.value("clean").toBool())
m_clean = true;
AbstractMakeStep::restoreFromLocalMap(map);
AbstractProcessStep::restoreFromLocalMap(map);
}
void MakeStep::storeIntoLocalMap(QMap<QString, QVariant> &map)
......@@ -96,13 +97,12 @@ void MakeStep::storeIntoLocalMap(QMap<QString, QVariant> &map)
map["additionalArguments"] = m_additionalArguments;
if (m_clean)
map["clean"] = true;
AbstractMakeStep::storeIntoLocalMap(map);
AbstractProcessStep::storeIntoLocalMap(map);
}
bool MakeStep::init()
{
CMakeBuildConfiguration *bc = cmakeBuildConfiguration();
setBuildParser(bc->buildParser());
setEnabled(true);
setWorkingDirectory(bc->buildDirectory());
......@@ -115,14 +115,18 @@ bool MakeStep::init()
setEnvironment(bc->environment());
setIgnoreReturnValue(m_clean);
return AbstractMakeStep::init();
setOutputParser(new ProjectExplorer::GnuMakeParser(workingDirectory()));
if (bc->toolChain())
appendOutputParser(bc->toolChain()->outputParser());
return AbstractProcessStep::init();
}
void MakeStep::run(QFutureInterface<bool> &fi)
{
m_futureInterface = &fi;
m_futureInterface->setProgressRange(0, 100);
AbstractMakeStep::run(fi);
AbstractProcessStep::run(fi);
m_futureInterface->setProgressValue(100);
m_futureInterface->reportFinished();
m_futureInterface = 0;
......@@ -135,7 +139,7 @@ QString MakeStep::name()
QString MakeStep::displayName()
{
return "Make";
return QLatin1String("Make");
}
BuildStepConfigWidget *MakeStep::createConfigWidget()
......@@ -156,7 +160,7 @@ void MakeStep::stdOut(const QString &line)
if (ok)
m_futureInterface->setProgressValue(percent);
}
AbstractMakeStep::stdOut(line);
AbstractProcessStep::stdOutput(line);
}
bool MakeStep::buildsTarget(const QString &target) const
......
......@@ -30,7 +30,7 @@
#ifndef MAKESTEP_H
#define MAKESTEP_H
#include <projectexplorer/abstractmakestep.h>
#include <projectexplorer/abstractprocessstep.h>
QT_BEGIN_NAMESPACE
class QLineEdit;
......@@ -43,7 +43,7 @@ namespace Internal {
class CMakeBuildConfiguration;
class MakeStep : public ProjectExplorer::AbstractMakeStep
class MakeStep : public ProjectExplorer::AbstractProcessStep
{
Q_OBJECT
friend class MakeStepConfigWidget; // TODO remove
......
......@@ -36,7 +36,7 @@
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/toolchain.h>
#include <projectexplorer/projectexplorer.h>
#include <utils/qtcassert.h>
#include <projectexplorer/gnumakeparser.h>
#include <coreplugin/variablemanager.h>
#include <QtGui/QFormLayout>
......@@ -48,13 +48,13 @@
using namespace GenericProjectManager;
using namespace GenericProjectManager::Internal;
GenericMakeStep::GenericMakeStep(ProjectExplorer::BuildConfiguration *bc)
: AbstractMakeStep(bc)
GenericMakeStep::GenericMakeStep(ProjectExplorer::BuildConfiguration *bc) :
AbstractProcessStep(bc)
{
}
GenericMakeStep::GenericMakeStep(GenericMakeStep *bs, ProjectExplorer::BuildConfiguration *bc)
: AbstractMakeStep(bs, bc)
GenericMakeStep::GenericMakeStep(GenericMakeStep *bs, ProjectExplorer::BuildConfiguration *bc) :
AbstractProcessStep(bs, bc)
{
m_buildTargets = bs->m_buildTargets;
m_makeArguments = bs->m_makeArguments;
......@@ -73,9 +73,6 @@ GenericBuildConfiguration *GenericMakeStep::genericBuildConfiguration() const
bool GenericMakeStep::init()
{
GenericBuildConfiguration *bc = genericBuildConfiguration();
//TODO
const QString buildParser = genericBuildConfiguration()->genericProject()->buildParser(bc);
setBuildParser(buildParser);
setEnabled(true);
Core::VariableManager *vm = Core::VariableManager::instance();
......@@ -87,7 +84,12 @@ bool GenericMakeStep::init()
setArguments(replacedArguments());
setEnvironment(bc->environment());
return AbstractMakeStep::init();
setOutputParser(new ProjectExplorer::GnuMakeParser(buildDir));
if (bc->genericProject()->toolChain())
appendOutputParser(bc->genericProject()->toolChain()->outputParser());
return AbstractProcessStep::init();
}
void GenericMakeStep::restoreFromLocalMap(const QMap<QString, QVariant> &map)
......@@ -95,7 +97,7 @@ void GenericMakeStep::restoreFromLocalMap(const QMap<QString, QVariant> &map)
m_buildTargets = map.value("buildTargets").toStringList();
m_makeArguments = map.value("makeArguments").toStringList();
m_makeCommand = map.value("makeCommand").toString();
ProjectExplorer::AbstractMakeStep::restoreFromLocalMap(map);
ProjectExplorer::AbstractProcessStep::restoreFromLocalMap(map);
}
void GenericMakeStep::storeIntoLocalMap(QMap<QString, QVariant> &map)
......@@ -103,7 +105,7 @@ void GenericMakeStep::storeIntoLocalMap(QMap<QString, QVariant> &map)
map["buildTargets"] = m_buildTargets;
map["makeArguments"] = m_makeArguments;
map["makeCommand"] = m_makeCommand;
ProjectExplorer::AbstractMakeStep::storeIntoLocalMap(map);
ProjectExplorer::AbstractProcessStep::storeIntoLocalMap(map);
}
QStringList GenericMakeStep::replacedArguments() const
......
......@@ -30,7 +30,7 @@
#ifndef GENERICMAKESTEP_H
#define GENERICMAKESTEP_H
#include <projectexplorer/abstractmakestep.h>
#include <projectexplorer/abstractprocessstep.h>
QT_BEGIN_NAMESPACE
class QListWidgetItem;
......@@ -51,7 +51,7 @@ struct GenericMakeStepSettings
};
class GenericMakeStep : public ProjectExplorer::AbstractMakeStep
class GenericMakeStep : public ProjectExplorer::AbstractProcessStep
{
Q_OBJECT
friend class GenericMakeStepConfigWidget; // TODO remove again?
......
......@@ -424,28 +424,6 @@ void GenericProject::setToolChainType(ProjectExplorer::ToolChain::ToolChainType
}
}
QString GenericProject::buildParser(BuildConfiguration *configuration) const
{
Q_UNUSED(configuration)
if (m_toolChain) {
switch (m_toolChain->type()) {
case ProjectExplorer::ToolChain::GCC:
//case ProjectExplorer::ToolChain::LinuxICC:
case ProjectExplorer::ToolChain::MinGW:
return QLatin1String(ProjectExplorer::Constants::BUILD_PARSER_GCC);
case ProjectExplorer::ToolChain::MSVC:
case ProjectExplorer::ToolChain::WINCE:
return ProjectExplorer::Constants::BUILD_PARSER_MSVC;
default:
break;
} // switch
}
return QString();
}
ProjectExplorer::ToolChain *GenericProject::toolChain() const
{
return m_toolChain;
......
......@@ -103,7 +103,6 @@ public:
virtual QStringList files(FilesMode fileMode) const;
QStringList targets() const;
QString buildParser(ProjectExplorer::BuildConfiguration *configuration) const;
ProjectExplorer::ToolChain *toolChain() const;
bool setFiles(const QStringList &filePaths);
......
/**************************************************************************
**
** 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 "abstractmakestep.h"
#include "projectexplorerconstants.h"
#include "project.h"
#include "buildconfiguration.h"
#include <extensionsystem/pluginmanager.h>
#include <utils/qtcassert.h>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
using ExtensionSystem::PluginManager;
using namespace ProjectExplorer;
namespace {
bool debug = false;
}
AbstractMakeStep::AbstractMakeStep(BuildConfiguration *bc)
: AbstractProcessStep(bc),
m_buildParser(0)
{
}
AbstractMakeStep::AbstractMakeStep(AbstractMakeStep *bs, BuildConfiguration *bc)
: AbstractProcessStep(bs, bc),
m_buildParser(0)
{
}
AbstractMakeStep::~AbstractMakeStep()
{
delete m_buildParser;
m_buildParser = 0;
}
bool AbstractMakeStep::init()
{
m_openDirectories.clear();
addDirectory(workingDirectory());
return AbstractProcessStep::init();
}
QString AbstractMakeStep::buildParser() const
{
return m_buildParserName;
}
void AbstractMakeStep::setBuildParser(const QString &parser)
{
// Nothing to do?
if (m_buildParserName == parser)
return;
// Clean up
delete m_buildParser;
m_buildParser = 0;
m_buildParserName = QString::null;
// Now look for new parser
QList<IBuildParserFactory *> buildParserFactories =
ExtensionSystem::PluginManager::instance()->getObjects<ProjectExplorer::IBuildParserFactory>();
foreach (IBuildParserFactory * factory, buildParserFactories)
if (factory->canCreate(parser)) {
m_buildParser = factory->create(parser);
break;
}
if (m_buildParser) {
m_buildParserName = parser;
connect(m_buildParser, SIGNAL(addToOutputWindow(QString)),
this, SIGNAL(addToOutputWindow(QString)),
Qt::DirectConnection);
connect(m_buildParser, SIGNAL(addToTaskWindow(ProjectExplorer::TaskWindow::Task)),
this, SLOT(slotAddToTaskWindow(ProjectExplorer::TaskWindow::Task)),
Qt::DirectConnection);
connect(m_buildParser, SIGNAL(enterDirectory(QString)),
this, SLOT(addDirectory(QString)),
Qt::DirectConnection);
connect(m_buildParser, SIGNAL(leaveDirectory(QString)),
this, SLOT(removeDirectory(QString)),
Qt::DirectConnection);
}
}
void AbstractMakeStep::slotAddToTaskWindow(const 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. Search for unique file in directories currently indicated as open by GNU make
// (Enter directory xxx, Leave directory xxx...) + current directory
// 3. Check if file is unique in whole project
// 4. Otherwise give up
QList<QFileInfo> possibleFiles;
foreach (const QString &dir, m_openDirectories) {
QFileInfo candidate(dir + QLatin1Char('/') + filePath);
if (debug)
qDebug() << "Checking path " << candidate.filePath();
if (candidate.exists()
&& !possibleFiles.contains(candidate)) {
if (debug)
qDebug() << candidate.filePath() << "exists!";
possibleFiles << candidate;
}
}
if (possibleFiles.count() == 0) {
if (debug)
qDebug() << "No success. Trying all files in project ...";
QString fileName = QFileInfo(filePath).fileName();
foreach (const QString &file, buildConfiguration()->project()->files(ProjectExplorer::Project::AllFiles)) {
QFileInfo candidate(file);
if (candidate.fileName() == fileName) {
if (debug)
qDebug() << "Found " << file;
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 addToTaskWindow(editable);
}
void AbstractMakeStep::addDirectory(const QString &dir)
{
if (!m_openDirectories.contains(dir))
m_openDirectories.insert(dir);
}
void AbstractMakeStep::removeDirectory(const QString &dir)
{
if (m_openDirectories.contains(dir))
m_openDirectories.remove(dir);
}
void AbstractMakeStep::run(QFutureInterface<bool> & fi)
{
AbstractProcessStep::run(fi);
}
void AbstractMakeStep::stdOut(const QString &line)
{
if (m_buildParser)
m_buildParser->stdOutput(line);
AbstractProcessStep::stdOut(line);
}
void AbstractMakeStep::stdError(const QString &line)
{
if (m_buildParser)
m_buildParser->stdError(line);
AbstractProcessStep::stdError(line);
}
......@@ -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(" "))));