|  | // Copyright 2015 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | import 'dart:async'; | 
|  | import 'dart:convert'; | 
|  | import 'dart:io'; | 
|  |  | 
|  | import 'context.dart'; | 
|  |  | 
|  | typedef String StringConverter(String string); | 
|  |  | 
|  | /// This runs the command and streams stdout/stderr from the child process to | 
|  | /// this process' stdout/stderr. | 
|  | Future<int> runCommandAndStreamOutput(List<String> cmd, { | 
|  | String workingDirectory, | 
|  | String prefix: '', | 
|  | RegExp filter, | 
|  | StringConverter mapFunction | 
|  | }) async { | 
|  | printTrace(cmd.join(' ')); | 
|  | Process process = await Process.start( | 
|  | cmd[0], | 
|  | cmd.sublist(1), | 
|  | workingDirectory: workingDirectory | 
|  | ); | 
|  | process.stdout | 
|  | .transform(UTF8.decoder) | 
|  | .transform(const LineSplitter()) | 
|  | .where((String line) => filter == null ? true : filter.hasMatch(line)) | 
|  | .listen((String line) { | 
|  | if (mapFunction != null) | 
|  | line = mapFunction(line); | 
|  | if (line != null) | 
|  | printStatus('$prefix$line'); | 
|  | }); | 
|  | process.stderr | 
|  | .transform(UTF8.decoder) | 
|  | .transform(const LineSplitter()) | 
|  | .where((String line) => filter == null ? true : filter.hasMatch(line)) | 
|  | .listen((String line) { | 
|  | if (mapFunction != null) | 
|  | line = mapFunction(line); | 
|  | if (line != null) | 
|  | printError('$prefix$line'); | 
|  | }); | 
|  | return await process.exitCode; | 
|  | } | 
|  |  | 
|  | Future runAndKill(List<String> cmd, Duration timeout) { | 
|  | Future<Process> proc = runDetached(cmd); | 
|  | return new Future.delayed(timeout, () async { | 
|  | printTrace('Intentionally killing ${cmd[0]}'); | 
|  | Process.killPid((await proc).pid); | 
|  | }); | 
|  | } | 
|  |  | 
|  | Future<Process> runDetached(List<String> cmd) { | 
|  | printTrace(cmd.join(' ')); | 
|  | Future<Process> proc = Process.start( | 
|  | cmd[0], cmd.getRange(1, cmd.length).toList(), | 
|  | mode: ProcessStartMode.DETACHED); | 
|  | return proc; | 
|  | } | 
|  |  | 
|  | /// Run cmd and return stdout. | 
|  | /// Throws an error if cmd exits with a non-zero value. | 
|  | String runCheckedSync(List<String> cmd, { String workingDirectory }) { | 
|  | return _runWithLoggingSync(cmd, workingDirectory: workingDirectory, checked: true, noisyErrors: true); | 
|  | } | 
|  |  | 
|  | /// Run cmd and return stdout. | 
|  | String runSync(List<String> cmd, { String workingDirectory }) { | 
|  | return _runWithLoggingSync(cmd, workingDirectory: workingDirectory); | 
|  | } | 
|  |  | 
|  | /// Return the platform specific name for the given Dart SDK binary. So, `pub` | 
|  | /// ==> `pub.bat`. | 
|  | String sdkBinaryName(String name) { | 
|  | return Platform.isWindows ? '$name.bat' : name; | 
|  | } | 
|  |  | 
|  | String _runWithLoggingSync(List<String> cmd, { | 
|  | bool checked: false, | 
|  | bool noisyErrors: false, | 
|  | String workingDirectory | 
|  | }) { | 
|  | printTrace(cmd.join(' ')); | 
|  | ProcessResult results = | 
|  | Process.runSync(cmd[0], cmd.getRange(1, cmd.length).toList(), workingDirectory: workingDirectory); | 
|  | if (results.exitCode != 0) { | 
|  | String errorDescription = 'Error code ${results.exitCode} ' | 
|  | 'returned when attempting to run command: ${cmd.join(' ')}'; | 
|  | printTrace(errorDescription); | 
|  | if (results.stderr.length > 0) { | 
|  | if (noisyErrors) { | 
|  | printError(results.stderr.trim()); | 
|  | } else { | 
|  | printTrace('Errors logged: ${results.stderr.trim()}'); | 
|  | } | 
|  | } | 
|  | if (checked) | 
|  | throw errorDescription; | 
|  | } | 
|  | if (results.stdout.trim().isNotEmpty) | 
|  | printTrace(results.stdout.trim()); | 
|  | return results.stdout; | 
|  | } | 
|  |  | 
|  | class ProcessExit implements Exception { | 
|  | final int exitCode; | 
|  | ProcessExit(this.exitCode); | 
|  | String get message => 'ProcessExit: $exitCode'; | 
|  | String toString() => message; | 
|  | } |