Adds tool warning log level and command line options to fail on warning/error output (#92031)
This commit is contained in:
parent
02cfbc320e
commit
52ae102f18
@ -170,6 +170,7 @@ Future<void> main(List<String> args) async {
|
|||||||
try {
|
try {
|
||||||
flutterTestArgs.addAll(args);
|
flutterTestArgs.addAll(args);
|
||||||
final Set<String> removeArgs = <String>{};
|
final Set<String> removeArgs = <String>{};
|
||||||
|
bool runSmokeTests = true;
|
||||||
for (final String arg in args) {
|
for (final String arg in args) {
|
||||||
if (arg.startsWith('--local-engine=')) {
|
if (arg.startsWith('--local-engine=')) {
|
||||||
localEngineEnv['FLUTTER_LOCAL_ENGINE'] = arg.substring('--local-engine='.length);
|
localEngineEnv['FLUTTER_LOCAL_ENGINE'] = arg.substring('--local-engine='.length);
|
||||||
@ -181,12 +182,18 @@ Future<void> main(List<String> args) async {
|
|||||||
_shuffleSeed = arg.substring('--test-randomize-ordering-seed='.length);
|
_shuffleSeed = arg.substring('--test-randomize-ordering-seed='.length);
|
||||||
removeArgs.add(arg);
|
removeArgs.add(arg);
|
||||||
}
|
}
|
||||||
|
if (arg == '--no-smoke-tests') {
|
||||||
|
runSmokeTests = false;
|
||||||
|
removeArgs.add(arg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
flutterTestArgs.removeWhere((String arg) => removeArgs.contains(arg));
|
flutterTestArgs.removeWhere((String arg) => removeArgs.contains(arg));
|
||||||
if (Platform.environment.containsKey(CIRRUS_TASK_NAME))
|
if (Platform.environment.containsKey(CIRRUS_TASK_NAME))
|
||||||
print('Running task: ${Platform.environment[CIRRUS_TASK_NAME]}');
|
print('Running task: ${Platform.environment[CIRRUS_TASK_NAME]}');
|
||||||
print('═' * 80);
|
print('═' * 80);
|
||||||
await _runSmokeTests();
|
if (runSmokeTests) {
|
||||||
|
await _runSmokeTests();
|
||||||
|
}
|
||||||
print('═' * 80);
|
print('═' * 80);
|
||||||
await selectShard(<String, ShardRunner>{
|
await selectShard(<String, ShardRunner>{
|
||||||
'add_to_app_life_cycle_tests': _runAddToAppLifeCycleTests,
|
'add_to_app_life_cycle_tests': _runAddToAppLifeCycleTests,
|
||||||
@ -474,7 +481,7 @@ Future<void> _runBuildTests() async {
|
|||||||
Future<void> _runExampleProjectBuildTests(Directory exampleDirectory, [File? mainFile]) async {
|
Future<void> _runExampleProjectBuildTests(Directory exampleDirectory, [File? mainFile]) async {
|
||||||
// Only verify caching with flutter gallery.
|
// Only verify caching with flutter gallery.
|
||||||
final bool verifyCaching = exampleDirectory.path.contains('flutter_gallery');
|
final bool verifyCaching = exampleDirectory.path.contains('flutter_gallery');
|
||||||
final String examplePath = exampleDirectory.path;
|
final String examplePath = path.relative(exampleDirectory.path, from: Directory.current.path);
|
||||||
final bool hasNullSafety = File(path.join(examplePath, 'null_safety')).existsSync();
|
final bool hasNullSafety = File(path.join(examplePath, 'null_safety')).existsSync();
|
||||||
final List<String> additionalArgs = <String>[
|
final List<String> additionalArgs = <String>[
|
||||||
if (hasNullSafety) '--no-sound-null-safety',
|
if (hasNullSafety) '--no-sound-null-safety',
|
||||||
@ -786,7 +793,8 @@ Future<void> _runFrameworkTests() async {
|
|||||||
await _pubRunTest(path.join(flutterRoot, 'dev', 'bots'));
|
await _pubRunTest(path.join(flutterRoot, 'dev', 'bots'));
|
||||||
await _pubRunTest(path.join(flutterRoot, 'dev', 'devicelab'), ensurePrecompiledTool: false); // See https://github.com/flutter/flutter/issues/86209
|
await _pubRunTest(path.join(flutterRoot, 'dev', 'devicelab'), ensurePrecompiledTool: false); // See https://github.com/flutter/flutter/issues/86209
|
||||||
await _pubRunTest(path.join(flutterRoot, 'dev', 'conductor', 'core'), forceSingleCore: true);
|
await _pubRunTest(path.join(flutterRoot, 'dev', 'conductor', 'core'), forceSingleCore: true);
|
||||||
await _runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'android_semantics_testing'));
|
// TODO(gspencergoog): Remove the exception for fatalWarnings once https://github.com/flutter/flutter/pull/91127 has landed.
|
||||||
|
await _runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'android_semantics_testing'), fatalWarnings: false);
|
||||||
await _runFlutterTest(path.join(flutterRoot, 'dev', 'manual_tests'));
|
await _runFlutterTest(path.join(flutterRoot, 'dev', 'manual_tests'));
|
||||||
await _runFlutterTest(path.join(flutterRoot, 'dev', 'tools', 'vitool'));
|
await _runFlutterTest(path.join(flutterRoot, 'dev', 'tools', 'vitool'));
|
||||||
await _runFlutterTest(path.join(flutterRoot, 'dev', 'tools', 'gen_keycodes'));
|
await _runFlutterTest(path.join(flutterRoot, 'dev', 'tools', 'gen_keycodes'));
|
||||||
@ -1621,6 +1629,7 @@ Future<void> _runFlutterTest(String workingDirectory, {
|
|||||||
Map<String, String>? environment,
|
Map<String, String>? environment,
|
||||||
List<String> tests = const <String>[],
|
List<String> tests = const <String>[],
|
||||||
bool shuffleTests = true,
|
bool shuffleTests = true,
|
||||||
|
bool fatalWarnings = true,
|
||||||
}) async {
|
}) async {
|
||||||
assert(!printOutput || outputChecker == null, 'Output either can be printed or checked but not both');
|
assert(!printOutput || outputChecker == null, 'Output either can be printed or checked but not both');
|
||||||
|
|
||||||
@ -1634,6 +1643,7 @@ Future<void> _runFlutterTest(String workingDirectory, {
|
|||||||
final List<String> args = <String>[
|
final List<String> args = <String>[
|
||||||
'test',
|
'test',
|
||||||
if (shuffleTests) '--test-randomize-ordering-seed=$shuffleSeed',
|
if (shuffleTests) '--test-randomize-ordering-seed=$shuffleSeed',
|
||||||
|
if (fatalWarnings) '--fatal-warnings',
|
||||||
...options,
|
...options,
|
||||||
...tags,
|
...tags,
|
||||||
...flutterTestArgs,
|
...flutterTestArgs,
|
||||||
|
@ -43,15 +43,13 @@ class CodesignCommand extends Command<void> {
|
|||||||
}
|
}
|
||||||
argParser.addFlag(
|
argParser.addFlag(
|
||||||
kVerify,
|
kVerify,
|
||||||
help:
|
help: 'Only verify expected binaries exist and are codesigned with entitlements.',
|
||||||
'Only verify expected binaries exist and are codesigned with entitlements.',
|
|
||||||
);
|
);
|
||||||
argParser.addFlag(
|
argParser.addFlag(
|
||||||
kSignatures,
|
kSignatures,
|
||||||
defaultsTo: true,
|
defaultsTo: true,
|
||||||
help:
|
help: 'When off, this command will only verify the existence of binaries, and not their\n'
|
||||||
'When off, this command will only verify the existence of binaries, and not their\n'
|
'signatures or entitlements. Must be used with --verify flag.',
|
||||||
'signatures or entitlements. Must be used with --verify flag.',
|
|
||||||
);
|
);
|
||||||
argParser.addOption(
|
argParser.addOption(
|
||||||
kUpstream,
|
kUpstream,
|
||||||
@ -92,24 +90,25 @@ class CodesignCommand extends Command<void> {
|
|||||||
Future<void> run() async {
|
Future<void> run() async {
|
||||||
if (!platform.isMacOS) {
|
if (!platform.isMacOS) {
|
||||||
throw ConductorException(
|
throw ConductorException(
|
||||||
'Error! Expected operating system "macos", actual operating system is: '
|
'Error! Expected operating system "macos", actual operating system is: '
|
||||||
'"${platform.operatingSystem}"');
|
'"${platform.operatingSystem}"',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argResults!['verify'] as bool != true) {
|
if (argResults!['verify'] as bool != true) {
|
||||||
throw ConductorException(
|
throw ConductorException(
|
||||||
'Sorry, but codesigning is not implemented yet. Please pass the '
|
'Sorry, but codesigning is not implemented yet. Please pass the '
|
||||||
'--$kVerify flag to verify signatures.');
|
'--$kVerify flag to verify signatures.',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String revision;
|
String revision;
|
||||||
if (argResults!.wasParsed(kRevision)) {
|
if (argResults!.wasParsed(kRevision)) {
|
||||||
stdio.printError(
|
stdio.printWarning(
|
||||||
'Warning! When providing an arbitrary revision, the contents of the cache may not');
|
'Warning! When providing an arbitrary revision, the contents of the cache may not '
|
||||||
stdio.printError(
|
'match the expected binaries in the conductor tool. It is preferred to check out '
|
||||||
'match the expected binaries in the conductor tool. It is preferred to check out');
|
'the desired revision and run that version of the conductor.\n',
|
||||||
stdio.printError(
|
);
|
||||||
'the desired revision and run that version of the conductor.\n');
|
|
||||||
revision = argResults![kRevision] as String;
|
revision = argResults![kRevision] as String;
|
||||||
} else {
|
} else {
|
||||||
revision = ((await processManager.run(
|
revision = ((await processManager.run(
|
||||||
@ -225,13 +224,11 @@ class CodesignCommand extends Command<void> {
|
|||||||
)
|
)
|
||||||
.toList();
|
.toList();
|
||||||
stdio.printError(
|
stdio.printError(
|
||||||
'Expected binaries not found in cache:\n\n${unfoundFiles.join('\n')}\n');
|
'Expected binaries not found in cache:\n\n${unfoundFiles.join('\n')}\n\n'
|
||||||
stdio.printError(
|
'If this commit is removing binaries from the cache, this test should be fixed by\n'
|
||||||
'If this commit is removing binaries from the cache, this test should be fixed by');
|
'removing the relevant entry from either the "binariesWithEntitlements" or\n'
|
||||||
stdio.printError(
|
'"binariesWithoutEntitlements" getters in dev/tools/lib/codesign.dart.',
|
||||||
'removing the relevant entry from either the `binariesWithEntitlements` or');
|
);
|
||||||
stdio.printError(
|
|
||||||
'`binariesWithoutEntitlements` getters in dev/tools/lib/codesign.dart.');
|
|
||||||
throw ConductorException('Did not find all expected binaries!');
|
throw ConductorException('Did not find all expected binaries!');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,9 +268,10 @@ class CodesignCommand extends Command<void> {
|
|||||||
if (codeSignResult.exitCode != 0) {
|
if (codeSignResult.exitCode != 0) {
|
||||||
unsignedBinaries.add(binaryPath);
|
unsignedBinaries.add(binaryPath);
|
||||||
stdio.printError(
|
stdio.printError(
|
||||||
'File "$binaryPath" does not appear to be codesigned.\n'
|
'File "$binaryPath" does not appear to be codesigned.\n'
|
||||||
'The `codesign` command failed with exit code ${codeSignResult.exitCode}:\n'
|
'The `codesign` command failed with exit code ${codeSignResult.exitCode}:\n'
|
||||||
'${codeSignResult.stderr}\n');
|
'${codeSignResult.stderr}\n',
|
||||||
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (verifyEntitlements) {
|
if (verifyEntitlements) {
|
||||||
@ -291,42 +289,39 @@ class CodesignCommand extends Command<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (wrongEntitlementBinaries.isNotEmpty) {
|
if (wrongEntitlementBinaries.isNotEmpty) {
|
||||||
stdio.printError(
|
stdio.printError('Found ${wrongEntitlementBinaries.length} binaries with unexpected entitlements:');
|
||||||
'Found ${wrongEntitlementBinaries.length} binaries with unexpected entitlements:');
|
|
||||||
wrongEntitlementBinaries.forEach(stdio.printError);
|
wrongEntitlementBinaries.forEach(stdio.printError);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unexpectedBinaries.isNotEmpty) {
|
if (unexpectedBinaries.isNotEmpty) {
|
||||||
stdio.printError(
|
stdio.printError('Found ${unexpectedBinaries.length} unexpected binaries in the cache:');
|
||||||
'Found ${unexpectedBinaries.length} unexpected binaries in the cache:');
|
|
||||||
unexpectedBinaries.forEach(print);
|
unexpectedBinaries.forEach(print);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, exit on any invalid state
|
// Finally, exit on any invalid state
|
||||||
if (unsignedBinaries.isNotEmpty) {
|
if (unsignedBinaries.isNotEmpty) {
|
||||||
throw ConductorException(
|
throw ConductorException('Test failed because unsigned binaries detected.');
|
||||||
'Test failed because unsigned binaries detected.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wrongEntitlementBinaries.isNotEmpty) {
|
if (wrongEntitlementBinaries.isNotEmpty) {
|
||||||
throw ConductorException(
|
throw ConductorException(
|
||||||
'Test failed because files found with the wrong entitlements:\n'
|
'Test failed because files found with the wrong entitlements:\n'
|
||||||
'${wrongEntitlementBinaries.join('\n')}');
|
'${wrongEntitlementBinaries.join('\n')}',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unexpectedBinaries.isNotEmpty) {
|
if (unexpectedBinaries.isNotEmpty) {
|
||||||
throw ConductorException(
|
throw ConductorException('Test failed because unexpected binaries found in the cache.');
|
||||||
'Test failed because unexpected binaries found in the cache.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final String? desiredRevision = argResults![kRevision] as String?;
|
final String? desiredRevision = argResults![kRevision] as String?;
|
||||||
if (desiredRevision == null) {
|
if (desiredRevision == null) {
|
||||||
stdio.printStatus(
|
stdio.printStatus('Verified that binaries are codesigned and have expected entitlements.');
|
||||||
'Verified that binaries are codesigned and have expected entitlements.');
|
|
||||||
} else {
|
} else {
|
||||||
stdio.printStatus(
|
stdio.printStatus(
|
||||||
'Verified that binaries for commit $desiredRevision are codesigned and have '
|
'Verified that binaries for commit $desiredRevision are codesigned and have '
|
||||||
'expected entitlements.');
|
'expected entitlements.',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,8 +382,9 @@ class CodesignCommand extends Command<void> {
|
|||||||
|
|
||||||
if (entitlementResult.exitCode != 0) {
|
if (entitlementResult.exitCode != 0) {
|
||||||
stdio.printError(
|
stdio.printError(
|
||||||
'The `codesign --entitlements` command failed with exit code ${entitlementResult.exitCode}:\n'
|
'The `codesign --entitlements` command failed with exit code ${entitlementResult.exitCode}:\n'
|
||||||
'${entitlementResult.stderr}\n');
|
'${entitlementResult.stderr}\n',
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,8 +395,9 @@ class CodesignCommand extends Command<void> {
|
|||||||
(await binariesWithEntitlements).contains(binaryPath);
|
(await binariesWithEntitlements).contains(binaryPath);
|
||||||
if (output.contains(entitlement) != entitlementExpected) {
|
if (output.contains(entitlement) != entitlementExpected) {
|
||||||
stdio.printError(
|
stdio.printError(
|
||||||
'File "$binaryPath" ${entitlementExpected ? 'does not have expected' : 'has unexpected'} '
|
'File "$binaryPath" ${entitlementExpected ? 'does not have expected' : 'has unexpected'} '
|
||||||
'entitlement $entitlement.');
|
'entitlement $entitlement.',
|
||||||
|
);
|
||||||
passes = false;
|
passes = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,25 +9,44 @@ import 'package:meta/meta.dart';
|
|||||||
abstract class Stdio {
|
abstract class Stdio {
|
||||||
final List<String> logs = <String>[];
|
final List<String> logs = <String>[];
|
||||||
|
|
||||||
/// Error/warning messages printed to STDERR.
|
/// Error messages printed to STDERR.
|
||||||
|
///
|
||||||
|
/// Display an error `message` to the user on stderr. Print errors if the code
|
||||||
|
/// fails in some way. Errors are typically followed shortly by exiting the
|
||||||
|
/// app with a non-zero exit status.
|
||||||
@mustCallSuper
|
@mustCallSuper
|
||||||
void printError(String message) {
|
void printError(String message) {
|
||||||
logs.add('[error] $message');
|
logs.add('[error] $message');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Warning messages printed to STDERR.
|
||||||
|
///
|
||||||
|
/// Display a warning `message` to the user on stderr. Print warnings if there
|
||||||
|
/// is important information to convey to the user that is not fatal.
|
||||||
|
@mustCallSuper
|
||||||
|
void printWarning(String message) {
|
||||||
|
logs.add('[warning] $message');
|
||||||
|
}
|
||||||
|
|
||||||
/// Ordinary STDOUT messages.
|
/// Ordinary STDOUT messages.
|
||||||
|
///
|
||||||
|
/// Displays normal output on stdout. This should be used for things like
|
||||||
|
/// progress messages, success messages, or just normal command output.
|
||||||
@mustCallSuper
|
@mustCallSuper
|
||||||
void printStatus(String message) {
|
void printStatus(String message) {
|
||||||
logs.add('[status] $message');
|
logs.add('[status] $message');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Debug messages that are only printed in verbose mode.
|
/// Debug messages that are only printed in verbose mode.
|
||||||
|
///
|
||||||
|
/// Use this for verbose tracing output. Users can turn this output on in order
|
||||||
|
/// to help diagnose issues.
|
||||||
@mustCallSuper
|
@mustCallSuper
|
||||||
void printTrace(String message) {
|
void printTrace(String message) {
|
||||||
logs.add('[trace] $message');
|
logs.add('[trace] $message');
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write string to STDOUT without trailing newline.
|
/// Write the `message` string to STDOUT without a trailing newline.
|
||||||
@mustCallSuper
|
@mustCallSuper
|
||||||
void write(String message) {
|
void write(String message) {
|
||||||
logs.add('[write] $message');
|
logs.add('[write] $message');
|
||||||
|
@ -49,6 +49,7 @@ class TestCommand extends Command<void> {
|
|||||||
'task, will write test results to the file.');
|
'task, will write test results to the file.');
|
||||||
argParser.addFlag(
|
argParser.addFlag(
|
||||||
'silent',
|
'silent',
|
||||||
|
help: 'Suppresses standard output and only print standard error output.',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
import 'package:args/args.dart';
|
import 'package:args/args.dart';
|
||||||
import 'package:flutter_tools/src/asset.dart' hide defaultManifestPath;
|
import 'package:flutter_tools/src/asset.dart' hide defaultManifestPath;
|
||||||
|
import 'package:flutter_tools/src/base/common.dart';
|
||||||
import 'package:flutter_tools/src/base/context.dart';
|
import 'package:flutter_tools/src/base/context.dart';
|
||||||
import 'package:flutter_tools/src/base/file_system.dart' as libfs;
|
import 'package:flutter_tools/src/base/file_system.dart' as libfs;
|
||||||
import 'package:flutter_tools/src/base/io.dart';
|
import 'package:flutter_tools/src/base/io.dart';
|
||||||
@ -70,8 +71,7 @@ Future<void> run(List<String> args) async {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (assets == null) {
|
if (assets == null) {
|
||||||
print('Unable to find assets.');
|
throwToolExit('Unable to find assets.', exitCode: 1);
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<Future<void>> calls = <Future<void>>[];
|
final List<Future<void>> calls = <Future<void>>[];
|
||||||
|
@ -39,7 +39,7 @@ Future<int> run(
|
|||||||
// Remove the verbose option; for help and doctor, users don't need to see
|
// Remove the verbose option; for help and doctor, users don't need to see
|
||||||
// verbose logs.
|
// verbose logs.
|
||||||
args = List<String>.of(args);
|
args = List<String>.of(args);
|
||||||
args.removeWhere((String option) => option == '-v' || option == '--verbose');
|
args.removeWhere((String option) => option == '-vv' || option == '-v' || option == '--verbose');
|
||||||
}
|
}
|
||||||
|
|
||||||
return runInContext<int>(() async {
|
return runInContext<int>(() async {
|
||||||
|
@ -7,6 +7,7 @@ import 'dart:async';
|
|||||||
import 'package:meta/meta.dart';
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
import '../convert.dart';
|
import '../convert.dart';
|
||||||
|
import 'common.dart';
|
||||||
import 'io.dart';
|
import 'io.dart';
|
||||||
import 'terminal.dart' show Terminal, TerminalColor, OutputPreferences;
|
import 'terminal.dart' show Terminal, TerminalColor, OutputPreferences;
|
||||||
import 'utils.dart';
|
import 'utils.dart';
|
||||||
@ -28,22 +29,41 @@ class StopwatchFactory {
|
|||||||
typedef VoidCallback = void Function();
|
typedef VoidCallback = void Function();
|
||||||
|
|
||||||
abstract class Logger {
|
abstract class Logger {
|
||||||
|
/// Whether or not this logger should print [printTrace] messages.
|
||||||
bool get isVerbose => false;
|
bool get isVerbose => false;
|
||||||
|
|
||||||
|
/// If true, silences the logger output.
|
||||||
bool quiet = false;
|
bool quiet = false;
|
||||||
|
|
||||||
|
/// If true, this logger supports color output.
|
||||||
bool get supportsColor;
|
bool get supportsColor;
|
||||||
|
|
||||||
|
/// If true, this logger is connected to a terminal.
|
||||||
bool get hasTerminal;
|
bool get hasTerminal;
|
||||||
|
|
||||||
|
/// If true, then [printError] has been called at least once for this logger
|
||||||
|
/// since the last time it was set to false.
|
||||||
|
bool hadErrorOutput = false;
|
||||||
|
|
||||||
|
/// If true, then [printWarning] has been called at least once for this logger
|
||||||
|
/// since the last time it was reset to false.
|
||||||
|
bool hadWarningOutput = false;
|
||||||
|
|
||||||
|
/// Causes [checkForFatalLogs] to call [throwToolExit] when it is called if
|
||||||
|
/// [hadWarningOutput] is true.
|
||||||
|
bool fatalWarnings = false;
|
||||||
|
|
||||||
|
/// Returns the terminal attached to this logger.
|
||||||
Terminal get terminal;
|
Terminal get terminal;
|
||||||
|
|
||||||
OutputPreferences get _outputPreferences;
|
OutputPreferences get _outputPreferences;
|
||||||
|
|
||||||
/// Display an error `message` to the user. Commands should use this if they
|
/// Display an error `message` to the user. Commands should use this if they
|
||||||
/// fail in some way.
|
/// fail in some way. Errors are typically followed shortly by a call to
|
||||||
|
/// [throwToolExit] to terminate the run.
|
||||||
///
|
///
|
||||||
/// The `message` argument is printed to the stderr in red by default.
|
/// The `message` argument is printed to the stderr in [TerminalColor.red] by
|
||||||
|
/// default.
|
||||||
///
|
///
|
||||||
/// The `stackTrace` argument is the stack trace that will be printed if
|
/// The `stackTrace` argument is the stack trace that will be printed if
|
||||||
/// supplied.
|
/// supplied.
|
||||||
@ -74,10 +94,41 @@ abstract class Logger {
|
|||||||
bool? wrap,
|
bool? wrap,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Display a warning `message` to the user. Commands should use this if they
|
||||||
|
/// important information to convey to the user that is not fatal.
|
||||||
|
///
|
||||||
|
/// The `message` argument is printed to the stderr in [TerminalColor.cyan] by
|
||||||
|
/// default.
|
||||||
|
///
|
||||||
|
/// The `emphasis` argument will cause the output message be printed in bold text.
|
||||||
|
///
|
||||||
|
/// The `color` argument will print the message in the supplied color instead
|
||||||
|
/// of the default of cyan. Colors will not be printed if the output terminal
|
||||||
|
/// doesn't support them.
|
||||||
|
///
|
||||||
|
/// The `indent` argument specifies the number of spaces to indent the overall
|
||||||
|
/// message. If wrapping is enabled in [outputPreferences], then the wrapped
|
||||||
|
/// lines will be indented as well.
|
||||||
|
///
|
||||||
|
/// If `hangingIndent` is specified, then any wrapped lines will be indented
|
||||||
|
/// by this much more than the first line, if wrapping is enabled in
|
||||||
|
/// [outputPreferences].
|
||||||
|
///
|
||||||
|
/// If `wrap` is specified, then it overrides the
|
||||||
|
/// `outputPreferences.wrapText` setting.
|
||||||
|
void printWarning(
|
||||||
|
String message, {
|
||||||
|
bool? emphasis,
|
||||||
|
TerminalColor? color,
|
||||||
|
int? indent,
|
||||||
|
int? hangingIndent,
|
||||||
|
bool? wrap,
|
||||||
|
});
|
||||||
|
|
||||||
/// Display normal output of the command. This should be used for things like
|
/// Display normal output of the command. This should be used for things like
|
||||||
/// progress messages, success messages, or just normal command output.
|
/// progress messages, success messages, or just normal command output.
|
||||||
///
|
///
|
||||||
/// The `message` argument is printed to the stderr in red by default.
|
/// The `message` argument is printed to the stdout.
|
||||||
///
|
///
|
||||||
/// The `stackTrace` argument is the stack trace that will be printed if
|
/// The `stackTrace` argument is the stack trace that will be printed if
|
||||||
/// supplied.
|
/// supplied.
|
||||||
@ -144,9 +195,21 @@ abstract class Logger {
|
|||||||
|
|
||||||
/// Clears all output.
|
/// Clears all output.
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
/// If [fatalWarnings] is set, causes the logger to check if
|
||||||
|
/// [hadWarningOutput] is true, and then to call [throwToolExit] if so.
|
||||||
|
///
|
||||||
|
/// The [fatalWarnings] flag can be set from the command line with the
|
||||||
|
/// "--fatal-warnings" option on commands that support it.
|
||||||
|
void checkForFatalLogs() {
|
||||||
|
if (fatalWarnings && (hadWarningOutput || hadErrorOutput)) {
|
||||||
|
throwToolExit('Logger received ${hadErrorOutput ? 'error' : 'warning'} output '
|
||||||
|
'during the run, and "--fatal-warnings" is enabled.');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [Logger] that forwards all methods to another one.
|
/// A [Logger] that forwards all methods to another logger.
|
||||||
///
|
///
|
||||||
/// Classes can derive from this to add functionality to an existing [Logger].
|
/// Classes can derive from this to add functionality to an existing [Logger].
|
||||||
class DelegatingLogger implements Logger {
|
class DelegatingLogger implements Logger {
|
||||||
@ -174,6 +237,24 @@ class DelegatingLogger implements Logger {
|
|||||||
@override
|
@override
|
||||||
bool get isVerbose => _delegate.isVerbose;
|
bool get isVerbose => _delegate.isVerbose;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get hadErrorOutput => _delegate.hadErrorOutput;
|
||||||
|
|
||||||
|
@override
|
||||||
|
set hadErrorOutput(bool value) => _delegate.hadErrorOutput = value;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get hadWarningOutput => _delegate.hadWarningOutput;
|
||||||
|
|
||||||
|
@override
|
||||||
|
set hadWarningOutput(bool value) => _delegate.hadWarningOutput = value;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get fatalWarnings => _delegate.fatalWarnings;
|
||||||
|
|
||||||
|
@override
|
||||||
|
set fatalWarnings(bool value) => _delegate.fatalWarnings = value;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void printError(String message, {
|
void printError(String message, {
|
||||||
StackTrace? stackTrace,
|
StackTrace? stackTrace,
|
||||||
@ -194,6 +275,24 @@ class DelegatingLogger implements Logger {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void printWarning(String message, {
|
||||||
|
bool? emphasis,
|
||||||
|
TerminalColor? color,
|
||||||
|
int? indent,
|
||||||
|
int? hangingIndent,
|
||||||
|
bool? wrap,
|
||||||
|
}) {
|
||||||
|
_delegate.printWarning(
|
||||||
|
message,
|
||||||
|
emphasis: emphasis,
|
||||||
|
color: color,
|
||||||
|
indent: indent,
|
||||||
|
hangingIndent: hangingIndent,
|
||||||
|
wrap: wrap,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void printStatus(String message, {
|
void printStatus(String message, {
|
||||||
bool? emphasis,
|
bool? emphasis,
|
||||||
@ -244,6 +343,9 @@ class DelegatingLogger implements Logger {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void clear() => _delegate.clear();
|
void clear() => _delegate.clear();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void checkForFatalLogs() => _delegate.checkForFatalLogs();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If [logger] is a [DelegatingLogger], walks the delegate chain and returns
|
/// If [logger] is a [DelegatingLogger], walks the delegate chain and returns
|
||||||
@ -303,6 +405,7 @@ class StdoutLogger extends Logger {
|
|||||||
int? hangingIndent,
|
int? hangingIndent,
|
||||||
bool? wrap,
|
bool? wrap,
|
||||||
}) {
|
}) {
|
||||||
|
hadErrorOutput = true;
|
||||||
_status?.pause();
|
_status?.pause();
|
||||||
message = wrapText(message,
|
message = wrapText(message,
|
||||||
indent: indent,
|
indent: indent,
|
||||||
@ -321,6 +424,31 @@ class StdoutLogger extends Logger {
|
|||||||
_status?.resume();
|
_status?.resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void printWarning(
|
||||||
|
String message, {
|
||||||
|
bool? emphasis,
|
||||||
|
TerminalColor? color,
|
||||||
|
int? indent,
|
||||||
|
int? hangingIndent,
|
||||||
|
bool? wrap,
|
||||||
|
}) {
|
||||||
|
hadWarningOutput = true;
|
||||||
|
_status?.pause();
|
||||||
|
message = wrapText(message,
|
||||||
|
indent: indent,
|
||||||
|
hangingIndent: hangingIndent,
|
||||||
|
shouldWrap: wrap ?? _outputPreferences.wrapText,
|
||||||
|
columnWidth: _outputPreferences.wrapColumn,
|
||||||
|
);
|
||||||
|
if (emphasis == true) {
|
||||||
|
message = terminal.bolden(message);
|
||||||
|
}
|
||||||
|
message = terminal.color(message, color ?? TerminalColor.cyan);
|
||||||
|
writeToStdErr('$message\n');
|
||||||
|
_status?.resume();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void printStatus(
|
void printStatus(
|
||||||
String message, {
|
String message, {
|
||||||
@ -482,7 +610,6 @@ class BufferLogger extends Logger {
|
|||||||
_outputPreferences = outputPreferences ?? OutputPreferences.test(),
|
_outputPreferences = outputPreferences ?? OutputPreferences.test(),
|
||||||
_stopwatchFactory = const StopwatchFactory();
|
_stopwatchFactory = const StopwatchFactory();
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final OutputPreferences _outputPreferences;
|
final OutputPreferences _outputPreferences;
|
||||||
|
|
||||||
@ -498,11 +625,13 @@ class BufferLogger extends Logger {
|
|||||||
bool get supportsColor => terminal.supportsColor;
|
bool get supportsColor => terminal.supportsColor;
|
||||||
|
|
||||||
final StringBuffer _error = StringBuffer();
|
final StringBuffer _error = StringBuffer();
|
||||||
|
final StringBuffer _warning = StringBuffer();
|
||||||
final StringBuffer _status = StringBuffer();
|
final StringBuffer _status = StringBuffer();
|
||||||
final StringBuffer _trace = StringBuffer();
|
final StringBuffer _trace = StringBuffer();
|
||||||
final StringBuffer _events = StringBuffer();
|
final StringBuffer _events = StringBuffer();
|
||||||
|
|
||||||
String get errorText => _error.toString();
|
String get errorText => _error.toString();
|
||||||
|
String get warningText => _warning.toString();
|
||||||
String get statusText => _status.toString();
|
String get statusText => _status.toString();
|
||||||
String get traceText => _trace.toString();
|
String get traceText => _trace.toString();
|
||||||
String get eventText => _events.toString();
|
String get eventText => _events.toString();
|
||||||
@ -520,6 +649,7 @@ class BufferLogger extends Logger {
|
|||||||
int? hangingIndent,
|
int? hangingIndent,
|
||||||
bool? wrap,
|
bool? wrap,
|
||||||
}) {
|
}) {
|
||||||
|
hadErrorOutput = true;
|
||||||
_error.writeln(terminal.color(
|
_error.writeln(terminal.color(
|
||||||
wrapText(message,
|
wrapText(message,
|
||||||
indent: indent,
|
indent: indent,
|
||||||
@ -531,6 +661,27 @@ class BufferLogger extends Logger {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void printWarning(
|
||||||
|
String message, {
|
||||||
|
bool? emphasis,
|
||||||
|
TerminalColor? color,
|
||||||
|
int? indent,
|
||||||
|
int? hangingIndent,
|
||||||
|
bool? wrap,
|
||||||
|
}) {
|
||||||
|
hadWarningOutput = true;
|
||||||
|
_warning.writeln(terminal.color(
|
||||||
|
wrapText(message,
|
||||||
|
indent: indent,
|
||||||
|
hangingIndent: hangingIndent,
|
||||||
|
shouldWrap: wrap ?? _outputPreferences.wrapText,
|
||||||
|
columnWidth: _outputPreferences.wrapColumn,
|
||||||
|
),
|
||||||
|
color ?? TerminalColor.cyan,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void printStatus(
|
void printStatus(
|
||||||
String message, {
|
String message, {
|
||||||
@ -625,6 +776,7 @@ class VerboseLogger extends DelegatingLogger {
|
|||||||
int? hangingIndent,
|
int? hangingIndent,
|
||||||
bool? wrap,
|
bool? wrap,
|
||||||
}) {
|
}) {
|
||||||
|
hadErrorOutput = true;
|
||||||
_emit(
|
_emit(
|
||||||
_LogType.error,
|
_LogType.error,
|
||||||
wrapText(message,
|
wrapText(message,
|
||||||
@ -637,6 +789,29 @@ class VerboseLogger extends DelegatingLogger {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void printWarning(
|
||||||
|
String message, {
|
||||||
|
StackTrace? stackTrace,
|
||||||
|
bool? emphasis,
|
||||||
|
TerminalColor? color,
|
||||||
|
int? indent,
|
||||||
|
int? hangingIndent,
|
||||||
|
bool? wrap,
|
||||||
|
}) {
|
||||||
|
hadWarningOutput = true;
|
||||||
|
_emit(
|
||||||
|
_LogType.warning,
|
||||||
|
wrapText(message,
|
||||||
|
indent: indent,
|
||||||
|
hangingIndent: hangingIndent,
|
||||||
|
shouldWrap: wrap ?? _outputPreferences.wrapText,
|
||||||
|
columnWidth: _outputPreferences.wrapColumn,
|
||||||
|
),
|
||||||
|
stackTrace,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void printStatus(
|
void printStatus(
|
||||||
String message, {
|
String message, {
|
||||||
@ -707,15 +882,25 @@ class VerboseLogger extends DelegatingLogger {
|
|||||||
final String indent = ''.padLeft(prefix.length);
|
final String indent = ''.padLeft(prefix.length);
|
||||||
final String indentMessage = message.replaceAll('\n', '\n$indent');
|
final String indentMessage = message.replaceAll('\n', '\n$indent');
|
||||||
|
|
||||||
if (type == _LogType.error) {
|
switch (type) {
|
||||||
super.printError(prefix + terminal.bolden(indentMessage));
|
case _LogType.error:
|
||||||
if (stackTrace != null) {
|
super.printError(prefix + terminal.bolden(indentMessage));
|
||||||
super.printError(indent + stackTrace.toString().replaceAll('\n', '\n$indent'));
|
if (stackTrace != null) {
|
||||||
}
|
super.printError(indent + stackTrace.toString().replaceAll('\n', '\n$indent'));
|
||||||
} else if (type == _LogType.status) {
|
}
|
||||||
super.printStatus(prefix + terminal.bolden(indentMessage));
|
break;
|
||||||
} else {
|
case _LogType.warning:
|
||||||
super.printStatus(prefix + indentMessage);
|
super.printWarning(prefix + terminal.bolden(indentMessage));
|
||||||
|
break;
|
||||||
|
case _LogType.status:
|
||||||
|
super.printStatus(prefix + terminal.bolden(indentMessage));
|
||||||
|
break;
|
||||||
|
case _LogType.trace:
|
||||||
|
// This seems wrong, since there is a 'printTrace' to call on the
|
||||||
|
// superclass, but it's actually the entire point of this logger: to
|
||||||
|
// make things more verbose than they normally would be.
|
||||||
|
super.printStatus(prefix + indentMessage);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -736,6 +921,7 @@ class PrefixedErrorLogger extends DelegatingLogger {
|
|||||||
int? hangingIndent,
|
int? hangingIndent,
|
||||||
bool? wrap,
|
bool? wrap,
|
||||||
}) {
|
}) {
|
||||||
|
hadErrorOutput = true;
|
||||||
if (message.trim().isNotEmpty == true) {
|
if (message.trim().isNotEmpty == true) {
|
||||||
message = 'ERROR: $message';
|
message = 'ERROR: $message';
|
||||||
}
|
}
|
||||||
@ -751,7 +937,7 @@ class PrefixedErrorLogger extends DelegatingLogger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum _LogType { error, status, trace }
|
enum _LogType { error, warning, status, trace }
|
||||||
|
|
||||||
typedef SlowWarningCallback = String Function();
|
typedef SlowWarningCallback = String Function();
|
||||||
|
|
||||||
@ -820,7 +1006,7 @@ abstract class Status {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [SilentStatus] shows nothing.
|
/// A [Status] that shows nothing.
|
||||||
class SilentStatus extends Status {
|
class SilentStatus extends Status {
|
||||||
SilentStatus({
|
SilentStatus({
|
||||||
required Stopwatch stopwatch,
|
required Stopwatch stopwatch,
|
||||||
|
@ -751,7 +751,7 @@ HostPlatform getCurrentHostPlatform() {
|
|||||||
return HostPlatform.windows_x64;
|
return HostPlatform.windows_x64;
|
||||||
}
|
}
|
||||||
|
|
||||||
globals.printError('Unsupported host platform, defaulting to Linux');
|
globals.printWarning('Unsupported host platform, defaulting to Linux');
|
||||||
|
|
||||||
return HostPlatform.linux_x64;
|
return HostPlatform.linux_x64;
|
||||||
}
|
}
|
||||||
|
@ -266,7 +266,7 @@ class Dart2JSTarget extends Target {
|
|||||||
final File dart2jsDeps = environment.buildDir
|
final File dart2jsDeps = environment.buildDir
|
||||||
.childFile('app.dill.deps');
|
.childFile('app.dill.deps');
|
||||||
if (!dart2jsDeps.existsSync()) {
|
if (!dart2jsDeps.existsSync()) {
|
||||||
globals.printError('Warning: dart2js did not produced expected deps list at '
|
globals.printWarning('Warning: dart2js did not produced expected deps list at '
|
||||||
'${dart2jsDeps.path}');
|
'${dart2jsDeps.path}');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,7 @@ Future<void> writeBundle(
|
|||||||
try {
|
try {
|
||||||
bundleDir.deleteSync(recursive: true);
|
bundleDir.deleteSync(recursive: true);
|
||||||
} on FileSystemException catch (err) {
|
} on FileSystemException catch (err) {
|
||||||
loggerOverride.printError(
|
loggerOverride.printWarning(
|
||||||
'Failed to clean up asset directory ${bundleDir.path}: $err\n'
|
'Failed to clean up asset directory ${bundleDir.path}: $err\n'
|
||||||
'To clean build artifacts, use the command "flutter clean".'
|
'To clean build artifacts, use the command "flutter clean".'
|
||||||
);
|
);
|
||||||
|
@ -164,6 +164,7 @@ class Cache {
|
|||||||
|
|
||||||
late final ArtifactUpdater _artifactUpdater = _createUpdater();
|
late final ArtifactUpdater _artifactUpdater = _createUpdater();
|
||||||
|
|
||||||
|
@visibleForTesting
|
||||||
@protected
|
@protected
|
||||||
void registerArtifact(ArtifactSet artifactSet) {
|
void registerArtifact(ArtifactSet artifactSet) {
|
||||||
_artifacts.add(artifactSet);
|
_artifacts.add(artifactSet);
|
||||||
@ -320,13 +321,17 @@ class Cache {
|
|||||||
} on FileSystemException {
|
} on FileSystemException {
|
||||||
if (!printed) {
|
if (!printed) {
|
||||||
_logger.printTrace('Waiting to be able to obtain lock of Flutter binary artifacts directory: ${_lock!.path}');
|
_logger.printTrace('Waiting to be able to obtain lock of Flutter binary artifacts directory: ${_lock!.path}');
|
||||||
// This needs to go to stderr to avoid cluttering up stdout if a parent
|
// This needs to go to stderr to avoid cluttering up stdout if a
|
||||||
// process is collecting stdout. It's not really an "error" though,
|
// parent process is collecting stdout (e.g. when calling "flutter
|
||||||
// so print it in grey.
|
// version --machine"). It's not really a "warning" though, so print it
|
||||||
_logger.printError(
|
// in grey. Also, make sure that it isn't counted as a warning for
|
||||||
|
// Logger.warningsAreFatal.
|
||||||
|
final bool oldWarnings = _logger.hadWarningOutput;
|
||||||
|
_logger.printWarning(
|
||||||
'Waiting for another flutter command to release the startup lock...',
|
'Waiting for another flutter command to release the startup lock...',
|
||||||
color: TerminalColor.grey,
|
color: TerminalColor.grey,
|
||||||
);
|
);
|
||||||
|
_logger.hadWarningOutput = oldWarnings;
|
||||||
printed = true;
|
printed = true;
|
||||||
}
|
}
|
||||||
await Future<void>.delayed(const Duration(milliseconds: 50));
|
await Future<void>.delayed(const Duration(milliseconds: 50));
|
||||||
@ -509,7 +514,7 @@ class Cache {
|
|||||||
ErrorHandlingFileSystem.deleteIfExists(file);
|
ErrorHandlingFileSystem.deleteIfExists(file);
|
||||||
}
|
}
|
||||||
} on FileSystemException catch (err) {
|
} on FileSystemException catch (err) {
|
||||||
_logger.printError('Failed to delete some stamp files: $err');
|
_logger.printWarning('Failed to delete some stamp files: $err');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -703,7 +708,7 @@ abstract class CachedArtifact extends ArtifactSet {
|
|||||||
await updateInner(artifactUpdater, fileSystem, operatingSystemUtils);
|
await updateInner(artifactUpdater, fileSystem, operatingSystemUtils);
|
||||||
try {
|
try {
|
||||||
if (version == null) {
|
if (version == null) {
|
||||||
logger.printError(
|
logger.printWarning(
|
||||||
'No known version for the artifact name "$name". '
|
'No known version for the artifact name "$name". '
|
||||||
'Flutter can continue, but the artifact may be re-downloaded on '
|
'Flutter can continue, but the artifact may be re-downloaded on '
|
||||||
'subsequent invocations until the problem is resolved.',
|
'subsequent invocations until the problem is resolved.',
|
||||||
@ -712,7 +717,7 @@ abstract class CachedArtifact extends ArtifactSet {
|
|||||||
cache.setStampFor(stampName, version!);
|
cache.setStampFor(stampName, version!);
|
||||||
}
|
}
|
||||||
} on FileSystemException catch (err) {
|
} on FileSystemException catch (err) {
|
||||||
logger.printError(
|
logger.printWarning(
|
||||||
'The new artifact "$name" was downloaded, but Flutter failed to update '
|
'The new artifact "$name" was downloaded, but Flutter failed to update '
|
||||||
'its stamp file, receiving the error "$err". '
|
'its stamp file, receiving the error "$err". '
|
||||||
'Flutter can continue, but the artifact may be re-downloaded on '
|
'Flutter can continue, but the artifact may be re-downloaded on '
|
||||||
@ -1103,7 +1108,7 @@ class ArtifactUpdater {
|
|||||||
try {
|
try {
|
||||||
file.deleteSync();
|
file.deleteSync();
|
||||||
} on FileSystemException catch (e) {
|
} on FileSystemException catch (e) {
|
||||||
_logger.printError('Failed to delete "${file.path}". Please delete manually. $e');
|
_logger.printWarning('Failed to delete "${file.path}". Please delete manually. $e');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (Directory directory = file.parent; directory.absolute.path != _tempStorage.absolute.path; directory = directory.parent) {
|
for (Directory directory = file.parent; directory.absolute.path != _tempStorage.absolute.path; directory = directory.parent) {
|
||||||
|
@ -65,8 +65,9 @@ class BuildCommand extends FlutterCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class BuildSubCommand extends FlutterCommand {
|
abstract class BuildSubCommand extends FlutterCommand {
|
||||||
BuildSubCommand() {
|
BuildSubCommand({@required bool verboseHelp}) {
|
||||||
requiresPubspecYaml();
|
requiresPubspecYaml();
|
||||||
|
usesFatalWarningsOption(verboseHelp: verboseHelp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -20,7 +20,7 @@ import '../runner/flutter_command.dart' show FlutterCommandResult;
|
|||||||
import 'build.dart';
|
import 'build.dart';
|
||||||
|
|
||||||
class BuildAarCommand extends BuildSubCommand {
|
class BuildAarCommand extends BuildSubCommand {
|
||||||
BuildAarCommand({ @required bool verboseHelp }) {
|
BuildAarCommand({ @required bool verboseHelp }) : super(verboseHelp: verboseHelp) {
|
||||||
argParser
|
argParser
|
||||||
..addFlag(
|
..addFlag(
|
||||||
'debug',
|
'debug',
|
||||||
|
@ -16,7 +16,7 @@ import '../runner/flutter_command.dart' show FlutterCommandResult;
|
|||||||
import 'build.dart';
|
import 'build.dart';
|
||||||
|
|
||||||
class BuildApkCommand extends BuildSubCommand {
|
class BuildApkCommand extends BuildSubCommand {
|
||||||
BuildApkCommand({bool verboseHelp = false}) {
|
BuildApkCommand({bool verboseHelp = false}) : super(verboseHelp: verboseHelp) {
|
||||||
addTreeShakeIconsFlag();
|
addTreeShakeIconsFlag();
|
||||||
usesTargetOption();
|
usesTargetOption();
|
||||||
addBuildModeFlags(verboseHelp: verboseHelp);
|
addBuildModeFlags(verboseHelp: verboseHelp);
|
||||||
|
@ -19,7 +19,9 @@ import '../runner/flutter_command.dart' show FlutterCommandResult;
|
|||||||
import 'build.dart';
|
import 'build.dart';
|
||||||
|
|
||||||
class BuildAppBundleCommand extends BuildSubCommand {
|
class BuildAppBundleCommand extends BuildSubCommand {
|
||||||
BuildAppBundleCommand({bool verboseHelp = false}) {
|
BuildAppBundleCommand({
|
||||||
|
bool verboseHelp = false,
|
||||||
|
}) : super(verboseHelp: verboseHelp) {
|
||||||
addTreeShakeIconsFlag();
|
addTreeShakeIconsFlag();
|
||||||
usesTargetOption();
|
usesTargetOption();
|
||||||
addBuildModeFlags(verboseHelp: verboseHelp);
|
addBuildModeFlags(verboseHelp: verboseHelp);
|
||||||
|
@ -16,7 +16,10 @@ import '../runner/flutter_command.dart';
|
|||||||
import 'build.dart';
|
import 'build.dart';
|
||||||
|
|
||||||
class BuildBundleCommand extends BuildSubCommand {
|
class BuildBundleCommand extends BuildSubCommand {
|
||||||
BuildBundleCommand({bool verboseHelp = false, this.bundleBuilder}) {
|
BuildBundleCommand({
|
||||||
|
bool verboseHelp = false,
|
||||||
|
this.bundleBuilder,
|
||||||
|
}) : super(verboseHelp: verboseHelp) {
|
||||||
usesTargetOption();
|
usesTargetOption();
|
||||||
usesFilesystemOptions(hide: !verboseHelp);
|
usesFilesystemOptions(hide: !verboseHelp);
|
||||||
usesBuildNumberOption();
|
usesBuildNumberOption();
|
||||||
|
@ -19,7 +19,9 @@ import 'build.dart';
|
|||||||
|
|
||||||
/// A command to build a Fuchsia target.
|
/// A command to build a Fuchsia target.
|
||||||
class BuildFuchsiaCommand extends BuildSubCommand {
|
class BuildFuchsiaCommand extends BuildSubCommand {
|
||||||
BuildFuchsiaCommand({ @required bool verboseHelp }) {
|
BuildFuchsiaCommand({
|
||||||
|
@required bool verboseHelp,
|
||||||
|
}) : super(verboseHelp: verboseHelp) {
|
||||||
addTreeShakeIconsFlag();
|
addTreeShakeIconsFlag();
|
||||||
usesTargetOption();
|
usesTargetOption();
|
||||||
usesDartDefineOption();
|
usesDartDefineOption();
|
||||||
|
@ -129,7 +129,7 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
|
|||||||
|
|
||||||
// xcarchive failed or not at expected location.
|
// xcarchive failed or not at expected location.
|
||||||
if (xcarchiveResult.exitStatus != ExitStatus.success) {
|
if (xcarchiveResult.exitStatus != ExitStatus.success) {
|
||||||
globals.logger.printStatus('Skipping IPA');
|
globals.printStatus('Skipping IPA');
|
||||||
return xcarchiveResult;
|
return xcarchiveResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,14 +176,16 @@ class BuildIOSArchiveCommand extends _BuildIOSSubCommand {
|
|||||||
throwToolExit('Encountered error while building IPA:\n$errorMessage');
|
throwToolExit('Encountered error while building IPA:\n$errorMessage');
|
||||||
}
|
}
|
||||||
|
|
||||||
globals.logger.printStatus('Built IPA to $outputPath.');
|
globals.printStatus('Built IPA to $outputPath.');
|
||||||
|
|
||||||
return FlutterCommandResult.success();
|
return FlutterCommandResult.success();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class _BuildIOSSubCommand extends BuildSubCommand {
|
abstract class _BuildIOSSubCommand extends BuildSubCommand {
|
||||||
_BuildIOSSubCommand({ @required bool verboseHelp }) {
|
_BuildIOSSubCommand({
|
||||||
|
@required bool verboseHelp
|
||||||
|
}) : super(verboseHelp: verboseHelp) {
|
||||||
addTreeShakeIconsFlag();
|
addTreeShakeIconsFlag();
|
||||||
addSplitDebugInfoOption();
|
addSplitDebugInfoOption();
|
||||||
addBuildModeFlags(verboseHelp: verboseHelp);
|
addBuildModeFlags(verboseHelp: verboseHelp);
|
||||||
|
@ -39,7 +39,8 @@ class BuildIOSFrameworkCommand extends BuildSubCommand {
|
|||||||
}) : _flutterVersion = flutterVersion,
|
}) : _flutterVersion = flutterVersion,
|
||||||
_buildSystem = buildSystem,
|
_buildSystem = buildSystem,
|
||||||
_injectedCache = cache,
|
_injectedCache = cache,
|
||||||
_injectedPlatform = platform {
|
_injectedPlatform = platform,
|
||||||
|
super(verboseHelp: verboseHelp) {
|
||||||
addTreeShakeIconsFlag();
|
addTreeShakeIconsFlag();
|
||||||
usesTargetOption();
|
usesTargetOption();
|
||||||
usesFlavorOption();
|
usesFlavorOption();
|
||||||
|
@ -23,7 +23,8 @@ class BuildLinuxCommand extends BuildSubCommand {
|
|||||||
BuildLinuxCommand({
|
BuildLinuxCommand({
|
||||||
@required OperatingSystemUtils operatingSystemUtils,
|
@required OperatingSystemUtils operatingSystemUtils,
|
||||||
bool verboseHelp = false,
|
bool verboseHelp = false,
|
||||||
}) : _operatingSystemUtils = operatingSystemUtils {
|
}) : _operatingSystemUtils = operatingSystemUtils,
|
||||||
|
super(verboseHelp: verboseHelp) {
|
||||||
addCommonDesktopBuildOptions(verboseHelp: verboseHelp);
|
addCommonDesktopBuildOptions(verboseHelp: verboseHelp);
|
||||||
final String defaultTargetPlatform =
|
final String defaultTargetPlatform =
|
||||||
(_operatingSystemUtils.hostPlatform == HostPlatform.linux_arm64) ?
|
(_operatingSystemUtils.hostPlatform == HostPlatform.linux_arm64) ?
|
||||||
|
@ -19,7 +19,9 @@ import 'build.dart';
|
|||||||
|
|
||||||
/// A command to build a macOS desktop target through a build shell script.
|
/// A command to build a macOS desktop target through a build shell script.
|
||||||
class BuildMacosCommand extends BuildSubCommand {
|
class BuildMacosCommand extends BuildSubCommand {
|
||||||
BuildMacosCommand({ @required bool verboseHelp }) {
|
BuildMacosCommand({
|
||||||
|
@required bool verboseHelp,
|
||||||
|
}) : super(verboseHelp: verboseHelp) {
|
||||||
addCommonDesktopBuildOptions(verboseHelp: verboseHelp);
|
addCommonDesktopBuildOptions(verboseHelp: verboseHelp);
|
||||||
usesBuildNumberOption();
|
usesBuildNumberOption();
|
||||||
usesBuildNameOption();
|
usesBuildNameOption();
|
||||||
|
@ -20,7 +20,7 @@ import 'build.dart';
|
|||||||
class BuildWebCommand extends BuildSubCommand {
|
class BuildWebCommand extends BuildSubCommand {
|
||||||
BuildWebCommand({
|
BuildWebCommand({
|
||||||
@required bool verboseHelp,
|
@required bool verboseHelp,
|
||||||
}) {
|
}) : super(verboseHelp: verboseHelp) {
|
||||||
addTreeShakeIconsFlag(enabledByDefault: false);
|
addTreeShakeIconsFlag(enabledByDefault: false);
|
||||||
usesTargetOption();
|
usesTargetOption();
|
||||||
usesPubOption();
|
usesPubOption();
|
||||||
|
@ -20,7 +20,9 @@ import 'build.dart';
|
|||||||
|
|
||||||
/// A command to build a windows desktop target through a build shell script.
|
/// A command to build a windows desktop target through a build shell script.
|
||||||
class BuildWindowsCommand extends BuildSubCommand {
|
class BuildWindowsCommand extends BuildSubCommand {
|
||||||
BuildWindowsCommand({ bool verboseHelp = false }) {
|
BuildWindowsCommand({
|
||||||
|
bool verboseHelp = false,
|
||||||
|
}) : super(verboseHelp: verboseHelp) {
|
||||||
addCommonDesktopBuildOptions(verboseHelp: verboseHelp);
|
addCommonDesktopBuildOptions(verboseHelp: verboseHelp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,9 @@ import 'build.dart';
|
|||||||
|
|
||||||
/// A command to build a Windows UWP desktop target.
|
/// A command to build a Windows UWP desktop target.
|
||||||
class BuildWindowsUwpCommand extends BuildSubCommand {
|
class BuildWindowsUwpCommand extends BuildSubCommand {
|
||||||
BuildWindowsUwpCommand({ bool verboseHelp = false }) {
|
BuildWindowsUwpCommand({
|
||||||
|
bool verboseHelp = false,
|
||||||
|
}) : super(verboseHelp: verboseHelp) {
|
||||||
addCommonDesktopBuildOptions(verboseHelp: verboseHelp);
|
addCommonDesktopBuildOptions(verboseHelp: verboseHelp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,7 +228,7 @@ class CreateCommand extends CreateBase {
|
|||||||
validateProjectDir(overwrite: overwrite);
|
validateProjectDir(overwrite: overwrite);
|
||||||
|
|
||||||
if (boolArg('with-driver-test')) {
|
if (boolArg('with-driver-test')) {
|
||||||
globals.printError(
|
globals.printWarning(
|
||||||
'The "--with-driver-test" argument has been deprecated and will no longer add a flutter '
|
'The "--with-driver-test" argument has been deprecated and will no longer add a flutter '
|
||||||
'driver template. Instead, learn how to use package:integration_test by '
|
'driver template. Instead, learn how to use package:integration_test by '
|
||||||
'visiting https://pub.dev/packages/integration_test .'
|
'visiting https://pub.dev/packages/integration_test .'
|
||||||
|
@ -309,7 +309,7 @@ class DaemonDomain extends Domain {
|
|||||||
// capture the print output for testing.
|
// capture the print output for testing.
|
||||||
// ignore: avoid_print
|
// ignore: avoid_print
|
||||||
print(message.message);
|
print(message.message);
|
||||||
} else if (message.level == 'error') {
|
} else if (message.level == 'error' || message.level == 'warning') {
|
||||||
globals.stdio.stderrWrite('${message.message}\n');
|
globals.stdio.stderrWrite('${message.message}\n');
|
||||||
if (message.stackTrace != null) {
|
if (message.stackTrace != null) {
|
||||||
globals.stdio.stderrWrite(
|
globals.stdio.stderrWrite(
|
||||||
@ -1011,6 +1011,18 @@ class NotifyingLogger extends DelegatingLogger {
|
|||||||
_sendMessage(LogMessage('error', message, stackTrace));
|
_sendMessage(LogMessage('error', message, stackTrace));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void printWarning(
|
||||||
|
String message, {
|
||||||
|
bool emphasis = false,
|
||||||
|
TerminalColor color,
|
||||||
|
int indent,
|
||||||
|
int hangingIndent,
|
||||||
|
bool wrap,
|
||||||
|
}) {
|
||||||
|
_sendMessage(LogMessage('warning', message));
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void printStatus(
|
void printStatus(
|
||||||
String message, {
|
String message, {
|
||||||
|
@ -48,7 +48,7 @@ class DevicesCommand extends FlutterCommand {
|
|||||||
@override
|
@override
|
||||||
Future<void> validateCommand() {
|
Future<void> validateCommand() {
|
||||||
if (argResults?['timeout'] != null) {
|
if (argResults?['timeout'] != null) {
|
||||||
globals.printError('${globals.logger.terminal.warningMark} The "--timeout" argument is deprecated; use "--${FlutterOptions.kDeviceTimeout}" instead.');
|
globals.printWarning('${globals.logger.terminal.warningMark} The "--timeout" argument is deprecated; use "--${FlutterOptions.kDeviceTimeout}" instead.');
|
||||||
}
|
}
|
||||||
return super.validateCommand();
|
return super.validateCommand();
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ Future<bool> installApp(
|
|||||||
if (uninstall && await device.isAppInstalled(package, userIdentifier: userIdentifier)) {
|
if (uninstall && await device.isAppInstalled(package, userIdentifier: userIdentifier)) {
|
||||||
globals.printStatus('Uninstalling old version...');
|
globals.printStatus('Uninstalling old version...');
|
||||||
if (!await device.uninstallApp(package, userIdentifier: userIdentifier)) {
|
if (!await device.uninstallApp(package, userIdentifier: userIdentifier)) {
|
||||||
globals.printError('Warning: uninstalling old version failed');
|
globals.printWarning('Warning: uninstalling old version failed');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on ProcessException catch (e) {
|
} on ProcessException catch (e) {
|
||||||
|
@ -153,6 +153,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
|
|||||||
addDdsOptions(verboseHelp: verboseHelp);
|
addDdsOptions(verboseHelp: verboseHelp);
|
||||||
addDevToolsOptions(verboseHelp: verboseHelp);
|
addDevToolsOptions(verboseHelp: verboseHelp);
|
||||||
addAndroidSpecificBuildOptions(hide: !verboseHelp);
|
addAndroidSpecificBuildOptions(hide: !verboseHelp);
|
||||||
|
usesFatalWarningsOption(verboseHelp: verboseHelp);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get traceStartup => boolArg('trace-startup');
|
bool get traceStartup => boolArg('trace-startup');
|
||||||
|
@ -216,7 +216,8 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
|
|||||||
'or as the string "none" to disable the timeout entirely.',
|
'or as the string "none" to disable the timeout entirely.',
|
||||||
defaultsTo: '30s',
|
defaultsTo: '30s',
|
||||||
);
|
);
|
||||||
addDdsOptions(verboseHelp: verboseHelp);
|
addDdsOptions(verboseHelp: verboseHelp);
|
||||||
|
usesFatalWarningsOption(verboseHelp: verboseHelp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The interface for starting and configuring the tester.
|
/// The interface for starting and configuring the tester.
|
||||||
@ -283,7 +284,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
|
|||||||
// correct [requiredArtifacts] can be identified before [run] takes place.
|
// correct [requiredArtifacts] can be identified before [run] takes place.
|
||||||
_isIntegrationTest = _shouldRunAsIntegrationTests(globals.fs.currentDirectory.absolute.path, _testFiles);
|
_isIntegrationTest = _shouldRunAsIntegrationTests(globals.fs.currentDirectory.absolute.path, _testFiles);
|
||||||
|
|
||||||
globals.logger.printTrace(
|
globals.printTrace(
|
||||||
'Found ${_testFiles.length} files which will be executed as '
|
'Found ${_testFiles.length} files which will be executed as '
|
||||||
'${_isIntegrationTest ? 'Integration' : 'Widget'} Tests.',
|
'${_isIntegrationTest ? 'Integration' : 'Widget'} Tests.',
|
||||||
);
|
);
|
||||||
@ -338,7 +339,7 @@ class TestCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts {
|
|||||||
}
|
}
|
||||||
if (_isIntegrationTest) {
|
if (_isIntegrationTest) {
|
||||||
if (argResults.wasParsed('concurrency')) {
|
if (argResults.wasParsed('concurrency')) {
|
||||||
globals.logger.printStatus(
|
globals.printStatus(
|
||||||
'-j/--concurrency was parsed but will be ignored, this option is not '
|
'-j/--concurrency was parsed but will be ignored, this option is not '
|
||||||
'supported when running Integration Tests.',
|
'supported when running Integration Tests.',
|
||||||
);
|
);
|
||||||
|
@ -190,7 +190,7 @@ class UpdatePackagesCommand extends FlutterCommand {
|
|||||||
if (pubspec.checksum.value == null) {
|
if (pubspec.checksum.value == null) {
|
||||||
// If the checksum is invalid or missing, we can just ask them run to run
|
// If the checksum is invalid or missing, we can just ask them run to run
|
||||||
// upgrade again to compute it.
|
// upgrade again to compute it.
|
||||||
globals.printError(
|
globals.printWarning(
|
||||||
'Warning: pubspec in ${directory.path} has out of date dependencies. '
|
'Warning: pubspec in ${directory.path} has out of date dependencies. '
|
||||||
'Please run "flutter update-packages --force-upgrade" to update them correctly.'
|
'Please run "flutter update-packages --force-upgrade" to update them correctly.'
|
||||||
);
|
);
|
||||||
@ -207,7 +207,7 @@ class UpdatePackagesCommand extends FlutterCommand {
|
|||||||
if (checksum != pubspec.checksum.value) {
|
if (checksum != pubspec.checksum.value) {
|
||||||
// If the checksum doesn't match, they may have added or removed some dependencies.
|
// If the checksum doesn't match, they may have added or removed some dependencies.
|
||||||
// we need to run update-packages to recapture the transitive deps.
|
// we need to run update-packages to recapture the transitive deps.
|
||||||
globals.printError(
|
globals.printWarning(
|
||||||
'Warning: pubspec in ${directory.path} has updated or new dependencies. '
|
'Warning: pubspec in ${directory.path} has updated or new dependencies. '
|
||||||
'Please run "flutter update-packages --force-upgrade" to update them correctly '
|
'Please run "flutter update-packages --force-upgrade" to update them correctly '
|
||||||
'(checksum ${pubspec.checksum.value} != $checksum).'
|
'(checksum ${pubspec.checksum.value} != $checksum).'
|
||||||
@ -1501,7 +1501,7 @@ Directory createTemporaryFlutterSdk(
|
|||||||
..createSync(recursive: true);
|
..createSync(recursive: true);
|
||||||
final PubspecYaml pubspecYaml = pubspecsByName[flutterPackage];
|
final PubspecYaml pubspecYaml = pubspecsByName[flutterPackage];
|
||||||
if (pubspecYaml == null) {
|
if (pubspecYaml == null) {
|
||||||
logger.printError(
|
logger.printWarning(
|
||||||
"Unexpected package '$flutterPackage' found in packages directory",
|
"Unexpected package '$flutterPackage' found in packages directory",
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
|
@ -339,11 +339,11 @@ class FlutterManifest {
|
|||||||
final YamlList? fontFiles = fontFamily['fonts'] as YamlList?;
|
final YamlList? fontFiles = fontFamily['fonts'] as YamlList?;
|
||||||
final String? familyName = fontFamily['family'] as String?;
|
final String? familyName = fontFamily['family'] as String?;
|
||||||
if (familyName == null) {
|
if (familyName == null) {
|
||||||
_logger.printError('Warning: Missing family name for font.', emphasis: true);
|
_logger.printWarning('Warning: Missing family name for font.', emphasis: true);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (fontFiles == null) {
|
if (fontFiles == null) {
|
||||||
_logger.printError('Warning: No fonts specified for font $familyName', emphasis: true);
|
_logger.printWarning('Warning: No fonts specified for font $familyName', emphasis: true);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,7 +351,7 @@ class FlutterManifest {
|
|||||||
for (final Map<Object?, Object?> fontFile in fontFiles.cast<Map<Object?, Object?>>()) {
|
for (final Map<Object?, Object?> fontFile in fontFiles.cast<Map<Object?, Object?>>()) {
|
||||||
final String? asset = fontFile['asset'] as String?;
|
final String? asset = fontFile['asset'] as String?;
|
||||||
if (asset == null) {
|
if (asset == null) {
|
||||||
_logger.printError('Warning: Missing asset in fonts for $familyName', emphasis: true);
|
_logger.printWarning('Warning: Missing asset in fonts for $familyName', emphasis: true);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -393,7 +393,7 @@ Future<void> _writeAndroidPluginRegistrant(FlutterProject project, List<Plugin>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pluginsUsingV1.length > 1) {
|
if (pluginsUsingV1.length > 1) {
|
||||||
globals.printError(
|
globals.printWarning(
|
||||||
'The plugins `${pluginsUsingV1.join(', ')}` use a deprecated version of the Android embedding.\n'
|
'The plugins `${pluginsUsingV1.join(', ')}` use a deprecated version of the Android embedding.\n'
|
||||||
'To avoid unexpected runtime failures, or future build failures, try to see if these plugins '
|
'To avoid unexpected runtime failures, or future build failures, try to see if these plugins '
|
||||||
'support the Android V2 embedding. Otherwise, consider removing them since a future release '
|
'support the Android V2 embedding. Otherwise, consider removing them since a future release '
|
||||||
@ -402,7 +402,7 @@ Future<void> _writeAndroidPluginRegistrant(FlutterProject project, List<Plugin>
|
|||||||
'https://flutter.dev/go/android-plugin-migration.'
|
'https://flutter.dev/go/android-plugin-migration.'
|
||||||
);
|
);
|
||||||
} else if (pluginsUsingV1.isNotEmpty) {
|
} else if (pluginsUsingV1.isNotEmpty) {
|
||||||
globals.printError(
|
globals.printWarning(
|
||||||
'The plugin `${pluginsUsingV1.first}` uses a deprecated version of the Android embedding.\n'
|
'The plugin `${pluginsUsingV1.first}` uses a deprecated version of the Android embedding.\n'
|
||||||
'To avoid unexpected runtime failures, or future build failures, try to see if this plugin '
|
'To avoid unexpected runtime failures, or future build failures, try to see if this plugin '
|
||||||
'supports the Android V2 embedding. Otherwise, consider removing it since a future release '
|
'supports the Android V2 embedding. Otherwise, consider removing it since a future release '
|
||||||
@ -414,7 +414,7 @@ Future<void> _writeAndroidPluginRegistrant(FlutterProject project, List<Plugin>
|
|||||||
templateContent = _androidPluginRegistryTemplateNewEmbedding;
|
templateContent = _androidPluginRegistryTemplateNewEmbedding;
|
||||||
break;
|
break;
|
||||||
case AndroidEmbeddingVersion.v1:
|
case AndroidEmbeddingVersion.v1:
|
||||||
globals.printError(
|
globals.printWarning(
|
||||||
'This app is using a deprecated version of the Android embedding.\n'
|
'This app is using a deprecated version of the Android embedding.\n'
|
||||||
'To avoid unexpected runtime failures, or future build failures, try to migrate this '
|
'To avoid unexpected runtime failures, or future build failures, try to migrate this '
|
||||||
'app to the V2 embedding.\n'
|
'app to the V2 embedding.\n'
|
||||||
@ -1301,7 +1301,7 @@ Future<void> generateMainDartWithPluginRegistrant(
|
|||||||
newMainDart.deleteSync();
|
newMainDart.deleteSync();
|
||||||
}
|
}
|
||||||
} on FileSystemException catch (error) {
|
} on FileSystemException catch (error) {
|
||||||
globals.printError(
|
globals.printWarning(
|
||||||
'Unable to remove ${newMainDart.path}, received error: $error.\n'
|
'Unable to remove ${newMainDart.path}, received error: $error.\n'
|
||||||
'You might need to run flutter clean.'
|
'You might need to run flutter clean.'
|
||||||
);
|
);
|
||||||
|
@ -124,6 +124,10 @@ Future<void> _buildAssets(
|
|||||||
assetDirPath: assetDir,
|
assetDirPath: assetDir,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (assets == null) {
|
||||||
|
throwToolExit('Unable to find assets.', exitCode: 1);
|
||||||
|
}
|
||||||
|
|
||||||
final Map<String, DevFSContent> assetEntries =
|
final Map<String, DevFSContent> assetEntries =
|
||||||
Map<String, DevFSContent>.of(assets.entries);
|
Map<String, DevFSContent>.of(assets.entries);
|
||||||
await writeBundle(globals.fs.directory(assetDir), assetEntries);
|
await writeBundle(globals.fs.directory(assetDir), assetEntries);
|
||||||
|
@ -150,6 +150,30 @@ void printError(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Display a warning level message to the user. Commands should use this if they
|
||||||
|
/// have important warnings to convey that aren't fatal.
|
||||||
|
///
|
||||||
|
/// Set [emphasis] to true to make the output bold if it's supported.
|
||||||
|
/// Set [color] to a [TerminalColor] to color the output, if the logger
|
||||||
|
/// supports it. The [color] defaults to [TerminalColor.cyan].
|
||||||
|
void printWarning(
|
||||||
|
String message, {
|
||||||
|
bool? emphasis,
|
||||||
|
TerminalColor? color,
|
||||||
|
int? indent,
|
||||||
|
int? hangingIndent,
|
||||||
|
bool? wrap,
|
||||||
|
}) {
|
||||||
|
logger.printWarning(
|
||||||
|
message,
|
||||||
|
emphasis: emphasis ?? false,
|
||||||
|
color: color,
|
||||||
|
indent: indent,
|
||||||
|
hangingIndent: hangingIndent,
|
||||||
|
wrap: wrap,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Display normal output of the command. This should be used for things like
|
/// Display normal output of the command. This should be used for things like
|
||||||
/// progress messages, success messages, or just normal command output.
|
/// progress messages, success messages, or just normal command output.
|
||||||
///
|
///
|
||||||
|
@ -176,7 +176,7 @@ class CocoaPods {
|
|||||||
final CocoaPodsStatus installation = await evaluateCocoaPodsInstallation;
|
final CocoaPodsStatus installation = await evaluateCocoaPodsInstallation;
|
||||||
switch (installation) {
|
switch (installation) {
|
||||||
case CocoaPodsStatus.notInstalled:
|
case CocoaPodsStatus.notInstalled:
|
||||||
_logger.printError(
|
_logger.printWarning(
|
||||||
'Warning: CocoaPods not installed. Skipping pod install.\n'
|
'Warning: CocoaPods not installed. Skipping pod install.\n'
|
||||||
'$noCocoaPodsConsequence\n'
|
'$noCocoaPodsConsequence\n'
|
||||||
'To install $cocoaPodsInstallInstructions\n',
|
'To install $cocoaPodsInstallInstructions\n',
|
||||||
@ -184,7 +184,7 @@ class CocoaPods {
|
|||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
case CocoaPodsStatus.brokenInstall:
|
case CocoaPodsStatus.brokenInstall:
|
||||||
_logger.printError(
|
_logger.printWarning(
|
||||||
'Warning: CocoaPods is installed but broken. Skipping pod install.\n'
|
'Warning: CocoaPods is installed but broken. Skipping pod install.\n'
|
||||||
'$brokenCocoaPodsConsequence\n'
|
'$brokenCocoaPodsConsequence\n'
|
||||||
'To re-install $cocoaPodsInstallInstructions\n',
|
'To re-install $cocoaPodsInstallInstructions\n',
|
||||||
@ -192,7 +192,7 @@ class CocoaPods {
|
|||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
case CocoaPodsStatus.unknownVersion:
|
case CocoaPodsStatus.unknownVersion:
|
||||||
_logger.printError(
|
_logger.printWarning(
|
||||||
'Warning: Unknown CocoaPods version installed.\n'
|
'Warning: Unknown CocoaPods version installed.\n'
|
||||||
'$unknownCocoaPodsConsequence\n'
|
'$unknownCocoaPodsConsequence\n'
|
||||||
'To upgrade $cocoaPodsInstallInstructions\n',
|
'To upgrade $cocoaPodsInstallInstructions\n',
|
||||||
@ -200,7 +200,7 @@ class CocoaPods {
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case CocoaPodsStatus.belowMinimumVersion:
|
case CocoaPodsStatus.belowMinimumVersion:
|
||||||
_logger.printError(
|
_logger.printWarning(
|
||||||
'Warning: CocoaPods minimum required version $cocoaPodsMinimumVersion or greater not installed. Skipping pod install.\n'
|
'Warning: CocoaPods minimum required version $cocoaPodsMinimumVersion or greater not installed. Skipping pod install.\n'
|
||||||
'$noCocoaPodsConsequence\n'
|
'$noCocoaPodsConsequence\n'
|
||||||
'To upgrade $cocoaPodsInstallInstructions\n',
|
'To upgrade $cocoaPodsInstallInstructions\n',
|
||||||
@ -208,7 +208,7 @@ class CocoaPods {
|
|||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
case CocoaPodsStatus.belowRecommendedVersion:
|
case CocoaPodsStatus.belowRecommendedVersion:
|
||||||
_logger.printError(
|
_logger.printWarning(
|
||||||
'Warning: CocoaPods recommended version $cocoaPodsRecommendedVersion or greater not installed.\n'
|
'Warning: CocoaPods recommended version $cocoaPodsRecommendedVersion or greater not installed.\n'
|
||||||
'Pods handling may fail on some projects involving plugins.\n'
|
'Pods handling may fail on some projects involving plugins.\n'
|
||||||
'To upgrade $cocoaPodsInstallInstructions\n',
|
'To upgrade $cocoaPodsInstallInstructions\n',
|
||||||
@ -406,15 +406,15 @@ class CocoaPods {
|
|||||||
// plugin_pods = parse_KV_file('../.flutter-plugins')
|
// plugin_pods = parse_KV_file('../.flutter-plugins')
|
||||||
if (xcodeProject.podfile.existsSync() &&
|
if (xcodeProject.podfile.existsSync() &&
|
||||||
xcodeProject.podfile.readAsStringSync().contains(".flutter-plugins'")) {
|
xcodeProject.podfile.readAsStringSync().contains(".flutter-plugins'")) {
|
||||||
const String error = 'Warning: Podfile is out of date\n'
|
const String warning = 'Warning: Podfile is out of date\n'
|
||||||
'$outOfDatePluginsPodfileConsequence\n'
|
'$outOfDatePluginsPodfileConsequence\n'
|
||||||
'To regenerate the Podfile, run:\n';
|
'To regenerate the Podfile, run:\n';
|
||||||
if (isIos) {
|
if (isIos) {
|
||||||
throwToolExit('$error\n$podfileIosMigrationInstructions\n');
|
throwToolExit('$warning\n$podfileIosMigrationInstructions\n');
|
||||||
} else {
|
} else {
|
||||||
// The old macOS Podfile will work until `.flutter-plugins` is removed.
|
// The old macOS Podfile will work until `.flutter-plugins` is removed.
|
||||||
// Warn instead of exit.
|
// Warn instead of exit.
|
||||||
_logger.printError('$error\n$podfileMacOSMigrationInstructions\n', emphasis: true);
|
_logger.printWarning('$warning\n$podfileMacOSMigrationInstructions\n', emphasis: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -415,7 +415,7 @@ class XCDevice {
|
|||||||
} else {
|
} else {
|
||||||
cpuArchitecture = DarwinArch.arm64;
|
cpuArchitecture = DarwinArch.arm64;
|
||||||
}
|
}
|
||||||
_logger.printError(
|
_logger.printWarning(
|
||||||
'Unknown architecture $architecture, defaulting to '
|
'Unknown architecture $architecture, defaulting to '
|
||||||
'${getNameForDarwinArch(cpuArchitecture)}',
|
'${getNameForDarwinArch(cpuArchitecture)}',
|
||||||
);
|
);
|
||||||
|
@ -110,7 +110,7 @@ class MDnsObservatoryDiscovery {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (srv.length > 1) {
|
if (srv.length > 1) {
|
||||||
_logger.printError('Unexpectedly found more than one observatory report for $domainName '
|
_logger.printWarning('Unexpectedly found more than one observatory report for $domainName '
|
||||||
'- using first one (${srv.first.port}).');
|
'- using first one (${srv.first.port}).');
|
||||||
}
|
}
|
||||||
_logger.printTrace('Checking for authentication code for $domainName');
|
_logger.printTrace('Checking for authentication code for $domainName');
|
||||||
|
@ -479,23 +479,6 @@ class AndroidProject extends FlutterProjectPlatform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> ensureReadyForPlatformSpecificTooling() async {
|
Future<void> ensureReadyForPlatformSpecificTooling() async {
|
||||||
if (getEmbeddingVersion() == AndroidEmbeddingVersion.v1) {
|
|
||||||
globals.printStatus(
|
|
||||||
"""
|
|
||||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
||||||
Warning
|
|
||||||
──────────────────────────────────────────────────────────────────────────────
|
|
||||||
Your Flutter application is created using an older version of the Android
|
|
||||||
embedding. It's being deprecated in favor of Android embedding v2. Follow the
|
|
||||||
steps at
|
|
||||||
|
|
||||||
https://flutter.dev/go/android-project-migration
|
|
||||||
|
|
||||||
to migrate your project.
|
|
||||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
||||||
"""
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (isModule && _shouldRegenerateFromTemplate()) {
|
if (isModule && _shouldRegenerateFromTemplate()) {
|
||||||
await _regenerateLibrary();
|
await _regenerateLibrary();
|
||||||
// Add ephemeral host app, if an editable host app does not already exist.
|
// Add ephemeral host app, if an editable host app does not already exist.
|
||||||
|
@ -1178,7 +1178,7 @@ abstract class ResidentRunner extends ResidentHandlers {
|
|||||||
);
|
);
|
||||||
if (!_lastBuild.success) {
|
if (!_lastBuild.success) {
|
||||||
for (final ExceptionMeasurement exceptionMeasurement in _lastBuild.exceptions.values) {
|
for (final ExceptionMeasurement exceptionMeasurement in _lastBuild.exceptions.values) {
|
||||||
globals.logger.printError(
|
globals.printError(
|
||||||
exceptionMeasurement.exception.toString(),
|
exceptionMeasurement.exception.toString(),
|
||||||
stackTrace: globals.logger.isVerbose
|
stackTrace: globals.logger.isVerbose
|
||||||
? exceptionMeasurement.stackTrace
|
? exceptionMeasurement.stackTrace
|
||||||
@ -1186,7 +1186,7 @@ abstract class ResidentRunner extends ResidentHandlers {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
globals.logger.printTrace('complete');
|
globals.printTrace('complete');
|
||||||
}
|
}
|
||||||
|
|
||||||
@protected
|
@protected
|
||||||
@ -1241,7 +1241,7 @@ abstract class ResidentRunner extends ResidentHandlers {
|
|||||||
if (_dillOutputPath != null) {
|
if (_dillOutputPath != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
globals.logger.printTrace('Caching compiled dill');
|
globals.printTrace('Caching compiled dill');
|
||||||
final File outputDill = globals.fs.file(dillOutputPath);
|
final File outputDill = globals.fs.file(dillOutputPath);
|
||||||
if (outputDill.existsSync()) {
|
if (outputDill.existsSync()) {
|
||||||
final String copyPath = getDefaultCachedKernelPath(
|
final String copyPath = getDefaultCachedKernelPath(
|
||||||
@ -1561,7 +1561,7 @@ class TerminalHandler {
|
|||||||
_logger.printTrace('Deleting pid file (${_actualPidFile.path}).');
|
_logger.printTrace('Deleting pid file (${_actualPidFile.path}).');
|
||||||
_actualPidFile.deleteSync();
|
_actualPidFile.deleteSync();
|
||||||
} on FileSystemException catch (error) {
|
} on FileSystemException catch (error) {
|
||||||
_logger.printError('Failed to delete pid file (${_actualPidFile.path}): ${error.message}');
|
_logger.printWarning('Failed to delete pid file (${_actualPidFile.path}): ${error.message}');
|
||||||
}
|
}
|
||||||
_actualPidFile = null;
|
_actualPidFile = null;
|
||||||
}
|
}
|
||||||
|
@ -77,8 +77,8 @@ class ColdRunner extends ResidentRunner {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} on Exception catch (err) {
|
} on Exception catch (err, stack) {
|
||||||
globals.printError(err.toString());
|
globals.printError('$err\n$stack');
|
||||||
appFailedToStart();
|
appFailedToStart();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -115,6 +115,7 @@ class FlutterOptions {
|
|||||||
static const String kDeferredComponents = 'deferred-components';
|
static const String kDeferredComponents = 'deferred-components';
|
||||||
static const String kAndroidProjectArgs = 'android-project-arg';
|
static const String kAndroidProjectArgs = 'android-project-arg';
|
||||||
static const String kInitializeFromDill = 'initialize-from-dill';
|
static const String kInitializeFromDill = 'initialize-from-dill';
|
||||||
|
static const String kFatalWarnings = 'fatal-warnings';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// flutter command categories for usage.
|
/// flutter command categories for usage.
|
||||||
@ -178,6 +179,8 @@ abstract class FlutterCommand extends Command<void> {
|
|||||||
|
|
||||||
bool _usesIpv6Flag = false;
|
bool _usesIpv6Flag = false;
|
||||||
|
|
||||||
|
bool _usesFatalWarnings = false;
|
||||||
|
|
||||||
bool get shouldRunPub => _usesPubOption && boolArg('pub');
|
bool get shouldRunPub => _usesPubOption && boolArg('pub');
|
||||||
|
|
||||||
bool get shouldUpdateCache => true;
|
bool get shouldUpdateCache => true;
|
||||||
@ -271,6 +274,15 @@ abstract class FlutterCommand extends Command<void> {
|
|||||||
_usesTargetOption = true;
|
_usesTargetOption = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void usesFatalWarningsOption({ required bool verboseHelp }) {
|
||||||
|
argParser.addFlag(FlutterOptions.kFatalWarnings,
|
||||||
|
hide: !verboseHelp,
|
||||||
|
help: 'Causes the command to fail if warnings are sent to the console '
|
||||||
|
'during its execution.'
|
||||||
|
);
|
||||||
|
_usesFatalWarnings = true;
|
||||||
|
}
|
||||||
|
|
||||||
String get targetFile {
|
String get targetFile {
|
||||||
if (argResults?.wasParsed('target') == true) {
|
if (argResults?.wasParsed('target') == true) {
|
||||||
return stringArg('target')!;
|
return stringArg('target')!;
|
||||||
@ -413,10 +425,10 @@ abstract class FlutterCommand extends Command<void> {
|
|||||||
// TODO(ianh): enable the following code once google3 is migrated away from --disable-dds (and add test to flutter_command_test.dart)
|
// TODO(ianh): enable the following code once google3 is migrated away from --disable-dds (and add test to flutter_command_test.dart)
|
||||||
if (false) { // ignore: dead_code
|
if (false) { // ignore: dead_code
|
||||||
if (ddsEnabled) {
|
if (ddsEnabled) {
|
||||||
globals.printError('${globals.logger.terminal
|
globals.printWarning('${globals.logger.terminal
|
||||||
.warningMark} The "--no-disable-dds" argument is deprecated and redundant, and should be omitted.');
|
.warningMark} The "--no-disable-dds" argument is deprecated and redundant, and should be omitted.');
|
||||||
} else {
|
} else {
|
||||||
globals.printError('${globals.logger.terminal
|
globals.printWarning('${globals.logger.terminal
|
||||||
.warningMark} The "--disable-dds" argument is deprecated. Use "--no-dds" instead.');
|
.warningMark} The "--disable-dds" argument is deprecated. Use "--no-dds" instead.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1123,6 +1135,9 @@ abstract class FlutterCommand extends Command<void> {
|
|||||||
name: 'command',
|
name: 'command',
|
||||||
overrides: <Type, Generator>{FlutterCommand: () => this},
|
overrides: <Type, Generator>{FlutterCommand: () => this},
|
||||||
body: () async {
|
body: () async {
|
||||||
|
if (_usesFatalWarnings) {
|
||||||
|
globals.logger.fatalWarnings = boolArg(FlutterOptions.kFatalWarnings);
|
||||||
|
}
|
||||||
// Prints the welcome message if needed.
|
// Prints the welcome message if needed.
|
||||||
globals.flutterUsage.printWelcome();
|
globals.flutterUsage.printWelcome();
|
||||||
_printDeprecationWarning();
|
_printDeprecationWarning();
|
||||||
@ -1139,6 +1154,9 @@ abstract class FlutterCommand extends Command<void> {
|
|||||||
if (commandPath != null) {
|
if (commandPath != null) {
|
||||||
_sendPostUsage(commandPath, commandResult, startTime, endTime);
|
_sendPostUsage(commandPath, commandResult, startTime, endTime);
|
||||||
}
|
}
|
||||||
|
if (_usesFatalWarnings) {
|
||||||
|
globals.logger.checkForFatalLogs();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -1146,13 +1164,12 @@ abstract class FlutterCommand extends Command<void> {
|
|||||||
|
|
||||||
void _printDeprecationWarning() {
|
void _printDeprecationWarning() {
|
||||||
if (deprecated) {
|
if (deprecated) {
|
||||||
globals.printError(
|
globals.printWarning(
|
||||||
'${globals.logger.terminal.warningMark} The "$name" command is deprecated and '
|
'${globals.logger.terminal.warningMark} The "$name" command is deprecated and '
|
||||||
'will be removed in a future version of Flutter. '
|
'will be removed in a future version of Flutter. '
|
||||||
'See https://flutter.dev/docs/development/tools/sdk/releases '
|
'See https://flutter.dev/docs/development/tools/sdk/releases '
|
||||||
'for previous releases of Flutter.',
|
'for previous releases of Flutter.\n',
|
||||||
);
|
);
|
||||||
globals.printError('');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,10 +277,10 @@ class FlutterVersion {
|
|||||||
);
|
);
|
||||||
} on VersionCheckError catch (error) {
|
} on VersionCheckError catch (error) {
|
||||||
if (globals.platform.environment.containsKey('FLUTTER_GIT_URL')) {
|
if (globals.platform.environment.containsKey('FLUTTER_GIT_URL')) {
|
||||||
globals.logger.printError('Warning: the Flutter git upstream was overridden '
|
globals.printWarning('Warning: the Flutter git upstream was overridden '
|
||||||
'by the environment variable FLUTTER_GIT_URL = ${globals.flutterGit}');
|
'by the environment variable FLUTTER_GIT_URL = ${globals.flutterGit}');
|
||||||
}
|
}
|
||||||
globals.logger.printError(error.toString());
|
globals.printError(error.toString());
|
||||||
rethrow;
|
rethrow;
|
||||||
} finally {
|
} finally {
|
||||||
await _removeVersionCheckRemoteIfExists();
|
await _removeVersionCheckRemoteIfExists();
|
||||||
|
@ -568,6 +568,20 @@ class StreamLogger extends Logger {
|
|||||||
int hangingIndent,
|
int hangingIndent,
|
||||||
bool wrap,
|
bool wrap,
|
||||||
}) {
|
}) {
|
||||||
|
hadErrorOutput = true;
|
||||||
|
_log('[stderr] $message');
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void printWarning(
|
||||||
|
String message, {
|
||||||
|
bool emphasis,
|
||||||
|
TerminalColor color,
|
||||||
|
int indent,
|
||||||
|
int hangingIndent,
|
||||||
|
bool wrap,
|
||||||
|
}) {
|
||||||
|
hadWarningOutput = true;
|
||||||
_log('[stderr] $message');
|
_log('[stderr] $message');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,6 +227,8 @@ void main() {
|
|||||||
const <String>['build', 'linux', '--debug', '--no-pub']
|
const <String>['build', 'linux', '--debug', '--no-pub']
|
||||||
);
|
);
|
||||||
expect(testLogger.statusText, isNot(contains('STDOUT STUFF')));
|
expect(testLogger.statusText, isNot(contains('STDOUT STUFF')));
|
||||||
|
expect(testLogger.warningText, isNot(contains('STDOUT STUFF')));
|
||||||
|
expect(testLogger.errorText, isNot(contains('STDOUT STUFF')));
|
||||||
expect(testLogger.traceText, contains('STDOUT STUFF'));
|
expect(testLogger.traceText, contains('STDOUT STUFF'));
|
||||||
}, overrides: <Type, Generator>{
|
}, overrides: <Type, Generator>{
|
||||||
FileSystem: () => fileSystem,
|
FileSystem: () => fileSystem,
|
||||||
@ -308,6 +310,8 @@ ERROR: No file or variants found for asset: images/a_dot_burr.jpeg
|
|||||||
);
|
);
|
||||||
expect(testLogger.statusText, contains('STDOUT STUFF'));
|
expect(testLogger.statusText, contains('STDOUT STUFF'));
|
||||||
expect(testLogger.traceText, isNot(contains('STDOUT STUFF')));
|
expect(testLogger.traceText, isNot(contains('STDOUT STUFF')));
|
||||||
|
expect(testLogger.warningText, isNot(contains('STDOUT STUFF')));
|
||||||
|
expect(testLogger.errorText, isNot(contains('STDOUT STUFF')));
|
||||||
}, overrides: <Type, Generator>{
|
}, overrides: <Type, Generator>{
|
||||||
FileSystem: () => fileSystem,
|
FileSystem: () => fileSystem,
|
||||||
ProcessManager: () => processManager,
|
ProcessManager: () => processManager,
|
||||||
|
@ -3,9 +3,13 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
// @dart = 2.8
|
// @dart = 2.8
|
||||||
|
|
||||||
import 'package:args/command_runner.dart';
|
import 'package:args/command_runner.dart';
|
||||||
|
import 'package:file/memory.dart';
|
||||||
|
import 'package:flutter_tools/src/base/file_system.dart';
|
||||||
|
import 'package:flutter_tools/src/cache.dart';
|
||||||
|
import 'package:flutter_tools/src/commands/build.dart';
|
||||||
import 'package:flutter_tools/src/runner/flutter_command.dart';
|
import 'package:flutter_tools/src/runner/flutter_command.dart';
|
||||||
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
import '../../src/common.dart';
|
import '../../src/common.dart';
|
||||||
import '../../src/context.dart';
|
import '../../src/context.dart';
|
||||||
@ -13,27 +17,97 @@ import '../../src/test_flutter_command_runner.dart';
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
testUsingContext('obfuscate requires split-debug-info', () {
|
testUsingContext('obfuscate requires split-debug-info', () {
|
||||||
final FakeBuildCommand command = FakeBuildCommand();
|
final FakeBuildInfoCommand command = FakeBuildInfoCommand();
|
||||||
final CommandRunner<void> commandRunner = createTestCommandRunner(command);
|
final CommandRunner<void> commandRunner = createTestCommandRunner(command);
|
||||||
|
|
||||||
expect(() => commandRunner.run(<String>[
|
expect(() => commandRunner.run(<String>[
|
||||||
'build',
|
'fake',
|
||||||
'--obfuscate',
|
'--obfuscate',
|
||||||
]), throwsToolExit());
|
]), throwsToolExit(message: '"--${FlutterOptions.kDartObfuscationOption}" can only be used in '
|
||||||
|
'combination with "--${FlutterOptions.kSplitDebugInfoOption}"'));
|
||||||
|
});
|
||||||
|
group('Fatal Logs', () {
|
||||||
|
FakeBuildCommand command;
|
||||||
|
MemoryFileSystem fs;
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
fs = MemoryFileSystem.test();
|
||||||
|
fs.file('/package/pubspec.yaml').createSync(recursive: true);
|
||||||
|
fs.currentDirectory = '/package';
|
||||||
|
Cache.disableLocking();
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext("doesn't fail if --fatal-warnings specified and no warnings occur", () async {
|
||||||
|
command = FakeBuildCommand();
|
||||||
|
try {
|
||||||
|
await createTestCommandRunner(command).run(<String>[
|
||||||
|
'build',
|
||||||
|
'test',
|
||||||
|
'--${FlutterOptions.kFatalWarnings}',
|
||||||
|
]);
|
||||||
|
} on Exception {
|
||||||
|
fail('Unexpected exception thrown');
|
||||||
|
}
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FileSystem: () => fs,
|
||||||
|
ProcessManager: () => FakeProcessManager.any(),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext("doesn't fail if --fatal-warnings not specified", () async {
|
||||||
|
command = FakeBuildCommand();
|
||||||
|
testLogger.printWarning('Warning: Mild annoyance Will Robinson!');
|
||||||
|
try {
|
||||||
|
await createTestCommandRunner(command).run(<String>[
|
||||||
|
'build',
|
||||||
|
'test',
|
||||||
|
]);
|
||||||
|
} on Exception {
|
||||||
|
fail('Unexpected exception thrown');
|
||||||
|
}
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FileSystem: () => fs,
|
||||||
|
ProcessManager: () => FakeProcessManager.any(),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('fails if --fatal-warnings specified and warnings emitted', () async {
|
||||||
|
command = FakeBuildCommand();
|
||||||
|
testLogger.printWarning('Warning: Mild annoyance Will Robinson!');
|
||||||
|
await expectLater(createTestCommandRunner(command).run(<String>[
|
||||||
|
'build',
|
||||||
|
'test',
|
||||||
|
'--${FlutterOptions.kFatalWarnings}',
|
||||||
|
]), throwsToolExit(message: 'Logger received warning output during the run, and "--${FlutterOptions.kFatalWarnings}" is enabled.'));
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FileSystem: () => fs,
|
||||||
|
ProcessManager: () => FakeProcessManager.any(),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('fails if --fatal-warnings specified and errors emitted', () async {
|
||||||
|
command = FakeBuildCommand();
|
||||||
|
testLogger.printError('Error: Danger Will Robinson!');
|
||||||
|
await expectLater(createTestCommandRunner(command).run(<String>[
|
||||||
|
'build',
|
||||||
|
'test',
|
||||||
|
'--${FlutterOptions.kFatalWarnings}',
|
||||||
|
]), throwsToolExit(message: 'Logger received error output during the run, and "--${FlutterOptions.kFatalWarnings}" is enabled.'));
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FileSystem: () => fs,
|
||||||
|
ProcessManager: () => FakeProcessManager.any(),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class FakeBuildCommand extends FlutterCommand {
|
class FakeBuildInfoCommand extends FlutterCommand {
|
||||||
FakeBuildCommand() {
|
FakeBuildInfoCommand() : super() {
|
||||||
addSplitDebugInfoOption();
|
addSplitDebugInfoOption();
|
||||||
addDartObfuscationOption();
|
addDartObfuscationOption();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get description => throw UnimplementedError();
|
String get description => '';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get name => 'build';
|
String get name => 'fake';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<FlutterCommandResult> runCommand() async {
|
Future<FlutterCommandResult> runCommand() async {
|
||||||
@ -41,3 +115,35 @@ class FakeBuildCommand extends FlutterCommand {
|
|||||||
return FlutterCommandResult.success();
|
return FlutterCommandResult.success();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FakeBuildCommand extends BuildCommand {
|
||||||
|
FakeBuildCommand({bool verboseHelp = false}) : super(verboseHelp: verboseHelp) {
|
||||||
|
addSubcommand(FakeBuildSubcommand(verboseHelp: verboseHelp));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get description => '';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get name => 'build';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<FlutterCommandResult> runCommand() async {
|
||||||
|
return FlutterCommandResult.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FakeBuildSubcommand extends BuildSubCommand {
|
||||||
|
FakeBuildSubcommand({@required bool verboseHelp}) : super(verboseHelp: verboseHelp);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get description => '';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get name => 'test';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<FlutterCommandResult> runCommand() async {
|
||||||
|
return FlutterCommandResult.success();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -130,6 +130,29 @@ void main() {
|
|||||||
Logger: () => notifyingLogger,
|
Logger: () => notifyingLogger,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testUsingContext('printWarning should send daemon.logMessage event', () async {
|
||||||
|
final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>();
|
||||||
|
final StreamController<Map<String, dynamic>> responses = StreamController<Map<String, dynamic>>();
|
||||||
|
daemon = Daemon(
|
||||||
|
commands.stream,
|
||||||
|
responses.add,
|
||||||
|
notifyingLogger: notifyingLogger,
|
||||||
|
);
|
||||||
|
globals.printWarning('daemon.logMessage test');
|
||||||
|
final Map<String, dynamic> response = await responses.stream.firstWhere((Map<String, dynamic> map) {
|
||||||
|
return map['event'] == 'daemon.logMessage' && (map['params'] as Map<String, dynamic>)['level'] == 'warning';
|
||||||
|
});
|
||||||
|
expect(response['id'], isNull);
|
||||||
|
expect(response['event'], 'daemon.logMessage');
|
||||||
|
final Map<String, String> logMessage = castStringKeyedMap(response['params']).cast<String, String>();
|
||||||
|
expect(logMessage['level'], 'warning');
|
||||||
|
expect(logMessage['message'], 'daemon.logMessage test');
|
||||||
|
await responses.close();
|
||||||
|
await commands.close();
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
Logger: () => notifyingLogger,
|
||||||
|
});
|
||||||
|
|
||||||
testUsingContext('printStatus should log to stdout when logToStdout is enabled', () async {
|
testUsingContext('printStatus should log to stdout when logToStdout is enabled', () async {
|
||||||
final StringBuffer buffer = await capturedConsolePrint(() {
|
final StringBuffer buffer = await capturedConsolePrint(() {
|
||||||
final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>();
|
final StreamController<Map<String, dynamic>> commands = StreamController<Map<String, dynamic>>();
|
||||||
|
@ -294,6 +294,75 @@ void main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group('Fatal Logs', () {
|
||||||
|
TestRunCommandWithFakeResidentRunner command;
|
||||||
|
MemoryFileSystem fs;
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
command = TestRunCommandWithFakeResidentRunner()
|
||||||
|
..fakeResidentRunner = FakeResidentRunner();
|
||||||
|
fs = MemoryFileSystem.test();
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext("doesn't fail if --fatal-warnings specified and no warnings occur", () async {
|
||||||
|
try {
|
||||||
|
await createTestCommandRunner(command).run(<String>[
|
||||||
|
'run',
|
||||||
|
'--no-pub',
|
||||||
|
'--no-hot',
|
||||||
|
'--${FlutterOptions.kFatalWarnings}',
|
||||||
|
]);
|
||||||
|
} on Exception {
|
||||||
|
fail('Unexpected exception thrown');
|
||||||
|
}
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FileSystem: () => fs,
|
||||||
|
ProcessManager: () => FakeProcessManager.any(),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext("doesn't fail if --fatal-warnings not specified", () async {
|
||||||
|
testLogger.printWarning('Warning: Mild annoyance Will Robinson!');
|
||||||
|
try {
|
||||||
|
await createTestCommandRunner(command).run(<String>[
|
||||||
|
'run',
|
||||||
|
'--no-pub',
|
||||||
|
'--no-hot',
|
||||||
|
]);
|
||||||
|
} on Exception {
|
||||||
|
fail('Unexpected exception thrown');
|
||||||
|
}
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FileSystem: () => fs,
|
||||||
|
ProcessManager: () => FakeProcessManager.any(),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('fails if --fatal-warnings specified and warnings emitted', () async {
|
||||||
|
testLogger.printWarning('Warning: Mild annoyance Will Robinson!');
|
||||||
|
await expectLater(createTestCommandRunner(command).run(<String>[
|
||||||
|
'run',
|
||||||
|
'--no-pub',
|
||||||
|
'--no-hot',
|
||||||
|
'--${FlutterOptions.kFatalWarnings}',
|
||||||
|
]), throwsToolExit(message: 'Logger received warning output during the run, and "--${FlutterOptions.kFatalWarnings}" is enabled.'));
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FileSystem: () => fs,
|
||||||
|
ProcessManager: () => FakeProcessManager.any(),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('fails if --fatal-warnings specified and errors emitted', () async {
|
||||||
|
testLogger.printError('Error: Danger Will Robinson!');
|
||||||
|
await expectLater(createTestCommandRunner(command).run(<String>[
|
||||||
|
'run',
|
||||||
|
'--no-pub',
|
||||||
|
'--no-hot',
|
||||||
|
'--${FlutterOptions.kFatalWarnings}',
|
||||||
|
]), throwsToolExit(message: 'Logger received error output during the run, and "--${FlutterOptions.kFatalWarnings}" is enabled.'));
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FileSystem: () => fs,
|
||||||
|
ProcessManager: () => FakeProcessManager.any(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
testUsingContext('should only request artifacts corresponding to connected devices', () async {
|
testUsingContext('should only request artifacts corresponding to connected devices', () async {
|
||||||
mockDeviceManager.devices = <Device>[FakeDevice(targetPlatform: TargetPlatform.android_arm)];
|
mockDeviceManager.devices = <Device>[FakeDevice(targetPlatform: TargetPlatform.android_arm)];
|
||||||
|
|
||||||
@ -496,7 +565,7 @@ class FakeDevice extends Fake implements Device {
|
|||||||
@override
|
@override
|
||||||
String get id => 'fake_device';
|
String get id => 'fake_device';
|
||||||
|
|
||||||
void _throwToolExit(int code) => throwToolExit(null, exitCode: code);
|
void _throwToolExit(int code) => throwToolExit('FakeDevice tool exit', exitCode: code);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> get isLocalEmulator => Future<bool>.value(_isLocalEmulator);
|
Future<bool> get isLocalEmulator => Future<bool>.value(_isLocalEmulator);
|
||||||
@ -504,6 +573,9 @@ class FakeDevice extends Fake implements Device {
|
|||||||
@override
|
@override
|
||||||
bool supportsRuntimeMode(BuildMode mode) => true;
|
bool supportsRuntimeMode(BuildMode mode) => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> get supportsHardwareRendering async => true;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool supportsHotReload = false;
|
bool supportsHotReload = false;
|
||||||
|
|
||||||
@ -542,7 +614,7 @@ class FakeDevice extends Fake implements Device {
|
|||||||
@override
|
@override
|
||||||
final PlatformType platformType = PlatformType.ios;
|
final PlatformType platformType = PlatformType.ios;
|
||||||
|
|
||||||
bool startAppSuccess = true;
|
bool startAppSuccess;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
DevFSWriter createDevFSWriter(
|
DevFSWriter createDevFSWriter(
|
||||||
@ -564,9 +636,12 @@ class FakeDevice extends Fake implements Device {
|
|||||||
bool ipv6 = false,
|
bool ipv6 = false,
|
||||||
String userIdentifier,
|
String userIdentifier,
|
||||||
}) async {
|
}) async {
|
||||||
if (!startAppSuccess) {
|
if (startAppSuccess == false) {
|
||||||
return LaunchResult.failed();
|
return LaunchResult.failed();
|
||||||
}
|
}
|
||||||
|
if (startAppSuccess == true) {
|
||||||
|
return LaunchResult.succeeded();
|
||||||
|
}
|
||||||
final String dartFlags = debuggingOptions.dartFlags;
|
final String dartFlags = debuggingOptions.dartFlags;
|
||||||
// In release mode, --dart-flags should be set to the empty string and
|
// In release mode, --dart-flags should be set to the empty string and
|
||||||
// provided flags should be dropped. In debug and profile modes,
|
// provided flags should be dropped. In debug and profile modes,
|
||||||
@ -587,18 +662,20 @@ class FakeDevice extends Fake implements Device {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FakeApplicationPackageFactory extends Fake implements ApplicationPackageFactory {
|
class FakeApplicationPackageFactory extends Fake implements ApplicationPackageFactory {
|
||||||
ApplicationPackage package;
|
FakeApplicationPackageFactory(this.applicationPackage);
|
||||||
|
|
||||||
|
ApplicationPackage applicationPackage;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<ApplicationPackage> getPackageForPlatform(
|
Future<ApplicationPackage> getPackageForPlatform(
|
||||||
TargetPlatform platform, {
|
TargetPlatform platform, {
|
||||||
BuildInfo buildInfo,
|
BuildInfo buildInfo,
|
||||||
File applicationBinary,
|
File applicationBinary,
|
||||||
}) async {
|
}) async => applicationPackage;
|
||||||
return package;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FakeApplicationPackage extends Fake implements ApplicationPackage { }
|
||||||
|
|
||||||
class TestRunCommandWithFakeResidentRunner extends RunCommand {
|
class TestRunCommandWithFakeResidentRunner extends RunCommand {
|
||||||
FakeResidentRunner fakeResidentRunner;
|
FakeResidentRunner fakeResidentRunner;
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ import 'package:flutter_tools/src/cache.dart';
|
|||||||
import 'package:flutter_tools/src/commands/test.dart';
|
import 'package:flutter_tools/src/commands/test.dart';
|
||||||
import 'package:flutter_tools/src/device.dart';
|
import 'package:flutter_tools/src/device.dart';
|
||||||
import 'package:flutter_tools/src/project.dart';
|
import 'package:flutter_tools/src/project.dart';
|
||||||
|
import 'package:flutter_tools/src/runner/flutter_command.dart';
|
||||||
import 'package:flutter_tools/src/test/runner.dart';
|
import 'package:flutter_tools/src/test/runner.dart';
|
||||||
import 'package:flutter_tools/src/test/test_wrapper.dart';
|
import 'package:flutter_tools/src/test/test_wrapper.dart';
|
||||||
import 'package:flutter_tools/src/test/watcher.dart';
|
import 'package:flutter_tools/src/test/watcher.dart';
|
||||||
@ -644,6 +645,60 @@ dev_dependencies:
|
|||||||
ProcessManager: () => FakeProcessManager.any(),
|
ProcessManager: () => FakeProcessManager.any(),
|
||||||
DeviceManager: () => _FakeDeviceManager(<Device>[]),
|
DeviceManager: () => _FakeDeviceManager(<Device>[]),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group('Fatal Logs', () {
|
||||||
|
testUsingContext("doesn't fail when --fatal-warnings is set and no warning output", () async {
|
||||||
|
final FakeFlutterTestRunner testRunner = FakeFlutterTestRunner(0);
|
||||||
|
|
||||||
|
final TestCommand testCommand = TestCommand(testRunner: testRunner);
|
||||||
|
final CommandRunner<void> commandRunner = createTestCommandRunner(testCommand);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await commandRunner.run(const <String>[
|
||||||
|
'test',
|
||||||
|
'--no-pub',
|
||||||
|
'--${FlutterOptions.kFatalWarnings}',
|
||||||
|
]);
|
||||||
|
} on Exception {
|
||||||
|
fail('Unexpected exception thrown');
|
||||||
|
}
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FileSystem: () => fs,
|
||||||
|
ProcessManager: () => FakeProcessManager.any(),
|
||||||
|
});
|
||||||
|
testUsingContext('fails if --fatal-warnings specified and warnings emitted', () async {
|
||||||
|
final FakeFlutterTestRunner testRunner = FakeFlutterTestRunner(0);
|
||||||
|
|
||||||
|
final TestCommand testCommand = TestCommand(testRunner: testRunner);
|
||||||
|
final CommandRunner<void> commandRunner = createTestCommandRunner(testCommand);
|
||||||
|
|
||||||
|
testLogger.printWarning('Warning: Mild annoyance, Will Robinson!');
|
||||||
|
expect(commandRunner.run(const <String>[
|
||||||
|
'test',
|
||||||
|
'--no-pub',
|
||||||
|
'--${FlutterOptions.kFatalWarnings}',
|
||||||
|
]), throwsToolExit(message: 'Logger received warning output during the run, and "--${FlutterOptions.kFatalWarnings}" is enabled.'));
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FileSystem: () => fs,
|
||||||
|
ProcessManager: () => FakeProcessManager.any(),
|
||||||
|
});
|
||||||
|
testUsingContext('fails when --fatal-warnings is set and only errors emitted', () async {
|
||||||
|
final FakeFlutterTestRunner testRunner = FakeFlutterTestRunner(0);
|
||||||
|
|
||||||
|
final TestCommand testCommand = TestCommand(testRunner: testRunner);
|
||||||
|
final CommandRunner<void> commandRunner = createTestCommandRunner(testCommand);
|
||||||
|
|
||||||
|
testLogger.printError('Error: Danger Will Robinson!');
|
||||||
|
expect(commandRunner.run(const <String>[
|
||||||
|
'test',
|
||||||
|
'--no-pub',
|
||||||
|
'--${FlutterOptions.kFatalWarnings}',
|
||||||
|
]), throwsToolExit(message: 'Logger received error output during the run, and "--${FlutterOptions.kFatalWarnings}" is enabled.'));
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
FileSystem: () => fs,
|
||||||
|
ProcessManager: () => FakeProcessManager.any(),
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class FakeFlutterTestRunner implements FlutterTestRunner {
|
class FakeFlutterTestRunner implements FlutterTestRunner {
|
||||||
|
@ -311,7 +311,7 @@ flutter:
|
|||||||
|
|
||||||
await writeBundle(directory, <String, DevFSContent>{}, loggerOverride: testLogger);
|
await writeBundle(directory, <String, DevFSContent>{}, loggerOverride: testLogger);
|
||||||
|
|
||||||
expect(testLogger.errorText, contains('Expected Error Text'));
|
expect(testLogger.warningText, contains('Expected Error Text'));
|
||||||
});
|
});
|
||||||
|
|
||||||
testUsingContext('does not unnecessarily recreate asset manifest, font manifest, license', () async {
|
testUsingContext('does not unnecessarily recreate asset manifest, font manifest, license', () async {
|
||||||
|
@ -137,7 +137,7 @@ void main() {
|
|||||||
final FakeSimpleArtifact artifact = FakeSimpleArtifact(cache);
|
final FakeSimpleArtifact artifact = FakeSimpleArtifact(cache);
|
||||||
await artifact.update(FakeArtifactUpdater(), logger, fileSystem, FakeOperatingSystemUtils());
|
await artifact.update(FakeArtifactUpdater(), logger, fileSystem, FakeOperatingSystemUtils());
|
||||||
|
|
||||||
expect(logger.errorText, contains('stamp write failed'));
|
expect(logger.warningText, contains('stamp write failed'));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('Continues on missing version file', () async {
|
testWithoutContext('Continues on missing version file', () async {
|
||||||
@ -153,7 +153,7 @@ void main() {
|
|||||||
final FakeSimpleArtifact artifact = FakeSimpleArtifact(cache);
|
final FakeSimpleArtifact artifact = FakeSimpleArtifact(cache);
|
||||||
await artifact.update(FakeArtifactUpdater(), logger, fileSystem, FakeOperatingSystemUtils());
|
await artifact.update(FakeArtifactUpdater(), logger, fileSystem, FakeOperatingSystemUtils());
|
||||||
|
|
||||||
expect(logger.errorText, contains('No known version for the artifact name "fake"'));
|
expect(logger.warningText, contains('No known version for the artifact name "fake"'));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('Gradle wrapper should not be up to date, if some cached artifact is not available', () {
|
testWithoutContext('Gradle wrapper should not be up to date, if some cached artifact is not available', () {
|
||||||
@ -725,7 +725,7 @@ void main() {
|
|||||||
|
|
||||||
cache.clearStampFiles();
|
cache.clearStampFiles();
|
||||||
|
|
||||||
expect(logger.errorText, contains('Failed to delete some stamp files'));
|
expect(logger.warningText, contains('Failed to delete some stamp files'));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('FlutterWebSdk fetches web artifacts and deletes previous directory contents', () async {
|
testWithoutContext('FlutterWebSdk fetches web artifacts and deletes previous directory contents', () async {
|
||||||
|
@ -83,6 +83,8 @@ void main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FakeBuildSubCommand extends BuildSubCommand {
|
class FakeBuildSubCommand extends BuildSubCommand {
|
||||||
|
FakeBuildSubCommand() : super(verboseHelp: false);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get description => throw UnimplementedError();
|
String get description => throw UnimplementedError();
|
||||||
|
|
||||||
|
@ -432,8 +432,8 @@ void main() {
|
|||||||
buildMode: BuildMode.debug,
|
buildMode: BuildMode.debug,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(logger.errorText, contains('Warning: Podfile is out of date'));
|
expect(logger.warningText, contains('Warning: Podfile is out of date'));
|
||||||
expect(logger.errorText, contains('rm macos/Podfile'));
|
expect(logger.warningText, contains('rm macos/Podfile'));
|
||||||
expect(fakeProcessManager, hasNoRemainingExpectations);
|
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -747,7 +747,7 @@ dependencies:
|
|||||||
.childFile('GeneratedPluginRegistrant.java');
|
.childFile('GeneratedPluginRegistrant.java');
|
||||||
expect(registrant.readAsStringSync(),
|
expect(registrant.readAsStringSync(),
|
||||||
contains('plugin3.UseOldEmbedding.registerWith(shimPluginRegistry.registrarFor("plugin3.UseOldEmbedding"));'));
|
contains('plugin3.UseOldEmbedding.registerWith(shimPluginRegistry.registrarFor("plugin3.UseOldEmbedding"));'));
|
||||||
expect(testLogger.errorText, equals(
|
expect(testLogger.warningText, equals(
|
||||||
'The plugin `plugin3` uses a deprecated version of the Android embedding.\n'
|
'The plugin `plugin3` uses a deprecated version of the Android embedding.\n'
|
||||||
'To avoid unexpected runtime failures, or future build failures, try to see if this plugin supports the Android V2 embedding. '
|
'To avoid unexpected runtime failures, or future build failures, try to see if this plugin supports the Android V2 embedding. '
|
||||||
'Otherwise, consider removing it since a future release of Flutter will remove these deprecated APIs.\n'
|
'Otherwise, consider removing it since a future release of Flutter will remove these deprecated APIs.\n'
|
||||||
@ -827,7 +827,7 @@ dependencies:
|
|||||||
|
|
||||||
await injectPlugins(flutterProject, androidPlatform: true);
|
await injectPlugins(flutterProject, androidPlatform: true);
|
||||||
|
|
||||||
expect(testLogger.errorText, equals(
|
expect(testLogger.warningText, equals(
|
||||||
'This app is using a deprecated version of the Android embedding.\n'
|
'This app is using a deprecated version of the Android embedding.\n'
|
||||||
'To avoid unexpected runtime failures, or future build failures, try to migrate this app to the V2 embedding.\n'
|
'To avoid unexpected runtime failures, or future build failures, try to migrate this app to the V2 embedding.\n'
|
||||||
'Take a look at the docs for migrating an app: https://github.com/flutter/flutter/wiki/Upgrading-pre-1.12-Android-projects\n'
|
'Take a look at the docs for migrating an app: https://github.com/flutter/flutter/wiki/Upgrading-pre-1.12-Android-projects\n'
|
||||||
@ -854,7 +854,7 @@ dependencies:
|
|||||||
contains('plugin3.UseOldEmbedding.registerWith(shimPluginRegistry.registrarFor("plugin3.UseOldEmbedding"));'));
|
contains('plugin3.UseOldEmbedding.registerWith(shimPluginRegistry.registrarFor("plugin3.UseOldEmbedding"));'));
|
||||||
expect(registrant.readAsStringSync(),
|
expect(registrant.readAsStringSync(),
|
||||||
contains('plugin4.UseOldEmbedding.registerWith(shimPluginRegistry.registrarFor("plugin4.UseOldEmbedding"));'));
|
contains('plugin4.UseOldEmbedding.registerWith(shimPluginRegistry.registrarFor("plugin4.UseOldEmbedding"));'));
|
||||||
expect(testLogger.errorText, equals(
|
expect(testLogger.warningText, equals(
|
||||||
'The plugins `plugin3, plugin4` use a deprecated version of the Android embedding.\n'
|
'The plugins `plugin3, plugin4` use a deprecated version of the Android embedding.\n'
|
||||||
'To avoid unexpected runtime failures, or future build failures, try to see if these plugins support the Android V2 embedding. '
|
'To avoid unexpected runtime failures, or future build failures, try to see if these plugins support the Android V2 embedding. '
|
||||||
'Otherwise, consider removing them since a future release of Flutter will remove these deprecated APIs.\n'
|
'Otherwise, consider removing them since a future release of Flutter will remove these deprecated APIs.\n'
|
||||||
@ -882,7 +882,7 @@ dependencies:
|
|||||||
contains('plugin3.UseOldEmbedding.registerWith(shimPluginRegistry.registrarFor("plugin3.UseOldEmbedding"));'));
|
contains('plugin3.UseOldEmbedding.registerWith(shimPluginRegistry.registrarFor("plugin3.UseOldEmbedding"));'));
|
||||||
expect(registrant.readAsStringSync(),
|
expect(registrant.readAsStringSync(),
|
||||||
contains('plugin4.UseOldEmbedding.registerWith(shimPluginRegistry.registrarFor("plugin4.UseOldEmbedding"));'));
|
contains('plugin4.UseOldEmbedding.registerWith(shimPluginRegistry.registrarFor("plugin4.UseOldEmbedding"));'));
|
||||||
expect(testLogger.errorText, equals(
|
expect(testLogger.warningText, equals(
|
||||||
'The plugins `plugin3, plugin4` use a deprecated version of the Android embedding.\n'
|
'The plugins `plugin3, plugin4` use a deprecated version of the Android embedding.\n'
|
||||||
'To avoid unexpected runtime failures, or future build failures, try to see if these plugins support the Android V2 embedding. '
|
'To avoid unexpected runtime failures, or future build failures, try to see if these plugins support the Android V2 embedding. '
|
||||||
'Otherwise, consider removing them since a future release of Flutter will remove these deprecated APIs.\n'
|
'Otherwise, consider removing them since a future release of Flutter will remove these deprecated APIs.\n'
|
||||||
|
@ -183,7 +183,7 @@ void main() {
|
|||||||
// android:name="flutterEmbedding" android:value="2" />.
|
// android:name="flutterEmbedding" android:value="2" />.
|
||||||
|
|
||||||
await project.regeneratePlatformSpecificTooling();
|
await project.regeneratePlatformSpecificTooling();
|
||||||
expect(testLogger.statusText, contains('https://flutter.dev/go/android-project-migration'));
|
expect(testLogger.warningText, contains('https://github.com/flutter/flutter/wiki/Upgrading-pre-1.12-Android-projects'));
|
||||||
});
|
});
|
||||||
_testInMemory('Android plugin without example app does not show a warning', () async {
|
_testInMemory('Android plugin without example app does not show a warning', () async {
|
||||||
final FlutterProject project = await aPluginProject();
|
final FlutterProject project = await aPluginProject();
|
||||||
|
@ -87,7 +87,7 @@ void main() {
|
|||||||
final CommandRunner<void> runner = createTestCommandRunner(flutterCommand);
|
final CommandRunner<void> runner = createTestCommandRunner(flutterCommand);
|
||||||
await runner.run(<String>['deprecated']);
|
await runner.run(<String>['deprecated']);
|
||||||
|
|
||||||
expect(testLogger.errorText,
|
expect(testLogger.warningText,
|
||||||
contains('The "deprecated" command is deprecated and will be removed in '
|
contains('The "deprecated" command is deprecated and will be removed in '
|
||||||
'a future version of Flutter.'));
|
'a future version of Flutter.'));
|
||||||
expect(flutterCommand.usage,
|
expect(flutterCommand.usage,
|
||||||
|
@ -129,7 +129,7 @@ void main() {
|
|||||||
|
|
||||||
// We get a warning about the unexpected package.
|
// We get a warning about the unexpected package.
|
||||||
expect(
|
expect(
|
||||||
bufferLogger.errorText,
|
bufferLogger.warningText,
|
||||||
contains("Unexpected package 'extra' found in packages directory"),
|
contains("Unexpected package 'extra' found in packages directory"),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -10,12 +10,15 @@ import 'package:file/file.dart';
|
|||||||
import 'package:flutter_tools/src/base/file_system.dart';
|
import 'package:flutter_tools/src/base/file_system.dart';
|
||||||
import 'package:flutter_tools/src/base/io.dart';
|
import 'package:flutter_tools/src/base/io.dart';
|
||||||
import 'package:flutter_tools/src/base/logger.dart';
|
import 'package:flutter_tools/src/base/logger.dart';
|
||||||
|
import 'package:flutter_tools/src/base/os.dart';
|
||||||
import 'package:flutter_tools/src/base/terminal.dart';
|
import 'package:flutter_tools/src/base/terminal.dart';
|
||||||
import 'package:flutter_tools/src/cache.dart';
|
import 'package:flutter_tools/src/cache.dart';
|
||||||
import 'package:process/process.dart';
|
import 'package:process/process.dart';
|
||||||
|
import 'package:test/fake.dart';
|
||||||
|
|
||||||
import '../src/common.dart';
|
import '../src/common.dart';
|
||||||
import '../src/context.dart';
|
import '../src/context.dart';
|
||||||
|
import '../src/fakes.dart';
|
||||||
import 'test_utils.dart';
|
import 'test_utils.dart';
|
||||||
|
|
||||||
final String dart = fileSystem.path
|
final String dart = fileSystem.path
|
||||||
@ -24,53 +27,122 @@ final String dart = fileSystem.path
|
|||||||
void main() {
|
void main() {
|
||||||
group('Cache.lock', () {
|
group('Cache.lock', () {
|
||||||
// Windows locking is too flaky for this to work reliably.
|
// Windows locking is too flaky for this to work reliably.
|
||||||
if (!platform.isWindows) {
|
if (platform.isWindows) {
|
||||||
testWithoutContext(
|
return;
|
||||||
'should log a message to stderr when lock is not acquired', () async {
|
}
|
||||||
final String oldRoot = Cache.flutterRoot;
|
testWithoutContext(
|
||||||
final Directory tempDir = fileSystem.systemTempDirectory.createTempSync('cache_test.');
|
'should log a message to stderr when lock is not acquired', () async {
|
||||||
final BufferLogger logger = BufferLogger(
|
final String oldRoot = Cache.flutterRoot;
|
||||||
terminal: Terminal.test(supportsColor: false, supportsEmoji: false),
|
final Directory tempDir = fileSystem.systemTempDirectory.createTempSync('cache_test.');
|
||||||
outputPreferences: OutputPreferences(),
|
final BufferLogger logger = BufferLogger(
|
||||||
|
terminal: Terminal.test(supportsColor: false, supportsEmoji: false),
|
||||||
|
outputPreferences: OutputPreferences(),
|
||||||
|
);
|
||||||
|
logger.fatalWarnings = true;
|
||||||
|
try {
|
||||||
|
Cache.flutterRoot = tempDir.absolute.path;
|
||||||
|
final Cache cache = Cache.test(
|
||||||
|
fileSystem: fileSystem,
|
||||||
|
processManager: FakeProcessManager.any(),
|
||||||
|
logger: logger,
|
||||||
);
|
);
|
||||||
try {
|
final File cacheFile = fileSystem.file(fileSystem.path
|
||||||
Cache.flutterRoot = tempDir.absolute.path;
|
.join(Cache.flutterRoot, 'bin', 'cache', 'lockfile'))
|
||||||
final Cache cache = Cache.test(
|
..createSync(recursive: true);
|
||||||
fileSystem: fileSystem,
|
final File script = fileSystem.file(fileSystem.path
|
||||||
processManager: FakeProcessManager.any(),
|
.join(Cache.flutterRoot, 'bin', 'cache', 'test_lock.dart'));
|
||||||
logger: logger,
|
script.writeAsStringSync(r'''
|
||||||
);
|
|
||||||
final File cacheFile = fileSystem.file(fileSystem.path
|
|
||||||
.join(Cache.flutterRoot, 'bin', 'cache', 'lockfile'))
|
|
||||||
..createSync(recursive: true);
|
|
||||||
final File script = fileSystem.file(fileSystem.path
|
|
||||||
.join(Cache.flutterRoot, 'bin', 'cache', 'test_lock.dart'));
|
|
||||||
script.writeAsStringSync(r'''
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
Future<void> main(List<String> args) async {
|
Future<void> main(List<String> args) async {
|
||||||
File file = File(args[0]);
|
File file = File(args[0]);
|
||||||
RandomAccessFile lock = file.openSync(mode: FileMode.write);
|
RandomAccessFile lock = file.openSync(mode: FileMode.write);
|
||||||
lock.lockSync();
|
lock.lockSync();
|
||||||
await Future<void>.delayed(const Duration(milliseconds: 1000));
|
await Future<void>.delayed(const Duration(milliseconds: 1000));
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
''');
|
''');
|
||||||
final Process process = await const LocalProcessManager().start(
|
final Process process = await const LocalProcessManager().start(
|
||||||
<String>[dart, script.absolute.path, cacheFile.absolute.path],
|
<String>[dart, script.absolute.path, cacheFile.absolute.path],
|
||||||
);
|
);
|
||||||
await Future<void>.delayed(const Duration(milliseconds: 500));
|
await Future<void>.delayed(const Duration(milliseconds: 500));
|
||||||
await cache.lock();
|
await cache.lock();
|
||||||
process.kill(io.ProcessSignal.sigkill);
|
process.kill(io.ProcessSignal.sigkill);
|
||||||
} finally {
|
} finally {
|
||||||
tryToDelete(tempDir);
|
tryToDelete(tempDir);
|
||||||
Cache.flutterRoot = oldRoot;
|
Cache.flutterRoot = oldRoot;
|
||||||
}
|
}
|
||||||
expect(logger.statusText, isEmpty);
|
expect(logger.statusText, isEmpty);
|
||||||
expect(logger.errorText,
|
expect(logger.errorText, isEmpty);
|
||||||
equals('Waiting for another flutter command to release the startup lock...\n'));
|
expect(logger.warningText,
|
||||||
});
|
equals('Waiting for another flutter command to release the startup lock...\n'));
|
||||||
}
|
expect(logger.hadErrorOutput, isFalse);
|
||||||
|
// Should still be false, since the particular "Waiting..." message above aims to
|
||||||
|
// avoid triggering failure as a fatal warning.
|
||||||
|
expect(logger.hadWarningOutput, isFalse);
|
||||||
|
});
|
||||||
|
testWithoutContext(
|
||||||
|
'should log a warning message for unknown version ', () async {
|
||||||
|
final String oldRoot = Cache.flutterRoot;
|
||||||
|
final Directory tempDir = fileSystem.systemTempDirectory.createTempSync('cache_test.');
|
||||||
|
final BufferLogger logger = BufferLogger(
|
||||||
|
terminal: Terminal.test(supportsColor: false, supportsEmoji: false),
|
||||||
|
outputPreferences: OutputPreferences(),
|
||||||
|
);
|
||||||
|
logger.fatalWarnings = true;
|
||||||
|
try {
|
||||||
|
Cache.flutterRoot = tempDir.absolute.path;
|
||||||
|
final Cache cache = Cache.test(
|
||||||
|
fileSystem: fileSystem,
|
||||||
|
processManager: FakeProcessManager.any(),
|
||||||
|
logger: logger,
|
||||||
|
);
|
||||||
|
final FakeVersionlessArtifact artifact = FakeVersionlessArtifact(cache);
|
||||||
|
cache.registerArtifact(artifact);
|
||||||
|
await artifact.update(FakeArtifactUpdater(), logger, fileSystem, FakeOperatingSystemUtils());
|
||||||
|
} finally {
|
||||||
|
tryToDelete(tempDir);
|
||||||
|
Cache.flutterRoot = oldRoot;
|
||||||
|
}
|
||||||
|
expect(logger.statusText, isEmpty);
|
||||||
|
expect(logger.warningText, equals('No known version for the artifact name "fake". '
|
||||||
|
'Flutter can continue, but the artifact may be re-downloaded on '
|
||||||
|
'subsequent invocations until the problem is resolved.\n'));
|
||||||
|
expect(logger.hadErrorOutput, isFalse);
|
||||||
|
expect(logger.hadWarningOutput, isTrue);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FakeArtifactUpdater extends Fake implements ArtifactUpdater {
|
||||||
|
void Function(String, Uri, Directory) onDownloadZipArchive;
|
||||||
|
void Function(String, Uri, Directory) onDownloadZipTarball;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> downloadZippedTarball(String message, Uri url, Directory location) async {
|
||||||
|
onDownloadZipTarball?.call(message, url, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> downloadZipArchive(String message, Uri url, Directory location) async {
|
||||||
|
onDownloadZipArchive?.call(message, url, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void removeDownloadedFiles() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
class FakeVersionlessArtifact extends CachedArtifact {
|
||||||
|
FakeVersionlessArtifact(Cache cache) : super(
|
||||||
|
'fake',
|
||||||
|
cache,
|
||||||
|
DevelopmentArtifact.universal,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get version => null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> updateInner(ArtifactUpdater artifactUpdater, FileSystem fileSystem, OperatingSystemUtils operatingSystemUtils) async { }
|
||||||
|
}
|
||||||
|
@ -115,84 +115,66 @@ void main() {
|
|||||||
testWithoutContext('flutter test should run a test when its name matches a regexp', () async {
|
testWithoutContext('flutter test should run a test when its name matches a regexp', () async {
|
||||||
final ProcessResult result = await _runFlutterTest('filtering', automatedTestsDirectory, flutterTestDirectory,
|
final ProcessResult result = await _runFlutterTest('filtering', automatedTestsDirectory, flutterTestDirectory,
|
||||||
extraArguments: const <String>['--name', 'inc.*de']);
|
extraArguments: const <String>['--name', 'inc.*de']);
|
||||||
if (!(result.stdout as String).contains('+1: All tests passed')) {
|
expect(result.stdout, contains(RegExp(r'\+\d+: All tests passed!')));
|
||||||
fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n');
|
|
||||||
}
|
|
||||||
expect(result.exitCode, 0);
|
expect(result.exitCode, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('flutter test should run a test when its name contains a string', () async {
|
testWithoutContext('flutter test should run a test when its name contains a string', () async {
|
||||||
final ProcessResult result = await _runFlutterTest('filtering', automatedTestsDirectory, flutterTestDirectory,
|
final ProcessResult result = await _runFlutterTest('filtering', automatedTestsDirectory, flutterTestDirectory,
|
||||||
extraArguments: const <String>['--plain-name', 'include']);
|
extraArguments: const <String>['--plain-name', 'include']);
|
||||||
if (!(result.stdout as String).contains('+1: All tests passed')) {
|
expect(result.stdout, contains(RegExp(r'\+\d+: All tests passed!')));
|
||||||
fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n');
|
|
||||||
}
|
|
||||||
expect(result.exitCode, 0);
|
expect(result.exitCode, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('flutter test should run a test with a given tag', () async {
|
testWithoutContext('flutter test should run a test with a given tag', () async {
|
||||||
final ProcessResult result = await _runFlutterTest('filtering_tag', automatedTestsDirectory, flutterTestDirectory,
|
final ProcessResult result = await _runFlutterTest('filtering_tag', automatedTestsDirectory, flutterTestDirectory,
|
||||||
extraArguments: const <String>['--tags', 'include-tag']);
|
extraArguments: const <String>['--tags', 'include-tag']);
|
||||||
if (!(result.stdout as String).contains('+1: All tests passed')) {
|
expect(result.stdout, contains(RegExp(r'\+\d+: All tests passed!')));
|
||||||
fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n');
|
|
||||||
}
|
|
||||||
expect(result.exitCode, 0);
|
expect(result.exitCode, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('flutter test should not run a test with excluded tag', () async {
|
testWithoutContext('flutter test should not run a test with excluded tag', () async {
|
||||||
final ProcessResult result = await _runFlutterTest('filtering_tag', automatedTestsDirectory, flutterTestDirectory,
|
final ProcessResult result = await _runFlutterTest('filtering_tag', automatedTestsDirectory, flutterTestDirectory,
|
||||||
extraArguments: const <String>['--exclude-tags', 'exclude-tag']);
|
extraArguments: const <String>['--exclude-tags', 'exclude-tag']);
|
||||||
if (!(result.stdout as String).contains('+1: All tests passed')) {
|
expect(result.stdout, contains(RegExp(r'\+\d+: All tests passed!')));
|
||||||
fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n');
|
|
||||||
}
|
|
||||||
expect(result.exitCode, 0);
|
expect(result.exitCode, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('flutter test should run all tests when tags are unspecified', () async {
|
testWithoutContext('flutter test should run all tests when tags are unspecified', () async {
|
||||||
final ProcessResult result = await _runFlutterTest('filtering_tag', automatedTestsDirectory, flutterTestDirectory);
|
final ProcessResult result = await _runFlutterTest('filtering_tag', automatedTestsDirectory, flutterTestDirectory);
|
||||||
if (!(result.stdout as String).contains('+1 -1: Some tests failed')) {
|
expect(result.stdout, contains(RegExp(r'\+\d+ -1: Some tests failed\.')));
|
||||||
fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n');
|
|
||||||
}
|
|
||||||
expect(result.exitCode, 1);
|
expect(result.exitCode, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('flutter test should run a widgetTest with a given tag', () async {
|
testWithoutContext('flutter test should run a widgetTest with a given tag', () async {
|
||||||
final ProcessResult result = await _runFlutterTest('filtering_tag_widget', automatedTestsDirectory, flutterTestDirectory,
|
final ProcessResult result = await _runFlutterTest('filtering_tag_widget', automatedTestsDirectory, flutterTestDirectory,
|
||||||
extraArguments: const <String>['--tags', 'include-tag']);
|
extraArguments: const <String>['--tags', 'include-tag']);
|
||||||
if (!(result.stdout as String).contains('+1: All tests passed')) {
|
expect(result.stdout, contains(RegExp(r'\+\d+: All tests passed!')));
|
||||||
fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n');
|
|
||||||
}
|
|
||||||
expect(result.exitCode, 0);
|
expect(result.exitCode, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('flutter test should not run a widgetTest with excluded tag', () async {
|
testWithoutContext('flutter test should not run a widgetTest with excluded tag', () async {
|
||||||
final ProcessResult result = await _runFlutterTest('filtering_tag_widget', automatedTestsDirectory, flutterTestDirectory,
|
final ProcessResult result = await _runFlutterTest('filtering_tag_widget', automatedTestsDirectory, flutterTestDirectory,
|
||||||
extraArguments: const <String>['--exclude-tags', 'exclude-tag']);
|
extraArguments: const <String>['--exclude-tags', 'exclude-tag']);
|
||||||
if (!(result.stdout as String).contains('+1: All tests passed')) {
|
expect(result.stdout, contains(RegExp(r'\+\d+: All tests passed!')));
|
||||||
fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n');
|
|
||||||
}
|
|
||||||
expect(result.exitCode, 0);
|
expect(result.exitCode, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('flutter test should run all widgetTest when tags are unspecified', () async {
|
testWithoutContext('flutter test should run all widgetTest when tags are unspecified', () async {
|
||||||
final ProcessResult result = await _runFlutterTest('filtering_tag_widget', automatedTestsDirectory, flutterTestDirectory);
|
final ProcessResult result = await _runFlutterTest('filtering_tag_widget', automatedTestsDirectory, flutterTestDirectory);
|
||||||
if (!(result.stdout as String).contains('+1 -1: Some tests failed')) {
|
expect(result.stdout, contains(RegExp(r'\+\d+ -1: Some tests failed\.')));
|
||||||
fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n');
|
|
||||||
}
|
|
||||||
expect(result.exitCode, 1);
|
expect(result.exitCode, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWithoutContext('flutter test should test runs to completion', () async {
|
testWithoutContext('flutter test should test runs to completion', () async {
|
||||||
final ProcessResult result = await _runFlutterTest('trivial', automatedTestsDirectory, flutterTestDirectory,
|
final ProcessResult result = await _runFlutterTest('trivial', automatedTestsDirectory, flutterTestDirectory,
|
||||||
extraArguments: const <String>['--verbose']);
|
extraArguments: const <String>['--verbose']);
|
||||||
final String stdout = result.stdout as String;
|
final String stdout = (result.stdout as String).replaceAll('\r', '\n');
|
||||||
if ((!stdout.contains('+1: All tests passed')) ||
|
expect(stdout, contains(RegExp(r'\+\d+: All tests passed\!')));
|
||||||
(!stdout.contains('test 0: Starting flutter_tester process with command')) ||
|
expect(stdout, contains('test 0: Starting flutter_tester process with command'));
|
||||||
(!stdout.contains('test 0: deleting temporary directory')) ||
|
expect(stdout, contains('test 0: deleting temporary directory'));
|
||||||
(!stdout.contains('test 0: finished')) ||
|
expect(stdout, contains('test 0: finished'));
|
||||||
(!stdout.contains('test package returned with exit code 0'))) {
|
expect(stdout, contains('test package returned with exit code 0'));
|
||||||
fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n');
|
|
||||||
}
|
|
||||||
if ((result.stderr as String).isNotEmpty) {
|
if ((result.stderr as String).isNotEmpty) {
|
||||||
fail('unexpected error output from test:\n\n${result.stderr}\n-- end stderr --\n\n');
|
fail('unexpected error output from test:\n\n${result.stderr}\n-- end stderr --\n\n');
|
||||||
}
|
}
|
||||||
@ -202,14 +184,12 @@ void main() {
|
|||||||
testWithoutContext('flutter test should run all tests inside of a directory with no trailing slash', () async {
|
testWithoutContext('flutter test should run all tests inside of a directory with no trailing slash', () async {
|
||||||
final ProcessResult result = await _runFlutterTest(null, automatedTestsDirectory, '$flutterTestDirectory/child_directory',
|
final ProcessResult result = await _runFlutterTest(null, automatedTestsDirectory, '$flutterTestDirectory/child_directory',
|
||||||
extraArguments: const <String>['--verbose']);
|
extraArguments: const <String>['--verbose']);
|
||||||
final String stdout = result.stdout as String;
|
final String stdout = (result.stdout as String).replaceAll('\r', '\n');
|
||||||
if ((!stdout.contains('+2: All tests passed')) ||
|
expect(result.stdout, contains(RegExp(r'\+\d+: All tests passed\!')));
|
||||||
(!stdout.contains('test 0: Starting flutter_tester process with command')) ||
|
expect(stdout, contains('test 0: Starting flutter_tester process with command'));
|
||||||
(!stdout.contains('test 0: deleting temporary directory')) ||
|
expect(stdout, contains('test 0: deleting temporary directory'));
|
||||||
(!stdout.contains('test 0: finished')) ||
|
expect(stdout, contains('test 0: finished'));
|
||||||
(!stdout.contains('test package returned with exit code 0'))) {
|
expect(stdout, contains('test package returned with exit code 0'));
|
||||||
fail('unexpected output from test:\n\n${result.stdout}\n-- end stdout --\n\n');
|
|
||||||
}
|
|
||||||
if ((result.stderr as String).isNotEmpty) {
|
if ((result.stderr as String).isNotEmpty) {
|
||||||
fail('unexpected error output from test:\n\n${result.stderr}\n-- end stderr --\n\n');
|
fail('unexpected error output from test:\n\n${result.stderr}\n-- end stderr --\n\n');
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user