When the Levee Breaks

Yesterday I decided to start working on the porting of the Gtk2::SourceView Perl module to the new upstream API. For my convenience, and because I know I’ll probably screw up, I decided to use a local git repository so I can experiment with all the branches I want before hitting CVS. Yes, you read that right: the Perl GTK+/GNOME bindings still use CVS on SourceForge.net ((there has been talk about moving them to GNOME CVS, then to SVN, but in the end the maintenance burden would be too high, and some of the members of the team would need at least SVN accounts anyway)). Thus, I decided to import the whole gtk2-perl repository into a git one using git-cvsimport, and – lo and behold – after four hours of checkout, I got it on my machine, complete of full history.

The layout of the bindings modules is composed of a single CVS module and all the Perl modules are inside it; this is far from optimal with git ((or any other SCM software that is not CVS, for that matter)), so I proceeded to split up each Perl module into its own repository, with the help of git-filter-branch – a new command taken from the Cogito suite and added to the 1.5.3 release of git.

The filter-branch command is extremely powerful: it rewrites the history of a repository (which is a destructive operation) by passing a filter function on it. It has a set of predefined filters and contexts of operations, so what you need to do to split out a sub-directory into its own repository is call:

  $ git filter-branch --subdirectory-filter directory refspec

and after that you get all the files filtered out marked as new or modified, so you can use git reset --hard to get rid of them, and have your sub-directory contents as the only recognised content of the repository.

Unfortunately, you can’t really filter out a direct import of a CVS repository: git-cvsimport stores branches and tags, and filtering will most likely create dangling objects; so, what I did was cloning the original repository, to get rid of the local branches, and remove all the tags:

  $ git clone --no-hardlinks /tmp/gtk2-perl Gtk2-SourceView.git
  $ for TAG in `git tag`; do git tag -f -d ${TAG}; done

The --no-hardlinks switch is important for later – I have to thank Ricardo Signes for this tip; in short: it makes git use real copies instead of hardlinking files when cloning a local repository, and will make the garbage collection and pruning phases actually work and prune the unused objects from the git database.

At this point, I just filter-branched and reset:

  $ git filter-branch --subdirectory-filter Gtk2-SourceView HEAD
  $ git reset --hard

and then called:

  $ git gc --aggressive
  $ git prune

and finally obtained my local git repository of the Gtk2-SourceView module from the original CVS repository – with all the history on HEAD preserved. The good part is that the entire set of operations is very repetitive, so it’s suitable for scripting ((I did write a small script which extracted every Perl module sub-directory into its own git repository – but it’s mostly 50 lines sugarcoating the core 5 lines of actual work)). Yey for git! :-)

My Wandering Days Are Over

This weekend I’ve finally tried Vala, something I wanted to do for a while now. Vala is, for those of you that never tried it, like GOB, but on PCP and steroids and with a syntax that doesn’t make using it feel like you’re being skull-raped through your eye sockets. It’s, actually, quite a pleasant experience – if you ignore the utter brain damage of connecting signals by overloading the plus operator ((which is more a fault of C# than anything, and one of the reasons operator overloading should be banished using necromancy. Come on: signal = signal + handler? Really?)).

Surely, there are a couple of issues with the underlying C translation layer:

  • connecting signals passes the class instance pointer, but if your class does not have any property then an empty struct will be generated, which doesn’t create valid C code;
  • if you then add a dummy int, the passed pointer is still called “self” but it’s never allocated, because the Vala compiler still expects for the class to inherit from GLib.Object in this case, while it really shouldn’t;
  • so, if you want to connect to signals, you have to make your class inherit from Object, create an instance and connect to the signals in the constructor or inside a method;

The last point is a perfectly legitimate choice to be made by language designers: but, then, this snippet:

using GLib;
using Gdict;

class TestSource {
  void on_definition_found (Gdict.Context context, Gdict.Definition definition) {
    stdout.printf ("*definition for `%s' found:\n%s\n",
                   definition.get_word(),
                   definition.get_text());
  }
  static void main (string[] args) {
    var loop = new GLib.MainLoop (null, false);
    var context = new Gdict.ClientContext ("dict.org", 2628);

    context.definition_found += on_definition_found;
    try {
      context.define_word ("*", "dictionary");
   } catch (Glib.Error e) { warning (e.message); }

    loop.run ();
  }
}

should fail to compile in Vala, and not in produce invalid C code ((I think this stems from the fact that Vala, like C#, allows a mixed OO-procedural approach, like Perl and Python; but those languages usually get it right)).

Anyway, Vala is an interesting project. If it had a better integration with the rest of the toolchain (gdb, valgrind, autotools, profilers, etc.) it should definitely become one of the first class citizens of GNOME ((for instance, Apple has native Objective-C support, and that is a layer above C like Vala)).

By the way, just to try out Vala I wrote the bindings for the Gdict API. They are mostly working, so if you want to check them out, you can clone the repository here:

  git clone http://www.gnome.org/~ebassi/git/gdict-vala.git

Those are the bindings for the unstable version of Gdict, which will be released for GNOME 2.20.