From 42ab36fbada60096cc7a428ecb9950273b45db00 Mon Sep 17 00:00:00 2001 From: Eberhard Graether Date: Mon, 2 Nov 2015 10:14:03 +0100 Subject: [PATCH] data: Saving application version to storage and refresh when version changes The version string of the application is stored on every parse. The utility class Version is used to parse the version string and compare application and stored string. The third number in the version string is now the storage refresh number, the project will be refreshed when it changes. (0.2.1 -> 0.2.2) --- src/app/main.cpp | 7 +- src/app/qt/window/QtAbout.cpp | 4 +- src/lib/Application.cpp | 8 ++- src/lib/Application.h | 5 +- src/lib/CMakeLists.txt | 4 +- src/lib/Project.cpp | 11 +++- src/lib/data/SqliteStorage.cpp | 64 ++++++++++++++++++ src/lib/data/SqliteStorage.h | 9 +++ src/lib/data/Storage.cpp | 7 ++ src/lib/data/Storage.h | 2 + src/lib/utility/Version.cpp | 114 +++++++++++++++++++++++++++++++++ src/lib/utility/Version.h | 33 ++++++++++ 12 files changed, 256 insertions(+), 12 deletions(-) create mode 100644 src/lib/utility/Version.cpp create mode 100644 src/lib/utility/Version.h diff --git a/src/app/main.cpp b/src/app/main.cpp index 72e9feef..c69c558a 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -5,6 +5,7 @@ #include "utility/logging/ConsoleLogger.h" #include "utility/logging/FileLogger.h" #include "utility/logging/LogManager.h" +#include "utility/Version.h" #include "Application.h" #include "includes.h" // defines 'void setup(int argc, char *argv[])' @@ -31,6 +32,8 @@ void init() int main(int argc, char *argv[]) { + Version version = Version::fromString(GIT_VERSION_NUMBER); + setup(argc, argv); QApplication qtApp(argc, argv); @@ -41,7 +44,7 @@ int main(int argc, char *argv[]) QtSplashScreen* splash = new QtSplashScreen(whitePixmap, Qt::WindowStaysOnTopHint); splash->setMessage("Loading UI"); - splash->setVersion(GIT_VERSION_NUMBER); + splash->setVersion(version.toDisplayString().c_str()); splash->exec(qtApp); init(); @@ -49,7 +52,7 @@ int main(int argc, char *argv[]) QtViewFactory viewFactory; QtNetworkFactory networkFactory; - std::shared_ptr app = Application::create(&viewFactory, &networkFactory); + std::shared_ptr app = Application::create(version, &viewFactory, &networkFactory); if (splash) { diff --git a/src/app/qt/window/QtAbout.cpp b/src/app/qt/window/QtAbout.cpp index 0a78f17d..69539452 100644 --- a/src/app/qt/window/QtAbout.cpp +++ b/src/app/qt/window/QtAbout.cpp @@ -4,7 +4,7 @@ #include #include -#include "version.h" +#include "utility/Version.h" QtAbout::QtAbout(QWidget *parent) : QtSettingsWindow(parent) @@ -46,7 +46,7 @@ void QtAbout::populateForm(QFormLayout* layout) acknowledgementsLabel->setAlignment(Qt::AlignTop); layout->addRow(acknowledgementsName, acknowledgementsLabel); - layout->addRow(QString("Version:"), new QLabel(GIT_VERSION_NUMBER)); + layout->addRow(QString("Version:"), new QLabel(Version::getApplicationVersion().toDisplayString().c_str())); } void QtAbout::handleCancelButtonPress() diff --git a/src/lib/Application.cpp b/src/lib/Application.cpp index 79584d42..bfceeb67 100644 --- a/src/lib/Application.cpp +++ b/src/lib/Application.cpp @@ -5,6 +5,7 @@ #include "utility/messaging/type/MessageActivateNodes.h" #include "utility/messaging/type/MessageStatus.h" #include "utility/scheduling/TaskScheduler.h" +#include "utility/Version.h" #include "component/view/GraphViewStyle.h" #include "component/controller/NetworkFactory.h" @@ -14,8 +15,11 @@ #include "settings/ApplicationSettings.h" #include "settings/ColorScheme.h" -std::shared_ptr Application::create(ViewFactory* viewFactory, NetworkFactory* networkFactory) -{ +std::shared_ptr Application::create( + const Version& version, ViewFactory* viewFactory, NetworkFactory* networkFactory +){ + Version::setApplicationVersion(version); + loadSettings(); std::shared_ptr ptr(new Application()); diff --git a/src/lib/Application.h b/src/lib/Application.h index f2266295..6f9a5ad0 100644 --- a/src/lib/Application.h +++ b/src/lib/Application.h @@ -16,6 +16,7 @@ class NetworkFactory; class ViewFactory; class MainView; class StorageCache; +class Version; class Application : public MessageListener @@ -24,7 +25,7 @@ class Application , public MessageListener { public: - static std::shared_ptr create(ViewFactory* viewFactory, NetworkFactory* networkFactory); + static std::shared_ptr create(const Version& version, ViewFactory* viewFactory, NetworkFactory* networkFactory); static void loadSettings(); ~Application(); @@ -50,8 +51,6 @@ private: std::shared_ptr m_componentManager; std::shared_ptr m_ideCommunicationController; - - bool m_isInitialParse; }; #endif // APPLICATION_H diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index dcf32d40..0c8bac6f 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -58,7 +58,7 @@ add_files( component/controller/FeatureController.h component/controller/GraphController.cpp component/controller/GraphController.h - + component/controller/IDECommunicationController.cpp component/controller/IDECommunicationController.h component/controller/NetworkFactory.cpp @@ -307,6 +307,8 @@ add_files( utility/utility.h utility/utilityString.cpp utility/utilityString.h + utility/Version.cpp + utility/Version.h Application.cpp Application.h diff --git a/src/lib/Project.cpp b/src/lib/Project.cpp index f86a9f32..2beedf13 100644 --- a/src/lib/Project.cpp +++ b/src/lib/Project.cpp @@ -1,8 +1,11 @@ #include "Project.h" +#include "utility/file/FileSystem.h" #include "utility/logging/logging.h" #include "utility/messaging/type/MessageFinishedParsing.h" +#include "utility/scheduling/TaskGroupSequential.h" #include "utility/utility.h" +#include "utility/Version.h" #include "data/access/StorageAccessProxy.h" #include "data/graph/Token.h" @@ -11,8 +14,6 @@ #include "data/TaskCleanStorage.h" #include "settings/ApplicationSettings.h" #include "settings/ProjectSettings.h" -#include "utility/file/FileSystem.h" -#include "utility/scheduling/TaskGroupSequential.h" std::shared_ptr Project::create(StorageAccessProxy* storageAccessProxy) { @@ -144,6 +145,12 @@ void Project::setProjectSettingsFilePath(const FilePath& path) FilePath dbPath = FilePath(path).replaceExtension("sqlite"); m_storageWasLoaded = dbPath.exists(); m_storage = std::make_shared(dbPath); + + if (m_storageWasLoaded && m_storage->getVersion().isOlderStorageVersionThan(Version::getApplicationVersion())) + { + m_storage->clear(); + m_storageWasLoaded = false; + } } m_storageAccessProxy->setSubject(m_storage.get()); diff --git a/src/lib/data/SqliteStorage.cpp b/src/lib/data/SqliteStorage.cpp index 8639ae87..57c9c8ba 100644 --- a/src/lib/data/SqliteStorage.cpp +++ b/src/lib/data/SqliteStorage.cpp @@ -6,6 +6,7 @@ #include "utility/text/TextAccess.h" #include "utility/utility.h" #include "utility/utilityString.h" +#include "utility/Version.h" SqliteStorage::SqliteStorage(const std::string& dbFilePath) { @@ -47,6 +48,23 @@ void SqliteStorage::rollbackTransaction() m_database.execDML("ROLLBACK TRANSACTION;"); } +Version SqliteStorage::getVersion() const +{ + std::string versionStr = getMetaValue("version"); + + if (versionStr.size()) + { + return Version::fromString(versionStr); + } + + return Version(); +} + +void SqliteStorage::setVersion(const Version& version) +{ + insertOrUpdateMetaValue("version", version.toString()); +} + Id SqliteStorage::addEdge(int type, Id sourceNodeId, Id targetNodeId) { m_database.execDML( @@ -708,10 +726,19 @@ void SqliteStorage::clearTables() m_database.execDML("DROP TABLE IF EXISTS main.node;"); m_database.execDML("DROP TABLE IF EXISTS main.edge;"); m_database.execDML("DROP TABLE IF EXISTS main.element;"); + m_database.execDML("DROP TABLE IF EXISTS main.meta;"); } void SqliteStorage::setupTables() { + m_database.execDML( + "CREATE TABLE IF NOT EXISTS meta(" + "id INTEGER, " + "key TEXT, " + "value TEXT, " + "PRIMARY KEY(id));" + ); + m_database.execDML( "CREATE TABLE IF NOT EXISTS element(" "id INTEGER, " @@ -793,6 +820,43 @@ void SqliteStorage::setupTables() ); } +bool SqliteStorage::hasTable(const std::string& tableName) const +{ + CppSQLite3Query q = m_database.execQuery(( + "SELECT name FROM sqlite_master WHERE type='table' AND name='" + tableName + "';" + ).c_str()); + + if (!q.eof()) + { + return q.getStringField(0, "") == tableName; + } + + return false; +} + +std::string SqliteStorage::getMetaValue(const std::string& key) const +{ + if (hasTable("meta")) + { + CppSQLite3Query q = m_database.execQuery(("SELECT value FROM meta WHERE key = '" + key + "';").c_str()); + + if (!q.eof()) + { + return q.getStringField(0, ""); + } + } + + return ""; +} + +void SqliteStorage::insertOrUpdateMetaValue(const std::string& key, const std::string& value) +{ + m_database.execDML(( + "INSERT OR REPLACE INTO meta(id, key, value) " + "VALUES( (SELECT id FROM meta WHERE key = '" + key + "'), '" + key + "', '" + value + "');" + ).c_str()); +} + StorageFile SqliteStorage::getFirstFile(const std::string& query) const { CppSQLite3Query q = m_database.execQuery(query.c_str()); diff --git a/src/lib/data/SqliteStorage.h b/src/lib/data/SqliteStorage.h index 8c412fc4..51c608f6 100644 --- a/src/lib/data/SqliteStorage.h +++ b/src/lib/data/SqliteStorage.h @@ -15,6 +15,7 @@ #include "data/StorageTypes.h" class TextAccess; +class Version; class SqliteStorage { @@ -29,6 +30,9 @@ public: void commitTransaction(); void rollbackTransaction(); + Version getVersion() const; + void setVersion(const Version& version); + Id addEdge(int type, Id sourceNodeId, Id targetNodeId); Id addNode(int type, Id nameId, bool defined); Id addFile(Id nameId, const std::string& filePath, const std::string& modificationTime); @@ -107,6 +111,11 @@ private: void clearTables(); void setupTables(); + bool hasTable(const std::string& tableName) const; + + std::string getMetaValue(const std::string& key) const; + void insertOrUpdateMetaValue(const std::string& key, const std::string& value); + StorageFile getFirstFile(const std::string& query) const; std::vector getAllFiles(const std::string& query) const; StorageSourceLocation getFirstSourceLocation(const std::string& query) const; diff --git a/src/lib/data/Storage.cpp b/src/lib/data/Storage.cpp index 3d296bf1..94eba30f 100644 --- a/src/lib/data/Storage.cpp +++ b/src/lib/data/Storage.cpp @@ -19,6 +19,7 @@ #include "data/parser/ParseVariable.h" #include "data/type/DataType.h" #include "settings/ApplicationSettings.h" +#include "utility/Version.h" Storage::Storage(const FilePath& dbPath) : m_sqliteStorage(dbPath.str()) @@ -29,6 +30,11 @@ Storage::~Storage() { } +Version Storage::getVersion() const +{ + return m_sqliteStorage.getVersion(); +} + void Storage::clear() { m_sqliteStorage.clear(); @@ -148,6 +154,7 @@ void Storage::logStats() const void Storage::startParsing() { + m_sqliteStorage.setVersion(Version::getApplicationVersion()); } void Storage::finishParsing() diff --git a/src/lib/data/Storage.h b/src/lib/data/Storage.h index 8b24b6ae..abd16a8d 100644 --- a/src/lib/data/Storage.h +++ b/src/lib/data/Storage.h @@ -23,6 +23,8 @@ public: Storage(const FilePath& dbPath); virtual ~Storage(); + Version getVersion() const; + void clear(); void clearCaches(); diff --git a/src/lib/utility/Version.cpp b/src/lib/utility/Version.cpp new file mode 100644 index 00000000..2b329966 --- /dev/null +++ b/src/lib/utility/Version.cpp @@ -0,0 +1,114 @@ +#include "utility/Version.h" + +#include "utility/utilityString.h" +#include "utility/logging/logging.h" + +Version Version::s_version; + +Version Version::fromString(const std::string& versionString) +{ + Version version; + std::vector components = utility::splitToVector(versionString, '-'); + + if (components.size() != 3) + { + LOG_ERROR("Version string is invalid: " + versionString); + return version; + } + + std::vector numbers = utility::splitToVector(components[0], '.'); + if (numbers.size() > 0) + { + version.m_majorNumber = std::stoi(numbers[0]); + } + if (numbers.size() > 1) + { + version.m_minorNumber = std::stoi(numbers[1]); + } + if (numbers.size() > 2) + { + version.m_refreshNumber = std::stoi(numbers[2]); + } + + version.m_commitNumber = std::stoi(components[1]); + version.m_commitHash = components[2]; + + return version; +} + +void Version::setApplicationVersion(const Version& version) +{ + s_version = version; +} + +const Version& Version::getApplicationVersion() +{ + return s_version; +} + +Version::Version() + : m_majorNumber(0) + , m_minorNumber(0) + , m_refreshNumber(0) + , m_commitNumber(0) +{ +} + +bool Version::operator<(const Version& other) +{ + if (m_majorNumber != other.m_majorNumber) + { + return m_majorNumber < other.m_majorNumber; + } + else if (m_minorNumber != other.m_minorNumber) + { + return m_minorNumber < other.m_minorNumber; + } + else if (m_refreshNumber != other.m_refreshNumber) + { + return m_refreshNumber < other.m_refreshNumber; + } + else if (m_commitNumber != other.m_commitNumber) + { + return m_commitNumber < other.m_commitNumber; + } + else + { + return false; + } +} + +bool Version::isOlderStorageVersionThan(const Version& other) +{ + if (m_majorNumber != other.m_majorNumber) + { + return m_majorNumber < other.m_majorNumber; + } + else if (m_minorNumber != other.m_minorNumber) + { + return m_minorNumber < other.m_minorNumber; + } + else if (m_refreshNumber != other.m_refreshNumber) + { + return m_refreshNumber < other.m_refreshNumber; + } + else + { + return false; + } +} + +std::string Version::toString() const +{ + std::stringstream ss; + ss << m_majorNumber << '.' << m_minorNumber << '.' << m_refreshNumber; + ss << '-' << m_commitNumber << '-' << m_commitHash; + return ss.str(); +} + +std::string Version::toDisplayString() const +{ + std::stringstream ss; + ss << m_majorNumber << '.' << m_minorNumber << '.' << m_refreshNumber << '.' << m_commitNumber; + return ss.str(); +} diff --git a/src/lib/utility/Version.h b/src/lib/utility/Version.h new file mode 100644 index 00000000..c2014e5f --- /dev/null +++ b/src/lib/utility/Version.h @@ -0,0 +1,33 @@ +#ifndef VERSION_H +#define VERSION_H + +#include + +class Version +{ +public: + static Version fromString(const std::string& versionString); + + static void setApplicationVersion(const Version& version); + static const Version& getApplicationVersion(); + + Version(); + + bool operator<(const Version& other); + bool isOlderStorageVersionThan(const Version& other); + + std::string toString() const; + std::string toDisplayString() const; + +private: + static Version s_version; + + int m_majorNumber; + int m_minorNumber; + int m_refreshNumber; + int m_commitNumber; + + std::string m_commitHash; +}; + +#endif // VERSION_H