X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2FConfig%2FConfig_ModuleReader.cpp;h=5c85bc2a9107f7839e9821cffc14da4984923c99;hb=77ce6d35ac8d2f0fdaecb4f23e0870bf74e36103;hp=6acffa268d3e46e2ac66c57df2602a93688c271f;hpb=8b78f08d1e6b2e6d57aa73b091579094e4a020d4;p=modules%2Fshaper.git diff --git a/src/Config/Config_ModuleReader.cpp b/src/Config/Config_ModuleReader.cpp index 6acffa268..5c85bc2a9 100644 --- a/src/Config/Config_ModuleReader.cpp +++ b/src/Config/Config_ModuleReader.cpp @@ -1,23 +1,37 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D +// Copyright (C) 2014-2024 CEA, EDF +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// -/* - * Config_ModuleReader.cpp - * - * Created on: Mar 20, 2014 - * Author: sbh - */ +#include #include #include #include #include -#include +#include +#include #include #include // Have to be included before std headers #include +#include //Necessary for cerr #include @@ -48,6 +62,21 @@ const std::map& Config_ModuleReader::featuresInFiles() return myFeaturesInFiles; } +const std::map& Config_ModuleReader::proprietaryFeatures() const +{ + return myProprietaryFeatures; +} + +const std::set& Config_ModuleReader::proprietaryPlugins() const +{ + return myProprietaryPlugins; +} + +const std::set& Config_ModuleReader::modulePluginFiles() const +{ + return myPluginFiles; +} + /*! * Get module name from plugins.xml * (property "module") @@ -58,20 +87,73 @@ std::string Config_ModuleReader::getModuleName() return getProperty(aRoot, PLUGINS_MODULE); } + +void Config_ModuleReader::addFeature(const std::string& theFeatureName, + const std::string& thePluginConfig) +{ + if (myProprietaryFeatures.count(theFeatureName)) { + myProprietaryFeatures.erase(theFeatureName); + } + + if (myFeaturesInFiles.count(theFeatureName)) { + std::string anErrorMsg = "Can not register feature '%1' in plugin '%2'." + " There is a feature with the same ID."; + Events_InfoMessage("Config_ModuleReader", anErrorMsg) + .arg(theFeatureName).arg(thePluginConfig).send(); + return; + } + + myFeaturesInFiles[theFeatureName] = thePluginConfig; +} + +void Config_ModuleReader::addFeatureRequireLicense(const std::string& theFeatureName, + const std::string& thePluginConfig) +{ + if (myFeaturesInFiles.count(theFeatureName) || + myProprietaryFeatures.count(theFeatureName)) { + std::string anErrorMsg = "Can not register feature '%1' in plugin '%2'." + " There is a feature with the same ID."; + Events_InfoMessage("Config_ModuleReader", anErrorMsg) + .arg(theFeatureName).arg(thePluginConfig).send(); + return; + } + + myProprietaryFeatures[theFeatureName] = thePluginConfig; +} + void Config_ModuleReader::processNode(xmlNodePtr theNode) { if (isNode(theNode, NODE_PLUGIN, NULL)) { if (!hasRequiredModules(theNode)) return; std::string aPluginConf = getProperty(theNode, PLUGIN_CONFIG); + if (!aPluginConf.empty()) + myPluginFiles.insert(aPluginConf); std::string aPluginLibrary = getProperty(theNode, PLUGIN_LIBRARY); std::string aPluginScript = getProperty(theNode, PLUGIN_SCRIPT); std::string aPluginName = addPlugin(aPluginLibrary, aPluginScript, aPluginConf); + std::string aPluginDocSection = getProperty(theNode, PLUGIN_DOCSECTION); + std::string aUsesPlugin = getProperty(theNode, PLUGIN_USES); + if (!aUsesPlugin.empty()) { // send information about the plugin dependencies + std::shared_ptr aMess(new Config_PluginMessage( + Events_Loop::loop()->eventByName(Config_PluginMessage::EVENT_ID()), aPluginName)); + aMess->setUses(aUsesPlugin); + Events_Loop::loop()->send(aMess); + } + + std::string aLicense = getProperty(theNode, PLUGIN_LICENSE); + std::transform(aLicense.begin(), aLicense.end(), aLicense.begin(), ::tolower); + bool isLicensed = aLicense == "true"; + if (isLicensed) + myProprietaryPlugins.insert(aPluginName); - std::list aFeatures = importPlugin(aPluginName, aPluginConf); + std::list aFeatures = importPlugin(aPluginName, aPluginConf, aPluginDocSection); std::list::iterator it = aFeatures.begin(); for (; it != aFeatures.end(); it++) { - myFeaturesInFiles[*it] = aPluginConf; + if (isLicensed) + addFeatureRequireLicense(*it, aPluginConf); + else + addFeature(*it, aPluginConf); } } } @@ -94,7 +176,8 @@ bool Config_ModuleReader::hasRequiredModules(xmlNodePtr theNode) const } std::list Config_ModuleReader::importPlugin(const std::string& thePluginLibrary, - const std::string& thePluginXmlConf) + const std::string& thePluginXmlConf, + const std::string& thePluginDocSection) { if (thePluginXmlConf.empty()) { //probably a third party library loadLibrary(thePluginLibrary); @@ -103,6 +186,7 @@ std::list Config_ModuleReader::importPlugin(const std::string& theP Config_FeatureReader aReader = Config_FeatureReader(thePluginXmlConf, thePluginLibrary, + thePluginDocSection, myEventGenerated); aReader.readAll(); return aReader.features(); @@ -132,6 +216,12 @@ std::string Config_ModuleReader::addPlugin(const std::string& aPluginLibrary, void Config_ModuleReader::loadPlugin(const std::string& thePluginName) { + // informs model that plugin loading is started + static const Events_ID kEVENT_ID = + Events_Loop::loop()->eventByName(Config_PluginMessage::EVENT_ID()); + std::shared_ptr aMess(new Config_PluginMessage(kEVENT_ID, thePluginName)); + Events_Loop::loop()->send(aMess); + PluginType aType = Config_ModuleReader::Binary; if(myPluginTypes.find(thePluginName) != myPluginTypes.end()) { aType = myPluginTypes.at(thePluginName); @@ -148,30 +238,150 @@ void Config_ModuleReader::loadPlugin(const std::string& thePluginName) } } -void Config_ModuleReader::loadScript(const std::string& theFileName) +namespace +{ + // Handle Python exception + // Reuse code from KERNEL module + typedef struct + { + PyObject_HEAD + int softspace; + std::string *out; + } PyStdOut; + + static void + PyStdOut_dealloc(PyStdOut *self) + { + PyObject_Del(self); + } + + static PyObject* + PyStdOut_write(PyStdOut* self, PyObject* args) + { + char *c; + if (!PyArg_ParseTuple(args, "s", &c)) + return NULL; + + *(self->out) = *(self->out) + c; + + Py_INCREF(Py_None); + return Py_None; + } + + static PyMethodDef PyStdOut_methods[] = + { + {"write", (PyCFunction)PyStdOut_write, METH_VARARGS, + PyDoc_STR("write(string) -> None")}, + {0, 0, 0, 0} /* sentinel */ + }; + + static PyMemberDef PyStdOut_memberlist[] = + { + {(char*)"softspace", T_INT, offsetof(PyStdOut, softspace), 0, + (char*)"flag indicating that a space needs to be printed; used by print"}, + {0, 0, 0, 0, 0} /* sentinel */ + }; + + static PyTypeObject PyStdOut_Type = + { + /* The ob_type field must be initialized in the module init function + * to be portable to Windows without using C++. */ + PyVarObject_HEAD_INIT(NULL, 0) + /* 0, */ /*ob_size*/ + "PyOut", /*tp_name*/ + sizeof(PyStdOut), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)PyStdOut_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + PyObject_GenericGetAttr, /*tp_getattro*/ + /* softspace is writable: we must supply tp_setattro */ + PyObject_GenericSetAttr, /* tp_setattro */ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + PyStdOut_methods, /*tp_methods*/ + PyStdOut_memberlist, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + 0, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0, /*tp_version_tag*/ + 0, /*tp_finalize*/ + }; + + PyObject* newPyStdOut(std::string& out) + { + PyStdOut* self = PyObject_New(PyStdOut, &PyStdOut_Type); + if (self) { + self->softspace = 0; + self->out=&out; + } + return (PyObject*)self; + } + + std::string parseException() + { + std::string error; + if (PyErr_Occurred()) + { + PyObject* new_stderr = newPyStdOut(error); + PyObject* old_stderr = PySys_GetObject((char*)"stderr"); + Py_INCREF(old_stderr); + PySys_SetObject((char*)"stderr", new_stderr); + PyErr_Print(); + PySys_SetObject((char*)"stderr", old_stderr); + Py_DECREF(new_stderr); + } + return error; + } +} + +void Config_ModuleReader::loadScript(const std::string& theFileName, bool theSendErr) { - /* aquire python thread */ + /* acquire python thread */ PyGILState_STATE gstate = PyGILState_Ensure(); PyObject* module = PyImport_ImportModule(theFileName.c_str()); if (!module) { - std::string anErrorMsg = "An error occured while importing " + theFileName; - //Get detailed error message: + std::string anErrorMsg = "An error occurred while importing " + theFileName; + // Get detailed error message (including traceback) if (PyErr_Occurred()) { - PyObject *pstr, *ptype, *pvalue, *ptraceback; - PyErr_Fetch(&ptype, &pvalue, &ptraceback); - PyErr_NormalizeException(&ptype, &pvalue, &ptraceback); - pstr = PyObject_Str(pvalue); - std::string aPyError = std::string(PyString_AsString(pstr)); - if (!aPyError.empty()) { + std::string aPyError = parseException(); + if (!aPyError.empty()) anErrorMsg += ":\n" + aPyError; - } - Py_XDECREF(pstr); - Py_XDECREF(ptype); - Py_XDECREF(pvalue); - Py_XDECREF(ptraceback); } - Events_Error::send(anErrorMsg); + if (theSendErr) + Events_InfoMessage("Config_ModuleReader", anErrorMsg).send(); } /* release python thread */ @@ -184,17 +394,31 @@ void Config_ModuleReader::loadLibrary(const std::string& theLibName) if (aFileName.empty()) return; -#ifdef WIN32 - HINSTANCE aModLib = ::LoadLibrary(aFileName.c_str()); -#else + #ifdef WIN32 + HINSTANCE aModLib = ::LoadLibraryA(aFileName.c_str()); + #else void* aModLib = dlopen( aFileName.c_str(), RTLD_LAZY | RTLD_GLOBAL ); -#endif + #endif if(!aModLib && theLibName != "DFBrowser") { // don't show error for internal debugging tool +// LCOV_EXCL_START std::string anErrorMsg = "Failed to load " + aFileName; - #ifndef WIN32 + #ifdef WIN32 + DWORD dwLastError = ::GetLastError(); + LPSTR messageBuffer = NULL; + size_t size = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dwLastError, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&messageBuffer, 0, NULL); + anErrorMsg += ": " + std::string(messageBuffer, size); + #else anErrorMsg += ": " + std::string(dlerror()); #endif - Events_Error::send(anErrorMsg); + std::cerr << anErrorMsg << std::endl; + Events_InfoMessage("Config_ModuleReader", anErrorMsg).send(); +// LCOV_EXCL_STOP } }