Merge branch 'stable-2.14' into stable-2.15
* stable-2.14:
Fix access path propagation on git/ssh protocol
Change-Id: Ia38a54d210fb53dcb36a364f885cb1f2e17abf23
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/AbstractGitCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/AbstractGitCommand.java
index b9a98b9..c747c3e 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/AbstractGitCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/AbstractGitCommand.java
@@ -33,8 +33,6 @@
@Argument(index = 0, metaVar = "PROJECT.git", required = true, usage = "project name")
protected ProjectControl projectControl;
- @Inject private SshScope sshScope;
-
@Inject private GitRepositoryManager repoManager;
@Inject private SshSession session;
@@ -53,28 +51,25 @@
@Override
public void start(Environment env) {
Context ctx = context.subContext(newSession(), context.getCommandLine());
- final Context old = sshScope.set(ctx);
- try {
- startThread(
- new ProjectCommandRunnable() {
- @Override
- public void executeParseCommand() throws Exception {
- parseCommandLine();
- }
+ startThreadWithContext(
+ ctx,
+ new ProjectCommandRunnable() {
+ @Override
+ public void executeParseCommand() throws Exception {
+ parseCommandLine();
+ }
- @Override
- public void run() throws Exception {
- AbstractGitCommand.this.service();
- }
+ @Override
+ public void run() throws Exception {
+ AbstractGitCommand.this.service();
+ }
- @Override
- public Project.NameKey getProjectName() {
- return projectControl.getProjectState().getNameKey();
- }
- });
- } finally {
- sshScope.set(old);
- }
+ @Override
+ public Project.NameKey getProjectName() {
+ Project project = projectControl.getProjectState().getProject();
+ return project.getNameKey();
+ }
+ });
}
private SshSession newSession() {
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java
index 788b33f..c881b87 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/BaseCommand.java
@@ -49,6 +49,7 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.Charset;
+import java.util.Optional;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicReference;
@@ -260,6 +261,38 @@
}
/**
+ * Spawn a function into its own thread with the provided context.
+ *
+ * <p>Typically this should be invoked within {@link Command#start(Environment)}, such as:
+ *
+ * <pre>
+ * startThreadWithContext(SshScope.Context context, new CommandRunnable() {
+ * public void run() throws Exception {
+ * runImp();
+ * }
+ * });
+ * </pre>
+ *
+ * <p>If the function throws an exception, it is translated to a simple message for the client, a
+ * non-zero exit code, and the stack trace is logged.
+ *
+ * @param thunk the runnable to execute on the thread, performing the command's logic.
+ */
+ protected void startThreadWithContext(SshScope.Context context, CommandRunnable thunk) {
+ final TaskThunk tt = new TaskThunk(thunk, Optional.ofNullable(context));
+
+ if (isAdminHighPriorityCommand()) {
+ // Admin commands should not block the main work threads (there
+ // might be an interactive shell there), nor should they wait
+ // for the main work threads.
+ //
+ new Thread(tt, tt.toString()).start();
+ } else {
+ task.set(executor.submit(tt));
+ }
+ }
+
+ /**
* Spawn a function into its own thread.
*
* <p>Typically this should be invoked within {@link Command#start(Environment)}, such as:
@@ -277,18 +310,8 @@
*
* @param thunk the runnable to execute on the thread, performing the command's logic.
*/
- protected void startThread(CommandRunnable thunk) {
- final TaskThunk tt = new TaskThunk(thunk);
-
- if (isAdminHighPriorityCommand()) {
- // Admin commands should not block the main work threads (there
- // might be an interactive shell there), nor should they wait
- // for the main work threads.
- //
- new Thread(tt, tt.toString()).start();
- } else {
- task.set(executor.submit(tt));
- }
+ protected void startThread(final CommandRunnable thunk) {
+ startThreadWithContext(null, thunk);
}
private boolean isAdminHighPriorityCommand() {
@@ -413,18 +436,21 @@
private final class TaskThunk implements CancelableRunnable, ProjectRunnable {
private final CommandRunnable thunk;
+ private final Context taskContext;
private final String taskName;
+
private Project.NameKey projectName;
- private TaskThunk(CommandRunnable thunk) {
+ private TaskThunk(CommandRunnable thunk, Optional<Context> oneOffContext) {
this.thunk = thunk;
this.taskName = getTaskName();
+ this.taskContext = oneOffContext.orElse(context);
}
@Override
public void cancel() {
synchronized (this) {
- final Context old = sshScope.set(context);
+ final Context old = sshScope.set(taskContext);
try {
onExit(STATUS_CANCEL);
} finally {
@@ -439,7 +465,7 @@
final Thread thisThread = Thread.currentThread();
final String thisName = thisThread.getName();
int rc = 0;
- final Context old = sshScope.set(context);
+ final Context old = sshScope.set(taskContext);
try {
context.started = TimeUtil.nowMs();
thisThread.setName("SSH " + taskName);