NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
| 112 | |
| 113 | // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) |
| 114 | void CppPluginSystem::scan(const std::string_view paths, const std::string_view pathsEnvVar, |
| 115 | const std::string_view moduleHookName, |
| 116 | const ValidationCallback& validationCallback) { |
| 117 | const auto scanPaths = [&](const std::string_view pathsToScan) { |
| 118 | std::size_t pathsStartIdx = 0; |
| 119 | std::size_t pathsEndIdx = 0; |
| 120 | |
| 121 | // Loop through each path in ';'/:'-delimited paths string. |
| 122 | while ((pathsStartIdx = pathsToScan.find_first_not_of(kPathSep, pathsEndIdx)) != |
| 123 | std::string::npos) { |
| 124 | pathsEndIdx = pathsToScan.find(kPathSep, pathsStartIdx); |
| 125 | const std::filesystem::path directoryPath = |
| 126 | pathsToScan.substr(pathsStartIdx, pathsEndIdx - pathsStartIdx); |
| 127 | |
| 128 | // Check the provided path is actually a searchable directory. |
| 129 | if (!is_directory(directoryPath)) { |
| 130 | logger_->debug(fmt::format("CppPluginSystem: Skipping as not a directory '{}'", |
| 131 | directoryPath.string())); |
| 132 | continue; |
| 133 | } |
| 134 | |
| 135 | // Loop each item in the provided search path. |
| 136 | for (const std::filesystem::directory_entry& directoryEntry : |
| 137 | std::filesystem::directory_iterator{directoryPath}) { |
| 138 | std::filesystem::path filePath = directoryEntry.path(); |
| 139 | |
| 140 | // Assume the item in the search path is a plugin file and attempt |
| 141 | // to load it. |
| 142 | if (MaybeIdentifierAndPlugin idAndPlugin = |
| 143 | maybeLoadPlugin(filePath, moduleHookName, validationCallback)) { |
| 144 | logger_->debug(fmt::format("CppPluginSystem: Registered plug-in '{}' from '{}'", |
| 145 | idAndPlugin->first, filePath.string())); |
| 146 | // Register the successfully loaded plugin. |
| 147 | plugins_[std::move(idAndPlugin->first)] = {std::move(filePath), |
| 148 | std::move(idAndPlugin->second)}; |
| 149 | } |
| 150 | } |
| 151 | } |
| 152 | }; |
| 153 | |
| 154 | // Prefer fixed paths, else fall back to env var. |
| 155 | if (!paths.empty()) { |
| 156 | scanPaths(paths); |
| 157 | } else { |
| 158 | const std::string_view pathsFromEnvVar = [&] { |
| 159 | if (pathsEnvVar.empty()) { // Defend against uninitialised string_view. |
| 160 | return ""; |
| 161 | } |
| 162 | // NOLINTNEXTLINE(*-suspicious-stringview-data-usage) |
| 163 | const char* maybePaths = std::getenv(pathsEnvVar.data()); |
| 164 | if (maybePaths == nullptr) { |
| 165 | return ""; |
| 166 | } |
| 167 | return maybePaths; |
| 168 | }(); |
| 169 | |
| 170 | if (pathsFromEnvVar.empty()) { |
| 171 | logger_->debug(fmt::format( |