Skip to content

Commit 12ec9fe

Browse files
[tool] Use 'flutter pub get' for Flutter packages (#4397)
Extracts common logic for running `pub get`, and switches commands to use it. The common logic always uses `flutter pub get` for Flutter packages, rather than `dart pub get`, since the latter will fail if someone has a non-Flutter `dart` in their path before `flutter` (e.g., Dart team members contributing PRs).
1 parent 958750d commit 12ec9fe

11 files changed

+179
-52
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'dart:io' as io;
6+
7+
import 'package:platform/platform.dart';
8+
9+
import 'process_runner.dart';
10+
import 'repository_package.dart';
11+
12+
/// Runs either `dart pub get` or `flutter pub get` in [package], depending on
13+
/// the package type.
14+
///
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+
///
19+
/// If [streamOutput] is false, output will only be printed if the command
20+
/// fails.
21+
Future<bool> runPubGet(
22+
RepositoryPackage package, ProcessRunner processRunner, Platform platform,
23+
{bool alwaysUseFlutter = false, bool streamOutput = true}) async {
24+
// Running `dart pub get` on a Flutter package can fail if a non-Flutter Dart
25+
// is first in the path, so use `flutter pub get` for any Flutter package.
26+
final bool useFlutter = alwaysUseFlutter || package.requiresFlutter();
27+
final String command =
28+
useFlutter ? (platform.isWindows ? 'flutter.bat' : 'flutter') : 'dart';
29+
final List<String> args = <String>['pub', 'get'];
30+
31+
final int exitCode;
32+
if (streamOutput) {
33+
exitCode = await processRunner.runAndStream(command, args,
34+
workingDir: package.directory);
35+
} else {
36+
final io.ProcessResult result =
37+
await processRunner.run(command, args, workingDir: package.directory);
38+
exitCode = result.exitCode;
39+
if (exitCode != 0) {
40+
print('${result.stdout}\n${result.stderr}\n');
41+
}
42+
}
43+
return exitCode == 0;
44+
}

script/tool/lib/src/create_all_packages_app_command.dart

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import 'common/core.dart';
1313
import 'common/file_utils.dart';
1414
import 'common/package_command.dart';
1515
import 'common/process_runner.dart';
16+
import 'common/pub_utils.dart';
1617
import 'common/repository_package.dart';
1718

1819
/// The name of the build-all-packages project, as passed to `flutter create`.
@@ -96,7 +97,7 @@ class CreateAllPackagesAppCommand extends PackageCommand {
9697
// further and/or implement https://github.com/flutter/flutter/issues/93407,
9798
// and remove the need for this conditional.
9899
if (!platform.isWindows) {
99-
if (!await _genNativeBuildFiles()) {
100+
if (!await runPubGet(app, processRunner, platform)) {
100101
printError(
101102
"Failed to generate native build files via 'flutter pub get'");
102103
throw ToolExit(_exitGenNativeBuildFilesFailed);
@@ -371,15 +372,6 @@ dev_dependencies:${_pubspecMapString(pubspec.devDependencies)}
371372
return buffer.toString();
372373
}
373374

374-
Future<bool> _genNativeBuildFiles() async {
375-
final int exitCode = await processRunner.runAndStream(
376-
flutterCommand,
377-
<String>['pub', 'get'],
378-
workingDir: _appDirectory,
379-
);
380-
return exitCode == 0;
381-
}
382-
383375
Future<void> _updateMacosPodfile() async {
384376
/// Only change the macOS deployment target if the host platform is macOS.
385377
/// The Podfile is not generated on other platforms.

script/tool/lib/src/custom_test_command.dart

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:platform/platform.dart';
77

88
import 'common/package_looping_command.dart';
99
import 'common/process_runner.dart';
10+
import 'common/pub_utils.dart';
1011
import 'common/repository_package.dart';
1112

1213
const String _scriptName = 'run_tests.dart';
@@ -47,10 +48,7 @@ class CustomTestCommand extends PackageLoopingCommand {
4748
// Run the custom Dart script if presest.
4849
if (script.existsSync()) {
4950
// Ensure that dependencies are available.
50-
final int pubGetExitCode = await processRunner.runAndStream(
51-
'dart', <String>['pub', 'get'],
52-
workingDir: package.directory);
53-
if (pubGetExitCode != 0) {
51+
if (!await runPubGet(package, processRunner, platform)) {
5452
return PackageResult.fail(
5553
<String>['Unable to get script dependencies']);
5654
}

script/tool/lib/src/dart_test_command.dart

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'common/core.dart';
99
import 'common/package_looping_command.dart';
1010
import 'common/plugin_utils.dart';
1111
import 'common/process_runner.dart';
12+
import 'common/pub_utils.dart';
1213
import 'common/repository_package.dart';
1314

1415
/// A command to run Dart unit tests for packages.
@@ -130,21 +131,16 @@ class DartTestCommand extends PackageLoopingCommand {
130131
/// Runs the Dart tests for a non-Flutter package, returning true on success.
131132
Future<bool> _runDartTests(RepositoryPackage package,
132133
{String? platform}) async {
133-
// Unlike `flutter test`, `pub run test` does not automatically get
134+
// Unlike `flutter test`, `dart run test` does not automatically get
134135
// packages
135-
int exitCode = await processRunner.runAndStream(
136-
'dart',
137-
<String>['pub', 'get'],
138-
workingDir: package.directory,
139-
);
140-
if (exitCode != 0) {
136+
if (!await runPubGet(package, processRunner, super.platform)) {
141137
printError('Unable to fetch dependencies.');
142138
return false;
143139
}
144140

145141
final String experiment = getStringArg(kEnableExperiment);
146142

147-
exitCode = await processRunner.runAndStream(
143+
final int exitCode = await processRunner.runAndStream(
148144
'dart',
149145
<String>[
150146
'run',

script/tool/lib/src/publish_check_command.dart

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import 'package:pub_semver/pub_semver.dart';
1414
import 'common/core.dart';
1515
import 'common/package_looping_command.dart';
1616
import 'common/process_runner.dart';
17+
import 'common/pub_utils.dart';
1718
import 'common/pub_version_finder.dart';
1819
import 'common/repository_package.dart';
1920

@@ -136,11 +137,7 @@ class PublishCheckCommand extends PackageLoopingCommand {
136137
// Run `dart pub get` on the examples of [package].
137138
Future<void> _fetchExampleDeps(RepositoryPackage package) async {
138139
for (final RepositoryPackage example in package.getExamples()) {
139-
await processRunner.runAndStream(
140-
'dart',
141-
<String>['pub', 'get'],
142-
workingDir: example.directory,
143-
);
140+
await runPubGet(example, processRunner, platform);
144141
}
145142
}
146143

script/tool/lib/src/update_dependency_command.dart

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import 'package:yaml_edit/yaml_edit.dart';
1313
import 'common/core.dart';
1414
import 'common/package_looping_command.dart';
1515
import 'common/process_runner.dart';
16+
import 'common/pub_utils.dart';
1617
import 'common/pub_version_finder.dart';
1718
import 'common/repository_package.dart';
1819

@@ -239,11 +240,9 @@ ${response.httpResponse.body}
239240
}
240241

241242
print('${indentation}Running pub get...');
242-
final io.ProcessResult getResult = await processRunner
243-
.run('dart', <String>['pub', 'get'], workingDir: package.directory);
244-
if (getResult.exitCode != 0) {
245-
printError('dart pub get failed (${getResult.exitCode}):\n'
246-
'${getResult.stdout}\n${getResult.stderr}\n');
243+
if (!await runPubGet(package, processRunner, platform,
244+
streamOutput: false)) {
245+
printError('${indentation}Fetching dependencies failed');
247246
return false;
248247
}
249248

@@ -273,11 +272,9 @@ ${response.httpResponse.body}
273272
}
274273

275274
print('${indentation}Running pub get...');
276-
final io.ProcessResult getResult = await processRunner
277-
.run('dart', <String>['pub', 'get'], workingDir: package.directory);
278-
if (getResult.exitCode != 0) {
279-
printError('dart pub get failed (${getResult.exitCode}):\n'
280-
'${getResult.stdout}\n${getResult.stderr}\n');
275+
if (!await runPubGet(package, processRunner, platform,
276+
streamOutput: false)) {
277+
printError('${indentation}Fetching dependencies failed');
281278
return false;
282279
}
283280

script/tool/lib/src/update_excerpts_command.dart

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import 'package:yaml_edit/yaml_edit.dart';
1414
import 'common/core.dart';
1515
import 'common/package_looping_command.dart';
1616
import 'common/process_runner.dart';
17+
import 'common/pub_utils.dart';
1718
import 'common/repository_package.dart';
1819

1920
/// A command to update .md code excerpts from code files.
@@ -81,10 +82,7 @@ class UpdateExcerptsCommand extends PackageLoopingCommand {
8182

8283
try {
8384
// Ensure that dependencies are available.
84-
final int pubGetExitCode = await processRunner.runAndStream(
85-
'dart', <String>['pub', 'get'],
86-
workingDir: example.directory);
87-
if (pubGetExitCode != 0) {
85+
if (!await runPubGet(example, processRunner, platform)) {
8886
return PackageResult.fail(
8987
<String>['Unable to get script dependencies']);
9088
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:file/file.dart';
6+
import 'package:file/memory.dart';
7+
import 'package:flutter_plugin_tools/src/common/pub_utils.dart';
8+
import 'package:test/test.dart';
9+
10+
import '../mocks.dart';
11+
import '../util.dart';
12+
13+
void main() {
14+
late FileSystem fileSystem;
15+
late Directory packagesDir;
16+
late RecordingProcessRunner processRunner;
17+
18+
setUp(() {
19+
fileSystem = MemoryFileSystem();
20+
packagesDir = createPackagesDirectory(fileSystem: fileSystem);
21+
processRunner = RecordingProcessRunner();
22+
});
23+
24+
test('runs with Dart for a non-Flutter package by default', () async {
25+
final RepositoryPackage package =
26+
createFakePackage('a_package', packagesDir);
27+
final MockPlatform platform = MockPlatform();
28+
29+
await runPubGet(package, processRunner, platform);
30+
31+
expect(
32+
processRunner.recordedCalls,
33+
orderedEquals(<ProcessCall>[
34+
ProcessCall('dart', const <String>['pub', 'get'], package.path),
35+
]));
36+
});
37+
38+
test('runs with Flutter for a Flutter package by default', () async {
39+
final RepositoryPackage package =
40+
createFakePackage('a_package', packagesDir, isFlutter: true);
41+
final MockPlatform platform = MockPlatform();
42+
43+
await runPubGet(package, processRunner, platform);
44+
45+
expect(
46+
processRunner.recordedCalls,
47+
orderedEquals(<ProcessCall>[
48+
ProcessCall('flutter', const <String>['pub', 'get'], package.path),
49+
]));
50+
});
51+
52+
test('runs with Flutter for a Dart package when requested', () async {
53+
final RepositoryPackage package =
54+
createFakePackage('a_package', packagesDir);
55+
final MockPlatform platform = MockPlatform();
56+
57+
await runPubGet(package, processRunner, platform, alwaysUseFlutter: true);
58+
59+
expect(
60+
processRunner.recordedCalls,
61+
orderedEquals(<ProcessCall>[
62+
ProcessCall('flutter', const <String>['pub', 'get'], package.path),
63+
]));
64+
});
65+
66+
test('uses the correct Flutter command on Windows', () async {
67+
final RepositoryPackage package =
68+
createFakePackage('a_package', packagesDir, isFlutter: true);
69+
final MockPlatform platform = MockPlatform(isWindows: true);
70+
71+
await runPubGet(package, processRunner, platform);
72+
73+
expect(
74+
processRunner.recordedCalls,
75+
orderedEquals(<ProcessCall>[
76+
ProcessCall(
77+
'flutter.bat', const <String>['pub', 'get'], package.path),
78+
]));
79+
});
80+
81+
test('reports success', () async {
82+
final RepositoryPackage package =
83+
createFakePackage('a_package', packagesDir);
84+
final MockPlatform platform = MockPlatform();
85+
86+
final bool result = await runPubGet(package, processRunner, platform);
87+
88+
expect(result, true);
89+
});
90+
91+
test('reports failure', () async {
92+
final RepositoryPackage package =
93+
createFakePackage('a_package', packagesDir);
94+
final MockPlatform platform = MockPlatform();
95+
96+
processRunner.mockProcessesForExecutable['dart'] = <FakeProcessInfo>[
97+
FakeProcessInfo(MockProcess(exitCode: 1), <String>['pub', 'get'])
98+
];
99+
100+
final bool result = await runPubGet(package, processRunner, platform);
101+
102+
expect(result, false);
103+
});
104+
}

script/tool/test/publish_check_command_test.dart

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ void main() {
8888
final Iterable<ProcessCall> pubGetCalls =
8989
plugin1.getExamples().map((RepositoryPackage example) {
9090
return ProcessCall(
91-
'dart',
91+
getFlutterCommand(mockPlatform),
9292
const <String>['pub', 'get'],
9393
example.path,
9494
);
@@ -117,6 +117,7 @@ void main() {
117117
createFakePlugin('plugin_tools_test_package_a', packagesDir);
118118

119119
processRunner.mockProcessesForExecutable['flutter'] = <FakeProcessInfo>[
120+
FakeProcessInfo(MockProcess(), <String>['pub', 'get']),
120121
FakeProcessInfo(MockProcess(exitCode: 1, stdout: 'Some error from pub'),
121122
<String>['pub', 'publish'])
122123
];
@@ -205,7 +206,8 @@ void main() {
205206
'Packages with an SDK constraint on a pre-release of the Dart '
206207
'SDK should themselves be published as a pre-release version.');
207208
processRunner.mockProcessesForExecutable['flutter'] = <FakeProcessInfo>[
208-
FakeProcessInfo(process, <String>['pub', 'publish'])
209+
FakeProcessInfo(MockProcess(), <String>['pub', 'get']),
210+
FakeProcessInfo(process, <String>['pub', 'publish']),
209211
];
210212

211213
expect(
@@ -223,7 +225,8 @@ void main() {
223225
'Packages with an SDK constraint on a pre-release of the Dart '
224226
'SDK should themselves be published as a pre-release version.');
225227
processRunner.mockProcessesForExecutable['flutter'] = <FakeProcessInfo>[
226-
FakeProcessInfo(process, <String>['pub', 'publish'])
228+
FakeProcessInfo(MockProcess(), <String>['pub', 'get']),
229+
FakeProcessInfo(process, <String>['pub', 'publish']),
227230
];
228231

229232
Error? commandError;
@@ -247,6 +250,7 @@ void main() {
247250
createFakePlugin('d', packagesDir);
248251

249252
processRunner.mockProcessesForExecutable['flutter'] = <FakeProcessInfo>[
253+
FakeProcessInfo(MockProcess(), <String>['pub', 'get']),
250254
FakeProcessInfo(MockProcess(stdout: 'Package has 0 warnings.'),
251255
<String>['pub', 'publish']),
252256
];

script/tool/test/update_dependency_command_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ dev_dependencies:
429429
expect(
430430
output,
431431
containsAllInOrder(<Matcher>[
432-
contains('dart pub get failed'),
432+
contains('Fetching dependencies failed'),
433433
contains('Failed to update pigeon files'),
434434
]),
435435
);
@@ -545,7 +545,7 @@ dev_dependencies:
545545
expect(
546546
output,
547547
containsAllInOrder(<Matcher>[
548-
contains('dart pub get failed'),
548+
contains('Fetching dependencies failed'),
549549
contains('Failed to update mocks'),
550550
]),
551551
);

0 commit comments

Comments
 (0)