FEATURE: fallback paths for the contents prefixes as well.

this is basically a merge of http://reviewboard.kde.org/r/5765/ with http://svn.reviewboard.kde.org/r/5763

svn path=/trunk/KDE/kdelibs/; revision=1193135
This commit is contained in:
Marco Martin 2010-11-04 19:18:32 +00:00
parent c09422cc8c
commit 5e9d88496a
3 changed files with 109 additions and 49 deletions

View File

@ -158,15 +158,23 @@ Package &Package::operator=(const Package &rhs)
bool Package::isValid() const
{
if (!d->valid) {
if (!d->valid || d->structure->contentsPrefixPaths().isEmpty()) {
return false;
}
//search for the file in all prefixes and in all possible paths for each prefix
//even if it's a big nested loop, usually there is one prefix and one location
//so shouldn't cause too much disk access
foreach (const char *dir, d->structure->requiredDirectories()) {
bool failed = true;
foreach (const QString &path, d->structure->searchPath(dir)) {
if (QFile::exists(d->structure->path() + d->structure->contentsPrefix() + path)) {
failed = false;
foreach (const QString &prefix, d->structure->contentsPrefixPaths()) {
if (QFile::exists(d->structure->path() + prefix + path)) {
failed = false;
break;
}
}
if (!failed) {
break;
}
}
@ -181,8 +189,13 @@ bool Package::isValid() const
foreach (const char *file, d->structure->requiredFiles()) {
bool failed = true;
foreach (const QString &path, d->structure->searchPath(file)) {
if (QFile::exists(d->structure->path() + d->structure->contentsPrefix() + path)) {
failed = false;
foreach (const QString &prefix, d->structure->contentsPrefixPaths()) {
if (QFile::exists(d->structure->path() + prefix + path)) {
failed = false;
break;
}
}
if (!failed) {
break;
}
}
@ -213,28 +226,35 @@ QString Package::filePath(const char *fileType, const QString &filename) const
//kDebug() << "no matching path came of it, while looking for" << fileType << filename;
return QString();
}
//when filetype is empty paths is always empty, so try with an empty string
} else {
paths << QString();
}
const QString prefix(d->structure->path() + d->structure->contentsPrefix());
//Nested loop, but in the medium case resolves to just one iteration
foreach (const QString &contentsPrefix, d->structure->contentsPrefixPaths()) {
const QString prefix(d->structure->path() + contentsPrefix);
foreach (const QString &path, paths) {
QString file = prefix + path;
foreach (const QString &path, paths) {
QString file = prefix + path;
if (!filename.isEmpty()) {
file.append("/").append(filename);
}
if (QFile::exists(file)) {
if (d->structure->allowExternalPaths()) {
return file;
if (!filename.isEmpty()) {
file.append("/").append(filename);
}
// ensure that we don't return files outside of our base path
// due to symlink or ../ games
QDir dir(file);
QString canonicalized = dir.canonicalPath() + QDir::separator();
if (canonicalized.startsWith(d->structure->path())) {
return file;
if (QFile::exists(file)) {
if (d->structure->allowExternalPaths()) {
return file;
}
// ensure that we don't return files outside of our base path
// due to symlink or ../ games
QDir dir(file);
QString canonicalized = dir.canonicalPath() + QDir::separator();
if (canonicalized.startsWith(d->structure->path())) {
return file;
}
}
}
}
@ -351,13 +371,6 @@ QString Package::contentsHash() const
return QString();
}
const QString basePath = d->structure->path() + d->structure->contentsPrefix();
QDir dir(basePath);
if (!dir.exists()) {
return QString();
}
QCA::Hash hash("sha1");
QString metadataPath = d->structure->path() + "metadata.desktop";
if (QFile::exists(metadataPath)) {
@ -373,7 +386,16 @@ QString Package::contentsHash() const
kWarning() << "no metadata at" << metadataPath;
}
d->updateHash(basePath, QString(), dir, hash);
foreach (QString prefix, d->structure->contentsPrefixPaths()) {
const QString basePath = d->structure->path() + prefix;
QDir dir(basePath);
if (!dir.exists()) {
return QString();
}
d->updateHash(basePath, QString(), dir, hash);
}
return QCA::arrayToHex(hash.final().toByteArray());
#else
// no QCA2!

View File

@ -75,12 +75,12 @@ class PackageStructurePrivate
public:
PackageStructurePrivate(const QString &t)
: type(t),
contentsPrefix("contents/"),
packageRoot("plasma/plasmoids"),
servicePrefix("plasma-applet-"),
metadata(0),
externalPaths(false)
{
contentsPrefixPaths << "contents/";
}
~PackageStructurePrivate()
@ -94,7 +94,7 @@ public:
QString type;
QString path;
QString contentsPrefix;
QStringList contentsPrefixPaths;
QString packageRoot;
QString servicePrefix;
QMap<QByteArray, ContentStructure> contents;
@ -282,22 +282,25 @@ QStringList PackageStructure::entryList(const char *key)
return QStringList();
}
QDir dir(d->path + d->contentsPrefix + p);
QStringList list;
foreach (QString prefix, d->contentsPrefixPaths) {
QDir dir(d->path + prefix + p);
if (dir.exists()) {
if (d->externalPaths) {
return dir.entryList(QDir::Files | QDir::Readable);
}
if (dir.exists()) {
if (d->externalPaths) {
return dir.entryList(QDir::Files | QDir::Readable);
}
// ensure that we don't return files outside of our base path
// due to symlink or ../ games
QString canonicalized = dir.canonicalPath();
if (canonicalized.startsWith(d->path)) {
return dir.entryList(QDir::Files | QDir::Readable);
// ensure that we don't return files outside of our base path
// due to symlink or ../ games
QString canonicalized = dir.canonicalPath();
if (canonicalized.startsWith(d->path)) {
list << dir.entryList(QDir::Files | QDir::Readable);
}
}
}
return QStringList();
return list;
}
void PackageStructure::addDirectoryDefinition(const char *key,
@ -469,7 +472,7 @@ void PackageStructure::read(const KConfigBase *config)
d->mimetypes.clear();
KConfigGroup general(config, QString());
d->type = general.readEntry("Type", QString());
d->contentsPrefix = general.readEntry("ContentsPrefix", d->contentsPrefix);
d->contentsPrefixPaths = general.readEntry("ContentsPrefixPaths", d->contentsPrefixPaths);
d->packageRoot = general.readEntry("DefaultPackageRoot", d->packageRoot);
d->externalPaths = general.readEntry("AllowExternalPaths", d->externalPaths);
@ -499,7 +502,7 @@ void PackageStructure::write(KConfigBase *config) const
{
KConfigGroup general = KConfigGroup(config, "");
general.writeEntry("Type", type());
general.writeEntry("ContentsPrefix", d->contentsPrefix);
general.writeEntry("ContentsPrefixPaths", d->contentsPrefixPaths);
general.writeEntry("DefaultPackageRoot", d->packageRoot);
general.writeEntry("AllowExternalPaths", d->externalPaths);
@ -524,12 +527,23 @@ void PackageStructure::write(KConfigBase *config) const
QString PackageStructure::contentsPrefix() const
{
return d->contentsPrefix;
return d->contentsPrefixPaths.first();
}
void PackageStructure::setContentsPrefix(const QString &prefix)
{
d->contentsPrefix = prefix;
d->contentsPrefixPaths.clear();
d->contentsPrefixPaths << prefix;
}
QStringList PackageStructure::contentsPrefixPaths() const
{
return d->contentsPrefixPaths;
}
void PackageStructure::setContentsPrefixPaths(const QStringList &prefixPaths)
{
d->contentsPrefixPaths = prefixPaths;
}
bool PackageStructure::installPackage(const QString &package, const QString &packageRoot)

View File

@ -169,7 +169,9 @@ public:
QString path(const char *key) const;
/**
* @return a list of paths relative to the package root for the given entry
* @return a list of paths relative to the package root for the given entry.
* They are orted by importance: when searching for a file the paths
* will be searched in order
* @since 4.6
**/
QStringList searchPath(const char *key) const;
@ -284,8 +286,16 @@ public:
/**
* @return the prefix inserted between the base path and content entries
* @deprecated use contentsPrefixPaths() instead.
*/
QString contentsPrefix() const;
KDE_DEPRECATED QString contentsPrefix() const;
/**
* @return the prefix paths inserted between the base path and content entries, in order of priority.
* When searching for a file, all paths will be tried in order.
* @since 4.6
*/
QStringList contentsPrefixPaths() const;
/**
* @return preferred package root. This defaults to plasma/plasmoids/
@ -334,8 +344,22 @@ protected:
* structure
*
* @arg prefix the directory prefix to use
* @deprecated use setContentsPrefixPaths() instead.
*/
void setContentsPrefix(const QString &prefix);
KDE_DEPRECATED void setContentsPrefix(const QString &prefix);
/**
* Sets the prefixes that all the contents in this package should
* appear under. This defaults to "contents/" and is added automatically
* between the base path and the entries as defined by the package
* structure. Multiple entries can be added.
* In this case each file request will be searched in all prefixes in order,
* and the first found will be returned.
*
* @arg prefix paths the directory prefix to use
* @since 4.6
*/
void setContentsPrefixPaths(const QStringList &prefixPaths);
/**
* Sets preferred package root.