01 February, 2012

PackageKit in Cheese

As I already mentioned in one of my last posts, the sharing functionality in Cheese uses nautilus-sendto, which is a runtime dependency, and we wanted to do it our best to let the user/developer/maintainer know about it:


  2. By writing a comment in the README file.

  3. By using PackageKit to install the package at runtime. If the package is not installed, and the user tries to use the sharing functionality, PackageKit will be used to install it at runtime. 

The adventure
The PackageKit bit has been quite challenging for me, and I have to admit that it took me much longer than expected :(! I have learned a lot of new things though!

The first problem I had, was that I spent a few days working on dbus-glib, which I later discovered through Dave, that was deprecated. The source of the problem and biggest issue for me was, that both of the examples I followed in the PackageKit FAQ and the Vala tutorial, were obsolete and using dbus-glib. I have already talked with Richard Hughes about the first example and marked the second one as obsolete in the Vala tutorial wiki.

After this discovery, I started using the C API and the org.freedesktop.PackageKit.Transaction interface, which offers the InstallPackages method. I realised of course, that all the examples I looked at, used the org.freedesktop.PackageKit.Modify interface instead, but from my last experience, and since I did not see this interface documented anywhere in the API, I just went on working using the 'Transaction' interface. It also took me a long time to get it 'almost' working, but it never did completely. Another failure!

While I was in the middle of this frustrating process, Dave found out, that the 'Modify' interface was actually not obsolete, and pointed me to a very interesting link that took him some time to find and explained us why all the examples we saw, were using the 'Modify' interface. We both wondered why this was not documented and so hidden, and agreed that this should be somewhere more visible.

After making all the changes in the code again to use D-Bus and the 'Modify' interface instead, I talked to Richard Hughes regarding all these issues. He was really nice, and informed me that the reason why this was not documented in the API, was because the API is just documenting the 'system interface', since the 'session interface' isn't really part of the core PackageKit project but a reference implementation that both KDE and GNOME provide. He also pointed me to another very useful link and agreed on the need of a better entry in the PackageKit FAQ, to provide the users with all these information and documentation, something I will be helping with.

Gained knowledge
I could resume what I have learned about PackageKit in a few paragraphs, that I hope will be useful for you in the future.

There are two different levels of API in PackageKit:

  - The system API: It is the 'Transaction' interface, which is more low level, but allows the developer to control everything, including things like GPG keys and EULAs. Everything is explained in the PackageKit reference manual.

  - The session API: It is the 'Modify' and 'Query' interface, which allows the developer to install a package without taking care of the low level part. This is the one used in Cheese. The documentation in this case, is not so visible as I already mentioned before, but you can find what you need in the git.gnome.org repositories under the /src and /docs directories of gnome-packagekit.

Dave wrote a nice generic synchronous example of PackageKit usage in Vala, using the 'Modify' interface:

[DBus (name = "org.freedesktop.PackageKit.Modify")]
interface Packagekit : Object {
    public abstract void install_package_names (uint xid, string[] packages,
                                                                            string interaction) throws IOError;}


int main () { 
    Packagekit pk;
    try {
        pk = Bus.get_proxy_sync (BusType.SESSION, "org.freedesktop.PackageKit",
                                                   "/org/freedesktop/PackageKit");

        string[] packages = {"nautilus-sendto" };
        var interaction = "hide-confirm-search,hide-finished,hide-warning";
        pk.install_package_names (0, packages, interaction);
    } catch (IOError error) {
        critical ("D-Bus error: %s", error.message);
        return 1;
    }
    return 0;

}

This is basically what you need to know if you want to install any package at runtime in your application using PackageKit, and do not want to bother with the details. I have used the asynchronous version of it for Cheese.

PackageKit in Cheese.

This has been a long post, but as you can see, it was quite an adventure to get here! I will write soon with more news!