Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Command

Commands are a powerful way of extending you application or library beyond the web. Providing a way to run maintenance tasks from a console or trigger recurring jobs through an external "cron" runner.

Getting started

Creating a command handler

Getting started with a command is pretty easy. You simply have to create a new struct and implement the quokka::state::CommandHandler trait.

The handler struct should implement the FromState trait too, so that it can be easily built by the global state.

use clap::Command;
use quokka::state::{CommandHandler, FromState};

#[derive(FromState)]
struct HelloWorldCommandHandler;

impl CommandHandler for HelloWorldCommandHandler {
    fn args() -> clap::Command {
        clap::Command::new("example:hello-world")
    }

    async fn call(self, _args: clap::ArgMatches) -> quokka::Result<()> {
        println!("Hello World");

        Ok(())
    }
}

Register the command handler

With the handler created you simply have to add it within your bundle

struct HelloWorldBundle;

impl<S: Clone + Send + Sync + 'static> Pouch<S> for HelloWorldBundle {
    fn configure_commands(&self, commands: &mut Commands<S>) -> quokka::Result<()> {
        commands.register_command::<ListSessionsCommand>();

        Ok(())
    }
}

Create a CLI binary

Additionally you now have to initialize Quokka differently. Instead of calling the serve function you want to call the execute_command function which will take care of collecting the commands and dispatching the commands from arguments. This requires either a second binary or you have to wrap some parsing around it.

#[tokio::main]
async fn main() -> quokka::Result<()> {
    quokka::Quokka::<DefaultState>::try_default()?
        .load::<HelloWorldBundle>()?
        .execute_command()
        .await
}

A note on command names

The command name will be the name of the CLIs subcommand. It is recommanded to use the same bundle namespace as you would use for templates or other resources to prevent conflicts from happening.

And while it is possible to make a $BUNDE_NAME command and organize subcommands using clap, I'd like to recommend to use a subcommand per task that should to be done. This reduces the complexity of your command handler and matching the proper subcommands and colling it with clap.