Add per-project prolog submit rule files
When loading the prolog environment, now checks refs/meta/config branch for a file called rules.pl. If it exists, consult the file. Expects a predicate called submit_rule. If no file is found, uses the default_submit predicate in common_rules.pl. Change-Id: Ia76d0dc5aba67cf3c68c56589fe013c63157bca5
This commit is contained in:
committed by
Shawn O. Pearce
parent
9f2535231b
commit
f93796cd53
@@ -72,6 +72,7 @@ public class ProjectConfig extends VersionedMetaData {
|
|||||||
private Map<AccountGroup.UUID, GroupReference> groupsByUUID;
|
private Map<AccountGroup.UUID, GroupReference> groupsByUUID;
|
||||||
private Map<String, AccessSection> accessSections;
|
private Map<String, AccessSection> accessSections;
|
||||||
private List<ValidationError> validationErrors;
|
private List<ValidationError> validationErrors;
|
||||||
|
private String prologRules;
|
||||||
|
|
||||||
public static ProjectConfig read(MetaDataUpdate update) throws IOException,
|
public static ProjectConfig read(MetaDataUpdate update) throws IOException,
|
||||||
ConfigInvalidException {
|
ConfigInvalidException {
|
||||||
@@ -148,6 +149,17 @@ public class ProjectConfig extends VersionedMetaData {
|
|||||||
return groupsByUUID.get(uuid);
|
return groupsByUUID.get(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the project's Prolog based rules.pl script,
|
||||||
|
* if present in the branch. Null if there are no rules.
|
||||||
|
*/
|
||||||
|
public String getPrologRules() {
|
||||||
|
if (prologRules.equals("")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return prologRules;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check all GroupReferences use current group name, repairing stale ones.
|
* Check all GroupReferences use current group name, repairing stale ones.
|
||||||
*
|
*
|
||||||
@@ -188,6 +200,7 @@ public class ProjectConfig extends VersionedMetaData {
|
|||||||
protected void onLoad() throws IOException, ConfigInvalidException {
|
protected void onLoad() throws IOException, ConfigInvalidException {
|
||||||
Map<String, GroupReference> groupsByName = readGroupList();
|
Map<String, GroupReference> groupsByName = readGroupList();
|
||||||
|
|
||||||
|
prologRules = readUTF8("rules.pl");
|
||||||
Config rc = readConfig(PROJECT_CONFIG);
|
Config rc = readConfig(PROJECT_CONFIG);
|
||||||
project = new Project(projectName);
|
project = new Project(projectName);
|
||||||
|
|
||||||
|
|||||||
@@ -28,10 +28,10 @@ import com.google.gwtorm.client.OrmException;
|
|||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Provider;
|
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.IntegerTerm;
|
||||||
import com.googlecode.prolog_cafe.lang.PrologException;
|
import com.googlecode.prolog_cafe.lang.PrologException;
|
||||||
import com.googlecode.prolog_cafe.lang.StructureTerm;
|
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.Term;
|
||||||
import com.googlecode.prolog_cafe.lang.VariableTerm;
|
import com.googlecode.prolog_cafe.lang.VariableTerm;
|
||||||
|
|
||||||
@@ -252,25 +252,36 @@ public class ChangeControl {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
PrologEnvironment env = getProjectControl().getProjectState().newPrologEnvironment();
|
PrologEnvironment env;
|
||||||
|
try {
|
||||||
|
env = getProjectControl().getProjectState().newPrologEnvironment();
|
||||||
|
} catch (CompileException err) {
|
||||||
|
log.error("cannot consult rules.pl", err);
|
||||||
|
return new CanSubmitResult("Error reading submit rule");
|
||||||
|
}
|
||||||
|
|
||||||
env.set(StoredValues.REVIEW_DB, db);
|
env.set(StoredValues.REVIEW_DB, db);
|
||||||
env.set(StoredValues.CHANGE, change);
|
env.set(StoredValues.CHANGE, change);
|
||||||
env.set(StoredValues.PATCH_SET_ID, patchSetId);
|
env.set(StoredValues.PATCH_SET_ID, patchSetId);
|
||||||
env.set(StoredValues.CHANGE_CONTROL, this);
|
env.set(StoredValues.CHANGE_CONTROL, this);
|
||||||
|
|
||||||
StructureTerm submitRule = SymbolTerm.makeSymbol(
|
Term submitRule = env.once("com.google.gerrit.rules.common", "locate_submit_rule",
|
||||||
"com.google.gerrit.rules.common", "default_submit", 1);
|
new VariableTerm());
|
||||||
|
if (submitRule == null) {
|
||||||
|
log.error("Error in locate_submit_rule: no submit_rule found");
|
||||||
|
return new CanSubmitResult("Error in finding submit rule");
|
||||||
|
}
|
||||||
|
|
||||||
List<Term> results = new ArrayList<Term>();
|
List<Term> results = new ArrayList<Term>();
|
||||||
try {
|
try {
|
||||||
for (Term[] template : env.all(
|
for (Term[] template : env.all(
|
||||||
"com.google.gerrit.rules.common", "can_submit",
|
"com.google.gerrit.rules.common", "can_submit",
|
||||||
submitRule,
|
submitRule,
|
||||||
new VariableTerm())) {
|
new VariableTerm())) {
|
||||||
results.add(template[1]);
|
results.add(template[1]);
|
||||||
}
|
}
|
||||||
} catch (PrologException err) {
|
} catch (PrologException err) {
|
||||||
log.error("PrologException calling "+submitRule, err);
|
log.error("PrologException calling " + submitRule, err);
|
||||||
return new CanSubmitResult("Error in submit rule");
|
return new CanSubmitResult("Error in submit rule");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,7 +330,7 @@ public class ChangeControl {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
} else if ("reject".equals(status.name())) {
|
} else if ("reject".equals(status.name())) {
|
||||||
return new CanSubmitResult("Submit blocked by "+ label);
|
return new CanSubmitResult("Submit blocked by " + label);
|
||||||
|
|
||||||
} else if ("need".equals(status.name())) {
|
} else if ("need".equals(status.name())) {
|
||||||
if (status.isStructure() && status.arg(0).isInteger()) {
|
if (status.isStructure() && status.arg(0).isInteger()) {
|
||||||
@@ -340,4 +351,4 @@ public class ChangeControl {
|
|||||||
|
|
||||||
return CanSubmitResult.OK;
|
return CanSubmitResult.OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,10 +29,17 @@ import com.google.gerrit.server.git.ProjectConfig;
|
|||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.assistedinject.Assisted;
|
import com.google.inject.assistedinject.Assisted;
|
||||||
|
|
||||||
|
import com.googlecode.prolog_cafe.compiler.CompileException;
|
||||||
|
import com.googlecode.prolog_cafe.lang.JavaObjectTerm;
|
||||||
|
import com.googlecode.prolog_cafe.lang.Prolog;
|
||||||
|
import com.googlecode.prolog_cafe.lang.SymbolTerm;
|
||||||
|
|
||||||
import org.eclipse.jgit.lib.Ref;
|
import org.eclipse.jgit.lib.Ref;
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.PushbackReader;
|
||||||
|
import java.io.StringReader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -121,9 +128,24 @@ public class ProjectState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @return Construct a new PrologEnvironment for the calling thread. */
|
/** @return Construct a new PrologEnvironment for the calling thread. */
|
||||||
public PrologEnvironment newPrologEnvironment() {
|
public PrologEnvironment newPrologEnvironment() throws CompileException {
|
||||||
// TODO Replace this with a per-project ClassLoader to isolate rules.
|
// TODO Replace this with a per-project ClassLoader to isolate rules.
|
||||||
return envFactory.create(getClass().getClassLoader());
|
PrologEnvironment env = envFactory.create(getClass().getClassLoader());
|
||||||
|
|
||||||
|
//consult rules.pl at refs/meta/config branch for custom submit rules
|
||||||
|
String rules = getConfig().getPrologRules();
|
||||||
|
if (rules != null) {
|
||||||
|
PushbackReader in =
|
||||||
|
new PushbackReader(new StringReader(rules), Prolog.PUSHBACK_SIZE);
|
||||||
|
JavaObjectTerm streamObject = new JavaObjectTerm(in);
|
||||||
|
if (!env.execute(Prolog.BUILTIN, "consult_stream",
|
||||||
|
SymbolTerm.makeSymbol("rules.pl"), streamObject)) {
|
||||||
|
throw new CompileException("Cannot consult rules.pl " +
|
||||||
|
getProject().getName() + " " + getConfig().getRevision());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Project getProject() {
|
public Project getProject() {
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ not_same(_, _).
|
|||||||
%%
|
%%
|
||||||
%% can_submit/2:
|
%% can_submit/2:
|
||||||
%%
|
%%
|
||||||
%% Execute the SubmitRule for each solution until one where all of the
|
%% Executes the SubmitRule for each solution until one where all of the
|
||||||
%% states has the format label(_, ok(_)) is found, then cut away any
|
%% states has the format label(_, ok(_)) is found, then cut away any
|
||||||
%% remaining choice points leaving this as the last solution.
|
%% remaining choice points leaving this as the last solution.
|
||||||
%%
|
%%
|
||||||
@@ -162,6 +162,30 @@ is_all_ok([label(_, ok(__)) | Ls]) :- is_all_ok(Ls).
|
|||||||
is_all_ok(_) :- fail.
|
is_all_ok(_) :- fail.
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
%%
|
||||||
|
%% locate_submit_rule/1:
|
||||||
|
%%
|
||||||
|
%% Finds a submit_rule depending on what rules are available.
|
||||||
|
%% If none are available, use default_submit/1.
|
||||||
|
%%
|
||||||
|
:- public locate_submit_rule/1.
|
||||||
|
%%
|
||||||
|
|
||||||
|
locate_submit_rule(RuleName) :-
|
||||||
|
clause(user:submit_rule(_), _),
|
||||||
|
!,
|
||||||
|
RuleName = user:submit_rule
|
||||||
|
.
|
||||||
|
locate_submit_rule(RuleName) :-
|
||||||
|
'$compiled_predicate'(user, submit_rule, 1),
|
||||||
|
!,
|
||||||
|
RuleName = user:submit_rule
|
||||||
|
.
|
||||||
|
locate_submit_rule(RuleName) :-
|
||||||
|
RuleName = 'com.google.gerrit.rules.common':default_submit.
|
||||||
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
%%
|
%%
|
||||||
%% default_submit/1:
|
%% default_submit/1:
|
||||||
|
|||||||
Reference in New Issue
Block a user