Introduce command-line tool for parsing build output.

It makes the functionality of Qt Creator's build-related
output parsers available on the command-line.
Concrete use case: Run this on the build machines and put
the output in the emails sent to potential build breakers.

Change-Id: Iea6870ed976790854aecfe3cdc0d5b2296b6bced
Reviewed-by: Tobias Hunger <tobias.hunger@digia.com>
This commit is contained in:
Christian Kandeler
2013-10-17 18:47:44 +02:00
parent 242b7bd209
commit bcd704d7bf
13 changed files with 322 additions and 9 deletions

View File

@@ -37,7 +37,7 @@
namespace ProjectExplorer { namespace ProjectExplorer {
class ClangParser : public ProjectExplorer::GccParser class PROJECTEXPLORER_EXPORT ClangParser : public ProjectExplorer::GccParser
{ {
Q_OBJECT Q_OBJECT

View File

@@ -38,7 +38,7 @@
namespace ProjectExplorer { namespace ProjectExplorer {
class GccParser : public ProjectExplorer::IOutputParser class PROJECTEXPLORER_EXPORT GccParser : public ProjectExplorer::IOutputParser
{ {
Q_OBJECT Q_OBJECT

View File

@@ -38,7 +38,7 @@
namespace ProjectExplorer { namespace ProjectExplorer {
class MsvcParser : public ProjectExplorer::IOutputParser class PROJECTEXPLORER_EXPORT MsvcParser : public ProjectExplorer::IOutputParser
{ {
Q_OBJECT Q_OBJECT

View File

@@ -38,7 +38,7 @@
namespace ProjectExplorer { namespace ProjectExplorer {
class OsParser : public ProjectExplorer::IOutputParser class PROJECTEXPLORER_EXPORT OsParser : public ProjectExplorer::IOutputParser
{ {
Q_OBJECT Q_OBJECT

View File

@@ -33,7 +33,6 @@
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
using namespace QmakeProjectManager; using namespace QmakeProjectManager;
using namespace QmakeProjectManager::Internal;
using ProjectExplorer::Task; using ProjectExplorer::Task;
QMakeParser::QMakeParser() : m_error(QLatin1String("^(.+):(\\d+):\\s(.+)$")) QMakeParser::QMakeParser() : m_error(QLatin1String("^(.+):(\\d+):\\s(.+)$"))

View File

@@ -30,14 +30,15 @@
#ifndef QMAKEPARSER_H #ifndef QMAKEPARSER_H
#define QMAKEPARSER_H #define QMAKEPARSER_H
#include "qmakeprojectmanager_global.h"
#include <projectexplorer/ioutputparser.h> #include <projectexplorer/ioutputparser.h>
#include <QRegExp> #include <QRegExp>
namespace QmakeProjectManager { namespace QmakeProjectManager {
namespace Internal {
class QMakeParser : public ProjectExplorer::IOutputParser class QT4PROJECTMANAGER_EXPORT QMakeParser : public ProjectExplorer::IOutputParser
{ {
Q_OBJECT Q_OBJECT
@@ -49,7 +50,6 @@ private:
QRegExp m_error; QRegExp m_error;
}; };
} // namesapce Internal
} // namespace QmakeProjectManager } // namespace QmakeProjectManager
#endif // QMAKEPARSER_H #endif // QMAKEPARSER_H

View File

@@ -0,0 +1,25 @@
TEMPLATE = app
TARGET = buildoutputparser
QTC_LIB_DEPENDS = utils
QTC_PLUGIN_DEPENDS = projectexplorer qtsupport qt4projectmanager
QT = core gui
CONFIG += console
CONFIG -= app_bundle
include(../../../qtcreator.pri)
include(../../rpath.pri)
LIBS += -L$$IDE_PLUGIN_PATH/QtProject
win32|equals(TEST, 1):DEFINES += HAS_MSVC_PARSER
DESTDIR = $$IDE_BIN_PATH
target.path = /bin
INSTALLS += target
SOURCES = \
main.cpp \
outputprocessor.cpp
HEADERS = \
outputprocessor.h

View File

@@ -0,0 +1,20 @@
import qbs
import QtcTool
QtcTool {
name: "buildoutputparser"
Depends { name: "Qt"; submodules: ["core", "widgets"]; }
Depends { name: "ProjectExplorer" }
Depends { name: "QtSupport" }
Depends { name: "Qt4ProjectManager" }
Depends { name: "Utils" }
files: [
"main.cpp",
"outputprocessor.cpp", "outputprocessor.h",
]
cpp.rpaths: base.concat(qbs.targetOS.contains("osx")
? ["@executable_path/../"]
: ["$ORIGIN/../" + project.ide_plugin_path + "/QtProject"])
cpp.defines: base.concat(qbs.targetOS.contains("windows") || project.testsEnabled
? ["HAS_MSVC_PARSER"] : [])
}

View File

@@ -0,0 +1,107 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "outputprocessor.h"
#include <QCoreApplication>
#include <QFile>
#include <QMetaObject>
#include <QFileInfo>
#include <QStringList>
#include <stdio.h>
#include <stdlib.h>
static void printUsage()
{
fprintf(stderr, "Usage: %s [--type <compiler type>] <file>\n",
qPrintable(QFileInfo(QCoreApplication::applicationFilePath()).fileName()));
fprintf(stderr, "Possible compiler types: gcc, clang%s. Default is gcc.\n",
#ifdef HAS_MSVC_PARSER
", msvc"
#else
""
#endif
);
}
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QStringList args = app.arguments().mid(1);
QString filePath;
CompilerType compilerType = CompilerTypeGcc;
while (filePath.isEmpty() && !args.isEmpty()) {
const QString currentArg = args.takeFirst();
if (currentArg == QLatin1String("--type")) {
if (args.isEmpty()) {
fprintf(stderr, "Error: Option --type needs argument.\n");
printUsage();
return EXIT_FAILURE;
}
const QString typeString = args.takeFirst();
if (typeString == QLatin1String("gcc")) {
compilerType = CompilerTypeGcc;
} else if (typeString == QLatin1String("clang")) {
compilerType = CompilerTypeClang;
#ifdef HAS_MSVC_PARSER
} else if (typeString == QLatin1String("msvc")) {
compilerType = CompilerTypeMsvc;
#endif
} else {
fprintf(stderr, "Invalid compiler type '%s'.\n", qPrintable(typeString));
printUsage();
return EXIT_FAILURE;
}
} else {
filePath = currentArg;
}
}
if (filePath.isEmpty()) {
fprintf(stderr, "Error: No file supplied.\n");
printUsage();
return EXIT_FAILURE;
}
if (!args.isEmpty())
qDebug("Ignoring extraneous parameters '%s'.\n", qPrintable(args.join(QLatin1String(" "))));
QFile compilerOutputFile(filePath);
if (!compilerOutputFile.open(QIODevice::ReadOnly)) {
fprintf(stderr, "Error opening file '%s': %s\n", qPrintable(compilerOutputFile.fileName()),
qPrintable(compilerOutputFile.errorString()));
return EXIT_FAILURE;
}
CompilerOutputProcessor cop(compilerType, compilerOutputFile);
QMetaObject::invokeMethod(&cop, "start", Qt::QueuedConnection);
return app.exec();
}

View File

@@ -0,0 +1,98 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "outputprocessor.h"
#include <projectexplorer/clangparser.h>
#include <projectexplorer/gccparser.h>
#include <projectexplorer/gnumakeparser.h>
#include <projectexplorer/osparser.h>
#include <qt4projectmanager/qmakeparser.h>
#include <qtsupport/qtparser.h>
#include <utils/fileutils.h>
#ifdef HAS_MSVC_PARSER
#include <projectexplorer/msvcparser.h>
#endif
#include <QIODevice>
#include <QTextStream>
#include <stdio.h>
CompilerOutputProcessor::CompilerOutputProcessor(CompilerType compilerType, QIODevice &source)
: m_compilerType(compilerType)
, m_source(source)
, m_ostream(new QTextStream(stdout, QIODevice::WriteOnly))
{
}
CompilerOutputProcessor::~CompilerOutputProcessor()
{
delete m_ostream;
}
void CompilerOutputProcessor::start()
{
ProjectExplorer::OsParser parser;
parser.appendOutputParser(new QmakeProjectManager::QMakeParser);
parser.appendOutputParser(new ProjectExplorer::GnuMakeParser);
parser.appendOutputParser(new QtSupport::QtParser);
switch (m_compilerType) {
case CompilerTypeGcc:
parser.appendOutputParser(new ProjectExplorer::GccParser);
break;
case CompilerTypeClang:
parser.appendOutputParser(new ProjectExplorer::ClangParser);
break;
#ifdef HAS_MSVC_PARSER
case CompilerTypeMsvc:
parser.appendOutputParser(new ProjectExplorer::MsvcParser);
break;
#endif
}
connect(&parser, SIGNAL(addTask(ProjectExplorer::Task)),
SLOT(handleTask(ProjectExplorer::Task)));
while (!m_source.atEnd())
parser.stdError(QString::fromLocal8Bit(m_source.readLine().trimmed()));
qApp->quit();
}
void CompilerOutputProcessor::handleTask(const ProjectExplorer::Task &task)
{
const QString &fileName = task.file.toString();
if (!fileName.isEmpty()) {
*m_ostream << fileName;
if (task.line != -1)
*m_ostream << ':' << task.line;
*m_ostream << ": ";
}
*m_ostream << task.description << endl;
}

View File

@@ -0,0 +1,62 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include <QObject>
QT_BEGIN_NAMESPACE
class QIODevice;
class QTextStream;
QT_END_NAMESPACE
namespace ProjectExplorer { class Task; }
enum CompilerType {
CompilerTypeGcc,
CompilerTypeClang,
#ifdef HAS_MSVC_PARSER
CompilerTypeMsvc
#endif
};
class CompilerOutputProcessor : public QObject
{
Q_OBJECT
public:
CompilerOutputProcessor(CompilerType compilerType, QIODevice &source);
~CompilerOutputProcessor();
private slots:
void start();
void handleTask(const ProjectExplorer::Task &task);
private:
const CompilerType m_compilerType;
QIODevice &m_source;
QTextStream * const m_ostream;
};

View File

@@ -5,7 +5,8 @@ SUBDIRS = qtpromaker \
../plugins/cpaster/frontend \ ../plugins/cpaster/frontend \
sdktool \ sdktool \
valgrindfake \ valgrindfake \
3rdparty 3rdparty \
buildoutputparser
win32 { win32 {
SUBDIRS += qtcdebugger SUBDIRS += qtcdebugger

View File

@@ -3,6 +3,7 @@ import qbs
Project { Project {
name: "Tools" name: "Tools"
references: [ references: [
"buildoutputparser/buildoutputparser.qbs",
"qtcdebugger/qtcdebugger.qbs", "qtcdebugger/qtcdebugger.qbs",
"qtcreatorcrashhandler/qtcreatorcrashhandler.qbs", "qtcreatorcrashhandler/qtcreatorcrashhandler.qbs",
"qtpromaker/qtpromaker.qbs", "qtpromaker/qtpromaker.qbs",