Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Jonah Williams | f6f59c5 | 2021-04-16 14:29:32 -0700 | [diff] [blame] | 5 | import 'dart:async'; |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 6 | import 'dart:convert'; |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 7 | import 'dart:core' hide print; |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 8 | import 'dart:io' hide exit; |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 9 | import 'dart:typed_data'; |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 10 | |
Darren Austin | 807ca68 | 2021-08-25 14:56:03 -0700 | [diff] [blame] | 11 | import 'package:analyzer/dart/analysis/features.dart'; |
| 12 | import 'package:analyzer/dart/analysis/results.dart'; |
| 13 | import 'package:analyzer/dart/analysis/utilities.dart'; |
| 14 | import 'package:analyzer/dart/ast/ast.dart'; |
| 15 | import 'package:analyzer/dart/ast/visitor.dart'; |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 16 | import 'package:crypto/crypto.dart'; |
Francisco Magdaleno | 04ea318 | 2020-01-02 09:25:59 -0800 | [diff] [blame] | 17 | import 'package:meta/meta.dart'; |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 18 | import 'package:path/path.dart' as path; |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 19 | |
Jonah Williams | f6f59c5 | 2021-04-16 14:29:32 -0700 | [diff] [blame] | 20 | import 'allowlist.dart'; |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 21 | import 'run_command.dart'; |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 22 | import 'utils.dart'; |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 23 | |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 24 | final String flutterRoot = path.dirname(path.dirname(path.dirname(path.fromUri(Platform.script)))); |
| 25 | final String flutter = path.join(flutterRoot, 'bin', Platform.isWindows ? 'flutter.bat' : 'flutter'); |
Kate Lovett | 616f9bc | 2021-08-30 17:41:02 -0500 | [diff] [blame] | 26 | final String flutterPackages = path.join(flutterRoot, 'packages'); |
Dan Field | ab0a335 | 2021-12-12 13:05:03 -0800 | [diff] [blame] | 27 | final String flutterExamples = path.join(flutterRoot, 'examples'); |
Paul Berry | f3a389c | 2021-12-15 13:39:16 -0800 | [diff] [blame] | 28 | |
| 29 | /// The path to the `dart` executable; set at the top of `main` |
| 30 | late final String dart; |
| 31 | |
| 32 | /// The path to the `pub` executable; set at the top of `main` |
| 33 | late final String pub; |
| 34 | |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 35 | final String pubCache = path.join(flutterRoot, '.pub-cache'); |
| 36 | |
| 37 | /// When you call this, you can pass additional arguments to pass custom |
| 38 | /// arguments to flutter analyze. For example, you might want to call this |
| 39 | /// script with the parameter --dart-sdk to use custom dart sdk. |
| 40 | /// |
| 41 | /// For example: |
| 42 | /// bin/cache/dart-sdk/bin/dart dev/bots/analyze.dart --dart-sdk=/tmp/dart-sdk |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 43 | Future<void> main(List<String> arguments) async { |
Paul Berry | f3a389c | 2021-12-15 13:39:16 -0800 | [diff] [blame] | 44 | final String dartSdk = path.join( |
| 45 | Directory.current.absolute.path, |
| 46 | _getDartSdkFromArguments(arguments) ?? path.join(flutterRoot, 'bin', 'cache', 'dart-sdk'), |
| 47 | ); |
| 48 | dart = path.join(dartSdk, 'bin', Platform.isWindows ? 'dart.exe' : 'dart'); |
| 49 | pub = path.join(dartSdk, 'bin', Platform.isWindows ? 'pub.bat' : 'pub'); |
Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 50 | print('$clock STARTING ANALYSIS'); |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 51 | try { |
| 52 | await run(arguments); |
| 53 | } on ExitException catch (error) { |
| 54 | error.apply(); |
| 55 | } |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 56 | print('$clock ${bold}Analysis successful.$reset'); |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 57 | } |
| 58 | |
Paul Berry | f3a389c | 2021-12-15 13:39:16 -0800 | [diff] [blame] | 59 | /// Scans [arguments] for an argument of the form `--dart-sdk` or |
| 60 | /// `--dart-sdk=...` and returns the configured SDK, if any. |
| 61 | String? _getDartSdkFromArguments(List<String> arguments) { |
| 62 | String? result; |
| 63 | for (int i = 0; i < arguments.length; i += 1) { |
| 64 | if (arguments[i] == '--dart-sdk') { |
| 65 | if (result != null) { |
| 66 | exitWithError(<String>['The --dart-sdk argument must not be used more than once.']); |
| 67 | } |
| 68 | if (i + 1 < arguments.length) { |
| 69 | result = arguments[i + 1]; |
| 70 | } else { |
| 71 | exitWithError(<String>['--dart-sdk must be followed by a path.']); |
| 72 | } |
| 73 | } |
| 74 | if (arguments[i].startsWith('--dart-sdk=')) { |
| 75 | if (result != null) { |
| 76 | exitWithError(<String>['The --dart-sdk argument must not be used more than once.']); |
| 77 | } |
| 78 | result = arguments[i].substring('--dart-sdk='.length); |
| 79 | } |
| 80 | } |
| 81 | return result; |
| 82 | } |
| 83 | |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 84 | Future<void> run(List<String> arguments) async { |
Ian Hickson | 58939b7 | 2019-02-12 12:29:36 -0800 | [diff] [blame] | 85 | bool assertsEnabled = false; |
| 86 | assert(() { assertsEnabled = true; return true; }()); |
| 87 | if (!assertsEnabled) { |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 88 | exitWithError(<String>['The analyze.dart script must be run with --enable-asserts.']); |
Ian Hickson | 58939b7 | 2019-02-12 12:29:36 -0800 | [diff] [blame] | 89 | } |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 90 | |
Dan Field | ab0a335 | 2021-12-12 13:05:03 -0800 | [diff] [blame] | 91 | print('$clock No sync*/async*'); |
| 92 | await verifyNoSyncAsyncStar(flutterPackages); |
| 93 | await verifyNoSyncAsyncStar(flutterExamples, minimumMatches: 200); |
| 94 | |
Ian Hickson | bde9f11 | 2021-11-19 13:13:05 -0800 | [diff] [blame] | 95 | print('$clock No runtimeType in toString...'); |
Dan Field | 3e63411 | 2020-01-14 16:43:01 -0800 | [diff] [blame] | 96 | await verifyNoRuntimeTypeInToString(flutterRoot); |
| 97 | |
Ian Hickson | bde9f11 | 2021-11-19 13:13:05 -0800 | [diff] [blame] | 98 | print('$clock Debug mode instead of checked mode...'); |
Jonah Williams | 0d3b44e | 2021-08-03 13:25:05 -0700 | [diff] [blame] | 99 | await verifyNoCheckedMode(flutterRoot); |
| 100 | |
Ian Hickson | bde9f11 | 2021-11-19 13:13:05 -0800 | [diff] [blame] | 101 | print('$clock Links for creating GitHub issues'); |
| 102 | await verifyIssueLinks(flutterRoot); |
| 103 | |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 104 | print('$clock Unexpected binaries...'); |
| 105 | await verifyNoBinaries(flutterRoot); |
| 106 | |
| 107 | print('$clock Trailing spaces...'); |
| 108 | await verifyNoTrailingSpaces(flutterRoot); // assumes no unexpected binaries, so should be after verifyNoBinaries |
| 109 | |
Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 110 | print('$clock Deprecations...'); |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 111 | await verifyDeprecations(flutterRoot); |
Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 112 | |
Kate Lovett | 616f9bc | 2021-08-30 17:41:02 -0500 | [diff] [blame] | 113 | print('$clock Goldens...'); |
| 114 | await verifyGoldenTags(flutterPackages); |
| 115 | |
Darren Austin | 41ff30c | 2021-08-10 23:03:48 -0700 | [diff] [blame] | 116 | print('$clock Skip test comments...'); |
| 117 | await verifySkipTestComments(flutterRoot); |
| 118 | |
Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 119 | print('$clock Licenses...'); |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 120 | await verifyNoMissingLicense(flutterRoot); |
Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 121 | |
| 122 | print('$clock Test imports...'); |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 123 | await verifyNoTestImports(flutterRoot); |
Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 124 | |
Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 125 | print('$clock Bad imports (framework)...'); |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 126 | await verifyNoBadImportsInFlutter(flutterRoot); |
Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 127 | |
| 128 | print('$clock Bad imports (tools)...'); |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 129 | await verifyNoBadImportsInFlutterTools(flutterRoot); |
Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 130 | |
| 131 | print('$clock Internationalization...'); |
Greg Spencer | 57224f8 | 2021-07-26 15:31:37 -0700 | [diff] [blame] | 132 | await verifyInternationalizations(flutterRoot, dart); |
Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 133 | |
Dan Field | 9c0bd18 | 2021-06-23 13:08:51 -0700 | [diff] [blame] | 134 | print('$clock Integration test timeouts...'); |
| 135 | await verifyIntegrationTestTimeouts(flutterRoot); |
| 136 | |
Jonah Williams | fda4094 | 2021-12-14 10:51:30 -0800 | [diff] [blame] | 137 | print('$clock null initialized debug fields...'); |
| 138 | await verifyNullInitializedDebugExpensiveFields(flutterRoot); |
| 139 | |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 140 | // Ensure that all package dependencies are in sync. |
Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 141 | print('$clock Package dependencies...'); |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 142 | await runCommand(flutter, <String>['update-packages', '--verify-only'], |
| 143 | workingDirectory: flutterRoot, |
| 144 | ); |
| 145 | |
Jonah Williams | f6f59c5 | 2021-04-16 14:29:32 -0700 | [diff] [blame] | 146 | /// Ensure that no new dependencies have been accidentally |
| 147 | /// added to core packages. |
| 148 | print('$clock Package Allowlist...'); |
| 149 | await _checkConsumerDependencies(); |
| 150 | |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 151 | // Analyze all the Dart code in the repo. |
Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 152 | print('$clock Dart analysis...'); |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 153 | await _runFlutterAnalyze(flutterRoot, options: <String>[ |
| 154 | '--flutter-repo', |
| 155 | ...arguments, |
| 156 | ]); |
| 157 | |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 158 | // Try with the --watch analyzer, to make sure it returns success also. |
| 159 | // The --benchmark argument exits after one run. |
Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 160 | print('$clock Dart analysis (with --watch)...'); |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 161 | await _runFlutterAnalyze(flutterRoot, options: <String>[ |
| 162 | '--flutter-repo', |
| 163 | '--watch', |
| 164 | '--benchmark', |
| 165 | ...arguments, |
| 166 | ]); |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 167 | |
Daco Harkes | 67fdf93 | 2021-09-27 21:38:07 +0200 | [diff] [blame] | 168 | // Analyze all the sample code in the repo. |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 169 | print('$clock Sample code...'); |
| 170 | await runCommand(dart, |
Daco Harkes | 67fdf93 | 2021-09-27 21:38:07 +0200 | [diff] [blame] | 171 | <String>[path.join(flutterRoot, 'dev', 'bots', 'analyze_sample_code.dart'), '--verbose'], |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 172 | workingDirectory: flutterRoot, |
| 173 | ); |
| 174 | |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 175 | // Try analysis against a big version of the gallery; generate into a temporary directory. |
Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 176 | print('$clock Dart analysis (mega gallery)...'); |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 177 | final Directory outDir = Directory.systemTemp.createTempSync('flutter_mega_gallery.'); |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 178 | try { |
| 179 | await runCommand(dart, |
| 180 | <String>[ |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 181 | path.join(flutterRoot, 'dev', 'tools', 'mega_gallery.dart'), |
| 182 | '--out', |
| 183 | outDir.path, |
| 184 | ], |
| 185 | workingDirectory: flutterRoot, |
| 186 | ); |
Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 187 | await _runFlutterAnalyze(outDir.path, options: <String>[ |
| 188 | '--watch', |
| 189 | '--benchmark', |
| 190 | ...arguments, |
| 191 | ]); |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 192 | } finally { |
| 193 | outDir.deleteSync(recursive: true); |
| 194 | } |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 195 | } |
| 196 | |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 197 | |
| 198 | // TESTS |
| 199 | |
Dan Field | ab0a335 | 2021-12-12 13:05:03 -0800 | [diff] [blame] | 200 | Future<void> verifyNoSyncAsyncStar(String workingDirectory, {int minimumMatches = 2000 }) async { |
| 201 | final RegExp syncPattern = RegExp(r'\s*?a?sync\*\s*?{'); |
Dan Field | bf60291 | 2021-12-14 19:00:52 -0800 | [diff] [blame] | 202 | final RegExp ignorePattern = RegExp(r'^\s*?// The following uses a?sync\* because:? '); |
| 203 | final RegExp commentPattern = RegExp(r'^\s*?//'); |
Dan Field | ab0a335 | 2021-12-12 13:05:03 -0800 | [diff] [blame] | 204 | final List<String> errors = <String>[]; |
| 205 | await for (final File file in _allFiles(workingDirectory, 'dart', minimumMatches: minimumMatches)) { |
| 206 | if (file.path.contains('test')) { |
| 207 | continue; |
| 208 | } |
| 209 | final List<String> lines = file.readAsLinesSync(); |
| 210 | for (int index = 0; index < lines.length; index += 1) { |
| 211 | final String line = lines[index]; |
| 212 | if (line.startsWith(commentPattern)) { |
| 213 | continue; |
| 214 | } |
Dan Field | bf60291 | 2021-12-14 19:00:52 -0800 | [diff] [blame] | 215 | if (line.contains(syncPattern)) { |
| 216 | int lookBehindIndex = index - 1; |
| 217 | bool hasExplanation = false; |
| 218 | while (lookBehindIndex >= 0 && lines[lookBehindIndex].startsWith(commentPattern)) { |
| 219 | if (lines[lookBehindIndex].startsWith(ignorePattern)) { |
| 220 | hasExplanation = true; |
| 221 | break; |
| 222 | } |
| 223 | lookBehindIndex -= 1; |
| 224 | } |
| 225 | if (!hasExplanation) { |
| 226 | errors.add('${file.path}:$index: sync*/async* without an explanation.'); |
| 227 | } |
Dan Field | ab0a335 | 2021-12-12 13:05:03 -0800 | [diff] [blame] | 228 | } |
| 229 | } |
| 230 | } |
| 231 | if (errors.isNotEmpty) { |
| 232 | exitWithError(<String>[ |
| 233 | '${bold}Do not use sync*/async* methods. See https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#avoid-syncasync for details.$reset', |
| 234 | ...errors, |
| 235 | ]); |
| 236 | } |
| 237 | } |
| 238 | |
Kate Lovett | 616f9bc | 2021-08-30 17:41:02 -0500 | [diff] [blame] | 239 | final RegExp _findGoldenTestPattern = RegExp(r'matchesGoldenFile\('); |
| 240 | final RegExp _findGoldenDefinitionPattern = RegExp(r'matchesGoldenFile\(Object'); |
| 241 | final RegExp _leadingComment = RegExp(r'\/\/'); |
| 242 | final RegExp _goldenTagPattern1 = RegExp(r'@Tags\('); |
| 243 | final RegExp _goldenTagPattern2 = RegExp(r"'reduced-test-set'"); |
| 244 | |
| 245 | /// Only golden file tests in the flutter package are subject to reduced testing, |
| 246 | /// for example, invocations in flutter_test to validate comparator |
| 247 | /// functionality do not require tagging. |
| 248 | const String _ignoreGoldenTag = '// flutter_ignore: golden_tag (see analyze.dart)'; |
| 249 | const String _ignoreGoldenTagForFile = '// flutter_ignore_for_file: golden_tag (see analyze.dart)'; |
| 250 | |
| 251 | Future<void> verifyGoldenTags(String workingDirectory, { int minimumMatches = 2000 }) async { |
| 252 | final List<String> errors = <String>[]; |
| 253 | await for (final File file in _allFiles(workingDirectory, 'dart', minimumMatches: minimumMatches)) { |
| 254 | bool needsTag = false; |
| 255 | bool hasTagNotation = false; |
| 256 | bool hasReducedTag = false; |
| 257 | bool ignoreForFile = false; |
| 258 | final List<String> lines = file.readAsLinesSync(); |
| 259 | for (final String line in lines) { |
| 260 | if (line.contains(_goldenTagPattern1)) { |
| 261 | hasTagNotation = true; |
| 262 | } |
| 263 | if (line.contains(_goldenTagPattern2)) { |
| 264 | hasReducedTag = true; |
| 265 | } |
| 266 | if (line.contains(_findGoldenTestPattern) |
| 267 | && !line.contains(_findGoldenDefinitionPattern) |
| 268 | && !line.contains(_leadingComment) |
| 269 | && !line.contains(_ignoreGoldenTag)) { |
| 270 | needsTag = true; |
| 271 | } |
| 272 | if (line.contains(_ignoreGoldenTagForFile)) { |
| 273 | ignoreForFile = true; |
| 274 | } |
| 275 | // If the file is being ignored or a reduced test tag is already accounted |
| 276 | // for, skip parsing the rest of the lines for golden file tests. |
| 277 | if (ignoreForFile || (hasTagNotation && hasReducedTag)) { |
| 278 | break; |
| 279 | } |
| 280 | } |
| 281 | // If a reduced test tag is already accounted for, move on to the next file. |
| 282 | if (ignoreForFile || (hasTagNotation && hasReducedTag)) { |
| 283 | continue; |
| 284 | } |
| 285 | // If there are golden file tests, ensure they are tagged for all reduced |
| 286 | // test environments. |
| 287 | if (needsTag) { |
| 288 | if (!hasTagNotation) { |
| 289 | errors.add('${file.path}: Files containing golden tests must be tagged using ' |
| 290 | '`@Tags(...)` at the top of the file before import statements.'); |
| 291 | } else if (!hasReducedTag) { |
| 292 | errors.add('${file.path}: Files containing golden tests must be tagged with ' |
| 293 | "'reduced-test-set'."); |
| 294 | } |
| 295 | } |
| 296 | } |
| 297 | if (errors.isNotEmpty) { |
| 298 | exitWithError(<String>[ |
| 299 | ...errors, |
| 300 | '${bold}See: https://github.com/flutter/flutter/wiki/Writing-a-golden-file-test-for-package:flutter$reset', |
| 301 | ]); |
| 302 | } |
| 303 | } |
| 304 | |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 305 | final RegExp _findDeprecationPattern = RegExp(r'@[Dd]eprecated'); |
Michael Goderbauer | 197b440 | 2021-03-19 15:33:05 -0700 | [diff] [blame] | 306 | final RegExp _deprecationPattern1 = RegExp(r'^( *)@Deprecated\($'); // flutter_ignore: deprecation_syntax (see analyze.dart) |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 307 | final RegExp _deprecationPattern2 = RegExp(r"^ *'(.+) '$"); |
Alexandre Ardhuin | a6832d4 | 2021-03-30 06:29:02 +0200 | [diff] [blame] | 308 | final RegExp _deprecationPattern3 = RegExp(r"^ *'This feature was deprecated after v([0-9]+)\.([0-9]+)\.([0-9]+)(\-[0-9]+\.[0-9]+\.pre)?\.',?$"); |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 309 | final RegExp _deprecationPattern4 = RegExp(r'^ *\)$'); |
| 310 | |
| 311 | /// Some deprecation notices are special, for example they're used to annotate members that |
| 312 | /// will never go away and were never allowed but which we are trying to show messages for. |
| 313 | /// (One example would be a library that intentionally conflicts with a member in another |
| 314 | /// library to indicate that it is incompatible with that other library. Another would be |
| 315 | /// the regexp just above...) |
Michael Goderbauer | 197b440 | 2021-03-19 15:33:05 -0700 | [diff] [blame] | 316 | const String _ignoreDeprecation = ' // flutter_ignore: deprecation_syntax (see analyze.dart)'; |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 317 | |
Michael Goderbauer | 584fd5f | 2020-06-16 09:15:43 -0700 | [diff] [blame] | 318 | /// Some deprecation notices are exempt for historical reasons. They must have an issue listed. |
Michael Goderbauer | 197b440 | 2021-03-19 15:33:05 -0700 | [diff] [blame] | 319 | final RegExp _legacyDeprecation = RegExp(r' // flutter_ignore: deprecation_syntax, https://github.com/flutter/flutter/issues/[0-9]+$'); |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 320 | |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 321 | Future<void> verifyDeprecations(String workingDirectory, { int minimumMatches = 2000 }) async { |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 322 | final List<String> errors = <String>[]; |
Yuqian Li | fb552ed | 2020-11-07 05:19:02 -0800 | [diff] [blame] | 323 | await for (final File file in _allFiles(workingDirectory, 'dart', minimumMatches: minimumMatches)) { |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 324 | int lineNumber = 0; |
| 325 | final List<String> lines = file.readAsLinesSync(); |
| 326 | final List<int> linesWithDeprecations = <int>[]; |
Alexandre Ardhuin | 4f9b6cf | 2020-01-07 16:32:04 +0100 | [diff] [blame] | 327 | for (final String line in lines) { |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 328 | if (line.contains(_findDeprecationPattern) && |
| 329 | !line.endsWith(_ignoreDeprecation) && |
Michael Goderbauer | 584fd5f | 2020-06-16 09:15:43 -0700 | [diff] [blame] | 330 | !line.contains(_legacyDeprecation)) { |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 331 | linesWithDeprecations.add(lineNumber); |
| 332 | } |
| 333 | lineNumber += 1; |
| 334 | } |
| 335 | for (int lineNumber in linesWithDeprecations) { |
| 336 | try { |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 337 | final Match? match1 = _deprecationPattern1.firstMatch(lines[lineNumber]); |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 338 | if (match1 == null) |
| 339 | throw 'Deprecation notice does not match required pattern.'; |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 340 | final String indent = match1[1]!; |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 341 | lineNumber += 1; |
| 342 | if (lineNumber >= lines.length) |
| 343 | throw 'Incomplete deprecation notice.'; |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 344 | Match? match3; |
| 345 | String? message; |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 346 | do { |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 347 | final Match? match2 = _deprecationPattern2.firstMatch(lines[lineNumber]); |
Tong Mu | 7abee11 | 2021-03-09 13:21:45 -0800 | [diff] [blame] | 348 | if (match2 == null) { |
| 349 | String possibleReason = ''; |
| 350 | if (lines[lineNumber].trimLeft().startsWith('"')) { |
| 351 | possibleReason = ' You might have used double quotes (") for the string instead of single quotes (\').'; |
| 352 | } |
| 353 | throw 'Deprecation notice does not match required pattern.$possibleReason'; |
| 354 | } |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 355 | if (!lines[lineNumber].startsWith("$indent '")) |
| 356 | throw 'Unexpected deprecation notice indent.'; |
| 357 | if (message == null) { |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 358 | final String firstChar = String.fromCharCode(match2[1]!.runes.first); |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 359 | if (firstChar.toUpperCase() != firstChar) |
Christopher Fujino | 5cfb16b | 2020-06-19 12:03:38 -0700 | [diff] [blame] | 360 | throw 'Deprecation notice should be a grammatically correct sentence and start with a capital letter; see style guide: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo'; |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 361 | } |
| 362 | message = match2[1]; |
| 363 | lineNumber += 1; |
| 364 | if (lineNumber >= lines.length) |
| 365 | throw 'Incomplete deprecation notice.'; |
| 366 | match3 = _deprecationPattern3.firstMatch(lines[lineNumber]); |
| 367 | } while (match3 == null); |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 368 | final int v1 = int.parse(match3[1]!); |
| 369 | final int v2 = int.parse(match3[2]!); |
Christopher Fujino | 5cfb16b | 2020-06-19 12:03:38 -0700 | [diff] [blame] | 370 | final bool hasV4 = match3[4] != null; |
| 371 | if (v1 > 1 || (v1 == 1 && v2 >= 20)) { |
| 372 | if (!hasV4) |
| 373 | throw 'Deprecation notice does not accurately indicate a dev branch version number; please see https://flutter.dev/docs/development/tools/sdk/releases to find the latest dev build version number.'; |
| 374 | } |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 375 | if (!message!.endsWith('.') && !message.endsWith('!') && !message.endsWith('?')) |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 376 | throw 'Deprecation notice should be a grammatically correct sentence and end with a period.'; |
| 377 | if (!lines[lineNumber].startsWith("$indent '")) |
| 378 | throw 'Unexpected deprecation notice indent.'; |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 379 | lineNumber += 1; |
| 380 | if (lineNumber >= lines.length) |
| 381 | throw 'Incomplete deprecation notice.'; |
| 382 | if (!lines[lineNumber].contains(_deprecationPattern4)) |
| 383 | throw 'End of deprecation notice does not match required pattern.'; |
| 384 | if (!lines[lineNumber].startsWith('$indent)')) |
| 385 | throw 'Unexpected deprecation notice indent.'; |
| 386 | } catch (error) { |
| 387 | errors.add('${file.path}:${lineNumber + 1}: $error'); |
| 388 | } |
| 389 | } |
| 390 | } |
| 391 | // Fail if any errors |
| 392 | if (errors.isNotEmpty) { |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 393 | exitWithError(<String>[ |
| 394 | ...errors, |
| 395 | '${bold}See: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes$reset', |
| 396 | ]); |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 397 | } |
| 398 | } |
| 399 | |
Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 400 | String _generateLicense(String prefix) { |
| 401 | assert(prefix != null); |
| 402 | return '${prefix}Copyright 2014 The Flutter Authors. All rights reserved.\n' |
| 403 | '${prefix}Use of this source code is governed by a BSD-style license that can be\n' |
| 404 | '${prefix}found in the LICENSE file.'; |
| 405 | } |
| 406 | |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 407 | Future<void> verifyNoMissingLicense(String workingDirectory, { bool checkMinimums = true }) async { |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 408 | final int? overrideMinimumMatches = checkMinimums ? null : 0; |
Zachary Anderson | 366648a | 2021-11-09 08:44:56 -0800 | [diff] [blame] | 409 | await _verifyNoMissingLicenseForExtension(workingDirectory, 'dart', overrideMinimumMatches ?? 2000, _generateLicense('// ')); |
| 410 | await _verifyNoMissingLicenseForExtension(workingDirectory, 'java', overrideMinimumMatches ?? 39, _generateLicense('// ')); |
| 411 | await _verifyNoMissingLicenseForExtension(workingDirectory, 'h', overrideMinimumMatches ?? 30, _generateLicense('// ')); |
| 412 | await _verifyNoMissingLicenseForExtension(workingDirectory, 'm', overrideMinimumMatches ?? 30, _generateLicense('// ')); |
| 413 | await _verifyNoMissingLicenseForExtension(workingDirectory, 'swift', overrideMinimumMatches ?? 10, _generateLicense('// ')); |
| 414 | await _verifyNoMissingLicenseForExtension(workingDirectory, 'gradle', overrideMinimumMatches ?? 80, _generateLicense('// ')); |
| 415 | await _verifyNoMissingLicenseForExtension(workingDirectory, 'gn', overrideMinimumMatches ?? 0, _generateLicense('# ')); |
| 416 | await _verifyNoMissingLicenseForExtension(workingDirectory, 'sh', overrideMinimumMatches ?? 1, '#!/usr/bin/env bash\n${_generateLicense('# ')}'); |
| 417 | await _verifyNoMissingLicenseForExtension(workingDirectory, 'bat', overrideMinimumMatches ?? 1, '@ECHO off\n${_generateLicense('REM ')}'); |
| 418 | await _verifyNoMissingLicenseForExtension(workingDirectory, 'ps1', overrideMinimumMatches ?? 1, _generateLicense('# ')); |
| 419 | await _verifyNoMissingLicenseForExtension(workingDirectory, 'html', overrideMinimumMatches ?? 1, '<!DOCTYPE HTML>\n<!-- ${_generateLicense('')} -->', trailingBlank: false); |
| 420 | await _verifyNoMissingLicenseForExtension(workingDirectory, 'xml', overrideMinimumMatches ?? 1, '<!-- ${_generateLicense('')} -->'); |
Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 421 | } |
| 422 | |
Zachary Anderson | 366648a | 2021-11-09 08:44:56 -0800 | [diff] [blame] | 423 | Future<void> _verifyNoMissingLicenseForExtension(String workingDirectory, String extension, int minimumMatches, String license, { bool trailingBlank = true }) async { |
Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 424 | assert(!license.endsWith('\n')); |
Zachary Anderson | 366648a | 2021-11-09 08:44:56 -0800 | [diff] [blame] | 425 | final String licensePattern = '$license\n${trailingBlank ? '\n' : ''}'; |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 426 | final List<String> errors = <String>[]; |
Yuqian Li | fb552ed | 2020-11-07 05:19:02 -0800 | [diff] [blame] | 427 | await for (final File file in _allFiles(workingDirectory, extension, minimumMatches: minimumMatches)) { |
Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 428 | final String contents = file.readAsStringSync().replaceAll('\r\n', '\n'); |
| 429 | if (contents.isEmpty) |
| 430 | continue; // let's not go down the /bin/true rabbit hole |
Zachary Anderson | 366648a | 2021-11-09 08:44:56 -0800 | [diff] [blame] | 431 | if (!contents.startsWith(licensePattern)) |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 432 | errors.add(file.path); |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 433 | } |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 434 | // Fail if any errors |
| 435 | if (errors.isNotEmpty) { |
Zachary Anderson | 366648a | 2021-11-09 08:44:56 -0800 | [diff] [blame] | 436 | final String s = errors.length == 1 ? ' does' : 's do'; |
| 437 | exitWithError(<String>[ |
| 438 | '${bold}The following ${errors.length} file$s not have the right license header:$reset', |
| 439 | ...errors, |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 440 | 'The expected license header is:', |
| 441 | license, |
| 442 | if (trailingBlank) '...followed by a blank line.', |
Zachary Anderson | 366648a | 2021-11-09 08:44:56 -0800 | [diff] [blame] | 443 | ]); |
xster | c7a09a4 | 2019-04-24 12:40:17 -0700 | [diff] [blame] | 444 | } |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 445 | } |
| 446 | |
Darren Austin | 807ca68 | 2021-08-25 14:56:03 -0700 | [diff] [blame] | 447 | class _TestSkip { |
| 448 | _TestSkip(this.line, this.content); |
| 449 | |
| 450 | final int line; |
| 451 | final String content; |
| 452 | } |
| 453 | |
| 454 | Iterable<_TestSkip> _getTestSkips(File file) { |
| 455 | final ParseStringResult parseResult = parseFile( |
| 456 | featureSet: FeatureSet.latestLanguageVersion(), |
| 457 | path: file.absolute.path, |
| 458 | ); |
| 459 | final _TestSkipLinesVisitor<CompilationUnit> visitor = _TestSkipLinesVisitor<CompilationUnit>(parseResult); |
| 460 | visitor.visitCompilationUnit(parseResult.unit); |
| 461 | return visitor.skips; |
| 462 | } |
| 463 | |
| 464 | class _TestSkipLinesVisitor<T> extends RecursiveAstVisitor<T> { |
| 465 | _TestSkipLinesVisitor(this.parseResult) : skips = <_TestSkip>{}; |
| 466 | |
| 467 | final ParseStringResult parseResult; |
| 468 | final Set<_TestSkip> skips; |
| 469 | |
| 470 | static bool isTestMethod(String name) { |
| 471 | return name.startsWith('test') || name == 'group' || name == 'expect'; |
| 472 | } |
| 473 | |
| 474 | @override |
| 475 | T? visitMethodInvocation(MethodInvocation node) { |
| 476 | if (isTestMethod(node.methodName.toString())) { |
| 477 | for (final Expression argument in node.argumentList.arguments) { |
| 478 | if (argument is NamedExpression && argument.name.label.name == 'skip') { |
| 479 | final int lineNumber = parseResult.lineInfo.getLocation(argument.beginToken.charOffset).lineNumber; |
| 480 | final String content = parseResult.content.substring(parseResult.lineInfo.getOffsetOfLine(lineNumber - 1), |
| 481 | parseResult.lineInfo.getOffsetOfLine(lineNumber) - 1); |
| 482 | skips.add(_TestSkip(lineNumber, content)); |
| 483 | } |
| 484 | } |
| 485 | } |
| 486 | return super.visitMethodInvocation(node); |
| 487 | } |
| 488 | } |
| 489 | |
| 490 | final RegExp _skipTestCommentPattern = RegExp(r'//(.*)$'); |
Darren Austin | 41ff30c | 2021-08-10 23:03:48 -0700 | [diff] [blame] | 491 | const Pattern _skipTestIntentionalPattern = '[intended]'; |
| 492 | final Pattern _skipTestTrackingBugPattern = RegExp(r'https+?://github.com/.*/issues/[0-9]+'); |
| 493 | |
| 494 | Future<void> verifySkipTestComments(String workingDirectory) async { |
| 495 | final List<String> errors = <String>[]; |
Darren Austin | 807ca68 | 2021-08-25 14:56:03 -0700 | [diff] [blame] | 496 | final Stream<File> testFiles =_allFiles(workingDirectory, 'dart', minimumMatches: 1500) |
Darren Austin | 41ff30c | 2021-08-10 23:03:48 -0700 | [diff] [blame] | 497 | .where((File f) => f.path.endsWith('_test.dart')); |
| 498 | |
| 499 | await for (final File file in testFiles) { |
Darren Austin | 807ca68 | 2021-08-25 14:56:03 -0700 | [diff] [blame] | 500 | for (final _TestSkip skip in _getTestSkips(file)) { |
| 501 | final Match? match = _skipTestCommentPattern.firstMatch(skip.content); |
Darren Austin | 41ff30c | 2021-08-10 23:03:48 -0700 | [diff] [blame] | 502 | final String? skipComment = match?.group(1); |
Darren Austin | 807ca68 | 2021-08-25 14:56:03 -0700 | [diff] [blame] | 503 | if (skipComment == null || |
| 504 | !(skipComment.contains(_skipTestIntentionalPattern) || |
| 505 | skipComment.contains(_skipTestTrackingBugPattern))) { |
| 506 | errors.add('${file.path}:${skip.line}: skip test without a justification comment.'); |
Darren Austin | 41ff30c | 2021-08-10 23:03:48 -0700 | [diff] [blame] | 507 | } |
| 508 | } |
| 509 | } |
| 510 | |
| 511 | // Fail if any errors |
| 512 | if (errors.isNotEmpty) { |
| 513 | exitWithError(<String>[ |
| 514 | ...errors, |
| 515 | '\n${bold}See: https://github.com/flutter/flutter/wiki/Tree-hygiene#skipped-tests$reset', |
| 516 | ]); |
| 517 | } |
| 518 | } |
| 519 | |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 520 | final RegExp _testImportPattern = RegExp(r'''import (['"])([^'"]+_test\.dart)\1'''); |
| 521 | const Set<String> _exemptTestImports = <String>{ |
| 522 | 'package:flutter_test/flutter_test.dart', |
| 523 | 'hit_test.dart', |
| 524 | 'package:test_api/src/backend/live_test.dart', |
Dan Field | 7678465 | 2020-11-05 17:28:47 -0800 | [diff] [blame] | 525 | 'package:integration_test/integration_test.dart', |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 526 | }; |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 527 | |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 528 | Future<void> verifyNoTestImports(String workingDirectory) async { |
| 529 | final List<String> errors = <String>[]; |
| 530 | assert("// foo\nimport 'binding_test.dart' as binding;\n'".contains(_testImportPattern)); |
Yuqian Li | fb552ed | 2020-11-07 05:19:02 -0800 | [diff] [blame] | 531 | final List<File> dartFiles = await _allFiles(path.join(workingDirectory, 'packages'), 'dart', minimumMatches: 1500).toList(); |
Alexandre Ardhuin | 4f9b6cf | 2020-01-07 16:32:04 +0100 | [diff] [blame] | 532 | for (final File file in dartFiles) { |
| 533 | for (final String line in file.readAsLinesSync()) { |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 534 | final Match? match = _testImportPattern.firstMatch(line); |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 535 | if (match != null && !_exemptTestImports.contains(match.group(2))) |
| 536 | errors.add(file.path); |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 537 | } |
| 538 | } |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 539 | // Fail if any errors |
| 540 | if (errors.isNotEmpty) { |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 541 | final String s = errors.length == 1 ? '' : 's'; |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 542 | exitWithError(<String>[ |
| 543 | '${bold}The following file$s import a test directly. Test utilities should be in their own file.$reset', |
| 544 | ...errors, |
| 545 | ]); |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 546 | } |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 547 | } |
| 548 | |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 549 | Future<void> verifyNoBadImportsInFlutter(String workingDirectory) async { |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 550 | final List<String> errors = <String>[]; |
| 551 | final String libPath = path.join(workingDirectory, 'packages', 'flutter', 'lib'); |
| 552 | final String srcPath = path.join(workingDirectory, 'packages', 'flutter', 'lib', 'src'); |
| 553 | // Verify there's one libPath/*.dart for each srcPath/*/. |
Alexandre Ardhuin | d927c93 | 2018-09-12 08:29:29 +0200 | [diff] [blame] | 554 | final List<String> packages = Directory(libPath).listSync() |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 555 | .where((FileSystemEntity entity) => entity is File && path.extension(entity.path) == '.dart') |
| 556 | .map<String>((FileSystemEntity entity) => path.basenameWithoutExtension(entity.path)) |
| 557 | .toList()..sort(); |
Alexandre Ardhuin | d927c93 | 2018-09-12 08:29:29 +0200 | [diff] [blame] | 558 | final List<String> directories = Directory(srcPath).listSync() |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 559 | .whereType<Directory>() |
| 560 | .map<String>((Directory entity) => path.basename(entity.path)) |
| 561 | .toList()..sort(); |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 562 | if (!_listEquals<String>(packages, directories)) { |
Alexandre Ardhuin | 34059ee | 2021-06-01 20:14:06 +0200 | [diff] [blame] | 563 | errors.add(<String>[ |
| 564 | 'flutter/lib/*.dart does not match flutter/lib/src/*/:', |
| 565 | 'These are the exported packages:', |
| 566 | ...packages.map<String>((String path) => ' lib/$path.dart'), |
| 567 | 'These are the directories:', |
| 568 | ...directories.map<String>((String path) => ' lib/src/$path/') |
| 569 | ].join('\n')); |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 570 | } |
| 571 | // Verify that the imports are well-ordered. |
| 572 | final Map<String, Set<String>> dependencyMap = <String, Set<String>>{}; |
Alexandre Ardhuin | 4f9b6cf | 2020-01-07 16:32:04 +0100 | [diff] [blame] | 573 | for (final String directory in directories) { |
Yuqian Li | fb552ed | 2020-11-07 05:19:02 -0800 | [diff] [blame] | 574 | dependencyMap[directory] = await _findFlutterDependencies(path.join(srcPath, directory), errors, checkForMeta: directory != 'foundation'); |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 575 | } |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 576 | assert(dependencyMap['material']!.contains('widgets') && |
| 577 | dependencyMap['widgets']!.contains('rendering') && |
| 578 | dependencyMap['rendering']!.contains('painting')); // to make sure we're convinced _findFlutterDependencies is finding some |
Alexandre Ardhuin | 4f9b6cf | 2020-01-07 16:32:04 +0100 | [diff] [blame] | 579 | for (final String package in dependencyMap.keys) { |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 580 | if (dependencyMap[package]!.contains(package)) { |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 581 | errors.add( |
| 582 | 'One of the files in the $yellow$package$reset package imports that package recursively.' |
| 583 | ); |
| 584 | } |
| 585 | } |
LongCatIsLooong | d291de0 | 2020-01-09 10:25:58 -0800 | [diff] [blame] | 586 | |
| 587 | for (final String key in dependencyMap.keys) { |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 588 | for (final String dependency in dependencyMap[key]!) { |
LongCatIsLooong | d291de0 | 2020-01-09 10:25:58 -0800 | [diff] [blame] | 589 | if (dependencyMap[dependency] != null) |
| 590 | continue; |
| 591 | // Sanity check before performing _deepSearch, to ensure there's no rogue |
| 592 | // dependencies. |
Alexandre Ardhuin | 34059ee | 2021-06-01 20:14:06 +0200 | [diff] [blame] | 593 | final String validFilenames = dependencyMap.keys.map((String name) => '$name.dart').join(', '); |
LongCatIsLooong | d291de0 | 2020-01-09 10:25:58 -0800 | [diff] [blame] | 594 | errors.add( |
| 595 | '$key imported package:flutter/$dependency.dart ' |
| 596 | 'which is not one of the valid exports { $validFilenames }.\n' |
| 597 | 'Consider changing $dependency.dart to one of them.' |
| 598 | ); |
| 599 | } |
| 600 | } |
| 601 | |
Alexandre Ardhuin | 4f9b6cf | 2020-01-07 16:32:04 +0100 | [diff] [blame] | 602 | for (final String package in dependencyMap.keys) { |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 603 | final List<String>? loop = _deepSearch<String>(dependencyMap, package); |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 604 | if (loop != null) { |
Alexandre Ardhuin | 34059ee | 2021-06-01 20:14:06 +0200 | [diff] [blame] | 605 | errors.add('${yellow}Dependency loop:$reset ${loop.join(' depends on ')}'); |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 606 | } |
| 607 | } |
| 608 | // Fail if any errors |
| 609 | if (errors.isNotEmpty) { |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 610 | exitWithError(<String>[ |
| 611 | if (errors.length == 1) |
| 612 | '${bold}An error was detected when looking at import dependencies within the Flutter package:$reset' |
| 613 | else |
| 614 | '${bold}Multiple errors were detected when looking at import dependencies within the Flutter package:$reset', |
| 615 | ...errors, |
| 616 | ]); |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 617 | } |
| 618 | } |
| 619 | |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 620 | Future<void> verifyNoBadImportsInFlutterTools(String workingDirectory) async { |
| 621 | final List<String> errors = <String>[]; |
Yuqian Li | fb552ed | 2020-11-07 05:19:02 -0800 | [diff] [blame] | 622 | final List<File> files = await _allFiles(path.join(workingDirectory, 'packages', 'flutter_tools', 'lib'), 'dart', minimumMatches: 200).toList(); |
Alexandre Ardhuin | 4f9b6cf | 2020-01-07 16:32:04 +0100 | [diff] [blame] | 623 | for (final File file in files) { |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 624 | if (file.readAsStringSync().contains('package:flutter_tools/')) { |
| 625 | errors.add('$yellow${file.path}$reset imports flutter_tools.'); |
| 626 | } |
| 627 | } |
| 628 | // Fail if any errors |
| 629 | if (errors.isNotEmpty) { |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 630 | exitWithError(<String>[ |
| 631 | if (errors.length == 1) |
| 632 | '${bold}An error was detected when looking at import dependencies within the flutter_tools package:$reset' |
| 633 | else |
| 634 | '${bold}Multiple errors were detected when looking at import dependencies within the flutter_tools package:$reset', |
| 635 | ...errors.map((String paragraph) => '$paragraph\n'), |
| 636 | ]); |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 637 | } |
| 638 | } |
| 639 | |
Dan Field | 9c0bd18 | 2021-06-23 13:08:51 -0700 | [diff] [blame] | 640 | Future<void> verifyIntegrationTestTimeouts(String workingDirectory) async { |
| 641 | final List<String> errors = <String>[]; |
| 642 | final String dev = path.join(workingDirectory, 'dev'); |
| 643 | final List<File> files = await _allFiles(dev, 'dart', minimumMatches: 1) |
| 644 | .where((File file) => file.path.contains('test_driver') && (file.path.endsWith('_test.dart') || file.path.endsWith('util.dart'))) |
| 645 | .toList(); |
| 646 | for (final File file in files) { |
| 647 | final String contents = file.readAsStringSync(); |
| 648 | final int testCount = ' test('.allMatches(contents).length; |
| 649 | final int timeoutNoneCount = 'timeout: Timeout.none'.allMatches(contents).length; |
| 650 | if (testCount != timeoutNoneCount) { |
| 651 | errors.add('$yellow${file.path}$reset has at least $testCount test(s) but only $timeoutNoneCount `Timeout.none`(s).'); |
| 652 | } |
| 653 | } |
| 654 | if (errors.isNotEmpty) { |
| 655 | exitWithError(<String>[ |
| 656 | if (errors.length == 1) |
Ian Hickson | 2420718 | 2021-09-15 09:42:05 -0700 | [diff] [blame] | 657 | '${bold}An error was detected when looking at integration test timeouts:$reset' |
Dan Field | 9c0bd18 | 2021-06-23 13:08:51 -0700 | [diff] [blame] | 658 | else |
Ian Hickson | 2420718 | 2021-09-15 09:42:05 -0700 | [diff] [blame] | 659 | '${bold}Multiple errors were detected when looking at integration test timeouts:$reset', |
Dan Field | 9c0bd18 | 2021-06-23 13:08:51 -0700 | [diff] [blame] | 660 | ...errors.map((String paragraph) => '$paragraph\n'), |
| 661 | ]); |
| 662 | } |
| 663 | } |
| 664 | |
Greg Spencer | 57224f8 | 2021-07-26 15:31:37 -0700 | [diff] [blame] | 665 | Future<void> verifyInternationalizations(String workingDirectory, String dartExecutable) async { |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 666 | final EvalResult materialGenResult = await _evalCommand( |
Greg Spencer | 57224f8 | 2021-07-26 15:31:37 -0700 | [diff] [blame] | 667 | dartExecutable, |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 668 | <String>[ |
Shi-Hao Hong | 7874bca | 2019-12-16 17:30:57 -0800 | [diff] [blame] | 669 | path.join('dev', 'tools', 'localization', 'bin', 'gen_localizations.dart'), |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 670 | '--material', |
| 671 | ], |
Greg Spencer | 57224f8 | 2021-07-26 15:31:37 -0700 | [diff] [blame] | 672 | workingDirectory: workingDirectory, |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 673 | ); |
| 674 | final EvalResult cupertinoGenResult = await _evalCommand( |
Greg Spencer | 57224f8 | 2021-07-26 15:31:37 -0700 | [diff] [blame] | 675 | dartExecutable, |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 676 | <String>[ |
Shi-Hao Hong | 7874bca | 2019-12-16 17:30:57 -0800 | [diff] [blame] | 677 | path.join('dev', 'tools', 'localization', 'bin', 'gen_localizations.dart'), |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 678 | '--cupertino', |
| 679 | ], |
Greg Spencer | 57224f8 | 2021-07-26 15:31:37 -0700 | [diff] [blame] | 680 | workingDirectory: workingDirectory, |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 681 | ); |
| 682 | |
Greg Spencer | 57224f8 | 2021-07-26 15:31:37 -0700 | [diff] [blame] | 683 | final String materialLocalizationsFile = path.join(workingDirectory, 'packages', 'flutter_localizations', 'lib', 'src', 'l10n', 'generated_material_localizations.dart'); |
| 684 | final String cupertinoLocalizationsFile = path.join(workingDirectory, 'packages', 'flutter_localizations', 'lib', 'src', 'l10n', 'generated_cupertino_localizations.dart'); |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 685 | final String expectedMaterialResult = await File(materialLocalizationsFile).readAsString(); |
| 686 | final String expectedCupertinoResult = await File(cupertinoLocalizationsFile).readAsString(); |
| 687 | |
| 688 | if (materialGenResult.stdout.trim() != expectedMaterialResult.trim()) { |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 689 | exitWithError(<String>[ |
| 690 | '<<<<<<< $materialLocalizationsFile', |
| 691 | expectedMaterialResult.trim(), |
| 692 | '=======', |
| 693 | materialGenResult.stdout.trim(), |
| 694 | '>>>>>>> gen_localizations', |
| 695 | 'The contents of $materialLocalizationsFile are different from that produced by gen_localizations.', |
| 696 | '', |
| 697 | 'Did you forget to run gen_localizations.dart after updating a .arb file?', |
| 698 | ]); |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 699 | } |
| 700 | if (cupertinoGenResult.stdout.trim() != expectedCupertinoResult.trim()) { |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 701 | exitWithError(<String>[ |
| 702 | '<<<<<<< $cupertinoLocalizationsFile', |
| 703 | expectedCupertinoResult.trim(), |
| 704 | '=======', |
| 705 | cupertinoGenResult.stdout.trim(), |
| 706 | '>>>>>>> gen_localizations', |
| 707 | 'The contents of $cupertinoLocalizationsFile are different from that produced by gen_localizations.', |
| 708 | '', |
| 709 | 'Did you forget to run gen_localizations.dart after updating a .arb file?', |
| 710 | ]); |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 711 | } |
| 712 | } |
| 713 | |
Jonah Williams | 0d3b44e | 2021-08-03 13:25:05 -0700 | [diff] [blame] | 714 | |
| 715 | /// Verifies that all instances of "checked mode" have been migrated to "debug mode". |
| 716 | Future<void> verifyNoCheckedMode(String workingDirectory) async { |
| 717 | final String flutterPackages = path.join(workingDirectory, 'packages'); |
| 718 | final List<File> files = await _allFiles(flutterPackages, 'dart', minimumMatches: 400) |
| 719 | .where((File file) => path.extension(file.path) == '.dart') |
| 720 | .toList(); |
| 721 | final List<String> problems = <String>[]; |
| 722 | for (final File file in files) { |
| 723 | int lineCount = 0; |
| 724 | for (final String line in file.readAsLinesSync()) { |
| 725 | if (line.toLowerCase().contains('checked mode')) { |
| 726 | problems.add('${file.path}:$lineCount uses deprecated "checked mode" instead of "debug mode".'); |
| 727 | } |
| 728 | lineCount += 1; |
| 729 | } |
| 730 | } |
| 731 | if (problems.isNotEmpty) { |
| 732 | exitWithError(problems); |
| 733 | } |
| 734 | } |
| 735 | |
| 736 | |
Dan Field | 3e63411 | 2020-01-14 16:43:01 -0800 | [diff] [blame] | 737 | Future<void> verifyNoRuntimeTypeInToString(String workingDirectory) async { |
| 738 | final String flutterLib = path.join(workingDirectory, 'packages', 'flutter', 'lib'); |
| 739 | final Set<String> excludedFiles = <String>{ |
| 740 | path.join(flutterLib, 'src', 'foundation', 'object.dart'), // Calls this from within an assert. |
| 741 | }; |
Yuqian Li | fb552ed | 2020-11-07 05:19:02 -0800 | [diff] [blame] | 742 | final List<File> files = await _allFiles(flutterLib, 'dart', minimumMatches: 400) |
Dan Field | 3e63411 | 2020-01-14 16:43:01 -0800 | [diff] [blame] | 743 | .where((File file) => !excludedFiles.contains(file.path)) |
| 744 | .toList(); |
| 745 | final RegExp toStringRegExp = RegExp(r'^\s+String\s+to(.+?)?String(.+?)?\(\)\s+(\{|=>)'); |
| 746 | final List<String> problems = <String>[]; |
| 747 | for (final File file in files) { |
| 748 | final List<String> lines = file.readAsLinesSync(); |
| 749 | for (int index = 0; index < lines.length; index++) { |
| 750 | if (toStringRegExp.hasMatch(lines[index])) { |
| 751 | final int sourceLine = index + 1; |
| 752 | bool _checkForRuntimeType(String line) { |
| 753 | if (line.contains(r'$runtimeType') || line.contains('runtimeType.toString()')) { |
| 754 | problems.add('${file.path}:$sourceLine}: toString calls runtimeType.toString'); |
| 755 | return true; |
| 756 | } |
| 757 | return false; |
| 758 | } |
| 759 | if (_checkForRuntimeType(lines[index])) { |
| 760 | continue; |
| 761 | } |
| 762 | if (lines[index].contains('=>')) { |
| 763 | while (!lines[index].contains(';')) { |
| 764 | index++; |
| 765 | assert(index < lines.length, 'Source file $file has unterminated toString method.'); |
| 766 | if (_checkForRuntimeType(lines[index])) { |
| 767 | break; |
| 768 | } |
| 769 | } |
| 770 | } else { |
| 771 | int openBraceCount = '{'.allMatches(lines[index]).length - '}'.allMatches(lines[index]).length; |
| 772 | while (!lines[index].contains('}') && openBraceCount > 0) { |
| 773 | index++; |
| 774 | assert(index < lines.length, 'Source file $file has unbalanced braces in a toString method.'); |
| 775 | if (_checkForRuntimeType(lines[index])) { |
| 776 | break; |
| 777 | } |
| 778 | openBraceCount += '{'.allMatches(lines[index]).length; |
| 779 | openBraceCount -= '}'.allMatches(lines[index]).length; |
| 780 | } |
| 781 | } |
| 782 | } |
| 783 | } |
| 784 | } |
| 785 | if (problems.isNotEmpty) |
| 786 | exitWithError(problems); |
| 787 | } |
| 788 | |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 789 | Future<void> verifyNoTrailingSpaces(String workingDirectory, { int minimumMatches = 4000 }) async { |
Yuqian Li | fb552ed | 2020-11-07 05:19:02 -0800 | [diff] [blame] | 790 | final List<File> files = await _allFiles(workingDirectory, null, minimumMatches: minimumMatches) |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 791 | .where((File file) => path.basename(file.path) != 'serviceaccount.enc') |
| 792 | .where((File file) => path.basename(file.path) != 'Ahem.ttf') |
| 793 | .where((File file) => path.extension(file.path) != '.snapshot') |
| 794 | .where((File file) => path.extension(file.path) != '.png') |
| 795 | .where((File file) => path.extension(file.path) != '.jpg') |
stuartmorgan | 685e9d1 | 2020-03-23 10:42:26 -0700 | [diff] [blame] | 796 | .where((File file) => path.extension(file.path) != '.ico') |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 797 | .where((File file) => path.extension(file.path) != '.jar') |
Jonah Williams | 0b3f5cf | 2020-04-21 20:39:36 -0700 | [diff] [blame] | 798 | .where((File file) => path.extension(file.path) != '.swp') |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 799 | .toList(); |
| 800 | final List<String> problems = <String>[]; |
Alexandre Ardhuin | 4f9b6cf | 2020-01-07 16:32:04 +0100 | [diff] [blame] | 801 | for (final File file in files) { |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 802 | final List<String> lines = file.readAsLinesSync(); |
| 803 | for (int index = 0; index < lines.length; index += 1) { |
| 804 | if (lines[index].endsWith(' ')) { |
| 805 | problems.add('${file.path}:${index + 1}: trailing U+0020 space character'); |
| 806 | } else if (lines[index].endsWith('\t')) { |
| 807 | problems.add('${file.path}:${index + 1}: trailing U+0009 tab character'); |
| 808 | } |
Ian Hickson | e768c92 | 2019-12-30 17:12:19 -0800 | [diff] [blame] | 809 | } |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 810 | if (lines.isNotEmpty && lines.last == '') |
| 811 | problems.add('${file.path}:${lines.length}: trailing blank line'); |
| 812 | } |
| 813 | if (problems.isNotEmpty) |
| 814 | exitWithError(problems); |
| 815 | } |
| 816 | |
Ian Hickson | bde9f11 | 2021-11-19 13:13:05 -0800 | [diff] [blame] | 817 | String _bullets(String value) => ' * $value'; |
| 818 | |
| 819 | Future<void> verifyIssueLinks(String workingDirectory) async { |
| 820 | const String issueLinkPrefix = 'https://github.com/flutter/flutter/issues/new'; |
| 821 | const Set<String> stops = <String>{ '\n', ' ', "'", '"', r'\', ')', '>' }; |
| 822 | assert(!stops.contains('.')); // instead of "visit https://foo." say "visit: https://", it copy-pastes better |
| 823 | const String kGiveTemplates = |
| 824 | 'Prefer to provide a link either to $issueLinkPrefix/choose (the list of issue ' |
| 825 | 'templates) or to a specific template directly ($issueLinkPrefix?template=...).\n'; |
| 826 | final Set<String> templateNames = |
| 827 | Directory(path.join(workingDirectory, '.github', 'ISSUE_TEMPLATE')) |
| 828 | .listSync() |
| 829 | .whereType<File>() |
| 830 | .where((File file) => path.extension(file.path) == '.md') |
| 831 | .map<String>((File file) => path.basename(file.path)) |
| 832 | .toSet(); |
| 833 | final String kTemplates = 'The available templates are:\n${templateNames.map(_bullets).join("\n")}'; |
| 834 | final List<String> problems = <String>[]; |
| 835 | final Set<String> suggestions = <String>{}; |
| 836 | final List<File> files = await _gitFiles(workingDirectory); |
| 837 | for (final File file in files) { |
Jonah Williams | fda4094 | 2021-12-14 10:51:30 -0800 | [diff] [blame] | 838 | if (path.basename(file.path).endsWith('_test.dart') || path.basename(file.path) == 'analyze.dart') |
Ian Hickson | bde9f11 | 2021-11-19 13:13:05 -0800 | [diff] [blame] | 839 | continue; // Skip tests, they're not public-facing. |
| 840 | final Uint8List bytes = file.readAsBytesSync(); |
| 841 | // We allow invalid UTF-8 here so that binaries don't trip us up. |
| 842 | // There's a separate test in this file that verifies that all text |
| 843 | // files are actually valid UTF-8 (see verifyNoBinaries below). |
| 844 | final String contents = utf8.decode(bytes, allowMalformed: true); |
| 845 | int start = 0; |
| 846 | while ((start = contents.indexOf(issueLinkPrefix, start)) >= 0) { |
| 847 | int end = start + issueLinkPrefix.length; |
| 848 | while (end < contents.length && !stops.contains(contents[end])) { |
| 849 | end += 1; |
| 850 | } |
| 851 | final String url = contents.substring(start, end); |
| 852 | if (url == issueLinkPrefix) { |
| 853 | if (file.path != path.join(workingDirectory, 'dev', 'bots', 'analyze.dart')) { |
| 854 | problems.add('${file.path} contains a direct link to $issueLinkPrefix.'); |
| 855 | suggestions.add(kGiveTemplates); |
| 856 | suggestions.add(kTemplates); |
| 857 | } |
| 858 | } else if (url.startsWith('$issueLinkPrefix?')) { |
| 859 | final Uri parsedUrl = Uri.parse(url); |
| 860 | final List<String>? templates = parsedUrl.queryParametersAll['template']; |
| 861 | if (templates == null) { |
| 862 | problems.add('${file.path} contains $url, which has no "template" argument specified.'); |
| 863 | suggestions.add(kGiveTemplates); |
| 864 | suggestions.add(kTemplates); |
| 865 | } else if (templates.length != 1) { |
| 866 | problems.add('${file.path} contains $url, which has ${templates.length} templates specified.'); |
| 867 | suggestions.add(kGiveTemplates); |
| 868 | suggestions.add(kTemplates); |
| 869 | } else if (!templateNames.contains(templates.single)) { |
| 870 | problems.add('${file.path} contains $url, which specifies a non-existent template ("${templates.single}").'); |
| 871 | suggestions.add(kTemplates); |
| 872 | } else if (parsedUrl.queryParametersAll.keys.length > 1) { |
| 873 | problems.add('${file.path} contains $url, which the analyze.dart script is not sure how to handle.'); |
| 874 | suggestions.add('Update analyze.dart to handle the URLs above, or change them to the expected pattern.'); |
| 875 | } |
| 876 | } else if (url != '$issueLinkPrefix/choose') { |
| 877 | problems.add('${file.path} contains $url, which the analyze.dart script is not sure how to handle.'); |
| 878 | suggestions.add('Update analyze.dart to handle the URLs above, or change them to the expected pattern.'); |
| 879 | } |
| 880 | start = end; |
| 881 | } |
| 882 | } |
| 883 | assert(problems.isEmpty == suggestions.isEmpty); |
| 884 | if (problems.isNotEmpty) { |
| 885 | exitWithError(<String>[ |
| 886 | ...problems, |
| 887 | ...suggestions, |
| 888 | ]); |
| 889 | } |
| 890 | } |
| 891 | |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 892 | @immutable |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 893 | class Hash256 { |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 894 | const Hash256(this.a, this.b, this.c, this.d); |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 895 | |
| 896 | factory Hash256.fromDigest(Digest digest) { |
| 897 | assert(digest.bytes.length == 32); |
| 898 | return Hash256( |
| 899 | digest.bytes[ 0] << 56 | |
| 900 | digest.bytes[ 1] << 48 | |
| 901 | digest.bytes[ 2] << 40 | |
| 902 | digest.bytes[ 3] << 32 | |
| 903 | digest.bytes[ 4] << 24 | |
| 904 | digest.bytes[ 5] << 16 | |
| 905 | digest.bytes[ 6] << 8 | |
| 906 | digest.bytes[ 7] << 0, |
| 907 | digest.bytes[ 8] << 56 | |
| 908 | digest.bytes[ 9] << 48 | |
| 909 | digest.bytes[10] << 40 | |
| 910 | digest.bytes[11] << 32 | |
| 911 | digest.bytes[12] << 24 | |
| 912 | digest.bytes[13] << 16 | |
| 913 | digest.bytes[14] << 8 | |
| 914 | digest.bytes[15] << 0, |
| 915 | digest.bytes[16] << 56 | |
| 916 | digest.bytes[17] << 48 | |
| 917 | digest.bytes[18] << 40 | |
| 918 | digest.bytes[19] << 32 | |
| 919 | digest.bytes[20] << 24 | |
| 920 | digest.bytes[21] << 16 | |
| 921 | digest.bytes[22] << 8 | |
| 922 | digest.bytes[23] << 0, |
| 923 | digest.bytes[24] << 56 | |
| 924 | digest.bytes[25] << 48 | |
| 925 | digest.bytes[26] << 40 | |
| 926 | digest.bytes[27] << 32 | |
| 927 | digest.bytes[28] << 24 | |
| 928 | digest.bytes[29] << 16 | |
| 929 | digest.bytes[30] << 8 | |
| 930 | digest.bytes[31] << 0, |
| 931 | ); |
| 932 | } |
| 933 | |
| 934 | final int a; |
| 935 | final int b; |
| 936 | final int c; |
| 937 | final int d; |
| 938 | |
| 939 | @override |
| 940 | bool operator ==(Object other) { |
| 941 | if (other.runtimeType != runtimeType) |
| 942 | return false; |
| 943 | return other is Hash256 |
| 944 | && other.a == a |
| 945 | && other.b == b |
| 946 | && other.c == c |
| 947 | && other.d == d; |
| 948 | } |
| 949 | |
| 950 | @override |
Dan Field | e36e62e | 2021-06-30 09:46:54 -0700 | [diff] [blame] | 951 | int get hashCode => Object.hash(a, b, c, d); |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 952 | } |
| 953 | |
| 954 | // DO NOT ADD ANY ENTRIES TO THIS LIST. |
| 955 | // We have a policy of not checking in binaries into this repository. |
stuartmorgan | 685e9d1 | 2020-03-23 10:42:26 -0700 | [diff] [blame] | 956 | // If you are adding/changing template images, use the flutter_template_images |
| 957 | // package and a .img.tmpl placeholder instead. |
| 958 | // If you have other binaries to add, please consult Hixie for advice. |
Michael Goderbauer | 584fd5f | 2020-06-16 09:15:43 -0700 | [diff] [blame] | 959 | final Set<Hash256> _legacyBinaries = <Hash256>{ |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 960 | // DEFAULT ICON IMAGES |
| 961 | |
| 962 | // packages/flutter_tools/templates/app/android.tmpl/app/src/main/res/mipmap-hdpi/ic_launcher.png |
| 963 | // packages/flutter_tools/templates/module/android/host_app_common/app.tmpl/src/main/res/mipmap-hdpi/ic_launcher.png |
| 964 | // (also used by many examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 965 | const Hash256(0x6A7C8F0D703E3682, 0x108F9662F8133022, 0x36240D3F8F638BB3, 0x91E32BFB96055FEF), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 966 | |
| 967 | // packages/flutter_tools/templates/app/android.tmpl/app/src/main/res/mipmap-mdpi/ic_launcher.png |
| 968 | // (also used by many examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 969 | const Hash256(0xC7C0C0189145E4E3, 0x2A401C61C9BDC615, 0x754B0264E7AFAE24, 0xE834BB81049EAF81), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 970 | |
| 971 | // packages/flutter_tools/templates/app/android.tmpl/app/src/main/res/mipmap-xhdpi/ic_launcher.png |
| 972 | // (also used by many examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 973 | const Hash256(0xE14AA40904929BF3, 0x13FDED22CF7E7FFC, 0xBF1D1AAC4263B5EF, 0x1BE8BFCE650397AA), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 974 | |
| 975 | // packages/flutter_tools/templates/app/android.tmpl/app/src/main/res/mipmap-xxhdpi/ic_launcher.png |
| 976 | // (also used by many examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 977 | const Hash256(0x4D470BF22D5C17D8, 0x4EDC5F82516D1BA8, 0xA1C09559CD761CEF, 0xB792F86D9F52B540), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 978 | |
| 979 | // packages/flutter_tools/templates/app/android.tmpl/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png |
| 980 | // (also used by many examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 981 | const Hash256(0x3C34E1F298D0C9EA, 0x3455D46DB6B7759C, 0x8211A49E9EC6E44B, 0x635FC5C87DFB4180), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 982 | |
| 983 | // packages/flutter_tools/templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png |
| 984 | // packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png |
| 985 | // (also used by a few examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 986 | const Hash256(0x7770183009E91411, 0x2DE7D8EF1D235A6A, 0x30C5834424858E0D, 0x2F8253F6B8D31926), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 987 | |
| 988 | // packages/flutter_tools/templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png |
| 989 | // packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png |
| 990 | // (also used by many examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 991 | const Hash256(0x5925DAB509451F9E, 0xCBB12CE8A625F9D4, 0xC104718EE20CAFF8, 0xB1B51032D1CD8946), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 992 | |
| 993 | // packages/flutter_tools/templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png |
| 994 | // packages/flutter_tools/templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png |
| 995 | // packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png |
| 996 | // packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png |
| 997 | // (also used by many examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 998 | const Hash256(0xC4D9A284C12301D0, 0xF50E248EC53ED51A, 0x19A10147B774B233, 0x08399250B0D44C55), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 999 | |
| 1000 | // packages/flutter_tools/templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png |
| 1001 | // packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png |
| 1002 | // (also used by many examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1003 | const Hash256(0xBF97F9D3233F33E1, 0x389B09F7B8ADD537, 0x41300CB834D6C7A5, 0xCA32CBED363A4FB2), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1004 | |
| 1005 | // packages/flutter_tools/templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png |
| 1006 | // packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png |
| 1007 | // (also used by many examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1008 | const Hash256(0x285442F69A06B45D, 0x9D79DF80321815B5, 0x46473548A37B7881, 0x9B68959C7B8ED237), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1009 | |
| 1010 | // packages/flutter_tools/templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png |
| 1011 | // packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png |
| 1012 | // (also used by many examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1013 | const Hash256(0x2AB64AF8AC727EA9, 0x9C6AB9EAFF847F46, 0xFBF2A9A0A78A0ABC, 0xBF3180F3851645B4), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1014 | |
| 1015 | // packages/flutter_tools/templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png |
| 1016 | // packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png |
| 1017 | // (also used by many examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1018 | const Hash256(0x9DCA09F4E5ED5684, 0xD3C4DFF41F4E8B7C, 0xB864B438172D72BE, 0x069315FA362930F9), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1019 | |
| 1020 | // packages/flutter_tools/templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png |
| 1021 | // packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png |
| 1022 | // (also used by many examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1023 | const Hash256(0xD5AD04DE321EF37C, 0xACC5A7B960AFCCE7, 0x1BDCB96FA020C482, 0x49C1545DD1A0F497), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1024 | |
| 1025 | // packages/flutter_tools/templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png |
| 1026 | // packages/flutter_tools/templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png |
| 1027 | // packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png |
| 1028 | // packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png |
| 1029 | // (also used by many examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1030 | const Hash256(0x809ABFE75C440770, 0xC13C4E2E46D09603, 0xC22053E9D4E0E227, 0x5DCB9C1DCFBB2C75), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1031 | |
| 1032 | // packages/flutter_tools/templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png |
| 1033 | // packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png |
| 1034 | // (also used by many examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1035 | const Hash256(0x3DB08CB79E7B01B9, 0xE81F956E3A0AE101, 0x48D0FAFDE3EA7AA7, 0x0048DF905AA52CFD), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1036 | |
| 1037 | // packages/flutter_tools/templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png |
| 1038 | // packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png |
| 1039 | // (also used by many examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1040 | const Hash256(0x23C13D463F5DCA5C, 0x1F14A14934003601, 0xC29F1218FD461016, 0xD8A22CEF579A665F), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1041 | |
| 1042 | // packages/flutter_tools/templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png |
| 1043 | // packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png |
| 1044 | // (also used by many examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1045 | const Hash256(0x6DB7726530D71D3F, 0x52CB59793EB69131, 0x3BAA04796E129E1E, 0x043C0A58A1BFFD2F), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1046 | |
| 1047 | // packages/flutter_tools/templates/app/ios.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png |
| 1048 | // packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png |
| 1049 | // (also used by many examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1050 | const Hash256(0xCEE565F5E6211656, 0x9B64980B209FD5CA, 0x4B3D3739011F5343, 0x250B33A1A2C6EB65), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1051 | |
| 1052 | // packages/flutter_tools/templates/app/ios.tmpl/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png |
| 1053 | // packages/flutter_tools/templates/app/ios.tmpl/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png |
| 1054 | // packages/flutter_tools/templates/app/ios.tmpl/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png |
| 1055 | // packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/LaunchImage.imageset/LaunchImage.png |
| 1056 | // packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png |
| 1057 | // packages/flutter_tools/templates/module/ios/host_app_ephemeral/Runner.tmpl/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png |
| 1058 | // (also used by many examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1059 | const Hash256(0x93AE7D494FAD0FB3, 0x0CBF3AE746A39C4B, 0xC7A0F8BBF87FBB58, 0x7A3F3C01F3C5CE20), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1060 | |
| 1061 | // packages/flutter_tools/templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png |
| 1062 | // (also used by a few examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1063 | const Hash256(0xB18BEBAAD1AD6724, 0xE48BCDF699BA3927, 0xDF3F258FEBE646A3, 0xAB5C62767C6BAB40), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1064 | |
| 1065 | // packages/flutter_tools/templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png |
| 1066 | // (also used by a few examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1067 | const Hash256(0xF90D839A289ECADB, 0xF2B0B3400DA43EB8, 0x08B84908335AE4A0, 0x07457C4D5A56A57C), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1068 | |
| 1069 | // packages/flutter_tools/templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png |
| 1070 | // (also used by a few examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1071 | const Hash256(0x592C2ABF84ADB2D3, 0x91AED8B634D3233E, 0x2C65369F06018DCD, 0x8A4B27BA755EDCBE), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1072 | |
| 1073 | // packages/flutter_tools/templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png |
| 1074 | // (also used by a few examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1075 | const Hash256(0x75D9A0C034113CA8, 0xA1EC11C24B81F208, 0x6630A5A5C65C7D26, 0xA5DC03A1C0A4478C), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1076 | |
| 1077 | // packages/flutter_tools/templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png |
| 1078 | // (also used by a few examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1079 | const Hash256(0xA896E65745557732, 0xC72BD4EE3A10782F, 0xE2AA95590B5AF659, 0x869E5808DB9C01C1), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1080 | |
| 1081 | // packages/flutter_tools/templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png |
| 1082 | // (also used by a few examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1083 | const Hash256(0x3A69A8A1AAC5D9A8, 0x374492AF4B6D07A4, 0xCE637659EB24A784, 0x9C4DFB261D75C6A3), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1084 | |
| 1085 | // packages/flutter_tools/templates/app/macos.tmpl/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png |
| 1086 | // (also used by a few examples) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1087 | const Hash256(0xD29D4E0AF9256DC9, 0x2D0A8F8810608A5E, 0x64A132AD8B397CA2, 0xC4DDC0B1C26A68C3), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1088 | |
Jonah Williams | 5d30c09 | 2020-01-10 09:37:20 -0800 | [diff] [blame] | 1089 | // packages/flutter_tools/templates/app/web/icons/Icon-192.png.copy.tmpl |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1090 | // dev/integration_tests/flutter_gallery/web/icons/Icon-192.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1091 | const Hash256(0x3DCE99077602F704, 0x21C1C6B2A240BC9B, 0x83D64D86681D45F2, 0x154143310C980BE3), |
Jonah Williams | 5d30c09 | 2020-01-10 09:37:20 -0800 | [diff] [blame] | 1092 | |
| 1093 | // packages/flutter_tools/templates/app/web/icons/Icon-512.png.copy.tmpl |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1094 | // dev/integration_tests/flutter_gallery/web/icons/Icon-512.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1095 | const Hash256(0xBACCB205AE45f0B4, 0x21BE1657259B4943, 0xAC40C95094AB877F, 0x3BCBE12CD544DCBE), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1096 | |
Jonah Williams | ab42685 | 2020-01-28 13:09:18 -0800 | [diff] [blame] | 1097 | // packages/flutter_tools/templates/app/web/favicon.png.copy.tmpl |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1098 | // dev/integration_tests/flutter_gallery/web/favicon.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1099 | const Hash256(0x7AB2525F4B86B65D, 0x3E4C70358A17E5A1, 0xAAF6F437f99CBCC0, 0x46DAD73d59BB9015), |
Jonah Williams | ab42685 | 2020-01-28 13:09:18 -0800 | [diff] [blame] | 1100 | |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1101 | // GALLERY ICONS |
| 1102 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1103 | // dev/integration_tests/flutter_gallery/android/app/src/main/res/mipmap-hdpi/ic_background.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1104 | const Hash256(0x03CFDE53C249475C, 0x277E8B8E90AC8A13, 0xE5FC13C358A94CCB, 0x67CA866C9862A0DD), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1105 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1106 | // dev/integration_tests/flutter_gallery/android/app/src/main/res/mipmap-hdpi/ic_foreground.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1107 | const Hash256(0x86A83E23A505EFCC, 0x39C358B699EDE12F, 0xC088EE516A1D0C73, 0xF3B5D74DDAD164B1), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1108 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1109 | // dev/integration_tests/flutter_gallery/android/app/src/main/res/mipmap-hdpi/ic_launcher.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1110 | const Hash256(0xD813B1A77320355E, 0xB68C485CD47D0F0F, 0x3C7E1910DCD46F08, 0x60A6401B8DC13647), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1111 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1112 | // dev/integration_tests/flutter_gallery/android/app/src/main/res/mipmap-xhdpi/ic_background.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1113 | const Hash256(0x35AFA76BD5D6053F, 0xEE927436C78A8794, 0xA8BA5F5D9FC9653B, 0xE5B96567BB7215ED), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1114 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1115 | // dev/integration_tests/flutter_gallery/android/app/src/main/res/mipmap-xhdpi/ic_foreground.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1116 | const Hash256(0x263CE9B4F1F69B43, 0xEBB08AE9FE8F80E7, 0x95647A59EF2C040B, 0xA8AEB246861A7DFF), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1117 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1118 | // dev/integration_tests/flutter_gallery/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1119 | const Hash256(0x5E1A93C3653BAAFF, 0x1AAC6BCEB8DCBC2F, 0x2AE7D68ECB07E507, 0xCB1FA8354B28313A), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1120 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1121 | // dev/integration_tests/flutter_gallery/android/app/src/main/res/mipmap-xxhdpi/ic_background.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1122 | const Hash256(0xA5C77499151DDEC6, 0xDB40D0AC7321FD74, 0x0646C0C0F786743F, 0x8F3C3C408CAC5E8C), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1123 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1124 | // dev/integration_tests/flutter_gallery/android/app/src/main/res/mipmap-xxhdpi/ic_foreground.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1125 | const Hash256(0x33DE450980A2A16B, 0x1982AC7CDC1E7B01, 0x919E07E0289C2139, 0x65F85BCED8895FEF), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1126 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1127 | // dev/integration_tests/flutter_gallery/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1128 | const Hash256(0xC3B8577F4A89BA03, 0x830944FB06C3566B, 0x4C99140A2CA52958, 0x089BFDC3079C59B7), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1129 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1130 | // dev/integration_tests/flutter_gallery/android/app/src/main/res/mipmap-xxxhdpi/ic_background.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1131 | const Hash256(0xDEBC241D6F9C5767, 0x8980FDD46FA7ED0C, 0x5B8ACD26BCC5E1BC, 0x473C89B432D467AD), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1132 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1133 | // dev/integration_tests/flutter_gallery/android/app/src/main/res/mipmap-xxxhdpi/ic_foreground.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1134 | const Hash256(0xBEFE5F7E82BF8B64, 0x148D869E3742004B, 0xF821A9F5A1BCDC00, 0x357D246DCC659DC2), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1135 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1136 | // dev/integration_tests/flutter_gallery/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1137 | const Hash256(0xC385404341FF9EDD, 0x30FBE76F0EC99155, 0x8EA4F4AFE8CC0C60, 0x1CA3EDEF177E1DA8), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1138 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1139 | // dev/integration_tests/flutter_gallery/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-1024.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1140 | const Hash256(0x6BE5751A29F57A80, 0x36A4B31CC542C749, 0x984E49B22BD65CAA, 0x75AE8B2440848719), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1141 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1142 | // dev/integration_tests/flutter_gallery/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-120.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1143 | const Hash256(0x9972A2264BFA8F8D, 0x964AFE799EADC1FA, 0x2247FB31097F994A, 0x1495DC32DF071793), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1144 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1145 | // dev/integration_tests/flutter_gallery/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-152.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1146 | const Hash256(0x4C7CC9B09BEEDA24, 0x45F57D6967753910, 0x57D68E1A6B883D2C, 0x8C52701A74F1400F), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1147 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1148 | // dev/integration_tests/flutter_gallery/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-167.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1149 | const Hash256(0x66DACAC1CFE4D349, 0xDBE994CB9125FFD7, 0x2D795CFC9CF9F739, 0xEDBB06CE25082E9C), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1150 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1151 | // dev/integration_tests/flutter_gallery/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-180.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1152 | const Hash256(0x5188621015EBC327, 0xC9EF63AD76E60ECE, 0xE82BDC3E4ABF09E2, 0xEE0139FA7C0A2BE5), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1153 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1154 | // dev/integration_tests/flutter_gallery/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-20.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1155 | const Hash256(0x27D2752D04EE9A6B, 0x78410E208F74A6CD, 0xC90D9E03B73B8C60, 0xD05F7D623E790487), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1156 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1157 | // dev/integration_tests/flutter_gallery/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-29.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1158 | const Hash256(0xBB20556B2826CF85, 0xD5BAC73AA69C2AC3, 0x8E71DAD64F15B855, 0xB30CB73E0AF89307), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1159 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1160 | // dev/integration_tests/flutter_gallery/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-40.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1161 | const Hash256(0x623820FA45CDB0AC, 0x808403E34AD6A53E, 0xA3E9FDAE83EE0931, 0xB020A3A4EF2CDDE7), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1162 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1163 | // dev/integration_tests/flutter_gallery/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-58.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1164 | const Hash256(0xC6D631D1E107215E, 0xD4A58FEC5F3AA4B5, 0x0AE9724E07114C0C, 0x453E5D87C2CAD3B3), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1165 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1166 | // dev/integration_tests/flutter_gallery/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-60.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1167 | const Hash256(0x4B6F58D1EB8723C6, 0xE717A0D09FEC8806, 0x90C6D1EF4F71836E, 0x618672827979B1A2), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1168 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1169 | // dev/integration_tests/flutter_gallery/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-76.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1170 | const Hash256(0x0A1744CC7634D508, 0xE85DD793331F0C8A, 0x0B7C6DDFE0975D8F, 0x29E91C905BBB1BED), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1171 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1172 | // dev/integration_tests/flutter_gallery/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-80.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1173 | const Hash256(0x24032FBD1E6519D6, 0x0BA93C0D5C189554, 0xF50EAE23756518A2, 0x3FABACF4BD5DAF08), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1174 | |
Michael Thomsen | e167181 | 2020-03-16 02:31:42 -0700 | [diff] [blame] | 1175 | // dev/integration_tests/flutter_gallery/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-87.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1176 | const Hash256(0xC17BAE6DF6BB234A, 0xE0AF4BEB0B805F12, 0x14E74EB7AA9A30F1, 0x5763689165DA7DDF), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1177 | |
| 1178 | |
| 1179 | // STOCKS ICONS |
| 1180 | |
Greg Spencer | 4b4cff9 | 2020-01-30 09:31:07 -0800 | [diff] [blame] | 1181 | // dev/benchmarks/test_apps/stocks/android/app/src/main/res/mipmap-hdpi/ic_launcher.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1182 | const Hash256(0x74052AB5241D4418, 0x7085180608BC3114, 0xD12493C50CD8BBC7, 0x56DED186C37ACE84), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1183 | |
Greg Spencer | 4b4cff9 | 2020-01-30 09:31:07 -0800 | [diff] [blame] | 1184 | // dev/benchmarks/test_apps/stocks/android/app/src/main/res/mipmap-mdpi/ic_launcher.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1185 | const Hash256(0xE37947332E3491CB, 0x82920EE86A086FEA, 0xE1E0A70B3700A7DA, 0xDCAFBDD8F40E2E19), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1186 | |
Greg Spencer | 4b4cff9 | 2020-01-30 09:31:07 -0800 | [diff] [blame] | 1187 | // dev/benchmarks/test_apps/stocks/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1188 | const Hash256(0xE608CDFC0C8579FB, 0xE38873BAAF7BC944, 0x9C9D2EE3685A4FAE, 0x671EF0C8BC41D17C), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1189 | |
Greg Spencer | 4b4cff9 | 2020-01-30 09:31:07 -0800 | [diff] [blame] | 1190 | // dev/benchmarks/test_apps/stocks/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1191 | const Hash256(0xBD53D86977DF9C54, 0xF605743C5ABA114C, 0x9D51D1A8BB917E1A, 0x14CAA26C335CAEBD), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1192 | |
Greg Spencer | 4b4cff9 | 2020-01-30 09:31:07 -0800 | [diff] [blame] | 1193 | // dev/benchmarks/test_apps/stocks/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1194 | const Hash256(0x64E4D02262C4F3D0, 0xBB4FDC21CD0A816C, 0x4CD2A0194E00FB0F, 0x1C3AE4142FAC0D15), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1195 | |
Greg Spencer | 4b4cff9 | 2020-01-30 09:31:07 -0800 | [diff] [blame] | 1196 | // dev/benchmarks/test_apps/stocks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png |
| 1197 | // dev/benchmarks/test_apps/stocks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1198 | const Hash256(0x5BA3283A76918FC0, 0xEE127D0F22D7A0B6, 0xDF03DAED61669427, 0x93D89DDD87A08117), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1199 | |
Greg Spencer | 4b4cff9 | 2020-01-30 09:31:07 -0800 | [diff] [blame] | 1200 | // dev/benchmarks/test_apps/stocks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1201 | const Hash256(0xCD7F26ED31DEA42A, 0x535D155EC6261499, 0x34E6738255FDB2C4, 0xBD8D4BDDE9A99B05), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1202 | |
Greg Spencer | 4b4cff9 | 2020-01-30 09:31:07 -0800 | [diff] [blame] | 1203 | // dev/benchmarks/test_apps/stocks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-76.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1204 | const Hash256(0x3FA1225FC9A96A7E, 0xCD071BC42881AB0E, 0x7747EB72FFB72459, 0xA37971BBAD27EE24), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1205 | |
Greg Spencer | 4b4cff9 | 2020-01-30 09:31:07 -0800 | [diff] [blame] | 1206 | // dev/benchmarks/test_apps/stocks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1207 | const Hash256(0xCD867001ACD7BBDB, 0x25CDFD452AE89FA2, 0x8C2DC980CAF55F48, 0x0B16C246CFB389BC), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1208 | |
Greg Spencer | 4b4cff9 | 2020-01-30 09:31:07 -0800 | [diff] [blame] | 1209 | // dev/benchmarks/test_apps/stocks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1210 | const Hash256(0x848E9736E5C4915A, 0x7945BCF6B32FD56B, 0x1F1E7CDDD914352E, 0xC9681D38EF2A70DA), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1211 | |
Greg Spencer | 4b4cff9 | 2020-01-30 09:31:07 -0800 | [diff] [blame] | 1212 | // dev/benchmarks/test_apps/stocks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Notification.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1213 | const Hash256(0x654BA7D6C4E05CA0, 0x7799878884EF8F11, 0xA383E1F24CEF5568, 0x3C47604A966983C8), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1214 | |
Greg Spencer | 4b4cff9 | 2020-01-30 09:31:07 -0800 | [diff] [blame] | 1215 | // dev/benchmarks/test_apps/stocks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Notification@2x.png |
| 1216 | // dev/benchmarks/test_apps/stocks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1217 | const Hash256(0x743056FE7D83FE42, 0xA2990825B6AD0415, 0x1AF73D0D43B227AA, 0x07EBEA9B767381D9), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1218 | |
Greg Spencer | 4b4cff9 | 2020-01-30 09:31:07 -0800 | [diff] [blame] | 1219 | // dev/benchmarks/test_apps/stocks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Notification@3x.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1220 | const Hash256(0xA7E1570812D119CF, 0xEF4B602EF28DD0A4, 0x100D066E66F5B9B9, 0x881765DC9303343B), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1221 | |
Greg Spencer | 4b4cff9 | 2020-01-30 09:31:07 -0800 | [diff] [blame] | 1222 | // dev/benchmarks/test_apps/stocks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1223 | const Hash256(0xB4102839A1E41671, 0x62DACBDEFA471953, 0xB1EE89A0AB7594BE, 0x1D9AC1E67DC2B2CE), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1224 | |
Greg Spencer | 4b4cff9 | 2020-01-30 09:31:07 -0800 | [diff] [blame] | 1225 | // dev/benchmarks/test_apps/stocks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1226 | const Hash256(0x70AC6571B593A967, 0xF1CBAEC9BC02D02D, 0x93AD766D8290ADE6, 0x840139BF9F219019), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1227 | |
Greg Spencer | 4b4cff9 | 2020-01-30 09:31:07 -0800 | [diff] [blame] | 1228 | // dev/benchmarks/test_apps/stocks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1229 | const Hash256(0x5D87A78386DA2C43, 0xDDA8FEF2CA51438C, 0xE5A276FE28C6CF0A, 0xEBE89085B56665B6), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1230 | |
Greg Spencer | 4b4cff9 | 2020-01-30 09:31:07 -0800 | [diff] [blame] | 1231 | // dev/benchmarks/test_apps/stocks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1232 | const Hash256(0x4D9F5E81F668DA44, 0xB20A77F8BF7BA2E1, 0xF384533B5AD58F07, 0xB3A2F93F8635CD96), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1233 | |
| 1234 | |
| 1235 | // LEGACY ICONS |
| 1236 | |
| 1237 | // dev/benchmarks/complex_layout/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png |
| 1238 | // dev/benchmarks/microbenchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png |
| 1239 | // examples/flutter_view/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@3x.png |
| 1240 | // (not really sure where this came from, or why neither the template nor most examples use them) |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1241 | const Hash256(0x6E645DC9ED913AAD, 0xB50ED29EEB16830D, 0xB32CA12F39121DB9, 0xB7BC1449DDDBF8B8), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1242 | |
| 1243 | // dev/benchmarks/macrobenchmarks/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png |
| 1244 | // dev/integration_tests/codegen/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png |
| 1245 | // dev/integration_tests/ios_add2app/ios_add2app/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png |
| 1246 | // dev/integration_tests/release_smoke_test/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1247 | const Hash256(0xDEFAC77E08EC71EC, 0xA04CCA3C95D1FC33, 0xB9F26E1CB15CB051, 0x47DEFC79CDD7C158), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1248 | |
| 1249 | // examples/flutter_view/ios/Runner/ic_add.png |
| 1250 | // examples/platform_view/ios/Runner/ic_add.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1251 | const Hash256(0x3CCE7450334675E2, 0xE3AABCA20B028993, 0x127BE82FE0EB3DFF, 0x8B027B3BAF052F2F), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1252 | |
| 1253 | // examples/image_list/images/coast.jpg |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1254 | const Hash256(0xDA957FD30C51B8D2, 0x7D74C2C918692DC4, 0xD3C5C99BB00F0D6B, 0x5EBB30395A6EDE82), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1255 | |
| 1256 | // examples/image_list/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1257 | const Hash256(0xB5792CA06F48A431, 0xD4379ABA2160BD5D, 0xE92339FC64C6A0D3, 0x417AA359634CD905), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1258 | |
| 1259 | |
| 1260 | // TEST ASSETS |
| 1261 | |
| 1262 | // dev/benchmarks/macrobenchmarks/assets/999x1000.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1263 | const Hash256(0x553E9C36DFF3E610, 0x6A608BDE822A0019, 0xDE4F1769B6FBDB97, 0xBC3C20E26B839F59), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1264 | |
| 1265 | // dev/bots/test/analyze-test-input/root/packages/foo/serviceaccount.enc |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1266 | const Hash256(0xA8100AE6AA1940D0, 0xB663BB31CD466142, 0xEBBDBD5187131B92, 0xD93818987832EB89), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1267 | |
| 1268 | // dev/automated_tests/icon/test.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1269 | const Hash256(0xE214B4A0FEEEC6FA, 0x8E7AA8CC9BFBEC40, 0xBCDAC2F2DEBC950F, 0x75AF8EBF02BCE459), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1270 | |
| 1271 | // dev/integration_tests/android_splash_screens/splash_screen_kitchen_sink/android/app/src/main/res/drawable-land-xxhdpi/flutter_splash_screen.png |
| 1272 | // dev/integration_tests/android_splash_screens/splash_screen_kitchen_sink/android/app/src/main/res/mipmap-land-xxhdpi/flutter_splash_screen.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1273 | const Hash256(0x2D4F8D7A3DFEF9D3, 0xA0C66938E169AB58, 0x8C6BBBBD1973E34E, 0x03C428416D010182), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1274 | |
| 1275 | // dev/integration_tests/android_splash_screens/splash_screen_kitchen_sink/android/app/src/main/res/drawable-xxhdpi/flutter_splash_screen.png |
| 1276 | // dev/integration_tests/android_splash_screens/splash_screen_kitchen_sink/android/app/src/main/res/mipmap-xxhdpi/flutter_splash_screen.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1277 | const Hash256(0xCD46C01BAFA3B243, 0xA6AA1645EEDDE481, 0x143AC8ABAB1A0996, 0x22CAA9D41F74649A), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1278 | |
| 1279 | // dev/integration_tests/flutter_driver_screenshot_test/assets/red_square.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1280 | const Hash256(0x40054377E1E084F4, 0x4F4410CE8F44C210, 0xABA945DFC55ED0EF, 0x23BDF9469E32F8D3), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1281 | |
| 1282 | // dev/integration_tests/flutter_driver_screenshot_test/test_driver/goldens/red_square_image/iPhone7,2.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1283 | const Hash256(0x7F9D27C7BC418284, 0x01214E21CA886B2F, 0x40D9DA2B31AE7754, 0x71D68375F9C8A824), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1284 | |
| 1285 | // examples/flutter_view/assets/flutter-mark-square-64.png |
| 1286 | // examples/platform_view/assets/flutter-mark-square-64.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1287 | const Hash256(0xF416B0D8AC552EC8, 0x819D1F492D1AB5E6, 0xD4F20CF45DB47C22, 0x7BB431FEFB5B67B2), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1288 | |
| 1289 | // packages/flutter_tools/test/data/intellij/plugins/Dart/lib/Dart.jar |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1290 | const Hash256(0x576E489D788A13DB, 0xBF40E4A39A3DAB37, 0x15CCF0002032E79C, 0xD260C69B29E06646), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1291 | |
| 1292 | // packages/flutter_tools/test/data/intellij/plugins/flutter-intellij.jar |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1293 | const Hash256(0x4C67221E25626CB2, 0x3F94E1F49D34E4CF, 0x3A9787A514924FC5, 0x9EF1E143E5BC5690), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1294 | |
| 1295 | |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1296 | // MISCELLANEOUS |
| 1297 | |
| 1298 | // dev/bots/serviceaccount.enc |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1299 | const Hash256(0x1F19ADB4D80AFE8C, 0xE61899BA776B1A8D, 0xCA398C75F5F7050D, 0xFB0E72D7FBBBA69B), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1300 | |
| 1301 | // dev/docs/favicon.ico |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1302 | const Hash256(0x67368CA1733E933A, 0xCA3BC56EF0695012, 0xE862C371AD4412F0, 0x3EC396039C609965), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1303 | |
| 1304 | // dev/snippets/assets/code_sample.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1305 | const Hash256(0xAB2211A47BDA001D, 0x173A52FD9C75EBC7, 0xE158942FFA8243AD, 0x2A148871990D4297), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1306 | |
| 1307 | // dev/snippets/assets/code_snippet.png |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1308 | const Hash256(0xDEC70574DA46DFBB, 0xFA657A771F3E1FBD, 0xB265CFC6B2AA5FE3, 0x93BA4F325D1520BA), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1309 | |
| 1310 | // packages/flutter_tools/static/Ahem.ttf |
Alexandre Ardhuin | f5a9902 | 2020-04-06 22:36:01 +0200 | [diff] [blame] | 1311 | const Hash256(0x63D2ABD0041C3E3B, 0x4B52AD8D382353B5, 0x3C51C6785E76CE56, 0xED9DACAD2D2E31C4), |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1312 | }; |
| 1313 | |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 1314 | Future<void> verifyNoBinaries(String workingDirectory, { Set<Hash256>? legacyBinaries }) async { |
Michael Goderbauer | 584fd5f | 2020-06-16 09:15:43 -0700 | [diff] [blame] | 1315 | // Please do not add anything to the _legacyBinaries set above. |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1316 | // We have a policy of not checking in binaries into this repository. |
stuartmorgan | 685e9d1 | 2020-03-23 10:42:26 -0700 | [diff] [blame] | 1317 | // If you are adding/changing template images, use the flutter_template_images |
| 1318 | // package and a .img.tmpl placeholder instead. |
| 1319 | // If you have other binaries to add, please consult Hixie for advice. |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1320 | assert( |
Michael Goderbauer | 584fd5f | 2020-06-16 09:15:43 -0700 | [diff] [blame] | 1321 | _legacyBinaries |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1322 | .expand<int>((Hash256 hash) => <int>[hash.a, hash.b, hash.c, hash.d]) |
Casey Hillers | 781cd4d | 2020-02-11 18:25:17 -0800 | [diff] [blame] | 1323 | .reduce((int value, int element) => value ^ element) == 0x606B51C908B40BFA // Please do not modify this line. |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1324 | ); |
Michael Goderbauer | 584fd5f | 2020-06-16 09:15:43 -0700 | [diff] [blame] | 1325 | legacyBinaries ??= _legacyBinaries; |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1326 | if (!Platform.isWindows) { // TODO(ianh): Port this to Windows |
Ian Hickson | bde9f11 | 2021-11-19 13:13:05 -0800 | [diff] [blame] | 1327 | final List<File> files = await _gitFiles(workingDirectory); |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1328 | final List<String> problems = <String>[]; |
Alexandre Ardhuin | 4f9b6cf | 2020-01-07 16:32:04 +0100 | [diff] [blame] | 1329 | for (final File file in files) { |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1330 | final Uint8List bytes = file.readAsBytesSync(); |
| 1331 | try { |
| 1332 | utf8.decode(bytes); |
| 1333 | } on FormatException catch (error) { |
Paul Berry | c32d138 | 2020-05-04 09:10:20 -0700 | [diff] [blame] | 1334 | final Digest digest = sha256.convert(bytes); |
Michael Goderbauer | 584fd5f | 2020-06-16 09:15:43 -0700 | [diff] [blame] | 1335 | if (!legacyBinaries.contains(Hash256.fromDigest(digest))) |
Paul Berry | c32d138 | 2020-05-04 09:10:20 -0700 | [diff] [blame] | 1336 | problems.add('${file.path}:${error.offset}: file is not valid UTF-8'); |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1337 | } |
| 1338 | } |
| 1339 | if (problems.isNotEmpty) { |
| 1340 | exitWithError(<String>[ |
| 1341 | ...problems, |
| 1342 | 'All files in this repository must be UTF-8. In particular, images and other binaries', |
| 1343 | 'must not be checked into this repository. This is because we are very sensitive to the', |
| 1344 | 'size of the repository as it is distributed to all our developers. If you have a binary', |
| 1345 | 'to which you need access, you should consider how to fetch it from another repository;', |
| 1346 | 'for example, the "assets-for-api-docs" repository is used for images in API docs.', |
| 1347 | ]); |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 1348 | } |
| 1349 | } |
| 1350 | } |
| 1351 | |
| 1352 | |
| 1353 | // UTILITY FUNCTIONS |
| 1354 | |
| 1355 | bool _listEquals<T>(List<T> a, List<T> b) { |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 1356 | assert(a != null); |
| 1357 | assert(b != null); |
| 1358 | if (a.length != b.length) |
| 1359 | return false; |
| 1360 | for (int index = 0; index < a.length; index += 1) { |
| 1361 | if (a[index] != b[index]) |
| 1362 | return false; |
| 1363 | } |
| 1364 | return true; |
| 1365 | } |
| 1366 | |
Yuqian Li | fb552ed | 2020-11-07 05:19:02 -0800 | [diff] [blame] | 1367 | Future<List<File>> _gitFiles(String workingDirectory, {bool runSilently = true}) async { |
| 1368 | final EvalResult evalResult = await _evalCommand( |
| 1369 | 'git', <String>['ls-files', '-z'], |
| 1370 | workingDirectory: workingDirectory, |
| 1371 | runSilently: runSilently, |
| 1372 | ); |
| 1373 | if (evalResult.exitCode != 0) { |
| 1374 | exitWithError(<String>[ |
Dan Field | 9c0bd18 | 2021-06-23 13:08:51 -0700 | [diff] [blame] | 1375 | 'git ls-files failed with exit code ${evalResult.exitCode}', |
Yuqian Li | fb552ed | 2020-11-07 05:19:02 -0800 | [diff] [blame] | 1376 | '${bold}stdout:$reset', |
| 1377 | evalResult.stdout, |
| 1378 | '${bold}stderr:$reset', |
| 1379 | evalResult.stderr, |
| 1380 | ]); |
| 1381 | } |
| 1382 | final List<String> filenames = evalResult |
| 1383 | .stdout |
| 1384 | .split('\x00'); |
| 1385 | assert(filenames.last.isEmpty); // git ls-files gives a trailing blank 0x00 |
| 1386 | filenames.removeLast(); |
| 1387 | return filenames |
| 1388 | .map<File>((String filename) => File(path.join(workingDirectory, filename))) |
| 1389 | .toList(); |
| 1390 | } |
| 1391 | |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 1392 | Stream<File> _allFiles(String workingDirectory, String? extension, { required int minimumMatches }) async* { |
Yuqian Li | fb552ed | 2020-11-07 05:19:02 -0800 | [diff] [blame] | 1393 | final Set<String> gitFileNamesSet = <String>{}; |
| 1394 | gitFileNamesSet.addAll((await _gitFiles(workingDirectory)).map((File f) => path.canonicalize(f.absolute.path))); |
| 1395 | |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1396 | assert(extension == null || !extension.startsWith('.'), 'Extension argument should not start with a period.'); |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 1397 | final Set<FileSystemEntity> pending = <FileSystemEntity>{ Directory(workingDirectory) }; |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1398 | int matches = 0; |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 1399 | while (pending.isNotEmpty) { |
| 1400 | final FileSystemEntity entity = pending.first; |
| 1401 | pending.remove(entity); |
Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 1402 | if (path.extension(entity.path) == '.tmpl') |
| 1403 | continue; |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 1404 | if (entity is File) { |
Yuqian Li | fb552ed | 2020-11-07 05:19:02 -0800 | [diff] [blame] | 1405 | if (!gitFileNamesSet.contains(path.canonicalize(entity.absolute.path))) |
| 1406 | continue; |
Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 1407 | if (_isGeneratedPluginRegistrant(entity)) |
| 1408 | continue; |
| 1409 | if (path.basename(entity.path) == 'flutter_export_environment.sh') |
| 1410 | continue; |
| 1411 | if (path.basename(entity.path) == 'gradlew.bat') |
| 1412 | continue; |
Darren Austin | 4253e42 | 2020-09-18 14:37:04 -0700 | [diff] [blame] | 1413 | if (path.basename(entity.path) == '.DS_Store') |
| 1414 | continue; |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1415 | if (extension == null || path.extension(entity.path) == '.$extension') { |
| 1416 | matches += 1; |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 1417 | yield entity; |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1418 | } |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 1419 | } else if (entity is Directory) { |
| 1420 | if (File(path.join(entity.path, '.dartignore')).existsSync()) |
| 1421 | continue; |
| 1422 | if (path.basename(entity.path) == '.git') |
| 1423 | continue; |
Jim Graham | 210f768 | 2020-07-29 17:16:26 -0700 | [diff] [blame] | 1424 | if (path.basename(entity.path) == '.idea') |
| 1425 | continue; |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1426 | if (path.basename(entity.path) == '.gradle') |
| 1427 | continue; |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 1428 | if (path.basename(entity.path) == '.dart_tool') |
| 1429 | continue; |
Darren Austin | 753b848 | 2020-07-20 18:51:04 -0700 | [diff] [blame] | 1430 | if (path.basename(entity.path) == '.idea') |
| 1431 | continue; |
Ian Hickson | 449f4a6 | 2019-11-27 15:04:02 -0800 | [diff] [blame] | 1432 | if (path.basename(entity.path) == 'build') |
| 1433 | continue; |
Ian Hickson | 62e4ab8 | 2019-11-15 19:21:53 -0800 | [diff] [blame] | 1434 | pending.addAll(entity.listSync()); |
| 1435 | } |
| 1436 | } |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1437 | assert(matches >= minimumMatches, 'Expected to find at least $minimumMatches files with extension ".$extension" in "$workingDirectory", but only found $matches.'); |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 1438 | } |
| 1439 | |
| 1440 | class EvalResult { |
| 1441 | EvalResult({ |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 1442 | required this.stdout, |
| 1443 | required this.stderr, |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 1444 | this.exitCode = 0, |
| 1445 | }); |
| 1446 | |
| 1447 | final String stdout; |
| 1448 | final String stderr; |
| 1449 | final int exitCode; |
| 1450 | } |
| 1451 | |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1452 | // TODO(ianh): Refactor this to reuse the code in run_command.dart |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 1453 | Future<EvalResult> _evalCommand(String executable, List<String> arguments, { |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 1454 | required String workingDirectory, |
| 1455 | Map<String, String>? environment, |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 1456 | bool allowNonZeroExit = false, |
Yuqian Li | fb552ed | 2020-11-07 05:19:02 -0800 | [diff] [blame] | 1457 | bool runSilently = false, |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 1458 | }) async { |
| 1459 | final String commandDescription = '${path.relative(executable, from: workingDirectory)} ${arguments.join(' ')}'; |
| 1460 | final String relativeWorkingDir = path.relative(workingDirectory); |
Yuqian Li | fb552ed | 2020-11-07 05:19:02 -0800 | [diff] [blame] | 1461 | |
| 1462 | if (!runSilently) { |
| 1463 | printProgress('RUNNING', relativeWorkingDir, commandDescription); |
| 1464 | } |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 1465 | |
| 1466 | final Stopwatch time = Stopwatch()..start(); |
| 1467 | final Process process = await Process.start(executable, arguments, |
| 1468 | workingDirectory: workingDirectory, |
| 1469 | environment: environment, |
| 1470 | ); |
| 1471 | |
| 1472 | final Future<List<List<int>>> savedStdout = process.stdout.toList(); |
| 1473 | final Future<List<List<int>>> savedStderr = process.stderr.toList(); |
| 1474 | final int exitCode = await process.exitCode; |
| 1475 | final EvalResult result = EvalResult( |
| 1476 | stdout: utf8.decode((await savedStdout).expand<int>((List<int> ints) => ints).toList()), |
| 1477 | stderr: utf8.decode((await savedStderr).expand<int>((List<int> ints) => ints).toList()), |
| 1478 | exitCode: exitCode, |
| 1479 | ); |
| 1480 | |
Yuqian Li | fb552ed | 2020-11-07 05:19:02 -0800 | [diff] [blame] | 1481 | if (!runSilently) { |
| 1482 | print('$clock ELAPSED TIME: $bold${prettyPrintDuration(time.elapsed)}$reset for $commandDescription in $relativeWorkingDir'); |
| 1483 | } |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 1484 | |
| 1485 | if (exitCode != 0 && !allowNonZeroExit) { |
| 1486 | stderr.write(result.stderr); |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1487 | exitWithError(<String>[ |
| 1488 | '${bold}ERROR:$red Last command exited with $exitCode.$reset', |
| 1489 | '${bold}Command:$red $commandDescription$reset', |
| 1490 | '${bold}Relative working directory:$red $relativeWorkingDir$reset', |
| 1491 | ]); |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 1492 | } |
| 1493 | |
| 1494 | return result; |
| 1495 | } |
| 1496 | |
Jonah Williams | f6f59c5 | 2021-04-16 14:29:32 -0700 | [diff] [blame] | 1497 | Future<void> _checkConsumerDependencies() async { |
| 1498 | final ProcessResult result = await Process.run(flutter, <String>[ |
| 1499 | 'update-packages', |
| 1500 | '--transitive-closure', |
| 1501 | '--consumer-only', |
| 1502 | ]); |
| 1503 | if (result.exitCode != 0) { |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 1504 | print(result.stdout as Object); |
| 1505 | print(result.stderr as Object); |
Jonah Williams | f6f59c5 | 2021-04-16 14:29:32 -0700 | [diff] [blame] | 1506 | exit(result.exitCode); |
| 1507 | } |
Ian Hickson | 126cd73 | 2021-10-04 10:28:03 -0700 | [diff] [blame] | 1508 | final Set<String> dependencies = <String>{}; |
Jonah Williams | f6f59c5 | 2021-04-16 14:29:32 -0700 | [diff] [blame] | 1509 | for (final String line in result.stdout.toString().split('\n')) { |
| 1510 | if (!line.contains('->')) { |
| 1511 | continue; |
| 1512 | } |
| 1513 | final List<String> parts = line.split('->'); |
| 1514 | final String name = parts[0].trim(); |
Ian Hickson | 126cd73 | 2021-10-04 10:28:03 -0700 | [diff] [blame] | 1515 | dependencies.add(name); |
Jonah Williams | f6f59c5 | 2021-04-16 14:29:32 -0700 | [diff] [blame] | 1516 | } |
Jonah Williams | f6f59c5 | 2021-04-16 14:29:32 -0700 | [diff] [blame] | 1517 | |
Ian Hickson | 126cd73 | 2021-10-04 10:28:03 -0700 | [diff] [blame] | 1518 | final Set<String> removed = kCorePackageAllowList.difference(dependencies); |
| 1519 | final Set<String> added = dependencies.difference(kCorePackageAllowList); |
Jonah Williams | f6f59c5 | 2021-04-16 14:29:32 -0700 | [diff] [blame] | 1520 | |
Ian Hickson | 126cd73 | 2021-10-04 10:28:03 -0700 | [diff] [blame] | 1521 | String plural(int n, String s, String p) => n == 1 ? s : p; |
| 1522 | |
| 1523 | if (added.isNotEmpty) { |
Jonah Williams | f6f59c5 | 2021-04-16 14:29:32 -0700 | [diff] [blame] | 1524 | exitWithError(<String>[ |
Ian Hickson | 126cd73 | 2021-10-04 10:28:03 -0700 | [diff] [blame] | 1525 | 'The transitive closure of package dependencies contains ${plural(added.length, "a non-allowlisted package", "non-allowlisted packages")}:', |
| 1526 | ' ${added.join(', ')}', |
| 1527 | 'We strongly desire to keep the number of dependencies to a minimum and', |
| 1528 | 'therefore would much prefer not to add new dependencies.', |
| 1529 | 'See dev/bots/allowlist.dart for instructions on how to update the package', |
| 1530 | 'allowlist if you nonetheless believe this is a necessary addition.', |
Jonah Williams | f6f59c5 | 2021-04-16 14:29:32 -0700 | [diff] [blame] | 1531 | ]); |
| 1532 | } |
| 1533 | |
Ian Hickson | 126cd73 | 2021-10-04 10:28:03 -0700 | [diff] [blame] | 1534 | if (removed.isNotEmpty) { |
Jonah Williams | f6f59c5 | 2021-04-16 14:29:32 -0700 | [diff] [blame] | 1535 | exitWithError(<String>[ |
Ian Hickson | 126cd73 | 2021-10-04 10:28:03 -0700 | [diff] [blame] | 1536 | 'Excellent news! ${plural(removed.length, "A package dependency has been removed!", "Multiple package dependencies have been removed!")}', |
| 1537 | ' ${removed.join(', ')}', |
| 1538 | 'To make sure we do not accidentally add ${plural(removed.length, "this dependency", "these dependencies")} back in the future,', |
| 1539 | 'please remove ${plural(removed.length, "this", "these")} packages from the allow-list in dev/bots/allowlist.dart.', |
| 1540 | 'Thanks!', |
Jonah Williams | f6f59c5 | 2021-04-16 14:29:32 -0700 | [diff] [blame] | 1541 | ]); |
| 1542 | } |
| 1543 | } |
| 1544 | |
Jonah Williams | fda4094 | 2021-12-14 10:51:30 -0800 | [diff] [blame] | 1545 | const String _kDebugOnlyAnnotation = '@_debugOnly'; |
| 1546 | final RegExp _nullInitializedField = RegExp(r'kDebugMode \? [\w\<\> ,{}()]+ : null;'); |
| 1547 | |
| 1548 | Future<void> verifyNullInitializedDebugExpensiveFields(String workingDirectory, {int minimumMatches = 400}) async { |
| 1549 | final String flutterLib = path.join(workingDirectory, 'packages', 'flutter', 'lib'); |
| 1550 | final List<File> files = await _allFiles(flutterLib, 'dart', minimumMatches: minimumMatches) |
| 1551 | .toList(); |
| 1552 | final List<String> errors = <String>[]; |
| 1553 | for (final File file in files) { |
| 1554 | final List<String> lines = file.readAsLinesSync(); |
| 1555 | for (int i = 0; i < lines.length; i += 1) { |
| 1556 | final String line = lines[i]; |
| 1557 | if (!line.contains(_kDebugOnlyAnnotation)) { |
| 1558 | continue; |
| 1559 | } |
| 1560 | final String nextLine = lines[i + 1]; |
| 1561 | if (_nullInitializedField.firstMatch(nextLine) == null) { |
| 1562 | errors.add('${file.path} L$i'); |
| 1563 | } |
| 1564 | } |
| 1565 | } |
| 1566 | |
| 1567 | if (errors.isNotEmpty) { |
| 1568 | exitWithError(<String>[ |
| 1569 | '${bold}ERROR: ${red}fields annotated with @_debugOnly must null initialize.$reset', |
| 1570 | 'to ensure both the field and initializer are removed from profile/release mode.', |
| 1571 | 'These fields should be written as:\n', |
| 1572 | 'field = kDebugMode ? <DebugValue> : null;\n', |
| 1573 | 'Errors were found in the following files:', |
| 1574 | ...errors, |
| 1575 | ]); |
| 1576 | } |
| 1577 | } |
| 1578 | |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 1579 | Future<CommandResult> _runFlutterAnalyze(String workingDirectory, { |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 1580 | List<String> options = const <String>[], |
Dan Field | 24f39d4 | 2020-01-02 11:47:28 -0800 | [diff] [blame] | 1581 | }) async { |
Michael Goderbauer | cb867bb | 2021-03-05 18:38:15 -0800 | [diff] [blame] | 1582 | return runCommand( |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 1583 | flutter, |
Jenn Magder | 95d7d67 | 2021-04-18 09:29:02 -0700 | [diff] [blame] | 1584 | <String>['analyze', ...options], |
Ian Hickson | eae05c7 | 2019-11-14 13:19:40 -0800 | [diff] [blame] | 1585 | workingDirectory: workingDirectory, |
| 1586 | ); |
| 1587 | } |
| 1588 | |
Greg Spencer | 35fcd90 | 2019-01-14 13:49:50 -0800 | [diff] [blame] | 1589 | final RegExp _importPattern = RegExp(r'''^\s*import (['"])package:flutter/([^.]+)\.dart\1'''); |
Ian Hickson | 58939b7 | 2019-02-12 12:29:36 -0800 | [diff] [blame] | 1590 | final RegExp _importMetaPattern = RegExp(r'''^\s*import (['"])package:meta/meta\.dart\1'''); |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 1591 | |
Yuqian Li | fb552ed | 2020-11-07 05:19:02 -0800 | [diff] [blame] | 1592 | Future<Set<String>> _findFlutterDependencies(String srcPath, List<String> errors, { bool checkForMeta = false }) async { |
Michael Goderbauer | cb867bb | 2021-03-05 18:38:15 -0800 | [diff] [blame] | 1593 | return _allFiles(srcPath, 'dart', minimumMatches: 1) |
Alexandre Ardhuin | ec1a015 | 2019-12-05 22:34:06 +0100 | [diff] [blame] | 1594 | .map<Set<String>>((File file) { |
| 1595 | final Set<String> result = <String>{}; |
Alexandre Ardhuin | 4f9b6cf | 2020-01-07 16:32:04 +0100 | [diff] [blame] | 1596 | for (final String line in file.readAsLinesSync()) { |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 1597 | Match? match = _importPattern.firstMatch(line); |
Alexandre Ardhuin | ec1a015 | 2019-12-05 22:34:06 +0100 | [diff] [blame] | 1598 | if (match != null) |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 1599 | result.add(match.group(2)!); |
Alexandre Ardhuin | ec1a015 | 2019-12-05 22:34:06 +0100 | [diff] [blame] | 1600 | if (checkForMeta) { |
| 1601 | match = _importMetaPattern.firstMatch(line); |
| 1602 | if (match != null) { |
| 1603 | errors.add( |
| 1604 | '${file.path}\nThis package imports the ${yellow}meta$reset package.\n' |
| 1605 | 'You should instead import the "foundation.dart" library.' |
| 1606 | ); |
| 1607 | } |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 1608 | } |
| 1609 | } |
Alexandre Ardhuin | ec1a015 | 2019-12-05 22:34:06 +0100 | [diff] [blame] | 1610 | return result; |
| 1611 | }) |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 1612 | .reduce((Set<String>? value, Set<String> element) { |
Alexandre Ardhuin | ec1a015 | 2019-12-05 22:34:06 +0100 | [diff] [blame] | 1613 | value ??= <String>{}; |
| 1614 | value.addAll(element); |
| 1615 | return value; |
| 1616 | }); |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 1617 | } |
| 1618 | |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 1619 | List<T>? _deepSearch<T>(Map<T, Set<T>> map, T start, [ Set<T>? seen ]) { |
LongCatIsLooong | d291de0 | 2020-01-09 10:25:58 -0800 | [diff] [blame] | 1620 | if (map[start] == null) |
| 1621 | return null; // We catch these separately. |
| 1622 | |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 1623 | for (final T key in map[start]!) { |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 1624 | if (key == start) |
| 1625 | continue; // we catch these separately |
| 1626 | if (seen != null && seen.contains(key)) |
| 1627 | return <T>[start, key]; |
Michael Goderbauer | 045ba2b | 2021-07-19 13:59:15 -0700 | [diff] [blame] | 1628 | final List<T>? result = _deepSearch<T>( |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 1629 | map, |
| 1630 | key, |
Alexandre Ardhuin | 919dcf5 | 2019-06-27 21:23:16 +0200 | [diff] [blame] | 1631 | <T>{ |
| 1632 | if (seen == null) start else ...seen, |
| 1633 | key, |
| 1634 | }, |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 1635 | ); |
| 1636 | if (result != null) { |
| 1637 | result.insert(0, start); |
| 1638 | // Only report the shortest chains. |
| 1639 | // For example a->b->a, rather than c->a->b->a. |
| 1640 | // Since we visit every node, we know the shortest chains are those |
| 1641 | // that start and end on the loop. |
| 1642 | if (result.first == result.last) |
| 1643 | return result; |
| 1644 | } |
| 1645 | } |
| 1646 | return null; |
| 1647 | } |
| 1648 | |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 1649 | bool _isGeneratedPluginRegistrant(File file) { |
| 1650 | final String filename = path.basename(file.path); |
| 1651 | return !file.path.contains('.pub-cache') |
| 1652 | && (filename == 'GeneratedPluginRegistrant.java' || |
| 1653 | filename == 'GeneratedPluginRegistrant.h' || |
Jonah Williams | 0b3f5cf | 2020-04-21 20:39:36 -0700 | [diff] [blame] | 1654 | filename == 'GeneratedPluginRegistrant.m' || |
Jonah Williams | 14722d3 | 2020-09-28 10:07:35 -0700 | [diff] [blame] | 1655 | filename == 'generated_plugin_registrant.dart' || |
| 1656 | filename == 'generated_plugin_registrant.h'); |
Alexander Aprelev | 391e91c | 2018-08-30 07:30:25 -0700 | [diff] [blame] | 1657 | } |