Update readGitDiff to work for rename and move patches
authorThomas Zander <thomas.zander@trolltech.com>
Wed, 22 Jul 2009 16:22:16 +0000 (22 19:22 +0300)
committerThomas Zander <thomas.zander@trolltech.com>
Wed, 22 Jul 2009 16:22:16 +0000 (22 19:22 +0300)
src/hunks/ChangeSet.cpp

index 276a3ab..4eb89be 100644 (file)
@@ -356,12 +356,29 @@ QList<File> ChangeSet::readGitDiff(QIODevice &git, File *fileToDiff)
     // parse the output and create objects for each hunk. (note how that can be made multi-threading)
     //  we have to have the filename in the hunk too to allow skipping a whole hunk
     char buf[10240];
-    bool inPatch = false;
+    enum State {
+        InPatch,
+        Empty,
+        InHeader
+    };
     // a diff can be multiple files, or just the one fileToDiff.  Lets keep one File object to point to the current file.
+    State state = Empty;
     File file;
     Hunk hunk;
     while(true) {
         qint64 lineLength = Vng::readLine(&git, buf, sizeof(buf));
+        if (lineLength == -1 || state == Empty) {
+            file.addHunk(hunk);
+            hunk = Hunk();
+            if (file.isValid())
+                filesInDiff << file;
+            if (fileToDiff)
+                file = File(*fileToDiff);
+            else
+                file = File();
+            state = Empty;
+        }
+
         if (lineLength == -1)
             break;
         QString line = QString::fromLocal8Bit(buf, lineLength);
@@ -369,29 +386,21 @@ QList<File> ChangeSet::readGitDiff(QIODevice &git, File *fileToDiff)
         const bool newfile = line.startsWith("--- /dev/null");
         if (line.length() > 6 && (newfile || line.startsWith("--- a/")
             || line.startsWith("--- \"a/"))) {
-            file.addHunk(hunk);
-            hunk = Hunk();
-            if (file.isValid())
-                filesInDiff << file;
-            if (fileToDiff) {
-                file = File(*fileToDiff);
-            } else {
-                file = File();
-                if (!newfile) {
-                    if (line[4].unicode() == '"') { // git-encoding...
-                        QByteArray array(buf + 7, strlen(buf) - 8);
-                        array.prepend('"');
-                        file.setOldFileName(File::escapeGitFilename(array));
-                    } else {
-                        QByteArray array(buf + 6, strlen(buf) - 7);
-                        file.setOldFileName(File::escapeGitFilename(array));
-                    }
+            if (!newfile) {
+                if (line[4].unicode() == '"') { // git-encoding...
+                    QByteArray array(buf + 7, strlen(buf) - 8);
+                    array.prepend('"');
+                    file.setOldFileName(File::escapeGitFilename(array));
+                } else {
+                    QByteArray array(buf + 6, strlen(buf) - 7);
+                    file.setOldFileName(File::escapeGitFilename(array));
                 }
             }
-            inPatch = false;
+            state = state == InPatch ? Empty : InHeader;
         }
         else if (fileToDiff == 0 && line.length() > 6 &&
                 (line.startsWith("+++ b/") || line.startsWith("+++ \"b"))) {
+            state = InHeader;
             if (line[4].unicode() == '"') { // git-encoding...
                 QByteArray array(buf + 7, strlen(buf) - 8);
                 array.prepend('"');
@@ -403,25 +412,45 @@ QList<File> ChangeSet::readGitDiff(QIODevice &git, File *fileToDiff)
         else if (line.length() > 5 && line.startsWith("@@ -")) {
             file.addHunk(hunk);
             hunk = Hunk();
-            inPatch = true;
+            state = InPatch;
         }
-        else if (inPatch && line.startsWith("diff --git ")) {
-            inPatch = false;
+        else if (line.startsWith("diff --git ")) {
+            state = state == InPatch ? Empty : InHeader;
+            continue;
         }
-        else if (line.startsWith("Binary files a/") && line.indexOf(" differ") > 0) { // TODO does git do translations?
+        else if (line.startsWith("Binary files a/") && line.indexOf(" differ") > 0) {
             Q_ASSERT(fileToDiff);
             fileToDiff->setBinary(true);
             git.close();
             return filesInDiff;
         }
-        if (inPatch) {
+        else if (line.startsWith("index ")) {
+            int dot = line.indexOf(QLatin1Char('.'), 6);
+            if (dot > 0 && line.length() > dot+3) {
+                file.setOldSha1(line.mid(6, dot-6));
+                int space = line.indexOf(QLatin1Char(' '), dot);
+                if (space == -1) {
+                    space = line.length()-1; // cut off the linefeed
+                } else {
+                    file.setProtection(line.mid(space+1).trimmed());
+                }
+                file.setSha1(line.mid(dot+2, space - dot - 2));
+            }
+            state = state == InPatch ? Empty : InHeader;
+        }
+        else if (line.startsWith("deleted file mode ")) {
+            file.setProtection(line.mid(18).trimmed());
+            state = state == InPatch ? Empty : InHeader;
+        }
+        else if (line.startsWith("new file mode ")) {
+            file.setProtection(line.mid(13).trimmed());
+            state = state == InPatch ? Empty : InHeader;
+        }
+        if (state == InPatch) {
             QByteArray array(buf, lineLength);
             hunk.addLine(array);
         }
     }
-    file.addHunk(hunk);
-    if (fileToDiff == 0 && file.isValid())
-        filesInDiff << file;
     git.close();
     return filesInDiff;
 }