Add the revision diff REST API implementation.

A revision diff shows the contents of a file diff'd against
a base revision.  The "content" key in the root object contains
an array of objects where there is:
  "ab" for common lines to both sides
   only "a" when lines were deleted in "b"
   only "b" when lines were inserted in "b"
   "a" and "b" when the lines were replaced
   skip line count when the file is too large to show all common lines

If the url parameter "intraline" is specified.  Replaced regions may
also contain an "edit_a" and "edit_b" list of <offset, length> pairs,
from the begining of the region. edit_a represents deleted text sections
and edit_b represents insterted text sections. Note, the implied newline
character is included in the offset position.

Whitespace behavior can be controlled via the "ignore-whitespace" URL
parameter. Also, # of lines of surrounding context can be control
via the "context" URL parameter.

PatchScript was updated to include the calculated content type of the
file, which is exposed in the meta_[a|b] field of the root object.

PatchScriptFactory was refactored to take the ChangeControl, due to
scoping issues in the REST API. Furthermore, Patch.Key was replaced by
fileName.  The Git patch diff header was updated to not include the
trailing newline.

TODO: improve the content-type detection, since it returns
"application/octet-stream" more often than it should.

Change-Id: I96a6e0d569f3ecf24c5529dc706ae85c61bfb699
This commit is contained in:
Colby Ranger
2013-05-10 09:21:24 -07:00
committed by Shawn Pearce
parent 010daed12d
commit efe7aca78d
7 changed files with 383 additions and 25 deletions

View File

@@ -171,7 +171,10 @@ public class PatchListEntry {
final List<String> headerLines = new ArrayList<String>(m.size() - 1);
for (int i = 1; i < m.size() - 1; i++) {
final int b = m.get(i);
final int e = m.get(i + 1);
int e = m.get(i + 1);
if (header[e - 1] == '\n') {
e--;
}
headerLines.add(RawParseUtils.decode(Constants.CHARSET, header, b, e));
}
return headerLines;

View File

@@ -211,7 +211,8 @@ class PatchScriptBuilder {
return new PatchScript(change.getKey(), content.getChangeType(),
content.getOldName(), content.getNewName(), a.fileMode, b.fileMode,
content.getHeaderLines(), diffPrefs, a.dst, b.dst, edits,
a.displayMethod, b.displayMethod, comments, history, hugeFile,
a.displayMethod, b.displayMethod, a.mimeType.toString(),
b.mimeType.toString(), comments, history, hugeFile,
intralineDifferenceIsPossible, intralineFailure, intralineTimeout);
}

View File

@@ -56,7 +56,9 @@ import javax.annotation.Nullable;
public class PatchScriptFactory implements Callable<PatchScript> {
public interface Factory {
PatchScriptFactory create(Patch.Key patchKey,
PatchScriptFactory create(
ChangeControl control,
String fileName,
@Assisted("patchSetA") PatchSet.Id patchSetA,
@Assisted("patchSetB") PatchSet.Id patchSetB,
AccountDiffPreference diffPrefs);
@@ -69,20 +71,17 @@ public class PatchScriptFactory implements Callable<PatchScript> {
private final Provider<PatchScriptBuilder> builderFactory;
private final PatchListCache patchListCache;
private final ReviewDb db;
private final ChangeControl.Factory changeControlFactory;
private final AccountInfoCacheFactory.Factory aicFactory;
private final Patch.Key patchKey;
private final String fileName;
@Nullable
private final PatchSet.Id psa;
private final PatchSet.Id psb;
private final AccountDiffPreference diffPrefs;
private final PatchSet.Id patchSetId;
private final Change.Id changeId;
private Change change;
private PatchSet patchSet;
private Project.NameKey projectKey;
private ChangeControl control;
private ObjectId aId;
@@ -94,9 +93,9 @@ public class PatchScriptFactory implements Callable<PatchScript> {
PatchScriptFactory(final GitRepositoryManager grm,
Provider<PatchScriptBuilder> builderFactory,
final PatchListCache patchListCache, final ReviewDb db,
final ChangeControl.Factory changeControlFactory,
final AccountInfoCacheFactory.Factory aicFactory,
@Assisted final Patch.Key patchKey,
@Assisted ChangeControl control,
@Assisted final String fileName,
@Assisted("patchSetA") @Nullable final PatchSet.Id patchSetA,
@Assisted("patchSetB") final PatchSet.Id patchSetB,
@Assisted final AccountDiffPreference diffPrefs) {
@@ -104,16 +103,15 @@ public class PatchScriptFactory implements Callable<PatchScript> {
this.builderFactory = builderFactory;
this.patchListCache = patchListCache;
this.db = db;
this.changeControlFactory = changeControlFactory;
this.control = control;
this.aicFactory = aicFactory;
this.patchKey = patchKey;
this.fileName = fileName;
this.psa = patchSetA;
this.psb = patchSetB;
this.diffPrefs = diffPrefs;
patchSetId = patchKey.getParentKey();
changeId = patchSetId.getParentKey();
changeId = patchSetB.getParentKey();
}
@Override
@@ -122,13 +120,8 @@ public class PatchScriptFactory implements Callable<PatchScript> {
validatePatchSetId(psa);
validatePatchSetId(psb);
control = changeControlFactory.validateFor(changeId);
change = control.getChange();
projectKey = change.getProject();
patchSet = db.patchSets().get(patchSetId);
if (patchSet == null) {
throw new NoSuchChangeException(changeId);
}
aId = psa != null ? toObjectId(db, psa) : null;
bId = toObjectId(db, psb);
@@ -146,7 +139,7 @@ public class PatchScriptFactory implements Callable<PatchScript> {
try {
final PatchList list = listFor(keyFor(diffPrefs.getIgnoreWhitespace()));
final PatchScriptBuilder b = newBuilder(list, git);
final PatchListEntry content = list.get(patchKey.getFileName());
final PatchListEntry content = list.get(fileName);
loadCommentsAndHistory(content.getChangeType(), //
content.getOldName(), //
@@ -227,7 +220,7 @@ public class PatchScriptFactory implements Callable<PatchScript> {
// proper rename detection between the patch sets.
//
for (final PatchSet ps : db.patchSets().byChange(changeId)) {
String name = patchKey.get();
String name = fileName;
if (psa != null) {
switch (changeType) {
case COPIED: