[kde-doc-english] [kservice] /: KSycoca: change DB filename to include language and sha1 of the dirs it's built from.
David Faure
faure at kde.org
Sun Sep 20 17:15:50 UTC 2015
Git commit f1bdf30501b87cb79806362a68c7515ba755275a by David Faure.
Committed on 20/09/2015 at 10:26.
Pushed by dfaure into branch 'master'.
KSycoca: change DB filename to include language and sha1 of the dirs it's built from.
This will prevent sycoca-rebuild ping-pong if two apps with different settings
would share the same file (and keep finding that it's wrong for them),
and it fixes Albert's bug that "LANG=de kcmshell5 --list" doesn't show German
translations for the strings coming from desktop files.
To avoid migration issues, the old filename ksycoca5 is still provided, as a hardlink
so that mmap works.
REVIEW: 125279
BUGS: 340731, 335780
FIXED-IN: 5.15
M +18 -7 autotests/ksycocatest.cpp
M +1 -1 docs/kbuildsycoca5/man-kbuildsycoca5.8.docbook
M +16 -0 src/sycoca/kbuildsycoca.cpp
M +15 -8 src/sycoca/ksycoca.cpp
M +1 -0 src/sycoca/ksycoca.h
http://commits.kde.org/kservice/f1bdf30501b87cb79806362a68c7515ba755275a
diff --git a/autotests/ksycocatest.cpp b/autotests/ksycocatest.cpp
index 7c2d91e..56a202f 100644
--- a/autotests/ksycocatest.cpp
+++ b/autotests/ksycocatest.cpp
@@ -18,6 +18,7 @@
*/
#include <ksycoca.h>
+#include <ksycoca_p.h>
#include <QTemporaryDir>
#include <QTest>
#include <QDebug>
@@ -27,6 +28,7 @@
#include <QSignalSpy>
#include <QProcess>
#include <kservice.h>
+#include <kservicefactory_p.h>
class KSycocaTest : public QObject
{
@@ -42,7 +44,11 @@ private Q_SLOTS:
// we don't need the services dir -> ensure there isn't one, so we can check allResourceDirs below.
QDir(servicesDir()).removeRecursively();
+ QSignalSpy spy(KSycoca::self(), SIGNAL(databaseChanged(QStringList)));
runKBuildSycoca(QProcessEnvironment::systemEnvironment());
+ qDebug() << "waiting for signal";
+ QVERIFY(spy.wait(10000));
+ qDebug() << "got signal";
}
void testAllResourceDirs();
void testOtherAppDir();
@@ -60,7 +66,6 @@ QTEST_MAIN(KSycocaTest)
void KSycocaTest::runKBuildSycoca(const QProcessEnvironment &environment)
{
- QSignalSpy spy(KSycoca::self(), SIGNAL(databaseChanged(QStringList)));
QProcess proc;
const QString kbuildsycoca = QStandardPaths::findExecutable(KBUILDSYCOCA_EXENAME);
QVERIFY(!kbuildsycoca.isEmpty());
@@ -72,15 +77,11 @@ void KSycocaTest::runKBuildSycoca(const QProcessEnvironment &environment)
proc.waitForFinished();
QCOMPARE(proc.exitStatus(), QProcess::NormalExit);
-
- qDebug() << "waiting for signal";
- QVERIFY(spy.wait(10000));
- qDebug() << "got signal";
}
void KSycocaTest::testAllResourceDirs()
{
- // Dirs that exist and dirs that don't exist, should both in allResourceDirs().
+ // Dirs that exist and dirs that don't exist, should both be in allResourceDirs().
const QStringList dirs = KSycoca::self()->allResourceDirs();
QVERIFY2(dirs.contains(servicesDir()), qPrintable(dirs.join(',')));
QVERIFY2(dirs.contains(serviceTypesDir()), qPrintable(dirs.join(',')));
@@ -126,7 +127,17 @@ void KSycocaTest::testOtherAppDir()
}
#endif
- QVERIFY(KService::serviceByStorageId("test_app_other.desktop"));
+ // This is still NOT available. kbuildsycoca created a different DB file, the one we read from hasn't changed.
+ // Changing XDG_DATA_DIRS at runtime isn't supported, so this test isn't doing what apps would do.
+ // The point however is that another app using different dirs cannot mess up our DB.
+ QVERIFY(!KService::serviceByStorageId("test_app_other.desktop"));
+
+ // Check here what the other app would see, by creating another sycoca instance.
+ KSycoca otherAppSycoca;
+ // do what serviceByStorageId does:
+ otherAppSycoca.ensureCacheValid();
+ QVERIFY(otherAppSycoca.d->serviceFactory()->findServiceByStorageId("test_app_other.desktop"));
+ QVERIFY(otherAppSycoca.d->m_databasePath != KSycoca::self()->d->m_databasePath); // check that they use a different filename
}
#include "ksycocatest.moc"
diff --git a/docs/kbuildsycoca5/man-kbuildsycoca5.8.docbook b/docs/kbuildsycoca5/man-kbuildsycoca5.8.docbook
index d7f8581..03add7a 100644
--- a/docs/kbuildsycoca5/man-kbuildsycoca5.8.docbook
+++ b/docs/kbuildsycoca5/man-kbuildsycoca5.8.docbook
@@ -166,7 +166,7 @@ Show version information.
<title>Files</title>
<variablelist>
<varlistentry>
-<term><filename><varname>cachedir</varname>/ksycoca5</filename></term>
+<term><filename><varname>cachedir</varname>/ksycoca5_[lang]_[sha1-of-dirs]</filename></term>
<listitem>
<para>The KService cache generated by <command>kbuildsycoca5</command>. On Unix systems, <varname>cachedir</varname>
is typically <filename class="directory"><envar>XDG_CONFIG_HOME</envar></filename></para>
diff --git a/src/sycoca/kbuildsycoca.cpp b/src/sycoca/kbuildsycoca.cpp
index d3328f0..ccb9350 100644
--- a/src/sycoca/kbuildsycoca.cpp
+++ b/src/sycoca/kbuildsycoca.cpp
@@ -448,6 +448,21 @@ bool KBuildSycoca::recreate(bool incremental)
qCWarning(SYCOCA) << "ERROR writing database" << database.fileName() << ". Disk full?";
return false;
}
+
+ if (!m_globalDatabase) {
+ // Compatibility code for KF < 5.15: provide a ksycoca5 symlink after the filename change, for old apps to keep working during the upgrade
+ const QString oldSycoca = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QLatin1String("/ksycoca5");
+ if (QFile::exists(oldSycoca)) {
+ QFile::remove(oldSycoca);
+#ifdef Q_OS_UNIX
+ if (::link(QFile::encodeName(path).constData(), QFile::encodeName(oldSycoca).constData()) != 0) {
+ QFile::copy(path, oldSycoca);
+ }
+#else
+ QFile::copy(path, oldSycoca);
+#endif
+ }
+ }
} else {
delete str;
str = 0;
@@ -615,6 +630,7 @@ quint32 KBuildSycoca::calcResourceHash(const QString &resourceSubDir, const QStr
bool KBuildSycoca::checkGlobalHeader()
{
+ // Since it's part of the filename, we are 99% sure that the locale and prefixes will match.
const QString current_language = QLocale().bcp47Name();
const quint32 current_update_sig = KBuildSycoca::calcResourceHash(QStringLiteral("kservices5"), QStringLiteral("update_ksycoca"));
const QString current_prefixes = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation).join(QString(QLatin1Char(':')));
diff --git a/src/sycoca/ksycoca.cpp b/src/sycoca/ksycoca.cpp
index a2b7040..0035f97 100644
--- a/src/sycoca/ksycoca.cpp
+++ b/src/sycoca/ksycoca.cpp
@@ -43,6 +43,7 @@
#include <kservicetypefactory_p.h>
#include <kservicegroupfactory_p.h>
#include <kservicefactory_p.h>
+#include <QCryptographicHash>
#include "kbuildsycoca_p.h"
#include "ksycocadevices_p.h"
@@ -54,11 +55,6 @@
*/
#define KSYCOCA_VERSION 302
-/**
- * Sycoca file name, used internally (by kbuildsycoca)
- */
-#define KSYCOCA_FILENAME "ksycoca5"
-
#if HAVE_MADVISE || HAVE_MMAP
#include <sys/mman.h> // This #include was checked when looking for posix_madvise
#endif
@@ -684,17 +680,28 @@ quint32 KSycoca::updateSignature()
QString KSycoca::absoluteFilePath(DatabaseType type)
{
+ const QString paths = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation).join(QString(QLatin1Char(':')));
+ QString suffix = QLatin1Char('_') + QLocale().bcp47Name();
+
if (type == GlobalDatabase) {
- QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QString::fromLatin1("kservices5/" KSYCOCA_FILENAME));
+ const QString fileName = QStringLiteral("ksycoca5") + suffix;
+ QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kservices5/") + fileName);
if (path.isEmpty()) {
- return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QString::fromLatin1("/kservices5/" KSYCOCA_FILENAME);
+ return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/kservices5/") + fileName;
}
return path;
}
const QByteArray ksycoca_env = qgetenv("KDESYCOCA");
if (ksycoca_env.isEmpty()) {
- return QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QLatin1Char('/') + QString::fromLatin1(KSYCOCA_FILENAME);
+ const QByteArray pathHash = QCryptographicHash::hash(paths.toUtf8(), QCryptographicHash::Sha1);
+ suffix += QLatin1Char('_') + QString::fromLatin1(pathHash.toBase64());
+ suffix.replace('/', '_');
+#ifdef Q_OS_WIN
+ suffix.replace(':', '_');
+#endif
+ const QString fileName = QStringLiteral("ksycoca5") + suffix;
+ return QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + QLatin1Char('/') + fileName;
} else {
return QFile::decodeName(ksycoca_env);
}
diff --git a/src/sycoca/ksycoca.h b/src/sycoca/ksycoca.h
index 34a2f63..c0c3502 100644
--- a/src/sycoca/ksycoca.h
+++ b/src/sycoca/ksycoca.h
@@ -244,6 +244,7 @@ private:
friend class KBuildSycoca;
friend class Kded;
friend class KSycocaPrivate;
+ friend class KSycocaTest;
Q_DISABLE_COPY(KSycoca)
KSycocaPrivate *const d;
More information about the kde-doc-english
mailing list