Control: tags -1 + patch pending Dear Tino,
I confirm that the patch pointed by Josselin fixes the bug. I have therefore uploaded to DELAYED/2 a NMU of syncevolution versioned 1.2.99.1-1.1, including this patch. The debdiff is attached. Le samedi 09 mars 2013 à 17:30 +0100, Tino Keitel a écrit : > I already prepared a -2 version with several fixes, including the > autosync issue, but got interrupted due to the birth of a baby girl. > I'll try to push it to the alioth git repository, and would appreciate > some help getting it reviewed/accepted for wheezy or wheezy-updates. I did not upload the changes that you have pushed to git for the following reasons: - you build-depend on a version of libsynthesis which is not (yet?) in Debian - you included several patches fixing bugs of non-RC severity; this is no longer possible at this stage of the freeze for an upload targeting Wheezy - your changelog entry is incomplete; it does not list all the added patches, and it does not close the present bug Thanks for your work, and congratulations for the birth of your girl, -- .''`. Sébastien Villemot : :' : Debian Developer `. `' http://www.dynare.org/sebastien `- GPG Key: 4096R/381A7594
diff -Nru syncevolution-1.2.99.1/debian/changelog syncevolution-1.2.99.1/debian/changelog --- syncevolution-1.2.99.1/debian/changelog 2012-06-29 12:42:39.000000000 +0200 +++ syncevolution-1.2.99.1/debian/changelog 2013-04-01 20:19:15.000000000 +0200 @@ -1,3 +1,12 @@ +syncevolution (1.2.99.1-1.1) unstable; urgency=low + + * Non-maintainer upload. + * dbus-auto-activation.patch: new patch backported from upstream; fix + D-Bus auto-activation. Thanks to Josselin Mouette for pointing to the + relevant commit. (Closes: #699852) + + -- Sébastien Villemot <sebast...@debian.org> Mon, 01 Apr 2013 20:12:55 +0200 + syncevolution (1.2.99.1-1) unstable; urgency=low * New upstream release candidate (Closes: #675288) diff -Nru syncevolution-1.2.99.1/debian/patches/dbus-auto-activation.patch syncevolution-1.2.99.1/debian/patches/dbus-auto-activation.patch --- syncevolution-1.2.99.1/debian/patches/dbus-auto-activation.patch 1970-01-01 01:00:00.000000000 +0100 +++ syncevolution-1.2.99.1/debian/patches/dbus-auto-activation.patch 2013-04-01 20:19:24.000000000 +0200 @@ -0,0 +1,313 @@ +commit 217a20fca5d4a861f33fb0ac5d3386dd2ac27a3b +Author: Patrick Ohly <patrick.o...@intel.com> +Date: Mon Aug 13 21:51:21 2012 +0200 + + D-Bus server + GIO D-Bus: fix auto-activation (Debian bug #599247) + + When syncevo-dbus-server was started on demand by the D-Bus daemon, + then it registered itself with the daemon before it was ready to + serve requests. Only happened in combination with GIO D-Bus and + thus was not a problem before 1.2.99.x. + + One user-visible effect was that the GTK UI did select the default + service when it was started for the first time, because it could not + retrieve that information from syncevo-dbus-server. + + The fix consists of delaying the name acquisition. That gives the + caller a chance to register D-Bus objects first, before completing the + connection setup. The semantic change is that + dbus_bus_connection_undelay() must be called on new connections which + have a name (a NOP with libdbus). + + This patch tries to minimize code changes. The downside of not + changing the GDBusCXX API more radically is that the bus name must be + attached to DBusConnectionPtr, where it will be copied into each + reference to the connection. Hopefully std::string is smart enough to + share the (small) data in this case. Should be solved cleaner once + libdbus support can be deprecated. + + A test for auto-activation and double start of syncevo-dbus-server + is also added. + + Modified src/dbus/server/main.cpp +diff --git a/src/dbus/server/main.cpp b/src/dbus/server/main.cpp +index 965821b..a63c735 100644 +--- a/src/dbus/server/main.cpp ++++ b/src/dbus/server/main.cpp +@@ -150,6 +150,7 @@ int main(int argc, char **argv, char **envp) + unsetenv("G_DBUS_DEBUG"); + } + ++ dbus_bus_connection_undelay(conn); + server->run(); + SE_LOG_DEBUG(NULL, NULL, "cleaning up"); + server.reset(); + Modified src/gdbusxx/gdbus-cxx-bridge.cpp +diff --git a/src/gdbusxx/gdbus-cxx-bridge.cpp b/src/gdbusxx/gdbus-cxx-bridge.cpp +index 1c26d11..1336fd3 100644 +--- a/src/gdbusxx/gdbus-cxx-bridge.cpp ++++ b/src/gdbusxx/gdbus-cxx-bridge.cpp +@@ -33,12 +33,63 @@ namespace GDBusCXX { + MethodHandler::MethodMap MethodHandler::m_methodMap; + boost::function<void (void)> MethodHandler::m_callback; + +-static void GDBusNameLost(GDBusConnection *connection, +- const gchar *name, +- gpointer user_data) ++// It should be okay to use global variables here because they are ++// only used inside the main thread while it waits in undelay() for a ++// positive or negative result to g_bus_own_name_on_connection(). ++// Once acquired, the name can only get lost again when the ++// D-Bus daemon dies (no name owership alloed), in which case the ++// process dies anyway. ++static bool nameError; ++static bool nameAcquired; ++static void BusNameAcquired(GDBusConnection *connection, ++ const gchar *name, ++ gpointer userData) throw () + { +- g_critical("lost D-Bus connection or failed to obtain %s D-Bus name, quitting", name); +- exit(1); ++ try { ++ g_debug("got D-Bus name %s", name); ++ nameAcquired = true; ++ } catch (...) { ++ nameError = true; ++ } ++} ++ ++static void BusNameLost(GDBusConnection *connection, ++ const gchar *name, ++ gpointer userData) throw () ++{ ++ try { ++ g_debug("lost %s %s", ++ connection ? "D-Bus connection for name" : ++ "D-Bus name", ++ name); ++ } catch (...) { ++ } ++ nameError = true; ++} ++ ++void DBusConnectionPtr::undelay() const ++{ ++ if (!m_name.empty()) { ++ g_debug("starting to acquire D-Bus name %s", m_name.c_str()); ++ nameAcquired = false; ++ nameError = false; ++ char *copy = g_strdup(m_name.c_str()); ++ g_bus_own_name_on_connection(get(), ++ copy, ++ G_BUS_NAME_OWNER_FLAGS_NONE, ++ BusNameAcquired, ++ BusNameLost, ++ copy, ++ g_free); ++ while (!nameAcquired && !nameError) { ++ g_main_context_iteration(NULL, true); ++ } ++ g_debug("done with acquisition of %s", m_name.c_str()); ++ if (nameError) { ++ throw std::runtime_error("could not obtain D-Bus name - already running?"); ++ } ++ } ++ g_dbus_connection_start_message_processing(get()); + } + + DBusConnectionPtr dbus_get_bus_connection(const char *busType, +@@ -48,10 +99,13 @@ DBusConnectionPtr dbus_get_bus_connection(const char *busType, + { + DBusConnectionPtr conn; + GError* error = NULL; ++ GBusType type = ++ boost::iequals(busType, "SESSION") ? ++ G_BUS_TYPE_SESSION : ++ G_BUS_TYPE_SYSTEM; + +- if(unshared) { +- char *address = g_dbus_address_get_for_bus_sync(boost::iequals(busType, "SESSION") ? +- G_BUS_TYPE_SESSION : G_BUS_TYPE_SYSTEM, ++ if (unshared) { ++ char *address = g_dbus_address_get_for_bus_sync(type, + NULL, &error); + if(address == NULL) { + if (err) { +@@ -76,9 +130,7 @@ DBusConnectionPtr dbus_get_bus_connection(const char *busType, + } + } else { + // This returns a singleton, shared connection object. +- conn = DBusConnectionPtr(g_bus_get_sync(boost::iequals(busType, "SESSION") ? +- G_BUS_TYPE_SESSION : +- G_BUS_TYPE_SYSTEM, ++ conn = DBusConnectionPtr(g_bus_get_sync(type, + NULL, &error), + false); + if(conn == NULL) { +@@ -89,11 +141,11 @@ DBusConnectionPtr dbus_get_bus_connection(const char *busType, + } + } + +- if(name) { +- // Copy name, to ensure that it remains available. +- char *copy = g_strdup(name); +- g_bus_own_name_on_connection(conn.get(), copy, G_BUS_NAME_OWNER_FLAGS_NONE, +- NULL, GDBusNameLost, copy, g_free); ++ if (name) { ++ // Request name later in undelay(), after the caller ++ // had a chance to add objects. ++ conn.addName(name); ++ // Acting as client, need to stop when D-Bus daemon dies. + g_dbus_connection_set_exit_on_close(conn.get(), TRUE); + } + +@@ -124,11 +176,6 @@ DBusConnectionPtr dbus_get_bus_connection(const std::string &address, + return conn; + } + +-void dbus_bus_connection_undelay(const DBusConnectionPtr &conn) +-{ +- g_dbus_connection_start_message_processing(conn.get()); +-} +- + static void ConnectionLost(GDBusConnection *connection, + gboolean remotePeerVanished, + GError *error, + Modified src/gdbusxx/gdbus-cxx-bridge.h +diff --git a/src/gdbusxx/gdbus-cxx-bridge.h b/src/gdbusxx/gdbus-cxx-bridge.h +index 289c3ae..7b78a03 100644 +--- a/src/gdbusxx/gdbus-cxx-bridge.h ++++ b/src/gdbusxx/gdbus-cxx-bridge.h +@@ -124,6 +124,14 @@ inline void throwFailure(const std::string &object, + + class DBusConnectionPtr : public boost::intrusive_ptr<GDBusConnection> + { ++ /** ++ * Bus name of client, as passed to dbus_get_bus_connection(). ++ * The name will be requested in dbus_bus_connection_undelay() = ++ * undelay(), to give the caller a chance to register objects on ++ * the new connection. ++ */ ++ std::string m_name; ++ + public: + DBusConnectionPtr() {} + // connections are typically created once, so increment the ref counter by default +@@ -141,6 +149,9 @@ class DBusConnectionPtr : public boost::intrusive_ptr<GDBusConnection> + typedef boost::function<void ()> Disconnect_t; + void setDisconnect(const Disconnect_t &func); + // #define GDBUS_CXX_HAVE_DISCONNECT 1 ++ ++ void undelay() const; ++ void addName(const std::string &name) { m_name = name; } + }; + + class DBusMessagePtr : public boost::intrusive_ptr<GDBusMessage> +@@ -224,7 +235,7 @@ DBusConnectionPtr dbus_get_bus_connection(const std::string &address, + DBusErrorCXX *err, + bool delayed = false); + +-void dbus_bus_connection_undelay(const DBusConnectionPtr &conn); ++inline void dbus_bus_connection_undelay(const DBusConnectionPtr &conn) { conn.undelay(); } + + /** + * Wrapper around DBusServer. Does intentionally not expose + Modified test/test-dbus.py +diff --git a/test/test-dbus.py b/test/test-dbus.py +index 3f2532d..5a4ee44 100755 +--- a/test/test-dbus.py ++++ b/test/test-dbus.py +@@ -63,6 +63,18 @@ configName = "dbus_unittest" + def usingValgrind(): + return 'valgrind' in os.environ.get("TEST_DBUS_PREFIX", "") + ++def which(program): ++ '''find absolute path to program (simple file name, no path) in PATH env variable''' ++ def isExe(fpath): ++ return os.path.isfile(fpath) and os.access(fpath, os.X_OK) ++ ++ for path in os.environ["PATH"].split(os.pathsep): ++ exeFile = os.path.join(path, program) ++ if isExe(exeFile): ++ return os.path.abspath(exeFile) ++ ++ return None ++ + def GrepNotifications(dbuslog): + '''finds all Notify calls and returns their parameters as list of line lists''' + return re.findall(r'^method call .* dest=.* .*interface=org.freedesktop.Notifications; member=Notify\n((?:^ .*\n)*)', +@@ -1224,6 +1236,56 @@ class TestDBusServer(DBusUtil, unittest.TestCase): + else: + self.fail("no exception thrown") + ++class TestDBusServerStart(DBusUtil, unittest.TestCase): ++ def testAutoActivation(self): ++ '''TestDBusServerStart.testAutoActivation - check that activating syncevo-dbus-server via D-Bus daemon works''' ++ # Create a D-Bus service file for the syncevo-dbus-server that we ++ # are testing (= the one in PATH). ++ shutil.rmtree(xdg_root, True) ++ dirname = os.path.join(xdg_root, "share", "dbus-1", "services") ++ os.makedirs(dirname) ++ service = open(os.path.join(dirname, "org.syncevolution.service"), "w") ++ service.write('''[D-BUS Service] ++Name=org.syncevolution ++Exec=%s ++''' % which('syncevo-dbus-server')) ++ service.close() ++ ++ # Now run a private D-Bus session in which dbus-send activates ++ # that syncevo-dbus-server. Uses a dbus-session.sh from the ++ # same dir as test-dbus.py itself. ++ env = copy.deepcopy(os.environ) ++ env['XDG_DATA_DIRS'] = os.path.abspath(os.path.join(xdg_root, "share")) ++ ++ # First run something which just starts the daemon. ++ dbus = subprocess.Popen((os.path.join(os.path.dirname(sys.argv[0]), 'dbus-session.sh'), ++ 'dbus-send', ++ '--print-reply', ++ '--dest=org.syncevolution', ++ '/', ++ 'org.freedesktop.DBus.Introspectable.Introspect'), ++ env=env, ++ stdout=subprocess.PIPE, ++ stderr=subprocess.STDOUT) ++ (out, err) = dbus.communicate() ++ self.assertEqual(0, dbus.returncode, ++ msg='introspection of syncevo-dbus-server failed:\n' + out) ++ ++ # Now try some real command. ++ dbus = subprocess.Popen((os.path.join(os.path.dirname(sys.argv[0]), 'dbus-session.sh'), ++ 'dbus-send', ++ '--print-reply', ++ '--dest=org.syncevolution', ++ '/org/syncevolution/Server', ++ 'org.syncevolution.Server.GetVersions'), ++ env=env, ++ stdout=subprocess.PIPE, ++ stderr=subprocess.STDOUT) ++ (out, err) = dbus.communicate() ++ self.assertEqual(0, dbus.returncode, ++ msg='GetVersions of syncevo-dbus-server failed:\n' + out) ++ ++ + class TestDBusServerTerm(DBusUtil, unittest.TestCase): + def setUp(self): + self.setUpServer() +@@ -1231,6 +1293,15 @@ class TestDBusServerTerm(DBusUtil, unittest.TestCase): + def run(self, result): + self.runTest(result, True, ["-d", "10"]) + ++ def testSingleton(self): ++ """TestDBusServerTerm.testSingleton - a second instance of syncevo-dbus-server must terminate right away""" ++ dbus = subprocess.Popen([ 'syncevo-dbus-server' ], ++ stdout=subprocess.PIPE, ++ stderr=subprocess.STDOUT) ++ (out, err) = dbus.communicate() ++ if not re.search(r'''\[ERROR.*already running\?\n''', out): ++ self.fail('second dbus server did not recognize already running server:\n%s' % out) ++ + @timeout(100) + def testNoTerm(self): + """TestDBusServerTerm.testNoTerm - D-Bus server must stay around during calls""" + +[back] diff -Nru syncevolution-1.2.99.1/debian/patches/series syncevolution-1.2.99.1/debian/patches/series --- syncevolution-1.2.99.1/debian/patches/series 1970-01-01 01:00:00.000000000 +0100 +++ syncevolution-1.2.99.1/debian/patches/series 2013-04-01 20:19:24.000000000 +0200 @@ -0,0 +1 @@ +dbus-auto-activation.patch
signature.asc
Description: This is a digitally signed message part