runDoctorChecks function

List<DoctorCheck> runDoctorChecks({
  1. ProcessProbe probe = _probe,
  2. String? locate(
    1. ExternalTool tool
    )?,
  3. String? dartVersion,
  4. Directory? project,
})

Every check, in the order the report prints them.

probe runs a program; locate finds an external tool. Both are parameters so a test can answer for a machine it is not running on.

project, when it has a pubspec.yaml, adds one more line: its data files below the version this build writes, as a note, since the engine still reads them.

Implementation

List<DoctorCheck> runDoctorChecks({
  ProcessProbe probe = _probe,
  String? Function(ExternalTool tool)? locate,
  String? dartVersion,
  Directory? project,
}) {
  final find = locate ?? (ExternalTool t) => t.locate();
  final checks = <DoctorCheck>[];

  final dart = dartVersion ?? Platform.version.split(' ').first;
  checks.add(
    _versionCheck('Dart', dart, dartFloor, dartTested, required: true),
  );

  final machine = probe(
    Platform.isWindows ? 'flutter.bat' : 'flutter',
    const <String>['--version', '--machine'],
  );
  String? flutterRoot;
  String? flutterDart;
  if (machine == null) {
    checks.add(
      const DoctorCheck(
        'Flutter',
        DoctorStatus.missing,
        'not found on PATH',
        fix:
            'a game needs Flutter $flutterFloor or later (https://docs.flutter.dev/get-started/install); '
            'the plain Dart packages and this command do not',
      ),
    );
  } else {
    final start = machine.indexOf('{');
    final Object? info = start < 0 ? null : _tryJson(machine.substring(start));
    final map = info is Map ? info : const <String, Object?>{};
    final version = '${map['frameworkVersion'] ?? '?'}';
    flutterRoot = map['flutterRoot'] as String?;
    final channel = map['channel'] as String?;
    checks.add(
      _versionCheck(
        'Flutter',
        version,
        flutterFloor,
        flutterTested,
        required: true,
        extra: channel == null ? '' : ', $channel channel',
      ),
    );
    if (map['dartSdkVersion'] case final String bundled) {
      flutterDart = bundled.split(' ').first;
      checks.add(
        _versionCheck(
          "Flutter's Dart",
          bundled,
          dartFloor,
          dartTested,
          required: true,
        ),
      );
    }
  }

  // impellerc: what builds the Impeller shader bundles from source.
  final impellerc = flutterRoot == null ? null : _impellerc(flutterRoot);
  checks.add(
    impellerc == null
        ? const DoctorCheck(
            'impellerc',
            DoctorStatus.missing,
            'not found in the Flutter SDK\'s engine artifacts',
            fix:
                'run `flutter precache`; needed only to build shader bundles from a checkout',
          )
        : DoctorCheck('impellerc', DoctorStatus.ok, impellerc),
  );

  for (final (name, purpose, install) in const <(String, String, String)>[
    (
      'glslangValidator',
      'the WebGPU section of a material bundle',
      'install the Vulkan SDK or `brew install glslang`',
    ),
    (
      'naga',
      'the WebGPU section of a material bundle',
      '`cargo install naga-cli`',
    ),
  ]) {
    final path = findOnPath(name);
    checks.add(
      path == null
          ? DoctorCheck(
              name,
              DoctorStatus.missing,
              'not on PATH: materials build without $purpose',
              fix: install,
            )
          : DoctorCheck(name, DoctorStatus.ok, path),
    );
  }

  for (final tool in externalTools) {
    final path = find(tool);
    checks.add(
      path == null
          ? DoctorCheck(
              tool.name,
              DoctorStatus.missing,
              'not found: flutter3d convert cannot use it (${tool.purpose})',
              fix: tool.install,
            )
          : DoctorCheck(tool.name, DoctorStatus.ok, '$path (${tool.purpose})'),
    );
  }

  if (project != null && File('${project.path}/pubspec.yaml').existsSync()) {
    checks.addAll(
      projectShaderChecks(
        project,
        dart: flutterDart ?? dart,
        engineRevision: flutterRoot == null
            ? null
            : engineRevisionAt(flutterRoot),
      ),
    );
    checks
      ..addAll(projectAssetChecks(project))
      ..addAll(projectPlatformChecks(project));
    final behind = dataFilesBehind(project);
    checks.add(
      behind.isEmpty
          ? const DoctorCheck(
              'Data files',
              DoctorStatus.ok,
              'every one at the version this build writes',
            )
          : DoctorCheck(
              'Data files',
              DoctorStatus.note,
              '${behind.length} below the version this build writes '
                  '(the engine still reads them): ${behind.join(', ')}',
              fix: 'run `flutter3d migrate --data .` to lift them on disk',
            ),
    );
  }
  return checks;
}