aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAqua-sama <aqua@iserlohn-fortress.net>2018-01-17 13:32:13 +0100
committerAqua-sama <aqua@iserlohn-fortress.net>2018-01-17 13:32:13 +0100
commitd592ee191e8aedc84c670e6d818fcf97c0bd7a92 (patch)
treeb2bd8413332cd1567b9ae954835a7a4c930de730
parentFixed build scripts for use with the mercurial repository (diff)
downloadsmolbote-d592ee191e8aedc84c670e6d818fcf97c0bd7a92.tar.xz
Configuration creates missing items based on defaults
-rw-r--r--data/poi.cfg5
-rw-r--r--lib/settings/configuration.cpp233
-rw-r--r--lib/settings/configuration.h50
-rw-r--r--src/browser.cpp5
-rw-r--r--src/main.cpp35
5 files changed, 141 insertions, 187 deletions
diff --git a/data/poi.cfg b/data/poi.cfg
index 26a4c34..557cda5 100644
--- a/data/poi.cfg
+++ b/data/poi.cfg
@@ -46,6 +46,11 @@ filter = {
path = "~/.config/smolbote/hosts.d";
};
+// Plugin settings
+plugins = {
+ path = "~/.config/smolbote/plugins.d";
+};
+
// Profile settings
profile = {
path = "~/.config/smolbote/Profiles";
diff --git a/lib/settings/configuration.cpp b/lib/settings/configuration.cpp
index 06ee0bd..af5af65 100644
--- a/lib/settings/configuration.cpp
+++ b/lib/settings/configuration.cpp
@@ -7,22 +7,20 @@
*/
#include "configuration.h"
-#include <libconfig.h++>
+#include <QtCore/QStandardPaths>
#include <sstream>
using namespace libconfig;
-Configuration::Configuration()
+Configuration::Configuration(const std::string &path, const std::string &home)
{
m_userCfg = new Config();
-#ifdef C_LIKE_CONFIG
+ // prettier output
m_userCfg->setOptions(Config::OptionSemicolonSeparators | Config::OptionOpenBraceOnSeparateLine);
-#endif
- // fsync after writing and before closing
m_userCfg->setOption(Config::OptionFsync, true);
- // make sure the cfgPath is empty
- m_userCfgPath = std::string();
+ m_userCfgPath = path;
+ m_homePath = home;
m_defaultCfg = new Config();
}
@@ -33,14 +31,13 @@ Configuration::~Configuration()
delete m_defaultCfg;
}
-bool Configuration::readUserConfiguration(const std::string &path)
+bool Configuration::read()
{
- m_userCfgPath = path;
try {
- m_userCfg->readFile(path.c_str());
- } catch(FileIOException) {
+ m_userCfg->readFile(m_userCfgPath.c_str());
+ } catch(const FileIOException &e) {
return false;
- } catch(ParseException) {
+ } catch(const ParseException &e) {
return false;
}
return true;
@@ -50,30 +47,27 @@ bool Configuration::parse(const std::string &contents)
{
try {
m_userCfg->readString(contents);
- } catch(ParseException) {
+ } catch(const ParseException &e) {
return false;
}
return true;
}
-bool Configuration::writeUserConfiguration(const std::string &path)
+bool Configuration::writeIfNeeded(const std::string &path)
{
- m_userCfgPath = path;
- try {
- m_userCfg->writeFile(m_userCfgPath.c_str());
- } catch(FileIOException) {
- return false;
- }
- return true;
-}
+ if(!path.empty())
+ m_userCfgPath = path;
+
+ if(!changed)
+ return true;
-bool Configuration::writeIfNeeded()
-{
try {
m_userCfg->writeFile(m_userCfgPath.c_str());
- } catch(FileIOException) {
+ } catch(const FileIOException &e) {
return false;
}
+
+ changed = false;
return true;
}
@@ -81,7 +75,7 @@ bool Configuration::parseDefaultConfiguration(const std::string &contents)
{
try {
m_defaultCfg->readString(contents);
- } catch(ParseException) {
+ } catch(const ParseException &e) {
return false;
}
return true;
@@ -94,7 +88,8 @@ std::vector<std::string> Configuration::childrenSettings(const char *name)
for(const Setting &setting : root) {
if(setting.getType() != Setting::TypeGroup) {
- groupNames.push_back(setting.getName());
+ groupNames.emplace_back(setting.getName());
+ //groupNames.push_back(setting.getName());
}
}
@@ -108,7 +103,8 @@ std::vector<std::string> Configuration::childrenGroups(const char *name)
for(const Setting &setting : root) {
if(setting.getType() == Setting::TypeGroup) {
- groupNames.push_back(setting.getName());
+ groupNames.emplace_back(setting.getName());
+ //groupNames.push_back(setting.getName());
}
}
return groupNames;
@@ -116,139 +112,109 @@ std::vector<std::string> Configuration::childrenGroups(const char *name)
void Configuration::resetValue(const char *path)
{
- if(m_userCfg->exists(path)) {
- Setting &v = m_userCfg->lookup(path);
- switch(v.getType()) {
- case Setting::TypeNone:
- break;
- case Setting::TypeInt:
- v = static_cast<int>(m_defaultCfg->lookup(path));
- break;
- case Setting::TypeInt64:
- v = static_cast<long>(m_defaultCfg->lookup(path));
- break;
- case Setting::TypeFloat:
- v = static_cast<double>(m_defaultCfg->lookup(path));
- break;
- case Setting::TypeString:
- v = static_cast<const char *>(m_defaultCfg->lookup(path));
- break;
- case Setting::TypeBoolean:
- v = static_cast<bool>(m_defaultCfg->lookup(path));
- break;
- case Setting::TypeGroup:
- break;
- case Setting::TypeArray:
- break;
- case Setting::TypeList:
- break;
+ if(!m_userCfg->exists(path) && m_defaultCfg->exists(path)) {
+ // entry doesn't exist, create path to it
+ // split path into array of items, sep=.
+ std::string s(path);
+ std::vector<std::string> pathTokens;
+ std::string::size_type prev_pos = 0, pos = 0;
+ while((pos = s.find('.', pos)) != std::string::npos) {
+ std::string substring(s.substr(prev_pos, pos - prev_pos));
+ pathTokens.push_back(substring);
+ prev_pos = ++pos;
}
- }
-}
+ pathTokens.push_back(s.substr(prev_pos, pos - prev_pos)); // Last word
-template <typename T>
-std::optional<T> Configuration::value(const char *path) const
-{
- // if setting doesn't exist, give back a nullopt
- if(!m_userCfg->exists(path)) {
- return std::nullopt;
+ s.clear();
+ // iterate through items, creating the path along the way
+ for(const std::string &t : pathTokens) {
+ Setting &v = m_userCfg->lookup(s);
+ Setting &d = m_defaultCfg->lookup(s).lookup(t);
+
+ if(!v.exists(t)) {
+ v.add(t, d.getType());
+ }
+
+ if(s.empty())
+ s.append(t);
+ else
+ s.append('.' + t);
+ }
}
- // setting was found
- const Setting &setting = m_userCfg->lookup(path);
- std::optional<T> r;
+ // if the path doesn't exist in the defaultCfg, this will crash
- // cast depending on type
- // type checks are done during compile time
- switch(setting.getType()) {
+ // entry exists, reset it
+ Setting &v = m_userCfg->lookup(path);
+ switch(v.getType()) {
case Setting::TypeNone:
- r = std::nullopt;
break;
-
case Setting::TypeInt:
- // int, unsigned int, long, unsigned long
- if constexpr(std::is_same_v<T, std::string>) {
- r = std::optional<std::string>(std::to_string(static_cast<int>(setting)));
- } else if constexpr(std::is_same_v<T, int> || std::is_same_v<T, unsigned int> || std::is_same_v<T, long> || std::is_same_v<T, unsigned long>) {
- r = std::optional<T>(static_cast<T>(setting));
- } else {
- r = std::nullopt;
- }
+ v = static_cast<int>(m_defaultCfg->lookup(path));
break;
-
case Setting::TypeInt64:
- // int, unsigned int; long long, unsigned long long
- if constexpr(std::is_same_v<T, std::string>) {
- r = std::optional<std::string>(std::to_string(static_cast<long long>(setting)));
- } else if constexpr(std::is_same_v<T, int> || std::is_same_v<T, unsigned int> || std::is_same_v<T, long long> || std::is_same_v<T, unsigned long long>) {
- r = std::optional<T>(static_cast<T>(setting));
- } else {
- r = std::nullopt;
- }
+ v = static_cast<long>(m_defaultCfg->lookup(path));
break;
-
case Setting::TypeFloat:
- // float, double
- if constexpr(std::is_same_v<T, std::string>) {
- r = std::optional<std::string>(std::to_string(static_cast<float>(setting)));
- } else if constexpr(std::is_same_v<T, float> || std::is_same_v<T, double>) {
- r = std::optional<T>(static_cast<T>(setting));
- } else {
- r = std::nullopt;
- }
+ v = static_cast<double>(m_defaultCfg->lookup(path));
break;
-
case Setting::TypeString:
- // const char*, std::string
- if constexpr(std::is_same<T, std::string>::value) {
- r = std::optional<std::string>(static_cast<const char *>(setting));
- } else {
- r = std::nullopt;
- }
+ v = static_cast<const char *>(m_defaultCfg->lookup(path));
break;
-
case Setting::TypeBoolean:
- // bool
- if constexpr(std::is_same<T, std::string>::value) {
- r = std::optional<std::string>(static_cast<bool>(setting) ? "true" : "false");
- } else if constexpr(std::is_same<T, bool>::value) {
- r = std::optional<bool>(static_cast<bool>(setting));
- } else {
- r = std::nullopt;
- }
+ v = static_cast<bool>(m_defaultCfg->lookup(path));
break;
-
case Setting::TypeGroup:
- r = std::nullopt;
break;
-
case Setting::TypeArray:
- r = std::nullopt;
break;
-
case Setting::TypeList:
- r = std::nullopt;
break;
}
- return r;
+ // if it's a string, it may contain a path
+ if(v.getType() == Setting::TypeString) {
+ std::string val(static_cast<const char *>(v));
+ v = patchHome(val, m_homePath).c_str();
+ }
+
+ changed = true;
}
-// tell the compiler to export these functions, otherwise you get linking errors
-template std::optional<int> Configuration::value<int>(const char *path) const;
-template std::optional<unsigned int> Configuration::value<unsigned int>(const char *path) const;
-template std::optional<long> Configuration::value<long>(const char *path) const;
-template std::optional<unsigned long> Configuration::value<unsigned long>(const char *path) const;
+std::string Configuration::castToString(const libconfig::Setting &v) const
+{
+ // cast depending on type
+ // type checks are done during compile time
+ switch(v.getType()) {
+ case Setting::TypeNone:
+ return std::string();
+
+ case Setting::TypeInt:
+ // int, unsigned int, long, unsigned long
+ return std::to_string(static_cast<int32_t>(v));
-template std::optional<long long> Configuration::value<long long>(const char *path) const;
-template std::optional<unsigned long long> Configuration::value<unsigned long long>(const char *path) const;
+ case Setting::TypeInt64:
+ // int, unsigned int; long long, unsigned long long
+ return std::to_string(static_cast<int64_t>(v));
-template std::optional<float> Configuration::value<float>(const char *path) const;
-template std::optional<double> Configuration::value<double>(const char *path) const;
+ case Setting::TypeFloat:
+ // float, double
+ return std::to_string(static_cast<double>(v));
+
+ case Setting::TypeString:
+ // const char*, std::string
+ return std::string(static_cast<const char *>(v));
-template std::optional<bool> Configuration::value<bool>(const char *path) const;
+ case Setting::TypeBoolean:
+ // bool
+ return std::string(static_cast<bool>(v) ? "true" : "false");
-template std::optional<std::string> Configuration::value<std::string>(const char *path) const;
+ case Setting::TypeGroup:
+ case Setting::TypeArray:
+ case Setting::TypeList:
+ return std::string();
+ }
+}
template <typename T>
bool Configuration::setValue(std::string path, const T &val)
@@ -319,11 +285,12 @@ template bool Configuration::setValue<bool>(std::string path, const bool &val);
template bool Configuration::setValue<std::string>(std::string path, const std::string &val);
-std::string &patchHome(std::string &path, const std::string &home)
+std::string patchHome(const std::string &path, const std::string &home)
{
+ std::string r = path;
const size_t location = path.find('~');
if(location != std::string::npos) {
- return path.replace(location, 1, home);
+ return r.replace(location, 1, home);
}
- return path;
+ return r;
}
diff --git a/lib/settings/configuration.h b/lib/settings/configuration.h
index 4fc614e..67ba7b1 100644
--- a/lib/settings/configuration.h
+++ b/lib/settings/configuration.h
@@ -9,26 +9,20 @@
#ifndef CONFIGURATION_H
#define CONFIGURATION_H
+#include <libconfig.h++>
#include <optional>
#include <string>
#include <vector>
-namespace libconfig
-{
-class Config;
-class Setting;
-}
-
class Configuration
{
public:
- Configuration();
+ explicit Configuration(const std::string &path, const std::string &home);
~Configuration();
- bool readUserConfiguration(const std::string &path);
+ bool read();
bool parse(const std::string &contents);
- bool writeUserConfiguration(const std::string &path);
- bool writeIfNeeded();
+ bool writeIfNeeded(const std::string &path = std::string());
bool parseDefaultConfiguration(const std::string &contents);
@@ -38,39 +32,39 @@ public:
void resetValue(const char *path);
template <typename T>
- std::optional<T> value(const char *path) const;
+ std::optional<T> value(const char *path) const
+ {
+ // if setting doesn't exist, give back a nullopt
+ if(!m_userCfg->exists(path)) {
+ const_cast<Configuration *>(this)->resetValue(path);
+ return value<T>(path);
+ }
+
+ const libconfig::Setting &v = m_userCfg->lookup(path);
+ if constexpr(std::is_same_v<T, std::string>)
+ return std::optional<std::string>(castToString(v));
+ else
+ return std::optional<T>(static_cast<T>(v));
+ }
template <typename T>
bool setValue(std::string path, const T &val);
private:
+ std::string castToString(const libconfig::Setting &v) const;
+
bool changed = false;
+ std::string m_homePath;
std::string m_userCfgPath;
libconfig::Config *m_userCfg, *m_defaultCfg;
};
// replace ~ with home
-std::string &patchHome(std::string &path, const std::string &home);
+std::string patchHome(const std::string &path, const std::string &home);
// instantiate functions
// this needs to be done because the implementation is in the cpp file
-// Settings::value<>
-extern template std::optional<int> Configuration::value<int>(const char *path) const;
-extern template std::optional<unsigned int> Configuration::value<unsigned int>(const char *path) const;
-extern template std::optional<long> Configuration::value<long>(const char *path) const;
-extern template std::optional<unsigned long> Configuration::value<unsigned long>(const char *path) const;
-
-extern template std::optional<long long> Configuration::value<long long>(const char *path) const;
-extern template std::optional<unsigned long long> Configuration::value<unsigned long long>(const char *path) const;
-
-extern template std::optional<float> Configuration::value<float>(const char *path) const;
-extern template std::optional<double> Configuration::value<double>(const char *path) const;
-
-extern template std::optional<bool> Configuration::value<bool>(const char *path) const;
-
-extern template std::optional<std::string> Configuration::value<std::string>(const char *path) const;
-
// Settings::setValue<>
extern template bool Configuration::setValue<int>(std::string path, const int &val);
extern template bool Configuration::setValue<unsigned int>(std::string path, const unsigned int &val);
diff --git a/src/browser.cpp b/src/browser.cpp
index 43cee5f..1e07a95 100644
--- a/src/browser.cpp
+++ b/src/browser.cpp
@@ -25,7 +25,10 @@ Browser::Browser(int &argc, char *argv[])
Browser::~Browser()
{
if(m_config) {
- QtConcurrent::run(QThreadPool::globalInstance(), m_config.get(), &Configuration::writeIfNeeded);
+ //QtConcurrent::run(QThreadPool::globalInstance(), m_config.get(), &Configuration::writeIfNeeded);
+ QtConcurrent::run([c = m_config.get()]() {
+ qDebug("Writing configuration: %s", c->writeIfNeeded() ? "ok" : "failed");
+ });
}
if(m_bookmarksManager) {
QtConcurrent::run(QThreadPool::globalInstance(), m_bookmarksManager.get(), &BookmarksWidget::save);
diff --git a/src/main.cpp b/src/main.cpp
index fb80b7e..0452fdd 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -36,35 +36,18 @@ void bootstrapUserConfig(const std::string &path, Configuration &config)
// set firstRun to false so we don't re-init on every run
config.setValue<bool>("browser.firstRun", false);
- // The .path's need to be overriden because ~ doesn't translate to home
- const QString &home = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
-
- // filter.path
- std::string filterPath = config.value<std::string>("filter.path").value();
- config.setValue<std::string>("filter.path", patchHome(filterPath, home.toStdString()));
-
- // profile.path
- std::string profilePath = config.value<std::string>("profile.path").value();
- config.setValue<std::string>("profile.path", patchHome(profilePath, home.toStdString()));
-
- // bookmarks.path
- std::string bookmarksPath = config.value<std::string>("bookmarks.path").value();
- config.setValue<std::string>("bookmarks.path", patchHome(bookmarksPath, home.toStdString()));
-
- // downloads.path
- std::string downloadsPath = config.value<std::string>("downloads.path").value();
- config.setValue<std::string>("downloads.path", patchHome(downloadsPath, home.toStdString()));
+ config.resetValue("filter.path");
+ config.resetValue("profile.path");
+ config.resetValue("bookmarks.path");
+ config.resetValue("downloads.path");
+ config.resetValue("plugins.path");
}
int main(int argc, char *argv[])
{
// Create application object
Browser instance(argc, argv);
-#ifdef SMOLBOTE_VERSION
instance.setApplicationVersion(SMOLBOTE_VERSION);
-#else
- instance.setApplicationVersion("1.0.0");
-#endif
#ifdef QT_DEBUG
QElapsedTimer timer;
@@ -122,8 +105,10 @@ int main(int argc, char *argv[])
return 0;
}
- std::shared_ptr<Configuration> config = std::make_shared<Configuration>();
- config->readUserConfiguration(parser.value(configOption).toStdString());
+ std::shared_ptr<Configuration> config = std::make_shared<Configuration>(
+ parser.value(configOption).toStdString(),
+ QStandardPaths::writableLocation(QStandardPaths::HomeLocation).toStdString());
+ config->read();
config->parseDefaultConfiguration(readConfig(parser.value(defaultConfigOption)));
// check if first run
@@ -151,7 +136,7 @@ int main(int argc, char *argv[])
// patch paths
bootstrapUserConfig(path.toStdString(), *config);
- std::cout << "Generating config to: " << qUtf8Printable(path) << (config->writeUserConfiguration(path.toStdString()) ? " ok" : " failed") << std::endl;
+ std::cout << "Writing configuration: " << (config->writeIfNeeded(path.toStdString()) ? "ok" : "failed") << std::endl;
// exit if this is the only thing we needed to do
if(parser.isSet(generateUserConfigOption)) {