Browse Source
TreeWalk provides the new method getEolStreamType. This new method can be used with EolStreamTypeUtil in order to create a wrapped InputStream or OutputStream when reading / writing files. The implementation implements support for the git configuration options core.crlf, core.eol and the .gitattributes "text", "eol" and "binary" CQ: 10896 Bug: 486563 Change-Id: Ie4f6367afc2a6aec1de56faf95120fff0339a358 Signed-off-by: Ivan Motsch <ivan.motsch@bsiag.com> Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>stable-4.3
Ivan Motsch
9 years ago
committed by
Christian Halstrick
23 changed files with 2160 additions and 255 deletions
@ -0,0 +1,692 @@
|
||||
/* |
||||
* Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com> |
||||
* |
||||
* This program and the accompanying materials are made available |
||||
* under the terms of the Eclipse Distribution License v1.0 which |
||||
* accompanies this distribution, is reproduced below, and is |
||||
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||
* |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or |
||||
* without modification, are permitted provided that the following |
||||
* conditions are met: |
||||
* |
||||
* - Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* - Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following |
||||
* disclaimer in the documentation and/or other materials provided |
||||
* with the distribution. |
||||
* |
||||
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||
* names of its contributors may be used to endorse or promote |
||||
* products derived from this software without specific prior |
||||
* written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
package org.eclipse.jgit.api; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertFalse; |
||||
import static org.junit.Assert.assertTrue; |
||||
|
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
|
||||
import org.eclipse.jgit.api.ResetCommand.ResetType; |
||||
import org.eclipse.jgit.api.errors.CheckoutConflictException; |
||||
import org.eclipse.jgit.api.errors.GitAPIException; |
||||
import org.eclipse.jgit.api.errors.NoFilepatternException; |
||||
import org.eclipse.jgit.attributes.Attribute; |
||||
import org.eclipse.jgit.dircache.DirCache; |
||||
import org.eclipse.jgit.dircache.DirCacheEntry; |
||||
import org.eclipse.jgit.dircache.DirCacheIterator; |
||||
import org.eclipse.jgit.errors.RevisionSyntaxException; |
||||
import org.eclipse.jgit.junit.RepositoryTestCase; |
||||
import org.eclipse.jgit.lib.ConfigConstants; |
||||
import org.eclipse.jgit.lib.Constants; |
||||
import org.eclipse.jgit.lib.CoreConfig.AutoCRLF; |
||||
import org.eclipse.jgit.lib.CoreConfig.EOL; |
||||
import org.eclipse.jgit.lib.FileMode; |
||||
import org.eclipse.jgit.lib.ObjectLoader; |
||||
import org.eclipse.jgit.storage.file.FileBasedConfig; |
||||
import org.eclipse.jgit.treewalk.FileTreeIterator; |
||||
import org.eclipse.jgit.treewalk.TreeWalk; |
||||
import org.eclipse.jgit.util.IO; |
||||
import org.junit.Assert; |
||||
import org.junit.Test; |
||||
import org.junit.experimental.theories.DataPoint; |
||||
import org.junit.experimental.theories.Theories; |
||||
import org.junit.runner.RunWith; |
||||
|
||||
/** |
||||
* Unit tests for end-of-line conversion and settings using core.autocrlf, * |
||||
* core.eol and the .gitattributes eol, text, binary (macro for -diff -merge |
||||
* -text) |
||||
*/ |
||||
@RunWith(Theories.class) |
||||
public class EolRepositoryTest extends RepositoryTestCase { |
||||
private static final FileMode D = FileMode.TREE; |
||||
|
||||
private static final FileMode F = FileMode.REGULAR_FILE; |
||||
|
||||
@DataPoint |
||||
public static String smallContents[] = { |
||||
generateTestData(3, 1, true, false), |
||||
generateTestData(3, 1, false, true), |
||||
generateTestData(3, 1, true, true) }; |
||||
|
||||
@DataPoint |
||||
public static String hugeContents[] = { |
||||
generateTestData(1000000, 17, true, false), |
||||
generateTestData(1000000, 17, false, true), |
||||
generateTestData(1000000, 17, true, true) }; |
||||
|
||||
static String generateTestData(int size, int lineSize, boolean withCRLF, |
||||
boolean withLF) { |
||||
StringBuilder sb = new StringBuilder(); |
||||
for (int i = 0; i < size; i++) { |
||||
if (i > 0 && i % lineSize == 0) { |
||||
// newline
|
||||
if (withCRLF && withLF) { |
||||
// mixed
|
||||
if (i % 2 == 0) |
||||
sb.append("\r\n"); |
||||
else |
||||
sb.append("\n"); |
||||
} else if (withCRLF) { |
||||
sb.append("\r\n"); |
||||
} else if (withLF) { |
||||
sb.append("\n"); |
||||
} |
||||
} |
||||
sb.append("A"); |
||||
} |
||||
return sb.toString(); |
||||
} |
||||
|
||||
public EolRepositoryTest(String[] testContent) { |
||||
CONTENT_CRLF = testContent[0]; |
||||
CONTENT_LF = testContent[1]; |
||||
CONTENT_MIXED = testContent[2]; |
||||
} |
||||
|
||||
protected String CONTENT_CRLF; |
||||
|
||||
protected String CONTENT_LF; |
||||
|
||||
protected String CONTENT_MIXED; |
||||
|
||||
private TreeWalk walk; |
||||
|
||||
/** work tree root .gitattributes */ |
||||
private File dotGitattributes; |
||||
|
||||
/** file containing CRLF */ |
||||
private File fileCRLF; |
||||
|
||||
/** file containing LF */ |
||||
private File fileLF; |
||||
|
||||
/** file containing mixed CRLF and LF */ |
||||
private File fileMixed; |
||||
|
||||
/** this values are set in {@link #collectRepositoryState()} */ |
||||
private static class ActualEntry { |
||||
private String attrs; |
||||
|
||||
private String file; |
||||
|
||||
private String index; |
||||
|
||||
private int indexContentLength; |
||||
} |
||||
|
||||
private ActualEntry entryCRLF = new ActualEntry(); |
||||
|
||||
private ActualEntry entryLF = new ActualEntry(); |
||||
|
||||
private ActualEntry entryMixed = new ActualEntry(); |
||||
|
||||
private DirCache dc; |
||||
|
||||
@Test |
||||
public void testDefaultSetup() throws Exception { |
||||
// for EOL to work, the text attribute must be set
|
||||
setupGitAndDoHardReset(null, null, null, null, "* text=auto"); |
||||
collectRepositoryState(); |
||||
assertEquals("text=auto", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF); |
||||
} |
||||
|
||||
public void checkEntryContent(ActualEntry entry, String fileContent, |
||||
String indexContent) { |
||||
assertEquals(fileContent, entry.file); |
||||
assertEquals(indexContent, entry.index); |
||||
assertEquals(fileContent.length(), entry.indexContentLength); |
||||
} |
||||
|
||||
@Test |
||||
public void test_ConfigAutoCRLF_false() throws Exception { |
||||
// for EOL to work, the text attribute must be set
|
||||
setupGitAndDoHardReset(AutoCRLF.FALSE, null, null, null, "* text=auto"); |
||||
collectRepositoryState(); |
||||
assertEquals("text=auto", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF); |
||||
} |
||||
|
||||
@Test |
||||
public void test_ConfigAutoCRLF_true() throws Exception { |
||||
// for EOL to work, the text attribute must be set
|
||||
setupGitAndDoHardReset(AutoCRLF.TRUE, null, null, null, "* text=auto"); |
||||
collectRepositoryState(); |
||||
assertEquals("text=auto", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF); |
||||
} |
||||
|
||||
@Test |
||||
public void test_ConfigAutoCRLF_input() throws Exception { |
||||
// for EOL to work, the text attribute must be set
|
||||
setupGitAndDoHardReset(AutoCRLF.INPUT, null, null, null, "* text=auto"); |
||||
collectRepositoryState(); |
||||
assertEquals("text=auto", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF); |
||||
} |
||||
|
||||
@Test |
||||
public void test_ConfigEOL_lf() throws Exception { |
||||
// for EOL to work, the text attribute must be set
|
||||
setupGitAndDoHardReset(null, EOL.LF, "*.txt text", null, null); |
||||
collectRepositoryState(); |
||||
assertEquals("text", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF); |
||||
} |
||||
|
||||
@Test |
||||
public void test_ConfigEOL_crlf() throws Exception { |
||||
// for EOL to work, the text attribute must be set
|
||||
setupGitAndDoHardReset(null, EOL.CRLF, "*.txt text", null, null); |
||||
collectRepositoryState(); |
||||
assertEquals("text", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF); |
||||
} |
||||
|
||||
@Test |
||||
public void test_ConfigEOL_native_windows() throws Exception { |
||||
String origLineSeparator = System.getProperty("line.separator", "\n"); |
||||
System.setProperty("line.separator", "\r\n"); |
||||
try { |
||||
// for EOL to work, the text attribute must be set
|
||||
setupGitAndDoHardReset(null, EOL.NATIVE, "*.txt text", null, null); |
||||
collectRepositoryState(); |
||||
assertEquals("text", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); |
||||
} finally { |
||||
System.setProperty("line.separator", origLineSeparator); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void test_ConfigEOL_native_xnix() throws Exception { |
||||
String origLineSeparator = System.getProperty("line.separator", "\n"); |
||||
System.setProperty("line.separator", "\n"); |
||||
try { |
||||
// for EOL to work, the text attribute must be set
|
||||
setupGitAndDoHardReset(null, EOL.NATIVE, "*.txt text", null, null); |
||||
collectRepositoryState(); |
||||
assertEquals("text", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); |
||||
} finally { |
||||
System.setProperty("line.separator", origLineSeparator); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void test_ConfigAutoCRLF_false_ConfigEOL_lf() throws Exception { |
||||
// for EOL to work, the text attribute must be set
|
||||
setupGitAndDoHardReset(AutoCRLF.FALSE, EOL.LF, "*.txt text", null, null); |
||||
collectRepositoryState(); |
||||
assertEquals("text", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF); |
||||
} |
||||
|
||||
@Test |
||||
public void test_ConfigAutoCRLF_false_ConfigEOL_native() throws Exception { |
||||
// for EOL to work, the text attribute must be set
|
||||
setupGitAndDoHardReset(AutoCRLF.FALSE, EOL.NATIVE, "*.txt text", null, null); |
||||
collectRepositoryState(); |
||||
assertEquals("text", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF); |
||||
} |
||||
|
||||
@Test |
||||
public void test_ConfigAutoCRLF_true_ConfigEOL_lf() throws Exception { |
||||
// for EOL to work, the text attribute must be set
|
||||
setupGitAndDoHardReset(AutoCRLF.TRUE, EOL.LF, "*.txt text", null, null); |
||||
collectRepositoryState(); |
||||
assertEquals("text", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF); |
||||
} |
||||
|
||||
@Test |
||||
public void test_switchToBranchWithTextAttributes() |
||||
throws Exception { |
||||
Git git = Git.wrap(db); |
||||
|
||||
// for EOL to work, the text attribute must be set
|
||||
setupGitAndDoHardReset(AutoCRLF.FALSE, EOL.CRLF, null, null, |
||||
"file1.txt text\nfile2.txt text\nfile3.txt text"); |
||||
collectRepositoryState(); |
||||
assertEquals("text", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF); |
||||
|
||||
// switch to binary for file1
|
||||
dotGitattributes = createAndAddFile(git, Constants.DOT_GIT_ATTRIBUTES, |
||||
"file1.txt binary\nfile2.txt text\nfile3.txt text"); |
||||
gitCommit(git, "switchedToBinaryFor1"); |
||||
recreateWorktree(git); |
||||
collectRepositoryState(); |
||||
assertEquals("binary -diff -merge -text", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF); |
||||
assertEquals("text", entryLF.attrs); |
||||
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF); |
||||
assertEquals("text", entryMixed.attrs); |
||||
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF); |
||||
|
||||
// checkout the commit which has text for file1
|
||||
gitCheckout(git, "HEAD^"); |
||||
recreateWorktree(git); |
||||
collectRepositoryState(); |
||||
assertEquals("text", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF); |
||||
} |
||||
|
||||
@Test |
||||
public void test_switchToBranchWithBinaryAttributes() throws Exception { |
||||
Git git = Git.wrap(db); |
||||
|
||||
// for EOL to work, the text attribute must be set
|
||||
setupGitAndDoHardReset(AutoCRLF.FALSE, EOL.LF, null, null, |
||||
"file1.txt binary\nfile2.txt binary\nfile3.txt binary"); |
||||
collectRepositoryState(); |
||||
assertEquals("binary -diff -merge -text", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_CRLF); |
||||
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_MIXED, CONTENT_MIXED); |
||||
|
||||
// switch to text for file1
|
||||
dotGitattributes = createAndAddFile(git, Constants.DOT_GIT_ATTRIBUTES, |
||||
"file1.txt text\nfile2.txt binary\nfile3.txt binary"); |
||||
gitCommit(git, "switchedToTextFor1"); |
||||
recreateWorktree(git); |
||||
collectRepositoryState(); |
||||
assertEquals("text", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF); |
||||
assertEquals("binary -diff -merge -text", entryLF.attrs); |
||||
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); |
||||
assertEquals("binary -diff -merge -text", entryMixed.attrs); |
||||
checkEntryContent(entryMixed, CONTENT_MIXED, CONTENT_MIXED); |
||||
|
||||
// checkout the commit which has text for file1
|
||||
gitCheckout(git, "HEAD^"); |
||||
recreateWorktree(git); |
||||
collectRepositoryState(); |
||||
assertEquals("binary -diff -merge -text", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_CRLF); |
||||
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_MIXED, CONTENT_MIXED); |
||||
} |
||||
|
||||
@Test |
||||
public void test_ConfigAutoCRLF_input_ConfigEOL_lf() throws Exception { |
||||
// for EOL to work, the text attribute must be set
|
||||
setupGitAndDoHardReset(AutoCRLF.INPUT, EOL.LF, "*.txt text", null, null); |
||||
collectRepositoryState(); |
||||
assertEquals("text", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF); |
||||
} |
||||
|
||||
@Test |
||||
public void test_ConfigAutoCRLF_true_GlobalEOL_lf() throws Exception { |
||||
setupGitAndDoHardReset(AutoCRLF.TRUE, EOL.LF, "*.txt eol=lf", null, null); |
||||
collectRepositoryState(); |
||||
assertEquals("eol=lf", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF); |
||||
} |
||||
|
||||
@Test |
||||
public void test_ConfigAutoCRLF_false_GlobalEOL_lf() throws Exception { |
||||
setupGitAndDoHardReset(AutoCRLF.FALSE, EOL.LF, "*.txt eol=lf", null, null); |
||||
collectRepositoryState(); |
||||
assertEquals("eol=lf", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF); |
||||
} |
||||
|
||||
@Test |
||||
public void test_ConfigAutoCRLF_input_GlobalEOL_lf() throws Exception { |
||||
setupGitAndDoHardReset(AutoCRLF.INPUT, EOL.LF, "*.txt eol=lf", null, null); |
||||
collectRepositoryState(); |
||||
assertEquals("eol=lf", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF); |
||||
} |
||||
|
||||
@Test |
||||
public void test_ConfigAutoCRLF_true_GlobalEOL_crlf() throws Exception { |
||||
setupGitAndDoHardReset(AutoCRLF.TRUE, EOL.LF, "*.txt eol=crlf", null, null); |
||||
collectRepositoryState(); |
||||
assertEquals("eol=crlf", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF); |
||||
} |
||||
|
||||
@Test |
||||
public void test_ConfigAutoCRLF_false_GlobalEOL_crlf() throws Exception { |
||||
setupGitAndDoHardReset(AutoCRLF.FALSE, EOL.LF, "*.txt eol=crlf", null, null); |
||||
collectRepositoryState(); |
||||
assertEquals("eol=crlf", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF); |
||||
} |
||||
|
||||
@Test |
||||
public void test_ConfigAutoCRLF_input_GlobalEOL_crlf() throws Exception { |
||||
setupGitAndDoHardReset(AutoCRLF.INPUT, EOL.LF, "*.txt eol=crlf", null, null); |
||||
collectRepositoryState(); |
||||
assertEquals("eol=crlf", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF); |
||||
} |
||||
|
||||
@Test |
||||
public void test_ConfigAutoCRLF_true_GlobalEOL_lf_InfoEOL_crlf() |
||||
throws Exception { |
||||
setupGitAndDoHardReset(AutoCRLF.TRUE, null, "*.txt eol=lf", "*.txt eol=crlf", null); |
||||
// info decides
|
||||
collectRepositoryState(); |
||||
assertEquals("eol=crlf", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF); |
||||
} |
||||
|
||||
@Test |
||||
public void test_ConfigAutoCRLF_false_GlobalEOL_crlf_InfoEOL_lf() |
||||
throws Exception { |
||||
setupGitAndDoHardReset(AutoCRLF.FALSE, null, "*.txt eol=crlf", "*.txt eol=lf", null); |
||||
// info decides
|
||||
collectRepositoryState(); |
||||
assertEquals("eol=lf", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF); |
||||
} |
||||
|
||||
@Test |
||||
public void test_GlobalEOL_lf_RootEOL_crlf() throws Exception { |
||||
setupGitAndDoHardReset(null, null, "*.txt eol=lf", null, "*.txt eol=crlf"); |
||||
// root over global
|
||||
collectRepositoryState(); |
||||
assertEquals("eol=crlf", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF); |
||||
} |
||||
|
||||
@Test |
||||
public void test_GlobalEOL_lf_InfoEOL_crlf_RootEOL_lf() throws Exception { |
||||
setupGitAndDoHardReset(null, null, "*.txt eol=lf", "*.txt eol=crlf", "*.txt eol=lf"); |
||||
// info overrides all
|
||||
collectRepositoryState(); |
||||
assertEquals("eol=crlf", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF); |
||||
} |
||||
|
||||
@Test |
||||
public void test_GlobalEOL_lf_InfoEOL_crlf_RootEOL_unspec() |
||||
throws Exception { |
||||
setupGitAndDoHardReset(null, null, "*.txt eol=lf", "*.txt eol=crlf", |
||||
"*.txt text !eol"); |
||||
// info overrides all
|
||||
collectRepositoryState(); |
||||
assertEquals("eol=crlf text", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF); |
||||
} |
||||
|
||||
@Test |
||||
public void test_GlobalEOL_lf_InfoEOL_unspec_RootEOL_crlf() |
||||
throws Exception { |
||||
setupGitAndDoHardReset(null, null, "*.txt eol=lf", "*.txt !eol", |
||||
"*.txt text eol=crlf"); |
||||
// info overrides all
|
||||
collectRepositoryState(); |
||||
assertEquals("text", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF); |
||||
} |
||||
|
||||
@Test |
||||
public void testBinary1() throws Exception { |
||||
setupGitAndDoHardReset(AutoCRLF.TRUE, EOL.CRLF, "*.txt text", "*.txt binary", |
||||
"*.txt eol=crlf"); |
||||
// info overrides all
|
||||
collectRepositoryState(); |
||||
assertEquals("binary -diff -merge -text eol=crlf", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_CRLF); |
||||
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_MIXED, CONTENT_MIXED); |
||||
} |
||||
|
||||
@Test |
||||
public void testBinary2() throws Exception { |
||||
setupGitAndDoHardReset(AutoCRLF.TRUE, EOL.CRLF, "*.txt text eol=crlf", null, |
||||
"*.txt binary"); |
||||
// root over global
|
||||
collectRepositoryState(); |
||||
assertEquals("binary -diff -merge -text eol=crlf", entryCRLF.attrs); |
||||
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_CRLF); |
||||
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); |
||||
checkEntryContent(entryMixed, CONTENT_MIXED, CONTENT_MIXED); |
||||
} |
||||
|
||||
// create new repo with
|
||||
// global .gitattributes
|
||||
// info .git/config/info/.gitattributes
|
||||
// workdir root .gitattributes
|
||||
// text file lf.txt CONTENT_LF
|
||||
// text file crlf.txt CONTENT_CRLF
|
||||
//
|
||||
// commit files (checkin)
|
||||
// delete working dir files
|
||||
// reset hard (checkout)
|
||||
private void setupGitAndDoHardReset(AutoCRLF autoCRLF, EOL eol, |
||||
String globalAttributesContent, String infoAttributesContent, |
||||
String workDirRootAttributesContent) throws Exception { |
||||
Git git = new Git(db); |
||||
FileBasedConfig config = db.getConfig(); |
||||
if (autoCRLF != null) { |
||||
config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null, |
||||
ConfigConstants.CONFIG_KEY_AUTOCRLF, autoCRLF); |
||||
} |
||||
if (eol != null) { |
||||
config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null, |
||||
ConfigConstants.CONFIG_KEY_EOL, eol); |
||||
} |
||||
if (globalAttributesContent != null) { |
||||
File f = new File(db.getDirectory(), "global/attrs"); |
||||
write(f, globalAttributesContent); |
||||
config.setString(ConfigConstants.CONFIG_CORE_SECTION, null, |
||||
ConfigConstants.CONFIG_KEY_ATTRIBUTESFILE, |
||||
f.getAbsolutePath()); |
||||
|
||||
} |
||||
if (infoAttributesContent != null) { |
||||
File f = new File(db.getDirectory(), Constants.INFO_ATTRIBUTES); |
||||
write(f, infoAttributesContent); |
||||
} |
||||
config.save(); |
||||
|
||||
if (workDirRootAttributesContent != null) { |
||||
dotGitattributes = createAndAddFile(git, |
||||
Constants.DOT_GIT_ATTRIBUTES, workDirRootAttributesContent); |
||||
} else { |
||||
dotGitattributes = null; |
||||
} |
||||
|
||||
fileCRLF = createAndAddFile(git, "file1.txt", CONTENT_CRLF); |
||||
|
||||
fileLF = createAndAddFile(git, "file2.txt", CONTENT_LF); |
||||
|
||||
fileMixed = createAndAddFile(git, "file3.txt", CONTENT_MIXED); |
||||
|
||||
gitCommit(git, "addFiles"); |
||||
|
||||
recreateWorktree(git); |
||||
} |
||||
|
||||
private void recreateWorktree(Git git) |
||||
throws GitAPIException, CheckoutConflictException, |
||||
InterruptedException, IOException, NoFilepatternException { |
||||
// re-create file from the repo
|
||||
for (File f : new File[] { dotGitattributes, fileCRLF, fileLF, fileMixed }) { |
||||
if (f == null) |
||||
continue; |
||||
f.delete(); |
||||
Assert.assertFalse(f.exists()); |
||||
} |
||||
gitResetHard(git); |
||||
fsTick(db.getIndexFile()); |
||||
gitAdd(git, "."); |
||||
} |
||||
|
||||
protected void gitCommit(Git git, String msg) throws GitAPIException { |
||||
git.commit().setMessage(msg).call(); |
||||
} |
||||
|
||||
protected void gitAdd(Git git, String path) throws GitAPIException { |
||||
git.add().addFilepattern(path).call(); |
||||
} |
||||
|
||||
protected void gitResetHard(Git git) throws GitAPIException { |
||||
git.reset().setMode(ResetType.HARD).call(); |
||||
} |
||||
|
||||
protected void gitCheckout(Git git, String revstr) |
||||
throws GitAPIException, RevisionSyntaxException, IOException { |
||||
git.checkout().setName(db.resolve(revstr).getName()).call(); |
||||
} |
||||
|
||||
// create a file and add it to the repo
|
||||
private File createAndAddFile(Git git, String path, String content) |
||||
throws Exception { |
||||
File f; |
||||
int pos = path.lastIndexOf('/'); |
||||
if (pos < 0) { |
||||
f = writeTrashFile(path, content); |
||||
} else { |
||||
f = writeTrashFile(path.substring(0, pos), path.substring(pos + 1), |
||||
content); |
||||
} |
||||
gitAdd(git, path); |
||||
Assert.assertTrue(f.exists()); |
||||
return f; |
||||
} |
||||
|
||||
private void collectRepositoryState() throws Exception { |
||||
dc = db.readDirCache(); |
||||
walk = beginWalk(); |
||||
if (dotGitattributes != null) |
||||
collectEntryContentAndAttributes(F, ".gitattributes", null); |
||||
collectEntryContentAndAttributes(F, fileCRLF.getName(), entryCRLF); |
||||
collectEntryContentAndAttributes(F, fileLF.getName(), entryLF); |
||||
collectEntryContentAndAttributes(F, fileMixed.getName(), entryMixed); |
||||
endWalk(); |
||||
} |
||||
|
||||
private TreeWalk beginWalk() throws Exception { |
||||
TreeWalk newWalk = new TreeWalk(db); |
||||
newWalk.addTree(new FileTreeIterator(db)); |
||||
newWalk.addTree(new DirCacheIterator(db.readDirCache())); |
||||
return newWalk; |
||||
} |
||||
|
||||
private void endWalk() throws IOException { |
||||
assertFalse("Not all files tested", walk.next()); |
||||
} |
||||
|
||||
private void collectEntryContentAndAttributes(FileMode type, String pathName, |
||||
ActualEntry e) throws IOException { |
||||
assertTrue("walk has entry", walk.next()); |
||||
|
||||
assertEquals(pathName, walk.getPathString()); |
||||
assertEquals(type, walk.getFileMode(0)); |
||||
|
||||
if (e != null) { |
||||
e.attrs = ""; |
||||
for (Attribute a : walk.getAttributes().getAll()) { |
||||
e.attrs += " " + a.toString(); |
||||
} |
||||
e.attrs = e.attrs.trim(); |
||||
e.file = new String( |
||||
IO.readFully(new File(db.getWorkTree(), pathName))); |
||||
DirCacheEntry dce = dc.getEntry(pathName); |
||||
ObjectLoader open = walk.getObjectReader().open(dce.getObjectId()); |
||||
e.index = new String(open.getBytes()); |
||||
e.indexContentLength = dce.getLength(); |
||||
} |
||||
|
||||
if (D.equals(type)) |
||||
walk.enterSubtree(); |
||||
} |
||||
} |
@ -0,0 +1,335 @@
|
||||
/* |
||||
* Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com> |
||||
* |
||||
* This program and the accompanying materials are made available |
||||
* under the terms of the Eclipse Distribution License v1.0 which |
||||
* accompanies this distribution, is reproduced below, and is |
||||
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||
* |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or |
||||
* without modification, are permitted provided that the following |
||||
* conditions are met: |
||||
* |
||||
* - Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* - Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following |
||||
* disclaimer in the documentation and/or other materials provided |
||||
* with the distribution. |
||||
* |
||||
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||
* names of its contributors may be used to endorse or promote |
||||
* products derived from this software without specific prior |
||||
* written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package org.eclipse.jgit.api; |
||||
|
||||
import static org.junit.Assert.assertArrayEquals; |
||||
import static org.eclipse.jgit.lib.CoreConfig.EolStreamType.*; |
||||
|
||||
import java.io.ByteArrayInputStream; |
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.InputStream; |
||||
import java.io.OutputStream; |
||||
import java.nio.charset.StandardCharsets; |
||||
import java.util.Arrays; |
||||
|
||||
import org.eclipse.jgit.lib.CoreConfig.EolStreamType; |
||||
import org.eclipse.jgit.util.IO; |
||||
import org.eclipse.jgit.util.io.EolStreamTypeUtil; |
||||
import org.junit.Test; |
||||
|
||||
/** |
||||
* Unit tests for end-of-line conversion streams |
||||
*/ |
||||
public class EolStreamTypeUtilTest { |
||||
|
||||
@Test |
||||
public void testCheckoutDirect() throws Exception { |
||||
testCheckout(DIRECT, DIRECT, "", ""); |
||||
testCheckout(DIRECT, DIRECT, "\r", "\r"); |
||||
testCheckout(DIRECT, DIRECT, "\n", "\n"); |
||||
|
||||
testCheckout(DIRECT, DIRECT, "\r\n", "\r\n"); |
||||
testCheckout(DIRECT, DIRECT, "\n\r", "\n\r"); |
||||
|
||||
testCheckout(DIRECT, DIRECT, "\n\r\n", "\n\r\n"); |
||||
testCheckout(DIRECT, DIRECT, "\r\n\r", "\r\n\r"); |
||||
|
||||
testCheckout(DIRECT, DIRECT, "a\nb\n", "a\nb\n"); |
||||
testCheckout(DIRECT, DIRECT, "a\rb\r", "a\rb\r"); |
||||
testCheckout(DIRECT, DIRECT, "a\n\rb\n\r", "a\n\rb\n\r"); |
||||
testCheckout(DIRECT, DIRECT, "a\r\nb\r\n", "a\r\nb\r\n"); |
||||
} |
||||
|
||||
@Test |
||||
public void testCheckoutLF() throws Exception { |
||||
testCheckout(TEXT_LF, AUTO_LF, "", ""); |
||||
testCheckout(TEXT_LF, AUTO_LF, "\r", "\r"); |
||||
testCheckout(TEXT_LF, AUTO_LF, "\n", "\n"); |
||||
|
||||
testCheckout(TEXT_LF, AUTO_LF, "\r\n", "\n"); |
||||
testCheckout(TEXT_LF, AUTO_LF, "\n\r", "\n\r"); |
||||
|
||||
testCheckout(TEXT_LF, AUTO_LF, "\n\r\n", "\n\n"); |
||||
testCheckout(TEXT_LF, AUTO_LF, "\r\n\r", "\n\r"); |
||||
|
||||
testCheckout(TEXT_LF, AUTO_LF, "a\nb\n", "a\nb\n"); |
||||
testCheckout(TEXT_LF, AUTO_LF, "a\rb\r", "a\rb\r"); |
||||
testCheckout(TEXT_LF, AUTO_LF, "a\n\rb\n\r", "a\n\rb\n\r"); |
||||
testCheckout(TEXT_LF, AUTO_LF, "a\r\nb\r\n", "a\nb\n"); |
||||
} |
||||
|
||||
@Test |
||||
public void testCheckoutCRLF() throws Exception { |
||||
testCheckout(TEXT_CRLF, AUTO_CRLF, "", ""); |
||||
testCheckout(TEXT_CRLF, AUTO_CRLF, "\r", "\r"); |
||||
testCheckout(TEXT_CRLF, AUTO_CRLF, "\n", "\r\n"); |
||||
|
||||
testCheckout(TEXT_CRLF, AUTO_CRLF, "\r\n", "\r\n"); |
||||
testCheckout(TEXT_CRLF, AUTO_CRLF, "\n\r", "\r\n\r"); |
||||
|
||||
testCheckout(TEXT_CRLF, AUTO_CRLF, "\n\r\n", "\r\n\r\n"); |
||||
testCheckout(TEXT_CRLF, AUTO_CRLF, "\r\n\r", "\r\n\r"); |
||||
|
||||
testCheckout(TEXT_CRLF, AUTO_CRLF, "a\nb\n", "a\r\nb\r\n"); |
||||
testCheckout(TEXT_CRLF, AUTO_CRLF, "a\rb\r", "a\rb\r"); |
||||
testCheckout(TEXT_CRLF, AUTO_CRLF, "a\n\rb\n\r", "a\r\n\rb\r\n\r"); |
||||
testCheckout(TEXT_CRLF, AUTO_CRLF, "a\r\nb\r\n", "a\r\nb\r\n"); |
||||
} |
||||
|
||||
/** |
||||
* Test stream type detection based on stream content. |
||||
* <p> |
||||
* Tests three things with the output text: |
||||
* <p> |
||||
* 1) conversion if output was declared as text |
||||
* <p> |
||||
* 2) conversion if output was declared as potentially text (AUTO_...) and |
||||
* is in fact text |
||||
* <p> |
||||
* 3) conversion if modified output (now with binary characters) was |
||||
* declared as potentially text but now contains binary characters |
||||
* <p> |
||||
* |
||||
* @param streamTypeText |
||||
* is the enum meaning that the output is definitely text (no |
||||
* binary check at all) |
||||
* @param streamTypeWithBinaryCheck |
||||
* is the enum meaning that the output may be text (binary check |
||||
* is done) |
||||
* @param output |
||||
* is a text output without binary characters |
||||
* @param expectedConversion |
||||
* is the expected converted output without binary characters |
||||
* @throws Exception |
||||
*/ |
||||
private void testCheckout(EolStreamType streamTypeText, |
||||
EolStreamType streamTypeWithBinaryCheck, String output, |
||||
String expectedConversion) throws Exception { |
||||
ByteArrayOutputStream b; |
||||
byte[] outputBytes = output.getBytes(StandardCharsets.UTF_8); |
||||
byte[] expectedConversionBytes = expectedConversion |
||||
.getBytes(StandardCharsets.UTF_8); |
||||
|
||||
// test using output text and assuming it was declared TEXT
|
||||
b = new ByteArrayOutputStream(); |
||||
try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b, |
||||
streamTypeText)) { |
||||
out.write(outputBytes); |
||||
} |
||||
assertArrayEquals(expectedConversionBytes, b.toByteArray()); |
||||
|
||||
// test using ouput text and assuming it was declared AUTO, using binary
|
||||
// detection
|
||||
b = new ByteArrayOutputStream(); |
||||
try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b, |
||||
streamTypeWithBinaryCheck)) { |
||||
out.write(outputBytes); |
||||
} |
||||
assertArrayEquals(expectedConversionBytes, b.toByteArray()); |
||||
|
||||
// now pollute output text with some binary bytes
|
||||
outputBytes = extendWithBinaryData(outputBytes); |
||||
expectedConversionBytes = extendWithBinaryData(expectedConversionBytes); |
||||
|
||||
// again, test using output text and assuming it was declared TEXT
|
||||
b = new ByteArrayOutputStream(); |
||||
try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b, |
||||
streamTypeText)) { |
||||
out.write(outputBytes); |
||||
} |
||||
assertArrayEquals(expectedConversionBytes, b.toByteArray()); |
||||
|
||||
// again, test using ouput text and assuming it was declared AUTO, using
|
||||
// binary
|
||||
// detection
|
||||
b = new ByteArrayOutputStream(); |
||||
try (OutputStream out = EolStreamTypeUtil.wrapOutputStream(b, |
||||
streamTypeWithBinaryCheck)) { |
||||
out.write(outputBytes); |
||||
} |
||||
// expect no conversion
|
||||
assertArrayEquals(outputBytes, b.toByteArray()); |
||||
} |
||||
|
||||
@Test |
||||
public void testCheckinDirect() throws Exception { |
||||
testCheckin(DIRECT, DIRECT, "", ""); |
||||
testCheckin(DIRECT, DIRECT, "\r", "\r"); |
||||
testCheckin(DIRECT, DIRECT, "\n", "\n"); |
||||
|
||||
testCheckin(DIRECT, DIRECT, "\r\n", "\r\n"); |
||||
testCheckin(DIRECT, DIRECT, "\n\r", "\n\r"); |
||||
|
||||
testCheckin(DIRECT, DIRECT, "\n\r\n", "\n\r\n"); |
||||
testCheckin(DIRECT, DIRECT, "\r\n\r", "\r\n\r"); |
||||
|
||||
testCheckin(DIRECT, DIRECT, "a\nb\n", "a\nb\n"); |
||||
testCheckin(DIRECT, DIRECT, "a\rb\r", "a\rb\r"); |
||||
testCheckin(DIRECT, DIRECT, "a\n\rb\n\r", "a\n\rb\n\r"); |
||||
testCheckin(DIRECT, DIRECT, "a\r\nb\r\n", "a\r\nb\r\n"); |
||||
} |
||||
|
||||
@Test |
||||
public void testCheckinLF() throws Exception { |
||||
testCheckin(TEXT_LF, AUTO_LF, "", ""); |
||||
testCheckin(TEXT_LF, AUTO_LF, "\r", "\r"); |
||||
testCheckin(TEXT_LF, AUTO_LF, "\n", "\n"); |
||||
|
||||
testCheckin(TEXT_LF, AUTO_LF, "\r\n", "\n"); |
||||
testCheckin(TEXT_LF, AUTO_LF, "\n\r", "\n\r"); |
||||
|
||||
testCheckin(TEXT_LF, AUTO_LF, "\n\r\n", "\n\n"); |
||||
testCheckin(TEXT_LF, AUTO_LF, "\r\n\r", "\n\r"); |
||||
|
||||
testCheckin(TEXT_LF, AUTO_LF, "a\nb\n", "a\nb\n"); |
||||
testCheckin(TEXT_LF, AUTO_LF, "a\rb\r", "a\rb\r"); |
||||
testCheckin(TEXT_LF, AUTO_LF, "a\n\rb\n\r", "a\n\rb\n\r"); |
||||
testCheckin(TEXT_LF, AUTO_LF, "a\r\nb\r\n", "a\nb\n"); |
||||
} |
||||
|
||||
@Test |
||||
public void testCheckinCRLF() throws Exception { |
||||
testCheckin(TEXT_CRLF, AUTO_CRLF, "", ""); |
||||
testCheckin(TEXT_CRLF, AUTO_CRLF, "\r", "\r"); |
||||
testCheckin(TEXT_CRLF, AUTO_CRLF, "\n", "\r\n"); |
||||
|
||||
testCheckin(TEXT_CRLF, AUTO_CRLF, "\r\n", "\r\n"); |
||||
testCheckin(TEXT_CRLF, AUTO_CRLF, "\n\r", "\r\n\r"); |
||||
|
||||
testCheckin(TEXT_CRLF, AUTO_CRLF, "\n\r\n", "\r\n\r\n"); |
||||
testCheckin(TEXT_CRLF, AUTO_CRLF, "\r\n\r", "\r\n\r"); |
||||
|
||||
testCheckin(TEXT_CRLF, AUTO_CRLF, "a\nb\n", "a\r\nb\r\n"); |
||||
testCheckin(TEXT_CRLF, AUTO_CRLF, "a\rb\r", "a\rb\r"); |
||||
testCheckin(TEXT_CRLF, AUTO_CRLF, "a\n\rb\n\r", "a\r\n\rb\r\n\r"); |
||||
testCheckin(TEXT_CRLF, AUTO_CRLF, "a\r\nb\r\n", "a\r\nb\r\n"); |
||||
} |
||||
|
||||
/** |
||||
* Test stream type detection based on stream content. |
||||
* <p> |
||||
* Tests three things with the input text: |
||||
* <p> |
||||
* 1) conversion if input was declared as text |
||||
* <p> |
||||
* 2) conversion if input was declared as potentially text (AUTO_...) and is |
||||
* in fact text |
||||
* <p> |
||||
* 3) conversion if modified input (now with binary characters) was declared |
||||
* as potentially text but now contains binary characters |
||||
* <p> |
||||
* |
||||
* @param streamTypeText |
||||
* is the enum meaning that the input is definitely text (no |
||||
* binary check at all) |
||||
* @param streamTypeWithBinaryCheck |
||||
* is the enum meaning that the input may be text (binary check |
||||
* is done) |
||||
* @param input |
||||
* is a text input without binary characters |
||||
* @param expectedConversion |
||||
* is the expected converted input without binary characters |
||||
* @throws Exception |
||||
*/ |
||||
private void testCheckin(EolStreamType streamTypeText, |
||||
EolStreamType streamTypeWithBinaryCheck, String input, |
||||
String expectedConversion) throws Exception { |
||||
byte[] inputBytes = input.getBytes(StandardCharsets.UTF_8); |
||||
byte[] expectedConversionBytes = expectedConversion |
||||
.getBytes(StandardCharsets.UTF_8); |
||||
|
||||
// test using input text and assuming it was declared TEXT
|
||||
try (InputStream in = EolStreamTypeUtil.wrapInputStream( |
||||
new ByteArrayInputStream(inputBytes), |
||||
streamTypeText)) { |
||||
byte[] b = new byte[1024]; |
||||
int len = IO.readFully(in, b, 0); |
||||
assertArrayEquals(expectedConversionBytes, Arrays.copyOf(b, len)); |
||||
} |
||||
|
||||
// test using input text and assuming it was declared AUTO, using binary
|
||||
// detection
|
||||
try (InputStream in = EolStreamTypeUtil.wrapInputStream( |
||||
new ByteArrayInputStream(inputBytes), |
||||
streamTypeWithBinaryCheck)) { |
||||
byte[] b = new byte[1024]; |
||||
int len = IO.readFully(in, b, 0); |
||||
assertArrayEquals(expectedConversionBytes, Arrays.copyOf(b, len)); |
||||
} |
||||
|
||||
// now pollute input text with some binary bytes
|
||||
inputBytes = extendWithBinaryData(inputBytes); |
||||
expectedConversionBytes = extendWithBinaryData(expectedConversionBytes); |
||||
|
||||
// again, test using input text and assuming it was declared TEXT
|
||||
try (InputStream in = EolStreamTypeUtil.wrapInputStream( |
||||
new ByteArrayInputStream(inputBytes), streamTypeText)) { |
||||
byte[] b = new byte[1024]; |
||||
int len = IO.readFully(in, b, 0); |
||||
assertArrayEquals(expectedConversionBytes, Arrays.copyOf(b, len)); |
||||
} |
||||
|
||||
// again, test using input text and assuming it was declared AUTO, using
|
||||
// binary
|
||||
// detection
|
||||
try (InputStream in = EolStreamTypeUtil.wrapInputStream( |
||||
new ByteArrayInputStream(inputBytes), |
||||
streamTypeWithBinaryCheck)) { |
||||
byte[] b = new byte[1024]; |
||||
int len = IO.readFully(in, b, 0); |
||||
// expect no conversion
|
||||
assertArrayEquals(inputBytes, Arrays.copyOf(b, len)); |
||||
} |
||||
} |
||||
|
||||
private byte[] extendWithBinaryData(byte[] data) throws Exception { |
||||
int n = 3; |
||||
byte[] dataEx = new byte[data.length + n]; |
||||
System.arraycopy(data, 0, dataEx, 0, data.length); |
||||
for (int i = 0; i < n; i++) { |
||||
dataEx[data.length + i] = (byte) i; |
||||
} |
||||
return dataEx; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,77 @@
|
||||
/* |
||||
* Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com> |
||||
* |
||||
* This program and the accompanying materials are made available |
||||
* under the terms of the Eclipse Distribution License v1.0 which |
||||
* accompanies this distribution, is reproduced below, and is |
||||
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||
* |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or |
||||
* without modification, are permitted provided that the following |
||||
* conditions are met: |
||||
* |
||||
* - Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* - Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following |
||||
* disclaimer in the documentation and/or other materials provided |
||||
* with the distribution. |
||||
* |
||||
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||
* names of its contributors may be used to endorse or promote |
||||
* products derived from this software without specific prior |
||||
* written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
package org.eclipse.jgit.util; |
||||
|
||||
/** |
||||
* Holder of an object. |
||||
* |
||||
* @param <T> |
||||
* the type of value held by this {@link Holder} |
||||
* |
||||
* @since 4.3 |
||||
*/ |
||||
public class Holder<T> { |
||||
private T value; |
||||
|
||||
/** |
||||
* @param value |
||||
* is the initial value that is {@link #set(Object)} |
||||
*/ |
||||
public Holder(T value) { |
||||
set(value); |
||||
} |
||||
|
||||
/** |
||||
* @return the value held by this {@link Holder} |
||||
*/ |
||||
public T get() { |
||||
return value; |
||||
} |
||||
|
||||
/** |
||||
* @param value |
||||
* to be set as new value held by this {@link Holder} |
||||
*/ |
||||
public void set(T value) { |
||||
this.value = value; |
||||
} |
||||
} |
@ -0,0 +1,199 @@
|
||||
/* |
||||
* Copyright (C) 2010, 2013 Marc Strapetz <marc.strapetz@syntevo.com> |
||||
* Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com> |
||||
* and other copyright owners as documented in the project's IP log. |
||||
* |
||||
* This program and the accompanying materials are made available |
||||
* under the terms of the Eclipse Distribution License v1.0 which |
||||
* accompanies this distribution, is reproduced below, and is |
||||
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||
* |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or |
||||
* without modification, are permitted provided that the following |
||||
* conditions are met: |
||||
* |
||||
* - Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* - Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following |
||||
* disclaimer in the documentation and/or other materials provided |
||||
* with the distribution. |
||||
* |
||||
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||
* names of its contributors may be used to endorse or promote |
||||
* products derived from this software without specific prior |
||||
* written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package org.eclipse.jgit.util.io; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
|
||||
import org.eclipse.jgit.diff.RawText; |
||||
|
||||
/** |
||||
* An InputStream that normalizes CRLF to LF. |
||||
* |
||||
* Existing single CR are not changed to LF, but retained as is. |
||||
* |
||||
* Optionally, a binary check on the first 8000 bytes is performed and in case |
||||
* of binary files, canonicalization is turned off (for the complete file). |
||||
* <p> |
||||
* This is the former EolCanonicalizingInputStream with a new name in order to |
||||
* have same naming for all LF / CRLF streams |
||||
* |
||||
* @since 4.3 |
||||
*/ |
||||
public class AutoLFInputStream extends InputStream { |
||||
private final byte[] single = new byte[1]; |
||||
|
||||
private final byte[] buf = new byte[8096]; |
||||
|
||||
private final InputStream in; |
||||
|
||||
private int cnt; |
||||
|
||||
private int ptr; |
||||
|
||||
private boolean isBinary; |
||||
|
||||
private boolean detectBinary; |
||||
|
||||
private boolean abortIfBinary; |
||||
|
||||
/** |
||||
* A special exception thrown when {@link AutoLFInputStream} is told to |
||||
* throw an exception when attempting to read a binary file. The exception |
||||
* may be thrown at any stage during reading. |
||||
* |
||||
* @since 3.3 |
||||
*/ |
||||
public static class IsBinaryException extends IOException { |
||||
private static final long serialVersionUID = 1L; |
||||
|
||||
IsBinaryException() { |
||||
super(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Creates a new InputStream, wrapping the specified stream |
||||
* |
||||
* @param in |
||||
* raw input stream |
||||
* @param detectBinary |
||||
* whether binaries should be detected |
||||
* @since 2.0 |
||||
*/ |
||||
public AutoLFInputStream(InputStream in, boolean detectBinary) { |
||||
this(in, detectBinary, false); |
||||
} |
||||
|
||||
/** |
||||
* Creates a new InputStream, wrapping the specified stream |
||||
* |
||||
* @param in |
||||
* raw input stream |
||||
* @param detectBinary |
||||
* whether binaries should be detected |
||||
* @param abortIfBinary |
||||
* throw an IOException if the file is binary |
||||
* @since 3.3 |
||||
*/ |
||||
public AutoLFInputStream(InputStream in, boolean detectBinary, |
||||
boolean abortIfBinary) { |
||||
this.in = in; |
||||
this.detectBinary = detectBinary; |
||||
this.abortIfBinary = abortIfBinary; |
||||
} |
||||
|
||||
@Override |
||||
public int read() throws IOException { |
||||
final int read = read(single, 0, 1); |
||||
return read == 1 ? single[0] & 0xff : -1; |
||||
} |
||||
|
||||
@Override |
||||
public int read(byte[] bs, final int off, final int len) |
||||
throws IOException { |
||||
if (len == 0) |
||||
return 0; |
||||
|
||||
if (cnt == -1) |
||||
return -1; |
||||
|
||||
int i = off; |
||||
final int end = off + len; |
||||
|
||||
while (i < end) { |
||||
if (ptr == cnt && !fillBuffer()) { |
||||
break; |
||||
} |
||||
|
||||
byte b = buf[ptr++]; |
||||
if (isBinary || b != '\r') { |
||||
// Logic for binary files ends here
|
||||
bs[i++] = b; |
||||
continue; |
||||
} |
||||
|
||||
if (ptr == cnt && !fillBuffer()) { |
||||
bs[i++] = '\r'; |
||||
break; |
||||
} |
||||
|
||||
if (buf[ptr] == '\n') { |
||||
bs[i++] = '\n'; |
||||
ptr++; |
||||
} else |
||||
bs[i++] = '\r'; |
||||
} |
||||
|
||||
return i == off ? -1 : i - off; |
||||
} |
||||
|
||||
/** |
||||
* @return true if the stream has detected as a binary so far |
||||
* @since 3.3 |
||||
*/ |
||||
public boolean isBinary() { |
||||
return isBinary; |
||||
} |
||||
|
||||
@Override |
||||
public void close() throws IOException { |
||||
in.close(); |
||||
} |
||||
|
||||
private boolean fillBuffer() throws IOException { |
||||
cnt = in.read(buf, 0, buf.length); |
||||
if (cnt < 1) |
||||
return false; |
||||
if (detectBinary) { |
||||
isBinary = RawText.isBinary(buf, cnt); |
||||
detectBinary = false; |
||||
if (isBinary && abortIfBinary) |
||||
throw new IsBinaryException(); |
||||
} |
||||
ptr = 0; |
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,200 @@
|
||||
/* |
||||
* Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com> |
||||
* |
||||
* This program and the accompanying materials are made available |
||||
* under the terms of the Eclipse Distribution License v1.0 which |
||||
* accompanies this distribution, is reproduced below, and is |
||||
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||
* |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or |
||||
* without modification, are permitted provided that the following |
||||
* conditions are met: |
||||
* |
||||
* - Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* - Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following |
||||
* disclaimer in the documentation and/or other materials provided |
||||
* with the distribution. |
||||
* |
||||
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||
* names of its contributors may be used to endorse or promote |
||||
* products derived from this software without specific prior |
||||
* written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package org.eclipse.jgit.util.io; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.OutputStream; |
||||
|
||||
import org.eclipse.jgit.diff.RawText; |
||||
|
||||
/** |
||||
* An OutputStream that reduces CRLF to LF. |
||||
* |
||||
* Existing single CR are not changed to LF, but retained as is. |
||||
* |
||||
* A binary check on the first 8000 bytes is performed and in case of binary |
||||
* files, canonicalization is turned off (for the complete file). |
||||
* |
||||
* @since 4.3 |
||||
*/ |
||||
public class AutoLFOutputStream extends OutputStream { |
||||
|
||||
static final int BUFFER_SIZE = 8000; |
||||
|
||||
private final OutputStream out; |
||||
|
||||
private int buf = -1; |
||||
|
||||
private byte[] binbuf = new byte[BUFFER_SIZE]; |
||||
|
||||
private byte[] onebytebuf = new byte[1]; |
||||
|
||||
private int binbufcnt = 0; |
||||
|
||||
private boolean detectBinary; |
||||
|
||||
private boolean isBinary; |
||||
|
||||
/** |
||||
* @param out |
||||
*/ |
||||
public AutoLFOutputStream(OutputStream out) { |
||||
this(out, true); |
||||
} |
||||
|
||||
/** |
||||
* @param out |
||||
* @param detectBinary |
||||
* whether binaries should be detected |
||||
*/ |
||||
public AutoLFOutputStream(OutputStream out, boolean detectBinary) { |
||||
this.out = out; |
||||
this.detectBinary = detectBinary; |
||||
} |
||||
|
||||
@Override |
||||
public void write(int b) throws IOException { |
||||
onebytebuf[0] = (byte) b; |
||||
write(onebytebuf, 0, 1); |
||||
} |
||||
|
||||
@Override |
||||
public void write(byte[] b) throws IOException { |
||||
int overflow = buffer(b, 0, b.length); |
||||
if (overflow > 0) { |
||||
write(b, b.length - overflow, overflow); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void write(byte[] b, final int startOff, final int startLen) |
||||
throws IOException { |
||||
final int overflow = buffer(b, startOff, startLen); |
||||
if (overflow < 0) { |
||||
return; |
||||
} |
||||
final int off = startOff + startLen - overflow; |
||||
final int len = overflow; |
||||
if (len == 0) { |
||||
return; |
||||
} |
||||
int lastw = off; |
||||
if (isBinary) { |
||||
out.write(b, off, len); |
||||
return; |
||||
} |
||||
for (int i = off; i < off + len; ++i) { |
||||
final byte c = b[i]; |
||||
if (c == '\r') { |
||||
// skip write r but backlog r
|
||||
if (lastw < i) { |
||||
out.write(b, lastw, i - lastw); |
||||
} |
||||
lastw = i + 1; |
||||
buf = '\r'; |
||||
} else if (c == '\n') { |
||||
if (buf == '\r') { |
||||
out.write('\n'); |
||||
lastw = i + 1; |
||||
buf = -1; |
||||
} else { |
||||
if (lastw < i + 1) { |
||||
out.write(b, lastw, i + 1 - lastw); |
||||
} |
||||
lastw = i + 1; |
||||
} |
||||
} else { |
||||
if (buf == '\r') { |
||||
out.write('\r'); |
||||
lastw = i; |
||||
} |
||||
buf = -1; |
||||
} |
||||
} |
||||
if (lastw < off + len) { |
||||
out.write(b, lastw, off + len - lastw); |
||||
} |
||||
} |
||||
|
||||
private int buffer(byte[] b, int off, int len) throws IOException { |
||||
if (binbufcnt > binbuf.length) { |
||||
return len; |
||||
} |
||||
int copy = Math.min(binbuf.length - binbufcnt, len); |
||||
System.arraycopy(b, off, binbuf, binbufcnt, copy); |
||||
binbufcnt += copy; |
||||
int remaining = len - copy; |
||||
if (remaining > 0) { |
||||
decideMode(); |
||||
} |
||||
return remaining; |
||||
} |
||||
|
||||
private void decideMode() throws IOException { |
||||
if (detectBinary) { |
||||
isBinary = RawText.isBinary(binbuf, binbufcnt); |
||||
detectBinary = false; |
||||
} |
||||
int cachedLen = binbufcnt; |
||||
binbufcnt = binbuf.length + 1; // full!
|
||||
write(binbuf, 0, cachedLen); |
||||
} |
||||
|
||||
@Override |
||||
public void flush() throws IOException { |
||||
if (binbufcnt <= binbuf.length) { |
||||
decideMode(); |
||||
} |
||||
out.flush(); |
||||
} |
||||
|
||||
@Override |
||||
public void close() throws IOException { |
||||
flush(); |
||||
if (buf == '\r') { |
||||
out.write(buf); |
||||
buf = -1; |
||||
} |
||||
out.close(); |
||||
} |
||||
} |
@ -0,0 +1,255 @@
|
||||
/* |
||||
* Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com> |
||||
* |
||||
* This program and the accompanying materials are made available |
||||
* under the terms of the Eclipse Distribution License v1.0 which |
||||
* accompanies this distribution, is reproduced below, and is |
||||
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||
* |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or |
||||
* without modification, are permitted provided that the following |
||||
* conditions are met: |
||||
* |
||||
* - Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* - Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following |
||||
* disclaimer in the documentation and/or other materials provided |
||||
* with the distribution. |
||||
* |
||||
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||
* names of its contributors may be used to endorse or promote |
||||
* products derived from this software without specific prior |
||||
* written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package org.eclipse.jgit.util.io; |
||||
|
||||
import java.io.InputStream; |
||||
import java.io.OutputStream; |
||||
|
||||
import org.eclipse.jgit.attributes.Attributes; |
||||
import org.eclipse.jgit.lib.Config; |
||||
import org.eclipse.jgit.lib.CoreConfig.EolStreamType; |
||||
import org.eclipse.jgit.treewalk.TreeWalk.OperationType; |
||||
import org.eclipse.jgit.treewalk.WorkingTreeOptions; |
||||
|
||||
/** |
||||
* Utility used to create input and output stream wrappers for |
||||
* {@link EolStreamType} |
||||
* |
||||
* @since 4.3 |
||||
*/ |
||||
public final class EolStreamTypeUtil { |
||||
private static final boolean FORCE_EOL_LF_ON_CHECKOUT = false; |
||||
|
||||
private EolStreamTypeUtil() { |
||||
} |
||||
|
||||
/** |
||||
* Convenience method used to detect if CRLF conversion has been configured |
||||
* using the |
||||
* <ul> |
||||
* <li>global repo options</li> |
||||
* <li>global attributes</li> |
||||
* <li>info attributes</li> |
||||
* <li>working tree .gitattributes</li> |
||||
* |
||||
* @param op |
||||
* is the {@link OperationType} of the current traversal |
||||
* @param options |
||||
* are the {@link Config} options with key |
||||
* {@link WorkingTreeOptions#KEY} |
||||
* @param attrs |
||||
* are the {@link Attributes} of the file for which the |
||||
* {@link EolStreamType} is to be detected |
||||
* |
||||
* @return the stream conversion {@link EolStreamType} to be performed for |
||||
* the selected {@link OperationType} |
||||
*/ |
||||
public static EolStreamType detectStreamType(OperationType op, |
||||
WorkingTreeOptions options, Attributes attrs) { |
||||
switch (op) { |
||||
case CHECKIN_OP: |
||||
return checkInStreamType(options, attrs); |
||||
case CHECKOUT_OP: |
||||
return checkOutStreamType(options, attrs); |
||||
default: |
||||
throw new IllegalArgumentException("unknown OperationType " + op); //$NON-NLS-1$
|
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @param in |
||||
* original stream |
||||
* @param conversion |
||||
* to be performed |
||||
* @return the converted stream depending on {@link EolStreamType} |
||||
*/ |
||||
public static InputStream wrapInputStream(InputStream in, |
||||
EolStreamType conversion) { |
||||
switch (conversion) { |
||||
case TEXT_CRLF: |
||||
return new AutoCRLFInputStream(in, false); |
||||
case TEXT_LF: |
||||
return new AutoLFInputStream(in, false); |
||||
case AUTO_CRLF: |
||||
return new AutoCRLFInputStream(in, true); |
||||
case AUTO_LF: |
||||
return new AutoLFInputStream(in, true); |
||||
default: |
||||
return in; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @param out |
||||
* original stream |
||||
* @param conversion |
||||
* to be performed |
||||
* @return the converted stream depending on {@link EolStreamType} |
||||
*/ |
||||
public static OutputStream wrapOutputStream(OutputStream out, |
||||
EolStreamType conversion) { |
||||
switch (conversion) { |
||||
case TEXT_CRLF: |
||||
return new AutoCRLFOutputStream(out, false); |
||||
case AUTO_CRLF: |
||||
return new AutoCRLFOutputStream(out, true); |
||||
case TEXT_LF: |
||||
return new AutoLFOutputStream(out, false); |
||||
case AUTO_LF: |
||||
return new AutoLFOutputStream(out, true); |
||||
default: |
||||
return out; |
||||
} |
||||
} |
||||
|
||||
private static EolStreamType checkInStreamType(WorkingTreeOptions options, |
||||
Attributes attrs) { |
||||
// old git system
|
||||
if (attrs.isSet("crlf")) {//$NON-NLS-1$
|
||||
return EolStreamType.TEXT_LF; |
||||
} else if (attrs.isUnset("crlf")) {//$NON-NLS-1$
|
||||
return EolStreamType.DIRECT; |
||||
} else if ("input".equals(attrs.getValue("crlf"))) {//$NON-NLS-1$ //$NON-NLS-2$
|
||||
return EolStreamType.TEXT_LF; |
||||
} |
||||
|
||||
// new git system
|
||||
if (attrs.isUnset("text")) {//$NON-NLS-1$
|
||||
return EolStreamType.DIRECT; |
||||
} |
||||
String eol = attrs.getValue("eol"); //$NON-NLS-1$
|
||||
if (eol != null) |
||||
// check-in is always normalized to LF
|
||||
return EolStreamType.TEXT_LF; |
||||
|
||||
if (attrs.isSet("text")) { //$NON-NLS-1$
|
||||
return EolStreamType.TEXT_LF; |
||||
} |
||||
|
||||
if ("auto".equals(attrs.getValue("text"))) { //$NON-NLS-1$ //$NON-NLS-2$
|
||||
return EolStreamType.AUTO_LF; |
||||
} |
||||
|
||||
switch (options.getAutoCRLF()) { |
||||
case TRUE: |
||||
case INPUT: |
||||
return EolStreamType.AUTO_LF; |
||||
case FALSE: |
||||
return EolStreamType.DIRECT; |
||||
} |
||||
|
||||
return EolStreamType.DIRECT; |
||||
} |
||||
|
||||
private static EolStreamType checkOutStreamType(WorkingTreeOptions options, |
||||
Attributes attrs) { |
||||
// old git system
|
||||
if (attrs.isSet("crlf")) {//$NON-NLS-1$
|
||||
return FORCE_EOL_LF_ON_CHECKOUT ? EolStreamType.TEXT_LF |
||||
: EolStreamType.DIRECT; |
||||
} else if (attrs.isUnset("crlf")) {//$NON-NLS-1$
|
||||
return EolStreamType.DIRECT; |
||||
} else if ("input".equals(attrs.getValue("crlf"))) {//$NON-NLS-1$ //$NON-NLS-2$
|
||||
return EolStreamType.DIRECT; |
||||
} |
||||
|
||||
// new git system
|
||||
if (attrs.isUnset("text")) {//$NON-NLS-1$
|
||||
return EolStreamType.DIRECT; |
||||
} |
||||
String eol = attrs.getValue("eol"); //$NON-NLS-1$
|
||||
if (eol != null && "crlf".equals(eol)) //$NON-NLS-1$
|
||||
return EolStreamType.TEXT_CRLF; |
||||
if (eol != null && "lf".equals(eol)) //$NON-NLS-1$
|
||||
return FORCE_EOL_LF_ON_CHECKOUT ? EolStreamType.TEXT_LF |
||||
: EolStreamType.DIRECT; |
||||
|
||||
if (attrs.isSet("text")) { //$NON-NLS-1$
|
||||
switch (options.getAutoCRLF()) { |
||||
case TRUE: |
||||
return EolStreamType.TEXT_CRLF; |
||||
default: |
||||
// no decision
|
||||
} |
||||
switch (options.getEOL()) { |
||||
case CRLF: |
||||
return EolStreamType.TEXT_CRLF; |
||||
case LF: |
||||
return FORCE_EOL_LF_ON_CHECKOUT ? EolStreamType.TEXT_LF |
||||
: EolStreamType.DIRECT; |
||||
case NATIVE: |
||||
default: |
||||
return EolStreamType.DIRECT; |
||||
} |
||||
} |
||||
|
||||
if ("auto".equals(attrs.getValue("text"))) { //$NON-NLS-1$ //$NON-NLS-2$
|
||||
switch (options.getAutoCRLF()) { |
||||
case TRUE: |
||||
return EolStreamType.AUTO_CRLF; |
||||
default: |
||||
// no decision
|
||||
} |
||||
switch (options.getEOL()) { |
||||
case CRLF: |
||||
return EolStreamType.AUTO_CRLF; |
||||
case LF: |
||||
return FORCE_EOL_LF_ON_CHECKOUT ? EolStreamType.TEXT_LF |
||||
: EolStreamType.DIRECT; |
||||
case NATIVE: |
||||
default: |
||||
return EolStreamType.DIRECT; |
||||
} |
||||
} |
||||
|
||||
switch (options.getAutoCRLF()) { |
||||
case TRUE: |
||||
return EolStreamType.AUTO_CRLF; |
||||
default: |
||||
// no decision
|
||||
} |
||||
|
||||
return EolStreamType.DIRECT; |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue