JDevlieghere created this revision. JDevlieghere added reviewers: labath, kastiglione, teemperor. JDevlieghere requested review of this revision.
Make it possible to use a relative path in `command script import` to the location of the file being sourced. This allows the user to put Python scripts next to LLDB command files and importing them without having to specify an absolute path. rdar://68310384 https://reviews.llvm.org/D89334 Files: lldb/include/lldb/Interpreter/CommandInterpreter.h lldb/include/lldb/Interpreter/ScriptInterpreter.h lldb/source/Commands/CommandObjectCommands.cpp lldb/source/Interpreter/CommandInterpreter.cpp lldb/source/Interpreter/ScriptInterpreter.cpp lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h lldb/test/Shell/ScriptInterpreter/Python/Inputs/zip.in lldb/test/Shell/ScriptInterpreter/Python/Inputs/zip.py lldb/test/Shell/ScriptInterpreter/Python/relative_import.test
Index: lldb/test/Shell/ScriptInterpreter/Python/relative_import.test =================================================================== --- /dev/null +++ lldb/test/Shell/ScriptInterpreter/Python/relative_import.test @@ -0,0 +1,7 @@ +# REQUIRES: python + +# RUN: rm -rf %t && mkdir -p %t/foo +# RUN: cp %S/Inputs/zip.py %t/foo +# RUN: cp %S/Inputs/zip.in %t/foo +# RUN: %lldb --script-language python -o 'command source %t/foo/zip.in' -o 'zip' 2>&1 | FileCheck %s +# CHECK: 95126 Index: lldb/test/Shell/ScriptInterpreter/Python/Inputs/zip.py =================================================================== --- /dev/null +++ lldb/test/Shell/ScriptInterpreter/Python/Inputs/zip.py @@ -0,0 +1,7 @@ +import lldb + +def zip(debugger, command, result, internal_dict): + print("95126") + +def __lldb_init_module(debugger, internal_dict): + debugger.HandleCommand('command script add -f zip.zip zip') Index: lldb/test/Shell/ScriptInterpreter/Python/Inputs/zip.in =================================================================== --- /dev/null +++ lldb/test/Shell/ScriptInterpreter/Python/Inputs/zip.in @@ -0,0 +1 @@ +command script import zip Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h +++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h @@ -231,10 +231,10 @@ bool RunScriptFormatKeyword(const char *impl_function, ValueObject *value, std::string &output, Status &error) override; - bool - LoadScriptingModule(const char *filename, bool init_session, - lldb_private::Status &error, - StructuredData::ObjectSP *module_sp = nullptr) override; + bool LoadScriptingModule(const char *filename, bool init_session, + lldb_private::Status &error, + StructuredData::ObjectSP *module_sp = nullptr, + FileSpec extra_search_dir = {}) override; bool IsReservedWord(const char *word) override; Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -2733,7 +2733,7 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule( const char *pathname, bool init_session, lldb_private::Status &error, - StructuredData::ObjectSP *module_sp) { + StructuredData::ObjectSP *module_sp, FileSpec extra_search_dir) { if (!pathname || !pathname[0]) { error.SetErrorString("invalid pathname"); return false; @@ -2760,24 +2760,12 @@ fs::file_status st; std::error_code ec = status(target_file.GetPath(), st); - if (ec || st.type() == fs::file_type::status_error || - st.type() == fs::file_type::type_unknown || - st.type() == fs::file_type::file_not_found) { - // if not a valid file of any sort, check if it might be a filename still - // dot can't be used but / and \ can, and if either is found, reject - if (strchr(pathname, '\\') || strchr(pathname, '/')) { - error.SetErrorString("invalid pathname"); - return false; - } - basename = pathname; // not a filename, probably a package of some sort, - // let it go through - } else if (is_directory(st) || is_regular_file(st)) { - if (target_file.GetDirectory().IsEmpty()) { - error.SetErrorString("invalid directory name"); - return false; + auto ExtendSysPath = [this](std::string directory) -> llvm::Error { + if (directory.empty()) { + return llvm::make_error<llvm::StringError>( + "invalid directory name", llvm::inconvertibleErrorCode()); } - std::string directory = target_file.GetDirectory().GetCString(); replace_all(directory, "\\", "\\\\"); replace_all(directory, "'", "\\'"); @@ -2793,7 +2781,35 @@ .SetSetLLDBGlobals(false)) .Success(); if (!syspath_retval) { - error.SetErrorString("Python sys.path handling failed"); + return llvm::make_error<llvm::StringError>( + "Python sys.path handling failed", llvm::inconvertibleErrorCode()); + } + + return llvm::Error::success(); + }; + + if (extra_search_dir) { + if (llvm::Error e = ExtendSysPath(extra_search_dir.GetPath())) { + error = std::move(e); + return false; + } + } + + if (ec || st.type() == fs::file_type::status_error || + st.type() == fs::file_type::type_unknown || + st.type() == fs::file_type::file_not_found) { + // if not a valid file of any sort, check if it might be a filename still + // dot can't be used but / and \ can, and if either is found, reject + if (strchr(pathname, '\\') || strchr(pathname, '/')) { + error.SetErrorString("invalid pathname"); + return false; + } + basename = pathname; // not a filename, probably a package of some sort, + // let it go through + } else if (is_directory(st) || is_regular_file(st)) { + if (llvm::Error e = + ExtendSysPath(target_file.GetDirectory().GetCString())) { + error = std::move(e); return false; } @@ -3229,11 +3245,16 @@ LLDBSwigPyInit(); - // Update the path python uses to search for modules to include the current - // directory. - + // We need to call this before AddToSysPath as it uses the sys module. PyRun_SimpleString("import sys"); + + // Update the path python uses to search for modules to include the current + // directory and the home directory. AddToSysPath(AddLocation::End, "."); + FileSpec home_dir_spec; + llvm::SmallString<128> home_dir; + if (FileSystem::Instance().GetHomeDirectory(home_dir)) + AddToSysPath(AddLocation::End, std::string(home_dir)); // Don't denormalize paths when calling file_spec.GetPath(). On platforms // that use a backslash as the path separator, this will result in executing Index: lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h +++ lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h @@ -25,10 +25,10 @@ void ExecuteInterpreterLoop() override; - bool - LoadScriptingModule(const char *filename, bool init_session, - lldb_private::Status &error, - StructuredData::ObjectSP *module_sp = nullptr) override; + bool LoadScriptingModule(const char *filename, bool init_session, + lldb_private::Status &error, + StructuredData::ObjectSP *module_sp = nullptr, + FileSpec extra_search_dir = {}) override; // Static Functions static void Initialize(); Index: lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp =================================================================== --- lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp +++ lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp @@ -124,7 +124,7 @@ bool ScriptInterpreterLua::LoadScriptingModule( const char *filename, bool init_session, lldb_private::Status &error, - StructuredData::ObjectSP *module_sp) { + StructuredData::ObjectSP *module_sp, FileSpec extra_search_dir) { FileSystem::Instance().Collect(filename); if (llvm::Error e = m_lua->LoadModule(filename)) { Index: lldb/source/Interpreter/ScriptInterpreter.cpp =================================================================== --- lldb/source/Interpreter/ScriptInterpreter.cpp +++ lldb/source/Interpreter/ScriptInterpreter.cpp @@ -47,9 +47,11 @@ "This script interpreter does not support watchpoint callbacks."); } -bool ScriptInterpreter::LoadScriptingModule( - const char *filename, bool init_session, lldb_private::Status &error, - StructuredData::ObjectSP *module_sp) { +bool ScriptInterpreter::LoadScriptingModule(const char *filename, + bool init_session, + lldb_private::Status &error, + StructuredData::ObjectSP *module_sp, + FileSpec extra_search_dir) { error.SetErrorString( "This script interpreter does not support importing modules."); return false; Index: lldb/source/Interpreter/CommandInterpreter.cpp =================================================================== --- lldb/source/Interpreter/CommandInterpreter.cpp +++ lldb/source/Interpreter/CommandInterpreter.cpp @@ -2554,11 +2554,15 @@ debugger.SetAsyncExecution(false); m_command_source_depth++; + m_command_source_dirs.push_back(cmd_file.CopyByRemovingLastPathComponent()); debugger.RunIOHandlerSync(io_handler_sp); if (!m_command_source_flags.empty()) m_command_source_flags.pop_back(); + + m_command_source_dirs.pop_back(); m_command_source_depth--; + result.SetStatus(eReturnStatusSuccessFinishNoResult); debugger.SetAsyncExecution(old_async_execution); } @@ -2964,6 +2968,12 @@ return true; } +FileSpec CommandInterpreter::GetCurrentSourceDir() { + if (m_command_source_dirs.empty()) + return {}; + return m_command_source_dirs.back(); +} + void CommandInterpreter::GetLLDBCommandsFromIOHandler( const char *prompt, IOHandlerDelegate &delegate, void *baton) { Debugger &debugger = GetDebugger(); Index: lldb/source/Commands/CommandObjectCommands.cpp =================================================================== --- lldb/source/Commands/CommandObjectCommands.cpp +++ lldb/source/Commands/CommandObjectCommands.cpp @@ -1294,6 +1294,9 @@ return false; } + FileSpec source_dir = + GetDebugger().GetCommandInterpreter().GetCurrentSourceDir(); + for (auto &entry : command.entries()) { Status error; @@ -1308,7 +1311,7 @@ // more) m_exe_ctx.Clear(); if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule( - entry.c_str(), init_session, error)) { + entry.c_str(), init_session, error, nullptr, source_dir)) { result.SetStatus(eReturnStatusSuccessFinishNoResult); } else { result.AppendErrorWithFormat("module importing failed: %s", Index: lldb/include/lldb/Interpreter/ScriptInterpreter.h =================================================================== --- lldb/include/lldb/Interpreter/ScriptInterpreter.h +++ lldb/include/lldb/Interpreter/ScriptInterpreter.h @@ -507,7 +507,8 @@ virtual bool LoadScriptingModule(const char *filename, bool init_session, lldb_private::Status &error, - StructuredData::ObjectSP *module_sp = nullptr); + StructuredData::ObjectSP *module_sp = nullptr, + FileSpec extra_search_dir = {}); virtual bool IsReservedWord(const char *word) { return false; } Index: lldb/include/lldb/Interpreter/CommandInterpreter.h =================================================================== --- lldb/include/lldb/Interpreter/CommandInterpreter.h +++ lldb/include/lldb/Interpreter/CommandInterpreter.h @@ -551,6 +551,8 @@ bool SaveTranscript(CommandReturnObject &result, llvm::Optional<std::string> output_file = llvm::None); + FileSpec GetCurrentSourceDir(); + protected: friend class Debugger; @@ -637,7 +639,13 @@ ChildrenTruncatedWarningStatus m_truncation_warning; // Whether we truncated // children and whether // the user has been told + + // FIXME: Stop using this to control adding to the history and then replace + // this with m_command_source_dirs.size(). uint32_t m_command_source_depth; + /// A stack of directory paths. When not empty, the last one is the directory + /// of the file that's currently sourced. + std::vector<FileSpec> m_command_source_dirs; std::vector<uint32_t> m_command_source_flags; CommandInterpreterRunResult m_result;
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits