aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xbmc/Application.cpp2
-rw-r--r--xbmc/ApplicationMessenger.cpp2
-rw-r--r--xbmc/addons/Addon.cpp20
-rw-r--r--xbmc/addons/IAddon.h10
-rw-r--r--xbmc/addons/Service.cpp2
-rw-r--r--xbmc/filesystem/PluginDirectory.cpp4
-rw-r--r--xbmc/interfaces/Builtins.cpp2
-rw-r--r--xbmc/interfaces/python/XBPyThread.cpp14
-rw-r--r--xbmc/interfaces/python/XBPyThread.h4
-rw-r--r--xbmc/interfaces/python/XBPython.cpp100
-rw-r--r--xbmc/interfaces/python/XBPython.h7
-rw-r--r--xbmc/interfaces/python/xbmcmodule/PythonAddon.cpp81
-rw-r--r--xbmc/windows/GUIMediaWindow.cpp2
-rw-r--r--xbmc/windows/GUIWindowFileManager.cpp2
-rw-r--r--xbmc/windows/GUIWindowWeather.cpp2
15 files changed, 197 insertions, 57 deletions
diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp
index 9412971e72..4c24c0e89a 100644
--- a/xbmc/Application.cpp
+++ b/xbmc/Application.cpp
@@ -4651,7 +4651,7 @@ bool CApplication::ExecuteXBMCAction(std::string actionStr)
#ifdef HAS_PYTHON
if (item.IsPythonScript())
{ // a python script
- g_pythonParser.evalFile(item.m_strPath.c_str());
+ g_pythonParser.evalFile(item.m_strPath.c_str(),ADDON::AddonPtr());
}
else
#endif
diff --git a/xbmc/ApplicationMessenger.cpp b/xbmc/ApplicationMessenger.cpp
index fdf69c0c97..cb90cf8892 100644
--- a/xbmc/ApplicationMessenger.cpp
+++ b/xbmc/ApplicationMessenger.cpp
@@ -505,7 +505,7 @@ case TMSG_POWERDOWN:
case TMSG_EXECUTE_SCRIPT:
#ifdef HAS_PYTHON
- g_pythonParser.evalFile(pMsg->strParam.c_str());
+ g_pythonParser.evalFile(pMsg->strParam.c_str(),ADDON::AddonPtr());
#endif
break;
diff --git a/xbmc/addons/Addon.cpp b/xbmc/addons/Addon.cpp
index 6a202c632e..d682126b4c 100644
--- a/xbmc/addons/Addon.cpp
+++ b/xbmc/addons/Addon.cpp
@@ -666,5 +666,25 @@ TYPE CAddonLibrary::SetAddonType()
return ADDON_UNKNOWN;
}
+CStdString GetXbmcApiVersionDependency(ADDON::AddonPtr addon)
+{
+ CStdString version("1.0");
+ if (addon.get() != NULL)
+ {
+ const ADDON::ADDONDEPS &deps = addon->GetDeps();
+ ADDON::ADDONDEPS::const_iterator it;
+ CStdString key("xbmc.python");
+ it = deps.find(key);
+ if (!(it == deps.end()))
+ {
+ const ADDON::AddonVersion * xbmcApiVersion = &(it->second.first);
+ version = xbmcApiVersion->c_str();
+ }
+ }
+
+ return version;
+}
+
+
} /* namespace ADDON */
diff --git a/xbmc/addons/IAddon.h b/xbmc/addons/IAddon.h
index 31ee5b1031..bbce986717 100644
--- a/xbmc/addons/IAddon.h
+++ b/xbmc/addons/IAddon.h
@@ -121,5 +121,15 @@ namespace ADDON
virtual bool LoadStrings() =0;
virtual void ClearStrings() =0;
};
+
+ // some utilitiy methods
+
+ /**
+ * This function will extract the Addon's currently assigned xbmc.python
+ * API version. If addon is NULL, or there is no xbmc.python dependency defined,
+ * then the version is assumed to be "1.0"
+ */
+ CStdString GetXbmcApiVersionDependency(ADDON::AddonPtr addon);
+
};
diff --git a/xbmc/addons/Service.cpp b/xbmc/addons/Service.cpp
index 8a30a61e27..d054be1a1c 100644
--- a/xbmc/addons/Service.cpp
+++ b/xbmc/addons/Service.cpp
@@ -50,7 +50,7 @@ bool CService::Start()
{
#ifdef HAS_PYTHON
case PYTHON:
- ret = (g_pythonParser.evalFile(LibPath()) != -1);
+ ret = (g_pythonParser.evalFile(LibPath(),ADDON::AddonPtr(this)) != -1);
break;
#endif
diff --git a/xbmc/filesystem/PluginDirectory.cpp b/xbmc/filesystem/PluginDirectory.cpp
index 0dd8d2e7fc..53e025e0ae 100644
--- a/xbmc/filesystem/PluginDirectory.cpp
+++ b/xbmc/filesystem/PluginDirectory.cpp
@@ -117,7 +117,7 @@ bool CPluginDirectory::StartScript(const CStdString& strPath, bool retrievingDir
bool success = false;
#ifdef HAS_PYTHON
CStdString file = m_addon->LibPath();
- if (g_pythonParser.evalFile(file, argv) >= 0)
+ if (g_pythonParser.evalFile(file, argv,m_addon) >= 0)
{ // wait for our script to finish
CStdString scriptName = m_addon->Name();
success = WaitOnScriptResult(file, scriptName, retrievingDir);
@@ -434,7 +434,7 @@ bool CPluginDirectory::RunScriptWithParams(const CStdString& strPath)
// run the script
#ifdef HAS_PYTHON
CLog::Log(LOGDEBUG, "%s - calling plugin %s('%s','%s','%s')", __FUNCTION__, addon->Name().c_str(), argv[0].c_str(), argv[1].c_str(), argv[2].c_str());
- if (g_pythonParser.evalFile(addon->LibPath(), argv) >= 0)
+ if (g_pythonParser.evalFile(addon->LibPath(), argv,addon) >= 0)
return true;
else
#endif
diff --git a/xbmc/interfaces/Builtins.cpp b/xbmc/interfaces/Builtins.cpp
index e0659288e1..99738e434d 100644
--- a/xbmc/interfaces/Builtins.cpp
+++ b/xbmc/interfaces/Builtins.cpp
@@ -375,7 +375,7 @@ int CBuiltins::Execute(const CStdString& execString)
if (CAddonMgr::Get().GetAddon(params[0], script))
scriptpath = script->LibPath();
- g_pythonParser.evalFile(scriptpath, argv);
+ g_pythonParser.evalFile(scriptpath, argv,script);
}
}
#endif
diff --git a/xbmc/interfaces/python/XBPyThread.cpp b/xbmc/interfaces/python/XBPyThread.cpp
index 6c152c8929..d43ec3136f 100644
--- a/xbmc/interfaces/python/XBPyThread.cpp
+++ b/xbmc/interfaces/python/XBPyThread.cpp
@@ -36,6 +36,7 @@
#include "threads/SingleLock.h"
#include "utils/URIUtils.h"
#include "addons/AddonManager.h"
+#include "addons/Addon.h"
#include "XBPyThread.h"
#include "XBPython.h"
@@ -145,7 +146,7 @@ void XBPyThread::Process()
// swap in my thread state
PyThreadState_Swap(state);
- m_pExecuter->InitializeInterpreter();
+ m_pExecuter->InitializeInterpreter(addon);
CLog::Log(LOGDEBUG, "%s - The source file to load is %s", __FUNCTION__, m_source);
@@ -233,6 +234,17 @@ void XBPyThread::Process()
{
PyObject *f = PyString_FromString(_P(m_source).c_str());
PyDict_SetItemString(moduleDict, "__file__", f);
+ if (addon.get() != NULL)
+ {
+ PyObject *pyaddonid = PyString_FromString(addon->ID().c_str());
+ PyDict_SetItemString(moduleDict, "__xbmcaddonid__", pyaddonid);
+
+ CStdString version = ADDON::GetXbmcApiVersionDependency(addon);
+ PyObject *pyxbmcapiversion = PyString_FromString(version.c_str());
+ PyDict_SetItemString(moduleDict, "__xbmcapiversion__", pyxbmcapiversion);
+
+ CLog::Log(LOGDEBUG,"Instantiating addon using automatically obtained id of \"%s\" dependent on version %s of the xbmc.python api",addon->ID().c_str(),version.c_str());
+ }
Py_DECREF(f);
PyRun_FileExFlags(fp, _P(m_source).c_str(), m_Py_file_input, moduleDict, moduleDict,1,NULL);
}
diff --git a/xbmc/interfaces/python/XBPyThread.h b/xbmc/interfaces/python/XBPyThread.h
index 2ffe1504c8..630ac27738 100644
--- a/xbmc/interfaces/python/XBPyThread.h
+++ b/xbmc/interfaces/python/XBPyThread.h
@@ -23,6 +23,7 @@
#define XBPYTHREAD_H_
#include "threads/Thread.h"
+#include "addons/IAddon.h"
class XBPython;
@@ -37,6 +38,8 @@ public:
bool isStopping();
void stop();
+ void setAddon(ADDON::AddonPtr _addon) { addon = _addon; }
+
protected:
XBPython *m_pExecuter;
void *m_threadState;
@@ -47,6 +50,7 @@ protected:
unsigned int m_argc;
bool m_stopping;
int m_id;
+ ADDON::AddonPtr addon;
virtual void OnStartup();
virtual void Process();
diff --git a/xbmc/interfaces/python/XBPython.cpp b/xbmc/interfaces/python/XBPython.cpp
index 487a30d7bb..30f2f7791c 100644
--- a/xbmc/interfaces/python/XBPython.cpp
+++ b/xbmc/interfaces/python/XBPython.cpp
@@ -39,6 +39,8 @@
#include "utils/TimeUtils.h"
#include "Util.h"
+#include "addons/Addon.h"
+
extern "C" HMODULE __stdcall dllLoadLibraryA(LPCSTR file);
extern "C" BOOL __stdcall dllFreeLibrary(HINSTANCE hLibModule);
@@ -229,48 +231,67 @@ void XBPython::UnloadExtensionLibs()
m_extensions.clear();
}
-void XBPython::InitializeInterpreter()
+#define RUNSCRIPT_PRAMBLE \
+ "" \
+ "import xbmc\n" \
+ "class xbmcout:\n" \
+ "\tdef __init__(self, loglevel=xbmc.LOGNOTICE):\n" \
+ "\t\tself.ll=loglevel\n" \
+ "\tdef write(self, data):\n" \
+ "\t\txbmc.output(data,self.ll)\n" \
+ "\tdef close(self):\n" \
+ "\t\txbmc.output('.')\n" \
+ "\tdef flush(self):\n" \
+ "\t\txbmc.output('.')\n" \
+ "import sys\n" \
+ "sys.stdout = xbmcout()\n" \
+ "sys.stderr = xbmcout(xbmc.LOGERROR)\n"
+
+#define RUNSCRIPT_OVERRIDE_HACK \
+ "" \
+ "import os\n" \
+ "def getcwd_xbmc():\n" \
+ " import __main__\n" \
+ " import warnings\n" \
+ " if hasattr(__main__, \"__file__\"):\n" \
+ " warnings.warn(\"os.getcwd() currently lies to you so please use addon.getAddonInfo('path') to find the script's root directory and DO NOT make relative path accesses based on the results of 'os.getcwd.' \", DeprecationWarning, stacklevel=2)\n" \
+ " return os.path.dirname(__main__.__file__)\n" \
+ " else:\n" \
+ " return os.getcwd_original()\n" \
+ "" \
+ "def chdir_xbmc(dir):\n" \
+ " raise RuntimeError(\"os.chdir not supported in xbmc\")\n" \
+ "" \
+ "os_getcwd_original = os.getcwd\n" \
+ "os.getcwd = getcwd_xbmc\n" \
+ "os.chdir_orignal = os.chdir\n" \
+ "os.chdir = chdir_xbmc\n" \
+ ""
+
+#define RUNSCRIPT_POSTSCRIPT \
+ "print '-->Python Interpreter Initialized<--'\n" \
+ ""
+
+#define RUNSCRIPT_BWCOMPATIBLE \
+ RUNSCRIPT_PRAMBLE RUNSCRIPT_OVERRIDE_HACK RUNSCRIPT_POSTSCRIPT
+
+#define RUNSCRIPT_COMPLIANT \
+ RUNSCRIPT_PRAMBLE RUNSCRIPT_POSTSCRIPT
+
+void XBPython::InitializeInterpreter(ADDON::AddonPtr addon)
{
InitXBMCModule(); // init xbmc modules
InitPluginModule(); // init xbmcplugin modules
InitGUIModule(); // init xbmcgui modules
InitAddonModule(); // init xbmcaddon modules
InitVFSModule(); // init xbmcvfs modules
-
+
+ CStdString addonVer = ADDON::GetXbmcApiVersionDependency(addon);
+ bool bwcompatMode = (addon.get() == NULL || (ADDON::AddonVersion(addonVer) <= ADDON::AddonVersion("1.0")));
+ const char* runscript = bwcompatMode ? RUNSCRIPT_BWCOMPATIBLE : RUNSCRIPT_COMPLIANT;
+
// redirecting default output to debug console
- if (PyRun_SimpleString(""
- "import xbmc\n"
- "class xbmcout:\n"
- "\tdef write(self, data):\n"
- "\t\txbmc.output(data)\n"
- "\tdef close(self):\n"
- "\t\txbmc.output('.')\n"
- "\tdef flush(self):\n"
- "\t\txbmc.output('.')\n"
- "import sys\n"
- "sys.stdout = xbmcout()\n"
- "sys.stderr = xbmcout()\n"
- ""
- "import os\n"
- "def getcwd_xbmc():\n"
- " import __main__\n"
- " import warnings\n"
- " if hasattr(__main__, \"__file__\"):\n"
- " warnings.warn(\"os.getcwd() is depreciated for getting addon directory use os.path.dirname(__main__.__file__)\", DeprecationWarning, stacklevel=2)\n"
- " return os.path.dirname(__main__.__file__)\n"
- " else:\n"
- " return os.getcwd_original()\n"
- ""
- "def chdir_xbmc(dir):\n"
- " raise RuntimeError(\"os.chdir not supported in xbmc\")\n"
- ""
- "os_getcwd_original = os.getcwd\n"
- "os.getcwd = getcwd_xbmc\n"
- "os.chdir_orignal = os.chdir\n"
- "os.chdir = chdir_xbmc\n"
- ""
- "print '-->Python Interpreter Initialized<--'\n"
- "") == -1)
+ if (PyRun_SimpleString(runscript) == -1)
{
CLog::Log(LOGFATAL, "Python Initialize Error");
}
@@ -448,7 +469,7 @@ void XBPython::Process()
CStdString strAutoExecPy = _P("special://profile/autoexec.py");
if ( XFILE::CFile::Exists(strAutoExecPy) )
- evalFile(strAutoExecPy);
+ evalFile(strAutoExecPy,ADDON::AddonPtr());
else
CLog::Log(LOGDEBUG, "%s - no profile autoexec.py (%s) found, skipping", __FUNCTION__, strAutoExecPy.c_str());
}
@@ -492,13 +513,13 @@ bool XBPython::StopScript(const CStdString &path)
return false;
}
-int XBPython::evalFile(const CStdString &src)
+int XBPython::evalFile(const CStdString &src, ADDON::AddonPtr addon)
{
std::vector<CStdString> argv;
- return evalFile(src, argv);
+ return evalFile(src, argv, addon);
}
// execute script, returns -1 if script doesn't exist
-int XBPython::evalFile(const CStdString &src, const std::vector<CStdString> &argv)
+int XBPython::evalFile(const CStdString &src, const std::vector<CStdString> &argv, ADDON::AddonPtr addon)
{
CSingleExit ex(g_graphicsContext);
CSingleLock lock(m_critSection);
@@ -520,6 +541,7 @@ int XBPython::evalFile(const CStdString &src, const std::vector<CStdString> &arg
m_nextid++;
XBPyThread *pyThread = new XBPyThread(this, m_nextid);
pyThread->setArgv(argv);
+ pyThread->setAddon(addon);
pyThread->evalFile(src);
PyElem inf;
inf.id = m_nextid;
diff --git a/xbmc/interfaces/python/XBPython.h b/xbmc/interfaces/python/XBPython.h
index 81b96352e6..c46039d069 100644
--- a/xbmc/interfaces/python/XBPython.h
+++ b/xbmc/interfaces/python/XBPython.h
@@ -24,6 +24,7 @@
#include "XBPyThread.h"
#include "cores/IPlayer.h"
#include "threads/CriticalSection.h"
+#include "addons/IAddon.h"
#include <vector>
@@ -64,8 +65,8 @@ public:
int ScriptsSize();
int GetPythonScriptId(int scriptPosition);
- int evalFile(const CStdString &src);
- int evalFile(const CStdString &src, const std::vector<CStdString> &argv);
+ int evalFile(const CStdString &src, ADDON::AddonPtr addon);
+ int evalFile(const CStdString &src, const std::vector<CStdString> &argv, ADDON::AddonPtr addon);
int evalString(const CStdString &src, const std::vector<CStdString> &argv);
bool isRunning(int scriptId);
@@ -80,7 +81,7 @@ public:
// inject xbmc stuff into the interpreter.
// should be called for every new interpreter
- void InitializeInterpreter();
+ void InitializeInterpreter(ADDON::AddonPtr addon);
// remove modules and references when interpreter done
void DeInitializeInterpreter();
diff --git a/xbmc/interfaces/python/xbmcmodule/PythonAddon.cpp b/xbmc/interfaces/python/xbmcmodule/PythonAddon.cpp
index 9459bb0dc7..72bcf0e74f 100644
--- a/xbmc/interfaces/python/xbmcmodule/PythonAddon.cpp
+++ b/xbmc/interfaces/python/xbmcmodule/PythonAddon.cpp
@@ -24,6 +24,7 @@
#include "pythreadstate.h"
#include "addons/AddonManager.h"
#include "addons/GUIDialogAddonSettings.h"
+#include "utils/log.h"
#ifndef __GNUC__
#pragma code_seg("PY_TEXT")
@@ -41,6 +42,35 @@ using ADDON::CAddonMgr;
namespace PYXBMC
{
+
+ static const char* getDefaultId()
+ {
+ const char* id = NULL;
+
+ // Get a reference to the main module
+ // and global dictionary
+ PyObject* main_module = PyImport_AddModule((char*)"__main__");
+ PyObject* global_dict = PyModule_GetDict(main_module);
+ // Extract a reference to the function "func_name"
+ // from the global dictionary
+ PyObject* pyid = PyDict_GetItemString(global_dict, "__xbmcaddonid__");
+ id = PyString_AsString(pyid);
+ return id;
+ }
+
+ static CStdString getAddonVersion()
+ {
+ // Get a reference to the main module
+ // and global dictionary
+ PyObject* main_module = PyImport_AddModule((char*)"__main__");
+ PyObject* global_dict = PyModule_GetDict(main_module);
+ // Extract a reference to the function "func_name"
+ // from the global dictionary
+ PyObject* pyversion = PyDict_GetItemString(global_dict, "__xbmcapiversion__");
+ CStdString version(PyString_AsString(pyversion));
+ return version;
+ }
+
PyObject* Addon_New(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
Addon *self;
@@ -49,25 +79,66 @@ namespace PYXBMC
if (!self) return NULL;
static const char *keywords[] = { "id", NULL };
- char *id = NULL;
+ const char *id = NULL;
// parse arguments
if (!PyArg_ParseTupleAndKeywords(
args,
kwds,
- (char*)"s",
+ (char*)"|s",
(char**)keywords,
- &id
+ (char**)&id
))
{
Py_DECREF(self);
return NULL;
};
+ // if the id wasn't passed then get the id from
+ // the global dictionary
+ if (!id)
+ id = getDefaultId();
+
+ // if we still don't have an id then bail
+ if (!id)
+ {
+ PyErr_SetString(PyExc_Exception, "No valid addon id could be obtained. None was passed and the script wasn't executed in a normal xbmc manner.");
+ Py_DECREF(self);
+ return NULL;
+ }
+
+ // if we still fail we MAY be able to recover.
if (!CAddonMgr::Get().GetAddon(id, self->pAddon))
{
- PyErr_SetString(PyExc_Exception, "Could not get AddonPtr!");
- return NULL;
+ // we need to check the version prior to trying a bw compatibility trick
+ ADDON::AddonVersion version(getAddonVersion());
+ ADDON::AddonVersion allowable("1.0");
+
+ if (version <= allowable)
+ {
+ // try the default ...
+ id = getDefaultId();
+
+ if (!CAddonMgr::Get().GetAddon(id, self->pAddon))
+ {
+ PyErr_SetString(PyExc_Exception, "Could not get AddonPtr!");
+ Py_DECREF(self);
+ return NULL;
+ }
+ else
+ CLog::Log(LOGERROR,"Use of deprecated functionality. Please to not assume that \"os.getcwd\" will return the script directory.");
+ }
+ else
+ {
+ CStdString errorMessage ("Could not get AddonPtr given a script id of ");
+ errorMessage += id;
+ errorMessage += ". If you are trying to use 'os.getcwd' to set the path, you cannot do that in a ";
+ errorMessage += version.Print();
+ errorMessage += " plugin.";
+ PyErr_SetString(PyExc_Exception, errorMessage.c_str());
+ Py_DECREF(self);
+ return NULL;
+ }
}
return (PyObject*)self;
diff --git a/xbmc/windows/GUIMediaWindow.cpp b/xbmc/windows/GUIMediaWindow.cpp
index ee50bc0242..a1a3dc5086 100644
--- a/xbmc/windows/GUIMediaWindow.cpp
+++ b/xbmc/windows/GUIMediaWindow.cpp
@@ -882,7 +882,7 @@ bool CGUIMediaWindow::OnClick(int iItem)
{
#ifdef HAS_PYTHON
if (!g_pythonParser.StopScript(addon->LibPath()))
- g_pythonParser.evalFile(addon->LibPath());
+ g_pythonParser.evalFile(addon->LibPath(),addon);
#endif
return true;
}
diff --git a/xbmc/windows/GUIWindowFileManager.cpp b/xbmc/windows/GUIWindowFileManager.cpp
index 4f56a7fcea..a058be4a33 100644
--- a/xbmc/windows/GUIWindowFileManager.cpp
+++ b/xbmc/windows/GUIWindowFileManager.cpp
@@ -621,7 +621,7 @@ void CGUIWindowFileManager::OnStart(CFileItem *pItem)
#ifdef HAS_PYTHON
if (pItem->IsPythonScript())
{
- g_pythonParser.evalFile(pItem->m_strPath.c_str());
+ g_pythonParser.evalFile(pItem->m_strPath.c_str(),ADDON::AddonPtr());
return ;
}
#endif
diff --git a/xbmc/windows/GUIWindowWeather.cpp b/xbmc/windows/GUIWindowWeather.cpp
index 02d48586d2..402c7e0eb8 100644
--- a/xbmc/windows/GUIWindowWeather.cpp
+++ b/xbmc/windows/GUIWindowWeather.cpp
@@ -332,7 +332,7 @@ void CGUIWindowWeather::CallScript()
argv.push_back(CWeather::GetAreaCode(g_guiSettings.GetString(strSetting)));
// call our script, passing the areacode
- g_pythonParser.evalFile(argv[0], argv);
+ g_pythonParser.evalFile(argv[0], argv,addon);
CLog::Log(LOGDEBUG, "%s - Weather script called: %s (%s)", __FUNCTION__, argv[0].c_str(), argv[1].c_str());
}