OSDN Git Service

88734e010c41872bea23931eef1804af864d5ef6
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qt4projectmanager / qt-s60 / sbsv2parser.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
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
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
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.
24 **
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.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "sbsv2parser.h"
35
36 #include <extensionsystem/pluginmanager.h>
37 #include <projectexplorer/projectexplorerconstants.h>
38 #include <projectexplorer/taskhub.h>
39
40 using namespace Qt4ProjectManager;
41 using namespace ProjectExplorer;
42 using namespace ProjectExplorer::Constants;
43
44 /*
45  * This parser takes a somewhat unusal approach of just eating most of its
46  * input :-)
47  *
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).
51  *
52  * In additon <error> and <warning> tags are reported, too.
53  */
54
55 SbsV2Parser::SbsV2Parser() :
56     m_hub(0)
57 {
58     setObjectName(QLatin1String("SbsV2Parser"));
59     ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
60     m_hub = pm->getObject<TaskHub>();
61 }
62
63 void SbsV2Parser::stdOutput(const QString &line)
64 {
65     // Eat most output!
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"),
70                                       logfile, -1,
71                                       QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM)));
72     }
73 }
74
75 void SbsV2Parser::stdError(const QString &line)
76 {
77     // Eat all output!
78     Q_UNUSED(line);
79 }
80
81 void SbsV2Parser::taskAdded(const ProjectExplorer::Task &task)
82 {
83     // Fix pathes:
84     ProjectExplorer::Task tmp(task);
85
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);
93         }
94     }
95
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!
98     m_hub->addTask(tmp);
99 }
100
101 void SbsV2Parser::parseLogFile(const QString &file)
102 {
103     QFile logFile(file);
104     logFile.open(QIODevice::ReadOnly);
105     m_log.setDevice(&logFile);
106
107     if (m_log.readNextStartElement()) {
108          if (m_log.name() == QLatin1String("buildlog"))
109              readBuildLog();
110          else
111              m_log.raiseError(tr("The file '%1' is not a SBSv2 log file.").arg(file));
112      }
113 }
114
115 void SbsV2Parser::readBuildLog()
116 {
117     Q_ASSERT(m_log.isStartElement() && m_log.name() == QLatin1String("buildlog"));
118
119      while (m_log.readNextStartElement()) {
120          if (m_log.name() == QLatin1String("error"))
121              readError();
122          else if (m_log.name() == QLatin1String("warning"))
123              readWarning();
124          else if (m_log.name() == QLatin1String("recipe"))
125              readRecipe();
126          else
127              m_log.skipCurrentElement();
128      }
129 }
130
131 void SbsV2Parser::readError()
132 {
133     Q_ASSERT(m_log.isStartElement() && m_log.name() == QLatin1String("error"));
134
135     QString error = m_log.readElementText();
136     addTask(Task(Task::Error, error, QString(), -1, Constants::TASK_CATEGORY_BUILDSYSTEM));
137 }
138
139 void SbsV2Parser::readWarning()
140 {
141     Q_ASSERT(m_log.isStartElement() && m_log.name() == QLatin1String("warning"));
142
143     QString warning = m_log.readElementText();
144     addTask(Task(Task::Warning, warning, QString(), -1, Constants::TASK_CATEGORY_BUILDSYSTEM));
145 }
146
147 void SbsV2Parser::readRecipe()
148 {
149     Q_ASSERT(m_log.isStartElement() && m_log.name() == QLatin1String("recipe"));
150
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();
154
155     int returnCode = 0;
156     QString outputText;
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();
165             }
166         } else if (tokenType == QXmlStreamReader::EndElement) {
167             if (m_log.name() == QLatin1String("recipe"))
168                 break;
169         }
170     }
171
172     QStringList output = outputText.split(QChar('\n'));
173     outputText.clear();
174     foreach (const QString &line, output) {
175         if (line.isEmpty())
176             continue;
177         if (line.startsWith(QChar('+'))) {
178             outputText.append(tr("Running command: %1\n").arg(line.mid(2)));
179             continue;
180         }
181         outputText.append(line);
182         outputText.append(QChar('\n'));
183         if (name == QLatin1String("compile") || name == QLatin1String("qmake_extra_pre_targetdep"))
184             IOutputParser::stdError(line);
185     }
186
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));
194     }
195 }
196
197 // Unit tests:
198
199 #ifdef WITH_TESTS
200 #   include <QTest>
201
202 #   include "qt4projectmanagerplugin.h"
203
204 #   include "projectexplorer/outputparser_test.h"
205
206 using namespace Qt4ProjectManager::Internal;
207
208 void Qt4ProjectManagerPlugin::testSbsV2OutputParsers_data()
209 {
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");
216
217
218     QTest::newRow("eat stdout")
219             << QString::fromLatin1("   Sometext") << OutputParserTester::STDOUT
220             << QString() << QString()
221             << QList<ProjectExplorer::Task>()
222             << QString();
223     QTest::newRow("eat stderr")
224             << QString::fromLatin1("   Sometext") << OutputParserTester::STDERR
225             << QString() << QString()
226             << QList<ProjectExplorer::Task>()
227             << QString();
228
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)))
236             << QString();
237 }
238
239 void Qt4ProjectManagerPlugin::testSbsV2OutputParsers()
240 {
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);
249
250     testbench.testParsing(input, inputChannel,
251                           tasks, childStdOutLines, childStdErrLines,
252                           outputLines);
253 }
254 #endif