diff options
author | pnv1 <pnv@ydb.tech> | 2022-09-05 15:48:19 +0300 |
---|---|---|
committer | pnv1 <pnv@ydb.tech> | 2022-09-05 15:48:19 +0300 |
commit | 8f78f0859f3b29634cde61f3a5f629d389366e29 (patch) | |
tree | fbe3410e5c5fdc2e6dae79a16f6ea2be4523b8d8 | |
parent | 0f9922b1cc7d537b63655c35d597f8964b65dbf0 (diff) | |
download | ydb-8f78f0859f3b29634cde61f3a5f629d389366e29.tar.gz |
Change YDB CLI processing with better system commands handling
-rw-r--r-- | ydb/apps/ydb/commands/ydb_cloud_root.cpp | 9 | ||||
-rw-r--r-- | ydb/apps/ydb/commands/ydb_update.cpp | 3 | ||||
-rw-r--r-- | ydb/apps/ydb/commands/ydb_version.cpp | 10 | ||||
-rw-r--r-- | ydb/apps/ydb/commands/ydb_version.h | 4 | ||||
-rw-r--r-- | ydb/core/driver_lib/cli_base/cli_cmds_root.cpp | 16 | ||||
-rw-r--r-- | ydb/public/lib/ydb_cli/commands/ydb_profile.cpp | 8 | ||||
-rw-r--r-- | ydb/public/lib/ydb_cli/commands/ydb_profile.h | 1 | ||||
-rw-r--r-- | ydb/public/lib/ydb_cli/commands/ydb_root_common.cpp | 33 | ||||
-rw-r--r-- | ydb/public/lib/ydb_cli/commands/ydb_root_common.h | 1 | ||||
-rw-r--r-- | ydb/public/lib/ydb_cli/common/command.cpp | 95 | ||||
-rw-r--r-- | ydb/public/lib/ydb_cli/common/command.h | 118 | ||||
-rw-r--r-- | ydb/public/lib/ydb_cli/common/root.cpp | 6 |
12 files changed, 160 insertions, 144 deletions
diff --git a/ydb/apps/ydb/commands/ydb_cloud_root.cpp b/ydb/apps/ydb/commands/ydb_cloud_root.cpp index 9a3e972a9a3..5814f8bd226 100644 --- a/ydb/apps/ydb/commands/ydb_cloud_root.cpp +++ b/ydb/apps/ydb/commands/ydb_cloud_root.cpp @@ -71,18 +71,17 @@ void TYCloudClientCommandRoot::Config(TConfig& config) { } int TYCloudClientCommandRoot::Run(TConfig& config) { - if (!config.IsUpdateCommand() && !config.IsSetVersionCheckCommand()) { + if (config.NeedToCheckForUpdate) { TYdbUpdater updater; - bool forceVersionCheck = config.IsVersionForceCheckCommand(); - if (forceVersionCheck) { + if (config.ForceVersionCheck) { Cout << "Force checking if there is a newer version..." << Endl; } - if (updater.CheckIfUpdateNeeded(forceVersionCheck)) { + if (updater.CheckIfUpdateNeeded(config.ForceVersionCheck)) { NColorizer::TColors colors = NColorizer::AutoColors(Cerr); Cerr << colors.RedColor() << "(!) New version of YDB CLI is available. Run 'ydb update' command for update. " << "You can also disable further version checks with 'ydb version --disable-checks' command" << colors.OldColor() << Endl; - } else if (forceVersionCheck) { + } else if (config.ForceVersionCheck) { NColorizer::TColors colors = NColorizer::AutoColors(Cerr); Cout << colors.GreenColor() << "Current version is up to date" << colors.OldColor() << Endl; diff --git a/ydb/apps/ydb/commands/ydb_update.cpp b/ydb/apps/ydb/commands/ydb_update.cpp index 4bee5308da5..8fc36015e99 100644 --- a/ydb/apps/ydb/commands/ydb_update.cpp +++ b/ydb/apps/ydb/commands/ydb_update.cpp @@ -10,6 +10,9 @@ TCommandUpdate::TCommandUpdate() void TCommandUpdate::Config(TConfig& config) { TClientCommand::Config(config); + config.NeedToConnect = false; + config.NeedToCheckForUpdate = false; + config.SetFreeArgsNum(0); config.Opts->AddLongOption('f', "force", "Force update. Do not check if there is a newer version available.") diff --git a/ydb/apps/ydb/commands/ydb_version.cpp b/ydb/apps/ydb/commands/ydb_version.cpp index be5b1fabb49..5f5e638dd08 100644 --- a/ydb/apps/ydb/commands/ydb_version.cpp +++ b/ydb/apps/ydb/commands/ydb_version.cpp @@ -14,12 +14,14 @@ TCommandVersion::TCommandVersion() void TCommandVersion::Config(TConfig& config) { TClientCommand::Config(config); + config.NeedToConnect = false; + config.SetFreeArgsNum(0); config.Opts->AddLongOption("semantic", "Print semantic version only") .StoreTrue(&Semantic); config.Opts->AddLongOption("check", "Force to check latest version available") - .StoreTrue(&ForceCheck); + .StoreTrue(&config.ForceVersionCheck); config.Opts->AddLongOption("disable-checks", "Disable version checks. CLI will not check whether there is a newer version available") .StoreTrue(&DisableChecks); config.Opts->AddLongOption("enable-checks", "Enable version checks. CLI will regularly check whether there is a newer version available") @@ -31,6 +33,12 @@ void TCommandVersion::Config(TConfig& config) { config.Opts->MutuallyExclusive("enable-checks", "semantic"); config.Opts->MutuallyExclusive("enable-checks", "check"); config.Opts->MutuallyExclusive("check", "semantic"); +}
+
+void TCommandVersion::Parse(TConfig& config) {
+ TClientCommand::Parse(config);
+
+ config.NeedToCheckForUpdate = !DisableChecks && !EnableChecks;
} int TCommandVersion::Run(TConfig& config) { diff --git a/ydb/apps/ydb/commands/ydb_version.h b/ydb/apps/ydb/commands/ydb_version.h index 84e4fb5a890..ca0584bfb31 100644 --- a/ydb/apps/ydb/commands/ydb_version.h +++ b/ydb/apps/ydb/commands/ydb_version.h @@ -9,11 +9,11 @@ class TCommandVersion : public TClientCommand { public: TCommandVersion(); virtual void Config(TConfig& config) override; - virtual int Run(TConfig& config) override; + virtual int Run(TConfig& config) override;
+ virtual void Parse(TConfig& config) override; private: bool Semantic = false; - bool ForceCheck = false; bool DisableChecks = false; bool EnableChecks = false; }; diff --git a/ydb/core/driver_lib/cli_base/cli_cmds_root.cpp b/ydb/core/driver_lib/cli_base/cli_cmds_root.cpp index 7c8f51b100c..37773ac3ac5 100644 --- a/ydb/core/driver_lib/cli_base/cli_cmds_root.cpp +++ b/ydb/core/driver_lib/cli_base/cli_cmds_root.cpp @@ -104,12 +104,7 @@ public: port = FromString<ui32>(portStr); } } else { - if (config.IsHelpCommand()) { - return; - } else { - throw TMisuseException() - << "Missing required option 'server'. Also couldn't find 'host' variable in profile config."; - } + return; } } ParseProtocol(config); @@ -127,6 +122,15 @@ public: } } + void Validate(TConfig& config) override { + TClientCommandRootBase::Validate(config); + + if (Address.empty() && config.NeedToConnect) { + throw TMisuseException() + << "Missing required option 'server'. Also couldn't find 'host' variable in profile config."; + } + } + private: bool DumpRequests = false; }; diff --git a/ydb/public/lib/ydb_cli/commands/ydb_profile.cpp b/ydb/public/lib/ydb_cli/commands/ydb_profile.cpp index e39e120fd15..566cfdcba1f 100644 --- a/ydb/public/lib/ydb_cli/commands/ydb_profile.cpp +++ b/ydb/public/lib/ydb_cli/commands/ydb_profile.cpp @@ -28,6 +28,12 @@ TCommandConfig::TCommandConfig() AddCommand(std::make_unique<TCommandProfile>()); } +void TCommandConfig::Config(TConfig& config) { + TClientCommandTree::Config(config); + + config.NeedToConnect = false; +} + TCommandProfile::TCommandProfile() : TClientCommandTree("profile", {}, "Manage configuration profiles") { @@ -368,6 +374,8 @@ TCommandInit::TCommandInit() void TCommandInit::Config(TConfig& config) { TClientCommand::Config(config); + config.NeedToConnect = false; + config.SetFreeArgsNum(0); } diff --git a/ydb/public/lib/ydb_cli/commands/ydb_profile.h b/ydb/public/lib/ydb_cli/commands/ydb_profile.h index c71c7adf3f5..514dc82f303 100644 --- a/ydb/public/lib/ydb_cli/commands/ydb_profile.h +++ b/ydb/public/lib/ydb_cli/commands/ydb_profile.h @@ -11,6 +11,7 @@ std::shared_ptr<IProfileManager> CreateYdbProfileManager(const TString& ydbDir); class TCommandConfig : public TClientCommandTree { public: TCommandConfig(); + virtual void Config(TConfig& config) override; }; class TCommandProfile : public TClientCommandTree { diff --git a/ydb/public/lib/ydb_cli/commands/ydb_root_common.cpp b/ydb/public/lib/ydb_cli/commands/ydb_root_common.cpp index 3be1dc27451..31805fd27e6 100644 --- a/ydb/public/lib/ydb_cli/commands/ydb_root_common.cpp +++ b/ydb/public/lib/ydb_cli/commands/ydb_root_common.cpp @@ -227,10 +227,8 @@ void TClientCommandRootCommon::Parse(TConfig& config) { ParseProfile(); TClientCommandRootBase::Parse(config); - if (!config.IsSystemCommand()) { - ParseDatabase(config); - ParseCaCerts(config); - } + ParseDatabase(config); + ParseCaCerts(config); config.IsVerbose = IsVerbose; } @@ -248,14 +246,7 @@ void TClientCommandRootCommon::ParseAddress(TConfig& config) { } } - if (Address.empty()) { - if (config.IsSystemCommand()) { - return; - } else { - throw TMisuseException() - << "Missing required option 'endpoint'."; - } - } else { + if (!Address.empty()) { config.EnableSsl = Settings.EnableSsl.GetRef(); ParseProtocol(config); auto colon_pos = Address.find(":"); @@ -293,14 +284,26 @@ void TClientCommandRootCommon::ParseDatabase(TConfig& config) { } } - if (Database.empty()) { + config.Database = Database; +} + +void TClientCommandRootCommon::Validate(TConfig& config) { + TClientCommandRootBase::Validate(config); + + if (Address.empty() && config.NeedToConnect) { throw TMisuseException() - << "Missing required option 'database'."; + << "Missing required option 'endpoint'."; + } + + if (Database.empty()) { + if (config.NeedToConnect) { + throw TMisuseException() + << "Missing required option 'database'."; + } } else if (!Database.StartsWith('/')) { throw TMisuseException() << "Path to a database \"" << Database << "\" is incorrect. It must be absolute and thus must begin with '/'."; } - config.Database = Database; } namespace { diff --git a/ydb/public/lib/ydb_cli/commands/ydb_root_common.h b/ydb/public/lib/ydb_cli/commands/ydb_root_common.h index 3ffa024ed33..c6a5713936b 100644 --- a/ydb/public/lib/ydb_cli/commands/ydb_root_common.h +++ b/ydb/public/lib/ydb_cli/commands/ydb_root_common.h @@ -32,6 +32,7 @@ public: void Parse(TConfig& config) override; void ParseAddress(TConfig& config) override; void ParseCredentials(TConfig& config) override; + void Validate(TConfig& config) override; protected: virtual void FillConfig(TConfig& config); diff --git a/ydb/public/lib/ydb_cli/common/command.cpp b/ydb/public/lib/ydb_cli/common/command.cpp index 580fe4d6c06..13d624b651b 100644 --- a/ydb/public/lib/ydb_cli/common/command.cpp +++ b/ydb/public/lib/ydb_cli/common/command.cpp @@ -98,21 +98,20 @@ TClientCommand::TClientCommand(const TString& name, const std::initializer_list< Opts.SetWrap(Max(Opts.Wrap_, static_cast<ui32>(TermWidth()))); } - -TClientCommand::TOptsParseOneLevelResult::TOptsParseOneLevelResult(const NLastGetopt::TOpts* options, int argc, char** argv) { +TClientCommand::TOptsParseOneLevelResult::TOptsParseOneLevelResult(TConfig& config) { int _argc = 1; int levels = 1; - while (levels > 0 && _argc < argc) { - if (argv[_argc][0] == '-') { + while (levels > 0 && _argc < config.ArgC) { + if (config.ArgV[_argc][0] == '-') { const NLastGetopt::TOpt* opt = nullptr; - TStringBuf optName(argv[_argc]); + TStringBuf optName(config.ArgV[_argc]); auto eqPos = optName.find('='); optName = optName.substr(0, eqPos); if (optName.StartsWith("--")) { - opt = options->FindLongOption(optName.substr(2)); + opt = config.Opts->FindLongOption(optName.substr(2)); } else { - opt = options->FindCharOption(optName[1]); + opt = config.Opts->FindCharOption(optName[1]); } if (opt != nullptr && opt->GetHasArg() != NLastGetopt::NO_ARGUMENT) { if (eqPos == TStringBuf::npos) { @@ -124,7 +123,32 @@ TClientCommand::TOptsParseOneLevelResult::TOptsParseOneLevelResult(const NLastGe } ++_argc; } - Init(options, _argc, const_cast<const char**>(argv)); + Init(config.Opts, _argc, const_cast<const char**>(config.ArgV)); +} + +void TClientCommand::CheckForExecutableOptions(TConfig& config) { + int argc = 1; + + while (argc < config.ArgC && config.ArgV[argc][0] == '-') { + const NLastGetopt::TOpt* opt = nullptr; + TStringBuf optName(config.ArgV[argc]); + auto eqPos = optName.find('='); + optName = optName.substr(0, eqPos); + if (optName.StartsWith("--")) { + opt = config.Opts->FindLongOption(optName.substr(2)); + } else { + opt = config.Opts->FindCharOption(optName[1]); + } + if (config.ExecutableOptions.find(optName) != config.ExecutableOptions.end()) { + config.HasExecutableOptions = true; + } + if (opt != nullptr && opt->GetHasArg() != NLastGetopt::NO_ARGUMENT) { + if (eqPos == TStringBuf::npos) { + ++argc; + } + } + ++argc; + } } void TClientCommand::Config(TConfig& config) { @@ -141,6 +165,10 @@ void TClientCommand::Parse(TConfig& config) { Y_UNUSED(config); } +void TClientCommand::Validate(TConfig& config) { + Y_UNUSED(config); +} + int TClientCommand::Run(TConfig& config) { Y_UNUSED(config); // TODO: invalid usage ? error? help? @@ -148,14 +176,30 @@ int TClientCommand::Run(TConfig& config) { } int TClientCommand::Process(TConfig& config) { + Prepare(config); + return ValidateAndRun(config); +} + +void TClientCommand::SaveParseResult(TConfig& config) { + ParseResult = std::make_shared<NLastGetopt::TOptsParseResult>(config.Opts, config.ArgC, config.ArgV); +} + +void TClientCommand::Prepare(TConfig& config) { config.ArgsSettings.Reset(new TConfig::TArgSettings()); config.Opts = &Opts; Config(config); + CheckForExecutableOptions(config); config.CheckParamsCount(); SetCustomUsage(config); - NLastGetopt::TOptsParseResult parseResult(config.Opts, config.ArgC, config.ArgV); - config.ParseResult = &parseResult; + SaveParseResult(config); + config.ParseResult = ParseResult.get(); Parse(config); +} + +int TClientCommand::ValidateAndRun(TConfig& config) { + config.Opts = &Opts; + config.ParseResult = ParseResult.get(); + Validate(config); return Run(config); } @@ -265,11 +309,6 @@ void TClientCommandTree::Config(TConfig& config) { TClientCommand::Config(config); SetFreeArgs(config); TString commands; - for (auto it = SubCommands.begin(); it != SubCommands.end(); ++it) { - if (!commands.empty()) - commands += ','; - commands += it->first; - } SetFreeArgTitle(0, "<subcommand>", commands); TStringStream stream; NColorizer::TColors colors = NColorizer::AutoColors(Cout); @@ -282,6 +321,10 @@ void TClientCommandTree::Config(TConfig& config) { config.Opts->SetCmdLineDescr(stream.Str()); } +void TClientCommandTree::SaveParseResult(TConfig& config) { + ParseResult = std::make_shared<TOptsParseOneLevelResult>(config); +} + void TClientCommandTree::Parse(TConfig& config) { TClientCommand::Parse(config); TString cmd = config.ParseResult->GetFreeArgs().at(0); @@ -310,22 +353,20 @@ void TClientCommandTree::Parse(TConfig& config) { int TClientCommandTree::Run(TConfig& config) { if (SelectedCommand) { - return SelectedCommand->Process(config); + return SelectedCommand->ValidateAndRun(config); } - throw yexception() << "Error"; + throw yexception() << "No child command to run"; } -int TClientCommandTree::Process(TConfig& config) { - config.ArgsSettings.Reset(new TConfig::TArgSettings()); - config.Opts = &Opts; - Config(config); - config.CheckParamsCount(); - SetCustomUsage(config); - TOptsParseOneLevelResult parseResult(config.Opts, config.ArgC, config.ArgV); - config.ParseResult = &parseResult; - Parse(config); +void TClientCommandTree::Prepare(TConfig& config) { + TClientCommand::Prepare(config); config.ParentCommands.push_back({ Name, HasOptionsToShow() ? &Opts : nullptr }); - return Run(config); + + if (SelectedCommand) { + SelectedCommand->Prepare(config); + } else { + throw yexception() << "No child command to prepare"; + } } void TClientCommandTree::SetFreeArgs(TConfig& config) { diff --git a/ydb/public/lib/ydb_cli/common/command.h b/ydb/public/lib/ydb_cli/common/command.h index 1d198478b38..2dc4744b972 100644 --- a/ydb/public/lib/ydb_cli/common/command.h +++ b/ydb/public/lib/ydb_cli/common/command.h @@ -29,11 +29,6 @@ public: TClientCommand(const TString& name, const std::initializer_list<TString>& aliases = std::initializer_list<TString>(), const TString& description = TString()); - class TOptsParseOneLevelResult : public NLastGetopt::TOptsParseResult { - public: - TOptsParseOneLevelResult(const NLastGetopt::TOpts* options, int argc, char** argv); - }; - class TConfig { struct TCommandInfo { TString Name; @@ -77,6 +72,8 @@ public: TVector<TString> Tokens; TString SecurityToken; TList<TCommandInfo> ParentCommands; + THashSet<TString> ExecutableOptions; + bool HasExecutableOptions = false; TString Path; THolder<TArgSettings> ArgsSettings; TString Address; @@ -106,6 +103,10 @@ public: bool UseIamAuth = false; bool UseStaticCredentials = false; bool UseExportToYt = true; + // Whether a command needs a connection to YDB + bool NeedToConnect = true; + bool NeedToCheckForUpdate = true; + bool ForceVersionCheck = false; TCredentialsGetter CredentialsGetter; @@ -126,76 +127,8 @@ public: }; } - bool IsHelpCommand() const { - TString lastArg = ArgV[ArgC - 1]; - return lastArg == "--help" || lastArg == "-h" || lastArg == "-?"; - } - - bool IsYdbCommand() const { - for (int i = 0; i < InitialArgC; ++i) { - TString arg = InitialArgV[i]; - if (arg.EndsWith("ydb") || arg.EndsWith("ydb.exe")) { - return true; - } - } - return false; - } - - bool IsSvnVersionCommand() const { - TString lastArg = ArgV[ArgC - 1]; - return lastArg == "--svnrevision" || lastArg == "-V"; - } - - bool IsVersionCommand() const { - return HasArgs({ "version" }); - } - - bool IsVersionForceCheckCommand() const { - return HasArgs({ "version", "--check" }); - } - - bool IsSetVersionCheckCommand() const { - return HasArgs({ "version", "--enable-checks" }) || HasArgs({ "version", "--disable-checks" }); - } - - bool IsUpdateCommand() const { - return HasArgs({ "update" }); - } - - bool IsInitCommand() const { - return HasArgs({ "init" }) && !HasArgs({ "workload" }); - } - - bool IsProfileCommand() const { - return HasArgs({ "profile" }); - } - - bool IsLicenseCommand() const { - TString lastArg = ArgV[ArgC - 1]; - return lastArg == "--license"; - } - - bool IsCreditsCommand() const { - TString lastArg = ArgV[ArgC - 1]; - return lastArg == "--credits"; - } - - bool IsHelpExCommand() const { - TString lastArg = ArgV[ArgC - 1]; - return lastArg == "--help-ex"; - } - - // "System" commands doesn't need endpoint, database and authentication to operate - bool IsSystemCommand() const { - if (IsHelpCommand()) { - return true; - } - if (!IsYdbCommand()) { - return false; - } - return IsSvnVersionCommand() || IsUpdateCommand() || IsVersionCommand() - || IsInitCommand() || IsProfileCommand() || IsLicenseCommand() || IsCreditsCommand() - || IsHelpExCommand(); + bool HasHelpCommand() const { + return HasArgs({ "--help" }) || HasArgs({ "-h" }) || HasArgs({ "-?" }) || HasArgs({ "--help-ex" }); } void SetFreeArgsMin(size_t value) { @@ -220,8 +153,8 @@ public: void CheckParamsCount() { size_t count = GetParamsCount(); - if (IsSystemCommand()) { - return; + if (HasHelpCommand() || HasExecutableOptions) {
+ return;
} bool minSet = ArgsSettings->Min.GetIsSet(); size_t minValue = ArgsSettings->Min.Get(); @@ -309,12 +242,16 @@ public: } }; + class TOptsParseOneLevelResult : public NLastGetopt::TOptsParseResult { + public: + TOptsParseOneLevelResult(TConfig& config); + }; + virtual ~TClientCommand() {} - virtual void Config(TConfig& config); - virtual void Parse(TConfig& config); - virtual int Run(TConfig& config); virtual int Process(TConfig& config); + virtual void Prepare(TConfig& config); + virtual int ValidateAndRun(TConfig& config); virtual void RenderCommandsDescription( TStringStream& stream, @@ -323,12 +260,22 @@ public: ); protected: + virtual void Config(TConfig& config); + virtual void SaveParseResult(TConfig& config); + virtual void Parse(TConfig& config); + virtual void Validate(TConfig& config); + virtual int Run(TConfig& config); + void SetFreeArgTitle(size_t pos, const TString& title, const TString& help); virtual void SetCustomUsage(TConfig& config); +protected: + std::shared_ptr<NLastGetopt::TOptsParseResult> ParseResult; + private: void HideOption(const TString& name); void ChangeOptionDescription(const TString& name, const TString& description); + void CheckForExecutableOptions(TConfig& config); constexpr static int DESCRIPTION_ALIGNMENT = 28; @@ -343,10 +290,7 @@ public: TClientCommandTree(const TString& name, const std::initializer_list<TString>& aliases = std::initializer_list<TString>(), const TString& description = TString()); void AddCommand(std::unique_ptr<TClientCommand> command); - virtual void Config(TConfig& config) override; - virtual void Parse(TConfig& config) override; - virtual int Run(TConfig& config) override; - virtual int Process(TConfig& config) override; + virtual void Prepare(TConfig& config) override; virtual void RenderCommandsDescription( TStringStream& stream, const NColorizer::TColors& colors = NColorizer::TColors(false), @@ -354,6 +298,12 @@ public: ) override; virtual void SetFreeArgs(TConfig& config); +protected: + virtual void Config(TConfig& config) override; + virtual void SaveParseResult(TConfig& config) override; + virtual void Parse(TConfig& config) override; + virtual int Run(TConfig& config) override; + private: bool HasOptionsToShow(); }; diff --git a/ydb/public/lib/ydb_cli/common/root.cpp b/ydb/public/lib/ydb_cli/common/root.cpp index 4637304645c..91a352faa60 100644 --- a/ydb/public/lib/ydb_cli/common/root.cpp +++ b/ydb/public/lib/ydb_cli/common/root.cpp @@ -37,10 +37,8 @@ void TClientCommandRootBase::SetCustomUsage(TConfig& config) { void TClientCommandRootBase::Parse(TConfig& config) { TClientCommandTree::Parse(config); - if (!config.IsSystemCommand()) { - ParseCredentials(config); - ParseAddress(config); - } + ParseCredentials(config); + ParseAddress(config); TClientCommand::TIME_REQUESTS = TimeRequests; TClientCommand::PROGRESS_REQUESTS = ProgressRequests; |