File indexing completed on 2024-04-21 04:38:09
0001 /* 0002 SPDX-FileCopyrightText: 2018 Anton Anikin <anton@anikin.xyz> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "checksdb.h" 0008 0009 #include "globalsettings.h" 0010 #include "utils.h" 0011 0012 #include <KLocalizedString> 0013 0014 #include <QDir> 0015 #include <QRegularExpression> 0016 0017 namespace Clazy 0018 { 0019 0020 ChecksDB::ChecksDB(const QUrl& docsPath) 0021 { 0022 static const QHash<QString, QString> levelName = { 0023 { QStringLiteral("manuallevel"), QStringLiteral("manual") }, 0024 { QStringLiteral("hiddenlevel"), QStringLiteral("manual") } 0025 }; 0026 0027 static const QHash<QString, QString> levelDisplayName = { 0028 { QStringLiteral("level0"), i18nc("@item level of checks", "Level 0") }, 0029 { QStringLiteral("level1"), i18nc("@item level of checks", "Level 1") }, 0030 { QStringLiteral("level2"), i18nc("@item level of checks", "Level 2") }, 0031 { QStringLiteral("level3"), i18nc("@item level of checks", "Level 3") }, 0032 { QStringLiteral("manual"), i18nc("@item level of checks", "Manual Level") } 0033 }; 0034 0035 static const QHash<QString, QString> levelDescription = { 0036 { QStringLiteral("level0"), 0037 i18n("Very stable checks, 99.99% safe, mostly no false-positives, very desirable.") }, 0038 0039 { QStringLiteral("level1"), 0040 i18n("The default level. Very similar to level 0, slightly more false-positives but very few.") }, 0041 0042 { QStringLiteral("level2"), 0043 i18n("Also very few false-positives, but contains noisy checks which not everyone agree should be default.") }, 0044 0045 { QStringLiteral("level3"), 0046 i18n("Contains checks with high rate of false-positives.") }, 0047 0048 { QStringLiteral("manual"), 0049 i18n("Checks here need to be enabled explicitly, as they don't belong to any level. " 0050 "Checks here are very stable and have very few false-positives.") } 0051 }; 0052 0053 const QString defaultError = i18n( 0054 "Unable to load Clazy checks information from '%1'. Please check your settings.", 0055 docsPath.toLocalFile()); 0056 0057 QDir docsDir(docsPath.toLocalFile()); 0058 if (!docsDir.exists()) { 0059 m_error = defaultError; 0060 return; 0061 } 0062 0063 const QRegularExpression levelRE(QStringLiteral(".*level.*")); 0064 const QRegularExpression checkRE(QStringLiteral("^README-(.+)\\.md$")); 0065 0066 const auto levelsDirs = docsDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); 0067 for (const auto& levelDir : levelsDirs) { 0068 if (!levelRE.match(levelDir).hasMatch()) { 0069 continue; 0070 } 0071 0072 if (!docsDir.cd(levelDir)) { 0073 continue; 0074 } 0075 0076 auto level = new Level; 0077 level->name = levelName.value(levelDir, levelDir); 0078 level->displayName = levelDisplayName.value(level->name, levelDir); 0079 level->description = levelDescription.value(level->name, {}); 0080 0081 const auto checksFiles = docsDir.entryList(QDir::Files | QDir::Readable); 0082 for (const auto& checkFile : checksFiles) { 0083 auto match = checkRE.match(checkFile); 0084 if (!match.hasMatch()) { 0085 continue; 0086 } 0087 0088 QFile mdFile(docsDir.absoluteFilePath(checkFile)); 0089 if (!mdFile.open(QIODevice::ReadOnly)) { 0090 continue; 0091 } 0092 0093 auto check = new Check; 0094 check->level = level; 0095 check->name = match.captured(1); 0096 check->description = markdown2html(mdFile.readAll()); 0097 level->checks[check->name] = check; 0098 0099 m_checks[check->name] = check; 0100 } 0101 0102 if (level->checks.isEmpty()) { 0103 delete level; 0104 } else { 0105 m_levels[level->name] = level; 0106 } 0107 0108 docsDir.cdUp(); 0109 } 0110 0111 if (m_levels.isEmpty()) { 0112 m_error = defaultError; 0113 } 0114 } 0115 0116 ChecksDB::~ChecksDB() 0117 { 0118 qDeleteAll(m_levels); 0119 qDeleteAll(m_checks); 0120 } 0121 0122 bool ChecksDB::isValid() const 0123 { 0124 return m_error.isEmpty(); 0125 } 0126 0127 QString ChecksDB::error() const 0128 { 0129 return m_error; 0130 } 0131 0132 const QMap<QString, Level*>& ChecksDB::levels() const 0133 { 0134 return m_levels; 0135 } 0136 0137 const QMap<QString, Check*>& ChecksDB::checks() const 0138 { 0139 return m_checks; 0140 } 0141 0142 QString ChecksDB::defaultChecks() 0143 { 0144 return QStringLiteral("level1"); 0145 } 0146 0147 }