mirror of
https://github.com/flutter/packages.git
synced 2025-06-20 06:08:35 +08:00

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
113 lines
3.7 KiB
Dart
113 lines
3.7 KiB
Dart
// Copyright 2013 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'dart:convert';
|
|
import 'dart:io' as io;
|
|
|
|
import 'package:file/file.dart';
|
|
|
|
import 'core.dart';
|
|
|
|
/// A class used to run processes.
|
|
///
|
|
/// We use this instead of directly running the process so it can be overridden
|
|
/// in tests.
|
|
class ProcessRunner {
|
|
/// Creates a new process runner.
|
|
const ProcessRunner();
|
|
|
|
/// Run the [executable] with [args] and stream output to stderr and stdout.
|
|
///
|
|
/// The current working directory of [executable] can be overridden by
|
|
/// passing [workingDir].
|
|
///
|
|
/// If [exitOnError] is set to `true`, then this will throw an error if
|
|
/// the [executable] terminates with a non-zero exit code.
|
|
///
|
|
/// Returns the exit code of the [executable].
|
|
Future<int> runAndStream(
|
|
String executable,
|
|
List<String> args, {
|
|
Directory? workingDir,
|
|
Map<String, String>? environment,
|
|
bool exitOnError = false,
|
|
}) async {
|
|
print(
|
|
'Running command: "$executable ${args.join(' ')}" in ${workingDir?.path ?? io.Directory.current.path}');
|
|
final io.Process process = await io.Process.start(executable, args,
|
|
workingDirectory: workingDir?.path, environment: environment);
|
|
await Future.wait(<Future<dynamic>>[
|
|
io.stdout.addStream(process.stdout),
|
|
io.stderr.addStream(process.stderr),
|
|
]);
|
|
if (exitOnError && await process.exitCode != 0) {
|
|
final String error =
|
|
_getErrorString(executable, args, workingDir: workingDir);
|
|
print('$error See above for details.');
|
|
throw ToolExit(await process.exitCode);
|
|
}
|
|
return process.exitCode;
|
|
}
|
|
|
|
/// Run the [executable] with [args].
|
|
///
|
|
/// The current working directory of [executable] can be overridden by
|
|
/// passing [workingDir].
|
|
///
|
|
/// If [exitOnError] is set to `true`, then this will throw an error if
|
|
/// the [executable] terminates with a non-zero exit code.
|
|
/// Defaults to `false`.
|
|
///
|
|
/// If [logOnError] is set to `true`, it will print a formatted message about the error.
|
|
/// Defaults to `false`
|
|
///
|
|
/// Returns the [io.ProcessResult] of the [executable].
|
|
Future<io.ProcessResult> run(
|
|
String executable,
|
|
List<String> args, {
|
|
Directory? workingDir,
|
|
Map<String, String>? environment,
|
|
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,
|
|
workingDirectory: workingDir?.path,
|
|
environment: environment,
|
|
stdoutEncoding: stdoutEncoding,
|
|
stderrEncoding: stderrEncoding);
|
|
if (result.exitCode != 0) {
|
|
if (logOnError) {
|
|
final String error =
|
|
_getErrorString(executable, args, workingDir: workingDir);
|
|
print('$error Stderr:\n${result.stdout}');
|
|
}
|
|
if (exitOnError) {
|
|
throw ToolExit(result.exitCode);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/// Starts the [executable] with [args].
|
|
///
|
|
/// The current working directory of [executable] can be overridden by
|
|
/// passing [workingDir].
|
|
///
|
|
/// Returns the started [io.Process].
|
|
Future<io.Process> start(String executable, List<String> args,
|
|
{Directory? workingDirectory}) async {
|
|
final io.Process process = await io.Process.start(executable, args,
|
|
workingDirectory: workingDirectory?.path);
|
|
return process;
|
|
}
|
|
|
|
String _getErrorString(String executable, List<String> args,
|
|
{Directory? workingDir}) {
|
|
final String workdir = workingDir == null ? '' : ' in ${workingDir.path}';
|
|
return 'ERROR: Unable to execute "$executable ${args.join(' ')}"$workdir.';
|
|
}
|
|
}
|