forked from qt-creator/qt-creator
ToolChain: Use SettingsAccessor to access XML settings
This allows for use of the new SettingsAccessor infrastructure for upgrading, backups, etc. Task-number: QTCREATORBUG-20148 Change-Id: I5419c86c0fd576a59ec91c212097c8f987e01da2 Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
@@ -81,10 +81,7 @@ QVariantMap SettingsAccessor::restoreSettings(QWidget *parent) const
|
||||
{
|
||||
QTC_ASSERT(!m_baseFilePath.isEmpty(), return QVariantMap());
|
||||
|
||||
const RestoreData result = readData(m_baseFilePath, parent);
|
||||
|
||||
const ProceedInfo pi = result.hasIssue() ? reportIssues(result.issue.value(), result.path, parent) : ProceedInfo::Continue;
|
||||
return pi == ProceedInfo::DiscardAndContinue ? QVariantMap() : result.data;
|
||||
return restoreSettings(m_baseFilePath, parent);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -120,6 +117,15 @@ SettingsAccessor::writeData(const FileName &path, const QVariantMap &data, QWidg
|
||||
return writeFile(path, prepareToWriteSettings(data));
|
||||
}
|
||||
|
||||
QVariantMap SettingsAccessor::restoreSettings(const FileName &settingsPath, QWidget *parent) const
|
||||
{
|
||||
const RestoreData result = readData(settingsPath, parent);
|
||||
|
||||
const ProceedInfo pi = result.hasIssue() ? reportIssues(result.issue.value(), result.path, parent)
|
||||
: ProceedInfo::Continue;
|
||||
return pi == ProceedInfo::DiscardAndContinue ? QVariantMap() : result.data;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Read a file at \a path from disk and extract the data into a RestoreData set.
|
||||
*
|
||||
@@ -422,7 +428,8 @@ QVariantMap VersionUpgrader::renameKeys(const QList<Change> &changes, QVariantMa
|
||||
* The UpgradingSettingsAccessor keeps version information in the settings file and will
|
||||
* upgrade the settings on load to the latest supported version (if possible).
|
||||
*/
|
||||
UpgradingSettingsAccessor::UpgradingSettingsAccessor(const QString &displayName,
|
||||
UpgradingSettingsAccessor::UpgradingSettingsAccessor(const QString &docType,
|
||||
const QString &displayName,
|
||||
const QString &applicationDisplayName) :
|
||||
UpgradingSettingsAccessor(std::make_unique<VersionedBackUpStrategy>(this), docType,
|
||||
displayName, applicationDisplayName)
|
||||
|
||||
@@ -129,6 +129,7 @@ public:
|
||||
|
||||
protected:
|
||||
// Report errors:
|
||||
QVariantMap restoreSettings(const Utils::FileName &settingsPath, QWidget *parent) const;
|
||||
ProceedInfo reportIssues(const Issue &issue, const FileName &path, QWidget *parent) const;
|
||||
|
||||
virtual QVariantMap preprocessReadSettings(const QVariantMap &data) const;
|
||||
@@ -234,7 +235,8 @@ class MergingSettingsAccessor;
|
||||
class QTCREATOR_UTILS_EXPORT UpgradingSettingsAccessor : public BackingUpSettingsAccessor
|
||||
{
|
||||
public:
|
||||
UpgradingSettingsAccessor(const QString &displayName, const QString &applicationDisplayName);
|
||||
UpgradingSettingsAccessor(const QString &docType,
|
||||
const QString &displayName, const QString &applicationDisplayName);
|
||||
UpgradingSettingsAccessor(std::unique_ptr<BackUpStrategy> &&strategy, const QString &docType,
|
||||
const QString &displayName, const QString &appDisplayName);
|
||||
|
||||
|
||||
@@ -231,8 +231,8 @@ private slots:
|
||||
|
||||
void testDeviceManager();
|
||||
|
||||
void testToolChainManager_data();
|
||||
void testToolChainManager();
|
||||
void testToolChainMerging_data();
|
||||
void testToolChainMerging();
|
||||
|
||||
void testUserFileAccessor_prepareToReadSettings();
|
||||
void testUserFileAccessor_prepareToReadSettingsObsoleteVersion();
|
||||
|
||||
@@ -88,6 +88,7 @@ HEADERS += projectexplorer.h \
|
||||
toolchainconfigwidget.h \
|
||||
toolchainmanager.h \
|
||||
toolchainoptionspage.h \
|
||||
toolchainsettingsaccessor.h \
|
||||
gccparser.h \
|
||||
projectexplorersettingspage.h \
|
||||
baseprojectwizarddialog.h \
|
||||
@@ -232,6 +233,7 @@ SOURCES += projectexplorer.cpp \
|
||||
toolchainconfigwidget.cpp \
|
||||
toolchainmanager.cpp \
|
||||
toolchainoptionspage.cpp \
|
||||
toolchainsettingsaccessor.cpp \
|
||||
gccparser.cpp \
|
||||
projectexplorersettingspage.cpp \
|
||||
baseprojectwizarddialog.cpp \
|
||||
|
||||
@@ -144,6 +144,7 @@ Project {
|
||||
"toolchainconfigwidget.cpp", "toolchainconfigwidget.h",
|
||||
"toolchainmanager.cpp", "toolchainmanager.h",
|
||||
"toolchainoptionspage.cpp", "toolchainoptionspage.h",
|
||||
"toolchainsettingsaccessor.cpp", "toolchainsettingsaccessor.h",
|
||||
"userfileaccessor.cpp", "userfileaccessor.h",
|
||||
"vcsannotatetaskhandler.cpp", "vcsannotatetaskhandler.h",
|
||||
"waitforstopdialog.cpp", "waitforstopdialog.h",
|
||||
|
||||
@@ -63,10 +63,11 @@ class HeaderPath;
|
||||
class IOutputParser;
|
||||
class ToolChainConfigWidget;
|
||||
class ToolChainFactory;
|
||||
class ToolChainManager;
|
||||
class Task;
|
||||
class Kit;
|
||||
|
||||
namespace Internal { class ToolChainSettingsAccessor; }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// ToolChain (documentation inside)
|
||||
// --------------------------------------------------------------------------
|
||||
@@ -169,7 +170,7 @@ private:
|
||||
|
||||
Internal::ToolChainPrivate *const d;
|
||||
|
||||
friend class ToolChainManager;
|
||||
friend class Internal::ToolChainSettingsAccessor;
|
||||
friend class ToolChainFactory;
|
||||
};
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "abi.h"
|
||||
#include "kitinformation.h"
|
||||
#include "toolchain.h"
|
||||
#include "toolchainsettingsaccessor.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
@@ -41,18 +42,8 @@
|
||||
|
||||
#include <tuple>
|
||||
|
||||
static const char TOOLCHAIN_DATA_KEY[] = "ToolChain.";
|
||||
static const char TOOLCHAIN_COUNT_KEY[] = "ToolChain.Count";
|
||||
static const char TOOLCHAIN_FILE_VERSION_KEY[] = "Version";
|
||||
static const char TOOLCHAIN_FILENAME[] = "/toolchains.xml";
|
||||
|
||||
using namespace Utils;
|
||||
|
||||
static FileName settingsFileName(const QString &path)
|
||||
{
|
||||
return FileName::fromString(Core::ICore::userResourcePath() + path);
|
||||
}
|
||||
|
||||
namespace ProjectExplorer {
|
||||
namespace Internal {
|
||||
|
||||
@@ -72,7 +63,7 @@ public:
|
||||
~ToolChainManagerPrivate();
|
||||
|
||||
QMap<QString, FileName> m_abiToDebugger;
|
||||
PersistentSettingsWriter *m_writer = nullptr;
|
||||
std::unique_ptr<ToolChainSettingsAccessor> m_accessor;
|
||||
|
||||
QList<ToolChain *> m_toolChains; // prioritized List
|
||||
QVector<LanguageDisplayPair> m_languages;
|
||||
@@ -82,7 +73,6 @@ ToolChainManagerPrivate::~ToolChainManagerPrivate()
|
||||
{
|
||||
qDeleteAll(m_toolChains);
|
||||
m_toolChains.clear();
|
||||
delete m_writer;
|
||||
}
|
||||
|
||||
static ToolChainManager *m_instance = nullptr;
|
||||
@@ -122,215 +112,22 @@ ToolChainManager *ToolChainManager::instance()
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
static QList<ToolChain *> restoreFromFile(const FileName &fileName)
|
||||
{
|
||||
QList<ToolChain *> result;
|
||||
|
||||
PersistentSettingsReader reader;
|
||||
if (!reader.load(fileName))
|
||||
return result;
|
||||
QVariantMap data = reader.restoreValues();
|
||||
|
||||
// Check version:
|
||||
int version = data.value(QLatin1String(TOOLCHAIN_FILE_VERSION_KEY), 0).toInt();
|
||||
if (version < 1)
|
||||
return result;
|
||||
|
||||
const QList<ToolChainFactory *> factories = ToolChainFactory::allToolChainFactories();
|
||||
|
||||
int count = data.value(QLatin1String(TOOLCHAIN_COUNT_KEY), 0).toInt();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
const QString key = QString::fromLatin1(TOOLCHAIN_DATA_KEY) + QString::number(i);
|
||||
if (!data.contains(key))
|
||||
break;
|
||||
|
||||
const QVariantMap tcMap = data.value(key).toMap();
|
||||
|
||||
bool restored = false;
|
||||
for (ToolChainFactory *f : factories) {
|
||||
if (f->canRestore(tcMap)) {
|
||||
if (ToolChain *tc = f->restore(tcMap)) {
|
||||
result.append(tc);
|
||||
restored = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!restored)
|
||||
qWarning("Warning: '%s': Unable to restore compiler type '%s' for tool chain %s.",
|
||||
qPrintable(fileName.toUserOutput()),
|
||||
qPrintable(ToolChainFactory::typeIdFromMap(tcMap).toString()),
|
||||
qPrintable(QString::fromUtf8(ToolChainFactory::idFromMap(tcMap))));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static QList<ToolChain *> autoDetectToolChains(const QList<ToolChain *> alreadyKnownTcs)
|
||||
{
|
||||
QList<ToolChain *> result;
|
||||
for (ToolChainFactory *f : ToolChainFactory::allToolChainFactories())
|
||||
result.append(f->autoDetect(alreadyKnownTcs));
|
||||
|
||||
// Remove invalid toolchains that might have sneaked in.
|
||||
result = Utils::filtered(result, [](const ToolChain *tc) { return tc->isValid(); });
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static QList<ToolChain *> subtractByEqual(const QList<ToolChain *> &a, const QList<ToolChain *> &b)
|
||||
{
|
||||
return Utils::filtered(a, [&b](ToolChain *atc) {
|
||||
return !Utils::anyOf(b, [atc](ToolChain *btc) { return *atc == *btc; });
|
||||
});
|
||||
}
|
||||
|
||||
static QList<ToolChain *> subtractByPointerEqual(const QList<ToolChain *> &a, const QList<ToolChain *> &b)
|
||||
{
|
||||
return Utils::filtered(a, [&b](ToolChain *atc) { return !b.contains(atc); });
|
||||
}
|
||||
|
||||
static QList<ToolChain *> subtractById(const QList<ToolChain *> &a, const QList<ToolChain *> &b)
|
||||
{
|
||||
return Utils::filtered(a, [&b](ToolChain *atc) {
|
||||
return !Utils::anyOf(b, Utils::equal(&ToolChain::id, atc->id()));
|
||||
});
|
||||
}
|
||||
|
||||
static bool containsByEqual(const QList<ToolChain *> &a, const ToolChain *atc)
|
||||
{
|
||||
return Utils::anyOf(a, [atc](ToolChain *btc) { return *atc == *btc; });
|
||||
}
|
||||
|
||||
static QList<ToolChain *> makeUniqueByPointerEqual(const QList<ToolChain *> &a)
|
||||
{
|
||||
return QSet<ToolChain *>::fromList(a).toList();
|
||||
}
|
||||
|
||||
static QList<ToolChain *> makeUniqueByEqual(const QList<ToolChain *> &a)
|
||||
{
|
||||
QList<ToolChain *> result;
|
||||
foreach (ToolChain *tc, a) {
|
||||
if (!Utils::contains(result, [tc](ToolChain *rtc) { return *tc == *rtc; }))
|
||||
result.append(tc);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct ToolChainOperations
|
||||
{
|
||||
QList<ToolChain *> toDemote;
|
||||
QList<ToolChain *> toRegister;
|
||||
QList<ToolChain *> toDelete;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
static ToolChainOperations mergeToolChainLists(const QList<ToolChain *> &systemFileTcs,
|
||||
const QList<ToolChain *> &userFileTcs,
|
||||
const QList<ToolChain *> &autodetectedTcs)
|
||||
{
|
||||
const QList<ToolChain *> uniqueUserFileTcs = makeUniqueByEqual(userFileTcs);
|
||||
QList<ToolChain *> manualUserFileTcs;
|
||||
QList<ToolChain *> autodetectedUserFileTcs;
|
||||
std::tie(autodetectedUserFileTcs, manualUserFileTcs)
|
||||
= Utils::partition(uniqueUserFileTcs, &ToolChain::isAutoDetected);
|
||||
const QList<ToolChain *> autodetectedUserTcs = subtractById(autodetectedUserFileTcs, systemFileTcs);
|
||||
|
||||
// Calculate a set of Tcs that were detected before (and saved to userFile) and that
|
||||
// got re-detected again. Take the userTcs (to keep Ids) over the same in autodetectedTcs.
|
||||
QList<ToolChain *> redetectedUserTcs;
|
||||
QList<ToolChain *> notRedetectedUserTcs;
|
||||
std::tie(redetectedUserTcs, notRedetectedUserTcs)
|
||||
= Utils::partition(autodetectedUserTcs,
|
||||
[&autodetectedTcs](ToolChain *tc) { return containsByEqual(autodetectedTcs, tc); });
|
||||
|
||||
// Remove redetected tcs from autodetectedTcs:
|
||||
const QList<ToolChain *> newlyAutodetectedTcs
|
||||
= subtractByEqual(autodetectedTcs, redetectedUserTcs);
|
||||
|
||||
const QList<ToolChain *> notRedetectedButValidUserTcs
|
||||
= Utils::filtered(notRedetectedUserTcs, &ToolChain::isValid);
|
||||
|
||||
const QList<ToolChain *> validManualUserTcs
|
||||
= Utils::filtered(manualUserFileTcs, &ToolChain::isValid);
|
||||
|
||||
ToolChainOperations result;
|
||||
result.toDemote = notRedetectedButValidUserTcs;
|
||||
result.toRegister = systemFileTcs + validManualUserTcs + result.toDemote // manual TCs
|
||||
+ redetectedUserTcs + newlyAutodetectedTcs; // auto TCs
|
||||
|
||||
result.toDelete = makeUniqueByPointerEqual(subtractByPointerEqual(systemFileTcs + userFileTcs + autodetectedTcs,
|
||||
result.toRegister));
|
||||
return result;
|
||||
}
|
||||
|
||||
void ToolChainManager::restoreToolChains()
|
||||
{
|
||||
QTC_ASSERT(!d->m_writer, return);
|
||||
d->m_writer =
|
||||
new PersistentSettingsWriter(settingsFileName(QLatin1String(TOOLCHAIN_FILENAME)),
|
||||
QLatin1String("QtCreatorToolChains"));
|
||||
QTC_ASSERT(!d->m_accessor, return);
|
||||
d->m_accessor = std::make_unique<Internal::ToolChainSettingsAccessor>();
|
||||
|
||||
// read all tool chains from SDK
|
||||
const QList<ToolChain *> systemFileTcs = readSystemFileToolChains();
|
||||
|
||||
// read all tool chains from user file.
|
||||
const QList<ToolChain *> userFileTcs
|
||||
= restoreFromFile(settingsFileName(QLatin1String(TOOLCHAIN_FILENAME)));
|
||||
|
||||
// Autodetect: Pass autodetected toolchains from user file so the information can be reused:
|
||||
const QList<ToolChain *> autodetectedUserFileTcs
|
||||
= Utils::filtered(userFileTcs, &ToolChain::isAutoDetected);
|
||||
const QList<ToolChain *> autodetectedTcs = autoDetectToolChains(autodetectedUserFileTcs);
|
||||
|
||||
// merge tool chains and register those that we need to keep:
|
||||
ToolChainOperations ops = mergeToolChainLists(systemFileTcs, userFileTcs, autodetectedTcs);
|
||||
|
||||
// Process ops:
|
||||
foreach (ToolChain *tc, ops.toDemote)
|
||||
tc->setDetection(ToolChain::ManualDetection);
|
||||
|
||||
foreach (ToolChain *tc, ops.toRegister)
|
||||
for (ToolChain *tc : d->m_accessor->restoreToolChains(Core::ICore::dialogParent()))
|
||||
registerToolChain(tc);
|
||||
|
||||
qDeleteAll(ops.toDelete);
|
||||
|
||||
emit m_instance->toolChainsLoaded();
|
||||
}
|
||||
|
||||
QList<ToolChain *> ToolChainManager::readSystemFileToolChains()
|
||||
{
|
||||
QList<ToolChain *> systemTcs = restoreFromFile(
|
||||
FileName::fromString(Core::ICore::installerResourcePath() + TOOLCHAIN_FILENAME));
|
||||
|
||||
foreach (ToolChain *tc, systemTcs)
|
||||
tc->setDetection(ToolChain::AutoDetection);
|
||||
|
||||
return systemTcs;
|
||||
}
|
||||
|
||||
void ToolChainManager::saveToolChains()
|
||||
{
|
||||
QVariantMap data;
|
||||
data.insert(QLatin1String(TOOLCHAIN_FILE_VERSION_KEY), 1);
|
||||
QTC_ASSERT(d->m_accessor, return);
|
||||
|
||||
int count = 0;
|
||||
foreach (ToolChain *tc, d->m_toolChains) {
|
||||
if (tc->isValid()) {
|
||||
QVariantMap tmp = tc->toMap();
|
||||
if (tmp.isEmpty())
|
||||
continue;
|
||||
data.insert(QString::fromLatin1(TOOLCHAIN_DATA_KEY) + QString::number(count), tmp);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
data.insert(QLatin1String(TOOLCHAIN_COUNT_KEY), count);
|
||||
d->m_writer->save(data, Core::ICore::mainWindow());
|
||||
|
||||
// Do not save default debuggers! Those are set by the SDK!
|
||||
d->m_accessor->saveToolChains(d->m_toolChains, Core::ICore::dialogParent());
|
||||
}
|
||||
|
||||
QList<ToolChain *> ToolChainManager::toolChains(const ToolChain::Predicate &predicate)
|
||||
@@ -386,7 +183,7 @@ FileName ToolChainManager::defaultDebugger(const Abi &abi)
|
||||
|
||||
bool ToolChainManager::isLoaded()
|
||||
{
|
||||
return d->m_writer;
|
||||
return bool(d->m_accessor);
|
||||
}
|
||||
|
||||
void ToolChainManager::notifyAboutUpdate(ToolChain *tc)
|
||||
@@ -400,7 +197,7 @@ bool ToolChainManager::registerToolChain(ToolChain *tc)
|
||||
{
|
||||
QTC_ASSERT(tc, return false);
|
||||
QTC_ASSERT(isLanguageSupported(tc->language()), return false);
|
||||
QTC_ASSERT(d->m_writer, return false);
|
||||
QTC_ASSERT(d->m_accessor, return false);
|
||||
|
||||
if (d->m_toolChains.contains(tc))
|
||||
return true;
|
||||
@@ -454,202 +251,3 @@ bool ToolChainManager::isLanguageSupported(const Core::Id &id)
|
||||
}
|
||||
|
||||
} // namespace ProjectExplorer
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
#include "projectexplorer.h"
|
||||
|
||||
#include "headerpath.h"
|
||||
|
||||
#include <QSet>
|
||||
#include <QTest>
|
||||
|
||||
namespace ProjectExplorer {
|
||||
|
||||
typedef QList<ToolChain *> TCList;
|
||||
|
||||
class TTC : public ToolChain
|
||||
{
|
||||
public:
|
||||
TTC(ToolChain::Detection d, const QByteArray &t, bool v = true) :
|
||||
ToolChain("TestToolChainType", d),
|
||||
token(t),
|
||||
m_valid(v)
|
||||
{
|
||||
m_toolChains.append(this);
|
||||
setLanguage(Constants::CXX_LANGUAGE_ID);
|
||||
}
|
||||
|
||||
static QList<TTC *> toolChains();
|
||||
static bool hasToolChains() { return !m_toolChains.isEmpty(); }
|
||||
|
||||
QString typeDisplayName() const override { return QLatin1String("Test Tool Chain"); }
|
||||
Abi targetAbi() const override { return Abi::hostAbi(); }
|
||||
bool isValid() const override { return m_valid; }
|
||||
PredefinedMacrosRunner createPredefinedMacrosRunner() const override { return PredefinedMacrosRunner(); }
|
||||
Macros predefinedMacros(const QStringList &cxxflags) const override { Q_UNUSED(cxxflags); return Macros(); }
|
||||
CompilerFlags compilerFlags(const QStringList &cxxflags) const override { Q_UNUSED(cxxflags); return NoFlags; }
|
||||
WarningFlags warningFlags(const QStringList &cflags) const override { Q_UNUSED(cflags); return WarningFlags::NoWarnings; }
|
||||
SystemHeaderPathsRunner createSystemHeaderPathsRunner() const override { return SystemHeaderPathsRunner(); }
|
||||
QList<HeaderPath> systemHeaderPaths(const QStringList &cxxflags, const FileName &sysRoot) const override
|
||||
{ Q_UNUSED(cxxflags); Q_UNUSED(sysRoot); return QList<HeaderPath>(); }
|
||||
void addToEnvironment(Environment &env) const override { Q_UNUSED(env); }
|
||||
QString makeCommand(const Environment &env) const override { Q_UNUSED(env); return QLatin1String("make"); }
|
||||
FileName compilerCommand() const override { return Utils::FileName::fromString(QLatin1String("/tmp/test/gcc")); }
|
||||
IOutputParser *outputParser() const override { return nullptr; }
|
||||
ToolChainConfigWidget *configurationWidget() override { return nullptr; }
|
||||
TTC *clone() const override { return new TTC(*this); }
|
||||
bool operator ==(const ToolChain &other) const override {
|
||||
if (!ToolChain::operator==(other))
|
||||
return false;
|
||||
return static_cast<const TTC *>(&other)->token == token;
|
||||
}
|
||||
|
||||
QByteArray token;
|
||||
|
||||
private:
|
||||
TTC(const TTC &other) :
|
||||
ToolChain(other.typeId(), other.detection()),
|
||||
token(other.token)
|
||||
{}
|
||||
|
||||
bool m_valid = false;
|
||||
|
||||
static QList<TTC *> m_toolChains;
|
||||
|
||||
// ToolChain interface
|
||||
public:
|
||||
};
|
||||
|
||||
QList<TTC *> TTC::m_toolChains;
|
||||
|
||||
} // namespace ProjectExplorer
|
||||
|
||||
Q_DECLARE_METATYPE(ProjectExplorer::ToolChain *)
|
||||
|
||||
namespace ProjectExplorer {
|
||||
|
||||
void ProjectExplorerPlugin::testToolChainManager_data()
|
||||
{
|
||||
QTest::addColumn<TCList>("system");
|
||||
QTest::addColumn<TCList>("user");
|
||||
QTest::addColumn<TCList>("autodetect");
|
||||
QTest::addColumn<TCList>("toDemote");
|
||||
QTest::addColumn<TCList>("toRegister");
|
||||
|
||||
TTC *system1 = nullptr;
|
||||
TTC *system1c = nullptr;
|
||||
TTC *system2 = nullptr;
|
||||
TTC *system3i = nullptr;
|
||||
TTC *user1 = nullptr;
|
||||
TTC *user1c = nullptr;
|
||||
TTC *user3i = nullptr;
|
||||
TTC *user2 = nullptr;
|
||||
TTC *auto1 = nullptr;
|
||||
TTC *auto1c = nullptr;
|
||||
TTC *auto1_2 = nullptr;
|
||||
TTC *auto2 = nullptr;
|
||||
TTC *auto3i = nullptr;
|
||||
|
||||
if (!TTC::hasToolChains()) {
|
||||
system1 = new TTC(ToolChain::AutoDetection, "system1"); Q_UNUSED(system1);
|
||||
system1c = system1->clone(); Q_UNUSED(system1c);
|
||||
system2 = new TTC(ToolChain::AutoDetection, "system2"); Q_UNUSED(system2);
|
||||
system3i = new TTC(ToolChain::AutoDetection, "system3", false); Q_UNUSED(system3i);
|
||||
user1 = new TTC(ToolChain::ManualDetection, "user1"); Q_UNUSED(user1);
|
||||
user1c = user1->clone(); Q_UNUSED(user1c);
|
||||
user2 = new TTC(ToolChain::ManualDetection, "user2"); Q_UNUSED(user2);
|
||||
user3i = new TTC(ToolChain::ManualDetection, "user3", false); Q_UNUSED(user3i);
|
||||
auto1 = new TTC(ToolChain::AutoDetectionFromSettings, "auto1"); Q_UNUSED(auto1);
|
||||
auto1c = auto1->clone(); Q_UNUSED(auto1c);
|
||||
auto1_2 = new TTC(ToolChain::AutoDetectionFromSettings, "auto1"); Q_UNUSED(auto1_2);
|
||||
auto2 = new TTC(ToolChain::AutoDetectionFromSettings, "auto2"); Q_UNUSED(auto2);
|
||||
auto3i = new TTC(ToolChain::AutoDetectionFromSettings, "auto3", false); Q_UNUSED(auto3i);
|
||||
}
|
||||
|
||||
QTest::newRow("no toolchains")
|
||||
<< (TCList()) << (TCList()) << (TCList())
|
||||
<< (TCList()) << (TCList());
|
||||
|
||||
QTest::newRow("System: system, no user")
|
||||
<< (TCList() << system1) << (TCList()) << (TCList())
|
||||
<< (TCList()) << (TCList() << system1);
|
||||
QTest::newRow("System: system, user")
|
||||
<< (TCList() << system1) << (TCList() << system1) << (TCList())
|
||||
<< (TCList()) << (TCList() << system1);
|
||||
QTest::newRow("System: no system, user") // keep, the user tool chain as it is still found
|
||||
<< (TCList()) << (TCList() << system1) << (TCList())
|
||||
<< (TCList() << system1) << (TCList() << system1);
|
||||
QTest::newRow("System: no system, invalid user")
|
||||
<< (TCList()) << (TCList() << system3i) << (TCList())
|
||||
<< (TCList()) << (TCList());
|
||||
|
||||
QTest::newRow("Auto: no auto, user")
|
||||
<< (TCList()) << (TCList() << auto1) << (TCList())
|
||||
<< (TCList() << auto1) << (TCList() << auto1);
|
||||
QTest::newRow("Auto: auto, no user")
|
||||
<< (TCList()) << (TCList()) << (TCList() << auto1)
|
||||
<< (TCList()) << (TCList() << auto1);
|
||||
QTest::newRow("Auto: auto, user")
|
||||
<< (TCList()) << (TCList() << auto1) << (TCList() << auto1)
|
||||
<< (TCList()) << (TCList() << auto1);
|
||||
QTest::newRow("Auto: auto-redetect, user")
|
||||
<< (TCList()) << (TCList() << auto1) << (TCList() << auto1_2)
|
||||
<< (TCList()) << (TCList() << auto1);
|
||||
QTest::newRow("Auto: auto-redetect, duplicate users")
|
||||
<< (TCList()) << (TCList() << auto1 << auto1c) << (TCList() << auto1_2)
|
||||
<< (TCList()) << (TCList() << auto1);
|
||||
QTest::newRow("Auto: (no) auto, invalid user")
|
||||
<< (TCList()) << (TCList() << auto3i) << (TCList())
|
||||
<< (TCList()) << (TCList());
|
||||
|
||||
QTest::newRow("Delete invalid user")
|
||||
<< (TCList()) << (TCList() << user3i) << (TCList())
|
||||
<< (TCList()) << (TCList());
|
||||
|
||||
QTest::newRow("one of everything")
|
||||
<< (TCList() << system1) << (TCList() << user1) << (TCList() << auto1)
|
||||
<< (TCList()) << (TCList() << system1 << user1 << auto1);
|
||||
}
|
||||
|
||||
void ProjectExplorerPlugin::testToolChainManager()
|
||||
{
|
||||
QFETCH(TCList, system);
|
||||
QFETCH(TCList, user);
|
||||
QFETCH(TCList, autodetect);
|
||||
QFETCH(TCList, toRegister);
|
||||
QFETCH(TCList, toDemote);
|
||||
|
||||
ToolChainOperations ops = mergeToolChainLists(system, user, autodetect);
|
||||
|
||||
QSet<ToolChain *> expToRegister = QSet<ToolChain *>::fromList(toRegister);
|
||||
QSet<ToolChain *> expToDemote = QSet<ToolChain *>::fromList(toDemote);
|
||||
|
||||
QSet<ToolChain *> actToRegister = QSet<ToolChain *>::fromList(ops.toRegister);
|
||||
QSet<ToolChain *> actToDemote = QSet<ToolChain *>::fromList(ops.toDemote);
|
||||
QSet<ToolChain *> actToDelete = QSet<ToolChain *>::fromList(ops.toDelete);
|
||||
|
||||
QCOMPARE(actToRegister.count(), ops.toRegister.count()); // no dups!
|
||||
QCOMPARE(actToDemote.count(), ops.toDemote.count()); // no dups!
|
||||
QCOMPARE(actToDelete.count(), ops.toDelete.count()); // no dups!
|
||||
|
||||
QSet<ToolChain *> tmp = actToRegister;
|
||||
tmp.intersect(actToDemote);
|
||||
QCOMPARE(tmp, actToDemote); // all toDemote are in toRegister
|
||||
|
||||
tmp = actToRegister;
|
||||
tmp.intersect(actToDelete);
|
||||
QVERIFY(tmp.isEmpty()); // Nothing that needs to be registered is to be deleted
|
||||
|
||||
tmp = actToRegister;
|
||||
tmp.unite(actToDelete);
|
||||
QCOMPARE(tmp, QSet<ToolChain *>::fromList(system + user + autodetect)); // All input is accounted for
|
||||
|
||||
QCOMPARE(expToRegister, actToRegister);
|
||||
QCOMPARE(expToDemote, actToDemote);
|
||||
QCOMPARE(QSet<ToolChain *>::fromList(system + user + autodetect),
|
||||
QSet<ToolChain *>::fromList(ops.toRegister + ops.toDemote + ops.toDelete));
|
||||
}
|
||||
|
||||
} // namespace ProjectExplorer
|
||||
|
||||
#endif // WITH_TESTS
|
||||
|
||||
477
src/plugins/projectexplorer/toolchainsettingsaccessor.cpp
Normal file
477
src/plugins/projectexplorer/toolchainsettingsaccessor.cpp
Normal file
@@ -0,0 +1,477 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 "toolchainsettingsaccessor.h"
|
||||
|
||||
#include "toolchain.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include <app/app_version.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
using namespace Utils;
|
||||
|
||||
namespace ProjectExplorer {
|
||||
namespace Internal {
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// ToolChainSettingsUpgraders:
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
class ToolChainSettingsUpgraderV0 : public Utils::VersionUpgrader
|
||||
{
|
||||
// Necessary to make Version 1 supported.
|
||||
public:
|
||||
ToolChainSettingsUpgraderV0() : Utils::VersionUpgrader(0, "4.6") { }
|
||||
|
||||
// NOOP
|
||||
QVariantMap upgrade(const QVariantMap &data) final { return data; }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Helpers:
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
static const char TOOLCHAIN_DATA_KEY[] = "ToolChain.";
|
||||
static const char TOOLCHAIN_COUNT_KEY[] = "ToolChain.Count";
|
||||
static const char TOOLCHAIN_FILENAME[] = "/toolchains.xml";
|
||||
|
||||
struct ToolChainOperations
|
||||
{
|
||||
QList<ToolChain *> toDemote;
|
||||
QList<ToolChain *> toRegister;
|
||||
QList<ToolChain *> toDelete;
|
||||
};
|
||||
|
||||
static QList<ToolChain *> autoDetectToolChains(const QList<ToolChain *> alreadyKnownTcs)
|
||||
{
|
||||
QList<ToolChain *> result;
|
||||
for (ToolChainFactory *f : ToolChainFactory::allToolChainFactories())
|
||||
result.append(f->autoDetect(alreadyKnownTcs));
|
||||
|
||||
// Remove invalid toolchains that might have sneaked in.
|
||||
return Utils::filtered(result, [](const ToolChain *tc) { return tc->isValid(); });
|
||||
}
|
||||
|
||||
static QList<ToolChain *> makeUniqueByEqual(const QList<ToolChain *> &a)
|
||||
{
|
||||
QList<ToolChain *> result;
|
||||
foreach (ToolChain *tc, a) {
|
||||
if (!Utils::contains(result, [tc](ToolChain *rtc) { return *tc == *rtc; }))
|
||||
result.append(tc);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static QList<ToolChain *> makeUniqueByPointerEqual(const QList<ToolChain *> &a)
|
||||
{
|
||||
return QSet<ToolChain *>::fromList(a).toList();
|
||||
}
|
||||
|
||||
static QList<ToolChain *> subtractById(const QList<ToolChain *> &a, const QList<ToolChain *> &b)
|
||||
{
|
||||
return Utils::filtered(a, [&b](ToolChain *atc) {
|
||||
return !Utils::anyOf(b, Utils::equal(&ToolChain::id, atc->id()));
|
||||
});
|
||||
}
|
||||
|
||||
static bool containsByEqual(const QList<ToolChain *> &a, const ToolChain *atc)
|
||||
{
|
||||
return Utils::anyOf(a, [atc](ToolChain *btc) { return *atc == *btc; });
|
||||
}
|
||||
|
||||
static QList<ToolChain *> subtractByEqual(const QList<ToolChain *> &a, const QList<ToolChain *> &b)
|
||||
{
|
||||
return Utils::filtered(a, [&b](ToolChain *atc) {
|
||||
return !Utils::anyOf(b, [atc](ToolChain *btc) { return *atc == *btc; });
|
||||
});
|
||||
}
|
||||
|
||||
static QList<ToolChain *> subtractByPointerEqual(const QList<ToolChain *> &a, const QList<ToolChain *> &b)
|
||||
{
|
||||
return Utils::filtered(a, [&b](ToolChain *atc) { return !b.contains(atc); });
|
||||
}
|
||||
|
||||
static QList<ToolChain *> stabilizeOrder(const QList<ToolChain *> &toRegister,
|
||||
const QList<ToolChain *> &userFileTcs)
|
||||
{
|
||||
// Keep the toolchains in their position in the user toolchain file to minimize diff!
|
||||
QList<ToolChain *> result;
|
||||
result.reserve(toRegister.size());
|
||||
QList<ToolChain *> toHandle = toRegister;
|
||||
|
||||
for (int i = 0; i < userFileTcs.count(); ++i) {
|
||||
const QByteArray userId = userFileTcs.at(i)->id();
|
||||
const int handlePos = Utils::indexOf(toHandle,
|
||||
[&userId](const ToolChain *htc) { return htc->id() == userId; });
|
||||
if (handlePos < 0)
|
||||
continue;
|
||||
|
||||
result.append(toHandle.at(handlePos));
|
||||
toHandle.removeAt(handlePos);
|
||||
}
|
||||
result.append(toHandle);
|
||||
return result;
|
||||
}
|
||||
|
||||
static ToolChainOperations mergeToolChainLists(const QList<ToolChain *> &systemFileTcs,
|
||||
const QList<ToolChain *> &userFileTcs,
|
||||
const QList<ToolChain *> &autodetectedTcs)
|
||||
{
|
||||
const QList<ToolChain *> uniqueUserFileTcs = makeUniqueByEqual(userFileTcs);
|
||||
QList<ToolChain *> manualUserFileTcs;
|
||||
QList<ToolChain *> autodetectedUserFileTcs;
|
||||
std::tie(autodetectedUserFileTcs, manualUserFileTcs)
|
||||
= Utils::partition(uniqueUserFileTcs, &ToolChain::isAutoDetected);
|
||||
const QList<ToolChain *> autodetectedUserTcs = subtractById(autodetectedUserFileTcs, systemFileTcs);
|
||||
|
||||
// Calculate a set of Tcs that were detected before (and saved to userFile) and that
|
||||
// got re-detected again. Take the userTcs (to keep Ids) over the same in autodetectedTcs.
|
||||
QList<ToolChain *> redetectedUserTcs;
|
||||
QList<ToolChain *> notRedetectedUserTcs;
|
||||
std::tie(redetectedUserTcs, notRedetectedUserTcs)
|
||||
= Utils::partition(autodetectedUserTcs,
|
||||
[&autodetectedTcs](ToolChain *tc) { return containsByEqual(autodetectedTcs, tc); });
|
||||
|
||||
// Remove redetected tcs from autodetectedTcs:
|
||||
const QList<ToolChain *> newlyAutodetectedTcs
|
||||
= subtractByEqual(autodetectedTcs, redetectedUserTcs);
|
||||
|
||||
const QList<ToolChain *> notRedetectedButValidUserTcs
|
||||
= Utils::filtered(notRedetectedUserTcs, &ToolChain::isValid);
|
||||
|
||||
const QList<ToolChain *> validManualUserTcs
|
||||
= Utils::filtered(manualUserFileTcs, &ToolChain::isValid);
|
||||
|
||||
ToolChainOperations result;
|
||||
result.toDemote = notRedetectedButValidUserTcs;
|
||||
result.toRegister = stabilizeOrder(systemFileTcs + validManualUserTcs + result.toDemote // manual TCs
|
||||
+ redetectedUserTcs + newlyAutodetectedTcs, // auto TCs
|
||||
userFileTcs);
|
||||
|
||||
result.toDelete = makeUniqueByPointerEqual(subtractByPointerEqual(systemFileTcs + userFileTcs + autodetectedTcs,
|
||||
result.toRegister));
|
||||
return result;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// ToolChainSettingsAccessor:
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
ToolChainSettingsAccessor::ToolChainSettingsAccessor() :
|
||||
UpgradingSettingsAccessor("QtCreatorToolChains",
|
||||
QCoreApplication::translate("ProjectExplorer::ToolChainManager", "ToolChains"),
|
||||
Core::Constants::IDE_DISPLAY_NAME)
|
||||
{
|
||||
setBaseFilePath(FileName::fromString(Core::ICore::userResourcePath() + TOOLCHAIN_FILENAME));
|
||||
|
||||
addVersionUpgrader(std::make_unique<ToolChainSettingsUpgraderV0>());
|
||||
}
|
||||
|
||||
QList<ToolChain *> ToolChainSettingsAccessor::restoreToolChains(QWidget *parent) const
|
||||
{
|
||||
// read all tool chains from SDK
|
||||
const QList<ToolChain *> systemFileTcs
|
||||
= toolChains(restoreSettings(FileName::fromString(Core::ICore::installerResourcePath() + TOOLCHAIN_FILENAME),
|
||||
parent));
|
||||
|
||||
// read all tool chains from user file.
|
||||
const QList<ToolChain *> userFileTcs = toolChains(restoreSettings(parent));
|
||||
|
||||
// Autodetect: Pass autodetected toolchains from user file so the information can be reused:
|
||||
const QList<ToolChain *> autodetectedUserFileTcs
|
||||
= Utils::filtered(userFileTcs, &ToolChain::isAutoDetected);
|
||||
const QList<ToolChain *> autodetectedTcs = autoDetectToolChains(autodetectedUserFileTcs);
|
||||
|
||||
// merge tool chains and register those that we need to keep:
|
||||
const ToolChainOperations ops = mergeToolChainLists(systemFileTcs, userFileTcs, autodetectedTcs);
|
||||
|
||||
// Process ops:
|
||||
for (ToolChain *tc : ops.toDemote)
|
||||
tc->setDetection(ToolChain::ManualDetection);
|
||||
|
||||
qDeleteAll(ops.toDelete);
|
||||
|
||||
return ops.toRegister;
|
||||
}
|
||||
|
||||
void ToolChainSettingsAccessor::saveToolChains(const QList<ToolChain *> &toolchains, QWidget *parent)
|
||||
{
|
||||
QVariantMap data;
|
||||
|
||||
int count = 0;
|
||||
for (const ToolChain *tc : toolchains) {
|
||||
if (!tc || !tc->isValid())
|
||||
continue;
|
||||
const QVariantMap tmp = tc->toMap();
|
||||
if (tmp.isEmpty())
|
||||
continue;
|
||||
data.insert(QString::fromLatin1(TOOLCHAIN_DATA_KEY) + QString::number(count), tmp);
|
||||
++count;
|
||||
}
|
||||
data.insert(TOOLCHAIN_COUNT_KEY, count);
|
||||
|
||||
// Do not save default debuggers! Those are set by the SDK!
|
||||
|
||||
saveSettings(data, parent);
|
||||
}
|
||||
|
||||
QList<ToolChain *> ToolChainSettingsAccessor::toolChains(const QVariantMap &data) const
|
||||
{
|
||||
QList<ToolChain *> result;
|
||||
const QList<ToolChainFactory *> factories = ToolChainFactory::allToolChainFactories();
|
||||
|
||||
const int count = data.value(TOOLCHAIN_COUNT_KEY, 0).toInt();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
const QString key = QString::fromLatin1(TOOLCHAIN_DATA_KEY) + QString::number(i);
|
||||
if (!data.contains(key))
|
||||
break;
|
||||
|
||||
const QVariantMap tcMap = data.value(key).toMap();
|
||||
|
||||
bool restored = false;
|
||||
for (ToolChainFactory *f : factories) {
|
||||
if (f->canRestore(tcMap)) {
|
||||
if (ToolChain *tc = f->restore(tcMap)) {
|
||||
result.append(tc);
|
||||
restored = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!restored)
|
||||
qWarning("Warning: Unable to restore compiler type '%s' for tool chain %s.",
|
||||
qPrintable(ToolChainFactory::typeIdFromMap(tcMap).toString()),
|
||||
qPrintable(QString::fromUtf8(ToolChainFactory::idFromMap(tcMap))));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ProjectExplorer
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
#include "projectexplorer.h"
|
||||
|
||||
#include "headerpath.h"
|
||||
|
||||
#include "abi.h"
|
||||
|
||||
#include <QSet>
|
||||
#include <QTest>
|
||||
|
||||
namespace ProjectExplorer {
|
||||
|
||||
typedef QList<ToolChain *> TCList;
|
||||
|
||||
class TTC : public ToolChain
|
||||
{
|
||||
public:
|
||||
TTC(ToolChain::Detection d, const QByteArray &t, bool v = true) :
|
||||
ToolChain("TestToolChainType", d),
|
||||
token(t),
|
||||
m_valid(v)
|
||||
{
|
||||
m_toolChains.append(this);
|
||||
setLanguage(Constants::CXX_LANGUAGE_ID);
|
||||
}
|
||||
|
||||
static QList<TTC *> toolChains();
|
||||
static bool hasToolChains() { return !m_toolChains.isEmpty(); }
|
||||
|
||||
QString typeDisplayName() const override { return "Test Tool Chain"; }
|
||||
Abi targetAbi() const override { return Abi::hostAbi(); }
|
||||
bool isValid() const override { return m_valid; }
|
||||
PredefinedMacrosRunner createPredefinedMacrosRunner() const override { return PredefinedMacrosRunner(); }
|
||||
Macros predefinedMacros(const QStringList &cxxflags) const override { Q_UNUSED(cxxflags); return Macros(); }
|
||||
CompilerFlags compilerFlags(const QStringList &cxxflags) const override { Q_UNUSED(cxxflags); return NoFlags; }
|
||||
WarningFlags warningFlags(const QStringList &cflags) const override { Q_UNUSED(cflags); return WarningFlags::NoWarnings; }
|
||||
SystemHeaderPathsRunner createSystemHeaderPathsRunner() const override { return SystemHeaderPathsRunner(); }
|
||||
QList<HeaderPath> systemHeaderPaths(const QStringList &cxxflags, const FileName &sysRoot) const override
|
||||
{ Q_UNUSED(cxxflags); Q_UNUSED(sysRoot); return QList<HeaderPath>(); }
|
||||
void addToEnvironment(Environment &env) const override { Q_UNUSED(env); }
|
||||
QString makeCommand(const Environment &env) const override { Q_UNUSED(env); return "make"; }
|
||||
FileName compilerCommand() const override { return Utils::FileName::fromString("/tmp/test/gcc"); }
|
||||
IOutputParser *outputParser() const override { return nullptr; }
|
||||
ToolChainConfigWidget *configurationWidget() override { return nullptr; }
|
||||
TTC *clone() const override { return new TTC(*this); }
|
||||
bool operator ==(const ToolChain &other) const override {
|
||||
if (!ToolChain::operator==(other))
|
||||
return false;
|
||||
return static_cast<const TTC *>(&other)->token == token;
|
||||
}
|
||||
|
||||
QByteArray token;
|
||||
|
||||
private:
|
||||
TTC(const TTC &other) :
|
||||
ToolChain(other.typeId(), other.detection()),
|
||||
token(other.token)
|
||||
{}
|
||||
|
||||
bool m_valid = false;
|
||||
|
||||
static QList<TTC *> m_toolChains;
|
||||
|
||||
public:
|
||||
};
|
||||
|
||||
QList<TTC *> TTC::m_toolChains;
|
||||
|
||||
} // namespace ProjectExplorer
|
||||
|
||||
Q_DECLARE_METATYPE(ProjectExplorer::ToolChain *)
|
||||
|
||||
namespace ProjectExplorer {
|
||||
|
||||
void ProjectExplorerPlugin::testToolChainMerging_data()
|
||||
{
|
||||
QTest::addColumn<TCList>("system");
|
||||
QTest::addColumn<TCList>("user");
|
||||
QTest::addColumn<TCList>("autodetect");
|
||||
QTest::addColumn<TCList>("toDemote");
|
||||
QTest::addColumn<TCList>("toRegister");
|
||||
|
||||
TTC *system1 = nullptr;
|
||||
TTC *system1c = nullptr;
|
||||
TTC *system2 = nullptr;
|
||||
TTC *system3i = nullptr;
|
||||
TTC *user1 = nullptr;
|
||||
TTC *user1c = nullptr;
|
||||
TTC *user3i = nullptr;
|
||||
TTC *user2 = nullptr;
|
||||
TTC *auto1 = nullptr;
|
||||
TTC *auto1c = nullptr;
|
||||
TTC *auto1_2 = nullptr;
|
||||
TTC *auto2 = nullptr;
|
||||
TTC *auto3i = nullptr;
|
||||
|
||||
if (!TTC::hasToolChains()) {
|
||||
system1 = new TTC(ToolChain::AutoDetection, "system1"); Q_UNUSED(system1);
|
||||
system1c = system1->clone(); Q_UNUSED(system1c);
|
||||
system2 = new TTC(ToolChain::AutoDetection, "system2"); Q_UNUSED(system2);
|
||||
system3i = new TTC(ToolChain::AutoDetection, "system3", false); Q_UNUSED(system3i);
|
||||
user1 = new TTC(ToolChain::ManualDetection, "user1"); Q_UNUSED(user1);
|
||||
user1c = user1->clone(); Q_UNUSED(user1c);
|
||||
user2 = new TTC(ToolChain::ManualDetection, "user2"); Q_UNUSED(user2);
|
||||
user3i = new TTC(ToolChain::ManualDetection, "user3", false); Q_UNUSED(user3i);
|
||||
auto1 = new TTC(ToolChain::AutoDetectionFromSettings, "auto1"); Q_UNUSED(auto1);
|
||||
auto1c = auto1->clone(); Q_UNUSED(auto1c);
|
||||
auto1_2 = new TTC(ToolChain::AutoDetectionFromSettings, "auto1"); Q_UNUSED(auto1_2);
|
||||
auto2 = new TTC(ToolChain::AutoDetectionFromSettings, "auto2"); Q_UNUSED(auto2);
|
||||
auto3i = new TTC(ToolChain::AutoDetectionFromSettings, "auto3", false); Q_UNUSED(auto3i);
|
||||
}
|
||||
|
||||
QTest::newRow("no toolchains")
|
||||
<< (TCList()) << (TCList()) << (TCList())
|
||||
<< (TCList()) << (TCList());
|
||||
|
||||
QTest::newRow("System: system, no user")
|
||||
<< (TCList() << system1) << (TCList()) << (TCList())
|
||||
<< (TCList()) << (TCList() << system1);
|
||||
QTest::newRow("System: system, user")
|
||||
<< (TCList() << system1) << (TCList() << system1) << (TCList())
|
||||
<< (TCList()) << (TCList() << system1);
|
||||
QTest::newRow("System: no system, user") // keep, the user tool chain as it is still found
|
||||
<< (TCList()) << (TCList() << system1) << (TCList())
|
||||
<< (TCList() << system1) << (TCList() << system1);
|
||||
QTest::newRow("System: no system, invalid user")
|
||||
<< (TCList()) << (TCList() << system3i) << (TCList())
|
||||
<< (TCList()) << (TCList());
|
||||
|
||||
QTest::newRow("Auto: no auto, user")
|
||||
<< (TCList()) << (TCList() << auto1) << (TCList())
|
||||
<< (TCList() << auto1) << (TCList() << auto1);
|
||||
QTest::newRow("Auto: auto, no user")
|
||||
<< (TCList()) << (TCList()) << (TCList() << auto1)
|
||||
<< (TCList()) << (TCList() << auto1);
|
||||
QTest::newRow("Auto: auto, user")
|
||||
<< (TCList()) << (TCList() << auto1) << (TCList() << auto1)
|
||||
<< (TCList()) << (TCList() << auto1);
|
||||
QTest::newRow("Auto: auto-redetect, user")
|
||||
<< (TCList()) << (TCList() << auto1) << (TCList() << auto1_2)
|
||||
<< (TCList()) << (TCList() << auto1);
|
||||
QTest::newRow("Auto: auto-redetect, duplicate users")
|
||||
<< (TCList()) << (TCList() << auto1 << auto1c) << (TCList() << auto1_2)
|
||||
<< (TCList()) << (TCList() << auto1);
|
||||
QTest::newRow("Auto: (no) auto, invalid user")
|
||||
<< (TCList()) << (TCList() << auto3i) << (TCList())
|
||||
<< (TCList()) << (TCList());
|
||||
|
||||
QTest::newRow("Delete invalid user")
|
||||
<< (TCList()) << (TCList() << user3i) << (TCList())
|
||||
<< (TCList()) << (TCList());
|
||||
|
||||
QTest::newRow("one of everything")
|
||||
<< (TCList() << system1) << (TCList() << user1) << (TCList() << auto1)
|
||||
<< (TCList()) << (TCList() << system1 << user1 << auto1);
|
||||
}
|
||||
|
||||
void ProjectExplorerPlugin::testToolChainMerging()
|
||||
{
|
||||
QFETCH(TCList, system);
|
||||
QFETCH(TCList, user);
|
||||
QFETCH(TCList, autodetect);
|
||||
QFETCH(TCList, toRegister);
|
||||
QFETCH(TCList, toDemote);
|
||||
|
||||
Internal::ToolChainOperations ops = Internal::mergeToolChainLists(system, user, autodetect);
|
||||
|
||||
QSet<ToolChain *> expToRegister = QSet<ToolChain *>::fromList(toRegister);
|
||||
QSet<ToolChain *> expToDemote = QSet<ToolChain *>::fromList(toDemote);
|
||||
|
||||
QSet<ToolChain *> actToRegister = QSet<ToolChain *>::fromList(ops.toRegister);
|
||||
QSet<ToolChain *> actToDemote = QSet<ToolChain *>::fromList(ops.toDemote);
|
||||
QSet<ToolChain *> actToDelete = QSet<ToolChain *>::fromList(ops.toDelete);
|
||||
|
||||
QCOMPARE(actToRegister.count(), ops.toRegister.count()); // no dups!
|
||||
QCOMPARE(actToDemote.count(), ops.toDemote.count()); // no dups!
|
||||
QCOMPARE(actToDelete.count(), ops.toDelete.count()); // no dups!
|
||||
|
||||
QSet<ToolChain *> tmp = actToRegister;
|
||||
tmp.intersect(actToDemote);
|
||||
QCOMPARE(tmp, actToDemote); // all toDemote are in toRegister
|
||||
|
||||
tmp = actToRegister;
|
||||
tmp.intersect(actToDelete);
|
||||
QVERIFY(tmp.isEmpty()); // Nothing that needs to be registered is to be deleted
|
||||
|
||||
tmp = actToRegister;
|
||||
tmp.unite(actToDelete);
|
||||
QCOMPARE(tmp, QSet<ToolChain *>::fromList(system + user + autodetect)); // All input is accounted for
|
||||
|
||||
QCOMPARE(expToRegister, actToRegister);
|
||||
QCOMPARE(expToDemote, actToDemote);
|
||||
QCOMPARE(QSet<ToolChain *>::fromList(system + user + autodetect),
|
||||
QSet<ToolChain *>::fromList(ops.toRegister + ops.toDemote + ops.toDelete));
|
||||
}
|
||||
|
||||
} // namespace ProjectExplorer
|
||||
|
||||
#endif // WITH_TESTS
|
||||
|
||||
54
src/plugins/projectexplorer/toolchainsettingsaccessor.h
Normal file
54
src/plugins/projectexplorer/toolchainsettingsaccessor.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 <QList>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace ProjectExplorer {
|
||||
|
||||
class ToolChain;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class ToolChainSettingsAccessor : public Utils::UpgradingSettingsAccessor
|
||||
{
|
||||
public:
|
||||
ToolChainSettingsAccessor();
|
||||
|
||||
QList<ToolChain *> restoreToolChains(QWidget *parent) const;
|
||||
|
||||
void saveToolChains(const QList<ToolChain *> &toolchains, QWidget *parent);
|
||||
|
||||
private:
|
||||
QList<ToolChain *> toolChains(const QVariantMap &data) const;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ProjectExplorer
|
||||
Reference in New Issue
Block a user