Predicates to expose commit filelist to Prolog

commit_delta/1,3,4 each takes a regular expression and matches it to
the path of all the files in the latest patchset of a commit.
If applicable (changes where the file is renamed or copied), the
regex is also checked against the old path.

commit_delta/1 returns true if any files match the regex
commit_delta/3 returns the changetype and path, if the changetype is
renamed, it also returns the old path. If the changetype is rename,
it returns a delete for oldpath and an add for newpath. If the
changetype is copy, an add is returned along with newpath.
commit_delta/4 returns the changetype, new path, and old path
(if applicable)

Change-Id: I05424029624b7d4bced05ebd642471fc27a0f50a
This commit is contained in:
Jason Tsay
2011-06-27 11:25:07 -07:00
parent c3a2f83605
commit 93f4de9fcf
4 changed files with 248 additions and 0 deletions

View File

@@ -51,6 +51,9 @@ public final class PatchSetInfo {
/** List of parents of the patch set. */
protected List<ParentInfo> parents;
/** SHA-1 of commit */
protected String revId;
protected PatchSetInfo() {
}
@@ -105,4 +108,12 @@ public final class PatchSetInfo {
public List<ParentInfo> getParents() {
return parents;
}
public void setRevId(final String s) {
revId = s;
}
public String getRevId() {
return revId;
}
}

View File

@@ -67,6 +67,7 @@ public class PatchSetInfoFactory {
info.setMessage(src.getFullMessage());
info.setAuthor(toUserIdentity(src.getAuthorIdent()));
info.setCommitter(toUserIdentity(src.getCommitterIdent()));
info.setRevId(src.getName());
return info;
}

View File

@@ -0,0 +1,214 @@
// Copyright (C) 2011 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 gerrit;
import com.google.gerrit.reviewdb.AccountDiffPreference.Whitespace;
import com.google.gerrit.reviewdb.Change;
import com.google.gerrit.reviewdb.Patch;
import com.google.gerrit.reviewdb.PatchSet;
import com.google.gerrit.reviewdb.PatchSetInfo;
import com.google.gerrit.reviewdb.Project;
import com.google.gerrit.rules.PrologEnvironment;
import com.google.gerrit.rules.StoredValues;
import com.google.gerrit.server.patch.PatchList;
import com.google.gerrit.server.patch.PatchListCache;
import com.google.gerrit.server.patch.PatchListEntry;
import com.google.gerrit.server.patch.PatchListKey;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
import com.googlecode.prolog_cafe.lang.IllegalTypeException;
import com.googlecode.prolog_cafe.lang.JavaException;
import com.googlecode.prolog_cafe.lang.JavaObjectTerm;
import com.googlecode.prolog_cafe.lang.Operation;
import com.googlecode.prolog_cafe.lang.PInstantiationException;
import com.googlecode.prolog_cafe.lang.Predicate;
import com.googlecode.prolog_cafe.lang.Prolog;
import com.googlecode.prolog_cafe.lang.PrologException;
import com.googlecode.prolog_cafe.lang.SymbolTerm;
import com.googlecode.prolog_cafe.lang.Term;
import org.eclipse.jgit.lib.ObjectId;
import java.util.Iterator;
import java.util.regex.Pattern;
/**
* Given a regular expression, checks it against the file list in the most
* recent patchset of a change. For all files that match the regex, returns the
* (new) path of the file, the change type, and the old path of the file if
* applicable (if the file was copied or renamed).
*
* <pre>
* 'commit_delta'(+Regex, -ChangeType, -NewPath, -OldPath)
* </pre>
*/
public class PRED_commit_delta_4 extends Predicate.P4 {
private static final long serialVersionUID = 1L;
private static final SymbolTerm add = SymbolTerm.intern("add");
private static final SymbolTerm modify = SymbolTerm.intern("modify");
private static final SymbolTerm delete = SymbolTerm.intern("delete");
private static final SymbolTerm rename = SymbolTerm.intern("rename");
private static final SymbolTerm copy = SymbolTerm.intern("copy");
static final Operation commit_delta_check = new PRED_commit_delta_check();
static final Operation commit_delta_next = new PRED_commit_delta_next();
static final Operation commit_delta_empty = new PRED_commit_delta_empty();
public PRED_commit_delta_4(Term a1, Term a2, Term a3, Term a4, Operation n) {
arg1 = a1;
arg2 = a2;
arg3 = a3;
arg4 = a4;
cont = n;
}
@Override
public Operation exec(Prolog engine) throws PrologException {
engine.cont = cont;
engine.setB0();
Term a1 = arg1.dereference();
if (a1.isVariable()) {
throw new PInstantiationException(this, 1);
}
if (!a1.isSymbol()) {
throw new IllegalTypeException(this, 1, "symbol", a1);
}
Pattern regex = Pattern.compile(a1.name());
engine.areg1 = new JavaObjectTerm(regex);
engine.areg2 = arg2;
engine.areg3 = arg3;
engine.areg4 = arg4;
PrologEnvironment env = (PrologEnvironment) engine.control;
PatchSetInfo psInfo;
try {
psInfo = getPatchSetInfo(env);
} catch (PatchSetInfoNotAvailableException err) {
throw new JavaException(this, 1, err);
}
PatchListCache plCache = env.getInjector().getInstance(PatchListCache.class);
Change change = StoredValues.CHANGE.get(engine);
Project.NameKey projectKey = change.getProject();
ObjectId a = null;
ObjectId b = ObjectId.fromString(psInfo.getRevId());
Whitespace ws = Whitespace.IGNORE_NONE;
PatchListKey plKey = new PatchListKey(projectKey, a, b, ws);
PatchList pl = plCache.get(plKey);
Iterator<PatchListEntry> iter = pl.getPatches().iterator();
engine.areg5 = new JavaObjectTerm(iter);
return engine.jtry5(commit_delta_check, commit_delta_next);
}
private static final class PRED_commit_delta_check extends Operation {
@Override
public Operation exec(Prolog engine) {
Term a1 = engine.areg1;
Term a2 = engine.areg2;
Term a3 = engine.areg3;
Term a4 = engine.areg4;
Term a5 = engine.areg5;
Pattern regex = (Pattern)((JavaObjectTerm)a1).object();
Iterator<PatchListEntry> iter =
(Iterator<PatchListEntry>)((JavaObjectTerm)a5).object();
if (iter.hasNext()) {
PatchListEntry patch = iter.next();
String newName = patch.getNewName();
String oldName = patch.getOldName();
Patch.ChangeType changeType = patch.getChangeType();
if (regex.matcher(newName).matches() ||
(oldName != null && regex.matcher(oldName).matches())) {
SymbolTerm changeSym = getTypeSymbol(changeType);
SymbolTerm newSym = SymbolTerm.create(newName);
SymbolTerm oldSym = Prolog.Nil;
if (oldName != null) {
oldSym = SymbolTerm.create(oldName);
}
if (!a2.unify(changeSym, engine.trail)) {
return engine.fail();
}
if (!a3.unify(newSym, engine.trail)) {
return engine.fail();
}
if (!a4.unify(oldSym, engine.trail)) {
return engine.fail();
}
return engine.cont;
}
}
return engine.fail();
}
}
private static final class PRED_commit_delta_next extends Operation {
@Override
public Operation exec(Prolog engine) {
return engine.trust(commit_delta_empty);
}
}
private static final class PRED_commit_delta_empty extends Operation {
@Override
public Operation exec(Prolog engine) {
Term a5 = engine.areg5;
Iterator<PatchListEntry> iter =
(Iterator<PatchListEntry>)((JavaObjectTerm)a5).object();
if (!iter.hasNext()) {
return engine.fail();
}
return engine.jtry5(commit_delta_check, commit_delta_next);
}
}
private static SymbolTerm getTypeSymbol(Patch.ChangeType type) {
switch (type) {
case ADDED:
return add;
case MODIFIED:
return modify;
case DELETED:
return delete;
case RENAMED:
return rename;
case COPIED:
return copy;
}
throw new IllegalArgumentException("ChangeType not recognized");
}
protected PatchSetInfo getPatchSetInfo(PrologEnvironment env)
throws PatchSetInfoNotAvailableException {
PatchSetInfo psInfo = env.get(StoredValues.PATCH_SET_INFO);
if (psInfo == null) {
PatchSet.Id patchSetId = env.get(StoredValues.PATCH_SET_ID);
PatchSetInfoFactory patchInfoFactory =
env.getInjector().getInstance(PatchSetInfoFactory.class);
psInfo = patchInfoFactory.get(patchSetId);
env.set(StoredValues.PATCH_SET_INFO, psInfo);
}
return psInfo;
}
}

View File

@@ -280,3 +280,25 @@ commit_author(Author) :-
%%
commit_committer(Committer) :-
commit_committer(Committer, _, _).
%% commit_delta/1:
%%
:- public commit_delta/1.
%%
commit_delta(Regex) :-
once(commit_delta(Regex, _, _, _)).
%% commit_delta/3:
%%
:- public commit_delta/3.
%%
commit_delta(Regex, Type, Path) :-
commit_delta(Regex, TmpType, NewPath, OldPath),
split_commit_delta(TmpType, NewPath, OldPath, Type, Path).
split_commit_delta(rename, NewPath, OldPath, delete, OldPath).
split_commit_delta(rename, NewPath, OldPath, add, NewPath) :- !.
split_commit_delta(copy, NewPath, OldPath, add, NewPath) :- !.
split_commit_delta(Type, Path, _, Type, Path).