如何为gconf创建一个假“活动会话”?
我已经自动化了我的Ubuntu安装过程——我写了一段Python代码,它会在全新安装后、用户第一次登录之前自动运行(这段代码放在一个临时的 /etc/init.d/ 脚本里),可以设置从Apache及其配置到我个人的Gnome偏好设置的一切。不过,后者让我遇到了一些麻烦。
在Ubuntu 8.04(Hardy)上,这一切都运行得很好,但在8.10(Intrepid)上,当我第一次尝试访问gconf时,就出现了这个错误:
无法联系配置服务器;可能的原因包括你需要为ORBit启用TCP/IP网络,或者由于系统崩溃导致NFS锁定过期。有关信息,请查看http://www.gnome.org/projects/gconf/。(详细信息 - 1: 未在活动会话中运行)
没错,这段代码运行时没有Gnome会话,因为用户还没有登录——不过,这在之前是可以的;看起来这是Intrepid的Gnome(2.24?)的新问题。
除了直接修改gconf的XML文件,还有没有办法创建一个代理Gnome会话?或者,有其他建议吗?
(更多细节:这段Python代码以root身份运行,但在使用“gconf”模块设置我的偏好设置之前,会切换到我的用户身份。)
3 个回答
我觉得我明白你的问题了。看起来你的脚本只需要启动dbus守护进程,或者确保它已经启动。我认为这里的“会话”指的是dbus会话,而不是Gnome会话。(这里有一些证据),其实dbus和gconf在没有Gnome的情况下也能正常运行。
无论如何,假装有一个“活跃的会话”听起来不是个好主意。它只会在需要的时候去查找。
也许我们可以在pastebin上看看这个脚本?在我发表评论之前,应该先看看它。
谢谢你们,Ali和Jeremy,你们的回答对我帮助很大。我还在继续这个项目(不过我今晚先停一下)。
首先,我听了Ali的建议,尝试了Jeremy的一部分想法:我用dbus-launch来运行“gconftool-2 --spawn”。结果没成功;现在我明白为什么了(谢谢你,Jeremy)——我试图在同一个启动dbus和gconftool的python程序里使用gconf,但那个环境里没有必要的环境变量——真是傻。
当我发现gconftool-2的--direct选项时,我就把之前的想法放一边了;其实,gconftool-2内部使用的API并没有通过gconf的python绑定暴露出来。所以,我修改了python-gconf,让它可以使用这个额外的方法,一旦这个修改成功编译(我在这方面遇到了一些无关的问题),我们就看看能否解决问题——如果不能解决(也许即使能解决,因为编译这些绑定似乎会编译整个gnome!),我会找到更好的方法来管理第一个策略中的环境变量。
(无论如何,我明天会再来这里补充一个答案)
第二天到了:我在修改后的python-gconf上遇到了一点麻烦,这让我想尝试Jeremy更简单的想法,结果很好用——在进行第一次gconf操作之前,我简单地运行了“dbus-launch”,解析了得到的名称-值对,然后直接把它们添加到python的环境中。这样做之后,我运行了“gconftool-2 --spawn”。问题解决了。
我在我的电脑上安装GConf 2.24时可以复现这个问题。GConf 2.22运行得很好,但2.24就出问题了。
GConf无法启动是因为D-Bus没有运行。手动启动D-Bus和GConf守护进程后,它又能正常工作了。
我尝试通过以下方式启动D-Bus会话总线:
import dbus
dummy_bus = dbus.SessionBus()
...但出现了这个错误:
dbus.exceptions.DBusException: org.freedesktop.DBus.Error.Spawn.ExecFailed: dbus-launch failed to autolaunch D-Bus session: Autolaunch error: X11 initialization failed.
真奇怪。看起来如果X没有运行,它就不喜欢启动。为了解决这个问题,可以手动启动dbus-launch(如果我没记错的话,使用os.system()调用):
$ dbus-launch
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-eAmT3q94u0,guid=c250f62d3c4739dcc9a12d48490fc268
DBUS_SESSION_BUS_PID=15836
你需要以某种方式解析输出,并把它们放入环境变量中(你可能想用os.putenv)。为了测试,我直接在命令行中手动设置了环境变量,比如用export DBUS_SESSION_BUS_ADDRESS=blahblah...
等等。
接下来,你需要用从dbus-launch
得到的环境变量来启动gconftool-2 --spawn
。这会启动GConf守护进程。如果没有设置D-Bus环境变量,守护进程就不会启动。
然后,运行你的GConf代码。只要你为自己的脚本设置了D-Bus会话总线的环境变量,你就可以和GConf守护进程进行通信了。
我知道这很复杂。
gconftool-2
提供了一个--direct
选项,让你可以在不需要和服务器通信的情况下设置GConf变量,但我还没找到Python绑定的等效选项(除了手动输出XML)。
编辑:为了将来参考,如果有人想在普通的bash
脚本中运行dbus-launch
(而不是像这个讨论的Python脚本),很容易就能在脚本中获取会话总线地址:
#!/bin/bash
eval `dbus-launch --sh-syntax`
export DBUS_SESSION_BUS_ADDRESS
export DBUS_SESSION_BUS_PID
do_other_stuff_here