show-queue accessible to users
Let non-admin users be able to run the show-queue command. If this command is invoked by a non-admin users, a smaller set of data will be displayed.
This commit is contained in:
@@ -0,0 +1,25 @@
|
|||||||
|
// Copyright (C) 2010 The Android Open Source Project
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
package com.google.gerrit.server.git;
|
||||||
|
|
||||||
|
import com.google.gerrit.reviewdb.Project;
|
||||||
|
|
||||||
|
/** Used to retrieve the project name from an operation **/
|
||||||
|
public interface ProjectRunnable extends Runnable {
|
||||||
|
Project.NameKey getProjectNameKey();
|
||||||
|
|
||||||
|
String getRemoteName();
|
||||||
|
|
||||||
|
boolean hasCustomizedPrint();
|
||||||
|
}
|
||||||
@@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
package com.google.gerrit.server.git;
|
package com.google.gerrit.server.git;
|
||||||
|
|
||||||
|
import com.google.gerrit.reviewdb.Project;
|
||||||
|
import com.google.gerrit.reviewdb.Project.NameKey;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.assistedinject.Assisted;
|
import com.google.inject.assistedinject.Assisted;
|
||||||
|
|
||||||
@@ -49,7 +51,7 @@ import java.util.Set;
|
|||||||
* Instance members are protected by the lock within PushQueue. Callers must
|
* Instance members are protected by the lock within PushQueue. Callers must
|
||||||
* take that lock to ensure they are working with a current view of the object.
|
* take that lock to ensure they are working with a current view of the object.
|
||||||
*/
|
*/
|
||||||
class PushOp implements Runnable {
|
class PushOp implements ProjectRunnable {
|
||||||
interface Factory {
|
interface Factory {
|
||||||
PushOp create(String d, URIish u);
|
PushOp create(String d, URIish u);
|
||||||
}
|
}
|
||||||
@@ -284,4 +286,19 @@ class PushOp implements Runnable {
|
|||||||
final boolean force = spec.isForceUpdate();
|
final boolean force = spec.isForceUpdate();
|
||||||
cmds.add(new RemoteRefUpdate(db, null, dst, force, null, null));
|
cmds.add(new RemoteRefUpdate(db, null, dst, force, null, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NameKey getProjectNameKey() {
|
||||||
|
return new Project.NameKey(projectName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRemoteName() {
|
||||||
|
return config.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasCustomizedPrint() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
package com.google.gerrit.server.git;
|
package com.google.gerrit.server.git;
|
||||||
|
|
||||||
import com.google.gerrit.lifecycle.LifecycleListener;
|
import com.google.gerrit.lifecycle.LifecycleListener;
|
||||||
|
import com.google.gerrit.reviewdb.Project.NameKey;
|
||||||
import com.google.gerrit.server.util.IdGenerator;
|
import com.google.gerrit.server.util.IdGenerator;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
@@ -168,7 +169,15 @@ public class WorkQueue {
|
|||||||
r = super.decorateTask(runnable, r);
|
r = super.decorateTask(runnable, r);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
final int id = idGenerator.next();
|
final int id = idGenerator.next();
|
||||||
final Task<V> task = new Task<V>(runnable, r, this, id);
|
|
||||||
|
Task<V> task;
|
||||||
|
|
||||||
|
if (runnable instanceof ProjectRunnable) {
|
||||||
|
task = new ProjectTask<V>((ProjectRunnable)runnable, r, this, id);
|
||||||
|
} else {
|
||||||
|
task = new Task<V>(runnable, r, this, id);
|
||||||
|
}
|
||||||
|
|
||||||
if (all.putIfAbsent(task.getTaskId(), task) == null) {
|
if (all.putIfAbsent(task.getTaskId(), task) == null) {
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
@@ -328,4 +337,33 @@ public class WorkQueue {
|
|||||||
return runnable.toString();
|
return runnable.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Same as Task class, but with a reference to ProjectRunnable, used to retrieve
|
||||||
|
* the project name from the operation queued
|
||||||
|
**/
|
||||||
|
public static class ProjectTask<V> extends Task<V> implements ProjectRunnable {
|
||||||
|
|
||||||
|
private final ProjectRunnable runnable;
|
||||||
|
|
||||||
|
ProjectTask(ProjectRunnable runnable, RunnableScheduledFuture<V> task,
|
||||||
|
Executor executor, int taskId) {
|
||||||
|
super(runnable, task, executor, taskId);
|
||||||
|
this.runnable = runnable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NameKey getProjectNameKey() {
|
||||||
|
return runnable.getProjectNameKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRemoteName() {
|
||||||
|
return runnable.getRemoteName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasCustomizedPrint() {
|
||||||
|
return runnable.hasCustomizedPrint();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,12 +58,22 @@ public abstract class AbstractGitCommand extends BaseCommand {
|
|||||||
Context ctx = context.subContext(newSession(), context.getCommandLine());
|
Context ctx = context.subContext(newSession(), context.getCommandLine());
|
||||||
final Context old = SshScope.set(ctx);
|
final Context old = SshScope.set(ctx);
|
||||||
try {
|
try {
|
||||||
startThread(new CommandRunnable() {
|
startThread(new ProjectCommandRunnable() {
|
||||||
|
@Override
|
||||||
|
public void executeParseCommand() throws Exception {
|
||||||
|
parseCommandLine();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
parseCommandLine();
|
|
||||||
AbstractGitCommand.this.service();
|
AbstractGitCommand.this.service();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Project.NameKey getProjectName() {
|
||||||
|
Project project = projectControl.getProjectState().getProject();
|
||||||
|
return project.getNameKey();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
SshScope.set(old);
|
SshScope.set(old);
|
||||||
|
|||||||
@@ -14,9 +14,12 @@
|
|||||||
|
|
||||||
package com.google.gerrit.sshd;
|
package com.google.gerrit.sshd;
|
||||||
|
|
||||||
|
import com.google.gerrit.reviewdb.Project;
|
||||||
|
import com.google.gerrit.reviewdb.Project.NameKey;
|
||||||
import com.google.gerrit.server.CurrentUser;
|
import com.google.gerrit.server.CurrentUser;
|
||||||
import com.google.gerrit.server.IdentifiedUser;
|
import com.google.gerrit.server.IdentifiedUser;
|
||||||
import com.google.gerrit.server.RequestCleanup;
|
import com.google.gerrit.server.RequestCleanup;
|
||||||
|
import com.google.gerrit.server.git.ProjectRunnable;
|
||||||
import com.google.gerrit.server.git.WorkQueue;
|
import com.google.gerrit.server.git.WorkQueue;
|
||||||
import com.google.gerrit.server.git.WorkQueue.CancelableRunnable;
|
import com.google.gerrit.server.git.WorkQueue.CancelableRunnable;
|
||||||
import com.google.gerrit.server.project.NoSuchChangeException;
|
import com.google.gerrit.server.project.NoSuchChangeException;
|
||||||
@@ -335,10 +338,11 @@ public abstract class BaseCommand implements Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class TaskThunk implements CancelableRunnable {
|
private final class TaskThunk implements CancelableRunnable, ProjectRunnable {
|
||||||
private final CommandRunnable thunk;
|
private final CommandRunnable thunk;
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final String taskName;
|
private final String taskName;
|
||||||
|
private Project.NameKey projectName;
|
||||||
|
|
||||||
private TaskThunk(final CommandRunnable thunk) {
|
private TaskThunk(final CommandRunnable thunk) {
|
||||||
this.thunk = thunk;
|
this.thunk = thunk;
|
||||||
@@ -372,6 +376,12 @@ public abstract class BaseCommand implements Command {
|
|||||||
try {
|
try {
|
||||||
context.started = System.currentTimeMillis();
|
context.started = System.currentTimeMillis();
|
||||||
thisThread.setName("SSH " + taskName);
|
thisThread.setName("SSH " + taskName);
|
||||||
|
|
||||||
|
if (thunk instanceof ProjectCommandRunnable) {
|
||||||
|
((ProjectCommandRunnable) thunk).executeParseCommand();
|
||||||
|
projectName = ((ProjectCommandRunnable) thunk).getProjectName();
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
thunk.run();
|
thunk.run();
|
||||||
} catch (NoSuchProjectException e) {
|
} catch (NoSuchProjectException e) {
|
||||||
@@ -379,6 +389,7 @@ public abstract class BaseCommand implements Command {
|
|||||||
} catch (NoSuchChangeException e) {
|
} catch (NoSuchChangeException e) {
|
||||||
throw new UnloggedFailure(1, e.getMessage() + " no such change");
|
throw new UnloggedFailure(1, e.getMessage() + " no such change");
|
||||||
}
|
}
|
||||||
|
|
||||||
out.flush();
|
out.flush();
|
||||||
err.flush();
|
err.flush();
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
@@ -405,6 +416,21 @@ public abstract class BaseCommand implements Command {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return taskName;
|
return taskName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NameKey getProjectNameKey() {
|
||||||
|
return projectName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRemoteName() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasCustomizedPrint() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Runnable function which can throw an exception. */
|
/** Runnable function which can throw an exception. */
|
||||||
@@ -412,6 +438,15 @@ public abstract class BaseCommand implements Command {
|
|||||||
public void run() throws Exception;
|
public void run() throws Exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Runnable function which can retrieve a project name related to the task */
|
||||||
|
public static interface ProjectCommandRunnable extends CommandRunnable {
|
||||||
|
// execute parser command before running, in order to be able to retrieve
|
||||||
|
// project name
|
||||||
|
public void executeParseCommand() throws Exception;
|
||||||
|
|
||||||
|
public Project.NameKey getProjectName();
|
||||||
|
}
|
||||||
|
|
||||||
/** Thrown from {@link CommandRunnable#run()} with client message and code. */
|
/** Thrown from {@link CommandRunnable#run()} with client message and code. */
|
||||||
public static class Failure extends Exception {
|
public static class Failure extends Exception {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class DefaultCommandModule extends CommandModule {
|
|||||||
command(gerrit, "ls-projects").to(ListProjects.class);
|
command(gerrit, "ls-projects").to(ListProjects.class);
|
||||||
command(gerrit, "show-caches").to(AdminShowCaches.class);
|
command(gerrit, "show-caches").to(AdminShowCaches.class);
|
||||||
command(gerrit, "show-connections").to(AdminShowConnections.class);
|
command(gerrit, "show-connections").to(AdminShowConnections.class);
|
||||||
command(gerrit, "show-queue").to(AdminShowQueue.class);
|
command(gerrit, "show-queue").to(ShowQueue.class);
|
||||||
command(gerrit, "stream-events").to(StreamEvents.class);
|
command(gerrit, "stream-events").to(StreamEvents.class);
|
||||||
|
|
||||||
command(git).toProvider(new DispatchCommandProvider(git));
|
command(git).toProvider(new DispatchCommandProvider(git));
|
||||||
|
|||||||
@@ -14,10 +14,14 @@
|
|||||||
|
|
||||||
package com.google.gerrit.sshd.commands;
|
package com.google.gerrit.sshd.commands;
|
||||||
|
|
||||||
|
import com.google.gerrit.reviewdb.Project;
|
||||||
|
import com.google.gerrit.server.CurrentUser;
|
||||||
import com.google.gerrit.server.git.WorkQueue;
|
import com.google.gerrit.server.git.WorkQueue;
|
||||||
|
import com.google.gerrit.server.git.WorkQueue.ProjectTask;
|
||||||
import com.google.gerrit.server.git.WorkQueue.Task;
|
import com.google.gerrit.server.git.WorkQueue.Task;
|
||||||
|
import com.google.gerrit.server.project.ProjectCache;
|
||||||
|
import com.google.gerrit.server.project.ProjectState;
|
||||||
import com.google.gerrit.server.util.IdGenerator;
|
import com.google.gerrit.server.util.IdGenerator;
|
||||||
import com.google.gerrit.sshd.AdminCommand;
|
|
||||||
import com.google.gerrit.sshd.BaseCommand;
|
import com.google.gerrit.sshd.BaseCommand;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
@@ -33,14 +37,19 @@ import java.util.List;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/** Display the current work queue. */
|
/** Display the current work queue. */
|
||||||
@AdminCommand
|
final class ShowQueue extends BaseCommand {
|
||||||
final class AdminShowQueue extends BaseCommand {
|
|
||||||
@Option(name = "-w", usage = "display without line width truncation")
|
@Option(name = "-w", usage = "display without line width truncation")
|
||||||
private boolean wide;
|
private boolean wide;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private WorkQueue workQueue;
|
private WorkQueue workQueue;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ProjectCache projectCache;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private CurrentUser userProvider;
|
||||||
|
|
||||||
private PrintWriter p;
|
private PrintWriter p;
|
||||||
private int columns = 80;
|
private int columns = 80;
|
||||||
private int taskNameWidth;
|
private int taskNameWidth;
|
||||||
@@ -60,7 +69,7 @@ final class AdminShowQueue extends BaseCommand {
|
|||||||
@Override
|
@Override
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
parseCommandLine();
|
parseCommandLine();
|
||||||
AdminShowQueue.this.display();
|
ShowQueue.this.display();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -97,7 +106,10 @@ final class AdminShowQueue extends BaseCommand {
|
|||||||
p.print("----------------------------------------------"
|
p.print("----------------------------------------------"
|
||||||
+ "--------------------------------\n");
|
+ "--------------------------------\n");
|
||||||
|
|
||||||
|
int numberOfPendingTasks = 0;
|
||||||
final long now = System.currentTimeMillis();
|
final long now = System.currentTimeMillis();
|
||||||
|
final boolean isAdministrator = userProvider.isAdministrator();
|
||||||
|
|
||||||
for (final Task<?> task : pending) {
|
for (final Task<?> task : pending) {
|
||||||
final long delay = task.getDelay(TimeUnit.MILLISECONDS);
|
final long delay = task.getDelay(TimeUnit.MILLISECONDS);
|
||||||
final Task.State state = task.getState();
|
final Task.State state = task.getState();
|
||||||
@@ -115,12 +127,56 @@ final class AdminShowQueue extends BaseCommand {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean regularUserCanSee = false;
|
||||||
|
boolean hasCustomizedPrint = true;
|
||||||
|
|
||||||
|
// If the user is not administrator, check if has rights to see
|
||||||
|
// the Task
|
||||||
|
Project.NameKey projectName = null;
|
||||||
|
String remoteName = null;
|
||||||
|
|
||||||
|
if (!isAdministrator) {
|
||||||
|
if (task instanceof ProjectTask<?>) {
|
||||||
|
projectName = ((ProjectTask<?>)task).getProjectNameKey();
|
||||||
|
remoteName = ((ProjectTask<?>)task).getRemoteName();
|
||||||
|
hasCustomizedPrint = ((ProjectTask<?>)task).hasCustomizedPrint();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectState e = null;
|
||||||
|
if (projectName != null) {
|
||||||
|
e = projectCache.get(projectName);
|
||||||
|
}
|
||||||
|
|
||||||
|
regularUserCanSee = e != null && e.controlFor(userProvider).isVisible();
|
||||||
|
|
||||||
|
if (regularUserCanSee) {
|
||||||
|
numberOfPendingTasks++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shows information about tasks depending on the user rights
|
||||||
|
if (isAdministrator || (!hasCustomizedPrint && regularUserCanSee)) {
|
||||||
p.print(String.format("%8s %-12s %-8s %s\n", //
|
p.print(String.format("%8s %-12s %-8s %s\n", //
|
||||||
id(task.getTaskId()), start, "", format(task)));
|
id(task.getTaskId()), start, "", format(task)));
|
||||||
|
} else if (regularUserCanSee) {
|
||||||
|
if (remoteName == null) {
|
||||||
|
remoteName = projectName.get();
|
||||||
|
} else {
|
||||||
|
remoteName = remoteName + "/" + projectName;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.print(String.format("%8s %-12s %-8s %s\n", //
|
||||||
|
id(task.getTaskId()), start, "", remoteName));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
p.print("----------------------------------------------"
|
p.print("----------------------------------------------"
|
||||||
+ "--------------------------------\n");
|
+ "--------------------------------\n");
|
||||||
p.print(" " + pending.size() + " tasks\n");
|
|
||||||
|
if (isAdministrator) {
|
||||||
|
numberOfPendingTasks = pending.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
p.print(" " + numberOfPendingTasks + " tasks\n");
|
||||||
|
|
||||||
p.flush();
|
p.flush();
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user