Commit 55f003e0 authored by pvuorela's avatar pvuorela

Merge branch 'master' into 'master'

Reformat code to common style and fix some small issues

See individual commits

@sage @rainemak

See merge request !6
parents a470b9b0 3321d4a1
......@@ -19,9 +19,9 @@ public:
* A list of types ssu provides shiny values suitable for displaying
*/
enum DisplayType {
DeviceManufacturer = Ssu::DeviceManufacturer, ///< Manufacturer, like ACME Corp. Board mappings key "deviceManufacturer"
DeviceModel = Ssu::DeviceModel, ///< Marketed device name, like Pogoblaster 3000. Board mappings key "prettyModel"
DeviceDesignation = Ssu::DeviceDesignation, ///< Type designation, like NCC-1701. Beard mappings key "deviceDesignation"
DeviceManufacturer = Ssu::DeviceManufacturer, ///< Manufacturer, like ACME Corp. Board mappings key "deviceManufacturer"
DeviceModel = Ssu::DeviceModel, ///< Marketed device name, like Pogoblaster 3000. Board mappings key "prettyModel"
DeviceDesignation = Ssu::DeviceDesignation, ///< Type designation, like NCC-1701. Beard mappings key "deviceDesignation"
};
DeclarativeSsuDeviceInfo();
......@@ -37,7 +37,7 @@ public:
* If the device is not a variant it will return an empty string. If
* fallback is set to true it return the device model in this case.
*/
Q_INVOKABLE QString deviceVariant(bool fallback=false);
Q_INVOKABLE QString deviceVariant(bool fallback = false);
/**
* Try to find out ond what kind of system this is running
*/
......
This diff is collapsed.
......@@ -18,20 +18,21 @@
getenv("SSU_TESTS_DATA_PATH") : \
TESTS_DATA_PATH)
class Sandbox {
public:
class Sandbox
{
public:
enum Usage {
UseDirectly,
UseAsSkeleton,
UseDirectly,
UseAsSkeleton,
};
enum Scope {
ThisProcess = 0x01,
ChildProcesses = 0x02,
ThisProcess = 0x01,
ChildProcesses = 0x02,
};
Q_DECLARE_FLAGS(Scopes, Scope)
public:
public:
Sandbox();
Sandbox(const QString &sandboxPath, Usage usage, Scopes scopes);
~Sandbox();
......@@ -45,15 +46,15 @@ class Sandbox {
static QString map(const QString &pathName, const QString &fileName);
bool addWorldFiles(const QString &directory, QDir::Filters filters = QDir::NoFilter,
const QStringList &filterNames = QStringList(), bool recurse = true);
const QStringList &filterNames = QStringList(), bool recurse = true);
bool addWorldFile(const QString &file);
private:
private:
bool prepare();
static QString createTmpDir(const QString &nameTemplate);
static bool copyDir(const QString &directory, const QString &newName);
private:
private:
static Sandbox *s_activeInstance;
const bool m_defaultConstructed;
const Usage m_usage;
......
This diff is collapsed.
......@@ -16,20 +16,21 @@ class QNetworkAccessManager;
class QNetworkReply;
class QDomDocument;
class Ssu: public QObject {
class Ssu: public QObject
{
Q_OBJECT
friend class UrlResolverTest;
public:
public:
/**
* Filters to control the output of the repository lookup methods
*/
enum RepoFilter {
NoFilter, ///< All repositories (global + user)
UserFilter, ///< Only user configured repositories
BoardFilter, ///< Only global repositories, with user blacklist ignored
BoardFilterUserBlacklist, ///< Only global repositories, with user blacklist applied
NoFilter, ///< All repositories (global + user)
UserFilter, ///< Only user configured repositories
BoardFilter, ///< Only global repositories, with user blacklist ignored
BoardFilterUserBlacklist, ///< Only global repositories, with user blacklist applied
};
/**
......@@ -43,12 +44,12 @@ class Ssu: public QObject {
* like in AppInstallMode.
*/
enum DeviceMode {
DisableRepoManager = 0x1, ///< Disable automagic repository management
RndMode = 0x2, ///< Enable RnD mode for device
ReleaseMode = 0x4, ///< Enable Release mode
LenientMode = 0x8, ///< Disable strict mode (i.e., keep unmanaged repositories)
UpdateMode = 0x10, ///< Do repo isolation and similar bits important for updating devices
AppInstallMode = 0x20 ///< Do repo isolation, but keep store repository enabled
DisableRepoManager = 0x1, ///< Disable automagic repository management
RndMode = 0x2, ///< Enable RnD mode for device
ReleaseMode = 0x4, ///< Enable Release mode
LenientMode = 0x8, ///< Disable strict mode (i.e., keep unmanaged repositories)
UpdateMode = 0x10, ///< Do repo isolation and similar bits important for updating devices
AppInstallMode = 0x20 ///< Do repo isolation, but keep store repository enabled
};
Q_DECLARE_FLAGS(DeviceModeFlags, DeviceMode)
......@@ -57,26 +58,26 @@ class Ssu: public QObject {
* A list of types ssu provides shiny values suitable for displaying
*/
enum DisplayType {
DeviceManufacturer = 0, ///< Manufacturer, like ACME Corp. Board mappings key "deviceManufacturer"
DeviceModel, ///< Marketed device name, like Pogoblaster 3000. Board mappings key "prettyModel"
DeviceDesignation, ///< Type designation, like NCC-1701. Beard mappings key "deviceDesignation"
DeviceManufacturer = 0, ///< Manufacturer, like ACME Corp. Board mappings key "deviceManufacturer"
DeviceModel, ///< Marketed device name, like Pogoblaster 3000. Board mappings key "prettyModel"
DeviceDesignation, ///< Type designation, like NCC-1701. Beard mappings key "deviceDesignation"
};
/**
* Edit modes for variables containing bitmasks
*/
enum EditMode {
Replace = 0x1, ///< Replace the old value with the new one
Add = 0x2, ///< Make sure the given value is set in the bitmask
Remove = 0x4, ///< Make sure the given value is not set in the bitmask
Replace = 0x1, ///< Replace the old value with the new one
Add = 0x2, ///< Make sure the given value is set in the bitmask
Remove = 0x4, ///< Make sure the given value is not set in the bitmask
};
/**
* Return codes to signal success or error conditions
*/
enum ReturnValue {
Success = 0,
ErrUpdateMode = -10,
Success = 0,
ErrUpdateMode = -10,
};
Ssu();
......@@ -94,7 +95,7 @@ class Ssu: public QObject {
*
* @return a string containing the scope; it can be used to look up login credentials using credentials()
*/
QString credentialsScope(QString repoName, bool rndRepo=false);
QString credentialsScope(QString repoName, bool rndRepo = false);
/**
* Return the URL for which credentials scope is valid
*/
......@@ -115,9 +116,9 @@ class Ssu: public QObject {
* Resolve a repository url
* @return the repository URL on success, an empty string on error
*/
QString repoUrl(QString repoName, bool rndRepo=false,
QHash<QString, QString> repoParameters=QHash<QString, QString>(),
QHash<QString, QString> parametersOverride=QHash<QString, QString>());
QString repoUrl(QString repoName, bool rndRepo = false,
QHash<QString, QString> repoParameters = QHash<QString, QString>(),
QHash<QString, QString> parametersOverride = QHash<QString, QString>());
/**
* Unregister a device. This will clean all registration data from a device,
* though will not touch the information on ssu server; the information there
......@@ -141,19 +142,19 @@ class Ssu: public QObject {
/// See SsuCoreConfig::lastCredentialsUpdate
Q_INVOKABLE QDateTime lastCredentialsUpdate();
/// See SsuCoreConfig::release
Q_INVOKABLE QString release(bool rnd=false);
Q_INVOKABLE QString release(bool rnd = false);
/// See SsuCoreConfig::setDeviceMode
Q_INVOKABLE void setDeviceMode(DeviceModeFlags mode, enum EditMode editMode=Replace);
Q_INVOKABLE void setDeviceMode(DeviceModeFlags mode, enum EditMode editMode = Replace);
/// See SsuCoreConfig::setFlavour
Q_INVOKABLE void setFlavour(QString flavour);
/// See SsuCoreConfig::setRelease
Q_INVOKABLE void setRelease(QString release, bool rnd=false);
Q_INVOKABLE void setRelease(QString release, bool rnd = false);
/// See SsuCoreConfig::setDomain
Q_INVOKABLE void setDomain(QString domain);
/// See SsuCoreConfig::useSslVerify
Q_INVOKABLE bool useSslVerify();
private:
private:
QString errorString;
bool errorFlag;
QNetworkAccessManager *manager;
......@@ -163,7 +164,7 @@ class Ssu: public QObject {
bool verifyResponse(QDomDocument *response);
void storeAuthorizedKeys(QByteArray data);
private slots:
private slots:
void requestFinished(QNetworkReply *reply);
/**
* Set errorString returned by lastError to errorMessage, set
......@@ -171,7 +172,7 @@ class Ssu: public QObject {
*/
void setError(QString errorMessage);
public slots:
public slots:
/**
* Attempt RND device registration, using @a username and @a password supplied
* @param username Jolla username
......@@ -193,13 +194,13 @@ class Ssu: public QObject {
* error() to check if an error occured, and use lastError() to retrieve the last
* error message.
*/
void updateCredentials(bool force=false);
void updateCredentials(bool force = false);
/**
* Try to update credentials for (Jolla) store
*/
void updateStoreCredentials();
signals:
signals:
/**
* Emitted after an asynchronous operation finished
*/
......
......@@ -17,141 +17,160 @@
SsuCoreConfig *SsuCoreConfig::ssuCoreConfig = 0;
SsuCoreConfig *SsuCoreConfig::instance(){
if (!ssuCoreConfig)
ssuCoreConfig = new SsuCoreConfig();
SsuCoreConfig *SsuCoreConfig::instance()
{
if (!ssuCoreConfig)
ssuCoreConfig = new SsuCoreConfig;
return ssuCoreConfig;
return ssuCoreConfig;
}
QPair<QString, QString> SsuCoreConfig::credentials(QString scope){
QPair<QString, QString> ret;
beginGroup("credentials-" + scope);
ret.first = value("username").toString();
ret.second = value("password").toString();
endGroup();
return ret;
QPair<QString, QString> SsuCoreConfig::credentials(QString scope)
{
QPair<QString, QString> ret;
beginGroup("credentials-" + scope);
ret.first = value("username").toString();
ret.second = value("password").toString();
endGroup();
return ret;
}
QString SsuCoreConfig::credentialsScope(QString repoName, bool rndRepo){
if (contains("credentials-scope"))
return value("credentials-scope").toString();
else
return "your-configuration-is-broken-and-does-not-contain-credentials-scope";
}
QString SsuCoreConfig::credentialsScope(QString repoName, bool rndRepo)
{
Q_UNUSED(repoName)
Q_UNUSED(rndRepo)
QString SsuCoreConfig::credentialsUrl(QString scope){
if (contains("credentials-url-" + scope))
return value("credentials-url-" + scope).toString();
else
return "your-configuration-is-broken-and-does-not-contain-credentials-url-for-" + scope;
if (contains("credentials-scope"))
return value("credentials-scope").toString();
else
return "your-configuration-is-broken-and-does-not-contain-credentials-scope";
}
QString SsuCoreConfig::flavour(){
if (contains("flavour"))
return value("flavour").toString();
else
return "release";
QString SsuCoreConfig::credentialsUrl(QString scope)
{
if (contains("credentials-url-" + scope))
return value("credentials-url-" + scope).toString();
else
return "your-configuration-is-broken-and-does-not-contain-credentials-url-for-" + scope;
}
Ssu::DeviceModeFlags SsuCoreConfig::deviceMode(){
if (!contains("deviceMode"))
return Ssu::ReleaseMode;
else
return Ssu::DeviceModeFlags(value("deviceMode").toInt());
QString SsuCoreConfig::flavour()
{
if (contains("flavour"))
return value("flavour").toString();
else
return "release";
}
QString SsuCoreConfig::domain(bool pretty){
if (contains("domain")){
if (pretty)
return value("domain").toString().replace(":", "-");
Ssu::DeviceModeFlags SsuCoreConfig::deviceMode()
{
if (!contains("deviceMode"))
return Ssu::ReleaseMode;
else
return value("domain").toString();
} else
return "";
return Ssu::DeviceModeFlags(value("deviceMode").toInt());
}
bool SsuCoreConfig::isRegistered(){
if (!contains("privateKey"))
return false;
if (!contains("certificate"))
return false;
return value("registered").toBool();
QString SsuCoreConfig::domain(bool pretty)
{
if (contains("domain")) {
if (pretty)
return value("domain").toString().replace(":", "-");
else
return value("domain").toString();
} else
return "";
}
QDateTime SsuCoreConfig::lastCredentialsUpdate(){
return value("lastCredentialsUpdate").toDateTime();
bool SsuCoreConfig::isRegistered()
{
if (!contains("privateKey"))
return false;
if (!contains("certificate"))
return false;
return value("registered").toBool();
}
QString SsuCoreConfig::release(bool rnd){
if (rnd)
return value("rndRelease").toString();
else
return value("release").toString();
QDateTime SsuCoreConfig::lastCredentialsUpdate()
{
return value("lastCredentialsUpdate").toDateTime();
}
void SsuCoreConfig::setDeviceMode(Ssu::DeviceModeFlags mode, enum Ssu::EditMode editMode){
int oldMode = value("deviceMode").toInt();
QString SsuCoreConfig::release(bool rnd)
{
if (rnd)
return value("rndRelease").toString();
else
return value("release").toString();
}
if ((editMode & Ssu::Add) == Ssu::Add){
oldMode |= mode;
} else if ((editMode & Ssu::Remove) == Ssu::Remove){
oldMode &= ~mode;
} else
oldMode = mode;
void SsuCoreConfig::setDeviceMode(Ssu::DeviceModeFlags mode, enum Ssu::EditMode editMode)
{
int oldMode = value("deviceMode").toInt();
setValue("deviceMode", oldMode);
sync();
}
if ((editMode & Ssu::Add) == Ssu::Add) {
oldMode |= mode;
} else if ((editMode & Ssu::Remove) == Ssu::Remove) {
oldMode &= ~mode;
} else
oldMode = mode;
void SsuCoreConfig::setFlavour(QString flavour){
setValue("flavour", flavour);
// flavour is RnD only, so enable RnD mode
setDeviceMode(Ssu::RndMode, Ssu::Add);
sync();
setValue("deviceMode", oldMode);
sync();
}
void SsuCoreConfig::setRelease(QString release, bool rnd){
if (rnd) {
setValue("rndRelease", release);
// switch rndMode on/off when setting releases
void SsuCoreConfig::setFlavour(QString flavour)
{
setValue("flavour", flavour);
// flavour is RnD only, so enable RnD mode
setDeviceMode(Ssu::RndMode, Ssu::Add);
} else {
setValue("release", release);
setDeviceMode(Ssu::RndMode, Ssu::Remove);
}
sync();
}
void SsuCoreConfig::setDomain(QString domain){
// - in domain messes with default section autodetection,
// so change it to :
setValue("domain", domain.replace("-", ":"));
sync();
}
bool SsuCoreConfig::useSslVerify(){
if (contains("ssl-verify"))
return value("ssl-verify").toBool();
else
return true;
}
QDBusConnection SsuCoreConfig::userSessionBus(){
int uid_min = getdef_num("UID_MIN", -1);
// For calls from valid UID we assume that they are properly logged in users.
// If they are not the call will fail, but it's their fault.
if (getuid() >= uid_min){
return QDBusConnection::sessionBus();
} else {
// DBus security policy will prevent this beeing used by callers other
// than root at the moment. Still do it generic in case DBus policy will
// be extended later, and just use the usual 'DBus: THOU SHALL NOT PASS!'
// @TODO the uid to be used should be determined using the logind API from
// systemd package to support multiuser systems in the future
QString sessionBusAddress=QString("unix:path=/run/user/%1/dbus/user_bus_socket")
.arg(uid_min);
return QDBusConnection::connectToBus(sessionBusAddress, "userSessionBus");
}
sync();
}
void SsuCoreConfig::setRelease(QString release, bool rnd)
{
if (rnd) {
setValue("rndRelease", release);
// switch rndMode on/off when setting releases
setDeviceMode(Ssu::RndMode, Ssu::Add);
} else {
setValue("release", release);
setDeviceMode(Ssu::RndMode, Ssu::Remove);
}
sync();
}
void SsuCoreConfig::setDomain(QString domain)
{
// - in domain messes with default section autodetection,
// so change it to :
setValue("domain", domain.replace("-", ":"));
sync();
}
bool SsuCoreConfig::useSslVerify()
{
if (contains("ssl-verify"))
return value("ssl-verify").toBool();
else
return true;
}
QDBusConnection SsuCoreConfig::userSessionBus()
{
int uid_min = getdef_num("UID_MIN", -1);
// For calls from valid UID we assume that they are properly logged in users.
// If they are not the call will fail, but it's their fault.
if (getuid() >= static_cast<uid_t>(uid_min)) {
return QDBusConnection::sessionBus();
} else {
// DBus security policy will prevent this beeing used by callers other
// than root at the moment. Still do it generic in case DBus policy will
// be extended later, and just use the usual 'DBus: THOU SHALL NOT PASS!'
// @TODO the uid to be used should be determined using the logind API from
// systemd package to support multiuser systems in the future
QString sessionBusAddress = QString("unix:path=/run/user/%1/dbus/user_bus_socket")
.arg(uid_min);
return QDBusConnection::connectToBus(sessionBusAddress, "userSessionBus");
}
}
......@@ -24,10 +24,11 @@
class QDBusConnection;
class SsuCoreConfig: public SsuSettings {
class SsuCoreConfig: public SsuSettings
{
Q_OBJECT
public:
public:
static SsuCoreConfig *instance();
/**
* Find a username/password pair for the given scope
......@@ -43,7 +44,7 @@ class SsuCoreConfig: public SsuSettings {
*
* @return a string containing the scope; it can be used to look up login credentials using credentials()
*/
QString credentialsScope(QString repoName, bool rndRepo=false);
QString credentialsScope(QString repoName, bool rndRepo = false);
/**
* Return the URL for which credentials scope is valid
*/
......@@ -63,7 +64,7 @@ class SsuCoreConfig: public SsuSettings {
* to print the domain name set pretty to true
* @return domain, or "" if not set
*/
Q_INVOKABLE QString domain(bool pretty=false);
Q_INVOKABLE QString domain(bool pretty = false);
/**
* Return devices RND registration status
* @retval true device is registered
......@@ -78,11 +79,11 @@ class SsuCoreConfig: public SsuSettings {
/**
* Return the release version string for either a release, or a RnD snapshot
*/
Q_INVOKABLE QString release(bool rnd=false);
Q_INVOKABLE QString release(bool rnd = false);
/**
* Set mode bits for the device
*/
Q_INVOKABLE void setDeviceMode(Ssu::DeviceModeFlags mode, enum Ssu::EditMode editMode=Ssu::Replace);
Q_INVOKABLE void setDeviceMode(Ssu::DeviceModeFlags mode, enum Ssu::EditMode editMode = Ssu::Replace);
/**
* Set the flavour used when resolving RND repositories
*/
......@@ -90,7 +91,7 @@ class SsuCoreConfig: public SsuSettings {
/**
* Set the release version string for either a release, or a RnD snapshot
*/
Q_INVOKABLE void setRelease(QString release, bool rnd=false);
Q_INVOKABLE void setRelease(QString release, bool rnd = false);
/**
* Set the domain string (usually something like nemo, jolla, ..)
*/
......@@ -107,9 +108,9 @@ class SsuCoreConfig: public SsuSettings {
static QDBusConnection userSessionBus();
private:
SsuCoreConfig(): SsuSettings(SSU_CONFIGURATION, QSettings::IniFormat, SSU_DEFAULT_CONFIGURATION) {};
SsuCoreConfig(const SsuCoreConfig &); // hide copy constructor
private:
SsuCoreConfig(): SsuSettings(SSU_CONFIGURATION, QSettings::IniFormat, SSU_DEFAULT_CONFIGURATION) {}
Q_DISABLE_COPY(SsuCoreConfig)
static SsuCoreConfig *ssuCoreConfig;
};
......
This diff is collapsed.
......@@ -14,14 +14,18 @@
class SsuSettings;
class SsuDeviceInfo: public QObject {
class SsuDeviceInfo: public QObject
{
Q_OBJECT
public:
public:
/**
* Initialize with device to override autodetection
*/
SsuDeviceInfo(QString model="");
SsuDeviceInfo(QString model = "");
virtual ~SsuDeviceInfo();
/**
* Return the list of adaptations used for the set model
*/
......@@ -36,7 +40,7 @@ class SsuDeviceInfo: public QObject {
* or as variant. If no model is provided as argument the autodetected or previously
* set model is used.
*/
bool contains(const QString &model="");
bool contains(const QString &model = "");
/**
* Try to find the device family for the system this is running on. This function
* temporarily changes the detected model, and therefore should not be used in a
......@@ -48,7 +52,7 @@ class SsuDeviceInfo: public QObject {
* If the device is not a variant it will return an empty string. If
* fallback is set to true it return the device model in this case.
*/
Q_INVOKABLE QString deviceVariant(bool fallback=false);
Q_INVOKABLE QString deviceVariant(bool fallback = false);
/**
* Try to find out ond what kind of system this is running
*/
......@@ -80,11 +84,11 @@ class SsuDeviceInfo: public QObject {
* only board-specific, or only user-specific are returned.
* Disabled repositories are excluded depending on filter settings.
*/
QStringList repos(bool rnd=false, int filter=Ssu::NoFilter);
QStringList repos(bool rnd = false, int filter = Ssu::NoFilter);
/**
* Override device model autodetection
*/
Q_INVOKABLE void setDeviceModel(QString model="");
Q_INVOKABLE void setDeviceModel(QString model = "");
/**
* Return a variable from the given variable section. 'var'- is automatically
* prepended to the section name if not specified already. Recursive search
......@@ -105,10 +109,10 @@ class SsuDeviceInfo: public QObject {
* dedicated device section the key from the device section will get
* returned, otherwise the one from the variant.
*/
QVariant value(const QString &key, const QVariant &value=QVariant());
QVariant value(const QString &key, const QVariant &value = QVariant());
private:
private:
SsuSettings *boardMappings;
QString cachedFamily, cachedModel, cachedVariant;
......
......@@ -18,8 +18,9 @@
#include "../constants.h"
SsuFeatureManager::SsuFeatureManager(): QObject() {
featureSettings = new SsuSettings(SSU_FEATURE_CONFIGURATION, SSU_FEATURE_CONFIGURATION_DIR);
SsuFeatureManager::SsuFeatureManager(): QObject()
{
featureSettings = new SsuSettings(SSU_FEATURE_CONFIGURATION, SSU_FEATURE_CONFIGURATION_DIR);
}
......@@ -30,41 +31,41 @@ SsuFeatureManager::SsuFeatureManager(): QObject() {
// all features have a list of repositories in the repos key
// if there are enabled/disabled features, check the repos keys from all enabled features
// and only enable the repositories from those
QStringList SsuFeatureManager::repos(bool rndRepo, int filter){
QStringList r;
QStringList keys;
SsuCoreConfig *settings = SsuCoreConfig::instance();
QStringList SsuFeatureManager::repos(bool rndRepo, int filter)
{
QStringList r;
// @TODO features currently can't be blacklisted, but just ignoring user filter
// is still the best way atm
if (filter == Ssu::UserFilter)
return r;
// @TODO features currently can't be blacklisted, but just ignoring user filter
// is still the best way atm
if (filter == Ssu::UserFilter)
return r;
QString repoHeader = QString("repositories-%1/")
.arg(rndRepo ? "rnd" : "release");
QString repoHeader = QString("repositories-%1/")
.arg(rndRepo ? "rnd" : "release");
// take the global groups
featureSettings->beginGroup("repositories");
r.append(featureSettings->allKeys());
featureSettings->endGroup();
// take the global groups
featureSettings->beginGroup("repositories");
r.append(featureSettings->allKeys());
featureSettings->endGroup();
// and override with rnd/release specific groups
featureSettings->beginGroup(repoHeader);
r.append(featureSettings->allKeys());
featureSettings->endGroup();
// and override with rnd/release specific groups
featureSettings->beginGroup(repoHeader);
r.append(featureSettings->allKeys());
featureSettings->endGroup();
r.removeDuplicates();
return r;
r.removeDuplicates();
return r;
}
QString SsuFeatureManager::url(QString repo, bool rndRepo){
QString repoHeader = QString("repositories-%1/")
.arg(rndRepo ? "rnd" : "release");
QString SsuFeatureManager::url(QString repo, bool rndRepo)
{
QString repoHeader = QString("repositories-%1/")
.arg(rndRepo ? "rnd" : "release");
if (featureSettings->contains(repoHeader + repo))
return featureSettings->value(repoHeader + repo).toString();
else if (featureSettings->contains("repositories/" + repo))
return featureSettings->value("repositories/" + repo).toString();
if (featureSettings->contains(repoHeader + repo))
return featureSettings->value