123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- #include <library/cpp/getopt/last_getopt.h>
- #include <library/cpp/getopt/modchooser.h>
- #include <library/cpp/colorizer/colors.h>
- // For the sake of this example, let's implement Wget
- Y_COMPLETER(HeaderCompleter) {
- AddCompletion("Host");
- AddCompletion("Referer");
- bool addPostHeaders = false;
- for (int i = 0; i < argc; ++i) {
- if (argv[i] == TStringBuf("--method") && i + 1 < argc) {
- auto method = TString(argv[i + 1]);
- method.to_upper();
- addPostHeaders = method == "POST" || method == "PUT";
- break;
- } else if (argv[i] == TStringBuf("--post-data") || argv[i] == TStringBuf("--post-file")) {
- addPostHeaders = true;
- break;
- }
- }
- if (addPostHeaders) {
- AddCompletion("Content-Type");
- AddCompletion("Content-Encoding");
- AddCompletion("Content-Language");
- AddCompletion("Content-Length");
- AddCompletion("Content-Location");
- AddCompletion("Content-MD5");
- AddCompletion("Content-Range");
- }
- }
- class TMain: public TMainClassArgs {
- bool Background_;
- size_t Timeout_;
- TString ExplicitMethod_;
- TString ImplicitMethod_ = "GET";
- TString UserAgent_;
- TMaybe<TString> PostData_;
- TMaybe<TString> PostFile_;
- TVector<TString> Headers_;
- protected:
- void RegisterOptions(NLastGetopt::TOpts& opts) override {
- // Brief description for the whole program, will appear in the beginning of a help message.
- opts.SetTitle("last_getopt_demo -- like wget, but doesn't actually do anything");
- // Built-in options.
- opts.AddHelpOption('h');
- opts.AddCompletionOption("last_getopt_demo");
- // Custom options.
- opts.AddLongOption('V', "version")
- .Help("print version and exit")
- .IfPresentDisableCompletion()
- .NoArgument()
- .Handler([]() {
- Cerr << "last_getopt_demo 1.0.0" << Endl;
- exit(0);
- });
- opts.AddLongOption('b', "background")
- .Help("go to background immediately after startup")
- .StoreTrue(&Background_);
- opts.AddLongOption("timeout")
- .RequiredArgument("timeout")
- .DefaultValue("60000")
- .Help("specify timeout in milliseconds for each request")
- .CompletionHelp("specify timeout for each request")
- .CompletionArgHelp("timeout (ms)")
- .StoreResult(&Timeout_)
- .Completer(NLastGetopt::NComp::Choice({{"1000"}, {"5000"}, {"10000"}, {"60000"}}));
- opts.AddLongOption("method")
- .RequiredArgument("http-method")
- .Help("specify HTTP method")
- .CompletionArgHelp("http method")
- .StoreResult(&ExplicitMethod_)
- .ChoicesWithCompletion({
- {"GET", "request representation of the specified resource"},
- {"HEAD", "request response identical to that of GET, but without response body"},
- {"POST", "submit an entry to the specified resource"},
- {"PUT", "replace representation of the specified resource with the request body"},
- {"DELETE", "delete the specified resource"},
- {"CONNECT", "establish a tunnel to the server identified by the target resource"},
- {"OPTIONS", "describe the communication options for the target resource"},
- {"TRACE", "perform a message loop-back test"},
- {"PATCH", "apply partial modifications to the specified resource"}});
- opts.AddLongOption('U', "user-agent")
- .RequiredArgument("agent-string")
- .DefaultValue("LastGetoptDemo/1.0.0")
- .Help("identify as `agent-string` to the HTTP server")
- .CompletionHelp("set custom user agent for each HTTP request")
- .CompletionArgHelp("user agent string")
- .StoreResult(&UserAgent_);
- opts.AddLongOption("post-data")
- .RequiredArgument("string")
- .Help("use POST method and send the specified data in the request body (cannot be used with --post-file)")
- .CompletionHelp("use POST method and send the specified data in the request body")
- .CompletionArgHelp("POST data string")
- .StoreResultT<TString>(&PostData_)
- .Handler0([this]() {
- ImplicitMethod_ = "POST";
- });
- opts.AddLongOption("post-file")
- .RequiredArgument("file")
- .Help("use POST method and send contents of the specified file in the request body (cannot be used with --post-data)")
- .CompletionHelp("use POST method and send contents of the specified file in the request body")
- .CompletionArgHelp("POST file")
- .StoreResultT<TString>(&PostFile_)
- .Handler0([this]() {
- ImplicitMethod_ = "POST";
- })
- .Completer(NLastGetopt::NComp::File());
- // These two options can't be together.
- opts.MutuallyExclusive("post-file", "post-data");
- opts.AddLongOption("header")
- .RequiredArgument("header-line")
- .Help("send `header-line` along with the rest of the headers in each HTTP request")
- .CompletionHelp("add header to each HTTP request")
- .CompletionArgHelp("header string")
- .AppendTo(&Headers_)
- .AllowMultipleCompletion()
- .Completer(NLastGetopt::NComp::LaunchSelf(HeaderCompleter));
- // Setting up free arguments.
- // We are going to have one mandatory argument and unlimited number of optional arguments.
- opts.SetFreeArgsMin(1);
- opts.SetFreeArgsMax(NLastGetopt::TOpts::UNLIMITED_ARGS);
- // Configuration for the first argument.
- opts.GetFreeArgSpec(0)
- .Title("URL")
- .Help("URL for download")
- .CompletionArgHelp("URL for download")
- .Completer(NLastGetopt::NComp::Url());
- // Configuration for optional arguments.
- opts.GetTrailingArgSpec()
- .Title("URL")
- .CompletionArgHelp("URL for download")
- .Completer(NLastGetopt::NComp::Url());
- // Let's add more text to our help. A nice description and examples.
- opts.AddSection(
- "Description",
- "LastGetoptDemo is a showcase of library/cpp/getopt capabilities. It mimics interface of Wget "
- "but doesn't actually do anything."
- "\n\n"
- "GNU Wget, on the other hand, is a free utility for non-interactive download of files from the Web."
- "It supports HTTP, HTTPS, and FTP protocols, as well as retrieval through HTTP proxies."
- "\n\n"
- "Wget is non-interactive, meaning that it can work in the background, while the user is not logged on. "
- "This allows you to start a retrieval and disconnect from the system, letting Wget finish the work. "
- "By contrast, most of the Web browsers require constant user's presence, "
- "which can be a great hindrance when transferring a lot of data."
- "\n\n"
- "Wget can follow links in HTML, XHTML, and CSS pages, to create local versions of remote web sites, "
- "fully recreating the directory structure of the original site. "
- "This is sometimes referred to as \"recursive downloading.\" "
- "While doing that, Wget respects the Robot Exclusion Standard (/robots.txt). "
- "Wget can be instructed to convert the links in downloaded files to point at the local files, "
- "for offline viewing."
- "\n\n"
- "Wget has been designed for robustness over slow or unstable network connections; "
- "if a download fails due to a network problem, "
- "it will keep retrying until the whole file has been retrieved. "
- "If the server supports regetting, "
- "it will instruct the server to continue the download from where it left off."
- "\n\n"
- "Wget does not support Client Revocation Lists (CRLs) so the HTTPS certificate "
- "you are connecting to might be revoked by the siteowner.");
- // We will use colors for this one.
- auto& colors = NColorizer::StdErr();
- opts.AddSection(
- "Examples",
- TStringBuilder()
- << "Download a file:"
- << "\n"
- << colors.Cyan()
- << " $ last_getopt_demo https://wordpress.org/latest.zip"
- << colors.Reset()
- << "\n"
- << "Download a file in background, set custom user agent:"
- << "\n"
- << colors.Cyan()
- << " $ last_getopt_demo -b -U 'Wget/1.0.0' https://wordpress.org/latest.zip"
- << colors.Reset());
- }
- int DoRun(NLastGetopt::TOptsParseResult&& parsedOptions) override {
- using namespace NColorizer;
- TString method = ExplicitMethod_ ? ExplicitMethod_ : ImplicitMethod_;
- Cerr << ST_LIGHT << "Settings:" << RESET << Endl;
- Cerr << GREEN << " Background: " << RESET << Background_ << Endl;
- Cerr << GREEN << " Timeout: " << RESET << Timeout_ << Endl;
- Cerr << GREEN << " Method: " << RESET << method.Quote() << Endl;
- Cerr << GREEN << " UserAgent: " << RESET << UserAgent_.Quote() << Endl;
- Cerr << GREEN << " PostData: " << RESET << (PostData_ ? PostData_->Quote() : "Nothing") << Endl;
- Cerr << GREEN << " PostFile: " << RESET << (PostFile_ ? PostFile_->Quote() : "Nothing") << Endl;
- Cerr << ST_LIGHT << "Headers:" << RESET << Endl;
- for (auto& header : Headers_) {
- Cerr << " " << header.Quote() << Endl;
- }
- if (!Headers_) {
- Cerr << GREEN << " no headers" << RESET << Endl;
- }
- Cerr << ST_LIGHT << "Will download the following URLs:" << RESET << Endl;
- for (auto& arg : parsedOptions.GetFreeArgs()) {
- Cerr << " " << arg.Quote() << Endl;
- }
- if (!parsedOptions.GetFreeArgs()) {
- Cerr << " no urls" << Endl;
- }
- return 0;
- }
- };
- int main(int argc, const char** argv) {
- NLastGetopt::NComp::TCustomCompleter::FireCustomCompleter(argc, argv);
- TMain().Run(argc, argv);
- }
|