From e57c8add84a25325a9ed1eb0e6ec13fc173fcf89 Mon Sep 17 00:00:00 2001 From: Martin Vidner Date: Fri, 4 Jan 2019 15:30:00 +0100 Subject: [PATCH 1/6] Fixed argument count reporting (debug) --- src/binary/YRuby.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/binary/YRuby.cc b/src/binary/YRuby.cc index 55b0bd8d..a5691b33 100644 --- a/src/binary/YRuby.cc +++ b/src/binary/YRuby.cc @@ -203,7 +203,7 @@ YCPValue YRuby::callInner (string module_name, string function, rb_gc_register_address(values + i + 3); } - y2debug( "Will call function '%s' in module '%s' with '%d' arguments", function.c_str(), module_name.c_str(), size-1); + y2debug( "Will call function '%s' in module '%s' with %d arguments", function.c_str(), module_name.c_str(), size); int error; VALUE result = rb_protect(protected_call, (VALUE)values, &error); From 01d2072246395c7244453fb97b0358b095b96a39 Mon Sep 17 00:00:00 2001 From: Martin Vidner Date: Fri, 4 Jan 2019 15:30:32 +0100 Subject: [PATCH 2/6] Don't crash if there is no backtrace ($@ nil, bsc#1119690#c9) --- src/binary/YRuby.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/binary/YRuby.cc b/src/binary/YRuby.cc index a5691b33..fb99da30 100644 --- a/src/binary/YRuby.cc +++ b/src/binary/YRuby.cc @@ -176,7 +176,7 @@ YCPValue YRuby::callInner (string module_name, string function, VALUE exception = rb_gv_get("$!"); /* get last exception */ VALUE reason = rb_funcall(exception, rb_intern("message"), 0 ); VALUE trace = rb_gv_get("$@"); /* get last exception trace */ - VALUE backtrace = RARRAY_LEN(trace)>0 ? rb_ary_entry(trace, 0) : rb_str_new2("Unknown"); + VALUE backtrace = (RTEST(trace) && RARRAY_LEN(trace)>0) ? rb_ary_entry(trace, 0) : rb_str_new2("Unknown"); y2error("%s load failed:%s at %s", full_name.c_str(), StringValuePtr(reason), StringValuePtr(backtrace)); return YCPVoid(); } @@ -217,7 +217,7 @@ YCPValue YRuby::callInner (string module_name, string function, VALUE exception = rb_gv_get("$!"); /* get last exception */ VALUE reason = rb_funcall(exception, rb_intern("message"), 0 ); VALUE trace = rb_gv_get("$@"); /* get last exception trace */ - VALUE backtrace = RARRAY_LEN(trace)>0 ? rb_ary_entry(trace, 0) : rb_str_new2("Unknown"); + VALUE backtrace = (RTEST(trace) && RARRAY_LEN(trace)>0) ? rb_ary_entry(trace, 0) : rb_str_new2("Unknown"); y2error("%s.%s failed:%s at %s", module_name.c_str(), function.c_str(), StringValuePtr(reason),StringValuePtr(backtrace)); //workaround if last_exception failed, then return always string with message if(function == "last_exception") //TODO constantify last_exception From 5d7398dcca1a925eab74542780aab0fed44b1723 Mon Sep 17 00:00:00 2001 From: Martin Vidner Date: Fri, 4 Jan 2019 16:27:28 +0100 Subject: [PATCH 3/6] Factored out exception detail reporting --- src/binary/Y2RubyComponent.cc | 13 +++++-------- src/binary/Y2RubyUtils.cc | 22 ++++++++++++++++------ src/binary/Y2RubyUtils.h | 5 +++++ src/binary/YRuby.cc | 19 +++++++------------ 4 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/binary/Y2RubyComponent.cc b/src/binary/Y2RubyComponent.cc index 8b14841e..915c75a1 100644 --- a/src/binary/Y2RubyComponent.cc +++ b/src/binary/Y2RubyComponent.cc @@ -27,6 +27,8 @@ as published by the Free Software Foundation; either version #include "Y2RubyComponent.h" #include "YRuby.h" #include "YRubyNamespace.h" +#include "Y2RubyUtils.h" + using std::string; using std::map; @@ -88,18 +90,13 @@ Y2Namespace *Y2RubyComponent::import (const char* name) } else // report more verbose why require failed { - VALUE exception = rb_errinfo(); /* get last exception */ + pair exc = exception_message_and_backtrace(); rb_set_errinfo(Qnil); // clear exception, so we can recover from it - VALUE reason = rb_funcall(exception, rb_intern("message"), 0 ); - VALUE trace = rb_funcall(exception, rb_intern("backtrace"), 0 ); - VALUE trace_to_s = rb_funcall(trace, rb_intern("join"), 1, rb_str_new_cstr("\n")); - string reason_s(StringValuePtr(reason)); - string trace_s(StringValuePtr(trace_to_s)); y2error("Reporting runtime error for import of module '%s' message '%s'", - name, reason_s.c_str()); + name, exc.first.c_str()); - Y2Namespace * res = new Y2ErrorNamespace (reason_s, trace_s); + Y2Namespace * res = new Y2ErrorNamespace (exc.first, exc.second); namespaces[name] = res; return res; } diff --git a/src/binary/Y2RubyUtils.cc b/src/binary/Y2RubyUtils.cc index a6a08688..1c7a3b93 100644 --- a/src/binary/Y2RubyUtils.cc +++ b/src/binary/Y2RubyUtils.cc @@ -12,18 +12,28 @@ using namespace std; +pair exception_message_and_backtrace() +{ + VALUE exception = rb_errinfo(); /* get last exception */ + + VALUE reason = rb_funcall(exception, rb_intern("message"), 0 ); + string reason_s(StringValuePtr(reason)); + + VALUE trace = rb_funcall(exception, rb_intern("backtrace"), 0 ); + VALUE trace_to_s = rb_funcall(trace, rb_intern("join"), 1, rb_str_new_cstr("\n")); + string trace_s(StringValuePtr(trace_to_s)); + + return make_pair(reason_s, trace_s); +} + bool y2_require(const char *str) { int error; rb_protect( (VALUE (*)(VALUE))rb_require, (VALUE) str, &error); if (error) { - VALUE exception = rb_errinfo(); /* get last exception */ - // do not clear exception yet, as it can be also processed later - VALUE reason = rb_funcall(exception, rb_intern("message"), 0 ); - VALUE trace = rb_funcall(exception, rb_intern("backtrace"), 0 ); - VALUE backtrace = RARRAY_LEN(trace)>0 ? rb_ary_entry(trace, 0) : rb_str_new2("Unknown"); - y2error("cannot require yast:%s at %s", StringValuePtr(reason),StringValuePtr(backtrace)); + pair exc = exception_message_and_backtrace(); + y2error("cannot require yast:%s at %s", exc.first.c_str(), exc.second.c_str()); return false; } diff --git a/src/binary/Y2RubyUtils.h b/src/binary/Y2RubyUtils.h index 5ced7928..2bf25006 100644 --- a/src/binary/Y2RubyUtils.h +++ b/src/binary/Y2RubyUtils.h @@ -31,6 +31,11 @@ as published by the Free Software Foundation; either version */ VALUE y2ruby_nested_const_get(const std::string &name); +/** + * call rb_errinfo and return its .message and .backtrace.join("\n") + */ +std::pair exception_message_and_backtrace(); + /** * safe variant of rb_require: if an exception happens then log it */ diff --git a/src/binary/YRuby.cc b/src/binary/YRuby.cc index fb99da30..c29ae85c 100644 --- a/src/binary/YRuby.cc +++ b/src/binary/YRuby.cc @@ -173,11 +173,8 @@ YCPValue YRuby::callInner (string module_name, string function, if (module == Qnil) { y2error ("The Ruby module '%s' is not loaded.", full_name.c_str()); - VALUE exception = rb_gv_get("$!"); /* get last exception */ - VALUE reason = rb_funcall(exception, rb_intern("message"), 0 ); - VALUE trace = rb_gv_get("$@"); /* get last exception trace */ - VALUE backtrace = (RTEST(trace) && RARRAY_LEN(trace)>0) ? rb_ary_entry(trace, 0) : rb_str_new2("Unknown"); - y2error("%s load failed:%s at %s", full_name.c_str(), StringValuePtr(reason), StringValuePtr(backtrace)); + pair exc = exception_message_and_backtrace(); + y2error("%s load failed:%s at %s", full_name.c_str(), exc.first.c_str(), exc.second.c_str()); return YCPVoid(); } @@ -214,17 +211,15 @@ YCPValue YRuby::callInner (string module_name, string function, if (error) { - VALUE exception = rb_gv_get("$!"); /* get last exception */ - VALUE reason = rb_funcall(exception, rb_intern("message"), 0 ); - VALUE trace = rb_gv_get("$@"); /* get last exception trace */ - VALUE backtrace = (RTEST(trace) && RARRAY_LEN(trace)>0) ? rb_ary_entry(trace, 0) : rb_str_new2("Unknown"); - y2error("%s.%s failed:%s at %s", module_name.c_str(), function.c_str(), StringValuePtr(reason),StringValuePtr(backtrace)); + pair exc = exception_message_and_backtrace(); + const string& reason = exc.first; + y2error("%s.%s failed:%s at %s", module_name.c_str(), function.c_str(), reason.c_str(), exc.second.c_str()); //workaround if last_exception failed, then return always string with message if(function == "last_exception") //TODO constantify last_exception { - return YCPString(StringValuePtr(reason)); + return YCPString(reason); } - set_last_exception(module,StringValuePtr(reason)); + set_last_exception(module, reason); return YCPVoid(); } else From 727b66add7a7611dc16da07d63861e859adf1548 Mon Sep 17 00:00:00 2001 From: Martin Vidner Date: Fri, 4 Jan 2019 16:32:39 +0100 Subject: [PATCH 4/6] Use the cmake-supplied FindRuby.cmake --- CMakeLists.txt | 23 +++++++----- cmake/modules/FindRuby.cmake | 69 ------------------------------------ 2 files changed, 14 insertions(+), 78 deletions(-) delete mode 100644 cmake/modules/FindRuby.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 27eea042..c9ee901b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,20 @@ set(PACKAGE "yast2-ruby-bindings") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x -g -O3 -Wall -Woverloaded-virtual") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu++0x -g -O3 -Wall") +# +# Where is Ruby ? +# + +find_package(Ruby REQUIRED) +if(NOT RUBY_EXECUTABLE) + message(FATAL_ERROR "Ruby not found.") +endif() + +# RUBY_BIN_PATH contains the full path including the version suffix, +# e.g. /usr/bin/ruby.ruby2.5 +EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print RbConfig.ruby" + OUTPUT_VARIABLE RUBY_BIN_PATH) + # # Where is YaST ? # @@ -26,15 +40,6 @@ if(NOT YAST_PLUGIN_UI_LIBRARY) message(FATAL_ERROR "YAST_PLUGIN_UI_LIBRARY not set, please install yast2-ycp-ui-bindings-devel.") endif() -# -# Where is Ruby ? -# - -find_package(Ruby REQUIRED) -if(NOT RUBY_EXECUTABLE) - message(FATAL_ERROR "Ruby not found.") -endif() - # # crypt.h or xcrypt.h ? # diff --git a/cmake/modules/FindRuby.cmake b/cmake/modules/FindRuby.cmake deleted file mode 100644 index 6d1130b1..00000000 --- a/cmake/modules/FindRuby.cmake +++ /dev/null @@ -1,69 +0,0 @@ -# - Find Ruby -# This module finds if Ruby is installed and determines where the include files -# and libraries are. It also determines what the name of the library is. This -# code sets the following variables: -# -# RUBY_INCLUDE_PATH = path to where ruby.h can be found -# RUBY_EXECUTABLE = full path to the ruby binary - -# Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. -# See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details. - - -if(RUBY_LIBRARY AND RUBY_INCLUDE_PATH) - # Already in cache, be silent - set(RUBY_FIND_QUIETLY TRUE) -endif (RUBY_LIBRARY AND RUBY_INCLUDE_PATH) - -FIND_PROGRAM(RUBY_EXECUTABLE NAMES ruby) - -EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print RbConfig::CONFIG['archdir']" - OUTPUT_VARIABLE RUBY_ARCH_DIR) - - EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print RbConfig::CONFIG['libdir']" - OUTPUT_VARIABLE RUBY_POSSIBLE_LIB_PATH) - - EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print RbConfig::CONFIG['rubylibdir']" - OUTPUT_VARIABLE RUBY_RUBY_LIB_PATH) - -# site_ruby -EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print RbConfig::CONFIG['sitearchdir']" - OUTPUT_VARIABLE RUBY_SITEARCH_DIR) - -EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print RbConfig::CONFIG['sitelibdir']" - OUTPUT_VARIABLE RUBY_SITELIB_DIR) - - -EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print RbConfig::CONFIG['vendorarchdir']" - OUTPUT_VARIABLE RUBY_VENDORARCH_DIR) - -EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print RbConfig::CONFIG['vendorlibdir']" - OUTPUT_VARIABLE RUBY_VENDORLIB_DIR) - -EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print RbConfig::CONFIG['rubyhdrdir']" - OUTPUT_VARIABLE RUBY_HEADER_DIR) - -EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print RbConfig::CONFIG['arch']" - OUTPUT_VARIABLE RUBY_ARCH) - -# RUBY_BIN_PATH contains the full path including the version suffix, -# e.g. /usr/bin/ruby.ruby2.4 -EXECUTE_PROCESS(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "print RbConfig.ruby" - OUTPUT_VARIABLE RUBY_BIN_PATH) - -FIND_PATH(RUBY_INCLUDE_PATH - NAMES ruby.h - PATHS - ${RUBY_HEADER_DIR} -) - -FIND_LIBRARY(RUBY_LIBRARY - NAMES ruby - PATHS ${RUBY_POSSIBLE_LIB_PATH} - ) - -MARK_AS_ADVANCED( - RUBY_EXECUTABLE - RUBY_LIBRARY - RUBY_INCLUDE_PATH - ) From 1179474800e52a0f33b7842750a03fd468b26320 Mon Sep 17 00:00:00 2001 From: Martin Vidner Date: Wed, 9 Jan 2019 15:46:47 +0100 Subject: [PATCH 5/6] Higher level of debuginfo, including macros --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c9ee901b..8580b36b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,8 +10,8 @@ endif() project(yast2-ruby-bindings) set(PACKAGE "yast2-ruby-bindings") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x -g -O3 -Wall -Woverloaded-virtual") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu++0x -g -O3 -Wall") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++0x -g3 -O3 -Wall -Woverloaded-virtual") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu++0x -g3 -O3 -Wall") # # Where is Ruby ? From bfe91b8353048a6b3b928d0127066084087cfde2 Mon Sep 17 00:00:00 2001 From: Martin Vidner Date: Thu, 10 Jan 2019 17:26:00 +0100 Subject: [PATCH 6/6] prototype: save exception info in a Y2Namespace --- src/binary/YRuby.cc | 8 ++++++++ src/ruby/CMakeLists.txt | 2 +- src/ruby/yast/y2_exception.rb | 15 +++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/ruby/yast/y2_exception.rb diff --git a/src/binary/YRuby.cc b/src/binary/YRuby.cc index c29ae85c..cf0a710a 100644 --- a/src/binary/YRuby.cc +++ b/src/binary/YRuby.cc @@ -220,6 +220,14 @@ YCPValue YRuby::callInner (string module_name, string function, return YCPString(reason); } set_last_exception(module, reason); + + VALUE exhash = rb_hash_new(); + rb_hash_aset(exhash, rb_str_new2("message"), rb_str_new2(exc.first.c_str())); + rb_hash_aset(exhash, rb_str_new2("backtrace"), rb_str_new2(exc.second.c_str())); + VALUE yast_module = y2ruby_nested_const_get("Yast"); + rb_funcall(yast_module, rb_intern("call_yast_function"), 3, + rb_str_new2("Y2Exception"), rb_str_new2("exception"), exhash); + return YCPVoid(); } else diff --git a/src/ruby/CMakeLists.txt b/src/ruby/CMakeLists.txt index 07e3117f..882ccbd4 100644 --- a/src/ruby/CMakeLists.txt +++ b/src/ruby/CMakeLists.txt @@ -7,4 +7,4 @@ INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/yast.rb DESTINATION ${RUBY_VENDORLIB_D INSTALL(FILES ${files} DESTINATION ${RUBY_VENDORLIB_DIR}/yast) INSTALL(FILES ${rspec} DESTINATION ${RUBY_VENDORLIB_DIR}/yast/rspec) INSTALL(FILES ${core_ext} DESTINATION ${RUBY_VENDORLIB_DIR}/yast/core_ext) - +INSTALL(FILES yast/y2_exception.rb DESTINATION /usr/share/YaST2/modules) diff --git a/src/ruby/yast/y2_exception.rb b/src/ruby/yast/y2_exception.rb new file mode 100644 index 00000000..f06f4418 --- /dev/null +++ b/src/ruby/yast/y2_exception.rb @@ -0,0 +1,15 @@ +require "yast" + +module Yast + # For passing exceptions through liby2 + class Y2ExceptionClass < Module + def main + @exception = {} + end + + publish variable: :exception, type: "map" + end + + Y2Exception = Y2ExceptionClass.new + Y2Exception.main +end