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

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

Issue 1848543002: Support --persistent_worker flag in --build-mode. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: tweaks 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';
7 import 'dart:core' hide Resource; 8 import 'dart:core' hide Resource;
8 import 'dart:io' as io; 9 import 'dart:io' as io;
9 10
10 import 'package:analyzer/dart/ast/ast.dart' show CompilationUnit; 11 import 'package:analyzer/dart/ast/ast.dart' show CompilationUnit;
11 import 'package:analyzer/dart/element/element.dart'; 12 import 'package:analyzer/dart/element/element.dart';
12 import 'package:analyzer/file_system/file_system.dart'; 13 import 'package:analyzer/file_system/file_system.dart';
13 import 'package:analyzer/file_system/physical_file_system.dart'; 14 import 'package:analyzer/file_system/physical_file_system.dart';
14 import 'package:analyzer/src/generated/engine.dart'; 15 import 'package:analyzer/src/generated/engine.dart';
15 import 'package:analyzer/src/generated/error.dart'; 16 import 'package:analyzer/src/generated/error.dart';
16 import 'package:analyzer/src/generated/java_io.dart'; 17 import 'package:analyzer/src/generated/java_io.dart';
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after
274 'Illegal input file (must be "\$uri|\$path"): $sourceFile'); 275 'Illegal input file (must be "\$uri|\$path"): $sourceFile');
275 return null; 276 return null;
276 } 277 }
277 Uri uri = Uri.parse(sourceFile.substring(0, pipeIndex)); 278 Uri uri = Uri.parse(sourceFile.substring(0, pipeIndex));
278 String path = sourceFile.substring(pipeIndex + 1); 279 String path = sourceFile.substring(pipeIndex + 1);
279 uriToFileMap[uri] = new JavaFile(path); 280 uriToFileMap[uri] = new JavaFile(path);
280 } 281 }
281 return uriToFileMap; 282 return uriToFileMap;
282 } 283 }
283 } 284 }
285
286 /**
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.
298 */
299 abstract class WorkerConnection {
300 /**
301 * Read a new line. Block until a line is read. Return `null` if EOF.
302 */
303 String readLineSync();
304
305 /**
306 * Write the given [json] as a new line to the stdout.
Paul Berry 2016/03/30 18:27:43 s/to the stdout/to the output/ (since this class
scheglov 2016/03/30 18:39:02 Done.
307 */
308 void writeJson(Map<String, Object> json);
309 }
310
311 /**
312 * Persistent Bazel worker.
313 */
314 class WorkerLoop {
315 final WorkerConnection connection;
316
317 final StringBuffer errorBuffer = new StringBuffer();
318 final StringBuffer outBuffer = new StringBuffer();
319
320 WorkerLoop(this.connection);
321
322 factory WorkerLoop.std() {
323 WorkerConnection connection = new _StdWorkerConnection();
324 return new WorkerLoop(connection);
325 }
326
327 /**
328 * Performs analysis with given [options].
329 */
330 void analyze(CommandLineOptions options) {
331 new BuildMode(options, new AnalysisStats()).analyze();
332 }
333
334 /**
335 * Perform a single loop step. Return `true` if should exit the loop.
336 */
337 bool performSingle() {
338 try {
339 WorkRequest request = _readRequest();
340 if (request == null) {
341 return true;
342 }
343 // Prepare options.
344 CommandLineOptions options =
345 CommandLineOptions.parse(request.arguments, (String msg) {
346 throw new ArgumentError(msg);
347 });
348 // Analyze and respond.
349 analyze(options);
350 String msg = _getErrorOutputBuffersText();
351 _writeResponse(new WorkResponse(0, msg));
352 } catch (e, st) {
353 String msg = _getErrorOutputBuffersText();
354 msg += '$e \n $st';
355 _writeResponse(new WorkResponse(15, msg));
Paul Berry 2016/03/30 18:27:43 Can we make constants for these exit codes (0 abov
scheglov 2016/03/30 18:39:02 Done.
356 }
357 return false;
358 }
359
360 /**
361 * Run the worker loop.
362 */
363 void run() {
364 errorSink = errorBuffer;
365 outSink = outBuffer;
366 exitHandler = (int exitCode) {
367 return throw new StateError('Exit called: $exitCode');
368 };
369 while (true) {
370 errorBuffer.clear();
371 outBuffer.clear();
372 bool shouldExit = performSingle();
373 if (shouldExit) {
374 break;
375 }
376 }
377 }
378
379 String _getErrorOutputBuffersText() {
380 String msg = '';
381 if (errorBuffer.isNotEmpty) {
382 msg += errorBuffer.toString() + '\n';
383 }
384 if (outBuffer.isNotEmpty) {
385 msg += outBuffer.toString() + '\n';
386 }
387 return msg;
388 }
389
390 /**
391 * Read a new [WorkRequest]. Return `null` if EOF.
392 * Throw [ArgumentError] if cannot be parsed.
393 */
394 WorkRequest _readRequest() {
395 String line = connection.readLineSync();
396 if (line == null) {
397 return null;
398 }
399 Object json = JSON.decode(line);
400 if (json is Map) {
401 return new WorkRequest.fromJson(json);
402 } else {
403 throw new ArgumentError('The request line is not a JSON object: $line');
404 }
405 }
406
407 void _writeResponse(WorkResponse response) {
408 Map<String, Object> json = response.toJson();
409 connection.writeJson(json);
410 }
411 }
412
413 /**
414 * Input file.
415 */
416 class WorkInput implements WorkDataObject {
417 final String path;
418 final List<int> digest;
419
420 WorkInput(this.path, this.digest);
421
422 factory WorkInput.fromJson(Map<String, Object> json) {
423 // Parse path.
424 Object path2 = json['path'];
425 if (path2 == null) {
426 throw new ArgumentError('The field "path" is missing.');
427 }
428 if (path2 is! String) {
429 throw new ArgumentError('The field "path" must be a string.');
430 }
431 // Parse digest.
432 List<int> digest = const <int>[];
433 {
434 Object digestJson = json['digest'];
435 if (digestJson != null) {
436 if (digestJson is List && digestJson.every((e) => e is int)) {
437 digest = digestJson;
438 } else {
439 throw new ArgumentError(
440 'The field "digest" should be a list of int.');
441 }
442 }
443 }
444 // OK
445 return new WorkInput(path2, digest);
446 }
447
448 @override
449 Map<String, Object> toJson() {
450 return <String, Object>{'path': path, 'digest': digest};
Paul Berry 2016/03/30 18:27:43 If digest is null, I'd prefer to see it not includ
scheglov 2016/03/30 18:39:02 Done.
451 }
452 }
453
454 /**
455 * Single work unit that Bazel sends to the worker.
456 */
457 class WorkRequest implements WorkDataObject {
458 /**
459 * Command line arguments for this request.
460 */
461 final List<String> arguments;
462
463 /**
464 * Input files that the worker is allowed to read during execution of this
465 * request.
466 */
467 final List<WorkInput> inputs;
468
469 WorkRequest(this.arguments, this.inputs);
470
471 factory WorkRequest.fromJson(Map<String, Object> json) {
472 // Parse arguments.
473 List<String> arguments = const <String>[];
474 {
475 Object argumentsJson = json['arguments'];
476 if (argumentsJson != null) {
477 if (argumentsJson is List && argumentsJson.every((e) => e is String)) {
478 arguments = argumentsJson;
479 } else {
480 throw new ArgumentError(
481 'The field "arguments" should be a list of strings.');
482 }
483 }
484 }
485 // Parse inputs.
486 List<WorkInput> inputs = const <WorkInput>[];
487 {
488 Object inputsJson = json['inputs'];
489 if (inputsJson != null) {
490 if (inputsJson is List &&
491 inputsJson.every((e) {
492 return e is Map && e.keys.every((key) => key is String);
493 })) {
494 inputs = inputsJson
495 .map((Map input) => new WorkInput.fromJson(input))
496 .toList();
497 } else {
498 throw new ArgumentError(
499 'The field "inputs" should be a list of objects.');
500 }
501 }
502 }
503 // No inputs.
504 if (arguments.isEmpty && inputs.isEmpty) {
505 throw new ArgumentError('Both "arguments" and "inputs" cannot be empty.');
506 }
507 // OK
508 return new WorkRequest(arguments, inputs);
509 }
510
511 @override
512 Map<String, Object> toJson() {
513 return <String, Object>{
514 'arguments': arguments,
515 'inputs': inputs.map((input) => input.toJson()).toList()
516 };
517 }
518 }
519
520 /**
521 * Result that the worker sends back to Bazel when it finished its work on a
522 * [WorkRequest] message.
523 */
524 class WorkResponse implements WorkDataObject {
525 final int exitCode;
526 final String output;
527
528 WorkResponse(this.exitCode, this.output);
529
530 @override
531 Map<String, Object> toJson() {
532 return <String, Object>{'exit_code': exitCode, 'output': output};
533 }
534 }
535
536 /**
537 * Default implementation of [WorkerConnection] that works with stdio.
538 */
539 class _StdWorkerConnection implements WorkerConnection {
540 @override
541 String readLineSync() {
542 return io.stdin.readLineSync();
543 }
544
545 @override
546 void writeJson(Map<String, Object> json) {
547 io.stdout.writeln(JSON.encode(json));
548 }
549 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer_cli/lib/src/driver.dart » ('j') | pkg/analyzer_cli/lib/src/options.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698