| Index: pkg/testing/lib/src/analyze.dart
|
| diff --git a/pkg/testing/lib/src/analyze.dart b/pkg/testing/lib/src/analyze.dart
|
| index ae689c8cf2ee4b167063f85169b7ca67473d4a6e..7f053e2c6feca8d8387f8f9e4b2b6799292d061d 100644
|
| --- a/pkg/testing/lib/src/analyze.dart
|
| +++ b/pkg/testing/lib/src/analyze.dart
|
| @@ -8,11 +8,12 @@ import 'dart:async' show Stream, Future;
|
|
|
| import 'dart:convert' show LineSplitter, UTF8;
|
|
|
| -import 'dart:io' show File, Process;
|
| +import 'dart:io'
|
| + show Directory, File, FileSystemEntity, Platform, Process, ProcessResult;
|
|
|
| import '../testing.dart' show startDart;
|
|
|
| -import 'log.dart' show isVerbose;
|
| +import 'log.dart' show isVerbose, splitLines;
|
|
|
| import 'suite.dart' show Suite;
|
|
|
| @@ -23,7 +24,12 @@ class Analyze extends Suite {
|
|
|
| final List<RegExp> exclude;
|
|
|
| - Analyze(this.analysisOptions, this.uris, this.exclude)
|
| + final List<String> gitGrepPathspecs;
|
| +
|
| + final List<String> gitGrepPatterns;
|
| +
|
| + Analyze(this.analysisOptions, this.uris, this.exclude, this.gitGrepPathspecs,
|
| + this.gitGrepPatterns)
|
| : super("analyze", "analyze", null);
|
|
|
| Future<Null> run(Uri packages, List<Uri> extraUris) {
|
| @@ -31,7 +37,8 @@ class Analyze extends Suite {
|
| if (extraUris != null) {
|
| allUris.addAll(extraUris);
|
| }
|
| - return analyzeUris(analysisOptions, packages, allUris, exclude);
|
| + return analyzeUris(analysisOptions, packages, allUris, exclude,
|
| + gitGrepPathspecs, gitGrepPatterns);
|
| }
|
|
|
| static Future<Analyze> fromJsonMap(
|
| @@ -45,7 +52,16 @@ class Analyze extends Suite {
|
| List<RegExp> exclude =
|
| new List<RegExp>.from(json["exclude"].map((String p) => new RegExp(p)));
|
|
|
| - return new Analyze(optionsUri, uris, exclude);
|
| + Map gitGrep = json["git grep"];
|
| + List<String> gitGrepPathspecs;
|
| + List<String> gitGrepPatterns;
|
| + if (gitGrep != null) {
|
| + gitGrepPathspecs = gitGrep["pathspecs"] ?? const <String>["."];
|
| + gitGrepPatterns = gitGrep["patterns"];
|
| + }
|
| +
|
| + return new Analyze(
|
| + optionsUri, uris, exclude, gitGrepPathspecs, gitGrepPatterns);
|
| }
|
|
|
| String toString() => "Analyze($uris, $exclude)";
|
| @@ -126,59 +142,135 @@ Stream<AnalyzerDiagnostic> parseAnalyzerOutput(
|
| Stream<String> lines =
|
| stream.transform(UTF8.decoder).transform(new LineSplitter());
|
| await for (String line in lines) {
|
| + if (line.startsWith(">>> ")) continue;
|
| yield new AnalyzerDiagnostic.fromLine(line);
|
| }
|
| }
|
|
|
| /// Run dartanalyzer on all tests in [uris].
|
| -Future<Null> analyzeUris(Uri analysisOptions, Uri packages, List<Uri> uris,
|
| - List<RegExp> exclude) async {
|
| +Future<Null> analyzeUris(
|
| + Uri analysisOptions,
|
| + Uri packages,
|
| + List<Uri> uris,
|
| + List<RegExp> exclude,
|
| + List<String> gitGrepPathspecs,
|
| + List<String> gitGrepPatterns) async {
|
| if (uris.isEmpty) return;
|
| + String topLevel;
|
| + try {
|
| + topLevel = Uri
|
| + .directory(await git("rev-parse", <String>["--show-toplevel"]))
|
| + .toFilePath();
|
| + } catch (e) {
|
| + topLevel = Uri.base.toFilePath(windows: false);
|
| + }
|
| +
|
| + String toFilePath(Uri uri) {
|
| + String path = uri.toFilePath(windows: false);
|
| + return path.startsWith(topLevel) ? path.substring(topLevel.length) : path;
|
| + }
|
| +
|
| + Set<String> filesToAnalyze = new Set<String>();
|
| +
|
| + for (Uri uri in uris) {
|
| + if (await new Directory.fromUri(uri).exists()) {
|
| + await for (FileSystemEntity entity in new Directory.fromUri(uri)
|
| + .list(recursive: true, followLinks: false)) {
|
| + if (entity is File && entity.path.endsWith(".dart")) {
|
| + filesToAnalyze.add(toFilePath(entity.uri));
|
| + }
|
| + }
|
| + } else if (await new File.fromUri(uri).exists()) {
|
| + filesToAnalyze.add(toFilePath(uri));
|
| + } else {
|
| + throw "File not found: ${uri}";
|
| + }
|
| + }
|
| +
|
| + if (gitGrepPatterns != null) {
|
| + List<String> arguments = <String>["-l"];
|
| + arguments.addAll(
|
| + gitGrepPatterns.expand((String pattern) => <String>["-e", pattern]));
|
| + arguments.add("--");
|
| + arguments.addAll(gitGrepPathspecs);
|
| + filesToAnalyze.addAll(splitLines(await git("grep", arguments))
|
| + .map((String line) => line.trimRight()));
|
| + }
|
| +
|
| const String analyzerPath = "pkg/analyzer_cli/bin/analyzer.dart";
|
| Uri analyzer = Uri.base.resolve(analyzerPath);
|
| if (!await new File.fromUri(analyzer).exists()) {
|
| - throw "Couldn't find '$analyzerPath' in '${Uri.base.toFilePath()}'";
|
| + throw "Couldn't find '$analyzerPath' in '${toFilePath(Uri.base)}'";
|
| }
|
| List<String> arguments = <String>[
|
| - "--packages=${packages.toFilePath()}",
|
| - "--package-warnings",
|
| + "--packages=${toFilePath(packages)}",
|
| "--format=machine",
|
| "--dart-sdk=${Uri.base.resolve('sdk/').toFilePath()}",
|
| ];
|
| if (analysisOptions != null) {
|
| - arguments.add("--options=${analysisOptions.toFilePath()}");
|
| + arguments.add("--options=${toFilePath(analysisOptions)}");
|
| }
|
| - arguments.addAll(uris.map((Uri uri) => uri.toFilePath()));
|
| +
|
| + filesToAnalyze = filesToAnalyze
|
| + .where((String path) => !exclude.any((RegExp r) => path.contains(r)))
|
| + .toSet();
|
| + arguments.addAll(filesToAnalyze);
|
| if (isVerbose) {
|
| - print("Running:\n ${analyzer.toFilePath()} ${arguments.join(' ')}");
|
| + print("Running:\n ${toFilePath(analyzer)} ${arguments.join(' ')}");
|
| } else {
|
| print("Running dartanalyzer.");
|
| }
|
| Stopwatch sw = new Stopwatch()..start();
|
| - Process process = await startDart(analyzer, arguments);
|
| + Process process = await startDart(analyzer, const <String>["--batch"]);
|
| + process.stdin.writeln(arguments.join(" "));
|
| process.stdin.close();
|
| - Future stdoutFuture = parseAnalyzerOutput(process.stdout).toList();
|
| - Future stderrFuture = parseAnalyzerOutput(process.stderr).toList();
|
| - await process.exitCode;
|
| - List<AnalyzerDiagnostic> diagnostics = <AnalyzerDiagnostic>[];
|
| - diagnostics.addAll(await stdoutFuture);
|
| - diagnostics.addAll(await stderrFuture);
|
| +
|
| bool hasOutput = false;
|
| Set<String> seen = new Set<String>();
|
| - for (AnalyzerDiagnostic diagnostic in diagnostics) {
|
| - String path = diagnostic.uri?.path;
|
| - if (path != null && exclude.any((RegExp r) => path.contains(r))) {
|
| - continue;
|
| - }
|
| - String message = "$diagnostic";
|
| - if (seen.add(message)) {
|
| - hasOutput = true;
|
| - print(message);
|
| +
|
| + processAnalyzerOutput(Stream<AnalyzerDiagnostic> diagnostics) async {
|
| + await for (AnalyzerDiagnostic diagnostic in diagnostics) {
|
| + if (diagnostic.uri != null) {
|
| + String path = toFilePath(diagnostic.uri);
|
| + if (diagnostic.code.startsWith("STRONG_MODE") &&
|
| + (path.startsWith("pkg/compiler/") ||
|
| + path.startsWith("tests/compiler/dart2js/"))) {
|
| + // Hack to work around dart2js not being strong-mode clean.
|
| + continue;
|
| + }
|
| + if (!filesToAnalyze.contains(path)) continue;
|
| + }
|
| + String message = "$diagnostic";
|
| + if (seen.add(message)) {
|
| + hasOutput = true;
|
| + print(message);
|
| + }
|
| }
|
| }
|
| +
|
| + Future stderrFuture =
|
| + processAnalyzerOutput(parseAnalyzerOutput(process.stderr));
|
| + Future stdoutFuture =
|
| + processAnalyzerOutput(parseAnalyzerOutput(process.stdout));
|
| + await process.exitCode;
|
| + await stdoutFuture;
|
| + await stderrFuture;
|
| + sw.stop();
|
| + print("Running analyzer took: ${sw.elapsed}.");
|
| if (hasOutput) {
|
| throw "Non-empty output from analyzer.";
|
| }
|
| - sw.stop();
|
| - print("Running analyzer took: ${sw.elapsed}.");
|
| +}
|
| +
|
| +Future<String> git(String command, Iterable<String> arguments,
|
| + {String workingDirectory}) async {
|
| + ProcessResult result = await Process.run(
|
| + Platform.isWindows ? "git.bat" : "git",
|
| + <String>[command]..addAll(arguments),
|
| + workingDirectory: workingDirectory);
|
| + if (result.exitCode != 0) {
|
| + throw "Non-zero exit code from git $command (${result.exitCode})\n"
|
| + "${result.stdout}\n${result.stderr}";
|
| + }
|
| + return result.stdout;
|
| }
|
|
|