From f71b3652f40eb046957c7aff2f47e153d1f4a7d5 Mon Sep 17 00:00:00 2001
From: Tobias Hunger <tobias.hunger@theqtcompany.com>
Date: Tue, 26 Jan 2016 17:26:46 +0100
Subject: [PATCH] CMake: Read CMakeCache.txt

Read the configuration from CMakeCache.txt files.

Change-Id: I7ddf9c9727420634086c973d0134059aac37ace0
Reviewed-by: Tim Jenssen <tim.jenssen@theqtcompany.com>
---
 .../cmakeprojectmanager/builddirmanager.cpp   | 92 +++++++++++++++++++
 .../cmakeprojectmanager/builddirmanager.h     |  3 +
 2 files changed, 95 insertions(+)

diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.cpp b/src/plugins/cmakeprojectmanager/builddirmanager.cpp
index fac3b491291..3a753fe9630 100644
--- a/src/plugins/cmakeprojectmanager/builddirmanager.cpp
+++ b/src/plugins/cmakeprojectmanager/builddirmanager.cpp
@@ -42,6 +42,7 @@
 #include <utils/synchronousprocess.h>
 
 #include <QDateTime>
+#include <QFile>
 #include <QFileInfo>
 #include <QFileSystemWatcher>
 #include <QRegularExpression>
@@ -187,6 +188,11 @@ QList<ProjectExplorer::FileNode *> BuildDirManager::files() const
     return m_files;
 }
 
+CMakeConfig BuildDirManager::configuration() const
+{
+    return parseConfiguration();
+}
+
 void BuildDirManager::extractData()
 {
     const Utils::FileName topCMake
@@ -367,5 +373,91 @@ void BuildDirManager::processCMakeError()
     });
 }
 
+static QByteArray trimCMakeCacheLine(const QByteArray &in) {
+    int start = 0;
+    while (start < in.count() && (in.at(start) == ' ' || in.at(start) == '\t'))
+        ++start;
+
+    return in.mid(start, in.count() - start - 1);
+}
+
+static QByteArrayList splitCMakeCacheLine(const QByteArray &line) {
+    const int colonPos = line.indexOf(':');
+    if (colonPos < 0)
+        return QByteArrayList();
+
+    const int equalPos = line.indexOf('=', colonPos + 1);
+    if (equalPos < colonPos)
+        return QByteArrayList();
+
+    return QByteArrayList() << line.mid(0, colonPos)
+                            << line.mid(colonPos + 1, equalPos - colonPos - 1)
+                            << line.mid(equalPos + 1);
+}
+
+static CMakeConfigItem::Type fromByteArray(const QByteArray &type) {
+    if (type == "BOOL")
+        return CMakeConfigItem::BOOL;
+    if (type == "STRING")
+        return CMakeConfigItem::STRING;
+    if (type == "FILEPATH")
+        return CMakeConfigItem::FILEPATH;
+    if (type == "PATH")
+        return CMakeConfigItem::PATH;
+    QTC_CHECK(type == "INTERNAL" || type == "STATIC");
+
+    return CMakeConfigItem::INTERNAL;
+}
+
+CMakeConfig BuildDirManager::parseConfiguration() const
+{
+    CMakeConfig result;
+    const QString cacheFile = QDir(m_buildDir.toString()).absoluteFilePath(QLatin1String("CMakeCache.txt"));
+    QFile cache(cacheFile);
+    if (!cache.open(QIODevice::ReadOnly | QIODevice::Text))
+        return CMakeConfig();
+
+    QSet<QByteArray> advancedSet;
+    QByteArray documentation;
+    while (!cache.atEnd()) {
+        const QByteArray line = trimCMakeCacheLine(cache.readLine());
+
+        if (line.isEmpty() || line.startsWith('#'))
+            continue;
+
+        if (line.startsWith("//")) {
+            documentation = line.mid(2);
+            continue;
+        }
+
+        const QByteArrayList pieces = splitCMakeCacheLine(line);
+        if (pieces.isEmpty())
+            continue;
+
+        QTC_ASSERT(pieces.count() == 3, continue);
+        const QByteArray key = pieces.at(0);
+        const QByteArray type = pieces.at(1);
+        const QByteArray value = pieces.at(2);
+
+        if (key.endsWith("-ADVANCED") && value == "1") {
+            advancedSet.insert(key.left(key.count() - 9 /* "-ADVANCED" */));
+        } else {
+            CMakeConfigItem::Type t = fromByteArray(type);
+            if (t != CMakeConfigItem::INTERNAL)
+                result << CMakeConfigItem(key, t, documentation, value);
+        }
+    }
+
+    // Set advanced flags:
+    for (int i = 0; i < result.count(); ++i) {
+        CMakeConfigItem &item = result[i];
+        item.isAdvanced = advancedSet.contains(item.key);
+    }
+
+    Utils::sort(result, CMakeConfigItem::sortOperator());
+
+    return result;
+}
+
 } // namespace Internal
 } // namespace CMakeProjectManager
diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.h b/src/plugins/cmakeprojectmanager/builddirmanager.h
index 6b903910e3a..7d234b5bbbd 100644
--- a/src/plugins/cmakeprojectmanager/builddirmanager.h
+++ b/src/plugins/cmakeprojectmanager/builddirmanager.h
@@ -78,6 +78,7 @@ public:
     QString projectName() const;
     QList<CMakeBuildTarget> buildTargets() const;
     QList<ProjectExplorer::FileNode *> files() const;
+    CMakeConfig configuration() const;
 
 signals:
     void parsingStarted() const;
@@ -93,6 +94,8 @@ private:
     void processCMakeOutput();
     void processCMakeError();
 
+    CMakeConfig parseConfiguration() const;
+
     const Utils::FileName m_sourceDir;
     Utils::FileName m_buildDir;
     const ProjectExplorer::Kit *const m_kit;
-- 
GitLab