diff options
5 files changed, 336 insertions, 203 deletions
diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro index 1b80127ace..c242998441 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.pro @@ -20,6 +20,7 @@ HEADERS = builddirmanager.h \ cmakelocatorfilter.h \ cmakefilecompletionassist.h \ cmaketool.h \ + cmaketoolsettingsaccessor.h \ cmakeparser.h \ cmakesettingspage.h \ cmaketoolmanager.h \ @@ -56,6 +57,7 @@ SOURCES = builddirmanager.cpp \ cmakelocatorfilter.cpp \ cmakefilecompletionassist.cpp \ cmaketool.cpp \ + cmaketoolsettingsaccessor.cpp \ cmakeparser.cpp \ cmakesettingspage.cpp \ cmaketoolmanager.cpp \ diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs index a69662f5b9..d0ce6bebe2 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs +++ b/src/plugins/cmakeprojectmanager/cmakeprojectmanager.qbs @@ -69,6 +69,8 @@ QtcPlugin { "cmaketool.h", "cmaketoolmanager.cpp", "cmaketoolmanager.h", + "cmaketoolsettingsaccessor.cpp", + "cmaketoolsettingsaccessor.h", "cmakesettingspage.h", "cmakesettingspage.cpp", "cmakeindenter.h", diff --git a/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp b/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp index ac7a11c6c1..a90fe59c81 100644 --- a/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketoolmanager.cpp @@ -25,17 +25,13 @@ #include "cmaketoolmanager.h" +#include "cmaketoolsettingsaccessor.h" + #include <coreplugin/icore.h> -#include <utils/environment.h> -#include <utils/persistentsettings.h> #include <utils/pointeralgorithm.h> #include <utils/qtcassert.h> -#include <QFileInfo> -#include <QDebug> -#include <QDir> - using namespace Core; using namespace Utils; using namespace ProjectExplorer; @@ -51,155 +47,11 @@ class CMakeToolManagerPrivate public: Id m_defaultCMake; std::vector<std::unique_ptr<CMakeTool>> m_cmakeTools; - PersistentSettingsWriter *m_writer = nullptr; + Internal::CMakeToolSettingsAccessor m_accessor; }; static CMakeToolManagerPrivate *d = nullptr; // -------------------------------------------------------------------- -// Helper: -// -------------------------------------------------------------------- - -const char CMAKETOOL_COUNT_KEY[] = "CMakeTools.Count"; -const char CMAKETOOL_DEFAULT_KEY[] = "CMakeTools.Default"; -const char CMAKETOOL_DATA_KEY[] = "CMakeTools."; -const char CMAKETOOL_FILE_VERSION_KEY[] = "Version"; -const char CMAKETOOL_FILENAME[] = "/cmaketools.xml"; - -static FileName userSettingsFileName() -{ - return FileName::fromString(ICore::userResourcePath() + CMAKETOOL_FILENAME); -} - -static std::vector<std::unique_ptr<CMakeTool>> -readCMakeTools(const FileName &fileName, Core::Id *defaultId, bool fromSDK) -{ - PersistentSettingsReader reader; - if (!reader.load(fileName)) - return {}; - - QVariantMap data = reader.restoreValues(); - - // Check version - int version = data.value(QLatin1String(CMAKETOOL_FILE_VERSION_KEY), 0).toInt(); - if (version < 1) - return {}; - - std::vector<std::unique_ptr<CMakeTool>> loaded; - - int count = data.value(QLatin1String(CMAKETOOL_COUNT_KEY), 0).toInt(); - for (int i = 0; i < count; ++i) { - const QString key = QString::fromLatin1(CMAKETOOL_DATA_KEY) + QString::number(i); - if (!data.contains(key)) - continue; - - const QVariantMap dbMap = data.value(key).toMap(); - auto item = std::make_unique<CMakeTool>(dbMap, fromSDK); - if (item->isAutoDetected()) { - if (!item->cmakeExecutable().toFileInfo().isExecutable()) { - qWarning() << QString::fromLatin1("CMakeTool \"%1\" (%2) read from \"%3\" dropped since the command is not executable.") - .arg(item->cmakeExecutable().toUserOutput(), item->id().toString(), fileName.toUserOutput()); - continue; - } - } - - loaded.emplace_back(std::move(item)); - } - - *defaultId = Id::fromSetting(data.value(QLatin1String(CMAKETOOL_DEFAULT_KEY), defaultId->toSetting())); - - return loaded; -} - -static std::vector<std::unique_ptr<CMakeTool>> autoDetectCMakeTools() -{ - Utils::Environment env = Environment::systemEnvironment(); - - Utils::FileNameList path = env.path(); - path = Utils::filteredUnique(path); - - if (HostOsInfo::isWindowsHost()) { - const QString progFiles = QLatin1String(qgetenv("ProgramFiles")); - path.append(Utils::FileName::fromString(progFiles + "/CMake")); - path.append(Utils::FileName::fromString(progFiles + "/CMake/bin")); - const QString progFilesX86 = QLatin1String(qgetenv("ProgramFiles(x86)")); - if (!progFilesX86.isEmpty()) { - path.append(Utils::FileName::fromString(progFilesX86 + "/CMake")); - path.append(Utils::FileName::fromString(progFilesX86 + "/CMake/bin")); - } - } - - if (HostOsInfo::isMacHost()) { - path.append(Utils::FileName::fromString("/Applications/CMake.app/Contents/bin")); - path.append(Utils::FileName::fromString("/usr/local/bin")); - path.append(Utils::FileName::fromString("/opt/local/bin")); - } - - const QStringList execs = env.appendExeExtensions(QLatin1String("cmake")); - - FileNameList suspects; - foreach (const Utils::FileName &base, path) { - if (base.isEmpty()) - continue; - - QFileInfo fi; - for (const QString &exec : execs) { - fi.setFile(QDir(base.toString()), exec); - if (fi.exists() && fi.isFile() && fi.isExecutable()) - suspects << FileName::fromString(fi.absoluteFilePath()); - } - } - - std::vector<std::unique_ptr<CMakeTool>> found; - foreach (const FileName &command, suspects) { - auto item = std::make_unique<CMakeTool>(CMakeTool::AutoDetection, CMakeTool::createId()); - item->setCMakeExecutable(command); - item->setDisplayName(CMakeToolManager::tr("System CMake at %1").arg(command.toUserOutput())); - - found.emplace_back(std::move(item)); - } - - return found; -} - -static std::vector<std::unique_ptr<CMakeTool>> -mergeTools(std::vector<std::unique_ptr<CMakeTool>> &sdkTools, - std::vector<std::unique_ptr<CMakeTool>> &userTools, - std::vector<std::unique_ptr<CMakeTool>> &autoDetectedTools) -{ - std::vector<std::unique_ptr<CMakeTool>> result; - while (userTools.size() > 0) { - std::unique_ptr<CMakeTool> userTool = std::move(userTools[0]); - userTools.erase(std::begin(userTools)); - - if (auto sdkTool = Utils::take(sdkTools, Utils::equal(&CMakeTool::id, userTool->id()))) { - result.emplace_back(std::move(sdkTool.value())); - } else { - if (userTool->isAutoDetected() - && !Utils::contains(autoDetectedTools, Utils::equal(&CMakeTool::cmakeExecutable, - userTool->cmakeExecutable()))) { - - qWarning() << QString::fromLatin1("Previously SDK provided CMakeTool \"%1\" (%2) dropped.") - .arg(userTool->cmakeExecutable().toUserOutput(), userTool->id().toString()); - continue; - } - result.emplace_back(std::move(userTool)); - } - } - - // add all the autodetected tools that are not known yet - while (autoDetectedTools.size() > 0) { - std::unique_ptr<CMakeTool> autoDetectedTool = std::move(autoDetectedTools[0]); - autoDetectedTools.erase(std::begin(autoDetectedTools)); - - if (!Utils::contains(result, - Utils::equal(&CMakeTool::cmakeExecutable, autoDetectedTool->cmakeExecutable()))) - result.emplace_back(std::move(autoDetectedTool)); - } - - return result; -} - -// -------------------------------------------------------------------- // CMakeToolManager: // -------------------------------------------------------------------- @@ -211,7 +63,6 @@ CMakeToolManager::CMakeToolManager(QObject *parent) : QObject(parent) m_instance = this; d = new CMakeToolManagerPrivate; - d->m_writer = new PersistentSettingsWriter(userSettingsFileName(), QStringLiteral("QtCreatorCMakeTools")); connect(ICore::instance(), &ICore::saveSettingsRequested, this, &CMakeToolManager::saveCMakeTools); @@ -222,7 +73,6 @@ CMakeToolManager::CMakeToolManager(QObject *parent) : QObject(parent) CMakeToolManager::~CMakeToolManager() { - delete d->m_writer; delete d; } @@ -311,37 +161,10 @@ CMakeTool *CMakeToolManager::findById(const Id &id) void CMakeToolManager::restoreCMakeTools() { - Core::Id defaultId; - - const FileName sdkSettingsFile = FileName::fromString(ICore::installerResourcePath() - + CMAKETOOL_FILENAME); - - std::vector<std::unique_ptr<CMakeTool>> sdkTools - = readCMakeTools(sdkSettingsFile, &defaultId, true); - - //read the tools from the user settings file - std::vector<std::unique_ptr<CMakeTool>> userTools - = readCMakeTools(userSettingsFileName(), &defaultId, false); - - //autodetect tools - std::vector<std::unique_ptr<CMakeTool>> autoDetectedTools = autoDetectCMakeTools(); - - //filter out the tools that were stored in SDK - std::vector<std::unique_ptr<CMakeTool>> toRegister = mergeTools(sdkTools, userTools, autoDetectedTools); - - // Store all tools - for (auto it = std::begin(toRegister); it != std::end(toRegister); ++it) { - const Utils::FileName executable = (*it)->cmakeExecutable(); - const Core::Id id = (*it)->id(); - - if (!registerCMakeTool(std::move(*it))) { - //this should never happen, but lets make sure we do not leak memory - qWarning() << QString::fromLatin1("CMakeTool \"%1\" (%2) dropped.") - .arg(executable.toUserOutput(), id.toString()); - } - } - - setDefaultCMakeTool(defaultId); + Internal::CMakeToolSettingsAccessor::CMakeTools tools + = d->m_accessor.restoreCMakeTools(ICore::dialogParent()); + d->m_cmakeTools = std::move(tools.cmakeTools); + setDefaultCMakeTool(tools.defaultToolId); emit m_instance->cmakeToolsLoaded(); } @@ -355,25 +178,7 @@ void CMakeToolManager::notifyAboutUpdate(CMakeTool *tool) void CMakeToolManager::saveCMakeTools() { - QTC_ASSERT(d->m_writer, return); - QVariantMap data; - data.insert(QLatin1String(CMAKETOOL_FILE_VERSION_KEY), 1); - data.insert(QLatin1String(CMAKETOOL_DEFAULT_KEY), d->m_defaultCMake.toSetting()); - - int count = 0; - for (const std::unique_ptr<CMakeTool> &item : d->m_cmakeTools) { - QFileInfo fi = item->cmakeExecutable().toFileInfo(); - - if (fi.isExecutable()) { - QVariantMap tmp = item->toMap(); - if (tmp.isEmpty()) - continue; - data.insert(QString::fromLatin1(CMAKETOOL_DATA_KEY) + QString::number(count), tmp); - ++count; - } - } - data.insert(QLatin1String(CMAKETOOL_COUNT_KEY), count); - d->m_writer->save(data, ICore::mainWindow()); + d->m_accessor.saveCMakeTools(cmakeTools(), d->m_defaultCMake, ICore::dialogParent()); } void CMakeToolManager::ensureDefaultCMakeToolIsValid() diff --git a/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp new file mode 100644 index 0000000000..71f8c58054 --- /dev/null +++ b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp @@ -0,0 +1,259 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** 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 +** 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. +** +** 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. +** +****************************************************************************/ + +#include "cmaketoolsettingsaccessor.h" + +#include "cmaketool.h" +#include "cmaketoolmanager.h" + +#include <coreplugin/icore.h> + +#include <app/app_version.h> + +#include <utils/algorithm.h> +#include <utils/environment.h> + +#include <QDebug> +#include <QDir> +#include <QFileInfo> + +using namespace Utils; + +namespace CMakeProjectManager { +namespace Internal { + +// -------------------------------------------------------------------- +// CMakeToolSettingsUpgraders: +// -------------------------------------------------------------------- + +class CMakeToolSettingsUpgraderV0 : public Utils::VersionUpgrader +{ + // Necessary to make Version 1 supported. +public: + CMakeToolSettingsUpgraderV0() : Utils::VersionUpgrader(0, "4.6") { } + + // NOOP + QVariantMap upgrade(const QVariantMap &data) final { return data; } +}; + +// -------------------------------------------------------------------- +// Helpers: +// -------------------------------------------------------------------- + +static const char CMAKE_TOOL_COUNT_KEY[] = "CMakeTools.Count"; +static const char CMAKE_TOOL_DATA_KEY[] = "CMakeTools."; +static const char CMAKE_TOOL_DEFAULT_KEY[] = "CMakeTools.Default"; +static const char CMAKE_TOOL_FILENAME[] = "/cmaketools.xml"; + + +static std::vector<std::unique_ptr<CMakeTool>> autoDetectCMakeTools() +{ + Utils::Environment env = Environment::systemEnvironment(); + + Utils::FileNameList path = env.path(); + path = Utils::filteredUnique(path); + + if (HostOsInfo::isWindowsHost()) { + const QString progFiles = QLatin1String(qgetenv("ProgramFiles")); + path.append(Utils::FileName::fromString(progFiles + "/CMake")); + path.append(Utils::FileName::fromString(progFiles + "/CMake/bin")); + const QString progFilesX86 = QLatin1String(qgetenv("ProgramFiles(x86)")); + if (!progFilesX86.isEmpty()) { + path.append(Utils::FileName::fromString(progFilesX86 + "/CMake")); + path.append(Utils::FileName::fromString(progFilesX86 + "/CMake/bin")); + } + } + + if (HostOsInfo::isMacHost()) { + path.append(Utils::FileName::fromString("/Applications/CMake.app/Contents/bin")); + path.append(Utils::FileName::fromString("/usr/local/bin")); + path.append(Utils::FileName::fromString("/opt/local/bin")); + } + + const QStringList execs = env.appendExeExtensions(QLatin1String("cmake")); + + FileNameList suspects; + foreach (const Utils::FileName &base, path) { + if (base.isEmpty()) + continue; + + QFileInfo fi; + for (const QString &exec : execs) { + fi.setFile(QDir(base.toString()), exec); + if (fi.exists() && fi.isFile() && fi.isExecutable()) + suspects << FileName::fromString(fi.absoluteFilePath()); + } + } + + std::vector<std::unique_ptr<CMakeTool>> found; + foreach (const FileName &command, suspects) { + auto item = std::make_unique<CMakeTool>(CMakeTool::AutoDetection, CMakeTool::createId()); + item->setCMakeExecutable(command); + item->setDisplayName(CMakeToolManager::tr("System CMake at %1").arg(command.toUserOutput())); + + found.emplace_back(std::move(item)); + } + + return found; +} + + +static std::vector<std::unique_ptr<CMakeTool>> +mergeTools(std::vector<std::unique_ptr<CMakeTool>> &sdkTools, + std::vector<std::unique_ptr<CMakeTool>> &userTools, + std::vector<std::unique_ptr<CMakeTool>> &autoDetectedTools) +{ + std::vector<std::unique_ptr<CMakeTool>> result; + while (userTools.size() > 0) { + std::unique_ptr<CMakeTool> userTool = std::move(userTools[0]); + userTools.erase(std::begin(userTools)); + + if (auto sdkTool = Utils::take(sdkTools, Utils::equal(&CMakeTool::id, userTool->id()))) { + result.emplace_back(std::move(sdkTool.value())); + } else { + if (userTool->isAutoDetected() + && !Utils::contains(autoDetectedTools, Utils::equal(&CMakeTool::cmakeExecutable, + userTool->cmakeExecutable()))) { + + qWarning() << QString::fromLatin1("Previously SDK provided CMakeTool \"%1\" (%2) dropped.") + .arg(userTool->cmakeExecutable().toUserOutput(), userTool->id().toString()); + continue; + } + result.emplace_back(std::move(userTool)); + } + } + + // add all the autodetected tools that are not known yet + while (autoDetectedTools.size() > 0) { + std::unique_ptr<CMakeTool> autoDetectedTool = std::move(autoDetectedTools[0]); + autoDetectedTools.erase(std::begin(autoDetectedTools)); + + if (!Utils::contains(result, + Utils::equal(&CMakeTool::cmakeExecutable, autoDetectedTool->cmakeExecutable()))) + result.emplace_back(std::move(autoDetectedTool)); + } + + return result; +} + + +// -------------------------------------------------------------------- +// CMakeToolSettingsAccessor: +// -------------------------------------------------------------------- + +CMakeToolSettingsAccessor::CMakeToolSettingsAccessor() : + UpgradingSettingsAccessor("QtCreatorCMakeTools", + QCoreApplication::translate("CMakeProjectManager::CMakeToolManager", "CMake"), + Core::Constants::IDE_DISPLAY_NAME) +{ + setBaseFilePath(FileName::fromString(Core::ICore::userResourcePath() + CMAKE_TOOL_FILENAME)); + + addVersionUpgrader(std::make_unique<CMakeToolSettingsUpgraderV0>()); +} + +CMakeToolSettingsAccessor::CMakeTools CMakeToolSettingsAccessor::restoreCMakeTools(QWidget *parent) const +{ + CMakeTools result; + + const FileName sdkSettingsFile = FileName::fromString(Core::ICore::installerResourcePath() + + CMAKE_TOOL_FILENAME); + + CMakeTools sdkTools = cmakeTools(restoreSettings(sdkSettingsFile, parent), true); + + //read the tools from the user settings file + CMakeTools userTools = cmakeTools(restoreSettings(parent), false); + + //autodetect tools + std::vector<std::unique_ptr<CMakeTool>> autoDetectedTools = autoDetectCMakeTools(); + + //filter out the tools that were stored in SDK + std::vector<std::unique_ptr<CMakeTool>> toRegister = mergeTools(sdkTools.cmakeTools, + userTools.cmakeTools, + autoDetectedTools); + + // Store all tools + for (auto it = std::begin(toRegister); it != std::end(toRegister); ++it) + result.cmakeTools.emplace_back(std::move(*it)); + + result.defaultToolId = userTools.defaultToolId.isValid() ? userTools.defaultToolId : sdkTools.defaultToolId; + + // Set default TC... + return result; +} + +void CMakeToolSettingsAccessor::saveCMakeTools(const QList<CMakeTool *> &cmakeTools, + const Core::Id &defaultId, + QWidget *parent) +{ + QVariantMap data; + data.insert(QLatin1String(CMAKE_TOOL_DEFAULT_KEY), defaultId.toSetting()); + + int count = 0; + for (const CMakeTool *item : cmakeTools) { + QFileInfo fi = item->cmakeExecutable().toFileInfo(); + + if (fi.isExecutable()) { + QVariantMap tmp = item->toMap(); + if (tmp.isEmpty()) + continue; + data.insert(QString::fromLatin1(CMAKE_TOOL_DATA_KEY) + QString::number(count), tmp); + ++count; + } + } + data.insert(QLatin1String(CMAKE_TOOL_COUNT_KEY), count); + + saveSettings(data, parent); +} + +CMakeToolSettingsAccessor::CMakeTools +CMakeToolSettingsAccessor::cmakeTools(const QVariantMap &data, bool fromSdk) const +{ + CMakeTools result; + + int count = data.value(QLatin1String(CMAKE_TOOL_COUNT_KEY), 0).toInt(); + for (int i = 0; i < count; ++i) { + const QString key = QString::fromLatin1(CMAKE_TOOL_DATA_KEY) + QString::number(i); + if (!data.contains(key)) + continue; + + const QVariantMap dbMap = data.value(key).toMap(); + auto item = std::make_unique<CMakeTool>(dbMap, fromSdk); + if (item->isAutoDetected() && !item->cmakeExecutable().toFileInfo().isExecutable()) { + qWarning() << QString::fromLatin1("CMakeTool \"%1\" (%2) dropped since the command is not executable.") + .arg(item->cmakeExecutable().toUserOutput(), item->id().toString()); + continue; + } + + result.cmakeTools.emplace_back(std::move(item)); + } + + result.defaultToolId = Core::Id::fromSetting(data.value(CMAKE_TOOL_DEFAULT_KEY, + Core::Id().toSetting())); + + return result; +} + +} // namespace Internal +} // namespace CMakeProjectManager diff --git a/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.h b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.h new file mode 100644 index 0000000000..05c7ac6920 --- /dev/null +++ b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** 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 +** 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. +** +** 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. +** +****************************************************************************/ + +#pragma once + +#include <utils/settingsaccessor.h> + +#include <coreplugin/id.h> + +#include <QList> + +#include <memory> + +namespace Core { class Id; } + +namespace CMakeProjectManager { + +class CMakeTool; + +namespace Internal { + +class CMakeToolSettingsAccessor : public Utils::UpgradingSettingsAccessor +{ +public: + CMakeToolSettingsAccessor(); + + struct CMakeTools { + Core::Id defaultToolId; + std::vector<std::unique_ptr<CMakeTool>> cmakeTools; + }; + + CMakeTools restoreCMakeTools(QWidget *parent) const; + + void saveCMakeTools(const QList<CMakeTool *> &cmakeTools, + const Core::Id &defaultId, + QWidget *parent); + +private: + CMakeTools cmakeTools(const QVariantMap &data, bool fromSdk) const; +}; + +} // namespace Internal +} // namespace CMakeProjectManager |