1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights. These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
32 **************************************************************************/
34 #include "sbsv2parser.h"
36 #include <extensionsystem/pluginmanager.h>
37 #include <projectexplorer/projectexplorerconstants.h>
38 #include <projectexplorer/taskhub.h>
40 using namespace Qt4ProjectManager;
41 using namespace ProjectExplorer;
42 using namespace ProjectExplorer::Constants;
45 * This parser takes a somewhat unusal approach of just eating most of its
48 * Only when the XML-based log file generated by SBSv2 is announced it will
49 * open that file and parse that. Tasks will then get generated by passing
50 * any CDATA found in the XML file on to its child parsers (using STDERR).
52 * In additon <error> and <warning> tags are reported, too.
55 SbsV2Parser::SbsV2Parser() :
58 setObjectName(QLatin1String("SbsV2Parser"));
59 ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
60 m_hub = pm->getObject<TaskHub>();
63 void SbsV2Parser::stdOutput(const QString &line)
66 if (line.startsWith(QLatin1String("sbs: build log in "))) {
67 QString logfile = QDir::fromNativeSeparators(line.mid(18).trimmed());
68 parseLogFile(logfile);
69 addTask(ProjectExplorer::Task(Task::Unknown, tr("SBSv2 build log"),
71 QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM)));
75 void SbsV2Parser::stdError(const QString &line)
81 void SbsV2Parser::taskAdded(const ProjectExplorer::Task &task)
84 ProjectExplorer::Task tmp(task);
86 if (!tmp.file.isEmpty()) {
87 QFileInfo fi(tmp.file);
88 if (!fi.isAbsolute()) {
89 if (m_currentSource.exists(tmp.file))
90 tmp.file = m_currentSource.absoluteFilePath(tmp.file);
91 else if (m_currentTarget.exists(tmp.file))
92 tmp.file = m_currentTarget.absoluteFilePath(tmp.file);
96 // Do not report tasks from our children via the normal channel:
97 // We do not want them get registered with the Compile output window!
101 void SbsV2Parser::parseLogFile(const QString &file)
104 logFile.open(QIODevice::ReadOnly);
105 m_log.setDevice(&logFile);
107 if (m_log.readNextStartElement()) {
108 if (m_log.name() == QLatin1String("buildlog"))
111 m_log.raiseError(tr("The file '%1' is not a SBSv2 log file.").arg(file));
115 void SbsV2Parser::readBuildLog()
117 Q_ASSERT(m_log.isStartElement() && m_log.name() == QLatin1String("buildlog"));
119 while (m_log.readNextStartElement()) {
120 if (m_log.name() == QLatin1String("error"))
122 else if (m_log.name() == QLatin1String("warning"))
124 else if (m_log.name() == QLatin1String("recipe"))
127 m_log.skipCurrentElement();
131 void SbsV2Parser::readError()
133 Q_ASSERT(m_log.isStartElement() && m_log.name() == QLatin1String("error"));
135 QString error = m_log.readElementText();
136 addTask(Task(Task::Error, error, QString(), -1, Constants::TASK_CATEGORY_BUILDSYSTEM));
139 void SbsV2Parser::readWarning()
141 Q_ASSERT(m_log.isStartElement() && m_log.name() == QLatin1String("warning"));
143 QString warning = m_log.readElementText();
144 addTask(Task(Task::Warning, warning, QString(), -1, Constants::TASK_CATEGORY_BUILDSYSTEM));
147 void SbsV2Parser::readRecipe()
149 Q_ASSERT(m_log.isStartElement() && m_log.name() == QLatin1String("recipe"));
151 const QString name = m_log.attributes().value(QLatin1String("name")).toString();
152 m_currentSource = QDir(m_log.attributes().value("source").toString()).absolutePath();
153 m_currentTarget = QDir(m_log.attributes().value("target").toString()).absolutePath();
157 QXmlStreamReader::TokenType tokenType = QXmlStreamReader::Invalid;
158 while ((tokenType = m_log.readNext()) != QXmlStreamReader::Invalid) {
159 if (tokenType == QXmlStreamReader::Characters) {
160 outputText.append(m_log.text());
161 } else if (tokenType == QXmlStreamReader::StartElement) {
162 if (m_log.name() == QLatin1String("status")) {
163 if (m_log.attributes().value(QLatin1String("exit")) == QLatin1String("failed"))
164 returnCode = m_log.attributes().value(QLatin1String("code")).toString().toInt();
166 } else if (tokenType == QXmlStreamReader::EndElement) {
167 if (m_log.name() == QLatin1String("recipe"))
172 QStringList output = outputText.split(QChar('\n'));
174 foreach (const QString &line, output) {
177 if (line.startsWith(QChar('+'))) {
178 outputText.append(tr("Running command: %1\n").arg(line.mid(2)));
181 outputText.append(line);
182 outputText.append(QChar('\n'));
183 if (name == QLatin1String("compile") || name == QLatin1String("qmake_extra_pre_targetdep"))
184 IOutputParser::stdError(line);
187 if (returnCode != 0) {
188 //: %1 is the SBSv2 build recipe name, %2 the return code of the failed command
189 QString description = tr("Recipe %1 failed with exit code %2.").arg(name).arg(returnCode);
190 m_hub->addTask(Task(Task::Error, description, QString(), -1,
191 ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM));
192 m_hub->addTask(Task(Task::Unknown, outputText, QString(), -1,
193 ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM));
202 # include "qt4projectmanagerplugin.h"
204 # include "projectexplorer/outputparser_test.h"
206 using namespace Qt4ProjectManager::Internal;
208 void Qt4ProjectManagerPlugin::testSbsV2OutputParsers_data()
210 QTest::addColumn<QString>("input");
211 QTest::addColumn<OutputParserTester::Channel>("inputChannel");
212 QTest::addColumn<QString>("childStdOutLines");
213 QTest::addColumn<QString>("childStdErrLines");
214 QTest::addColumn<QList<ProjectExplorer::Task> >("tasks");
215 QTest::addColumn<QString>("outputLines");
218 QTest::newRow("eat stdout")
219 << QString::fromLatin1(" Sometext") << OutputParserTester::STDOUT
220 << QString() << QString()
221 << QList<ProjectExplorer::Task>()
223 QTest::newRow("eat stderr")
224 << QString::fromLatin1(" Sometext") << OutputParserTester::STDERR
225 << QString() << QString()
226 << QList<ProjectExplorer::Task>()
229 QTest::newRow("build log")
230 << QString::fromLatin1("sbs: build log in X:/epoc32/build/Makefile.2010-08-10-15-25-52.log") << OutputParserTester::STDOUT
231 << QString() << QString()
232 << (QList<ProjectExplorer::Task>()
233 << ProjectExplorer::Task(Task::Unknown, QLatin1String("SBSv2 build log"),
234 QLatin1String("X:/epoc32/build/Makefile.2010-08-10-15-25-52.log"), -1,
235 QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM)))
239 void Qt4ProjectManagerPlugin::testSbsV2OutputParsers()
241 OutputParserTester testbench;
242 testbench.appendOutputParser(new SbsV2Parser);
243 QFETCH(QString, input);
244 QFETCH(OutputParserTester::Channel, inputChannel);
245 QFETCH(QList<Task>, tasks);
246 QFETCH(QString, childStdOutLines);
247 QFETCH(QString, childStdErrLines);
248 QFETCH(QString, outputLines);
250 testbench.testParsing(input, inputChannel,
251 tasks, childStdOutLines, childStdErrLines,