// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. package com.google.dart.runner; import com.google.common.collect.Lists; import java.io.BufferedReader; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Runs a given JS-script in d8 (part of V8). */ public class V8Launcher implements JavaScriptLauncher { private static class Drainer implements Runnable { private final InputStream stream; private final List lines; private final PrintStream out; public Drainer(InputStream stream, PrintStream out, List lines) { this.stream = stream; this.lines = lines; this.out = out; } @Override public void run() { BufferedReader r = new BufferedReader(new InputStreamReader(stream)); String str; try { while ((str = r.readLine()) != null) { if (lines != null) { lines.add(str); } out.println(str); } } catch (IOException e) { throw new AssertionError(e); } } } private static final String D8_ENVIRONMENT_VARIABLE = "D8_EXEC"; private static final String EOL = System.getProperty("line.separator"); public V8Launcher() { } @Override public void execute(String jsScript, String sourceName, String[] args, RunnerOptions options, PrintStream stdout, PrintStream stderr) throws RunnerError { if (!isConfigured()) { throw new RunnerError("Please set the " + D8_ENVIRONMENT_VARIABLE + " environment variable."); } File sourceFile; try { sourceFile = writeTempFile(sourceName, jsScript); } catch (IOException e) { throw new RunnerError(e); } try { ArrayList command = new ArrayList(); command.add(v8Executable().getAbsolutePath()); command.add(sourceFile.getAbsolutePath()); if (options.shouldProfile()) { command.add("--prof"); } command.add("--"); command.addAll(Arrays.asList(args)); int exitValue; Process p = null; List stdOutLines = Lists.newArrayList(); Thread stdOutDrain = null; Thread stdErrDrain = null; try { p = Runtime.getRuntime().exec(command.toArray(new String[0])); // TODO(floitsch): we should handle timeouts (but how long should we wait?). stdOutDrain = new Thread(new Drainer(p.getInputStream(), stdout, stdOutLines)); stdErrDrain = new Thread(new Drainer(p.getErrorStream(), stderr, null)); stdOutDrain.start(); stdErrDrain.start(); try { exitValue = p.waitFor(); } catch (InterruptedException e) { throw new RuntimeException(e); } } catch (IOException e) { throw new RunnerError(e); } finally { try { if (stdOutDrain != null) { stdOutDrain.join(); } if (stdErrDrain != null) { stdErrDrain.join(); } } catch (InterruptedException e) { throw new RuntimeException(e); } try { p.getInputStream().close(); p.getOutputStream().close(); p.getOutputStream().close(); } catch (IOException e) { throw new RunnerError(e); } p.destroy(); } if (exitValue != 0) { StringWriter stringWriter = new StringWriter(); PrintWriter out = new PrintWriter(stringWriter); if (options.verbose()) { out.println(jsScript); } out.println("Execution failed."); out.println("V8 execution returned non-zero exit-code: " + p.exitValue()); out.flush(); throw new RunnerError(stringWriter.toString()); } } finally { sourceFile.delete(); } } private File writeTempFile(String name, String content) throws IOException { // The first argument to createTempFile must be at least three characters long, and be a // valid file-name. name = name.replace('/', '_'); File file = File.createTempFile("dart_" + name, ".js"); FileWriter writer = new FileWriter(file); try { writer.write(content); } finally { writer.close(); } return file; } private static File v8Executable() { String d8Path = System.getProperty("com.google.dart.runner.d8", System.getenv(D8_ENVIRONMENT_VARIABLE)); if (d8Path == null) { String testSrcDir = System.getenv("TEST_SRCDIR"); if (testSrcDir == null) { return null; } return new File(new File(new File(new File(testSrcDir, "google3"), "third_party"), "v8"), "d8"); } else { return new File(d8Path); } } /** * @return true if the D8_EXEC environment variable is correctly set up. */ public static boolean isConfigured() { File file = v8Executable(); if (file == null) { return false; } return file.canExecute(); } }