27 #include <config-kded.h>
38 #include <QtCore/QDataStream>
39 #include <QtCore/QDir>
40 #include <QtCore/QEventLoop>
41 #include <QtCore/QFile>
42 #include <QtCore/QTimer>
43 #include <QtDBus/QtDBus>
56 #ifndef KBUILDSYCOCA_NO_KCRASH
113 KSycocaEntry::Ptr KBuildSycoca::createEntry(
const QString &file,
bool addToFactory)
118 timeStamp = KGlobal::dirs()->calcResourceHash(
g_resource, file,
121 KSycocaEntry::Ptr entry;
127 if (timeStamp && (timeStamp == oldTimestamp))
130 if (g_currentFactory == g_buildServiceGroupFactory)
132 entry = g_currentEntryDict->value(file.left(file.length()-10));
134 entry = g_currentEntryDict->value(file);
139 if (file.contains(
"fake"))
140 kDebug(7021) <<
g_resource <<
"reusing (and removing) old entry [\"fake\"] for:" << file;
143 else if (oldTimestamp)
161 if ( entry && entry->isValid() )
164 g_currentFactory->addEntry(entry);
169 return KSycocaEntry::Ptr();
174 KSycocaEntry::Ptr entry = createEntry(path,
false);
179 bool KBuildSycoca::build()
182 KBSEntryDictList entryDictList;
195 const KSycocaEntry::List
list = (*g_allEntries)[i++];
196 for( KSycocaEntry::List::const_iterator it = list.begin();
200 entryDict->insert( (*it)->entryPath(), *it );
204 serviceEntryDict = entryDict;
206 g_serviceGroupEntryDict = entryDict;
207 entryDictList.append(entryDict);
220 for( KSycocaResourceList::ConstIterator it1 = list->constBegin();
221 it1 != list->constEnd();
225 if (!allResources.contains(res.
resource))
231 bool uptodate =
true;
233 for( QStringList::ConstIterator it1 = allResources.constBegin();
234 it1 != allResources.constEnd();
242 (void) KGlobal::dirs()->findAllResources(
g_resource,
251 KBSEntryDictList::const_iterator ed_it = entryDictList.begin();
252 const KBSEntryDictList::const_iterator ed_end = entryDictList.end();
253 KSycocaFactoryList::const_iterator it =
factories()->constBegin();
254 const KSycocaFactoryList::const_iterator
end =
factories()->constEnd();
255 for ( ; it != end; ++it, ++ed_it )
257 g_currentFactory = (*it);
259 g_currentEntryDict = ed_it == ed_end ? 0 : *ed_it;
264 for( KSycocaResourceList::ConstIterator it2 = list->constBegin();
265 it2 != list->constEnd();
269 if (res.
resource != (*it1))
continue;
272 for( QStringList::ConstIterator it3 = relFiles.constBegin();
273 it3 != relFiles.constEnd();
278 createEntry(*it3,
true);
282 if (g_changed || !g_allEntries)
290 bool result = !uptodate || (g_ctimeDict && !g_ctimeDict->
isEmpty());
291 if (g_ctimeDict && !g_ctimeDict->
isEmpty()) {
299 kDebug() <<
"Still in the time dict (i.e. deleted files)" << resources;
300 m_changedResources += resources;
303 if (result || bMenuTest)
307 g_currentEntryDict = serviceEntryDict;
310 g_vfolder =
new VFolderMenu(g_serviceFactory,
this);
311 if (!m_trackId.isEmpty())
323 if (g_changed || !g_allEntries)
334 qDeleteAll(entryDictList);
347 if (directoryFile.isEmpty())
348 directoryFile = subName+
".directory";
351 timeStamp = KGlobal::dirs()->calcResourceHash(
g_resource, directoryFile,
360 if (timeStamp && (timeStamp == oldTimestamp))
362 KSycocaEntry::Ptr
group = g_serviceGroupEntryDict->value(subName);
366 if (entry->directoryEntryPath() != directoryFile)
375 if (! (bMenuTest && entry->noDisplay()) )
376 createMenu(caption + entry->caption() +
'/', subName, subMenu);
378 if (caption.isEmpty())
387 printf(
"%s\t%s\t%s\n", qPrintable( caption ), qPrintable( p->
menuId() ), qPrintable(
KStandardDirs::locate(
"apps", p->entryPath() ) ) );
403 bool openedOK = database.
open();
404 if (!openedOK && database.
error() == QFile::PermissionsError && QFile::exists(path))
406 QFile::remove( path );
407 openedOK = database.
open();
411 fprintf(stderr,
"kbuildsycoca4: ERROR creating database '%s'! %s\n",
412 path.toLocal8Bit().data(), database.
errorString().toLocal8Bit().data());
416 QDataStream* str =
new QDataStream(&database);
417 str->setVersion(QDataStream::Qt_3_1);
419 kDebug(7021).nospace() <<
"Recreating ksycoca file (" << path <<
", version " <<
KSycoca::version() <<
")";
432 if (str->status() != QDataStream::Ok)
438 fprintf(stderr,
"kbuildsycoca4: ERROR writing database '%s'!\n", database.
fileName().toLocal8Bit().data());
439 fprintf(stderr,
"kbuildsycoca4: Disk full?\n");
450 kDebug(7021) <<
"Database is up to date";
453 if (!bGlobalDatabase)
456 QString stamppath = path +
"stamp";
457 QFile ksycocastamp(stamppath);
458 ksycocastamp.open( QIODevice::WriteOnly );
459 QDataStream str( &ksycocastamp );
460 str.setVersion(QDataStream::Qt_3_1);
472 void KBuildSycoca::save(QDataStream* str)
475 str->device()->seek(0);
487 aId = (*factory)->factoryId();
488 if ( aId == KST_KServiceTypeFactory )
489 servicetypeFactory = *factory;
490 else if ( aId == KST_KMimeTypeFactory )
492 else if ( aId == KST_KServiceFactory )
494 aOffset = (*factory)->offset();
500 (*str) << KGlobal::dirs()->kfsstnd_prefixes();
502 (*str) << KGlobal::locale()->language();
503 (*str) << KGlobal::dirs()->calcResourceHash(
"services",
"update_ksycoca",
505 (*str) << (*g_allResourceDirs);
518 (*factory)->save(*str);
519 if (str->status() != QDataStream::Ok)
523 int endOfData = str->device()->pos();
526 str->device()->seek(0);
530 factory !=
factories()->end(); ++factory)
534 aId = (*factory)->factoryId();
535 aOffset = (*factory)->offset();
542 str->device()->seek(endOfData);
545 bool KBuildSycoca::checkDirTimestamps(
const QString& dirname,
const QDateTime& stamp,
bool top )
549 QFileInfo inf( dirname );
550 if( inf.lastModified() > stamp ) {
551 kDebug( 7021 ) <<
"timestamp changed:" << dirname;
556 const QFileInfoList list =
dir.entryInfoList( QDir::NoFilter, QDir::Unsorted );
560 foreach (
const QFileInfo& fi, list ) {
561 if( fi.fileName() ==
"." || fi.fileName() ==
".." )
563 if( fi.lastModified() > stamp )
565 kDebug( 7201 ) <<
"timestamp changed:" << fi.filePath();
568 if( fi.isDir() && !checkDirTimestamps( fi.filePath(), stamp, false ))
580 kDebug( 7021 ) <<
"checking file timestamps";
582 stamp.setTime_t( timestamp );
583 for( QStringList::ConstIterator it = dirs.begin();
587 if( !checkDirTimestamps( *it, stamp,
true ))
590 kDebug( 7021 ) <<
"timestamps check ok";
608 while( !resources.empty())
610 QString res = resources.front();
611 *dirs += KGlobal::dirs()->resourceDirs( res.toLatin1());
612 resources.removeAll( res );
615 *g_allResourceDirs = *dirs;
617 for( QStringList::Iterator it = dirs->begin();
620 QFileInfo inf( *it );
621 if( !inf.exists() || !inf.isReadable() )
622 it = dirs->erase( it );
630 static const char appName[] =
"kbuildsycoca4";
636 ki18n(
"Rebuilds the system configuration cache."),
642 options.
add(
"nosignal",
ki18n(
"Do not signal applications to update"));
643 options.
add(
"noincremental",
ki18n(
"Disable incremental update, re-read everything"));
644 options.
add(
"checkstamps",
ki18n(
"Check file timestamps"));
645 options.
add(
"nocheckfiles",
ki18n(
"Disable checking files (dangerous)"));
646 options.
add(
"global",
ki18n(
"Create global database"));
647 options.
add(
"menutest",
ki18n(
"Perform menu generation test run only"));
648 options.
add(
"track <menu-id>",
ki18n(
"Track menu id for debug purposes"));
653 bGlobalDatabase = args->
isSet(
"global");
654 bMenuTest = args->
isSet(
"menutest");
658 setenv(
"KDEHOME",
"-", 1);
659 setenv(
"KDEROOTHOME",
"-", 1);
662 QCoreApplication k(argc, argv);
665 #ifndef KBUILDSYCOCA_NO_KCRASH
666 KCrash::setCrashHandler(KCrash::defaultCrashHandler);
668 KCrash::setApplicationName(
QString(appName));
674 KGlobal::dirs()->addResourceType(
"app-reg", 0,
"share/application-registry" );
676 while(QDBusConnection::sessionBus().isConnected())
680 if (QDBusConnection::sessionBus().interface()->registerService(appFullName, QDBusConnectionInterface::QueueService)
681 != QDBusConnectionInterface::ServiceQueued)
685 fprintf(stderr,
"Waiting for already running %s to finish.\n", appName);
687 QEventLoop eventLoop;
688 QObject::connect(QDBusConnection::sessionBus().interface(), SIGNAL(serviceRegistered(
QString)),
689 &eventLoop, SLOT(
quit()));
690 eventLoop.exec( QEventLoop::ExcludeUserInputEvents );
692 fprintf(stderr,
"%s running...\n", appName);
694 bool checkfiles = bGlobalDatabase || args->
isSet(
"checkfiles");
696 bool incremental = !bGlobalDatabase && args->
isSet(
"incremental") && checkfiles;
697 if (incremental || !checkfiles)
700 QString current_language = KGlobal::locale()->language();
702 quint32 current_update_sig = KGlobal::dirs()->calcResourceHash(
"services",
"update_ksycoca",
705 QString current_prefixes = KGlobal::dirs()->kfsstnd_prefixes();
708 if ((current_update_sig != ksycoca_update_sig) ||
709 (current_language != ksycoca_language) ||
710 (current_prefixes != ksycoca_prefixes) ||
719 bool checkstamps = incremental && args->
isSet(
"checkstamps") && checkfiles;
722 if( checkstamps && incremental )
725 QByteArray qPath = QFile::encodeName(path);
727 QFile ksycocastamp(path);
728 if( ksycocastamp.open( QIODevice::ReadOnly ))
730 QDataStream str( &ksycocastamp );
731 str.setVersion(QDataStream::Qt_3_1);
737 str >> oldresourcedirs;
748 str >> extraResourceDirs;
749 oldresourcedirs += extraResourceDirs;
759 newTimestamp = (
quint32) time(0);
764 QByteArray qSycocaPath = QFile::encodeName(
sycocaPath());
771 kDebug(7021) <<
"Reusing existing ksycoca";
785 for (KSycocaFactoryList::Iterator factory = factories->begin();
786 factory != factories->end(); ++factory)
788 const KSycocaEntry::List list = (*factory)->allEntries();
789 g_allEntries->append( list );
791 delete factories; factories = 0;
793 *g_ctimeDict = ctimeInfo->
loadDict();
798 if (args->
isSet(
"track"))
809 QString applnkDir = KGlobal::dirs()->saveLocation(
"apps",
QString(),
false);
810 ::rmdir(QFile::encodeName(applnkDir));
811 QString servicetypesDir = KGlobal::dirs()->saveLocation(
"servicetypes",
QString(),
false);
812 ::rmdir(QFile::encodeName(servicetypesDir));
816 if (args->
isSet(
"signal"))
819 QDBusMessage signal = QDBusMessage::createSignal(
"/",
"org.kde.KSycoca",
"notifyDatabaseChanged" );
820 signal << changedResources;
822 if (QDBusConnection::sessionBus().isConnected()) {
823 kDebug() <<
"Emitting notifyDatabaseChanged" << changedResources;
824 QDBusConnection::sessionBus().send(signal);
825 qApp->processEvents();
832 #include "kbuildsycoca.moc"