Extend JSON QStandardPaths to support multiple paths per location
Allow a location to be specified as an array of paths.
LOCATION: ["first", "second"]
The first value is selected for writableLocation().
Define the first entry as an empty string for no writable path.
LOCATION: ["", "second"]
A single path may be expressed as a string.
LOCATION: "only"
Change-Id: I897cf40a039ad7cb680bdf643bfa78020e8eb1cb
Reviewed-by: Lincoln Ramsay <lincoln.ramsay@nokia.com>
Reviewed-by: David Faure <faure@kde.org>
bb10
parent
a85d15259c
commit
cd89b164a5
|
|
@ -40,15 +40,18 @@
|
|||
****************************************************************************/
|
||||
#include "qstandardpaths.h"
|
||||
|
||||
#include <QRegExp>
|
||||
#include <QString>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QJsonArray>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QAtomicPointer>
|
||||
#include <QCoreApplication>
|
||||
#include <QRegularExpression>
|
||||
#include <QRegularExpressionMatchIterator>
|
||||
#include <QRegularExpressionMatch>
|
||||
|
||||
#ifndef QT_NO_STANDARDPATHS
|
||||
|
||||
|
|
@ -65,6 +68,49 @@ Q_GLOBAL_STATIC(QStandardPathsPrivate, configCache);
|
|||
|
||||
static bool qsp_testMode = false;
|
||||
|
||||
/*!
|
||||
\internal
|
||||
Substitute environment variables in the form ${name}
|
||||
|
||||
The JSON QStandardPaths implementation can be configured on a per user
|
||||
(or per application) basis through the use of environment variables,
|
||||
which are evaluated each time a location is queried. This function
|
||||
performs that evaluation on \a value. No substitution is performed
|
||||
for undefined variables.
|
||||
|
||||
This slightly underselects according to the 2009-09-20 version of
|
||||
the GNU setenv(3) manual page: It disallows '}' within the variable
|
||||
name. ${var}} will look for a variable named "var", not "var}".
|
||||
*/
|
||||
static QString substituteEnvVars(const QJsonValue & value)
|
||||
{
|
||||
QString str = value.toString();
|
||||
if (str.isEmpty() || !str.contains(QLatin1String("${")))
|
||||
return str;
|
||||
|
||||
// optimize for a common case
|
||||
str.replace(QLatin1String("${HOME}"), QDir::homePath());
|
||||
|
||||
// Do ${} format environment variable substitution if necessary
|
||||
// repeat this test because ${HOME} might expand to the empty string
|
||||
if (!str.isEmpty() && str.contains(QLatin1String("${"))) {
|
||||
QRegularExpression varRegExp(QLatin1String("\\$\\{([^\\}=]*)\\}"));
|
||||
QRegularExpressionMatchIterator matchIterator =
|
||||
varRegExp.globalMatch(str);
|
||||
while (matchIterator.hasNext()) {
|
||||
QRegularExpressionMatch match = matchIterator.next();
|
||||
QByteArray envValue =
|
||||
qgetenv(match.captured(1).toLatin1().data());
|
||||
if (!envValue.isNull()) {
|
||||
QString replacement =
|
||||
QFile::decodeName(envValue);
|
||||
str.replace(match.captured(0), replacement);
|
||||
}
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
void QStandardPaths::enableTestMode(bool testMode)
|
||||
{
|
||||
qsp_testMode = testMode;
|
||||
|
|
@ -81,12 +127,20 @@ static void appendOrganizationAndApp(QString &path)
|
|||
}
|
||||
|
||||
QString QStandardPaths::writableLocation(StandardLocation type)
|
||||
{
|
||||
QStringList locations = QStandardPaths::standardLocations(type);
|
||||
if (locations.isEmpty())
|
||||
return QString();
|
||||
return locations.first();
|
||||
}
|
||||
|
||||
QStringList QStandardPaths::standardLocations(StandardLocation type)
|
||||
{
|
||||
switch (type) {
|
||||
case HomeLocation:
|
||||
return QDir::homePath(); // set $HOME
|
||||
return QStringList(QDir::homePath()); // set $HOME
|
||||
case TempLocation:
|
||||
return QDir::tempPath(); // set $TMPDIR
|
||||
return QStringList(QDir::tempPath()); // set $TMPDIR
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -100,15 +154,15 @@ QString QStandardPaths::writableLocation(StandardLocation type)
|
|||
path = qttestDir + QLatin1String("/share");
|
||||
if (type == DataLocation)
|
||||
appendOrganizationAndApp(path);
|
||||
return path;
|
||||
return QStringList(path);
|
||||
case GenericCacheLocation:
|
||||
case CacheLocation:
|
||||
path = qttestDir + QLatin1String("/cache");
|
||||
if (type == CacheLocation)
|
||||
appendOrganizationAndApp(path);
|
||||
return path;
|
||||
return QStringList(path);
|
||||
case ConfigLocation:
|
||||
return qttestDir + QLatin1String("/config");
|
||||
return QStringList(qttestDir + QLatin1String("/config"));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -124,7 +178,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
|
|||
if (file.open(QIODevice::ReadOnly)) {
|
||||
QJsonDocument configDoc = QJsonDocument::fromJson(file.readAll());
|
||||
if (configDoc.isNull())
|
||||
return QString();
|
||||
return QStringList();
|
||||
|
||||
QJsonObject myConfigObject = configDoc.object();
|
||||
localConfigObject = new QJsonObject(myConfigObject);
|
||||
|
|
@ -133,7 +187,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
|
|||
localConfigObject = configCache()->object.loadAcquire();
|
||||
}
|
||||
} else {
|
||||
return QString();
|
||||
return QStringList();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -184,35 +238,26 @@ QString QStandardPaths::writableLocation(StandardLocation type)
|
|||
break;
|
||||
|
||||
default:
|
||||
return QString();
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
QJsonObject::const_iterator iter = localConfigObject->constFind(key);
|
||||
if (iter == localConfigObject->constEnd() || ! iter.value().isString())
|
||||
return QString();
|
||||
QString value = iter.value().toString();
|
||||
if (iter == localConfigObject->constEnd())
|
||||
return QStringList();
|
||||
|
||||
// optimize for a common case
|
||||
value.replace(QLatin1String("${HOME}"), QDir::homePath());
|
||||
|
||||
// Do ${} format environment variable substitution if necessary
|
||||
if (!value.isEmpty() && value.contains(QLatin1String("${"))) {
|
||||
QRegExp varRegExp(QLatin1String("\\$\\{([^\\}]*)\\}"));
|
||||
while (value.contains(varRegExp)) {
|
||||
QString replacement =
|
||||
QFile::decodeName(qgetenv(varRegExp.cap(1).toLatin1().data()));
|
||||
value.replace(varRegExp.cap(0), replacement);
|
||||
}
|
||||
switch (iter.value().type()) {
|
||||
case QJsonValue::Array: {
|
||||
QStringList resultList;
|
||||
foreach (const QJsonValue &item, iter.value().toArray())
|
||||
resultList.append(substituteEnvVars(item));
|
||||
return resultList;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
QStringList QStandardPaths::standardLocations(StandardLocation type)
|
||||
{
|
||||
QStringList dirs;
|
||||
const QString localDir = writableLocation(type);
|
||||
dirs.prepend(localDir);
|
||||
return dirs;
|
||||
case QJsonValue::String:
|
||||
return QStringList(substituteEnvVars(iter.value()));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
|||
Loading…
Reference in New Issue