mirror of
https://github.com/flutter/packages.git
synced 2025-06-18 04:33:52 +08:00
[tool/ci] Add iOS/macOS and Dart support to fetch-deps
(#4562)
Adds `fetch-deps` support for: - iOS/macOS dependencies, using `pod install` - Dart package dependencies, using `pub get` To make avoid doing extra work in the Dart dependencies step when using this with `*_platform_tests` CI, also adds flags for all of the other platforms, and adds a flag that allows skipping Dart dependencies for any package that doesn't have an example supporting any requested platform. This means that we can pass, e.g., `--windows --supporting-target-platforms-only` to only fetch Dart packages for packages with examples that will be build during the build-and-drive Windows tests. Adds this as a new step in every platform tests CI task, and in the standard analyze step, so that we will pre-fetch Dart packages (and for iOS/macOS, pods). This won't yet fully eliminate later network access (see https://github.com/flutter/flutter/issues/131204), but will give us early warning on any major failures, such as pub being entirely unreachable from the bots. - These are marked as an infrastructure step; we'll have to see if this ends up being confusing in practice. If `pub` resolution fails for legitimate reasons, such as a PR that tries to require a version of a package that doesn't exist or that has conflicts, this will cause a failure that is marked as infra. My assumption is that the much more common case is going to be that it is actually an infra failure. Fixes https://github.com/flutter/flutter/issues/130280
This commit is contained in:
@ -4,6 +4,10 @@ tasks:
|
|||||||
infra_step: true # Note infra steps failing prevents "always" from running.
|
infra_step: true # Note infra steps failing prevents "always" from running.
|
||||||
- name: analyze repo tools
|
- name: analyze repo tools
|
||||||
script: .ci/scripts/analyze_repo_tools.sh
|
script: .ci/scripts/analyze_repo_tools.sh
|
||||||
|
- name: download Dart deps
|
||||||
|
script: script/tool_runner.sh
|
||||||
|
args: ["fetch-deps"]
|
||||||
|
infra_step: true
|
||||||
- name: analyze
|
- name: analyze
|
||||||
script: script/tool_runner.sh
|
script: script/tool_runner.sh
|
||||||
# DO NOT change the custom-analysis argument here without changing the Dart repo.
|
# DO NOT change the custom-analysis argument here without changing the Dart repo.
|
||||||
|
@ -2,10 +2,10 @@ tasks:
|
|||||||
- name: prepare tool
|
- name: prepare tool
|
||||||
script: .ci/scripts/prepare_tool.sh
|
script: .ci/scripts/prepare_tool.sh
|
||||||
infra_step: true # Note infra steps failing prevents "always" from running.
|
infra_step: true # Note infra steps failing prevents "always" from running.
|
||||||
- name: download android deps
|
- name: download Dart and Android deps
|
||||||
script: script/tool_runner.sh
|
script: script/tool_runner.sh
|
||||||
infra_step: true
|
infra_step: true
|
||||||
args: ["fetch-deps"]
|
args: ["fetch-deps", "--android", "--supporting-target-platforms-only"]
|
||||||
- name: build examples
|
- name: build examples
|
||||||
script: script/tool_runner.sh
|
script: script/tool_runner.sh
|
||||||
args: ["build-examples", "--apk"]
|
args: ["build-examples", "--apk"]
|
||||||
|
@ -5,6 +5,10 @@ tasks:
|
|||||||
- name: create simulator
|
- name: create simulator
|
||||||
script: .ci/scripts/create_simulator.sh
|
script: .ci/scripts/create_simulator.sh
|
||||||
infra_step: true # Note infra steps failing prevents "always" from running.
|
infra_step: true # Note infra steps failing prevents "always" from running.
|
||||||
|
- name: download Dart and iOS deps
|
||||||
|
script: script/tool_runner.sh
|
||||||
|
args: ["fetch-deps", "--ios", "--supporting-target-platforms-only"]
|
||||||
|
infra_step: true
|
||||||
- name: build examples
|
- name: build examples
|
||||||
script: script/tool_runner.sh
|
script: script/tool_runner.sh
|
||||||
args: ["build-examples", "--ios"]
|
args: ["build-examples", "--ios"]
|
||||||
|
@ -3,6 +3,11 @@ tasks:
|
|||||||
script: .ci/scripts/prepare_tool.sh
|
script: .ci/scripts/prepare_tool.sh
|
||||||
- name: set default apps
|
- name: set default apps
|
||||||
script: .ci/scripts/set_default_linux_apps.sh
|
script: .ci/scripts/set_default_linux_apps.sh
|
||||||
|
infra_step: true
|
||||||
|
- name: download Dart deps
|
||||||
|
script: script/tool_runner.sh
|
||||||
|
args: ["fetch-deps", "--linux", "--supporting-target-platforms-only"]
|
||||||
|
infra_step: true
|
||||||
- name: build examples
|
- name: build examples
|
||||||
script: script/tool_runner.sh
|
script: script/tool_runner.sh
|
||||||
args: ["build-examples", "--linux"]
|
args: ["build-examples", "--linux"]
|
||||||
|
@ -2,6 +2,10 @@ tasks:
|
|||||||
- name: prepare tool
|
- name: prepare tool
|
||||||
script: .ci/scripts/prepare_tool.sh
|
script: .ci/scripts/prepare_tool.sh
|
||||||
infra_step: true # Note infra steps failing prevents "always" from running.
|
infra_step: true # Note infra steps failing prevents "always" from running.
|
||||||
|
- name: download Dart and macOS deps
|
||||||
|
script: script/tool_runner.sh
|
||||||
|
args: ["fetch-deps", "--macos", "--supporting-target-platforms-only"]
|
||||||
|
infra_step: true
|
||||||
- name: build examples
|
- name: build examples
|
||||||
script: script/tool_runner.sh
|
script: script/tool_runner.sh
|
||||||
args: ["build-examples", "--macos"]
|
args: ["build-examples", "--macos"]
|
||||||
|
@ -2,6 +2,10 @@ tasks:
|
|||||||
- name: prepare tool
|
- name: prepare tool
|
||||||
script: .ci/scripts/prepare_tool.sh
|
script: .ci/scripts/prepare_tool.sh
|
||||||
infra_step: true # Note infra steps failing prevents "always" from running.
|
infra_step: true # Note infra steps failing prevents "always" from running.
|
||||||
|
- name: download Dart deps
|
||||||
|
script: script/tool_runner.sh
|
||||||
|
args: ["fetch-deps", "--web", "--supporting-target-platforms-only"]
|
||||||
|
infra_step: true
|
||||||
- name: build examples
|
- name: build examples
|
||||||
script: script/tool_runner.sh
|
script: script/tool_runner.sh
|
||||||
args: ["build-examples", "--web"]
|
args: ["build-examples", "--web"]
|
||||||
|
@ -2,6 +2,10 @@ tasks:
|
|||||||
- name: prepare tool
|
- name: prepare tool
|
||||||
script: .ci/scripts/prepare_tool.sh
|
script: .ci/scripts/prepare_tool.sh
|
||||||
infra_step: true # Note infra steps failing prevents "always" from running.
|
infra_step: true # Note infra steps failing prevents "always" from running.
|
||||||
|
- name: download Dart deps
|
||||||
|
script: script/tool_runner.sh
|
||||||
|
args: ["fetch-deps", "--windows", "--supporting-target-platforms-only"]
|
||||||
|
infra_step: true
|
||||||
- name: build examples (Win32)
|
- name: build examples (Win32)
|
||||||
script: .ci/scripts/build_examples_win32.sh
|
script: .ci/scripts/build_examples_win32.sh
|
||||||
- name: native unit tests (Win32)
|
- name: native unit tests (Win32)
|
||||||
|
@ -176,9 +176,8 @@ class BuildExamplesCommand extends PackageLoopingCommand {
|
|||||||
// supported platforms. For packages, just log and skip any requested
|
// supported platforms. For packages, just log and skip any requested
|
||||||
// platform that a package doesn't have set up.
|
// platform that a package doesn't have set up.
|
||||||
if (!isPlugin &&
|
if (!isPlugin &&
|
||||||
!example.directory
|
!example.appSupportsPlatform(
|
||||||
.childDirectory(platform.flutterPlatformDirectory)
|
getPlatformByName(platform.pluginPlatform))) {
|
||||||
.existsSync()) {
|
|
||||||
print('Skipping ${platform.label} for $packageName; not supported.');
|
print('Skipping ${platform.label} for $packageName; not supported.');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -304,11 +303,6 @@ class _PlatformDetails {
|
|||||||
/// The `flutter build` build type.
|
/// The `flutter build` build type.
|
||||||
final String flutterBuildType;
|
final String flutterBuildType;
|
||||||
|
|
||||||
/// The Flutter platform directory name.
|
|
||||||
// In practice, this is the same as the plugin platform key for all platforms.
|
|
||||||
// If that changes, this can be adjusted.
|
|
||||||
String get flutterPlatformDirectory => pluginPlatform;
|
|
||||||
|
|
||||||
/// Any extra flags to pass to `flutter build`.
|
/// Any extra flags to pass to `flutter build`.
|
||||||
final List<String> extraBuildFlags;
|
final List<String> extraBuildFlags;
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,25 @@ const String kEnableExperiment = 'enable-experiment';
|
|||||||
// ignore: public_member_api_docs
|
// ignore: public_member_api_docs
|
||||||
enum FlutterPlatform { android, ios, linux, macos, web, windows }
|
enum FlutterPlatform { android, ios, linux, macos, web, windows }
|
||||||
|
|
||||||
|
const Map<String, FlutterPlatform> _platformByName = <String, FlutterPlatform>{
|
||||||
|
platformAndroid: FlutterPlatform.android,
|
||||||
|
platformIOS: FlutterPlatform.ios,
|
||||||
|
platformLinux: FlutterPlatform.linux,
|
||||||
|
platformMacOS: FlutterPlatform.macos,
|
||||||
|
platformWeb: FlutterPlatform.web,
|
||||||
|
platformWindows: FlutterPlatform.windows,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Maps from a platform name (e.g., flag or platform directory) to the
|
||||||
|
/// corresponding platform enum.
|
||||||
|
FlutterPlatform getPlatformByName(String name) {
|
||||||
|
final FlutterPlatform? platform = _platformByName[name];
|
||||||
|
if (platform == null) {
|
||||||
|
throw ArgumentError('Invalid platform: $name');
|
||||||
|
}
|
||||||
|
return platform;
|
||||||
|
}
|
||||||
|
|
||||||
// Flutter->Dart SDK version mapping. Any time a command fails to look up a
|
// Flutter->Dart SDK version mapping. Any time a command fails to look up a
|
||||||
// corresponding version, this map should be updated.
|
// corresponding version, this map should be updated.
|
||||||
final Map<Version, Version> _dartSdkForFlutterSdk = <Version, Version>{
|
final Map<Version, Version> _dartSdkForFlutterSdk = <Version, Version>{
|
||||||
|
@ -30,12 +30,13 @@ class ProcessRunner {
|
|||||||
String executable,
|
String executable,
|
||||||
List<String> args, {
|
List<String> args, {
|
||||||
Directory? workingDir,
|
Directory? workingDir,
|
||||||
|
Map<String, String>? environment,
|
||||||
bool exitOnError = false,
|
bool exitOnError = false,
|
||||||
}) async {
|
}) async {
|
||||||
print(
|
print(
|
||||||
'Running command: "$executable ${args.join(' ')}" in ${workingDir?.path ?? io.Directory.current.path}');
|
'Running command: "$executable ${args.join(' ')}" in ${workingDir?.path ?? io.Directory.current.path}');
|
||||||
final io.Process process = await io.Process.start(executable, args,
|
final io.Process process = await io.Process.start(executable, args,
|
||||||
workingDirectory: workingDir?.path);
|
workingDirectory: workingDir?.path, environment: environment);
|
||||||
await Future.wait(<Future<dynamic>>[
|
await Future.wait(<Future<dynamic>>[
|
||||||
io.stdout.addStream(process.stdout),
|
io.stdout.addStream(process.stdout),
|
||||||
io.stderr.addStream(process.stderr),
|
io.stderr.addStream(process.stderr),
|
||||||
@ -62,14 +63,19 @@ class ProcessRunner {
|
|||||||
/// Defaults to `false`
|
/// Defaults to `false`
|
||||||
///
|
///
|
||||||
/// Returns the [io.ProcessResult] of the [executable].
|
/// Returns the [io.ProcessResult] of the [executable].
|
||||||
Future<io.ProcessResult> run(String executable, List<String> args,
|
Future<io.ProcessResult> run(
|
||||||
{Directory? workingDir,
|
String executable,
|
||||||
bool exitOnError = false,
|
List<String> args, {
|
||||||
bool logOnError = false,
|
Directory? workingDir,
|
||||||
Encoding stdoutEncoding = io.systemEncoding,
|
Map<String, String>? environment,
|
||||||
Encoding stderrEncoding = io.systemEncoding}) async {
|
bool exitOnError = false,
|
||||||
|
bool logOnError = false,
|
||||||
|
Encoding stdoutEncoding = io.systemEncoding,
|
||||||
|
Encoding stderrEncoding = io.systemEncoding,
|
||||||
|
}) async {
|
||||||
final io.ProcessResult result = await io.Process.run(executable, args,
|
final io.ProcessResult result = await io.Process.run(executable, args,
|
||||||
workingDirectory: workingDir?.path,
|
workingDirectory: workingDir?.path,
|
||||||
|
environment: environment,
|
||||||
stdoutEncoding: stdoutEncoding,
|
stdoutEncoding: stdoutEncoding,
|
||||||
stderrEncoding: stderrEncoding);
|
stderrEncoding: stderrEncoding);
|
||||||
if (result.exitCode != 0) {
|
if (result.exitCode != 0) {
|
||||||
|
@ -92,6 +92,16 @@ class RepositoryPackage {
|
|||||||
return directory.childDirectory(directoryName);
|
return directory.childDirectory(directoryName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the package is an app that supports [platform].
|
||||||
|
///
|
||||||
|
/// The "app" prefix on this method is because this currently only works
|
||||||
|
/// for app packages (e.g., examples).
|
||||||
|
// TODO(stuartmorgan): Add support for non-app packages, by parsing the
|
||||||
|
// pubspec for `flutter:platform:` or `platform:` sections.
|
||||||
|
bool appSupportsPlatform(FlutterPlatform platform) {
|
||||||
|
return platformDirectory(platform).existsSync();
|
||||||
|
}
|
||||||
|
|
||||||
late final Pubspec _parsedPubspec =
|
late final Pubspec _parsedPubspec =
|
||||||
Pubspec.parse(pubspecFile.readAsStringSync());
|
Pubspec.parse(pubspecFile.readAsStringSync());
|
||||||
|
|
||||||
|
@ -254,7 +254,7 @@ class DriveExamplesCommand extends PackageLoopingCommand {
|
|||||||
for (final MapEntry<String, List<String>> entry
|
for (final MapEntry<String, List<String>> entry
|
||||||
in _targetDeviceFlags.entries) {
|
in _targetDeviceFlags.entries) {
|
||||||
final String platform = entry.key;
|
final String platform = entry.key;
|
||||||
if (example.directory.childDirectory(platform).existsSync()) {
|
if (example.appSupportsPlatform(getPlatformByName(platform))) {
|
||||||
deviceFlags.addAll(entry.value);
|
deviceFlags.addAll(entry.value);
|
||||||
} else {
|
} else {
|
||||||
final String exampleName =
|
final String exampleName =
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:file/file.dart';
|
||||||
|
|
||||||
import 'common/core.dart';
|
import 'common/core.dart';
|
||||||
import 'common/gradle.dart';
|
import 'common/gradle.dart';
|
||||||
@ -10,12 +11,15 @@ import 'common/package_looping_command.dart';
|
|||||||
import 'common/plugin_utils.dart';
|
import 'common/plugin_utils.dart';
|
||||||
import 'common/repository_package.dart';
|
import 'common/repository_package.dart';
|
||||||
|
|
||||||
/// Download dependencies for the following platforms {android}.
|
const int _exitPrecacheFailed = 3;
|
||||||
|
const int _exitNothingRequested = 4;
|
||||||
|
|
||||||
|
/// Download dependencies, both Dart and native.
|
||||||
///
|
///
|
||||||
/// Specficially each platform runs:
|
/// Specficially each platform runs:
|
||||||
/// Android: 'gradlew dependencies'.
|
/// Android: 'gradlew dependencies'.
|
||||||
/// Dart: TBD (flutter/flutter/issues/130279)
|
/// Dart: 'flutter pub get'.
|
||||||
/// iOS: TBD (flutter/flutter/issues/130280)
|
/// iOS/macOS: 'pod install'.
|
||||||
///
|
///
|
||||||
/// See https://docs.gradle.org/6.4/userguide/core_dependency_management.html#sec:dependency-mgmt-in-gradle.
|
/// See https://docs.gradle.org/6.4/userguide/core_dependency_management.html#sec:dependency-mgmt-in-gradle.
|
||||||
class FetchDepsCommand extends PackageLoopingCommand {
|
class FetchDepsCommand extends PackageLoopingCommand {
|
||||||
@ -24,25 +28,153 @@ class FetchDepsCommand extends PackageLoopingCommand {
|
|||||||
super.packagesDir, {
|
super.packagesDir, {
|
||||||
super.processRunner,
|
super.processRunner,
|
||||||
super.platform,
|
super.platform,
|
||||||
});
|
}) {
|
||||||
|
argParser.addFlag(_dartFlag, defaultsTo: true, help: 'Run "pub get"');
|
||||||
|
argParser.addFlag(_supportingTargetPlatformsOnlyFlag,
|
||||||
|
help: 'Restricts "pub get" runs to packages that have at least one '
|
||||||
|
'example supporting at least one of the platform flags passed.\n'
|
||||||
|
'If no platform flags are passed, this will exclude all packages.');
|
||||||
|
argParser.addFlag(platformAndroid,
|
||||||
|
help: 'Run "gradlew dependencies" for Android plugins.\n'
|
||||||
|
'Include packages with Android examples when used with '
|
||||||
|
'--$_supportingTargetPlatformsOnlyFlag');
|
||||||
|
argParser.addFlag(platformIOS,
|
||||||
|
help: 'Run "pod install" for iOS plugins.\n'
|
||||||
|
'Include packages with iOS examples when used with '
|
||||||
|
'--$_supportingTargetPlatformsOnlyFlag');
|
||||||
|
argParser.addFlag(platformLinux,
|
||||||
|
help: 'Include packages with Linux examples when used with '
|
||||||
|
'--$_supportingTargetPlatformsOnlyFlag');
|
||||||
|
argParser.addFlag(platformMacOS,
|
||||||
|
help: 'Run "pod install" for macOS plugins.\n'
|
||||||
|
'Include packages with macOS examples when used with '
|
||||||
|
'--$_supportingTargetPlatformsOnlyFlag');
|
||||||
|
argParser.addFlag(platformWeb,
|
||||||
|
help: 'Include packages with Web examples when used with '
|
||||||
|
'--$_supportingTargetPlatformsOnlyFlag');
|
||||||
|
argParser.addFlag(platformWindows,
|
||||||
|
help: 'Include packages with Windows examples when used with '
|
||||||
|
'--$_supportingTargetPlatformsOnlyFlag');
|
||||||
|
}
|
||||||
|
|
||||||
|
static const String _dartFlag = 'dart';
|
||||||
|
static const String _supportingTargetPlatformsOnlyFlag =
|
||||||
|
'supporting-target-platforms-only';
|
||||||
|
|
||||||
|
static const Iterable<String> _platforms = <String>[
|
||||||
|
platformAndroid,
|
||||||
|
platformIOS,
|
||||||
|
platformLinux,
|
||||||
|
platformMacOS,
|
||||||
|
platformWeb,
|
||||||
|
platformWindows,
|
||||||
|
];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final String name = 'fetch-deps';
|
final String name = 'fetch-deps';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final String description = 'Fetches dependencies for plugins.\n'
|
final String description = 'Fetches dependencies for packages';
|
||||||
'Runs "gradlew dependencies" on Android plugins.\n'
|
|
||||||
'Dart see flutter/flutter/issues/130279\n'
|
@override
|
||||||
'iOS plugins see flutter/flutter/issues/130280\n'
|
Future<void> initializeRun() async {
|
||||||
'\n'
|
// `pod install` requires having the platform artifacts precached. See
|
||||||
'Requires the examples to have been built at least once before running.';
|
// https://github.com/flutter/flutter/blob/fb7a763c640d247d090cbb373e4b3a0459ac171b/packages/flutter_tools/bin/podhelper.rb#L47
|
||||||
|
// https://github.com/flutter/flutter/blob/fb7a763c640d247d090cbb373e4b3a0459ac171b/packages/flutter_tools/bin/podhelper.rb#L130
|
||||||
|
if (getBoolArg(platformIOS)) {
|
||||||
|
final int exitCode = await processRunner.runAndStream(
|
||||||
|
flutterCommand,
|
||||||
|
<String>['precache', '--ios'],
|
||||||
|
);
|
||||||
|
if (exitCode != 0) {
|
||||||
|
throw ToolExit(_exitPrecacheFailed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (getBoolArg(platformMacOS)) {
|
||||||
|
final int exitCode = await processRunner.runAndStream(
|
||||||
|
flutterCommand,
|
||||||
|
<String>['precache', '--macos'],
|
||||||
|
);
|
||||||
|
if (exitCode != 0) {
|
||||||
|
throw ToolExit(_exitPrecacheFailed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<PackageResult> runForPackage(RepositoryPackage package) async {
|
Future<PackageResult> runForPackage(RepositoryPackage package) async {
|
||||||
|
bool fetchedDeps = false;
|
||||||
|
final List<String> skips = <String>[];
|
||||||
|
if (getBoolArg(_dartFlag)) {
|
||||||
|
final bool filterPlatforms =
|
||||||
|
getBoolArg(_supportingTargetPlatformsOnlyFlag);
|
||||||
|
if (!filterPlatforms || _hasExampleSupportingRequestedPlatform(package)) {
|
||||||
|
fetchedDeps = true;
|
||||||
|
if (!await _fetchDartPackages(package)) {
|
||||||
|
// If Dart-level depenendencies fail, fail immediately since the
|
||||||
|
// native dependencies won't be useful.
|
||||||
|
return PackageResult.fail(<String>['Failed to "pub get".']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
skips.add('Skipping Dart dependencies; no examples support requested '
|
||||||
|
'platforms.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<String> errors = <String>[];
|
||||||
|
for (final FlutterPlatform platform in _targetPlatforms) {
|
||||||
|
final PackageResult result;
|
||||||
|
switch (platform) {
|
||||||
|
case FlutterPlatform.android:
|
||||||
|
result = await _fetchAndroidDeps(package);
|
||||||
|
break;
|
||||||
|
case FlutterPlatform.ios:
|
||||||
|
result = await _fetchDarwinDeps(package, platformIOS);
|
||||||
|
break;
|
||||||
|
case FlutterPlatform.macos:
|
||||||
|
result = await _fetchDarwinDeps(package, platformMacOS);
|
||||||
|
break;
|
||||||
|
case FlutterPlatform.linux:
|
||||||
|
case FlutterPlatform.web:
|
||||||
|
case FlutterPlatform.windows:
|
||||||
|
// No native dependency handling yet.
|
||||||
|
result = PackageResult.skip('Nothing to do for $platform.');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (result.state) {
|
||||||
|
case RunState.succeeded:
|
||||||
|
fetchedDeps = true;
|
||||||
|
break;
|
||||||
|
case RunState.skipped:
|
||||||
|
skips.add(result.details.first);
|
||||||
|
break;
|
||||||
|
case RunState.failed:
|
||||||
|
errors.addAll(result.details);
|
||||||
|
break;
|
||||||
|
case RunState.excluded:
|
||||||
|
throw StateError('Unreachable');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errors.isNotEmpty) {
|
||||||
|
return PackageResult.fail(errors);
|
||||||
|
}
|
||||||
|
if (fetchedDeps) {
|
||||||
|
return PackageResult.success();
|
||||||
|
}
|
||||||
|
if (skips.isNotEmpty) {
|
||||||
|
return PackageResult.skip(<String>['', ...skips].join('\n- '));
|
||||||
|
}
|
||||||
|
|
||||||
|
printError('At least one type of dependency must be requested');
|
||||||
|
throw ToolExit(_exitNothingRequested);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<PackageResult> _fetchAndroidDeps(RepositoryPackage package) async {
|
||||||
if (!pluginSupportsPlatform(platformAndroid, package,
|
if (!pluginSupportsPlatform(platformAndroid, package,
|
||||||
requiredMode: PlatformSupport.inline)) {
|
requiredMode: PlatformSupport.inline)) {
|
||||||
return PackageResult.skip(
|
return PackageResult.skip(
|
||||||
'Plugin does not have an Android implementation.');
|
'Package does not have native Android dependencies.');
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final RepositoryPackage example in package.getExamples()) {
|
for (final RepositoryPackage example in package.getExamples()) {
|
||||||
@ -63,7 +195,8 @@ class FetchDepsCommand extends PackageLoopingCommand {
|
|||||||
|
|
||||||
final String packageName = package.directory.basename;
|
final String packageName = package.directory.basename;
|
||||||
|
|
||||||
final int exitCode = await gradleProject.runCommand('$packageName:dependencies');
|
final int exitCode =
|
||||||
|
await gradleProject.runCommand('$packageName:dependencies');
|
||||||
if (exitCode != 0) {
|
if (exitCode != 0) {
|
||||||
return PackageResult.fail();
|
return PackageResult.fail();
|
||||||
}
|
}
|
||||||
@ -71,4 +204,78 @@ class FetchDepsCommand extends PackageLoopingCommand {
|
|||||||
|
|
||||||
return PackageResult.success();
|
return PackageResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<PackageResult> _fetchDarwinDeps(
|
||||||
|
RepositoryPackage package, final String platform) async {
|
||||||
|
if (!pluginSupportsPlatform(platform, package,
|
||||||
|
requiredMode: PlatformSupport.inline)) {
|
||||||
|
// Convert from the flag (lower case ios/macos) to the actual name.
|
||||||
|
final String displayPlatform = platform.replaceFirst('os', 'OS');
|
||||||
|
return PackageResult.skip(
|
||||||
|
'Package does not have native $displayPlatform dependencies.');
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final RepositoryPackage example in package.getExamples()) {
|
||||||
|
final Directory platformDir =
|
||||||
|
example.platformDirectory(getPlatformByName(platform));
|
||||||
|
|
||||||
|
// Running `pod install` requires `flutter pub get` or `flutter build` to
|
||||||
|
// have been run at some point to create the necessary native build files.
|
||||||
|
// See https://github.com/flutter/flutter/blob/fb7a763c640d247d090cbb373e4b3a0459ac171b/packages/flutter_tools/templates/cocoapods/Podfile-macos#L13-L15
|
||||||
|
// and https://github.com/flutter/flutter/blob/fb7a763c640d247d090cbb373e4b3a0459ac171b/packages/flutter_tools/templates/cocoapods/Podfile-ios-swift#L14-L16
|
||||||
|
final File generatedXCConfig = platform == platformMacOS
|
||||||
|
? platformDir
|
||||||
|
.childDirectory('Flutter')
|
||||||
|
.childDirectory('ephemeral')
|
||||||
|
.childFile('Flutter-Generated.xcconfig')
|
||||||
|
: platformDir
|
||||||
|
.childDirectory('Flutter')
|
||||||
|
.childFile('Generated.xcconfig');
|
||||||
|
if (!generatedXCConfig.existsSync()) {
|
||||||
|
final int exitCode = await processRunner.runAndStream(
|
||||||
|
flutterCommand,
|
||||||
|
<String>['pub', 'get'],
|
||||||
|
workingDir: example.directory,
|
||||||
|
);
|
||||||
|
if (exitCode != 0) {
|
||||||
|
printError('Unable to prepare native project files.');
|
||||||
|
return PackageResult.fail(<String>['Unable to configure project.']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final int exitCode = await processRunner.runAndStream(
|
||||||
|
'pod',
|
||||||
|
<String>['install'],
|
||||||
|
workingDir: platformDir,
|
||||||
|
environment: <String, String>{
|
||||||
|
'LANG': 'en_US.UTF-8',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (exitCode != 0) {
|
||||||
|
printError('Unable to "pod install"');
|
||||||
|
return PackageResult.fail(<String>['Unable to "pod install"']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PackageResult.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _fetchDartPackages(RepositoryPackage package) async {
|
||||||
|
final String command = package.requiresFlutter() ? flutterCommand : 'dart';
|
||||||
|
final int exitCode = await processRunner.runAndStream(
|
||||||
|
command, <String>['pub', 'get'],
|
||||||
|
workingDir: package.directory);
|
||||||
|
return exitCode == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _hasExampleSupportingRequestedPlatform(RepositoryPackage package) {
|
||||||
|
return package.getExamples().any((RepositoryPackage example) {
|
||||||
|
return _targetPlatforms.any(
|
||||||
|
(FlutterPlatform platform) => example.appSupportsPlatform(platform));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterable<FlutterPlatform> get _targetPlatforms => _platforms
|
||||||
|
.where((String platform) => getBoolArg(platform))
|
||||||
|
.map((String platformName) => getPlatformByName(platformName));
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,142 @@ void main() {
|
|||||||
CommandRunner<void>('fetch_deps_test', 'Test for $FetchDepsCommand');
|
CommandRunner<void>('fetch_deps_test', 'Test for $FetchDepsCommand');
|
||||||
runner.addCommand(command);
|
runner.addCommand(command);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group('dart', () {
|
||||||
|
test('runs pub get', () async {
|
||||||
|
final RepositoryPackage plugin = createFakePlugin(
|
||||||
|
'plugin1', packagesDir, platformSupport: <String, PlatformDetails>{
|
||||||
|
platformIOS: const PlatformDetails(PlatformSupport.inline)
|
||||||
|
});
|
||||||
|
|
||||||
|
final List<String> output =
|
||||||
|
await runCapturingPrint(runner, <String>['fetch-deps']);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
processRunner.recordedCalls,
|
||||||
|
orderedEquals(<ProcessCall>[
|
||||||
|
ProcessCall(
|
||||||
|
'flutter',
|
||||||
|
const <String>['pub', 'get'],
|
||||||
|
plugin.directory.path,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
output,
|
||||||
|
containsAllInOrder(<Matcher>[
|
||||||
|
contains('Running for plugin1'),
|
||||||
|
contains('No issues found!'),
|
||||||
|
]));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('fails if pub get fails', () async {
|
||||||
|
createFakePlugin('plugin1', packagesDir,
|
||||||
|
platformSupport: <String, PlatformDetails>{
|
||||||
|
platformIOS: const PlatformDetails(PlatformSupport.inline)
|
||||||
|
});
|
||||||
|
|
||||||
|
processRunner
|
||||||
|
.mockProcessesForExecutable[getFlutterCommand(mockPlatform)] =
|
||||||
|
<FakeProcessInfo>[
|
||||||
|
FakeProcessInfo(MockProcess(exitCode: 1)),
|
||||||
|
];
|
||||||
|
|
||||||
|
Error? commandError;
|
||||||
|
final List<String> output = await runCapturingPrint(
|
||||||
|
runner, <String>['fetch-deps'], errorHandler: (Error e) {
|
||||||
|
commandError = e;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(commandError, isA<ToolExit>());
|
||||||
|
expect(
|
||||||
|
output,
|
||||||
|
containsAllInOrder(
|
||||||
|
<Matcher>[
|
||||||
|
contains('Failed to "pub get"'),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('skips unsupported packages when any platforms are passed',
|
||||||
|
() async {
|
||||||
|
final RepositoryPackage packageWithBoth = createFakePackage(
|
||||||
|
'supports_both', packagesDir, extraFiles: <String>[
|
||||||
|
'example/linux/placeholder',
|
||||||
|
'example/windows/placeholder'
|
||||||
|
]);
|
||||||
|
final RepositoryPackage packageWithOne = createFakePackage(
|
||||||
|
'supports_one', packagesDir,
|
||||||
|
extraFiles: <String>['example/linux/placeholder']);
|
||||||
|
createFakePackage('supports_neither', packagesDir);
|
||||||
|
|
||||||
|
await runCapturingPrint(runner, <String>[
|
||||||
|
'fetch-deps',
|
||||||
|
'--linux',
|
||||||
|
'--windows',
|
||||||
|
'--supporting-target-platforms-only'
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
processRunner.recordedCalls,
|
||||||
|
orderedEquals(<ProcessCall>[
|
||||||
|
ProcessCall(
|
||||||
|
'dart',
|
||||||
|
const <String>['pub', 'get'],
|
||||||
|
packageWithBoth.path,
|
||||||
|
),
|
||||||
|
ProcessCall(
|
||||||
|
'dart',
|
||||||
|
const <String>['pub', 'get'],
|
||||||
|
packageWithOne.path,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
group('android', () {
|
group('android', () {
|
||||||
|
test('runs pub get before gradlew dependencies', () async {
|
||||||
|
final RepositoryPackage plugin =
|
||||||
|
createFakePlugin('plugin1', packagesDir, extraFiles: <String>[
|
||||||
|
'example/android/gradlew',
|
||||||
|
], platformSupport: <String, PlatformDetails>{
|
||||||
|
platformAndroid: const PlatformDetails(PlatformSupport.inline)
|
||||||
|
});
|
||||||
|
|
||||||
|
final Directory androidDir = plugin
|
||||||
|
.getExamples()
|
||||||
|
.first
|
||||||
|
.platformDirectory(FlutterPlatform.android);
|
||||||
|
|
||||||
|
final List<String> output = await runCapturingPrint(
|
||||||
|
runner, <String>['fetch-deps', '--android']);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
processRunner.recordedCalls,
|
||||||
|
orderedEquals(<ProcessCall>[
|
||||||
|
ProcessCall(
|
||||||
|
'flutter',
|
||||||
|
const <String>['pub', 'get'],
|
||||||
|
plugin.directory.path,
|
||||||
|
),
|
||||||
|
ProcessCall(
|
||||||
|
androidDir.childFile('gradlew').path,
|
||||||
|
const <String>['plugin1:dependencies'],
|
||||||
|
androidDir.path,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
output,
|
||||||
|
containsAllInOrder(<Matcher>[
|
||||||
|
contains('Running for plugin1'),
|
||||||
|
contains('No issues found!'),
|
||||||
|
]));
|
||||||
|
});
|
||||||
|
|
||||||
test('runs gradlew dependencies', () async {
|
test('runs gradlew dependencies', () async {
|
||||||
final RepositoryPackage plugin =
|
final RepositoryPackage plugin =
|
||||||
createFakePlugin('plugin1', packagesDir, extraFiles: <String>[
|
createFakePlugin('plugin1', packagesDir, extraFiles: <String>[
|
||||||
@ -50,8 +185,8 @@ void main() {
|
|||||||
.first
|
.first
|
||||||
.platformDirectory(FlutterPlatform.android);
|
.platformDirectory(FlutterPlatform.android);
|
||||||
|
|
||||||
final List<String> output =
|
final List<String> output = await runCapturingPrint(
|
||||||
await runCapturingPrint(runner, <String>['fetch-deps']);
|
runner, <String>['fetch-deps', '--no-dart', '--android']);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
processRunner.recordedCalls,
|
processRunner.recordedCalls,
|
||||||
@ -89,8 +224,8 @@ void main() {
|
|||||||
(RepositoryPackage example) =>
|
(RepositoryPackage example) =>
|
||||||
example.platformDirectory(FlutterPlatform.android));
|
example.platformDirectory(FlutterPlatform.android));
|
||||||
|
|
||||||
final List<String> output =
|
final List<String> output = await runCapturingPrint(
|
||||||
await runCapturingPrint(runner, <String>['fetch-deps']);
|
runner, <String>['fetch-deps', '--no-dart', '--android']);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
processRunner.recordedCalls,
|
processRunner.recordedCalls,
|
||||||
@ -123,8 +258,8 @@ void main() {
|
|||||||
.first
|
.first
|
||||||
.platformDirectory(FlutterPlatform.android);
|
.platformDirectory(FlutterPlatform.android);
|
||||||
|
|
||||||
final List<String> output =
|
final List<String> output = await runCapturingPrint(
|
||||||
await runCapturingPrint(runner, <String>['fetch-deps']);
|
runner, <String>['fetch-deps', '--no-dart', '--android']);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
processRunner.recordedCalls,
|
processRunner.recordedCalls,
|
||||||
@ -164,7 +299,8 @@ void main() {
|
|||||||
|
|
||||||
Error? commandError;
|
Error? commandError;
|
||||||
final List<String> output = await runCapturingPrint(
|
final List<String> output = await runCapturingPrint(
|
||||||
runner, <String>['fetch-deps'], errorHandler: (Error e) {
|
runner, <String>['fetch-deps', '--no-dart', '--android'],
|
||||||
|
errorHandler: (Error e) {
|
||||||
commandError = e;
|
commandError = e;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -199,7 +335,8 @@ void main() {
|
|||||||
|
|
||||||
Error? commandError;
|
Error? commandError;
|
||||||
final List<String> output = await runCapturingPrint(
|
final List<String> output = await runCapturingPrint(
|
||||||
runner, <String>['fetch-deps'], errorHandler: (Error e) {
|
runner, <String>['fetch-deps', '--no-dart', '--android'],
|
||||||
|
errorHandler: (Error e) {
|
||||||
commandError = e;
|
commandError = e;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -212,41 +349,479 @@ void main() {
|
|||||||
],
|
],
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('skips non-Android plugins', () async {
|
||||||
|
createFakePlugin('plugin1', packagesDir);
|
||||||
|
|
||||||
|
final List<String> output = await runCapturingPrint(
|
||||||
|
runner, <String>['fetch-deps', '--no-dart', '--android']);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
output,
|
||||||
|
containsAllInOrder(
|
||||||
|
<Matcher>[
|
||||||
|
contains('Package does not have native Android dependencies.')
|
||||||
|
],
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('skips non-inline plugins', () async {
|
||||||
|
createFakePlugin('plugin1', packagesDir,
|
||||||
|
platformSupport: <String, PlatformDetails>{
|
||||||
|
platformAndroid: const PlatformDetails(PlatformSupport.federated)
|
||||||
|
});
|
||||||
|
|
||||||
|
final List<String> output = await runCapturingPrint(
|
||||||
|
runner, <String>['fetch-deps', '--no-dart', '--android']);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
output,
|
||||||
|
containsAllInOrder(
|
||||||
|
<Matcher>[
|
||||||
|
contains('Package does not have native Android dependencies.')
|
||||||
|
],
|
||||||
|
));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('skips non-Android plugins', () async {
|
group('ios', () {
|
||||||
createFakePlugin('plugin1', packagesDir);
|
test('runs pub get before pod install', () async {
|
||||||
|
final RepositoryPackage plugin =
|
||||||
|
createFakePlugin('plugin1', packagesDir, extraFiles: <String>[
|
||||||
|
'example/ios/Flutter/Generated.xcconfig',
|
||||||
|
], platformSupport: <String, PlatformDetails>{
|
||||||
|
platformIOS: const PlatformDetails(PlatformSupport.inline)
|
||||||
|
});
|
||||||
|
|
||||||
final List<String> output =
|
final Directory iOSDir =
|
||||||
await runCapturingPrint(runner, <String>['fetch-deps']);
|
plugin.getExamples().first.platformDirectory(FlutterPlatform.ios);
|
||||||
|
|
||||||
expect(
|
final List<String> output =
|
||||||
output,
|
await runCapturingPrint(runner, <String>['fetch-deps', '--ios']);
|
||||||
containsAllInOrder(
|
|
||||||
<Matcher>[
|
expect(
|
||||||
contains(
|
processRunner.recordedCalls,
|
||||||
'SKIPPING: Plugin does not have an Android implementation.')
|
orderedEquals(<ProcessCall>[
|
||||||
|
const ProcessCall(
|
||||||
|
'flutter',
|
||||||
|
<String>['precache', '--ios'],
|
||||||
|
null,
|
||||||
|
),
|
||||||
|
ProcessCall(
|
||||||
|
'flutter',
|
||||||
|
const <String>['pub', 'get'],
|
||||||
|
plugin.directory.path,
|
||||||
|
),
|
||||||
|
ProcessCall(
|
||||||
|
'pod',
|
||||||
|
const <String>['install'],
|
||||||
|
iOSDir.path,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
output,
|
||||||
|
containsAllInOrder(<Matcher>[
|
||||||
|
contains('Running for plugin1'),
|
||||||
|
contains('No issues found!'),
|
||||||
|
]));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('runs on all examples', () async {
|
||||||
|
final List<String> examples = <String>['example1', 'example2'];
|
||||||
|
final RepositoryPackage plugin = createFakePlugin(
|
||||||
|
'plugin1', packagesDir,
|
||||||
|
examples: examples,
|
||||||
|
extraFiles: <String>[
|
||||||
|
'example/example1/ios/Flutter/Generated.xcconfig',
|
||||||
|
'example/example2/ios/Flutter/Generated.xcconfig',
|
||||||
],
|
],
|
||||||
));
|
platformSupport: <String, PlatformDetails>{
|
||||||
|
platformIOS: const PlatformDetails(PlatformSupport.inline)
|
||||||
|
});
|
||||||
|
|
||||||
|
final Iterable<Directory> exampleIOSDirs = plugin.getExamples().map(
|
||||||
|
(RepositoryPackage example) =>
|
||||||
|
example.platformDirectory(FlutterPlatform.ios));
|
||||||
|
|
||||||
|
final List<String> output = await runCapturingPrint(
|
||||||
|
runner, <String>['fetch-deps', '--no-dart', '--ios']);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
processRunner.recordedCalls,
|
||||||
|
orderedEquals(<ProcessCall>[
|
||||||
|
const ProcessCall(
|
||||||
|
'flutter',
|
||||||
|
<String>['precache', '--ios'],
|
||||||
|
null,
|
||||||
|
),
|
||||||
|
for (final Directory directory in exampleIOSDirs)
|
||||||
|
ProcessCall(
|
||||||
|
'pod',
|
||||||
|
const <String>['install'],
|
||||||
|
directory.path,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
output,
|
||||||
|
containsAllInOrder(<Matcher>[
|
||||||
|
contains('Running for plugin1'),
|
||||||
|
contains('No issues found!'),
|
||||||
|
]));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('runs pub get if example is not configured', () async {
|
||||||
|
final RepositoryPackage plugin = createFakePlugin(
|
||||||
|
'plugin1', packagesDir, platformSupport: <String, PlatformDetails>{
|
||||||
|
platformIOS: const PlatformDetails(PlatformSupport.inline)
|
||||||
|
});
|
||||||
|
|
||||||
|
final RepositoryPackage example = plugin.getExamples().first;
|
||||||
|
|
||||||
|
final List<String> output = await runCapturingPrint(
|
||||||
|
runner, <String>['fetch-deps', '--no-dart', '--ios']);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
processRunner.recordedCalls,
|
||||||
|
orderedEquals(<ProcessCall>[
|
||||||
|
const ProcessCall(
|
||||||
|
'flutter',
|
||||||
|
<String>['precache', '--ios'],
|
||||||
|
null,
|
||||||
|
),
|
||||||
|
ProcessCall(
|
||||||
|
'flutter',
|
||||||
|
const <String>['pub', 'get'],
|
||||||
|
example.directory.path,
|
||||||
|
),
|
||||||
|
ProcessCall(
|
||||||
|
'pod',
|
||||||
|
const <String>['install'],
|
||||||
|
example.platformDirectory(FlutterPlatform.ios).path,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
output,
|
||||||
|
containsAllInOrder(<Matcher>[
|
||||||
|
contains('Running for plugin1'),
|
||||||
|
contains('No issues found!'),
|
||||||
|
]));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('fails if pre-pod pub get fails', () async {
|
||||||
|
createFakePlugin('plugin1', packagesDir,
|
||||||
|
platformSupport: <String, PlatformDetails>{
|
||||||
|
platformIOS: const PlatformDetails(PlatformSupport.inline)
|
||||||
|
});
|
||||||
|
|
||||||
|
processRunner
|
||||||
|
.mockProcessesForExecutable[getFlutterCommand(mockPlatform)] =
|
||||||
|
<FakeProcessInfo>[
|
||||||
|
FakeProcessInfo(MockProcess(), <String>['precache']),
|
||||||
|
FakeProcessInfo(MockProcess(exitCode: 1), <String>['pub', 'get']),
|
||||||
|
];
|
||||||
|
|
||||||
|
Error? commandError;
|
||||||
|
final List<String> output = await runCapturingPrint(
|
||||||
|
runner, <String>['fetch-deps', '--no-dart', '--ios'],
|
||||||
|
errorHandler: (Error e) {
|
||||||
|
commandError = e;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(commandError, isA<ToolExit>());
|
||||||
|
expect(
|
||||||
|
output,
|
||||||
|
containsAllInOrder(
|
||||||
|
<Matcher>[
|
||||||
|
contains('Unable to configure project'),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('fails if pod install fails', () async {
|
||||||
|
createFakePlugin('plugin1', packagesDir,
|
||||||
|
platformSupport: <String, PlatformDetails>{
|
||||||
|
platformIOS: const PlatformDetails(PlatformSupport.inline)
|
||||||
|
});
|
||||||
|
|
||||||
|
processRunner.mockProcessesForExecutable['pod'] = <FakeProcessInfo>[
|
||||||
|
FakeProcessInfo(MockProcess(exitCode: 1)),
|
||||||
|
];
|
||||||
|
|
||||||
|
Error? commandError;
|
||||||
|
final List<String> output = await runCapturingPrint(
|
||||||
|
runner, <String>['fetch-deps', '--no-dart', '--ios'],
|
||||||
|
errorHandler: (Error e) {
|
||||||
|
commandError = e;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(commandError, isA<ToolExit>());
|
||||||
|
expect(
|
||||||
|
output,
|
||||||
|
containsAllInOrder(
|
||||||
|
<Matcher>[
|
||||||
|
contains('The following packages had errors:'),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('skips non-iOS plugins', () async {
|
||||||
|
createFakePlugin('plugin1', packagesDir);
|
||||||
|
|
||||||
|
final List<String> output = await runCapturingPrint(
|
||||||
|
runner, <String>['fetch-deps', '--no-dart', '--ios']);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
output,
|
||||||
|
containsAllInOrder(
|
||||||
|
<Matcher>[
|
||||||
|
contains('Package does not have native iOS dependencies.')
|
||||||
|
],
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('skips non-inline plugins', () async {
|
||||||
|
createFakePlugin('plugin1', packagesDir,
|
||||||
|
platformSupport: <String, PlatformDetails>{
|
||||||
|
platformIOS: const PlatformDetails(PlatformSupport.federated)
|
||||||
|
});
|
||||||
|
|
||||||
|
final List<String> output = await runCapturingPrint(
|
||||||
|
runner, <String>['fetch-deps', '--no-dart', '--ios']);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
output,
|
||||||
|
containsAllInOrder(
|
||||||
|
<Matcher>[
|
||||||
|
contains('Package does not have native iOS dependencies.')
|
||||||
|
],
|
||||||
|
));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('skips non-inline plugins', () async {
|
group('macos', () {
|
||||||
createFakePlugin('plugin1', packagesDir,
|
test('runs pub get before pod install', () async {
|
||||||
platformSupport: <String, PlatformDetails>{
|
final RepositoryPackage plugin =
|
||||||
platformAndroid: const PlatformDetails(PlatformSupport.federated)
|
createFakePlugin('plugin1', packagesDir, extraFiles: <String>[
|
||||||
});
|
'example/macos/Flutter/ephemeral/Flutter-Generated.xcconfig',
|
||||||
|
], platformSupport: <String, PlatformDetails>{
|
||||||
|
platformMacOS: const PlatformDetails(PlatformSupport.inline)
|
||||||
|
});
|
||||||
|
|
||||||
final List<String> output =
|
final Directory macOSDir =
|
||||||
await runCapturingPrint(runner, <String>['fetch-deps']);
|
plugin.getExamples().first.platformDirectory(FlutterPlatform.macos);
|
||||||
|
|
||||||
expect(
|
final List<String> output =
|
||||||
output,
|
await runCapturingPrint(runner, <String>['fetch-deps', '--macos']);
|
||||||
containsAllInOrder(
|
|
||||||
<Matcher>[
|
expect(
|
||||||
contains(
|
processRunner.recordedCalls,
|
||||||
'SKIPPING: Plugin does not have an Android implementation.')
|
orderedEquals(<ProcessCall>[
|
||||||
|
const ProcessCall(
|
||||||
|
'flutter',
|
||||||
|
<String>['precache', '--macos'],
|
||||||
|
null,
|
||||||
|
),
|
||||||
|
ProcessCall(
|
||||||
|
'flutter',
|
||||||
|
const <String>['pub', 'get'],
|
||||||
|
plugin.directory.path,
|
||||||
|
),
|
||||||
|
ProcessCall(
|
||||||
|
'pod',
|
||||||
|
const <String>['install'],
|
||||||
|
macOSDir.path,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
output,
|
||||||
|
containsAllInOrder(<Matcher>[
|
||||||
|
contains('Running for plugin1'),
|
||||||
|
contains('No issues found!'),
|
||||||
|
]));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('runs on all examples', () async {
|
||||||
|
final List<String> examples = <String>['example1', 'example2'];
|
||||||
|
final RepositoryPackage plugin = createFakePlugin(
|
||||||
|
'plugin1', packagesDir,
|
||||||
|
examples: examples,
|
||||||
|
extraFiles: <String>[
|
||||||
|
'example/example1/macos/Flutter/ephemeral/Flutter-Generated.xcconfig',
|
||||||
|
'example/example2/macos/Flutter/ephemeral/Flutter-Generated.xcconfig',
|
||||||
],
|
],
|
||||||
));
|
platformSupport: <String, PlatformDetails>{
|
||||||
|
platformMacOS: const PlatformDetails(PlatformSupport.inline)
|
||||||
|
});
|
||||||
|
|
||||||
|
final Iterable<Directory> examplemacOSDirs = plugin.getExamples().map(
|
||||||
|
(RepositoryPackage example) =>
|
||||||
|
example.platformDirectory(FlutterPlatform.macos));
|
||||||
|
|
||||||
|
final List<String> output = await runCapturingPrint(
|
||||||
|
runner, <String>['fetch-deps', '--no-dart', '--macos']);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
processRunner.recordedCalls,
|
||||||
|
orderedEquals(<ProcessCall>[
|
||||||
|
const ProcessCall(
|
||||||
|
'flutter',
|
||||||
|
<String>['precache', '--macos'],
|
||||||
|
null,
|
||||||
|
),
|
||||||
|
for (final Directory directory in examplemacOSDirs)
|
||||||
|
ProcessCall(
|
||||||
|
'pod',
|
||||||
|
const <String>['install'],
|
||||||
|
directory.path,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
output,
|
||||||
|
containsAllInOrder(<Matcher>[
|
||||||
|
contains('Running for plugin1'),
|
||||||
|
contains('No issues found!'),
|
||||||
|
]));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('runs pub get if example is not configured', () async {
|
||||||
|
final RepositoryPackage plugin = createFakePlugin(
|
||||||
|
'plugin1', packagesDir, platformSupport: <String, PlatformDetails>{
|
||||||
|
platformMacOS: const PlatformDetails(PlatformSupport.inline)
|
||||||
|
});
|
||||||
|
|
||||||
|
final RepositoryPackage example = plugin.getExamples().first;
|
||||||
|
|
||||||
|
final List<String> output = await runCapturingPrint(
|
||||||
|
runner, <String>['fetch-deps', '--no-dart', '--macos']);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
processRunner.recordedCalls,
|
||||||
|
orderedEquals(<ProcessCall>[
|
||||||
|
const ProcessCall(
|
||||||
|
'flutter',
|
||||||
|
<String>['precache', '--macos'],
|
||||||
|
null,
|
||||||
|
),
|
||||||
|
ProcessCall(
|
||||||
|
'flutter',
|
||||||
|
const <String>['pub', 'get'],
|
||||||
|
example.directory.path,
|
||||||
|
),
|
||||||
|
ProcessCall(
|
||||||
|
'pod',
|
||||||
|
const <String>['install'],
|
||||||
|
example.platformDirectory(FlutterPlatform.macos).path,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
output,
|
||||||
|
containsAllInOrder(<Matcher>[
|
||||||
|
contains('Running for plugin1'),
|
||||||
|
contains('No issues found!'),
|
||||||
|
]));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('fails if pre-pod pub get fails', () async {
|
||||||
|
createFakePlugin('plugin1', packagesDir,
|
||||||
|
platformSupport: <String, PlatformDetails>{
|
||||||
|
platformMacOS: const PlatformDetails(PlatformSupport.inline)
|
||||||
|
});
|
||||||
|
|
||||||
|
processRunner
|
||||||
|
.mockProcessesForExecutable[getFlutterCommand(mockPlatform)] =
|
||||||
|
<FakeProcessInfo>[
|
||||||
|
FakeProcessInfo(MockProcess(), <String>['precache']),
|
||||||
|
FakeProcessInfo(MockProcess(exitCode: 1), <String>['pub', 'get']),
|
||||||
|
];
|
||||||
|
|
||||||
|
Error? commandError;
|
||||||
|
final List<String> output = await runCapturingPrint(
|
||||||
|
runner, <String>['fetch-deps', '--no-dart', '--macos'],
|
||||||
|
errorHandler: (Error e) {
|
||||||
|
commandError = e;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(commandError, isA<ToolExit>());
|
||||||
|
expect(
|
||||||
|
output,
|
||||||
|
containsAllInOrder(
|
||||||
|
<Matcher>[
|
||||||
|
contains('Unable to configure project'),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('fails if pod install fails', () async {
|
||||||
|
createFakePlugin('plugin1', packagesDir,
|
||||||
|
platformSupport: <String, PlatformDetails>{
|
||||||
|
platformMacOS: const PlatformDetails(PlatformSupport.inline)
|
||||||
|
});
|
||||||
|
|
||||||
|
processRunner.mockProcessesForExecutable['pod'] = <FakeProcessInfo>[
|
||||||
|
FakeProcessInfo(MockProcess(exitCode: 1)),
|
||||||
|
];
|
||||||
|
|
||||||
|
Error? commandError;
|
||||||
|
final List<String> output = await runCapturingPrint(
|
||||||
|
runner, <String>['fetch-deps', '--no-dart', '--macos'],
|
||||||
|
errorHandler: (Error e) {
|
||||||
|
commandError = e;
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(commandError, isA<ToolExit>());
|
||||||
|
expect(
|
||||||
|
output,
|
||||||
|
containsAllInOrder(
|
||||||
|
<Matcher>[
|
||||||
|
contains('The following packages had errors:'),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('skips non-macOS plugins', () async {
|
||||||
|
createFakePlugin('plugin1', packagesDir);
|
||||||
|
|
||||||
|
final List<String> output = await runCapturingPrint(
|
||||||
|
runner, <String>['fetch-deps', '--no-dart', '--macos']);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
output,
|
||||||
|
containsAllInOrder(
|
||||||
|
<Matcher>[
|
||||||
|
contains('Package does not have native macOS dependencies.')
|
||||||
|
],
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('skips non-inline plugins', () async {
|
||||||
|
createFakePlugin('plugin1', packagesDir,
|
||||||
|
platformSupport: <String, PlatformDetails>{
|
||||||
|
platformMacOS: const PlatformDetails(PlatformSupport.federated)
|
||||||
|
});
|
||||||
|
|
||||||
|
final List<String> output = await runCapturingPrint(
|
||||||
|
runner, <String>['fetch-deps', '--no-dart', '--macos']);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
output,
|
||||||
|
containsAllInOrder(
|
||||||
|
<Matcher>[
|
||||||
|
contains('Package does not have native macOS dependencies.')
|
||||||
|
],
|
||||||
|
));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -394,6 +394,7 @@ class RecordingProcessRunner extends ProcessRunner {
|
|||||||
String executable,
|
String executable,
|
||||||
List<String> args, {
|
List<String> args, {
|
||||||
Directory? workingDir,
|
Directory? workingDir,
|
||||||
|
Map<String, String>? environment,
|
||||||
bool exitOnError = false,
|
bool exitOnError = false,
|
||||||
}) async {
|
}) async {
|
||||||
recordedCalls.add(ProcessCall(executable, args, workingDir?.path));
|
recordedCalls.add(ProcessCall(executable, args, workingDir?.path));
|
||||||
@ -412,6 +413,7 @@ class RecordingProcessRunner extends ProcessRunner {
|
|||||||
String executable,
|
String executable,
|
||||||
List<String> args, {
|
List<String> args, {
|
||||||
Directory? workingDir,
|
Directory? workingDir,
|
||||||
|
Map<String, String>? environment,
|
||||||
bool exitOnError = false,
|
bool exitOnError = false,
|
||||||
bool logOnError = false,
|
bool logOnError = false,
|
||||||
Encoding stdoutEncoding = io.systemEncoding,
|
Encoding stdoutEncoding = io.systemEncoding,
|
||||||
|
Reference in New Issue
Block a user