View Javadoc
1   /*
2    * Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com>
3    *
4    * This program and the accompanying materials are made available
5    * under the terms of the Eclipse Distribution License v1.0 which
6    * accompanies this distribution, is reproduced below, and is
7    * available at http://www.eclipse.org/org/documents/edl-v10.php
8    *
9    * All rights reserved.
10   *
11   * Redistribution and use in source and binary forms, with or
12   * without modification, are permitted provided that the following
13   * conditions are met:
14   *
15   * - Redistributions of source code must retain the above copyright
16   *   notice, this list of conditions and the following disclaimer.
17   *
18   * - Redistributions in binary form must reproduce the above
19   *   copyright notice, this list of conditions and the following
20   *   disclaimer in the documentation and/or other materials provided
21   *   with the distribution.
22   *
23   * - Neither the name of the Eclipse Foundation, Inc. nor the
24   *   names of its contributors may be used to endorse or promote
25   *   products derived from this software without specific prior
26   *   written permission.
27   *
28   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
29   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
30   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
31   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
33   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
35   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
36   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
37   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
38   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
40   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41   */
42  
43  package org.eclipse.jgit.util.io;
44  
45  import java.io.InputStream;
46  import java.io.OutputStream;
47  
48  import org.eclipse.jgit.attributes.Attributes;
49  import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
50  import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
51  import org.eclipse.jgit.treewalk.WorkingTreeOptions;
52  
53  /**
54   * Utility used to create input and output stream wrappers for
55   * {@link org.eclipse.jgit.lib.CoreConfig.EolStreamType}
56   *
57   * @since 4.3
58   */
59  public final class EolStreamTypeUtil {
60  	private static final boolean FORCE_EOL_LF_ON_CHECKOUT = false;
61  
62  	private EolStreamTypeUtil() {
63  	}
64  
65  	/**
66  	 * Convenience method used to detect if CRLF conversion has been configured
67  	 * using the
68  	 * <ul>
69  	 * <li>global repo options</li>
70  	 * <li>global attributes</li>
71  	 * <li>info attributes</li>
72  	 * <li>working tree .gitattributes</li>
73  	 * </ul>
74  	 *
75  	 * @param op
76  	 *            is the
77  	 *            {@link org.eclipse.jgit.treewalk.TreeWalk.OperationType} of
78  	 *            the current traversal
79  	 * @param options
80  	 *            are the {@link org.eclipse.jgit.lib.Config} options with key
81  	 *            {@link org.eclipse.jgit.treewalk.WorkingTreeOptions#KEY}
82  	 * @param attrs
83  	 *            are the {@link org.eclipse.jgit.attributes.Attributes} of the
84  	 *            file for which the
85  	 *            {@link org.eclipse.jgit.lib.CoreConfig.EolStreamType} is to be
86  	 *            detected
87  	 * @return the stream conversion
88  	 *         {@link org.eclipse.jgit.lib.CoreConfig.EolStreamType} to be
89  	 *         performed for the selected
90  	 *         {@link org.eclipse.jgit.treewalk.TreeWalk.OperationType}
91  	 */
92  	public static EolStreamType detectStreamType(OperationType op,
93  			WorkingTreeOptions options, Attributes attrs) {
94  		switch (op) {
95  		case CHECKIN_OP:
96  			return checkInStreamType(options, attrs);
97  		case CHECKOUT_OP:
98  			return checkOutStreamType(options, attrs);
99  		default:
100 			throw new IllegalArgumentException("unknown OperationType " + op); //$NON-NLS-1$
101 		}
102 	}
103 
104 	/**
105 	 * Wrap the input stream depending on
106 	 * {@link org.eclipse.jgit.lib.CoreConfig.EolStreamType}
107 	 *
108 	 * @param in
109 	 *            original stream
110 	 * @param conversion
111 	 *            to be performed
112 	 * @return the converted stream depending on
113 	 *         {@link org.eclipse.jgit.lib.CoreConfig.EolStreamType}
114 	 */
115 	public static InputStream wrapInputStream(InputStream in,
116 			EolStreamType conversion) {
117 		switch (conversion) {
118 		case TEXT_CRLF:
119 			return new AutoCRLFInputStream(in, false);
120 		case TEXT_LF:
121 			return new AutoLFInputStream(in, false);
122 		case AUTO_CRLF:
123 			return new AutoCRLFInputStream(in, true);
124 		case AUTO_LF:
125 			return new AutoLFInputStream(in, true);
126 		default:
127 			return in;
128 		}
129 	}
130 
131 	/**
132 	 * Wrap the output stream depending on
133 	 * {@link org.eclipse.jgit.lib.CoreConfig.EolStreamType}
134 	 *
135 	 * @param out
136 	 *            original stream
137 	 * @param conversion
138 	 *            to be performed
139 	 * @return the converted stream depending on
140 	 *         {@link org.eclipse.jgit.lib.CoreConfig.EolStreamType}
141 	 */
142 	public static OutputStream wrapOutputStream(OutputStream out,
143 			EolStreamType conversion) {
144 		switch (conversion) {
145 		case TEXT_CRLF:
146 			return new AutoCRLFOutputStream(out, false);
147 		case AUTO_CRLF:
148 			return new AutoCRLFOutputStream(out, true);
149 		case TEXT_LF:
150 			return new AutoLFOutputStream(out, false);
151 		case AUTO_LF:
152 			return new AutoLFOutputStream(out, true);
153 		default:
154 			return out;
155 		}
156 	}
157 
158 	private static EolStreamType checkInStreamType(WorkingTreeOptions options,
159 			Attributes attrs) {
160 		if (attrs.isUnset("text")) {//$NON-NLS-1$
161 			// "binary" or "-text" (which is included in the binary expansion)
162 			return EolStreamType.DIRECT;
163 		}
164 
165 		// old git system
166 		if (attrs.isSet("crlf")) {//$NON-NLS-1$
167 			return EolStreamType.TEXT_LF;
168 		} else if (attrs.isUnset("crlf")) {//$NON-NLS-1$
169 			return EolStreamType.DIRECT;
170 		} else if ("input".equals(attrs.getValue("crlf"))) {//$NON-NLS-1$ //$NON-NLS-2$
171 			return EolStreamType.TEXT_LF;
172 		}
173 
174 		// new git system
175 		String eol = attrs.getValue("eol"); //$NON-NLS-1$
176 		if (eol != null)
177 			// check-in is always normalized to LF
178 			return EolStreamType.TEXT_LF;
179 
180 		if (attrs.isSet("text")) { //$NON-NLS-1$
181 			return EolStreamType.TEXT_LF;
182 		}
183 
184 		if ("auto".equals(attrs.getValue("text"))) { //$NON-NLS-1$ //$NON-NLS-2$
185 			return EolStreamType.AUTO_LF;
186 		}
187 
188 		switch (options.getAutoCRLF()) {
189 		case TRUE:
190 		case INPUT:
191 			return EolStreamType.AUTO_LF;
192 		case FALSE:
193 			return EolStreamType.DIRECT;
194 		}
195 
196 		return EolStreamType.DIRECT;
197 	}
198 
199 	private static EolStreamType checkOutStreamType(WorkingTreeOptions options,
200 			Attributes attrs) {
201 		if (attrs.isUnset("text")) {//$NON-NLS-1$
202 			// "binary" or "-text" (which is included in the binary expansion)
203 			return EolStreamType.DIRECT;
204 		}
205 
206 		// old git system
207 		if (attrs.isSet("crlf")) {//$NON-NLS-1$
208 			return FORCE_EOL_LF_ON_CHECKOUT ? EolStreamType.TEXT_LF
209 					: EolStreamType.DIRECT;
210 		} else if (attrs.isUnset("crlf")) {//$NON-NLS-1$
211 			return EolStreamType.DIRECT;
212 		} else if ("input".equals(attrs.getValue("crlf"))) {//$NON-NLS-1$ //$NON-NLS-2$
213 			return EolStreamType.DIRECT;
214 		}
215 
216 		// new git system
217 		String eol = attrs.getValue("eol"); //$NON-NLS-1$
218 		if (eol != null && "crlf".equals(eol)) //$NON-NLS-1$
219 			return EolStreamType.TEXT_CRLF;
220 		if (eol != null && "lf".equals(eol)) //$NON-NLS-1$
221 			return FORCE_EOL_LF_ON_CHECKOUT ? EolStreamType.TEXT_LF
222 					: EolStreamType.DIRECT;
223 
224 		if (attrs.isSet("text")) { //$NON-NLS-1$
225 			switch (options.getAutoCRLF()) {
226 			case TRUE:
227 				return EolStreamType.TEXT_CRLF;
228 			default:
229 				// no decision
230 			}
231 			switch (options.getEOL()) {
232 			case CRLF:
233 				return EolStreamType.TEXT_CRLF;
234 			case LF:
235 				return FORCE_EOL_LF_ON_CHECKOUT ? EolStreamType.TEXT_LF
236 						: EolStreamType.DIRECT;
237 			case NATIVE:
238 			default:
239 				return EolStreamType.DIRECT;
240 			}
241 		}
242 
243 		if ("auto".equals(attrs.getValue("text"))) { //$NON-NLS-1$ //$NON-NLS-2$
244 			switch (options.getAutoCRLF()) {
245 			case TRUE:
246 				return EolStreamType.AUTO_CRLF;
247 			default:
248 				// no decision
249 			}
250 			switch (options.getEOL()) {
251 			case CRLF:
252 				return EolStreamType.AUTO_CRLF;
253 			case LF:
254 				return FORCE_EOL_LF_ON_CHECKOUT ? EolStreamType.TEXT_LF
255 						: EolStreamType.DIRECT;
256 			case NATIVE:
257 			default:
258 				return EolStreamType.DIRECT;
259 			}
260 		}
261 
262 		switch (options.getAutoCRLF()) {
263 		case TRUE:
264 			return EolStreamType.AUTO_CRLF;
265 		default:
266 			// no decision
267 		}
268 
269 		return EolStreamType.DIRECT;
270 	}
271 
272 }