Refactor SSH commands with SshCommand base class
The SshCommand base class extends BaseCommand and provides the common pattern of calling startThread with a CommandRunnable that parses argments and then invokes the real logic. The new annotation @RequiresCapability can be declared on any concrete implementation of SshCommand to name a capability the caller must have before they can run the contained command. This is enforced inside of the DispatchCommand, which is what handles creating and delegating to any paticular command implementation. @AdminCommand is replaced by the new @RequriesCapability annotation, which is more explicitly declaring the administrate server dependency. Most existing commands have been ported to this SshCommand base class, cleaning up a lot of the code. A few special cases still exist such as StreamEvents or ScpCommand that are not trivial to port, as their start implementation is well outside of the common pattern. Plugin authors should be encouraged to extend from SshCommand for the foreseeable future. I eventually would like to get away from needing to extend this class, and instead use a simpler interface declaration, but that is a much bigger change to make with how DispatchCommand and BaseCommand are connected together. Change-Id: I4f1de60c6fdeb207197dfccc135b4d532443d5b2
This commit is contained in:
@@ -15,12 +15,12 @@
|
||||
package com.google.gerrit.sshd.commands;
|
||||
|
||||
import com.google.gerrit.common.Version;
|
||||
import com.google.gerrit.common.data.GlobalCapability;
|
||||
import com.google.gerrit.lifecycle.LifecycleListener;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.config.SitePath;
|
||||
import com.google.gerrit.server.git.WorkQueue;
|
||||
import com.google.gerrit.server.git.WorkQueue.Task;
|
||||
import com.google.gerrit.sshd.BaseCommand;
|
||||
import com.google.gerrit.sshd.RequiresCapability;
|
||||
import com.google.gerrit.sshd.SshDaemon;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
@@ -30,13 +30,11 @@ import net.sf.ehcache.config.CacheConfiguration;
|
||||
|
||||
import org.apache.mina.core.service.IoAcceptor;
|
||||
import org.apache.mina.core.session.IoSession;
|
||||
import org.apache.sshd.server.Environment;
|
||||
import org.eclipse.jgit.storage.file.WindowCacheStatAccessor;
|
||||
import org.kohsuke.args4j.Option;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.OperatingSystemMXBean;
|
||||
import java.lang.management.RuntimeMXBean;
|
||||
@@ -47,6 +45,7 @@ import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
/** Show the current cache states. */
|
||||
@RequiresCapability(GlobalCapability.VIEW_CACHES)
|
||||
final class ShowCaches extends CacheCommand {
|
||||
private static volatile long serverStarted;
|
||||
|
||||
@@ -67,9 +66,6 @@ final class ShowCaches extends CacheCommand {
|
||||
@Option(name = "--show-jvm", usage = "show details about the JVM")
|
||||
private boolean showJVM;
|
||||
|
||||
@Inject
|
||||
private IdentifiedUser currentUser;
|
||||
|
||||
@Inject
|
||||
private WorkQueue workQueue;
|
||||
|
||||
@@ -80,42 +76,21 @@ final class ShowCaches extends CacheCommand {
|
||||
@SitePath
|
||||
private File sitePath;
|
||||
|
||||
private PrintWriter p;
|
||||
|
||||
@Override
|
||||
public void start(final Environment env) {
|
||||
startThread(new CommandRunnable() {
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
if (!currentUser.getCapabilities().canViewCaches()) {
|
||||
String msg = String.format(
|
||||
"fatal: %s does not have \"View Caches\" capability.",
|
||||
currentUser.getUserName());
|
||||
throw new UnloggedFailure(BaseCommand.STATUS_NOT_ADMIN, msg);
|
||||
}
|
||||
|
||||
parseCommandLine();
|
||||
display();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void display() {
|
||||
p = toPrintWriter(out);
|
||||
|
||||
protected void run() {
|
||||
Date now = new Date();
|
||||
p.format(
|
||||
stdout.format(
|
||||
"%-25s %-20s now %16s\n",
|
||||
"Gerrit Code Review",
|
||||
Version.getVersion() != null ? Version.getVersion() : "",
|
||||
new SimpleDateFormat("HH:mm:ss zzz").format(now));
|
||||
p.format(
|
||||
stdout.format(
|
||||
"%-25s %-20s uptime %16s\n",
|
||||
"", "",
|
||||
uptime(now.getTime() - serverStarted));
|
||||
p.print('\n');
|
||||
stdout.print('\n');
|
||||
|
||||
p.print(String.format(//
|
||||
stdout.print(String.format(//
|
||||
"%1s %-18s %-4s|%-20s| %-5s |%-14s|\n" //
|
||||
, "" //
|
||||
, "Name" //
|
||||
@@ -124,7 +99,7 @@ final class ShowCaches extends CacheCommand {
|
||||
, "AvgGet" //
|
||||
, "Hit Ratio" //
|
||||
));
|
||||
p.print(String.format(//
|
||||
stdout.print(String.format(//
|
||||
"%1s %-18s %-4s|%6s %6s %6s| %-5s |%-4s %-4s %-4s|\n" //
|
||||
, "" //
|
||||
, "" //
|
||||
@@ -137,7 +112,7 @@ final class ShowCaches extends CacheCommand {
|
||||
, "Mem" //
|
||||
, "Agg" //
|
||||
));
|
||||
p.print("------------------"
|
||||
stdout.print("------------------"
|
||||
+ "-------+--------------------+----------+--------------+\n");
|
||||
for (final Ehcache cache : getAllCaches()) {
|
||||
final CacheConfiguration cfg = cache.getCacheConfiguration();
|
||||
@@ -146,7 +121,7 @@ final class ShowCaches extends CacheCommand {
|
||||
final long total = stat.getCacheHits() + stat.getCacheMisses();
|
||||
|
||||
if (useDisk) {
|
||||
p.print(String.format(//
|
||||
stdout.print(String.format(//
|
||||
"D %-18s %-4s|%6s %6s %6s| %7s |%4s %4s %4s|\n" //
|
||||
, cache.getName() //
|
||||
, interval(cfg.getTimeToLiveSeconds()) //
|
||||
@@ -159,7 +134,7 @@ final class ShowCaches extends CacheCommand {
|
||||
, percent(stat.getCacheHits(), total) //
|
||||
));
|
||||
} else {
|
||||
p.print(String.format(//
|
||||
stdout.print(String.format(//
|
||||
" %-18s %-4s|%6s %6s %6s| %7s |%4s %4s %4s|\n" //
|
||||
, cache.getName() //
|
||||
, interval(cfg.getTimeToLiveSeconds()) //
|
||||
@@ -171,7 +146,7 @@ final class ShowCaches extends CacheCommand {
|
||||
));
|
||||
}
|
||||
}
|
||||
p.print('\n');
|
||||
stdout.print('\n');
|
||||
|
||||
if (gc) {
|
||||
System.gc();
|
||||
@@ -187,7 +162,7 @@ final class ShowCaches extends CacheCommand {
|
||||
jvmSummary();
|
||||
}
|
||||
|
||||
p.flush();
|
||||
stdout.flush();
|
||||
}
|
||||
|
||||
private void memSummary() {
|
||||
@@ -200,17 +175,17 @@ final class ShowCaches extends CacheCommand {
|
||||
final int jgitOpen = WindowCacheStatAccessor.getOpenFiles();
|
||||
final long jgitBytes = WindowCacheStatAccessor.getOpenBytes();
|
||||
|
||||
p.format("Mem: %s total = %s used + %s free + %s buffers\n",
|
||||
stdout.format("Mem: %s total = %s used + %s free + %s buffers\n",
|
||||
bytes(mTotal),
|
||||
bytes(mInuse - jgitBytes),
|
||||
bytes(mFree),
|
||||
bytes(jgitBytes));
|
||||
p.format(" %s max\n", bytes(mMax));
|
||||
p.format(" %8d open files, %8d cpus available, %8d threads\n",
|
||||
stdout.format(" %s max\n", bytes(mMax));
|
||||
stdout.format(" %8d open files, %8d cpus available, %8d threads\n",
|
||||
jgitOpen,
|
||||
r.availableProcessors(),
|
||||
ManagementFactory.getThreadMXBean().getThreadCount());
|
||||
p.print('\n');
|
||||
stdout.print('\n');
|
||||
}
|
||||
|
||||
private void taskSummary() {
|
||||
@@ -224,7 +199,7 @@ final class ShowCaches extends CacheCommand {
|
||||
case SLEEPING: tasksSleeping++; break;
|
||||
}
|
||||
}
|
||||
p.format(
|
||||
stdout.format(
|
||||
"Tasks: %4d total = %4d running + %4d ready + %4d sleeping\n",
|
||||
tasksTotal,
|
||||
tasksRunning,
|
||||
@@ -245,7 +220,7 @@ final class ShowCaches extends CacheCommand {
|
||||
oldest = Math.min(oldest, s.getCreationTime());
|
||||
}
|
||||
|
||||
p.format(
|
||||
stdout.format(
|
||||
"SSH: %4d users, oldest session started %s ago\n",
|
||||
list.size(),
|
||||
uptime(now - oldest));
|
||||
@@ -254,22 +229,22 @@ final class ShowCaches extends CacheCommand {
|
||||
private void jvmSummary() {
|
||||
OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
|
||||
RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
|
||||
p.format("JVM: %s %s %s\n",
|
||||
stdout.format("JVM: %s %s %s\n",
|
||||
runtimeBean.getVmVendor(),
|
||||
runtimeBean.getVmName(),
|
||||
runtimeBean.getVmVersion());
|
||||
p.format(" on %s %s %s\n", "",
|
||||
stdout.format(" on %s %s %s\n", "",
|
||||
osBean.getName(),
|
||||
osBean.getVersion(),
|
||||
osBean.getArch());
|
||||
try {
|
||||
p.format(" running as %s on %s\n",
|
||||
stdout.format(" running as %s on %s\n",
|
||||
System.getProperty("user.name"),
|
||||
InetAddress.getLocalHost().getHostName());
|
||||
} catch (UnknownHostException e) {
|
||||
}
|
||||
p.format(" cwd %s\n", path(new File(".").getAbsoluteFile().getParentFile()));
|
||||
p.format(" site %s\n", path(sitePath));
|
||||
stdout.format(" cwd %s\n", path(new File(".").getAbsoluteFile().getParentFile()));
|
||||
stdout.format(" site %s\n", path(sitePath));
|
||||
}
|
||||
|
||||
private String path(File file) {
|
||||
|
||||
Reference in New Issue
Block a user