Merge "Introduce Gerrit Inspector: interactive Jython shell"

This commit is contained in:
Shawn Pearce
2013-10-18 01:15:20 +00:00
committed by Gerrit Code Review
7 changed files with 672 additions and 31 deletions

View File

@@ -0,0 +1,302 @@
Gerrit Inspector
================
NAME
----
Gerrit Inspector - Interactive Jython environment for Gerrit
SYNOPSIS
--------
[verse]
'java' -jar gerrit.war 'daemon'
-d <SITE_PATH>
[\--enable-httpd | \--disable-httpd]
[\--enable-sshd | \--disable-sshd]
[\--console-log]
[\--slave]
-s
DESCRIPTION
-----------
Runs the Gerrit network daemon on the local system as described
in the link:pgm-daemon.html[Daemon documentation], additionally
starting an interactive Jython shell for inspection
and troubleshooting of live data of the Gerrit instance.
CAUTION: Gerrit Inspector works directly on instances of Java Virtual
Machine objects and it is possible to read and write instance
members as well as invoke Java functions. Access is granted
also to 'private' and 'protected' members. Therefore it is possible
to introduce changes to the internal state of the system in
an inconsistent way. Care must be taken not to break the running system
and/or destroy the data.
INSTALLATION
------------
Gerrit Inspector requires Jython library ('jython.jar') to be installed
in the '$site_path/lib' directory. Jython, a Python interpreter for
the Java Virtual Machine, can be obtained from the http://www.jython.org/
website. Only 'jython.jar' file is needed, installation of Jython libraries
is optional. Gerrit Inspector has been tested with Jython 2.5.2 but
might work an earlier version.
STARTUP
-------
During startup Jython examines Java libraries found on the classpath.
While libraries are inspected a large amount of messages is displayed on the console:
----
*sys-package-mgr*: processing new jar, '/home/user/.gerritcodereview/tmp/gerrit_4890671371398741854_app/sshd-core-0.5.1-r1095809.jar'
----
After this a system-wide embedded initialization script is started. This script
is contained in the gerrit's WAR archive. This script produces output similar to
the following on the console:
----
"Shell" is "com.google.gerrit.pgm.shell.JythonShell@61644f2d"
"m" is "com.google.gerrit.lifecycle.LifecycleManager@6f03b248"
"ds" is "com.google.gerrit.server.schema.DataSourceProvider@6b3592c"
"schk" is "com.google.gerrit.server.schema.SchemaVersionCheck@5e8cb9bd"
Welcome to the Gerrit Inspector
Enter help() to see the above again, EOF to quit and stop Gerrit
----
Then an optional user startup script is processed. It should be
located in the gerrit user home directory as '.gerritcodereview/Startup.py'.
This script can access all variables defined in the system (such
as the ones displayed by the initialization script as shown above).
Variables and functions defined by the startup scripts are available for
the interactive interpreter.
When interactive interpreter exits (by issuing EOF on the command line),
a whole Gerrit instance is shut down gracefully.
USING THE INTERPRETER
---------------------
Gerrit Inspector launches Jython interpreter in the context of the Gerrit
Java Virtual Machine. All core facilities of the Jython (and Python)
language are available to the user.
Additional facilities can be provided, for example a 'Lib' directory from the
Jython distribution can be installed under '$site_path/lib/Lib' to provide
access to many standard Python modules. Jython can also use additional Java
classes and libraries and most of the Python modules and scripts.
The Inspector has by default access to classes and object instances available
in the Java Virtual Machine. Objects are introspected and *private* and *protected*
members are also available.
For more information on using Jython, especially with regards to its limitations
in interfacing to the Java Virtual Machine, please refer to the
http://www.jython.org/[Jython documentation].
After sucessful initialization it is possible to examine components of
Java packages, classes and live instances.
----
>>> import com.google.inject
>>> dir(com.google.inject)
['AbstractModule', 'Binder', 'Binding', 'BindingAnnotation', 'ConfigurationException', 'CreationException', 'Exposed', 'Guice', 'ImplementedBy', 'Inject', 'Injector', 'Key', 'MembersInjector', 'Module', 'OutOfScopeException', 'PrivateBinder', 'PrivateModule', 'ProvidedBy', 'Provider', 'Provides', 'ProvisionException', 'Scope', 'ScopeAnnotation', 'Scopes', 'Singleton', 'Stage', 'TypeLiteral', '__name__', 'assistedinject', 'binder', 'internal', 'matcher', 'name', 'servlet', 'spi', 'util']
>>> type(com.google.inject)
<type 'javapackage'>
>>> dir(com.google.inject.Guice)
['__class__', '__copy__', '__deepcopy__', '__delattr__', '__doc__',
'__eq__', '__getattribute__', '__hash__', '__init__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__str__', '__unicode__', 'class', 'clone', 'createInjector',
'equals', 'finalize', 'getClass', 'hashCode', 'notify', 'notifyAll',
'registerNatives', 'toString', 'wait']
----
Startup script provides some convenient variables to access some global Gerrit components,
for example a connection to the review database is kept open:
----
>>> ds
org.apache.commons.dbcp.BasicDataSource@61db2215
>>> ds.driverClassName
u'org.postgresql.Driver'
>>> ds.dataSource
org.apache.commons.dbcp.PoolingDataSource@23226fe1
>>> ds.dataSource.connection
jdbc:postgresql://localhost/reviewdb, UserName=rv, PostgreSQL Native Driver
----
It is also possible to interact with the ORM layer:
----
>>> db = schk.schema.open()
>>> db
com.google.gerrit.reviewdb.server.ReviewDb_Schema_GwtOrm$$28@24cbbdf3
>>> db.getDialect()
com.google.gwtorm.schema.sql.DialectPostgreSQL@4de07d3e
>>> for x in db.patchSets().iterateAllEntities():
... print x
...
[PatchSet 1,1]
[PatchSet 2,1]
[PatchSet 3,1]
[PatchSet 4,1]
[PatchSet 5,1]
[PatchSet 6,1]
[PatchSet 7,1]
[PatchSet 8,1]
[PatchSet 6,2]
>>> for x in db.patchComments().iterateAllEntities():
... print x
com.google.gerrit.reviewdb.client.PatchLineComment@5381298a
com.google.gerrit.reviewdb.client.PatchLineComment@44ce4dda
com.google.gerrit.reviewdb.client.PatchLineComment@44594680
>>> dir(com.google.gerrit.reviewdb.client.PatchLineComment)
['Key', 'STATUS_DRAFT', 'STATUS_PUBLISHED', 'Status', '__class__',
'__copy__', '__deepcopy__', '__delattr__', '__doc__', '__eq__',
'__getattribute__', '__hash__', '__init__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__',
'__unicode__', 'author', 'class', 'clone', 'equals', 'finalize',
'getAuthor', 'getClass', 'getKey', 'getLine', 'getMessage',
'getParentUuid', 'getSide', 'getStatus', 'getWrittenOn', 'hashCode',
'key', 'line', 'lineNbr', 'message', 'notify', 'notifyAll',
'parentUuid', 'registerNatives', 'setMessage', 'setSide', 'setStatus',
'side', 'status', 'toString', 'updated', 'wait', 'writtenOn']
>>> for x in db.patchComments().iterateAllEntities():
... print x.status, x.line, x.message
...
P 2 I like it!
P 2 more
P 1 better
----
A built-in *help()* function provides values of global variables
defined in the interpreter:
----
>>> help()
"schk" is "com.google.gerrit.server.schema.SchemaVersionCheck@5e8cb9bd"
"ds" is "com.google.gerrit.server.schema.DataSourceProvider@6b3592c"
"m" is "com.google.gerrit.lifecycle.LifecycleManager@6f03b248"
"q" is "com.google.gerrit.reviewdb.server.ReviewDb_Schema_GwtOrm$$23@56d3384d"
"Shell" is "com.google.gerrit.pgm.shell.JythonShell@61644f2d"
"x" is "com.google.gerrit.reviewdb.client.PatchLineComment@518acfa7"
"z" is "com.google.gwtorm.jdbc.Database@668dfd9b"
"db" is "com.google.gerrit.reviewdb.server.ReviewDb_Schema_GwtOrm$$23@6a3ccb09"
Welcome to the Gerrit Inspector
Enter help() to see the above again, EOF to quit and stop Gerrit
----
Java and Python exceptions are intercepted by the Inspector:
----
>>> import java.lang.RuntimeException
>>> raise java.lang.RuntimeException("Exiting")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:532)
at org.python.core.PyReflectedConstructor.constructProxy(PyReflectedConstructor.java:210)
java.lang.RuntimeException: java.lang.RuntimeException: Exiting
>>>
----
To exit the interpreter, use EOF character (Ctrl-D on Unix systems, Ctrl-Z on Windows).
It is also possible to shut down the JVM by using *System.exit()*
----
>>> import java.lang.System
>>> java.lang.System.exit(1)
----
And Gerrit should shut down all its subsystems and exit:
----
[2012-04-17 15:31:08,458] INFO com.google.gerrit.pgm.Daemon : caught shutdown, cleaning up
----
TROUBLESHOOTING
---------------
Gerrit Inspector is logging to the Gerrit error log.
A successful startup is indicated in the logfile:
----
[2012-04-17 13:43:44,888] INFO com.google.gerrit.pgm.shell.JythonShell : Jython shell instance created.
----
If 'jython.jar' library is not available, Gerrit refuses to start when given *-s* option:
----
[2012-04-17 13:57:29,611] ERROR com.google.gerrit.pgm.Daemon : Unable to start daemon
com.google.inject.ProvisionException: Guice provision errors:
1) Error injecting constructor, java.lang.UnsupportedOperationException: Cannot create Jython shell: Class org.python.util.InteractiveConsole not found
(You might need to install jython.jar in the lib directory)
at com.google.gerrit.pgm.shell.JythonShell.<init>(JythonShell.java:47)
while locating com.google.gerrit.pgm.shell.JythonShell
while locating com.google.gerrit.pgm.shell.InteractiveShell
----
Errors during processing of the startup script, 'Startup.py', are logged
to the error log:
----
[2012-04-17 14:20:30,558] INFO com.google.gerrit.pgm.shell.JythonShell : Jython shell instance created.
[2012-04-17 14:20:38,005] ERROR com.google.gerrit.pgm.shell.JythonShell : Exception occured while loading file Startup.py :
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at com.google.gerrit.pgm.shell.JythonShell.runMethod0(JythonShell.java:112)
at com.google.gerrit.pgm.shell.JythonShell.execFile(JythonShell.java:194)
at com.google.gerrit.pgm.shell.JythonShell.reload(JythonShell.java:178)
at com.google.gerrit.pgm.shell.JythonShell.run(JythonShell.java:152)
at com.google.gerrit.pgm.Daemon.run(Daemon.java:190)
at com.google.gerrit.pgm.util.AbstractProgram.main(AbstractProgram.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at com.google.gerrit.launcher.GerritLauncher.invokeProgram(GerritLauncher.java:167)
at com.google.gerrit.launcher.GerritLauncher.mainImpl(GerritLauncher.java:91)
at com.google.gerrit.launcher.GerritLauncher.main(GerritLauncher.java:49)
at Main.main(Main.java:25)
Caused by: Traceback (most recent call last):
File "/home/user/.gerritcodereview/Startup.py", line 1, in <module>
Test
NameError: name 'Test' is not defined
----
Those errors are non-fatal. System and user scripts can be loaded again
by issuing the following command in the Gerrit Inspector console:
----
Shell.reload()
----
LOGGING
-------
Error and warning messages from the server are automatically written
to the log file under '$site_path/logs/error_log'.
Output and error messages (including Java and Python exceptions)
resulting from interactive work are logged to the console.
KNOWN ISSUES
------------
The Inspector does not yet recognize Google Guice bindings.
IMPORTANT: Using the Inspector may void your warranty.
GERRIT
------
Part of link:index.html[Gerrit Code Review]

View File

@@ -106,6 +106,43 @@ copying to the test site:
java -jar buck-out/gen/gerrit.war daemon -d ../test_site
----
Running the Daemon with Gerrit Inspector
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
link:dev-inspector.html[Gerrit Inspector] is an interactive scriptable
environment to inspect and modify internal state of the system.
This environment is available on the system console after
the system starts. Leaving the Inspector will shutdown the Gerrit
instance.
The environment allows interactive work as well as running of
Python scripts for troubleshooting.
Gerrit Inspect can be started by adding '-s' option to the
command used to launch the daemon:
----
java -jar buck-out/gen/gerrit.war daemon -d ../test_site -s
----
Gerrit Inspector examines Java libraries first, then loads
its initialization scripts and then starts a command line
prompt on the console:
----
Welcome to the Gerrit Inspector
Enter help() to see the above again, EOF to quit and stop Gerrit
Jython 2.5.2 (Release_2_5_2:7206, Mar 2 2011, 23:12:06)
[OpenJDK 64-Bit Server VM (Sun Microsystems Inc.)] on java1.6.0 running for Gerrit 2.3-rc0-163-g01967ef
>>>
----
With the Inspector enabled Gerrit can be used normally and all
interfaces (HTTP, SSH etc.) are available.
Care must be taken not to modify internal state of the system
when using the Inspector.
Querying the Database
~~~~~~~~~~~~~~~~~~~~~

View File

@@ -16,6 +16,7 @@ SYNOPSIS
[\--slave]
[\--headless]
[\--init]
[-s]
DESCRIPTION
-----------
@@ -68,6 +69,14 @@ This option automatically implies '\--disable-httpd \--enable-sshd'.
Run init before starting the daemon. This will create a new site or
upgrade an existing site.
\--s::
Start link:dev-inspector.html[Gerrit Inspector] on the console, a
built-in interactive inspection environment to assist debugging and
troubleshooting of Gerrit code.
+
This options requires 'jython.jar' from the http://www.jython.org[Jython distribution]
to be present in '$site_path/lib' directory.
CONTEXT
-------
This command can only be run on a server which has direct

View File

@@ -302,6 +302,7 @@ public final class GerritLauncher {
}
private volatile static File myArchive;
private static File myHome;
/**
* Locate the JAR/WAR file we were launched from.
@@ -459,42 +460,26 @@ public final class GerritLauncher {
return tmp;
}
/**
* Provide path to a working directory
*
* @return local path of the working directory or null if cannot be determined
*/
public static File getHomeDirectory() {
if (myHome == null) {
myHome = locateHomeDirectory();
}
return myHome;
}
private static File tmproot() {
File tmp;
String gerritTemp = System.getenv("GERRIT_TMP");
if (gerritTemp != null && gerritTemp.length() > 0) {
tmp = new File(gerritTemp);
} else {
// Try to find the user's home directory. If we can't find it
// return null so the JVM's default temporary directory is used
// instead. This is probably /tmp or /var/tmp.
//
String userHome = System.getProperty("user.home");
if (userHome == null || "".equals(userHome)) {
userHome = System.getenv("HOME");
if (userHome == null || "".equals(userHome)) {
System.err.println("warning: cannot determine home directory");
System.err.println("warning: using system temporary directory instead");
return null;
}
}
// Ensure the home directory exists. If it doesn't, try to make it.
//
final File home = new File(userHome);
if (!home.exists()) {
if (home.mkdirs()) {
System.err.println("warning: created " + home.getAbsolutePath());
} else {
System.err.println("warning: " + home.getAbsolutePath() + " not found");
System.err.println("warning: using system temporary directory instead");
return null;
}
}
// Use $HOME/.gerritcodereview/tmp for our temporary file area.
//
tmp = new File(new File(home, ".gerritcodereview"), "tmp");
tmp = new File(getHomeDirectory(), "tmp");
}
if (!tmp.exists() && !tmp.mkdirs()) {
System.err.println("warning: cannot create " + tmp.getAbsolutePath());
@@ -527,6 +512,49 @@ public final class GerritLauncher {
}
}
private static File locateHomeDirectory() {
// Try to find the user's home directory. If we can't find it
// return null so the JVM's default temporary directory is used
// instead. This is probably /tmp or /var/tmp.
//
String userHome = System.getProperty("user.home");
if (userHome == null || "".equals(userHome)) {
userHome = System.getenv("HOME");
if (userHome == null || "".equals(userHome)) {
System.err.println("warning: cannot determine home directory");
System.err.println("warning: using system temporary directory instead");
return null;
}
}
// Ensure the home directory exists. If it doesn't, try to make it.
//
final File home = new File(userHome);
if (!home.exists()) {
if (home.mkdirs()) {
System.err.println("warning: created " + home.getAbsolutePath());
} else {
System.err.println("warning: " + home.getAbsolutePath() + " not found");
System.err.println("warning: using system temporary directory instead");
return null;
}
}
// Use $HOME/.gerritcodereview/tmp for our temporary file area.
//
final File gerrithome = new File(home, ".gerritcodereview");
if (!gerrithome.exists() && !gerrithome.mkdirs()) {
System.err.println("warning: cannot create " + gerrithome.getAbsolutePath());
System.err.println("warning: using system temporary directory instead");
return null;
}
try {
return gerrithome.getCanonicalFile();
} catch (IOException e) {
return gerrithome;
}
}
private GerritLauncher() {
}
}

View File

@@ -33,6 +33,7 @@ import com.google.gerrit.pgm.http.jetty.GetUserFilter;
import com.google.gerrit.pgm.http.jetty.JettyEnv;
import com.google.gerrit.pgm.http.jetty.JettyModule;
import com.google.gerrit.pgm.http.jetty.ProjectQoSFilter;
import com.google.gerrit.pgm.shell.JythonShell;
import com.google.gerrit.pgm.util.ErrorLogFile;
import com.google.gerrit.pgm.util.GarbageCollectionLogFile;
import com.google.gerrit.pgm.util.LogFileCompressor;
@@ -57,6 +58,7 @@ import com.google.gerrit.server.mail.SmtpEmailSender;
import com.google.gerrit.server.patch.IntraLineWorkerPool;
import com.google.gerrit.server.plugins.PluginGuiceEnvironment;
import com.google.gerrit.server.plugins.PluginRestApiModule;
import com.google.gerrit.server.schema.DataSourceProvider;
import com.google.gerrit.server.schema.SchemaVersionCheck;
import com.google.gerrit.server.ssh.NoSshKeyCache;
import com.google.gerrit.server.ssh.NoSshModule;
@@ -109,6 +111,9 @@ public class Daemon extends SiteProgram {
@Option(name = "--console-log", usage = "Log to console (not $site_path/logs)")
private boolean consoleLog;
@Option(name = "-s", usage = "Start interactive shell")
private boolean inspector;
@Option(name = "--run-id", usage = "Cookie to store in $site_path/logs/gerrit.run")
private String runId;
@@ -224,7 +229,15 @@ public class Daemon extends SiteProgram {
serverStarted.run();
}
if (inspector) {
JythonShell shell = new JythonShell();
shell.set("m", manager);
shell.set("ds", dbInjector.getInstance(DataSourceProvider.class));
shell.set("schk", dbInjector.getInstance(SchemaVersionCheck.class));
shell.run();
} else {
RuntimeShutdown.waitFor();
}
return 0;
} catch (Throwable err) {
log.error("Unable to start daemon", err);

View File

@@ -0,0 +1,221 @@
// Copyright (C) 2013 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.google.gerrit.pgm.shell;
import com.google.gerrit.launcher.GerritLauncher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Properties;
public class JythonShell {
private static final Logger log = LoggerFactory.getLogger(JythonShell.class);
private static final String STARTUP_RESOURCE = "com/google/gerrit/pgm/Startup.py";
private static final String STARTUP_FILE = "Startup.py";
private Class<?> console;
private Class<?> pyObject;
private Class<?> pySystemState;
private Object shell;
private ArrayList <String> injectedVariables;
public JythonShell() {
Properties env = new Properties();
// Let us inspect private class members
env.setProperty("python.security.respectJavaAccessibility", "false");
File home = GerritLauncher.getHomeDirectory();
if (home != null) {
env.setProperty("python.cachedir", new File(home, "jythoncache").getPath());
}
// For package introspection and "import com.google" to work,
// Jython needs to inspect actual .jar files (not just classloader)
StringBuilder classPath = new StringBuilder();
final ClassLoader cl = getClass().getClassLoader();
if (cl instanceof java.net.URLClassLoader) {
URLClassLoader ucl = (URLClassLoader) cl;
for (URL u : ucl.getURLs()) {
if ("file".equals(u.getProtocol())) {
if (classPath.length() > 0) {
classPath.append(java.io.File.pathSeparatorChar);
}
classPath.append(u.getFile());
}
}
}
env.setProperty("java.class.path", classPath.toString());
console = findClass("org.python.util.InteractiveConsole");
pyObject = findClass("org.python.core.PyObject");
pySystemState = findClass("org.python.core.PySystemState");
runMethod(pySystemState, pySystemState, "initialize",
new Class[] { Properties.class, Properties.class },
new Object[] { null, env }
);
try {
shell = console.newInstance();
log.info("Jython shell instance created.");
} catch (InstantiationException e) {
throw noInterpreter(e);
} catch (IllegalAccessException e) {
throw noInterpreter(e);
}
injectedVariables = new ArrayList<String>();
set("Shell", this);
}
protected Object runMethod0(Class<?> klazz, Object instance,
String name, Class<?>[] sig, Object[] args)
throws InvocationTargetException {
try {
Method m;
m = klazz.getMethod(name, sig);
return m.invoke(instance, args);
} catch (NoSuchMethodException e) {
throw cannotStart(e);
} catch (SecurityException e) {
throw cannotStart(e);
} catch (IllegalArgumentException e) {
throw cannotStart(e);
} catch (IllegalAccessException e) {
throw cannotStart(e);
}
}
protected Object runMethod(Class<?> klazz, Object instance,
String name, Class<?>[] sig, Object[] args) {
try {
return runMethod0(klazz, instance, name, sig, args);
} catch (InvocationTargetException e) {
throw cannotStart(e);
}
}
protected Object runInterpreter(String name, Class<?>[] sig, Object[] args) {
return runMethod(console, shell, name, sig, args);
}
protected String getDefaultBanner() {
return (String)runInterpreter("getDefaultBanner",
new Class[] { }, new Object[] { });
}
protected void printInjectedVariable(String id) {
runInterpreter("exec",
new Class[] { String.class },
new Object[] { "print '\"%s\" is \"%s\"' % (\"" + id + "\", " + id + ")" }
);
}
public void run() {
for (String key : injectedVariables) {
printInjectedVariable(key);
}
reload();
runInterpreter("interact",
new Class[] { String.class, pyObject },
new Object[] { getDefaultBanner() +
" running for Gerrit " + com.google.gerrit.common.Version.getVersion(),
null });
}
public void set(String key, Object content) {
runInterpreter("set",
new Class[] { String.class, Object.class },
new Object[] { key, content }
);
injectedVariables.add(key);
}
private static Class<?> findClass(String klazzname) {
try {
return Class.forName(klazzname);
} catch (ClassNotFoundException e) {
throw noShell("Class " + klazzname + " not found", e);
}
}
public void reload() {
execResource(STARTUP_RESOURCE);
execFile(GerritLauncher.getHomeDirectory(), STARTUP_FILE);
}
protected void execResource(final String p) {
InputStream in = JythonShell.class.getClassLoader().getResourceAsStream(p);
if (in != null) {
execStream(in, "resource " + p);
} else {
log.error("Cannot load resource " + p);
}
}
protected void execFile(final File parent, final String p) {
try {
File script = new File(parent, p);
if (script.canExecute()) {
runMethod0(console, shell, "execfile",
new Class[] { String.class },
new Object[] { script.getAbsolutePath() }
);
} else {
log.info("User initialization file "
+ script.getAbsolutePath()
+ " is not found or not executable");
}
} catch (InvocationTargetException e) {
log.error("Exception occured while loading file " + p + " : ", e);
} catch (SecurityException e) {
log.error("SecurityException occured while loading file " + p + " : ", e);
}
}
protected void execStream(final InputStream in, final String p) {
try {
runMethod0(console, shell, "execfile",
new Class[] { InputStream.class, String.class },
new Object[] { in, p }
);
} catch (InvocationTargetException e) {
log.error("Exception occured while loading " + p + " : ", e);
}
}
private static UnsupportedOperationException noShell(final String m, Throwable why) {
final String prefix = "Cannot create Jython shell: ";
final String postfix = "\n (You might need to install jython.jar in the lib directory)";
return new UnsupportedOperationException(prefix + m + postfix, why);
}
private static UnsupportedOperationException noInterpreter(Throwable why) {
final String msg = "Cannot create Python interpreter";
return noShell(msg, why);
}
private static UnsupportedOperationException cannotStart(Throwable why) {
final String msg = "Cannot start Jython shell";
return new UnsupportedOperationException(msg, why);
}
}

View File

@@ -0,0 +1,31 @@
# Copyright (C) 2013 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.
# -----------------------------------------------------------------------
# Startup script for Gerrit Inspector - a Jython introspector
# -----------------------------------------------------------------------
import sys
def help():
for (n, v) in vars(sys.modules['__main__']).items():
if not n.startswith("__") and not n in ['help', 'reload'] \
and str(type(v)) != "<type 'javapackage'>" \
and not str(v).startswith("<module"):
print "\"%s\" is \"%s\"" % (n, v)
print
print "Welcome to the Gerrit Inspector"
print "Enter help() to see the above again, EOF to quit and stop Gerrit"
help()