mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

These are essentially self-inflicted race conditions. Instead of timeouts we're going to try a more verbose logging mechanism that points out when things are taking a long time.
165 lines
5.5 KiB
Dart
165 lines
5.5 KiB
Dart
// Copyright 2015 The Chromium 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 'package:args/args.dart';
|
|
|
|
import '../base/common.dart';
|
|
import '../base/file_system.dart';
|
|
import '../base/io.dart';
|
|
import '../base/logger.dart';
|
|
import '../base/terminal.dart';
|
|
import '../base/utils.dart';
|
|
import '../cache.dart';
|
|
import '../dart/analysis.dart';
|
|
import '../dart/sdk.dart' as sdk;
|
|
import '../globals.dart';
|
|
import 'analyze_base.dart';
|
|
|
|
class AnalyzeContinuously extends AnalyzeBase {
|
|
AnalyzeContinuously(ArgResults argResults, this.repoRoots, this.repoPackages) : super(argResults);
|
|
|
|
final List<String> repoRoots;
|
|
final List<Directory> repoPackages;
|
|
|
|
String analysisTarget;
|
|
bool firstAnalysis = true;
|
|
Set<String> analyzedPaths = Set<String>();
|
|
Map<String, List<AnalysisError>> analysisErrors = <String, List<AnalysisError>>{};
|
|
Stopwatch analysisTimer;
|
|
int lastErrorCount = 0;
|
|
Status analysisStatus;
|
|
|
|
@override
|
|
Future<void> analyze() async {
|
|
List<String> directories;
|
|
|
|
if (argResults['flutter-repo']) {
|
|
final PackageDependencyTracker dependencies = PackageDependencyTracker();
|
|
dependencies.checkForConflictingDependencies(repoPackages, dependencies);
|
|
|
|
directories = repoRoots;
|
|
analysisTarget = 'Flutter repository';
|
|
|
|
printTrace('Analyzing Flutter repository:');
|
|
for (String projectPath in repoRoots) {
|
|
printTrace(' ${fs.path.relative(projectPath)}');
|
|
}
|
|
} else {
|
|
directories = <String>[fs.currentDirectory.path];
|
|
analysisTarget = fs.currentDirectory.path;
|
|
}
|
|
|
|
final String sdkPath = argResults['dart-sdk'] ?? sdk.dartSdkPath;
|
|
|
|
final AnalysisServer server = AnalysisServer(sdkPath, directories);
|
|
server.onAnalyzing.listen((bool isAnalyzing) => _handleAnalysisStatus(server, isAnalyzing));
|
|
server.onErrors.listen(_handleAnalysisErrors);
|
|
|
|
Cache.releaseLockEarly();
|
|
|
|
await server.start();
|
|
final int exitCode = await server.onExit;
|
|
|
|
final String message = 'Analysis server exited with code $exitCode.';
|
|
if (exitCode != 0)
|
|
throwToolExit(message, exitCode: exitCode);
|
|
printStatus(message);
|
|
}
|
|
|
|
void _handleAnalysisStatus(AnalysisServer server, bool isAnalyzing) {
|
|
if (isAnalyzing) {
|
|
analysisStatus?.cancel();
|
|
if (!firstAnalysis)
|
|
printStatus('\n');
|
|
analysisStatus = logger.startProgress('Analyzing $analysisTarget...', timeout: kSlowOperation);
|
|
analyzedPaths.clear();
|
|
analysisTimer = Stopwatch()..start();
|
|
} else {
|
|
analysisStatus?.stop();
|
|
analysisStatus = null;
|
|
analysisTimer.stop();
|
|
|
|
logger.printStatus(terminal.clearScreen(), newline: false);
|
|
|
|
// Remove errors for deleted files, sort, and print errors.
|
|
final List<AnalysisError> errors = <AnalysisError>[];
|
|
for (String path in analysisErrors.keys.toList()) {
|
|
if (fs.isFileSync(path)) {
|
|
errors.addAll(analysisErrors[path]);
|
|
} else {
|
|
analysisErrors.remove(path);
|
|
}
|
|
}
|
|
|
|
int issueCount = errors.length;
|
|
|
|
// count missing dartdocs
|
|
final int undocumentedMembers = errors.where((AnalysisError error) {
|
|
return error.code == 'public_member_api_docs';
|
|
}).length;
|
|
if (!argResults['dartdocs']) {
|
|
errors.removeWhere((AnalysisError error) => error.code == 'public_member_api_docs');
|
|
issueCount -= undocumentedMembers;
|
|
}
|
|
|
|
errors.sort();
|
|
|
|
for (AnalysisError error in errors) {
|
|
printStatus(error.toString());
|
|
if (error.code != null)
|
|
printTrace('error code: ${error.code}');
|
|
}
|
|
|
|
dumpErrors(errors.map<String>((AnalysisError error) => error.toLegacyString()));
|
|
|
|
// Print an analysis summary.
|
|
String errorsMessage;
|
|
final int issueDiff = issueCount - lastErrorCount;
|
|
lastErrorCount = issueCount;
|
|
|
|
if (firstAnalysis)
|
|
errorsMessage = '$issueCount ${pluralize('issue', issueCount)} found';
|
|
else if (issueDiff > 0)
|
|
errorsMessage = '$issueCount ${pluralize('issue', issueCount)} found ($issueDiff new)';
|
|
else if (issueDiff < 0)
|
|
errorsMessage = '$issueCount ${pluralize('issue', issueCount)} found (${-issueDiff} fixed)';
|
|
else if (issueCount != 0)
|
|
errorsMessage = '$issueCount ${pluralize('issue', issueCount)} found';
|
|
else
|
|
errorsMessage = 'no issues found';
|
|
|
|
String dartdocMessage;
|
|
if (undocumentedMembers == 1) {
|
|
dartdocMessage = 'one public member lacks documentation';
|
|
} else {
|
|
dartdocMessage = '$undocumentedMembers public members lack documentation';
|
|
}
|
|
|
|
final String files = '${analyzedPaths.length} ${pluralize('file', analyzedPaths.length)}';
|
|
final String seconds = (analysisTimer.elapsedMilliseconds / 1000.0).toStringAsFixed(2);
|
|
if (undocumentedMembers > 0) {
|
|
printStatus('$errorsMessage • $dartdocMessage • analyzed $files in $seconds seconds');
|
|
} else {
|
|
printStatus('$errorsMessage • analyzed $files in $seconds seconds');
|
|
}
|
|
|
|
if (firstAnalysis && isBenchmarking) {
|
|
writeBenchmark(analysisTimer, issueCount, undocumentedMembers);
|
|
server.dispose().whenComplete(() { exit(issueCount > 0 ? 1 : 0); });
|
|
}
|
|
|
|
firstAnalysis = false;
|
|
}
|
|
}
|
|
|
|
void _handleAnalysisErrors(FileAnalysisErrors fileErrors) {
|
|
fileErrors.errors.removeWhere((AnalysisError error) => error.type == 'TODO');
|
|
|
|
analyzedPaths.add(fileErrors.file);
|
|
analysisErrors[fileErrors.file] = fileErrors.errors;
|
|
}
|
|
}
|