Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor admin tools #6301

Open
jonasfj opened this issue Dec 21, 2022 · 0 comments
Open

Refactor admin tools #6301

jonasfj opened this issue Dec 21, 2022 · 0 comments

Comments

@jonasfj
Copy link
Member

jonasfj commented Dec 21, 2022

I propose that we refactor our admin tools into something that looks as follows:

/// Exception thrown when the invocation of an [AdminAction] fails.
@sealed
class AdminActionFailedException implements Exception {
  final String message;
  AdminActionFailedException(this.message);
  @override
  String toString() => message;
}

@sealed
class AdminAction {
  /// Name of the action is an identifier to be specified when the action is triggered.
  final String name;

  /// Map from option name to description of the option.
  final Map<String,String> options;

  /// A one-liner summary of what this action does.
  final String summary;

  /// A multi-line explanation of what this action does, written in markdown.
  ///
  /// This **must** explain what the action does? What the implications are?
  /// What other actions could be useful to use in conjunction.
  /// What are reasonable expectations around cache-time outs, etc.
  ///
  /// Do write detailed documentation and include examples.
  final String description;

  /// Function to be called to invoke the action.
  ///
  /// This function is passed an [arguments] Map where keys match the keys in [options].
  /// Returns a JSON response, a failed invocation should throw [AdminActionFailedException], or
  /// a [ResponseException].
  /// Any other exception will be considered an internal error.
  final Future<Map<String, dynamic>>Function(Map<String,String> arguments) invoke;

  AdminAction({
    required this.name,
    required this.summary,
    required this.description,
    this.options = const <String,String>{},
    required this.invoke
  }} {
    // Check that name works as a command-line argument
    if (!RegExp(r'^[a-z][a-z0-9-]{0,128}$').hasMatch(name)) {
      throw ArgumentError.value(name, 'name');
    }
    // Check that the keys for options works as command-line options
    if (options.keys.any((k) => !RegExp(r'^[a-z][a-z0-9-]{0,128}$').hasMatch(k))) {
      throw ArgumentError.value(options, 'options');
    }
  }
}


final _adminHelpAction = AdminAction(
  name: 'help',
  summary: 'Display help message',
  description: '''Display help messages for a given action.

**Example** `help --action=help` will show the help message for this action.
''',
  options: {
    'action': 'Action for which the help message should be displayed',
  },
  invoke: (arguments) async {
    final actionName = arguments['action'] ?? '';
    final action = _registeredAdminActions.firstWhere((a) => a.name == actionName, orElse: () => null);
    if (action == null) {
      throw AdminActionFailedException('unknown action: "$actionName"');
    }
    return {
      'name': action.name,
      'summary': action.summary,
      'description': action.description,
      'options': action.options,
    };
  },
);

final _adminListAction = AdminAction(
  name: 'list',
  summary: 'List available actions',
  description: '''Display a list of available admin actions.

**Example** `list` will show a list of actions.
''',
  invoke: (arguments) async {
    return {
      'actions': {
        for (final action in _registeredAdminActions)
          action.name: action.summary,
      },
    };
  },
);

final _registeredAdminActions = [
  _adminHelpAction,
  _adminListAction,
];

On the CLI client side, we'll have to print the output JSON as pretty-printed YAML -- this will only be nice if we can make format YAML in the output using wrapAsCustomStyledYamlNode as proposed in dart-lang/yaml_edit#26

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant