2014-04-17 12:47:38 +02:00
/****************************************************************************
* *
2016-01-15 14:57:40 +01:00
* * Copyright ( C ) 2016 The Qt Company Ltd .
* * Contact : https : //www.qt.io/licensing/
2014-04-17 12:47:38 +02:00
* *
* * 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
2016-01-15 14:57:40 +01:00
* * a written agreement between you and The Qt Company . For licensing terms
* * and conditions see https : //www.qt.io/terms-conditions. For further
* * information use the contact form at https : //www.qt.io/contact-us.
2014-04-17 12:47:38 +02:00
* *
2016-01-15 14:57:40 +01:00
* * GNU General Public License Usage
* * Alternatively , this file may be used under the terms of the GNU
* * General Public License version 3 as published by the Free Software
* * Foundation with exceptions as appearing in the file LICENSE . GPL3 - EXCEPT
* * included in the packaging of this file . Please review the following
* * information to ensure the GNU General Public License requirements will
* * be met : https : //www.gnu.org/licenses/gpl-3.0.html.
2014-04-17 12:47:38 +02:00
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "patchtool.h"
# include "messagemanager.h"
# include "icore.h"
# include <utils/synchronousprocess.h>
2016-04-07 13:06:01 +02:00
# include <utils/environment.h>
2014-04-17 12:47:38 +02:00
# include <QProcess>
2015-09-24 23:50:50 +03:00
# include <QProcessEnvironment>
2014-04-17 12:47:38 +02:00
# include <QDir>
# include <QApplication>
static const char settingsGroupC [ ] = " General " ;
static const char legacySettingsGroupC [ ] = " VCS " ;
static const char patchCommandKeyC [ ] = " PatchCommand " ;
static const char patchCommandDefaultC [ ] = " patch " ;
namespace Core {
static QString readLegacyCommand ( )
{
2014-11-16 10:52:41 +02:00
QSettings * s = ICore : : settings ( ) ;
2014-04-17 12:47:38 +02:00
s - > beginGroup ( QLatin1String ( legacySettingsGroupC ) ) ;
const bool legacyExists = s - > contains ( QLatin1String ( patchCommandKeyC ) ) ;
const QString legacyCommand = s - > value ( QLatin1String ( patchCommandKeyC ) , QLatin1String ( patchCommandDefaultC ) ) . toString ( ) ;
if ( legacyExists )
s - > remove ( QLatin1String ( patchCommandKeyC ) ) ;
s - > endGroup ( ) ;
if ( legacyExists & & legacyCommand ! = QLatin1String ( patchCommandDefaultC ) )
PatchTool : : setPatchCommand ( legacyCommand ) ;
return legacyCommand ;
}
QString PatchTool : : patchCommand ( )
{
2014-11-16 10:52:41 +02:00
QSettings * s = ICore : : settings ( ) ;
2014-04-17 12:47:38 +02:00
const QString defaultCommand = readLegacyCommand ( ) ; // replace it with QLatin1String(patchCommandDefaultC) when dropping legacy stuff
s - > beginGroup ( QLatin1String ( settingsGroupC ) ) ;
const QString command = s - > value ( QLatin1String ( patchCommandKeyC ) , defaultCommand ) . toString ( ) ;
s - > endGroup ( ) ;
return command ;
}
void PatchTool : : setPatchCommand ( const QString & newCommand )
{
2014-11-16 10:52:41 +02:00
QSettings * s = ICore : : settings ( ) ;
2014-04-17 12:47:38 +02:00
s - > beginGroup ( QLatin1String ( settingsGroupC ) ) ;
s - > setValue ( QLatin1String ( patchCommandKeyC ) , newCommand ) ;
s - > endGroup ( ) ;
}
2015-09-24 23:50:50 +03:00
static bool runPatchHelper ( const QByteArray & input , const QString & workingDirectory ,
int strip , bool reverse , bool withCrlf )
2014-04-17 12:47:38 +02:00
{
2015-09-24 23:50:50 +03:00
const QString patch = PatchTool : : patchCommand ( ) ;
2014-04-17 12:47:38 +02:00
if ( patch . isEmpty ( ) ) {
MessageManager : : write ( QApplication : : translate ( " Core::PatchTool " , " There is no patch-command configured in the general \" Environment \" settings. " ) ) ;
return false ;
}
2017-07-27 11:14:55 +02:00
if ( ! Utils : : FileName : : fromString ( patch ) . exists ( )
& & ! Utils : : Environment : : systemEnvironment ( ) . searchInPath ( patch ) . exists ( ) ) {
MessageManager : : write ( QApplication : : translate ( " Core::PatchTool " , " The patch-command configured in the general \" Environment \" settings does not exist. " ) ) ;
return false ;
}
2014-04-17 12:47:38 +02:00
QProcess patchProcess ;
if ( ! workingDirectory . isEmpty ( ) )
patchProcess . setWorkingDirectory ( workingDirectory ) ;
2015-09-24 23:50:50 +03:00
QProcessEnvironment env = QProcessEnvironment : : systemEnvironment ( ) ;
2016-04-07 13:06:01 +02:00
Utils : : Environment : : setupEnglishOutput ( & env ) ;
2015-09-24 23:50:50 +03:00
patchProcess . setProcessEnvironment ( env ) ;
2014-02-13 16:43:28 +01:00
QStringList args ;
2015-08-28 08:55:15 +02:00
// Add argument 'apply' when git is used as patch command since git 2.5/Windows
// no longer ships patch.exe.
if ( patch . endsWith ( QLatin1String ( " git " ) , Qt : : CaseInsensitive )
| | patch . endsWith ( QLatin1String ( " git.exe " ) , Qt : : CaseInsensitive ) ) {
args < < QLatin1String ( " apply " ) ;
}
2014-02-13 16:43:28 +01:00
if ( strip > = 0 )
args < < ( QLatin1String ( " -p " ) + QString : : number ( strip ) ) ;
2014-04-17 12:47:38 +02:00
if ( reverse )
args < < QLatin1String ( " -R " ) ;
2015-09-24 23:50:50 +03:00
if ( withCrlf )
args < < QLatin1String ( " --binary " ) ;
2017-01-08 12:05:05 +01:00
MessageManager : : write ( QApplication : : translate ( " Core::PatchTool " , " Running in %1: %2 %3 " ) .
2014-04-17 12:47:38 +02:00
arg ( QDir : : toNativeSeparators ( workingDirectory ) ,
2014-08-29 14:00:18 +02:00
QDir : : toNativeSeparators ( patch ) , args . join ( QLatin1Char ( ' ' ) ) ) ) ;
2014-04-17 12:47:38 +02:00
patchProcess . start ( patch , args ) ;
if ( ! patchProcess . waitForStarted ( ) ) {
MessageManager : : write ( QApplication : : translate ( " Core::PatchTool " , " Unable to launch \" %1 \" : %2 " ) . arg ( patch , patchProcess . errorString ( ) ) ) ;
return false ;
}
patchProcess . write ( input ) ;
patchProcess . closeWriteChannel ( ) ;
QByteArray stdOut ;
QByteArray stdErr ;
2015-04-14 22:30:46 +03:00
if ( ! Utils : : SynchronousProcess : : readDataFromProcess ( patchProcess , 30 , & stdOut , & stdErr , true ) ) {
2014-04-17 12:47:38 +02:00
Utils : : SynchronousProcess : : stopProcess ( patchProcess ) ;
MessageManager : : write ( QApplication : : translate ( " Core::PatchTool " , " A timeout occurred running \" %1 \" " ) . arg ( patch ) ) ;
return false ;
}
2015-09-24 23:50:50 +03:00
if ( ! stdOut . isEmpty ( ) ) {
if ( stdOut . contains ( " (different line endings) " ) & & ! withCrlf ) {
QByteArray crlfInput = input ;
crlfInput . replace ( ' \n ' , " \r \n " ) ;
return runPatchHelper ( crlfInput , workingDirectory , strip , reverse , true ) ;
} else {
MessageManager : : write ( QString : : fromLocal8Bit ( stdOut ) ) ;
}
}
2014-04-17 12:47:38 +02:00
if ( ! stdErr . isEmpty ( ) )
MessageManager : : write ( QString : : fromLocal8Bit ( stdErr ) ) ;
if ( patchProcess . exitStatus ( ) ! = QProcess : : NormalExit ) {
MessageManager : : write ( QApplication : : translate ( " Core::PatchTool " , " \" %1 \" crashed. " ) . arg ( patch ) ) ;
return false ;
}
if ( patchProcess . exitCode ( ) ! = 0 ) {
MessageManager : : write ( QApplication : : translate ( " Core::PatchTool " , " \" %1 \" failed (exit code %2). " ) . arg ( patch ) . arg ( patchProcess . exitCode ( ) ) ) ;
return false ;
}
return true ;
}
2015-09-24 23:50:50 +03:00
bool PatchTool : : runPatch ( const QByteArray & input , const QString & workingDirectory ,
int strip , bool reverse )
{
return runPatchHelper ( input , workingDirectory , strip , reverse , false ) ;
}
2014-04-17 12:47:38 +02:00
} // namespace Core