kdelibs/kded/kbuildsycoca.cpp
Ivailo Monev 93c35e4c15 generic: remove build-time compat options
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
2023-10-21 19:57:19 +03:00

817 lines
26 KiB
C++

// -*- c-basic-offset: 3 -*-
/* This file is part of the KDE libraries
* Copyright (C) 1999 David Faure <faure@kde.org>
* Copyright (C) 2002-2003 Waldo Bastian <bastian@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License version 2 as published by the Free Software Foundation;
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
**/
#include "kbuildsycoca.h"
#include "ksycoca_p.h"
#include "ksycocaresourcelist.h"
#include "vfolder_menu.h"
#include <config.h>
#include <kservice.h>
#include <kmimetype.h>
#include "kbuildservicetypefactory.h"
#include "kbuildmimetypefactory.h"
#include "kbuildservicefactory.h"
#include "kbuildservicegroupfactory.h"
#include "kbuildprotocolinfofactory.h"
#include "kctimefactory.h"
#include <ktemporaryfile.h>
#include <kglobal.h>
#include <kdebug.h>
#include <kdirwatch.h>
#include <kstandarddirs.h>
#include <ksavefile.h>
#include <klocale.h>
#include <kaboutdata.h>
#include <kcmdlineargs.h>
#include <kde_file.h>
#include <kcrash.h>
#include <QDir>
#include <QFileInfo>
#include <QCoreApplication>
#include <QDBusConnectionInterface>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>
#include <errno.h>
#include <assert.h>
typedef QHash<QString, KSycocaEntry::Ptr> KBSEntryDict;
typedef QList<KSycocaEntry::List> KSycocaEntryListList;
static quint32 newTimestamp = 0;
static KBuildServiceFactory *g_serviceFactory = 0;
static KBuildServiceGroupFactory *g_buildServiceGroupFactory = 0;
static KSycocaFactory *g_currentFactory = 0;
static KCTimeInfo *g_ctimeInfo = 0; // factory
static KCTimeDict *g_ctimeDict = 0; // old timestamps
static QByteArray g_resource = 0;
static KBSEntryDict *g_currentEntryDict = 0;
static KBSEntryDict *g_serviceGroupEntryDict = 0;
static KSycocaEntryListList *g_allEntries = 0; // entries from existing ksycoca
static QStringList *g_allResourceDirs = 0;
static bool g_changed = false;
static KSycocaEntry::List g_tempStorage;
static VFolderMenu *g_vfolder = 0;
static QByteArray g_sycocaPath = 0;
static QLatin1String g_defaultMenu = QLatin1String("kde-applications.menu");
static bool bGlobalDatabase = false;
static bool bMenuTest = false;
void crashHandler(int sig)
{
KDE_signal(sig, SIG_DFL);
// If we crash while reading sycoca, we delete the database in an attempt to recover.
if (!g_sycocaPath.isEmpty()) {
unlink(g_sycocaPath.constData());
}
::exit(sig);
}
static QString sycocaPath()
{
return KSycoca::absoluteFilePath(bGlobalDatabase ? KSycoca::GlobalDatabase : KSycoca::LocalDatabase);
}
KBuildSycoca::KBuildSycoca()
: KSycoca( true )
{
}
KBuildSycoca::~KBuildSycoca()
{
}
KSycocaEntry::Ptr KBuildSycoca::createEntry(const QString &file, bool addToFactory)
{
quint32 timeStamp = g_ctimeInfo->dict()->ctime(file, g_resource);
if (!timeStamp)
{
timeStamp = KGlobal::dirs()->calcResourceHash( g_resource, file,
KStandardDirs::Recursive);
}
KSycocaEntry::Ptr entry;
if (g_allEntries)
{
assert(g_ctimeDict);
quint32 oldTimestamp = g_ctimeDict->ctime(file, g_resource);
if (timeStamp && (timeStamp == oldTimestamp))
{
// Re-use old entry
if (g_currentFactory == g_buildServiceGroupFactory) // Strip .directory from service-group entries
{
entry = g_currentEntryDict->value(file.left(file.length()-10));
} else {
entry = g_currentEntryDict->value(file);
}
// remove from g_ctimeDict; if g_ctimeDict is not empty
// after all files have been processed, it means
// some files were removed since last time
if (file.contains("fake"))
kDebug(7021) << g_resource << "reusing (and removing) old entry [\"fake\"] for:" << file;
g_ctimeDict->remove(file, g_resource);
}
else if (oldTimestamp)
{
g_changed = true;
g_ctimeDict->remove(file, g_resource);
kDebug(7021) << "modified:" << file << "in" << g_resource.constData();
}
else
{
g_changed = true;
kDebug(7021) << "new:" << file << "in" << g_resource.constData();
}
}
g_ctimeInfo->dict()->addCTime(file, g_resource, timeStamp);
if (!entry)
{
// Create a new entry
entry = g_currentFactory->createEntry( file, g_resource );
}
if ( entry && entry->isValid() )
{
if (addToFactory)
g_currentFactory->addEntry(entry);
else
g_tempStorage.append(entry);
return entry;
}
return KSycocaEntry::Ptr();
}
KService::Ptr KBuildSycoca::createService(const QString &path)
{
KSycocaEntry::Ptr entry = createEntry(path, false);
return KService::Ptr::staticCast(entry);
}
// returns false if the database is up to date, true if it needs to be saved
bool KBuildSycoca::build()
{
typedef QList<KBSEntryDict *> KBSEntryDictList;
KBSEntryDictList entryDictList;
KBSEntryDict *serviceEntryDict = 0;
// Convert for each factory the entryList to a Dict.
int i = 0;
// For each factory
for (KSycocaFactoryList::Iterator factory = factories()->begin();
factory != factories()->end();
++factory)
{
KBSEntryDict *entryDict = new KBSEntryDict;
if (g_allEntries)
{
const KSycocaEntry::List list = (*g_allEntries)[i++];
for( KSycocaEntry::List::const_iterator it = list.begin();
it != list.end();
++it)
{
entryDict->insert( (*it)->entryPath(), *it );
}
}
if ((*factory) == g_serviceFactory)
serviceEntryDict = entryDict;
else if ((*factory) == g_buildServiceGroupFactory)
g_serviceGroupEntryDict = entryDict;
entryDictList.append(entryDict);
}
QStringList allResources; // we could use QSet<QString> - does order matter?
// For each factory
for (KSycocaFactoryList::Iterator factory = factories()->begin();
factory != factories()->end();
++factory)
{
// For each resource the factory deals with
const KSycocaResourceList *list = (*factory)->resourceList();
if (!list) continue;
for( KSycocaResourceList::ConstIterator it1 = list->constBegin();
it1 != list->constEnd();
++it1 )
{
KSycocaResource res = (*it1);
if (!allResources.contains(res.resource))
allResources.append(res.resource);
}
}
g_ctimeInfo = new KCTimeInfo(); // This is a build factory too, don't delete!!
bool uptodate = true;
// For all resources
foreach(const QString &it1, allResources)
{
g_changed = false;
g_resource = it1.toLatin1();
QStringList relFiles;
(void) KGlobal::dirs()->findAllResources( g_resource,
QString(),
KStandardDirs::Recursive |
KStandardDirs::NoDuplicates,
relFiles);
// Now find all factories that use this resource....
// For each factory
KBSEntryDictList::const_iterator ed_it = entryDictList.begin();
const KBSEntryDictList::const_iterator ed_end = entryDictList.end();
KSycocaFactoryList::const_iterator it = factories()->constBegin();
const KSycocaFactoryList::const_iterator end = factories()->constEnd();
for ( ; it != end; ++it, ++ed_it )
{
g_currentFactory = (*it);
// g_ctimeInfo gets created after the initial loop, so it has no entryDict.
g_currentEntryDict = ed_it == ed_end ? 0 : *ed_it;
// For each resource the factory deals with
const KSycocaResourceList *list = g_currentFactory->resourceList();
if (!list) continue;
for( KSycocaResourceList::ConstIterator it2 = list->constBegin();
it2 != list->constEnd();
++it2 )
{
KSycocaResource res = (*it2);
if (res.resource != it1) continue;
// For each file in the resource
foreach(const QString &it3, relFiles)
{
// Check if file matches filter
if (it3.endsWith(res.extension))
createEntry(it3, true);
}
}
}
if (g_changed || !g_allEntries)
{
uptodate = false;
//kDebug() << "CHANGED:" << g_resource;
m_changedResources.append(g_resource);
}
}
bool result = !uptodate || (g_ctimeDict && !g_ctimeDict->isEmpty());
if (g_ctimeDict && !g_ctimeDict->isEmpty()) {
//kDebug() << "Still in time dict:";
//g_ctimeDict->dump();
// ## It seems entries filtered out by vfolder are still in there,
// so we end up always saving ksycoca, i.e. this method never returns false
// Get the list of resources from which some files were deleted
const QStringList resources = g_ctimeDict->resourceList();
kDebug() << "Still in the time dict (i.e. deleted files)" << resources;
m_changedResources += resources;
}
if (result || bMenuTest)
{
g_resource = "xdgdata-apps";
g_currentFactory = g_serviceFactory;
g_currentEntryDict = serviceEntryDict;
g_changed = false;
g_vfolder = new VFolderMenu(g_serviceFactory, this);
if (!m_trackId.isEmpty())
g_vfolder->setTrackId(m_trackId);
QString applicationsMenu = g_defaultMenu;
const QString xdgMenuPrefix = QString::fromLocal8Bit(qgetenv("XDG_MENU_PREFIX"));
if (!xdgMenuPrefix.isEmpty())
{
applicationsMenu = xdgMenuPrefix + QLatin1String("applications.menu");
const bool isValid = !KStandardDirs::locate("xdgconf-menu", applicationsMenu).isEmpty();
if (!isValid) {
kWarning() << "Specified XDG_MENU_PREFIX results in invalid menu" << applicationsMenu;
applicationsMenu = g_defaultMenu;
}
}
VFolderMenu::SubMenu *kdeMenu = g_vfolder->parseMenu(applicationsMenu);
KServiceGroup::Ptr entry = g_buildServiceGroupFactory->addNew("/", kdeMenu->directoryFile, KServiceGroup::Ptr(), false);
entry->setLayoutInfo(kdeMenu->layoutList);
createMenu(QString(), QString(), kdeMenu);
(void) existingResourceDirs();
*g_allResourceDirs += g_vfolder->allDirectories();
if (g_changed || !g_allEntries)
{
uptodate = false;
//kDebug() << "CHANGED:" << g_resource;
m_changedResources.append(g_resource);
}
if (bMenuTest) {
result = false;
}
}
qDeleteAll(entryDictList);
return result;
}
void KBuildSycoca::createMenu(const QString &caption_, const QString &name_, VFolderMenu::SubMenu *menu)
{
QString caption = caption_;
QString name = name_;
foreach (VFolderMenu::SubMenu *subMenu, menu->subMenus)
{
QString subName = name+subMenu->name+'/';
QString directoryFile = subMenu->directoryFile;
if (directoryFile.isEmpty())
directoryFile = subName+".directory";
quint32 timeStamp = g_ctimeInfo->dict()->ctime(directoryFile, g_resource);
if (!timeStamp) {
timeStamp = KGlobal::dirs()->calcResourceHash( g_resource, directoryFile,
KStandardDirs::Recursive );
}
KServiceGroup::Ptr entry;
if (g_allEntries)
{
const quint32 oldTimestamp = g_ctimeDict->ctime(directoryFile, g_resource);
if (timeStamp && (timeStamp == oldTimestamp))
{
KSycocaEntry::Ptr group = g_serviceGroupEntryDict->value(subName);
if ( group )
{
entry = KServiceGroup::Ptr::staticCast( group );
if (entry->directoryEntryPath() != directoryFile)
entry = 0; // Can't reuse this one!
}
}
}
g_ctimeInfo->dict()->addCTime(directoryFile, g_resource, timeStamp);
entry = g_buildServiceGroupFactory->addNew(subName, subMenu->directoryFile, entry, subMenu->isDeleted);
entry->setLayoutInfo(subMenu->layoutList);
if (! (bMenuTest && entry->noDisplay()) )
createMenu(caption + entry->caption() + '/', subName, subMenu);
}
if (caption.isEmpty())
caption += '/';
if (name.isEmpty())
name += '/';
foreach (const KService::Ptr &p, menu->items)
{
if (bMenuTest)
{
if (!menu->isDeleted && !p->noDisplay())
printf("%s\t%s\t%s\n", qPrintable( caption ), qPrintable( p->menuId() ), qPrintable( KStandardDirs::locate("xdgdata-apps", p->entryPath() ) ) );
}
else
{
g_buildServiceGroupFactory->addNewEntryTo( name, p );
}
}
}
bool KBuildSycoca::recreate()
{
QString path(sycocaPath());
// KSaveFile first writes to a temp file.
// Upon finalize() it moves the stuff to the right place.
KSaveFile database(path);
bool openedOK = database.open();
if (!openedOK && database.error() == QFile::PermissionsError && QFile::exists(path))
{
QFile::remove( path );
openedOK = database.open();
}
if (!openedOK)
{
fprintf(stderr, "kbuildsycoca4: ERROR creating database '%s'! %s\n",
path.toLocal8Bit().data(), database.errorString().toLocal8Bit().data());
return false;
}
QDataStream* str = new QDataStream(&database);
kDebug(7021).nospace() << "Recreating ksycoca file (" << path << ", version " << KSycoca::version() << ")";
// It is very important to build the servicetype one first
// Both are registered in KSycoca, no need to keep the pointers
KSycocaFactory *stf = new KBuildServiceTypeFactory;
KBuildMimeTypeFactory* mimeTypeFactory = new KBuildMimeTypeFactory;
g_buildServiceGroupFactory = new KBuildServiceGroupFactory();
g_serviceFactory = new KBuildServiceFactory(stf, mimeTypeFactory, g_buildServiceGroupFactory);
(void) new KBuildProtocolInfoFactory();
if( build()) // Parse dirs
{
save(str); // Save database
if (str->status() != QDataStream::Ok) // ######## TODO: does this detect write errors, e.g. disk full?
database.abort(); // Error
delete str;
str = 0;
if (!database.finalize())
{
fprintf(stderr, "kbuildsycoca4: ERROR writing database '%s'!\n", database.fileName().toLocal8Bit().data());
fprintf(stderr, "kbuildsycoca4: Disk full?\n");
return false;
}
}
else
{
delete str;
str = 0;
database.abort();
if (bMenuTest)
return true;
kDebug(7021) << "Database is up to date";
}
if (!bGlobalDatabase)
{
// update the timestamp file
QString stamppath = path + "stamp";
QFile ksycocastamp(stamppath);
ksycocastamp.open( QIODevice::WriteOnly );
QDataStream str( &ksycocastamp );
str << newTimestamp;
str << existingResourceDirs();
if (g_vfolder)
str << g_vfolder->allDirectories(); // Extra resource dirs
}
return true;
}
void KBuildSycoca::save(QDataStream* str)
{
// Write header (#pass 1)
str->device()->seek(0);
(*str) << (qint32) KSycoca::version();
KBuildServiceFactory * serviceFactory = 0;
for(KSycocaFactoryList::Iterator factory = factories()->begin();
factory != factories()->end();
++factory)
{
qint32 aId;
qint32 aOffset;
aId = (*factory)->factoryId();
if ( aId == KST_KServiceFactory )
serviceFactory = static_cast<KBuildServiceFactory *>( *factory );
aOffset = (*factory)->offset(); // not set yet, so always 0
(*str) << aId;
(*str) << aOffset;
}
(*str) << (qint32) 0; // No more factories.
// Write KDEDIRS
(*str) << KGlobal::dirs()->kfsstnd_prefixes();
(*str) << newTimestamp;
(*str) << KGlobal::locale()->language();
(*str) << KGlobal::dirs()->calcResourceHash("services", "update_ksycoca",
KStandardDirs::Recursive );
(*str) << (*g_allResourceDirs);
// Calculate per-servicetype/mimetype data
serviceFactory->postProcessServices();
// Here so that it's the last debug message
kDebug(7021) << "Saving";
// Write factory data....
for(KSycocaFactoryList::Iterator factory = factories()->begin();
factory != factories()->end();
++factory)
{
(*factory)->save(*str);
if (str->status() != QDataStream::Ok) // ######## TODO: does this detect write errors, e.g. disk full?
return; // error
}
int endOfData = str->device()->pos();
// Write header (#pass 2)
str->device()->seek(0);
(*str) << (qint32) KSycoca::version();
for(KSycocaFactoryList::Iterator factory = factories()->begin();
factory != factories()->end(); ++factory)
{
qint32 aId;
qint32 aOffset;
aId = (*factory)->factoryId();
aOffset = (*factory)->offset();
(*str) << aId;
(*str) << aOffset;
}
(*str) << (qint32) 0; // No more factories.
// Jump to end of database
str->device()->seek(endOfData);
}
bool KBuildSycoca::checkDirTimestamps( const QString& dirname, const QDateTime& stamp, bool top )
{
if( top )
{
QFileInfo inf( dirname );
if( inf.lastModified() > stamp ) {
kDebug( 7021 ) << "timestamp changed:" << dirname;
return false;
}
}
QDir dir( dirname );
const QFileInfoList list = dir.entryInfoList( QDir::NoFilter, QDir::Unsorted );
if (list.isEmpty())
return true;
foreach ( const QFileInfo& fi, list ) {
if( fi.fileName() == "." || fi.fileName() == ".." )
continue;
if( fi.lastModified() > stamp )
{
kDebug( 7021 ) << "timestamp changed:" << fi.filePath();
return false;
}
if( fi.isDir() && !checkDirTimestamps( fi.filePath(), stamp, false ))
return false;
}
return true;
}
// check times of last modification of all files on which ksycoca depens,
// and also their directories
// if all of them are older than the timestamp in file ksycocastamp, this
// means that there's no need to rebuild ksycoca
bool KBuildSycoca::checkTimestamps( quint32 timestamp, const QStringList &dirs )
{
kDebug( 7021 ) << "checking file timestamps";
QDateTime stamp;
stamp.setTime_t( timestamp );
foreach(const QString &it, dirs)
{
if( !checkDirTimestamps( it, stamp, true ))
return false;
}
kDebug( 7021 ) << "timestamps check ok";
return true;
}
QStringList KBuildSycoca::existingResourceDirs()
{
static QStringList* dirs = NULL;
if( dirs != NULL )
return *dirs;
dirs = new QStringList;
g_allResourceDirs = new QStringList;
// these are all resources cached by ksycoca
QStringList resources;
resources += KBuildServiceTypeFactory::resourceTypes();
resources += KBuildMimeTypeFactory::resourceTypes();
resources += KBuildServiceGroupFactory::resourceTypes();
resources += KBuildServiceFactory::resourceTypes();
resources += KBuildProtocolInfoFactory::resourceTypes();
while( !resources.empty())
{
QString res = resources.front();
*dirs += KGlobal::dirs()->resourceDirs( res.toLatin1());
resources.removeAll( res );
}
*g_allResourceDirs = *dirs;
for( QStringList::Iterator it = dirs->begin();
it != dirs->end(); )
{
QFileInfo inf( *it );
if( !inf.exists() || !inf.isReadable() )
it = dirs->erase( it );
else
++it;
}
return *dirs;
}
static const char appFullName[] = "org.kde.kbuildsycoca";
static const char appName[] = "kbuildsycoca4";
static const char appVersion[] = "1.1";
int main(int argc, char **argv)
{
KAboutData d(appName, "kdelibs4", ki18n("KBuildSycoca"), appVersion,
ki18n("Rebuilds the system configuration cache."),
KAboutData::License_GPL, ki18n("(c) 1999-2002 KDE Developers"));
d.addAuthor(ki18n("David Faure"), ki18n("Author"), "faure@kde.org");
d.addAuthor(ki18n("Waldo Bastian"), ki18n("Author"), "bastian@kde.org");
KCmdLineOptions options;
options.add("nosignal", ki18n("Do not signal applications to update"));
options.add("noincremental", ki18n("Disable incremental update, re-read everything"));
options.add("checkstamps", ki18n("Check file timestamps"));
options.add("nocheckfiles", ki18n("Disable checking files (dangerous)"));
options.add("global", ki18n("Create global database"));
options.add("menutest", ki18n("Perform menu generation test run only"));
options.add("track <menu-id>", ki18n("Track menu id for debug purposes"));
KCmdLineArgs::init(argc, argv, &d);
KCmdLineArgs::addCmdLineOptions(options);
KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
bGlobalDatabase = args->isSet("global");
bMenuTest = args->isSet("menutest");
if (bGlobalDatabase)
{
setenv("KDEHOME", "-", 1);
setenv("KDEROOTHOME", "-", 1);
}
QCoreApplication k(argc, argv);
KComponentData mainComponent(d);
KCrash::setCrashHandler(crashHandler);
// force generating of KLocale object. if not, the database will get
// be translated
KGlobal::locale();
KGlobal::dirs()->addResourceType("app-reg", 0, "share/application-registry" );
while(QDBusConnection::sessionBus().isConnected())
{
// kapp registered already, but with the PID in the name.
// We need to re-register without it, to detect already-running kbuildsycoca instances.
if (QDBusConnection::sessionBus().interface()->registerService(appFullName, QDBusConnectionInterface::QueueService)
!= QDBusConnectionInterface::ServiceQueued)
{
break; // Go
}
fprintf(stderr, "Waiting for already running %s to finish.\n", appName);
QEventLoop eventLoop;
QObject::connect(QDBusConnection::sessionBus().interface(), SIGNAL(serviceRegistered(QString)),
&eventLoop, SLOT(quit()));
eventLoop.exec( QEventLoop::ExcludeUserInputEvents );
}
fprintf(stderr, "%s running...\n", appName);
bool checkfiles = bGlobalDatabase || args->isSet("checkfiles");
bool incremental = !bGlobalDatabase && args->isSet("incremental") && checkfiles;
if (incremental || !checkfiles)
{
KSycoca::disableAutoRebuild(); // Prevent deadlock
QString current_language = KGlobal::locale()->language();
QString ksycoca_language = KSycoca::self()->language();
quint32 current_update_sig = KGlobal::dirs()->calcResourceHash("services", "update_ksycoca",
KStandardDirs::Recursive );
quint32 ksycoca_update_sig = KSycoca::self()->updateSignature();
QString current_prefixes = KGlobal::dirs()->kfsstnd_prefixes();
QString ksycoca_prefixes = KSycoca::self()->kfsstnd_prefixes();
if ((current_update_sig != ksycoca_update_sig) ||
(current_language != ksycoca_language) ||
(current_prefixes != ksycoca_prefixes) ||
(KSycoca::self()->timeStamp() == 0))
{
incremental = false;
checkfiles = true;
KBuildSycoca::clearCaches();
}
}
bool checkstamps = incremental && args->isSet("checkstamps") && checkfiles;
quint32 filestamp = 0;
QStringList oldresourcedirs;
if( checkstamps && incremental )
{
QString path = sycocaPath()+"stamp";
g_sycocaPath = QFile::encodeName(path); // Delete timestamps on crash
QFile ksycocastamp(path);
if( ksycocastamp.open( QIODevice::ReadOnly ))
{
QDataStream str( &ksycocastamp );
if (!str.atEnd())
str >> filestamp;
if (!str.atEnd())
{
str >> oldresourcedirs;
if( oldresourcedirs != KBuildSycoca::existingResourceDirs())
checkstamps = false;
}
else
{
checkstamps = false;
}
if (!str.atEnd())
{
QStringList extraResourceDirs;
str >> extraResourceDirs;
oldresourcedirs += extraResourceDirs;
}
}
else
{
checkstamps = false;
}
g_sycocaPath.clear();
}
newTimestamp = (quint32) time(0);
QStringList changedResources;
if( checkfiles && ( !checkstamps || !KBuildSycoca::checkTimestamps( filestamp, oldresourcedirs )))
{
g_sycocaPath = QFile::encodeName(sycocaPath());
g_allEntries = 0;
g_ctimeDict = 0;
if (incremental)
{
kDebug(7021) << "Reusing existing ksycoca";
KSycoca::self();
KSycocaFactoryList *factories = new KSycocaFactoryList;
g_allEntries = new KSycocaEntryListList;
g_ctimeDict = new KCTimeDict;
// Must be in same order as in KBuildSycoca::recreate()!
factories->append( new KServiceTypeFactory );
factories->append( new KMimeTypeFactory );
factories->append( new KServiceGroupFactory );
factories->append( new KServiceFactory );
factories->append( new KProtocolInfoFactory );
// For each factory
for (KSycocaFactoryList::Iterator factory = factories->begin();
factory != factories->end(); ++factory)
{
const KSycocaEntry::List list = (*factory)->allEntries();
g_allEntries->append( list );
}
delete factories; factories = 0;
KCTimeInfo *ctimeInfo = new KCTimeInfo;
*g_ctimeDict = ctimeInfo->loadDict();
}
g_sycocaPath.clear();
KBuildSycoca *sycoca = new KBuildSycoca; // Build data base (deletes oldSycoca)
if (args->isSet("track"))
sycoca->setTrackId(args->getOption("track"));
if (!sycoca->recreate()) {
return -1;
}
changedResources = sycoca->changedResources();
if (bGlobalDatabase)
{
// These directories may have been created with 0700 permission
// better delete them if they are empty
QString servicetypesDir = KGlobal::dirs()->saveLocation("servicetypes", QString(), false);
::rmdir(QFile::encodeName(servicetypesDir));
}
}
if (args->isSet("signal"))
{
// Notify ALL applications that have a ksycoca object, using a signal
changedResources.removeDuplicates();
QDBusMessage signal = QDBusMessage::createSignal("/", "org.kde.KSycoca", "notifyDatabaseChanged" );
signal << changedResources;
if (QDBusConnection::sessionBus().isConnected()) {
kDebug() << "Emitting notifyDatabaseChanged" << changedResources;
QDBusConnection::sessionBus().send(signal);
qApp->processEvents(); // make sure the dbus signal is sent before we quit.
}
}
return 0;
}
#include "moc_kbuildsycoca.cpp"