17169aa30eeaac89c49984bb9d061ca152d43391aBill Napier/* 27169aa30eeaac89c49984bb9d061ca152d43391aBill Napier * Copyright (C) 2010 The Android Open Source Project 37169aa30eeaac89c49984bb9d061ca152d43391aBill Napier * 47169aa30eeaac89c49984bb9d061ca152d43391aBill Napier * Licensed under the Apache License, Version 2.0 (the "License"); 57169aa30eeaac89c49984bb9d061ca152d43391aBill Napier * you may not use this file except in compliance with the License. 67169aa30eeaac89c49984bb9d061ca152d43391aBill Napier * You may obtain a copy of the License at 77169aa30eeaac89c49984bb9d061ca152d43391aBill Napier * 87169aa30eeaac89c49984bb9d061ca152d43391aBill Napier * http://www.apache.org/licenses/LICENSE-2.0 97169aa30eeaac89c49984bb9d061ca152d43391aBill Napier * 107169aa30eeaac89c49984bb9d061ca152d43391aBill Napier * Unless required by applicable law or agreed to in writing, software 117169aa30eeaac89c49984bb9d061ca152d43391aBill Napier * distributed under the License is distributed on an "AS IS" BASIS, 127169aa30eeaac89c49984bb9d061ca152d43391aBill Napier * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137169aa30eeaac89c49984bb9d061ca152d43391aBill Napier * See the License for the specific language governing permissions and 147169aa30eeaac89c49984bb9d061ca152d43391aBill Napier * limitations under the License. 157169aa30eeaac89c49984bb9d061ca152d43391aBill Napier */ 167169aa30eeaac89c49984bb9d061ca152d43391aBill Napierpackage com.android.monkeyrunner; 177169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 187169aa30eeaac89c49984bb9d061ca152d43391aBill Napierimport com.google.common.base.Predicate; 197169aa30eeaac89c49984bb9d061ca152d43391aBill Napierimport com.google.common.collect.ImmutableMap; 207169aa30eeaac89c49984bb9d061ca152d43391aBill Napierimport com.google.common.collect.ImmutableMap.Builder; 21d1efb3282762072d219285643792ff0119e3ed96Bill Napierimport com.google.common.collect.Lists; 227169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 237169aa30eeaac89c49984bb9d061ca152d43391aBill Napierimport org.python.core.Py; 247169aa30eeaac89c49984bb9d061ca152d43391aBill Napierimport org.python.core.PyException; 25d1efb3282762072d219285643792ff0119e3ed96Bill Napierimport org.python.core.PyJavaPackage; 26d1efb3282762072d219285643792ff0119e3ed96Bill Napierimport org.python.core.PyList; 277169aa30eeaac89c49984bb9d061ca152d43391aBill Napierimport org.python.core.PyObject; 28d1efb3282762072d219285643792ff0119e3ed96Bill Napierimport org.python.core.PyString; 29d1efb3282762072d219285643792ff0119e3ed96Bill Napierimport org.python.core.PySystemState; 307169aa30eeaac89c49984bb9d061ca152d43391aBill Napierimport org.python.util.InteractiveConsole; 317169aa30eeaac89c49984bb9d061ca152d43391aBill Napierimport org.python.util.JLineConsole; 327169aa30eeaac89c49984bb9d061ca152d43391aBill Napierimport org.python.util.PythonInterpreter; 337169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 347169aa30eeaac89c49984bb9d061ca152d43391aBill Napierimport java.io.File; 357169aa30eeaac89c49984bb9d061ca152d43391aBill Napierimport java.util.Arrays; 367169aa30eeaac89c49984bb9d061ca152d43391aBill Napierimport java.util.Collection; 377169aa30eeaac89c49984bb9d061ca152d43391aBill Napierimport java.util.Collections; 387169aa30eeaac89c49984bb9d061ca152d43391aBill Napierimport java.util.List; 397169aa30eeaac89c49984bb9d061ca152d43391aBill Napierimport java.util.Map; 407169aa30eeaac89c49984bb9d061ca152d43391aBill Napierimport java.util.Properties; 417169aa30eeaac89c49984bb9d061ca152d43391aBill Napierimport java.util.logging.Level; 427169aa30eeaac89c49984bb9d061ca152d43391aBill Napierimport java.util.logging.Logger; 437169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 447169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 457169aa30eeaac89c49984bb9d061ca152d43391aBill Napier/** 467169aa30eeaac89c49984bb9d061ca152d43391aBill Napier * Runs Jython based scripts. 477169aa30eeaac89c49984bb9d061ca152d43391aBill Napier */ 487169aa30eeaac89c49984bb9d061ca152d43391aBill Napierpublic class ScriptRunner { 497169aa30eeaac89c49984bb9d061ca152d43391aBill Napier private static final Logger LOG = Logger.getLogger(MonkeyRunnerOptions.class.getName()); 507169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 517169aa30eeaac89c49984bb9d061ca152d43391aBill Napier /** The "this" scope object for scripts. */ 527169aa30eeaac89c49984bb9d061ca152d43391aBill Napier private final Object scope; 537169aa30eeaac89c49984bb9d061ca152d43391aBill Napier private final String variable; 547169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 557169aa30eeaac89c49984bb9d061ca152d43391aBill Napier /** Private constructor. */ 567169aa30eeaac89c49984bb9d061ca152d43391aBill Napier private ScriptRunner(Object scope, String variable) { 577169aa30eeaac89c49984bb9d061ca152d43391aBill Napier this.scope = scope; 587169aa30eeaac89c49984bb9d061ca152d43391aBill Napier this.variable = variable; 597169aa30eeaac89c49984bb9d061ca152d43391aBill Napier } 607169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 617169aa30eeaac89c49984bb9d061ca152d43391aBill Napier /** Creates a new instance for the given scope object. */ 627169aa30eeaac89c49984bb9d061ca152d43391aBill Napier public static ScriptRunner newInstance(Object scope, String variable) { 637169aa30eeaac89c49984bb9d061ca152d43391aBill Napier return new ScriptRunner(scope, variable); 647169aa30eeaac89c49984bb9d061ca152d43391aBill Napier } 657169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 667169aa30eeaac89c49984bb9d061ca152d43391aBill Napier /** 677169aa30eeaac89c49984bb9d061ca152d43391aBill Napier * Runs the specified Jython script. First runs the initialization script to 687169aa30eeaac89c49984bb9d061ca152d43391aBill Napier * preload the appropriate client library version. 697169aa30eeaac89c49984bb9d061ca152d43391aBill Napier * 707169aa30eeaac89c49984bb9d061ca152d43391aBill Napier * @param scriptfilename the name of the file to run. 717169aa30eeaac89c49984bb9d061ca152d43391aBill Napier * @param args the arguments passed in (excluding the filename). 727169aa30eeaac89c49984bb9d061ca152d43391aBill Napier * @param plugins a list of plugins to load. 737169aa30eeaac89c49984bb9d061ca152d43391aBill Napier * @return the error code from running the script. 747169aa30eeaac89c49984bb9d061ca152d43391aBill Napier */ 755026cf75831b905d5002709abbd4b5a592628ddaBill Napier public static int run(String executablePath, String scriptfilename, 765026cf75831b905d5002709abbd4b5a592628ddaBill Napier Collection<String> args, Map<String, 775026cf75831b905d5002709abbd4b5a592628ddaBill Napier Predicate<PythonInterpreter>> plugins) { 787169aa30eeaac89c49984bb9d061ca152d43391aBill Napier // Add the current directory of the script to the python.path search path. 797169aa30eeaac89c49984bb9d061ca152d43391aBill Napier File f = new File(scriptfilename); 807169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 817169aa30eeaac89c49984bb9d061ca152d43391aBill Napier // Adjust the classpath so jython can access the classes in the specified classpath. 827169aa30eeaac89c49984bb9d061ca152d43391aBill Napier Collection<String> classpath = Lists.newArrayList(f.getParent()); 837169aa30eeaac89c49984bb9d061ca152d43391aBill Napier classpath.addAll(plugins.keySet()); 847169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 857169aa30eeaac89c49984bb9d061ca152d43391aBill Napier String[] argv = new String[args.size() + 1]; 867169aa30eeaac89c49984bb9d061ca152d43391aBill Napier argv[0] = f.getAbsolutePath(); 877169aa30eeaac89c49984bb9d061ca152d43391aBill Napier int x = 1; 887169aa30eeaac89c49984bb9d061ca152d43391aBill Napier for (String arg : args) { 897169aa30eeaac89c49984bb9d061ca152d43391aBill Napier argv[x++] = arg; 907169aa30eeaac89c49984bb9d061ca152d43391aBill Napier } 917169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 925026cf75831b905d5002709abbd4b5a592628ddaBill Napier initPython(executablePath, classpath, argv); 937169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 947169aa30eeaac89c49984bb9d061ca152d43391aBill Napier PythonInterpreter python = new PythonInterpreter(); 957169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 967169aa30eeaac89c49984bb9d061ca152d43391aBill Napier // Now let the mains run. 977169aa30eeaac89c49984bb9d061ca152d43391aBill Napier for (Map.Entry<String, Predicate<PythonInterpreter>> entry : plugins.entrySet()) { 987169aa30eeaac89c49984bb9d061ca152d43391aBill Napier boolean success; 997169aa30eeaac89c49984bb9d061ca152d43391aBill Napier try { 1007169aa30eeaac89c49984bb9d061ca152d43391aBill Napier success = entry.getValue().apply(python); 1017169aa30eeaac89c49984bb9d061ca152d43391aBill Napier } catch (Exception e) { 1027169aa30eeaac89c49984bb9d061ca152d43391aBill Napier LOG.log(Level.SEVERE, "Plugin Main through an exception.", e); 1037169aa30eeaac89c49984bb9d061ca152d43391aBill Napier continue; 1047169aa30eeaac89c49984bb9d061ca152d43391aBill Napier } 1057169aa30eeaac89c49984bb9d061ca152d43391aBill Napier if (!success) { 1067169aa30eeaac89c49984bb9d061ca152d43391aBill Napier LOG.severe("Plugin Main returned error for: " + entry.getKey()); 1077169aa30eeaac89c49984bb9d061ca152d43391aBill Napier } 1087169aa30eeaac89c49984bb9d061ca152d43391aBill Napier } 1097169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 1107169aa30eeaac89c49984bb9d061ca152d43391aBill Napier // Bind __name__ to __main__ so mains will run 1117169aa30eeaac89c49984bb9d061ca152d43391aBill Napier python.set("__name__", "__main__"); 112d1efb3282762072d219285643792ff0119e3ed96Bill Napier // Also find __file__ 113d1efb3282762072d219285643792ff0119e3ed96Bill Napier python.set("__file__", scriptfilename); 1147169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 1157169aa30eeaac89c49984bb9d061ca152d43391aBill Napier try { 1167169aa30eeaac89c49984bb9d061ca152d43391aBill Napier python.execfile(scriptfilename); 1177169aa30eeaac89c49984bb9d061ca152d43391aBill Napier } catch (PyException e) { 1187169aa30eeaac89c49984bb9d061ca152d43391aBill Napier if (Py.SystemExit.equals(e.type)) { 1197169aa30eeaac89c49984bb9d061ca152d43391aBill Napier // Then recover the error code so we can pass it on 1207169aa30eeaac89c49984bb9d061ca152d43391aBill Napier return (Integer) e.value.__tojava__(Integer.class); 1217169aa30eeaac89c49984bb9d061ca152d43391aBill Napier } 1227169aa30eeaac89c49984bb9d061ca152d43391aBill Napier // Then some other kind of exception was thrown. Log it and return error; 1237169aa30eeaac89c49984bb9d061ca152d43391aBill Napier LOG.log(Level.SEVERE, "Script terminated due to an exception", e); 1247169aa30eeaac89c49984bb9d061ca152d43391aBill Napier return 1; 1257169aa30eeaac89c49984bb9d061ca152d43391aBill Napier } 1267169aa30eeaac89c49984bb9d061ca152d43391aBill Napier return 0; 1277169aa30eeaac89c49984bb9d061ca152d43391aBill Napier } 1287169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 1295026cf75831b905d5002709abbd4b5a592628ddaBill Napier public static void runString(String executablePath, String script) { 1305026cf75831b905d5002709abbd4b5a592628ddaBill Napier initPython(executablePath); 1317169aa30eeaac89c49984bb9d061ca152d43391aBill Napier PythonInterpreter python = new PythonInterpreter(); 1327169aa30eeaac89c49984bb9d061ca152d43391aBill Napier python.exec(script); 1337169aa30eeaac89c49984bb9d061ca152d43391aBill Napier } 1347169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 1355026cf75831b905d5002709abbd4b5a592628ddaBill Napier public static Map<String, PyObject> runStringAndGet(String executablePath, 1365026cf75831b905d5002709abbd4b5a592628ddaBill Napier String script, String... names) { 1375026cf75831b905d5002709abbd4b5a592628ddaBill Napier return runStringAndGet(executablePath, script, Arrays.asList(names)); 1387169aa30eeaac89c49984bb9d061ca152d43391aBill Napier } 1397169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 1405026cf75831b905d5002709abbd4b5a592628ddaBill Napier public static Map<String, PyObject> runStringAndGet(String executablePath, 1415026cf75831b905d5002709abbd4b5a592628ddaBill Napier String script, Collection<String> names) { 1425026cf75831b905d5002709abbd4b5a592628ddaBill Napier initPython(executablePath); 1437169aa30eeaac89c49984bb9d061ca152d43391aBill Napier final PythonInterpreter python = new PythonInterpreter(); 1447169aa30eeaac89c49984bb9d061ca152d43391aBill Napier python.exec(script); 1457169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 1467169aa30eeaac89c49984bb9d061ca152d43391aBill Napier Builder<String, PyObject> builder = ImmutableMap.builder(); 1477169aa30eeaac89c49984bb9d061ca152d43391aBill Napier for (String name : names) { 1487169aa30eeaac89c49984bb9d061ca152d43391aBill Napier builder.put(name, python.get(name)); 1497169aa30eeaac89c49984bb9d061ca152d43391aBill Napier } 1507169aa30eeaac89c49984bb9d061ca152d43391aBill Napier return builder.build(); 1517169aa30eeaac89c49984bb9d061ca152d43391aBill Napier } 1527169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 1535026cf75831b905d5002709abbd4b5a592628ddaBill Napier private static void initPython(String executablePath) { 1547169aa30eeaac89c49984bb9d061ca152d43391aBill Napier List<String> arg = Collections.emptyList(); 1555026cf75831b905d5002709abbd4b5a592628ddaBill Napier initPython(executablePath, arg, new String[] {""}); 1567169aa30eeaac89c49984bb9d061ca152d43391aBill Napier } 1577169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 1585026cf75831b905d5002709abbd4b5a592628ddaBill Napier private static void initPython(String executablePath, 1595026cf75831b905d5002709abbd4b5a592628ddaBill Napier Collection<String> pythonPath, String[] argv) { 1607169aa30eeaac89c49984bb9d061ca152d43391aBill Napier Properties props = new Properties(); 1617169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 1627169aa30eeaac89c49984bb9d061ca152d43391aBill Napier // Build up the python.path 1637169aa30eeaac89c49984bb9d061ca152d43391aBill Napier StringBuilder sb = new StringBuilder(); 1647169aa30eeaac89c49984bb9d061ca152d43391aBill Napier sb.append(System.getProperty("java.class.path")); 1657169aa30eeaac89c49984bb9d061ca152d43391aBill Napier for (String p : pythonPath) { 1667169aa30eeaac89c49984bb9d061ca152d43391aBill Napier sb.append(":").append(p); 1677169aa30eeaac89c49984bb9d061ca152d43391aBill Napier } 1687169aa30eeaac89c49984bb9d061ca152d43391aBill Napier props.setProperty("python.path", sb.toString()); 1697169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 1707169aa30eeaac89c49984bb9d061ca152d43391aBill Napier /** Initialize the python interpreter. */ 1717169aa30eeaac89c49984bb9d061ca152d43391aBill Napier // Default is 'message' which displays sys-package-mgr bloat 1727169aa30eeaac89c49984bb9d061ca152d43391aBill Napier // Choose one of error,warning,message,comment,debug 1737169aa30eeaac89c49984bb9d061ca152d43391aBill Napier props.setProperty("python.verbose", "error"); 1747169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 1755026cf75831b905d5002709abbd4b5a592628ddaBill Napier // This needs to be set for sys.executable to function properly 1765026cf75831b905d5002709abbd4b5a592628ddaBill Napier props.setProperty("python.executable", executablePath); 1775026cf75831b905d5002709abbd4b5a592628ddaBill Napier 1787169aa30eeaac89c49984bb9d061ca152d43391aBill Napier PythonInterpreter.initialize(System.getProperties(), props, argv); 179d1efb3282762072d219285643792ff0119e3ed96Bill Napier 180d1efb3282762072d219285643792ff0119e3ed96Bill Napier String frameworkDir = System.getProperty("java.ext.dirs"); 181d1efb3282762072d219285643792ff0119e3ed96Bill Napier File monkeyRunnerJar = new File(frameworkDir, "monkeyrunner.jar"); 182d1efb3282762072d219285643792ff0119e3ed96Bill Napier if (monkeyRunnerJar.canRead()) { 183d1efb3282762072d219285643792ff0119e3ed96Bill Napier PySystemState.packageManager.addJar(monkeyRunnerJar.getAbsolutePath(), false); 184d1efb3282762072d219285643792ff0119e3ed96Bill Napier } 1857169aa30eeaac89c49984bb9d061ca152d43391aBill Napier } 1867169aa30eeaac89c49984bb9d061ca152d43391aBill Napier 1877169aa30eeaac89c49984bb9d061ca152d43391aBill Napier /** 1887169aa30eeaac89c49984bb9d061ca152d43391aBill Napier * Start an interactive python interpreter. 1897169aa30eeaac89c49984bb9d061ca152d43391aBill Napier */ 1905026cf75831b905d5002709abbd4b5a592628ddaBill Napier public static void console(String executablePath) { 1915026cf75831b905d5002709abbd4b5a592628ddaBill Napier initPython(executablePath); 1927169aa30eeaac89c49984bb9d061ca152d43391aBill Napier InteractiveConsole python = new JLineConsole(); 1937169aa30eeaac89c49984bb9d061ca152d43391aBill Napier python.interact(); 1947169aa30eeaac89c49984bb9d061ca152d43391aBill Napier } 1957169aa30eeaac89c49984bb9d061ca152d43391aBill Napier} 196