Skip to content

Commit

Permalink
Make changes to allow subsequent json files to overwrite earlier ones,
Browse files Browse the repository at this point in the history
and command line flags to overwrite json files after that.
  • Loading branch information
angela28chen committed Aug 19, 2023
1 parent 655de0c commit 306397a
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 78 deletions.
15 changes: 9 additions & 6 deletions include/ppx/command_line_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ class CliOptions
// Same as above, but appends an array of values at the same key
void AddOption(std::string_view optionName, const std::vector<std::string>& valueArray);

// For all options existing in newOptions, current entries in mAllOptions will be replaced by them
void OverwriteOptions(const CliOptions& newOptions);

template <typename T>
T GetParsedOrDefault(std::string_view valueStr, const T& defaultValue) const
{
Expand Down Expand Up @@ -160,8 +163,12 @@ class CommandLineParser
// and write the error to `out_error`.
std::optional<ParsingError> Parse(int argc, const char* argv[]);

// Adds all options specified within jsonConfig to mOpts.
std::optional<ParsingError> AddJsonOptions(const nlohmann::json& jsonConfig);
// Parses all options specified within jsonConfig and adds them to cliOptions.
std::optional<ParsingError> ParseJson(CliOptions& cliOptions, const nlohmann::json& jsonConfig);

// Parses an option, handles the special --no-flag-name case, then adds the option to cliOptions
// Expects option names without the "--" prefix.
std::optional<ParsingError> ParseOption(CliOptions& cliOptions, std::string_view optionName, std::string_view valueStr);

std::string GetJsonConfigFlagName() const { return mJsonConfigFlagName; }
const CliOptions& GetOptions() const { return mOpts; }
Expand All @@ -170,10 +177,6 @@ class CommandLineParser
void AppendUsageMsg(const std::string& additionalMsg) { mUsageMsg += additionalMsg; }

private:
// Adds an option to mOpts and handles the special --no-flag-name case.
// Expects option names without the "--" prefix.
std::optional<ParsingError> AddOption(std::string_view optionName, std::string_view valueStr);

CliOptions mOpts;
std::string mJsonConfigFlagName = "config-json-path";
std::string mUsageMsg = R"(
Expand Down
11 changes: 5 additions & 6 deletions src/ppx/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -672,8 +672,8 @@ void Application::DispatchConfig()

auto assetPaths = mStandardOpts.pAssetsPaths->GetValue();
if (!assetPaths.empty()) {
// Asset directories specified later have higher priority
for (auto it = assetPaths.begin(); it < assetPaths.end(); it++) {
// Insert at front, in reverse order, so we respect the command line ordering for priority.
for (auto it = assetPaths.rbegin(); it < assetPaths.rend(); it++) {
AddAssetDir(*it, /* insert_at_front= */ true);
}
}
Expand Down Expand Up @@ -810,15 +810,14 @@ void Application::InitStandardKnobs()
mStandardOpts.pAssetsPaths =
mKnobManager.CreateKnob<KnobFlag<std::vector<std::string>>>("assets-path", defaultEmptyList);
mStandardOpts.pAssetsPaths->SetFlagDescription(
"Add a path in front of the assets search path list.");
"Add a path before the default assets folder in the search list.");
mStandardOpts.pAssetsPaths->SetFlagParameters("<path>");

mStandardOpts.pConfigJsonPaths = mKnobManager.CreateKnob<KnobFlag<std::vector<std::string>>>(mCommandLineParser.GetJsonConfigFlagName(), defaultEmptyList);
mStandardOpts.pConfigJsonPaths->SetFlagDescription(
"Additional commandline flags specified in a JSON file. Values specified in JSON files are "
"always lower priority than those specified on the command line. Between different files, the "
"later ones take priority. For lists, the JSON values will come earlier in the array than the "
"command-line values");
"always overwritten by those specified on the command line. Between different files, the "
"later ones take priority.");
mStandardOpts.pConfigJsonPaths->SetFlagParameters("<path>");

mStandardOpts.pDeterministic =
Expand Down
49 changes: 41 additions & 8 deletions src/ppx/command_line_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,22 @@ bool StartsWithDoubleDash(std::string_view s)

namespace ppx {

void CliOptions::OverwriteOptions(const CliOptions& newOptions)
{
PPX_LOG_INFO("UNICORN entered OverwriteOptions");
PPX_LOG_INFO("UNICORN GetNumUniqueOptions: " << newOptions.GetNumUniqueOptions());
PPX_LOG_INFO("UNICORN SHOW newOptions");
for (auto& it : newOptions.mAllOptions) {
PPX_LOG_INFO("UNICORN key: " << it.first << "value: " << ppx::string_util::ToString(it.second));
mAllOptions[it.first] = it.second;
}

PPX_LOG_INFO("UNICORN SHOW mAllOptions");
for (auto& it : mAllOptions) {
PPX_LOG_INFO("UNICORN key: " << it.first << "value: " << ppx::string_util::ToString(it.second));
}
}

std::pair<int, int> CliOptions::GetOptionValueOrDefault(const std::string& optionName, const std::pair<int, int>& defaultValue) const
{
auto it = mAllOptions.find(optionName);
Expand All @@ -57,27 +73,33 @@ std::pair<int, int> CliOptions::GetOptionValueOrDefault(const std::string& optio

void CliOptions::AddOption(std::string_view optionName, std::string_view value)
{
PPX_LOG_INFO("UNICORN AddOption About to add option: " << optionName << " valueStr: " << value);
std::string optionNameStr(optionName);
std::string valueStr(value);
auto it = mAllOptions.find(optionNameStr);
if (it == mAllOptions.cend()) {
std::vector<std::string> v{std::move(valueStr)};
mAllOptions.emplace(std::move(optionNameStr), std::move(v));
PPX_LOG_INFO("UNICORN AddOption added new option");
return;
}
it->second.push_back(valueStr);
PPX_LOG_INFO("UNICORN AddOption appended to existing option");
}

void CliOptions::AddOption(std::string_view optionName, const std::vector<std::string>& valueArray)
{
PPX_LOG_INFO("UNICORN AddOption About to add list option: " << optionName << " valueArray: " << ppx::string_util::ToString(valueArray));
std::string optionNameStr(optionName);
auto it = mAllOptions.find(optionNameStr);
if (it == mAllOptions.cend()) {
mAllOptions.emplace(std::move(optionNameStr), valueArray);
PPX_LOG_INFO("UNICORN AddOption list : added new option");
return;
}
auto storedValueArray = it->second;
storedValueArray.insert(storedValueArray.end(), valueArray.cbegin(), valueArray.cend());
PPX_LOG_INFO("UNICORN AddOption list : appended to existing option");
}

bool CliOptions::Parse(std::string_view valueStr, bool defaultValue) const
Expand Down Expand Up @@ -163,11 +185,17 @@ std::optional<CommandLineParser::ParsingError> CommandLineParser::Parse(int argc
return "The following config file could not be parsed as a JSON object: " + jsonPath;
}

if (auto error = AddJsonOptions(data)) {
CliOptions jsonOptions;
if (auto error = ParseJson(jsonOptions, data)) {
return error;
}
PPX_LOG_INFO("UNICORN jsonOptions num unique: " << jsonOptions.GetNumUniqueOptions());
PPX_LOG_INFO("UNICORN About to overwrite main options");
mOpts.OverwriteOptions(jsonOptions);
PPX_LOG_INFO("UNICORN mOpts num unique: " << mOpts.GetNumUniqueOptions());
}

CliOptions commandlineOptions;
// Main pass, process arguments into either standalone flags or options with parameters.
for (size_t i = 0; i < args.size(); ++i) {
std::string_view name = ppx::string_util::TrimBothEnds(args[i]);
Expand All @@ -186,41 +214,45 @@ std::optional<CommandLineParser::ParsingError> CommandLineParser::Parse(int argc
}
}

if (auto error = AddOption(name, value)) {
if (auto error = ParseOption(commandlineOptions, name, value)) {
return error;
}
}
PPX_LOG_INFO("UNICORN commandlineOptions num unique: " << commandlineOptions.GetNumUniqueOptions());
PPX_LOG_INFO("UNICORN About to overwrite main options");
mOpts.OverwriteOptions(commandlineOptions);
PPX_LOG_INFO("UNICORN mOpts num unique: " << mOpts.GetNumUniqueOptions());

return std::nullopt;
}

std::optional<CommandLineParser::ParsingError> CommandLineParser::AddJsonOptions(const nlohmann::json& jsonConfig)
std::optional<CommandLineParser::ParsingError> CommandLineParser::ParseJson(CliOptions& cliOptions, const nlohmann::json& jsonConfig)
{
std::stringstream ss;
for (auto it = jsonConfig.cbegin(); it != jsonConfig.cend(); ++it) {
if ((it.value()).is_array()) {
// Special case, arrays specified in JSON are added directly to mOpts to avoid inserting element by element
// Special case, arrays specified in JSON are added directly to cliOptions to avoid inserting element by element
std::vector<std::string> jsonStringArray;
for (const auto& elem : it.value()) {
ss << elem;
jsonStringArray.push_back(std::string(ppx::string_util::TrimBothEnds(ss.str(), " \t\"")));
ss.str("");
}
mOpts.AddOption(it.key(), jsonStringArray);
cliOptions.AddOption(it.key(), jsonStringArray);
continue;
}

ss << it.value();
std::string value = ss.str();
ss.str("");
if (auto error = AddOption(it.key(), ppx::string_util::TrimBothEnds(value, " \t\""))) {
if (auto error = ParseOption(cliOptions, it.key(), ppx::string_util::TrimBothEnds(value, " \t\""))) {
return error;
}
}
return std::nullopt;
}

std::optional<CommandLineParser::ParsingError> CommandLineParser::AddOption(std::string_view optionName, std::string_view valueStr)
std::optional<CommandLineParser::ParsingError> CommandLineParser::ParseOption(CliOptions& cliOptions, std::string_view optionName, std::string_view valueStr)
{
if (optionName.length() > 2 && optionName.substr(0, 3) == "no-") {
if (valueStr.length() > 0) {
Expand All @@ -229,7 +261,8 @@ std::optional<CommandLineParser::ParsingError> CommandLineParser::AddOption(std:
optionName = optionName.substr(3);
valueStr = "0";
}
mOpts.AddOption(optionName, valueStr);
PPX_LOG_INFO("UNICORN ParseOption About to add option: " << optionName << " valueStr: " << valueStr);
cliOptions.AddOption(optionName, valueStr);
return std::nullopt;
}

Expand Down
Loading

0 comments on commit 306397a

Please sign in to comment.