summaryrefslogtreecommitdiffhomepage
path: root/migration
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2016-09-09 08:51:25 +0200
committerStanislaw Halik <sthalik@misaki.pl>2016-09-09 15:00:58 +0200
commit6bc3fe31a3f354afc7be870a4a2d375ab6c746b6 (patch)
tree39b439b16cb872b3d982a6083a546456001d0f8e /migration
parentcc6fc6577940df89c57db08743b181291c2a4b43 (diff)
add support for migrations
They're run from the UI thread so can even be interactive.
Diffstat (limited to 'migration')
-rw-r--r--migration/20160906_0-mappings.cpp14
-rw-r--r--migration/20160906_1-axis-signs.cpp0
-rw-r--r--migration/CMakeLists.txt2
-rw-r--r--migration/export.hpp28
-rw-r--r--migration/migration.cpp129
-rw-r--r--migration/migration.hpp72
6 files changed, 245 insertions, 0 deletions
diff --git a/migration/20160906_0-mappings.cpp b/migration/20160906_0-mappings.cpp
new file mode 100644
index 00000000..0ff3095a
--- /dev/null
+++ b/migration/20160906_0-mappings.cpp
@@ -0,0 +1,14 @@
+#include "migration.hpp"
+
+#include <QDebug>
+
+using namespace migrations;
+
+struct foo : migration
+{
+ const QString& unique_date() const override { qDebug() << "foo"; static QString ret(""); return ret; }
+ bool should_run() const override { qDebug() << "bar"; return false; }
+ bool run() override { return false; }
+};
+
+OPENTRACK_MIGRATION(foo);
diff --git a/migration/20160906_1-axis-signs.cpp b/migration/20160906_1-axis-signs.cpp
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/migration/20160906_1-axis-signs.cpp
diff --git a/migration/CMakeLists.txt b/migration/CMakeLists.txt
new file mode 100644
index 00000000..d220b002
--- /dev/null
+++ b/migration/CMakeLists.txt
@@ -0,0 +1,2 @@
+opentrack_boilerplate(opentrack-migration BIN)
+target_link_libraries(opentrack-migration opentrack-logic opentrack-spline-widget)
diff --git a/migration/export.hpp b/migration/export.hpp
new file mode 100644
index 00000000..800ddf35
--- /dev/null
+++ b/migration/export.hpp
@@ -0,0 +1,28 @@
+#pragma once
+
+#ifdef BUILD_migration
+# ifdef _WIN32
+# define OPENTRACK_MIGRATION_LINKAGE __declspec(dllexport)
+# else
+# define OPENTRACK_MIGRATION_LINKAGE
+# endif
+
+# ifndef _MSC_VER
+# define OPENTRACK_MIGRATION_EXPORT __attribute__ ((visibility ("default"))) OPENTRACK_MIGRATION_LINKAGE
+# else
+# define OPENTRACK_MIGRATION_EXPORT OPENTRACK_MIGRATION_LINKAGE
+# endif
+
+#else
+ #ifdef _WIN32
+ # define OPENTRACK_MIGRATION_LINKAGE __declspec(dllimport)
+ #else
+ # define OPENTRACK_MIGRATION_LINKAGE
+ #endif
+
+ #ifndef _MSC_VER
+ # define OPENTRACK_MIGRATION_EXPORT __attribute__ ((visibility ("default"))) OPENTRACK_MIGRATION_LINKAGE
+ #else
+ # define OPENTRACK_MIGRATION_EXPORT OPENTRACK_MIGRATION_LINKAGE
+ #endif
+#endif
diff --git a/migration/migration.cpp b/migration/migration.cpp
new file mode 100644
index 00000000..6e54de19
--- /dev/null
+++ b/migration/migration.cpp
@@ -0,0 +1,129 @@
+#include "migration.hpp"
+
+#include "options/options.hpp"
+#include "compat/util.hpp"
+
+#include <QString>
+#include <QSettings>
+#include <QDebug>
+
+#include <memory>
+
+namespace migrations {
+
+namespace detail {
+
+void migrator::register_migration(migration* m)
+{
+ migrations().push_back(m);
+}
+
+migrator::vec& migrator::migrations()
+{
+ static vec ret;
+ return ret;
+}
+
+QString migrator::last_migration_time()
+{
+ QString ret;
+
+ std::shared_ptr<QSettings> s(options::group::ini_file());
+
+ s->beginGroup("migrations");
+ ret = s->value("last-migration-at", "19700101_00").toString();
+ s->endGroup();
+
+ return ret;
+}
+
+QString migrator::time_after_migrations()
+{
+ const vec list = sorted_migrations();
+
+ if (list.size() == 0u)
+ return QStringLiteral("19700101_00");
+
+ QString ret = list[list.size() - 1]->unique_date();
+ ret += QStringLiteral("~");
+
+ return ret;
+}
+
+void migrator::set_last_migration_time(const QString& val)
+{
+ std::shared_ptr<QSettings> s(options::group::ini_file());
+
+ s->beginGroup("migrations");
+ s->setValue("last-migration-at", val);
+ s->endGroup();
+}
+
+migrator::vec migrator::sorted_migrations()
+{
+ vec list(migrations());
+ std::sort(list.begin(), list.end(), [](const mm x, const mm y) { return x->unique_date() < y->unique_date(); });
+ return list;
+}
+
+std::vector<QString> migrator::run()
+{
+ vec migrations = sorted_migrations();
+ vstr done;
+
+ const QString last_migration = last_migration_time();
+
+ qDebug() << "migration: config" << options::group::ini_filename() << "time" << last_migration;
+
+ for (migration* m_ : migrations)
+ {
+ migration& m(*m_);
+
+ const QString date = m.unique_date();
+
+ if (date <= last_migration)
+ continue;
+
+ if (m.should_run())
+ {
+ m.run();
+ done.push_back(m.name());
+ }
+ }
+
+ mark_config_as_not_needing_migration();
+
+ if (done.size())
+ {
+ qDebug() << "migration: done" << done.size() << "units";
+ for (const QString& name : done)
+ qDebug() << "--" << name;
+ qDebug() << "";
+ }
+
+ return done;
+}
+
+}
+
+migration::migration() {}
+migration::~migration() {}
+
+} // ns
+
+std::vector<QString> run_migrations()
+{
+ return migrations::detail::migrator::run();
+}
+
+void mark_config_as_not_needing_migration()
+{
+ using m = migrations::detail::migrator;
+
+ m::mark_config_as_not_needing_migration();
+}
+
+void migrations::detail::migrator::mark_config_as_not_needing_migration()
+{
+ set_last_migration_time(time_after_migrations());
+}
diff --git a/migration/migration.hpp b/migration/migration.hpp
new file mode 100644
index 00000000..b9c20f15
--- /dev/null
+++ b/migration/migration.hpp
@@ -0,0 +1,72 @@
+#pragma once
+
+#include <QString>
+#include <vector>
+
+#include "export.hpp"
+
+namespace migrations {
+
+class migration;
+class registrator;
+
+namespace detail {
+ class migrator final
+ {
+ using mm = migration*;
+ template<typename t> using vec_ = std::vector<t>;
+ using vstr = vec_<QString>;
+ using vec = vec_<mm>;
+ static vec& migrations();
+ static QString last_migration_time();
+ static QString time_after_migrations();
+ static void set_last_migration_time(const QString& val);
+ migrator() = delete;
+ static vec sorted_migrations();
+ public:
+ static vstr run();
+ static void register_migration(migration* m);
+ static void mark_config_as_not_needing_migration();
+ };
+
+ template<typename t>
+ struct registrator final
+ {
+ registrator()
+ {
+ static t m;
+ migrator::register_migration(static_cast<migration*>(&m));
+ }
+ };
+}
+
+#ifndef __COUNTER__
+# error "oops, need __COUNTER__ extension for preprocessor"
+#endif
+
+#define OPENTRACK_MIGRATION(type) static ::migrations::detail::registrator<type> opentrack_migration_registrator__ ## __COUNTER__ ## _gensym;
+
+#ifdef Q_CREATOR_RUN
+# pragma clang diagnostic ignored "-Wweak-vtables"
+#endif
+
+class migration
+{
+ migration& operator=(const migration&) = delete;
+ migration(const migration&) = delete;
+ migration& operator=(migration&&) = delete;
+ migration(migration&&) = delete;
+
+public:
+ migration();
+ virtual ~migration();
+ virtual QString unique_date() const = 0;
+ virtual QString name() const = 0;
+ virtual bool should_run() const = 0;
+ virtual void run() = 0;
+};
+
+}
+
+OPENTRACK_MIGRATION_EXPORT std::vector<QString> run_migrations();
+OPENTRACK_MIGRATION_EXPORT void mark_config_as_not_needing_migration();