project_validator.dart 6.27 KB
Newer Older
1 2 3 4
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6 7 8 9 10 11
import 'dart:collection';

import 'package:process/process.dart';

import 'base/io.dart';
import 'convert.dart';
import 'dart_pub_json_formatter.dart';
12
import 'flutter_manifest.dart';
13 14 15 16
import 'project.dart';
import 'project_validator_result.dart';

abstract class ProjectValidator {
17
  const ProjectValidator();
18 19 20 21 22
  String get title;
  bool supportsProject(FlutterProject project);
  /// Can return more than one result in case a file/command have a lot of info to share to the user
  Future<List<ProjectValidatorResult>> start(FlutterProject project);
}
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115

/// Validator run for all platforms that extract information from the pubspec.yaml.
///
/// Specific info from different platforms should be written in their own ProjectValidator.
class GeneralInfoProjectValidator extends ProjectValidator{
  @override
  Future<List<ProjectValidatorResult>> start(FlutterProject project) async {
    final FlutterManifest flutterManifest = project.manifest;
    final List<ProjectValidatorResult> result = <ProjectValidatorResult>[];
    final ProjectValidatorResult appNameValidatorResult = _getAppNameResult(flutterManifest);
    result.add(appNameValidatorResult);
    final String supportedPlatforms = _getSupportedPlatforms(project);
    if (supportedPlatforms.isEmpty) {
      return result;
    }
    final ProjectValidatorResult supportedPlatformsResult = ProjectValidatorResult(
        name: 'Supported Platforms',
        value: supportedPlatforms,
        status: StatusProjectValidator.success
    );
    final ProjectValidatorResult isFlutterPackage = _isFlutterPackageValidatorResult(flutterManifest);
    result.addAll(<ProjectValidatorResult>[supportedPlatformsResult, isFlutterPackage]);
    if (flutterManifest.flutterDescriptor.isNotEmpty) {
      result.add(_materialDesignResult(flutterManifest));
      result.add(_pluginValidatorResult(flutterManifest));
    }
    return result;
  }

  ProjectValidatorResult _getAppNameResult(FlutterManifest flutterManifest) {
    final String appName = flutterManifest.appName;
    const String name = 'App Name';
    if (appName.isEmpty) {
      return const ProjectValidatorResult(
          name: name,
          value: 'name not found',
          status: StatusProjectValidator.error
      );
    }
    return ProjectValidatorResult(
        name: name,
        value: appName,
        status: StatusProjectValidator.success
    );
  }

  ProjectValidatorResult _isFlutterPackageValidatorResult(FlutterManifest flutterManifest) {
    final String value;
    final StatusProjectValidator status;
    if (flutterManifest.flutterDescriptor.isNotEmpty) {
      value = 'yes';
      status = StatusProjectValidator.success;
    } else {
      value = 'no';
      status = StatusProjectValidator.warning;
    }

    return ProjectValidatorResult(
        name: 'Is Flutter Package',
        value: value,
        status: status
    );
  }

  ProjectValidatorResult _materialDesignResult(FlutterManifest flutterManifest) {
    return ProjectValidatorResult(
      name: 'Uses Material Design',
      value: flutterManifest.usesMaterialDesign? 'yes' : 'no',
      status: StatusProjectValidator.success
    );
  }

  String _getSupportedPlatforms(FlutterProject project) {
    return project.getSupportedPlatforms().map((SupportedPlatform platform) => platform.name).join(', ');
  }

  ProjectValidatorResult _pluginValidatorResult(FlutterManifest flutterManifest) {
    return ProjectValidatorResult(
      name: 'Is Plugin',
      value: flutterManifest.isPlugin? 'yes' : 'no',
      status: StatusProjectValidator.success
    );
  }

  @override
  bool supportsProject(FlutterProject project) {
    // this validator will run for any type of project
    return true;
  }

  @override
  String get title => 'General Info';
}
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189

class PubDependenciesProjectValidator extends ProjectValidator {
  const PubDependenciesProjectValidator(this._processManager);
  final ProcessManager _processManager;

  @override
  Future<List<ProjectValidatorResult>> start(FlutterProject project) async {
    const String name = 'Dart dependencies';
    final ProcessResult processResult = await _processManager.run(<String>['dart', 'pub', 'deps', '--json']);
    if (processResult.stdout is! String) {
      return <ProjectValidatorResult>[
        _createProjectValidatorError(name, 'Command dart pub deps --json failed')
      ];
    }

    final LinkedHashMap<String, dynamic> jsonResult;
    final List<ProjectValidatorResult> result = <ProjectValidatorResult>[];
    try {
      jsonResult = json.decode(
        processResult.stdout.toString()
      ) as LinkedHashMap<String, dynamic>;
    } on FormatException{
      result.add(_createProjectValidatorError(name, processResult.stderr.toString()));
      return result;
    }

    final DartPubJson dartPubJson = DartPubJson(jsonResult);
    final List <String> dependencies = <String>[];

    // Information retrieved from the pubspec.lock file if a dependency comes from
    // the hosted url https://pub.dartlang.org we ignore it or if the package
    // is the current directory being analyzed (root).
    final Set<String> hostedDependencies = <String>{'hosted', 'root'};

    for (final DartDependencyPackage package in dartPubJson.packages) {
      if (!hostedDependencies.contains(package.source)) {
        dependencies.addAll(package.dependencies);
      }
    }

    if (dependencies.isNotEmpty) {
      final String verb = dependencies.length == 1 ? 'is' : 'are';
      result.add(
        ProjectValidatorResult(
          name: name,
          value: '${dependencies.join(', ')} $verb not hosted',
          status: StatusProjectValidator.warning,
        )
      );
    } else {
      result.add(
        const ProjectValidatorResult(
          name: name,
          value: 'All pub dependencies are hosted on https://pub.dartlang.org',
          status: StatusProjectValidator.success,
        )
      );
    }

    return result;
  }

  @override
  bool supportsProject(FlutterProject project) {
    return true;
  }

  @override
  String get title => 'Pub dependencies';

  ProjectValidatorResult _createProjectValidatorError(String name, String value) {
    return ProjectValidatorResult(name: name, value: value, status: StatusProjectValidator.error);
  }
}