Chromium Code Reviews| Index: utils/testrunner/pipeline_utils.dart |
| =================================================================== |
| --- utils/testrunner/pipeline_utils.dart (revision 21707) |
| +++ utils/testrunner/pipeline_utils.dart (working copy) |
| @@ -4,7 +4,7 @@ |
| part of pipeline; |
| -List stdout, stderr, log; |
| +List log; |
| var replyPort; |
| int _procId = 1; |
| Map _procs = {}; |
| @@ -14,7 +14,7 @@ |
| * [tmpDir] directory, with name [basis], but with any extension |
| * stripped and replaced by [suffix]. |
| */ |
| -String createTempName(String tmpDir, String basis, String suffix) { |
| +String createTempName(String tmpDir, String basis, [String suffix='']) { |
| var p = new Path(basis); |
| return '$tmpDir${Platform.pathSeparator}' |
| '${p.filenameWithoutExtension}${suffix}'; |
| @@ -41,9 +41,7 @@ |
| /** Create a file [fileName] and populate it with [contents]. */ |
| void writeFile(String fileName, String contents) { |
| var file = new File(fileName); |
| - var ostream = file.openOutputStream(FileMode.WRITE); |
| - ostream.writeString(contents); |
| - ostream.close(); |
| + file.writeAsStringSync(contents); |
| } |
| /* |
| @@ -59,62 +57,84 @@ |
| * Returns a [Future] for when the process terminates. |
| */ |
| Future _processHelper(String command, List<String> args, |
|
Siggi Cherem (dart-lang)
2013/04/19 21:39:39
is this duplicate code with the other _processHelp
gram
2013/04/22 23:54:27
No, it is not a dup; it has some subtle difference
Siggi Cherem (dart-lang)
2013/04/23 01:10:04
I think you can use Future.wait instead, using str
gram
2013/04/23 22:53:40
Done.
|
| - [int timeout = 300, int procId = 0, Function outputMonitor]) { |
| - var completer = procId == 0 ? new Completer() : null; |
| + List stdout, List stderr, |
| + [int timeout = 30, int procId = 0, Function outputMonitor]) { |
| + var completer = procId == 0 ? (new Completer()) : null; |
| + var timer = null; |
| + if (Platform.operatingSystem == 'windows' && command.endsWith('.bat')) { |
| + var oldArgs = args; |
| + args = new List(); |
| + args.add('/k'); |
| + // TODO(gram): We may need some escaping here if any of the |
| + // components contain spaces. |
| + args.add("$command ${oldArgs.join(' ')}"); |
| + command='cmd.exe'; |
| + } |
| log.add('Running $command ${args.join(" ")}'); |
| - var timer = null; |
| - var stdoutHandler, stderrHandler; |
| + // We are not done until the process has exited and both the stdout |
| + // and stderr streams have drained; at that point we want to return |
| + // the process exit code. We manage this with local state consisting |
| + // of three flags and an int in a List. |
| + // There is probably a better way to do this. |
| + var doneState = [ false, false, false, 0 ]; |
| var processFuture = Process.start(command, args); |
| processFuture.then((process) { |
| - _procs[procId] = process; |
| + _procs[procId.toString()] = process; |
| timer = new Timer(new Duration(seconds: timeout), () { |
| timer = null; |
| process.kill(); |
| }); |
| - process.onExit = (exitCode) { |
| + process.exitCode.then((exitCode) { |
| if (timer != null) { |
| timer.cancel(); |
| } |
| - process.close(); |
| if (completer != null) { |
| - completer.complete(exitCode); |
| + doneState[3] = exitCode; |
| + _checkComplete(doneState, 2, completer); |
| } |
| - }; |
| - |
| - _pipeStream(process.stdout, stdout, outputMonitor); |
| - _pipeStream(process.stderr, stderr, outputMonitor); |
| - }); |
| - processFuture.handleException((e) { |
| + }); |
| + _pipeStream(process.stdout, stdout, outputMonitor, |
| + doneState, 0, completer); |
| + _pipeStream(process.stderr, stderr, outputMonitor, |
| + doneState, 1, completer); |
| + }) |
| + .catchError((e) { |
| stderr.add("Error starting process:"); |
| stderr.add(" Command: $command"); |
| - stderr.add(" Error: $e"); |
| - completePipeline(-1); |
| - return true; |
| + stderr.add(" Error: ${e.error}"); |
| + completePipeline(stdout, stderr, -1); |
| }); |
| - return completer.future; |
| + return completer == null ? null : completer.future; |
| } |
| -void _pipeStream(InputStream stream, List<String> destination, |
| - Function outputMonitor) { |
| - var source = new StringInputStream(stream); |
| - source.onLine = () { |
| - if (source.available() == 0) return; |
| - var line = source.readLine(); |
| - while (null != line) { |
| +void _checkComplete(List doneState, int index, Completer completer) { |
| + doneState[index] = true; |
| + if (completer != null && doneState[0] && doneState[1] && doneState[2]) { |
| + completer.complete(doneState[3]); |
| + } |
| +} |
| + |
| +void _pipeStream(Stream stream, List<String> destination, |
| + Function outputMonitor, |
| + List doneState, int stateIndex, Completer completer) { |
| + stream |
| + .transform(new StringDecoder()) |
| + .transform(new LineTransformer()) |
| + .listen((String line) { |
| if (config["immediate"] && line.startsWith('###')) { |
| - // TODO - when we dump the list later skip '###' messages if immediate. |
| print(line.substring(3)); |
| } |
| if (outputMonitor != null) { |
| outputMonitor(line); |
| } |
| destination.add(line); |
| - line = source.readLine(); |
| - } |
| - }; |
| + }, |
| + onDone: () { |
| + _checkComplete(doneState, stateIndex, completer); |
| + }); |
| } |
| /** |
| @@ -124,26 +144,32 @@ |
| * Returns a [Future] for when the process terminates. |
| */ |
| Future runCommand(String command, List<String> args, |
| - [int timeout = 300, Function outputMonitor]) { |
| - return _processHelper(command, args, timeout, outputMonitor:outputMonitor); |
| + List stdout, List stderr, |
| + [int timeout = 30, Function outputMonitor]) { |
| + return _processHelper(command, args, stdout, stderr, |
| + timeout, 0, outputMonitor); |
| } |
| /** |
| * Start an external process [cmd] with command line arguments [args]. |
| * Returns an ID by which it can later be stopped. |
| */ |
| -int startProcess(String command, List<String> args, [Function outputMonitor]) { |
| +int startProcess(String command, List<String> args, List stdout, List stderr, |
| + [Function outputMonitor]) { |
| int id = _procId++; |
| - _processHelper(command, args, 3000, id, |
| - outputMonitor:outputMonitor).then((e) { |
| - _procs.remove(id); |
| - }); |
| + var f = _processHelper(command, args, stdout, stderr, 3000, id, |
| + outputMonitor); |
| + if (f != null) { |
| + f.then((e) { |
| + _procs.remove(id.toString()); |
| + }); |
| + } |
| return id; |
| } |
| /** Checks if a process is still running. */ |
| bool isProcessRunning(int id) { |
| - return _procs.containsKey(id); |
| + return _procs.containsKey(id.toString()); |
| } |
| /** |
| @@ -151,15 +177,16 @@ |
| * given the id string. |
| */ |
| void stopProcess(int id) { |
| - if (_procs.containsKey(id)) { |
| - Process p = _procs.remove(id); |
| + var sid = id.toString(); |
| + if (_procs.containsKey(sid)) { |
| + Process p = _procs.remove(sid); |
| p.kill(); |
| } |
| } |
| /** Delete a file named [fname] if it exists. */ |
| bool cleanup(String fname) { |
| - if (fname != null && !config['keep-files']) { |
| + if (fname != null && config['clean-files']) { |
| var f = new File(fname); |
| try { |
| if (f.existsSync()) { |
| @@ -173,6 +200,22 @@ |
| return true; |
| } |
| +/** Delete a directory named [dname] if it exists. */ |
| +bool cleanupDir(String dname) { |
| + if (dname != null && config['clean-files']) { |
| + var d = new Directory(dname); |
| + try { |
| + if (d.existsSync()) { |
| + logMessage('Removing $dname'); |
| + d.deleteSync(recursive: true); |
| + } |
| + } catch (e) { |
| + return false; |
| + } |
| + } |
| + return true; |
| +} |
| + |
| initPipeline(port) { |
| replyPort = port; |
| stdout = new List(); |
| @@ -180,9 +223,12 @@ |
| log = new List(); |
| } |
| -void completePipeline([exitCode = 0]) { |
| +void completePipeline(List stdout, List stderr, [exitCode = 0]) { |
| replyPort.send([stdout, stderr, log, exitCode]); |
| } |
| /** Utility function to log diagnostic messages. */ |
| void logMessage(msg) => log.add(msg); |
| + |
| +/** Turn file paths into standard form with forward slashes. */ |
| +String normalizePath(String p) => (new Path(p)).toString(); |