DBus support for JHBuild (2)

Since the last post, I’ve began to implement all the required methods to provide a complete DBus functionality in jhbuild. I added the following DBus interfaces:

  • dict:string,dict:string,string info (array:string modulelist): returns the information about the modules requested.
  • array:struct:string,string list (array:string modulelist): returns the list of required dependencies required to compile the module list.
  • async update (array:string modulelist, array:string skiplist, string start, string datespec): updates the modules in modulelist and their dependencies, starting in start parameter, ignoring the modules in skiplist. The checkouts will be obtained using the datespec.
  • async updateone (array:string modulelist, string datespec): updates the modules in modulelist. The checkouts will be obtained using the datespec.
  • async build (array:string modulelist, array:string skiplist, string start, string datespec, dict:string,string options): builds the modules in modulelist and their dependencies, starting in start parameter, ignoring the modules in skiplist. The checkouts will be obtained using the datespec. The options parameter is a dictionary of additional options. They can be autogen (forces autogen.sh of the module), clean (calls make clean before compiling the modules) and nonetwork (forces avoiding access to network, and then, avoids accessing version control repositories).
  • async buildone (array:string modulelist, string datespec, dict:string,string options): builds the modules in modulelist. The checkouts will be obtained using the datespec. The options work in the same way as in build command.
  • void set_autogen(boolean enabled): set the global autogen parameter value. If set, it will run always autogen.sh before compiling modules.
  • boolean get_autogen(): obtains the current global autogen parameter value.
  • void set_clean(boolean enabled): set the global makeclean parameter value. If set, it will run always run make clean before compiling modules.
  • boolean get_ckean(): obtains the current global autogen parameter value.
  • void set_nonetwork(boolean enabled): set the global nonetwork parameter value. If set, it will run always avoid networks access (and checkouts) for build and buildone commands.
  • boolean get_nonetwork(): obtains the current global nonetwork parameter value.
  • struct:string,string,string get_status(): obtains the current compilation status. The struct has three fields: the current command (build, buildone, updateone, update), the current module, and the status/phase (idle, build, checkout, …).

You can hook to the following signals:

  • start_build_signal (): called when a build starts.
  • end_build_signal (array:string failures):called when the build ends. failures contains the list of modules that did fail.
  • start_module_signal (string module): called when a module build starts. module contains the name of the module.
  • end_module_signal (string module, boolean failed): called when a module build ends. module contains the name of the module. failed tells if the module build has failed.
  • start_phase_signal (string module, string state): called when a phase in the build of a module begins. module contains the name of the module. state contains the name of the phase.
  • end_phase_signal (string module, string state, boolean failed): called when a phase in the build of a module ends.module contains the name of the module. state contains the name of the phase. failed tells if the build phase has failed.
  • message (string message): all the messages from compilation logs are sent through this signal. If you want to retrieve the compilation log, you should hook and get all this messages. This signal is called in each phase with a frequency of 5 seconds.

The biggest problem I’ve faced these days was related to the way I could launch the subprocess for build/update commands. As it’s called in a dbus handler, I couldn’t put the jhbuild script in another thread. And the method should return immediately without waiting for the end of the command. I had to use the gobject.Idle interface to hook the build to the gobject mainloop, this way:

  1. I implemented a gobject.Idle child, and add a callback implementation calling the builder script and returning False (in order to be called only one time).
  2. I attach this idle object to the mainloop, and then end the dbus procedure implementation.

The code for the idle child is something like this:

class JHBuildBuilderIdle(gobject.Idle):
def __init__(self, builder):
gobject.Idle.__init__(self)
self.set_callback(self.callback, builder)

def callback(self, builder):
builder.build()
return False

And the call in the dbus handler is this:

@dbus.service.method('org.gnome.JHBuildIFace')
def build(self, modulelist = [], skiplist = [], start = None, datespec = None, options = {}):
[...]

build = jhbuild.frontends.get_buildscript(ownconfig, module_list)

idle = JHBuildBuilderIdle(build)
idle.attach()
return

Tomorrow I’ll add this work to the jhbuild bugzilla in order to begin the discussion upstream.