lawrence_danna created this revision.
lawrence_danna added reviewers: JDevlieghere, jasonmolenda, labath.
Herald added a project: LLDB.

This makes SBFile::GetFile public and adds a SWIG typemap to convert
the result back into a python native file.

If the underlying File itself came from a python file, it is returned
identically.   Otherwise a new python file object is created using
the file descriptor.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D68737

Files:
  lldb/include/lldb/API/SBFile.h
  lldb/include/lldb/Host/File.h
  lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py
  lldb/scripts/Python/python-typemaps.swig
  lldb/scripts/interface/SBFile.i
  lldb/source/API/SBFile.cpp
  lldb/source/Host/common/File.cpp
  lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
  lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h

Index: lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
+++ lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h
@@ -658,7 +658,6 @@
 class PythonFile : public PythonObject {
 public:
   PythonFile();
-  PythonFile(File &file, const char *mode);
   PythonFile(PyRefType type, PyObject *o);
 
   ~PythonFile() override;
@@ -668,7 +667,19 @@
   using PythonObject::Reset;
 
   void Reset(PyRefType type, PyObject *py_obj) override;
-  void Reset(File &file, const char *mode);
+
+  static llvm::Expected<PythonFile> FromFile(File &file,
+                                             const char *mode = nullptr);
+
+  PythonFile(File &file, const char *mode = nullptr) {
+    auto f = FromFile(file, mode);
+    if (f)
+      *this = std::move(f.get());
+    else {
+      Reset();
+      llvm::consumeError(f.takeError());
+    }
+  }
 
   lldb::FileUP GetUnderlyingFile() const;
 
Index: lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
+++ lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
@@ -1012,8 +1012,6 @@
 
 PythonFile::PythonFile() : PythonObject() {}
 
-PythonFile::PythonFile(File &file, const char *mode) { Reset(file, mode); }
-
 PythonFile::PythonFile(PyRefType type, PyObject *o) { Reset(type, o); }
 
 PythonFile::~PythonFile() {}
@@ -1063,24 +1061,36 @@
   PythonObject::Reset(PyRefType::Borrowed, result.get());
 }
 
-void PythonFile::Reset(File &file, const char *mode) {
-  if (!file.IsValid()) {
-    Reset();
-    return;
-  }
+Expected<PythonFile> PythonFile::FromFile(File &file, const char *mode) {
+  if (!file.IsValid())
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "invalid file");
+
+  PyObject *file_obj = (PyObject *)file.GetPythonObject();
+  if (file_obj)
+    return Retain<PythonFile>(file_obj);
+
+  if (!mode)
+    mode = file.GetOpenMode();
+  if (!mode)
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "can't determine open mode for file");
 
-  char *cmode = const_cast<char *>(mode);
 #if PY_MAJOR_VERSION >= 3
-  Reset(PyRefType::Owned, PyFile_FromFd(file.GetDescriptor(), nullptr, cmode,
-                                        -1, nullptr, "ignore", nullptr, 0));
+  file_obj = PyFile_FromFd(file.GetDescriptor(), nullptr, mode, -1, nullptr,
+                           "ignore", nullptr, 0);
 #else
   // Read through the Python source, doesn't seem to modify these strings
-  Reset(PyRefType::Owned,
-        PyFile_FromFile(file.GetStream(), const_cast<char *>(""), cmode,
-                        nullptr));
+  char *cmode = const_cast<char *>(mode);
+  file_obj =
+      PyFile_FromFile(file.GetStream(), const_cast<char *>(""), cmode, nullptr);
 #endif
-}
 
+  if (!file_obj)
+    return exception();
+
+  return Take<PythonFile>(file_obj);
+}
 
 FileUP PythonFile::GetUnderlyingFile() const {
   if (!IsValid())
@@ -1233,6 +1243,8 @@
     return base_error;
   };
 
+  void *GetPythonObject() const override { return m_py_obj.get(); }
+
 protected:
   PythonFile m_py_obj;
   bool m_borrowed;
@@ -1316,6 +1328,15 @@
     return Status();
   }
 
+  uint32_t GetOptions() const override {
+    GIL takeGIL;
+    auto options = GetOptionsForPyObject(m_py_obj);
+    if (!options) {
+      llvm::consumeError(options.takeError());
+      return 0;
+    }
+    return options.get();
+  }
 };
 } // namespace
 
Index: lldb/source/Host/common/File.cpp
===================================================================
--- lldb/source/Host/common/File.cpp
+++ lldb/source/Host/common/File.cpp
@@ -38,7 +38,7 @@
 using namespace lldb;
 using namespace lldb_private;
 
-static const char *GetStreamOpenModeFromOptions(uint32_t options) {
+const char *File::GetStreamOpenModeFromOptions(uint32_t options) {
   if (options & File::eOpenOptionAppend) {
     if (options & File::eOpenOptionRead) {
       if (options & File::eOpenOptionCanCreateNewOnly)
@@ -215,6 +215,10 @@
   return result;
 }
 
+void *File::GetPythonObject() const { return nullptr; }
+
+uint32_t File::GetOptions() const { return 0; }
+
 uint32_t File::GetPermissions(Status &error) const {
   int fd = GetDescriptor();
   if (!DescriptorIsValid(fd)) {
@@ -230,6 +234,8 @@
   return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
 }
 
+uint32_t NativeFile::GetOptions() const { return m_options; }
+
 int NativeFile::GetDescriptor() const {
   if (DescriptorIsValid())
     return m_descriptor;
Index: lldb/source/API/SBFile.cpp
===================================================================
--- lldb/source/API/SBFile.cpp
+++ lldb/source/API/SBFile.cpp
@@ -103,6 +103,11 @@
   return LLDB_RECORD_RESULT(!IsValid());
 }
 
+FileSP SBFile::GetFile() const {
+  LLDB_RECORD_METHOD_CONST_NO_ARGS(FileSP, SBFile, GetFile);
+  return m_opaque_sp;
+}
+
 namespace lldb_private {
 namespace repro {
 
@@ -112,6 +117,7 @@
   LLDB_REGISTER_METHOD_CONST(bool, SBFile, IsValid, ());
   LLDB_REGISTER_METHOD_CONST(bool, SBFile, operator bool,());
   LLDB_REGISTER_METHOD_CONST(bool, SBFile, operator!,());
+  LLDB_REGISTER_METHOD_CONST(FileSP, SBFile, GetFile, ());
   LLDB_REGISTER_METHOD(lldb::SBError, SBFile, Close, ());
 }
 } // namespace repro
Index: lldb/scripts/interface/SBFile.i
===================================================================
--- lldb/scripts/interface/SBFile.i
+++ lldb/scripts/interface/SBFile.i
@@ -77,6 +77,9 @@
     operator bool() const;
 
     SBError Close();
+
+    %feature("docstring", "convert this SBFile into a python io.IOBase file object");
+    FileSP GetFile();
 };
 
 } // namespace lldb
Index: lldb/scripts/Python/python-typemaps.swig
===================================================================
--- lldb/scripts/Python/python-typemaps.swig
+++ lldb/scripts/Python/python-typemaps.swig
@@ -434,6 +434,22 @@
   }
 }
 
+%typemap(out) lldb::FileSP {
+  using namespace lldb_private;
+  $result = nullptr;
+  lldb::FileSP &sp = $1;
+  if (sp) {
+    PythonFile pyfile = unwrapOrSetPythonException(PythonFile::FromFile(*sp));
+    if (!pyfile.IsValid())
+      return nullptr;
+    $result = pyfile.release();
+  }
+  if (!$result)
+  {
+      $result = Py_None;
+      Py_INCREF(Py_None);
+  }
+}
 
 // FIXME both of these paths wind up calling fdopen() with no provision for ever calling
 // fclose() on the result.  SB interfaces that use FILE* should be deprecated for scripting
Index: lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py
+++ lldb/packages/Python/lldbsuite/test/python_api/file_handle/TestFileHandle.py
@@ -773,7 +773,6 @@
 
 
     @add_test_categories(['pyapi'])
-    @expectedFailure # FIXME implement SBFile::GetFile
     @skipIf(py_version=['<', (3,)])
     def test_identity(self):
 
Index: lldb/include/lldb/Host/File.h
===================================================================
--- lldb/include/lldb/Host/File.h
+++ lldb/include/lldb/Host/File.h
@@ -53,6 +53,7 @@
   static mode_t ConvertOpenOptionsForPOSIXOpen(uint32_t open_options);
   static uint32_t GetOptionsFromMode(llvm::StringRef mode);
   static bool DescriptorIsValid(int descriptor) { return descriptor >= 0; };
+  static const char *GetStreamOpenModeFromOptions(uint32_t options);
 
   File()
       : IOObject(eFDTypeFile), m_is_interactive(eLazyBoolCalculate),
@@ -308,6 +309,28 @@
   ///     format string \a format.
   virtual size_t PrintfVarArg(const char *format, va_list args);
 
+  /// If this file is a wrapper for a python file object, return it.
+  ///
+  /// \return
+  ///    The PyObject* that this File wraps, or NULL.
+  virtual void *GetPythonObject() const;
+
+  /// Return the OpenOptions for this file.
+  ///
+  /// Some options like eOpenOptionDontFollowSymlinks only make
+  /// sense when a file is being opened (or not at all)
+  /// and may not be preserved for this method.  But any valid
+  /// File should return either or both of eOpenOptionRead and
+  /// eOpenOptionWrite here.
+  ///
+  /// \return
+  ///    OpenOptions flags for this file, or 0 if unknown.
+  virtual uint32_t GetOptions() const;
+
+  const char *GetOpenMode() const {
+    return GetStreamOpenModeFromOptions(GetOptions());
+  }
+
   /// Get the permissions for a this file.
   ///
   /// \return
@@ -390,6 +413,7 @@
   Status Flush() override;
   Status Sync() override;
   size_t PrintfVarArg(const char *format, va_list args) override;
+  uint32_t GetOptions() const override;
 
 protected:
   bool DescriptorIsValid() const {
Index: lldb/include/lldb/API/SBFile.h
===================================================================
--- lldb/include/lldb/API/SBFile.h
+++ lldb/include/lldb/API/SBFile.h
@@ -34,6 +34,8 @@
   operator bool() const;
   bool operator!() const;
 
+  FileSP GetFile() const;
+
 private:
   FileSP m_opaque_sp;
 };
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to