aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/utils/settingsaccessor.cpp
diff options
context:
space:
mode:
authorTobias Hunger <tobias.hunger@qt.io>2017-12-12 12:23:03 +0100
committerTobias Hunger <tobias.hunger@qt.io>2018-02-13 12:21:33 +0000
commit23bb71710171a10f36c2b4e47b7049926a007698 (patch)
tree39199d6e0ad1d84dc887436dbea20f34288f1a78 /src/libs/utils/settingsaccessor.cpp
parenta2581a2a89caa538972d2325bfdb17f3f71d24f4 (diff)
SettingsAccessor: Extract handling of backups
Extract the code that handles backups from the SettingsAccessor into a BackingUpSettingsAccessor. Move code up from SettingsAccessor into UserFileAccessor where it belongs. This became possible due to the extraction. Change-Id: Icacaa4e7231b3c0c520154c76f9338227f96a614 Reviewed-by: Eike Ziller <eike.ziller@qt.io>
Diffstat (limited to 'src/libs/utils/settingsaccessor.cpp')
-rw-r--r--src/libs/utils/settingsaccessor.cpp434
1 files changed, 203 insertions, 231 deletions
diff --git a/src/libs/utils/settingsaccessor.cpp b/src/libs/utils/settingsaccessor.cpp
index 4c96ed95cc..53c1ab319b 100644
--- a/src/libs/utils/settingsaccessor.cpp
+++ b/src/libs/utils/settingsaccessor.cpp
@@ -25,6 +25,7 @@
#include "settingsaccessor.h"
+#include "algorithm.h"
#include "asconst.h"
#include "qtcassert.h"
@@ -49,6 +50,7 @@ static QString generateSuffix(const QString &suffix)
return result;
}
+// FIXME: Remove this!
class Operation {
public:
virtual ~Operation() { }
@@ -98,18 +100,6 @@ public:
};
-class TrackStickyness : public Operation
-{
-public:
- void apply(QVariantMap &userMap, const QString &key, const QVariant &)
- {
- const QString stickyKey = USER_STICKY_KEYS_KEY;
- QVariantList sticky = userMap.value(stickyKey).toList();
- sticky.append(key);
- userMap.insert(stickyKey, sticky);
- }
-};
-
// When restoring settings...
// We check whether a .shared file exists. If so, we compare the settings in this file with
// corresponding ones in the .user file. Whenever we identify a corresponding setting which
@@ -128,24 +118,7 @@ QVariantMap mergeSharedSettings(const QVariantMap &userMap, const QVariantMap &s
return result;
}
-// When saving settings...
-// If a .shared file was considered in the previous restoring step, we check whether for
-// any of the current .shared settings there's a .user one which is different. If so, this
-// means the user explicitly changed it and we mark this setting as sticky.
-// Note that settings are considered sticky only when they differ from the .shared ones.
-// Although this approach is more flexible than permanent/forever sticky settings, it has
-// the side-effect that if a particular value unintentionally becomes the same in both
-// the .user and .shared files, this setting will "unstick".
-void trackUserStickySettings(QVariantMap &userMap, const QVariantMap &sharedMap)
-{
- if (sharedMap.isEmpty())
- return;
-
- TrackStickyness op;
- op.synchronize(userMap, sharedMap);
-}
-
-} // end namespace
+} // namespace
namespace Utils {
@@ -304,6 +277,151 @@ QVariantMap BasicSettingsAccessor::prepareToWriteSettings(const QVariantMap &dat
}
// --------------------------------------------------------------------
+// BackingUpSettingsAccessor:
+// --------------------------------------------------------------------
+
+FileNameList BackUpStrategy::readFileCandidates(const FileName &baseFileName) const
+{
+
+ const QFileInfo pfi = baseFileName.toFileInfo();
+ const QStringList filter(pfi.fileName() + '*');
+ const QFileInfoList list = QDir(pfi.dir()).entryInfoList(filter, QDir::Files | QDir::Hidden | QDir::System);
+
+ return Utils::transform(list, [](const QFileInfo &fi) { return FileName::fromString(fi.absoluteFilePath()); });
+}
+
+int BackUpStrategy::compare(const BasicSettingsAccessor::RestoreData &data1,
+ const BasicSettingsAccessor::RestoreData &data2) const
+{
+ if (!data1.issue && !data1.data.isEmpty())
+ return -1;
+
+ if (!data2.issue && !data2.data.isEmpty())
+ return 1;
+
+ return 0;
+}
+
+QString BackUpStrategy::backupName(const QVariantMap &oldData, const FileName &path,
+ const QVariantMap &data) const
+{
+ if (oldData == data)
+ return path.toString();
+ return path.toString() + ".bak";
+}
+
+int VersionedBackUpStrategy::compare(const BasicSettingsAccessor::RestoreData &data1,
+ const BasicSettingsAccessor::RestoreData &data2) const
+{
+ const int origVersion = versionFromMap(data1.data);
+ const bool origValid = isValidVersionAndId(origVersion, settingsIdFromMap(data1.data));
+
+ const int newVersion = versionFromMap(data2.data);
+ const bool newValid = isValidVersionAndId(newVersion, settingsIdFromMap(data2.data));
+
+ if ((!origValid && !newValid) || (origValid && newValid && origVersion == newVersion))
+ return 0;
+ if ((!origValid && newValid) || (origValid && newValid && origVersion < newVersion))
+ return 1;
+ return -1;
+}
+
+QString VersionedBackUpStrategy::backupName(const QVariantMap &oldData, const FileName &path, const QVariantMap &data) const
+{
+ Q_UNUSED(oldData);
+ QString backupName = path.toString();
+ const QByteArray oldEnvironmentId = settingsIdFromMap(data);
+
+ if (!oldEnvironmentId.isEmpty() && oldEnvironmentId != id())
+ backupName += '.' + QString::fromLatin1(oldEnvironmentId).mid(1, 7);
+
+ const int oldVersion = versionFromMap(data);
+ if (oldVersion != currentVersion())
+ backupName += '.' + QString::number(oldVersion);
+ return backupName;
+}
+
+bool VersionedBackUpStrategy::isValidVersionAndId(const int version, const QByteArray &otherId) const
+{
+ return (version >= firstSupportedVersion() && version <= currentVersion())
+ && (otherId == id() || id().isEmpty());
+}
+
+BackingUpSettingsAccessor::BackingUpSettingsAccessor(const QString &docType,
+ const QString &displayName,
+ const QString &applicationDisplayName) :
+ BackingUpSettingsAccessor(std::make_unique<BackUpStrategy>(), docType, displayName, applicationDisplayName)
+{ }
+
+BackingUpSettingsAccessor::BackingUpSettingsAccessor(std::unique_ptr<BackUpStrategy> &&strategy,
+ const QString &docType,
+ const QString &displayName,
+ const QString &applicationDisplayName) :
+ BasicSettingsAccessor(docType, displayName, applicationDisplayName),
+ m_strategy(std::move(strategy))
+{ }
+
+BasicSettingsAccessor::RestoreData
+BackingUpSettingsAccessor::readData(const Utils::FileName &path, QWidget *parent) const
+{
+ const FileNameList fileList = readFileCandidates(path);
+ if (fileList.isEmpty()) // No settings found at all.
+ return RestoreData(path, QVariantMap());
+
+ RestoreData result = bestReadFileData(fileList, parent);
+ if (result.path.isEmpty())
+ result.path = baseFilePath().parentDir();
+
+ return result;
+}
+
+Utils::optional<BasicSettingsAccessor::Issue>
+BackingUpSettingsAccessor::writeData(const Utils::FileName &path, const QVariantMap &data) const
+{
+ if (data.isEmpty())
+ return {};
+
+ backupFile(path, data);
+
+ return BasicSettingsAccessor::writeData(path, data);
+
+}
+
+FileNameList BackingUpSettingsAccessor::readFileCandidates(const Utils::FileName &path) const
+{
+ FileNameList result = Utils::filteredUnique(m_strategy->readFileCandidates(path));
+ if (result.removeOne(baseFilePath()))
+ result.prepend(baseFilePath());
+
+ return result;
+}
+
+BasicSettingsAccessor::RestoreData
+BackingUpSettingsAccessor::bestReadFileData(const FileNameList &candidates, QWidget *parent) const
+{
+ BasicSettingsAccessor::RestoreData bestMatch;
+ for (const FileName &c : candidates) {
+ RestoreData cData = BasicSettingsAccessor::readData(c, parent);
+ if (m_strategy->compare(bestMatch, cData) > 0)
+ bestMatch = cData;
+ }
+ return bestMatch;
+}
+
+void BackingUpSettingsAccessor::backupFile(const FileName &path, const QVariantMap &data) const
+{
+ RestoreData oldSettings = BasicSettingsAccessor::readFile(path);
+ if (oldSettings.data.isEmpty())
+ return;
+
+ // Do we need to do a backup?
+ const QString origName = path.toString();
+ QString backupFileName = m_strategy->backupName(oldSettings.data, path, data);
+ if (backupFileName != origName)
+ QFile::copy(origName, backupFileName);
+}
+
+// --------------------------------------------------------------------
// SettingsAccessorPrivate:
// --------------------------------------------------------------------
@@ -312,14 +430,6 @@ class SettingsAccessorPrivate
public:
SettingsAccessorPrivate(const FileName &projectFilePath) : m_projectFilePath(projectFilePath) { }
- // The relevant data from the settings currently in use.
- class Settings
- {
- public:
- QVariantMap map;
- FileName path;
- };
-
int firstVersion() const { return m_upgraders.size() == 0 ? -1 : m_upgraders.front()->version(); }
int lastVersion() const { return m_upgraders.size() == 0 ? -1 : m_upgraders.back()->version(); }
int currentVersion() const { return lastVersion() + 1; }
@@ -331,13 +441,11 @@ public:
return m_upgraders[static_cast<size_t>(pos)].get();
return nullptr;
}
- BasicSettingsAccessor::RestoreData bestSettings(const SettingsAccessor *accessor, const FileNameList &pathList, QWidget *parent);
std::vector<std::unique_ptr<VersionUpgrader>> m_upgraders;
- std::unique_ptr<PersistentSettingsWriter> m_writer;
QByteArray m_settingsId;
- std::unique_ptr<BasicSettingsAccessor> m_sharedFile;
+ std::unique_ptr<BackingUpSettingsAccessor> m_sharedFile;
const FileName m_projectFilePath;
};
@@ -458,16 +566,19 @@ QVariantMap VersionUpgrader::renameKeys(const QList<Change> &changes, QVariantMa
// SettingsAccessor:
// -----------------------------------------------------------------------------
-SettingsAccessor::SettingsAccessor(const Utils::FileName &baseFile, const QString &docType,
+SettingsAccessor::SettingsAccessor(std::unique_ptr<BackUpStrategy> &&strategy,
+ const Utils::FileName &baseFile, const QString &docType,
const QString &displayName, const QString &appDisplayName) :
- BasicSettingsAccessor(docType, displayName, appDisplayName),
+ BackingUpSettingsAccessor(std::move(strategy), docType, displayName, appDisplayName),
d(new SettingsAccessorPrivate(baseFile))
{
const FileName externalUser = externalUserFile();
const FileName projectUser = projectUserFile();
setBaseFilePath(externalUser.isEmpty() ? projectUser : externalUser);
- d->m_sharedFile = std::make_unique<BasicSettingsAccessor>(docType, displayName, appDisplayName);
+ d->m_sharedFile
+ = std::make_unique<BackingUpSettingsAccessor>(std::make_unique<NoBackUpStrategy>(),
+ docType, displayName, appDisplayName);
d->m_sharedFile->setBaseFilePath(sharedFile());
}
@@ -476,66 +587,6 @@ SettingsAccessor::~SettingsAccessor()
delete d;
}
-int SettingsAccessor::versionFromMap(const QVariantMap &data)
-{
- return data.value(VERSION_KEY, -1).toInt();
-}
-
-int SettingsAccessor::originalVersionFromMap(const QVariantMap &data)
-{
- return data.value(ORIGINAL_VERSION_KEY, versionFromMap(data)).toInt();
-}
-
-QVariantMap SettingsAccessor::setOriginalVersionInMap(const QVariantMap &data, int version)
-{
- QVariantMap result = data;
- result.insert(ORIGINAL_VERSION_KEY, version);
- return result;
-}
-
-QVariantMap SettingsAccessor::setVersionInMap(const QVariantMap &data, int version)
-{
- QVariantMap result = data;
- result.insert(VERSION_KEY, version);
- return result;
-}
-
-/*!
- * Check which of two sets of data are a better match to load.
- *
- * This method is used to compare data extracted from two XML settings files.
- *
- * Compares \a newData against \a origData.
- *
- * Returns \c true if \a newData is a better match than \a origData and \c false otherwise.
- */
-bool SettingsAccessor::isBetterMatch(const QVariantMap &origData, const QVariantMap &newData) const
-{
- const int origVersion = versionFromMap(origData);
- const bool origValid = isValidVersionAndId(origVersion, settingsIdFromMap(origData));
-
- const int newVersion = versionFromMap(newData);
- const bool newValid = isValidVersionAndId(newVersion, settingsIdFromMap(newData));
-
- if (!origValid)
- return newValid;
-
- if (!newValid)
- return false;
-
- return newVersion > origVersion;
-}
-
-bool SettingsAccessor::isValidVersionAndId(const int version, const QByteArray &id) const
-{
- const QByteArray requiredId = settingsId();
- const int firstVersion = firstSupportedVersion();
- const int lastVersion = currentVersion();
-
- return (version >= firstVersion && version <= lastVersion)
- && ( id == requiredId || requiredId.isEmpty());
-}
-
/*!
* Upgrade the settings in \a data to the version \a toVersion.
*
@@ -552,25 +603,32 @@ QVariantMap SettingsAccessor::upgradeSettings(const QVariantMap &data, int targe
QTC_ASSERT(targetVersion <= currentVersion(), return data);
const int version = versionFromMap(data);
- if (!isValidVersionAndId(version, settingsIdFromMap(data)))
+ VersionedBackUpStrategy *strat = dynamic_cast<VersionedBackUpStrategy *>(strategy());
+ if (!strat || !strat->isValidVersionAndId(version, settingsIdFromMap(data)))
return data;
- QVariantMap result;
+ QVariantMap result = data;
if (!data.contains(ORIGINAL_VERSION_KEY))
- result = setOriginalVersionInMap(data, version);
- else
- result = data;
+ setOriginalVersionInMap(result, version);
for (int i = version; i < targetVersion; ++i) {
VersionUpgrader *upgrader = d->upgrader(i);
QTC_CHECK(upgrader && upgrader->version() == i);
result = upgrader->upgrade(result);
- result = setVersionInMap(result, i + 1);
+ setVersionInMap(result, i + 1);
}
return result;
}
+QVariantMap SettingsAccessor::prepareToWriteSettings(const QVariantMap &data) const
+{
+ QVariantMap result = data;
+ setVersionInMap(result, currentVersion());
+ setSettingsIdInMap(result, settingsId());
+ return result;
+}
+
/*!
* Checks \a data located at \a path for issues to be displayed with reportIssues.
*
@@ -632,11 +690,6 @@ void SettingsAccessor::storeSharedSettings(const QVariantMap &data) const
Q_UNUSED(data);
}
-QVariant SettingsAccessor::retrieveSharedSettings() const
-{
- return QVariant();
-}
-
QString SettingsAccessor::differentEnvironmentMsg(const QString &projectName)
{
return QApplication::translate("Utils::EnvironmentIdAccessor",
@@ -644,24 +697,6 @@ QString SettingsAccessor::differentEnvironmentMsg(const QString &projectName)
.arg(projectName);
}
-QByteArray SettingsAccessor::settingsIdFromMap(const QVariantMap &data)
-{
- return data.value(SETTINGS_ID_KEY).toByteArray();
-}
-
-QVariantMap SettingsAccessor::prepareToWriteSettings(const QVariantMap &data) const
-{
- QVariantMap tmp = data;
- const QVariant &shared = retrieveSharedSettings();
- if (shared.isValid())
- trackUserStickySettings(tmp, shared.toMap());
-
- tmp.insert(VERSION_KEY, d->currentVersion());
- tmp.insert(SETTINGS_ID_KEY, settingsId());
-
- return tmp;
-}
-
bool SettingsAccessor::addVersionUpgrader(std::unique_ptr<VersionUpgrader> upgrader)
{
QTC_ASSERT(upgrader.get(), return false);
@@ -704,7 +739,7 @@ BasicSettingsAccessor::RestoreData SettingsAccessor::readData(const FileName &pa
// FIXME: Do better error handling:
QTC_ASSERT(d->lastVersion() >= 0, return RestoreData("SETUP FAILED", "SETUP FAILED"));
- RestoreData userSettings = readUserSettings(parent);
+ RestoreData userSettings = BackingUpSettingsAccessor::readData(path, parent);
if (userSettings.issue && reportIssues(userSettings.issue.value(), userSettings.path, parent) == DiscardAndContinue)
userSettings.data.clear();
@@ -717,51 +752,11 @@ BasicSettingsAccessor::RestoreData SettingsAccessor::readData(const FileName &pa
return mergedSettings;
}
-Utils::optional<BasicSettingsAccessor::Issue> SettingsAccessor::writeData(const FileName &path,
- const QVariantMap &data) const
-{
- if (data.isEmpty())
- return {};
-
- backupUserFile();
-
- return BasicSettingsAccessor::writeData(path, data);
-}
-
void SettingsAccessor::setSettingsId(const QByteArray &id)
{
d->m_settingsId = id;
}
-/* Will always return the default name first (if applicable) */
-FileNameList SettingsAccessor::settingsFiles() const
-{
- FileNameList result;
-
- QFileInfoList list;
- const QFileInfo pfi = baseFilePath().toFileInfo();
- const QStringList filter(pfi.fileName() + '*');
-
- const FileName externalUser = externalUserFile();
- if (!externalUser.isEmpty()) {
- const QString externalPath = externalUser.toString() + '/' + makeRelative(pfi.absolutePath());
- list.append(QDir(externalPath).entryInfoList(filter, QDir::Files | QDir::Hidden | QDir::System));
- }
- list.append(QDir(pfi.dir()).entryInfoList(filter, QDir::Files | QDir::Hidden | QDir::System));
-
- foreach (const QFileInfo &fi, list) {
- const FileName path = FileName::fromString(fi.absoluteFilePath());
- if (!result.contains(path)) {
- if (path == baseFilePath())
- result.prepend(path);
- else
- result.append(path);
- }
- }
-
- return result;
-}
-
QByteArray SettingsAccessor::settingsId() const
{
return d->m_settingsId;
@@ -777,49 +772,6 @@ int SettingsAccessor::firstSupportedVersion() const
return d->firstVersion();
}
-FileName SettingsAccessor::backupName(const QVariantMap &data) const
-{
- QString backupName = baseFilePath().toString();
- const QByteArray oldEnvironmentId = settingsIdFromMap(data);
- if (!oldEnvironmentId.isEmpty() && oldEnvironmentId != settingsId())
- backupName += '.' + QString::fromLatin1(oldEnvironmentId).mid(1, 7);
- const int oldVersion = versionFromMap(data);
- if (oldVersion != currentVersion()) {
- VersionUpgrader *upgrader = d->upgrader(oldVersion);
- if (upgrader)
- backupName += '.' + upgrader->backupExtension();
- else
- backupName += '.' + QString::number(oldVersion);
- }
- return FileName::fromString(backupName);
-}
-
-void SettingsAccessor::backupUserFile() const
-{
- RestoreData oldSettings = BasicSettingsAccessor::readFile(baseFilePath());
- if (oldSettings.data.isEmpty())
- return;
-
- // Do we need to do a backup?
- const QString origName = oldSettings.path.toString();
- QString backupFileName = backupName(oldSettings.data).toString();
- if (backupFileName != origName)
- QFile::copy(origName, backupFileName);
-}
-
-SettingsAccessor::RestoreData SettingsAccessor::readUserSettings(QWidget *parent) const
-{
- FileNameList fileList = settingsFiles();
- if (fileList.isEmpty()) // No settings found at all.
- return RestoreData(baseFilePath(), QVariantMap());
-
- RestoreData result = d->bestSettings(this, fileList, parent);
- if (result.path.isEmpty())
- result.path = baseFilePath().parentDir();
-
- return result;
-}
-
SettingsAccessor::RestoreData SettingsAccessor::readSharedSettings(QWidget *parent) const
{
RestoreData sharedSettings = d->m_sharedFile->readData(d->m_sharedFile->baseFilePath(), parent);
@@ -845,20 +797,6 @@ SettingsAccessor::RestoreData SettingsAccessor::readSharedSettings(QWidget *pare
return sharedSettings;
}
-SettingsAccessor::RestoreData SettingsAccessorPrivate::bestSettings(const SettingsAccessor *accessor,
- const FileNameList &pathList,
- QWidget *parent)
-{
- SettingsAccessor::RestoreData bestMatch;
- foreach (const FileName &path, pathList) {
- const SettingsAccessor::RestoreData tmp = accessor->BasicSettingsAccessor::readData(path, parent);
-
- if (accessor->isBetterMatch(bestMatch.data, tmp.data))
- bestMatch = tmp;
- }
- return bestMatch;
-}
-
QVariantMap
SettingsAccessor::mergeSettings(const QVariantMap &userMap, const QVariantMap &sharedMap) const
{
@@ -881,4 +819,38 @@ SettingsAccessor::mergeSettings(const QVariantMap &userMap, const QVariantMap &s
return upgradeSettings(result);
}
+// --------------------------------------------------------------------
+// Helper functions:
+// --------------------------------------------------------------------
+
+int versionFromMap(const QVariantMap &data)
+{
+ return data.value(VERSION_KEY, -1).toInt();
+}
+
+int originalVersionFromMap(const QVariantMap &data)
+{
+ return data.value(ORIGINAL_VERSION_KEY, versionFromMap(data)).toInt();
+}
+
+QByteArray settingsIdFromMap(const QVariantMap &data)
+{
+ return data.value(SETTINGS_ID_KEY).toByteArray();
+}
+
+void setOriginalVersionInMap(QVariantMap &data, int version)
+{
+ data.insert(ORIGINAL_VERSION_KEY, version);
+}
+
+void setVersionInMap(QVariantMap &data, int version)
+{
+ data.insert(VERSION_KEY, version);
+}
+
+void setSettingsIdInMap(QVariantMap &data, const QByteArray &id)
+{
+ data.insert(SETTINGS_ID_KEY, id);
+}
+
} // namespace Utils