logic: Added migration for C/C++ standard to ProjectSettings

* extended SettingsMigrator to support lambdas
* added PROJECT_STATE_NEEDS_MIGRATION and dialog for loading old project files
This commit is contained in:
Eberhard Graether
2016-09-15 12:23:18 +02:00
parent 73ef7c1bcb
commit 5680bf7b25
12 changed files with 261 additions and 82 deletions
@@ -7,6 +7,8 @@
<!-- COLOR: int int int int - rgba e.g. 125 125 125 255 -->
<config>
<version><!-- INTEGER: Version number --></version>
<info>
<description><!-- STRING: optional description shown in overview. Symbols can be linked with syntax [main] --></description>
</info>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<config>
<language_settings>
<language>C++</language>
<standard>1z</standard>
</language_settings>
<language_settings>
<language>C++</language>
<standard>c++1z</standard>
</language_settings>
<source>
<extensions>
<header_extensions>.h</header_extensions>
@@ -18,4 +18,5 @@
</source_paths>
<use_source_paths_for_header_search>0</use_source_paths_for_header_search>
</source>
<version>1</version>
</config>
+27 -3
View File
@@ -106,6 +106,12 @@ bool Project::refresh(bool forceRefresh)
forceRefresh = true;
break;
case PROJECT_STATE_NEEDS_MIGRATION:
question =
"This project was created with a different version of Coati. The project file needs to get updated and "
"the project fully reindexed. Do you want to update the project file and reindex the project?";
forceRefresh = true;
default:
break;
}
@@ -129,6 +135,11 @@ bool Project::refresh(bool forceRefresh)
return false;
}
if (m_state == PROJECT_STATE_NEEDS_MIGRATION)
{
getProjectSettings()->migrate();
}
getProjectSettings()->reload();
updateFileManager(m_fileManager);
@@ -199,7 +210,7 @@ void Project::load()
{
m_storageAccessProxy->setSubject(nullptr);
const std::shared_ptr<ProjectSettings> projectSettings = getProjectSettings();
std::shared_ptr<ProjectSettings> projectSettings = getProjectSettings();
bool loadedSettings = projectSettings->reload();
if (!loadedSettings)
@@ -214,7 +225,18 @@ void Project::load()
m_storage = std::make_shared<PersistentStorage>(dbPath);
if (m_storage->isEmpty())
bool canLoad = false;
if (projectSettings->needMigration())
{
m_state = PROJECT_STATE_NEEDS_MIGRATION;
if (!m_storage->isEmpty() && !m_storage->isIncompatible())
{
canLoad = true;
}
}
else if (m_storage->isEmpty())
{
m_state = PROJECT_STATE_EMPTY;
m_storage->setup();
@@ -226,13 +248,15 @@ void Project::load()
else if (TextAccess::createFromFile(projectSettingsPath.str())->getText() != m_storage->getProjectSettingsText())
{
m_state = PROJECT_STATE_OUTDATED;
canLoad = true;
}
else
{
m_state = PROJECT_STATE_LOADED;
canLoad = true;
}
if (m_state == PROJECT_STATE_LOADED || m_state == PROJECT_STATE_OUTDATED)
if (canLoad)
{
m_storage->finishParsing();
m_storageAccessProxy->setSubject(m_storage.get());
+2 -1
View File
@@ -52,7 +52,8 @@ private:
PROJECT_STATE_LOADED,
PROJECT_STATE_OUTDATED,
PROJECT_STATE_OUTVERSIONED,
PROJECT_STATE_SETTINGS_UPDATED
PROJECT_STATE_SETTINGS_UPDATED,
PROJECT_STATE_NEEDS_MIGRATION
};
Project(const Project&);
+2 -27
View File
@@ -10,38 +10,13 @@ int StorageProvider::getStorageCount() const
void StorageProvider::pushIndexerTarget(std::shared_ptr<IntermediateStorage> storage)
{
const std::size_t storageSize = storage->getSourceLocationCount();
std::list<std::shared_ptr<IntermediateStorage>>::iterator it;
std::lock_guard<std::mutex> lock(m_storagesMutex);
for (it = m_storages.begin(); it != m_storages.end(); it++)
{
if ((*it)->getSourceLocationCount() < storageSize)
{
break;
}
}
m_storages.insert(it, storage);
m_storages.push_back(storage);
}
std::shared_ptr<IntermediateStorage> StorageProvider::popIndexerTarget()
{
std::shared_ptr<IntermediateStorage> ret;
{
std::lock_guard<std::mutex> lock(m_storagesMutex);
if (m_storages.size() > 1)
{
std::list<std::shared_ptr<IntermediateStorage>>::iterator it = m_storages.begin();
it++;
ret = *it;
m_storages.erase(it);
}
else
{
ret = std::make_shared<IntermediateStorage>();
}
}
return ret;
return std::make_shared<IntermediateStorage>();;
}
std::shared_ptr<IntermediateStorage> StorageProvider::popInjectionSource()
+47
View File
@@ -3,6 +3,9 @@
#include "settings/CxxProjectSettings.h"
#include "settings/JavaProjectSettings.h"
#include "utility/utility.h"
#include "utility/utilityString.h"
const size_t ProjectSettings::VERSION = 1;
LanguageType ProjectSettings::getLanguageOfProject(FilePath projectFilePath)
{
@@ -45,6 +48,22 @@ std::vector<std::string> ProjectSettings::getLanguageStandards() const
return std::vector<std::string>();
}
bool ProjectSettings::needMigration() const
{
return getMigrations().willMigrate(this, ProjectSettings::VERSION);
}
void ProjectSettings::migrate()
{
SettingsMigrator migrator = getMigrations();
bool migrated = migrator.migrate(this, ProjectSettings::VERSION);
if (migrated)
{
save();
}
}
bool ProjectSettings::reload()
{
return Settings::load(getFilePath());
@@ -163,3 +182,31 @@ std::string ProjectSettings::getDefaultStandard() const
return "";
}
SettingsMigrator ProjectSettings::getMigrations() const
{
SettingsMigrator migrator;
if (getLanguage() == LANGUAGE_C || getLanguage() == LANGUAGE_CPP)
{
migrator.addLambdaMigration(1,
[](Settings* settings)
{
ProjectSettings* s = dynamic_cast<ProjectSettings*>(settings);
if (s->getLanguage() == LANGUAGE_C && !utility::isPrefix("c", s->getStandard()))
{
s->setStandard("c" + s->getStandard());
}
if (s->getLanguage() == LANGUAGE_CPP && !utility::isPrefix("c++", s->getStandard()))
{
s->setStandard("c++" + s->getStandard());
}
}
);
}
return migrator;
}
+7
View File
@@ -13,6 +13,8 @@ class ProjectSettings
public:
static LanguageType getLanguageOfProject(FilePath projectFilePath);
static const size_t VERSION;
ProjectSettings();
ProjectSettings(const FilePath& projectFilePath);
ProjectSettings(std::string projectName, const FilePath& projectFileLocation);
@@ -22,6 +24,9 @@ public:
virtual std::vector<std::string> getLanguageStandards() const;
bool needMigration() const;
void migrate();
bool reload();
std::string getProjectName() const;
@@ -55,6 +60,8 @@ protected:
private:
virtual std::vector<std::string> getDefaultSourceExtensions() const;
virtual std::string getDefaultStandard() const;
SettingsMigrator getMigrations() const;
};
#endif // PROJECT_SETTINGS_H
+2 -19
View File
@@ -6,8 +6,8 @@
#include "utility/utilityString.h"
Settings::Settings(const Settings& other)
: m_filePath(other.m_filePath)
, m_config(other.m_config->createCopy())
: m_config(other.m_config->createCopy())
, m_filePath(other.m_filePath)
{
}
@@ -83,23 +83,6 @@ void Settings::setVersion(size_t version)
setValue<int>("version", version);
}
Settings Settings::createFromText(const std::shared_ptr<TextAccess> textAccess)
{
Settings settings;
settings.m_config = ConfigManager::createAndLoad(textAccess);
return settings;
}
std::string Settings::getAsText() const
{
if (m_config)
{
return m_config->toString();
}
return "";
}
Settings::Settings()
{
clear();
+2 -4
View File
@@ -28,9 +28,6 @@ public:
size_t getVersion() const;
void setVersion(size_t version);
static Settings createFromText(const std::shared_ptr<TextAccess> textAccess);
std::string getAsText() const;
protected:
Settings();
@@ -62,9 +59,10 @@ protected:
friend bool SettingsMigrator::migrate(Settings* settings, size_t targetVersion) const;
std::shared_ptr<ConfigManager> m_config;
private:
FilePath m_filePath;
std::shared_ptr<ConfigManager> m_config;
};
template<typename T>
+35 -1
View File
@@ -20,6 +20,36 @@ void SettingsMigrator::addMigration(size_t targetVersion, std::string oldKey, st
m_migrations.emplace(targetVersion, migration);
}
void SettingsMigrator::addLambdaMigration(size_t targetVersion, std::function<void(Settings*)> lambda)
{
Migration migration;
migration.targetVersion = targetVersion;
migration.lambda = lambda;
m_migrations.emplace(targetVersion, migration);
}
bool SettingsMigrator::willMigrate(const Settings* settings, size_t targetVersion) const
{
size_t originVersion = settings->getVersion();
if (originVersion < targetVersion)
{
for (; originVersion <= targetVersion; originVersion++)
{
std::pair<std::multimap<size_t, Migration>::const_iterator, std::multimap<size_t, Migration>::const_iterator> ret;
ret = m_migrations.equal_range(originVersion);
for (std::multimap<size_t, Migration>::const_iterator it = ret.first; it != ret.second; it++)
{
return true;
}
}
}
return false;
}
bool SettingsMigrator::migrate(Settings* settings, size_t targetVersion) const
{
size_t originVersion = settings->getVersion();
@@ -35,7 +65,11 @@ bool SettingsMigrator::migrate(Settings* settings, size_t targetVersion) const
{
const Migration& migration = it->second;
if (!settings->isValueDefined(migration.newKey))
if (!migration.oldKey.size())
{
migration.lambda(settings);
}
else if (!settings->isValueDefined(migration.newKey))
{
settings->setValues<std::string>(
migration.newKey,
+5
View File
@@ -1,6 +1,7 @@
#ifndef SETTNGS_MIGRATOR_H
#define SETTNGS_MIGRATOR_H
#include <functional>
#include <map>
#include <string>
@@ -15,7 +16,9 @@ public:
virtual ~SettingsMigrator();
void addMigration(size_t targetVersion, std::string oldKey, std::string newKey);
void addLambdaMigration(size_t targetVersion, std::function<void(Settings*)> lambda);
bool willMigrate(const Settings* settings, size_t targetVersion) const;
bool migrate(Settings* settings, size_t targetVersion) const;
private:
@@ -24,6 +27,8 @@ private:
size_t targetVersion;
std::string oldKey;
std::string newKey;
std::function<void(Settings*)> lambda;
};
std::multimap<size_t, Migration> m_migrations;
+125 -23
View File
@@ -8,14 +8,14 @@ class SettingsMigratorTestSuite : public CxxTest::TestSuite
public:
void test_migrator_changes_nothing_without_migrations_except_version()
{
Settings settingsBefore = createSettings(
TestSettings settingsBefore = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <value>2</value>\n"
"</config>\n"
);
Settings settingsAfter = createSettings(
TestSettings settingsAfter = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <value>2</value>\n"
@@ -31,14 +31,14 @@ public:
void test_migrator_changes_name()
{
Settings settingsBefore = createSettings(
TestSettings settingsBefore = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <value>2</value>\n"
"</config>\n"
);
Settings settingsAfter = createSettings(
TestSettings settingsAfter = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <int>2</int>\n"
@@ -55,14 +55,14 @@ public:
void test_migrator_changes_path()
{
Settings settingsBefore = createSettings(
TestSettings settingsBefore = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <value>2</value>\n"
"</config>\n"
);
Settings settingsAfter = createSettings(
TestSettings settingsAfter = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <sub>\n"
@@ -81,7 +81,7 @@ public:
void test_migrator_changes_group_name()
{
Settings settingsBefore = createSettings(
TestSettings settingsBefore = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <values>\n"
@@ -92,7 +92,7 @@ public:
"</config>\n"
);
Settings settingsAfter = createSettings(
TestSettings settingsAfter = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <vals>\n"
@@ -113,7 +113,7 @@ public:
void test_migrator_changes_group_element_name()
{
Settings settingsBefore = createSettings(
TestSettings settingsBefore = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <values>\n"
@@ -124,7 +124,7 @@ public:
"</config>\n"
);
Settings settingsAfter = createSettings(
TestSettings settingsAfter = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <values>\n"
@@ -145,14 +145,14 @@ public:
void test_migrator_changes_only_up_specified_version()
{
Settings settingsBefore = createSettings(
TestSettings settingsBefore = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <value>2</value>\n"
"</config>\n"
);
Settings settingsAfter = createSettings(
TestSettings settingsAfter = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <int>2</int>\n"
@@ -170,7 +170,7 @@ public:
void test_migrator_changes_only_from_specified_version()
{
Settings settingsBefore = createSettings(
TestSettings settingsBefore = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <int>2</int>\n"
@@ -178,7 +178,7 @@ public:
"</config>\n"
);
Settings settingsAfter = createSettings(
TestSettings settingsAfter = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <val>2</val>\n"
@@ -196,14 +196,14 @@ public:
void test_migrator_changes_for_multiple_versions()
{
Settings settingsBefore = createSettings(
TestSettings settingsBefore = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <value>2</value>\n"
"</config>\n"
);
Settings settingsAfter = createSettings(
TestSettings settingsAfter = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <val>2</val>\n"
@@ -221,7 +221,7 @@ public:
void test_migrator_changes_for_multiple_migrations()
{
Settings settingsBefore = createSettings(
TestSettings settingsBefore = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <value>2</value>\n"
@@ -229,7 +229,7 @@ public:
"</config>\n"
);
Settings settingsAfter = createSettings(
TestSettings settingsAfter = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <val>2</val>\n"
@@ -248,7 +248,7 @@ public:
void test_migrator_changes_for_multiple_versions_and_migrations()
{
Settings settingsBefore = createSettings(
TestSettings settingsBefore = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <value>2</value>\n"
@@ -258,7 +258,7 @@ public:
"</config>\n"
);
Settings settingsAfter = createSettings(
TestSettings settingsAfter = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <int>2</int>\n"
@@ -281,9 +281,111 @@ public:
TS_ASSERT_EQUALS(settingsBefore.getAsText(), settingsAfter.getAsText());
}
private:
Settings createSettings(const std::string& text)
void test_migrator_with_lambda()
{
return Settings::createFromText(TextAccess::createFromString(text));
TestSettings settingsBefore = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <value>2</value>\n"
"</config>\n"
);
TestSettings settingsAfter = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <value>4</value>\n"
" <version>1</version>\n"
"</config>\n"
);
SettingsMigrator migrator;
migrator.addLambdaMigration(
1,
[](Settings* settings)
{
TestSettings* test = dynamic_cast<TestSettings*>(settings);
test->set("value", test->get("value") * 2);
}
);
migrator.migrate(&settingsBefore, 1);
TS_ASSERT_EQUALS(settingsBefore.getAsText(), settingsAfter.getAsText());
}
void test_migrator_with_multiple_lambdas()
{
TestSettings settingsBefore = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <value>2</value>\n"
"</config>\n"
);
TestSettings settingsAfter = createSettings(
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
"<config>\n"
" <value>3</value>\n"
" <version>2</version>\n"
"</config>\n"
);
SettingsMigrator migrator;
migrator.addLambdaMigration(
1,
[](Settings* settings)
{
TestSettings* test = dynamic_cast<TestSettings*>(settings);
test->set("value", test->get("value") * 2);
}
);
migrator.addLambdaMigration(
2,
[](Settings* settings)
{
TestSettings* test = dynamic_cast<TestSettings*>(settings);
test->set("value", test->get("value") - 1);
}
);
migrator.migrate(&settingsBefore, 2);
TS_ASSERT_EQUALS(settingsBefore.getAsText(), settingsAfter.getAsText());
}
private:
class TestSettings
: public Settings
{
public:
static TestSettings createFromText(const std::shared_ptr<TextAccess> textAccess)
{
TestSettings settings;
settings.m_config = ConfigManager::createAndLoad(textAccess);
return settings;
}
std::string getAsText() const
{
if (m_config)
{
return m_config->toString();
}
return "";
}
int get(const std::string& key)
{
return getValue<int>(key, 0);
}
void set(const std::string& key, int value)
{
setValue<int>(key, value);
}
};
TestSettings createSettings(const std::string& text)
{
return TestSettings::createFromText(TextAccess::createFromString(text));
}
};