[current results] Add 'fetch' and 'getResults' subcommands to client

Change-Id: Ic99e8c665ff5892cbebd5b46f8240bb1dcaa5a7e
Reviewed-on: https://dart-review.googlesource.com/c/dart_ci/+/151243
Reviewed-by: Alexander Thomas <athom@google.com>
diff --git a/current_results/bin/client.dart b/current_results/bin/client.dart
index 0801250..1b85b0a 100644
--- a/current_results/bin/client.dart
+++ b/current_results/bin/client.dart
@@ -2,36 +2,63 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'package:args/args.dart';
+import 'package:args/command_runner.dart';
 import 'package:grpc/grpc.dart';
 
+import 'package:current_results/src/generated/google/protobuf/empty.pb.dart';
 import 'package:current_results/src/generated/query.pbgrpc.dart';
 
 void main(List<String> args) async {
-  final results = parseArgs(args);
+  final runner = CommandRunner<void>(
+      'client.dart', 'Send gRPC requests to current results server')
+    ..addCommand(QueryCommand())
+    ..addCommand(FetchCommand())
+    ..argParser.addOption('host', help: 'Current results server to query')
+    ..argParser
+        .addOption('port', abbr: 'p', help: 'Port of current results server');
+  await runner.run(args);
+}
 
-  final query = GetResultsRequest();
-  query.names.addAll(results['name']);
-  query.configurations.addAll(results['configuration']);
-
-  final channel = ClientChannel(results['host'],
-      port: int.parse(results['port']),
-      options:
-          const ChannelOptions(credentials: ChannelCredentials.insecure()));
-  try {
-    final result = await QueryClient(channel).getResults(query);
-    print(result.toProto3Json());
-  } finally {
-    await channel.shutdown();
+abstract class gRpcCommand extends Command {
+  Future<void> runWithChannel(ClientChannel channel);
+  Future<void> run() async {
+    final channel = ClientChannel(globalResults['host'],
+        port: int.parse(globalResults['port']),
+        options:
+            const ChannelOptions(credentials: ChannelCredentials.insecure()));
+    try {
+      await runWithChannel(channel);
+    } finally {
+      await channel.shutdown();
+    }
   }
 }
 
-ArgResults parseArgs(List<String> args) {
-  final parser = ArgParser();
-  parser.addMultiOption('name', abbr: 'n', help: 'Test to fetch results for');
-  parser.addMultiOption('configuration',
-      abbr: 'c', help: 'Configuration to fetch results for');
-  parser.addOption('host', abbr: 'h', help: 'Current results server to query');
-  parser.addOption('port', abbr: 'p', help: 'Port of current results server');
-  return parser.parse(args);
+class QueryCommand extends gRpcCommand {
+  QueryCommand() {
+    argParser.addMultiOption('name',
+        abbr: 'n', help: 'Test name or prefix to fetch results for');
+    argParser.addMultiOption('configuration',
+        abbr: 'c', help: 'Configuration to fetch results for');
+  }
+  String get name => 'getResults';
+  String get description => 'Send a GetResults gRPC request to the server';
+
+  Future<void> runWithChannel(ClientChannel channel) async {
+    final request = GetResultsRequest();
+    request.names.addAll(argResults['name']);
+    request.configurations.addAll(argResults['configuration']);
+    final result = await QueryClient(channel).getResults(request);
+    print(result.toProto3Json());
+  }
+}
+
+class FetchCommand extends gRpcCommand {
+  String get name => 'fetch';
+  String get description => 'Send a Fetch gRPC request to the server';
+
+  Future<void> runWithChannel(ClientChannel channel) async {
+    final result = await QueryClient(channel).fetch(Empty());
+    print(result.toProto3Json());
+  }
 }