PothosUtil.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. // Copyright (c) 2013-2018 Josh Blum
  2. // 2020 Nicholas Corgan
  3. // SPDX-License-Identifier: BSL-1.0
  4. #include "PothosUtil.hpp"
  5. #include <Poco/Util/Application.h>
  6. #include <Poco/Util/ServerApplication.h>
  7. #include <Poco/Util/Option.h>
  8. #include <Poco/Util/OptionSet.h>
  9. #include <Poco/Util/HelpFormatter.h>
  10. #include <Poco/Util/IntValidator.h>
  11. #include <Pothos/System.hpp>
  12. #include <Pothos/Exception.hpp>
  13. #include <iostream>
  14. class PothosUtil : public PothosUtilBase
  15. {
  16. public:
  17. PothosUtil(int argc):
  18. _helpRequested(argc <= 1),
  19. _docParseRequested(false),
  20. _deviceInfoRequested(false),
  21. _runTopologyRequested(false),
  22. _simdFeaturesRequested(false)
  23. {
  24. this->setUnixOptions(true); //always unix style --option
  25. //restore logging config after Poco::Util::Application::initialize() obliterates it
  26. Pothos::System::Logger::setupDefaultLogging();
  27. }
  28. ~PothosUtil()
  29. {
  30. return;
  31. }
  32. protected:
  33. void defineOptions(Poco::Util::OptionSet &options)
  34. {
  35. Poco::Util::Application::defineOptions(options);
  36. options.addOption(Poco::Util::Option("help", "h", "display argument help information")
  37. .required(false)
  38. .repeatable(false));
  39. options.addOption(Poco::Util::Option("system-info", "", "display system information")
  40. .required(false)
  41. .repeatable(false)
  42. .callback(Poco::Util::OptionCallback<PothosUtil>(this, &PothosUtil::printSystemInfo)));
  43. options.addOption(Poco::Util::Option("module-info", "",
  44. "Display a summary of loaded modules.\n"
  45. "Or specify an optional module path to print the list of associated plugins."
  46. "Or specify the special value of 'builtin' to see Builtin library plugins.")
  47. .required(false)
  48. .repeatable(false)
  49. .argument("modulePath", false/*optional*/)
  50. .binding("modulePath")
  51. .callback(Poco::Util::OptionCallback<PothosUtil>(this, &PothosUtil::printModuleInfo)));
  52. options.addOption(Poco::Util::Option("list-modules", "", "list all loaded modules")
  53. .required(false)
  54. .repeatable(false)
  55. .callback(Poco::Util::OptionCallback<PothosUtil>(this, &PothosUtil::listModules)));
  56. options.addOption(Poco::Util::Option("device-info", "", "display device information")
  57. .required(false)
  58. .repeatable(false)
  59. .argument("deviceType", false/*optional*/)
  60. .binding("deviceType"));
  61. options.addOption(Poco::Util::Option("plugin-tree", "", "display plugin tree")
  62. .required(false)
  63. .repeatable(false)
  64. .argument("pluginPath", false/*optional*/)
  65. .callback(Poco::Util::OptionCallback<PothosUtil>(this, &PothosUtil::printPluginTree)));
  66. options.addOption(Poco::Util::Option("proxy-server", "", "run the proxy server, tcp://bindHost:bindPort")
  67. .required(false)
  68. .repeatable(false)
  69. .argument("URI", false/*optional*/)
  70. .callback(Poco::Util::OptionCallback<PothosUtil>(this, &PothosUtil::proxyServer)));
  71. options.addOption(Poco::Util::Option("load-module", "", "test load a library module")
  72. .required(false)
  73. .repeatable(false)
  74. .argument("modulePath")
  75. .callback(Poco::Util::OptionCallback<PothosUtil>(this, &PothosUtil::loadModule)));
  76. options.addOption(Poco::Util::Option("run-topology", "", "run a topology from a JSON description")
  77. .required(false)
  78. .repeatable(false)
  79. .argument("inputFile")
  80. .binding("inputFile"));
  81. options.addOption(Poco::Util::Option("run-duration", "", "run the topology for the duration in seconds")
  82. .required(false)
  83. .repeatable(false)
  84. .argument("runDuration")
  85. .binding("runDuration"));
  86. options.addOption(Poco::Util::Option("idle-time", "",
  87. "The maximum allowed idle time in seconds.\n"
  88. "The topology will exit after all flows remain idle for the specified time in seconds. "
  89. "Use this option with --run-duration to specify a timeout to wait for idle to occur. "
  90. "PothosUtil will return an error code if the timeout is reached before idle occurs.")
  91. .required(false)
  92. .repeatable(false)
  93. .argument("idleTime")
  94. .binding("idleTime"));
  95. options.addOption(Poco::Util::Option("var", "",
  96. "Specify an arbitrary keyword + value variable\n"
  97. "using the format --var=name:value\n"
  98. "Multiple instances of --var are possible.\n"
  99. "Use with --run-topology to overload globals.")
  100. .required(false)
  101. .repeatable(true)
  102. .argument("variable")
  103. .binding("variable"));
  104. options.addOption(Poco::Util::Option("self-tests", "", "run all plugin self tests")
  105. .required(false)
  106. .repeatable(false)
  107. .argument("pluginPath", false/*optional*/)
  108. .callback(Poco::Util::OptionCallback<PothosUtil>(this, &PothosUtil::selfTests)));
  109. options.addOption(Poco::Util::Option("self-test1", "", "run a particular plugin self test")
  110. .required(false)
  111. .repeatable(false)
  112. .argument("pluginPath")
  113. .callback(Poco::Util::OptionCallback<PothosUtil>(this, &PothosUtil::selfTestOne)));
  114. options.addOption(Poco::Util::Option("num-trials", "", "how many times to run each self test")
  115. .required(false)
  116. .repeatable(false)
  117. .argument("numTrials")
  118. .validator(new Poco::Util::IntValidator(1, 255))
  119. .binding("numTrials"));
  120. options.addOption(Poco::Util::Option("success-code", "", "the success status return code (default 0)")
  121. .required(false)
  122. .repeatable(false)
  123. .argument("successCode")
  124. .validator(new Poco::Util::IntValidator(0, 255))
  125. .binding("successCode"));
  126. options.addOption(Poco::Util::Option("require-active", "", "proxy server shuts off without active clients")
  127. .required(false)
  128. .repeatable(false)
  129. .binding("requireActive"));
  130. options.addOption(Poco::Util::Option("output", "",
  131. "Specify an output file (used by various options)\n"
  132. "Use with --run-topology to dump JSON statistics.")
  133. .required(false)
  134. .repeatable(false)
  135. .argument("outputFile")
  136. .binding("outputFile"));
  137. options.addOption(Poco::Util::Option("doc-parse", "", "parse specified files for documentation markup")
  138. .required(false)
  139. .repeatable(false));
  140. options.addOption(Poco::Util::Option("proxy-environment-info", "", "display information for a given proxy environment")
  141. .required(false)
  142. .repeatable(false)
  143. .argument("proxyEnvName", false/*optional*/)
  144. .binding("proxyEnvName")
  145. .callback(Poco::Util::OptionCallback<PothosUtil>(this, &PothosUtil::printProxyEnvironmentInfo)));
  146. options.addOption(Poco::Util::Option("simd-features", "", "print available SIMD features")
  147. .required(false)
  148. .repeatable(false));
  149. options.addOption(Poco::Util::Option("generate-simd-dispatchers", "", "Generate SIMD dispatchers based on a given JSON file")
  150. .required(false)
  151. .repeatable(false)
  152. .argument("inputFile")
  153. .binding("inputFile")
  154. .callback(Poco::Util::OptionCallback<PothosUtil>(this, &PothosUtil::generateSIMDDispatchers)));
  155. options.addOption(Poco::Util::Option("simd-arches", "", "A comma-delimited list of SIMD arches, as generated at CMake-time")
  156. .required(false)
  157. .repeatable(false)
  158. .argument("simdArches")
  159. .binding("simdArches"));
  160. options.addOption(Poco::Util::Option("type-conversions", "", "Print types convertible to and from a given type")
  161. .required(false)
  162. .repeatable(false)
  163. .argument("type", false /*optional*/)
  164. .binding("type")
  165. .callback(Poco::Util::OptionCallback<PothosUtil>(this, &PothosUtil::printTypeConversions)));
  166. }
  167. void handleOption(const std::string &name, const std::string &value)
  168. {
  169. ServerApplication::handleOption(name, value);
  170. if (name == "help") _helpRequested = true;
  171. if (name == "doc-parse") _docParseRequested = true;
  172. if (name == "device-info") _deviceInfoRequested = true;
  173. if (name == "run-topology") _runTopologyRequested = true;
  174. if (name == "simd-features") _simdFeaturesRequested = true;
  175. if (name == "help") this->stopOptionsProcessing();
  176. //store --var options into the ordered vars map
  177. if (name == "var")
  178. {
  179. const auto pos = value.find(":");
  180. if (pos == std::string::npos) throw Pothos::InvalidArgumentException(
  181. "Cannot parse --var="+value+", expected --var=name:value format");
  182. _vars.emplace_back(value.substr(0, pos), value.substr(pos+1));
  183. }
  184. }
  185. void displayHelp(void)
  186. {
  187. Poco::Util::HelpFormatter helpFormatter(this->options());
  188. helpFormatter.setUnixStyle(true); //always unix style --option
  189. helpFormatter.setCommand(commandName());
  190. helpFormatter.setUsage("OPTIONS");
  191. helpFormatter.setHeader("\n"
  192. "PothosUtil is a helper executable for the Pothos Library; "
  193. "used both internally by the library, and externally by the user. "
  194. "The util provides a command-line interface for the self-tests, "
  195. "and can spawn servers and daemons for remote interfaces. ");
  196. helpFormatter.format(std::cout);
  197. }
  198. int main(const std::vector<std::string> &args)
  199. {
  200. try
  201. {
  202. if (_helpRequested) this->displayHelp();
  203. else if (_docParseRequested) this->docParse(args);
  204. else if (_deviceInfoRequested) this->printDeviceInfo();
  205. else if (_runTopologyRequested) this->runTopology();
  206. else if (_simdFeaturesRequested) this->printSIMDFeatures();
  207. }
  208. catch(const Pothos::Exception &ex)
  209. {
  210. std::cerr << ex.displayText() << std::endl;
  211. std::cout << std::endl;
  212. throw ex;
  213. }
  214. return Poco::Util::Application::EXIT_OK;
  215. }
  216. private:
  217. bool _helpRequested;
  218. bool _docParseRequested;
  219. bool _deviceInfoRequested;
  220. bool _runTopologyRequested;
  221. bool _simdFeaturesRequested;
  222. };
  223. int main(int argc, char *argv[])
  224. {
  225. POTHOS_EXCEPTION_TRY
  226. {
  227. PothosUtil app(argc);
  228. const int ret = app.run(argc, argv);
  229. if (ret == 0) return app.config().getInt("successCode", 0);
  230. return ret;
  231. }
  232. POTHOS_EXCEPTION_CATCH(const Pothos::Exception &ex)
  233. {
  234. std::cerr << ex.displayText() << std::endl;
  235. std::cout << std::endl;
  236. }
  237. return Poco::Util::Application::EXIT_USAGE;
  238. }