Author: jdevlieghere Date: Thu Oct 25 17:00:17 2018 New Revision: 345346 URL: http://llvm.org/viewvc/llvm-project?rev=345346&view=rev Log: 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 Added: lldb/trunk/lit/Settings/TestExport.test Modified: lldb/trunk/include/lldb/Interpreter/OptionValue.h lldb/trunk/source/Commands/CommandObjectSettings.cpp lldb/trunk/source/Interpreter/OptionValueArray.cpp lldb/trunk/source/Interpreter/OptionValueDictionary.cpp lldb/trunk/source/Interpreter/OptionValueFileSpecLIst.cpp lldb/trunk/source/Interpreter/OptionValueFormatEntity.cpp lldb/trunk/source/Interpreter/OptionValueLanguage.cpp lldb/trunk/source/Interpreter/Property.cpp Modified: lldb/trunk/include/lldb/Interpreter/OptionValue.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/OptionValue.h?rev=345346&r1=345345&r2=345346&view=diff ============================================================================== --- lldb/trunk/include/lldb/Interpreter/OptionValue.h (original) +++ lldb/trunk/include/lldb/Interpreter/OptionValue.h Thu Oct 25 17:00:17 2018 @@ -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() Added: lldb/trunk/lit/Settings/TestExport.test URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lit/Settings/TestExport.test?rev=345346&view=auto ============================================================================== --- lldb/trunk/lit/Settings/TestExport.test (added) +++ lldb/trunk/lit/Settings/TestExport.test Thu Oct 25 17:00:17 2018 @@ -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 Modified: lldb/trunk/source/Commands/CommandObjectSettings.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectSettings.cpp?rev=345346&r1=345345&r2=345346&view=diff ============================================================================== --- lldb/trunk/source/Commands/CommandObjectSettings.cpp (original) +++ lldb/trunk/source/Commands/CommandObjectSettings.cpp Thu Oct 25 17:00:17 2018 @@ -321,6 +321,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::CommandO 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; Modified: lldb/trunk/source/Interpreter/OptionValueArray.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/OptionValueArray.cpp?rev=345346&r1=345345&r2=345346&view=diff ============================================================================== --- lldb/trunk/source/Interpreter/OptionValueArray.cpp (original) +++ lldb/trunk/source/Interpreter/OptionValueArray.cpp Thu Oct 25 17:00:17 2018 @@ -31,13 +31,17 @@ void OptionValueArray::DumpValue(const E 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 E 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(); } } Modified: lldb/trunk/source/Interpreter/OptionValueDictionary.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/OptionValueDictionary.cpp?rev=345346&r1=345345&r2=345346&view=diff ============================================================================== --- lldb/trunk/source/Interpreter/OptionValueDictionary.cpp (original) +++ lldb/trunk/source/Interpreter/OptionValueDictionary.cpp Thu Oct 25 17:00:17 2018 @@ -33,16 +33,23 @@ void OptionValueDictionary::DumpValue(co 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(co break; } } - strm.IndentLess(); + if (!one_line) + strm.IndentLess(); } } Modified: lldb/trunk/source/Interpreter/OptionValueFileSpecLIst.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/OptionValueFileSpecLIst.cpp?rev=345346&r1=345345&r2=345346&view=diff ============================================================================== --- lldb/trunk/source/Interpreter/OptionValueFileSpecLIst.cpp (original) +++ lldb/trunk/source/Interpreter/OptionValueFileSpecLIst.cpp Thu Oct 25 17:00:17 2018 @@ -25,16 +25,24 @@ void OptionValueFileSpecList::DumpValue( 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(); } } Modified: lldb/trunk/source/Interpreter/OptionValueFormatEntity.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/OptionValueFormatEntity.cpp?rev=345346&r1=345345&r2=345346&view=diff ============================================================================== --- lldb/trunk/source/Interpreter/OptionValueFormatEntity.cpp (original) +++ lldb/trunk/source/Interpreter/OptionValueFormatEntity.cpp Thu Oct 25 17:00:17 2018 @@ -61,10 +61,10 @@ void OptionValueFormatEntity::DumpValue( 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 << '"'; } } Modified: lldb/trunk/source/Interpreter/OptionValueLanguage.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/OptionValueLanguage.cpp?rev=345346&r1=345345&r2=345346&view=diff ============================================================================== --- lldb/trunk/source/Interpreter/OptionValueLanguage.cpp (original) +++ lldb/trunk/source/Interpreter/OptionValueLanguage.cpp Thu Oct 25 17:00:17 2018 @@ -28,7 +28,8 @@ void OptionValueLanguage::DumpValue(cons 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)); } } Modified: lldb/trunk/source/Interpreter/Property.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/Property.cpp?rev=345346&r1=345345&r2=345346&view=diff ============================================================================== --- lldb/trunk/source/Interpreter/Property.cpp (original) +++ lldb/trunk/source/Interpreter/Property.cpp Thu Oct 25 17:00:17 2018 @@ -233,7 +233,10 @@ void Property::Dump(const ExecutionConte 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); _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits