mirror of
https://github.com/flutter/packages.git
synced 2025-06-29 22:33:11 +08:00
[tool] Conditionalize color on stdout
(#4436)
Refactors colorization to a centralized utility file, and makes it all conditional on `stdout` having ANSI escape support. This makes the output more readable on LUCI, which unlike the Cirrus log display doesn't handle ANSI. Fixes https://github.com/flutter/flutter/issues/89392
This commit is contained in:
@ -5,7 +5,7 @@
|
||||
import 'package:file/file.dart';
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
import 'common/repository_package.dart';
|
||||
|
||||
|
@ -6,6 +6,7 @@ import 'package:file/file.dart';
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
import 'common/plugin_utils.dart';
|
||||
import 'common/repository_package.dart';
|
||||
|
@ -6,6 +6,7 @@ import 'package:file/file.dart';
|
||||
import 'package:platform/platform.dart';
|
||||
|
||||
import 'core.dart';
|
||||
import 'output_utils.dart';
|
||||
import 'process_runner.dart';
|
||||
|
||||
const String _cacheCommandKey = 'CMAKE_COMMAND:INTERNAL';
|
||||
|
@ -2,7 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:colorize/colorize.dart';
|
||||
import 'package:file/file.dart';
|
||||
import 'package:pub_semver/pub_semver.dart';
|
||||
|
||||
@ -69,16 +68,6 @@ bool isPackage(FileSystemEntity entity) {
|
||||
return entity.childFile('pubspec.yaml').existsSync();
|
||||
}
|
||||
|
||||
/// Prints `successMessage` in green.
|
||||
void printSuccess(String successMessage) {
|
||||
print(Colorize(successMessage)..green());
|
||||
}
|
||||
|
||||
/// Prints `errorMessage` in red.
|
||||
void printError(String errorMessage) {
|
||||
print(Colorize(errorMessage)..red());
|
||||
}
|
||||
|
||||
/// Error thrown when a command needs to exit with a non-zero exit code.
|
||||
///
|
||||
/// While there is no specific definition of the meaning of different non-zero
|
||||
|
44
script/tool/lib/src/common/output_utils.dart
Normal file
44
script/tool/lib/src/common/output_utils.dart
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:colorize/colorize.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
export 'package:colorize/colorize.dart' show Styles;
|
||||
|
||||
/// True if color should be applied.
|
||||
///
|
||||
/// Defaults to autodetecting stdout.
|
||||
@visibleForTesting
|
||||
bool useColorForOutput = stdout.supportsAnsiEscapes;
|
||||
|
||||
String _colorizeIfAppropriate(String string, Styles color) {
|
||||
if (!useColorForOutput) {
|
||||
return string;
|
||||
}
|
||||
return Colorize(string).apply(color).toString();
|
||||
}
|
||||
|
||||
/// Prints [message] in green, if the environment supports color.
|
||||
void printSuccess(String message) {
|
||||
print(_colorizeIfAppropriate(message, Styles.GREEN));
|
||||
}
|
||||
|
||||
/// Prints [message] in yellow, if the environment supports color.
|
||||
void printWarning(String message) {
|
||||
print(_colorizeIfAppropriate(message, Styles.YELLOW));
|
||||
}
|
||||
|
||||
/// Prints [message] in red, if the environment supports color.
|
||||
void printError(String message) {
|
||||
print(_colorizeIfAppropriate(message, Styles.RED));
|
||||
}
|
||||
|
||||
/// Returns [message] with escapes to print it in [color], if the environment
|
||||
/// supports color.
|
||||
String colorizeString(String message, Styles color) {
|
||||
return _colorizeIfAppropriate(message, color);
|
||||
}
|
@ -14,6 +14,7 @@ import 'package:yaml/yaml.dart';
|
||||
|
||||
import 'core.dart';
|
||||
import 'git_version_finder.dart';
|
||||
import 'output_utils.dart';
|
||||
import 'process_runner.dart';
|
||||
import 'repository_package.dart';
|
||||
|
||||
|
@ -4,12 +4,12 @@
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:colorize/colorize.dart';
|
||||
import 'package:file/file.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:pub_semver/pub_semver.dart';
|
||||
|
||||
import 'core.dart';
|
||||
import 'output_utils.dart';
|
||||
import 'package_command.dart';
|
||||
import 'repository_package.dart';
|
||||
|
||||
@ -208,7 +208,7 @@ abstract class PackageLoopingCommand extends PackageCommand {
|
||||
/// messages. DO NOT RELY on someone noticing a warning; instead, use it for
|
||||
/// things that might be useful to someone debugging an unexpected result.
|
||||
void logWarning(String warningMessage) {
|
||||
_printColorized(warningMessage, Styles.YELLOW);
|
||||
printWarning(warningMessage);
|
||||
if (_currentPackageEntry != null) {
|
||||
_packagesWithWarnings.add(_currentPackageEntry!);
|
||||
} else {
|
||||
@ -467,7 +467,7 @@ abstract class PackageLoopingCommand extends PackageCommand {
|
||||
}
|
||||
|
||||
if (!captureOutput) {
|
||||
summary = (Colorize(summary)..apply(style)).toString();
|
||||
summary = colorizeString(summary, style);
|
||||
}
|
||||
print(' ${entry.package.displayName} - $summary');
|
||||
}
|
||||
@ -500,7 +500,7 @@ abstract class PackageLoopingCommand extends PackageCommand {
|
||||
if (captureOutput) {
|
||||
print(message);
|
||||
} else {
|
||||
print(Colorize(message)..apply(color));
|
||||
print(colorizeString(message, color));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ import 'dart:io' as io;
|
||||
|
||||
import 'package:file/file.dart';
|
||||
|
||||
import 'core.dart';
|
||||
import 'output_utils.dart';
|
||||
import 'process_runner.dart';
|
||||
|
||||
const String _xcodeBuildCommand = 'xcodebuild';
|
||||
|
@ -11,6 +11,7 @@ import 'package:pubspec_parse/pubspec_parse.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/file_utils.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_command.dart';
|
||||
import 'common/process_runner.dart';
|
||||
import 'common/pub_utils.dart';
|
||||
|
@ -5,6 +5,7 @@
|
||||
import 'package:file/file.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
import 'common/plugin_utils.dart';
|
||||
import 'common/pub_utils.dart';
|
||||
|
@ -5,7 +5,7 @@
|
||||
import 'package:file/file.dart';
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
import 'common/repository_package.dart';
|
||||
|
||||
|
@ -8,6 +8,7 @@ import 'dart:io';
|
||||
import 'package:file/file.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
import 'common/plugin_utils.dart';
|
||||
import 'common/repository_package.dart';
|
||||
|
@ -6,9 +6,9 @@ import 'package:file/file.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:pub_semver/pub_semver.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/file_utils.dart';
|
||||
import 'common/git_version_finder.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
import 'common/plugin_utils.dart';
|
||||
import 'common/repository_package.dart';
|
||||
|
@ -9,6 +9,7 @@ import 'package:uuid/uuid.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/gradle.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
import 'common/plugin_utils.dart';
|
||||
import 'common/repository_package.dart';
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
import 'common/repository_package.dart';
|
||||
|
||||
|
@ -10,6 +10,7 @@ import 'package:http/http.dart' as http;
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_command.dart';
|
||||
|
||||
/// In theory this should be 8191, but in practice that was still resulting in
|
||||
|
@ -7,6 +7,7 @@ import 'package:meta/meta.dart';
|
||||
import 'package:pub_semver/pub_semver.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
import 'common/plugin_utils.dart';
|
||||
import 'common/repository_package.dart';
|
||||
|
@ -6,6 +6,7 @@ import 'package:file/file.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_command.dart';
|
||||
|
||||
const Set<String> _codeFileExtensions = <String>{
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/gradle.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
import 'common/plugin_utils.dart';
|
||||
import 'common/repository_package.dart';
|
||||
|
@ -11,6 +11,7 @@ import 'package:yaml_edit/yaml_edit.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/git_version_finder.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_command.dart';
|
||||
import 'common/repository_package.dart';
|
||||
|
||||
|
@ -8,6 +8,7 @@ import 'package:meta/meta.dart';
|
||||
import 'common/cmake.dart';
|
||||
import 'common/core.dart';
|
||||
import 'common/gradle.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
import 'common/plugin_utils.dart';
|
||||
import 'common/repository_package.dart';
|
||||
|
@ -8,6 +8,7 @@ import 'dart:io';
|
||||
import 'package:file/file.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
import 'common/repository_package.dart';
|
||||
|
||||
|
@ -9,7 +9,7 @@ import 'dart:io' as io;
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:pub_semver/pub_semver.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
import 'common/pub_utils.dart';
|
||||
import 'common/pub_version_finder.dart';
|
||||
|
@ -18,6 +18,7 @@ import 'package:yaml/yaml.dart';
|
||||
import 'common/core.dart';
|
||||
import 'common/file_utils.dart';
|
||||
import 'common/git_version_finder.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_command.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
import 'common/pub_version_finder.dart';
|
||||
|
@ -9,6 +9,7 @@ import 'package:pubspec_parse/pubspec_parse.dart';
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
import 'common/repository_package.dart';
|
||||
|
||||
|
@ -6,6 +6,7 @@ import 'package:file/file.dart';
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
import 'common/repository_package.dart';
|
||||
|
||||
|
@ -11,6 +11,7 @@ import 'package:pubspec_parse/pubspec_parse.dart';
|
||||
import 'package:yaml_edit/yaml_edit.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
import 'common/pub_utils.dart';
|
||||
import 'common/pub_version_finder.dart';
|
||||
|
@ -9,7 +9,7 @@ import 'package:meta/meta.dart';
|
||||
import 'package:yaml/yaml.dart';
|
||||
import 'package:yaml_edit/yaml_edit.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
import 'common/pub_utils.dart';
|
||||
import 'common/repository_package.dart';
|
||||
|
@ -6,6 +6,7 @@ import 'package:pub_semver/pub_semver.dart';
|
||||
import 'package:yaml_edit/yaml_edit.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
import 'common/repository_package.dart';
|
||||
|
||||
|
@ -7,8 +7,8 @@ import 'package:file/file.dart';
|
||||
import 'package:pub_semver/pub_semver.dart';
|
||||
import 'package:yaml_edit/yaml_edit.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/git_version_finder.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
import 'common/package_state_utils.dart';
|
||||
import 'common/repository_package.dart';
|
||||
|
@ -8,8 +8,8 @@ import 'package:meta/meta.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:pub_semver/pub_semver.dart';
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/git_version_finder.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
import 'common/package_state_utils.dart';
|
||||
import 'common/pub_version_finder.dart';
|
||||
|
@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'common/core.dart';
|
||||
import 'common/output_utils.dart';
|
||||
import 'common/package_looping_command.dart';
|
||||
import 'common/plugin_utils.dart';
|
||||
import 'common/repository_package.dart';
|
||||
|
100
script/tool/test/common/output_utils_test.dart
Normal file
100
script/tool/test/common/output_utils_test.dart
Normal file
@ -0,0 +1,100 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_plugin_tools/src/common/output_utils.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group('with color support', () {
|
||||
setUp(() {
|
||||
useColorForOutput = true;
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
useColorForOutput = stdout.supportsAnsiEscapes;
|
||||
});
|
||||
|
||||
test('colorize works', () async {
|
||||
const String message = 'a message';
|
||||
|
||||
expect(
|
||||
colorizeString(message, Styles.MAGENTA), '\x1B[35m$message\x1B[0m');
|
||||
});
|
||||
|
||||
test('printSuccess is green', () async {
|
||||
const String message = 'a message';
|
||||
|
||||
expect(await _capturePrint(() => printSuccess(message)),
|
||||
'\x1B[32m$message\x1B[0m');
|
||||
});
|
||||
|
||||
test('printWarning is yellow', () async {
|
||||
const String message = 'a message';
|
||||
|
||||
expect(await _capturePrint(() => printWarning(message)),
|
||||
'\x1B[33m$message\x1B[0m');
|
||||
});
|
||||
|
||||
test('printError is red', () async {
|
||||
const String message = 'a message';
|
||||
|
||||
expect(await _capturePrint(() => printError(message)),
|
||||
'\x1B[31m$message\x1B[0m');
|
||||
});
|
||||
});
|
||||
|
||||
group('without color support', () {
|
||||
setUp(() {
|
||||
useColorForOutput = false;
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
useColorForOutput = stdout.supportsAnsiEscapes;
|
||||
});
|
||||
|
||||
test('colorize no-ops', () async {
|
||||
const String message = 'a message';
|
||||
|
||||
expect(colorizeString(message, Styles.MAGENTA), message);
|
||||
});
|
||||
|
||||
test('printSuccess just prints', () async {
|
||||
const String message = 'a message';
|
||||
|
||||
expect(await _capturePrint(() => printSuccess(message)), message);
|
||||
});
|
||||
|
||||
test('printWarning just prints', () async {
|
||||
const String message = 'a message';
|
||||
|
||||
expect(await _capturePrint(() => printWarning(message)), message);
|
||||
});
|
||||
|
||||
test('printError just prints', () async {
|
||||
const String message = 'a message';
|
||||
|
||||
expect(await _capturePrint(() => printError(message)), message);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// Run the command [runner] with the given [args] and return
|
||||
/// what was printed.
|
||||
/// A custom [errorHandler] can be used to handle the runner error as desired without throwing.
|
||||
Future<String> _capturePrint(void Function() printFunction) async {
|
||||
final StringBuffer output = StringBuffer();
|
||||
final ZoneSpecification spec = ZoneSpecification(
|
||||
print: (_, __, ___, String message) {
|
||||
output.write(message);
|
||||
},
|
||||
);
|
||||
await Zone.current
|
||||
.fork(specification: spec)
|
||||
.run<Future<void>>(() async => printFunction());
|
||||
|
||||
return output.toString();
|
||||
}
|
@ -9,6 +9,7 @@ import 'package:args/command_runner.dart';
|
||||
import 'package:file/file.dart';
|
||||
import 'package:file/memory.dart';
|
||||
import 'package:flutter_plugin_tools/src/common/core.dart';
|
||||
import 'package:flutter_plugin_tools/src/common/output_utils.dart';
|
||||
import 'package:flutter_plugin_tools/src/common/package_looping_command.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:test/test.dart';
|
||||
@ -82,6 +83,8 @@ void main() {
|
||||
late Directory thirdPartyPackagesDir;
|
||||
|
||||
setUp(() {
|
||||
// Correct color handling is part of the behavior being tested here.
|
||||
useColorForOutput = true;
|
||||
fileSystem = MemoryFileSystem();
|
||||
mockPlatform = MockPlatform();
|
||||
packagesDir = createPackagesDirectory(fileSystem: fileSystem);
|
||||
@ -90,6 +93,11 @@ void main() {
|
||||
.childDirectory('packages');
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
// Restore the default behavior.
|
||||
useColorForOutput = io.stdout.supportsAnsiEscapes;
|
||||
});
|
||||
|
||||
/// Creates a TestPackageLoopingCommand instance that uses [gitDiffResponse]
|
||||
/// for git diffs, and logs output to [printOutput].
|
||||
TestPackageLoopingCommand createTestCommand({
|
||||
|
@ -525,8 +525,8 @@ void main() {
|
||||
'Publishing all packages that have changed relative to "HEAD~"'),
|
||||
contains('Running `pub publish ` in ${plugin1.path}...'),
|
||||
contains('Running `pub publish ` in ${plugin2.path}...'),
|
||||
contains('plugin1 - \x1B[32mpublished\x1B[0m'),
|
||||
contains('plugin2/plugin2 - \x1B[32mpublished\x1B[0m'),
|
||||
contains('plugin1 - published'),
|
||||
contains('plugin2/plugin2 - published'),
|
||||
]));
|
||||
expect(
|
||||
processRunner.recordedCalls,
|
||||
|
Reference in New Issue
Block a user