From 5680bf7b253028bf3e3e72a0b5908dfe405edf79 Mon Sep 17 00:00:00 2001 From: Eberhard Graether Date: Thu, 15 Sep 2016 12:23:18 +0200 Subject: [PATCH] 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 --- bin/app/data/ProjectSettings_template.xml | 2 + .../projects/tictactoe/tictactoe.coatiproject | 9 +- src/lib/Project.cpp | 30 +++- src/lib/Project.h | 3 +- src/lib/data/StorageProvider.cpp | 29 +--- src/lib/settings/ProjectSettings.cpp | 47 ++++++ src/lib/settings/ProjectSettings.h | 7 + src/lib/settings/Settings.cpp | 21 +-- src/lib/settings/Settings.h | 6 +- src/lib/settings/SettingsMigrator.cpp | 36 ++++- src/lib/settings/SettingsMigrator.h | 5 + src/test/SettingsMigratorTestSuite.h | 148 +++++++++++++++--- 12 files changed, 261 insertions(+), 82 deletions(-) diff --git a/bin/app/data/ProjectSettings_template.xml b/bin/app/data/ProjectSettings_template.xml index ea44e49f..a45d4e79 100644 --- a/bin/app/data/ProjectSettings_template.xml +++ b/bin/app/data/ProjectSettings_template.xml @@ -7,6 +7,8 @@ + + diff --git a/bin/app/data/projects/tictactoe/tictactoe.coatiproject b/bin/app/data/projects/tictactoe/tictactoe.coatiproject index c2aacc4d..9b2248a7 100644 --- a/bin/app/data/projects/tictactoe/tictactoe.coatiproject +++ b/bin/app/data/projects/tictactoe/tictactoe.coatiproject @@ -1,9 +1,9 @@ - - C++ - 1z - + + C++ + c++1z + .h @@ -18,4 +18,5 @@ 0 + 1 diff --git a/src/lib/Project.cpp b/src/lib/Project.cpp index e2a4d2c1..b1cc4ad0 100644 --- a/src/lib/Project.cpp +++ b/src/lib/Project.cpp @@ -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 = getProjectSettings(); + std::shared_ptr projectSettings = getProjectSettings(); bool loadedSettings = projectSettings->reload(); if (!loadedSettings) @@ -214,7 +225,18 @@ void Project::load() m_storage = std::make_shared(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()); diff --git a/src/lib/Project.h b/src/lib/Project.h index 1b89f781..d905031c 100644 --- a/src/lib/Project.h +++ b/src/lib/Project.h @@ -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&); diff --git a/src/lib/data/StorageProvider.cpp b/src/lib/data/StorageProvider.cpp index 7d73ff0f..6bec370b 100644 --- a/src/lib/data/StorageProvider.cpp +++ b/src/lib/data/StorageProvider.cpp @@ -10,38 +10,13 @@ int StorageProvider::getStorageCount() const void StorageProvider::pushIndexerTarget(std::shared_ptr storage) { - const std::size_t storageSize = storage->getSourceLocationCount(); - std::list>::iterator it; - std::lock_guard 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 StorageProvider::popIndexerTarget() { - std::shared_ptr ret; - { - std::lock_guard lock(m_storagesMutex); - if (m_storages.size() > 1) - { - std::list>::iterator it = m_storages.begin(); - it++; - ret = *it; - m_storages.erase(it); - } - else - { - ret = std::make_shared(); - } - } - return ret; + return std::make_shared();; } std::shared_ptr StorageProvider::popInjectionSource() diff --git a/src/lib/settings/ProjectSettings.cpp b/src/lib/settings/ProjectSettings.cpp index 532447c8..77df752e 100644 --- a/src/lib/settings/ProjectSettings.cpp +++ b/src/lib/settings/ProjectSettings.cpp @@ -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 ProjectSettings::getLanguageStandards() const return std::vector(); } +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(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; +} + + diff --git a/src/lib/settings/ProjectSettings.h b/src/lib/settings/ProjectSettings.h index d1fb607c..b8b6aaf4 100644 --- a/src/lib/settings/ProjectSettings.h +++ b/src/lib/settings/ProjectSettings.h @@ -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 getLanguageStandards() const; + bool needMigration() const; + void migrate(); + bool reload(); std::string getProjectName() const; @@ -55,6 +60,8 @@ protected: private: virtual std::vector getDefaultSourceExtensions() const; virtual std::string getDefaultStandard() const; + + SettingsMigrator getMigrations() const; }; #endif // PROJECT_SETTINGS_H diff --git a/src/lib/settings/Settings.cpp b/src/lib/settings/Settings.cpp index 12a008e6..99ff0d04 100644 --- a/src/lib/settings/Settings.cpp +++ b/src/lib/settings/Settings.cpp @@ -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("version", version); } -Settings Settings::createFromText(const std::shared_ptr 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(); diff --git a/src/lib/settings/Settings.h b/src/lib/settings/Settings.h index 1ab55a5a..5d0008fc 100644 --- a/src/lib/settings/Settings.h +++ b/src/lib/settings/Settings.h @@ -28,9 +28,6 @@ public: size_t getVersion() const; void setVersion(size_t version); - static Settings createFromText(const std::shared_ptr 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 m_config; + private: FilePath m_filePath; - std::shared_ptr m_config; }; template diff --git a/src/lib/settings/SettingsMigrator.cpp b/src/lib/settings/SettingsMigrator.cpp index e9d86790..8c7d1091 100644 --- a/src/lib/settings/SettingsMigrator.cpp +++ b/src/lib/settings/SettingsMigrator.cpp @@ -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 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::const_iterator, std::multimap::const_iterator> ret; + ret = m_migrations.equal_range(originVersion); + + for (std::multimap::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( migration.newKey, diff --git a/src/lib/settings/SettingsMigrator.h b/src/lib/settings/SettingsMigrator.h index 343030b2..e4a58cdd 100644 --- a/src/lib/settings/SettingsMigrator.h +++ b/src/lib/settings/SettingsMigrator.h @@ -1,6 +1,7 @@ #ifndef SETTNGS_MIGRATOR_H #define SETTNGS_MIGRATOR_H +#include #include #include @@ -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 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 lambda; }; std::multimap m_migrations; diff --git a/src/test/SettingsMigratorTestSuite.h b/src/test/SettingsMigratorTestSuite.h index 557e3cf0..d6b0deef 100644 --- a/src/test/SettingsMigratorTestSuite.h +++ b/src/test/SettingsMigratorTestSuite.h @@ -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( "\n" "\n" " 2\n" "\n" ); - Settings settingsAfter = createSettings( + TestSettings settingsAfter = createSettings( "\n" "\n" " 2\n" @@ -31,14 +31,14 @@ public: void test_migrator_changes_name() { - Settings settingsBefore = createSettings( + TestSettings settingsBefore = createSettings( "\n" "\n" " 2\n" "\n" ); - Settings settingsAfter = createSettings( + TestSettings settingsAfter = createSettings( "\n" "\n" " 2\n" @@ -55,14 +55,14 @@ public: void test_migrator_changes_path() { - Settings settingsBefore = createSettings( + TestSettings settingsBefore = createSettings( "\n" "\n" " 2\n" "\n" ); - Settings settingsAfter = createSettings( + TestSettings settingsAfter = createSettings( "\n" "\n" " \n" @@ -81,7 +81,7 @@ public: void test_migrator_changes_group_name() { - Settings settingsBefore = createSettings( + TestSettings settingsBefore = createSettings( "\n" "\n" " \n" @@ -92,7 +92,7 @@ public: "\n" ); - Settings settingsAfter = createSettings( + TestSettings settingsAfter = createSettings( "\n" "\n" " \n" @@ -113,7 +113,7 @@ public: void test_migrator_changes_group_element_name() { - Settings settingsBefore = createSettings( + TestSettings settingsBefore = createSettings( "\n" "\n" " \n" @@ -124,7 +124,7 @@ public: "\n" ); - Settings settingsAfter = createSettings( + TestSettings settingsAfter = createSettings( "\n" "\n" " \n" @@ -145,14 +145,14 @@ public: void test_migrator_changes_only_up_specified_version() { - Settings settingsBefore = createSettings( + TestSettings settingsBefore = createSettings( "\n" "\n" " 2\n" "\n" ); - Settings settingsAfter = createSettings( + TestSettings settingsAfter = createSettings( "\n" "\n" " 2\n" @@ -170,7 +170,7 @@ public: void test_migrator_changes_only_from_specified_version() { - Settings settingsBefore = createSettings( + TestSettings settingsBefore = createSettings( "\n" "\n" " 2\n" @@ -178,7 +178,7 @@ public: "\n" ); - Settings settingsAfter = createSettings( + TestSettings settingsAfter = createSettings( "\n" "\n" " 2\n" @@ -196,14 +196,14 @@ public: void test_migrator_changes_for_multiple_versions() { - Settings settingsBefore = createSettings( + TestSettings settingsBefore = createSettings( "\n" "\n" " 2\n" "\n" ); - Settings settingsAfter = createSettings( + TestSettings settingsAfter = createSettings( "\n" "\n" " 2\n" @@ -221,7 +221,7 @@ public: void test_migrator_changes_for_multiple_migrations() { - Settings settingsBefore = createSettings( + TestSettings settingsBefore = createSettings( "\n" "\n" " 2\n" @@ -229,7 +229,7 @@ public: "\n" ); - Settings settingsAfter = createSettings( + TestSettings settingsAfter = createSettings( "\n" "\n" " 2\n" @@ -248,7 +248,7 @@ public: void test_migrator_changes_for_multiple_versions_and_migrations() { - Settings settingsBefore = createSettings( + TestSettings settingsBefore = createSettings( "\n" "\n" " 2\n" @@ -258,7 +258,7 @@ public: "\n" ); - Settings settingsAfter = createSettings( + TestSettings settingsAfter = createSettings( "\n" "\n" " 2\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( + "\n" + "\n" + " 2\n" + "\n" + ); + + TestSettings settingsAfter = createSettings( + "\n" + "\n" + " 4\n" + " 1\n" + "\n" + ); + + SettingsMigrator migrator; + migrator.addLambdaMigration( + 1, + [](Settings* settings) + { + TestSettings* test = dynamic_cast(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( + "\n" + "\n" + " 2\n" + "\n" + ); + + TestSettings settingsAfter = createSettings( + "\n" + "\n" + " 3\n" + " 2\n" + "\n" + ); + + SettingsMigrator migrator; + migrator.addLambdaMigration( + 1, + [](Settings* settings) + { + TestSettings* test = dynamic_cast(settings); + test->set("value", test->get("value") * 2); + } + ); + migrator.addLambdaMigration( + 2, + [](Settings* settings) + { + TestSettings* test = dynamic_cast(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) + { + 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(key, 0); + } + + void set(const std::string& key, int value) + { + setValue(key, value); + } + }; + + TestSettings createSettings(const std::string& text) + { + return TestSettings::createFromText(TextAccess::createFromString(text)); } };