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
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
179 String line = removeRoot ? currentLine : currentLine.replace('\\', '/');
180
181
182
183 final String octetStream = " - application/octet-stream";
184
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 }