Skip to content

Commit 81b5b2f

Browse files
[tool] Make more commands work without Flutter (#11797)
- Updates some cases where 'flutter' was used unconditionally, now that we need to support a repository without Flutter installed. - Removes some outdated comments and plumbing for forcing `flutter pub` over `dart pub`, as the reason we used to do it no longer applies now that `dart pub` also fetches examples by default. - Adds `--skip-if-not-supporting-dart-version` to support N-1 and N-2 testing in core-packages.
1 parent 744bbf0 commit 81b5b2f

12 files changed

Lines changed: 185 additions & 82 deletions

script/tool/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
## 0.14.2
2+
3+
* Ensures that pub commands use `flutter` or `dart` depending on whether the
4+
package requires Flutter for analysis and publishing, to support
5+
non-Flutter-based repositories.
6+
* Adds `--skip-if-not-supporting-dart-version` to support package constraints
7+
via Dart versions rather than Flutter versions.
8+
19
## 0.14.1
210

311
* Adds `min_dart` as an alternative to `min_flutter` in tool configuration.

script/tool/lib/src/analyze_command.dart

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import 'common/gradle.dart';
1313
import 'common/output_utils.dart';
1414
import 'common/package_looping_command.dart';
1515
import 'common/plugin_utils.dart';
16+
import 'common/pub_utils.dart';
1617
import 'common/repository_package.dart';
1718
import 'common/xcode.dart';
1819

@@ -357,12 +358,13 @@ class AnalyzeCommand extends PackageLoopingCommand {
357358
}
358359

359360
Future<bool> _runPubCommand(RepositoryPackage package, String command) async {
360-
final int exitCode = await processRunner.runAndStream(
361-
flutterCommand,
362-
<String>['pub', command],
363-
workingDir: package.directory,
361+
return runPubCommand(
362+
<String>[command],
363+
package,
364+
processRunner,
365+
platform,
366+
dartSdkPathOverride: _dartBinaryPath,
364367
);
365-
return exitCode == 0;
366368
}
367369

368370
/// Runs Gradle lint analysis for the given package, and returns the result

script/tool/lib/src/common/package_looping_command.dart

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,20 @@ abstract class PackageLoopingCommand extends PackageCommand {
9595
'the provided version, or a Dart version newer than the '
9696
'corresponding Dart version.',
9797
);
98+
argParser.addOption(
99+
_skipByDartVersionArg,
100+
help:
101+
'Skip any packages that require a Dart version newer than the '
102+
'provided version.',
103+
);
98104
}
99105

100106
static const String _skipByFlutterVersionArg =
101107
'skip-if-not-supporting-flutter-version';
102108

109+
static const String _skipByDartVersionArg =
110+
'skip-if-not-supporting-dart-version';
111+
103112
/// Packages that had at least one [logWarning] call.
104113
final Set<PackageEnumerationEntry> _packagesWithWarnings =
105114
<PackageEnumerationEntry>{};
@@ -289,9 +298,15 @@ abstract class PackageLoopingCommand extends PackageCommand {
289298
final Version? minFlutterVersion = minFlutterVersionArg.isEmpty
290299
? null
291300
: Version.parse(minFlutterVersionArg);
292-
final Version? minDartVersion = minFlutterVersion == null
293-
? null
294-
: getDartSdkForFlutterSdk(minFlutterVersion);
301+
302+
// Use the explicit Dart min if provided, otherwise fall back to the
303+
// version corresponding to the Flutter min if that was provided.
304+
final String minDartVersionArg = getStringArg(_skipByDartVersionArg);
305+
final Version? minDartVersion = minDartVersionArg.isNotEmpty
306+
? Version.parse(minDartVersionArg)
307+
: (minFlutterVersion == null
308+
? null
309+
: getDartSdkForFlutterSdk(minFlutterVersion));
295310

296311
final runStart = DateTime.now();
297312

script/tool/lib/src/common/pub_utils.dart

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,42 @@ import 'repository_package.dart';
1212
/// Runs either `dart pub get` or `flutter pub get` in [package], depending on
1313
/// the package type.
1414
///
15-
/// If [alwaysUseFlutter] is true, it will use `flutter pub get` regardless.
16-
/// This can be useful, for instance, to get the `flutter`-default behavior
17-
/// of fetching example packages as well.
18-
///
1915
/// If [streamOutput] is false, output will only be printed if the command
2016
/// fails.
2117
Future<bool> runPubGet(
2218
RepositoryPackage package,
2319
ProcessRunner processRunner,
2420
Platform platform, {
25-
bool alwaysUseFlutter = false,
2621
bool streamOutput = true,
2722
}) async {
28-
// Running `dart pub get` on a Flutter package can fail if a non-Flutter Dart
29-
// is first in the path, so use `flutter pub get` for any Flutter package.
30-
final bool useFlutter = alwaysUseFlutter || package.requiresFlutter();
31-
final command = useFlutter
32-
? (platform.isWindows ? 'flutter.bat' : 'flutter')
33-
: 'dart';
34-
final args = <String>['pub', 'get'];
23+
return runPubCommand(
24+
<String>['get'],
25+
package,
26+
processRunner,
27+
platform,
28+
streamOutput: streamOutput,
29+
);
30+
}
3531

32+
/// Runs a pub command with the given arguments in [package],
33+
/// using either 'dart' or 'flutter' depending on the package type.
34+
///
35+
/// If [streamOutput] is false, output will only be printed if the command
36+
/// fails.
37+
Future<bool> runPubCommand(
38+
List<String> commandArgs,
39+
RepositoryPackage package,
40+
ProcessRunner processRunner,
41+
Platform platform, {
42+
bool streamOutput = true,
43+
String? dartSdkPathOverride,
44+
}) async {
45+
final String command = _pubCommand(
46+
package,
47+
platform,
48+
dartSdkPathOverride: dartSdkPathOverride,
49+
);
50+
final args = <String>['pub', ...commandArgs];
3651
final int exitCode;
3752
if (streamOutput) {
3853
exitCode = await processRunner.runAndStream(
@@ -53,3 +68,32 @@ Future<bool> runPubGet(
5368
}
5469
return exitCode == 0;
5570
}
71+
72+
/// Starts a pub command with the given arguments in [package],
73+
/// using either 'dart' or 'flutter' depending on the package type, and returns
74+
/// a process that can be used to wait for completion and stream output.
75+
///
76+
/// If no output capturing is necessary, prefer [runPubCommand].
77+
Future<io.Process> startPubCommand(
78+
List<String> commandArgs,
79+
RepositoryPackage package,
80+
ProcessRunner processRunner,
81+
Platform platform,
82+
) async {
83+
return processRunner.start(_pubCommand(package, platform), <String>[
84+
'pub',
85+
...commandArgs,
86+
], workingDirectory: package.directory);
87+
}
88+
89+
String _pubCommand(
90+
RepositoryPackage package,
91+
Platform platform, {
92+
String? dartSdkPathOverride,
93+
}) {
94+
// Running `dart pub get` on a Flutter package can fail if a non-Flutter Dart
95+
// is first in the path, so use `flutter pub get` for any Flutter package.
96+
return package.requiresFlutter()
97+
? (platform.isWindows ? 'flutter.bat' : 'flutter')
98+
: (dartSdkPathOverride ?? 'dart');
99+
}

script/tool/lib/src/publish_check_command.dart

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,10 +163,11 @@ class PublishCheckCommand extends PackageLoopingCommand {
163163
await _fetchExampleDeps(package);
164164

165165
print('Running pub publish --dry-run:');
166-
final io.Process process = await processRunner.start(
167-
flutterCommand,
168-
<String>['pub', 'publish', '--', '--dry-run'],
169-
workingDirectory: package.directory,
166+
final io.Process process = await startPubCommand(
167+
<String>['publish', '--dry-run'],
168+
package,
169+
processRunner,
170+
platform,
170171
);
171172

172173
final outputBuffer = StringBuffer();

script/tool/lib/src/publish_command.dart

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -477,10 +477,11 @@ Safe to ignore if the package is deleted in this commit.
477477
_ensureValidPubCredential();
478478
}
479479

480-
final io.Process publish = await processRunner.start(
481-
flutterCommand,
482-
<String>['pub', 'publish', ..._publishFlags],
483-
workingDirectory: package.directory,
480+
final io.Process publish = await startPubCommand(
481+
<String>['publish', ..._publishFlags],
482+
package,
483+
processRunner,
484+
platform,
484485
);
485486
publish.stdout.transform(utf8.decoder).listen((String data) => print(data));
486487
publish.stderr.transform(utf8.decoder).listen((String data) => print(data));

script/tool/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: flutter_plugin_tools
22
description: Productivity and CI utils for Flutter team package repositories.
33
repository: https://github.com/flutter/packages/tree/main/script/tool
4-
version: 0.14.1
4+
version: 0.14.2
55

66
dependencies:
77
args: ^2.1.0

script/tool/test/analyze_command_test.dart

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ void main() {
136136

137137
group('dart analyze', () {
138138
test('analyzes all packages', () async {
139+
// Create a non-Flutter Dart package and a Flutter plugin to make sure
140+
// the right command is used for each.
139141
final RepositoryPackage package1 = createFakePackage('a', packagesDir);
140142
final RepositoryPackage plugin2 = createFakePlugin('b', packagesDir);
141143

@@ -144,7 +146,7 @@ void main() {
144146
expect(
145147
processRunner.recordedCalls,
146148
orderedEquals(<ProcessCall>[
147-
ProcessCall('flutter', const <String>['pub', 'get'], package1.path),
149+
ProcessCall('dart', const <String>['pub', 'get'], package1.path),
148150
ProcessCall('dart', const <String>[
149151
'analyze',
150152
'--fatal-infos',
@@ -158,7 +160,7 @@ void main() {
158160
);
159161
});
160162

161-
test('skips flutter pub get for examples', () async {
163+
test('skips pub get for examples', () async {
162164
final RepositoryPackage plugin1 = createFakePlugin('a', packagesDir);
163165

164166
await runCapturingPrint(runner, <String>['analyze']);
@@ -175,7 +177,7 @@ void main() {
175177
);
176178
});
177179

178-
test('runs flutter pub get for non-example subpackages', () async {
180+
test('runs pub get for non-example subpackages', () async {
179181
final RepositoryPackage mainPackage = createFakePackage('a', packagesDir);
180182
final Directory otherPackagesDir = mainPackage.directory.childDirectory(
181183
'other_packages',
@@ -194,18 +196,9 @@ void main() {
194196
expect(
195197
processRunner.recordedCalls,
196198
orderedEquals(<ProcessCall>[
197-
ProcessCall('flutter', const <String>[
198-
'pub',
199-
'get',
200-
], mainPackage.path),
201-
ProcessCall('flutter', const <String>[
202-
'pub',
203-
'get',
204-
], subpackage1.path),
205-
ProcessCall('flutter', const <String>[
206-
'pub',
207-
'get',
208-
], subpackage2.path),
199+
ProcessCall('dart', const <String>['pub', 'get'], mainPackage.path),
200+
ProcessCall('dart', const <String>['pub', 'get'], subpackage1.path),
201+
ProcessCall('dart', const <String>['pub', 'get'], subpackage2.path),
209202
ProcessCall('dart', const <String>[
210203
'analyze',
211204
'--fatal-infos',
@@ -225,7 +218,7 @@ void main() {
225218
expect(
226219
processRunner.recordedCalls,
227220
orderedEquals(<ProcessCall>[
228-
ProcessCall('flutter', const <String>['pub', 'get'], package.path),
221+
ProcessCall('dart', const <String>['pub', 'get'], package.path),
229222
ProcessCall('dart', const <String>[
230223
'analyze',
231224
'--fatal-infos',
@@ -255,7 +248,7 @@ void main() {
255248
});
256249

257250
test(
258-
'does not run flutter pub get for non-example subpackages with --lib-only',
251+
'does not run pub get for non-example subpackages with --lib-only',
259252
() async {
260253
final RepositoryPackage mainPackage = createFakePackage(
261254
'a',
@@ -272,10 +265,7 @@ void main() {
272265
expect(
273266
processRunner.recordedCalls,
274267
orderedEquals(<ProcessCall>[
275-
ProcessCall('flutter', const <String>[
276-
'pub',
277-
'get',
278-
], mainPackage.path),
268+
ProcessCall('dart', const <String>['pub', 'get'], mainPackage.path),
279269
ProcessCall('dart', const <String>[
280270
'analyze',
281271
'--fatal-infos',

script/tool/test/common/package_looping_command_test.dart

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,51 @@ skip/b
501501
);
502502
});
503503

504-
test('skips unsupported Dart versions when requested', () async {
504+
test(
505+
'skips unsupported Dart versions when requested implicitly by Flutter version',
506+
() async {
507+
final RepositoryPackage excluded = createFakePackage(
508+
'excluded_package',
509+
packagesDir,
510+
dartConstraint: '>=2.18.0 <4.0.0',
511+
);
512+
final RepositoryPackage included = createFakePackage(
513+
'a_package',
514+
packagesDir,
515+
);
516+
517+
final TestPackageLoopingCommand command = createTestCommand(
518+
packageLoopingType: PackageLoopingType.includeAllSubpackages,
519+
hasLongOutput: false,
520+
);
521+
final List<String> output = await runCommand(
522+
command,
523+
arguments: <String>[
524+
'--skip-if-not-supporting-flutter-version=3.0.0', // Flutter 3.0.0 -> Dart 2.17.0
525+
],
526+
);
527+
528+
expect(
529+
command.checkedPackages,
530+
unorderedEquals(<String>[
531+
included.path,
532+
getExampleDir(included).path,
533+
]),
534+
);
535+
expect(command.checkedPackages, isNot(contains(excluded.path)));
536+
537+
expect(
538+
output,
539+
containsAllInOrder(<String>[
540+
'${_startHeadingColor}Running for a_package...$_endColor',
541+
'${_startHeadingColor}Running for excluded_package...$_endColor',
542+
'$_startSkipColor SKIPPING: Does not support Dart 2.17.0$_endColor',
543+
]),
544+
);
545+
},
546+
);
547+
548+
test('skips unsupported Dart versions when requested explicitly', () async {
505549
final RepositoryPackage excluded = createFakePackage(
506550
'excluded_package',
507551
packagesDir,
@@ -518,9 +562,7 @@ skip/b
518562
);
519563
final List<String> output = await runCommand(
520564
command,
521-
arguments: <String>[
522-
'--skip-if-not-supporting-flutter-version=3.0.0', // Flutter 3.0.0 -> Dart 2.17.0
523-
],
565+
arguments: <String>['--skip-if-not-supporting-dart-version=2.17.0'],
524566
);
525567

526568
expect(

script/tool/test/common/pub_utils_test.dart

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -53,23 +53,6 @@ void main() {
5353
);
5454
});
5555

56-
test('runs with Flutter for a Dart package when requested', () async {
57-
final RepositoryPackage package = createFakePackage(
58-
'a_package',
59-
packagesDir,
60-
);
61-
final platform = MockPlatform();
62-
63-
await runPubGet(package, processRunner, platform, alwaysUseFlutter: true);
64-
65-
expect(
66-
processRunner.recordedCalls,
67-
orderedEquals(<ProcessCall>[
68-
ProcessCall('flutter', const <String>['pub', 'get'], package.path),
69-
]),
70-
);
71-
});
72-
7356
test('uses the correct Flutter command on Windows', () async {
7457
final RepositoryPackage package = createFakePackage(
7558
'a_package',

0 commit comments

Comments
 (0)