Allow unescaped quoted strings with --config CLI (#2835)
* Parsing issue with --config CLI * Allow original behaviour with escaped quotations * Support arrays * Formatting
This commit is contained in:
parent
c3c7b92805
commit
facc103527
7 changed files with 120 additions and 4 deletions
|
@ -1,3 +1,4 @@
|
|||
#include <nano/lib/cli.hpp>
|
||||
#include <nano/node/cli.hpp>
|
||||
#include <nano/secure/utility.hpp>
|
||||
#include <nano/test_common/testutil.hpp>
|
||||
|
@ -43,6 +44,31 @@ TEST (cli, key_create)
|
|||
ASSERT_EQ (vals[2], public_key.to_account ());
|
||||
}
|
||||
|
||||
TEST (cli, config_override_parsing)
|
||||
{
|
||||
std::vector<nano::config_key_value_pair> key_value_pairs;
|
||||
auto config_overrides = nano::config_overrides (key_value_pairs);
|
||||
ASSERT_TRUE (config_overrides.empty ());
|
||||
key_value_pairs.push_back ({ "key", "value" });
|
||||
config_overrides = nano::config_overrides (key_value_pairs);
|
||||
ASSERT_EQ (config_overrides[0], "key=\"value\"");
|
||||
key_value_pairs.push_back ({ "node.online_weight_minimum", "40000000000000000000000000000000000000" });
|
||||
config_overrides = nano::config_overrides (key_value_pairs);
|
||||
ASSERT_EQ (config_overrides[1], "node.online_weight_minimum=\"40000000000000000000000000000000000000\"");
|
||||
|
||||
// Should add this as it contains escaped quotes, and make sure these are not escaped again
|
||||
key_value_pairs.push_back ({ "key", "\"value\"" });
|
||||
config_overrides = nano::config_overrides (key_value_pairs);
|
||||
ASSERT_EQ (config_overrides[2], "key=\"value\"");
|
||||
ASSERT_EQ (config_overrides.size (), 3);
|
||||
|
||||
// Try it with arrays, with and without escaped quotes
|
||||
key_value_pairs.push_back ({ "node.work_peers", "[127.0.0.1:7000,\"128.0.0.1:50000\"]" });
|
||||
config_overrides = nano::config_overrides (key_value_pairs);
|
||||
ASSERT_EQ (config_overrides[3], "node.work_peers=[\"127.0.0.1:7000\",\"128.0.0.1:50000\"]");
|
||||
ASSERT_EQ (config_overrides.size (), 4);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
std::string call_cli_command (boost::program_options::variables_map const & vm)
|
||||
|
|
|
@ -20,6 +20,8 @@ add_library (nano_lib
|
|||
blockbuilders.cpp
|
||||
blocks.hpp
|
||||
blocks.cpp
|
||||
cli.hpp
|
||||
cli.cpp
|
||||
config.hpp
|
||||
config.cpp
|
||||
configbase.hpp
|
||||
|
|
66
nano/lib/cli.cpp
Normal file
66
nano/lib/cli.cpp
Normal file
|
@ -0,0 +1,66 @@
|
|||
#include <nano/lib/cli.hpp>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
std::vector<std::string> nano::config_overrides (std::vector<config_key_value_pair> const & key_value_pairs_a)
|
||||
{
|
||||
std::vector<std::string> overrides;
|
||||
auto format (boost::format ("%1%=%2%"));
|
||||
auto format_add_escaped_quotes (boost::format ("%1%=\"%2%\""));
|
||||
for (auto pair : key_value_pairs_a)
|
||||
{
|
||||
auto start = pair.value.find ('[');
|
||||
|
||||
std::string value;
|
||||
auto is_array = (start != std::string::npos);
|
||||
if (is_array)
|
||||
{
|
||||
// Trim off the square brackets [] of the array
|
||||
auto end = pair.value.find (']');
|
||||
auto array_values = pair.value.substr (start + 1, end - start - 1);
|
||||
|
||||
// Split the string by comma
|
||||
std::vector<std::string> split_elements;
|
||||
boost::split (split_elements, array_values, boost::is_any_of (","));
|
||||
|
||||
auto format (boost::format ("%1%"));
|
||||
auto format_add_escaped_quotes (boost::format ("\"%1%\""));
|
||||
|
||||
// Rebuild the array string adding escaped quotes if necessary
|
||||
std::ostringstream ss;
|
||||
ss << "[";
|
||||
for (auto i = 0; i < split_elements.size (); ++i)
|
||||
{
|
||||
auto & elem = split_elements[i];
|
||||
auto already_escaped = elem.find ('\"') != std::string::npos;
|
||||
ss << ((!already_escaped ? format_add_escaped_quotes : format) % elem).str ();
|
||||
if (i != split_elements.size () - 1)
|
||||
{
|
||||
ss << ",";
|
||||
}
|
||||
}
|
||||
ss << "]";
|
||||
value = ss.str ();
|
||||
}
|
||||
else
|
||||
{
|
||||
value = pair.value;
|
||||
}
|
||||
auto already_escaped = value.find ('\"') != std::string::npos;
|
||||
overrides.push_back (((!already_escaped ? format_add_escaped_quotes : format) % pair.key % value).str ());
|
||||
}
|
||||
return overrides;
|
||||
}
|
||||
|
||||
std::istream & nano::operator>> (std::istream & is, nano::config_key_value_pair & into)
|
||||
{
|
||||
char ch;
|
||||
while (is >> ch && ch != '=')
|
||||
{
|
||||
into.key += ch;
|
||||
}
|
||||
return is >> into.value;
|
||||
}
|
19
nano/lib/cli.hpp
Normal file
19
nano/lib/cli.hpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class config_key_value_pair
|
||||
{
|
||||
public:
|
||||
std::string key;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
std::vector<std::string> config_overrides (std::vector<config_key_value_pair> const & key_value_pairs_a);
|
||||
|
||||
std::istream & operator>> (std::istream & is, nano::config_key_value_pair & into);
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
#include <nano/crypto_lib/random_pool.hpp>
|
||||
#include <nano/lib/cli.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
#include <nano/nano_node/daemon.hpp>
|
||||
#include <nano/node/cli.hpp>
|
||||
|
@ -68,7 +69,7 @@ int main (int argc, char * const * argv)
|
|||
description.add_options ()
|
||||
("help", "Print out options")
|
||||
("version", "Prints out version")
|
||||
("config", boost::program_options::value<std::vector<std::string>>()->multitoken(), "Pass node configuration values. This takes precedence over any values in the configuration file. This option can be repeated multiple times.")
|
||||
("config", boost::program_options::value<std::vector<nano::config_key_value_pair>>()->multitoken(), "Pass node configuration values. This takes precedence over any values in the configuration file. This option can be repeated multiple times.")
|
||||
("daemon", "Start node daemon")
|
||||
("compare_rep_weights", "Display a summarized comparison between the hardcoded bootstrap weights and representative weights from the ledger. Full comparison is output to logs")
|
||||
("debug_block_count", "Display the number of block")
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include <nano/lib/cli.hpp>
|
||||
#include <nano/lib/errors.hpp>
|
||||
#include <nano/lib/threading.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
|
@ -90,7 +91,7 @@ int main (int argc, char * const * argv)
|
|||
// clang-format off
|
||||
description.add_options ()
|
||||
("help", "Print out options")
|
||||
("config", boost::program_options::value<std::vector<std::string>>()->multitoken(), "Pass RPC configuration values. This takes precedence over any values in the configuration file. This option can be repeated multiple times.")
|
||||
("config", boost::program_options::value<std::vector<nano::config_key_value_pair>>()->multitoken(), "Pass RPC configuration values. This takes precedence over any values in the configuration file. This option can be repeated multiple times.")
|
||||
("daemon", "Start RPC daemon")
|
||||
("data_path", boost::program_options::value<std::string> (), "Use the supplied path as the data directory")
|
||||
("network", boost::program_options::value<std::string> (), "Use the supplied network (live, beta or test)")
|
||||
|
@ -139,7 +140,7 @@ int main (int argc, char * const * argv)
|
|||
auto config (vm.find ("config"));
|
||||
if (config != vm.end ())
|
||||
{
|
||||
config_overrides = config->second.as<std::vector<std::string>> ();
|
||||
config_overrides = nano::config_overrides (config->second.as<std::vector<nano::config_key_value_pair>> ());
|
||||
}
|
||||
run (data_path, config_overrides);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include <nano/lib/cli.hpp>
|
||||
#include <nano/lib/tomlconfig.hpp>
|
||||
#include <nano/node/cli.hpp>
|
||||
#include <nano/node/common.hpp>
|
||||
|
@ -170,7 +171,7 @@ std::error_code nano::update_flags (nano::node_flags & flags_a, boost::program_o
|
|||
auto config (vm.find ("config"));
|
||||
if (config != vm.end ())
|
||||
{
|
||||
flags_a.config_overrides = config->second.as<std::vector<std::string>> ();
|
||||
flags_a.config_overrides = nano::config_overrides (config->second.as<std::vector<nano::config_key_value_pair>> ());
|
||||
}
|
||||
return ec;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue