Skip to content

Commit 15cedbc

Browse files
Begin migrating tools to NNBD (flutter#3891)
- Updates dependencies to null-safe versions - Migrates common.dart (which doesn't depend on anything) - Migrates common_tests.dart and its one dependency, utils.dart - Adds build_runner for Mockito mock generation - Adds a new utility methods for getting arguments that handle both the casting and the removal of nullability to address a common problematic pattern while migrating code. - Converts all files, not just the migrated ones, to those new helpers. Migrating common.dart and utils.dart should unblock a command-by-command migration to null safety. Reverts the separate of podspect lints into a step that doesn't do a Flutter upgrade (flutter/plugins#3700) because without that step we had a version of Dart too old to run null-safe tooling. First step of flutter#81912
1 parent 0a8eec5 commit 15cedbc

38 files changed

+403
-190
lines changed

.cirrus.yml

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,12 @@ task:
194194
<< : *MACOS_TEMPLATE
195195
<< : *FLUTTER_UPGRADE_TEMPLATE
196196
matrix:
197+
### iOS+macOS tasks ***
198+
- name: lint_darwin_plugins
199+
script:
200+
# TODO(jmagman): Lint macOS podspecs but skip any that fail library validation.
201+
- find . -name "*.podspec" | xargs grep -l "osx" | xargs rm
202+
- ./script/tool_runner.sh podspecs
197203
### iOS tasks ###
198204
- name: build_all_plugins_ipa
199205
env:
@@ -251,14 +257,3 @@ task:
251257
- ./script/tool_runner.sh build-examples --macos --no-ipa
252258
drive_script:
253259
- ./script/tool_runner.sh drive-examples --macos
254-
255-
task:
256-
# Don't use FLUTTER_UPGRADE_TEMPLATE, Flutter tooling not needed.
257-
<< : *MACOS_TEMPLATE
258-
<< : *TOOL_SETUP_TEMPLATE
259-
matrix:
260-
- name: lint_darwin_plugins
261-
script:
262-
# TODO(jmagman): Lint macOS podspecs but skip any that fail library validation.
263-
- find . -name "*.podspec" | xargs grep -l "osx" | xargs rm
264-
- ./script/tool_runner.sh podspecs

script/tool/bin/flutter_plugin_tools.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
// @dart=2.9
6+
57
export 'package:flutter_plugin_tools/src/main.dart';

script/tool/lib/src/analyze_command.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
// @dart=2.9
6+
57
import 'dart:async';
68

79
import 'package:file/file.dart';
@@ -42,8 +44,8 @@ class AnalyzeCommand extends PluginCommand {
4244
continue;
4345
}
4446

45-
final bool allowed = (argResults[_customAnalysisFlag] as List<String>)
46-
.any((String directory) =>
47+
final bool allowed = (getStringListArg(_customAnalysisFlag)).any(
48+
(String directory) =>
4749
directory != null &&
4850
directory.isNotEmpty &&
4951
p.isWithin(p.join(packagesDir.path, directory), file.path));

script/tool/lib/src/build_examples_command.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
// @dart=2.9
6+
57
import 'dart:async';
68
import 'dart:io' as io;
79

@@ -52,7 +54,7 @@ class BuildExamplesCommand extends PluginCommand {
5254
];
5355
final Map<String, bool> platforms = <String, bool>{
5456
for (final String platform in platformSwitches)
55-
platform: argResults[platform] as bool
57+
platform: getBoolArg(platform)
5658
};
5759
if (!platforms.values.any((bool enabled) => enabled)) {
5860
print(
@@ -63,7 +65,7 @@ class BuildExamplesCommand extends PluginCommand {
6365
final String flutterCommand =
6466
const LocalPlatform().isWindows ? 'flutter.bat' : 'flutter';
6567

66-
final String enableExperiment = argResults[kEnableExperiment] as String;
68+
final String enableExperiment = getStringArg(kEnableExperiment);
6769

6870
final List<String> failingPackages = <String>[];
6971
await for (final Directory plugin in getPlugins()) {

script/tool/lib/src/common.dart

Lines changed: 56 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,13 @@ import 'package:colorize/colorize.dart';
1212
import 'package:file/file.dart';
1313
import 'package:git/git.dart';
1414
import 'package:http/http.dart' as http;
15-
import 'package:meta/meta.dart';
1615
import 'package:path/path.dart' as p;
1716
import 'package:pub_semver/pub_semver.dart';
1817
import 'package:yaml/yaml.dart';
1918

2019
/// The signature for a print handler for commands that allow overriding the
2120
/// print destination.
22-
typedef Print = void Function(Object object);
21+
typedef Print = void Function(Object? object);
2322

2423
/// Key for windows platform.
2524
const String kWindows = 'windows';
@@ -50,7 +49,7 @@ const String kEnableExperiment = 'enable-experiment';
5049

5150
/// Returns whether the given directory contains a Flutter package.
5251
bool isFlutterPackage(FileSystemEntity entity, FileSystem fileSystem) {
53-
if (entity == null || entity is! Directory) {
52+
if (entity is! Directory) {
5453
return false;
5554
}
5655

@@ -59,7 +58,7 @@ bool isFlutterPackage(FileSystemEntity entity, FileSystem fileSystem) {
5958
fileSystem.file(p.join(entity.path, 'pubspec.yaml'));
6059
final YamlMap pubspecYaml =
6160
loadYaml(pubspecFile.readAsStringSync()) as YamlMap;
62-
final YamlMap dependencies = pubspecYaml['dependencies'] as YamlMap;
61+
final YamlMap? dependencies = pubspecYaml['dependencies'] as YamlMap?;
6362
if (dependencies == null) {
6463
return false;
6564
}
@@ -87,7 +86,7 @@ bool pluginSupportsPlatform(
8786
platform == kMacos ||
8887
platform == kWindows ||
8988
platform == kLinux);
90-
if (entity == null || entity is! Directory) {
89+
if (entity is! Directory) {
9190
return false;
9291
}
9392

@@ -96,15 +95,15 @@ bool pluginSupportsPlatform(
9695
fileSystem.file(p.join(entity.path, 'pubspec.yaml'));
9796
final YamlMap pubspecYaml =
9897
loadYaml(pubspecFile.readAsStringSync()) as YamlMap;
99-
final YamlMap flutterSection = pubspecYaml['flutter'] as YamlMap;
98+
final YamlMap? flutterSection = pubspecYaml['flutter'] as YamlMap?;
10099
if (flutterSection == null) {
101100
return false;
102101
}
103-
final YamlMap pluginSection = flutterSection['plugin'] as YamlMap;
102+
final YamlMap? pluginSection = flutterSection['plugin'] as YamlMap?;
104103
if (pluginSection == null) {
105104
return false;
106105
}
107-
final YamlMap platforms = pluginSection['platforms'] as YamlMap;
106+
final YamlMap? platforms = pluginSection['platforms'] as YamlMap?;
108107
if (platforms == null) {
109108
// Legacy plugin specs are assumed to support iOS and Android.
110109
if (!pluginSection.containsKey('platforms')) {
@@ -151,7 +150,7 @@ bool isLinuxPlugin(FileSystemEntity entity, FileSystem fileSystem) {
151150
}
152151

153152
/// Throws a [ToolExit] with `exitCode` and log the `errorMessage` in red.
154-
void printErrorAndExit({@required String errorMessage, int exitCode = 1}) {
153+
void printErrorAndExit({required String errorMessage, int exitCode = 1}) {
155154
final Colorize redError = Colorize(errorMessage)..red();
156155
print(redError);
157156
throw ToolExit(exitCode);
@@ -236,30 +235,45 @@ abstract class PluginCommand extends Command<void> {
236235
/// The git directory to use. By default it uses the parent directory.
237236
///
238237
/// This can be mocked for testing.
239-
final GitDir gitDir;
238+
final GitDir? gitDir;
240239

241-
int _shardIndex;
242-
int _shardCount;
240+
int? _shardIndex;
241+
int? _shardCount;
243242

244243
/// The shard of the overall command execution that this instance should run.
245244
int get shardIndex {
246245
if (_shardIndex == null) {
247246
_checkSharding();
248247
}
249-
return _shardIndex;
248+
return _shardIndex!;
250249
}
251250

252251
/// The number of shards this command is divided into.
253252
int get shardCount {
254253
if (_shardCount == null) {
255254
_checkSharding();
256255
}
257-
return _shardCount;
256+
return _shardCount!;
257+
}
258+
259+
/// Convenience accessor for boolean arguments.
260+
bool getBoolArg(String key) {
261+
return (argResults![key] as bool?) ?? false;
262+
}
263+
264+
/// Convenience accessor for String arguments.
265+
String getStringArg(String key) {
266+
return (argResults![key] as String?) ?? '';
267+
}
268+
269+
/// Convenience accessor for List<String> arguments.
270+
List<String> getStringListArg(String key) {
271+
return (argResults![key] as List<String>?) ?? <String>[];
258272
}
259273

260274
void _checkSharding() {
261-
final int shardIndex = int.tryParse(argResults[_shardIndexArg] as String);
262-
final int shardCount = int.tryParse(argResults[_shardCountArg] as String);
275+
final int? shardIndex = int.tryParse(getStringArg(_shardIndexArg));
276+
final int? shardCount = int.tryParse(getStringArg(_shardCountArg));
263277
if (shardIndex == null) {
264278
usageException('$_shardIndexArg must be an integer');
265279
}
@@ -317,12 +331,10 @@ abstract class PluginCommand extends Command<void> {
317331
/// is a sibling of the packages directory. This is used for a small number
318332
/// of packages in the flutter/packages repository.
319333
Stream<Directory> _getAllPlugins() async* {
320-
Set<String> plugins =
321-
Set<String>.from(argResults[_pluginsArg] as List<String>);
334+
Set<String> plugins = Set<String>.from(getStringListArg(_pluginsArg));
322335
final Set<String> excludedPlugins =
323-
Set<String>.from(argResults[_excludeArg] as List<String>);
324-
final bool runOnChangedPackages =
325-
argResults[_runOnChangedPackagesArg] as bool;
336+
Set<String>.from(getStringListArg(_excludeArg));
337+
final bool runOnChangedPackages = getBoolArg(_runOnChangedPackagesArg);
326338
if (plugins.isEmpty && runOnChangedPackages) {
327339
plugins = await _getChangedPackages();
328340
}
@@ -429,9 +441,9 @@ abstract class PluginCommand extends Command<void> {
429441
/// Throws tool exit if [gitDir] nor root directory is a git directory.
430442
Future<GitVersionFinder> retrieveVersionFinder() async {
431443
final String rootDir = packagesDir.parent.absolute.path;
432-
final String baseSha = argResults[_kBaseSha] as String;
444+
final String baseSha = getStringArg(_kBaseSha);
433445

434-
GitDir baseGitDir = gitDir;
446+
GitDir? baseGitDir = gitDir;
435447
if (baseGitDir == null) {
436448
if (!await GitDir.isGitDir(rootDir)) {
437449
printErrorAndExit(
@@ -490,7 +502,7 @@ class ProcessRunner {
490502
Future<int> runAndStream(
491503
String executable,
492504
List<String> args, {
493-
Directory workingDir,
505+
Directory? workingDir,
494506
bool exitOnError = false,
495507
}) async {
496508
print(
@@ -522,7 +534,7 @@ class ProcessRunner {
522534
///
523535
/// Returns the [io.ProcessResult] of the [executable].
524536
Future<io.ProcessResult> run(String executable, List<String> args,
525-
{Directory workingDir,
537+
{Directory? workingDir,
526538
bool exitOnError = false,
527539
bool logOnError = false,
528540
Encoding stdoutEncoding = io.systemEncoding,
@@ -550,15 +562,15 @@ class ProcessRunner {
550562
/// passing [workingDir].
551563
///
552564
/// Returns the started [io.Process].
553-
Future<io.Process> start(String executable, List<String> args,
554-
{Directory workingDirectory}) async {
565+
Future<io.Process?> start(String executable, List<String> args,
566+
{Directory? workingDirectory}) async {
555567
final io.Process process = await io.Process.start(executable, args,
556568
workingDirectory: workingDirectory?.path);
557569
return process;
558570
}
559571

560572
String _getErrorString(String executable, List<String> args,
561-
{Directory workingDir}) {
573+
{Directory? workingDir}) {
562574
final String workdir = workingDir == null ? '' : ' in ${workingDir.path}';
563575
return 'ERROR: Unable to execute "$executable ${args.join(' ')}"$workdir.';
564576
}
@@ -569,7 +581,7 @@ class PubVersionFinder {
569581
/// Constructor.
570582
///
571583
/// Note: you should manually close the [httpClient] when done using the finder.
572-
PubVersionFinder({this.pubHost = defaultPubHost, @required this.httpClient});
584+
PubVersionFinder({this.pubHost = defaultPubHost, required this.httpClient});
573585

574586
/// The default pub host to use.
575587
static const String defaultPubHost = 'https://pub.dev';
@@ -584,8 +596,8 @@ class PubVersionFinder {
584596

585597
/// Get the package version on pub.
586598
Future<PubVersionFinderResponse> getPackageVersion(
587-
{@required String package}) async {
588-
assert(package != null && package.isNotEmpty);
599+
{required String package}) async {
600+
assert(package.isNotEmpty);
589601
final Uri pubHostUri = Uri.parse(pubHost);
590602
final Uri url = pubHostUri.replace(path: '/packages/$package.json');
591603
final http.Response response = await httpClient.get(url);
@@ -618,8 +630,8 @@ class PubVersionFinder {
618630
class PubVersionFinderResponse {
619631
/// Constructor.
620632
PubVersionFinderResponse({this.versions, this.result, this.httpResponse}) {
621-
if (versions != null && versions.isNotEmpty) {
622-
versions.sort((Version a, Version b) {
633+
if (versions != null && versions!.isNotEmpty) {
634+
versions!.sort((Version a, Version b) {
623635
// TODO(cyanglaz): Think about how to handle pre-release version with [Version.prioritize].
624636
// https://github.com/flutter/flutter/issues/82222
625637
return b.compareTo(a);
@@ -631,13 +643,13 @@ class PubVersionFinderResponse {
631643
///
632644
/// This is sorted by largest to smallest, so the first element in the list is the largest version.
633645
/// Might be `null` if the [result] is not [PubVersionFinderResult.success].
634-
final List<Version> versions;
646+
final List<Version>? versions;
635647

636648
/// The result of the version finder.
637-
final PubVersionFinderResult result;
649+
final PubVersionFinderResult? result;
638650

639651
/// The response object of the http request.
640-
final http.Response httpResponse;
652+
final http.Response? httpResponse;
641653
}
642654

643655
/// An enum representing the result of [PubVersionFinder].
@@ -667,7 +679,7 @@ class GitVersionFinder {
667679
final GitDir baseGitDir;
668680

669681
/// The base sha used to get diff.
670-
final String baseSha;
682+
final String? baseSha;
671683

672684
static bool _isPubspec(String file) {
673685
return file.trim().endsWith('pubspec.yaml');
@@ -684,8 +696,7 @@ class GitVersionFinder {
684696
final io.ProcessResult changedFilesCommand = await baseGitDir
685697
.runCommand(<String>['diff', '--name-only', baseSha, 'HEAD']);
686698
print('Determine diff with base sha: $baseSha');
687-
final String changedFilesStdout =
688-
changedFilesCommand.stdout.toString() ?? '';
699+
final String changedFilesStdout = changedFilesCommand.stdout.toString();
689700
if (changedFilesStdout.isEmpty) {
690701
return <String>[];
691702
}
@@ -696,7 +707,8 @@ class GitVersionFinder {
696707

697708
/// Get the package version specified in the pubspec file in `pubspecPath` and
698709
/// at the revision of `gitRef` (defaulting to the base if not provided).
699-
Future<Version> getPackageVersion(String pubspecPath, {String gitRef}) async {
710+
Future<Version?> getPackageVersion(String pubspecPath,
711+
{String? gitRef}) async {
700712
final String ref = gitRef ?? (await _getBaseSha());
701713

702714
io.ProcessResult gitShow;
@@ -707,20 +719,19 @@ class GitVersionFinder {
707719
return null;
708720
}
709721
final String fileContent = gitShow.stdout as String;
710-
final String versionString = loadYaml(fileContent)['version'] as String;
722+
final String? versionString = loadYaml(fileContent)['version'] as String?;
711723
return versionString == null ? null : Version.parse(versionString);
712724
}
713725

714726
Future<String> _getBaseSha() async {
715-
if (baseSha != null && baseSha.isNotEmpty) {
716-
return baseSha;
727+
if (baseSha != null && baseSha!.isNotEmpty) {
728+
return baseSha!;
717729
}
718730

719731
io.ProcessResult baseShaFromMergeBase = await baseGitDir.runCommand(
720732
<String>['merge-base', '--fork-point', 'FETCH_HEAD', 'HEAD'],
721733
throwOnError: false);
722-
if (baseShaFromMergeBase == null ||
723-
baseShaFromMergeBase.stderr != null ||
734+
if (baseShaFromMergeBase.stderr != null ||
724735
baseShaFromMergeBase.stdout == null) {
725736
baseShaFromMergeBase = await baseGitDir
726737
.runCommand(<String>['merge-base', 'FETCH_HEAD', 'HEAD']);

script/tool/lib/src/create_all_plugins_app_command.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
// @dart=2.9
6+
57
import 'dart:async';
68
import 'dart:io' as io;
79

0 commit comments

Comments
 (0)