Convert ListChildProjects to PermissionBackend
Rewrite the code to use Java 8 streams and the new PermissionBackend to filter batches of direct children for ACCESS permission. Change-Id: I7ca6b5566a6ec675760dc937db369e9150546dd3
This commit is contained in:

committed by
David Pursehouse

parent
cb149254bb
commit
571f99c02a
@@ -378,7 +378,11 @@ public class ProjectApiImpl implements ProjectApi {
|
||||
public List<ProjectInfo> children(boolean recursive) throws RestApiException {
|
||||
ListChildProjects list = children.list();
|
||||
list.setRecursive(recursive);
|
||||
try {
|
||||
return list.apply(checkExists());
|
||||
} catch (PermissionBackendException e) {
|
||||
throw new RestApiException("Cannot list children", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -14,14 +14,21 @@
|
||||
|
||||
package com.google.gerrit.server.project;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.gerrit.extensions.common.ProjectInfo;
|
||||
import com.google.gerrit.extensions.restapi.RestReadView;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.permissions.PermissionBackend;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.gerrit.server.permissions.ProjectPermission;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -33,20 +40,23 @@ public class ListChildProjects implements RestReadView<ProjectResource> {
|
||||
private boolean recursive;
|
||||
|
||||
private final ProjectCache projectCache;
|
||||
private final PermissionBackend permissionBackend;
|
||||
private final Provider<CurrentUser> user;
|
||||
private final AllProjectsName allProjects;
|
||||
private final ProjectJson json;
|
||||
private final ProjectNode.Factory projectNodeFactory;
|
||||
|
||||
@Inject
|
||||
ListChildProjects(
|
||||
ProjectCache projectCache,
|
||||
PermissionBackend permissionBackend,
|
||||
Provider<CurrentUser> user,
|
||||
AllProjectsName allProjectsName,
|
||||
ProjectJson json,
|
||||
ProjectNode.Factory projectNodeFactory) {
|
||||
ProjectJson json) {
|
||||
this.projectCache = projectCache;
|
||||
this.permissionBackend = permissionBackend;
|
||||
this.user = user;
|
||||
this.allProjects = allProjectsName;
|
||||
this.json = json;
|
||||
this.projectNodeFactory = projectNodeFactory;
|
||||
}
|
||||
|
||||
public void setRecursive(boolean recursive) {
|
||||
@@ -54,60 +64,82 @@ public class ListChildProjects implements RestReadView<ProjectResource> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProjectInfo> apply(ProjectResource rsrc) {
|
||||
public List<ProjectInfo> apply(ProjectResource rsrc) throws PermissionBackendException {
|
||||
if (recursive) {
|
||||
return getChildProjectsRecursively(rsrc.getNameKey(), rsrc.getControl().getUser());
|
||||
return recursiveChildProjects(rsrc.getNameKey());
|
||||
}
|
||||
return getDirectChildProjects(rsrc.getNameKey());
|
||||
return directChildProjects(rsrc.getNameKey());
|
||||
}
|
||||
|
||||
private List<ProjectInfo> getDirectChildProjects(Project.NameKey parent) {
|
||||
List<ProjectInfo> childProjects = new ArrayList<>();
|
||||
for (Project.NameKey projectName : projectCache.all()) {
|
||||
ProjectState e = projectCache.get(projectName);
|
||||
if (e == null) {
|
||||
// If we can't get it from the cache, pretend it's not present.
|
||||
continue;
|
||||
}
|
||||
if (parent.equals(e.getProject().getParent(allProjects))) {
|
||||
childProjects.add(json.format(e.getProject()));
|
||||
}
|
||||
}
|
||||
return childProjects;
|
||||
}
|
||||
|
||||
private List<ProjectInfo> getChildProjectsRecursively(Project.NameKey parent, CurrentUser user) {
|
||||
Map<Project.NameKey, ProjectNode> projects = new HashMap<>();
|
||||
private List<ProjectInfo> directChildProjects(Project.NameKey parent)
|
||||
throws PermissionBackendException {
|
||||
Map<Project.NameKey, Project> children = new HashMap<>();
|
||||
for (Project.NameKey name : projectCache.all()) {
|
||||
ProjectState p = projectCache.get(name);
|
||||
if (p == null) {
|
||||
// If we can't get it from the cache, pretend it's not present.
|
||||
continue;
|
||||
ProjectState c = projectCache.get(name);
|
||||
if (c != null && parent.equals(c.getProject().getParent(allProjects))) {
|
||||
children.put(c.getProject().getNameKey(), c.getProject());
|
||||
}
|
||||
projects.put(name, projectNodeFactory.create(p.getProject(), p.controlFor(user).isVisible()));
|
||||
}
|
||||
for (ProjectNode key : projects.values()) {
|
||||
ProjectNode node = projects.get(key.getParentName());
|
||||
if (node != null) {
|
||||
node.addChild(key);
|
||||
}
|
||||
return permissionBackend
|
||||
.user(user)
|
||||
.filter(ProjectPermission.ACCESS, children.keySet())
|
||||
.stream()
|
||||
.sorted()
|
||||
.map((p) -> json.format(children.get(p)))
|
||||
.collect(toList());
|
||||
}
|
||||
|
||||
ProjectNode n = projects.get(parent);
|
||||
if (n != null) {
|
||||
return getChildProjectsRecursively(n);
|
||||
}
|
||||
return Collections.emptyList();
|
||||
private List<ProjectInfo> recursiveChildProjects(Project.NameKey parent)
|
||||
throws PermissionBackendException {
|
||||
Map<Project.NameKey, Project> projects = readAllProjects();
|
||||
Multimap<Project.NameKey, Project.NameKey> children = parentToChildren(projects);
|
||||
PermissionBackend.WithUser perm = permissionBackend.user(user);
|
||||
|
||||
List<ProjectInfo> results = new ArrayList<>();
|
||||
depthFirstFormat(results, perm, projects, children, parent);
|
||||
return results;
|
||||
}
|
||||
|
||||
private List<ProjectInfo> getChildProjectsRecursively(ProjectNode p) {
|
||||
List<ProjectInfo> allChildren = new ArrayList<>();
|
||||
for (ProjectNode c : p.getChildren()) {
|
||||
if (c.isVisible()) {
|
||||
allChildren.add(json.format(c.getProject()));
|
||||
allChildren.addAll(getChildProjectsRecursively(c));
|
||||
private Map<Project.NameKey, Project> readAllProjects() {
|
||||
Map<Project.NameKey, Project> projects = new HashMap<>();
|
||||
for (Project.NameKey name : projectCache.all()) {
|
||||
ProjectState c = projectCache.get(name);
|
||||
if (c != null) {
|
||||
projects.put(c.getProject().getNameKey(), c.getProject());
|
||||
}
|
||||
}
|
||||
return allChildren;
|
||||
return projects;
|
||||
}
|
||||
|
||||
/** Map of parent project to direct child. */
|
||||
private Multimap<Project.NameKey, Project.NameKey> parentToChildren(
|
||||
Map<Project.NameKey, Project> projects) {
|
||||
Multimap<Project.NameKey, Project.NameKey> m = ArrayListMultimap.create();
|
||||
for (Map.Entry<Project.NameKey, Project> e : projects.entrySet()) {
|
||||
if (!allProjects.equals(e.getKey())) {
|
||||
m.put(e.getValue().getParent(allProjects), e.getKey());
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
private void depthFirstFormat(
|
||||
List<ProjectInfo> results,
|
||||
PermissionBackend.WithUser perm,
|
||||
Map<Project.NameKey, Project> projects,
|
||||
Multimap<Project.NameKey, Project.NameKey> children,
|
||||
Project.NameKey parent)
|
||||
throws PermissionBackendException {
|
||||
List<Project.NameKey> canSee =
|
||||
perm.filter(ProjectPermission.ACCESS, children.get(parent))
|
||||
.stream()
|
||||
.sorted()
|
||||
.collect(toList());
|
||||
children.removeAll(parent); // removing all entries prevents cycles.
|
||||
|
||||
for (Project.NameKey c : canSee) {
|
||||
results.add(json.format(projects.get(c)));
|
||||
depthFirstFormat(results, perm, projects, children, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@ package com.google.gerrit.server.query.change;
|
||||
import com.google.gerrit.extensions.common.ProjectInfo;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.gerrit.server.project.ListChildProjects;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.project.ProjectResource;
|
||||
@@ -27,8 +28,12 @@ import com.google.inject.Provider;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ParentProjectPredicate extends OrPredicate<ChangeData> {
|
||||
private static final Logger log = LoggerFactory.getLogger(ParentProjectPredicate.class);
|
||||
|
||||
protected final String value;
|
||||
|
||||
public ParentProjectPredicate(
|
||||
@@ -52,11 +57,16 @@ public class ParentProjectPredicate extends OrPredicate<ChangeData> {
|
||||
|
||||
List<Predicate<ChangeData>> r = new ArrayList<>();
|
||||
r.add(new ProjectPredicate(projectState.getProject().getName()));
|
||||
try {
|
||||
ProjectResource proj = new ProjectResource(projectState.controlFor(self.get()));
|
||||
ListChildProjects children = listChildProjects.get();
|
||||
children.setRecursive(true);
|
||||
for (ProjectInfo p : children.apply(new ProjectResource(projectState.controlFor(self.get())))) {
|
||||
for (ProjectInfo p : children.apply(proj)) {
|
||||
r.add(new ProjectPredicate(p.name));
|
||||
}
|
||||
} catch (PermissionBackendException e) {
|
||||
log.warn("cannot check permissions to expand child projects", e);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@@ -21,6 +21,7 @@ import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.server.config.AllProjectsName;
|
||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||
import com.google.gerrit.server.git.ProjectConfig;
|
||||
import com.google.gerrit.server.permissions.PermissionBackendException;
|
||||
import com.google.gerrit.server.project.ListChildProjects;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.project.ProjectControl;
|
||||
@@ -129,7 +130,11 @@ final class AdminSetParent extends SshCommand {
|
||||
childProjects.add(pc.getProject().getNameKey());
|
||||
}
|
||||
if (oldParent != null) {
|
||||
try {
|
||||
childProjects.addAll(getChildrenForReparenting(oldParent));
|
||||
} catch (PermissionBackendException e) {
|
||||
throw new Failure(1, "permissions unavailable", e);
|
||||
}
|
||||
}
|
||||
|
||||
for (final Project.NameKey nameKey : childProjects) {
|
||||
@@ -185,7 +190,8 @@ final class AdminSetParent extends SshCommand {
|
||||
* list of child projects does not contain projects that were specified to be excluded from
|
||||
* reparenting.
|
||||
*/
|
||||
private List<Project.NameKey> getChildrenForReparenting(final ProjectControl parent) {
|
||||
private List<Project.NameKey> getChildrenForReparenting(final ProjectControl parent)
|
||||
throws PermissionBackendException {
|
||||
final List<Project.NameKey> childProjects = new ArrayList<>();
|
||||
final List<Project.NameKey> excluded = new ArrayList<>(excludedChildren.size());
|
||||
for (final ProjectControl excludedChild : excludedChildren) {
|
||||
|
Reference in New Issue
Block a user