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 bool Package::isValid() const
{ {
if (!d->valid) { if (!d->valid || d->structure->contentsPrefixPaths().isEmpty()) {
return false; 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()) { foreach (const char *dir, d->structure->requiredDirectories()) {
bool failed = true; bool failed = true;
foreach (const QString &path, d->structure->searchPath(dir)) { foreach (const QString &path, d->structure->searchPath(dir)) {
if (QFile::exists(d->structure->path() + d->structure->contentsPrefix() + path)) { foreach (const QString &prefix, d->structure->contentsPrefixPaths()) {
failed = false; if (QFile::exists(d->structure->path() + prefix + path)) {
failed = false;
break;
}
}
if (!failed) {
break; break;
} }
} }
@ -181,8 +189,13 @@ bool Package::isValid() const
foreach (const char *file, d->structure->requiredFiles()) { foreach (const char *file, d->structure->requiredFiles()) {
bool failed = true; bool failed = true;
foreach (const QString &path, d->structure->searchPath(file)) { foreach (const QString &path, d->structure->searchPath(file)) {
if (QFile::exists(d->structure->path() + d->structure->contentsPrefix() + path)) { foreach (const QString &prefix, d->structure->contentsPrefixPaths()) {
failed = false; if (QFile::exists(d->structure->path() + prefix + path)) {
failed = false;
break;
}
}
if (!failed) {
break; 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; //kDebug() << "no matching path came of it, while looking for" << fileType << filename;
return QString(); 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) { foreach (const QString &path, paths) {
QString file = prefix + path; QString file = prefix + path;
if (!filename.isEmpty()) { if (!filename.isEmpty()) {
file.append("/").append(filename); file.append("/").append(filename);
}
if (QFile::exists(file)) {
if (d->structure->allowExternalPaths()) {
return file;
} }
// ensure that we don't return files outside of our base path if (QFile::exists(file)) {
// due to symlink or ../ games if (d->structure->allowExternalPaths()) {
QDir dir(file); return file;
QString canonicalized = dir.canonicalPath() + QDir::separator(); }
if (canonicalized.startsWith(d->structure->path())) {
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(); return QString();
} }
const QString basePath = d->structure->path() + d->structure->contentsPrefix();
QDir dir(basePath);
if (!dir.exists()) {
return QString();
}
QCA::Hash hash("sha1"); QCA::Hash hash("sha1");
QString metadataPath = d->structure->path() + "metadata.desktop"; QString metadataPath = d->structure->path() + "metadata.desktop";
if (QFile::exists(metadataPath)) { if (QFile::exists(metadataPath)) {
@ -373,7 +386,16 @@ QString Package::contentsHash() const
kWarning() << "no metadata at" << metadataPath; 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()); return QCA::arrayToHex(hash.final().toByteArray());
#else #else
// no QCA2! // no QCA2!

View File

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

View File

@ -169,7 +169,9 @@ public:
QString path(const char *key) const; 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 * @since 4.6
**/ **/
QStringList searchPath(const char *key) const; QStringList searchPath(const char *key) const;
@ -284,8 +286,16 @@ public:
/** /**
* @return the prefix inserted between the base path and content entries * @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/ * @return preferred package root. This defaults to plasma/plasmoids/
@ -334,8 +344,22 @@ protected:
* structure * structure
* *
* @arg prefix the directory prefix to use * @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. * Sets preferred package root.