summaryrefslogtreecommitdiffstats
path: root/mgrapp/src/com/google/codereview/manager/unpack/DiffReader.java
diff options
context:
space:
mode:
Diffstat (limited to 'mgrapp/src/com/google/codereview/manager/unpack/DiffReader.java')
-rw-r--r--mgrapp/src/com/google/codereview/manager/unpack/DiffReader.java149
1 files changed, 149 insertions, 0 deletions
diff --git a/mgrapp/src/com/google/codereview/manager/unpack/DiffReader.java b/mgrapp/src/com/google/codereview/manager/unpack/DiffReader.java
new file mode 100644
index 0000000000..866ca7598a
--- /dev/null
+++ b/mgrapp/src/com/google/codereview/manager/unpack/DiffReader.java
@@ -0,0 +1,149 @@
+// Copyright 2008 Google Inc.
+//
+// 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.codereview.manager.unpack;
+
+import static org.spearce.jgit.lib.Constants.encodeASCII;
+
+import com.google.codereview.internal.UploadPatchsetFile.UploadPatchsetFileRequest.StatusType;
+
+import org.spearce.jgit.lib.Constants;
+import org.spearce.jgit.lib.ObjectId;
+import org.spearce.jgit.lib.ObjectWriter;
+import org.spearce.jgit.lib.Repository;
+import org.spearce.jgit.lib.Tree;
+import org.spearce.jgit.revwalk.RevCommit;
+import org.spearce.jgit.util.RawParseUtils;
+
+import java.io.IOException;
+
+/** Parses 'git diff-tree' output into {@link FileDiff} objects. */
+class DiffReader {
+ private static final byte[] GIT_DIFF = encodeASCII("diff --git a/");
+ private static final byte[] H_DELETED_FILE = encodeASCII("deleted file ");
+ private static final byte[] H_NEW_FILE = encodeASCII("new file ");
+ private static final byte[] H_INDEX = encodeASCII("index ");
+ static final byte[] H_NEWPATH = encodeASCII("+++ b/");
+ private static final byte[] H_BINARY = encodeASCII("Binary file");
+ private static final int MAX_PATCH_SIZE = 1024 * 1024; // bytes
+
+ static boolean match(final byte[] key, final byte[] line, int offset) {
+ int remain = line.length - offset;
+ if (remain < key.length) {
+ return false;
+ }
+ for (int k = 0; k < key.length;) {
+ if (key[k++] != line[offset++]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static String str(final byte[] b, final int off) {
+ return RawParseUtils.decode(Constants.CHARSET, b, off, b.length);
+ }
+
+ private Process proc;
+ private RecordInputStream in;
+ private FileDiff current;
+
+ DiffReader(final Repository db, final RevCommit c) throws IOException {
+ final String baseTree;
+ if (c.getParentCount() > 0) {
+ baseTree = c.getParent(0).getTree().getId().name();
+ } else {
+ baseTree = new ObjectWriter(db).writeTree(new Tree(db)).name();
+ }
+ final String headTree = c.getTree().getId().name();
+ proc =
+ Runtime.getRuntime().exec(
+ new String[] {"git", "--git-dir=.", "diff-tree", "--unified=1",
+ "-M", "--full-index", baseTree, headTree}, null,
+ db.getDirectory());
+ proc.getOutputStream().close();
+ proc.getErrorStream().close();
+ in = new RecordInputStream(proc.getInputStream());
+ }
+
+ FileDiff next() throws IOException {
+ return readOneDiff();
+ }
+
+ private FileDiff readOneDiff() throws IOException {
+ boolean consume = false;
+ for (;;) {
+ final byte[] hdr = in.readRecord('\n');
+ if (hdr == null) {
+ final FileDiff prior = current;
+ current = null;
+ return prior;
+ }
+
+ if (match(GIT_DIFF, hdr, 0)) {
+ final FileDiff prior = current;
+ current = new FileDiff();
+ current.appendLine(hdr);
+
+ // TODO(sop) This can split the old and new names wrong if the
+ // old name was "f b/c". Until we can do diffs in-core we'll
+ // just assume nobody uses spaces in filenames.
+ //
+ final String hdrStr = str(hdr, 0);
+ final int newpos = hdrStr.indexOf(" b/");
+ if (newpos > 0) {
+ current.setFilename(hdrStr.substring(newpos + 3));
+ }
+
+ if (prior != null) {
+ return prior;
+ } else {
+ continue;
+ }
+ }
+
+ if (match(H_INDEX, hdr, 0)) {
+ current.setBaseId(ObjectId.fromString(hdr, H_INDEX.length));
+ current.setFinalId(ObjectId.fromString(hdr, H_INDEX.length
+ + Constants.OBJECT_ID_LENGTH * 2 + 2));
+ } else if (match(H_NEW_FILE, hdr, 0)) {
+ current.setStatus(StatusType.ADD);
+ } else if (match(H_DELETED_FILE, hdr, 0)) {
+ current.setStatus(StatusType.DELETE);
+ } else if (match(H_BINARY, hdr, 0)) {
+ current.setBinary(true);
+ } else if (match(H_NEWPATH, hdr, 0)) {
+ current.setFilename(str(hdr, H_NEWPATH.length));
+ }
+
+ if (consume) {
+ continue;
+ } else if (current.getPatchSize() + hdr.length >= MAX_PATCH_SIZE) {
+ current.truncatePatch();
+ consume = true;
+ } else {
+ current.appendLine(hdr);
+ }
+ }
+ }
+
+ void close() throws IOException {
+ in.close();
+ try {
+ proc.waitFor();
+ } catch (InterruptedException ie) {
+ //
+ }
+ }
+}