forked from OSchip/llvm-project
Add functionality to export settings
For the reproducer feature I need to be able to export and import the current LLDB configuration. To realize this I've extended the existing functionality to print settings. With the help of a new formatting option, we can now write the settings and their values to a file structured as regular commands. Concretely the functionality works as follows: (lldb) settings export -f /path/to/file This file contains a bunch of settings set commands, followed by the setting's name and value. ... settings set use-external-editor false settings set use-color true settings set auto-one-line-summaries true settings set auto-indent true ... You can import the settings again by either sourcing the file or using the settings read command. (lldb) settings read -f /path/to/file Differential revision: https://reviews.llvm.org/D52651 llvm-svn: 345346
This commit is contained in:
parent
24faf859e5
commit
b76e25a26d
|
@ -58,9 +58,11 @@ public:
|
|||
eDumpOptionValue = (1u << 2),
|
||||
eDumpOptionDescription = (1u << 3),
|
||||
eDumpOptionRaw = (1u << 4),
|
||||
eDumpOptionCommand = (1u << 5),
|
||||
eDumpGroupValue = (eDumpOptionName | eDumpOptionType | eDumpOptionValue),
|
||||
eDumpGroupHelp =
|
||||
(eDumpOptionName | eDumpOptionType | eDumpOptionDescription)
|
||||
(eDumpOptionName | eDumpOptionType | eDumpOptionDescription),
|
||||
eDumpGroupExport = (eDumpOptionCommand | eDumpOptionName | eDumpOptionValue)
|
||||
};
|
||||
|
||||
OptionValue()
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
# This tests writing and reading settings from LLDB.
|
||||
|
||||
# Check that the settings can be written to file and read again without
|
||||
# altering the values.
|
||||
# RUN: %lldb -b -o 'settings write -f %t.foo' -o 'settings read -f %t.foo' -o 'settings export %t.bar' -o 'settings read -f %t.bar' 2>&1 | FileCheck %s --check-prefix SUCCESS
|
||||
# RUN: diff -w %t.foo %t.bar
|
||||
# SUCCESS-NOT: error:
|
||||
|
||||
# Check that exporting target settings only export target settings and nothing else.
|
||||
# RUN: %lldb -b -o 'settings write -f %t.target target' 2>&1 | FileCheck %s --check-prefix SUCCESS
|
||||
# RUN: cat %t.target | FileCheck %s --check-prefix TARGET
|
||||
# TARGET: settings set target
|
||||
# TARGET-NOT: settings set platform
|
||||
# TARGET-NOT: settings set symbols
|
||||
# TARGET-NOT: settings set interpreter
|
||||
# TARGET-NOT: settings set plugin
|
||||
|
||||
# Check that settings appear twice when appending.
|
||||
# RUN: %lldb -b -o 'settings write -a -f %t.append target' -o 'settings write -a -f %t.append target' 2>&1 | FileCheck %s --check-prefix SUCCESS
|
||||
# RUN: cat %t.append | FileCheck %s --check-prefix APPEND
|
||||
# APPEND: settings set target.language
|
||||
# APPEND: settings set target.language
|
||||
|
||||
# Check that an error is printed for non-existing setting.
|
||||
# RUN: echo "settings set bogus" > %t.bogus_setting
|
||||
# RUN: %lldb -b -o 'settings read -f %t.bogus_setting' 2>&1 | FileCheck %s --check-prefix BOGUS-SETTING
|
||||
# BOGUS-SETTING: error: invalid value path
|
||||
|
||||
# Check that an error is printed for invalid value.
|
||||
# RUN: echo "settings set target.language bogus" > %t.bogus_value
|
||||
# RUN: %lldb -b -o 'settings read -f %t.bogus_value' 2>&1 | FileCheck %s --check-prefix BOGUS-VALUE
|
||||
# BOGUS-VALUE: error: invalid language type
|
|
@ -320,6 +320,207 @@ protected:
|
|||
}
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// CommandObjectSettingsWrite -- Write settings to file
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
static constexpr OptionDefinition g_settings_write_options[] = {
|
||||
// clang-format off
|
||||
{ LLDB_OPT_SET_ALL, true, "file", 'f', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eDiskFileCompletion, eArgTypeFilename, "The file into which to write the settings." },
|
||||
{ LLDB_OPT_SET_ALL, false, "append",'a', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Append to saved settings file if it exists."},
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
class CommandObjectSettingsWrite : public CommandObjectParsed {
|
||||
public:
|
||||
CommandObjectSettingsWrite(CommandInterpreter &interpreter)
|
||||
: CommandObjectParsed(
|
||||
interpreter, "settings export",
|
||||
"Write matching debugger settings and their "
|
||||
"current values to a file that can be read in with "
|
||||
"\"settings read\". Defaults to writing all settings.",
|
||||
nullptr),
|
||||
m_options() {
|
||||
CommandArgumentEntry arg1;
|
||||
CommandArgumentData var_name_arg;
|
||||
|
||||
// Define the first (and only) variant of this arg.
|
||||
var_name_arg.arg_type = eArgTypeSettingVariableName;
|
||||
var_name_arg.arg_repetition = eArgRepeatOptional;
|
||||
|
||||
// There is only one variant this argument could be; put it into the
|
||||
// argument entry.
|
||||
arg1.push_back(var_name_arg);
|
||||
|
||||
// Push the data for the first argument into the m_arguments vector.
|
||||
m_arguments.push_back(arg1);
|
||||
}
|
||||
|
||||
~CommandObjectSettingsWrite() override = default;
|
||||
|
||||
Options *GetOptions() override { return &m_options; }
|
||||
|
||||
class CommandOptions : public Options {
|
||||
public:
|
||||
CommandOptions() : Options() {}
|
||||
|
||||
~CommandOptions() override = default;
|
||||
|
||||
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
|
||||
ExecutionContext *execution_context) override {
|
||||
Status error;
|
||||
const int short_option = m_getopt_table[option_idx].val;
|
||||
|
||||
switch (short_option) {
|
||||
case 'f':
|
||||
m_filename.assign(option_arg);
|
||||
break;
|
||||
case 'a':
|
||||
m_append = true;
|
||||
break;
|
||||
default:
|
||||
error.SetErrorStringWithFormat("unrecognized option '%c'",
|
||||
short_option);
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void OptionParsingStarting(ExecutionContext *execution_context) override {
|
||||
m_filename.clear();
|
||||
m_append = false;
|
||||
}
|
||||
|
||||
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
|
||||
return llvm::makeArrayRef(g_settings_write_options);
|
||||
}
|
||||
|
||||
// Instance variables to hold the values for command options.
|
||||
std::string m_filename;
|
||||
bool m_append = false;
|
||||
};
|
||||
|
||||
protected:
|
||||
bool DoExecute(Args &args, CommandReturnObject &result) override {
|
||||
std::string path(FileSpec(m_options.m_filename, true).GetPath());
|
||||
uint32_t options = File::OpenOptions::eOpenOptionWrite |
|
||||
File::OpenOptions::eOpenOptionCanCreate;
|
||||
if (m_options.m_append)
|
||||
options |= File::OpenOptions::eOpenOptionAppend;
|
||||
else
|
||||
options |= File::OpenOptions::eOpenOptionTruncate;
|
||||
|
||||
StreamFile out_file(path.c_str(), options,
|
||||
lldb::eFilePermissionsFileDefault);
|
||||
|
||||
if (!out_file.GetFile().IsValid()) {
|
||||
result.AppendErrorWithFormat("%s: unable to write to file", path.c_str());
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Exporting should not be context sensitive.
|
||||
ExecutionContext clean_ctx;
|
||||
|
||||
if (args.empty()) {
|
||||
m_interpreter.GetDebugger().DumpAllPropertyValues(
|
||||
&clean_ctx, out_file, OptionValue::eDumpGroupExport);
|
||||
return result.Succeeded();
|
||||
}
|
||||
|
||||
for (const auto &arg : args) {
|
||||
Status error(m_interpreter.GetDebugger().DumpPropertyValue(
|
||||
&clean_ctx, out_file, arg.ref, OptionValue::eDumpGroupExport));
|
||||
if (!error.Success()) {
|
||||
result.AppendError(error.AsCString());
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
}
|
||||
}
|
||||
|
||||
return result.Succeeded();
|
||||
}
|
||||
|
||||
private:
|
||||
CommandOptions m_options;
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// CommandObjectSettingsRead -- Read settings from file
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
static constexpr OptionDefinition g_settings_read_options[] = {
|
||||
// clang-format off
|
||||
{LLDB_OPT_SET_ALL, true, "file",'f', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eDiskFileCompletion, eArgTypeFilename, "The file from which to read the breakpoints." },
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
class CommandObjectSettingsRead : public CommandObjectParsed {
|
||||
public:
|
||||
CommandObjectSettingsRead(CommandInterpreter &interpreter)
|
||||
: CommandObjectParsed(
|
||||
interpreter, "settings read",
|
||||
"Read settings previously saved to a file with \"settings write\".",
|
||||
nullptr),
|
||||
m_options() {}
|
||||
|
||||
~CommandObjectSettingsRead() override = default;
|
||||
|
||||
Options *GetOptions() override { return &m_options; }
|
||||
|
||||
class CommandOptions : public Options {
|
||||
public:
|
||||
CommandOptions() : Options() {}
|
||||
|
||||
~CommandOptions() override = default;
|
||||
|
||||
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
|
||||
ExecutionContext *execution_context) override {
|
||||
Status error;
|
||||
const int short_option = m_getopt_table[option_idx].val;
|
||||
|
||||
switch (short_option) {
|
||||
case 'f':
|
||||
m_filename.assign(option_arg);
|
||||
break;
|
||||
default:
|
||||
error.SetErrorStringWithFormat("unrecognized option '%c'",
|
||||
short_option);
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void OptionParsingStarting(ExecutionContext *execution_context) override {
|
||||
m_filename.clear();
|
||||
}
|
||||
|
||||
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
|
||||
return llvm::makeArrayRef(g_settings_read_options);
|
||||
}
|
||||
|
||||
// Instance variables to hold the values for command options.
|
||||
std::string m_filename;
|
||||
};
|
||||
|
||||
protected:
|
||||
bool DoExecute(Args &command, CommandReturnObject &result) override {
|
||||
FileSpec file(m_options.m_filename, true);
|
||||
ExecutionContext clean_ctx;
|
||||
CommandInterpreterRunOptions options;
|
||||
options.SetAddToHistory(false);
|
||||
options.SetEchoCommands(false);
|
||||
options.SetPrintResults(true);
|
||||
options.SetStopOnError(false);
|
||||
m_interpreter.HandleCommandsFromFile(file, &clean_ctx, options, result);
|
||||
return result.Succeeded();
|
||||
}
|
||||
|
||||
private:
|
||||
CommandOptions m_options;
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// CommandObjectSettingsList -- List settable variables
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -1007,6 +1208,10 @@ CommandObjectMultiwordSettings::CommandObjectMultiwordSettings(
|
|||
CommandObjectSP(new CommandObjectSettingsAppend(interpreter)));
|
||||
LoadSubCommand("clear",
|
||||
CommandObjectSP(new CommandObjectSettingsClear(interpreter)));
|
||||
LoadSubCommand("write",
|
||||
CommandObjectSP(new CommandObjectSettingsWrite(interpreter)));
|
||||
LoadSubCommand("read",
|
||||
CommandObjectSP(new CommandObjectSettingsRead(interpreter)));
|
||||
}
|
||||
|
||||
CommandObjectMultiwordSettings::~CommandObjectMultiwordSettings() = default;
|
||||
|
|
|
@ -31,13 +31,17 @@ void OptionValueArray::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
|
|||
strm.Printf("(%s)", GetTypeAsCString());
|
||||
}
|
||||
if (dump_mask & eDumpOptionValue) {
|
||||
if (dump_mask & eDumpOptionType)
|
||||
strm.Printf(" =%s", (m_values.size() > 0) ? "\n" : "");
|
||||
strm.IndentMore();
|
||||
const bool one_line = dump_mask & eDumpOptionCommand;
|
||||
const uint32_t size = m_values.size();
|
||||
if (dump_mask & eDumpOptionType)
|
||||
strm.Printf(" =%s", (m_values.size() > 0 && !one_line) ? "\n" : "");
|
||||
if (!one_line)
|
||||
strm.IndentMore();
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
strm.Indent();
|
||||
strm.Printf("[%u]: ", i);
|
||||
if (!one_line) {
|
||||
strm.Indent();
|
||||
strm.Printf("[%u]: ", i);
|
||||
}
|
||||
const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0;
|
||||
switch (array_element_type) {
|
||||
default:
|
||||
|
@ -63,10 +67,16 @@ void OptionValueArray::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
|
|||
extra_dump_options);
|
||||
break;
|
||||
}
|
||||
if (i < (size - 1))
|
||||
strm.EOL();
|
||||
|
||||
if (!one_line) {
|
||||
if (i < (size - 1))
|
||||
strm.EOL();
|
||||
} else {
|
||||
strm << ' ';
|
||||
}
|
||||
}
|
||||
strm.IndentLess();
|
||||
if (!one_line)
|
||||
strm.IndentLess();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,16 +33,23 @@ void OptionValueDictionary::DumpValue(const ExecutionContext *exe_ctx,
|
|||
strm.Printf("(%s)", GetTypeAsCString());
|
||||
}
|
||||
if (dump_mask & eDumpOptionValue) {
|
||||
const bool one_line = dump_mask & eDumpOptionCommand;
|
||||
if (dump_mask & eDumpOptionType)
|
||||
strm.PutCString(" =");
|
||||
|
||||
collection::iterator pos, end = m_values.end();
|
||||
|
||||
strm.IndentMore();
|
||||
if (!one_line)
|
||||
strm.IndentMore();
|
||||
|
||||
for (pos = m_values.begin(); pos != end; ++pos) {
|
||||
OptionValue *option_value = pos->second.get();
|
||||
strm.EOL();
|
||||
|
||||
if (one_line)
|
||||
strm << ' ';
|
||||
else
|
||||
strm.EOL();
|
||||
|
||||
strm.Indent(pos->first.GetCString());
|
||||
|
||||
const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0;
|
||||
|
@ -74,7 +81,8 @@ void OptionValueDictionary::DumpValue(const ExecutionContext *exe_ctx,
|
|||
break;
|
||||
}
|
||||
}
|
||||
strm.IndentLess();
|
||||
if (!one_line)
|
||||
strm.IndentLess();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,16 +25,24 @@ void OptionValueFileSpecList::DumpValue(const ExecutionContext *exe_ctx,
|
|||
if (dump_mask & eDumpOptionType)
|
||||
strm.Printf("(%s)", GetTypeAsCString());
|
||||
if (dump_mask & eDumpOptionValue) {
|
||||
if (dump_mask & eDumpOptionType)
|
||||
strm.Printf(" =%s", m_current_value.GetSize() > 0 ? "\n" : "");
|
||||
strm.IndentMore();
|
||||
const bool one_line = dump_mask & eDumpOptionCommand;
|
||||
const uint32_t size = m_current_value.GetSize();
|
||||
if (dump_mask & eDumpOptionType)
|
||||
strm.Printf(" =%s",
|
||||
(m_current_value.GetSize() > 0 && !one_line) ? "\n" : "");
|
||||
if (!one_line)
|
||||
strm.IndentMore();
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
strm.Indent();
|
||||
strm.Printf("[%u]: ", i);
|
||||
if (!one_line) {
|
||||
strm.Indent();
|
||||
strm.Printf("[%u]: ", i);
|
||||
}
|
||||
m_current_value.GetFileSpecAtIndex(i).Dump(&strm);
|
||||
if (one_line)
|
||||
strm << ' ';
|
||||
}
|
||||
strm.IndentLess();
|
||||
if (!one_line)
|
||||
strm.IndentLess();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -61,10 +61,10 @@ void OptionValueFormatEntity::DumpValue(const ExecutionContext *exe_ctx,
|
|||
strm.Printf("(%s)", GetTypeAsCString());
|
||||
if (dump_mask & eDumpOptionValue) {
|
||||
if (dump_mask & eDumpOptionType)
|
||||
strm.PutCString(" = \"");
|
||||
strm.PutCString(" = ");
|
||||
std::string escaped;
|
||||
EscapeBackticks(m_current_format, escaped);
|
||||
strm << escaped << '"';
|
||||
strm << '"' << escaped << '"';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,8 @@ void OptionValueLanguage::DumpValue(const ExecutionContext *exe_ctx,
|
|||
if (dump_mask & eDumpOptionValue) {
|
||||
if (dump_mask & eDumpOptionType)
|
||||
strm.PutCString(" = ");
|
||||
strm.PutCString(Language::GetNameForLanguageType(m_current_value));
|
||||
if (m_current_value != eLanguageTypeUnknown)
|
||||
strm.PutCString(Language::GetNameForLanguageType(m_current_value));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -233,7 +233,10 @@ void Property::Dump(const ExecutionContext *exe_ctx, Stream &strm,
|
|||
uint32_t dump_mask) const {
|
||||
if (m_value_sp) {
|
||||
const bool dump_desc = dump_mask & OptionValue::eDumpOptionDescription;
|
||||
const bool dump_cmd = dump_mask & OptionValue::eDumpOptionCommand;
|
||||
const bool transparent = m_value_sp->ValueIsTransparent();
|
||||
if (dump_cmd && !transparent)
|
||||
strm << "settings set -f ";
|
||||
if (dump_desc || !transparent) {
|
||||
if ((dump_mask & OptionValue::eDumpOptionName) && m_name) {
|
||||
DumpQualifiedName(strm);
|
||||
|
|
Loading…
Reference in New Issue