Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Side by Side Diff: pkg/analyzer_cli/lib/src/build_mode.dart

Issue 1868663002: Update worker mode to use the bazel protos directly instead of json (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: remove dep on async Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library analyzer_cli.src.build_mode; 5 library analyzer_cli.src.build_mode;
6 6
7 import 'dart:convert';
8 import 'dart:core' hide Resource; 7 import 'dart:core' hide Resource;
9 import 'dart:io' as io; 8 import 'dart:io' as io;
10 9
10 import 'package:protobuf/protobuf.dart';
11
11 import 'package:analyzer/dart/ast/ast.dart' show CompilationUnit; 12 import 'package:analyzer/dart/ast/ast.dart' show CompilationUnit;
12 import 'package:analyzer/dart/element/element.dart'; 13 import 'package:analyzer/dart/element/element.dart';
13 import 'package:analyzer/file_system/file_system.dart'; 14 import 'package:analyzer/file_system/file_system.dart';
14 import 'package:analyzer/file_system/physical_file_system.dart'; 15 import 'package:analyzer/file_system/physical_file_system.dart';
15 import 'package:analyzer/src/generated/engine.dart'; 16 import 'package:analyzer/src/generated/engine.dart';
16 import 'package:analyzer/src/generated/error.dart'; 17 import 'package:analyzer/src/generated/error.dart';
17 import 'package:analyzer/src/generated/java_io.dart'; 18 import 'package:analyzer/src/generated/java_io.dart';
18 import 'package:analyzer/src/generated/sdk_io.dart'; 19 import 'package:analyzer/src/generated/sdk_io.dart';
19 import 'package:analyzer/src/generated/source.dart'; 20 import 'package:analyzer/src/generated/source.dart';
20 import 'package:analyzer/src/generated/source_io.dart'; 21 import 'package:analyzer/src/generated/source_io.dart';
21 import 'package:analyzer/src/summary/format.dart'; 22 import 'package:analyzer/src/summary/format.dart';
22 import 'package:analyzer/src/summary/idl.dart'; 23 import 'package:analyzer/src/summary/idl.dart';
23 import 'package:analyzer/src/summary/package_bundle_reader.dart'; 24 import 'package:analyzer/src/summary/package_bundle_reader.dart';
24 import 'package:analyzer/src/summary/prelink.dart'; 25 import 'package:analyzer/src/summary/prelink.dart';
25 import 'package:analyzer/src/summary/summarize_ast.dart'; 26 import 'package:analyzer/src/summary/summarize_ast.dart';
26 import 'package:analyzer/src/summary/summarize_elements.dart'; 27 import 'package:analyzer/src/summary/summarize_elements.dart';
27 import 'package:analyzer/task/dart.dart'; 28 import 'package:analyzer/task/dart.dart';
28 import 'package:analyzer_cli/src/analyzer_impl.dart'; 29 import 'package:analyzer_cli/src/analyzer_impl.dart';
29 import 'package:analyzer_cli/src/driver.dart'; 30 import 'package:analyzer_cli/src/driver.dart';
30 import 'package:analyzer_cli/src/error_formatter.dart'; 31 import 'package:analyzer_cli/src/error_formatter.dart';
31 import 'package:analyzer_cli/src/options.dart'; 32 import 'package:analyzer_cli/src/options.dart';
32 33
34 import 'message_grouper.dart';
35 import 'worker_protocol.pb.dart';
36
33 /** 37 /**
34 * Analyzer used when the "--build-mode" option is supplied. 38 * Analyzer used when the "--build-mode" option is supplied.
35 */ 39 */
36 class BuildMode { 40 class BuildMode {
37 final CommandLineOptions options; 41 final CommandLineOptions options;
38 final AnalysisStats stats; 42 final AnalysisStats stats;
39 43
40 final ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE; 44 final ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
41 SummaryDataStore summaryDataStore; 45 SummaryDataStore summaryDataStore;
42 InternalAnalysisContext context; 46 InternalAnalysisContext context;
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after
277 } 281 }
278 Uri uri = Uri.parse(sourceFile.substring(0, pipeIndex)); 282 Uri uri = Uri.parse(sourceFile.substring(0, pipeIndex));
279 String path = sourceFile.substring(pipeIndex + 1); 283 String path = sourceFile.substring(pipeIndex + 1);
280 uriToFileMap[uri] = new JavaFile(path); 284 uriToFileMap[uri] = new JavaFile(path);
281 } 285 }
282 return uriToFileMap; 286 return uriToFileMap;
283 } 287 }
284 } 288 }
285 289
286 /** 290 /**
287 * Interface that every worker related data object has.
288 */
289 abstract class WorkDataObject {
290 /**
291 * Translate the data in this class into a JSON map.
292 */
293 Map<String, Object> toJson();
294 }
295
296 /**
297 * Connection between a worker and input / output. 291 * Connection between a worker and input / output.
298 */ 292 */
299 abstract class WorkerConnection { 293 abstract class WorkerConnection {
300 /** 294 /**
301 * Read a new line. Block until a line is read. Return `null` if EOF. 295 * Read a new [WorkRequest]. Returns [null] when there are no more requests.
302 */ 296 */
303 String readLineSync(); 297 WorkRequest readRequest();
304 298
305 /** 299 /**
306 * Write the given [json] as a new line to the output. 300 * Write the given [response] as bytes to the output.
307 */ 301 */
308 void writeJson(Map<String, Object> json); 302 void writeResponse(WorkResponse response);
309 } 303 }
310 304
311 /** 305 /**
312 * Persistent Bazel worker. 306 * Persistent Bazel worker.
313 */ 307 */
314 class WorkerLoop { 308 class WorkerLoop {
315 static const int EXIT_CODE_OK = 0; 309 static const int EXIT_CODE_OK = 0;
316 static const int EXIT_CODE_ERROR = 15; 310 static const int EXIT_CODE_ERROR = 15;
317 311
318 final WorkerConnection connection; 312 final WorkerConnection connection;
319 313
320 final StringBuffer errorBuffer = new StringBuffer(); 314 final StringBuffer errorBuffer = new StringBuffer();
321 final StringBuffer outBuffer = new StringBuffer(); 315 final StringBuffer outBuffer = new StringBuffer();
322 316
323 WorkerLoop(this.connection); 317 WorkerLoop(this.connection);
324 318
325 factory WorkerLoop.std() { 319 factory WorkerLoop.std({io.Stdin stdinStream, io.Stdout stdoutStream}) {
326 WorkerConnection connection = new _StdWorkerConnection(); 320 stdinStream ??= io.stdin;
321 stdoutStream ??= io.stdout;
322 WorkerConnection connection =
323 new StdWorkerConnection(stdinStream, stdoutStream);
327 return new WorkerLoop(connection); 324 return new WorkerLoop(connection);
328 } 325 }
329 326
330 /** 327 /**
331 * Performs analysis with given [options]. 328 * Performs analysis with given [options].
332 */ 329 */
333 void analyze(CommandLineOptions options) { 330 void analyze(CommandLineOptions options) {
334 new BuildMode(options, new AnalysisStats()).analyze(); 331 new BuildMode(options, new AnalysisStats()).analyze();
335 } 332 }
336 333
337 /** 334 /**
338 * Perform a single loop step. Return `true` if should exit the loop. 335 * Perform a single loop step. Return `true` if should exit the loop.
339 */ 336 */
340 bool performSingle() { 337 bool performSingle() {
341 try { 338 try {
342 WorkRequest request = _readRequest(); 339 WorkRequest request = connection.readRequest();
343 if (request == null) { 340 if (request == null) {
344 return true; 341 return true;
345 } 342 }
346 // Prepare options. 343 // Prepare options.
347 CommandLineOptions options = 344 CommandLineOptions options =
348 CommandLineOptions.parse(request.arguments, (String msg) { 345 CommandLineOptions.parse(request.arguments, (String msg) {
349 throw new ArgumentError(msg); 346 throw new ArgumentError(msg);
350 }); 347 });
351 // Analyze and respond. 348 // Analyze and respond.
352 analyze(options); 349 analyze(options);
353 String msg = _getErrorOutputBuffersText(); 350 String msg = _getErrorOutputBuffersText();
354 _writeResponse(new WorkResponse(EXIT_CODE_OK, msg)); 351 connection.writeResponse(new WorkResponse()
352 ..exitCode = EXIT_CODE_OK
353 ..output = msg);
355 } catch (e, st) { 354 } catch (e, st) {
356 String msg = _getErrorOutputBuffersText(); 355 String msg = _getErrorOutputBuffersText();
357 msg += '$e \n $st'; 356 msg += '$e \n $st';
358 _writeResponse(new WorkResponse(EXIT_CODE_ERROR, msg)); 357 connection.writeResponse(new WorkResponse()
358 ..exitCode = EXIT_CODE_ERROR
359 ..output = msg);
359 } 360 }
360 return false; 361 return false;
361 } 362 }
362 363
363 /** 364 /**
364 * Run the worker loop. 365 * Run the worker loop.
365 */ 366 */
366 void run() { 367 void run() {
367 errorSink = errorBuffer; 368 errorSink = errorBuffer;
368 outSink = outBuffer; 369 outSink = outBuffer;
(...skipping 13 matching lines...) Expand all
382 String _getErrorOutputBuffersText() { 383 String _getErrorOutputBuffersText() {
383 String msg = ''; 384 String msg = '';
384 if (errorBuffer.isNotEmpty) { 385 if (errorBuffer.isNotEmpty) {
385 msg += errorBuffer.toString() + '\n'; 386 msg += errorBuffer.toString() + '\n';
386 } 387 }
387 if (outBuffer.isNotEmpty) { 388 if (outBuffer.isNotEmpty) {
388 msg += outBuffer.toString() + '\n'; 389 msg += outBuffer.toString() + '\n';
389 } 390 }
390 return msg; 391 return msg;
391 } 392 }
392
393 /**
394 * Read a new [WorkRequest]. Return `null` if EOF.
395 * Throw [ArgumentError] if cannot be parsed.
396 */
397 WorkRequest _readRequest() {
398 String line = connection.readLineSync();
399 if (line == null) {
400 return null;
401 }
402 Object json = JSON.decode(line);
403 if (json is Map) {
404 return new WorkRequest.fromJson(json);
405 } else {
406 throw new ArgumentError('The request line is not a JSON object: $line');
407 }
408 }
409
410 void _writeResponse(WorkResponse response) {
411 Map<String, Object> json = response.toJson();
412 connection.writeJson(json);
413 }
414 }
415
416 /**
417 * Input file.
418 */
419 class WorkInput implements WorkDataObject {
420 final String path;
421 final List<int> digest;
422
423 WorkInput(this.path, this.digest);
424
425 factory WorkInput.fromJson(Map<String, Object> json) {
426 // Parse path.
427 Object path2 = json['path'];
428 if (path2 == null) {
429 throw new ArgumentError('The field "path" is missing.');
430 }
431 if (path2 is! String) {
432 throw new ArgumentError('The field "path" must be a string.');
433 }
434 // Parse digest.
435 List<int> digest = const <int>[];
436 {
437 Object digestJson = json['digest'];
438 if (digestJson != null) {
439 if (digestJson is List && digestJson.every((e) => e is int)) {
440 digest = digestJson;
441 } else {
442 throw new ArgumentError(
443 'The field "digest" should be a list of int.');
444 }
445 }
446 }
447 // OK
448 return new WorkInput(path2, digest);
449 }
450
451 @override
452 Map<String, Object> toJson() {
453 Map<String, Object> json = <String, Object>{};
454 if (path != null) {
455 json['path'] = path;
456 }
457 if (digest != null) {
458 json['digest'] = digest;
459 }
460 return json;
461 }
462 }
463
464 /**
465 * Single work unit that Bazel sends to the worker.
466 */
467 class WorkRequest implements WorkDataObject {
468 /**
469 * Command line arguments for this request.
470 */
471 final List<String> arguments;
472
473 /**
474 * Input files that the worker is allowed to read during execution of this
475 * request.
476 */
477 final List<WorkInput> inputs;
478
479 WorkRequest(this.arguments, this.inputs);
480
481 factory WorkRequest.fromJson(Map<String, Object> json) {
482 // Parse arguments.
483 List<String> arguments = const <String>[];
484 {
485 Object argumentsJson = json['arguments'];
486 if (argumentsJson != null) {
487 if (argumentsJson is List && argumentsJson.every((e) => e is String)) {
488 arguments = argumentsJson;
489 } else {
490 throw new ArgumentError(
491 'The field "arguments" should be a list of strings.');
492 }
493 }
494 }
495 // Parse inputs.
496 List<WorkInput> inputs = const <WorkInput>[];
497 {
498 Object inputsJson = json['inputs'];
499 if (inputsJson != null) {
500 if (inputsJson is List &&
501 inputsJson.every((e) {
502 return e is Map && e.keys.every((key) => key is String);
503 })) {
504 inputs = inputsJson
505 .map((Map input) => new WorkInput.fromJson(input))
506 .toList();
507 } else {
508 throw new ArgumentError(
509 'The field "inputs" should be a list of objects.');
510 }
511 }
512 }
513 // No inputs.
514 if (arguments.isEmpty && inputs.isEmpty) {
515 throw new ArgumentError('Both "arguments" and "inputs" cannot be empty.');
516 }
517 // OK
518 return new WorkRequest(arguments, inputs);
519 }
520
521 @override
522 Map<String, Object> toJson() {
523 Map<String, Object> json = <String, Object>{};
524 if (arguments != null) {
525 json['arguments'] = arguments;
526 }
527 if (inputs != null) {
528 json['inputs'] = inputs.map((input) => input.toJson()).toList();
529 }
530 return json;
531 }
532 }
533
534 /**
535 * Result that the worker sends back to Bazel when it finished its work on a
536 * [WorkRequest] message.
537 */
538 class WorkResponse implements WorkDataObject {
539 final int exitCode;
540 final String output;
541
542 WorkResponse(this.exitCode, this.output);
543
544 @override
545 Map<String, Object> toJson() {
546 Map<String, Object> json = <String, Object>{};
547 if (exitCode != null) {
548 json['exit_code'] = exitCode;
549 }
550 if (output != null) {
551 json['output'] = output;
552 }
553 return json;
554 }
555 } 393 }
556 394
557 /** 395 /**
558 * Default implementation of [WorkerConnection] that works with stdio. 396 * Default implementation of [WorkerConnection] that works with stdio.
559 */ 397 */
560 class _StdWorkerConnection implements WorkerConnection { 398 class StdWorkerConnection implements WorkerConnection {
399 final MessageGrouper _messageGrouper;
400 final io.Stdout _stdoutStream;
401
402 StdWorkerConnection(io.Stdin stdinStream, this._stdoutStream)
403 : _messageGrouper = new MessageGrouper(stdinStream);
404
561 @override 405 @override
562 String readLineSync() { 406 WorkRequest readRequest() {
563 return io.stdin.readLineSync(); 407 var buffer = _messageGrouper.next;
408 if (buffer == null) return null;
409
410 return new WorkRequest.fromBuffer(buffer);
564 } 411 }
565 412
566 @override 413 @override
567 void writeJson(Map<String, Object> json) { 414 void writeResponse(WorkResponse response) {
568 io.stdout.writeln(JSON.encode(json)); 415 var responseBuffer = response.writeToBuffer();
416
417 var writer = new CodedBufferWriter();
418 writer.writeInt32NoTag(responseBuffer.length);
419 writer.writeRawBytes(responseBuffer);
420
421 _stdoutStream.add(writer.toBuffer());
569 } 422 }
570 } 423 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698