Merge branch 'stable-2.8'
* stable-2.8:
Inject right plugin name @PluginName in init step
diff --git a/Documentation/cmd-query.txt b/Documentation/cmd-query.txt
index 66bd845..f7a784f 100644
--- a/Documentation/cmd-query.txt
+++ b/Documentation/cmd-query.txt
@@ -17,6 +17,7 @@
[--commit-message]
[--dependencies]
[--submit-records]
+ [--all-reviewers]
[--]
<query>
[limit:<n>]
@@ -89,6 +90,10 @@
Show information about patch sets which depend on, or are needed by,
each patch set.
+--all-reviewers::
+ Show the name and email of all reviewers which are added to a change
+ (irrespective of whether they have been voting on that change or not).
+
--submit-records::
Show submit record information about the change, which
includes whether the change meets the criteria for submission
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index c644ef9..814472a 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -2705,6 +2705,13 @@
+
By default, `host/canonical.host.name`
+[[sshd.requestLog]]sshd.requestLog::
++
+Enable (or disable) the `'$site_path'/logs/sshd_log` request log.
+If enabled, a request log file is written out by the SSH daemon.
++
+By default, true.
+
[[suggest]] Section suggest
~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/Documentation/config-gitweb.txt b/Documentation/config-gitweb.txt
index 7ba15b8..711174f 100644
--- a/Documentation/config-gitweb.txt
+++ b/Documentation/config-gitweb.txt
@@ -245,6 +245,10 @@
After updating `'$site_path'/etc/gerrit.config`, the Gerrit server must
be restarted and clients must reload the host page to see the change.
+Note that when using a custom gitweb configuration, values must be
+specified for all of the `project`, `revision`, `branch` and `filehistory`
+settings, otherwise the configuration will not be used.
+
Access Control
++++++++++++++
diff --git a/Documentation/dev-inspector.txt b/Documentation/dev-inspector.txt
new file mode 100644
index 0000000..485ad7b
--- /dev/null
+++ b/Documentation/dev-inspector.txt
@@ -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]
diff --git a/Documentation/dev-readme.txt b/Documentation/dev-readme.txt
index ced8648..728c8dc 100644
--- a/Documentation/dev-readme.txt
+++ b/Documentation/dev-readme.txt
@@ -106,6 +106,43 @@
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
~~~~~~~~~~~~~~~~~~~~~
diff --git a/Documentation/json.txt b/Documentation/json.txt
index 2836e5b..9278cde 100644
--- a/Documentation/json.txt
+++ b/Documentation/json.txt
@@ -72,6 +72,9 @@
submitRecords:: The <<submitRecord,submitRecord attribute>> contains
information about whether this change has been or can be submitted.
+allReviewers:: List of all reviewers in <<account,account attribute>>
+which are added to a change.
+
[[trackingid]]
trackingid
----------
diff --git a/Documentation/pgm-daemon.txt b/Documentation/pgm-daemon.txt
index ce88ab7..4b920ea 100644
--- a/Documentation/pgm-daemon.txt
+++ b/Documentation/pgm-daemon.txt
@@ -16,6 +16,7 @@
[\--slave]
[\--headless]
[\--init]
+ [-s]
DESCRIPTION
-----------
@@ -68,6 +69,14 @@
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
diff --git a/gerrit-acceptance-tests/BUCK b/gerrit-acceptance-tests/BUCK
index f762c1e..11311e8 100644
--- a/gerrit-acceptance-tests/BUCK
+++ b/gerrit-acceptance-tests/BUCK
@@ -11,6 +11,7 @@
'//gerrit-pgm:pgm',
'//gerrit-reviewdb:server',
'//gerrit-server:server',
+ '//gerrit-server:testutil',
'//gerrit-sshd:sshd',
'//lib:args4j',
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
index adb346f..784b461 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
@@ -30,7 +30,8 @@
return new Statement() {
@Override
public void evaluate() throws Throwable {
- beforeTest(config(description));
+ boolean mem = description.getAnnotation(UseLocalDisk.class) == null;
+ beforeTest(config(description), mem);
base.evaluate();
afterTest();
}
@@ -53,8 +54,8 @@
}
}
- private void beforeTest(Config cfg) throws Exception {
- server = GerritServer.start(cfg);
+ private void beforeTest(Config cfg, boolean memory) throws Exception {
+ server = GerritServer.start(cfg, memory);
server.getTestInjector().injectMembers(this);
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java
index f97d2b9..daf9d38 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/GerritServer.java
@@ -14,18 +14,19 @@
package com.google.gerrit.acceptance;
-import com.google.gerrit.lifecycle.LifecycleManager;
+import com.google.common.collect.ImmutableList;
import com.google.gerrit.pgm.Daemon;
import com.google.gerrit.pgm.Init;
import com.google.gerrit.server.config.FactoryModule;
+import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.util.SocketUtil;
import com.google.inject.Injector;
+import com.google.inject.Key;
import com.google.inject.Module;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.RepositoryCache;
-import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.util.FS;
import java.io.File;
@@ -46,8 +47,7 @@
public class GerritServer {
/** Returns fully started Gerrit server */
- static GerritServer start(Config base) throws Exception {
- final File site = initSite(base);
+ static GerritServer start(Config base, boolean memory) throws Exception {
final CyclicBarrier serverStarted = new CyclicBarrier(2);
final Daemon daemon = new Daemon(new Runnable() {
public void run() {
@@ -61,21 +61,34 @@
}
});
- ExecutorService daemonService = Executors.newSingleThreadExecutor();
- daemonService.submit(new Callable<Void>() {
- public Void call() throws Exception {
- int rc = daemon.main(new String[] {"-d", site.getPath(), "--headless" });
- if (rc != 0) {
- System.out.println("Failed to start Gerrit daemon. Check "
- + site.getPath() + "/logs/error_log");
- serverStarted.reset();
- }
- return null;
- };
- });
-
- serverStarted.await();
- System.out.println("Gerrit Server Started");
+ final File site;
+ ExecutorService daemonService = null;
+ if (memory) {
+ site = null;
+ Config cfg = base != null ? base : new Config();
+ mergeTestConfig(cfg);
+ cfg.setBoolean("httpd", null, "requestLog", false);
+ cfg.setBoolean("sshd", null, "requestLog", false);
+ daemon.setDatabaseForTesting(ImmutableList.<Module>of(
+ new InMemoryTestingDatabaseModule(cfg)));
+ daemon.start();
+ } else {
+ site = initSite(base);
+ daemonService = Executors.newSingleThreadExecutor();
+ daemonService.submit(new Callable<Void>() {
+ public Void call() throws Exception {
+ int rc = daemon.main(new String[] {"-d", site.getPath(), "--headless" });
+ if (rc != 0) {
+ System.out.println("Failed to start Gerrit daemon. Check "
+ + site.getPath() + "/logs/error_log");
+ serverStarted.reset();
+ }
+ return null;
+ };
+ });
+ serverStarted.await();
+ System.out.println("Gerrit Server Started");
+ }
Injector i = createTestInjector(daemon);
return new GerritServer(site, i, daemon, daemonService);
@@ -91,14 +104,22 @@
throw new RuntimeException("Couldn't initialize site");
}
- InetSocketAddress http = newPort();
- InetSocketAddress sshd = newPort();
- String url = "http://" + format(http) + "/";
MergeableFileBasedConfig cfg = new MergeableFileBasedConfig(
new File(new File(tmp, "etc"), "gerrit.config"),
FS.DETECTED);
cfg.load();
cfg.merge(base);
+ mergeTestConfig(cfg);
+ cfg.save();
+ return tmp;
+ }
+
+ private static void mergeTestConfig(Config cfg)
+ throws IOException {
+ InetSocketAddress http = newPort();
+ InetSocketAddress sshd = newPort();
+ String url = "http://" + format(http) + "/";
+
cfg.setString("gerrit", null, "canonicalWebUrl", url);
cfg.setString("httpd", null, "listenUrl", url);
cfg.setString("sshd", null, "listenAddress", format(sshd));
@@ -106,8 +127,6 @@
cfg.setBoolean("sendemail", null, "enable", false);
cfg.setInt("cache", "projects", "checkFrequency", 0);
cfg.setInt("plugins", null, "checkFrequency", 0);
- cfg.save();
- return tmp;
}
private static String format(InetSocketAddress s) {
@@ -169,11 +188,8 @@
this.daemon = daemon;
this.daemonService = daemonService;
- FileBasedConfig cfg = new FileBasedConfig(
- new File(new File(sitePath, "etc"), "gerrit.config"),
- FS.DETECTED);
- cfg.load();
-
+ Config cfg = testInjector.getInstance(
+ Key.get(Config.class, GerritServerConfig.class));
url = cfg.getString("gerrit", null, "canonicalWebUrl");
URI uri = URI.create(url);
@@ -200,12 +216,15 @@
}
void stop() throws Exception {
- LifecycleManager manager = get(daemon, "manager");
- System.out.println("Gerrit Server Shutdown");
- manager.stop();
- daemonService.shutdownNow();
- daemonService.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
- TempFileUtil.recursivelyDelete(sitePath);
+ daemon.getLifecycleManager().stop();
+ if (daemonService != null) {
+ System.out.println("Gerrit Server Shutdown");
+ daemonService.shutdownNow();
+ daemonService.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
+ }
+ if (sitePath != null) {
+ TempFileUtil.recursivelyDelete(sitePath);
+ }
RepositoryCache.clear();
}
}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
new file mode 100644
index 0000000..5576c4f
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
@@ -0,0 +1,129 @@
+// 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.acceptance;
+
+import static com.google.inject.Scopes.SINGLETON;
+
+import com.google.gerrit.extensions.events.LifecycleListener;
+import com.google.gerrit.lifecycle.LifecycleModule;
+import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.config.SitePath;
+import com.google.gerrit.server.config.SitePaths;
+import com.google.gerrit.server.config.TrackingFooters;
+import com.google.gerrit.server.config.TrackingFootersProvider;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.schema.DataSourceType;
+import com.google.gerrit.server.schema.SchemaModule;
+import com.google.gerrit.server.schema.SchemaVersion;
+import com.google.gerrit.testutil.InMemoryDatabase;
+import com.google.gerrit.testutil.InMemoryH2Type;
+import com.google.gerrit.testutil.InMemoryRepositoryManager;
+import com.google.gwtorm.server.OrmException;
+import com.google.gwtorm.server.OrmRuntimeException;
+import com.google.gwtorm.server.SchemaFactory;
+import com.google.inject.AbstractModule;
+import com.google.inject.Inject;
+import com.google.inject.Provides;
+import com.google.inject.Singleton;
+import com.google.inject.TypeLiteral;
+
+import org.apache.sshd.common.KeyPairProvider;
+import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
+import org.eclipse.jgit.lib.Config;
+
+import java.io.File;
+
+class InMemoryTestingDatabaseModule extends AbstractModule {
+ private final Config cfg;
+
+ InMemoryTestingDatabaseModule(Config cfg) {
+ this.cfg = cfg;
+ }
+
+ @Override
+ protected void configure() {
+ bind(Config.class)
+ .annotatedWith(GerritServerConfig.class)
+ .toInstance(cfg);
+
+ bind(File.class)
+ .annotatedWith(SitePath.class)
+ .toInstance(new File("UNIT_TEST_GERRIT_SITE"));
+
+ bind(GitRepositoryManager.class)
+ .toInstance(new InMemoryRepositoryManager());
+
+ bind(DataSourceType.class).to(InMemoryH2Type.class);
+ bind(InMemoryDatabase.class).in(SINGLETON);
+ bind(new TypeLiteral<SchemaFactory<ReviewDb>>() {})
+ .to(InMemoryDatabase.class);
+
+ install(new LifecycleModule() {
+ @Override
+ protected void configure() {
+ listener().to(CreateDatabase.class);
+ }
+ });
+
+ bind(SitePaths.class);
+ bind(TrackingFooters.class)
+ .toProvider(TrackingFootersProvider.class)
+ .in(SINGLETON);
+
+ install(new SchemaModule());
+ bind(SchemaVersion.class).to(SchemaVersion.C);
+ }
+
+ @Provides
+ @Singleton
+ KeyPairProvider createHostKey() {
+ return getHostKeys();
+ }
+
+ private static SimpleGeneratorHostKeyProvider keys;
+
+ private static synchronized KeyPairProvider getHostKeys() {
+ if (keys == null) {
+ keys = new SimpleGeneratorHostKeyProvider();
+ keys.setAlgorithm("RSA");
+ keys.loadKeys();
+ }
+ return keys;
+ }
+
+ static class CreateDatabase implements LifecycleListener {
+ private final InMemoryDatabase mem;
+
+ @Inject
+ CreateDatabase(InMemoryDatabase mem) {
+ this.mem = mem;
+ }
+
+ @Override
+ public void start() {
+ try {
+ mem.create();
+ } catch (OrmException e) {
+ throw new OrmRuntimeException(e);
+ }
+ }
+
+ @Override
+ public void stop() {
+ mem.drop();
+ }
+ }
+}
\ No newline at end of file
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/UseLocalDisk.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/UseLocalDisk.java
new file mode 100644
index 0000000..f9367ec
--- /dev/null
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/UseLocalDisk.java
@@ -0,0 +1,26 @@
+// 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.acceptance;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Target({METHOD})
+@Retention(RUNTIME)
+public @interface UseLocalDisk {
+}
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GarbageCollectionIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GarbageCollectionIT.java
index a1ad627..7057a4f 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GarbageCollectionIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/project/GarbageCollectionIT.java
@@ -24,6 +24,7 @@
import com.google.gerrit.acceptance.RestSession;
import com.google.gerrit.acceptance.SshSession;
import com.google.gerrit.acceptance.TestAccount;
+import com.google.gerrit.acceptance.UseLocalDisk;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gwtorm.server.OrmException;
@@ -83,8 +84,8 @@
}
@Test
+ @UseLocalDisk
public void testGcOneProject() throws JSchException, IOException {
-
assertEquals(HttpStatus.SC_OK, POST("/projects/" + allProjects.get() + "/gc"));
gcAssert.assertHasPackFile(allProjects);
gcAssert.assertHasNoPackFile(project1, project2);
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/GarbageCollectionIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/GarbageCollectionIT.java
index e93973b..f10258c 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/GarbageCollectionIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/ssh/GarbageCollectionIT.java
@@ -24,6 +24,7 @@
import com.google.gerrit.acceptance.GcAssert;
import com.google.gerrit.acceptance.SshSession;
import com.google.gerrit.acceptance.TestAccount;
+import com.google.gerrit.acceptance.UseLocalDisk;
import com.google.gerrit.common.data.GarbageCollectionResult;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.config.AllProjectsName;
@@ -83,6 +84,7 @@
}
@Test
+ @UseLocalDisk
public void testGc() throws JSchException, IOException {
String response =
sshSession.exec("gerrit gc \"" + project1.get() + "\" \""
@@ -94,6 +96,7 @@
}
@Test
+ @UseLocalDisk
public void testGcAll() throws JSchException, IOException {
String response = sshSession.exec("gerrit gc --all");
assertFalse(sshSession.hasError());
@@ -110,6 +113,7 @@
}
@Test
+ @UseLocalDisk
public void testGcAlreadyScheduled() {
gcQueue.addAll(Arrays.asList(project1));
GarbageCollectionResult result = garbageCollectionFactory.create().run(
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
index 28e361c..2dde16e 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
@@ -168,7 +168,7 @@
Element userlistElement = HtmlDomUtil.find(doc, "userlist");
ReviewDb db = schema.open();
try {
- ResultSet<Account> accounts = db.accounts().firstNById(5);
+ ResultSet<Account> accounts = db.accounts().firstNById(100);
for (Account a : accounts) {
String displayName;
if (a.getUserName() != null) {
diff --git a/gerrit-launcher/src/main/java/com/google/gerrit/launcher/GerritLauncher.java b/gerrit-launcher/src/main/java/com/google/gerrit/launcher/GerritLauncher.java
index 2dd20a2..fb117767 100644
--- a/gerrit-launcher/src/main/java/com/google/gerrit/launcher/GerritLauncher.java
+++ b/gerrit-launcher/src/main/java/com/google/gerrit/launcher/GerritLauncher.java
@@ -302,6 +302,7 @@
}
private volatile static File myArchive;
+ private static File myHome;
/**
* Locate the JAR/WAR file we were launched from.
@@ -459,42 +460,26 @@
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 @@
}
}
+ 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() {
}
}
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
index 891dadc..35d8e76 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Daemon.java
@@ -16,6 +16,8 @@
import static com.google.gerrit.server.schema.DataSourceProvider.Context.MULTI_USER;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Objects;
import com.google.gerrit.common.ChangeHookRunner;
import com.google.gerrit.httpd.AllRequestFilter;
import com.google.gerrit.httpd.CacheBasedWebSession;
@@ -33,6 +35,7 @@
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,18 +60,22 @@
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;
import com.google.gerrit.solr.SolrIndexModule;
+import com.google.gerrit.sshd.SshHostKeyModule;
import com.google.gerrit.sshd.SshKeyCacheImpl;
import com.google.gerrit.sshd.SshModule;
import com.google.gerrit.sshd.commands.MasterCommandModule;
import com.google.gerrit.sshd.commands.SlaveCommandModule;
import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Provider;
+import com.google.inject.Stage;
import org.kohsuke.args4j.Option;
import org.slf4j.Logger;
@@ -109,6 +116,9 @@
@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;
@@ -127,12 +137,14 @@
private Injector webInjector;
private Injector httpdInjector;
private File runFile;
+ private boolean test;
private Runnable serverStarted;
public Daemon() {
}
+ @VisibleForTesting
public Daemon(Runnable serverStarted) {
this.serverStarted = serverStarted;
}
@@ -176,22 +188,7 @@
}
try {
- dbInjector = createDbInjector(MULTI_USER);
- cfgInjector = createCfgInjector();
- sysInjector = createSysInjector();
- sysInjector.getInstance(PluginGuiceEnvironment.class)
- .setCfgInjector(cfgInjector);
- manager.add(dbInjector, cfgInjector, sysInjector);
-
- if (sshd) {
- initSshd();
- }
-
- if (httpd) {
- initHttpd();
- }
-
- manager.start();
+ start();
RuntimeShutdown.add(new Runnable() {
@Override
public void run() {
@@ -224,7 +221,15 @@
serverStarted.run();
}
- RuntimeShutdown.waitFor();
+ 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);
@@ -232,6 +237,45 @@
}
}
+ @VisibleForTesting
+ public LifecycleManager getLifecycleManager() {
+ return manager;
+ }
+
+ @VisibleForTesting
+ public void setDatabaseForTesting(List<Module> modules) {
+ dbInjector = Guice.createInjector(Stage.PRODUCTION, modules);
+ test = true;
+ headless = true;
+ }
+
+ @VisibleForTesting
+ public void start() {
+ if (dbInjector == null) {
+ dbInjector = createDbInjector(MULTI_USER);
+ }
+ cfgInjector = createCfgInjector();
+ sysInjector = createSysInjector();
+ sysInjector.getInstance(PluginGuiceEnvironment.class)
+ .setCfgInjector(cfgInjector);
+ manager.add(dbInjector, cfgInjector, sysInjector);
+
+ if (sshd) {
+ initSshd();
+ }
+
+ if (Objects.firstNonNull(httpd, true)) {
+ initHttpd();
+ }
+
+ manager.start();
+ }
+
+ @VisibleForTesting
+ public void stop() {
+ manager.stop();
+ }
+
private String myVersion() {
return com.google.gerrit.common.Version.getVersion();
}
@@ -268,7 +312,7 @@
changeIndexModule = new NoIndexModule();
}
modules.add(changeIndexModule);
- if (httpd) {
+ if (Objects.firstNonNull(httpd, true)) {
modules.add(new CanonicalWebUrlModule() {
@Override
protected Class<? extends Provider<String>> provider() {
@@ -311,6 +355,9 @@
final List<Module> modules = new ArrayList<Module>();
if (sshd) {
modules.add(sysInjector.getInstance(SshModule.class));
+ if (!test) {
+ modules.add(new SshHostKeyModule());
+ }
if (slave) {
modules.add(new SlaveCommandModule());
} else {
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/GetUserFilter.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/GetUserFilter.java
index f54b3c5..4f35f1c 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/GetUserFilter.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/GetUserFilter.java
@@ -50,7 +50,7 @@
Module(@GerritServerConfig final Config cfg) {
URI[] urls = JettyServer.listenURLs(cfg);
boolean reverseProxy = JettyServer.isReverseProxied(urls);
- this.loggingEnabled = cfg.getBoolean("httpd", "requestlog", !reverseProxy);
+ this.loggingEnabled = cfg.getBoolean("httpd", "requestLog", !reverseProxy);
}
@Override
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java
index da08804..e1d1281b 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/http/jetty/JettyServer.java
@@ -136,7 +136,7 @@
httpd.setThreadPool(threadPool(cfg));
Handler app = makeContext(env, cfg);
- if (cfg.getBoolean("httpd", "requestlog", !reverseProxy)) {
+ if (cfg.getBoolean("httpd", "requestLog", !reverseProxy)) {
RequestLogHandler handler = new RequestLogHandler();
handler.setRequestLog(new HttpLog(site, cfg));
handler.setHandler(app);
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/shell/JythonShell.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/shell/JythonShell.java
new file mode 100644
index 0000000..4ad91d9
--- /dev/null
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/shell/JythonShell.java
@@ -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);
+ }
+}
diff --git a/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/Startup.py b/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/Startup.py
new file mode 100644
index 0000000..92d6e56
--- /dev/null
+++ b/gerrit-pgm/src/main/resources/com/google/gerrit/pgm/Startup.py
@@ -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()
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/data/ChangeAttribute.java b/gerrit-server/src/main/java/com/google/gerrit/server/data/ChangeAttribute.java
index 7339829..5f5fd33 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/data/ChangeAttribute.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/data/ChangeAttribute.java
@@ -43,4 +43,5 @@
public List<DependencyAttribute> dependsOn;
public List<DependencyAttribute> neededBy;
public List<SubmitRecordAttribute> submitRecords;
+ public List<AccountAttribute> allReviewers;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java b/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java
index 98e803f..58d16dc 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/events/EventFactory.java
@@ -14,6 +14,8 @@
package com.google.gerrit.server.events;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.common.data.LabelTypes;
@@ -69,6 +71,7 @@
import java.util.Collection;
import java.util.List;
import java.util.Map;
+import java.util.Set;
@Singleton
public class EventFactory {
@@ -158,6 +161,29 @@
}
/**
+ * Add allReviewers to an existing ChangeAttribute.
+ *
+ * @param a
+ * @param change
+ */
+ public void addAllReviewers(ChangeAttribute a, Change change)
+ throws OrmException {
+ List<PatchSetApproval> approvals =
+ db.get().patchSetApprovals().byChange(change.getId()).toList();
+ if (!approvals.isEmpty()) {
+ a.allReviewers = Lists.newArrayList();
+ Set<Account.Id> seen = Sets.newHashSet();
+ for (PatchSetApproval psa : approvals) {
+ Account.Id id = psa.getAccountId();
+ if (!seen.contains(id)) {
+ seen.add(id);
+ a.allReviewers.add(asAccountAttribute(id));
+ }
+ }
+ }
+ }
+
+ /**
* Add submitRecords to an existing ChangeAttribute.
*
* @param ca
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java
index 5624f45..e569ff5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java
@@ -113,6 +113,7 @@
private boolean includeCommitMessage;
private boolean includeDependencies;
private boolean includeSubmitRecords;
+ private boolean includeAllReviewers;
private OutputStream outputStream = DisabledOutputStream.INSTANCE;
private PrintWriter out;
@@ -200,6 +201,10 @@
includeSubmitRecords = on;
}
+ public void setIncludeAllReviewers(boolean on) {
+ includeAllReviewers = on;
+ }
+
public void setOutput(OutputStream out, OutputFormat fmt) {
this.outputStream = out;
this.outputFormat = fmt;
@@ -304,6 +309,10 @@
eventFactory.extend(c, d.getChange());
eventFactory.addTrackingIds(c, d.trackingIds(db));
+ if (includeAllReviewers) {
+ eventFactory.addAllReviewers(c, d.getChange());
+ }
+
if (includeSubmitRecords) {
PatchSet.Id psId = d.getChange().currentPatchSetId();
PatchSet patchSet = db.get().patchSets().get(psId);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_55.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_55.java
index 9032bb0..006c759 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_55.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_55.java
@@ -17,6 +17,7 @@
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.SystemConfig;
import com.google.gerrit.reviewdb.server.ReviewDb;
+import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.LocalDiskRepositoryManager;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
@@ -30,10 +31,10 @@
import java.util.Collections;
public class Schema_55 extends SchemaVersion {
- private final LocalDiskRepositoryManager mgr;
+ private final GitRepositoryManager mgr;
@Inject
- Schema_55(Provider<Schema_54> prior, LocalDiskRepositoryManager mgr) {
+ Schema_55(Provider<Schema_54> prior, GitRepositoryManager mgr) {
super(prior);
this.mgr = mgr;
}
@@ -46,7 +47,7 @@
if ("-- All Projects --".equals(oldName)) {
ui.message("Renaming \"" + oldName + "\" to \"" + newName + "\"");
- File base = mgr.getBasePath();
+ File base = ((LocalDiskRepositoryManager) mgr).getBasePath();
File oldDir = FileKey.resolve(new File(base, oldName), FS.DETECTED);
File newDir = new File(base, newName + Constants.DOT_GIT_EXT);
if (!oldDir.renameTo(newDir)) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_56.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_56.java
index 27bf0bc..3ba77ec 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_56.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_56.java
@@ -17,11 +17,9 @@
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.git.LocalDiskRepositoryManager;
import com.google.inject.Inject;
import com.google.inject.Provider;
-import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefDatabase;
@@ -34,12 +32,12 @@
import java.util.Set;
public class Schema_56 extends SchemaVersion {
- private final LocalDiskRepositoryManager mgr;
+ private final GitRepositoryManager mgr;
private final Set<String> keysOne;
private final Set<String> keysTwo;
@Inject
- Schema_56(Provider<Schema_55> prior, LocalDiskRepositoryManager mgr) {
+ Schema_56(Provider<Schema_55> prior, GitRepositoryManager mgr) {
super(prior);
this.mgr = mgr;
@@ -57,7 +55,7 @@
Repository git;
try {
git = mgr.openRepository(name);
- } catch (RepositoryNotFoundException e) {
+ } catch (IOException e) {
ui.message("warning: Cannot open " + name.get());
continue;
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_57.java b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_57.java
index bf488e3..0edbc06 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_57.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/schema/Schema_57.java
@@ -27,7 +27,7 @@
import com.google.gerrit.server.config.AllProjectsNameProvider;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
-import com.google.gerrit.server.git.LocalDiskRepositoryManager;
+import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gwtorm.jdbc.JdbcSchema;
@@ -48,12 +48,12 @@
public class Schema_57 extends SchemaVersion {
private final SitePaths site;
- private final LocalDiskRepositoryManager mgr;
+ private final GitRepositoryManager mgr;
private final PersonIdent serverUser;
@Inject
Schema_57(Provider<Schema_56> prior, SitePaths site,
- LocalDiskRepositoryManager mgr, @GerritPersonIdent PersonIdent serverUser) {
+ GitRepositoryManager mgr, @GerritPersonIdent PersonIdent serverUser) {
super(prior);
this.site = site;
this.mgr = mgr;
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java
index 880d0e1..5039cc2 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/schema/SchemaUpdaterTest.java
@@ -25,9 +25,9 @@
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.git.LocalDiskRepositoryManager;
import com.google.gerrit.testutil.InMemoryDatabase;
import com.google.gerrit.testutil.InMemoryH2Type;
+import com.google.gerrit.testutil.InMemoryRepositoryManager;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.SchemaFactory;
import com.google.gwtorm.server.StatementExecutor;
@@ -74,7 +74,6 @@
install(new SchemaVersion.Module());
Config cfg = new Config();
- cfg.setString("gerrit", null, "basePath", "git");
cfg.setString("user", null, "name", "Gerrit Code Review");
cfg.setString("user", null, "email", "gerrit@localhost");
@@ -89,8 +88,8 @@
bind(AllProjectsName.class)
.toInstance(new AllProjectsName("All-Projects"));
- bind(GitRepositoryManager.class) //
- .to(LocalDiskRepositoryManager.class);
+ bind(GitRepositoryManager.class)
+ .toInstance(new InMemoryRepositoryManager());
bind(String.class) //
.annotatedWith(AnonymousCowardName.class) //
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshHostKeyModule.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshHostKeyModule.java
new file mode 100644
index 0000000..fdf34a2
--- /dev/null
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshHostKeyModule.java
@@ -0,0 +1,28 @@
+// 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.sshd;
+
+import static com.google.inject.Scopes.SINGLETON;
+
+import com.google.inject.AbstractModule;
+
+import org.apache.sshd.common.KeyPairProvider;
+
+public class SshHostKeyModule extends AbstractModule {
+ @Override
+ protected void configure() {
+ bind(KeyPairProvider.class).toProvider(HostKeyProvider.class).in(SINGLETON);
+ }
+}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshLog.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshLog.java
index b3b6815..a78f9f5 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshLog.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshLog.java
@@ -72,24 +72,28 @@
this.context = context;
this.auditService = auditService;
- final DailyRollingFileAppender dst = new DailyRollingFileAppender();
- dst.setName(LOG_NAME);
- dst.setLayout(new MyLayout());
- dst.setEncoding("UTF-8");
- dst.setFile(new File(resolve(site.logs_dir), LOG_NAME).getPath());
- dst.setImmediateFlush(true);
- dst.setAppend(true);
- dst.setThreshold(Level.INFO);
- dst.setErrorHandler(new DieErrorHandler());
- dst.activateOptions();
- dst.setErrorHandler(new LogLogHandler());
+ if (config.getBoolean("sshd", "requestLog", true)) {
+ final DailyRollingFileAppender dst = new DailyRollingFileAppender();
+ dst.setName(LOG_NAME);
+ dst.setLayout(new MyLayout());
+ dst.setEncoding("UTF-8");
+ dst.setFile(new File(resolve(site.logs_dir), LOG_NAME).getPath());
+ dst.setImmediateFlush(true);
+ dst.setAppend(true);
+ dst.setThreshold(Level.INFO);
+ dst.setErrorHandler(new DieErrorHandler());
+ dst.activateOptions();
+ dst.setErrorHandler(new LogLogHandler());
- async = new AsyncAppender();
- async.setBlocking(true);
- async.setBufferSize(config.getInt("core", "asyncLoggingBufferSize", 64));
- async.setLocationInfo(false);
- async.addAppender(dst);
- async.activateOptions();
+ async = new AsyncAppender();
+ async.setBlocking(true);
+ async.setBufferSize(config.getInt("core", "asyncLoggingBufferSize", 64));
+ async.setLocationInfo(false);
+ async.addAppender(dst);
+ async.activateOptions();
+ } else {
+ async = null;
+ }
}
@Override
@@ -98,11 +102,17 @@
@Override
public void stop() {
- async.close();
+ if (async != null) {
+ async.close();
+ }
}
void onLogin() {
- async.append(log("LOGIN FROM " + session.get().getRemoteAddressAsString()));
+ LoggingEvent entry =
+ log("LOGIN FROM " + session.get().getRemoteAddressAsString());
+ if (async != null) {
+ async.append(entry);
+ }
audit(context.get(), "0", "LOGIN");
}
@@ -127,8 +137,9 @@
if (error != null) {
event.setProperty(P_STATUS, error);
}
-
- async.append(event);
+ if (async != null) {
+ async.append(event);
+ }
audit(null, "FAIL", "AUTH");
}
@@ -162,7 +173,9 @@
}
event.setProperty(P_STATUS, status);
- async.append(event);
+ if (async != null) {
+ async.append(event);
+ }
audit(context.get(), status, dcmd);
}
@@ -209,7 +222,10 @@
}
void onLogout() {
- async.append(log("LOGOUT"));
+ LoggingEvent entry = log("LOGOUT");
+ if (async != null) {
+ async.append(entry);
+ }
audit(context.get(), "0", "LOGOUT");
}
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
index 48c565d..39b7f16 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
@@ -38,7 +38,6 @@
import com.google.inject.internal.UniqueAnnotations;
import com.google.inject.servlet.RequestScoped;
-import org.apache.sshd.common.KeyPairProvider;
import org.apache.sshd.server.CommandFactory;
import org.apache.sshd.server.PublickeyAuthenticator;
import org.apache.sshd.server.auth.gss.GSSAuthenticator;
@@ -85,7 +84,6 @@
bind(GSSAuthenticator.class).to(GerritGSSAuthenticator.class);
bind(PublickeyAuthenticator.class).to(DatabasePubKeyAuth.class);
- bind(KeyPairProvider.class).toProvider(HostKeyProvider.class).in(SINGLETON);
install(new DefaultCommandModule());
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Query.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Query.java
index 185bb67..af42e1b 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Query.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Query.java
@@ -72,6 +72,11 @@
processor.setIncludeDependencies(on);
}
+ @Option(name = "--all-reviewers", usage = "Include all reviewers")
+ void setAllReviewers(boolean on) {
+ processor.setIncludeAllReviewers(on);
+ }
+
@Option(name = "--submit-records", usage = "Include submit and label status")
void setSubmitRecords(boolean on) {
processor.setIncludeSubmitRecords(on);
diff --git a/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java b/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
index bccd0de..5936911 100644
--- a/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
+++ b/gerrit-war/src/main/java/com/google/gerrit/httpd/WebAppInitializer.java
@@ -52,6 +52,7 @@
import com.google.gerrit.server.schema.SchemaModule;
import com.google.gerrit.server.schema.SchemaVersionCheck;
import com.google.gerrit.solr.SolrIndexModule;
+import com.google.gerrit.sshd.SshHostKeyModule;
import com.google.gerrit.sshd.SshKeyCacheImpl;
import com.google.gerrit.sshd.SshModule;
import com.google.gerrit.sshd.commands.MasterCommandModule;
@@ -294,6 +295,7 @@
private Injector createSshInjector() {
final List<Module> modules = new ArrayList<Module>();
modules.add(sysInjector.getInstance(SshModule.class));
+ modules.add(new SshHostKeyModule());
modules.add(new MasterCommandModule());
return sysInjector.createChildInjector(modules);
}
diff --git a/plugins/download-commands b/plugins/download-commands
index eaeb186..32254d3 160000
--- a/plugins/download-commands
+++ b/plugins/download-commands
@@ -1 +1 @@
-Subproject commit eaeb1862180782bd5f696c79379a909dce7320b7
+Subproject commit 32254d3b75d65aceb485950fbf30d464574e02fc