• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

kconf_update

  • sources
  • kde-4.14
  • kdelibs
  • kconf_update
kconf_update.cpp
Go to the documentation of this file.
1 /*
2  *
3  * This file is part of the KDE libraries
4  * Copyright (c) 2001 Waldo Bastian <bastian@kde.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License version 2 as published by the Free Software Foundation.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB. If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  **/
20 
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <kde_file.h>
26 
27 #include <QtCore/QDate>
28 #include <QtCore/QFile>
29 #include <QtCore/QTextStream>
30 #include <QtCore/QTextCodec>
31 #ifdef _WIN32_WCE
32 #include <QtCore/QDir>
33 #endif
34 
35 #include <kconfig.h>
36 #include <kconfiggroup.h>
37 #include <kdebug.h>
38 #include <klocale.h>
39 #include <kcmdlineargs.h>
40 #include <kglobal.h>
41 #include <kstandarddirs.h>
42 #include <kaboutdata.h>
43 #include <kcomponentdata.h>
44 #include <ktemporaryfile.h>
45 #include <kurl.h>
46 
47 #include "kconfigutils.h"
48 
49 class KonfUpdate
50 {
51 public:
52  KonfUpdate();
53  ~KonfUpdate();
54  QStringList findUpdateFiles(bool dirtyOnly);
55 
56  QTextStream &log();
57  QTextStream &logFileError();
58 
59  bool checkFile(const QString &filename);
60  void checkGotFile(const QString &_file, const QString &id);
61 
62  bool updateFile(const QString &filename);
63 
64  void gotId(const QString &_id);
65  void gotFile(const QString &_file);
66  void gotGroup(const QString &_group);
67  void gotRemoveGroup(const QString &_group);
68  void gotKey(const QString &_key);
69  void gotRemoveKey(const QString &_key);
70  void gotAllKeys();
71  void gotAllGroups();
72  void gotOptions(const QString &_options);
73  void gotScript(const QString &_script);
74  void gotScriptArguments(const QString &_arguments);
75  void resetOptions();
76 
77  void copyGroup(const KConfigBase *cfg1, const QString &group1,
78  KConfigBase *cfg2, const QString &group2);
79  void copyGroup(const KConfigGroup &cg1, KConfigGroup &cg2);
80  void copyOrMoveKey(const QStringList &srcGroupPath, const QString &srcKey, const QStringList &dstGroupPath, const QString &dstKey);
81  void copyOrMoveGroup(const QStringList &srcGroupPath, const QStringList &dstGroupPath);
82 
83  QStringList parseGroupString(const QString &_str);
84 
85 protected:
86  KConfig *m_config;
87  QString m_currentFilename;
88  bool m_skip;
89  bool m_skipFile;
90  bool m_debug;
91  QString m_id;
92 
93  QString m_oldFile;
94  QString m_newFile;
95  QString m_newFileName;
96  KConfig *m_oldConfig1; // Config to read keys from.
97  KConfig *m_oldConfig2; // Config to delete keys from.
98  KConfig *m_newConfig;
99 
100  QStringList m_oldGroup;
101  QStringList m_newGroup;
102 
103  bool m_bCopy;
104  bool m_bOverwrite;
105  bool m_bUseConfigInfo;
106  QString m_arguments;
107  QTextStream *m_textStream;
108  QFile *m_file;
109  QString m_line;
110  int m_lineCount;
111 };
112 
113 KonfUpdate::KonfUpdate()
114  : m_textStream(0), m_file(0)
115 {
116  bool updateAll = false;
117  m_oldConfig1 = 0;
118  m_oldConfig2 = 0;
119  m_newConfig = 0;
120 
121  m_config = new KConfig("kconf_updaterc");
122  KConfigGroup cg(m_config, QString());
123 
124  QStringList updateFiles;
125  KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
126 
127  m_debug = args->isSet("debug");
128 
129  m_bUseConfigInfo = false;
130  if (args->isSet("check")) {
131  m_bUseConfigInfo = true;
132  QString file = KStandardDirs::locate("data", "kconf_update/" + args->getOption("check"));
133  if (file.isEmpty()) {
134  qWarning("File '%s' not found.", args->getOption("check").toLocal8Bit().data());
135  log() << "File '" << args->getOption("check") << "' passed on command line not found" << endl;
136  return;
137  }
138  updateFiles.append(file);
139  } else if (args->count()) {
140  for (int i = 0; i < args->count(); i++) {
141  KUrl url = args->url(i);
142  if (!url.isLocalFile()) {
143  KCmdLineArgs::usageError(i18n("Only local files are supported."));
144  }
145  updateFiles.append(url.toLocalFile());
146  }
147  } else {
148  if (cg.readEntry("autoUpdateDisabled", false))
149  return;
150  updateFiles = findUpdateFiles(true);
151  updateAll = true;
152  }
153 
154  for (QStringList::ConstIterator it = updateFiles.constBegin();
155  it != updateFiles.constEnd();
156  ++it) {
157  updateFile(*it);
158  }
159 
160  if (updateAll && !cg.readEntry("updateInfoAdded", false)) {
161  cg.writeEntry("updateInfoAdded", true);
162  updateFiles = findUpdateFiles(false);
163 
164  for (QStringList::ConstIterator it = updateFiles.constBegin();
165  it != updateFiles.constEnd();
166  ++it) {
167  checkFile(*it);
168  }
169  updateFiles.clear();
170  }
171 }
172 
173 KonfUpdate::~KonfUpdate()
174 {
175  delete m_config;
176  delete m_file;
177  delete m_textStream;
178 }
179 
180 QTextStream & operator<<(QTextStream & stream, const QStringList & lst)
181 {
182  stream << lst.join(", ");
183  return stream;
184 }
185 
186 QTextStream &
187 KonfUpdate::log()
188 {
189  if (!m_textStream) {
190  QString file = KStandardDirs::locateLocal("data", "kconf_update/log/update.log");
191  m_file = new QFile(file);
192  if (m_file->open(QIODevice::WriteOnly | QIODevice::Append)) {
193  m_textStream = new QTextStream(m_file);
194  } else {
195  // Error
196  m_textStream = new QTextStream(stderr, QIODevice::WriteOnly);
197  }
198  }
199 
200  (*m_textStream) << QDateTime::currentDateTime().toString(Qt::ISODate) << " ";
201 
202  return *m_textStream;
203 }
204 
205 QTextStream &
206 KonfUpdate::logFileError()
207 {
208  return log() << m_currentFilename << ':' << m_lineCount << ":'" << m_line << "': ";
209 }
210 
211 QStringList KonfUpdate::findUpdateFiles(bool dirtyOnly)
212 {
213  QStringList result;
214  const QStringList list = KGlobal::dirs()->findAllResources("data", "kconf_update/*.upd",
215  KStandardDirs::NoDuplicates);
216  for (QStringList::ConstIterator it = list.constBegin();
217  it != list.constEnd();
218  ++it) {
219  QString file = *it;
220  KDE_struct_stat buff;
221  if (KDE::stat(file, &buff) == 0) {
222  int i = file.lastIndexOf('/');
223  if (i != -1) {
224  file = file.mid(i + 1);
225  }
226  KConfigGroup cg(m_config, file);
227  time_t ctime = cg.readEntry("ctime", 0);
228  time_t mtime = cg.readEntry("mtime", 0);
229  if (!dirtyOnly ||
230  (ctime != buff.st_ctime) || (mtime != buff.st_mtime)) {
231  result.append(*it);
232  }
233  }
234  }
235  return result;
236 }
237 
238 bool KonfUpdate::checkFile(const QString &filename)
239 {
240  m_currentFilename = filename;
241  int i = m_currentFilename.lastIndexOf('/');
242  if (i != -1) {
243  m_currentFilename = m_currentFilename.mid(i + 1);
244  }
245  m_skip = true;
246  QFile file(filename);
247  if (!file.open(QIODevice::ReadOnly)) {
248  return false;
249  }
250 
251  QTextStream ts(&file);
252  ts.setCodec(QTextCodec::codecForName("ISO-8859-1"));
253  int lineCount = 0;
254  resetOptions();
255  QString id;
256  while (!ts.atEnd()) {
257  QString line = ts.readLine().trimmed();
258  lineCount++;
259  if (line.isEmpty() || (line[0] == '#')) {
260  continue;
261  }
262  if (line.startsWith("Id=")) {
263  id = m_currentFilename + ':' + line.mid(3);
264  } else if (line.startsWith("File=")) {
265  checkGotFile(line.mid(5), id);
266  }
267  }
268 
269  return true;
270 }
271 
272 void KonfUpdate::checkGotFile(const QString &_file, const QString &id)
273 {
274  QString file;
275  int i = _file.indexOf(',');
276  if (i == -1) {
277  file = _file.trimmed();
278  } else {
279  file = _file.mid(i + 1).trimmed();
280  }
281 
282 // qDebug("File %s, id %s", file.toLatin1().constData(), id.toLatin1().constData());
283 
284  KConfig cfg(file, KConfig::SimpleConfig);
285  KConfigGroup cg(&cfg, "$Version");
286  QStringList ids = cg.readEntry("update_info", QStringList());
287  if (ids.contains(id)) {
288  return;
289  }
290  ids.append(id);
291  cg.writeEntry("update_info", ids);
292 }
293 
313 bool KonfUpdate::updateFile(const QString &filename)
314 {
315  m_currentFilename = filename;
316  int i = m_currentFilename.lastIndexOf('/');
317  if (i != -1) {
318  m_currentFilename = m_currentFilename.mid(i + 1);
319  }
320  m_skip = true;
321  QFile file(filename);
322  if (!file.open(QIODevice::ReadOnly)) {
323  return false;
324  }
325 
326  log() << "Checking update-file '" << filename << "' for new updates" << endl;
327 
328  QTextStream ts(&file);
329  ts.setCodec(QTextCodec::codecForName("ISO-8859-1"));
330  m_lineCount = 0;
331  resetOptions();
332  while (!ts.atEnd()) {
333  m_line = ts.readLine().trimmed();
334  m_lineCount++;
335  if (m_line.isEmpty() || (m_line[0] == '#')) {
336  continue;
337  }
338  if (m_line.startsWith(QLatin1String("Id="))) {
339  gotId(m_line.mid(3));
340  } else if (m_skip) {
341  continue;
342  } else if (m_line.startsWith(QLatin1String("Options="))) {
343  gotOptions(m_line.mid(8));
344  } else if (m_line.startsWith(QLatin1String("File="))) {
345  gotFile(m_line.mid(5));
346  } else if (m_skipFile) {
347  continue;
348  } else if (m_line.startsWith(QLatin1String("Group="))) {
349  gotGroup(m_line.mid(6));
350  } else if (m_line.startsWith(QLatin1String("RemoveGroup="))) {
351  gotRemoveGroup(m_line.mid(12));
352  resetOptions();
353  } else if (m_line.startsWith(QLatin1String("Script="))) {
354  gotScript(m_line.mid(7));
355  resetOptions();
356  } else if (m_line.startsWith(QLatin1String("ScriptArguments="))) {
357  gotScriptArguments(m_line.mid(16));
358  } else if (m_line.startsWith(QLatin1String("Key="))) {
359  gotKey(m_line.mid(4));
360  resetOptions();
361  } else if (m_line.startsWith(QLatin1String("RemoveKey="))) {
362  gotRemoveKey(m_line.mid(10));
363  resetOptions();
364  } else if (m_line == "AllKeys") {
365  gotAllKeys();
366  resetOptions();
367  } else if (m_line == "AllGroups") {
368  gotAllGroups();
369  resetOptions();
370  } else {
371  logFileError() << "Parse error" << endl;
372  }
373  }
374  // Flush.
375  gotId(QString());
376 
377  KDE_struct_stat buff;
378  if (KDE::stat(filename, &buff) == 0) {
379  KConfigGroup cg(m_config, m_currentFilename);
380  cg.writeEntry("ctime", int(buff.st_ctime));
381  cg.writeEntry("mtime", int(buff.st_mtime));
382  cg.sync();
383  }
384  return true;
385 }
386 
387 
388 
389 void KonfUpdate::gotId(const QString &_id)
390 {
391  if (!m_id.isEmpty() && !m_skip) {
392  KConfigGroup cg(m_config, m_currentFilename);
393 
394  QStringList ids = cg.readEntry("done", QStringList());
395  if (!ids.contains(m_id)) {
396  ids.append(m_id);
397  cg.writeEntry("done", ids);
398  cg.sync();
399  }
400  }
401 
402  // Flush pending changes
403  gotFile(QString());
404  KConfigGroup cg(m_config, m_currentFilename);
405 
406  QStringList ids = cg.readEntry("done", QStringList());
407  if (!_id.isEmpty()) {
408  if (ids.contains(_id)) {
409  //qDebug("Id '%s' was already in done-list", _id.toLatin1().constData());
410  if (!m_bUseConfigInfo) {
411  m_skip = true;
412  return;
413  }
414  }
415  m_skip = false;
416  m_skipFile = false;
417  m_id = _id;
418  if (m_bUseConfigInfo) {
419  log() << m_currentFilename << ": Checking update '" << _id << "'" << endl;
420  } else {
421  log() << m_currentFilename << ": Found new update '" << _id << "'" << endl;
422  }
423  }
424 }
425 
426 void KonfUpdate::gotFile(const QString &_file)
427 {
428  // Reset group
429  gotGroup(QString());
430 
431  if (!m_oldFile.isEmpty()) {
432  // Close old file.
433  delete m_oldConfig1;
434  m_oldConfig1 = 0;
435 
436  KConfigGroup cg(m_oldConfig2, "$Version");
437  QStringList ids = cg.readEntry("update_info", QStringList());
438  QString cfg_id = m_currentFilename + ':' + m_id;
439  if (!ids.contains(cfg_id) && !m_skip) {
440  ids.append(cfg_id);
441  cg.writeEntry("update_info", ids);
442  }
443  cg.sync();
444  delete m_oldConfig2;
445  m_oldConfig2 = 0;
446 
447  QString file = KStandardDirs::locateLocal("config", m_oldFile);
448  KDE_struct_stat s_buf;
449  if (KDE::stat(file, &s_buf) == 0) {
450  if (s_buf.st_size == 0) {
451  // Delete empty file.
452  QFile::remove(file);
453  }
454  }
455 
456  m_oldFile.clear();
457  }
458  if (!m_newFile.isEmpty()) {
459  // Close new file.
460  KConfigGroup cg(m_newConfig, "$Version");
461  QStringList ids = cg.readEntry("update_info", QStringList());
462  QString cfg_id = m_currentFilename + ':' + m_id;
463  if (!ids.contains(cfg_id) && !m_skip) {
464  ids.append(cfg_id);
465  cg.writeEntry("update_info", ids);
466  }
467  m_newConfig->sync();
468  delete m_newConfig;
469  m_newConfig = 0;
470 
471  m_newFile.clear();
472  }
473  m_newConfig = 0;
474 
475  int i = _file.indexOf(',');
476  if (i == -1) {
477  m_oldFile = _file.trimmed();
478  } else {
479  m_oldFile = _file.left(i).trimmed();
480  m_newFile = _file.mid(i + 1).trimmed();
481  if (m_oldFile == m_newFile) {
482  m_newFile.clear();
483  }
484  }
485 
486  if (!m_oldFile.isEmpty()) {
487  m_oldConfig2 = new KConfig(m_oldFile, KConfig::NoGlobals);
488  QString cfg_id = m_currentFilename + ':' + m_id;
489  KConfigGroup cg(m_oldConfig2, "$Version");
490  QStringList ids = cg.readEntry("update_info", QStringList());
491  if (ids.contains(cfg_id)) {
492  m_skip = true;
493  m_newFile.clear();
494  log() << m_currentFilename << ": Skipping update '" << m_id << "'" << endl;
495  }
496 
497  if (!m_newFile.isEmpty()) {
498  m_newConfig = new KConfig(m_newFile, KConfig::NoGlobals);
499  KConfigGroup cg(m_newConfig, "$Version");
500  ids = cg.readEntry("update_info", QStringList());
501  if (ids.contains(cfg_id)) {
502  m_skip = true;
503  log() << m_currentFilename << ": Skipping update '" << m_id << "'" << endl;
504  }
505  } else {
506  m_newConfig = m_oldConfig2;
507  }
508 
509  m_oldConfig1 = new KConfig(m_oldFile, KConfig::NoGlobals);
510  } else {
511  m_newFile.clear();
512  }
513  m_newFileName = m_newFile;
514  if (m_newFileName.isEmpty()) {
515  m_newFileName = m_oldFile;
516  }
517 
518  m_skipFile = false;
519  if (!m_oldFile.isEmpty()) { // if File= is specified, it doesn't exist, is empty or contains only kconf_update's [$Version] group, skip
520  if (m_oldConfig1 != NULL
521  && (m_oldConfig1->groupList().isEmpty()
522  || (m_oldConfig1->groupList().count() == 1 && m_oldConfig1->groupList().first() == "$Version"))) {
523  log() << m_currentFilename << ": File '" << m_oldFile << "' does not exist or empty, skipping" << endl;
524  m_skipFile = true;
525  }
526  }
527 }
528 
529 QStringList KonfUpdate::parseGroupString(const QString &str)
530 {
531  bool ok;
532  QString error;
533  QStringList lst = KConfigUtils::parseGroupString(str, &ok, &error);
534  if (!ok) {
535  logFileError() << error;
536  }
537  return lst;
538 }
539 
540 void KonfUpdate::gotGroup(const QString &_group)
541 {
542  QString group = _group.trimmed();
543  if (group.isEmpty()) {
544  m_oldGroup = m_newGroup = QStringList();
545  return;
546  }
547 
548  QStringList tokens = group.split(',');
549  m_oldGroup = parseGroupString(tokens.at(0));
550  if (tokens.count() == 1) {
551  m_newGroup = m_oldGroup;
552  } else {
553  m_newGroup = parseGroupString(tokens.at(1));
554  }
555 }
556 
557 void KonfUpdate::gotRemoveGroup(const QString &_group)
558 {
559  m_oldGroup = parseGroupString(_group);
560 
561  if (!m_oldConfig1) {
562  logFileError() << "RemoveGroup without previous File specification" << endl;
563  return;
564  }
565 
566  KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig2, m_oldGroup);
567  if (!cg.exists()) {
568  return;
569  }
570  // Delete group.
571  cg.deleteGroup();
572  log() << m_currentFilename << ": RemoveGroup removes group " << m_oldFile << ":" << m_oldGroup << endl;
573 }
574 
575 
576 void KonfUpdate::gotKey(const QString &_key)
577 {
578  QString oldKey, newKey;
579  int i = _key.indexOf(',');
580  if (i == -1) {
581  oldKey = _key.trimmed();
582  newKey = oldKey;
583  } else {
584  oldKey = _key.left(i).trimmed();
585  newKey = _key.mid(i + 1).trimmed();
586  }
587 
588  if (oldKey.isEmpty() || newKey.isEmpty()) {
589  logFileError() << "Key specifies invalid key" << endl;
590  return;
591  }
592  if (!m_oldConfig1) {
593  logFileError() << "Key without previous File specification" << endl;
594  return;
595  }
596  copyOrMoveKey(m_oldGroup, oldKey, m_newGroup, newKey);
597 }
598 
599 void KonfUpdate::copyOrMoveKey(const QStringList &srcGroupPath, const QString &srcKey, const QStringList &dstGroupPath, const QString &dstKey)
600 {
601  KConfigGroup dstCg = KConfigUtils::openGroup(m_newConfig, dstGroupPath);
602  if (!m_bOverwrite && dstCg.hasKey(dstKey)) {
603  log() << m_currentFilename << ": Skipping " << m_newFileName << ":" << dstCg.name() << ":" << dstKey << ", already exists." << endl;
604  return;
605  }
606 
607  KConfigGroup srcCg = KConfigUtils::openGroup(m_oldConfig1, srcGroupPath);
608  if (!srcCg.hasKey(srcKey))
609  return;
610  QString value = srcCg.readEntry(srcKey, QString());
611  log() << m_currentFilename << ": Updating " << m_newFileName << ":" << dstCg.name() << ":" << dstKey << " to '" << value << "'" << endl;
612  dstCg.writeEntry(dstKey, value);
613 
614  if (m_bCopy) {
615  return; // Done.
616  }
617 
618  // Delete old entry
619  if (m_oldConfig2 == m_newConfig
620  && srcGroupPath == dstGroupPath
621  && srcKey == dstKey) {
622  return; // Don't delete!
623  }
624  KConfigGroup srcCg2 = KConfigUtils::openGroup(m_oldConfig2, srcGroupPath);
625  srcCg2.deleteEntry(srcKey);
626  log() << m_currentFilename << ": Removing " << m_oldFile << ":" << srcCg2.name() << ":" << srcKey << ", moved." << endl;
627 }
628 
629 void KonfUpdate::copyOrMoveGroup(const QStringList &srcGroupPath, const QStringList &dstGroupPath)
630 {
631  KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig1, srcGroupPath);
632 
633  // Keys
634  Q_FOREACH(const QString &key, cg.keyList()) {
635  copyOrMoveKey(srcGroupPath, key, dstGroupPath, key);
636  }
637 
638  // Subgroups
639  Q_FOREACH(const QString &group, cg.groupList()) {
640  QStringList groupPath = QStringList() << group;
641  copyOrMoveGroup(srcGroupPath + groupPath, dstGroupPath + groupPath);
642  }
643 }
644 
645 void KonfUpdate::gotRemoveKey(const QString &_key)
646 {
647  QString key = _key.trimmed();
648 
649  if (key.isEmpty()) {
650  logFileError() << "RemoveKey specifies invalid key" << endl;
651  return;
652  }
653 
654  if (!m_oldConfig1) {
655  logFileError() << "Key without previous File specification" << endl;
656  return;
657  }
658 
659  KConfigGroup cg1 = KConfigUtils::openGroup(m_oldConfig1, m_oldGroup);
660  if (!cg1.hasKey(key)) {
661  return;
662  }
663  log() << m_currentFilename << ": RemoveKey removes " << m_oldFile << ":" << m_oldGroup << ":" << key << endl;
664 
665  // Delete old entry
666  KConfigGroup cg2 = KConfigUtils::openGroup(m_oldConfig2, m_oldGroup);
667  cg2.deleteEntry(key);
668  /*if (m_oldConfig2->deleteGroup(m_oldGroup, KConfig::Normal)) { // Delete group if empty.
669  log() << m_currentFilename << ": Removing empty group " << m_oldFile << ":" << m_oldGroup << endl;
670  } (this should be automatic)*/
671 }
672 
673 void KonfUpdate::gotAllKeys()
674 {
675  if (!m_oldConfig1) {
676  logFileError() << "AllKeys without previous File specification" << endl;
677  return;
678  }
679 
680  copyOrMoveGroup(m_oldGroup, m_newGroup);
681 }
682 
683 void KonfUpdate::gotAllGroups()
684 {
685  if (!m_oldConfig1) {
686  logFileError() << "AllGroups without previous File specification" << endl;
687  return;
688  }
689 
690  const QStringList allGroups = m_oldConfig1->groupList();
691  for (QStringList::ConstIterator it = allGroups.begin();
692  it != allGroups.end(); ++it) {
693  m_oldGroup = QStringList() << *it;
694  m_newGroup = m_oldGroup;
695  gotAllKeys();
696  }
697 }
698 
699 void KonfUpdate::gotOptions(const QString &_options)
700 {
701  const QStringList options = _options.split(',');
702  for (QStringList::ConstIterator it = options.begin();
703  it != options.end();
704  ++it) {
705  if ((*it).toLower().trimmed() == "copy") {
706  m_bCopy = true;
707  }
708 
709  if ((*it).toLower().trimmed() == "overwrite") {
710  m_bOverwrite = true;
711  }
712  }
713 }
714 
715 void KonfUpdate::copyGroup(const KConfigBase *cfg1, const QString &group1,
716  KConfigBase *cfg2, const QString &group2)
717 {
718  KConfigGroup cg1(cfg1, group1);
719  KConfigGroup cg2(cfg2, group2);
720  copyGroup(cg1, cg2);
721 }
722 
723 void KonfUpdate::copyGroup(const KConfigGroup &cg1, KConfigGroup &cg2)
724 {
725  // Copy keys
726  QMap<QString, QString> list = cg1.entryMap();
727  for (QMap<QString, QString>::ConstIterator it = list.constBegin();
728  it != list.constEnd(); ++it) {
729  if (m_bOverwrite || !cg2.hasKey(it.key())) {
730  cg2.writeEntry(it.key(), it.value());
731  }
732  }
733 
734  // Copy subgroups
735  Q_FOREACH(const QString &group, cg1.groupList()) {
736  copyGroup(&cg1, group, &cg2, group);
737  }
738 }
739 
740 void KonfUpdate::gotScriptArguments(const QString &_arguments)
741 {
742  m_arguments = _arguments;
743 }
744 
745 void KonfUpdate::gotScript(const QString &_script)
746 {
747  QString script, interpreter;
748  int i = _script.indexOf(',');
749  if (i == -1) {
750  script = _script.trimmed();
751  } else {
752  script = _script.left(i).trimmed();
753  interpreter = _script.mid(i + 1).trimmed();
754  }
755 
756 
757  if (script.isEmpty()) {
758  logFileError() << "Script fails to specify filename";
759  m_skip = true;
760  return;
761  }
762 
763 
764 
765  QString path = KStandardDirs::locate("data", "kconf_update/" + script);
766  if (path.isEmpty()) {
767  if (interpreter.isEmpty()) {
768  path = KStandardDirs::locate("lib", "kconf_update_bin/" + script);
769  }
770 
771  if (path.isEmpty()) {
772  logFileError() << "Script '" << script << "' not found" << endl;
773  m_skip = true;
774  return;
775  }
776  }
777 
778  if (!m_arguments.isNull()) {
779  log() << m_currentFilename << ": Running script '" << script << "' with arguments '" << m_arguments << "'" << endl;
780  } else {
781  log() << m_currentFilename << ": Running script '" << script << "'" << endl;
782  }
783 
784  QString cmd;
785  if (interpreter.isEmpty()) {
786  cmd = path;
787  } else {
788  cmd = interpreter + ' ' + path;
789  }
790 
791  if (!m_arguments.isNull()) {
792  cmd += ' ';
793  cmd += m_arguments;
794  }
795 
796  KTemporaryFile scriptIn;
797  scriptIn.open();
798  KTemporaryFile scriptOut;
799  scriptOut.open();
800  KTemporaryFile scriptErr;
801  scriptErr.open();
802 
803  int result;
804  if (m_oldConfig1) {
805  if (m_debug) {
806  scriptIn.setAutoRemove(false);
807  log() << "Script input stored in " << scriptIn.fileName() << endl;
808  }
809  KConfig cfg(scriptIn.fileName(), KConfig::SimpleConfig);
810 
811  if (m_oldGroup.isEmpty()) {
812  // Write all entries to tmpFile;
813  const QStringList grpList = m_oldConfig1->groupList();
814  for (QStringList::ConstIterator it = grpList.begin();
815  it != grpList.end();
816  ++it) {
817  copyGroup(m_oldConfig1, *it, &cfg, *it);
818  }
819  } else {
820  KConfigGroup cg1 = KConfigUtils::openGroup(m_oldConfig1, m_oldGroup);
821  KConfigGroup cg2(&cfg, QString());
822  copyGroup(cg1, cg2);
823  }
824  cfg.sync();
825 #ifndef _WIN32_WCE
826  result = system(QFile::encodeName(QString("%1 < %2 > %3 2> %4").arg(cmd, scriptIn.fileName(), scriptOut.fileName(), scriptErr.fileName())));
827 #else
828  QString path_ = QDir::convertSeparators ( QFileInfo ( cmd ).absoluteFilePath() );
829  QString file_ = QFileInfo ( cmd ).fileName();
830  SHELLEXECUTEINFO execInfo;
831  memset ( &execInfo,0,sizeof ( execInfo ) );
832  execInfo.cbSize = sizeof ( execInfo );
833  execInfo.fMask = SEE_MASK_FLAG_NO_UI;
834  execInfo.lpVerb = L"open";
835  execInfo.lpFile = (LPCWSTR) path_.utf16();
836  execInfo.lpDirectory = (LPCWSTR) file_.utf16();
837  execInfo.lpParameters = (LPCWSTR) QString(" < %1 > %2 2> %3").arg( scriptIn.fileName(), scriptOut.fileName(), scriptErr.fileName()).utf16();
838  result = ShellExecuteEx ( &execInfo );
839  if (result != 0)
840  {
841  result = 0;
842  }
843  else
844  {
845  result = -1;
846  }
847 #endif
848  } else {
849  // No config file
850 #ifndef _WIN32_WCE
851  result = system(QFile::encodeName(QString("%1 2> %2").arg(cmd, scriptErr.fileName())));
852 #else
853  QString path_ = QDir::convertSeparators ( QFileInfo ( cmd ).absoluteFilePath() );
854  QString file_ = QFileInfo ( cmd ).fileName();
855  SHELLEXECUTEINFO execInfo;
856  memset ( &execInfo,0,sizeof ( execInfo ) );
857  execInfo.cbSize = sizeof ( execInfo );
858  execInfo.fMask = SEE_MASK_FLAG_NO_UI;
859  execInfo.lpVerb = L"open";
860  execInfo.lpFile = (LPCWSTR) path_.utf16();
861  execInfo.lpDirectory = (LPCWSTR) file_.utf16();
862  execInfo.lpParameters = (LPCWSTR) QString(" 2> %1").arg( scriptErr.fileName()).utf16();
863  result = ShellExecuteEx ( &execInfo );
864  if (result != 0)
865  {
866  result = 0;
867  }
868  else
869  {
870  result = -1;
871  }
872 #endif
873  }
874 
875  // Copy script stderr to log file
876  {
877  QFile output(scriptErr.fileName());
878  if (output.open(QIODevice::ReadOnly)) {
879  QTextStream ts(&output);
880  ts.setCodec(QTextCodec::codecForName("UTF-8"));
881  while (!ts.atEnd()) {
882  QString line = ts.readLine();
883  log() << "[Script] " << line << endl;
884  }
885  }
886  }
887 
888  if (result) {
889  log() << m_currentFilename << ": !! An error occurred while running '" << cmd << "'" << endl;
890  return;
891  }
892 
893  if (!m_oldConfig1) {
894  return; // Nothing to merge
895  }
896 
897  if (m_debug) {
898  scriptOut.setAutoRemove(false);
899  log() << "Script output stored in " << scriptOut.fileName() << endl;
900  }
901 
902  // Deleting old entries
903  {
904  QStringList group = m_oldGroup;
905  QFile output(scriptOut.fileName());
906  if (output.open(QIODevice::ReadOnly)) {
907  QTextStream ts(&output);
908  ts.setCodec(QTextCodec::codecForName("UTF-8"));
909  while (!ts.atEnd()) {
910  QString line = ts.readLine();
911  if (line.startsWith('[')) {
912  group = parseGroupString(line);
913  } else if (line.startsWith(QLatin1String("# DELETE "))) {
914  QString key = line.mid(9);
915  if (key[0] == '[') {
916  int j = key.lastIndexOf(']') + 1;
917  if (j > 0) {
918  group = parseGroupString(key.left(j));
919  key = key.mid(j);
920  }
921  }
922  KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig2, group);
923  cg.deleteEntry(key);
924  log() << m_currentFilename << ": Script removes " << m_oldFile << ":" << group << ":" << key << endl;
925  /*if (m_oldConfig2->deleteGroup(group, KConfig::Normal)) { // Delete group if empty.
926  log() << m_currentFilename << ": Removing empty group " << m_oldFile << ":" << group << endl;
927  } (this should be automatic)*/
928  } else if (line.startsWith(QLatin1String("# DELETEGROUP"))) {
929  QString str = line.mid(13).trimmed();
930  if (!str.isEmpty()) {
931  group = parseGroupString(str);
932  }
933  KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig2, group);
934  cg.deleteGroup();
935  log() << m_currentFilename << ": Script removes group " << m_oldFile << ":" << group << endl;
936  }
937  }
938  }
939  }
940 
941  // Merging in new entries.
942  KConfig scriptOutConfig(scriptOut.fileName(), KConfig::NoGlobals);
943  if (m_newGroup.isEmpty()) {
944  // Copy "default" keys as members of "default" keys
945  copyGroup(&scriptOutConfig, QString(), m_newConfig, QString());
946  } else {
947  // Copy default keys as members of m_newGroup
948  KConfigGroup srcCg = KConfigUtils::openGroup(&scriptOutConfig, QStringList());
949  KConfigGroup dstCg = KConfigUtils::openGroup(m_newConfig, m_newGroup);
950  copyGroup(srcCg, dstCg);
951  }
952  Q_FOREACH(const QString &group, scriptOutConfig.groupList()) {
953  copyGroup(&scriptOutConfig, group, m_newConfig, group);
954  }
955 }
956 
957 void KonfUpdate::resetOptions()
958 {
959  m_bCopy = false;
960  m_bOverwrite = false;
961  m_arguments.clear();
962 }
963 
964 
965 extern "C" KDE_EXPORT int kdemain(int argc, char **argv)
966 {
967  KCmdLineOptions options;
968  options.add("debug", ki18n("Keep output results from scripts"));
969  options.add("check <update-file>", ki18n("Check whether config file itself requires updating"));
970  options.add("+[file]", ki18n("File to read update instructions from"));
971 
972  KAboutData aboutData("kconf_update", 0, ki18n("KConf Update"),
973  "1.0.2",
974  ki18n("KDE Tool for updating user configuration files"),
975  KAboutData::License_GPL,
976  ki18n("(c) 2001, Waldo Bastian"));
977 
978  aboutData.addAuthor(ki18n("Waldo Bastian"), KLocalizedString(), "bastian@kde.org");
979 
980  KCmdLineArgs::init(argc, argv, &aboutData);
981  KCmdLineArgs::addCmdLineOptions(options);
982 
983  KComponentData componentData(&aboutData);
984 
985  KonfUpdate konfUpdate;
986 
987  return 0;
988 }
QList::clear
void clear()
QDateTime::toString
QString toString(Qt::DateFormat format) const
QString::indexOf
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
KConfigUtils::parseGroupString
QStringList parseGroupString(const QString &_str, bool *ok, QString *error)
Definition: kconfigutils.cpp:49
operator<<
QTextStream & operator<<(QTextStream &stream, const QStringList &lst)
Definition: kconf_update.cpp:180
QFile::remove
bool remove()
QString::split
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
QDir::convertSeparators
QString convertSeparators(const QString &pathName)
QMap::constBegin
const_iterator constBegin() const
QList::at
const T & at(int i) const
QMap
QStringList::contains
bool contains(const QString &str, Qt::CaseSensitivity cs) const
kconfigutils.h
QStringList::join
QString join(const QString &separator) const
QFile
QTextStream
QString::lastIndexOf
int lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
QString::clear
void clear()
QList::count
int count(const T &value) const
QList::append
void append(const T &value)
QFileInfo::fileName
QString fileName() const
QString::isEmpty
bool isEmpty() const
QString::trimmed
QString trimmed() const
QMap::constEnd
const_iterator constEnd() const
QString::startsWith
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
kdemain
int kdemain(int argc, char **argv)
Definition: kconf_update.cpp:965
QString
QStringList
QFileInfo
QList::end
iterator end()
QDateTime::currentDateTime
QDateTime currentDateTime()
QString::utf16
const ushort * utf16() const
QString::mid
QString mid(int position, int n) const
QLatin1String
QTextCodec::codecForName
QTextCodec * codecForName(const QByteArray &name)
QList::ConstIterator
typedef ConstIterator
KConfigUtils::openGroup
KConfigGroup openGroup(KConfig *config, const QStringList &_lst)
Definition: kconfigutils.cpp:36
QString::left
QString left(int n) const
QList::constEnd
const_iterator constEnd() const
QList::constBegin
const_iterator constBegin() const
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QList::begin
iterator begin()
QFile::encodeName
QByteArray encodeName(const QString &fileName)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:22:06 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kconf_update

Skip menu "kconf_update"
  • Main Page
  • Namespace List
  • Namespace Members
  • File List
  • File Members
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal