Mailinglist Archive: opensuse-commit (2092 mails)

< Previous Next >
commit libopensync-plugin-python-module
  • From: root@xxxxxxxxxxxxxxx (h_root)
  • Date: Fri, 03 Aug 2007 15:12:32 +0200
  • Message-id: <20070803131232.E57D6678180@xxxxxxxxxxxxxxx>

Hello community,

here is the log from the commit of package libopensync-plugin-python-module
checked in at Fri Aug 3 15:12:32 CEST 2007.

--------
--- libopensync-plugin-python-module/libopensync-plugin-python-module.changes   2007-07-18 16:52:06.000000000 +0200
+++ /mounts/work_src_done/STABLE/libopensync-plugin-python-module/libopensync-plugin-python-module.changes      2007-08-02 15:50:35.000000000 +0200
@@ -1,0 +2,6 @@
+Thu Aug  2 15:50:22 CEST 2007 - cstender@xxxxxxx
+
+- updated to version 0.32
+       o ported to the new OpenSync 0.3x API
+
+-------------------------------------------------------------------

Old:
----
  libopensync-plugin-python-module-0.22.tar.bz2

New:
----
  libopensync-plugin-python-module-0.32.tar.bz2

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ libopensync-plugin-python-module.spec ++++++
--- /var/tmp/diff_new_pack.rc8448/_old  2007-08-03 15:11:56.000000000 +0200
+++ /var/tmp/diff_new_pack.rc8448/_new  2007-08-03 15:11:56.000000000 +0200
@@ -1,5 +1,5 @@
 #
-# spec file for package libopensync-plugin-python-module (Version 0.22)
+# spec file for package libopensync-plugin-python-module (Version 0.32)
 #
 # Copyright (c) 2007 SUSE LINUX Products GmbH, Nuernberg, Germany.
 # This file and all modifications and additions to the pristine
@@ -13,15 +13,15 @@
 Name:           libopensync-plugin-python-module
 BuildRequires:  libopensync-devel
 URL:            http://www.opensync.org
-Version:        0.22
-Release:        30
+Version:        0.32
+Release:        1
 Summary:        OpenSync module for Python plugins
 License:        LGPL v2 or later
 Group:          Productivity/Other
 Autoreqprov:    on
 Source:         %{name}-%{version}.tar.bz2
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
-Requires:       python-opensync
+Requires:       python-opensync libopensync1 >= 0.32
 
 %py_requires
 
@@ -48,10 +48,9 @@
 
 %install
 make DESTDIR=$RPM_BUILD_ROOT install
+mkdir -p $RPM_BUILD_ROOT/%{_libdir}/opensync/python-plugins
 # only needed for development
 rm $RPM_BUILD_ROOT/%{_libdir}/opensync/plugins/python_module.la
-# only an example plugin
-rm $RPM_BUILD_ROOT/%{_libdir}/opensync/python-plugins/sample.py
 
 %clean
 rm -rf $RPM_BUILD_ROOT
@@ -62,11 +61,14 @@
 
 %files
 %defattr(-, root, root)
+%doc AUTHORS COPYING INSTALL
 %{_libdir}/opensync/plugins/python_module.so
-%{_libdir}/opensync/python-plugins/
-%doc AUTHORS COPYING INSTALL ChangeLog NEWS README
+%{_libdir}/opensync/python-plugins
 
 %changelog
+* Thu Aug 02 2007 - cstender@xxxxxxx
+- updated to version 0.32
+  o ported to the new OpenSync 0.3x API
 * Wed Jul 18 2007 - dmueller@xxxxxxx
 - use py_requires macro for more accurate requires
 * Thu Mar 29 2007 - cstender@xxxxxxx

++++++ libopensync-plugin-python-module-0.22.tar.bz2 -> libopensync-plugin-python-module-0.32.tar.bz2 ++++++
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/libopensync-plugin-python-module-0.22/AUTHORS new/libopensync-plugin-python-module-0.32/AUTHORS
--- old/libopensync-plugin-python-module-0.22/AUTHORS   2005-01-02 14:56:30.000000000 +0100
+++ new/libopensync-plugin-python-module-0.32/AUTHORS   2007-02-20 11:50:36.000000000 +0100
@@ -1 +1,2 @@
 Eduardo Pereira Habkost <ehabkost@xxxxxxxxxxxxxxxx>
+Andrew Baumann <andrewb@xxxxxxxxxxxxxxx>
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/libopensync-plugin-python-module-0.22/configure.in new/libopensync-plugin-python-module-0.32/configure.in
--- old/libopensync-plugin-python-module-0.22/configure.in      2007-03-25 18:17:30.000000000 +0200
+++ new/libopensync-plugin-python-module-0.32/configure.in      2007-08-02 12:21:29.000000000 +0200
@@ -1,7 +1,7 @@
 dnl Process this file with autoconf to produce a configure script.
 
 AC_PREREQ(2.58)
-AC_INIT([OpenSync Python Module], 0.22, [], [libopensync-plugin-python])
+AC_INIT([OpenSync Python Module], 0.32, [], [libopensync-plugin-python])
 AM_INIT_AUTOMAKE(foreign)
 AC_CONFIG_SRCDIR(src/python_module.c)
 AM_CONFIG_HEADER(config.h)
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/libopensync-plugin-python-module-0.22/Makefile.am new/libopensync-plugin-python-module-0.32/Makefile.am
--- old/libopensync-plugin-python-module-0.22/Makefile.am       2006-09-08 16:32:11.000000000 +0200
+++ new/libopensync-plugin-python-module-0.32/Makefile.am       2007-02-19 09:48:32.000000000 +0100
@@ -3,8 +3,6 @@
 
 INCLUDES = -I$(top_srcdir)
 
-EXTRA_DIST = src/sample.py
-
 OPENSYNC_LIBS=-lopensync
 
 plugin_LTLIBRARIES = python_module.la
@@ -15,4 +13,6 @@
 python_module_la_CPPFLAGS = @PYTHON_CFLAGS@ -DOPENSYNC_PYTHONPLG_DIR=\"$(pythonplgdir)\"
 python_module_la_LIBADD = @PYTHON_LIBS@
 
-pythonplg_DATA = src/sample.py
+# uncomment these to install the sample plugin
+#EXTRA_DIST = src/sample.py
+#pythonplg_DATA = src/sample.py
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/libopensync-plugin-python-module-0.22/setup.py new/libopensync-plugin-python-module-0.32/setup.py
--- old/libopensync-plugin-python-module-0.22/setup.py  2005-04-11 17:41:43.000000000 +0200
+++ new/libopensync-plugin-python-module-0.32/setup.py  1970-01-01 01:00:00.000000000 +0100
@@ -1,10 +0,0 @@
-from distutils.core import setup, Extension
-setup(name='opensync',
-      version='0.3',
-      ext_modules=[
-          Extension(
-              'opensync', ['src/opensync.c', 'src/pywrap.c'],
-              libraries=['opensync']
-          )
-      ],
-)
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/libopensync-plugin-python-module-0.22/src/python_module.c new/libopensync-plugin-python-module-0.32/src/python_module.c
--- old/libopensync-plugin-python-module-0.22/src/python_module.c       2006-08-25 13:57:03.000000000 +0200
+++ new/libopensync-plugin-python-module-0.32/src/python_module.c       2007-07-03 09:39:37.000000000 +0200
@@ -1,5 +1,6 @@
 /* Python module for OpenSync
  * Copyright (C) 2005  Eduardo Pereira Habkost <ehabkost@xxxxxxxxxxxxxxxx>
+ * Copyright (C) 2007  Andrew Baumann <andrewb@xxxxxxxxxxxxxxx>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -16,22 +17,27 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
  *
  * @author Eduardo Pereira Habkost <ehabkost@xxxxxxxxxxxxxxxx>
+ * @author Andrew Baumann <andrewb@xxxxxxxxxxxxxxx>
  *
  * Additional changes by Armin Bauer <armin.bauer@xxxxxxxxxxx>
  */
 
 #include <Python.h>
-
 #include <opensync/opensync.h>
+#include <opensync/opensync-plugin.h>
+#include <opensync/opensync-context.h>
 #include <signal.h>
 #include <glib.h>
 #include "config.h"
 
+/* change this define for python exception output on stderr */
+//#define PYERR_CLEAR() PyErr_Clear()
+#define PYERR_CLEAR() PyErr_Print()
+
 typedef struct MemberData {
-       PyThreadState *interp_thread;
        PyObject *osync_module;
        PyObject *module;
-       PyObject *object;
+       GSList *sinks;
 } MemberData;
 
 static PyObject *pm_load_opensync(OSyncError **error)
@@ -39,49 +45,26 @@
        PyObject *osync_module = PyImport_ImportModule("opensync");
        if (!osync_module) {
                osync_error_set(error, OSYNC_ERROR_GENERIC, "Couldn't load OpenSync module");
-               //PyErr_Print();
+               PYERR_CLEAR();
                return NULL;
        }
        return osync_module;
 }
 
-static PyObject *pm_load_script(const char *filename, OSyncError **error)
-{
-       FILE *fp = fopen(filename, "r");
-       if (!fp) {
-               osync_error_set(error, OSYNC_ERROR_GENERIC, "Unable to open file %s", filename);
-               return NULL;
-       }
-       
-       if (PyRun_SimpleFile(fp, filename) == -1) {
-               osync_error_set(error, OSYNC_ERROR_GENERIC, "Couldn't run module from file %s", filename);
-               PyErr_Print();
-               return NULL;
-       }
-       
-       PyObject *module = PyImport_AddModule("__main__");
-       if (!module) {
-               osync_error_set(error, OSYNC_ERROR_GENERIC, "Couldn't load module from file %s", filename);
-               PyErr_Print();
-               return NULL;
-       }
-       return module;
-}
-
 static PyObject *pm_make_change(PyObject *osync_module, OSyncChange *change, OSyncError **error)
 {
        PyObject *pychg_cobject = PyCObject_FromVoidPtr(change, NULL);
        if (!pychg_cobject) {
                osync_error_set(error, OSYNC_ERROR_GENERIC, "Couldnt make pychg cobject");
-               PyErr_Print();
+               PYERR_CLEAR();
                return NULL;
        }
        
-       PyObject *pychg = PyObject_CallMethod(osync_module, "OSyncChange", "O", pychg_cobject);
+       PyObject *pychg = PyObject_CallMethod(osync_module, "Change", "O", pychg_cobject);
+       Py_DECREF(pychg_cobject);
        if (!pychg) {
                osync_error_set(error, OSYNC_ERROR_GENERIC, "Cannot create Python OSyncChange");
-               PyErr_Print();
-               Py_XDECREF(pychg_cobject);
+               PYERR_CLEAR();
                return NULL;
        }
        return pychg;
@@ -92,216 +75,359 @@
        PyObject *pyctx_cobject = PyCObject_FromVoidPtr(ctx, NULL);
        if (!pyctx_cobject) {
                osync_error_set(error, OSYNC_ERROR_GENERIC, "Couldnt make pyctx cobject");
-               PyErr_Print();
+               PYERR_CLEAR();
                return NULL;
        }
        
-       PyObject *pyctx = PyObject_CallMethod(osync_module, "OSyncContext", "O", pyctx_cobject);
+       PyObject *pyctx = PyObject_CallMethod(osync_module, "Context", "O", pyctx_cobject);
+       Py_DECREF(pyctx_cobject);
        if (!pyctx) {
                osync_error_set(error, OSYNC_ERROR_GENERIC, "Cannot create Python OSyncContext");
-               PyErr_Print();
-               Py_XDECREF(pyctx_cobject);
+               PYERR_CLEAR();
                return NULL;
        }
        return pyctx;
 }
 
-static PyObject *pm_make_member(PyObject *osync_module, OSyncMember *member, OSyncError **error)
+static PyObject *pm_make_info(PyObject *osync_module, OSyncPluginInfo *info, OSyncError **error)
 {
-       PyObject *pymember_cobject = PyCObject_FromVoidPtr(member, NULL);
-       if (!pymember_cobject) {
-               osync_error_set(error, OSYNC_ERROR_GENERIC, "Couldnt make pymember cobject");
-               PyErr_Print();
+       PyObject *pyinfo_cobject = PyCObject_FromVoidPtr(info, NULL);
+       if (!pyinfo_cobject) {
+               osync_error_set(error, OSYNC_ERROR_GENERIC, "Couldnt make pyinfo cobject");
+               PYERR_CLEAR();
                return NULL;
        }
        
-       PyObject *pymember = PyObject_CallMethod(osync_module, "OSyncMember", "O", pymember_cobject);
-       if (!pymember) {
-               osync_error_set(error, OSYNC_ERROR_GENERIC, "Cannot create Python OSyncMember");
-               PyErr_Print();
-               Py_XDECREF(pymember_cobject);
+       PyObject *pyinfo = PyObject_CallMethod(osync_module, "PluginInfo", "O", pyinfo_cobject);
+       Py_DECREF(pyinfo_cobject);
+       if (!pyinfo) {
+               osync_error_set(error, OSYNC_ERROR_GENERIC, "Cannot create Python OSyncPluginInfo");
+               PYERR_CLEAR();
                return NULL;
        }
-       return pymember;
+       return pyinfo;
 }
 
-/** Calls the method initialize function
- *
- * The python initialize() function should return an object that
- * has the other plugin methods (get_changeinfo, commit, etc.)
- */
-static void *pm_initialize(OSyncMember *member, OSyncError **error)
+/* convert a python exception to an OSyncError containing the traceback of the exception */
+static void pm_pyexcept_to_oserror(PyObject *pytype, PyObject *pyvalue, PyObject *pytraceback, OSyncError **error)
 {
-       const char *name = osync_member_get_plugindata(member);
-       if (!name) {
-               osync_error_set(error, OSYNC_ERROR_GENERIC, "No script name was set");
-               return NULL;
+       const char *errmsg = NULL;
+       PyObject *tracebackmod = NULL, *stringmod = NULL;
+       PyObject *pystrs = NULL, *pystr = NULL;
+       
+       tracebackmod = PyImport_ImportModule("traceback");
+       if (!tracebackmod) {
+               errmsg = "import traceback";
+               goto error;
        }
 
-       MemberData *data = g_malloc(sizeof(MemberData));
-
-       data->interp_thread = Py_NewInterpreter();
-       if (!data->interp_thread) {
-               osync_error_set(error, OSYNC_ERROR_GENERIC, "Couldn't initialize python sub interpreter");
-               goto error_free_data;
+       pystrs = PyObject_CallMethod(tracebackmod, "format_exception", "OOO", pytype, pyvalue, pytraceback);
+       if (!pystrs) {
+               errmsg = "traceback.format_exception";
+               goto error;
        }
-       
-       if (!(data->osync_module = pm_load_opensync(error)))
-               goto error_free_interp;
-       
-       if (!(data->module = pm_load_script(name, error)))
-               goto error_free_interp;
-       
-       PyObject *pymember = pm_make_member(data->osync_module, member, error);
-       if (!pymember)
-               goto error_unload_module;
-       
-       data->object = PyObject_CallMethod(data->module, "initialize", "O", pymember);
-       if (!data->object) {
-               osync_error_set(error, OSYNC_ERROR_GENERIC, "Couldn't initialize module");
-               PyErr_Print();
-               goto error_unload_module;
+
+       stringmod = PyImport_ImportModule("string");
+       if (!stringmod) {
+               errmsg = "import string";
+               goto error;
        }
 
-       PyEval_ReleaseThread(data->interp_thread);
+       pystr = PyObject_CallMethod(stringmod, "join", "Os", pystrs, "");
+       if (!pystr) {
+               errmsg = "string.join";
+               goto error;
+       }
 
-       return data;
+       osync_error_set(error, OSYNC_ERROR_GENERIC, "%s", PyString_AsString(pystr));
 
-error_unload_module:
-       Py_DECREF(data->module);
-error_free_interp:
-       Py_EndInterpreter(data->interp_thread);
-error_free_data:
-       free(data);
-       return NULL;
-}
+error:
+       Py_XDECREF(tracebackmod);
+       Py_XDECREF(stringmod);
+       Py_XDECREF(pystrs);
+       Py_XDECREF(pystr);
 
-static void pm_finalize(void *data)
-{
-       osync_trace(TRACE_ENTRY, "%s(%p)", __func__, data);
-       MemberData *mydata = data;
-       PyEval_AcquireThread(mydata->interp_thread);
-       {
-               PyObject *ret = PyObject_CallMethod(mydata->object, "finalize", NULL);
-               if (!ret) {
-                       osync_trace(TRACE_INTERNAL, "Error during finalize()");
-                       PyErr_Print();
-               } else
-                       Py_DECREF(ret);
+       if (errmsg) {
+               PYERR_CLEAR();
+               osync_error_set(error, OSYNC_ERROR_GENERIC, "pm_pyexcept_to_oserror: failed to report error: exception in %s", errmsg);
        }
-       Py_DECREF(mydata->object);
-       Py_DECREF(mydata->module);
-       Py_EndInterpreter(mydata->interp_thread);
-       
-       free(mydata);
-       osync_trace(TRACE_EXIT, "%s", __func__);
 }
 
-/** Call a python method
+/** Call a python method, report any exception it raises as an error, if no exception was raised report success
  *
  * Methods called using this function can
  * have one of these formats:
  *
- * - function(context)
- * - function(context, change)
+ * - function(info, context)
+ * - function(info, context, change)
  */
-static osync_bool pm_call_module_method(OSyncContext *ctx, OSyncChange *chg, char *name, OSyncError **error)
+static osync_bool pm_call_module_method(MemberData *data, char *name, OSyncPluginInfo *info, OSyncContext *ctx, OSyncChange *chg)
 {
-       osync_trace(TRACE_ENTRY, "%s(%p, %p, %s, %p)", __func__, ctx, chg, name, error);
-       PyObject *pycontext = NULL;
+       osync_trace(TRACE_ENTRY, "%s(%s, %p, %p, %p)", __func__, name, info, ctx, chg);
        PyObject *ret = NULL;
+       OSyncError *error = NULL;
+       osync_bool report_error = TRUE;
+
+       PyGILState_STATE pystate = PyGILState_Ensure();
 
-       MemberData *data = osync_context_get_plugin_data(ctx);
-       PyEval_AcquireThread(data->interp_thread);
+       PyObject *pyinfo = pm_make_info(data->osync_module, info, &error);
+       if (!pyinfo)
+               goto error;
 
-       pycontext = pm_make_context(data->osync_module, ctx, error);
+       PyObject *pycontext = pm_make_context(data->osync_module, ctx, &error);
        if (!pycontext) {
-               PyEval_ReleaseThread(data->interp_thread);
-               osync_context_report_osyncerror(ctx, error);
-               osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
-               return FALSE;
+               Py_DECREF(pyinfo);
+               goto error;
        }
 
+       OSyncObjTypeSink *sink = osync_plugin_info_get_sink(info);
+       PyObject *sink_pyobject = osync_objtype_sink_get_userdata(sink);
+
        if (chg) {
-               PyObject *pychange = pm_make_change(data->osync_module, chg, error);
+               PyObject *pychange = pm_make_change(data->osync_module, chg, &error);
                if (!pychange) {
-                       PyEval_ReleaseThread(data->interp_thread);
-                       osync_context_report_osyncerror(ctx, error);
-                       osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
-                       return FALSE;
+                       Py_DECREF(pyinfo);
+                       Py_DECREF(pycontext);
+                       goto error;
                }
                
-               ret = PyObject_CallMethod(data->object, name, "OO", pycontext, pychange);
+               ret = PyObject_CallMethod(sink_pyobject, name, "OOO", pyinfo, pycontext, pychange);
                
-               Py_XDECREF(pychange);
+               Py_DECREF(pychange);
        } else {
-               ret = PyObject_CallMethod(data->object, name, "O", pycontext);
+               ret = PyObject_CallMethod(sink_pyobject, name, "OO", pyinfo, pycontext);
        }
-       
-       if (!ret) {
-               osync_error_set(error, OSYNC_ERROR_GENERIC, "Error during %s() method", name);
-               PyErr_Print();
-               PyEval_ReleaseThread(data->interp_thread);
-               osync_context_report_osyncerror(ctx, error);
-               osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
-               return FALSE;
+
+       Py_DECREF(pyinfo);
+
+       if (ret) {
+               Py_DECREF(pycontext);
+               Py_DECREF(ret);
+               PyGILState_Release(pystate);
+               osync_context_report_success(ctx);
+               osync_trace(TRACE_EXIT, "%s", __func__);
+               return TRUE;
+       }
+
+       /* an exception occurred. get the python exception data */
+       PyObject *pytype, *pyvalue, *pytraceback;
+       PyErr_Fetch(&pytype, &pyvalue, &pytraceback);
+       
+       PyObject *osyncerror = NULL;
+       osyncerror = PyObject_GetAttrString(data->osync_module, "Error");
+       if (!osyncerror) {
+               PYERR_CLEAR();
+               osync_error_set(&error, OSYNC_ERROR_GENERIC, "Failed to get OSyncError class object");
+               goto out;
+       }
+       
+       if (PyErr_GivenExceptionMatches(pytype, osyncerror)) {
+               /* if it's an OSyncError, just report that up on the context object */
+               PyObject *obj = PyObject_CallMethod(pyvalue, "report", "O", pycontext);
+               if (!obj) {
+                       PYERR_CLEAR();
+                       osync_error_set(&error, OSYNC_ERROR_GENERIC, "Failed reporting OSyncError");
+                       goto out;
+               }
+               
+               Py_DECREF(obj);
+               osync_error_set(&error, OSYNC_ERROR_GENERIC, "Reported OSyncError");
+               report_error = FALSE;
+       } else if (PyErr_GivenExceptionMatches(pytype, PyExc_IOError)
+                  || PyErr_GivenExceptionMatches(pytype, PyExc_OSError)) {
+               /* for IOError or OSError, we just report the &error message */
+               PyObject *pystr = PyObject_Str(pyvalue);
+               if (!pystr) {
+                       PYERR_CLEAR();
+                       osync_error_set(&error, OSYNC_ERROR_GENERIC, "Failed reporting IOError/OSError");
+                       goto out;
+               }
+
+               osync_error_set(&error, OSYNC_ERROR_IO_ERROR, "%s", PyString_AsString(pystr));
+               Py_DECREF(pystr);
+       } else {
+               /* for other exceptions, we report a full traceback */
+               pm_pyexcept_to_oserror(pytype, pyvalue, pytraceback, &error);
        }
 
-       Py_XDECREF(ret);
-       PyEval_ReleaseThread(data->interp_thread);
-       
-       osync_trace(TRACE_EXIT, "%s", __func__);
-       return TRUE;
+out:
+       Py_DECREF(pycontext);
+       Py_XDECREF(pytype);
+       Py_XDECREF(pyvalue);
+       Py_XDECREF(pytraceback);
+       Py_XDECREF(osyncerror);
+
+error:
+       PyGILState_Release(pystate);
+       if (report_error)
+               osync_context_report_osyncerror(ctx, error);
+       osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(&error));
+       return FALSE;
 }
 
-static void pm_connect(OSyncContext *ctx)
+static void pm_connect(void *data, OSyncPluginInfo *info, OSyncContext *ctx)
 {
-       osync_trace(TRACE_ENTRY, "%s(%p)", __func__, ctx);
-       OSyncError *error = NULL;
-       pm_call_module_method(ctx, NULL, "connect", &error);
-       osync_trace(TRACE_EXIT, "%s", __func__);
+       pm_call_module_method(data, "connect", info, ctx, NULL);
 }
 
+static void pm_disconnect(void *data, OSyncPluginInfo *info, OSyncContext *ctx)
+{
+       pm_call_module_method(data, "disconnect", info, ctx, NULL);
+}
 
-static void pm_get_changeinfo(OSyncContext *ctx)
+static void pm_get_changes(void *data, OSyncPluginInfo *info, OSyncContext *ctx)
 {
-       osync_trace(TRACE_ENTRY, "%s(%p)", __func__, ctx);
-       OSyncError *error = NULL;
-       pm_call_module_method(ctx, NULL, "get_changeinfo", &error);
-       osync_trace(TRACE_EXIT, "%s", __func__);
+       pm_call_module_method(data, "get_changes", info, ctx, NULL);
 }
 
-static osync_bool pm_access(OSyncContext *ctx, OSyncChange *change)
+static void pm_commit(void *data, OSyncPluginInfo *info, OSyncContext *ctx, OSyncChange *change)
 {      
-       osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, ctx, change);
-       OSyncError *error = NULL;
-       pm_call_module_method(ctx, change, "access", &error);
-       osync_trace(TRACE_EXIT, "%s", __func__);
-       return TRUE;
+       pm_call_module_method(data, "commit", info, ctx, change);
 }
 
-static osync_bool pm_commit_change(OSyncContext *ctx, OSyncChange *change)
+static void pm_committed_all(void *data, OSyncPluginInfo *info, OSyncContext *ctx)
 {      
-       osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, ctx, change);
-       OSyncError *error = NULL;
-       pm_call_module_method(ctx, change, "commit_change", &error);
+       pm_call_module_method(data, "committed_all", info, ctx, NULL);
+}
+
+static osync_bool pm_write(void *data, OSyncPluginInfo *info, OSyncContext *ctx, OSyncChange *change)
+{      
+       return pm_call_module_method(data, "write", info, ctx, change);
+}
+
+static osync_bool pm_read(void *data, OSyncPluginInfo *info, OSyncContext *ctx, OSyncChange *change)
+{      
+       return pm_call_module_method(data, "read", info, ctx, change);
+}
+
+static void pm_sync_done(void *data, OSyncPluginInfo *info, OSyncContext *ctx)
+{
+       pm_call_module_method(data, "sync_done", info, ctx, NULL);
+}
+
+static OSyncObjTypeSinkFunctions pm_sink_functions = {
+       .connect = pm_connect,
+       .disconnect = pm_disconnect,
+       .get_changes = pm_get_changes,
+       .commit = pm_commit,
+       .write = pm_write,
+       .committed_all = pm_committed_all,
+       .read = pm_read,
+       .batch_commit = NULL, /* not (yet) supported for python plugins */
+       .sync_done = pm_sync_done
+};
+
+/** Calls the method initialize function
+ *
+ * The python initialize() function register one or more sink objects
+ * that have the other plugin methods (get_changeinfo, commit, etc.)
+ */
+static void *pm_initialize(OSyncPlugin *plugin, OSyncPluginInfo *info, OSyncError **error)
+{
+       osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, plugin, info, error);
+       MemberData *data = g_malloc0(sizeof(MemberData));
+       char *modulename;
+
+       if (!(modulename = osync_plugin_get_data(plugin)))
+               return NULL;
+       osync_plugin_set_data(plugin, NULL);
+
+       PyGILState_STATE pystate = PyGILState_Ensure();
+
+       if (!(data->module = PyImport_ImportModule(modulename))) {
+               PYERR_CLEAR();
+               osync_error_set(error, OSYNC_ERROR_GENERIC, "Couldn't load module %s", modulename);
+               free(modulename);
+               goto error;
+       }
+
+       free(modulename);
+
+       if (!(data->osync_module = pm_load_opensync(error)))
+               goto error;
+       
+       PyObject *pyinfo = pm_make_info(data->osync_module, info, error);
+       if (!pyinfo)
+               goto error;
+       
+       PyObject *ret = PyObject_CallMethod(data->module, "initialize", "O", pyinfo);
+       Py_DECREF(pyinfo);
+       if (!ret) {
+               osync_error_set(error, OSYNC_ERROR_GENERIC, "Couldn't initialize module");
+               PYERR_CLEAR();
+               goto error;
+       }
+       Py_DECREF(ret);
+
+       /* loop through all objtype sinks, set up function pointers */
+       int n, max = osync_plugin_info_num_objtypes(info);
+       for (n = 0; n < max; n++) {
+               OSyncObjTypeSink *sink = osync_plugin_info_nth_objtype(info, n);
+               PyObject *sinkobj = osync_objtype_sink_get_userdata(sink);
+               osync_objtype_sink_set_functions(sink, pm_sink_functions, sinkobj);
+               Py_INCREF(sinkobj);
+               data->sinks = g_slist_prepend(data->sinks, sinkobj);
+       }
+
+       PyGILState_Release(pystate);
        osync_trace(TRACE_EXIT, "%s", __func__);
-       return TRUE;
+       return data;
+
+error:
+       Py_XDECREF(data->module);
+       Py_XDECREF(data->osync_module);
+       PyGILState_Release(pystate);
+       free(data);
+       osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
+       return NULL;
 }
 
-static void pm_sync_done(OSyncContext *ctx)
+static osync_bool pm_discover(void *data_in, OSyncPluginInfo *info, OSyncError **error)
 {
-       osync_trace(TRACE_ENTRY, "%s(%p)", __func__, ctx);
-       OSyncError *error = NULL;
-       pm_call_module_method(ctx, NULL, "sync_done", &error);
+       osync_trace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, data_in, info, error);
+
+       MemberData *data = data_in;
+
+       PyGILState_STATE pystate = PyGILState_Ensure();
+
+       PyObject *pyinfo = pm_make_info(data->osync_module, info, error);
+       if (!pyinfo)
+               goto error;
+
+       PyObject *ret = PyObject_CallMethod(data->module, "discover", "O", pyinfo);
+       Py_DECREF(pyinfo);
+       if (!ret)
+               goto error;
+
+       Py_DECREF(ret);
+       PyGILState_Release(pystate);
        osync_trace(TRACE_EXIT, "%s", __func__);
+       return TRUE;
+
+error:
+       osync_error_set(error, OSYNC_ERROR_GENERIC, "Couldn't call discover method");
+       PYERR_CLEAR();
+       PyGILState_Release(pystate);
+       osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
+       return FALSE;
 }
 
-static void pm_disconnect(OSyncContext *ctx)
+static void pm_finalize(void *data)
 {
-       osync_trace(TRACE_ENTRY, "%s(%p)", __func__, ctx);
-       OSyncError *error = NULL;
-       pm_call_module_method(ctx, NULL, "disconnect", &error);
+       osync_trace(TRACE_ENTRY, "%s(%p)", __func__, data);
+       MemberData *mydata = data;
+       PyGILState_STATE pystate = PyGILState_Ensure();
+
+       /* free all sink objects */
+       while (mydata->sinks) {
+               Py_DECREF((PyObject *)mydata->sinks->data);
+               mydata->sinks = g_slist_delete_link(mydata->sinks, mydata->sinks);
+       }
+
+       Py_DECREF(mydata->module);
+       Py_DECREF(mydata->osync_module);
+       free(mydata);
+       PyGILState_Release(pystate);
        osync_trace(TRACE_EXIT, "%s", __func__);
 }
 
@@ -312,84 +438,86 @@
  *       plugin information on another place (including
  *       accepted objtypes/formats info)
  */
-static osync_bool register_plugin(OSyncEnv *env, PyObject *osync_module,
-                                  const char *filename, OSyncError **error)
+static osync_bool register_plugin(OSyncPluginEnv *env, PyObject *osync_module,
+                                  char *modulename, OSyncError **error)
 {
-       osync_trace(TRACE_ENTRY, "%s(%p, %s, %p)", __func__, env, filename, error);
+       osync_trace(TRACE_ENTRY, "%s(%p, %s, %p)", __func__, env, modulename, error);
 
-       PyObject *module = pm_load_script(filename, error);
-       if (!module) {
-               osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
+       PyObject *module = NULL, *pyplugin_cobj = NULL, *pyplugin = NULL;
+
+       OSyncPlugin *plugin = osync_plugin_new(error);
+       if (!plugin)
                return FALSE;
+
+       module = PyImport_ImportModule(modulename);
+       if (!module) {
+               osync_error_set(error, OSYNC_ERROR_GENERIC, "Couldn't load module %s", modulename);
+               goto error;
        }
-       
-       OSyncPluginInfo *info = osync_plugin_new_info(env);
-       info->functions.initialize = pm_initialize;
-       info->functions.connect = pm_connect;
-       info->functions.get_changeinfo = pm_get_changeinfo;
-       info->functions.sync_done = pm_sync_done;
-       info->functions.disconnect = pm_disconnect;
-       info->functions.finalize = pm_finalize;
-       
-       info->plugin_data = g_strdup(filename);
-       
-       PyObject *pyinfo_cobject = PyCObject_FromVoidPtr(info, NULL);
-       if (!pyinfo_cobject) {
-               osync_error_set(error, OSYNC_ERROR_GENERIC, "Couldnt make pyinfo cobject");
-               PyErr_Print();
-               PyErr_Clear();
-               osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
-               return FALSE;
+
+       pyplugin_cobj = PyCObject_FromVoidPtr(plugin, NULL);
+       if (!pyplugin_cobj) {
+               osync_error_set(error, OSYNC_ERROR_GENERIC, "Couldnt make pyplugin cobject");
+               goto error;
        }
        
-       PyObject *pyinfo = PyObject_CallMethod(osync_module, "OSyncPluginInfo", "O", pyinfo_cobject);
-       if (!pyinfo) {
-               osync_error_set(error, OSYNC_ERROR_GENERIC, "Cannot create Python OSyncPluginInfo");
-               PyErr_Print();
-               PyErr_Clear();
-               osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
-               return FALSE;
+       pyplugin = PyObject_CallMethod(osync_module, "Plugin", "O", pyplugin_cobj);
+       if (!pyplugin) {
+               osync_error_set(error, OSYNC_ERROR_GENERIC, "Cannot create Python OSyncPlugin");
+               goto error;
        }
        
-       if (!PyObject_CallMethod(module, "get_info", "O", pyinfo)) {
-               osync_error_set(error, OSYNC_ERROR_GENERIC, "Error calling get_info");
-               PyErr_Print();
-               PyErr_Clear();
-               osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
-               return FALSE;
+       PyObject *pyret = PyObject_CallMethod(module, "get_sync_info", "O", pyplugin);
+       if (!pyret) {
+               osync_error_set(error, OSYNC_ERROR_GENERIC, "Error calling get_sync_info");
+               goto error;
        }
-       
-       if (!info->name) {
-               osync_debug("python", 1, "The plugin didn't set its name!");
+       Py_DECREF(pyret);
+
+       if (!osync_plugin_get_name(plugin)) {
+               osync_trace(TRACE_INTERNAL, "%s: the plugin %s didn't set its name", __func__, modulename);
        }
 
-       osync_plugin_set_access_objformat(info, NULL, NULL, pm_access);
-       osync_plugin_set_commit_objformat(info, NULL, NULL, pm_commit_change);
+       osync_plugin_set_initialize(plugin, pm_initialize);
+       osync_plugin_set_discover(plugin, pm_discover);
+       osync_plugin_set_finalize(plugin, pm_finalize);
+       osync_plugin_set_data(plugin, g_strdup(modulename));
+       osync_plugin_env_register_plugin(env, plugin);
+       osync_plugin_unref(plugin);
 
        osync_trace(TRACE_EXIT, "%s", __func__);
        return TRUE;
+
+error:
+       PYERR_CLEAR();
+       osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
+       Py_XDECREF(module);
+       Py_XDECREF(pyplugin_cobj);
+       Py_XDECREF(pyplugin);
+       return FALSE;
 }
 
-static osync_bool scan_for_plugins(OSyncEnv *env, PyObject *osync_module)
+static osync_bool scan_for_plugins(OSyncPluginEnv *env, PyObject *osync_module, OSyncError **error)
 {
-       osync_trace(TRACE_ENTRY, "%s(%p)", __func__, env);
+       osync_trace(TRACE_ENTRY, "%s(%p, %p)", __func__, env, osync_module);
 
-       char *path = OPENSYNC_PYTHONPLG_DIR;
        GError *gerror = NULL;
-       GDir *dir = g_dir_open(path, 0, &gerror);
+       GDir *dir = g_dir_open(OPENSYNC_PYTHONPLG_DIR, 0, &gerror);
        if (!dir) {
-               osync_trace(TRACE_EXIT_ERROR, "%s: Unable to open directory %s: %s", __func__, path, gerror ? gerror->message : "None");
+               osync_trace(TRACE_EXIT_ERROR, "%s: Unable to open directory %s: %s", __func__, OPENSYNC_PYTHONPLG_DIR, gerror ? gerror->message : "None");
                return FALSE;
        }
 
-       const char *de = NULL;
-       while ((de = g_dir_read_name(dir))) {
-               char *filename = g_build_filename(path, de, NULL);
-               OSyncError *error = NULL;
-               if (!register_plugin(env, osync_module, filename, &error))
-                       osync_debug("python", 1, "Couldn't register plugin \"%s\": %s", filename, osync_error_print(&error));
-
-               g_free(filename);
+       /* scan through the plugin directory looking for python modules (*.py)
+        * for each matching file, drop the .py extension to get the module name, and try to register its plugin */
+       const char *filename = NULL;
+       while ((filename = g_dir_read_name(dir))) {
+               if (g_str_has_suffix(filename, ".py")) {
+                       char *modulename = g_strndup(filename, strlen(filename) - 3);
+                       if (!register_plugin(env, osync_module, modulename, error))
+                               osync_trace(TRACE_INTERNAL, "Couldn't register python plugin \"%s\": %s", filename, osync_error_print(error));
+                       g_free(modulename);
+               }
        }
        g_dir_close(dir);
 
@@ -397,21 +525,113 @@
        return TRUE;
 }
 
-void get_info(OSyncEnv *env)
+/* set python search path to look in our module directory first */
+static osync_bool set_search_path(OSyncError **error)
+{
+       PyObject *sys_module = PyImport_ImportModule("sys");
+       if (!sys_module) {
+               osync_error_set(error, OSYNC_ERROR_GENERIC, "Couldn't import sys module");
+               PYERR_CLEAR();
+               return FALSE;
+       }
+       
+       PyObject *path = PyObject_GetAttrString(sys_module, "path");
+       if (!path) {
+               osync_error_set(error, OSYNC_ERROR_GENERIC, "sys module has no path attribute?");
+               PYERR_CLEAR();
+               Py_DECREF(sys_module);
+               return FALSE;
+       }
+       
+       if (!PyList_Check(path)) {
+               osync_error_set(error, OSYNC_ERROR_GENERIC, "sys.path is not a list?");
+               Py_DECREF(sys_module);
+               Py_DECREF(path);
+               return FALSE;
+       }
+       
+       PyObject *plugindir = Py_BuildValue("s", OPENSYNC_PYTHONPLG_DIR);
+       if (!plugindir) {
+               osync_error_set(error, OSYNC_ERROR_GENERIC, "Error constructing plugindir string for sys.path");
+               PYERR_CLEAR();
+               Py_DECREF(sys_module);
+               Py_DECREF(path);
+               return FALSE;
+       }
+       
+       int r = PySequence_Contains(path, plugindir);
+       if (r < 0) {
+               osync_error_set(error, OSYNC_ERROR_GENERIC, "Error checking for 'plugindir in sys.path'");
+               PYERR_CLEAR();
+               Py_DECREF(sys_module);
+               Py_DECREF(path);
+               Py_DECREF(plugindir);
+               return FALSE;
+       }
+       
+       if (r == 0 && PyList_Insert(path, 0, plugindir) != 0) {
+               osync_error_set(error, OSYNC_ERROR_GENERIC, "Error inserting plugin directory into sys.path");
+               PYERR_CLEAR();
+               Py_DECREF(sys_module);
+               Py_DECREF(path);
+               Py_DECREF(plugindir);
+               return FALSE;
+       }
+       
+       Py_DECREF(sys_module);
+       Py_DECREF(path);
+       Py_DECREF(plugindir);
+
+       return TRUE;
+}
+
+osync_bool get_sync_info(OSyncPluginEnv *env, OSyncError **error)
 {
-       /* Python initialization */
-       struct sigaction old_sigint;
+       osync_trace(TRACE_ENTRY, "%s(%p)", __func__, env);
+       
+       /* Because OpenSync likes to call this function multiple times in
+        * different threads, and because we may be sharing the python
+        * interpreter with other code, we have to:
+        *  * init python only once
+        *  * acquire the Python lock before making any API calls
+        */
+
+       if (!Py_IsInitialized()) {
+               /* We're the first user of python in this process. Initialise
+                 * it, enable threading, and release the lock that will be
+                 * re-acquired by the PyGILState_Ensure() call below. */
+               Py_InitializeEx(0);
+               PyEval_InitThreads();
+               PyEval_ReleaseLock();
+       } else if (!PyEval_ThreadsInitialized()) {
+               /* Python has been initialised, but threads are not. */
+                osync_error_set(error, OSYNC_ERROR_GENERIC, "The Python interpreter in this process has been initialised without threading support.");
+               osync_trace(TRACE_EXIT_ERROR, "%s: %s", __func__, osync_error_print(error));
+               return FALSE;
+       }
 
-       /* Hack to make python not overwrite SIGINT */
-       sigaction(SIGINT, NULL, &old_sigint);  /* Save old handler */
-       Py_Initialize();
-       sigaction(SIGINT, &old_sigint, NULL);  /* Restore it */
-       PyEval_InitThreads();
+       PyGILState_STATE pystate = PyGILState_Ensure();
+       osync_bool ret = FALSE;
 
-       OSyncError *error = NULL;
-       PyObject *osync_module = pm_load_opensync(&error); 
+       if (!set_search_path(error))
+               goto out;
+
+       /* import opensync module */
+       PyObject *osync_module = pm_load_opensync(error); 
        if (!osync_module)
-               return;
+               goto out;
+
+       ret = scan_for_plugins(env, osync_module, error);
+       Py_DECREF(osync_module);
+
+out:
+       PyGILState_Release(pystate);
 
-       scan_for_plugins(env, osync_module);
+       osync_trace(ret ? TRACE_EXIT : TRACE_EXIT_ERROR, "%s", __func__);
+       return ret;
+}
+
+int get_version(void)
+{
+       return 1; /* opensync plugin API version we expect */
 }
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/libopensync-plugin-python-module-0.22/src/sample.py new/libopensync-plugin-python-module-0.32/src/sample.py
--- old/libopensync-plugin-python-module-0.22/src/sample.py     2006-08-25 13:57:03.000000000 +0200
+++ new/libopensync-plugin-python-module-0.32/src/sample.py     2007-02-21 01:05:21.000000000 +0100
@@ -1,47 +1,65 @@
 import opensync
 
-class SyncClass:
-       def __init__(self, member):
-               self.__member = member
-
-       def connect(self, ctx):
-               print "Connect called!!"
-               ctx.report_success()
-
-       def get_changeinfo(self, ctx):
-               print "get_changeinfo called!!"
-               if self.__member.get_slow_sync("data"):
-                       print "Slow-sync requested"
-               change = opensync.OSyncChange()
-               change.uid = "testuid"
-               change.data = "testdata"
-               change.format = "plain"
-               change.objtype = "data"
-               change.changetype = opensync.CHANGE_ADDED
-               change.report(ctx)
-               ctx.report_success()
-               print "done with get_changeinfo"
+class DummySink(opensync.ObjTypeSinkCallbacks):
+       def __init__(self, objtype):
+               opensync.ObjTypeSinkCallbacks.__init__(self, objtype)
+               self.sink.add_objformat("file")
+
+       def connect(self, info, ctx):
+               print "Connect called!"
+
+       def get_changes(self, info, ctx):
+               print "get_changes called!"
+               #if self.__member.get_slow_sync("data"):
+                       #print "Slow-sync requested"
+               #change = opensync.Change()
+               #change.uid = "testuid"
+               #change.data = "testdata"
+               #change.format = "plain"
+               #change.objtype = "data"
+               #change.changetype = opensync.CHANGE_ADDED
+               #change.report(ctx)
+               #print "done with get_changeinfo"
        
-       def commit_change(self, ctx, chg):
-               print "commit called!!"
-               print "Opensync wants me to write data with size " + len(chg.data)
-               ctx.report_success()
+       def commit(self, info, ctx, chg):
+               print "commit called!"
+               print "Opensync wants me to write data for UID", chg.uid
+       
+       def committed_all(self, info, ctx):
+               print "committed_all called!"
+
+       def read(self, info, ctx, chg):
+               print "read called!"
+               print "OpenSync wants me to read the data for UID", chg.uid
+
+       def write(self, info, ctx, chg):
+               print "write called!"
+               print "Opensync wants me to write data for UID", chg.uid
        
-       def disconnect(self, ctx):
+       def disconnect(self, info, ctx):
                print "disconnect called!"
-               ctx.report_success()
 
-       def sync_done(self, ctx):
+       def sync_done(self, info, ctx):
                print "sync_done called!"
-               ctx.report_success()
-               
-       def finalize(self):
-               print "finalize called!"
-       
-def initialize(member):
-       return SyncClass(member)
 
-def get_info(info):
-       info.accept_objtype("data")
-       info.accept_objformat("data", "plain")
-       info.name = "testmodule"
\ No newline at end of file
+def initialize(info):
+       print "initialize called!"
+       print "My config is:", info.config
+       print "Adding new sink"
+       info.add_objtype(DummySink("data").sink)
+       print "Done"
+
+def discover(info):
+       print "discover called!"
+       for sink in info.objtypes:
+               print "setting sink available:", sink
+               sink.available = True
+       info.version = opensync.Version()
+       info.version.plugin = "python-sample"
+       print "done"
+
+def get_sync_info(plugin):
+       plugin.name = "python-sample"
+       plugin.longname = "Sample sync plugin for the Python module"
+       plugin.description = "This plugin only shows what must be implemented."
+       plugin.config_type = opensync.PLUGIN_NO_CONFIGURATION


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



Remember to have fun...

---------------------------------------------------------------------
To unsubscribe, e-mail: opensuse-commit+unsubscribe@xxxxxxxxxxxx
For additional commands, e-mail: opensuse-commit+help@xxxxxxxxxxxx

< Previous Next >
This Thread