Args Riverpod

DISCLAIMER: this package is not part of the official Riverpod packages.

args package extention with Riverpod capabilities.

args_riverpod introduce following classes:

  • ProviderCommandRunner: provides a CommandRunner with a root ProviderContainer (instanciated along with runner).
  • ProviderCommand: provides a Command with access to the root ProviderContainer.

Usage is the same as args package with following differences:

  • Branch commands can override processArgs function to handle the arguments they declare
  • Leaf commands can override processArgs function to handle the arguments they declare and must override execute function (which replace run function)
  • Provider Command Runner provides a setGlobalArgsProcessor that enable to register a listener to handle global arguments.

Note: run has been replaced by execute due to args package implementation constraints.

Root Provider Container

When creating the ProviderCommandRunner, you can pass the root ProviderContainer overrides and observers.

ProviderCommandRunner("cli", "A super CLI.", overrides: [], observers: []);

Global Options Processing

ProviderCommandRunner instanciates a Riverpod ProviderContainer that is supplied to all commands/sub-commands & args processors. This container is available as ref in processArgs and execute functions.

In order to declare a global options processor, call setGlobalArgProcessor on the ProviderCommandRunner.

void main(List<String> arguments) {
  ProviderCommandRunner("cli", "A super CLI.")
    ..setGlobalArgProcessor(GlobalOptionParser())
    ..addCommand(BranchCommand())
    ..argParser.addOption('host', help: 'Server host URL')
    ..argParser.addOption('token', help: 'Server access token')
    ..run(arguments);
}

class GlobalOptionParser extends ProviderArgsProcessor {
  @override
  Future<void> processArgs() async {
    print('GlobalOptionParser.processArgs called');
    ref.read(hostArgProvider.notifier).state = argResults?['host'];
    ref.read(tokenArgProvider.notifier).state = argResults?['token'];
  }
}

Branch Command Options Processing

A command with subcommands is known as a "branch command" and cannot be executed itself. It should call addSubcommand (often from the constructor) to register subcommands. A branch command can override processArgs to process its related arguments.

class BranchCommand extends ProviderCommand {
  @override
  final name = "branch";
  @override
  final description = "branch command";

  BranchCommand() {
    argParser.addOption('input', help: 'input file path');
    addSubcommand(LeafCommand());
  }

  @override
  void processArgs() {
    print('BranchCommand.processArgs called');
    ref.read(inputArgProvider.notifier).state = argResults?['input'];
  }
}

Leaf Command Options Processing

A command is known as a "leaf command" if it has no subcommands and is meant to be run. Leaf commands must override execute and can override processArgs.

class LeafCommand extends ProviderCommand {
  @override
  final name = "leaf";
  @override
  final description = "leaf command";

  LeafCommand() {
    argParser.addOption('output', help: 'output file path');
  }

  @override
  void processArgs() {
    print('LeafCommand.processArgs called');
    ref.read(ouputArgProvider.notifier).state = argResults?['output'];
  }

  @override
  void execute() {
    print('LeafCommand.execute called');
    ref.read(fooServiceProvider).doSomething();
  }
}

Complete Usage Example

Full usage example is available here.

You can run it as follow:

git clone git@gitlab.com:noan-public/dart-and-flutter/args_riverpod.git && cd args_riverpod

dart "$PWD/args_riverpod/example/args_riverpod_example.dart" --host server.com  --token my_token branch --input path/in-file.txt leaf --output path/out-file.txt

Libraries

args_riverpod
Support for doing something awesome.