CMake: Check CMakeCache.txt for changes

Check CMakeCache.txt for changes and ask whether to apply these to the
project going forward.

This will only consider settings that were previously changed by Qt Creator
and will not pick up on newly changed settings.

Change-Id: Ia20c67bc2a5e9965243f08003c10ec684875387f
Reviewed-by: Tim Jenssen <tim.jenssen@theqtcompany.com>
This commit is contained in:
Tobias Hunger
2016-05-13 16:19:31 +02:00
parent 8c316aa1c1
commit 5bc0d12c6d
3 changed files with 72 additions and 5 deletions

View File

@@ -30,6 +30,7 @@
#include "cmakeprojectmanager.h"
#include "cmaketool.h"
#include <coreplugin/icore.h>
#include <coreplugin/messagemanager.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <projectexplorer/kit.h>
@@ -49,6 +50,7 @@
#include <QFile>
#include <QFileInfo>
#include <QFileSystemWatcher>
#include <QMessageBox>
#include <QRegularExpression>
#include <QSet>
#include <QTemporaryDir>
@@ -91,7 +93,7 @@ static QStringList toArguments(const CMakeConfig &config, const ProjectExplorer:
// BuildDirManager:
// --------------------------------------------------------------------
BuildDirManager::BuildDirManager(const CMakeBuildConfiguration *bc) :
BuildDirManager::BuildDirManager(CMakeBuildConfiguration *bc) :
m_buildConfiguration(bc),
m_watcher(new QFileSystemWatcher(this))
{
@@ -201,6 +203,8 @@ bool BuildDirManager::persistCMakeState()
void BuildDirManager::parse()
{
checkConfiguration();
CMakeTool *tool = CMakeKitInformation::cmakeTool(kit());
const QString generator = CMakeGeneratorKitInformation::generator(kit());
@@ -275,6 +279,8 @@ CMakeConfig BuildDirManager::parsedConfiguration() const
if (m_cmakeCache.isEmpty()) {
Utils::FileName cacheFile = workDirectory();
cacheFile.appendPath(QLatin1String("CMakeCache.txt"));
if (!cacheFile.exists())
return m_cmakeCache;
QString errorMessage;
m_cmakeCache = parseConfiguration(cacheFile, &errorMessage);
if (!errorMessage.isEmpty())
@@ -350,6 +356,7 @@ void BuildDirManager::extractData()
return;
m_watcher->addPath(cbpFile);
m_watcher->addPath(workDirectory().toString() + QLatin1String("/CMakeCache.txt"));
// setFolderName
CMakeCbpParser cbpparser;
@@ -512,6 +519,61 @@ void BuildDirManager::processCMakeError()
});
}
void BuildDirManager::checkConfiguration()
{
if (m_tempDir) // always throw away changes in the tmpdir!
return;
ProjectExplorer::Kit *k = m_buildConfiguration->target()->kit();
const CMakeConfig cache = parsedConfiguration();
if (cache.isEmpty())
return; // No cache file yet.
CMakeConfig newConfig;
QSet<QString> changedKeys;
QSet<QString> removedKeys;
foreach (const CMakeConfigItem &iBc, intendedConfiguration()) {
const CMakeConfigItem &iCache
= Utils::findOrDefault(cache, [&iBc](const CMakeConfigItem &i) { return i.key == iBc.key; });
if (iCache.isNull()) {
removedKeys << QString::fromUtf8(iBc.key);
} else if (QString::fromUtf8(iCache.value) != iBc.expandedValue(k)) {
changedKeys << QString::fromUtf8(iBc.key);
newConfig.append(iCache);
} else {
newConfig.append(iBc);
}
}
if (!changedKeys.isEmpty() || !removedKeys.isEmpty()) {
QSet<QString> total = removedKeys + changedKeys;
QStringList keyList = total.toList();
Utils::sort(keyList);
QString table = QLatin1String("<table>");
foreach (const QString &k, keyList) {
QString change;
if (removedKeys.contains(k))
change = tr("<removed>");
else
change = QString::fromUtf8(CMakeConfigItem::valueOf(k.toUtf8(), cache)).trimmed();
if (change.isEmpty())
change = tr("<empty>");
table += QString::fromLatin1("\n<tr><td>%1</td><td>%2</td></tr>").arg(k).arg(change.toHtmlEscaped());
}
table += QLatin1String("\n</table>");
QPointer<QMessageBox> box = new QMessageBox(Core::ICore::mainWindow());
box->setText(tr("CMake configuration has changed on disk."));
box->setInformativeText(tr("The CMakeCache.txt file has changed: %1").arg(table));
box->setStandardButtons(QMessageBox::Discard | QMessageBox::Apply);
box->setDefaultButton(QMessageBox::Discard);
int ret = box->exec();
if (ret == QMessageBox::Apply)
m_buildConfiguration->setCMakeConfiguration(newConfig);
}
}
static QByteArray trimCMakeCacheLine(const QByteArray &in) {
int start = 0;
while (start < in.count() && (in.at(start) == ' ' || in.at(start) == '\t'))
@@ -602,6 +664,8 @@ CMakeConfig BuildDirManager::parseConfiguration(const Utils::FileName &cacheFile
void BuildDirManager::maybeForceReparse()
{
checkConfiguration();
const QByteArray GENERATOR_KEY = "CMAKE_GENERATOR";
const QByteArray EXTRA_GENERATOR_KEY = "CMAKE_EXTRA_GENERATOR";
const QByteArray CMAKE_COMMAND_KEY = "CMAKE_COMMAND";

View File

@@ -63,7 +63,7 @@ class BuildDirManager : public QObject
Q_OBJECT
public:
BuildDirManager(const CMakeBuildConfiguration *bc);
BuildDirManager(CMakeBuildConfiguration *bc);
~BuildDirManager() override;
const ProjectExplorer::Kit *kit() const;
@@ -87,6 +87,8 @@ public:
void clearFiles();
CMakeConfig parsedConfiguration() const;
void checkConfiguration();
static CMakeConfig parseConfiguration(const Utils::FileName &cacheFile,
QString *errorMessage);
@@ -106,10 +108,9 @@ private:
void processCMakeOutput();
void processCMakeError();
bool m_hasData = false;
const CMakeBuildConfiguration *m_buildConfiguration = nullptr;
CMakeBuildConfiguration *m_buildConfiguration = nullptr;
Utils::QtcProcess *m_cmakeProcess = nullptr;
QTemporaryDir *m_tempDir = nullptr;
mutable CMakeConfig m_cmakeCache;

View File

@@ -305,8 +305,10 @@ void CMakeProject::runCMake()
return;
BuildDirManager *bdm = bc->buildDirManager();
if (bdm && !bdm->isParsing())
if (bdm && !bdm->isParsing()) {
bdm->checkConfiguration();
bdm->forceReparse();
}
}
QList<CMakeBuildTarget> CMakeProject::buildTargets() const