blob: 1ccf6734cdc32634ca98201921d6ea4b21c2ba58 [file] [log] [blame]
// Copyright (C) 2020 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 com.google.common.annotations.VisibleForTesting;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.config.AllProjectsNameProvider;
import com.google.gerrit.server.config.AllUsersNameProvider;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import java.nio.file.Paths;
import java.util.NoSuchElementException;
import org.antlr.v4.runtime.BaseErrorListener;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.Lexer;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Recognizer;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.eclipse.jgit.errors.ConfigInvalidException;
/** This class is used by TaskExpression to decode the task from task reference. */
public class TaskReference {
protected final String reference;
protected final TaskKey.Builder taskKeyBuilder;
interface Factory {
TaskReference create(FileKey relativeTo, String reference);
}
@Inject
public TaskReference(
AllProjectsNameProvider allProjectsNameProvider,
AllUsersNameProvider allUsersNameProvider,
AccountCache accountCache,
GroupCache groupCache,
TaskPluginConfiguration config,
@Assisted FileKey relativeTo,
@Assisted String reference) {
this(
new TaskKey.Builder(
relativeTo,
allProjectsNameProvider.get(),
allUsersNameProvider.get(),
accountCache,
groupCache,
config),
reference);
}
@VisibleForTesting
public TaskReference(TaskKey.Builder taskKeyBuilder, String reference) {
this.taskKeyBuilder = taskKeyBuilder;
this.reference = reference.trim();
if (reference.isEmpty()) {
throw new NoSuchElementException();
}
}
public TaskKey getTaskKey() throws ConfigInvalidException {
ParseTreeWalker walker = new ParseTreeWalker();
try {
walker.walk(new TaskReferenceListener(taskKeyBuilder), parse());
} catch (RuntimeConfigInvalidException e) {
throw e.checkedException;
}
return taskKeyBuilder.buildTaskKey();
}
protected ParseTree parse() {
Lexer lexer = new TaskReferenceLexer(CharStreams.fromString(reference));
lexer.removeErrorListeners();
lexer.addErrorListener(TaskReferenceErrorListener.INSTANCE);
return new TaskReferenceParser(new CommonTokenStream(lexer)).reference();
}
protected static class TaskReferenceErrorListener extends BaseErrorListener {
protected static final TaskReferenceErrorListener INSTANCE = new TaskReferenceErrorListener();
@Override
public void syntaxError(
Recognizer<?, ?> recognizer,
Object offendingSymbol,
int line,
int charPositionInLine,
String msg,
RecognitionException e) {
throw new NoSuchElementException();
}
}
protected class TaskReferenceListener extends TaskReferenceBaseListener {
TaskKey.Builder builder;
TaskReferenceListener(TaskKey.Builder builder) {
this.builder = builder;
}
@Override
public void enterAbsolute(TaskReferenceParser.AbsoluteContext ctx) {
builder.setAbsolute();
}
@Override
public void enterRelative(TaskReferenceParser.RelativeContext ctx) {
try {
builder.setPath(
ctx.dir().stream()
.map(dir -> Paths.get(dir.NAME().getText()))
.reduce(Paths.get(""), (a, b) -> a.resolve(b))
.resolve(ctx.NAME().getText()));
} catch (ConfigInvalidException e) {
throw new RuntimeConfigInvalidException(e);
}
}
@Override
public void enterReference(TaskReferenceParser.ReferenceContext ctx) {
builder.setTaskName(ctx.TASK().getText());
}
@Override
public void enterFile_path(TaskReferenceParser.File_pathContext ctx) {
if (ctx.ROOT_PROJECT() != null || (ctx.FWD_SLASH() != null && ctx.absolute() != null)) {
builder.setReferringRootConfigBranchTask();
}
if (ctx.absolute() == null && ctx.relative() == null) {
try {
builder.setRefRootFile();
} catch (ConfigInvalidException e) {
throw new RuntimeConfigInvalidException(e);
}
}
}
@Override
public void enterUser(TaskReferenceParser.UserContext ctx) {
try {
builder.setUsername(ctx.NAME().getText());
} catch (ConfigInvalidException e) {
throw new RuntimeConfigInvalidException(e);
}
}
@Override
public void enterGroup_name(TaskReferenceParser.Group_nameContext ctx) {
try {
String groupName =
ctx.NAME() == null
? (ctx.NAME_WITH_SPACES() == null ? "" : ctx.NAME_WITH_SPACES().getText())
: ctx.NAME().getText();
builder.setGroupName(groupName);
} catch (ConfigInvalidException e) {
throw new RuntimeConfigInvalidException(e);
}
}
@Override
public void enterGroup_uuid(TaskReferenceParser.Group_uuidContext ctx) {
try {
builder.setGroupUUID(ctx.INTERNAL_GROUP_UUID().getText());
} catch (ConfigInvalidException e) {
throw new RuntimeConfigInvalidException(e);
}
}
}
}