Improvements to API doc generation (#24084)

* Re-order platform_integration to be more featured
* Remove flutter_goldens_client
* Fix snippet precompilation to always run `pub get` and
  to detect snapshot failure
diff --git a/dev/tools/dartdoc.dart b/dev/tools/dartdoc.dart
index 752ccd2..ed542a4 100644
--- a/dev/tools/dartdoc.dart
+++ b/dev/tools/dartdoc.dart
@@ -9,9 +9,11 @@
 import 'package:args/args.dart';
 import 'package:intl/intl.dart';
 import 'package:path/path.dart' as path;
+import 'package:process/process.dart';
 
 const String kDocsRoot = 'dev/docs';
 const String kPublishRoot = '$kDocsRoot/doc';
+const String kSnippetsRoot = 'dev/snippets';
 
 /// This script expects to run with the cwd as the root of the flutter repo. It
 /// will generate documentation for the packages in `//packages/` and write the
@@ -84,22 +86,22 @@
   final String pubExecutable = '$flutterRoot/bin/cache/dart-sdk/bin/pub';
 
   // Run pub.
-  Process process = await Process.start(
+  ProcessWrapper process = ProcessWrapper(await Process.start(
     pubExecutable,
     <String>['get'],
     workingDirectory: kDocsRoot,
     environment: pubEnvironment,
-  );
+  ));
   printStream(process.stdout, prefix: 'pub:stdout: ');
   printStream(process.stderr, prefix: 'pub:stderr: ');
-  final int code = await process.exitCode;
+  final int code = await process.done;
   if (code != 0)
     exit(code);
 
   createFooter('$kDocsRoot/lib/footer.html');
   copyAssets();
   cleanOutSnippets();
-  precompileSnippetsTool();
+  await precompileSnippetsTool(pubExecutable, pubEnvironment);
 
   final List<String> dartdocBaseArgs = <String>['global', 'run'];
   if (args['checked']) {
@@ -142,6 +144,7 @@
       'cli_util',
       'csslib',
       'flutter_goldens',
+      'flutter_goldens_client',
       'front_end',
       'fuchsia_remote_debug_protocol',
       'glob',
@@ -176,19 +179,19 @@
       'package:web_socket_channel/html.dart',
     ].join(','),
     '--favicon=favicon.ico',
-    '--package-order', 'flutter,Dart,flutter_test,flutter_driver',
+    '--package-order', 'flutter,Dart,platform_integration,flutter_test,flutter_driver',
     '--auto-include-dependencies',
   ]);
 
   String quote(String arg) => arg.contains(' ') ? "'$arg'" : arg;
   print('Executing: (cd $kDocsRoot ; $pubExecutable ${dartdocArgs.map<String>(quote).join(' ')})');
 
-  process = await Process.start(
+  process = ProcessWrapper(await Process.start(
     pubExecutable,
     dartdocArgs,
     workingDirectory: kDocsRoot,
     environment: pubEnvironment,
-  );
+  ));
   printStream(process.stdout, prefix: args['json'] ? '' : 'dartdoc:stdout: ',
     filter: args['verbose'] ? const <Pattern>[] : <Pattern>[
       RegExp(r'^generating docs for library '), // unnecessary verbosity
@@ -200,7 +203,7 @@
       RegExp(r'^ warning: .+: \(.+/\.pub-cache/hosted/pub.dartlang.org/.+\)'), // packages outside our control
     ],
   );
-  final int exitCode = await process.exitCode;
+  final int exitCode = await process.done;
 
   if (exitCode != 0)
     exit(exitCode);
@@ -300,30 +303,53 @@
   }
 }
 
-File precompileSnippetsTool() {
+Future<File> precompileSnippetsTool(
+  String pubExecutable,
+  Map<String, String> pubEnvironment,
+) async {
   final File snapshotPath = File(path.join('bin', 'cache', 'snippets.snapshot'));
   print('Precompiling snippets tool into ${snapshotPath.absolute.path}');
   if (snapshotPath.existsSync()) {
     snapshotPath.deleteSync();
   }
+
+  final ProcessWrapper process = ProcessWrapper(await Process.start(
+    pubExecutable,
+    <String>['get'],
+    workingDirectory: kSnippetsRoot,
+    environment: pubEnvironment,
+  ));
+  printStream(process.stdout, prefix: 'pub:stdout: ');
+  printStream(process.stderr, prefix: 'pub:stderr: ');
+  final int code = await process.done;
+  if (code != 0)
+    exit(code);
+
   // In order to be able to optimize properly, we need to provide a training set
   // of arguments, and an input file to process.
   final Directory tempDir = Directory.systemTemp.createTempSync('dartdoc_snippet_');
   final File trainingFile = File(path.join(tempDir.path, 'snippet_training'));
   trainingFile.writeAsStringSync('```dart\nvoid foo(){}\n```');
-  Process.runSync(Platform.resolvedExecutable, <String>[
-    '--snapshot=${snapshotPath.absolute.path}',
-    '--snapshot_kind=app-jit',
-    path.join(
-      'dev',
-      'snippets',
-      'lib',
-      'main.dart',
-    ),
-    '--type=sample',
-    '--input=${trainingFile.absolute.path}',
-    '--output=${path.join(tempDir.absolute.path, 'training_output.txt')}',
-  ]);
+  try {
+    final ProcessResult result = Process.runSync(Platform.resolvedExecutable, <String>[
+      '--snapshot=${snapshotPath.absolute.path}',
+      '--snapshot_kind=app-jit',
+      path.join(
+        'lib',
+        'main.dart',
+      ),
+      '--type=sample',
+      '--input=${trainingFile.absolute.path}',
+      '--output=${path.join(tempDir.absolute.path, 'training_output.txt')}',
+    ], workingDirectory: path.absolute(kSnippetsRoot));
+    if (result.exitCode != 0) {
+      stdout.writeln(result.stdout);
+      stderr.writeln(result.stderr);
+      throw Exception('Could not generate snippets snapshot: process exited with code ${result.exitCode}');
+    }
+  } on ProcessException catch (error) {
+    throw Exception('Could not generate snippets snapshot:\n$error');
+  }
   tempDir.deleteSync(recursive: true);
   return snapshotPath;
 }