// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "jsonwizardscannergenerator.h" #include "jsonwizardgeneratorfactory.h" #include "../projectmanager.h" #include "../projectexplorertr.h" #include #include #include #include #include #include #include #include #include using namespace Utils; namespace ProjectExplorer::Internal { class JsonWizardScannerGenerator final : public JsonWizardGenerator { public: bool setup(const QVariant &data, QString *errorMessage); Core::GeneratedFiles fileList(MacroExpander *expander, const FilePath &wizardDir, const FilePath &projectDir, QString *errorMessage) final; private: Core::GeneratedFiles scan(const FilePath &dir, const FilePath &base); bool matchesSubdirectoryPattern(const FilePath &path); QString m_binaryPattern; QList m_subDirectoryExpressions; }; bool JsonWizardScannerGenerator::setup(const QVariant &data, QString *errorMessage) { if (data.isNull()) return true; if (data.type() != QVariant::Map) { *errorMessage = Tr::tr("Key is not an object."); return false; } QVariantMap gen = data.toMap(); m_binaryPattern = gen.value(QLatin1String("binaryPattern")).toString(); const QStringList patterns = gen.value(QLatin1String("subdirectoryPatterns")).toStringList(); for (const QString &pattern : patterns) { QRegularExpression regexp(pattern); if (!regexp.isValid()) { *errorMessage = Tr::tr("Pattern \"%1\" is no valid regular expression."); return false; } m_subDirectoryExpressions << regexp; } return true; } Core::GeneratedFiles JsonWizardScannerGenerator::fileList(Utils::MacroExpander *expander, const Utils::FilePath &wizardDir, const Utils::FilePath &projectDir, QString *errorMessage) { Q_UNUSED(wizardDir) errorMessage->clear(); Core::GeneratedFiles result; QRegularExpression binaryPattern; if (!m_binaryPattern.isEmpty()) { binaryPattern = QRegularExpression(expander->expand(m_binaryPattern)); if (!binaryPattern.isValid()) { qWarning() << Tr::tr("ScannerGenerator: Binary pattern \"%1\" not valid.") .arg(m_binaryPattern); return result; } } result = scan(projectDir, projectDir); static const auto getDepth = [](const Utils::FilePath &filePath) { return int(filePath.path().count('/')); }; int minDepth = std::numeric_limits::max(); for (auto it = result.begin(); it != result.end(); ++it) { const Utils::FilePath relPath = it->filePath().relativePathFrom(projectDir); it->setBinary(binaryPattern.match(relPath.toString()).hasMatch()); bool found = ProjectManager::canOpenProjectForMimeType(Utils::mimeTypeForFile(relPath)); if (found) { it->setAttributes(it->attributes() | Core::GeneratedFile::OpenProjectAttribute); minDepth = std::min(minDepth, getDepth(it->filePath())); } } // Project files that appear on a lower level in the file system hierarchy than // other project files are not candidates for opening. for (Core::GeneratedFile &f : result) { if (f.attributes().testFlag(Core::GeneratedFile::OpenProjectAttribute) && getDepth(f.filePath()) > minDepth) { f.setAttributes(f.attributes().setFlag(Core::GeneratedFile::OpenProjectAttribute, false)); } } return result; } bool JsonWizardScannerGenerator::matchesSubdirectoryPattern(const Utils::FilePath &path) { for (const QRegularExpression ®exp : std::as_const(m_subDirectoryExpressions)) { if (regexp.match(path.path()).hasMatch()) return true; } return false; } Core::GeneratedFiles JsonWizardScannerGenerator::scan(const Utils::FilePath &dir, const Utils::FilePath &base) { Core::GeneratedFiles result; if (!dir.exists()) return result; const Utils::FilePaths entries = dir.dirEntries({{}, QDir::AllEntries | QDir::NoDotAndDotDot}, QDir::DirsLast | QDir::Name); for (const Utils::FilePath &fi : entries) { const Utils::FilePath relativePath = fi.relativePathFrom(base); if (fi.isDir() && matchesSubdirectoryPattern(relativePath)) { result += scan(fi, base); } else { Core::GeneratedFile f(fi); f.setAttributes(f.attributes() | Core::GeneratedFile::KeepExistingFileAttribute); result.append(f); } } return result; } // JsonWizardScannerGeneratorFactory class JsonWizardScannerGeneratorFactory final : public JsonWizardGeneratorFactory { public: JsonWizardScannerGeneratorFactory() { setTypeIdsSuffix(QLatin1String("Scanner")); } JsonWizardGenerator *create(Id typeId, const QVariant &data, const QString &path, Id platform, const QVariantMap &variables) final { Q_UNUSED(path) Q_UNUSED(platform) Q_UNUSED(variables) QTC_ASSERT(canCreate(typeId), return nullptr); auto gen = new JsonWizardScannerGenerator; QString errorMessage; gen->setup(data, &errorMessage); if (!errorMessage.isEmpty()) { qWarning() << "JsonWizardScannerGeneratorFactory setup error:" << errorMessage; delete gen; return nullptr; } return gen; } bool validateData(Id typeId, const QVariant &data, QString *errorMessage) final { QTC_ASSERT(canCreate(typeId), return false); QScopedPointer gen(new JsonWizardScannerGenerator); return gen->setup(data, errorMessage); } }; void setupJsonWizardScannerGenerator() { static JsonWizardScannerGeneratorFactory theScannerGeneratorFactory; } } // ProjectExplorer::Internal