[Lldb-commits] [lldb] r345346 - Add functionality to export settings

Jonas Devlieghere via lldb-commits lldb-commits at lists.llvm.org
Thu Oct 25 17:00:17 PDT 2018


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);




More information about the lldb-commits mailing list