// Copyright (c) 2016-2017 Josh Blum // SPDX-License-Identifier: BSL-1.0 #include #include #include #include #include #include #include #include #include #include #include #include static Poco::Logger &confLoaderLogger(void) { static Poco::Logger &logger(Poco::Logger::get("Pothos.ConfLoader")); return logger; } std::string Pothos_FileRealPath(const std::string &path); /*********************************************************************** * Load a config file by iterating through sections and running action **********************************************************************/ static std::vector loadConfFile(const std::string &path) { poco_debug_f1(confLoaderLogger(), "loading %s", path); //parse the configuration file with the INI parser Poco::AutoPtr conf; try { conf = new Poco::Util::PropertyFileConfiguration(path); } catch (const Poco::Exception &ex) { throw Pothos::Exception("ConfLoader("+path+")", ex.displayText()); } //store then config into a map structure std::map configMap; Poco::Util::AbstractConfiguration::Keys keys; conf->keys(keys); for (const auto &key : keys) configMap[key] = conf->getString(key); //and other config file parameters configMap["confFilePath"] = path; //handle the loader POTHOS_EXCEPTION_TRY { //get the loader if (not conf->hasProperty("loader")) throw Pothos::Exception( Poco::format("%s does not specify a loader", path)); const std::string loader(conf->getString("loader")); const auto loaderPath = Pothos::PluginPath("/framework/conf_loader").join(loader); if (not Pothos::PluginRegistry::exists(loaderPath)) throw Pothos::Exception( Poco::format("%s loader %s does not exist", path, loader)); //call the loader const auto plugin = Pothos::PluginRegistry::get(loaderPath); const auto &loaderFcn = plugin.getObject().extract(); return loaderFcn.call(configMap); } POTHOS_EXCEPTION_CATCH (const Pothos::Exception &ex) { throw Pothos::Exception("ConfLoader("+path+")", ex); } } /*********************************************************************** * Traverse a path for configuration files **********************************************************************/ static std::vector getConfFilePaths(const Poco::Path &path) { poco_debug_f1(confLoaderLogger(), "traversing %s", path.toString()); std::vector paths; const Poco::File file(path); if (not file.exists()) return paths; else if (file.isFile() and (path.getExtension() == "conf")) { paths.push_back(Pothos_FileRealPath(path.toString())); } else if (file.isDirectory()) { std::vector files; file.list(files); for (size_t i = 0; i < files.size(); i++) { auto subpaths = getConfFilePaths(Poco::Path(path, files[i]).absolute()); paths.insert(paths.end(), subpaths.begin(), subpaths.end()); } } return paths; } /*********************************************************************** * Entry point: traversal and loading of configuration files **********************************************************************/ std::vector Pothos_ConfLoader_loadConfFiles(void) { //the default search path std::vector searchPaths; Poco::Path confPath = Pothos::System::getRootPath(); confPath.append("share"); confPath.append("Pothos"); confPath.append("modules"); searchPaths.push_back(confPath); //support /usr/local module installs when the install prefix is /usr if (Pothos::System::getRootPath() == "/usr") { searchPaths.push_back("/usr/local/share/Pothos/modules"); } //the user's home config path confPath = Pothos::System::getUserConfigPath(); confPath.append("modules"); searchPaths.push_back(confPath); //separator for search paths const std::string sep(1, Poco::Path::pathSeparator()); //check the environment's search path const auto confPaths = Poco::Environment::get("POTHOS_CONF_PATH", ""); for (const auto &confPath : Poco::StringTokenizer(confPaths, sep)) { if (confPath.empty()) continue; searchPaths.push_back(Poco::Path(confPath)); } //traverse the search paths and spawn futures std::vector>> futures; for (const auto &searchPath : searchPaths) { for (const auto &path : getConfFilePaths(searchPath.absolute())) { futures.push_back(std::async(std::launch::async, &loadConfFile, path.toString())); } } //wait for completion of future module load std::vector entries; for (auto &future : futures) { try { auto subEntries = future.get(); entries.insert(entries.end(), subEntries.begin(), subEntries.end()); } catch(const Pothos::Exception &ex) { confLoaderLogger().error(ex.message()); } } return entries; }