summaryrefslogtreecommitdiffhomepage
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
parentcc6fc6577940df89c57db08743b181291c2a4b43 (diff)
add support for migrations
They're run from the UI thread so can even be interactive.
-rwxr-xr-xCMakeLists.txt1
-rw-r--r--gui/CMakeLists.txt1
-rw-r--r--gui/main-window.cpp35
-rw-r--r--gui/main-window.hpp4
-rw-r--r--gui/main.cpp9
-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
-rw-r--r--options/bundle.cpp10
-rw-r--r--options/bundle.hpp6
-rw-r--r--options/group.cpp4
-rw-r--r--options/group.hpp5
15 files changed, 294 insertions, 26 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8fadd0f6..c2353d70 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -32,6 +32,7 @@ file(GLOB opentrack-subprojects
"qxt-mini/${C}"
"macosx/${C}"
"cv/${C}"
+ "migration/${C}"
)
list(SORT opentrack-subprojects)
diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt
index c793a65f..f33e2a3d 100644
--- a/gui/CMakeLists.txt
+++ b/gui/CMakeLists.txt
@@ -13,6 +13,7 @@ opentrack_boilerplate(opentrack EXECUTABLE BIN ${console})
set_target_properties(opentrack PROPERTIES SUFFIX "${opentrack-binary-suffix}")
target_link_libraries(opentrack
+ opentrack-migration
opentrack-logic
opentrack-spline-widget
opentrack-pose-widget
diff --git a/gui/main-window.cpp b/gui/main-window.cpp
index 94034bd6..30211128 100644
--- a/gui/main-window.cpp
+++ b/gui/main-window.cpp
@@ -11,6 +11,7 @@
#include "options/options.hpp"
#include "opentrack-library-path.h"
#include "new_file_dialog.h"
+#include "migration/migration.hpp"
#include <QFile>
#include <QFileDialog>
#include <QDesktopServices>
@@ -42,7 +43,7 @@ MainWindow::MainWindow() :
setFixedSize(size());
updateButtonState(false, false);
- refresh_config_list();
+ refresh_config_list(true);
connect(ui.btnEditCurves, SIGNAL(clicked()), this, SLOT(showCurveConfiguration()));
connect(ui.btnShortcuts, SIGNAL(clicked()), this, SLOT(show_options_dialog()));
@@ -87,7 +88,7 @@ MainWindow::MainWindow() :
}
// timers
- connect(&config_list_timer, SIGNAL(timeout()), this, SLOT(refresh_config_list()));
+ connect(&config_list_timer, &QTimer::timeout, this, [this]() { refresh_config_list(false); });
connect(&pose_update_timer, SIGNAL(timeout()), this, SLOT(showHeadPose()));
connect(&det_timer, SIGNAL(timeout()), this, SLOT(maybe_start_profile_from_executable()));
@@ -112,6 +113,8 @@ MainWindow::MainWindow() :
(void) file.open(QFile::ReadWrite);
}
}
+ else
+ set_profile(group::ini_filename());
connect(this, &MainWindow::emit_start_tracker,
this, [&]() -> void { qDebug() << "start tracker"; startTracker(); },
@@ -228,7 +231,7 @@ void MainWindow::register_shortcuts()
work->reload_shortcuts();
}
-void MainWindow::warn_on_config_not_writable()
+bool MainWindow::warn_on_config_not_writable()
{
QString current_file = group::ini_pathname();
QFile f(current_file);
@@ -237,7 +240,10 @@ void MainWindow::warn_on_config_not_writable()
if (!f.isOpen())
{
QMessageBox::warning(this, "Something went wrong", "Check permissions and ownership for your .ini file!", QMessageBox::Ok, QMessageBox::NoButton);
+ return false;
}
+
+ return true;
}
bool MainWindow::get_new_config_name_from_dialog(QString& ret)
@@ -273,8 +279,9 @@ void MainWindow::make_empty_config()
{
QFile filename(dir + "/" + name);
(void) filename.open(QFile::ReadWrite);
- refresh_config_list();
+ refresh_config_list(true);
ui.iconcomboProfile->setCurrentText(name);
+ mark_config_as_not_needing_migration();
}
}
@@ -288,8 +295,9 @@ void MainWindow::make_copied_config()
const QString new_name = dir + "/" + name;
(void) QFile::remove(new_name);
(void) QFile::copy(cur, new_name);
- refresh_config_list();
+ refresh_config_list(true);
ui.iconcomboProfile->setCurrentText(name);
+ mark_config_as_not_needing_migration();
}
}
@@ -302,7 +310,7 @@ void MainWindow::open_config_directory()
}
}
-void MainWindow::refresh_config_list()
+void MainWindow::refresh_config_list(bool warn)
{
if (work)
return;
@@ -357,7 +365,8 @@ void MainWindow::refresh_config_list()
}
set_title();
- warn_on_config_not_writable();
+ if (warn)
+ warn_on_config_not_writable();
}
void MainWindow::updateButtonState(bool running, bool inertialp)
@@ -776,7 +785,13 @@ bool MainWindow::is_tray_enabled()
void MainWindow::set_profile(const QString &profile)
{
- QSettings settings(OPENTRACK_ORG);
- settings.setValue(OPENTRACK_CONFIG_FILENAME_KEY, profile);
- warn_on_config_not_writable();
+ {
+ QSettings settings(OPENTRACK_ORG);
+ settings.setValue(OPENTRACK_CONFIG_FILENAME_KEY, profile);
+ }
+ const bool ok = warn_on_config_not_writable();
+ if (ok)
+ // migrations are for config layout changes and other user-visible
+ // incompatibilities in future versions
+ run_migrations();
}
diff --git a/gui/main-window.hpp b/gui/main-window.hpp
index 75a66b0e..7cd94e93 100644
--- a/gui/main-window.hpp
+++ b/gui/main-window.hpp
@@ -112,7 +112,7 @@ private slots:
void make_empty_config();
void make_copied_config();
void open_config_directory();
- void refresh_config_list();
+ void refresh_config_list(bool warn);
void startTracker();
void stopTracker();
@@ -128,6 +128,6 @@ public:
MainWindow();
~MainWindow();
static void set_working_directory();
- void warn_on_config_not_writable();
+ bool warn_on_config_not_writable();
bool is_tray_enabled();
};
diff --git a/gui/main.cpp b/gui/main.cpp
index e452b781..7ac822dc 100644
--- a/gui/main.cpp
+++ b/gui/main.cpp
@@ -7,6 +7,7 @@
# include <QString>
#endif
+#include "migration/migration.hpp"
#include "main-window.hpp"
#include "options/options.hpp"
#include "compat/win32-com.hpp"
@@ -23,8 +24,7 @@ using namespace options;
void set_qt_style()
{
#if defined(_WIN32) || defined(__APPLE__)
- // qt5 designer-made controls look like shit on 'doze -sh 20140921
- // also our OSX look leaves a lot to be desired -sh 20150726
+ // our layouts on OSX make some control wrongly sized -sh 20160908
{
const QStringList preferred { "fusion", "windowsvista", "macintosh" };
for (const auto& style_name : preferred)
@@ -176,10 +176,7 @@ main(int argc, char** argv)
#ifdef _MSC_VER
int WINAPI
-WinMain (struct HINSTANCE__ *hInstance,
- struct HINSTANCE__ *hPrevInstance,
- char *lpszCmdLine,
- int nCmdShow)
+WinMain (struct HINSTANCE__*, struct HINSTANCE__*, char*, int)
{
return main (__argc, __argv);
}
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();
diff --git a/options/bundle.cpp b/options/bundle.cpp
index 48689720..61be509a 100644
--- a/options/bundle.cpp
+++ b/options/bundle.cpp
@@ -16,6 +16,10 @@ bundle::bundle(const QString& group_name)
{
}
+bundle::~bundle()
+{
+}
+
void bundle::reload()
{
if (group_name.size())
@@ -114,7 +118,7 @@ void bundler::bundle_decf(const bundler::k& key)
if (--std::get<0>(implsgl_data[key]) == 0)
{
- qDebug() << "bundle -" << key;
+ //qDebug() << "bundle -" << key;
implsgl_data.erase(key);
}
@@ -132,7 +136,7 @@ void bundler::after_profile_changed_()
mem<v> bundle_ = bundle.lock();
if (bundle_)
{
- qDebug() << "bundle: reverting" << kv.first << "due to profile change";
+ //qDebug() << "bundle: reverting" << kv.first << "due to profile change";
bundle_->reload();
}
}
@@ -163,7 +167,7 @@ std::shared_ptr<bundler::v> bundler::make_bundle(const bundler::k &key)
return shared;
}
- qDebug() << "bundle +" << key;
+ //qDebug() << "bundle +" << key;
std::shared_ptr<v> shr(new v(key), [this](v* val) { bundle_decf(val->name()); });
diff --git a/options/bundle.hpp b/options/bundle.hpp
index 20ec9eaa..3d75a8de 100644
--- a/options/bundle.hpp
+++ b/options/bundle.hpp
@@ -24,6 +24,8 @@ namespace options {
namespace detail {
+struct bundler;
+
class OPENTRACK_OPTIONS_EXPORT bundle final : public QObject, public virtual connector
{
class OPENTRACK_OPTIONS_EXPORT mutex final : public QMutex
@@ -35,6 +37,8 @@ class OPENTRACK_OPTIONS_EXPORT bundle final : public QObject, public virtual con
Q_OBJECT
private:
+ friend bundler;
+
mutex mtx;
const QString group_name;
group saved;
@@ -50,7 +54,7 @@ signals:
void changed() const;
public:
bundle(const QString& group_name);
- ~bundle() override {}
+ ~bundle() override;
QString name() { return group_name; }
void reload();
void store_kv(const QString& name, const QVariant& datum);
diff --git a/options/group.cpp b/options/group.cpp
index a2169ae5..69b79cef 100644
--- a/options/group.cpp
+++ b/options/group.cpp
@@ -72,7 +72,7 @@ QString group::ini_pathname()
return dir + "/" + ini_filename();
}
-const QStringList group::ini_list()
+QStringList group::ini_list()
{
const auto dirname = ini_directory();
if (dirname == "")
@@ -83,7 +83,7 @@ const QStringList group::ini_list()
return list;
}
-const std::shared_ptr<QSettings> group::ini_file()
+std::shared_ptr<QSettings> group::ini_file()
{
const auto pathname = ini_pathname();
if (pathname != "")
diff --git a/options/group.hpp b/options/group.hpp
index f76978ad..f5b3e523 100644
--- a/options/group.hpp
+++ b/options/group.hpp
@@ -17,6 +17,7 @@ class OPENTRACK_OPTIONS_EXPORT group final
QString name;
public:
std::map<QString, QVariant> kvs;
+ group(const QString& name, mem<QSettings> s);
group(const QString& name);
void save() const;
void save_deferred(QSettings& s) const;
@@ -25,8 +26,8 @@ public:
static QString ini_directory();
static QString ini_filename();
static QString ini_pathname();
- static const QStringList ini_list();
- static const std::shared_ptr<QSettings> ini_file();
+ static QStringList ini_list();
+ static std::shared_ptr<QSettings> ini_file();
template<typename t>
t get(const QString& k) const