Index: pkg/analysis_server/bin/fuzz/server_manager.dart |
diff --git a/pkg/analysis_server/bin/fuzz/server_manager.dart b/pkg/analysis_server/bin/fuzz/server_manager.dart |
deleted file mode 100644 |
index e9dcf24d81065ed1b05e0de93ca457a5b3fb558b..0000000000000000000000000000000000000000 |
--- a/pkg/analysis_server/bin/fuzz/server_manager.dart |
+++ /dev/null |
@@ -1,365 +0,0 @@ |
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-library server.manager; |
- |
-import 'dart:async'; |
-import 'dart:convert'; |
-import 'dart:io'; |
- |
-import 'package:matcher/matcher.dart'; |
-import 'package:analysis_server/src/protocol.dart'; |
-import 'package:analysis_server/src/channel/channel.dart'; |
-import 'package:analysis_server/src/channel/byte_stream_channel.dart'; |
- |
-part 'logging_client_channel.dart'; |
- |
-/** |
- * The results returned by [ServerManager].analyze(...) once analysis |
- * has finished. |
- */ |
-class AnalysisResults { |
- Duration elapsed; |
- int errorCount = 0; |
- int hintCount = 0; |
- int warningCount = 0; |
-} |
- |
- |
-/** |
- * [CompletionResults] contains the completion results returned by the server |
- * along with the elapse time to receive those completions. |
- */ |
-class CompletionResults { |
- final Duration elapsed; |
- final CompletionResultsParams params; |
- |
- CompletionResults(this.elapsed, this.params); |
- |
- int get suggestionCount => params.results.length; |
-} |
- |
-/** |
- * [Editor] is a virtual editor for inspecting and modifying a file's content |
- * and updating the server with those modifications. |
- */ |
-class Editor { |
- final ServerManager manager; |
- final File file; |
- int offset = 0; |
- String _content = null; |
- |
- Editor(this.manager, this.file); |
- |
- /// Return a future that returns the file content |
- Future<String> get content { |
- if (_content != null) { |
- return new Future.value(_content); |
- } |
- return file.readAsString().then((String content) { |
- _content = content; |
- return _content; |
- }); |
- } |
- |
- /** |
- * Request completion suggestions from the server. |
- * Return a future that completes with the completions sent. |
- */ |
- Future<List<CompletionResults>> getSuggestions() { |
- Request request = new CompletionGetSuggestionsParams( |
- file.path, |
- offset).toRequest(manager._nextRequestId); |
- Stopwatch stopwatch = new Stopwatch()..start(); |
- return manager.channel.sendRequest(request).then((Response response) { |
- String completionId = |
- new CompletionGetSuggestionsResult.fromResponse(response).id; |
- var completer = new Completer<List<CompletionResults>>(); |
- List<CompletionResults> results = []; |
- |
- // Listen for completion suggestions |
- StreamSubscription<Notification> subscription; |
- subscription = |
- manager.channel.notificationStream.listen((Notification notification) { |
- if (notification.event == 'completion.results') { |
- CompletionResultsParams params = |
- new CompletionResultsParams.fromNotification(notification); |
- if (params.id == completionId) { |
- results.add(new CompletionResults(stopwatch.elapsed, params)); |
- if (params.isLast) { |
- stopwatch.stop(); |
- subscription.cancel(); |
- completer.complete(results); |
- } |
- } |
- } |
- }); |
- |
- return completer.future; |
- }); |
- } |
- |
- /** |
- * Move the virtual cursor after the given pattern in the source. |
- * Return a future that completes once the cursor has been moved. |
- */ |
- Future<Editor> moveAfter(String pattern) { |
- return content.then((String content) { |
- offset = content.indexOf(pattern); |
- return this; |
- }); |
- } |
- |
- /** |
- * Replace the specified number of characters at the current cursor location |
- * with the given text, but do not save that content to disk. |
- * Return a future that completes once the server has been notified. |
- */ |
- Future<Editor> replace(int replacementLength, String text) { |
- return content.then((String oldContent) { |
- StringBuffer sb = new StringBuffer(); |
- sb.write(oldContent.substring(0, offset)); |
- sb.write(text); |
- sb.write(oldContent.substring(offset)); |
- _content = sb.toString(); |
- SourceEdit sourceEdit = new SourceEdit(offset, replacementLength, text); |
- Request request = new AnalysisUpdateContentParams({ |
- file.path: new ChangeContentOverlay([sourceEdit]) |
- }).toRequest(manager._nextRequestId); |
- offset += text.length; |
- return manager.channel.sendRequest(request).then((Response response) { |
- return this; |
- }); |
- }); |
- } |
-} |
- |
-/** |
- * [ServerManager] is used to launch and manage an analysis server |
- * running in a separate process. |
- */ |
-class ServerManager { |
- |
- /** |
- * The analysis server process being managed or `null` if not started. |
- */ |
- Process process; |
- |
- /** |
- * The root directory containing the Dart source files to be analyzed. |
- */ |
- Directory appDir; |
- |
- /** |
- * The channel used to communicate with the analysis server. |
- */ |
- LoggingClientChannel _channel; |
- |
- /** |
- * The identifier used in the most recent request to the server. |
- * See [_nextRequestId]. |
- */ |
- int _lastRequestId = 0; |
- |
- /** |
- * `true` if a server exception was detected on stderr as opposed to an |
- * exception that the server reported via the server.error notification. |
- */ |
- bool _unreportedServerException = false; |
- |
- /** |
- * `true` if the [stop] method has been called. |
- */ |
- bool _stopRequested = false; |
- |
- /** |
- * Return the channel used to communicate with the analysis server. |
- */ |
- ClientCommunicationChannel get channel => _channel; |
- |
- /** |
- * Return `true` if a server error occurred. |
- */ |
- bool get errorOccurred => |
- _unreportedServerException || (_channel.serverErrorCount > 0); |
- |
- String get _nextRequestId => (++_lastRequestId).toString(); |
- |
- /** |
- * Direct the server to analyze all sources in the given directory, |
- * all sub directories recursively, and any source referenced sources |
- * outside this directory hierarch such as referenced packages. |
- * Return a future that completes when the analysis is finished. |
- */ |
- Future<AnalysisResults> analyze(Directory appDir) { |
- this.appDir = appDir; |
- Stopwatch stopwatch = new Stopwatch()..start(); |
- Request request = new AnalysisSetAnalysisRootsParams( |
- [appDir.path], |
- []).toRequest(_nextRequestId); |
- |
- // Request analysis |
- return channel.sendRequest(request).then((Response response) { |
- AnalysisResults results = new AnalysisResults(); |
- StreamSubscription<Notification> subscription; |
- Completer<AnalysisResults> completer = new Completer<AnalysisResults>(); |
- subscription = |
- channel.notificationStream.listen((Notification notification) { |
- |
- // Gather analysis results |
- if (notification.event == 'analysis.errors') { |
- AnalysisErrorsParams params = |
- new AnalysisErrorsParams.fromNotification(notification); |
- params.errors.forEach((AnalysisError error) { |
- AnalysisErrorSeverity severity = error.severity; |
- if (severity == AnalysisErrorSeverity.ERROR) { |
- results.errorCount += 1; |
- } else if (severity == AnalysisErrorSeverity.WARNING) { |
- results.warningCount += 1; |
- } else if (severity == AnalysisErrorSeverity.INFO) { |
- results.hintCount += 1; |
- } else { |
- print('Unknown error severity: ${severity.name}'); |
- } |
- }); |
- } |
- |
- // Stop gathering once analysis is complete |
- if (notification.event == 'server.status') { |
- ServerStatusParams status = |
- new ServerStatusParams.fromNotification(notification); |
- AnalysisStatus analysis = status.analysis; |
- if (analysis != null && !analysis.isAnalyzing) { |
- stopwatch.stop(); |
- results.elapsed = stopwatch.elapsed; |
- subscription.cancel(); |
- completer.complete(results); |
- } |
- } |
- }); |
- return completer.future; |
- }); |
- } |
- |
- /** |
- * Send a request to the server for its version information |
- * and return a future that completes with the result. |
- */ |
- Future<ServerGetVersionResult> getVersion() { |
- Request request = new ServerGetVersionParams().toRequest(_nextRequestId); |
- return channel.sendRequest(request).then((Response response) { |
- return new ServerGetVersionResult.fromResponse(response); |
- }); |
- } |
- |
- /** |
- * Notify the server that the given file will be edited. |
- * Return a virtual editor for inspecting and modifying the file's content. |
- */ |
- Future<Editor> openFileNamed(String fileName) { |
- return _findFile(fileName, appDir).then((File file) { |
- if (file == null) { |
- throw 'Failed to find file named $fileName in ${appDir.path}'; |
- } |
- file = file.absolute; |
- Request request = |
- new AnalysisSetPriorityFilesParams([file.path]).toRequest(_nextRequestId); |
- return channel.sendRequest(request).then((Response response) { |
- return new Editor(this, file); |
- }); |
- }); |
- } |
- |
- /** |
- * Send a request for notifications. |
- * Return when the server has acknowledged that request. |
- */ |
- Future setSubscriptions() { |
- Request request = new ServerSetSubscriptionsParams( |
- [ServerService.STATUS]).toRequest(_nextRequestId); |
- return channel.sendRequest(request); |
- } |
- |
- /** |
- * Stop the analysis server. |
- * Return a future that completes when the server is terminated. |
- */ |
- Future stop([_]) { |
- _stopRequested = true; |
- print("Requesting server shutdown"); |
- Request request = new ServerShutdownParams().toRequest(_nextRequestId); |
- Duration waitTime = new Duration(seconds: 5); |
- return channel.sendRequest(request).timeout(waitTime, onTimeout: () { |
- print('Expected shutdown response'); |
- }).then((Response response) { |
- return channel.close().then((_) => process.exitCode); |
- }).timeout(new Duration(seconds: 2), onTimeout: () { |
- print('Expected server to shutdown'); |
- process.kill(); |
- }); |
- } |
- |
- /** |
- * Locate the given file in the directory tree. |
- */ |
- Future<File> _findFile(String fileName, Directory appDir) { |
- return appDir.list(recursive: true).firstWhere((FileSystemEntity entity) { |
- return entity is File && entity.path.endsWith(fileName); |
- }); |
- } |
- |
- /** |
- * Launch an analysis server and open a connection to that server. |
- */ |
- Future<ServerManager> _launchServer(String pathToServer) { |
- List<String> serverArgs = [pathToServer]; |
- return Process.start(Platform.executable, serverArgs).catchError((error) { |
- exitCode = 21; |
- throw 'Failed to launch analysis server: $error'; |
- }).then((Process process) { |
- this.process = process; |
- _channel = new LoggingClientChannel( |
- new ByteStreamClientChannel(process.stdout, process.stdin)); |
- |
- // simple out of band exception handling |
- process.stderr.transform( |
- new Utf8Codec().decoder).transform(new LineSplitter()).listen((String line) { |
- if (!_unreportedServerException) { |
- _unreportedServerException = true; |
- stderr.writeln('>>> Unreported server exception'); |
- } |
- stderr.writeln('server.stderr: $line'); |
- }); |
- |
- // watch for unexpected process termination and catch the exit code |
- process.exitCode.then((int code) { |
- if (!_stopRequested) { |
- fail('Unexpected server termination: $code'); |
- } |
- if (code != null && code != 0) { |
- exitCode = code; |
- } |
- print('Server stopped: $code'); |
- }); |
- |
- return channel.notificationStream.first.then((Notification notification) { |
- print('Server connection established'); |
- return setSubscriptions().then((_) { |
- return getVersion().then((ServerGetVersionResult result) { |
- print('Server version ${result.version}'); |
- return this; |
- }); |
- }); |
- }); |
- }); |
- } |
- |
- /** |
- * Launch analysis server in a separate process |
- * and return a future with a manager for that analysis server. |
- */ |
- static Future<ServerManager> start(String serverPath) { |
- return new ServerManager()._launchServer(serverPath); |
- } |
-} |