Added the --regset-file option for setreg file loading (#5768)

The SettingsRegistryMergeUtils.cpp now supports specifying a path to a JSON Merge Patch formated settings registry file via the --regset-file option.
The option supports specify an anchor key to merge the settings underneath that is separated from the filepath via "::"
Ex. `--regset-file="Registry/custom.setreg::/Custom/Anchor"`

An AZ::Console command of "sr_regset-file" has also been added to allow merging of a setting registry file as well.

closes #5767

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>
This commit is contained in:
lumberyard-employee-dm
2021-11-30 13:03:46 -06:00
committed by GitHub
parent 356e267fe5
commit 879012b1ae
6 changed files with 96 additions and 15 deletions
+2 -1
View File
@@ -78,7 +78,8 @@ namespace AZ::IO
// native format observers
//! Returns string_view stored within the PathView
constexpr AZStd::string_view Native() const noexcept;
constexpr const AZStd::string_view& Native() const noexcept;
constexpr AZStd::string_view& Native() noexcept;
//! Conversion operator to retrieve string_view stored within the PathView
constexpr explicit operator AZStd::string_view() const noexcept;
@@ -101,7 +101,11 @@ namespace AZ::IO
}
// native format observers
constexpr auto PathView::Native() const noexcept -> AZStd::string_view
constexpr auto PathView::Native() const noexcept -> const AZStd::string_view&
{
return m_path;
}
constexpr auto PathView::Native() noexcept -> AZStd::string_view&
{
return m_path;
}
@@ -9,6 +9,7 @@
#include <AzCore/Console/IConsole.h>
#include <AzCore/Console/ConsoleFunctor.h>
#include <AzCore/IO/ByteContainerStream.h>
#include <AzCore/IO/Path/Path.h>
#include <AzCore/Settings/SettingsRegistryConsoleUtils.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzCore/StringFunc/StringFunc.h>
@@ -36,7 +37,7 @@ namespace AZ::SettingsRegistryConsoleUtils
combinedKeyValueCommand.c_str());
AZ::Debug::Trace::Output("SettingsRegistry", setOutput.c_str());
}
};
}
static void ConsoleRemoveSettingsRegistryValue(SettingsRegistryInterface& settingsRegistry, const ConsoleCommandContainer& commandArgs)
{
@@ -57,7 +58,7 @@ namespace AZ::SettingsRegistryConsoleUtils
AZ::Debug::Trace::Output("SettingsRegistry", removeOutput.c_str());
}
}
};
}
static void ConsoleDumpSettingsRegistryValue(SettingsRegistryInterface& settingsRegistry, const ConsoleCommandContainer& commandArgs)
{
@@ -88,13 +89,39 @@ namespace AZ::SettingsRegistryConsoleUtils
}
AZ::Debug::Trace::Output("SettingsRegistry", outputString.c_str());
};
}
static void ConsoleDumpAllSettingsRegistryValues(SettingsRegistryInterface& settingsRegistry,
[[maybe_unused]] const ConsoleCommandContainer& commandArgs)
{
ConsoleDumpSettingsRegistryValue(settingsRegistry, { "" });
};
}
static void ConsoleMergeFileToSettingsRegistry(SettingsRegistryInterface& settingsRegistry, const ConsoleCommandContainer& commandArgs)
{
if (commandArgs.empty())
{
AZ_Error("SettingsRegistryConsoleUtils", false, "Command %s requires a <file path> argument to locate json file to merge",
SettingsRegistryMergeFile);
return;
}
auto commandArgumentsIter = commandArgs.begin();
// Extract the JSON pointer path from the argument list
AZStd::string_view filePath{ *commandArgumentsIter++ };
AZ::SettingsRegistryInterface::FixedValueString jsonAnchorPath;
AZ::StringFunc::Join(jsonAnchorPath, commandArgumentsIter, commandArgs.end(), ' ');
const auto mergeFormat = AZ::IO::PathView(filePath).Extension() != ".setregpatch" ? AZ::SettingsRegistryInterface::Format::JsonMergePatch : AZ::SettingsRegistryInterface::Format::JsonPatch;
if (settingsRegistry.MergeSettingsFile(filePath, mergeFormat, jsonAnchorPath))
{
const auto mergeFileOutput = AZ::SettingsRegistryInterface::FixedValueString::format(
R"(Merged json file "%*.s" anchored to json path "%s" into the global settings registry)" "\n",
AZ_STRING_ARG(filePath), jsonAnchorPath.c_str());
AZ::Debug::Trace::Output("SettingsRegistry", mergeFileOutput.c_str());
}
}
[[nodiscard]] ConsoleFunctorHandle RegisterAzConsoleCommands(SettingsRegistryInterface& registry, AZ::IConsole& azConsole)
{
@@ -115,6 +142,11 @@ namespace AZ::SettingsRegistryConsoleUtils
resultHandle.m_consoleFunctors.emplace_back(azConsole, SettingsRegistryDumpAll,
R"(Dumps all values from the global settings registry)" "\n",
ConsoleFunctorFlags::Null, AZ::TypeId::CreateNull(), registry, &ConsoleDumpAllSettingsRegistryValues);
resultHandle.m_consoleFunctors.emplace_back(azConsole, SettingsRegistryMergeFile,
R"(Merges File into the global settings registry)" "\n"
R"(@param file-path - path to JSON formatted file to merge)" "\n"
R"(@param anchor-path - JSON path to anchor merge operation. Defaults to "")" "\n",
ConsoleFunctorFlags::Null, AZ::TypeId::CreateNull(), registry, &ConsoleMergeFileToSettingsRegistry);
return resultHandle;
}
@@ -14,15 +14,16 @@
namespace AZ::SettingsRegistryConsoleUtils
{
//! Only 4 console command are registered for the settings registry
//! "regset", "regremove", "regdump", "regdumpall"
//! The following console command are registered for the settings registry
//! "regset", "regremove", "regdump", "regdumpall", "regset-file"
//! The value should be increased if more commands are needed
inline constexpr size_t MaxSettingsRegistryConsoleFunctors = 4;
inline constexpr size_t MaxSettingsRegistryConsoleFunctors = 5;
inline constexpr const char* SettingsRegistrySet = "sr_regset";
inline constexpr const char* SettingsRegistryRemove = "sr_regremove";
inline constexpr const char* SettingsRegistryDump = "sr_regdump";
inline constexpr const char* SettingsRegistryDumpAll = "sr_regdumpall";
inline constexpr const char* SettingsRegistryMergeFile = "sr_regset-file";
// RAII structure which owns the instances of the Settings Registry Console commands
// registered with an AZ Console
@@ -51,6 +52,10 @@ namespace AZ::SettingsRegistryConsoleUtils
//!
//! "sr_regdumpall" accepts 0 arguments and dumps the entire settings registry
//! NOTE: this might result in a large amount of output to the console
//!
//! "sr_regset-file" accepts 1 or 2 arguments - <file-path> [<anchor json path>]
//! Merges the json formatted file <file path> into the settings registry underneath the root anchor ""
//! or <anchor json path> if supplied
[[nodiscard]] ConsoleFunctorHandle RegisterAzConsoleCommands(SettingsRegistryInterface& registry, AZ::IConsole& azConsole);
}
@@ -19,9 +19,6 @@
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzCore/Settings/CommandLine.h>
#include <AzCore/std/string/conversions.h>
#include <AzCore/std/string/wildcard.h>
#include <AzCore/std/tuple.h>
#include <AzCore/std/containers/variant.h>
#include <AzCore/Utils/Utils.h>
#include <cinttypes>
@@ -983,7 +980,7 @@ namespace AZ::SettingsRegistryMergeUtils
// code in the loop makes calls that mutates the `commandLine` instance, invalidating the iterators. Making a copy
// ensures that the iterators remain valid.
// NOLINTNEXTLINE(performance-unnecessary-value-param)
void MergeSettingsToRegistry_CommandLine(SettingsRegistryInterface& registry, AZ::CommandLine commandLine, bool executeCommands)
void MergeSettingsToRegistry_CommandLine(SettingsRegistryInterface& registry, AZ::CommandLine commandLine, bool executeRegdumpCommands)
{
// Iterate over all the command line options in order to parse the --regset and --regremove
// arguments in the order they were supplied
@@ -998,18 +995,44 @@ namespace AZ::SettingsRegistryMergeUtils
continue;
}
}
else if (commandArgument.m_option == "regset-file")
{
AZStd::string_view fileArg(commandArgument.m_value);
AZStd::string_view jsonAnchorPath;
// double colons is treated as the separator for an anchor path
// single colon cannot be used as it is used in Windows paths
if (auto anchorPathIndex = AZ::StringFunc::Find(fileArg, "::");
anchorPathIndex != AZStd::string_view::npos)
{
jsonAnchorPath = fileArg.substr(anchorPathIndex + 2);
fileArg = fileArg.substr(0, anchorPathIndex);
}
if (!fileArg.empty())
{
AZ::IO::PathView filePath(fileArg);
const auto mergeFormat = filePath.Extension() != ".setregpatch"
? AZ::SettingsRegistryInterface::Format::JsonMergePatch
: AZ::SettingsRegistryInterface::Format::JsonPatch;
if (!registry.MergeSettingsFile(filePath.Native(), mergeFormat, jsonAnchorPath))
{
AZ_Warning("SettingsRegistryMergeUtils", false, R"(Merging of file "%.*s" to the Settings Registry has failed at anchor "%.*s".)",
AZ_STRING_ARG(filePath.Native()), AZ_STRING_ARG(jsonAnchorPath));
continue;
}
}
}
else if (commandArgument.m_option == "regremove")
{
if (!registry.Remove(commandArgument.m_value))
{
AZ_Warning("SettingsRegistryMergeUtils", false, "Unable to remove value at JSON Pointer %s for --regremove.",
commandArgument.m_value.data());
commandArgument.m_value.c_str());
continue;
}
}
}
if (executeCommands)
if (executeRegdumpCommands)
{
constexpr bool prettifyOutput = true;
const size_t regdumpSwitchValues = commandLine.GetNumSwitchValues("regdump");
@@ -539,6 +539,22 @@ tags=tools,renderer,metal)"
EXPECT_STREQ("Bat", commandLine.GetMiscValue(2).c_str());
}
TEST_F(SettingsRegistryMergeUtilsCommandLineFixture, RegsetFileArgument_DoesNotMergeNUL)
{
AZStd::string regsetFile = AZ::IO::SystemFile::GetNullFilename();
AZ::CommandLine commandLine;
commandLine.Parse({ "--regset-file", regsetFile });
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*m_registry, commandLine, false);
// Add a settings path to anchor loaded settings underneath
regsetFile = AZStd::string::format("%s::/AnchorPath/Of/Settings", AZ::IO::SystemFile::GetNullFilename());
commandLine.Parse({ "--regset-file", regsetFile });
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_CommandLine(*m_registry, commandLine, false);
EXPECT_EQ(AZ::SettingsRegistryInterface::Type::NoType, m_registry->GetType("/AnchorPath/Of/Settings"));
}
using SettingsRegistryAncestorDescendantOrEqualPathFixture = SettingsRegistryMergeUtilsCommandLineFixture;
TEST_F(SettingsRegistryAncestorDescendantOrEqualPathFixture, ValidateThatAncestorOrDescendantOrPathWithTheSameValue_Succeeds)