Add many more global analyses. (#47875)
* Update packages. * Add many more global analyses. * Catch trailing spaces and trailing newlines in all text files. Before we were only checking newly added files, but that means we missed some. * Port the trailing spaces logic to work on Windows too. * Correct all the files with trailing spaces and newlines. * Refactor some of the dev/bots logic into a utils.dart library. Notably, the "exit" and "print" shims for testing are now usable from test.dart, analyze.dart, and run_command.dart. * Add an "exitWithError" function that prints the red lines and then exits. This is the preferred way to exit from test.dart, analyze.dart, and run_command.dart. * More consistency in the output of analyze.dart. * Refactor analyze.dart to use the _allFiles file enumerating logic more widely. * Add some double-checking logic to the _allFiles logic to catch cases where changes to that logic end up catching fewer files than expected (helps prevent future false positives). * Add a check to prevent new binary files from being added to the repository. Grandfather in the binaries that we've already added. * Update all the dependencies (needed because we now import crypto in dev/bots/analyze.dart).
This commit is contained in:
@@ -4,44 +4,14 @@
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:core' hide print;
|
||||
import 'dart:io' hide exit;
|
||||
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
final bool hasColor = stdout.supportsAnsiEscapes;
|
||||
import 'utils.dart';
|
||||
|
||||
final String bold = hasColor ? '\x1B[1m' : ''; // used for shard titles
|
||||
final String red = hasColor ? '\x1B[31m' : ''; // used for errors
|
||||
final String green = hasColor ? '\x1B[32m' : ''; // used for section titles, commands
|
||||
final String yellow = hasColor ? '\x1B[33m' : ''; // unused
|
||||
final String cyan = hasColor ? '\x1B[36m' : ''; // used for paths
|
||||
final String reverse = hasColor ? '\x1B[7m' : ''; // used for clocks
|
||||
final String reset = hasColor ? '\x1B[0m' : '';
|
||||
final String redLine = '$red━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━$reset';
|
||||
|
||||
String get clock {
|
||||
final DateTime now = DateTime.now();
|
||||
return '$reverse▌'
|
||||
'${now.hour.toString().padLeft(2, "0")}:'
|
||||
'${now.minute.toString().padLeft(2, "0")}:'
|
||||
'${now.second.toString().padLeft(2, "0")}'
|
||||
'▐$reset';
|
||||
}
|
||||
|
||||
String prettyPrintDuration(Duration duration) {
|
||||
String result = '';
|
||||
final int minutes = duration.inMinutes;
|
||||
if (minutes > 0)
|
||||
result += '${minutes}min ';
|
||||
final int seconds = duration.inSeconds - minutes * 60;
|
||||
final int milliseconds = duration.inMilliseconds - (seconds * 1000 + minutes * 60 * 1000);
|
||||
result += '$seconds.${milliseconds.toString().padLeft(3, "0")}s';
|
||||
return result;
|
||||
}
|
||||
|
||||
void printProgress(String action, String workingDir, String command) {
|
||||
print('$clock $action: cd $cyan$workingDir$reset; $green$command$reset');
|
||||
}
|
||||
// TODO(ianh): These two functions should be refactored into something that avoids all this code duplication.
|
||||
|
||||
Stream<String> runAndGetStdout(String executable, List<String> arguments, {
|
||||
String workingDirectory,
|
||||
@@ -49,11 +19,14 @@ Stream<String> runAndGetStdout(String executable, List<String> arguments, {
|
||||
bool expectNonZeroExit = false,
|
||||
int expectedExitCode,
|
||||
String failureMessage,
|
||||
Function beforeExit,
|
||||
bool skip = false,
|
||||
}) async* {
|
||||
final String commandDescription = '${path.relative(executable, from: workingDirectory)} ${arguments.join(' ')}';
|
||||
final String relativeWorkingDir = path.relative(workingDirectory);
|
||||
|
||||
if (skip) {
|
||||
printProgress('SKIPPING', relativeWorkingDir, commandDescription);
|
||||
return;
|
||||
}
|
||||
printProgress('RUNNING', relativeWorkingDir, commandDescription);
|
||||
|
||||
final Stopwatch time = Stopwatch()..start();
|
||||
@@ -64,26 +37,21 @@ Stream<String> runAndGetStdout(String executable, List<String> arguments, {
|
||||
|
||||
stderr.addStream(process.stderr);
|
||||
final Stream<String> lines = process.stdout.transform(utf8.decoder).transform(const LineSplitter());
|
||||
await for (String line in lines) {
|
||||
await for (String line in lines)
|
||||
yield line;
|
||||
}
|
||||
|
||||
final int exitCode = await process.exitCode;
|
||||
print('$clock ELAPSED TIME: ${prettyPrintDuration(time.elapsed)} for $green$commandDescription$reset in $cyan$relativeWorkingDir$reset');
|
||||
if ((exitCode == 0) == expectNonZeroExit || (expectedExitCode != null && exitCode != expectedExitCode)) {
|
||||
if (failureMessage != null) {
|
||||
print(failureMessage);
|
||||
}
|
||||
print(
|
||||
'$redLine\n'
|
||||
'${bold}ERROR: ${red}Last command exited with $exitCode (expected: ${expectNonZeroExit ? (expectedExitCode ?? 'non-zero') : 'zero'}).$reset\n'
|
||||
'${bold}Command: $green$commandDescription$reset\n'
|
||||
'${bold}Relative working directory: $cyan$relativeWorkingDir$reset\n'
|
||||
'$redLine'
|
||||
);
|
||||
beforeExit?.call();
|
||||
exit(1);
|
||||
exitWithError(<String>[
|
||||
if (failureMessage != null)
|
||||
failureMessage
|
||||
else
|
||||
'${bold}ERROR: ${red}Last command exited with $exitCode (expected: ${expectNonZeroExit ? (expectedExitCode ?? 'non-zero') : 'zero'}).$reset',
|
||||
'${bold}Command: $green$commandDescription$reset',
|
||||
'${bold}Relative working directory: $cyan$relativeWorkingDir$reset',
|
||||
]);
|
||||
}
|
||||
print('$clock ELAPSED TIME: ${prettyPrintDuration(time.elapsed)} for $green$commandDescription$reset in $cyan$relativeWorkingDir$reset');
|
||||
}
|
||||
|
||||
Future<void> runCommand(String executable, List<String> arguments, {
|
||||
@@ -97,9 +65,10 @@ Future<void> runCommand(String executable, List<String> arguments, {
|
||||
bool skip = false,
|
||||
bool Function(String) removeLine,
|
||||
}) async {
|
||||
assert((outputMode == OutputMode.capture) == (output != null),
|
||||
'The output parameter must be non-null with and only with '
|
||||
'OutputMode.capture');
|
||||
assert(
|
||||
(outputMode == OutputMode.capture) == (output != null),
|
||||
'The output parameter must be non-null with and only with OutputMode.capture',
|
||||
);
|
||||
|
||||
final String commandDescription = '${path.relative(executable, from: workingDirectory)} ${arguments.join(' ')}';
|
||||
final String relativeWorkingDir = path.relative(workingDirectory);
|
||||
@@ -137,18 +106,12 @@ Future<void> runCommand(String executable, List<String> arguments, {
|
||||
}
|
||||
|
||||
final int exitCode = await process.exitCode;
|
||||
print('$clock ELAPSED TIME: ${prettyPrintDuration(time.elapsed)} for $green$commandDescription$reset in $cyan$relativeWorkingDir$reset');
|
||||
|
||||
if (output != null) {
|
||||
output.stdout = _flattenToString(await savedStdout);
|
||||
output.stderr = _flattenToString(await savedStderr);
|
||||
}
|
||||
|
||||
if ((exitCode == 0) == expectNonZeroExit || (expectedExitCode != null && exitCode != expectedExitCode)) {
|
||||
if (failureMessage != null) {
|
||||
print(failureMessage);
|
||||
}
|
||||
|
||||
// Print the output when we get unexpected results (unless output was
|
||||
// printed already).
|
||||
switch (outputMode) {
|
||||
@@ -160,15 +123,16 @@ Future<void> runCommand(String executable, List<String> arguments, {
|
||||
stderr.writeln(_flattenToString(await savedStderr));
|
||||
break;
|
||||
}
|
||||
print(
|
||||
'$redLine\n'
|
||||
'${bold}ERROR: ${red}Last command exited with $exitCode (expected: ${expectNonZeroExit ? (expectedExitCode ?? 'non-zero') : 'zero'}).$reset\n'
|
||||
'${bold}Command: $green$commandDescription$reset\n'
|
||||
'${bold}Relative working directory: $cyan$relativeWorkingDir$reset\n'
|
||||
'$redLine'
|
||||
);
|
||||
exit(1);
|
||||
exitWithError(<String>[
|
||||
if (failureMessage != null)
|
||||
failureMessage
|
||||
else
|
||||
'${bold}ERROR: ${red}Last command exited with $exitCode (expected: ${expectNonZeroExit ? (expectedExitCode ?? 'non-zero') : 'zero'}).$reset',
|
||||
'${bold}Command: $green$commandDescription$reset',
|
||||
'${bold}Relative working directory: $cyan$relativeWorkingDir$reset',
|
||||
]);
|
||||
}
|
||||
print('$clock ELAPSED TIME: ${prettyPrintDuration(time.elapsed)} for $green$commandDescription$reset in $cyan$relativeWorkingDir$reset');
|
||||
}
|
||||
|
||||
/// Flattens a nested list of UTF-8 code units into a single string.
|
||||
|
||||
Reference in New Issue
Block a user