ssu
ssusettings.cpp
Go to the documentation of this file.
1 
8 #include <QStringList>
9 #include <QDirIterator>
10 #include <QFileInfo>
11 #include <QDateTime>
12 
13 #include "sandbox_p.h"
14 #include "ssusettings_p.h"
15 #include "ssulog_p.h"
16 
17 SsuSettings::SsuSettings()
18  : QSettings()
19 {
20 }
21 
22 SsuSettings::SsuSettings(const QString &fileName, Format format, QObject *parent)
23  : QSettings(Sandbox::map(fileName), format, parent)
24 {
25 }
26 
27 SsuSettings::SsuSettings(const QString &fileName, Format format, const QString &defaultFileName, QObject *parent)
28  : QSettings(Sandbox::map(fileName), format, parent)
29 {
30  defaultSettingsFile = Sandbox::map(defaultFileName);
31  upgrade();
32 }
33 
34 SsuSettings::SsuSettings(const QString &fileName, const QString &settingsDirectory, QObject *parent)
35  : QSettings(Sandbox::map(fileName), QSettings::IniFormat, parent)
36 {
37  settingsd = Sandbox::map(settingsDirectory);
38  merge();
39 }
40 
41 void SsuSettings::merge(bool keepOld)
42 {
43  if (settingsd.isEmpty())
44  return;
45 
46  bool skipMerge = true;
47 
48  QDirIterator it(settingsd, QDir::AllEntries | QDir::NoDot | QDir::NoDotDot, QDirIterator::FollowSymlinks);
49  QStringList settingsFiles;
50 
51  QFileInfo oldSettingsInfo(fileName());
52 
53  while (it.hasNext()) {
54  QString f = it.next();
55 
56  settingsFiles.append(it.filePath());
57 
58  QFileInfo info(it.filePath());
59  if (info.lastModified() >= oldSettingsInfo.lastModified())
60  skipMerge = false;
61  }
62 
63  if (skipMerge) {
64  // systemd journal does not seem to allow selective loglevels for different services, disabling for now
65  //ssuLog->print(LOG_DEBUG, QString("Configuration file is newer than all config.d files, skipping merge"));
66  return;
67  }
68 
69  settingsFiles.sort();
70 
71  // delete all keys in the cached settings
72  if (settingsFiles.count() > 0 && !keepOld)
73  clear();
74 
75  merge(this, settingsFiles);
76  sync();
77 }
78 
79 void SsuSettings::merge(QSettings *masterSettings, const QStringList &settingsFiles)
80 {
81  SsuLog *ssuLog = SsuLog::instance();
82 
83  foreach (const QString &settingsFile, settingsFiles) {
84  QSettings settings(settingsFile, QSettings::IniFormat);
85  QStringList groups = settings.childGroups();
86 
87  ssuLog->print(LOG_DEBUG, QString("Merging %1 into %2")
88  .arg(settingsFile)
89  .arg(masterSettings->fileName()));
90 
91  foreach (const QString &group, groups) {
92  masterSettings->beginGroup(group);
93  settings.beginGroup(group);
94 
95  QStringList keys = settings.allKeys();
96  foreach (const QString &key, keys) {
97  masterSettings->setValue(key, settings.value(key));
98  }
99 
100  settings.endGroup();
101  masterSettings->endGroup();
102  }
103  }
104 }
105 
106 /*
107  * If you change anything here, run `make update-upgrade-test-recipe` inside
108  * tests/ut_settings/ and check the impact of your changes with
109  * `git diff testdata/upgrade/recipe`. See ut_settings/upgradetesthelper.cpp for
110  * more details.
111  */
112 void SsuSettings::upgrade()
113 {
114  if (defaultSettingsFile.isEmpty())
115  return;
116 
117  int configVersion = 0;
118  int defaultConfigVersion = 0;
119 
120  SsuLog *ssuLog = SsuLog::instance();
121 
122  QSettings defaultSettings(defaultSettingsFile, QSettings::IniFormat);
123 
124  if (contains("configVersion"))
125  configVersion = value("configVersion").toInt();
126  if (defaultSettings.contains("configVersion"))
127  defaultConfigVersion = defaultSettings.value("configVersion").toInt();
128 
129  if (configVersion < defaultConfigVersion) {
130  ssuLog->print(LOG_DEBUG, QString("Configuration is outdated, updating from %1 to %2")
131  .arg(configVersion)
132  .arg(defaultConfigVersion));
133 
134  for (int i = configVersion + 1; i <= defaultConfigVersion; i++) {
135  QString currentSection = QString("%1/").arg(i);
136 
137  ssuLog->print(LOG_DEBUG, QString("Processing configuration version %1").arg(i));
138  defaultSettings.beginGroup(currentSection);
139  QStringList defaultKeys = defaultSettings.allKeys();
140  defaultSettings.endGroup();
141 
142  foreach (const QString &key, defaultKeys) {
143  // Default keys support both commands and new keys
144  if (key.compare("cmd-remove", Qt::CaseSensitive) == 0) {
145  // Remove keys listed in value as string list
146  QStringList oldKeys = defaultSettings.value(currentSection + key).toStringList();
147  foreach (const QString &oldKey, oldKeys) {
148  if (contains(oldKey)) {
149  remove(oldKey);
150  ssuLog->print(LOG_DEBUG, QString("Removing old key: %1").arg(oldKey));
151  }
152  }
153  } else if (!contains(key)) {
154  // Add new keys..
155  setValue(key, defaultSettings.value(currentSection + key));
156  ssuLog->print(LOG_DEBUG, QString("Adding key: %1").arg(key));
157  } else {
158  // ... or update the ones where default values has changed.
159  QVariant oldValue;
160 
161  // check if an old value exists in an older configuration version
162  for (int j = i - 1; j > 0; j--) {
163  if (defaultSettings.contains(QString("%1/").arg(j) + key)) {
164  oldValue = defaultSettings.value(QString("%1/").arg(j) + key);
165  break;
166  }
167  }
168 
169  // skip updating if there is no old value, since we can't check if the
170  // default value has changed
171  if (oldValue.isNull())
172  continue;
173 
174  QVariant newValue = defaultSettings.value(currentSection + key);
175  if (oldValue == newValue) {
176  // old and new value match, no need to do anything, apart from beating the
177  // person who added a useless key
178  continue;
179  } else {
180  // default value has changed, so check if the configuration is still
181  // using the old default value...
182  QVariant currentValue = value(key);
183  // testcase: handles properly default update of thing with changed value in ssu.ini?
184  if (currentValue == oldValue) {
185  // ...and update the key if it does
186  setValue(key, newValue);
187  ssuLog->print(LOG_DEBUG, QString("Updating %1 from %2 to %3")
188  .arg(key)
189  .arg(currentValue.toString())
190  .arg(newValue.toString()));
191  }
192  }
193  }
194  }
195  setValue("configVersion", i);
196  }
197  sync();
198  }
199 }
SsuLog
Definition: ssulog_p.h:15
Sandbox
Helps to redirect file operations into sandbox directory.
Definition: sandbox_p.h:21
SsuLog::print
void print(int priority, const QString &message)
Definition: ssulog.cpp:27
sandbox_p.h
ssusettings_p.h
ssulog_p.h