From 971615fb250dbabd4b65e4d1fc59514fb892d905 Mon Sep 17 00:00:00 2001 From: Duncan Mac-Vicar P Date: Fri, 30 Nov 2007 16:33:28 +0100 Subject: [PATCH] - fix builtins, scr - add builtin introspection - 0.3.1 --- CMakeLists.txt | 2 +- VERSION.cmake | 2 +- examples/ruby/scr.rb | 4 +- package/yast2-ruby-bindings.changes | 6 + src/ruby/YCP.cc | 237 +++++++++++++++------------- src/ruby/yast.rb | 120 +++++++++----- 6 files changed, 222 insertions(+), 149 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cde6c79..5108dfe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ PROJECT(yast2-ruby-bindings) -SET(PACKAGE "yast2-ruby-bindings") +SET(RPMNAME "yast2-ruby-bindings") SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O3 -Wall -Woverloaded-virtual" ) SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O3 -Wall" ) diff --git a/VERSION.cmake b/VERSION.cmake index 097bf49..b9741c4 100644 --- a/VERSION.cmake +++ b/VERSION.cmake @@ -1,3 +1,3 @@ SET(VERSION_MAJOR "0") SET(VERSION_MINOR "3") -SET(VERSION_PATCH "0") +SET(VERSION_PATCH "1") diff --git a/examples/ruby/scr.rb b/examples/ruby/scr.rb index dc027f7..2427e4e 100644 --- a/examples/ruby/scr.rb +++ b/examples/ruby/scr.rb @@ -1,7 +1,7 @@ require 'yast' +require 'ycp/scr' -m = YaST::Module.new("SCR") -modules = m.Read(".proc.modules") +modules = YCP::SCR::Read(".proc.modules") modules.each do | k, v | puts "#{k}:" v.each do | a, b | diff --git a/package/yast2-ruby-bindings.changes b/package/yast2-ruby-bindings.changes index c512e79..6334377 100644 --- a/package/yast2-ruby-bindings.changes +++ b/package/yast2-ruby-bindings.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Fri Nov 30 16:32:43 CET 2007 - dmacvicar@suse.de + +- fix SCR, builtin calls and add instrospection + for builtins + ------------------------------------------------------------------- Wed Sep 19 16:42:35 CEST 2007 - dmacvicar@suse.de diff --git a/src/ruby/YCP.cc b/src/ruby/YCP.cc index 0a1f3dd..48aa768 100644 --- a/src/ruby/YCP.cc +++ b/src/ruby/YCP.cc @@ -58,7 +58,6 @@ as published by the Free Software Foundation; either version Data_Get_Struct(obj, Y2Namespace, po) static VALUE rb_mYaST; -static VALUE rb_mY2ModuleProxy; static VALUE rb_mUi; static VALUE rb_mYCP; @@ -76,6 +75,9 @@ typedef VALUE (ruby_method)(...); Y2Component *owned_uic = 0; Y2Component *owned_wfmc = 0; +//Y2Component *owned_scr = 0; + +extern "C" { static Y2Namespace * @@ -85,7 +87,7 @@ getNs (const char * ns_name) Y2Namespace *ns = import.nameSpace(); if (ns == NULL) { - y2error ("Ruby call: Can't import namespace '%s'", ns_name); + y2error ("ruby call: Can't import namespace '%s'", ns_name); } else { @@ -108,6 +110,20 @@ void init_wfm() // } } +// void init_scr() +// { +// y2milestone("init_scr"); +// // if (Y2WFMComponent::instance () == 0) +// // { +// y2milestone("WFM init"); +// owned_scr = Y2ComponentBroker::createClient ("scr"); +// if (owned_scr == 0) +// { +// y2error ("Cannot create WFM component"); +// } +// // } +// } + static VALUE rb_init_ui( int argc, VALUE *argv, VALUE self ) { @@ -120,7 +136,7 @@ rb_init_ui( int argc, VALUE *argv, VALUE self ) } else if (argc != 0) { - y2error ("Zero or one arguments required (ui name, default %s", ui_name); + y2error ("zero or one arguments required (ui name, default %s", ui_name); return Qnil; } @@ -132,13 +148,13 @@ rb_init_ui( int argc, VALUE *argv, VALUE self ) c = Y2ComponentBroker::createServer (ui_name); if (c == 0) { - y2error ("Cannot create component %s", ui_name); + y2error ("can't create component %s", ui_name); return Qnil; } if (YUIComponent::uiComponent () == 0) { - y2error ("Component %s is not a UI", ui_name); + y2error ("component %s is not a UI", ui_name); return Qnil; } else @@ -155,59 +171,8 @@ rb_init_ui( int argc, VALUE *argv, VALUE self ) return Qnil; } -typedef struct brokerinfo -{ - Y2Component *component; - Y2Namespace *ns; -} -BrokerInfo; - -// mark for garbage collection -// NOT USED, ONLY WHEN USING DATA_WRAP_STRUCT -void -yast_module_mark( BrokerInfo *info ) -{} - -// dispose a namespace -// NOT USED, ONLY WHEN USING DATA_WRAP_STRUCT -void -yast_module_free( BrokerInfo *info ) -{ - //std::cout << "Deleting namespace." << std::endl; - //delete info; -} - -VALUE -yast_module_allocate( VALUE klass ) -{ - BrokerInfo *info = new BrokerInfo; - return Data_Wrap_Struct( klass, yast_module_mark, RB_FINALIZER(yast_module_free), info ); -} - -VALUE -yast_module_initialize( VALUE self, VALUE param_ns_name ) -{ - Check_Type(param_ns_name, T_STRING); - rb_iv_set(self, "@namespace_name", param_ns_name); - init_wfm(); - return self; -} - - -VALUE -yast_module_name( VALUE self ) -{ - return rb_iv_get(self, "@namespace_name"); -} - -VALUE -yast_module_methods( VALUE self ) -{ - return Qnil; -} - //forward declaration -YCPValue ycp_call_builtin ( const string &module_name, const string &func_name, int argc, VALUE *argv ); +YCPValue _call_ycp_builtin ( const string &module_name, const string &func_name, int argc, VALUE *argv ); /** * looks a component for a namespace @@ -220,8 +185,8 @@ ycp_module_lookup_namespace_component(VALUE self, VALUE name) c = Y2ComponentBroker::getNamespaceComponent(RSTRING(name)->ptr); if (c == NULL) { - y2internal("No component can provide namespace %s\n", RSTRING (name)->ptr); - rb_raise( rb_eRuntimeError, "No YaST component can provide namespace %s\n", RSTRING (name)->ptr); + y2internal("no component can provide namespace %s\n", RSTRING (name)->ptr); + rb_raise( rb_eRuntimeError, "no YaST component can provide namespace %s\n", RSTRING (name)->ptr); } y2internal("component name %s\n", c->name().c_str()); return Qtrue; @@ -237,12 +202,12 @@ ycp_module_import_namespace( VALUE self, VALUE namespace_name) Y2Namespace *ns = getNs( RSTRING (namespace_name)->ptr); if (ns == NULL) { - rb_raise( rb_eNameError, "Component cannot import namespace '%s'", RSTRING (namespace_name)->ptr); + rb_raise( rb_eNameError, "component cannot import namespace '%s'", RSTRING (namespace_name)->ptr); return Qnil; } else { - y2internal("Namespace created from %s\n", ns->filename().c_str()); + y2internal("namespace created from %s\n", ns->filename().c_str()); } return Qtrue; } @@ -258,18 +223,18 @@ ycp_module_import( VALUE self, VALUE name) * iterates all symbols in a namespace and yields the * symbol name and category */ -VALUE +static VALUE ycp_module_each_symbol(VALUE self, VALUE namespace_name) { Y2Namespace *ns = getNs( RSTRING (namespace_name)->ptr); if (ns == NULL) { - rb_raise( rb_eRuntimeError, "Error getting namespace '%s'", RSTRING (namespace_name)->ptr ); + rb_raise( rb_eRuntimeError, "error getting namespace '%s'", RSTRING (namespace_name)->ptr ); return Qnil; } else { - y2internal("Got namespace from %s\n", ns->filename().c_str()); + y2internal("got namespace from %s\n", ns->filename().c_str()); } for (unsigned int i=0; i < ns->symbolCount(); ++i) @@ -283,13 +248,77 @@ ycp_module_each_symbol(VALUE self, VALUE namespace_name) return Qnil; } +/** + * helper method + */ +static bool _yield_symbol_entry(const SymbolEntry & s) +{ + VALUE arr = rb_ary_new(); + rb_ary_push(arr, rb_str_new2(s.name())); + rb_ary_push(arr, ID2SYM(rb_intern(s.catString().c_str()))); + rb_yield(arr); + return true; +} + +/** + * helper for each_builtin_symbol + */ +static const SymbolEntry * __symbol = 0L; +static string __name; + +static +bool __find_symbol(const SymbolEntry & s) +{ + if (s.name() == __name) + { + __symbol = &s; + return false; + } + return true; +} + +/** + * iterates all symbols in a namespace and yields the + * symbol name and category + */ +static VALUE +ycp_module_each_builtin_symbol(VALUE self, VALUE name) +{ + extern StaticDeclaration static_declarations; + __name = RSTRING(name)->ptr; + static_declarations.symbolTable()->forEach(__find_symbol); + + const SymbolEntry *se = __symbol; + if (se == NULL) + { + y2error ("no such builtin '%s'", RSTRING(name)->ptr); + rb_raise( rb_eRuntimeError, "no YCP builtin %s\n", RSTRING(name)->ptr); + } + + // convert to a YSymbol to access child symbols + const YSymbolEntry *ys = dynamic_cast(se); + if ( ys ) + { + if ( ys->table() ) ys->table()->forEach(_yield_symbol_entry); + } + return Qnil; +} + +static VALUE +ycp_module_each_builtin(VALUE self) +{ + extern StaticDeclaration static_declarations; + static_declarations.symbolTable()->forEach(_yield_symbol_entry); + return Qnil; +} + /** * Forwards a ruby call to the namespace * First argument is the namespace * then function name and arguments */ -VALUE -ycp_module_forward_call(int argc, VALUE *argv, VALUE self) +static VALUE +ycp_module_call_ycp_function(int argc, VALUE *argv, VALUE self) { y2internal("Dynamic Proxy: [%d] params\n", argc); VALUE symbol = argv[1]; @@ -307,18 +336,6 @@ ycp_module_forward_call(int argc, VALUE *argv, VALUE self) // get the name of the module //VALUE namespace_name = rb_funcall(self, rb_intern("name"), 0); - - - // SCR - // this is a hack before the builtin namespaces get a uniform interface: - if (! strcmp (RSTRING (namespace_name)->ptr, "SCR")) - { - y2internal("Dynamic Proxy: [%s::%s] is a call to SCR\n", RSTRING(namespace_name)->ptr, RSTRING(symbol_str)->ptr); - YCPValue res; - res = ycp_call_builtin( RSTRING(namespace_name)->ptr, RSTRING(symbol_str)->ptr, argc, argv); - return ycpvalue_2_rbvalue(res); - //return Qnil; - } ycp_module_lookup_namespace_component(self, namespace_name); @@ -359,8 +376,8 @@ ycp_module_forward_call(int argc, VALUE *argv, VALUE self) if (call == NULL) { - y2internal ("Cannot create function call %s\n", RSTRING(symbol_str)->ptr); - rb_raise( rb_eRuntimeError, "Can't create call to %s::%s", RSTRING (namespace_name)->ptr, RSTRING(symbol_str)->ptr); + y2internal ("cannot create function call %s\n", RSTRING(symbol_str)->ptr); + rb_raise( rb_eRuntimeError, "can't create call to %s::%s", RSTRING (namespace_name)->ptr, RSTRING(symbol_str)->ptr); } // add the parameters @@ -373,39 +390,28 @@ ycp_module_forward_call(int argc, VALUE *argv, VALUE self) YCPValue res = call->evaluateCall (); delete call; - y2internal ("Call succeded\n"); + y2internal ("call succeded\n"); //y2internal ("Result: %i\n", res->asList()->size()); return ycpvalue_2_rbvalue(res); } return Qnil; } -YCPValue ycp_call_builtin ( const string &module_name, const string &func_name, int argc, VALUE *argv ) +YCPValue _call_ycp_builtin ( const string &module_name, const string &func_name, int argc, VALUE *argv ) { // access directly the statically declared builtins extern StaticDeclaration static_declarations; + string qualified_name_s = module_name + "::" + func_name; const char *qualified_name = qualified_name_s.c_str (); - y2milestone("Qualified name '%s'", qualified_name); - /* - this does not work across namespaces - TableEntry *bi_te = static_declarations.symbolTable ()->find (qualified_name); - if (bi_te == NULL) - { - y2error ("No such builtin %s",qualified_name); - return YCPNull (); - } + y2milestone("qualified name '%s', %d args", qualified_name, argc); - SymbolEntry *bi_se = bi_te->sentry (); - assert (bi_se != NULL); - assert (bi_se->isBuiltin ()); - declaration_t bi_dt = bi_se->declaration (); - */ declaration_t *bi_dt = static_declarations.findDeclaration (qualified_name); if (bi_dt == NULL) { - y2error ("No such builtin '%s'", qualified_name); + y2error ("no such builtin '%s'", qualified_name); + rb_raise( rb_eRuntimeError, "no YCP builtin %s\n", RSTRING(qualified_name)->ptr); return YCPNull (); } y2milestone("builtin '%s' found.", module_name.c_str()); @@ -417,26 +423,22 @@ YCPValue ycp_call_builtin ( const string &module_name, const string &func_name, // we would like to know the destination type so that we could // convert eg a Ruby scalar to a YCP symbol, but because the // builtins may be overloaded, let's say we want Any - // maybe a special exceptional hack to make Path for the 1st argument? - // go through the actual parameters int j; - for (j = 1; j < argc; ++j) + for (j = 0; j < argc; ++j) { - y2milestone("builtin param '%d'", j-1); // convert the value according to the expected type: constTypePtr param_tp = (j == 0)? Type::Path : Type::Any; - y2milestone("builtin param '%d' 1", j-1); // convert the first argument to a path YCPValue param_v; - if ( j == 1 ) + // HACK SCR path conversion + if ( (j == 0) && (module_name == "SCR") ) param_v = rbvalue_2_ycppath(argv[j]); else param_v = rbvalue_2_ycpvalue(argv[j] /*, param_tp */); - y2milestone("builtin param '%d' 2", j-1); if (param_v.isNull ()) { // an error has already been reported, now refine it. @@ -490,8 +492,21 @@ YCPValue ycp_call_builtin ( const string &module_name, const string &func_name, return ret_yv; } +VALUE +ycp_module_call_ycp_builtin( int argc, VALUE *argv, VALUE self ) +{ + VALUE symbol = argv[1]; + VALUE namespace_name = argv[0]; + // the func name (1st argument, is a symbol + // lets convert it to string + VALUE symbol_str = rb_funcall(symbol, rb_intern("to_s"), 0); + y2internal("builtin proxy: [%s::%s] is a builtin call with %d params\n", RSTRING(namespace_name)->ptr, RSTRING(symbol_str)->ptr, argc); + YCPValue res; + res = _call_ycp_builtin( RSTRING(namespace_name)->ptr, RSTRING(symbol_str)->ptr, argc-2, argv+2); + return ycpvalue_2_rbvalue(res); +} //y2_logger_helper //y2_logger (level, comp, file, line, function, "%s", message); @@ -514,16 +529,19 @@ rb_y2_logger( int argc, VALUE *argv, VALUE self ) return Qnil; } +} //extern C + extern "C" { void Init_yastx() { YCPPathSearch::initialize (); - + init_wfm(); + for ( list::const_iterator it = YCPPathSearch::searchListBegin (YCPPathSearch::Module); it != YCPPathSearch::searchListEnd (YCPPathSearch::Module) ; ++it ) { - y2internal("%s\n", (*it).c_str() ); + y2internal("search path %s\n", (*it).c_str() ); } rb_mYaST = rb_define_module("YaST"); @@ -531,8 +549,12 @@ extern "C" //rb_mYCP = rb_define_module_under(rb_mYaST, "YCP"); rb_mYCP = rb_define_module("YCP"); rb_define_singleton_method( rb_mYCP, "import", RB_METHOD(ycp_module_import), 1); - rb_define_singleton_method( rb_mYCP, "forward_call", RB_METHOD(ycp_module_forward_call), -1); + rb_define_singleton_method( rb_mYCP, "call_ycp_function", RB_METHOD(ycp_module_call_ycp_function), -1); + rb_define_singleton_method( rb_mYCP, "call_ycp_builtin", RB_METHOD(ycp_module_call_ycp_builtin), -1); + rb_define_singleton_method( rb_mYCP, "each_symbol", RB_METHOD(ycp_module_each_symbol), 1); + rb_define_singleton_method( rb_mYCP, "each_builtin_symbol", RB_METHOD(ycp_module_each_builtin_symbol), 1); + rb_define_singleton_method( rb_mYCP, "each_builtin", RB_METHOD(ycp_module_each_builtin), 0); rb_mUi = rb_define_module_under(rb_mYCP, "Ui"); rb_define_singleton_method( rb_mUi, "init", RB_METHOD(rb_init_ui), -1); @@ -544,3 +566,4 @@ extern "C" ryast_term_init(rb_mYaST); } } + diff --git a/src/ruby/yast.rb b/src/ruby/yast.rb index 444306c..8e9ff23 100644 --- a/src/ruby/yast.rb +++ b/src/ruby/yast.rb @@ -23,20 +23,82 @@ ENV['LD_LIBRARY_PATH'] = "/usr/lib/YaST2/plugin" # Load the native part (.so) require 'yastx' +module YaST + def y2_logger_helper(*args) + level = args.shift + + caller[0] =~ /(.+):(\d+):in `([^']+)'/ + y2_logger(level,"Ruby",$1,$2.to_i,"",args[0]) + end + + def y2debug(*args) + y2_logger_helper(0, args) + end + + def y2milestone(*args) + y2_logger_helper(1, args) + end + + def y2warning(*args) + y2_logger_helper(2, args) + end + + def y2error(*args) + y2_logger_helper(3, args) + end + + def y2security(*args) + y2_logger_helper(4, args) + end + + def y2internal(*args) + y2_logger_helper(5, args) + end +end # module YaST + module YCP - def self.method_missing(id, *args) - puts "stop" + + # inserts a builtin in the + # ycp module + def self.import_builtin(name) + YCP::each_builtin do |bi, cat| + if name == bi + if cat == :namespace + m = Module.new + YCP::each_builtin_symbol(bi) do |bs, scat| + if scat == :builtin + m.module_eval <<-"END" + def self.#{bs.downcase.to_s}(*args) + return YCP::call_ycp_builtin("SCR", "#{bs.to_s}", *args) + end + END + end + end # each builtin symbol + YCP.const_set(bi.to_s, m) + return + else + raise "builtin #{bi} can't be imported (not namespace)" + end # if namespace + end + end # each builtin + raise "can't import builtin '#{bi}'" + end + + # initialize builtins and add them to + # the ycp module + def self.init_builtins + end def self.add_ycp_module(mname) - puts "import #{mname}" + #y2internal("tryng to add import #{mname}") YCP::import(mname) m = Module.new YCP::each_symbol(mname) do |sname,stype| if (stype == :function) and !sname.empty? m.module_eval <<-"END" def self.#{sname}(*args) - return YCP::forward_call("#{mname}", :#{sname}, *args) + return YCP::call_ycp_function("#{mname}", :#{sname}, *args) end END end # if function @@ -45,12 +107,27 @@ module YCP end end +YCP::init_builtins + module Kernel alias require_ require def require(name) if name =~ /^ycp\/(.+)$/ ycpns = $1 - YCP::add_ycp_module(ycpns.capitalize) + + YCP::each_builtin do |bi, cat| + if bi.downcase == ycpns.downcase + YCP::import_builtin(bi) + return + end + end + + begin + YCP::add_ycp_module(ycpns.upcase) + rescue RuntimeError => e + puts e + YCP::add_ycp_module(ycpns.capitalize) + end return true end return require_(name) @@ -103,7 +180,6 @@ module YCP end module YaST - class TermBuilder # blank slate instance_methods.each { |m| undef_method m unless (m =~ /^__|instance_eval$/)} @@ -141,36 +217,4 @@ module YaST end end - - def y2_logger_helper(*args) - level = args.shift - - caller[0] =~ /(.+):(\d+):in `([^']+)'/ - y2_logger(level,"Ruby",$1,$2.to_i,"",args[0]) - end - - def y2debug(*args) - y2_logger_helper(0, args) - end - - def y2milestone(*args) - y2_logger_helper(1, args) - end - - def y2warning(*args) - y2_logger_helper(2, args) - end - - def y2error(*args) - y2_logger_helper(3, args) - end - - def y2security(*args) - y2_logger_helper(4, args) - end - - def y2internal(*args) - y2_logger_helper(5, args) - end - end # module YaST \ No newline at end of file -- 2.39.2