File indexing completed on 2024-05-05 04:39:27
0001 /* 0002 SPDX-FileCopyrightText: 2020 Friedrich W. H. Kossebau <kossebau@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "compileanalyzejob.h" 0008 0009 // lib 0010 #include <debug.h> 0011 // KF 0012 #include <KLocalizedString> 0013 // Qt 0014 #include <QTemporaryFile> 0015 0016 namespace KDevelop 0017 { 0018 0019 QString CompileAnalyzeJob::spaceEscapedString(const QString& s) 0020 { 0021 return QString(s).replace(QLatin1Char(' '), QLatin1String("\\ ")); 0022 } 0023 0024 CompileAnalyzeJob::CompileAnalyzeJob(QObject* parent) 0025 : OutputExecuteJob(parent) 0026 { 0027 setCapabilities(KJob::Killable); 0028 setStandardToolView(IOutputView::TestView); 0029 setBehaviours(IOutputView::AutoScroll); 0030 setProperties(JobProperties(DisplayStdout | DisplayStderr | PostProcessOutput)); 0031 } 0032 0033 CompileAnalyzeJob::~CompileAnalyzeJob() 0034 { 0035 doKill(); 0036 0037 if (!m_makeFilePath.isEmpty()) { 0038 QFile::remove(m_makeFilePath); 0039 } 0040 } 0041 0042 void CompileAnalyzeJob::setParallelJobCount(int parallelJobCount) 0043 { 0044 m_parallelJobCount = parallelJobCount; 0045 } 0046 0047 void CompileAnalyzeJob::setBuildDirectoryRoot(const QString& buildDir) 0048 { 0049 m_buildDir = buildDir; 0050 } 0051 0052 void CompileAnalyzeJob::setCommand(const QString& command, bool verboseOutput) 0053 { 0054 m_command = command; 0055 m_verboseOutput = verboseOutput; 0056 } 0057 0058 void CompileAnalyzeJob::setToolDisplayName(const QString& toolDisplayName) 0059 { 0060 m_toolDisplayName = toolDisplayName; 0061 0062 m_fileStartedRegex = QRegularExpression(m_toolDisplayName + QLatin1String(" check started for (.+)$")); 0063 m_fileFinishedRegex = QRegularExpression(m_toolDisplayName + QLatin1String(" check finished for (.+)$")); 0064 } 0065 0066 void CompileAnalyzeJob::setSources(const QStringList& sources) 0067 { 0068 m_sources = sources; 0069 } 0070 0071 void CompileAnalyzeJob::generateMakefile() 0072 { 0073 QTemporaryFile makefile(m_buildDir + QLatin1String("/kdevcompileanalyzerXXXXXX.makefile")); 0074 makefile.setAutoRemove(false); 0075 makefile.open(); 0076 m_makeFilePath = makefile.fileName(); 0077 0078 QTextStream scriptStream(&makefile); 0079 0080 scriptStream << QStringLiteral("SOURCES ="); 0081 for (const auto& source : qAsConst(m_sources)) { 0082 scriptStream << QLatin1String(" \\\n\t") << spaceEscapedString(source); 0083 } 0084 scriptStream << QLatin1Char('\n'); 0085 0086 scriptStream << QLatin1String("COMMAND = "); 0087 if (!m_verboseOutput) { 0088 scriptStream << QLatin1Char('@'); 0089 } 0090 scriptStream << m_command << QLatin1Char('\n'); 0091 0092 scriptStream << QLatin1String(".PHONY: all $(SOURCES)\n"); 0093 scriptStream << QLatin1String("all: $(SOURCES)\n"); 0094 scriptStream << QLatin1String("$(SOURCES):\n"); 0095 0096 scriptStream << QLatin1String("\t@echo '") << m_toolDisplayName << QLatin1String(" check started for $@'\n"); 0097 // Wrap filename ($@) with quotas to handle "whitespaced" file names. 0098 scriptStream << QLatin1String("\t$(COMMAND) \"$@\"\n"); 0099 scriptStream << QLatin1String("\t@echo '") << m_toolDisplayName << QLatin1String(" check finished for $@'\n"); 0100 0101 makefile.close(); 0102 } 0103 0104 void CompileAnalyzeJob::start() 0105 { 0106 // TODO: check success of creation 0107 generateMakefile(); 0108 0109 *this << QStringList{ 0110 QStringLiteral("make"), 0111 QStringLiteral("-j"), 0112 QString::number(m_parallelJobCount), 0113 QStringLiteral("-k"), // keep-going 0114 QStringLiteral("-f"), 0115 m_makeFilePath, 0116 }; 0117 0118 qCDebug(KDEV_COMPILEANALYZER) << "executing:" << commandLine().join(QLatin1Char(' ')); 0119 0120 m_finishedCount = 0; 0121 m_totalCount = m_sources.size(); 0122 0123 setPercent(0); 0124 0125 KDevelop::OutputExecuteJob::start(); 0126 } 0127 0128 void CompileAnalyzeJob::parseProgress(const QStringList& lines) 0129 { 0130 for (const auto& line : lines) { 0131 const auto startedMatch = m_fileStartedRegex.match(line); 0132 if (startedMatch.hasMatch()) { 0133 emit infoMessage(this, startedMatch.captured(1)); 0134 continue; 0135 } 0136 0137 const auto finishedMatch = m_fileFinishedRegex.match(line); 0138 if (finishedMatch.hasMatch()) { 0139 ++m_finishedCount; 0140 setPercent(static_cast<double>(m_finishedCount)/m_totalCount * 100); 0141 continue; 0142 } 0143 } 0144 } 0145 0146 void CompileAnalyzeJob::postProcessStdout(const QStringList& lines) 0147 { 0148 parseProgress(lines); 0149 0150 KDevelop::OutputExecuteJob::postProcessStdout(lines); 0151 } 0152 0153 void CompileAnalyzeJob::childProcessExited(int exitCode, QProcess::ExitStatus exitStatus) 0154 { 0155 qCDebug(KDEV_COMPILEANALYZER) << "Process Finished, exitCode" << exitCode << "process exit status" << exitStatus; 0156 0157 setPercent(100); 0158 0159 KDevelop::OutputExecuteJob::childProcessExited(exitCode, exitStatus); 0160 } 0161 0162 } 0163 0164 #include "moc_compileanalyzejob.cpp"