Added dashed-settings and support for unicode dash in cli arguments

This commit is contained in:
Aleksei Golub 2023-04-20 20:07:44 +03:00
parent 5ebf66819b
commit 1ec5773dc6
5 changed files with 150 additions and 8 deletions

View File

@ -3,13 +3,29 @@
#include <Poco/Util/LayeredConfiguration.h>
#include <Poco/Util/MapConfiguration.h>
void argsToConfig(const Poco::Util::Application::ArgVec & argv, Poco::Util::LayeredConfiguration & config, int priority)
void argsToConfig(const Poco::Util::Application::ArgVec & argv,
Poco::Util::LayeredConfiguration & config,
int priority,
const std::unordered_set<std::string>* alias_names)
{
/// Parsing all args and converting to config layer
/// Test: -- --1=1 --1=2 --3 5 7 8 -9 10 -11=12 14= 15== --16==17 --=18 --19= --20 21 22 --23 --24 25 --26 -27 28 ---29=30 -- ----31 32 --33 3-4
Poco::AutoPtr<Poco::Util::MapConfiguration> map_config = new Poco::Util::MapConfiguration;
std::string key;
auto add_arg = [&map_config, &alias_names](const std::string & k, const std::string & v)
{
map_config->setString(k, v);
if (alias_names && !alias_names->contains(k))
{
std::string alias_key = k;
std::replace(alias_key.begin(), alias_key.end(), '-', '_');
if (alias_names->contains(alias_key))
map_config->setString(alias_key, v);
}
};
for (const auto & arg : argv)
{
auto key_start = arg.find_first_not_of('-');
@ -19,7 +35,7 @@ void argsToConfig(const Poco::Util::Application::ArgVec & argv, Poco::Util::Laye
// old saved '--key', will set to some true value "1"
if (!key.empty() && pos_minus != std::string::npos && pos_minus < key_start)
{
map_config->setString(key, "1");
add_arg(key, "1");
key = "";
}
@ -29,7 +45,7 @@ void argsToConfig(const Poco::Util::Application::ArgVec & argv, Poco::Util::Laye
{
if (pos_minus == std::string::npos || pos_minus > key_start)
{
map_config->setString(key, arg);
add_arg(key, arg);
}
key = "";
}
@ -55,7 +71,7 @@ void argsToConfig(const Poco::Util::Application::ArgVec & argv, Poco::Util::Laye
if (arg.size() > pos_eq)
value = arg.substr(pos_eq + 1);
map_config->setString(key, value);
add_arg(key, value);
key = "";
}

View File

@ -1,6 +1,8 @@
#pragma once
#include <Poco/Util/Application.h>
#include <string>
#include <unordered_set>
namespace Poco::Util
{
@ -8,4 +10,7 @@ class LayeredConfiguration; // NOLINT(cppcoreguidelines-virtual-class-destructor
}
/// Import extra command line arguments to configuration. These are command line arguments after --.
void argsToConfig(const Poco::Util::Application::ArgVec & argv, Poco::Util::LayeredConfiguration & config, int priority);
void argsToConfig(const Poco::Util::Application::ArgVec & argv,
Poco::Util::LayeredConfiguration & config,
int priority,
const std::unordered_set<std::string>* registered_alias_names = nullptr);

View File

@ -68,6 +68,7 @@
#include <iostream>
#include <filesystem>
#include <map>
#include <regex>
#include <unordered_map>
#include "config_version.h"
@ -120,6 +121,7 @@ namespace ProfileEvents
namespace
{
constexpr UInt64 THREAD_GROUP_ID = 0;
const std::string UNICODE_DASH = "";
}
namespace DB
@ -2395,6 +2397,54 @@ struct TransparentStringHash
}
};
/*
* This functor is used to parse command line arguments and replace dashes with underscores,
* allowing options to be specified using either dashes or underscores.
*/
class OptionsAliasParser
{
public:
explicit OptionsAliasParser(const boost::program_options::options_description& options)
{
options_names.reserve(options.options().size());
for (const auto& option : options.options())
options_names.insert(option->long_name());
}
/*
* Parses arguments by replacing dashes with underscores, and matches the resulting name with known options
* Implements boost::program_options::ext_parser logic
*/
std::pair<std::string, std::string> operator()(const std::string& token) const
{
if (token.find("--") != 0)
return {};
std::string arg = token.substr(2);
// divide token by '=' to separate key and value if options style=long_allow_adjacent
auto pos_eq = arg.find('=');
std::string key = arg.substr(0, pos_eq);
if (options_names.contains(key))
// option does not require any changes, because it is already correct
return {};
std::replace(key.begin(), key.end(), '-', '_');
if (!options_names.contains(key))
// after replacing '-' with '_' argument is still unknown
return {};
std::string value;
if (pos_eq != std::string::npos && pos_eq < arg.size())
value = arg.substr(pos_eq + 1);
return {key, value};
}
private:
std::unordered_set<std::string> options_names;
};
}
@ -2445,7 +2495,10 @@ void ClientBase::parseAndCheckOptions(OptionsDescription & options_description,
}
/// Parse main commandline options.
auto parser = po::command_line_parser(arguments).options(options_description.main_description.value()).allow_unregistered();
auto parser = po::command_line_parser(arguments)
.options(options_description.main_description.value())
.extra_parser(OptionsAliasParser(options_description.main_description.value()))
.allow_unregistered();
po::parsed_options parsed = parser.run();
/// Check unrecognized options without positional options.
@ -2487,6 +2540,11 @@ void ClientBase::init(int argc, char ** argv)
readArguments(argc, argv, common_arguments, external_tables_arguments, hosts_and_ports_arguments);
/// Support for Unicode dashes
/// Interpret Unicode dash as default double-dash
for (auto & arg : common_arguments)
arg = std::regex_replace(arg, std::regex(UNICODE_DASH), "--");
po::variables_map options;
OptionsDescription options_description;
options_description.main_description.emplace(createOptionsDescription("Main options", terminal_width));
@ -2660,7 +2718,14 @@ void ClientBase::init(int argc, char ** argv)
profile_events.delay_ms = options["profile-events-delay-ms"].as<UInt64>();
processOptions(options_description, options, external_tables_arguments, hosts_and_ports_arguments);
argsToConfig(common_arguments, config(), 100);
{
std::unordered_set<std::string> alias_names;
alias_names.reserve(options_description.main_description->options().size());
for (const auto& option : options_description.main_description->options())
alias_names.insert(option->long_name());
argsToConfig(common_arguments, config(), 100, &alias_names);
}
clearPasswordFromCommandLine(argc, argv);
/// Limit on total memory usage

View File

@ -0,0 +1,12 @@
Test 1: Check that you can specify options with a dashes, not an underscores
Test 1.1: Check option from config - server_logs_file
1
0
1
0
1
0
Test 1.1: Check some option from Settings.h - allow_deprecated_syntax_for_merge_tree
0
Test 2: check that unicode dash processed correctly
1

View File

@ -0,0 +1,44 @@
#!/usr/bin/env bash
CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
# shellcheck source=../shell_config.sh
. "$CURDIR"/../shell_config.sh
file_name=${CLICKHOUSE_TEST_UNIQUE_NAME}
file_name_1=${file_name}_1
file_name_2=${file_name}_2
file_name_3=${file_name}_3
#################
echo "Test 1: Check that you can specify options with a dashes, not an underscores"
[[ -e $file_name_1 ]] && rm $file_name_1
[[ -e $file_name_2 ]] && rm $file_name_2
[[ -e $file_name_3 ]] && rm $file_name_3
echo "Test 1.1: Check option from config - server_logs_file"
$CLICKHOUSE_LOCAL --log-level=debug --server-logs-file=$file_name_1 -q "SELECT 1;" 2> /dev/null
ls | grep -q $file_name_1
echo $?
$CLICKHOUSE_LOCAL --log-level=debug --server-logs-file $file_name_2 -q "SELECT 1;" 2> /dev/null
ls | grep -q $file_name_2
echo $?
$CLICKHOUSE_LOCAL --log-level=debug --server_logs_file $file_name_3 -q "SELECT 1;" 2> /dev/null
ls | grep -q $file_name_3
echo $?
echo "Test 1.1: Check some option from Settings.h - allow_deprecated_syntax_for_merge_tree"
$CLICKHOUSE_CLIENT --query="DROP TABLE IF EXISTS test";
$CLICKHOUSE_CLIENT --allow-deprecated-syntax-for-merge-tree=1 --query="CREATE TABLE test (d Date, s String) ENGINE = MergeTree(d, s, 8192)";
$CLICKHOUSE_CLIENT --query="DROP TABLE test";
echo $?
#################
echo "Test 2: check that unicode dash processed correctly"
$CLICKHOUSE_LOCAL —query "SELECT 1";
rm $file_name_1
rm $file_name_2
rm $file_name_3