ProjectImporter: Generalize handling of temporary data associated with kits

Generalize handling of temporary Qt versions, etc. that is associated with
temporary kits while importing projects.

Change-Id: I16a0c2e7f32546e131dcbeddc7a1e5048a9ad4c8
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
Tobias Hunger
2016-08-26 12:22:47 +02:00
parent b07f92abc9
commit 15ac730438
5 changed files with 154 additions and 52 deletions

View File

@@ -40,6 +40,7 @@
#include <QLoggingCategory>
#include <QMessageBox>
#include <QString>
namespace ProjectExplorer {
@@ -48,6 +49,26 @@ static const Core::Id KIT_TEMPORARY_NAME("PE.TempName");
static const Core::Id KIT_FINAL_NAME("PE.FinalName");
static const Core::Id TEMPORARY_OF_PROJECTS("PE.TempProject");
static Core::Id fullId(Core::Id id)
{
const QString prefix = "PE.Temporary.";
const QString idStr = id.toString();
QTC_ASSERT(!idStr.startsWith(prefix), return Core::Id::fromString(idStr));
return Core::Id::fromString(prefix + idStr);
}
static bool hasOtherUsers(Core::Id id, const QVariant &v, Kit *k)
{
return Utils::contains(KitManager::kits(), [id, v, k](Kit *in) -> bool {
if (in == k)
return false;
QVariantList tmp = in->value(id).toList();
return tmp.contains(v);
});
}
ProjectImporter::ProjectImporter(const QString &path) : m_projectPath(path)
{ }
@@ -146,7 +167,7 @@ Target *ProjectImporter::preferredTarget(const QList<Target *> &possibleTargets)
return activeTarget;
}
void ProjectImporter::markTemporary(Kit *k) const
void ProjectImporter::markKitAsTemporary(Kit *k) const
{
QTC_ASSERT(!k->hasValue(KIT_IS_TEMPORARY), return);
@@ -161,13 +182,14 @@ void ProjectImporter::markTemporary(Kit *k) const
k->setValue(KIT_IS_TEMPORARY, true);
}
void ProjectImporter::makePermanent(Kit *k) const
void ProjectImporter::makePersistent(Kit *k) const
{
if (!k->hasValue(KIT_IS_TEMPORARY))
return;
UpdateGuard guard(*this);
KitGuard kitGuard(k);
k->removeKey(KIT_IS_TEMPORARY);
k->removeKey(TEMPORARY_OF_PROJECTS);
const QString tempName = k->value(KIT_TEMPORARY_NAME).toString();
@@ -175,11 +197,38 @@ void ProjectImporter::makePermanent(Kit *k) const
k->setUnexpandedDisplayName(k->value(KIT_FINAL_NAME).toString());
k->removeKey(KIT_TEMPORARY_NAME);
k->removeKey(KIT_FINAL_NAME);
foreach (const TemporaryInformationHandler &tih, m_temporaryHandlers) {
const Core::Id fid = fullId(tih.id);
const QVariantList temporaryValues = k->value(fid).toList();
// Mark permanent in all other kits:
foreach (Kit *ok, KitManager::kits()) {
if (ok == k)
continue;
QVariantList otherTemporaryValues = ok->value(fid).toList();
otherTemporaryValues = Utils::filtered(otherTemporaryValues, [&temporaryValues](const QVariant &v) {
return temporaryValues.contains(v);
});
ok->setValueSilently(fid, otherTemporaryValues);
}
// persist:
tih.persist(k, temporaryValues);
}
}
void ProjectImporter::cleanupKit(Kit *k)
{
Q_UNUSED(k);
foreach (const TemporaryInformationHandler &tih, m_temporaryHandlers) {
const Core::Id fid = fullId(tih.id);
QVariantList temporaryValues = k->value(fid).toList();
temporaryValues = Utils::filtered(temporaryValues, [fid, k](const QVariant &v) {
return !hasOtherUsers(fid, v, k);
});
tih.cleanup(k, temporaryValues);
}
}
void ProjectImporter::addProject(Kit *k)
@@ -220,7 +269,7 @@ Kit *ProjectImporter::createTemporaryKit(const KitSetupFunction &setup) const
{
KitGuard kitGuard(k);
k->setUnexpandedDisplayName(QCoreApplication::translate("ProjectExplorer::ProjectImporter", "Imported Kit"));;
markTemporary(k);
markKitAsTemporary(k);
setup(k);
@@ -232,4 +281,37 @@ Kit *ProjectImporter::createTemporaryKit(const KitSetupFunction &setup) const
return k;
}
bool ProjectImporter::findTemporaryHandler(Core::Id id) const
{
return Utils::contains(m_temporaryHandlers, [id](const TemporaryInformationHandler &ch) { return ch.id == id; });
}
void ProjectImporter::useTemporaryKitInformation(Core::Id id,
ProjectImporter::CleanupFunction cleanup,
ProjectImporter::PersistFunction persist)
{
QTC_ASSERT(!findTemporaryHandler(id), return);
m_temporaryHandlers.append({ id, cleanup, persist });
}
void ProjectImporter::addTemporaryData(Core::Id id, const QVariant &cleanupData, Kit *k) const
{
QTC_ASSERT(findTemporaryHandler(id), return);
const Core::Id fid = fullId(id);
KitGuard guard(k);
QVariantList tmp = k->value(fid).toList();
QTC_ASSERT(!tmp.contains(cleanupData), return);
tmp.append(cleanupData);
k->setValue(fid, tmp);
}
bool ProjectImporter::hasKitWithTemporaryData(Core::Id id, const QVariant &data) const
{
Core::Id fid = fullId(id);
return Utils::contains(KitManager::kits(), [data, fid](Kit *k) {
return k->value(fid).toList().contains(data);
});
}
} // namespace ProjectExplorer

View File

@@ -27,6 +27,8 @@
#include "projectexplorer_export.h"
#include <coreplugin/id.h>
#include <utils/fileutils.h>
namespace ProjectExplorer {
@@ -51,10 +53,8 @@ public:
bool isUpdating() const { return m_isUpdating; }
virtual void makePermanent(Kit *k) const;
// Additional cleanup that has to happen when kits are removed
virtual void cleanupKit(Kit *k);
void makePersistent(Kit *k) const;
void cleanupKit(Kit *k);
bool isTemporaryKit(Kit *k) const;
@@ -89,12 +89,30 @@ protected:
using KitSetupFunction = std::function<void(Kit *)>;
ProjectExplorer::Kit *createTemporaryKit(const KitSetupFunction &setup) const;
// Handle temporary additions to Kits (Qt Versions, ToolChains, etc.)
using CleanupFunction = std::function<void(Kit *, const QVariantList &)>;
using PersistFunction = std::function<void(Kit *, const QVariantList &)>;
void useTemporaryKitInformation(Core::Id id,
CleanupFunction cleanup, PersistFunction persist);
void addTemporaryData(Core::Id id, const QVariant &cleanupData, Kit *k) const;
// Does *any* kit feature the requested data yet?
bool hasKitWithTemporaryData(Core::Id id, const QVariant &data) const;
private:
void markTemporary(Kit *k) const;
void markKitAsTemporary(Kit *k) const;
bool findTemporaryHandler(Core::Id id) const;
const QString m_projectPath;
mutable bool m_isUpdating = false;
class TemporaryInformationHandler {
public:
Core::Id id;
CleanupFunction cleanup;
PersistFunction persist;
};
QList<TemporaryInformationHandler> m_temporaryHandlers;
friend class UpdateGuard;
};

View File

@@ -362,7 +362,7 @@ void TargetSetupPage::handleKitUpdate(Kit *k)
return;
if (m_importer)
m_importer->makePermanent(k);
m_importer->makePersistent(k);
TargetSetupWidget *widget = m_widgets.value(k->id());
@@ -543,7 +543,7 @@ bool TargetSetupPage::setupProject(Project *project)
Kit *k = widget->kit();
if (m_importer)
m_importer->makePermanent(k);
m_importer->makePersistent(k);
toSetUp << widget->selectedBuildInfoList();
widget->clearKit();
}

View File

@@ -35,6 +35,7 @@
#include <utils/algorithm.h>
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
#include <QFileInfo>
#include <QList>
@@ -43,38 +44,11 @@ using namespace ProjectExplorer;
namespace QtSupport {
const Core::Id QT_IS_TEMPORARY("Qt.TempQt");
static void cleanTemporaryVersion(BaseQtVersion *version) {
if (!version)
return;
// count how many kits are using this version
const int qtId = version->uniqueId();
const int users = Utils::count(KitManager::kits(), [qtId](Kit *k) {
return k->value(QT_IS_TEMPORARY, -1).toInt() == qtId;
});
if (users == 0) // Remove if no other kit is using it. (The Kit k is not in KitManager::kits()
QtVersionManager::removeVersion(version);
}
void QtProjectImporter::makePermanent(Kit *k) const
QtProjectImporter::QtProjectImporter(const QString &path) : ProjectImporter(path)
{
if (!isTemporaryKit(k))
return;
UpdateGuard guard(*this);
const int tempId = k->value(QT_IS_TEMPORARY, -1).toInt();
k->removeKeySilently(QT_IS_TEMPORARY);
const int qtId = QtKitInformation::qtVersionId(k);
if (tempId != qtId)
cleanTemporaryVersion(QtVersionManager::version(tempId));
foreach (Kit *kit, KitManager::kits())
if (kit->value(QT_IS_TEMPORARY, -1).toInt() == tempId)
kit->removeKeySilently(QT_IS_TEMPORARY);
ProjectImporter::makePermanent(k);
useTemporaryKitInformation(QtKitInformation::id(),
[this](Kit *k, const QVariantList &vl) { cleanupTemporaryQt(k, vl); },
[this](Kit *k, const QVariantList &vl) { persistTemporaryQt(k, vl); });
}
QtProjectImporter::QtVersionData
@@ -92,9 +66,7 @@ QtProjectImporter::findOrCreateQtVersion(const Utils::FileName &qmakePath) const
if (result.qt) {
// Check if version is a temporary qt
const int qtId = result.qt->uniqueId();
result.isTemporary = Utils::anyOf(KitManager::kits(), [&qtId](Kit *k) {
return k->value(QT_IS_TEMPORARY, -1).toInt() == qtId;
});
result.isTemporary = hasKitWithTemporaryData(QtKitInformation::id(), qtId);
return result;
}
@@ -111,17 +83,46 @@ QtProjectImporter::findOrCreateQtVersion(const Utils::FileName &qmakePath) const
}
Kit *QtProjectImporter::createTemporaryKit(const QtVersionData &versionData,
const ProjectImporter::KitSetupFunction &setup) const
const ProjectImporter::KitSetupFunction &additionalSetup) const
{
return ProjectImporter::createTemporaryKit([&setup, &versionData](Kit *k) -> void {
return ProjectImporter::createTemporaryKit([&additionalSetup, &versionData, this](Kit *k) -> void {
QtKitInformation::setQtVersion(k, versionData.qt);
if (versionData.isTemporary)
k->setValue(QT_IS_TEMPORARY, versionData.qt->uniqueId());
addTemporaryData(QtKitInformation::id(), versionData.qt->uniqueId(), k);
k->setUnexpandedDisplayName(versionData.qt->displayName());;
setup(k);
additionalSetup(k);
});
}
static BaseQtVersion *versionFromVariant(const QVariant &v)
{
bool ok;
const int qtId = v.toInt(&ok);
QTC_ASSERT(ok, return nullptr);
return QtVersionManager::version(qtId);
}
void QtProjectImporter::cleanupTemporaryQt(Kit *k, const QVariantList &vl)
{
Q_UNUSED(k);
QTC_ASSERT(vl.count() == 1, return);
BaseQtVersion *version = versionFromVariant(vl.at(0));
QTC_ASSERT(version, return);
QtVersionManager::removeVersion(version);
}
void QtProjectImporter::persistTemporaryQt(Kit *k, const QVariantList &vl)
{
QTC_ASSERT(vl.count() == 1, return);
BaseQtVersion *tmpVersion = versionFromVariant(vl.at(0));
BaseQtVersion *actualVersion = QtKitInformation::qtVersion(k);
// User changed Kit away from temporary Qt that was set up:
if (tmpVersion && actualVersion != tmpVersion)
QtVersionManager::removeVersion(tmpVersion);
}
} // namespace QtSupport

View File

@@ -41,9 +41,6 @@ class QTSUPPORT_EXPORT QtProjectImporter : public ProjectExplorer::ProjectImport
public:
QtProjectImporter(const QString &path);
void cleanupKit(ProjectExplorer::Kit *k) override;
void makePermanent(ProjectExplorer::Kit *k) const override;
class QtVersionData
{
public:
@@ -55,6 +52,10 @@ protected:
QtVersionData findOrCreateQtVersion(const Utils::FileName &qmakePath) const;
ProjectExplorer::Kit *createTemporaryKit(const QtVersionData &versionData,
const KitSetupFunction &setup) const;
private:
void cleanupTemporaryQt(ProjectExplorer::Kit *k, const QVariantList &vl);
void persistTemporaryQt(ProjectExplorer::Kit *k, const QVariantList &vl);
};
} // namespace QmakeProjectManager