demo.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. #include <library/cpp/getopt/last_getopt.h>
  2. #include <library/cpp/getopt/modchooser.h>
  3. #include <library/cpp/colorizer/colors.h>
  4. // For the sake of this example, let's implement Wget
  5. Y_COMPLETER(HeaderCompleter) {
  6. AddCompletion("Host");
  7. AddCompletion("Referer");
  8. bool addPostHeaders = false;
  9. for (int i = 0; i < argc; ++i) {
  10. if (argv[i] == TStringBuf("--method") && i + 1 < argc) {
  11. auto method = TString(argv[i + 1]);
  12. method.to_upper();
  13. addPostHeaders = method == "POST" || method == "PUT";
  14. break;
  15. } else if (argv[i] == TStringBuf("--post-data") || argv[i] == TStringBuf("--post-file")) {
  16. addPostHeaders = true;
  17. break;
  18. }
  19. }
  20. if (addPostHeaders) {
  21. AddCompletion("Content-Type");
  22. AddCompletion("Content-Encoding");
  23. AddCompletion("Content-Language");
  24. AddCompletion("Content-Length");
  25. AddCompletion("Content-Location");
  26. AddCompletion("Content-MD5");
  27. AddCompletion("Content-Range");
  28. }
  29. }
  30. class TMain: public TMainClassArgs {
  31. bool Background_;
  32. size_t Timeout_;
  33. TString ExplicitMethod_;
  34. TString ImplicitMethod_ = "GET";
  35. TString UserAgent_;
  36. TMaybe<TString> PostData_;
  37. TMaybe<TString> PostFile_;
  38. TVector<TString> Headers_;
  39. protected:
  40. void RegisterOptions(NLastGetopt::TOpts& opts) override {
  41. // Brief description for the whole program, will appear in the beginning of a help message.
  42. opts.SetTitle("last_getopt_demo -- like wget, but doesn't actually do anything");
  43. // Built-in options.
  44. opts.AddHelpOption('h');
  45. opts.AddCompletionOption("last_getopt_demo");
  46. // Custom options.
  47. opts.AddLongOption('V', "version")
  48. .Help("print version and exit")
  49. .IfPresentDisableCompletion()
  50. .NoArgument()
  51. .Handler([]() {
  52. Cerr << "last_getopt_demo 1.0.0" << Endl;
  53. exit(0);
  54. });
  55. opts.AddLongOption('b', "background")
  56. .Help("go to background immediately after startup")
  57. .StoreTrue(&Background_);
  58. opts.AddLongOption("timeout")
  59. .RequiredArgument("timeout")
  60. .DefaultValue("60000")
  61. .Help("specify timeout in milliseconds for each request")
  62. .CompletionHelp("specify timeout for each request")
  63. .CompletionArgHelp("timeout (ms)")
  64. .StoreResult(&Timeout_)
  65. .Completer(NLastGetopt::NComp::Choice({{"1000"}, {"5000"}, {"10000"}, {"60000"}}));
  66. opts.AddLongOption("method")
  67. .RequiredArgument("http-method")
  68. .Help("specify HTTP method")
  69. .CompletionArgHelp("http method")
  70. .StoreResult(&ExplicitMethod_)
  71. .ChoicesWithCompletion({
  72. {"GET", "request representation of the specified resource"},
  73. {"HEAD", "request response identical to that of GET, but without response body"},
  74. {"POST", "submit an entry to the specified resource"},
  75. {"PUT", "replace representation of the specified resource with the request body"},
  76. {"DELETE", "delete the specified resource"},
  77. {"CONNECT", "establish a tunnel to the server identified by the target resource"},
  78. {"OPTIONS", "describe the communication options for the target resource"},
  79. {"TRACE", "perform a message loop-back test"},
  80. {"PATCH", "apply partial modifications to the specified resource"}});
  81. opts.AddLongOption('U', "user-agent")
  82. .RequiredArgument("agent-string")
  83. .DefaultValue("LastGetoptDemo/1.0.0")
  84. .Help("identify as `agent-string` to the HTTP server")
  85. .CompletionHelp("set custom user agent for each HTTP request")
  86. .CompletionArgHelp("user agent string")
  87. .StoreResult(&UserAgent_);
  88. opts.AddLongOption("post-data")
  89. .RequiredArgument("string")
  90. .Help("use POST method and send the specified data in the request body (cannot be used with --post-file)")
  91. .CompletionHelp("use POST method and send the specified data in the request body")
  92. .CompletionArgHelp("POST data string")
  93. .StoreResultT<TString>(&PostData_)
  94. .Handler0([this]() {
  95. ImplicitMethod_ = "POST";
  96. });
  97. opts.AddLongOption("post-file")
  98. .RequiredArgument("file")
  99. .Help("use POST method and send contents of the specified file in the request body (cannot be used with --post-data)")
  100. .CompletionHelp("use POST method and send contents of the specified file in the request body")
  101. .CompletionArgHelp("POST file")
  102. .StoreResultT<TString>(&PostFile_)
  103. .Handler0([this]() {
  104. ImplicitMethod_ = "POST";
  105. })
  106. .Completer(NLastGetopt::NComp::File());
  107. // These two options can't be together.
  108. opts.MutuallyExclusive("post-file", "post-data");
  109. opts.AddLongOption("header")
  110. .RequiredArgument("header-line")
  111. .Help("send `header-line` along with the rest of the headers in each HTTP request")
  112. .CompletionHelp("add header to each HTTP request")
  113. .CompletionArgHelp("header string")
  114. .AppendTo(&Headers_)
  115. .AllowMultipleCompletion()
  116. .Completer(NLastGetopt::NComp::LaunchSelf(HeaderCompleter));
  117. // Setting up free arguments.
  118. // We are going to have one mandatory argument and unlimited number of optional arguments.
  119. opts.SetFreeArgsMin(1);
  120. opts.SetFreeArgsMax(NLastGetopt::TOpts::UNLIMITED_ARGS);
  121. // Configuration for the first argument.
  122. opts.GetFreeArgSpec(0)
  123. .Title("URL")
  124. .Help("URL for download")
  125. .CompletionArgHelp("URL for download")
  126. .Completer(NLastGetopt::NComp::Url());
  127. // Configuration for optional arguments.
  128. opts.GetTrailingArgSpec()
  129. .Title("URL")
  130. .CompletionArgHelp("URL for download")
  131. .Completer(NLastGetopt::NComp::Url());
  132. // Let's add more text to our help. A nice description and examples.
  133. opts.AddSection(
  134. "Description",
  135. "LastGetoptDemo is a showcase of library/cpp/getopt capabilities. It mimics interface of Wget "
  136. "but doesn't actually do anything."
  137. "\n\n"
  138. "GNU Wget, on the other hand, is a free utility for non-interactive download of files from the Web."
  139. "It supports HTTP, HTTPS, and FTP protocols, as well as retrieval through HTTP proxies."
  140. "\n\n"
  141. "Wget is non-interactive, meaning that it can work in the background, while the user is not logged on. "
  142. "This allows you to start a retrieval and disconnect from the system, letting Wget finish the work. "
  143. "By contrast, most of the Web browsers require constant user's presence, "
  144. "which can be a great hindrance when transferring a lot of data."
  145. "\n\n"
  146. "Wget can follow links in HTML, XHTML, and CSS pages, to create local versions of remote web sites, "
  147. "fully recreating the directory structure of the original site. "
  148. "This is sometimes referred to as \"recursive downloading.\" "
  149. "While doing that, Wget respects the Robot Exclusion Standard (/robots.txt). "
  150. "Wget can be instructed to convert the links in downloaded files to point at the local files, "
  151. "for offline viewing."
  152. "\n\n"
  153. "Wget has been designed for robustness over slow or unstable network connections; "
  154. "if a download fails due to a network problem, "
  155. "it will keep retrying until the whole file has been retrieved. "
  156. "If the server supports regetting, "
  157. "it will instruct the server to continue the download from where it left off."
  158. "\n\n"
  159. "Wget does not support Client Revocation Lists (CRLs) so the HTTPS certificate "
  160. "you are connecting to might be revoked by the siteowner.");
  161. // We will use colors for this one.
  162. auto& colors = NColorizer::StdErr();
  163. opts.AddSection(
  164. "Examples",
  165. TStringBuilder()
  166. << "Download a file:"
  167. << "\n"
  168. << colors.Cyan()
  169. << " $ last_getopt_demo https://wordpress.org/latest.zip"
  170. << colors.Reset()
  171. << "\n"
  172. << "Download a file in background, set custom user agent:"
  173. << "\n"
  174. << colors.Cyan()
  175. << " $ last_getopt_demo -b -U 'Wget/1.0.0' https://wordpress.org/latest.zip"
  176. << colors.Reset());
  177. }
  178. int DoRun(NLastGetopt::TOptsParseResult&& parsedOptions) override {
  179. using namespace NColorizer;
  180. TString method = ExplicitMethod_ ? ExplicitMethod_ : ImplicitMethod_;
  181. Cerr << ST_LIGHT << "Settings:" << RESET << Endl;
  182. Cerr << GREEN << " Background: " << RESET << Background_ << Endl;
  183. Cerr << GREEN << " Timeout: " << RESET << Timeout_ << Endl;
  184. Cerr << GREEN << " Method: " << RESET << method.Quote() << Endl;
  185. Cerr << GREEN << " UserAgent: " << RESET << UserAgent_.Quote() << Endl;
  186. Cerr << GREEN << " PostData: " << RESET << (PostData_ ? PostData_->Quote() : "Nothing") << Endl;
  187. Cerr << GREEN << " PostFile: " << RESET << (PostFile_ ? PostFile_->Quote() : "Nothing") << Endl;
  188. Cerr << ST_LIGHT << "Headers:" << RESET << Endl;
  189. for (auto& header : Headers_) {
  190. Cerr << " " << header.Quote() << Endl;
  191. }
  192. if (!Headers_) {
  193. Cerr << GREEN << " no headers" << RESET << Endl;
  194. }
  195. Cerr << ST_LIGHT << "Will download the following URLs:" << RESET << Endl;
  196. for (auto& arg : parsedOptions.GetFreeArgs()) {
  197. Cerr << " " << arg.Quote() << Endl;
  198. }
  199. if (!parsedOptions.GetFreeArgs()) {
  200. Cerr << " no urls" << Endl;
  201. }
  202. return 0;
  203. }
  204. };
  205. int main(int argc, const char** argv) {
  206. NLastGetopt::NComp::TCustomCompleter::FireCustomCompleter(argc, argv);
  207. TMain().Run(argc, argv);
  208. }