27#include <QCoreApplication>
31#include <QJsonDocument>
32#include <QJsonParseError>
36QueryDependenciesParallelRunner::QueryDependenciesParallelRunner(QObject *parent)
40 const QString &compilationDatabasePath,
41 const QString &outputFilePath,
42 const QString &queryDependenciesBinary) {
44 compilationDatabasePath_ = compilationDatabasePath;
47 queryDependenciesBinary_ = queryDependenciesBinary.isEmpty()
48 ? QCoreApplication::applicationDirPath() +
"/query-dependencies"
49 : queryDependenciesBinary;
53 std::vector<std::string> sourceFilesVec =
55 compilationDatabasePath.toStdString(), errorMsg);
57 if (sourceFilesVec.empty()) {
58 emit
error(QString(
"Failed to load source files: %1")
59 .arg(QString::fromStdString(errorMsg)));
64 QStringList sourceFiles;
65 for (
const auto& file : sourceFilesVec) {
66 sourceFiles.append(QString::fromStdString(file));
71 runParallel(queryDependenciesBinary_, sourceFiles, outputFilePath);
76 const QStringList &chunkData,
77 const QString &tempOutputPath) {
81 QStringList arguments;
82 arguments <<
"--compilation-database" << compilationDatabasePath_;
83 arguments <<
"--output" << tempOutputPath;
84 if (!clangResourceDir_.isEmpty()) {
85 arguments <<
"--clang-resource-dir" << clangResourceDir_;
89 for (
const QString& sourceFile : chunkData) {
90 arguments <<
"--source" << sourceFile;
97 const QStringList &tempOutputPaths,
98 const QString &finalOutputPath,
99 QString &errorMessage) {
102 QJsonArray mergedFiles;
103 QJsonArray mergedErrors;
105 int successCount = 0;
106 int failureCount = 0;
107 int totalHeaderCount = 0;
110 for (
const QString& tempPath : tempOutputPaths) {
111 QFile file(tempPath);
112 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
113 qDebug() <<
"Warning: Could not open chunk file:" << tempPath;
117 QByteArray jsonData = file.readAll();
120 QJsonParseError parseError;
121 QJsonDocument doc = QJsonDocument::fromJson(jsonData, &parseError);
122 if (parseError.error != QJsonParseError::NoError) {
123 qDebug() <<
"Warning: Could not parse chunk file:" << tempPath
124 <<
"Error:" << parseError.errorString();
128 QJsonObject chunkObj = doc.object();
131 if (chunkObj.contains(
"statistics")) {
132 QJsonObject stats = chunkObj[
"statistics"].toObject();
133 totalCount += stats[
"totalCount"].toInt();
134 successCount += stats[
"successCount"].toInt();
135 failureCount += stats[
"failureCount"].toInt();
136 totalHeaderCount += stats[
"totalHeaderCount"].toInt();
140 if (chunkObj.contains(
"files")) {
141 QJsonArray filesArray = chunkObj[
"files"].toArray();
142 for (
const QJsonValue& val : filesArray) {
143 mergedFiles.append(val);
148 if (chunkObj.contains(
"errors")) {
149 QJsonArray errorsArray = chunkObj[
"errors"].toArray();
150 for (
const QJsonValue& val : errorsArray) {
151 mergedErrors.append(val);
157 QJsonObject finalObj;
158 finalObj[
"statistics"] = QJsonObject{
159 {
"totalCount", totalCount},
160 {
"successCount", successCount},
161 {
"failureCount", failureCount},
162 {
"totalHeaderCount", totalHeaderCount}
164 finalObj[
"files"] = mergedFiles;
166 if (!mergedErrors.isEmpty()) {
167 finalObj[
"errors"] = mergedErrors;
171 QFile outputFile(finalOutputPath);
172 if (!outputFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
173 errorMessage = QString(
"Cannot open output file: %1")
174 .arg(outputFile.errorString());
178 QJsonDocument finalDoc(finalObj);
179 outputFile.write(finalDoc.toJson(QJsonDocument::Indented));
186 int successCount,
int failureCount,
int totalCount) {
194 if (!outputFile.exists()) {
199 if (!outputFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
200 emit
error(QString(
"Failed to read merged output: %1")
201 .arg(outputFile.errorString()));
205 QByteArray jsonData = outputFile.readAll();
208 QJsonParseError parseError;
209 QJsonDocument doc = QJsonDocument::fromJson(jsonData, &parseError);
210 if (parseError.error != QJsonParseError::NoError) {
211 emit
error(QString(
"Failed to parse merged JSON: %1")
212 .arg(parseError.errorString()));
216 QJsonObject jsonObj = doc.object();
220 (jsonObj.contains(
"errors") && !jsonObj[
"errors"].toArray().isEmpty())) {
223 const double seconds = elapsed_.isValid()
224 ?
static_cast<double>(elapsed_.elapsed()) / 1000.0
227 QString(
"query-dependencies (parallel): %1s")
228 .arg(QString::number(seconds,
'f', 2)));
Utilities for interacting with Clang at runtime This includes runtime detection of Clang paths and AS...
std::vector< std::string > getSourceFilesFromCompilationDatabase(const std::string &compDbPath, std::string &errorMessage)
Extract source file paths from a compilation database.
Parallel runner specifically for query-dependencies tool.
Generic parallel process runner for executing multiple instances of a program.
void error(const QString &errorMessage)
Emitted when an error occurs that prevents execution.
void progress(const QString &message)
Emitted with progress updates (e.g., "Completed 3/8 chunks").
QString finalOutputPath_
Final output file path.
virtual void onAllCompleted(int successCount, int failureCount, int totalCount)
Called when all processes have completed (success or failure).
QStringList errorMessages_
Aggregated error messages.
void runParallel(const QString &programPath, const QStringList &inputData, const QString &finalOutputPath)
Start parallel execution.
bool mergeResults(const QStringList &tempOutputPaths, const QString &finalOutputPath, QString &errorMessage) override
Merge JSON dependency files.
void dependenciesReadyWithErrors(const QJsonObject &dependencies, const QStringList &errorMessages)
Emitted when processes complete with some errors.
void run(const QString &compilationDatabasePath, const QString &outputFilePath, const QString &queryDependenciesBinary=QString())
Run query-dependencies in parallel.
void dependenciesReady(const QJsonObject &dependencies)
Emitted when all processes complete successfully.
QStringList prepareProcessArguments(int chunkIndex, const QStringList &chunkData, const QString &tempOutputPath) override
Build command-line arguments for query-dependencies.
void onAllCompleted(int successCount, int failureCount, int totalCount) override
Handle completion and emit domain-specific signals.