Share this post

Driving Akonadi Next from the command line

Christian recently blogged about a small command line tool that added to the client demo application a bunch of useful functionality for interacting with Akonadi Next from the command line. This inspired me to reach into my hard drive and pull out a bit of code I'd written for a side project of mine last year and turn up the Akonadi Next command line to 11. Say hello to akonadish.

akonadish supports all the commands Christian wrote about, and adds:

  • piping and file redirect of commands for More Unix(tm)
  • able to be used in stand-alone scripts (#!/usr/bin/env akonadish style)
  • an interactive shell featuring command history, tab completion, configuration knobs, and more

Here's a quick demo of it I recorded this evening (please excuse my stuffy nose ... recovering from a Christmas cold):

We feel this will be a big help for developers, power users and system administrators alike; in fact, we could have used a tool exactly like this for Akonadi with a client just this month ... alas, this only exists for Akonadi Next.

I will continue to develop the tool in response to user need. That may include things like access to useful system information (user name, e.g.?), new Akonadi Next commands, perhaps even that ability to define custom functions that combine multiple commands into one call... it's rather flexible, all-in-all.

Adopt it for your own

Speaking of which, if you have a project that would benefit from something similar, this tool can easily be re-purposed. The Akonadi parts are all kept in their own files, while the functionality of the shell itself is entirely generic. You can add new custom syntax by adding new modules that register syntax which references functions to run in response. A simple command module looks like this:

namespace Example
{

bool hello(const QStringList &args, State &state)
{
    state.printLine("Hello to you, too!");
}

Syntax::List syntax()
{
    return Syntax::List() << Syntax("hello", QObject::tr("Description"), &Example::hello);
}

REGISTER_SYNTAX(Example)

}

Automcompletion is provided via a lambda assigned to the Syntax object's completer member:

sync.completer = &AkonadishUtils::resourceCompleter;

and sub-commands can be added by adding Syntax object to the children member:

get.children << Syntax("debug", QObject::tr("The current debug level from 0 to 6"), &CoreSyntax::printDebugLevel);

Commands can be run in an event loop when async results are needed by adding the EventDriven flag:

Syntax sync("sync", QObject::tr("..."), &AkonadiSync::sync, Syntax::EventDriven);

and autocompleters can do similarly using the State object passed in which provides commandStarted/commandFinished methods.
... all in all, pretty straightforward. If there is enough demand for it, I could even make it load commands from a plugin that matches the name of the binary (think: ln -s genericappsh myappsh), allowing it to be used entirely generically with little fuss. shrug I doubt it will come to that, but these are the possibilities that float through my head as I wait for compiles to finish. ;)

For the curious, the code can be found here.

Share this post