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