Rebase: Use PatchSetUtil

Because we need to make ChangeNotes available for the calls into
PatchSetUtil, we already have the Change and ChangeControl available.
Use an @AutoValue return type to give these back to the caller and
avoid a double lookup.

Change-Id: I4d0c7cd735cd02efed0dcc672998a8042df8614d
This commit is contained in:
Dave Borowitz
2016-01-15 16:00:28 -05:00
parent 24928208f8
commit 0dfabcc1ac

View File

@@ -14,6 +14,7 @@
package com.google.gerrit.server.change;
import com.google.auto.value.AutoValue;
import com.google.common.primitives.Ints;
import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.common.errors.EmailException;
@@ -29,8 +30,8 @@ import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Change.Status;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.PatchSetUtil;
import com.google.gerrit.server.git.BatchUpdate;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.UpdateException;
@@ -69,6 +70,7 @@ public class Rebase implements RestModifyView<RevisionResource, RebaseInput>,
private final ChangeJson.Factory json;
private final Provider<ReviewDb> dbProvider;
private final Provider<InternalChangeQuery> queryProvider;
private final PatchSetUtil psUtil;
@Inject
public Rebase(BatchUpdate.Factory updateFactory,
@@ -77,7 +79,8 @@ public class Rebase implements RestModifyView<RevisionResource, RebaseInput>,
RebaseUtil rebaseUtil,
ChangeJson.Factory json,
Provider<ReviewDb> dbProvider,
Provider<InternalChangeQuery> queryProvider) {
Provider<InternalChangeQuery> queryProvider,
PatchSetUtil psUtil) {
this.updateFactory = updateFactory;
this.repoManager = repoManager;
this.rebaseFactory = rebaseFactory;
@@ -85,6 +88,7 @@ public class Rebase implements RestModifyView<RevisionResource, RebaseInput>,
this.json = json;
this.dbProvider = dbProvider;
this.queryProvider = queryProvider;
this.psUtil = psUtil;
}
@Override
@@ -127,28 +131,26 @@ public class Rebase implements RestModifyView<RevisionResource, RebaseInput>,
}
Change change = rsrc.getChange();
String base = input.base.trim();
if (base.equals("")) {
String str = input.base.trim();
if (str.equals("")) {
// remove existing dependency to other patch set
return change.getDest().get();
}
@SuppressWarnings("resource")
ReviewDb db = dbProvider.get();
PatchSet basePatchSet = parseBase(change.getProject(), base);
if (basePatchSet == null) {
throw new ResourceConflictException("base revision is missing: " + base);
} else if (!rsrc.getControl().isPatchVisible(basePatchSet, db)) {
throw new AuthException("base revision not accessible: " + base);
} else if (change.getId().equals(basePatchSet.getId().getParentKey())) {
Base base = parseBase(rsrc, str);
if (base == null) {
throw new ResourceConflictException("base revision is missing: " + str);
}
PatchSet.Id baseId = base.patchSet().getId();
if (!base.control().isPatchVisible(base.patchSet(), db)) {
throw new AuthException("base revision not accessible: " + str);
} else if (change.getId().equals(baseId.getParentKey())) {
throw new ResourceConflictException("cannot depend on self");
}
Change baseChange = db.changes().get(basePatchSet.getId().getParentKey());
if (baseChange == null) {
return null;
}
Change baseChange = base.control().getChange();
if (!baseChange.getProject().equals(change.getProject())) {
throw new ResourceConflictException(
"base change is in wrong project: " + baseChange.getProject());
@@ -158,12 +160,12 @@ public class Rebase implements RestModifyView<RevisionResource, RebaseInput>,
} else if (baseChange.getStatus() == Status.ABANDONED) {
throw new ResourceConflictException(
"base change is abandoned: " + baseChange.getKey());
} else if (isMergedInto(rw, rsrc.getPatchSet(), basePatchSet)) {
} else if (isMergedInto(rw, rsrc.getPatchSet(), base.patchSet())) {
throw new ResourceConflictException(
"base change " + baseChange.getKey()
+ " is a descendant of the current change - recursion not allowed");
}
return basePatchSet.getRevision().get();
return base.patchSet().getRevision().get();
}
private boolean isMergedInto(RevWalk rw, PatchSet base, PatchSet tip)
@@ -173,46 +175,65 @@ public class Rebase implements RestModifyView<RevisionResource, RebaseInput>,
return rw.isMergedInto(rw.parseCommit(baseId), rw.parseCommit(tipId));
}
private PatchSet parseBase(Project.NameKey project, String base)
@AutoValue
static abstract class Base {
private static Base create(ChangeControl ctl, PatchSet ps) {
if (ctl == null) {
return null;
}
return new AutoValue_Rebase_Base(ctl, ps);
}
abstract ChangeControl control();
abstract PatchSet patchSet();
}
private Base parseBase(RevisionResource rsrc, String base)
throws OrmException {
ReviewDb db = dbProvider.get();
// Try parsing the base as a ref string.
PatchSet.Id basePatchSetId = PatchSet.Id.fromRef(base);
if (basePatchSetId != null) {
// Try parsing the base as a ref string.
return db.patchSets().get(basePatchSetId);
return Base.create(
controlFor(rsrc, basePatchSetId.getParentKey()),
psUtil.get(db, rsrc.getNotes(), basePatchSetId));
}
// TODO(dborowitz): Use PatchSetUtil; requires additional refactoring as we
// just turn around and get the change at the caller.
// Try parsing base as a change number (assume current patch set).
PatchSet basePatchSet = null;
Integer baseChangeId = Ints.tryParse(base);
if (baseChangeId != null) {
for (PatchSet ps : db.patchSets().byChange(new Change.Id(baseChangeId))) {
if (basePatchSet == null
|| basePatchSet.getId().get() < ps.getId().get()) {
basePatchSet = ps;
}
}
if (basePatchSet != null) {
return basePatchSet;
ChangeControl baseCtl = controlFor(rsrc, new Change.Id(baseChangeId));
if (baseCtl != null) {
return Base.create(baseCtl, psUtil.current(db, baseCtl.getNotes()));
}
}
// Try parsing as SHA-1.
for (ChangeData cd : queryProvider.get().byProjectCommit(project, base)) {
Base ret = null;
for (ChangeData cd : queryProvider.get()
.byProjectCommit(rsrc.getProject(), base)) {
for (PatchSet ps : cd.patchSets()) {
if (!ps.getRevision().matches(base)) {
continue;
}
if (basePatchSet == null
|| basePatchSet.getId().get() < ps.getId().get()) {
basePatchSet = ps;
if (ret == null || ret.patchSet().getId().get() < ps.getId().get()) {
ret = Base.create(
rsrc.getControl().getProjectControl().controlFor(cd.change()),
ps);
}
}
}
return basePatchSet;
return ret;
}
private ChangeControl controlFor(RevisionResource rsrc, Change.Id id)
throws OrmException {
Change c = dbProvider.get().changes().get(id);
if (c == null) {
return null;
}
return rsrc.getControl().getProjectControl().controlFor(c);
}
private boolean hasOneParent(RevWalk rw, PatchSet ps) throws IOException {