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

kconf_update

  • 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  KDE::stat(filename, &buff);
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  return true;
384 }
385 
386 
387 
388 void KonfUpdate::gotId(const QString &_id)
389 {
390  if (!m_id.isEmpty() && !m_skip) {
391  KConfigGroup cg(m_config, m_currentFilename);
392 
393  QStringList ids = cg.readEntry("done", QStringList());
394  if (!ids.contains(m_id)) {
395  ids.append(m_id);
396  cg.writeEntry("done", ids);
397  cg.sync();
398  }
399  }
400 
401  // Flush pending changes
402  gotFile(QString());
403  KConfigGroup cg(m_config, m_currentFilename);
404 
405  QStringList ids = cg.readEntry("done", QStringList());
406  if (!_id.isEmpty()) {
407  if (ids.contains(_id)) {
408  //qDebug("Id '%s' was already in done-list", _id.toLatin1().constData());
409  if (!m_bUseConfigInfo) {
410  m_skip = true;
411  return;
412  }
413  }
414  m_skip = false;
415  m_skipFile = false;
416  m_id = _id;
417  if (m_bUseConfigInfo) {
418  log() << m_currentFilename << ": Checking update '" << _id << "'" << endl;
419  } else {
420  log() << m_currentFilename << ": Found new update '" << _id << "'" << endl;
421  }
422  }
423 }
424 
425 void KonfUpdate::gotFile(const QString &_file)
426 {
427  // Reset group
428  gotGroup(QString());
429 
430  if (!m_oldFile.isEmpty()) {
431  // Close old file.
432  delete m_oldConfig1;
433  m_oldConfig1 = 0;
434 
435  KConfigGroup cg(m_oldConfig2, "$Version");
436  QStringList ids = cg.readEntry("update_info", QStringList());
437  QString cfg_id = m_currentFilename + ':' + m_id;
438  if (!ids.contains(cfg_id) && !m_skip) {
439  ids.append(cfg_id);
440  cg.writeEntry("update_info", ids);
441  }
442  cg.sync();
443  delete m_oldConfig2;
444  m_oldConfig2 = 0;
445 
446  QString file = KStandardDirs::locateLocal("config", m_oldFile);
447  KDE_struct_stat s_buf;
448  if (KDE::stat(file, &s_buf) == 0) {
449  if (s_buf.st_size == 0) {
450  // Delete empty file.
451  QFile::remove(file);
452  }
453  }
454 
455  m_oldFile.clear();
456  }
457  if (!m_newFile.isEmpty()) {
458  // Close new file.
459  KConfigGroup cg(m_newConfig, "$Version");
460  QStringList ids = cg.readEntry("update_info", QStringList());
461  QString cfg_id = m_currentFilename + ':' + m_id;
462  if (!ids.contains(cfg_id) && !m_skip) {
463  ids.append(cfg_id);
464  cg.writeEntry("update_info", ids);
465  }
466  m_newConfig->sync();
467  delete m_newConfig;
468  m_newConfig = 0;
469 
470  m_newFile.clear();
471  }
472  m_newConfig = 0;
473 
474  int i = _file.indexOf(',');
475  if (i == -1) {
476  m_oldFile = _file.trimmed();
477  } else {
478  m_oldFile = _file.left(i).trimmed();
479  m_newFile = _file.mid(i + 1).trimmed();
480  if (m_oldFile == m_newFile) {
481  m_newFile.clear();
482  }
483  }
484 
485  if (!m_oldFile.isEmpty()) {
486  m_oldConfig2 = new KConfig(m_oldFile, KConfig::NoGlobals);
487  QString cfg_id = m_currentFilename + ':' + m_id;
488  KConfigGroup cg(m_oldConfig2, "$Version");
489  QStringList ids = cg.readEntry("update_info", QStringList());
490  if (ids.contains(cfg_id)) {
491  m_skip = true;
492  m_newFile.clear();
493  log() << m_currentFilename << ": Skipping update '" << m_id << "'" << endl;
494  }
495 
496  if (!m_newFile.isEmpty()) {
497  m_newConfig = new KConfig(m_newFile, KConfig::NoGlobals);
498  KConfigGroup cg(m_newConfig, "$Version");
499  ids = cg.readEntry("update_info", QStringList());
500  if (ids.contains(cfg_id)) {
501  m_skip = true;
502  log() << m_currentFilename << ": Skipping update '" << m_id << "'" << endl;
503  }
504  } else {
505  m_newConfig = m_oldConfig2;
506  }
507 
508  m_oldConfig1 = new KConfig(m_oldFile, KConfig::NoGlobals);
509  } else {
510  m_newFile.clear();
511  }
512  m_newFileName = m_newFile;
513  if (m_newFileName.isEmpty()) {
514  m_newFileName = m_oldFile;
515  }
516 
517  m_skipFile = false;
518  if (!m_oldFile.isEmpty()) { // if File= is specified, it doesn't exist, is empty or contains only kconf_update's [$Version] group, skip
519  if (m_oldConfig1 != NULL
520  && (m_oldConfig1->groupList().isEmpty()
521  || (m_oldConfig1->groupList().count() == 1 && m_oldConfig1->groupList().first() == "$Version"))) {
522  log() << m_currentFilename << ": File '" << m_oldFile << "' does not exist or empty, skipping" << endl;
523  m_skipFile = true;
524  }
525  }
526 }
527 
528 QStringList KonfUpdate::parseGroupString(const QString &str)
529 {
530  bool ok;
531  QString error;
532  QStringList lst = KConfigUtils::parseGroupString(str, &ok, &error);
533  if (!ok) {
534  logFileError() << error;
535  }
536  return lst;
537 }
538 
539 void KonfUpdate::gotGroup(const QString &_group)
540 {
541  QString group = _group.trimmed();
542  if (group.isEmpty()) {
543  m_oldGroup = m_newGroup = QStringList();
544  return;
545  }
546 
547  QStringList tokens = group.split(',');
548  m_oldGroup = parseGroupString(tokens.at(0));
549  if (tokens.count() == 1) {
550  m_newGroup = m_oldGroup;
551  } else {
552  m_newGroup = parseGroupString(tokens.at(1));
553  }
554 }
555 
556 void KonfUpdate::gotRemoveGroup(const QString &_group)
557 {
558  m_oldGroup = parseGroupString(_group);
559 
560  if (!m_oldConfig1) {
561  logFileError() << "RemoveGroup without previous File specification" << endl;
562  return;
563  }
564 
565  KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig2, m_oldGroup);
566  if (!cg.exists()) {
567  return;
568  }
569  // Delete group.
570  cg.deleteGroup();
571  log() << m_currentFilename << ": RemoveGroup removes group " << m_oldFile << ":" << m_oldGroup << endl;
572 }
573 
574 
575 void KonfUpdate::gotKey(const QString &_key)
576 {
577  QString oldKey, newKey;
578  int i = _key.indexOf(',');
579  if (i == -1) {
580  oldKey = _key.trimmed();
581  newKey = oldKey;
582  } else {
583  oldKey = _key.left(i).trimmed();
584  newKey = _key.mid(i + 1).trimmed();
585  }
586 
587  if (oldKey.isEmpty() || newKey.isEmpty()) {
588  logFileError() << "Key specifies invalid key" << endl;
589  return;
590  }
591  if (!m_oldConfig1) {
592  logFileError() << "Key without previous File specification" << endl;
593  return;
594  }
595  copyOrMoveKey(m_oldGroup, oldKey, m_newGroup, newKey);
596 }
597 
598 void KonfUpdate::copyOrMoveKey(const QStringList &srcGroupPath, const QString &srcKey, const QStringList &dstGroupPath, const QString &dstKey)
599 {
600  KConfigGroup dstCg = KConfigUtils::openGroup(m_newConfig, dstGroupPath);
601  if (!m_bOverwrite && dstCg.hasKey(dstKey)) {
602  log() << m_currentFilename << ": Skipping " << m_newFileName << ":" << dstCg.name() << ":" << dstKey << ", already exists." << endl;
603  return;
604  }
605 
606  KConfigGroup srcCg = KConfigUtils::openGroup(m_oldConfig1, srcGroupPath);
607  QString value = srcCg.readEntry(srcKey, QString());
608  log() << m_currentFilename << ": Updating " << m_newFileName << ":" << dstCg.name() << ":" << dstKey << " to '" << value << "'" << endl;
609  dstCg.writeEntry(dstKey, value);
610 
611  if (m_bCopy) {
612  return; // Done.
613  }
614 
615  // Delete old entry
616  if (m_oldConfig2 == m_newConfig
617  && srcGroupPath == dstGroupPath
618  && srcKey == dstKey) {
619  return; // Don't delete!
620  }
621  KConfigGroup srcCg2 = KConfigUtils::openGroup(m_oldConfig2, srcGroupPath);
622  srcCg2.deleteEntry(srcKey);
623  log() << m_currentFilename << ": Removing " << m_oldFile << ":" << srcCg2.name() << ":" << srcKey << ", moved." << endl;
624 }
625 
626 void KonfUpdate::copyOrMoveGroup(const QStringList &srcGroupPath, const QStringList &dstGroupPath)
627 {
628  KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig1, srcGroupPath);
629 
630  // Keys
631  Q_FOREACH(const QString &key, cg.keyList()) {
632  copyOrMoveKey(srcGroupPath, key, dstGroupPath, key);
633  }
634 
635  // Subgroups
636  Q_FOREACH(const QString &group, cg.groupList()) {
637  QStringList groupPath = QStringList() << group;
638  copyOrMoveGroup(srcGroupPath + groupPath, dstGroupPath + groupPath);
639  }
640 }
641 
642 void KonfUpdate::gotRemoveKey(const QString &_key)
643 {
644  QString key = _key.trimmed();
645 
646  if (key.isEmpty()) {
647  logFileError() << "RemoveKey specifies invalid key" << endl;
648  return;
649  }
650 
651  if (!m_oldConfig1) {
652  logFileError() << "Key without previous File specification" << endl;
653  return;
654  }
655 
656  KConfigGroup cg1 = KConfigUtils::openGroup(m_oldConfig1, m_oldGroup);
657  if (!cg1.hasKey(key)) {
658  return;
659  }
660  log() << m_currentFilename << ": RemoveKey removes " << m_oldFile << ":" << m_oldGroup << ":" << key << endl;
661 
662  // Delete old entry
663  KConfigGroup cg2 = KConfigUtils::openGroup(m_oldConfig2, m_oldGroup);
664  cg2.deleteEntry(key);
665  /*if (m_oldConfig2->deleteGroup(m_oldGroup, KConfig::Normal)) { // Delete group if empty.
666  log() << m_currentFilename << ": Removing empty group " << m_oldFile << ":" << m_oldGroup << endl;
667  } (this should be automatic)*/
668 }
669 
670 void KonfUpdate::gotAllKeys()
671 {
672  if (!m_oldConfig1) {
673  logFileError() << "AllKeys without previous File specification" << endl;
674  return;
675  }
676 
677  copyOrMoveGroup(m_oldGroup, m_newGroup);
678 }
679 
680 void KonfUpdate::gotAllGroups()
681 {
682  if (!m_oldConfig1) {
683  logFileError() << "AllGroups without previous File specification" << endl;
684  return;
685  }
686 
687  const QStringList allGroups = m_oldConfig1->groupList();
688  for (QStringList::ConstIterator it = allGroups.begin();
689  it != allGroups.end(); ++it) {
690  m_oldGroup = QStringList() << *it;
691  m_newGroup = m_oldGroup;
692  gotAllKeys();
693  }
694 }
695 
696 void KonfUpdate::gotOptions(const QString &_options)
697 {
698  const QStringList options = _options.split(',');
699  for (QStringList::ConstIterator it = options.begin();
700  it != options.end();
701  ++it) {
702  if ((*it).toLower().trimmed() == "copy") {
703  m_bCopy = true;
704  }
705 
706  if ((*it).toLower().trimmed() == "overwrite") {
707  m_bOverwrite = true;
708  }
709  }
710 }
711 
712 void KonfUpdate::copyGroup(const KConfigBase *cfg1, const QString &group1,
713  KConfigBase *cfg2, const QString &group2)
714 {
715  KConfigGroup cg1(cfg1, group1);
716  KConfigGroup cg2(cfg2, group2);
717  copyGroup(cg1, cg2);
718 }
719 
720 void KonfUpdate::copyGroup(const KConfigGroup &cg1, KConfigGroup &cg2)
721 {
722  // Copy keys
723  QMap<QString, QString> list = cg1.entryMap();
724  for (QMap<QString, QString>::ConstIterator it = list.constBegin();
725  it != list.constEnd(); ++it) {
726  if (m_bOverwrite || !cg2.hasKey(it.key())) {
727  cg2.writeEntry(it.key(), it.value());
728  }
729  }
730 
731  // Copy subgroups
732  Q_FOREACH(const QString &group, cg1.groupList()) {
733  copyGroup(&cg1, group, &cg2, group);
734  }
735 }
736 
737 void KonfUpdate::gotScriptArguments(const QString &_arguments)
738 {
739  m_arguments = _arguments;
740 }
741 
742 void KonfUpdate::gotScript(const QString &_script)
743 {
744  QString script, interpreter;
745  int i = _script.indexOf(',');
746  if (i == -1) {
747  script = _script.trimmed();
748  } else {
749  script = _script.left(i).trimmed();
750  interpreter = _script.mid(i + 1).trimmed();
751  }
752 
753 
754  if (script.isEmpty()) {
755  logFileError() << "Script fails to specify filename";
756  m_skip = true;
757  return;
758  }
759 
760 
761 
762  QString path = KStandardDirs::locate("data", "kconf_update/" + script);
763  if (path.isEmpty()) {
764  if (interpreter.isEmpty()) {
765  path = KStandardDirs::locate("lib", "kconf_update_bin/" + script);
766  }
767 
768  if (path.isEmpty()) {
769  logFileError() << "Script '" << script << "' not found" << endl;
770  m_skip = true;
771  return;
772  }
773  }
774 
775  if (!m_arguments.isNull()) {
776  log() << m_currentFilename << ": Running script '" << script << "' with arguments '" << m_arguments << "'" << endl;
777  } else {
778  log() << m_currentFilename << ": Running script '" << script << "'" << endl;
779  }
780 
781  QString cmd;
782  if (interpreter.isEmpty()) {
783  cmd = path;
784  } else {
785  cmd = interpreter + ' ' + path;
786  }
787 
788  if (!m_arguments.isNull()) {
789  cmd += ' ';
790  cmd += m_arguments;
791  }
792 
793  KTemporaryFile scriptIn;
794  scriptIn.open();
795  KTemporaryFile scriptOut;
796  scriptOut.open();
797  KTemporaryFile scriptErr;
798  scriptErr.open();
799 
800  int result;
801  if (m_oldConfig1) {
802  if (m_debug) {
803  scriptIn.setAutoRemove(false);
804  log() << "Script input stored in " << scriptIn.fileName() << endl;
805  }
806  KConfig cfg(scriptIn.fileName(), KConfig::SimpleConfig);
807 
808  if (m_oldGroup.isEmpty()) {
809  // Write all entries to tmpFile;
810  const QStringList grpList = m_oldConfig1->groupList();
811  for (QStringList::ConstIterator it = grpList.begin();
812  it != grpList.end();
813  ++it) {
814  copyGroup(m_oldConfig1, *it, &cfg, *it);
815  }
816  } else {
817  KConfigGroup cg1 = KConfigUtils::openGroup(m_oldConfig1, m_oldGroup);
818  KConfigGroup cg2(&cfg, QString());
819  copyGroup(cg1, cg2);
820  }
821  cfg.sync();
822 #ifndef _WIN32_WCE
823  result = system(QFile::encodeName(QString("%1 < %2 > %3 2> %4").arg(cmd, scriptIn.fileName(), scriptOut.fileName(), scriptErr.fileName())));
824 #else
825  QString path_ = QDir::convertSeparators ( QFileInfo ( cmd ).absoluteFilePath() );
826  QString file_ = QFileInfo ( cmd ).fileName();
827  SHELLEXECUTEINFO execInfo;
828  memset ( &execInfo,0,sizeof ( execInfo ) );
829  execInfo.cbSize = sizeof ( execInfo );
830  execInfo.fMask = SEE_MASK_FLAG_NO_UI;
831  execInfo.lpVerb = L"open";
832  execInfo.lpFile = (LPCWSTR) path_.utf16();
833  execInfo.lpDirectory = (LPCWSTR) file_.utf16();
834  execInfo.lpParameters = (LPCWSTR) QString(" < %1 > %2 2> %3").arg( scriptIn.fileName(), scriptOut.fileName(), scriptErr.fileName()).utf16();
835  result = ShellExecuteEx ( &execInfo );
836  if (result != 0)
837  {
838  result = 0;
839  }
840  else
841  {
842  result = -1;
843  }
844 #endif
845  } else {
846  // No config file
847 #ifndef _WIN32_WCE
848  result = system(QFile::encodeName(QString("%1 2> %2").arg(cmd, scriptErr.fileName())));
849 #else
850  QString path_ = QDir::convertSeparators ( QFileInfo ( cmd ).absoluteFilePath() );
851  QString file_ = QFileInfo ( cmd ).fileName();
852  SHELLEXECUTEINFO execInfo;
853  memset ( &execInfo,0,sizeof ( execInfo ) );
854  execInfo.cbSize = sizeof ( execInfo );
855  execInfo.fMask = SEE_MASK_FLAG_NO_UI;
856  execInfo.lpVerb = L"open";
857  execInfo.lpFile = (LPCWSTR) path_.utf16();
858  execInfo.lpDirectory = (LPCWSTR) file_.utf16();
859  execInfo.lpParameters = (LPCWSTR) QString(" 2> %1").arg( scriptErr.fileName()).utf16();
860  result = ShellExecuteEx ( &execInfo );
861  if (result != 0)
862  {
863  result = 0;
864  }
865  else
866  {
867  result = -1;
868  }
869 #endif
870  }
871 
872  // Copy script stderr to log file
873  {
874  QFile output(scriptErr.fileName());
875  if (output.open(QIODevice::ReadOnly)) {
876  QTextStream ts(&output);
877  ts.setCodec(QTextCodec::codecForName("UTF-8"));
878  while (!ts.atEnd()) {
879  QString line = ts.readLine();
880  log() << "[Script] " << line << endl;
881  }
882  }
883  }
884 
885  if (result) {
886  log() << m_currentFilename << ": !! An error occurred while running '" << cmd << "'" << endl;
887  return;
888  }
889 
890  if (!m_oldConfig1) {
891  return; // Nothing to merge
892  }
893 
894  if (m_debug) {
895  scriptOut.setAutoRemove(false);
896  log() << "Script output stored in " << scriptOut.fileName() << endl;
897  }
898 
899  // Deleting old entries
900  {
901  QStringList group = m_oldGroup;
902  QFile output(scriptOut.fileName());
903  if (output.open(QIODevice::ReadOnly)) {
904  QTextStream ts(&output);
905  ts.setCodec(QTextCodec::codecForName("UTF-8"));
906  while (!ts.atEnd()) {
907  QString line = ts.readLine();
908  if (line.startsWith('[')) {
909  group = parseGroupString(line);
910  } else if (line.startsWith(QLatin1String("# DELETE "))) {
911  QString key = line.mid(9);
912  if (key[0] == '[') {
913  int j = key.lastIndexOf(']') + 1;
914  if (j > 0) {
915  group = parseGroupString(key.left(j));
916  key = key.mid(j);
917  }
918  }
919  KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig2, group);
920  cg.deleteEntry(key);
921  log() << m_currentFilename << ": Script removes " << m_oldFile << ":" << group << ":" << key << endl;
922  /*if (m_oldConfig2->deleteGroup(group, KConfig::Normal)) { // Delete group if empty.
923  log() << m_currentFilename << ": Removing empty group " << m_oldFile << ":" << group << endl;
924  } (this should be automatic)*/
925  } else if (line.startsWith(QLatin1String("# DELETEGROUP"))) {
926  QString str = line.mid(13).trimmed();
927  if (!str.isEmpty()) {
928  group = parseGroupString(str);
929  }
930  KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig2, group);
931  cg.deleteGroup();
932  log() << m_currentFilename << ": Script removes group " << m_oldFile << ":" << group << endl;
933  }
934  }
935  }
936  }
937 
938  // Merging in new entries.
939  KConfig scriptOutConfig(scriptOut.fileName(), KConfig::NoGlobals);
940  if (m_newGroup.isEmpty()) {
941  // Copy "default" keys as members of "default" keys
942  copyGroup(&scriptOutConfig, QString(), m_newConfig, QString());
943  } else {
944  // Copy default keys as members of m_newGroup
945  KConfigGroup srcCg = KConfigUtils::openGroup(&scriptOutConfig, QStringList());
946  KConfigGroup dstCg = KConfigUtils::openGroup(m_newConfig, m_newGroup);
947  copyGroup(srcCg, dstCg);
948  }
949  Q_FOREACH(const QString &group, scriptOutConfig.groupList()) {
950  copyGroup(&scriptOutConfig, group, m_newConfig, group);
951  }
952 }
953 
954 void KonfUpdate::resetOptions()
955 {
956  m_bCopy = false;
957  m_bOverwrite = false;
958  m_arguments.clear();
959 }
960 
961 
962 extern "C" KDE_EXPORT int kdemain(int argc, char **argv)
963 {
964  KCmdLineOptions options;
965  options.add("debug", ki18n("Keep output results from scripts"));
966  options.add("check <update-file>", ki18n("Check whether config file itself requires updating"));
967  options.add("+[file]", ki18n("File to read update instructions from"));
968 
969  KAboutData aboutData("kconf_update", 0, ki18n("KConf Update"),
970  "1.0.2",
971  ki18n("KDE Tool for updating user configuration files"),
972  KAboutData::License_GPL,
973  ki18n("(c) 2001, Waldo Bastian"));
974 
975  aboutData.addAuthor(ki18n("Waldo Bastian"), KLocalizedString(), "bastian@kde.org");
976 
977  KCmdLineArgs::init(argc, argv, &aboutData);
978  KCmdLineArgs::addCmdLineOptions(options);
979 
980  KComponentData componentData(&aboutData);
981 
982  KonfUpdate konfUpdate;
983 
984  return 0;
985 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Thu Feb 21 2013 11:00:50 by doxygen 1.8.1 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-4.8.5 API Reference

Skip menu "kdelibs-4.8.5 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
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