blob: 5a61d2945f9dabd11248cbdb976361cbd3cad5ec [file] [log] [blame]
// Copyright (C) 2021 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 com.googlesource.gerrit.plugins.task;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A TaskExpression represents a config string pointing to an expression which includes zero or more
* task names separated by a '|', and potentially termintated by a '|'. If the expression is not
* terminated by a '|' it indicates that task resolution of at least one task is required. Task
* selection priority is from left to right. This can be expressed as: <code>
* EXPR = [ TASK_NAME '|' ] TASK_NAME [ '|' ]</code>
*
* <p>Example expressions to prioritized names and requirements:
*
* <ul>
* <li><code> "simple" -> ("simple") required</code>
* <li><code> "world | peace" -> ("world", "peace") required</code>
* <li><code> "shadenfreud |" -> ("shadenfreud") optional</code>
* <li><code> "foo | bar |" -> ("foo", "bar") optional</code>
* </ul>
*/
public class TaskExpression implements Iterable<TaskKey> {
protected static final Pattern EXPRESSION_PATTERN = Pattern.compile("([^ |]+[^|]*)(\\|)?");
protected final TaskExpressionKey key;
public TaskExpression(FileKey key, String expression) {
this.key = TaskExpressionKey.create(key, expression);
}
@Override
public Iterator<TaskKey> iterator() {
return new Iterator<TaskKey>() {
Matcher m = EXPRESSION_PATTERN.matcher(key.expression());
Boolean hasNext;
boolean optional;
@Override
public boolean hasNext() {
if (hasNext == null) {
hasNext = m.find();
if (hasNext) {
optional = m.group(2) != null;
}
}
if (!hasNext && !optional) {
return true; // fake it so next() throws an Exception
}
return hasNext;
}
@Override
public TaskKey next() {
// Can't use @SuppressWarnings("ReturnValueIgnored") on method call
boolean ignored = hasNext(); // in case next() was (re)called w/o calling hasNext()
if (!hasNext) {
throw new NoSuchElementException("No more names, yet expression was not optional");
}
hasNext = null;
return TaskKey.create(key.file(), m.group(1).trim());
}
};
}
}