aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn Pearce <sop@google.com>2011-07-11 11:45:06 -0700
committerAndroid Code Review <code-review@android.com>2011-07-11 11:45:06 -0700
commit57aa8edde11f7643acb3b1c23151bcf6df857f1e (patch)
tree2ab05a99146667efadbc561ae3b586bc6d817cf9
parentac54919987975f8e426d503fb8c65f7878d3d430 (diff)
parent82c088e282e5e433cb4eb7dc9af0dfbac82e2162 (diff)
downloadgerrit-57aa8edde11f7643acb3b1c23151bcf6df857f1e.tar.gz
Merge "Add inheritance of prolog rules"
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java59
-rw-r--r--gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java20
-rw-r--r--gerrit-server/src/main/prolog/gerrit_common.pl92
-rw-r--r--gerrit-server/src/test/resources/com/google/gerrit/rules/gerrit_common_test.pl66
4 files changed, 235 insertions, 2 deletions
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java
index 26a01356..2c554622 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ChangeControl.java
@@ -32,8 +32,11 @@ import com.google.inject.Provider;
import com.googlecode.prolog_cafe.compiler.CompileException;
import com.googlecode.prolog_cafe.lang.IntegerTerm;
+import com.googlecode.prolog_cafe.lang.ListTerm;
+import com.googlecode.prolog_cafe.lang.Prolog;
import com.googlecode.prolog_cafe.lang.PrologException;
import com.googlecode.prolog_cafe.lang.StructureTerm;
+import com.googlecode.prolog_cafe.lang.SymbolTerm;
import com.googlecode.prolog_cafe.lang.Term;
import com.googlecode.prolog_cafe.lang.VariableTerm;
@@ -42,7 +45,9 @@ import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/** Access control management for a user accessing a single change. */
@@ -238,9 +243,10 @@ public class ChangeControl {
return ruleError("Patch set " + patchSetId + " is not current");
}
+ ProjectState projectState = getProjectControl().getProjectState();
PrologEnvironment env;
try {
- env = getProjectControl().getProjectState().newPrologEnvironment();
+ env = projectState.newPrologEnvironment();
} catch (CompileException err) {
return logRuleError("Cannot consult rules.pl for "
+ getProject().getName(), err);
@@ -275,6 +281,49 @@ public class ChangeControl {
+ change.getId() + " of " + getProject().getName(), err);
}
+ ProjectState parentState = projectState.getParentState();
+ PrologEnvironment childEnv = env;
+ Set<Project.NameKey> projectsSeen = new HashSet<Project.NameKey>();
+ projectsSeen.add(getProject().getNameKey());
+
+ while (parentState != null) {
+ if (!projectsSeen.add(parentState.getProject().getNameKey())) {
+ //parent has been seen before, stop walk up inheritance tree
+ break;
+ }
+ PrologEnvironment parentEnv;
+ try {
+ parentEnv = parentState.newPrologEnvironment();
+ } catch (CompileException err) {
+ return logRuleError("Cannot consult rules.pl for "
+ + parentState.getProject().getName(), err);
+ }
+ parentEnv.copyStoredValues(childEnv);
+ Term filterRule =
+ parentEnv.once("gerrit", "locate_submit_filter", new VariableTerm());
+ if (filterRule != null) {
+ try {
+ Term resultsTerm = toListTerm(results);
+ results.clear();
+ Term[] template = parentEnv.once(
+ "gerrit", "filter_submit_results",
+ filterRule,
+ resultsTerm,
+ new VariableTerm());
+ results.addAll(((ListTerm) template[2]).toJava());
+ } catch (PrologException err) {
+ return logRuleError("Exception calling " + filterRule + " on change "
+ + change.getId() + " of " + parentState.getProject().getName(), err);
+ } catch (RuntimeException err) {
+ return logRuleError("Exception calling " + filterRule + " on change "
+ + change.getId() + " of " + parentState.getProject().getName(), err);
+ }
+ }
+
+ parentState = parentState.getParentState();
+ childEnv = parentEnv;
+ }
+
if (results.isEmpty()) {
// This should never occur. A well written submit rule will always produce
// at least one result informing the caller of the labels that are
@@ -398,4 +447,12 @@ public class ChangeControl {
&& who.name().equals("user")
&& who.arg(0).isInteger();
}
+
+ private static Term toListTerm(List<Term> terms) {
+ Term list = Prolog.Nil;
+ for (int i = terms.size() - 1; i >= 0; i--) {
+ list = new ListTerm(terms.get(i), list);
+ }
+ return list;
+ }
} \ No newline at end of file
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
index c587829c..9f6f6e71 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectState.java
@@ -52,6 +52,7 @@ public class ProjectState {
}
private final boolean isAllProjects;
+ private final AllProjectsName allProjectsName;
private final ProjectCache projectCache;
private final ProjectControl.AssistedFactory projectControlFactory;
private final PrologEnvironment.Factory envFactory;
@@ -84,6 +85,7 @@ public class ProjectState {
@Assisted final ProjectConfig config) {
this.projectCache = projectCache;
this.isAllProjects = config.getProject().getNameKey().equals(allProjectsName);
+ this.allProjectsName = allProjectsName;
this.projectControlFactory = projectControlFactory;
this.envFactory = envFactory;
this.gitMgr = gitMgr;
@@ -257,4 +259,20 @@ public class ProjectState {
public ProjectControl controlFor(final CurrentUser user) {
return projectControlFactory.create(user, this);
}
-}
+
+ /**
+ * @return ProjectState of project's parent. If the project does not have a
+ * parent, return state of the top level project, All-Projects. If
+ * this project is All-Projects, return null.
+ */
+ public ProjectState getParentState() {
+ if (isAllProjects) {
+ return null;
+ }
+ Project.NameKey parentName = getProject().getParent();
+ if (parentName == null) {
+ parentName = allProjectsName;
+ }
+ return projectCache.get(parentName);
+ }
+} \ No newline at end of file
diff --git a/gerrit-server/src/main/prolog/gerrit_common.pl b/gerrit-server/src/main/prolog/gerrit_common.pl
index 7ff05c14..eb83ffdd 100644
--- a/gerrit-server/src/main/prolog/gerrit_common.pl
+++ b/gerrit-server/src/main/prolog/gerrit_common.pl
@@ -266,6 +266,98 @@ check_label_range_permission(Label, ExpValue, ok(Who)) :-
% .
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% filter_submit_results/3:
+%%
+%% Executes the submit_filter against the given list of results,
+%% returns a list of filtered results.
+%%
+:- public filter_submit_results/3.
+%%
+filter_submit_results(Filter, In, Out) :-
+ filter_submit_results(Filter, In, [], Tmp),
+ reverse(Tmp, Out).
+filter_submit_results(Filter, [I | In], Tmp, Out) :-
+ arg(1, I, R),
+ call_submit_filter(Filter, R, S),
+ !,
+ S =.. [submit | Ls],
+ ( is_all_ok(Ls) -> T = ok(S) ; T = not_ready(S) ),
+ filter_submit_results(Filter, In, [T | Tmp], Out).
+filter_submit_results(Filter, [_ | In], Tmp, Out) :-
+ filter_submit_results(Filter, In, Tmp, Out),
+ !
+ .
+filter_submit_results(Filter, [], Out, Out).
+
+call_submit_filter(P:X, R, S) :- !, F =.. [X, R, S], P:F.
+call_submit_filter(X, R, S) :- F =.. [X, R, S], F.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% locate_submit_filter/1:
+%%
+%% Finds a submit_filter if available.
+%%
+:- public locate_submit_filter/1.
+%%
+locate_submit_filter(FilterName) :-
+ '$compiled_predicate'(user, submit_filter, 2),
+ !,
+ FilterName = user:submit_filter
+ .
+locate_submit_filter(FilterName) :-
+ clause(user:submit_filter(_,_), _),
+ FilterName = user:submit_filter
+ .
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% find_label/3:
+%%
+%% Finds labels successively and fails when there are no more results.
+%%
+:- public find_label/3.
+%%
+find_label([], _, _) :- !, fail.
+find_label(List, Name, Label) :-
+ List = [_ | _],
+ !,
+ find_label2(List, Name, Label).
+find_label(S, Name, Label) :-
+ S =.. [submit | Ls],
+ find_label2(Ls, Name, Label).
+
+find_label2([L | _ ], Name, L) :- L = label(Name, _).
+find_label2([_ | Ls], Name, L) :- find_label2(Ls, Name, L).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% remove_label/3:
+%%
+%% Removes all occurances of label(Name, Status).
+%%
+:- public remove_label/3.
+%%
+remove_label([], _, []) :- !.
+remove_label(List, Label, Out) :-
+ List = [_ | _],
+ !,
+ subtract1(List, Label, Out).
+remove_label(S, Label, Out) :-
+ S =.. [submit | Ls],
+ subtract1(Ls, Label, Tmp),
+ Out =.. [submit | Tmp].
+
+subtract1([], _, []) :- !.
+subtract1([E | L], E, R) :- !, subtract1(L, E, R).
+subtract1([H | L], E, [H | R]) :- subtract1(L, E, R).
+
+
%% commit_author/1:
%%
:- public commit_author/1.
diff --git a/gerrit-server/src/test/resources/com/google/gerrit/rules/gerrit_common_test.pl b/gerrit-server/src/test/resources/com/google/gerrit/rules/gerrit_common_test.pl
index 6aae5094..db899a7a 100644
--- a/gerrit-server/src/test/resources/com/google/gerrit/rules/gerrit_common_test.pl
+++ b/gerrit-server/src/test/resources/com/google/gerrit/rules/gerrit_common_test.pl
@@ -87,6 +87,57 @@ test(can_submit_not_ready) :-
C = label('Code-Review', ok(test_user(alice))),
V = label('Verified', need(1)).
+test(can_submit_only_verified_not_ready) :-
+ can_submit(submit_only_verified, S),
+ S = not_ready(submit(V)),
+ V = label('Verified', need(1)).
+
+
+%% filter_submit_results
+%%
+test(filter_submit_remove_verified) :-
+ can_submit(gerrit:default_submit, R),
+ filter_submit_results(filter_out_v, [R], S),
+ S = [ok(submit(C))],
+ C = label('Code-Review', ok(test_user(alice))).
+
+test(filter_submit_add_code_review) :-
+ set_commit_labels([
+ commit_label( label('Code-Review', 2), test_user(alice) ),
+ commit_label( label('Verified', 1), test_user(builder) )
+ ]),
+ can_submit(submit_only_verified, R),
+ filter_submit_results(filter_in_cr, [R], S),
+ S = [ok(submit(C, V))],
+ C = label('Code-Review', ok(test_user(alice))),
+ V = label('Verified', ok(test_user(builder))).
+
+
+%% find_label
+%%
+test(find_default_code_review) :-
+ can_submit(gerrit:default_submit, R),
+ arg(1, R, S),
+ find_label(S, 'Code-Review', L),
+ L = label('Code-Review', ok(test_user(alice))).
+
+test(find_default_verified) :-
+ can_submit(gerrit:default_submit, R),
+ arg(1, R, S),
+ find_label(S, 'Verified', L),
+ L = label('Verified', need(1)).
+
+
+%% remove_label
+%%
+test(remove_default_code_review) :-
+ can_submit(gerrit:default_submit, R),
+ arg(1, R, S),
+ C = label('Code-Review', ok(test_user(alice))),
+ remove_label(S, C, Out),
+ Out = submit(V),
+ V = label('Verified', need(1)).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
@@ -107,6 +158,21 @@ all_commit_labels(Ls) :-
commit_label( label('You-Fail', -1), test_user(alice) )
].
+submit_only_verified(P) :-
+ max_with_block('Verified', -1, 1, Status),
+ P = submit(label('Verified', Status)).
+
+filter_out_v(R, S) :-
+ find_label(R, 'Verified', Verified), !,
+ remove_label(R, Verified, S).
+filter_out_v(R, S).
+
+filter_in_cr(R, S) :-
+ R =.. [submit | Labels],
+ max_with_block('Code-Review', -2, 2, Status),
+ CR = label('Code-Review', Status),
+ S =.. [submit , CR | Labels].
+
:- package user.
test_grant('Code-Review', test_user(alice), range(-2, 2)).
test_grant('Verified', test_user(builder), range(-1, 1)).