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

kconf_update

kconf_update.cpp

Go to the documentation of this file.
00001 /*
00002  *
00003  *  This file is part of the KDE libraries
00004  *  Copyright (c) 2001 Waldo Bastian <bastian@kde.org>
00005  *
00006  *  This library is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU Library General Public
00008  *  License version 2 as published by the Free Software Foundation.
00009  *
00010  *  This library is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  *  Library General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU Library General Public License
00016  *  along with this library; see the file COPYING.LIB.  If not, write to
00017  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  *  Boston, MA 02110-1301, USA.
00019  **/
00020 
00021 #include <sys/types.h>
00022 #include <sys/stat.h>
00023 #include <unistd.h>
00024 #include <stdlib.h>
00025 #include <kde_file.h>
00026 
00027 #include <QtCore/QDate>
00028 #include <QtCore/QFile>
00029 #include <QtCore/QTextStream>
00030 #include <QtCore/QTextCodec>
00031 #ifdef _WIN32_WCE
00032 #include <QtCore/QDir>
00033 #endif
00034 
00035 #include <kconfig.h>
00036 #include <kconfiggroup.h>
00037 #include <kdebug.h>
00038 #include <klocale.h>
00039 #include <kcmdlineargs.h>
00040 #include <kglobal.h>
00041 #include <kstandarddirs.h>
00042 #include <kaboutdata.h>
00043 #include <kcomponentdata.h>
00044 #include <ktemporaryfile.h>
00045 #include <kurl.h>
00046 
00047 #include "kconfigutils.h"
00048 
00049 class KonfUpdate
00050 {
00051 public:
00052     KonfUpdate();
00053     ~KonfUpdate();
00054     QStringList findUpdateFiles(bool dirtyOnly);
00055 
00056     QTextStream &log();
00057     QTextStream &logFileError();
00058 
00059     bool checkFile(const QString &filename);
00060     void checkGotFile(const QString &_file, const QString &id);
00061 
00062     bool updateFile(const QString &filename);
00063 
00064     void gotId(const QString &_id);
00065     void gotFile(const QString &_file);
00066     void gotGroup(const QString &_group);
00067     void gotRemoveGroup(const QString &_group);
00068     void gotKey(const QString &_key);
00069     void gotRemoveKey(const QString &_key);
00070     void gotAllKeys();
00071     void gotAllGroups();
00072     void gotOptions(const QString &_options);
00073     void gotScript(const QString &_script);
00074     void gotScriptArguments(const QString &_arguments);
00075     void resetOptions();
00076 
00077     void copyGroup(const KConfigBase *cfg1, const QString &group1,
00078                    KConfigBase *cfg2, const QString &group2);
00079     void copyGroup(const KConfigGroup &cg1, KConfigGroup &cg2);
00080     void copyOrMoveKey(const QStringList &srcGroupPath, const QString &srcKey, const QStringList &dstGroupPath, const QString &dstKey);
00081     void copyOrMoveGroup(const QStringList &srcGroupPath, const QStringList &dstGroupPath);
00082 
00083     QStringList parseGroupString(const QString &_str);
00084 
00085 protected:
00086     KConfig *m_config;
00087     QString m_currentFilename;
00088     bool m_skip;
00089     bool m_skipFile;
00090     bool m_debug;
00091     QString m_id;
00092 
00093     QString m_oldFile;
00094     QString m_newFile;
00095     QString m_newFileName;
00096     KConfig *m_oldConfig1; // Config to read keys from.
00097     KConfig *m_oldConfig2; // Config to delete keys from.
00098     KConfig *m_newConfig;
00099 
00100     QStringList m_oldGroup;
00101     QStringList m_newGroup;
00102 
00103     bool m_bCopy;
00104     bool m_bOverwrite;
00105     bool m_bUseConfigInfo;
00106     QString m_arguments;
00107     QTextStream *m_textStream;
00108     QFile *m_file;
00109     QString m_line;
00110     int m_lineCount;
00111 };
00112 
00113 KonfUpdate::KonfUpdate()
00114         : m_textStream(0), m_file(0)
00115 {
00116     bool updateAll = false;
00117     m_oldConfig1 = 0;
00118     m_oldConfig2 = 0;
00119     m_newConfig = 0;
00120 
00121     m_config = new KConfig("kconf_updaterc");
00122     KConfigGroup cg(m_config, QString());
00123 
00124     QStringList updateFiles;
00125     KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
00126 
00127     m_debug = args->isSet("debug");
00128 
00129     m_bUseConfigInfo = false;
00130     if (args->isSet("check")) {
00131         m_bUseConfigInfo = true;
00132         QString file = KStandardDirs::locate("data", "kconf_update/" + args->getOption("check"));
00133         if (file.isEmpty()) {
00134             qWarning("File '%s' not found.", args->getOption("check").toLocal8Bit().data());
00135             log() << "File '" << args->getOption("check") << "' passed on command line not found" << endl;
00136             return;
00137         }
00138         updateFiles.append(file);
00139     } else if (args->count()) {
00140         for (int i = 0; i < args->count(); i++) {
00141             KUrl url = args->url(i);
00142             if (!url.isLocalFile()) {
00143                 KCmdLineArgs::usageError(i18n("Only local files are supported."));
00144             }
00145             updateFiles.append(url.path());
00146         }
00147     } else {
00148         if (cg.readEntry("autoUpdateDisabled", false))
00149             return;
00150         updateFiles = findUpdateFiles(true);
00151         updateAll = true;
00152     }
00153 
00154     for (QStringList::ConstIterator it = updateFiles.constBegin();
00155             it != updateFiles.constEnd();
00156             ++it) {
00157         updateFile(*it);
00158     }
00159 
00160     if (updateAll && !cg.readEntry("updateInfoAdded", false)) {
00161         cg.writeEntry("updateInfoAdded", true);
00162         updateFiles = findUpdateFiles(false);
00163 
00164         for (QStringList::ConstIterator it = updateFiles.constBegin();
00165                 it != updateFiles.constEnd();
00166                 ++it) {
00167             checkFile(*it);
00168         }
00169         updateFiles.clear();
00170     }
00171 }
00172 
00173 KonfUpdate::~KonfUpdate()
00174 {
00175     delete m_config;
00176     delete m_file;
00177     delete m_textStream;
00178 }
00179 
00180 QTextStream & operator<<(QTextStream & stream, const QStringList & lst)
00181 {
00182     stream << lst.join(", ");
00183     return stream;
00184 }
00185 
00186 QTextStream &
00187 KonfUpdate::log()
00188 {
00189     if (!m_textStream) {
00190         QString file = KStandardDirs::locateLocal("data", "kconf_update/log/update.log");
00191         m_file = new QFile(file);
00192         if (m_file->open(QIODevice::WriteOnly | QIODevice::Append)) {
00193             m_textStream = new QTextStream(m_file);
00194         } else {
00195             // Error
00196             m_textStream = new QTextStream(stderr, QIODevice::WriteOnly);
00197         }
00198     }
00199 
00200     (*m_textStream) << QDateTime::currentDateTime().toString(Qt::ISODate) << " ";
00201 
00202     return *m_textStream;
00203 }
00204 
00205 QTextStream &
00206 KonfUpdate::logFileError()
00207 {
00208     return log() << m_currentFilename << ':' << m_lineCount << ":'" << m_line << "': ";
00209 }
00210 
00211 QStringList KonfUpdate::findUpdateFiles(bool dirtyOnly)
00212 {
00213     QStringList result;
00214     const QStringList list = KGlobal::dirs()->findAllResources("data", "kconf_update/*.upd",
00215                              KStandardDirs::NoDuplicates);
00216     for (QStringList::ConstIterator it = list.constBegin();
00217             it != list.constEnd();
00218             ++it) {
00219         QString file = *it;
00220         KDE_struct_stat buff;
00221         if (KDE::stat(file, &buff) == 0) {
00222             int i = file.lastIndexOf('/');
00223             if (i != -1) {
00224                 file = file.mid(i + 1);
00225             }
00226             KConfigGroup cg(m_config, file);
00227             time_t ctime = cg.readEntry("ctime", 0);
00228             time_t mtime = cg.readEntry("mtime", 0);
00229             if (!dirtyOnly ||
00230                     (ctime != buff.st_ctime) || (mtime != buff.st_mtime)) {
00231                 result.append(*it);
00232             }
00233         }
00234     }
00235     return result;
00236 }
00237 
00238 bool KonfUpdate::checkFile(const QString &filename)
00239 {
00240     m_currentFilename = filename;
00241     int i = m_currentFilename.lastIndexOf('/');
00242     if (i != -1) {
00243         m_currentFilename = m_currentFilename.mid(i + 1);
00244     }
00245     m_skip = true;
00246     QFile file(filename);
00247     if (!file.open(QIODevice::ReadOnly)) {
00248         return false;
00249     }
00250 
00251     QTextStream ts(&file);
00252     ts.setCodec(QTextCodec::codecForName("ISO-8859-1"));
00253     int lineCount = 0;
00254     resetOptions();
00255     QString id;
00256     while (!ts.atEnd()) {
00257         QString line = ts.readLine().trimmed();
00258         lineCount++;
00259         if (line.isEmpty() || (line[0] == '#')) {
00260             continue;
00261         }
00262         if (line.startsWith("Id=")) {
00263             id = m_currentFilename + ':' + line.mid(3);
00264         } else if (line.startsWith("File=")) {
00265             checkGotFile(line.mid(5), id);
00266         }
00267     }
00268 
00269     return true;
00270 }
00271 
00272 void KonfUpdate::checkGotFile(const QString &_file, const QString &id)
00273 {
00274     QString file;
00275     int i = _file.indexOf(',');
00276     if (i == -1) {
00277         file = _file.trimmed();
00278     } else {
00279         file = _file.mid(i + 1).trimmed();
00280     }
00281 
00282 //   qDebug("File %s, id %s", file.toLatin1().constData(), id.toLatin1().constData());
00283 
00284     KConfig cfg(file, KConfig::SimpleConfig);
00285     KConfigGroup cg(&cfg, "$Version");
00286     QStringList ids = cg.readEntry("update_info", QStringList());
00287     if (ids.contains(id)) {
00288         return;
00289     }
00290     ids.append(id);
00291     cg.writeEntry("update_info", ids);
00292 }
00293 
00313 bool KonfUpdate::updateFile(const QString &filename)
00314 {
00315     m_currentFilename = filename;
00316     int i = m_currentFilename.lastIndexOf('/');
00317     if (i != -1) {
00318         m_currentFilename = m_currentFilename.mid(i + 1);
00319     }
00320     m_skip = true;
00321     QFile file(filename);
00322     if (!file.open(QIODevice::ReadOnly)) {
00323         return false;
00324     }
00325 
00326     log() << "Checking update-file '" << filename << "' for new updates" << endl;
00327 
00328     QTextStream ts(&file);
00329     ts.setCodec(QTextCodec::codecForName("ISO-8859-1"));
00330     m_lineCount = 0;
00331     resetOptions();
00332     while (!ts.atEnd()) {
00333         m_line = ts.readLine().trimmed();
00334         m_lineCount++;
00335         if (m_line.isEmpty() || (m_line[0] == '#')) {
00336             continue;
00337         }
00338         if (m_line.startsWith(QLatin1String("Id="))) {
00339             gotId(m_line.mid(3));
00340         } else if (m_skip) {
00341             continue;
00342         } else if (m_line.startsWith(QLatin1String("Options="))) {
00343             gotOptions(m_line.mid(8));
00344         } else if (m_line.startsWith(QLatin1String("File="))) {
00345             gotFile(m_line.mid(5));
00346         } else if (m_skipFile) {
00347             continue;
00348         } else if (m_line.startsWith(QLatin1String("Group="))) {
00349             gotGroup(m_line.mid(6));
00350         } else if (m_line.startsWith(QLatin1String("RemoveGroup="))) {
00351             gotRemoveGroup(m_line.mid(12));
00352             resetOptions();
00353         } else if (m_line.startsWith(QLatin1String("Script="))) {
00354             gotScript(m_line.mid(7));
00355             resetOptions();
00356         } else if (m_line.startsWith(QLatin1String("ScriptArguments="))) {
00357             gotScriptArguments(m_line.mid(16));
00358         } else if (m_line.startsWith(QLatin1String("Key="))) {
00359             gotKey(m_line.mid(4));
00360             resetOptions();
00361         } else if (m_line.startsWith(QLatin1String("RemoveKey="))) {
00362             gotRemoveKey(m_line.mid(10));
00363             resetOptions();
00364         } else if (m_line == "AllKeys") {
00365             gotAllKeys();
00366             resetOptions();
00367         } else if (m_line == "AllGroups") {
00368             gotAllGroups();
00369             resetOptions();
00370         } else {
00371             logFileError() << "Parse error" << endl;
00372         }
00373     }
00374     // Flush.
00375     gotId(QString());
00376 
00377     KDE_struct_stat buff;
00378     KDE::stat(filename, &buff);
00379     KConfigGroup cg(m_config, m_currentFilename);
00380     cg.writeEntry("ctime", int(buff.st_ctime));
00381     cg.writeEntry("mtime", int(buff.st_mtime));
00382     cg.sync();
00383     return true;
00384 }
00385 
00386 
00387 
00388 void KonfUpdate::gotId(const QString &_id)
00389 {
00390     if (!m_id.isEmpty() && !m_skip) {
00391         KConfigGroup cg(m_config, m_currentFilename);
00392 
00393         QStringList ids = cg.readEntry("done", QStringList());
00394         if (!ids.contains(m_id)) {
00395             ids.append(m_id);
00396             cg.writeEntry("done", ids);
00397             cg.sync();
00398         }
00399     }
00400 
00401     // Flush pending changes
00402     gotFile(QString());
00403     KConfigGroup cg(m_config, m_currentFilename);
00404 
00405     QStringList ids = cg.readEntry("done", QStringList());
00406     if (!_id.isEmpty()) {
00407         if (ids.contains(_id)) {
00408             //qDebug("Id '%s' was already in done-list", _id.toLatin1().constData());
00409             if (!m_bUseConfigInfo) {
00410                 m_skip = true;
00411                 return;
00412             }
00413         }
00414         m_skip = false;
00415         m_skipFile = false;
00416         m_id = _id;
00417         if (m_bUseConfigInfo) {
00418             log() << m_currentFilename << ": Checking update '" << _id << "'" << endl;
00419         } else {
00420             log() << m_currentFilename << ": Found new update '" << _id << "'" << endl;
00421         }
00422     }
00423 }
00424 
00425 void KonfUpdate::gotFile(const QString &_file)
00426 {
00427     // Reset group
00428     gotGroup(QString());
00429 
00430     if (!m_oldFile.isEmpty()) {
00431         // Close old file.
00432         delete m_oldConfig1;
00433         m_oldConfig1 = 0;
00434 
00435         KConfigGroup cg(m_oldConfig2, "$Version");
00436         QStringList ids = cg.readEntry("update_info", QStringList());
00437         QString cfg_id = m_currentFilename + ':' + m_id;
00438         if (!ids.contains(cfg_id) && !m_skip) {
00439             ids.append(cfg_id);
00440             cg.writeEntry("update_info", ids);
00441         }
00442         cg.sync();
00443         delete m_oldConfig2;
00444         m_oldConfig2 = 0;
00445 
00446         QString file = KStandardDirs::locateLocal("config", m_oldFile);
00447         KDE_struct_stat s_buf;
00448         if (KDE::stat(file, &s_buf) == 0) {
00449             if (s_buf.st_size == 0) {
00450                 // Delete empty file.
00451                 QFile::remove(file);
00452             }
00453         }
00454 
00455         m_oldFile.clear();
00456     }
00457     if (!m_newFile.isEmpty()) {
00458         // Close new file.
00459         KConfigGroup cg(m_newConfig, "$Version");
00460         QStringList ids = cg.readEntry("update_info", QStringList());
00461         QString cfg_id = m_currentFilename + ':' + m_id;
00462         if (!ids.contains(cfg_id) && !m_skip) {
00463             ids.append(cfg_id);
00464             cg.writeEntry("update_info", ids);
00465         }
00466         m_newConfig->sync();
00467         delete m_newConfig;
00468         m_newConfig = 0;
00469 
00470         m_newFile.clear();
00471     }
00472     m_newConfig = 0;
00473 
00474     int i = _file.indexOf(',');
00475     if (i == -1) {
00476         m_oldFile = _file.trimmed();
00477     } else {
00478         m_oldFile = _file.left(i).trimmed();
00479         m_newFile = _file.mid(i + 1).trimmed();
00480         if (m_oldFile == m_newFile) {
00481             m_newFile.clear();
00482         }
00483     }
00484 
00485     if (!m_oldFile.isEmpty()) {
00486         m_oldConfig2 = new KConfig(m_oldFile, KConfig::NoGlobals);
00487         QString cfg_id = m_currentFilename + ':' + m_id;
00488         KConfigGroup cg(m_oldConfig2, "$Version");
00489         QStringList ids = cg.readEntry("update_info", QStringList());
00490         if (ids.contains(cfg_id)) {
00491             m_skip = true;
00492             m_newFile.clear();
00493             log() << m_currentFilename << ": Skipping update '" << m_id << "'" << endl;
00494         }
00495 
00496         if (!m_newFile.isEmpty()) {
00497             m_newConfig = new KConfig(m_newFile, KConfig::NoGlobals);
00498             KConfigGroup cg(m_newConfig, "$Version");
00499             ids = cg.readEntry("update_info", QStringList());
00500             if (ids.contains(cfg_id)) {
00501                 m_skip = true;
00502                 log() << m_currentFilename << ": Skipping update '" << m_id << "'" << endl;
00503             }
00504         } else {
00505             m_newConfig = m_oldConfig2;
00506         }
00507 
00508         m_oldConfig1 = new KConfig(m_oldFile, KConfig::NoGlobals);
00509     } else {
00510         m_newFile.clear();
00511     }
00512     m_newFileName = m_newFile;
00513     if (m_newFileName.isEmpty()) {
00514         m_newFileName = m_oldFile;
00515     }
00516 
00517     m_skipFile = false;
00518     if (!m_oldFile.isEmpty()) { // if File= is specified, it doesn't exist, is empty or contains only kconf_update's [$Version] group, skip
00519         if (m_oldConfig1 != NULL
00520                 && (m_oldConfig1->groupList().isEmpty()
00521                     || (m_oldConfig1->groupList().count() == 1 && m_oldConfig1->groupList().first() == "$Version"))) {
00522             log() << m_currentFilename << ": File '" << m_oldFile << "' does not exist or empty, skipping" << endl;
00523             m_skipFile = true;
00524         }
00525     }
00526 }
00527 
00528 QStringList KonfUpdate::parseGroupString(const QString &str)
00529 {
00530     bool ok;
00531     QString error;
00532     QStringList lst = KConfigUtils::parseGroupString(str, &ok, &error);
00533     if (!ok) {
00534         logFileError() << error;
00535     }
00536     return lst;
00537 }
00538 
00539 void KonfUpdate::gotGroup(const QString &_group)
00540 {
00541     QString group = _group.trimmed();
00542     if (group.isEmpty()) {
00543         m_oldGroup = m_newGroup = QStringList();
00544         return;
00545     }
00546 
00547     QStringList tokens = group.split(',');
00548     m_oldGroup = parseGroupString(tokens.at(0));
00549     if (tokens.count() == 1) {
00550         m_newGroup = m_oldGroup;
00551     } else {
00552         m_newGroup = parseGroupString(tokens.at(1));
00553     }
00554 }
00555 
00556 void KonfUpdate::gotRemoveGroup(const QString &_group)
00557 {
00558     m_oldGroup = parseGroupString(_group);
00559 
00560     if (!m_oldConfig1) {
00561         logFileError() << "RemoveGroup without previous File specification" << endl;
00562         return;
00563     }
00564 
00565     KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig2, m_oldGroup);
00566     if (!cg.exists()) {
00567         return;
00568     }
00569     // Delete group.
00570     cg.deleteGroup();
00571     log() << m_currentFilename << ": RemoveGroup removes group " << m_oldFile << ":" << m_oldGroup << endl;
00572 }
00573 
00574 
00575 void KonfUpdate::gotKey(const QString &_key)
00576 {
00577     QString oldKey, newKey;
00578     int i = _key.indexOf(',');
00579     if (i == -1) {
00580         oldKey = _key.trimmed();
00581         newKey = oldKey;
00582     } else {
00583         oldKey = _key.left(i).trimmed();
00584         newKey = _key.mid(i + 1).trimmed();
00585     }
00586 
00587     if (oldKey.isEmpty() || newKey.isEmpty()) {
00588         logFileError() << "Key specifies invalid key" << endl;
00589         return;
00590     }
00591     if (!m_oldConfig1) {
00592         logFileError() << "Key without previous File specification" << endl;
00593         return;
00594     }
00595     copyOrMoveKey(m_oldGroup, oldKey, m_newGroup, newKey);
00596 }
00597 
00598 void KonfUpdate::copyOrMoveKey(const QStringList &srcGroupPath, const QString &srcKey, const QStringList &dstGroupPath, const QString &dstKey)
00599 {
00600     KConfigGroup dstCg = KConfigUtils::openGroup(m_newConfig, dstGroupPath);
00601     if (!m_bOverwrite && dstCg.hasKey(dstKey)) {
00602         log() << m_currentFilename << ": Skipping " << m_newFileName << ":" << dstCg.name() << ":" << dstKey << ", already exists." << endl;
00603         return;
00604     }
00605 
00606     KConfigGroup srcCg = KConfigUtils::openGroup(m_oldConfig1, srcGroupPath);
00607     QString value = srcCg.readEntry(srcKey, QString());
00608     log() << m_currentFilename << ": Updating " << m_newFileName << ":" << dstCg.name() << ":" << dstKey << " to '" << value << "'" << endl;
00609     dstCg.writeEntry(dstKey, value);
00610 
00611     if (m_bCopy) {
00612         return; // Done.
00613     }
00614 
00615     // Delete old entry
00616     if (m_oldConfig2 == m_newConfig
00617         && srcGroupPath == dstGroupPath
00618         && srcKey == dstKey) {
00619         return; // Don't delete!
00620     }
00621     KConfigGroup srcCg2 = KConfigUtils::openGroup(m_oldConfig2, srcGroupPath);
00622     srcCg2.deleteEntry(srcKey);
00623     log() << m_currentFilename << ": Removing " << m_oldFile << ":" << srcCg2.name() << ":" << srcKey << ", moved." << endl;
00624 }
00625 
00626 void KonfUpdate::copyOrMoveGroup(const QStringList &srcGroupPath, const QStringList &dstGroupPath)
00627 {
00628     KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig1, srcGroupPath);
00629 
00630     // Keys
00631     Q_FOREACH(const QString &key, cg.keyList()) {
00632         copyOrMoveKey(srcGroupPath, key, dstGroupPath, key);
00633     }
00634 
00635     // Subgroups
00636     Q_FOREACH(const QString &group, cg.groupList()) {
00637         QStringList groupPath = QStringList() << group;
00638         copyOrMoveGroup(srcGroupPath + groupPath, dstGroupPath + groupPath);
00639     }
00640 }
00641 
00642 void KonfUpdate::gotRemoveKey(const QString &_key)
00643 {
00644     QString key = _key.trimmed();
00645 
00646     if (key.isEmpty()) {
00647         logFileError() << "RemoveKey specifies invalid key" << endl;
00648         return;
00649     }
00650 
00651     if (!m_oldConfig1) {
00652         logFileError() << "Key without previous File specification" << endl;
00653         return;
00654     }
00655 
00656     KConfigGroup cg1 = KConfigUtils::openGroup(m_oldConfig1, m_oldGroup);
00657     if (!cg1.hasKey(key)) {
00658         return;
00659     }
00660     log() << m_currentFilename << ": RemoveKey removes " << m_oldFile << ":" << m_oldGroup << ":" << key << endl;
00661 
00662     // Delete old entry
00663     KConfigGroup cg2 = KConfigUtils::openGroup(m_oldConfig2, m_oldGroup);
00664     cg2.deleteEntry(key);
00665     /*if (m_oldConfig2->deleteGroup(m_oldGroup, KConfig::Normal)) { // Delete group if empty.
00666        log() << m_currentFilename << ": Removing empty group " << m_oldFile << ":" << m_oldGroup << endl;
00667     }   (this should be automatic)*/
00668 }
00669 
00670 void KonfUpdate::gotAllKeys()
00671 {
00672     if (!m_oldConfig1) {
00673         logFileError() << "AllKeys without previous File specification" << endl;
00674         return;
00675     }
00676 
00677     copyOrMoveGroup(m_oldGroup, m_newGroup);
00678 }
00679 
00680 void KonfUpdate::gotAllGroups()
00681 {
00682     if (!m_oldConfig1) {
00683         logFileError() << "AllGroups without previous File specification" << endl;
00684         return;
00685     }
00686 
00687     const QStringList allGroups = m_oldConfig1->groupList();
00688     for (QStringList::ConstIterator it = allGroups.begin();
00689             it != allGroups.end(); ++it) {
00690         m_oldGroup = QStringList() << *it;
00691         m_newGroup = m_oldGroup;
00692         gotAllKeys();
00693     }
00694 }
00695 
00696 void KonfUpdate::gotOptions(const QString &_options)
00697 {
00698     const QStringList options = _options.split(',');
00699     for (QStringList::ConstIterator it = options.begin();
00700             it != options.end();
00701             ++it) {
00702         if ((*it).toLower().trimmed() == "copy") {
00703             m_bCopy = true;
00704         }
00705 
00706         if ((*it).toLower().trimmed() == "overwrite") {
00707             m_bOverwrite = true;
00708         }
00709     }
00710 }
00711 
00712 void KonfUpdate::copyGroup(const KConfigBase *cfg1, const QString &group1,
00713                            KConfigBase *cfg2, const QString &group2)
00714 {
00715     KConfigGroup cg1(cfg1, group1);
00716     KConfigGroup cg2(cfg2, group2);
00717     copyGroup(cg1, cg2);
00718 }
00719 
00720 void KonfUpdate::copyGroup(const KConfigGroup &cg1, KConfigGroup &cg2)
00721 {
00722     // Copy keys
00723     QMap<QString, QString> list = cg1.entryMap();
00724     for (QMap<QString, QString>::ConstIterator it = list.constBegin();
00725             it != list.constEnd(); ++it) {
00726         if (m_bOverwrite || !cg2.hasKey(it.key())) {
00727             cg2.writeEntry(it.key(), it.value());
00728         }
00729     }
00730 
00731     // Copy subgroups
00732     Q_FOREACH(const QString &group, cg1.groupList()) {
00733         copyGroup(&cg1, group, &cg2, group);
00734     }
00735 }
00736 
00737 void KonfUpdate::gotScriptArguments(const QString &_arguments)
00738 {
00739     m_arguments = _arguments;
00740 }
00741 
00742 void KonfUpdate::gotScript(const QString &_script)
00743 {
00744     QString script, interpreter;
00745     int i = _script.indexOf(',');
00746     if (i == -1) {
00747         script = _script.trimmed();
00748     } else {
00749         script = _script.left(i).trimmed();
00750         interpreter = _script.mid(i + 1).trimmed();
00751     }
00752 
00753 
00754     if (script.isEmpty()) {
00755         logFileError() << "Script fails to specify filename";
00756         m_skip = true;
00757         return;
00758     }
00759 
00760 
00761 
00762     QString path = KStandardDirs::locate("data", "kconf_update/" + script);
00763     if (path.isEmpty()) {
00764         if (interpreter.isEmpty()) {
00765             path = KStandardDirs::locate("lib", "kconf_update_bin/" + script);
00766         }
00767 
00768         if (path.isEmpty()) {
00769             logFileError() << "Script '" << script << "' not found" << endl;
00770             m_skip = true;
00771             return;
00772         }
00773     }
00774 
00775     if (!m_arguments.isNull()) {
00776         log() << m_currentFilename << ": Running script '" << script << "' with arguments '" << m_arguments << "'" << endl;
00777     } else {
00778         log() << m_currentFilename << ": Running script '" << script << "'" << endl;
00779     }
00780 
00781     QString cmd;
00782     if (interpreter.isEmpty()) {
00783         cmd = path;
00784     } else {
00785         cmd = interpreter + ' ' + path;
00786     }
00787 
00788     if (!m_arguments.isNull()) {
00789         cmd += ' ';
00790         cmd += m_arguments;
00791     }
00792 
00793     KTemporaryFile scriptIn;
00794     scriptIn.open();
00795     KTemporaryFile scriptOut;
00796     scriptOut.open();
00797     KTemporaryFile scriptErr;
00798     scriptErr.open();
00799 
00800     int result;
00801     if (m_oldConfig1) {
00802         if (m_debug) {
00803             scriptIn.setAutoRemove(false);
00804             log() << "Script input stored in " << scriptIn.fileName() << endl;
00805         }
00806         KConfig cfg(scriptIn.fileName(), KConfig::SimpleConfig);
00807 
00808         if (m_oldGroup.isEmpty()) {
00809             // Write all entries to tmpFile;
00810             const QStringList grpList = m_oldConfig1->groupList();
00811             for (QStringList::ConstIterator it = grpList.begin();
00812                     it != grpList.end();
00813                     ++it) {
00814                 copyGroup(m_oldConfig1, *it, &cfg, *it);
00815             }
00816         } else {
00817             KConfigGroup cg1 = KConfigUtils::openGroup(m_oldConfig1, m_oldGroup);
00818             KConfigGroup cg2(&cfg, QString());
00819             copyGroup(cg1, cg2);
00820         }
00821         cfg.sync();
00822 #ifndef _WIN32_WCE
00823         result = system(QFile::encodeName(QString("%1 < %2 > %3 2> %4").arg(cmd, scriptIn.fileName(), scriptOut.fileName(), scriptErr.fileName())));
00824 #else
00825         QString path_ = QDir::convertSeparators ( QFileInfo ( cmd ).absoluteFilePath() );
00826         QString file_ = QFileInfo ( cmd ).fileName();
00827         SHELLEXECUTEINFO execInfo;
00828         memset ( &execInfo,0,sizeof ( execInfo ) );
00829         execInfo.cbSize = sizeof ( execInfo );
00830         execInfo.fMask =  SEE_MASK_FLAG_NO_UI;
00831         execInfo.lpVerb = L"open";
00832         execInfo.lpFile = (LPCWSTR) path_.utf16();
00833         execInfo.lpDirectory = (LPCWSTR) file_.utf16();
00834         execInfo.lpParameters = (LPCWSTR) QString(" < %1 > %2 2> %3").arg( scriptIn.fileName(), scriptOut.fileName(), scriptErr.fileName()).utf16();
00835         result = ShellExecuteEx ( &execInfo );
00836         if (result != 0)
00837         {
00838             result = 0;
00839         }
00840         else
00841         {
00842             result = -1;
00843         }
00844 #endif
00845     } else {
00846         // No config file
00847 #ifndef _WIN32_WCE
00848         result = system(QFile::encodeName(QString("%1 2> %2").arg(cmd, scriptErr.fileName())));
00849 #else
00850         QString path_ = QDir::convertSeparators ( QFileInfo ( cmd ).absoluteFilePath() );
00851         QString file_ = QFileInfo ( cmd ).fileName();
00852         SHELLEXECUTEINFO execInfo;
00853         memset ( &execInfo,0,sizeof ( execInfo ) );
00854         execInfo.cbSize = sizeof ( execInfo );
00855         execInfo.fMask =  SEE_MASK_FLAG_NO_UI;
00856         execInfo.lpVerb = L"open";
00857         execInfo.lpFile = (LPCWSTR) path_.utf16();
00858         execInfo.lpDirectory = (LPCWSTR) file_.utf16();
00859         execInfo.lpParameters = (LPCWSTR) QString(" 2> %1").arg( scriptErr.fileName()).utf16();
00860         result = ShellExecuteEx ( &execInfo );
00861         if (result != 0)
00862         {
00863             result = 0;
00864         }
00865         else
00866         {
00867             result = -1;
00868         }
00869 #endif
00870     }
00871 
00872     // Copy script stderr to log file
00873     {
00874         QFile output(scriptErr.fileName());
00875         if (output.open(QIODevice::ReadOnly)) {
00876             QTextStream ts(&output);
00877             ts.setCodec(QTextCodec::codecForName("UTF-8"));
00878             while (!ts.atEnd()) {
00879                 QString line = ts.readLine();
00880                 log() << "[Script] " << line << endl;
00881             }
00882         }
00883     }
00884 
00885     if (result) {
00886         log() << m_currentFilename << ": !! An error occurred while running '" << cmd << "'" << endl;
00887         return;
00888     }
00889 
00890     if (!m_oldConfig1) {
00891         return; // Nothing to merge
00892     }
00893 
00894     if (m_debug) {
00895         scriptOut.setAutoRemove(false);
00896         log() << "Script output stored in " << scriptOut.fileName() << endl;
00897     }
00898 
00899     // Deleting old entries
00900     {
00901         QStringList group = m_oldGroup;
00902         QFile output(scriptOut.fileName());
00903         if (output.open(QIODevice::ReadOnly)) {
00904             QTextStream ts(&output);
00905             ts.setCodec(QTextCodec::codecForName("UTF-8"));
00906             while (!ts.atEnd()) {
00907                 QString line = ts.readLine();
00908                 if (line.startsWith('[')) {
00909                     group = parseGroupString(line);
00910                 } else if (line.startsWith(QLatin1String("# DELETE "))) {
00911                     QString key = line.mid(9);
00912                     if (key[0] == '[') {
00913                         int j = key.lastIndexOf(']') + 1;
00914                         if (j > 0) {
00915                             group = parseGroupString(key.left(j));
00916                             key = key.mid(j);
00917                         }
00918                     }
00919                     KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig2, group);
00920                     cg.deleteEntry(key);
00921                     log() << m_currentFilename << ": Script removes " << m_oldFile << ":" << group << ":" << key << endl;
00922                     /*if (m_oldConfig2->deleteGroup(group, KConfig::Normal)) { // Delete group if empty.
00923                        log() << m_currentFilename << ": Removing empty group " << m_oldFile << ":" << group << endl;
00924                     } (this should be automatic)*/
00925                 } else if (line.startsWith(QLatin1String("# DELETEGROUP"))) {
00926                     QString str = line.mid(13).trimmed();
00927                     if (!str.isEmpty()) {
00928                         group = parseGroupString(str);
00929                     }
00930                     KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig2, group);
00931                     cg.deleteGroup();
00932                     log() << m_currentFilename << ": Script removes group " << m_oldFile << ":" << group << endl;
00933                 }
00934             }
00935         }
00936     }
00937 
00938     // Merging in new entries.
00939     KConfig scriptOutConfig(scriptOut.fileName(), KConfig::NoGlobals);
00940     if (m_newGroup.isEmpty()) {
00941         // Copy "default" keys as members of "default" keys
00942         copyGroup(&scriptOutConfig, QString(), m_newConfig, QString());
00943     } else {
00944         // Copy default keys as members of m_newGroup
00945         KConfigGroup srcCg = KConfigUtils::openGroup(&scriptOutConfig, QStringList());
00946         KConfigGroup dstCg = KConfigUtils::openGroup(m_newConfig, m_newGroup);
00947         copyGroup(srcCg, dstCg);
00948     }
00949     Q_FOREACH(const QString &group, scriptOutConfig.groupList()) {
00950         copyGroup(&scriptOutConfig, group, m_newConfig, group);
00951     }
00952 }
00953 
00954 void KonfUpdate::resetOptions()
00955 {
00956     m_bCopy = false;
00957     m_bOverwrite = false;
00958     m_arguments.clear();
00959 }
00960 
00961 
00962 extern "C" KDE_EXPORT int kdemain(int argc, char **argv)
00963 {
00964     KCmdLineOptions options;
00965     options.add("debug", ki18n("Keep output results from scripts"));
00966     options.add("check <update-file>", ki18n("Check whether config file itself requires updating"));
00967     options.add("+[file]", ki18n("File to read update instructions from"));
00968 
00969     KAboutData aboutData("kconf_update", 0, ki18n("KConf Update"),
00970                          "1.0.2",
00971                          ki18n("KDE Tool for updating user configuration files"),
00972                          KAboutData::License_GPL,
00973                          ki18n("(c) 2001, Waldo Bastian"));
00974 
00975     aboutData.addAuthor(ki18n("Waldo Bastian"), KLocalizedString(), "bastian@kde.org");
00976 
00977     KCmdLineArgs::init(argc, argv, &aboutData);
00978     KCmdLineArgs::addCmdLineOptions(options);
00979 
00980     KComponentData componentData(&aboutData);
00981 
00982     KonfUpdate konfUpdate;
00983 
00984     return 0;
00985 }

kconf_update

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • 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
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal