ConfLoader.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. // Copyright (c) 2016-2017 Josh Blum
  2. // SPDX-License-Identifier: BSL-1.0
  3. #include <Pothos/System.hpp>
  4. #include <Pothos/Plugin.hpp>
  5. #include <Poco/StringTokenizer.h>
  6. #include <Poco/SharedLibrary.h>
  7. #include <Poco/Environment.h>
  8. #include <Poco/Logger.h>
  9. #include <Poco/Path.h>
  10. #include <Poco/File.h>
  11. #include <Poco/Format.h>
  12. #include <Poco/Util/PropertyFileConfiguration.h>
  13. #include <future>
  14. #include <map>
  15. static Poco::Logger &confLoaderLogger(void)
  16. {
  17. static Poco::Logger &logger(Poco::Logger::get("Pothos.ConfLoader"));
  18. return logger;
  19. }
  20. std::string Pothos_FileRealPath(const std::string &path);
  21. /***********************************************************************
  22. * Load a config file by iterating through sections and running action
  23. **********************************************************************/
  24. static std::vector<Pothos::PluginPath> loadConfFile(const std::string &path)
  25. {
  26. poco_debug_f1(confLoaderLogger(), "loading %s", path);
  27. //parse the configuration file with the INI parser
  28. Poco::AutoPtr<Poco::Util::PropertyFileConfiguration> conf;
  29. try
  30. {
  31. conf = new Poco::Util::PropertyFileConfiguration(path);
  32. }
  33. catch (const Poco::Exception &ex)
  34. {
  35. throw Pothos::Exception("ConfLoader("+path+")", ex.displayText());
  36. }
  37. //store then config into a map structure
  38. std::map<std::string, std::string> configMap;
  39. Poco::Util::AbstractConfiguration::Keys keys; conf->keys(keys);
  40. for (const auto &key : keys) configMap[key] = conf->getString(key);
  41. //and other config file parameters
  42. configMap["confFilePath"] = path;
  43. //handle the loader
  44. POTHOS_EXCEPTION_TRY
  45. {
  46. //get the loader
  47. if (not conf->hasProperty("loader")) throw Pothos::Exception(
  48. Poco::format("%s does not specify a loader", path));
  49. const std::string loader(conf->getString("loader"));
  50. const auto loaderPath = Pothos::PluginPath("/framework/conf_loader").join(loader);
  51. if (not Pothos::PluginRegistry::exists(loaderPath)) throw Pothos::Exception(
  52. Poco::format("%s loader %s does not exist", path, loader));
  53. //call the loader
  54. const auto plugin = Pothos::PluginRegistry::get(loaderPath);
  55. const auto &loaderFcn = plugin.getObject().extract<Pothos::Callable>();
  56. return loaderFcn.call(configMap);
  57. }
  58. POTHOS_EXCEPTION_CATCH (const Pothos::Exception &ex)
  59. {
  60. throw Pothos::Exception("ConfLoader("+path+")", ex);
  61. }
  62. }
  63. /***********************************************************************
  64. * Traverse a path for configuration files
  65. **********************************************************************/
  66. static std::vector<Poco::Path> getConfFilePaths(const Poco::Path &path)
  67. {
  68. poco_debug_f1(confLoaderLogger(), "traversing %s", path.toString());
  69. std::vector<Poco::Path> paths;
  70. const Poco::File file(path);
  71. if (not file.exists()) return paths;
  72. else if (file.isFile() and (path.getExtension() == "conf"))
  73. {
  74. paths.push_back(Pothos_FileRealPath(path.toString()));
  75. }
  76. else if (file.isDirectory())
  77. {
  78. std::vector<std::string> files; file.list(files);
  79. for (size_t i = 0; i < files.size(); i++)
  80. {
  81. auto subpaths = getConfFilePaths(Poco::Path(path, files[i]).absolute());
  82. paths.insert(paths.end(), subpaths.begin(), subpaths.end());
  83. }
  84. }
  85. return paths;
  86. }
  87. /***********************************************************************
  88. * Entry point: traversal and loading of configuration files
  89. **********************************************************************/
  90. std::vector<Pothos::PluginPath> Pothos_ConfLoader_loadConfFiles(void)
  91. {
  92. //the default search path
  93. std::vector<Poco::Path> searchPaths;
  94. Poco::Path confPath = Pothos::System::getRootPath();
  95. confPath.append("share");
  96. confPath.append("Pothos");
  97. confPath.append("modules");
  98. searchPaths.push_back(confPath);
  99. //support /usr/local module installs when the install prefix is /usr
  100. if (Pothos::System::getRootPath() == "/usr")
  101. {
  102. searchPaths.push_back("/usr/local/share/Pothos/modules");
  103. }
  104. //the user's home config path
  105. confPath = Pothos::System::getUserConfigPath();
  106. confPath.append("modules");
  107. searchPaths.push_back(confPath);
  108. //separator for search paths
  109. const std::string sep(1, Poco::Path::pathSeparator());
  110. //check the environment's search path
  111. const auto confPaths = Poco::Environment::get("POTHOS_CONF_PATH", "");
  112. for (const auto &confPath : Poco::StringTokenizer(confPaths, sep))
  113. {
  114. if (confPath.empty()) continue;
  115. searchPaths.push_back(Poco::Path(confPath));
  116. }
  117. //traverse the search paths and spawn futures
  118. std::vector<std::future<std::vector<Pothos::PluginPath>>> futures;
  119. for (const auto &searchPath : searchPaths)
  120. {
  121. for (const auto &path : getConfFilePaths(searchPath.absolute()))
  122. {
  123. futures.push_back(std::async(std::launch::async, &loadConfFile, path.toString()));
  124. }
  125. }
  126. //wait for completion of future module load
  127. std::vector<Pothos::PluginPath> entries;
  128. for (auto &future : futures)
  129. {
  130. try
  131. {
  132. auto subEntries = future.get();
  133. entries.insert(entries.end(), subEntries.begin(), subEntries.end());
  134. }
  135. catch(const Pothos::Exception &ex)
  136. {
  137. confLoaderLogger().error(ex.message());
  138. }
  139. }
  140. return entries;
  141. }