blob: 65d48dd09c7008f9d72e1fbda4363cacff5f165e [file] [log] [blame]
// Copyright (C) 2014 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.google.gerrit.sshd.commands;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.Project;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.git.ObjectIds;
import com.google.gerrit.server.PatchSetUtil;
import com.google.gerrit.server.change.ChangeFinder;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.InternalChangeQuery;
import com.google.gerrit.sshd.BaseCommand.UnloggedFailure;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Singleton
public class PatchSetParser {
private final Provider<InternalChangeQuery> queryProvider;
private final ChangeNotes.Factory notesFactory;
private final PatchSetUtil psUtil;
private final ChangeFinder changeFinder;
@Inject
PatchSetParser(
Provider<InternalChangeQuery> queryProvider,
ChangeNotes.Factory notesFactory,
PatchSetUtil psUtil,
ChangeFinder changeFinder) {
this.queryProvider = queryProvider;
this.notesFactory = notesFactory;
this.psUtil = psUtil;
this.changeFinder = changeFinder;
}
public PatchSet parsePatchSet(String token, ProjectState projectState, String branch)
throws UnloggedFailure {
// By commit?
//
if (token.matches("^([0-9a-fA-F]{4," + ObjectIds.STR_LEN + "})$")) {
InternalChangeQuery query = queryProvider.get();
List<ChangeData> cds;
branch = branch != null ? RefNames.fullName(branch) : null;
if (projectState != null) {
Project.NameKey p = projectState.getNameKey();
if (branch != null) {
cds = query.byBranchCommit(p.get(), branch, token);
} else {
cds = query.byProjectCommit(p, token);
}
} else {
cds = query.byCommit(token);
}
List<PatchSet> matches = new ArrayList<>(cds.size());
for (ChangeData cd : cds) {
Change c = cd.change();
if (!(inProject(c, projectState) && inBranch(c, branch))) {
continue;
}
for (PatchSet ps : cd.patchSets()) {
if (ObjectIds.matchesAbbreviation(ps.commitId(), token)) {
matches.add(ps);
}
}
}
switch (matches.size()) {
case 1:
return matches.iterator().next();
case 0:
throw error("\"" + token + "\" no such patch set");
default:
throw error("\"" + token + "\" matches multiple patch sets");
}
}
// By older style change,patchset?
//
if (token.matches("^[1-9][0-9]*,[1-9][0-9]*$")) {
PatchSet.Id patchSetId;
try {
patchSetId = PatchSet.Id.parse(token);
} catch (IllegalArgumentException e) {
throw error("\"" + token + "\" is not a valid patch set", e);
}
ChangeNotes notes = getNotes(projectState, patchSetId.changeId());
PatchSet patchSet = psUtil.get(notes, patchSetId);
if (patchSet == null) {
throw error("\"" + token + "\" no such patch set");
}
if (projectState != null || branch != null) {
Change change = notes.getChange();
if (!inProject(change, projectState)) {
throw error("change " + change.getId() + " not in project " + projectState.getName());
}
if (!inBranch(change, branch)) {
throw error("change " + change.getId() + " not in branch " + branch);
}
}
return patchSet;
}
throw error("\"" + token + "\" is not a valid patch set");
}
private ChangeNotes getNotes(@Nullable ProjectState projectState, Change.Id changeId)
throws UnloggedFailure {
if (projectState != null) {
return notesFactory.create(projectState.getNameKey(), changeId);
}
Optional<ChangeNotes> notes = changeFinder.findOne(changeId);
if (!notes.isPresent()) {
throw error("\"" + changeId + "\" no such change");
}
return notesFactory.create(notes.get().getProjectName(), changeId);
}
private static boolean inProject(Change change, ProjectState projectState) {
if (projectState == null) {
// No --project option, so they want every project.
return true;
}
return projectState.getNameKey().equals(change.getProject());
}
private static boolean inBranch(Change change, String branch) {
if (branch == null) {
// No --branch option, so they want every branch.
return true;
}
return change.getDest().branch().equals(branch);
}
public static UnloggedFailure error(String msg) {
return new UnloggedFailure(1, msg);
}
public static UnloggedFailure error(String msg, Throwable why) {
return new UnloggedFailure(1, msg, why);
}
}