View Javadoc

1   package net.sf.statsvn.util;
2   
3   import java.io.IOException;
4   import java.io.InputStreamReader;
5   import java.util.ArrayList;
6   import java.util.List;
7   
8   import net.sf.statcvs.util.LookaheadReader;
9   import net.sf.statsvn.output.SvnConfigurationOptions;
10  
11  /**
12   * Utilities class that manages calls to svn propget. Used to find binary files.
13   * 
14   * @author Jason Kealey <jkealey@shade.ca>
15   * 
16   * @version $Id: SvnPropgetUtils.java 283 2007-02-19 09:28:35Z benoitx $
17   */
18  public final class SvnPropgetUtils {
19  
20  	private static List binaryFiles;
21  
22  	/**
23  	 * A utility class (only static methods) should be final and have a private
24  	 * constructor.
25  	 */
26  	private SvnPropgetUtils() {
27  	}
28  
29  	/**
30  	 * Get the svn:mime-types for all files, latest revision.
31  	 * 
32  	 * @return the inputstream from which to read the information.
33  	 */
34  	private static synchronized ProcessUtils getFileMimeTypes() {
35  		return getFileMimeTypes(null, null);
36  	}
37  
38  	/**
39  	 * Get the svn:mime-type for a certain file (leave null for all files).
40  	 * 
41  	 * @param revision
42  	 *            revision for which to query;
43  	 * @param filename
44  	 *            the filename (or null for all files)
45  	 * @return the inputstream from which to read the information.
46  	 */
47  	protected static synchronized ProcessUtils getFileMimeTypes(final String revision, final String filename) {
48  		String svnPropgetCommand = "svn propget svn:mime-type";
49  		if (revision != null && revision.length() > 0) {
50  			svnPropgetCommand += " -r " + revision;
51  		}
52  
53  		if (filename != null && filename.length() > 0) {
54  			svnPropgetCommand += " " + SvnInfoUtils.replace(" ", "%20", SvnInfoUtils.relativePathToUrl(filename));
55  
56  			if (revision != null && revision.length() > 0) {
57  				svnPropgetCommand += "@" + revision;
58  			}
59  		} else {
60  			svnPropgetCommand += " -R ";
61  		}
62  
63  		svnPropgetCommand += SvnCommandHelper.getAuthString();
64  
65  		try {
66  			return ProcessUtils.call(svnPropgetCommand);
67  		} catch (final Exception e) {
68  			SvnConfigurationOptions.getTaskLogger().info(e.toString());
69  			return null;
70  		}
71  	}
72  
73  	/**
74  	 * Returns the list of binary files in the working directory.
75  	 * 
76  	 * @return the list of binary files
77  	 */
78  	public static List getBinaryFiles() {
79  		if (binaryFiles == null) {
80  			ProcessUtils pUtils = null;
81  			try {
82  				pUtils = getFileMimeTypes();
83  				loadBinaryFiles(pUtils);
84  			} finally {
85  				if (pUtils != null) {
86  					try {
87  						pUtils.close();
88  					} catch (final IOException e) {
89  						SvnConfigurationOptions.getTaskLogger().info(e.toString());
90  					}
91  				}
92  			}
93  		}
94  
95  		return binaryFiles;
96  	}
97  
98  	/**
99  	 * Loads the list of binary files from the input stream equivalent to an svn
100 	 * propget command.
101 	 * 
102 	 * @param stream
103 	 *            stream equivalent to an svn propget command
104 	 */
105 	public static void loadBinaryFiles(final ProcessUtils pUtils) {
106 		// public for tests
107 		binaryFiles = new ArrayList();
108 		final LookaheadReader mimeReader = new LookaheadReader(new InputStreamReader(pUtils.getInputStream()));
109 		try {
110 			while (mimeReader.hasNextLine()) {
111 				mimeReader.nextLine();
112 				final String file = getBinaryFilename(mimeReader.getCurrentLine(), false);
113 				if (file != null) {
114 					binaryFiles.add(file);
115 				}
116 			}
117 			if (pUtils.hasErrorOccured()) {
118 				throw new IOException(pUtils.getErrorMessage());
119 			}
120 		} catch (final IOException e) {
121 			SvnConfigurationOptions.getTaskLogger().info(e.getMessage());
122 		}
123 	}
124 
125 	/**
126 	 * It was first thought that a the mime-type of a file's previous revision
127 	 * could be found. This is not the case. Leave revision null until future
128 	 * upgrade of svn propget command line.
129 	 * 
130 	 * @param revision
131 	 *            the revision to query
132 	 * @param filename
133 	 *            the filename
134 	 * @return if that version of a file is binary
135 	 */
136 	public static boolean isBinaryFile(final String revision, final String filename) {
137 		ProcessUtils pUtils = null;
138 		try {
139 			pUtils = getFileMimeTypes(revision, filename);
140 			final LookaheadReader mimeReader = new LookaheadReader(new InputStreamReader(pUtils.getInputStream()));
141 			while (mimeReader.hasNextLine()) {
142 				mimeReader.nextLine();
143 				final String file = getBinaryFilename(mimeReader.getCurrentLine(), true);
144 				if (file != null && file.equals(filename)) {
145 					return true;
146 				}
147 			}
148 		} catch (final IOException e) {
149 			SvnConfigurationOptions.getTaskLogger().info(e.toString());
150 		} finally {
151 			if (pUtils != null) {
152 				try {
153 					pUtils.close();
154 				} catch (final IOException e) {
155 					SvnConfigurationOptions.getTaskLogger().info(e.toString());
156 				}
157 			}
158 		}
159 
160 		return false;
161 	}
162 
163 	/**
164 	 * Given a string such as: "lib\junit.jar - application/octet-stream" or
165 	 * "svn:\\host\repo\lib\junit.jar - application/octet-stream" will return
166 	 * the filename if the mime type is binary (doesn't end with text/*)
167 	 * 
168 	 * Will return the filename with / was a directory seperator.
169 	 * 
170 	 * @param currentLine
171 	 *            the line obtained from svn propget svn:mime-type
172 	 * @param removeRoot
173 	 *            if true, will remove any repository prefix
174 	 * @return should return lib\junit.jar in both cases, given that
175 	 *         removeRoot==true in the second case.
176 	 */
177 	private static String getBinaryFilename(final String currentLine, final boolean removeRoot) {
178 		// want to make sure we only have / in end result.
179 		String line = removeRoot ? currentLine : currentLine.replace('\\', '/');
180 
181 		// HACK: See bug 18. if removeRoot==true, no - will be found because we
182 		// are calling for one specific file.
183 		final String octetStream = " - application/octet-stream";
184 		// if is common binary file or identified as something other than text
185 		if (line.endsWith(octetStream) || line.lastIndexOf(" - text/") < 0 && line.lastIndexOf(" - text/") == line.lastIndexOf(" - ")
186 		        && line.lastIndexOf(" - ") >= 0) {
187 			line = line.substring(0, line.lastIndexOf(" - "));
188 			if (removeRoot) {
189 				line = SvnInfoUtils.urlToRelativePath(line);
190 			}
191 			return line;
192 		}
193 
194 		return null;
195 	}
196 
197 }