]> source.dussan.org Git - jgit.git/commitdiff
Use a TemporaryBuffer to do a content merge 84/116584/1
authorThomas Wolf <thomas.wolf@paranor.ch>
Fri, 2 Feb 2018 09:42:54 +0000 (10:42 +0100)
committerThomas Wolf <thomas.wolf@paranor.ch>
Fri, 2 Feb 2018 09:50:12 +0000 (10:50 +0100)
This avoids having to re-read the merged file (twice even!) to
update the index.

Change-Id: Id13e0fd38906ed6f859604f86ca352761dca9ffe
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
org.eclipse.jgit/src/org/eclipse/jgit/merge/ResolveMerger.java [changed mode: 0644->0755]

old mode 100644 (file)
new mode 100755 (executable)
index 837528e..c3b3295
@@ -3,6 +3,7 @@
  * Copyright (C) 2010-2012, Matthias Sohn <matthias.sohn@sap.com>
  * Copyright (C) 2012, Research In Motion Limited
  * Copyright (C) 2017, Obeo (mathieu.cartaud@obeo.fr)
+ * Copyright (C) 2018, Thomas Wolf <thomas.wolf@paranor.ch>
  * and other copyright owners as documented in the project's IP log.
  *
  * This program and the accompanying materials are made available
@@ -51,10 +52,8 @@ import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_ALGORITHM;
 import static org.eclipse.jgit.lib.Constants.CHARACTER_ENCODING;
 import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
 
-import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -874,94 +873,55 @@ public class ResolveMerger extends ThreeWayMerger {
                        CanonicalTreeParser ours, CanonicalTreeParser theirs,
                        MergeResult<RawText> result) throws FileNotFoundException,
                        IOException {
-               File mergedFile = !inCore ? writeMergedFile(result) : null;
-
-               if (result.containsConflicts()) {
-                       // A conflict occurred, the file will contain conflict markers
-                       // the index will be populated with the three stages and the
-                       // workdir (if used) contains the halfway merged content.
-                       add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
-                       add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
-                       add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
-                       mergeResults.put(tw.getPathString(), result);
-                       return;
-               }
-
-               // No conflict occurred, the file will contain fully merged content.
-               // The index will be populated with the new merged version.
-               DirCacheEntry dce = new DirCacheEntry(tw.getPathString());
-
-               // Set the mode for the new content. Fall back to REGULAR_FILE if
-               // we can't merge modes of OURS and THEIRS.
-               int newMode = mergeFileModes(
-                               tw.getRawMode(0),
-                               tw.getRawMode(1),
-                               tw.getRawMode(2));
-               dce.setFileMode(newMode == FileMode.MISSING.getBits()
-                               ? FileMode.REGULAR_FILE
-                               : FileMode.fromBits(newMode));
-               if (mergedFile != null) {
-                       long len = mergedFile.length();
-                       dce.setLastModified(FS.DETECTED.lastModified(mergedFile));
-                       dce.setLength((int) len);
-                       EolStreamType streamType = EolStreamTypeUtil.detectStreamType(
-                                       OperationType.CHECKIN_OP, workingTreeOptions,
-                                       tw.getAttributes());
-                       long blobLen = len == 0 ? 0
-                                       : getEntryContentLength(mergedFile, streamType);
-                       // TODO: we read the file twice because insert() needs the blob
-                       // length up front. C.f. AddCommand.
-                       try (InputStream is = EolStreamTypeUtil.wrapInputStream(
-                                       new FileInputStream(mergedFile), streamType)) {
-                               dce.setObjectId(
-                                               getObjectInserter().insert(OBJ_BLOB, blobLen, is));
+               TemporaryBuffer rawMerged = null;
+               try {
+                       rawMerged = doMerge(result);
+                       File mergedFile = inCore ? null : writeMergedFile(rawMerged);
+                       if (result.containsConflicts()) {
+                               // A conflict occurred, the file will contain conflict markers
+                               // the index will be populated with the three stages and the
+                               // workdir (if used) contains the halfway merged content.
+                               add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, 0, 0);
+                               add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, 0, 0);
+                               add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, 0, 0);
+                               mergeResults.put(tw.getPathString(), result);
+                               return;
                        }
-               } else
-                       dce.setObjectId(insertMergeResult(result));
-               builder.add(dce);
-       }
 
-       /**
-        * Computes the length of the index blob for a given file.
-        *
-        * @param file
-        *            on disk
-        * @param streamType
-        *            specifying CRLF translation
-        * @return the number of bytes after CRLF translations have been done.
-        * @throws IOException
-        *             if the file cannot be read
-        */
-       private long getEntryContentLength(File file, EolStreamType streamType)
-                       throws IOException {
-               if (streamType == EolStreamType.DIRECT) {
-                       return file.length();
-               }
-               long length = 0;
-               try (InputStream is = EolStreamTypeUtil.wrapInputStream(
-                               new BufferedInputStream(new FileInputStream(file)),
-                               streamType)) {
-                       for (;;) {
-                               long n = is.skip(1 << 20);
-                               if (n <= 0) {
-                                       break;
-                               }
-                               length += n;
+                       // No conflict occurred, the file will contain fully merged content.
+                       // The index will be populated with the new merged version.
+                       DirCacheEntry dce = new DirCacheEntry(tw.getPathString());
+
+                       // Set the mode for the new content. Fall back to REGULAR_FILE if
+                       // we can't merge modes of OURS and THEIRS.
+                       int newMode = mergeFileModes(tw.getRawMode(0), tw.getRawMode(1),
+                                       tw.getRawMode(2));
+                       dce.setFileMode(newMode == FileMode.MISSING.getBits()
+                                       ? FileMode.REGULAR_FILE : FileMode.fromBits(newMode));
+                       if (mergedFile != null) {
+                               dce.setLastModified(
+                                               nonNullRepo().getFS().lastModified(mergedFile));
+                               dce.setLength((int) mergedFile.length());
+                       }
+                       dce.setObjectId(insertMergeResult(rawMerged));
+                       builder.add(dce);
+               } finally {
+                       if (rawMerged != null) {
+                               rawMerged.destroy();
                        }
-                       return length;
                }
        }
 
        /**
         * Writes merged file content to the working tree.
         *
-        * @param result
-        *            the result of the content merge
+        * @param rawMerged
+        *            the raw merged content
         * @return the working tree file to which the merged content was written.
         * @throws FileNotFoundException
         * @throws IOException
         */
-       private File writeMergedFile(MergeResult<RawText> result)
+       private File writeMergedFile(TemporaryBuffer rawMerged)
                        throws FileNotFoundException, IOException {
                File workTree = nonNullRepo().getWorkTree();
                FS fs = nonNullRepo().getFS();
@@ -976,13 +936,12 @@ public class ResolveMerger extends ThreeWayMerger {
                try (OutputStream os = EolStreamTypeUtil.wrapOutputStream(
                                new BufferedOutputStream(new FileOutputStream(of)),
                                streamType)) {
-                       new MergeFormatter().formatMerge(os, result,
-                                       Arrays.asList(commitNames), CHARACTER_ENCODING);
+                       rawMerged.writeTo(os, null);
                }
                return of;
        }
 
-       private ObjectId insertMergeResult(MergeResult<RawText> result)
+       private TemporaryBuffer doMerge(MergeResult<RawText> result)
                        throws IOException {
                TemporaryBuffer.LocalFile buf = new TemporaryBuffer.LocalFile(
                                db != null ? nonNullRepo().getDirectory() : null, inCoreLimit);
@@ -990,11 +949,16 @@ public class ResolveMerger extends ThreeWayMerger {
                        new MergeFormatter().formatMerge(buf, result,
                                        Arrays.asList(commitNames), CHARACTER_ENCODING);
                        buf.close();
-                       try (InputStream in = buf.openInputStream()) {
-                               return getObjectInserter().insert(OBJ_BLOB, buf.length(), in);
-                       }
-               } finally {
+               } catch (IOException e) {
                        buf.destroy();
+                       throw e;
+               }
+               return buf;
+       }
+
+       private ObjectId insertMergeResult(TemporaryBuffer buf) throws IOException {
+               try (InputStream in = buf.openInputStream()) {
+                       return getObjectInserter().insert(OBJ_BLOB, buf.length(), in);
                }
        }