2009-02-25 09:15:00 +01:00
/**************************************************************************
2008-12-02 12:01:29 +01:00
* *
* * This file is part of Qt Creator
* *
2010-03-05 11:25:49 +01:00
* * Copyright ( c ) 2010 Nokia Corporation and / or its subsidiary ( - ies ) .
2008-12-02 12:01:29 +01:00
* *
2009-06-17 00:01:27 +10:00
* * Contact : Nokia Corporation ( qt - info @ nokia . com )
2008-12-02 12:01:29 +01:00
* *
2009-02-25 09:15:00 +01:00
* * Commercial Usage
2008-12-02 14:17:16 +01:00
* *
2009-02-25 09:15:00 +01:00
* * 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 .
2008-12-02 14:17:16 +01:00
* *
2009-02-25 09:15:00 +01:00
* * GNU Lesser General Public License Usage
2008-12-02 14:17:16 +01:00
* *
2009-02-25 09:15:00 +01:00
* * 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.
2008-12-02 14:17:16 +01:00
* *
2009-02-25 09:15:00 +01:00
* * If you are unsure which license is appropriate for your use , please
2009-08-14 09:30:56 +02:00
* * contact the sales department at http : //qt.nokia.com/contact.
2008-12-02 12:01:29 +01:00
* *
2009-02-25 09:15:00 +01:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-12-02 16:19:05 +01:00
2008-12-02 12:01:29 +01:00
# include "abstractprocessstep.h"
2009-12-09 13:54:46 +01:00
# include "buildconfiguration.h"
2008-12-02 12:01:29 +01:00
# include "buildstep.h"
2009-12-09 13:54:46 +01:00
# include "ioutputparser.h"
2008-12-02 12:01:29 +01:00
# include "project.h"
2010-02-08 15:50:06 +01:00
# include "target.h"
2008-12-02 16:19:05 +01:00
2009-12-09 13:54:46 +01:00
# include <utils/qtcassert.h>
2008-12-02 12:01:29 +01:00
# include <QtCore/QProcess>
# include <QtCore/QEventLoop>
# include <QtCore/QTimer>
2008-12-03 10:55:18 +01:00
# include <QtGui/QTextDocument>
2008-12-02 12:01:29 +01:00
using namespace ProjectExplorer ;
2010-01-14 17:41:29 +01:00
AbstractProcessStep : : AbstractProcessStep ( BuildConfiguration * bc , const QString & id ) :
BuildStep ( bc , id ) , m_timer ( 0 ) , m_futureInterface ( 0 ) ,
2009-12-09 13:54:46 +01:00
m_enabled ( true ) , m_ignoreReturnValue ( false ) ,
m_process ( 0 ) , m_eventLoop ( 0 ) , m_outputParserChain ( 0 )
2008-12-02 12:01:29 +01:00
{
2009-10-27 14:16:28 +01:00
}
2010-01-14 17:41:29 +01:00
AbstractProcessStep : : AbstractProcessStep ( BuildConfiguration * bc ,
AbstractProcessStep * bs ) :
BuildStep ( bc , bs ) , m_timer ( 0 ) , m_futureInterface ( 0 ) ,
2009-12-09 13:54:46 +01:00
m_enabled ( bs - > m_enabled ) , m_ignoreReturnValue ( bs - > m_ignoreReturnValue ) ,
m_process ( 0 ) , m_eventLoop ( 0 ) , m_outputParserChain ( 0 )
2009-10-27 14:16:28 +01:00
{
2008-12-02 12:01:29 +01:00
}
2009-12-09 13:54:46 +01:00
AbstractProcessStep : : ~ AbstractProcessStep ( )
{
delete m_process ;
delete m_timer ;
// do not delete m_futureInterface, we do not own it.
delete m_outputParserChain ;
}
2009-10-15 19:06:51 +02:00
void AbstractProcessStep : : setCommand ( const QString & cmd )
2008-12-02 12:01:29 +01:00
{
2009-10-15 19:06:51 +02:00
m_command = cmd ;
2008-12-02 12:01:29 +01:00
}
2009-10-15 19:06:51 +02:00
QString AbstractProcessStep : : workingDirectory ( ) const
2008-12-02 12:01:29 +01:00
{
2009-10-15 19:06:51 +02:00
return m_workingDirectory ;
2008-12-02 12:01:29 +01:00
}
2009-12-09 13:54:46 +01:00
void AbstractProcessStep : : setOutputParser ( ProjectExplorer : : IOutputParser * parser )
{
delete m_outputParserChain ;
m_outputParserChain = parser ;
if ( m_outputParserChain ) {
2010-06-08 15:04:42 +02:00
connect ( parser , SIGNAL ( addOutput ( QString , QTextCharFormat ) ) ,
this , SLOT ( outputAdded ( QString , QTextCharFormat ) ) ) ;
2010-03-12 13:53:00 +01:00
connect ( parser , SIGNAL ( addTask ( ProjectExplorer : : Task ) ) ,
this , SLOT ( taskAdded ( ProjectExplorer : : Task ) ) ) ;
2009-12-09 13:54:46 +01:00
}
}
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 ;
}
2009-10-15 19:06:51 +02:00
void AbstractProcessStep : : setWorkingDirectory ( const QString & workingDirectory )
2008-12-02 12:01:29 +01:00
{
2009-10-15 19:06:51 +02:00
m_workingDirectory = workingDirectory ;
2008-12-02 12:01:29 +01:00
}
2009-10-15 19:06:51 +02:00
void AbstractProcessStep : : setArguments ( const QStringList & arguments )
2008-12-02 12:01:29 +01:00
{
2009-10-15 19:06:51 +02:00
m_arguments = arguments ;
2008-12-02 12:01:29 +01:00
}
2009-10-15 19:06:51 +02:00
void AbstractProcessStep : : setEnabled ( bool b )
2009-06-22 16:11:45 +02:00
{
2009-10-15 19:06:51 +02:00
m_enabled = b ;
2009-06-22 16:11:45 +02:00
}
2009-10-15 19:06:51 +02:00
void AbstractProcessStep : : setIgnoreReturnValue ( bool b )
2009-06-22 16:11:45 +02:00
{
2009-10-15 19:06:51 +02:00
m_ignoreReturnValue = b ;
2009-06-22 16:11:45 +02:00
}
2009-10-15 19:06:51 +02:00
void AbstractProcessStep : : setEnvironment ( Environment env )
2008-12-02 12:01:29 +01:00
{
2009-10-15 19:06:51 +02:00
m_environment = env ;
2008-12-02 12:01:29 +01:00
}
2009-10-27 14:16:28 +01:00
bool AbstractProcessStep : : init ( )
2008-12-02 12:01:29 +01:00
{
2009-10-15 19:06:51 +02:00
if ( QFileInfo ( m_command ) . isRelative ( ) ) {
QString searchInPath = m_environment . searchInPath ( m_command ) ;
if ( ! searchInPath . isEmpty ( ) )
m_command = searchInPath ;
}
2008-12-02 12:01:29 +01:00
return true ;
}
2009-12-09 13:54:46 +01:00
void AbstractProcessStep : : run ( QFutureInterface < bool > & fi )
2008-12-02 12:01:29 +01:00
{
m_futureInterface = & fi ;
2008-12-09 11:07:24 +01:00
if ( ! m_enabled ) {
2008-12-02 12:01:29 +01:00
fi . reportResult ( true ) ;
return ;
}
QDir wd ( m_workingDirectory ) ;
if ( ! wd . exists ( ) )
wd . mkpath ( wd . absolutePath ( ) ) ;
m_process = new QProcess ( ) ;
m_process - > setWorkingDirectory ( m_workingDirectory ) ;
m_process - > setEnvironment ( m_environment . toStringList ( ) ) ;
connect ( m_process , SIGNAL ( readyReadStandardOutput ( ) ) ,
this , SLOT ( processReadyReadStdOutput ( ) ) ,
Qt : : DirectConnection ) ;
connect ( m_process , SIGNAL ( readyReadStandardError ( ) ) ,
this , SLOT ( processReadyReadStdError ( ) ) ,
Qt : : DirectConnection ) ;
connect ( m_process , SIGNAL ( finished ( int , QProcess : : ExitStatus ) ) ,
this , SLOT ( slotProcessFinished ( int , QProcess : : ExitStatus ) ) ,
Qt : : DirectConnection ) ;
m_process - > start ( m_command , m_arguments ) ;
2008-12-09 11:07:24 +01:00
if ( ! m_process - > waitForStarted ( ) ) {
2008-12-02 12:01:29 +01:00
processStartupFailed ( ) ;
delete m_process ;
m_process = 0 ;
fi . reportResult ( false ) ;
return ;
}
processStarted ( ) ;
m_timer = new QTimer ( ) ;
connect ( m_timer , SIGNAL ( timeout ( ) ) , this , SLOT ( checkForCancel ( ) ) , Qt : : DirectConnection ) ;
m_timer - > start ( 500 ) ;
m_eventLoop = new QEventLoop ;
m_eventLoop - > exec ( ) ;
m_timer - > stop ( ) ;
delete m_timer ;
2009-10-27 14:16:28 +01:00
m_timer = 0 ;
2008-12-02 12:01:29 +01:00
// The process has finished, leftover data is read in processFinished
2010-04-09 13:10:59 +02:00
processFinished ( m_process - > exitCode ( ) , m_process - > exitStatus ( ) ) ;
bool returnValue = processSucceeded ( m_process - > exitCode ( ) , m_process - > exitStatus ( ) ) | | m_ignoreReturnValue ;
2008-12-02 12:01:29 +01:00
delete m_process ;
m_process = 0 ;
delete m_eventLoop ;
m_eventLoop = 0 ;
fi . reportResult ( returnValue ) ;
2009-10-27 14:16:28 +01:00
m_futureInterface = 0 ;
2008-12-02 12:01:29 +01:00
return ;
}
void AbstractProcessStep : : processStarted ( )
{
2010-06-08 15:04:42 +02:00
QTextCharFormat textCharFormat ;
textCharFormat . setForeground ( Qt : : blue ) ;
2010-07-07 14:38:57 +02:00
emit addOutput ( tr ( " Starting: \" %1 \" %2 \n " ) . arg ( QDir : : toNativeSeparators ( m_command ) , m_arguments . join ( " " ) ) , textCharFormat ) ;
2008-12-02 12:01:29 +01:00
}
2010-04-09 13:10:59 +02:00
void AbstractProcessStep : : processFinished ( int exitCode , QProcess : : ExitStatus status )
2008-12-02 12:01:29 +01:00
{
2010-06-08 15:04:42 +02:00
QTextCharFormat textCharFormat ;
if ( status = = QProcess : : NormalExit & & exitCode = = 0 ) {
textCharFormat . setForeground ( Qt : : blue ) ;
2010-07-07 14:38:57 +02:00
emit addOutput ( tr ( " The process \" %1 \" exited normally. " ) . arg ( QDir : : toNativeSeparators ( m_command ) ) , textCharFormat ) ;
2010-06-08 15:04:42 +02:00
} else if ( status = = QProcess : : NormalExit ) {
textCharFormat . setForeground ( Qt : : red ) ;
textCharFormat . setFontWeight ( QFont : : Bold ) ;
2010-07-07 14:38:57 +02:00
emit addOutput ( tr ( " The process \" %1 \" exited with code %2. " ) . arg ( QDir : : toNativeSeparators ( m_command ) , QString : : number ( m_process - > exitCode ( ) ) ) , textCharFormat ) ;
2010-06-08 15:04:42 +02:00
} else {
textCharFormat . setForeground ( Qt : : red ) ;
textCharFormat . setFontWeight ( QFont : : Bold ) ;
2010-07-07 14:38:57 +02:00
emit addOutput ( tr ( " The process \" %1 \" crashed. " ) . arg ( QDir : : toNativeSeparators ( m_command ) ) , textCharFormat ) ;
2010-06-08 15:04:42 +02:00
}
2008-12-02 12:01:29 +01:00
}
void AbstractProcessStep : : processStartupFailed ( )
{
2010-06-08 15:04:42 +02:00
QTextCharFormat textCharFormat ;
textCharFormat . setForeground ( Qt : : red ) ;
textCharFormat . setFontWeight ( QFont : : Bold ) ;
2010-07-07 14:38:57 +02:00
emit addOutput ( tr ( " Could not start process \" %1 \" " ) . arg ( QDir : : toNativeSeparators ( m_command ) ) , textCharFormat ) ;
2010-04-09 13:10:59 +02:00
}
bool AbstractProcessStep : : processSucceeded ( int exitCode , QProcess : : ExitStatus status )
{
return exitCode = = 0 & & status = = QProcess : : NormalExit ;
2008-12-02 12:01:29 +01:00
}
void AbstractProcessStep : : processReadyReadStdOutput ( )
{
m_process - > setReadChannel ( QProcess : : StandardOutput ) ;
2008-12-09 11:07:24 +01:00
while ( m_process - > canReadLine ( ) ) {
2010-03-23 15:22:05 +01:00
QString line = QString : : fromLocal8Bit ( m_process - > readLine ( ) ) ;
2009-12-09 13:54:46 +01:00
stdOutput ( line ) ;
2008-12-02 12:01:29 +01:00
}
}
2009-12-09 13:54:46 +01:00
void AbstractProcessStep : : stdOutput ( const QString & line )
2008-12-02 12:01:29 +01:00
{
2009-12-09 13:54:46 +01:00
if ( m_outputParserChain )
m_outputParserChain - > stdOutput ( line ) ;
2010-06-08 15:04:42 +02:00
QTextCharFormat textCharFormat ;
2010-06-10 18:02:38 +02:00
emit addOutput ( line , textCharFormat ) ;
2008-12-02 12:01:29 +01:00
}
void AbstractProcessStep : : processReadyReadStdError ( )
{
m_process - > setReadChannel ( QProcess : : StandardError ) ;
2008-12-09 11:07:24 +01:00
while ( m_process - > canReadLine ( ) ) {
2010-03-23 15:22:05 +01:00
QString line = QString : : fromLocal8Bit ( m_process - > readLine ( ) ) ;
2008-12-02 12:01:29 +01:00
stdError ( line ) ;
}
}
void AbstractProcessStep : : stdError ( const QString & line )
{
2009-12-09 13:54:46 +01:00
if ( m_outputParserChain )
m_outputParserChain - > stdError ( line ) ;
2010-06-08 15:04:42 +02:00
QTextCharFormat textCharFormat ;
textCharFormat . setForeground ( Qt : : red ) ;
emit addOutput ( line , textCharFormat ) ;
2008-12-02 12:01:29 +01:00
}
void AbstractProcessStep : : checkForCancel ( )
{
2008-12-09 11:07:24 +01:00
if ( m_futureInterface - > isCanceled ( ) & & m_timer - > isActive ( ) ) {
2008-12-02 12:01:29 +01:00
m_timer - > stop ( ) ;
m_process - > terminate ( ) ;
m_process - > waitForFinished ( 5000 ) ;
m_process - > kill ( ) ;
}
}
2010-03-12 13:53:00 +01:00
void AbstractProcessStep : : taskAdded ( const ProjectExplorer : : Task & task )
2009-12-09 13:54:46 +01:00
{
2010-04-09 13:10:59 +02:00
// Do not bother to report issues if we do not care about the results of
// the buildstep anyway:
if ( m_ignoreReturnValue )
return ;
2010-03-12 13:53:00 +01:00
Task editable ( task ) ;
2009-12-09 13:54:46 +01:00
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 ( ) ;
2010-02-08 15:50:06 +01:00
foreach ( const QString & file , buildConfiguration ( ) - > target ( ) - > project ( ) - > files ( ProjectExplorer : : Project : : AllFiles ) ) {
2009-12-09 13:54:46 +01:00
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 "../"
2010-02-01 12:43:56 +01:00
while ( filePath . startsWith ( QLatin1String ( " ../ " ) ) )
filePath . remove ( 0 , 3 ) ;
2009-12-09 13:54:46 +01:00
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 ) ;
}
2010-06-08 15:04:42 +02:00
void AbstractProcessStep : : outputAdded ( const QString & string , const QTextCharFormat & textCharFormat )
2009-12-09 13:54:46 +01:00
{
2010-06-08 15:04:42 +02:00
emit addOutput ( string , textCharFormat ) ;
2009-12-09 13:54:46 +01:00
}
2008-12-02 12:01:29 +01:00
void AbstractProcessStep : : slotProcessFinished ( int , QProcess : : ExitStatus )
{
2010-03-23 15:22:05 +01:00
QString line = QString : : fromLocal8Bit ( m_process - > readAllStandardError ( ) ) ;
2008-12-09 11:07:24 +01:00
if ( ! line . isEmpty ( ) )
2009-11-24 13:24:47 +01:00
stdError ( line ) ;
2008-12-02 12:01:29 +01:00
2010-03-23 15:22:05 +01:00
line = QString : : fromLocal8Bit ( m_process - > readAllStandardOutput ( ) ) ;
2008-12-09 11:07:24 +01:00
if ( ! line . isEmpty ( ) )
2009-12-09 13:54:46 +01:00
stdOutput ( line ) ;
2008-12-09 11:07:24 +01:00
2008-12-02 12:01:29 +01:00
m_eventLoop - > exit ( 0 ) ;
}