blob: c247a5f1a1dd8cf082bdc8408c9674dac4dfaea8 [file] [log] [blame]
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.monkeyrunner;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.ImmutableMap.Builder;
import org.python.core.Py;
import org.python.core.PyException;
import org.python.core.PyObject;
import org.python.util.InteractiveConsole;
import org.python.util.JLineConsole;
import org.python.util.PythonInterpreter;
import java.io.File;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Runs Jython based scripts.
*/
public class ScriptRunner {
private static final Logger LOG = Logger.getLogger(MonkeyRunnerOptions.class.getName());
/** The "this" scope object for scripts. */
private final Object scope;
private final String variable;
/** Private constructor. */
private ScriptRunner(Object scope, String variable) {
this.scope = scope;
this.variable = variable;
}
/** Creates a new instance for the given scope object. */
public static ScriptRunner newInstance(Object scope, String variable) {
return new ScriptRunner(scope, variable);
}
/**
* Runs the specified Jython script. First runs the initialization script to
* preload the appropriate client library version.
*
* @param scriptfilename the name of the file to run.
* @param args the arguments passed in (excluding the filename).
* @param plugins a list of plugins to load.
* @return the error code from running the script.
*/
public static int run(String scriptfilename, Collection<String> args,
Map<String, Predicate<PythonInterpreter>> plugins) {
// Add the current directory of the script to the python.path search path.
File f = new File(scriptfilename);
// Adjust the classpath so jython can access the classes in the specified classpath.
Collection<String> classpath = Lists.newArrayList(f.getParent());
classpath.addAll(plugins.keySet());
String[] argv = new String[args.size() + 1];
argv[0] = f.getAbsolutePath();
int x = 1;
for (String arg : args) {
argv[x++] = arg;
}
initPython(classpath, argv);
PythonInterpreter python = new PythonInterpreter();
// Now let the mains run.
for (Map.Entry<String, Predicate<PythonInterpreter>> entry : plugins.entrySet()) {
boolean success;
try {
success = entry.getValue().apply(python);
} catch (Exception e) {
LOG.log(Level.SEVERE, "Plugin Main through an exception.", e);
continue;
}
if (!success) {
LOG.severe("Plugin Main returned error for: " + entry.getKey());
}
}
// Bind __name__ to __main__ so mains will run
python.set("__name__", "__main__");
try {
python.execfile(scriptfilename);
} catch (PyException e) {
if (Py.SystemExit.equals(e.type)) {
// Then recover the error code so we can pass it on
return (Integer) e.value.__tojava__(Integer.class);
}
// Then some other kind of exception was thrown. Log it and return error;
LOG.log(Level.SEVERE, "Script terminated due to an exception", e);
return 1;
}
return 0;
}
public static void runString(String script) {
initPython();
PythonInterpreter python = new PythonInterpreter();
python.exec(script);
}
public static Map<String, PyObject> runStringAndGet(String script, String... names) {
return runStringAndGet(script, Arrays.asList(names));
}
public static Map<String, PyObject> runStringAndGet(String script, Collection<String> names) {
initPython();
final PythonInterpreter python = new PythonInterpreter();
python.exec(script);
Builder<String, PyObject> builder = ImmutableMap.builder();
for (String name : names) {
builder.put(name, python.get(name));
}
return builder.build();
}
private static void initPython() {
List<String> arg = Collections.emptyList();
initPython(arg, new String[] {""});
}
private static void initPython(Collection<String> pythonPath,
String[] argv) {
Properties props = new Properties();
// Build up the python.path
StringBuilder sb = new StringBuilder();
sb.append(System.getProperty("java.class.path"));
for (String p : pythonPath) {
sb.append(":").append(p);
}
props.setProperty("python.path", sb.toString());
/** Initialize the python interpreter. */
// Default is 'message' which displays sys-package-mgr bloat
// Choose one of error,warning,message,comment,debug
props.setProperty("python.verbose", "error");
PythonInterpreter.initialize(System.getProperties(), props, argv);
}
/**
* Start an interactive python interpreter.
*/
public static void console() {
initPython();
InteractiveConsole python = new JLineConsole();
python.interact();
}
}