@ -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 ) ;
}
}