Commit 06a1fdf8 authored by Victor Yacovlev's avatar Victor Yacovlev

Initial implementation without separate spec files

parent 3e88d015
......@@ -10,6 +10,6 @@ endforeach(PACKAGE)
add_subdirectory(kumir2-libs)
add_subdirectory(plugins)
add_subdirectory(actors)
#add_subdirectory(actors)
add_subdirectory(app)
add_subdirectory(tools)
......@@ -161,13 +161,13 @@ public:
QString error;
qDebug() << "Initialized plugin manager";
#ifdef CONFIGURATION_TEMPLATE
const QString defaultTemplate = CONFIGURATION_TEMPLATE;
const QByteArray defaultTemplate = CONFIGURATION_TEMPLATE;
#else
#error No default configuration passed to GCC
#endif
QString templ = defaultTemplate;
QByteArray templ = defaultTemplate;
for (int i=1; i<arguments.size(); i++) {
QString arg = arguments[i];
QByteArray arg = arguments[i].toLatin1();
if (arg.startsWith("[") && arg.endsWith("]")) {
templ = arg.mid(1, arg.length()-2);
}
......
......@@ -14,7 +14,6 @@ set(MOC_HEADERS
set(SOURCES
logger.cpp
kplugin.cpp
pluginspec.cpp
pluginmanager.cpp
pluginmanager_impl.cpp
settings.cpp
......
......@@ -9,28 +9,29 @@ KPlugin::KPlugin()
}
QList<KPlugin*> KPlugin::loadedPlugins(const QString &pattern)
QList<KPlugin*> KPlugin::loadedPlugins(const QByteArray &pattern)
{
return PluginManager::instance()->loadedPlugins(pattern);
}
QList<const KPlugin*> KPlugin::loadedPlugins(const QString &pattern) const
QList<const KPlugin*> KPlugin::loadedPlugins(const QByteArray &pattern) const
{
const QList<const KPlugin*> result = PluginManager::instance()->loadedConstPlugins(pattern);
return result;
}
PluginSpec KPlugin::pluginSpec() const
const PluginSpec & KPlugin::pluginSpec() const
{
return PluginManager::instance()->specByObject(this);
return _pluginSpec;
}
KPlugin::State KPlugin::state() const
{
return PluginManager::instance()->stateByObject(this);
return _state;
}
KPlugin * KPlugin::myDependency(const QString &name) const
KPlugin * KPlugin::myDependency(const QByteArray &name) const
{
return PluginManager::instance()->dependentPlugin(name, this);
}
......@@ -58,24 +59,21 @@ QByteArray KPlugin::pluginName() const
void KPlugin::initialize(const QString & resourcesRootPath)
{
settings_ = SettingsPtr(new Settings(QString::fromLatin1(pluginName())));
resourcesDir_ = resourcesRootPath;
_settings = SettingsPtr(new Settings(QString::fromLatin1(pluginName())));
_resourcesDir = resourcesRootPath;
initialize(QStringList(), CommandLine());
}
SettingsPtr KPlugin::mySettings() const
{
if (settings_)
return settings_;
else
return PluginManager::instance()->settingsByObject(this);
return _settings;
}
QDir KPlugin::myResourcesDir() const
{
QString thisModulePath;
if (PluginManager::instance()->sharePath().isEmpty()) {
thisModulePath = resourcesDir_;
thisModulePath = _resourcesDir;
}
else {
const QString sharePath = PluginManager::instance()->sharePath();
......
......@@ -32,7 +32,7 @@ public:
virtual QByteArray pluginName() const;
enum State { Disabled = 0x00, Loaded=0x01, Initialized=0x02, Started=0x03, Stopped=0x04 };
KPlugin();
PluginSpec pluginSpec() const;
const PluginSpec & pluginSpec() const;
State state() const;
inline virtual bool isGuiRequired() const { return pluginSpec().gui; } // Can be overridden in special cases
......@@ -70,15 +70,19 @@ public:
inline virtual void start() {}
inline virtual void stop() {}
virtual void updateSettings(const QStringList & keys) = 0;
KPlugin * myDependency(const QString & name) const;
KPlugin * myDependency(const QByteArray & name) const;
QList<KPlugin*> loadedPlugins(const QString &pattern = "*");
QList<const KPlugin*> loadedPlugins(const QString &pattern = "*") const;
QList<KPlugin*> loadedPlugins(const QByteArray &pattern = "*");
QList<const KPlugin*> loadedPlugins(const QByteArray &pattern = "*") const;
private:
SettingsPtr settings_;
QString resourcesDir_;
protected:
virtual void createPluginSpec() = 0;
PluginSpec _pluginSpec;
private:
SettingsPtr _settings;
QString _resourcesDir;
State _state;
};
} // namespace ExtensionSystem
......
......@@ -55,13 +55,7 @@ PluginManager::~PluginManager()
bool PluginManager::isPluginLoaded(const QByteArray &name) const
{
for (int i=0; i<pImpl_->specs.size(); i++) {
const PluginSpec & spec = pImpl_->specs.at(i);
if (spec.name.toLatin1() == name) {
return true;
}
}
return false;
return pImpl_->isPluginLoaded(name);
}
void PluginManager::destroy()
......@@ -119,19 +113,13 @@ QString PluginManager::sharePath() const
QString PluginManager::loadPluginsByTemplate(const QString &templ)
QString PluginManager::loadPluginsByTemplate(const QByteArray &templ)
{
QList<PluginRequest> requests;
QStringList names;
QList<PluginSpec> requests;
QString error = "";
error = pImpl_->parsePluginsRequest(templ, requests, names);
error = pImpl_->parsePluginsRequest(templ, requests);
if (!error.isEmpty())
return error;
//QScriptEngine engine;
//engine.evaluate("var data = null;\n");
//error = d->loadSpecs(names, &engine);
qDebug() << "Loading plugin spec files for: " << names;
error = pImpl_->loadSpecs(names);
if (!error.isEmpty())
return error;
......@@ -139,136 +127,91 @@ QString PluginManager::loadPluginsByTemplate(const QString &templ)
#ifdef Q_OS_UNIX
console = getenv("DISPLAY")==0;
#endif
// console = true; // !!! was here for debug purposes
// if (console) {
// // Remove GUI plugins
// QList<PluginSpec>::iterator it;
// for (it=pImpl_->specs.begin(); it!=pImpl_->specs.end(); ) {
// PluginSpec spec = (*it);
// bool forceLoad = false;
// if (spec.name.startsWith("Actor") && templ.contains("(tablesOnly)")) {
// forceLoad = true;
// }
// if (spec.gui && !forceLoad) {
// names.removeAll(spec.name);
// QList<PluginRequest>::iterator rit;
// for (rit=requests.begin(); rit!=requests.end(); ) {
// PluginRequest r = *(rit);
// if (r.name==spec.name) {
// rit = requests.erase(rit);
// }
// else {
// rit ++;
// }
// }
// it = pImpl_->specs.erase(it);
// }
// else {
// it++;
// }
// }
// }
// orderedList will contain names in order of load and initialization
QStringList orderedList;
// make dependencies for entry point plugin first
qDebug() << "Reordering plugin load order and building dependencies...";
error = pImpl_->makeDependencies(pImpl_->mainPluginName,orderedList);
if (!error.isEmpty())
return error;
// make dependencies for other requests
for (int i=0; i<requests.size(); i++) {
error = pImpl_->makeDependencies(requests[i].name,orderedList);
if (!error.isEmpty())
Q_FOREACH(PluginSpec spec, requests) {
error = pImpl_->loadPlugin(spec, requests);
if (!error.isEmpty()) {
return error;
}
}
error = pImpl_->reorderSpecsAndCreateStates(orderedList);
if (!error.isEmpty())
return error;
qDebug() << "New plugin load ordered list: " << orderedList;
qDebug() << "Begin loading plugins";
error = pImpl_->loadPlugins();
if (!error.isEmpty())
return error;
qDebug() << "Done loading plugins";
pImpl_->requests = requests;
return "";
}
QString PluginManager::loadExtraModule(const std::string &canonicalFileName)
{
QString moduleName = QString::fromStdString(canonicalFileName);
if ( moduleName.length()>0 )
moduleName[0] = moduleName[0].toUpper();
QString libraryFileName = moduleName.replace(" ", "");
#if defined(Q_OS_WIN32)
libraryFileName += ".dll";
#elif defined(Q_OS_MACX)
libraryFileName = "lib"+libraryFileName+".dylib";
#else
libraryFileName = "lib"+libraryFileName+".so";
#endif
QString fullPath;
QString check;
check = pImpl_->path + "/" + libraryFileName;
if (QFile::exists(check)) {
fullPath = check;
}
if (fullPath.isEmpty()) {
check = QDir::currentPath()+"/"+libraryFileName;
if (QFile::exists(check)) {
fullPath = check;
}
}
return "Not implemented yet";
// QString moduleName = QString::fromStdString(canonicalFileName);
// if ( moduleName.length()>0 )
// moduleName[0] = moduleName[0].toUpper();
// QString libraryFileName = moduleName.replace(" ", "");
//#if defined(Q_OS_WIN32)
// libraryFileName += ".dll";
//#elif defined(Q_OS_MACX)
// libraryFileName = "lib"+libraryFileName+".dylib";
//#else
// libraryFileName = "lib"+libraryFileName+".so";
//#endif
// QString fullPath;
// QString check;
// check = pImpl_->path + "/" + libraryFileName;
// if (QFile::exists(check)) {
// fullPath = check;
// }
// if (fullPath.isEmpty()) {
// check = QDir::currentPath()+"/"+libraryFileName;
// if (QFile::exists(check)) {
// fullPath = check;
// }
// }
if (fullPath.isEmpty()) {
const QString errorMessage = tr("Can't load module %1: file not found")
.arg(libraryFileName);
return errorMessage;
}
// if (fullPath.isEmpty()) {
// const QString errorMessage = tr("Can't load module %1: file not found")
// .arg(libraryFileName);
// return errorMessage;
// }
QPluginLoader loader(fullPath);
// QPluginLoader loader(fullPath);
if (!loader.load()) {
return QString("Can't load module %1: %2")
.arg(libraryFileName)
.arg(loader.errorString());
}
KPlugin * plugin = qobject_cast<KPlugin*>(loader.instance());
if (!plugin) {
return QString("Plugin is not valid (does not implement interface KPlugin)");
loader.unload();
}
pImpl_->objects.push_back(plugin);
pImpl_->states.push_back(KPlugin::Loaded);
PluginSpec spec;
spec.name = QString::fromStdString(canonicalFileName);
spec.libraryFileName = libraryFileName;
spec.gui = plugin->isGuiRequired();
pImpl_->specs.push_back(spec);
Settings * sett = new Settings(moduleName);
sett->changeWorkingDirectory(pImpl_->settingsWorkspacePath);
pImpl_->settings.push_back(SettingsPtr(sett));
plugin->updateSettings(QStringList());
CommandLine runtimeParameters;
if (!pImpl_->extractRuntimeParametersForPlugin(plugin, runtimeParameters)) {
QString error = tr("The following command line parameters required, but not set:\n");
for (int i=0; i<runtimeParameters.data_.size(); i++) {
const CommandLineParameter & param = runtimeParameters.data_[i];
if (param.shortDescription_.length() > 0) {
if (!param.isValid() && plugin==pImpl_->objects.last())
error += " " + param.toHelpLine() + "\n";
}
else if (!param.isValid()) {
error += " " + param.toHelpLine() + "\n";
}
}
return error;
}
QString result = plugin->initialize(QStringList(), runtimeParameters);
pImpl_->states.last() = KPlugin::Initialized;
return result;
// if (!loader.load()) {
// return QString("Can't load module %1: %2")
// .arg(libraryFileName)
// .arg(loader.errorString());
// }
// KPlugin * plugin = qobject_cast<KPlugin*>(loader.instance());
// if (!plugin) {
// return QString("Plugin is not valid (does not implement interface KPlugin)");
// loader.unload();
// }
// pImpl_->objects.push_back(plugin);
// pImpl_->states.push_back(KPlugin::Loaded);
// PluginSpec spec;
// spec.name = QString::fromStdString(canonicalFileName);
// spec.libraryFileName = libraryFileName;
// spec.gui = plugin->isGuiRequired();
// pImpl_->specs.push_back(spec);
// Settings * sett = new Settings(moduleName);
// sett->changeWorkingDirectory(pImpl_->settingsWorkspacePath);
// pImpl_->settings.push_back(SettingsPtr(sett));
// plugin->updateSettings(QStringList());
// CommandLine runtimeParameters;
// if (!pImpl_->extractRuntimeParametersForPlugin(plugin, runtimeParameters)) {
// QString error = tr("The following command line parameters required, but not set:\n");
// for (int i=0; i<runtimeParameters.data_.size(); i++) {
// const CommandLineParameter & param = runtimeParameters.data_[i];
// if (param.shortDescription_.length() > 0) {
// if (!param.isValid() && plugin==pImpl_->objects.last())
// error += " " + param.toHelpLine() + "\n";
// }
// else if (!param.isValid()) {
// error += " " + param.toHelpLine() + "\n";
// }
// }
// return error;
// }
// QString result = plugin->initialize(QStringList(), runtimeParameters);
// pImpl_->states.last() = KPlugin::Initialized;
// return result;
}
bool PluginManager::isGuiRequired() const
......@@ -280,9 +223,37 @@ bool PluginManager::isGuiRequired() const
return false;
}
QString PluginManager::initializePlugins()
{
QString error;
// Initialize plugins with exact order from starting entry point
KPlugin * entryPoint = loadedPlugin(pImpl_->mainPluginName);
error = pImpl_->initializePlugin(entryPoint);
if (error.length() > 0) {
return error;
}
// Initialize rest of plugins
Q_FOREACH(KPlugin * plugin, pImpl_->objects) {
error = pImpl_->initializePlugin(plugin);
if (error.length() > 0) {
return error;
}
}
return "";
}
QString PluginManager::commandLineHelp() const
{
const PluginSpec &mainSpec = pImpl_->specs.last();
PluginSpec mainSpec;
Q_FOREACH(KPlugin * plugin, pImpl_->objects) {
if (plugin->pluginSpec().main) {
mainSpec = plugin->pluginSpec();
break;
}
}
bool guiMode = mainSpec.gui;
QString result = tr("Usage:\n");
QString programName = QCoreApplication::applicationFilePath();
......@@ -369,91 +340,40 @@ QFont PluginManager::initialApplicationFont() const
return pImpl_->initialApplicationFont;
}
QString PluginManager::initializePlugins()
{
Q_ASSERT(pImpl_->specs.size()==pImpl_->objects.size());
for (int i=0; i<pImpl_->objects.size(); i++) {
if (pImpl_->states[i] != KPlugin::Loaded)
continue;
const QString name = pImpl_->specs[i].name;
QStringList arguments;
for (int j=0; j<pImpl_->requests.size(); j++) {
if (pImpl_->requests[j].name==name) {
arguments = pImpl_->requests[j].arguments;
}
}
CommandLine runtimeParameters;
if (!pImpl_->extractRuntimeParametersForPlugin(pImpl_->objects[i], runtimeParameters)) {
QString error = tr("The following command line parameters required, but not set:\n");
for (int i=0; i<runtimeParameters.data_.size(); i++) {
const CommandLineParameter & param = runtimeParameters.data_[i];
if (!param.isValid()) {
error += " " + param.toHelpLine() + "\n";
}
}
error += tr("Run with --help for more details.\n");
return error;
}
qDebug() << "Begin initialization of plugin " <<
pImpl_->specs[i].name << " with parameters " << arguments;
QString error = pImpl_->objects[i]->initialize(arguments, runtimeParameters);
if (!error.isEmpty()) {
return QString("Error initializing %1: %2")
.arg(name)
.arg(error);
}
qDebug() << "Plugin initialization done";
pImpl_->states[i] = KPlugin::Initialized;
}
std::list<QString> remainingParameters = pImpl_->namedProgramArguments;
remainingParameters.merge(pImpl_->unnamedProgramArguments);;
if (remainingParameters.size() > 0) {
QString error = tr("Extra command line arguments:\n");
for (std::list<QString>::const_iterator it=remainingParameters.begin();
it!=remainingParameters.end(); ++it)
{
error += " " + (*it) + "\n";
}
error += tr("Run with --help for more details.\n");
return error;
}
return "";
}
QList<const KPlugin*> PluginManager::loadedConstPlugins(const QString &pattern) const
QList<const KPlugin*> PluginManager::loadedConstPlugins(const QByteArray &pattern) const
{
QList<const KPlugin*> result;
const QRegExp rx = QRegExp(pattern, Qt::CaseSensitive, QRegExp::Wildcard);
for (int i=0; i<pImpl_->specs.size(); i++) {
if (rx.exactMatch(pImpl_->specs[i].name)) {
result << pImpl_->objects[i];
Q_FOREACH(const KPlugin * p, pImpl_->objects) {
const PluginSpec & spec = p->pluginSpec();
if (rx.exactMatch(spec.name)) {
result.append(p);
}
}
return result;
}
QList<KPlugin*> PluginManager::loadedPlugins(const QString &pattern)
QList<KPlugin*> PluginManager::loadedPlugins(const QByteArray &pattern)
{
QList<KPlugin*> result;
const QRegExp rx = QRegExp(pattern, Qt::CaseSensitive, QRegExp::Wildcard);
for (int i=0; i<pImpl_->specs.size(); i++) {
if (rx.exactMatch(pImpl_->specs[i].name)) {
result << pImpl_->objects[i];
Q_FOREACH(KPlugin * p, pImpl_->objects) {
const PluginSpec & spec = p->pluginSpec();
if (rx.exactMatch(spec.name)) {
result.append(p);
}
}
return result;
}
KPlugin* PluginManager::loadedPlugin(const QString &name)
KPlugin* PluginManager::loadedPlugin(const QByteArray &name)
{
for (int i=0; i<pImpl_->specs.size(); i++) {
if (pImpl_->specs[i].name==name)
return pImpl_->objects[i];
Q_FOREACH(KPlugin * p, pImpl_->objects) {
const PluginSpec & spec = p->pluginSpec();
if (spec.name == name) {
return p;
}
}
return 0;
}
......@@ -466,80 +386,23 @@ KPlugin* PluginManager::startupModule()
QString PluginManager::start()
{
KPlugin * p = startupModule();
int index = pImpl_->objects.indexOf(p);
p->start();
pImpl_->states[index] = KPlugin::Started;
p->_state = KPlugin::Started;
return "";
}
PluginSpec PluginManager::specByObject(const KPlugin *p) const
{
Q_ASSERT(pImpl_->specs.size()==pImpl_->objects.size());
for (int i=0; i<pImpl_->specs.size(); i++) {
if (pImpl_->objects[i]==p) {
return pImpl_->specs[i];
}
}
return PluginSpec();
}
KPlugin * PluginManager::dependentPlugin(const QString &name, const KPlugin *p) const
KPlugin * PluginManager::dependentPlugin(const QByteArray &name, const KPlugin *p) const
{
PluginSpec spec;
Q_ASSERT(pImpl_->specs.size()==pImpl_->objects.size());
for (int i=0; i<pImpl_->specs.size(); i++) {
if (pImpl_->objects[i]==p) {
spec = pImpl_->specs[i];
}
}
bool hasDep = false;
QSet<QString> depAliases;
for (int i=0; i<spec.dependencies.size(); i++) {
for (int j=0; j<pImpl_->specs.size(); j++) {
if (pImpl_->specs[j].provides.contains(spec.dependencies[i]))
depAliases |= QSet<QString>::fromList(pImpl_->specs[j].provides);
}
}
for (int i=0; i<spec.dependencies.size(); i++) {
if (depAliases.contains(spec.dependencies[i])) {
hasDep = true;
break;
}
}
if (!hasDep) {
return 0;
}
for (int i=0; i<pImpl_->specs.size(); i++) {
PluginSpec ss=pImpl_->specs[i];
if (pImpl_->specs[i].provides.contains(name)) {
return pImpl_->objects[i];
Q_FOREACH(KPlugin * anotherPlugin, pImpl_->objects) {
const PluginSpec & anotherSpec = anotherPlugin->pluginSpec();