diff options
-rw-r--r-- | src/qmlcompiler/qqmljsresourcefilemapper.cpp | 157 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsresourcefilemapper_p.h | 39 | ||||
-rw-r--r-- | tools/qmlcachegen/qmlcachegen.cpp | 8 | ||||
-rw-r--r-- | tools/qmlimportscanner/main.cpp | 6 |
4 files changed, 178 insertions, 32 deletions
diff --git a/src/qmlcompiler/qqmljsresourcefilemapper.cpp b/src/qmlcompiler/qqmljsresourcefilemapper.cpp index a31aeb29e5..ee05482b11 100644 --- a/src/qmlcompiler/qqmljsresourcefilemapper.cpp +++ b/src/qmlcompiler/qqmljsresourcefilemapper.cpp @@ -34,6 +34,42 @@ QT_BEGIN_NAMESPACE +QQmlJSResourceFileMapper::Filter QQmlJSResourceFileMapper::allQmlJSFilter() { + return Filter { + QString(), + QStringList { QStringLiteral("qml"), QStringLiteral("js"), QStringLiteral("mjs") }, + Directory | Recurse + }; +} + +QQmlJSResourceFileMapper::Filter QQmlJSResourceFileMapper::localFileFilter(const QString &file) +{ + return Filter { + QFileInfo(file).canonicalFilePath(), + QStringList(), + File + }; +} + +QQmlJSResourceFileMapper::Filter QQmlJSResourceFileMapper::resourceFileFilter(const QString &file) +{ + return Filter { + file, + QStringList(), + Resource + }; +} + +QQmlJSResourceFileMapper::Filter QQmlJSResourceFileMapper::resourceQmlDirectoryFilter( + const QString &directory) +{ + return Filter { + directory, + QStringList { QStringLiteral("qml") }, + Directory | Resource + }; +} + QQmlJSResourceFileMapper::QQmlJSResourceFileMapper(const QStringList &resourceFiles) { for (const QString &fileName: resourceFiles) { @@ -49,32 +85,111 @@ bool QQmlJSResourceFileMapper::isEmpty() const return qrcPathToFileSystemPath.isEmpty(); } -QStringList QQmlJSResourceFileMapper::resourcePaths(const QString &fileName) +bool QQmlJSResourceFileMapper::isFile(const QString &resourcePath) const { - const QString absPath = QDir::cleanPath(QDir::current().absoluteFilePath(fileName)); - QStringList resourcePaths; - for (auto it = qrcPathToFileSystemPath.cbegin(), end = qrcPathToFileSystemPath.cend(); it != end; ++it) { - if (QFileInfo(it.value()) == QFileInfo(absPath)) - resourcePaths.append(it.key()); + for (const auto &entry : qrcPathToFileSystemPath) { + if (entry.resourcePath == resourcePath) + return true; } - return resourcePaths; + return false; } -QStringList QQmlJSResourceFileMapper::qmlCompilerFiles(FileOutput fo) const +static bool hasSuffix(const QString &qrcPath, const QStringList &suffixes) { - QStringList files; - for (auto it = qrcPathToFileSystemPath.constBegin(), end = qrcPathToFileSystemPath.constEnd(); - it != end; ++it) { - const QString &qrcPath = it.key(); - const QString suffix = QFileInfo(qrcPath).suffix(); - if (suffix != QStringLiteral("qml") && suffix != QStringLiteral("js") && suffix != QStringLiteral("mjs")) - continue; - if (fo == FileOutput::AbsoluteFilePath) - files << it.value(); - else - files << qrcPath; + if (suffixes.isEmpty()) + return true; + const QString suffix = QFileInfo(qrcPath).suffix(); + return suffixes.contains(suffix); +} + +template<typename HandleMatch> +void doFilter(const QList<QQmlJSResourceFileMapper::Entry> &qrcPathToFileSystemPath, + const QQmlJSResourceFileMapper::Filter &filter, + const HandleMatch &handler) +{ + if (filter.flags & QQmlJSResourceFileMapper::Directory) { + const QString terminatedDirectory = filter.path.endsWith(u'/') + ? filter.path : (filter.path + u'/'); + + for (auto it = qrcPathToFileSystemPath.constBegin(), + end = qrcPathToFileSystemPath.constEnd(); it != end; ++it) { + + const QString candidate = (filter.flags & QQmlJSResourceFileMapper::Resource) + ? it->resourcePath + : it->filePath; + + if (!candidate.startsWith(terminatedDirectory)) + continue; + + if (!hasSuffix(candidate, filter.suffixes)) + continue; + + if ((filter.flags & QQmlJSResourceFileMapper::Recurse) + // Crude. But shall we really allow slashes in QRC file names? + || !candidate.mid(terminatedDirectory.length()).contains(u'/')) { + if (handler(*it)) + return; + } + } + return; + } + + if (!hasSuffix(filter.path, filter.suffixes)) + return; + + for (auto it = qrcPathToFileSystemPath.constBegin(), + end = qrcPathToFileSystemPath.constEnd(); it != end; ++it) { + if (filter.flags & QQmlJSResourceFileMapper::Resource) { + if (it->resourcePath == filter.path && handler(*it)) + return; + } else if (it->filePath == filter.path && handler(*it)) { + return; + } } - return files; +} + +QList<QQmlJSResourceFileMapper::Entry> QQmlJSResourceFileMapper::filter( + const QQmlJSResourceFileMapper::Filter &filter) const +{ + QList<Entry> result; + doFilter(qrcPathToFileSystemPath, filter, [&](const Entry &entry) { + result.append(entry); + return false; + }); + return result; +} + +QStringList QQmlJSResourceFileMapper::filePaths( + const QQmlJSResourceFileMapper::Filter &filter) const +{ + QStringList result; + doFilter(qrcPathToFileSystemPath, filter, [&](const Entry &entry) { + result.append(entry.filePath); + return false; + }); + return result; +} + +QStringList QQmlJSResourceFileMapper::resourcePaths( + const QQmlJSResourceFileMapper::Filter &filter) const +{ + QStringList result; + doFilter(qrcPathToFileSystemPath, filter, [&](const Entry &entry) { + result.append(entry.resourcePath); + return false; + }); + return result; +} + +QQmlJSResourceFileMapper::Entry QQmlJSResourceFileMapper::entry( + const QQmlJSResourceFileMapper::Filter &filter) const +{ + Entry result; + doFilter(qrcPathToFileSystemPath, filter, [&](const Entry &entry) { + result = entry; + return true; + }); + return result; } void QQmlJSResourceFileMapper::populateFromQrcFile(QFile &file) @@ -162,7 +277,7 @@ void QQmlJSResourceFileMapper::populateFromQrcFile(QFile &file) const QString qrcPath = prefix + currentFileName; if (QFile::exists(fsPath)) - qrcPathToFileSystemPath.insert(qrcPath, fsPath); + qrcPathToFileSystemPath.append({qrcPath, fsPath}); continue; } diff --git a/src/qmlcompiler/qqmljsresourcefilemapper_p.h b/src/qmlcompiler/qqmljsresourcefilemapper_p.h index 2946075387..6be1503556 100644 --- a/src/qmlcompiler/qqmljsresourcefilemapper_p.h +++ b/src/qmlcompiler/qqmljsresourcefilemapper_p.h @@ -46,23 +46,50 @@ QT_BEGIN_NAMESPACE struct QQmlJSResourceFileMapper { - enum class FileOutput { - RelativeFilePath, - AbsoluteFilePath + struct Entry + { + QString resourcePath; + QString filePath; + bool isValid() const { return !resourcePath.isEmpty() && !filePath.isEmpty(); } }; + + enum FilterMode { + File = 0x0, // Default is local (non-directory) file, without recursion + Directory = 0x1, // Directory, either local or resource + Resource = 0x2, // Resource path, either to file or directory + Recurse = 0x4, // Recurse into subdirectories if Directory + }; + Q_DECLARE_FLAGS(FilterFlags, FilterMode); + + struct Filter { + QString path; + QStringList suffixes; + FilterFlags flags; + }; + + static Filter allQmlJSFilter(); + static Filter localFileFilter(const QString &file); + static Filter resourceFileFilter(const QString &file); + static Filter resourceQmlDirectoryFilter(const QString &directory); + QQmlJSResourceFileMapper(const QStringList &resourceFiles); bool isEmpty() const; + bool isFile(const QString &resourcePath) const; - QStringList resourcePaths(const QString &fileName); - QStringList qmlCompilerFiles(FileOutput fo = FileOutput::RelativeFilePath) const; + QList<Entry> filter(const Filter &filter) const; + QStringList filePaths(const Filter &filter) const; + QStringList resourcePaths(const Filter &filter) const; + Entry entry(const Filter &filter) const; private: void populateFromQrcFile(QFile &file); - QHash<QString, QString> qrcPathToFileSystemPath; + QList<Entry> qrcPathToFileSystemPath; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlJSResourceFileMapper::FilterFlags); + QT_END_NAMESPACE #endif // QMLJSRESOURCEFILEMAPPER_P_H diff --git a/tools/qmlcachegen/qmlcachegen.cpp b/tools/qmlcachegen/qmlcachegen.cpp index a011442528..285e6c02ea 100644 --- a/tools/qmlcachegen/qmlcachegen.cpp +++ b/tools/qmlcachegen/qmlcachegen.cpp @@ -167,8 +167,9 @@ int main(int argc, char **argv) QQmlJSResourceFileMapper mapper(sources); QQmlJSCompileError error; - if (!qQmlJSGenerateLoader(mapper.qmlCompilerFiles(), outputFileName, - parser.values(resourceFileMappingOption), &error.message)) { + if (!qQmlJSGenerateLoader( + mapper.resourcePaths(QQmlJSResourceFileMapper::allQmlJSFilter()), + outputFileName, parser.values(resourceFileMappingOption), &error.message)) { error.augment(QLatin1String("Error generating loader stub: ")).print(); return EXIT_FAILURE; } @@ -194,7 +195,8 @@ int main(int argc, char **argv) // If the user didn't specify the resource path corresponding to the file on disk being // compiled, try to determine it from the resource file, if one was supplied. if (inputResourcePath.isEmpty()) { - const QStringList resourcePaths = fileMapper.resourcePaths(inputFile); + const QStringList resourcePaths = fileMapper.resourcePaths( + QQmlJSResourceFileMapper::localFileFilter(inputFile)); if (resourcePaths.isEmpty()) { fprintf(stderr, "No resource path for file: %s\n", qPrintable(inputFile)); return EXIT_FAILURE; diff --git a/tools/qmlimportscanner/main.cpp b/tools/qmlimportscanner/main.cpp index 9313dee634..ea17df921f 100644 --- a/tools/qmlimportscanner/main.cpp +++ b/tools/qmlimportscanner/main.cpp @@ -631,8 +631,10 @@ int main(int argc, char *argv[]) } } - if (!qrcFiles.isEmpty()) - scanFiles << QQmlJSResourceFileMapper(qrcFiles).qmlCompilerFiles(QQmlJSResourceFileMapper::FileOutput::AbsoluteFilePath); + if (!qrcFiles.isEmpty()) { + scanFiles << QQmlJSResourceFileMapper(qrcFiles).filePaths( + QQmlJSResourceFileMapper::allQmlJSFilter()); + } g_qmlImportPaths = qmlImportPaths; |