mib updated this revision to Diff 262999.
mib added a comment.

With the first implementation, I thought it'd be a good idea to have separate 
Command Objects for `platform shell` and `shell` because I was imagining the 
latter could be more "powerful": `shell` could have an interactive mode like 
the `script` command, which might not be as relevant for `platform shell` when 
debugging a remote target.

That was my original idea, but I agree we should avoid code duplication, so 
here is a different implementation following @jingham's suggestions. `shell` is 
an alias to `platform shell -h --` in this case.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D79659/new/

https://reviews.llvm.org/D79659

Files:
  lldb/source/Commands/CommandObjectPlatform.cpp
  lldb/source/Commands/Options.td
  lldb/source/Interpreter/CommandInterpreter.cpp
  lldb/test/API/commands/shell/TestShellCommand.py

Index: lldb/test/API/commands/shell/TestShellCommand.py
===================================================================
--- /dev/null
+++ lldb/test/API/commands/shell/TestShellCommand.py
@@ -0,0 +1,45 @@
+"""
+Test the lldb host shell command.
+"""
+
+
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class ShellCommandTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    @no_debug_info_test
+    def test_help_platform(self):
+        self.expect("help shell", substrs=["shell <shell-command>",
+                                           "Run a shell command on the host."])
+
+    @expectedFailureAll(oslist=["windows"])
+    @no_debug_info_test
+    def test_shell(self):
+        """ Test that the shell command can invoke ls. """
+        triple = self.dbg.GetSelectedPlatform().GetTriple()
+        if re.match(".*-.*-windows", triple):
+            self.expect("shell dir c:\\", substrs=["Windows", "Program Files"])
+        elif re.match(".*-.*-.*-android", triple):
+            self.expect("shell ls /",
+                substrs=["cache", "dev", "system"])
+        else:
+            self.expect("shell ls /", substrs=["dev", "tmp", "usr"])
+
+    @no_debug_info_test
+    def test_shell_builtin(self):
+        """ Test a shell built-in command (echo) """
+        self.expect("shell echo hello lldb",
+                    substrs=["hello lldb"])
+
+    @no_debug_info_test
+    def test_shell_timeout(self):
+        """ Test a shell built-in command (sleep) that times out """
+        self.expect("shell -t 1 --  sleep 3", error=True, substrs=[
+                    "error: timed out waiting for shell command to complete"])
Index: lldb/source/Interpreter/CommandInterpreter.cpp
===================================================================
--- lldb/source/Interpreter/CommandInterpreter.cpp
+++ lldb/source/Interpreter/CommandInterpreter.cpp
@@ -381,6 +381,16 @@
     }
   }
 
+  cmd_obj_sp = GetCommandSPExact("platform shell", false);
+  if (cmd_obj_sp) {
+    CommandAlias *shell_alias = AddAlias("shell", cmd_obj_sp, " --host --");
+    if (shell_alias) {
+      shell_alias->SetHelp("Run a shell command on the host.");
+      shell_alias->SetHelpLong("");
+      shell_alias->SetSyntax("shell <shell-command>");
+    }
+  }
+
   cmd_obj_sp = GetCommandSPExact("process kill", false);
   if (cmd_obj_sp) {
     AddAlias("kill", cmd_obj_sp);
Index: lldb/source/Commands/Options.td
===================================================================
--- lldb/source/Commands/Options.td
+++ lldb/source/Commands/Options.td
@@ -622,6 +622,8 @@
 }
 
 let Command = "platform shell" in {
+  def platform_shell_host : Option<"host", "h">,
+    Desc<"Run the commands on the host shell when enabled.">;
   def platform_shell_timeout : Option<"timeout", "t">, Arg<"Value">,
     Desc<"Seconds to wait for the remote host to finish running the command.">;
 }
@@ -701,6 +703,7 @@
     Desc<"Set the synchronicity of this command's executions with regard to "
     "LLDB event system.">;
 }
+
 let Command = "source info" in {
   def source_info_count : Option<"count", "c">, Arg<"Count">,
     Desc<"The number of line entries to display.">;
Index: lldb/source/Commands/CommandObjectPlatform.cpp
===================================================================
--- lldb/source/Commands/CommandObjectPlatform.cpp
+++ lldb/source/Commands/CommandObjectPlatform.cpp
@@ -1567,6 +1567,9 @@
       const char short_option = (char)GetDefinitions()[option_idx].short_option;
 
       switch (short_option) {
+      case 'h':
+        m_use_host_platform = true;
+        break;
       case 't':
         uint32_t timeout_sec;
         if (option_arg.getAsInteger(10, timeout_sec))
@@ -1574,7 +1577,7 @@
               "could not convert \"%s\" to a numeric value.",
               option_arg.str().c_str());
         else
-          timeout = std::chrono::seconds(timeout_sec);
+          m_timeout = std::chrono::seconds(timeout_sec);
         break;
       default:
         llvm_unreachable("Unimplemented option");
@@ -1583,9 +1586,12 @@
       return error;
     }
 
-    void OptionParsingStarting(ExecutionContext *execution_context) override {}
+    void OptionParsingStarting(ExecutionContext *execution_context) override {
+      m_use_host_platform = false;
+    }
 
-    Timeout<std::micro> timeout = std::chrono::seconds(10);
+    Timeout<std::micro> m_timeout = std::chrono::seconds(10);
+    bool m_use_host_platform;
   };
 
   CommandObjectPlatformShell(CommandInterpreter &interpreter)
@@ -1616,8 +1622,14 @@
       if (!ParseOptions(args.GetArgs(), result))
         return false;
 
+    // When called from the `shell` alias with no argument, exit.
+    if (args.GetRawPart().empty())
+      return false;
+
     PlatformSP platform_sp(
-        GetDebugger().GetPlatformList().GetSelectedPlatform());
+        m_options.m_use_host_platform
+            ? Platform::GetHostPlatform()
+            : GetDebugger().GetPlatformList().GetSelectedPlatform());
     Status error;
     if (platform_sp) {
       FileSpec working_dir{};
@@ -1625,7 +1637,7 @@
       int status = -1;
       int signo = -1;
       error = (platform_sp->RunShellCommand(expr, working_dir, &status, &signo,
-                                            &output, m_options.timeout));
+                                            &output, m_options.m_timeout));
       if (!output.empty())
         result.GetOutputStream().PutCString(output);
       if (status > 0) {
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to