summaryrefslogtreecommitdiffstats
path: root/gerrit-server/src/main/java/gerrit/PRED_commit_delta_4.java
blob: c2c2d1ca75cbaf43b031f7892561f3e27bdad02e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
// 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.client.Patch;
import com.google.gerrit.rules.StoredValues;
import com.google.gerrit.server.patch.PatchList;
import com.google.gerrit.server.patch.PatchListEntry;

import com.googlecode.prolog_cafe.lang.IllegalTypeException;
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 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;

    PatchList pl = StoredValues.PATCH_LIST.get(engine);
    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();
      @SuppressWarnings("unchecked")
      Iterator<PatchListEntry> iter =
        (Iterator<PatchListEntry>)((JavaObjectTerm)a5).object();
      while (iter.hasNext()) {
        PatchListEntry patch = iter.next();
        String newName = patch.getNewName();
        String oldName = patch.getOldName();
        Patch.ChangeType changeType = patch.getChangeType();

        if (newName.equals("/COMMIT_MSG")) {
          continue;
        }

        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)) {
            continue;
          }
          if (!a3.unify(newSym, engine.trail)) {
            continue;
          }
          if (!a4.unify(oldSym, engine.trail)) {
            continue;
          }
          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;

      @SuppressWarnings("unchecked")
      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");
  }
}