• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.9.4 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  if (!srcCg.hasKey(srcKey))
608  return;
609  QString value = srcCg.readEntry(srcKey, QString());
610  log() << m_currentFilename << ": Updating " << m_newFileName << ":" << dstCg.name() << ":" << dstKey << " to '" << value << "'" << endl;
611  dstCg.writeEntry(dstKey, value);
612 
613  if (m_bCopy) {
614  return; // Done.
615  }
616 
617  // Delete old entry
618  if (m_oldConfig2 == m_newConfig
619  && srcGroupPath == dstGroupPath
620  && srcKey == dstKey) {
621  return; // Don't delete!
622  }
623  KConfigGroup srcCg2 = KConfigUtils::openGroup(m_oldConfig2, srcGroupPath);
624  srcCg2.deleteEntry(srcKey);
625  log() << m_currentFilename << ": Removing " << m_oldFile << ":" << srcCg2.name() << ":" << srcKey << ", moved." << endl;
626 }
627 
628 void KonfUpdate::copyOrMoveGroup(const QStringList &srcGroupPath, const QStringList &dstGroupPath)
629 {
630  KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig1, srcGroupPath);
631 
632  // Keys
633  Q_FOREACH(const QString &key, cg.keyList()) {
634  copyOrMoveKey(srcGroupPath, key, dstGroupPath, key);
635  }
636 
637  // Subgroups
638  Q_FOREACH(const QString &group, cg.groupList()) {
639  QStringList groupPath = QStringList() << group;
640  copyOrMoveGroup(srcGroupPath + groupPath, dstGroupPath + groupPath);
641  }
642 }
643 
644 void KonfUpdate::gotRemoveKey(const QString &_key)
645 {
646  QString key = _key.trimmed();
647 
648  if (key.isEmpty()) {
649  logFileError() << "RemoveKey specifies invalid key" << endl;
650  return;
651  }
652 
653  if (!m_oldConfig1) {
654  logFileError() << "Key without previous File specification" << endl;
655  return;
656  }
657 
658  KConfigGroup cg1 = KConfigUtils::openGroup(m_oldConfig1, m_oldGroup);
659  if (!cg1.hasKey(key)) {
660  return;
661  }
662  log() << m_currentFilename << ": RemoveKey removes " << m_oldFile << ":" << m_oldGroup << ":" << key << endl;
663 
664  // Delete old entry
665  KConfigGroup cg2 = KConfigUtils::openGroup(m_oldConfig2, m_oldGroup);
666  cg2.deleteEntry(key);
667  /*if (m_oldConfig2->deleteGroup(m_oldGroup, KConfig::Normal)) { // Delete group if empty.
668  log() << m_currentFilename << ": Removing empty group " << m_oldFile << ":" << m_oldGroup << endl;
669  } (this should be automatic)*/
670 }
671 
672 void KonfUpdate::gotAllKeys()
673 {
674  if (!m_oldConfig1) {
675  logFileError() << "AllKeys without previous File specification" << endl;
676  return;
677  }
678 
679  copyOrMoveGroup(m_oldGroup, m_newGroup);
680 }
681 
682 void KonfUpdate::gotAllGroups()
683 {
684  if (!m_oldConfig1) {
685  logFileError() << "AllGroups without previous File specification" << endl;
686  return;
687  }
688 
689  const QStringList allGroups = m_oldConfig1->groupList();
690  for (QStringList::ConstIterator it = allGroups.begin();
691  it != allGroups.end(); ++it) {
692  m_oldGroup = QStringList() << *it;
693  m_newGroup = m_oldGroup;
694  gotAllKeys();
695  }
696 }
697 
698 void KonfUpdate::gotOptions(const QString &_options)
699 {
700  const QStringList options = _options.split(',');
701  for (QStringList::ConstIterator it = options.begin();
702  it != options.end();
703  ++it) {
704  if ((*it).toLower().trimmed() == "copy") {
705  m_bCopy = true;
706  }
707 
708  if ((*it).toLower().trimmed() == "overwrite") {
709  m_bOverwrite = true;
710  }
711  }
712 }
713 
714 void KonfUpdate::copyGroup(const KConfigBase *cfg1, const QString &group1,
715  KConfigBase *cfg2, const QString &group2)
716 {
717  KConfigGroup cg1(cfg1, group1);
718  KConfigGroup cg2(cfg2, group2);
719  copyGroup(cg1, cg2);
720 }
721 
722 void KonfUpdate::copyGroup(const KConfigGroup &cg1, KConfigGroup &cg2)
723 {
724  // Copy keys
725  QMap<QString, QString> list = cg1.entryMap();
726  for (QMap<QString, QString>::ConstIterator it = list.constBegin();
727  it != list.constEnd(); ++it) {
728  if (m_bOverwrite || !cg2.hasKey(it.key())) {
729  cg2.writeEntry(it.key(), it.value());
730  }
731  }
732 
733  // Copy subgroups
734  Q_FOREACH(const QString &group, cg1.groupList()) {
735  copyGroup(&cg1, group, &cg2, group);
736  }
737 }
738 
739 void KonfUpdate::gotScriptArguments(const QString &_arguments)
740 {
741  m_arguments = _arguments;
742 }
743 
744 void KonfUpdate::gotScript(const QString &_script)
745 {
746  QString script, interpreter;
747  int i = _script.indexOf(',');
748  if (i == -1) {
749  script = _script.trimmed();
750  } else {
751  script = _script.left(i).trimmed();
752  interpreter = _script.mid(i + 1).trimmed();
753  }
754 
755 
756  if (script.isEmpty()) {
757  logFileError() << "Script fails to specify filename";
758  m_skip = true;
759  return;
760  }
761 
762 
763 
764  QString path = KStandardDirs::locate("data", "kconf_update/" + script);
765  if (path.isEmpty()) {
766  if (interpreter.isEmpty()) {
767  path = KStandardDirs::locate("lib", "kconf_update_bin/" + script);
768  }
769 
770  if (path.isEmpty()) {
771  logFileError() << "Script '" << script << "' not found" << endl;
772  m_skip = true;
773  return;
774  }
775  }
776 
777  if (!m_arguments.isNull()) {
778  log() << m_currentFilename << ": Running script '" << script << "' with arguments '" << m_arguments << "'" << endl;
779  } else {
780  log() << m_currentFilename << ": Running script '" << script << "'" << endl;
781  }
782 
783  QString cmd;
784  if (interpreter.isEmpty()) {
785  cmd = path;
786  } else {
787  cmd = interpreter + ' ' + path;
788  }
789 
790  if (!m_arguments.isNull()) {
791  cmd += ' ';
792  cmd += m_arguments;
793  }
794 
795  KTemporaryFile scriptIn;
796  scriptIn.open();
797  KTemporaryFile scriptOut;
798  scriptOut.open();
799  KTemporaryFile scriptErr;
800  scriptErr.open();
801 
802  int result;
803  if (m_oldConfig1) {
804  if (m_debug) {
805  scriptIn.setAutoRemove(false);
806  log() << "Script input stored in " << scriptIn.fileName() << endl;
807  }
808  KConfig cfg(scriptIn.fileName(), KConfig::SimpleConfig);
809 
810  if (m_oldGroup.isEmpty()) {
811  // Write all entries to tmpFile;
812  const QStringList grpList = m_oldConfig1->groupList();
813  for (QStringList::ConstIterator it = grpList.begin();
814  it != grpList.end();
815  ++it) {
816  copyGroup(m_oldConfig1, *it, &cfg, *it);
817  }
818  } else {
819  KConfigGroup cg1 = KConfigUtils::openGroup(m_oldConfig1, m_oldGroup);
820  KConfigGroup cg2(&cfg, QString());
821  copyGroup(cg1, cg2);
822  }
823  cfg.sync();
824 #ifndef _WIN32_WCE
825  result = system(QFile::encodeName(QString("%1 < %2 > %3 2> %4").arg(cmd, scriptIn.fileName(), scriptOut.fileName(), scriptErr.fileName())));
826 #else
827  QString path_ = QDir::convertSeparators ( QFileInfo ( cmd ).absoluteFilePath() );
828  QString file_ = QFileInfo ( cmd ).fileName();
829  SHELLEXECUTEINFO execInfo;
830  memset ( &execInfo,0,sizeof ( execInfo ) );
831  execInfo.cbSize = sizeof ( execInfo );
832  execInfo.fMask = SEE_MASK_FLAG_NO_UI;
833  execInfo.lpVerb = L"open";
834  execInfo.lpFile = (LPCWSTR) path_.utf16();
835  execInfo.lpDirectory = (LPCWSTR) file_.utf16();
836  execInfo.lpParameters = (LPCWSTR) QString(" < %1 > %2 2> %3").arg( scriptIn.fileName(), scriptOut.fileName(), scriptErr.fileName()).utf16();
837  result = ShellExecuteEx ( &execInfo );
838  if (result != 0)
839  {
840  result = 0;
841  }
842  else
843  {
844  result = -1;
845  }
846 #endif
847  } else {
848  // No config file
849 #ifndef _WIN32_WCE
850  result = system(QFile::encodeName(QString("%1 2> %2").arg(cmd, scriptErr.fileName())));
851 #else
852  QString path_ = QDir::convertSeparators ( QFileInfo ( cmd ).absoluteFilePath() );
853  QString file_ = QFileInfo ( cmd ).fileName();
854  SHELLEXECUTEINFO execInfo;
855  memset ( &execInfo,0,sizeof ( execInfo ) );
856  execInfo.cbSize = sizeof ( execInfo );
857  execInfo.fMask = SEE_MASK_FLAG_NO_UI;
858  execInfo.lpVerb = L"open";
859  execInfo.lpFile = (LPCWSTR) path_.utf16();
860  execInfo.lpDirectory = (LPCWSTR) file_.utf16();
861  execInfo.lpParameters = (LPCWSTR) QString(" 2> %1").arg( scriptErr.fileName()).utf16();
862  result = ShellExecuteEx ( &execInfo );
863  if (result != 0)
864  {
865  result = 0;
866  }
867  else
868  {
869  result = -1;
870  }
871 #endif
872  }
873 
874  // Copy script stderr to log file
875  {
876  QFile output(scriptErr.fileName());
877  if (output.open(QIODevice::ReadOnly)) {
878  QTextStream ts(&output);
879  ts.setCodec(QTextCodec::codecForName("UTF-8"));
880  while (!ts.atEnd()) {
881  QString line = ts.readLine();
882  log() << "[Script] " << line << endl;
883  }
884  }
885  }
886 
887  if (result) {
888  log() << m_currentFilename << ": !! An error occurred while running '" << cmd << "'" << endl;
889  return;
890  }
891 
892  if (!m_oldConfig1) {
893  return; // Nothing to merge
894  }
895 
896  if (m_debug) {
897  scriptOut.setAutoRemove(false);
898  log() << "Script output stored in " << scriptOut.fileName() << endl;
899  }
900 
901  // Deleting old entries
902  {
903  QStringList group = m_oldGroup;
904  QFile output(scriptOut.fileName());
905  if (output.open(QIODevice::ReadOnly)) {
906  QTextStream ts(&output);
907  ts.setCodec(QTextCodec::codecForName("UTF-8"));
908  while (!ts.atEnd()) {
909  QString line = ts.readLine();
910  if (line.startsWith('[')) {
911  group = parseGroupString(line);
912  } else if (line.startsWith(QLatin1String("# DELETE "))) {
913  QString key = line.mid(9);
914  if (key[0] == '[') {
915  int j = key.lastIndexOf(']') + 1;
916  if (j > 0) {
917  group = parseGroupString(key.left(j));
918  key = key.mid(j);
919  }
920  }
921  KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig2, group);
922  cg.deleteEntry(key);
923  log() << m_currentFilename << ": Script removes " << m_oldFile << ":" << group << ":" << key << endl;
924  /*if (m_oldConfig2->deleteGroup(group, KConfig::Normal)) { // Delete group if empty.
925  log() << m_currentFilename << ": Removing empty group " << m_oldFile << ":" << group << endl;
926  } (this should be automatic)*/
927  } else if (line.startsWith(QLatin1String("# DELETEGROUP"))) {
928  QString str = line.mid(13).trimmed();
929  if (!str.isEmpty()) {
930  group = parseGroupString(str);
931  }
932  KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig2, group);
933  cg.deleteGroup();
934  log() << m_currentFilename << ": Script removes group " << m_oldFile << ":" << group << endl;
935  }
936  }
937  }
938  }
939 
940  // Merging in new entries.
941  KConfig scriptOutConfig(scriptOut.fileName(), KConfig::NoGlobals);
942  if (m_newGroup.isEmpty()) {
943  // Copy "default" keys as members of "default" keys
944  copyGroup(&scriptOutConfig, QString(), m_newConfig, QString());
945  } else {
946  // Copy default keys as members of m_newGroup
947  KConfigGroup srcCg = KConfigUtils::openGroup(&scriptOutConfig, QStringList());
948  KConfigGroup dstCg = KConfigUtils::openGroup(m_newConfig, m_newGroup);
949  copyGroup(srcCg, dstCg);
950  }
951  Q_FOREACH(const QString &group, scriptOutConfig.groupList()) {
952  copyGroup(&scriptOutConfig, group, m_newConfig, group);
953  }
954 }
955 
956 void KonfUpdate::resetOptions()
957 {
958  m_bCopy = false;
959  m_bOverwrite = false;
960  m_arguments.clear();
961 }
962 
963 
964 extern "C" KDE_EXPORT int kdemain(int argc, char **argv)
965 {
966  KCmdLineOptions options;
967  options.add("debug", ki18n("Keep output results from scripts"));
968  options.add("check <update-file>", ki18n("Check whether config file itself requires updating"));
969  options.add("+[file]", ki18n("File to read update instructions from"));
970 
971  KAboutData aboutData("kconf_update", 0, ki18n("KConf Update"),
972  "1.0.2",
973  ki18n("KDE Tool for updating user configuration files"),
974  KAboutData::License_GPL,
975  ki18n("(c) 2001, Waldo Bastian"));
976 
977  aboutData.addAuthor(ki18n("Waldo Bastian"), KLocalizedString(), "bastian@kde.org");
978 
979  KCmdLineArgs::init(argc, argv, &aboutData);
980  KCmdLineArgs::addCmdLineOptions(options);
981 
982  KComponentData componentData(&aboutData);
983 
984  KonfUpdate konfUpdate;
985 
986  return 0;
987 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Dec 10 2012 13:38:38 by doxygen 1.8.1.2 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.9.4 API Reference

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