From 22d3af523c89ed673ae9f2e9d98ea6ba49cf0dbc Mon Sep 17 00:00:00 2001 From: Sigmund Cherem Date: Wed, 20 Dec 2017 21:16:46 +0000 Subject: [PATCH] Add worker support to DDK Change-Id: I0ae333f1bd6776840b1377579377695a582c46ef Reviewed-on: https://dart-review.googlesource.com/30623 Reviewed-by: Jens Johansen Reviewed-by: Jake Macdonald Commit-Queue: Sigmund Cherem --- pkg/dev_compiler/bin/dartdevk.dart | 87 ++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 3 deletions(-) diff --git a/pkg/dev_compiler/bin/dartdevk.dart b/pkg/dev_compiler/bin/dartdevk.dart index 7a212de94b0..b0d6aecab0a 100755 --- a/pkg/dev_compiler/bin/dartdevk.dart +++ b/pkg/dev_compiler/bin/dartdevk.dart @@ -9,14 +9,18 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:bazel_worker/bazel_worker.dart'; import 'package:dev_compiler/src/kernel/command.dart'; import 'package:front_end/src/api_unstable/ddc.dart' as fe; Future main(List args) async { - if (args.isNotEmpty && args.last == "--batch") { - await runBatch(args.sublist(0, args.length - 1)); + var parsedArgs = _preprocessArgs(args); + if (parsedArgs.isBatch) { + await runBatch(parsedArgs.args); + } else if (parsedArgs.isWorker) { + await new _CompilerWorker(parsedArgs.args).run(); } else { - var result = await compile(args); + var result = await compile(parsedArgs.args); var succeeded = result.result; exitCode = succeeded ? 0 : 1; } @@ -60,3 +64,80 @@ Future runBatch(List batchArgs) async { var time = watch.elapsedMilliseconds; print('>>> BATCH END (${tests - failed})/$tests ${time}ms'); } + +/// Runs the compiler worker loop. +class _CompilerWorker extends AsyncWorkerLoop { + /// The original args supplied to the executable. + final List _startupArgs; + + _CompilerWorker(this._startupArgs) : super(); + + /// Performs each individual work request. + Future performRequest(WorkRequest request) async { + var args = _startupArgs.toList()..addAll(request.arguments); + + var output = new StringBuffer(); + var result = await runZoned(() => compile(args), zoneSpecification: + new ZoneSpecification(print: (self, parent, zone, message) { + output.writeln(message.toString()); + })); + return new WorkResponse() + ..exitCode = result.result ? 0 : 1 + ..output = output.toString(); + } +} + +/// Preprocess arguments to determine whether DDK is used in batch mode or as a +/// persistent worker. +/// +/// When used in batch mode, we expect a `--batch` parameter last. +/// +/// When used as a persistent bazel worker, the `--persistent_worker` might be +/// present, and an argument of the form `@path/to/file` might be provided. The +/// latter needs to be replaced by reading all the contents of the +/// file and expanding them into the resulting argument list. +_ParsedArgs _preprocessArgs(List args) { + if (args.isEmpty) return new _ParsedArgs(false, false, args); + + String lastArg = args.last; + if (lastArg == '--batch') { + return new _ParsedArgs(true, false, args.sublist(0, args.length - 1)); + } + + var newArgs = []; + bool isWorker = false; + var len = args.length; + for (int i = 0; i < len; i++) { + var arg = args[i]; + if (i == len - 1 && arg.startsWith('@')) { + newArgs.addAll(_readLines(arg.substring(1))); + } else if (arg == '--persistent_worker') { + isWorker = true; + } else { + newArgs.add(arg); + } + } + return new _ParsedArgs(false, isWorker, newArgs); +} + +/// Return all lines in a file found at [path]. +Iterable _readLines(String path) { + try { + return new File(path) + .readAsStringSync() + .replaceAll('\r\n', '\n') + .replaceAll('\r', '\n') + .split('\n') + .where((String line) => line.isNotEmpty); + } on FileSystemException catch (e) { + throw new Exception('Failed to read $path: $e'); + } +} + +class _ParsedArgs { + final bool isBatch; + final bool isWorker; + final List args; + + _ParsedArgs(this.isBatch, this.isWorker, this.args); +}