|
@@ -1,10 +1,13 @@ |
1 |
1 |
|
package com.esotericsoftware.scar; |
2 |
2 |
|
|
3 |
3 |
|
import java.io.*; |
|
4 |
+ |
import java.net.*; |
4 |
5 |
|
import java.nio.channels.*; |
5 |
6 |
|
import java.util.*; |
6 |
7 |
|
import java.util.regex.*; |
7 |
8 |
|
|
|
9 |
+ |
import javax.tools.*; |
|
10 |
+ |
|
8 |
11 |
|
import static com.esotericsoftware.minlog.Log.*; |
9 |
12 |
|
|
10 |
13 |
|
public class Utils |
|
@@ -14,60 +17,93 @@ |
14 |
17 |
|
* "scar.home" System property can be defined. |
15 |
18 |
|
*/ |
16 |
19 |
|
static public final String SCAR_HOME; |
17 |
|
- |
static { |
18 |
|
- |
if (System.getProperty("scar.home") != null) |
19 |
|
- |
SCAR_HOME = System.getProperty("scar.home"); |
|
20 |
+ |
|
|
21 |
+ |
static |
|
22 |
+ |
{ |
|
23 |
+ |
if ( System.getProperty( "scar.home" ) != null ) |
|
24 |
+ |
{ |
|
25 |
+ |
SCAR_HOME = System.getProperty( "scar.home" ); |
|
26 |
+ |
} |
20 |
27 |
|
else |
21 |
|
- |
SCAR_HOME = System.getenv("SCAR_HOME"); |
|
28 |
+ |
{ |
|
29 |
+ |
SCAR_HOME = System.getenv( "SCAR_HOME" ); |
|
30 |
+ |
} |
22 |
31 |
|
} |
23 |
32 |
|
|
24 |
33 |
|
/** |
25 |
34 |
|
* The Java installation directory. |
26 |
35 |
|
*/ |
27 |
|
- |
static public final String JAVA_HOME = System.getProperty("java.home"); |
|
36 |
+ |
static public final String JAVA_HOME = System.getProperty( "java.home" ); |
28 |
37 |
|
|
29 |
38 |
|
/** |
30 |
39 |
|
* True if running on a Mac OS. |
31 |
40 |
|
*/ |
32 |
|
- |
static public final boolean isMac = System.getProperty("os.name").toLowerCase().contains("mac os x"); |
|
41 |
+ |
static public final boolean isMac = System.getProperty( "os.name" ).toLowerCase().contains( "mac os x" ); |
33 |
42 |
|
|
34 |
43 |
|
/** |
35 |
44 |
|
* True if running on a Windows OS. |
36 |
45 |
|
*/ |
37 |
|
- |
static public final boolean isWindows = System.getProperty("os.name").toLowerCase().contains("windows"); |
|
46 |
+ |
static public final boolean isWindows = System.getProperty( "os.name" ).toLowerCase().contains( "windows" ); |
38 |
47 |
|
|
39 |
48 |
|
/** |
40 |
49 |
|
* Returns the full path for the specified file name in the current working directory, the {@link #SCAR_HOME}, and the bin |
41 |
50 |
|
* directory of {@link #JAVA_HOME}. |
42 |
51 |
|
*/ |
43 |
|
- |
static public String resolvePath (String fileName) { |
44 |
|
- |
if (fileName == null) return null; |
|
52 |
+ |
static public String resolvePath( String fileName ) |
|
53 |
+ |
{ |
|
54 |
+ |
if ( fileName == null ) |
|
55 |
+ |
{ |
|
56 |
+ |
return null; |
|
57 |
+ |
} |
45 |
58 |
|
|
46 |
59 |
|
String foundFile = lowLevelResolve( fileName ); |
47 |
|
- |
if (TRACE) trace("scar", "Path \"" + fileName + "\" resolved to: " + foundFile); |
|
60 |
+ |
if ( TRACE ) |
|
61 |
+ |
{ |
|
62 |
+ |
trace( "scar", "Path \"" + fileName + "\" resolved to: " + foundFile ); |
|
63 |
+ |
} |
48 |
64 |
|
return foundFile; |
49 |
65 |
|
} |
50 |
66 |
|
|
51 |
|
- |
private static String lowLevelResolve( String fileName ){ |
|
67 |
+ |
private static String lowLevelResolve( String fileName ) |
|
68 |
+ |
{ |
52 |
69 |
|
String foundFile; |
53 |
|
- |
if (fileExists(foundFile = canonical(fileName))) return foundFile; |
54 |
|
- |
if (fileExists(foundFile = new File(SCAR_HOME, fileName).getPath())) return foundFile; |
55 |
|
- |
if (fileExists(foundFile = new File(JAVA_HOME, "bin/" + fileName).getPath())) return foundFile; |
56 |
|
- |
return fileName; |
|
70 |
+ |
if ( fileExists( foundFile = canonical( fileName ) ) ) |
|
71 |
+ |
{ |
|
72 |
+ |
return foundFile; |
|
73 |
+ |
} |
|
74 |
+ |
if ( fileExists( foundFile = new File( SCAR_HOME, fileName ).getPath() ) ) |
|
75 |
+ |
{ |
|
76 |
+ |
return foundFile; |
|
77 |
+ |
} |
|
78 |
+ |
if ( fileExists( foundFile = new File( JAVA_HOME, "bin/" + fileName ).getPath() ) ) |
|
79 |
+ |
{ |
|
80 |
+ |
return foundFile; |
|
81 |
+ |
} |
|
82 |
+ |
return fileName; |
57 |
83 |
|
} |
58 |
84 |
|
|
59 |
85 |
|
/** |
60 |
86 |
|
* Returns the canonical path for the specified path. Eg, if "." is passed, this will resolve the actual path and return it. |
61 |
87 |
|
*/ |
62 |
|
- |
static public String canonical (String path) { |
63 |
|
- |
if (path == null) throw new IllegalArgumentException("path cannot be null."); |
|
88 |
+ |
static public String canonical( String path ) |
|
89 |
+ |
{ |
|
90 |
+ |
if ( path == null ) |
|
91 |
+ |
{ |
|
92 |
+ |
throw new IllegalArgumentException( "path cannot be null." ); |
|
93 |
+ |
} |
64 |
94 |
|
|
65 |
|
- |
File file = new File(path); |
66 |
|
- |
try { |
|
95 |
+ |
File file = new File( path ); |
|
96 |
+ |
try |
|
97 |
+ |
{ |
67 |
98 |
|
return file.getCanonicalPath(); |
68 |
|
- |
} catch (IOException ex) { |
|
99 |
+ |
} |
|
100 |
+ |
catch ( IOException ex ) |
|
101 |
+ |
{ |
69 |
102 |
|
file = file.getAbsoluteFile(); |
70 |
|
- |
if (file.getName().equals(".")) file = file.getParentFile(); |
|
103 |
+ |
if ( file.getName().equals( "." ) ) |
|
104 |
+ |
{ |
|
105 |
+ |
file = file.getParentFile(); |
|
106 |
+ |
} |
71 |
107 |
|
return file.getPath(); |
72 |
108 |
|
} |
73 |
109 |
|
} |
|
@@ -75,66 +111,107 @@ |
75 |
111 |
|
/** |
76 |
112 |
|
* Deletes a file or directory and all files and subdirecties under it. |
77 |
113 |
|
*/ |
78 |
|
- |
static public boolean delete (String fileName) { |
79 |
|
- |
if (fileName == null) throw new IllegalArgumentException("fileName cannot be null."); |
|
114 |
+ |
static public boolean delete( String fileName ) |
|
115 |
+ |
{ |
|
116 |
+ |
if ( fileName == null ) |
|
117 |
+ |
{ |
|
118 |
+ |
throw new IllegalArgumentException( "fileName cannot be null." ); |
|
119 |
+ |
} |
80 |
120 |
|
|
81 |
|
- |
File file = new File(fileName); |
|
121 |
+ |
File file = new File( fileName ); |
82 |
122 |
|
return !file.exists() || delete( file ); |
83 |
123 |
|
} |
84 |
124 |
|
|
85 |
|
- |
private static boolean delete(File file) { |
86 |
|
- |
if (file.isDirectory()) { |
|
125 |
+ |
private static boolean delete( File file ) |
|
126 |
+ |
{ |
|
127 |
+ |
if ( file.isDirectory() ) |
|
128 |
+ |
{ |
87 |
129 |
|
File[] files = file.listFiles(); |
88 |
130 |
|
for ( File aFile : files ) |
89 |
131 |
|
{ |
90 |
132 |
|
delete( aFile ); |
91 |
133 |
|
} |
92 |
134 |
|
} |
93 |
|
- |
if (TRACE) trace("scar", "Deleting file: " + file); |
|
135 |
+ |
if ( TRACE ) |
|
136 |
+ |
{ |
|
137 |
+ |
trace( "scar", "Deleting file: " + file ); |
|
138 |
+ |
} |
94 |
139 |
|
return file.delete(); |
95 |
140 |
|
} |
96 |
141 |
|
|
97 |
142 |
|
/** |
98 |
143 |
|
* Creates the directories in the specified path. |
99 |
144 |
|
*/ |
100 |
|
- |
static public String mkdir (String path) { |
101 |
|
- |
if (path == null) throw new IllegalArgumentException("path cannot be null."); |
|
145 |
+ |
static public String mkdir( String path ) |
|
146 |
+ |
{ |
|
147 |
+ |
if ( path == null ) |
|
148 |
+ |
{ |
|
149 |
+ |
throw new IllegalArgumentException( "path cannot be null." ); |
|
150 |
+ |
} |
102 |
151 |
|
|
103 |
|
- |
if (new File(path).mkdirs() && TRACE) trace("scar", "Created directory: " + path); |
|
152 |
+ |
if ( new File( path ).mkdirs() && TRACE ) |
|
153 |
+ |
{ |
|
154 |
+ |
trace( "scar", "Created directory: " + path ); |
|
155 |
+ |
} |
104 |
156 |
|
return path; |
105 |
157 |
|
} |
106 |
158 |
|
|
107 |
159 |
|
/** |
108 |
160 |
|
* Returns true if the file exists. |
109 |
161 |
|
*/ |
110 |
|
- |
static public boolean fileExists (String path) { |
111 |
|
- |
if (path == null) throw new IllegalArgumentException("path cannot be null."); |
|
162 |
+ |
static public boolean fileExists( String path ) |
|
163 |
+ |
{ |
|
164 |
+ |
if ( path == null ) |
|
165 |
+ |
{ |
|
166 |
+ |
throw new IllegalArgumentException( "path cannot be null." ); |
|
167 |
+ |
} |
112 |
168 |
|
|
113 |
|
- |
return new File(path).exists(); |
|
169 |
+ |
return new File( path ).exists(); |
114 |
170 |
|
} |
115 |
171 |
|
|
116 |
172 |
|
/** |
117 |
173 |
|
* Reads to the end of the input stream and writes the bytes to the output stream. |
118 |
174 |
|
*/ |
119 |
|
- |
static public void copyStream (InputStream input, OutputStream output) throws IOException { |
120 |
|
- |
if (input == null) throw new IllegalArgumentException("input cannot be null."); |
121 |
|
- |
if (output == null) throw new IllegalArgumentException("output cannot be null."); |
|
175 |
+ |
static public void copyStream( InputStream input, OutputStream output ) |
|
176 |
+ |
throws IOException |
|
177 |
+ |
{ |
|
178 |
+ |
if ( input == null ) |
|
179 |
+ |
{ |
|
180 |
+ |
throw new IllegalArgumentException( "input cannot be null." ); |
|
181 |
+ |
} |
|
182 |
+ |
if ( output == null ) |
|
183 |
+ |
{ |
|
184 |
+ |
throw new IllegalArgumentException( "output cannot be null." ); |
|
185 |
+ |
} |
122 |
186 |
|
|
123 |
|
- |
try { |
|
187 |
+ |
try |
|
188 |
+ |
{ |
124 |
189 |
|
byte[] buffer = new byte[4096]; |
125 |
|
- |
while (true) { |
126 |
|
- |
int length = input.read(buffer); |
127 |
|
- |
if (length == -1) break; |
128 |
|
- |
output.write(buffer, 0, length); |
|
190 |
+ |
while ( true ) |
|
191 |
+ |
{ |
|
192 |
+ |
int length = input.read( buffer ); |
|
193 |
+ |
if ( length == -1 ) |
|
194 |
+ |
{ |
|
195 |
+ |
break; |
|
196 |
+ |
} |
|
197 |
+ |
output.write( buffer, 0, length ); |
129 |
198 |
|
} |
130 |
|
- |
} finally { |
131 |
|
- |
try { |
|
199 |
+ |
} |
|
200 |
+ |
finally |
|
201 |
+ |
{ |
|
202 |
+ |
try |
|
203 |
+ |
{ |
132 |
204 |
|
output.close(); |
133 |
|
- |
} catch (Exception ignored) { |
134 |
205 |
|
} |
135 |
|
- |
try { |
|
206 |
+ |
catch ( Exception ignored ) |
|
207 |
+ |
{ |
|
208 |
+ |
} |
|
209 |
+ |
try |
|
210 |
+ |
{ |
136 |
211 |
|
input.close(); |
137 |
|
- |
} catch (Exception ignored) { |
|
212 |
+ |
} |
|
213 |
+ |
catch ( Exception ignored ) |
|
214 |
+ |
{ |
138 |
215 |
|
} |
139 |
216 |
|
} |
140 |
217 |
|
} |
|
@@ -142,26 +219,52 @@ |
142 |
219 |
|
/** |
143 |
220 |
|
* Copies a file, overwriting any existing file at the destination. |
144 |
221 |
|
*/ |
145 |
|
- |
static public String copyFile (String in, String out) throws IOException { |
146 |
|
- |
if (in == null) throw new IllegalArgumentException("in cannot be null."); |
147 |
|
- |
if (out == null) throw new IllegalArgumentException("out cannot be null."); |
|
222 |
+ |
static public String copyFile( String in, String out ) |
|
223 |
+ |
throws IOException |
|
224 |
+ |
{ |
|
225 |
+ |
if ( in == null ) |
|
226 |
+ |
{ |
|
227 |
+ |
throw new IllegalArgumentException( "in cannot be null." ); |
|
228 |
+ |
} |
|
229 |
+ |
if ( out == null ) |
|
230 |
+ |
{ |
|
231 |
+ |
throw new IllegalArgumentException( "out cannot be null." ); |
|
232 |
+ |
} |
148 |
233 |
|
|
149 |
|
- |
if (TRACE) trace("scar", "Copying file: " + in + " -> " + out); |
|
234 |
+ |
if ( TRACE ) |
|
235 |
+ |
{ |
|
236 |
+ |
trace( "scar", "Copying file: " + in + " -> " + out ); |
|
237 |
+ |
} |
150 |
238 |
|
|
151 |
239 |
|
FileChannel sourceChannel = null; |
152 |
240 |
|
FileChannel destinationChannel = null; |
153 |
|
- |
try { |
154 |
|
- |
sourceChannel = new FileInputStream(in).getChannel(); |
155 |
|
- |
destinationChannel = new FileOutputStream(out).getChannel(); |
156 |
|
- |
sourceChannel.transferTo(0, sourceChannel.size(), destinationChannel); |
157 |
|
- |
} finally { |
158 |
|
- |
try { |
159 |
|
- |
if (sourceChannel != null) sourceChannel.close(); |
160 |
|
- |
} catch (Exception ignored) { |
161 |
|
- |
} |
162 |
|
- |
try { |
163 |
|
- |
if (destinationChannel != null) destinationChannel.close(); |
164 |
|
- |
} catch (Exception ignored) { |
|
241 |
+ |
try |
|
242 |
+ |
{ |
|
243 |
+ |
sourceChannel = new FileInputStream( in ).getChannel(); |
|
244 |
+ |
destinationChannel = new FileOutputStream( out ).getChannel(); |
|
245 |
+ |
sourceChannel.transferTo( 0, sourceChannel.size(), destinationChannel ); |
|
246 |
+ |
} |
|
247 |
+ |
finally |
|
248 |
+ |
{ |
|
249 |
+ |
try |
|
250 |
+ |
{ |
|
251 |
+ |
if ( sourceChannel != null ) |
|
252 |
+ |
{ |
|
253 |
+ |
sourceChannel.close(); |
|
254 |
+ |
} |
|
255 |
+ |
} |
|
256 |
+ |
catch ( Exception ignored ) |
|
257 |
+ |
{ |
|
258 |
+ |
} |
|
259 |
+ |
try |
|
260 |
+ |
{ |
|
261 |
+ |
if ( destinationChannel != null ) |
|
262 |
+ |
{ |
|
263 |
+ |
destinationChannel.close(); |
|
264 |
+ |
} |
|
265 |
+ |
} |
|
266 |
+ |
catch ( Exception ignored ) |
|
267 |
+ |
{ |
165 |
268 |
|
} |
166 |
269 |
|
} |
167 |
270 |
|
return out; |
|
@@ -170,32 +273,52 @@ |
170 |
273 |
|
/** |
171 |
274 |
|
* Moves a file, overwriting any existing file at the destination. |
172 |
275 |
|
*/ |
173 |
|
- |
static public String moveFile (String in, String out) throws IOException { |
174 |
|
- |
if (in == null) throw new IllegalArgumentException("in cannot be null."); |
175 |
|
- |
if (out == null) throw new IllegalArgumentException("out cannot be null."); |
|
276 |
+ |
static public String moveFile( String in, String out ) |
|
277 |
+ |
throws IOException |
|
278 |
+ |
{ |
|
279 |
+ |
if ( in == null ) |
|
280 |
+ |
{ |
|
281 |
+ |
throw new IllegalArgumentException( "in cannot be null." ); |
|
282 |
+ |
} |
|
283 |
+ |
if ( out == null ) |
|
284 |
+ |
{ |
|
285 |
+ |
throw new IllegalArgumentException( "out cannot be null." ); |
|
286 |
+ |
} |
176 |
287 |
|
|
177 |
|
- |
copyFile(in, out); |
178 |
|
- |
delete(in); |
|
288 |
+ |
copyFile( in, out ); |
|
289 |
+ |
delete( in ); |
179 |
290 |
|
return out; |
180 |
291 |
|
} |
181 |
292 |
|
|
182 |
293 |
|
/** |
183 |
294 |
|
* Returns the textual contents of the specified file. |
184 |
295 |
|
*/ |
185 |
|
- |
static public String fileContents (String path) throws IOException { |
186 |
|
- |
StringBuilder stringBuffer = new StringBuilder(4096); |
187 |
|
- |
FileReader reader = new FileReader(path); |
188 |
|
- |
try { |
|
296 |
+ |
static public String fileContents( String path ) |
|
297 |
+ |
throws IOException |
|
298 |
+ |
{ |
|
299 |
+ |
StringBuilder stringBuffer = new StringBuilder( 4096 ); |
|
300 |
+ |
FileReader reader = new FileReader( path ); |
|
301 |
+ |
try |
|
302 |
+ |
{ |
189 |
303 |
|
char[] buffer = new char[2048]; |
190 |
|
- |
while (true) { |
191 |
|
- |
int length = reader.read(buffer); |
192 |
|
- |
if (length == -1) break; |
193 |
|
- |
stringBuffer.append(buffer, 0, length); |
|
304 |
+ |
while ( true ) |
|
305 |
+ |
{ |
|
306 |
+ |
int length = reader.read( buffer ); |
|
307 |
+ |
if ( length == -1 ) |
|
308 |
+ |
{ |
|
309 |
+ |
break; |
|
310 |
+ |
} |
|
311 |
+ |
stringBuffer.append( buffer, 0, length ); |
194 |
312 |
|
} |
195 |
|
- |
} finally { |
196 |
|
- |
try { |
|
313 |
+ |
} |
|
314 |
+ |
finally |
|
315 |
+ |
{ |
|
316 |
+ |
try |
|
317 |
+ |
{ |
197 |
318 |
|
reader.close(); |
198 |
|
- |
} catch (Exception ignored) { |
|
319 |
+ |
} |
|
320 |
+ |
catch ( Exception ignored ) |
|
321 |
+ |
{ |
199 |
322 |
|
} |
200 |
323 |
|
} |
201 |
324 |
|
return stringBuffer.toString(); |
|
@@ -204,167 +327,350 @@ |
204 |
327 |
|
/** |
205 |
328 |
|
* Returns only the filename portion of the specified path. |
206 |
329 |
|
*/ |
207 |
|
- |
static public String fileName (String path) { |
208 |
|
- |
return new File(canonical(path)).getName(); |
|
330 |
+ |
static public String fileName( String path ) |
|
331 |
+ |
{ |
|
332 |
+ |
return new File( canonical( path ) ).getName(); |
209 |
333 |
|
} |
210 |
334 |
|
|
211 |
335 |
|
/** |
212 |
336 |
|
* Returns the parent directory of the specified path. |
213 |
337 |
|
*/ |
214 |
|
- |
static public String parent (String path) { |
215 |
|
- |
return new File(canonical(path)).getParent(); |
|
338 |
+ |
static public String parent( String path ) |
|
339 |
+ |
{ |
|
340 |
+ |
return new File( canonical( path ) ).getParent(); |
216 |
341 |
|
} |
217 |
342 |
|
|
218 |
343 |
|
/** |
219 |
344 |
|
* Returns only the extension portion of the specified path, or an empty string if there is no extension. |
220 |
345 |
|
*/ |
221 |
|
- |
static public String fileExtension (String file) { |
222 |
|
- |
if (file == null) throw new IllegalArgumentException("fileName cannot be null."); |
|
346 |
+ |
static public String fileExtension( String file ) |
|
347 |
+ |
{ |
|
348 |
+ |
if ( file == null ) |
|
349 |
+ |
{ |
|
350 |
+ |
throw new IllegalArgumentException( "fileName cannot be null." ); |
|
351 |
+ |
} |
223 |
352 |
|
|
224 |
353 |
|
int commaIndex = file.indexOf( '.' ); |
225 |
|
- |
if (commaIndex == -1) return ""; |
226 |
|
- |
return file.substring(commaIndex + 1); |
|
354 |
+ |
if ( commaIndex == -1 ) |
|
355 |
+ |
{ |
|
356 |
+ |
return ""; |
|
357 |
+ |
} |
|
358 |
+ |
return file.substring( commaIndex + 1 ); |
227 |
359 |
|
} |
228 |
360 |
|
|
229 |
361 |
|
/** |
230 |
362 |
|
* Returns only the filename portion of the specified path, without the extension, if any. |
231 |
363 |
|
*/ |
232 |
|
- |
static public String fileWithoutExtension (String file) { |
233 |
|
- |
if (file == null) throw new IllegalArgumentException("fileName cannot be null."); |
|
364 |
+ |
static public String fileWithoutExtension( String file ) |
|
365 |
+ |
{ |
|
366 |
+ |
if ( file == null ) |
|
367 |
+ |
{ |
|
368 |
+ |
throw new IllegalArgumentException( "fileName cannot be null." ); |
|
369 |
+ |
} |
234 |
370 |
|
|
235 |
|
- |
int commaIndex = file.indexOf('.'); |
236 |
|
- |
if (commaIndex == -1) commaIndex = file.length(); |
237 |
|
- |
int slashIndex = file.replace('\\', '/').lastIndexOf('/'); |
238 |
|
- |
if (slashIndex == -1) |
|
371 |
+ |
int commaIndex = file.indexOf( '.' ); |
|
372 |
+ |
if ( commaIndex == -1 ) |
|
373 |
+ |
{ |
|
374 |
+ |
commaIndex = file.length(); |
|
375 |
+ |
} |
|
376 |
+ |
int slashIndex = file.replace( '\\', '/' ).lastIndexOf( '/' ); |
|
377 |
+ |
if ( slashIndex == -1 ) |
|
378 |
+ |
{ |
239 |
379 |
|
slashIndex = 0; |
|
380 |
+ |
} |
240 |
381 |
|
else |
|
382 |
+ |
{ |
241 |
383 |
|
slashIndex++; |
242 |
|
- |
return file.substring(slashIndex, commaIndex); |
|
384 |
+ |
} |
|
385 |
+ |
return file.substring( slashIndex, commaIndex ); |
243 |
386 |
|
} |
244 |
387 |
|
|
245 |
388 |
|
/** |
246 |
389 |
|
* Returns a substring of the specified text. |
|
390 |
+ |
* |
247 |
391 |
|
* @param end The end index of the substring. If negative, the index used will be "text.length() + end". |
248 |
392 |
|
*/ |
249 |
|
- |
static public String substring (String text, int start, int end) { |
250 |
|
- |
if (text == null) throw new IllegalArgumentException("text cannot be null."); |
|
393 |
+ |
static public String substring( String text, int start, int end ) |
|
394 |
+ |
{ |
|
395 |
+ |
if ( text == null ) |
|
396 |
+ |
{ |
|
397 |
+ |
throw new IllegalArgumentException( "text cannot be null." ); |
|
398 |
+ |
} |
251 |
399 |
|
|
252 |
|
- |
if (end >= 0) return text.substring(start, end); |
253 |
|
- |
return text.substring(start, text.length() + end); |
|
400 |
+ |
if ( end >= 0 ) |
|
401 |
+ |
{ |
|
402 |
+ |
return text.substring( start, end ); |
|
403 |
+ |
} |
|
404 |
+ |
return text.substring( start, text.length() + end ); |
254 |
405 |
|
} |
255 |
406 |
|
|
256 |
407 |
|
/** |
257 |
408 |
|
* Splits the specified command at spaces that are not surrounded by quotes and passes the result to {@link #shell(String...)}. |
258 |
409 |
|
*/ |
259 |
|
- |
static public void shell (String command) throws IOException { |
|
410 |
+ |
static public void shell( String command ) |
|
411 |
+ |
throws IOException |
|
412 |
+ |
{ |
260 |
413 |
|
List<String> matchList = new ArrayList<String>(); |
261 |
|
- |
Pattern regex = Pattern.compile("[^\\s\"']+|\"([^\"]*)\"|'([^']*)'"); |
262 |
|
- |
Matcher regexMatcher = regex.matcher(command); |
263 |
|
- |
while (regexMatcher.find()) { |
264 |
|
- |
if (regexMatcher.group(1) != null) |
265 |
|
- |
matchList.add(regexMatcher.group(1)); |
266 |
|
- |
else if (regexMatcher.group(2) != null) |
267 |
|
- |
matchList.add(regexMatcher.group(2)); |
|
414 |
+ |
Pattern regex = Pattern.compile( "[^\\s\"']+|\"([^\"]*)\"|'([^']*)'" ); |
|
415 |
+ |
Matcher regexMatcher = regex.matcher( command ); |
|
416 |
+ |
while ( regexMatcher.find() ) |
|
417 |
+ |
{ |
|
418 |
+ |
if ( regexMatcher.group( 1 ) != null ) |
|
419 |
+ |
{ |
|
420 |
+ |
matchList.add( regexMatcher.group( 1 ) ); |
|
421 |
+ |
} |
|
422 |
+ |
else if ( regexMatcher.group( 2 ) != null ) |
|
423 |
+ |
{ |
|
424 |
+ |
matchList.add( regexMatcher.group( 2 ) ); |
|
425 |
+ |
} |
268 |
426 |
|
else |
269 |
|
- |
matchList.add(regexMatcher.group()); |
|
427 |
+ |
{ |
|
428 |
+ |
matchList.add( regexMatcher.group() ); |
|
429 |
+ |
} |
270 |
430 |
|
} |
271 |
|
- |
shell(matchList.toArray(new String[matchList.size()])); |
|
431 |
+ |
shell( matchList.toArray( new String[matchList.size()] ) ); |
272 |
432 |
|
} |
273 |
433 |
|
|
274 |
434 |
|
/** |
275 |
435 |
|
* Executes the specified shell command. {@link #resolvePath(String)} is used to locate the file to execute. If not found, on |
276 |
436 |
|
* Windows the same filename with an "exe" extension is also tried. |
277 |
437 |
|
*/ |
278 |
|
- |
static public void shell (String... command) throws IOException { |
279 |
|
- |
if (command == null) throw new IllegalArgumentException("command cannot be null."); |
280 |
|
- |
if (command.length == 0) throw new IllegalArgumentException("command cannot be empty."); |
|
438 |
+ |
static public void shell( String... command ) |
|
439 |
+ |
throws IOException |
|
440 |
+ |
{ |
|
441 |
+ |
if ( command == null ) |
|
442 |
+ |
{ |
|
443 |
+ |
throw new IllegalArgumentException( "command cannot be null." ); |
|
444 |
+ |
} |
|
445 |
+ |
if ( command.length == 0 ) |
|
446 |
+ |
{ |
|
447 |
+ |
throw new IllegalArgumentException( "command cannot be empty." ); |
|
448 |
+ |
} |
281 |
449 |
|
|
282 |
450 |
|
String originalCommand = command[0]; |
283 |
|
- |
command[0] = resolvePath(command[0]); |
284 |
|
- |
if (!fileExists(command[0]) && isWindows) { |
285 |
|
- |
command[0] = resolvePath(command[0] + ".exe"); |
286 |
|
- |
if (!fileExists(command[0])) command[0] = originalCommand; |
|
451 |
+ |
command[0] = resolvePath( command[0] ); |
|
452 |
+ |
if ( !fileExists( command[0] ) && isWindows ) |
|
453 |
+ |
{ |
|
454 |
+ |
command[0] = resolvePath( command[0] + ".exe" ); |
|
455 |
+ |
if ( !fileExists( command[0] ) ) |
|
456 |
+ |
{ |
|
457 |
+ |
command[0] = originalCommand; |
|
458 |
+ |
} |
287 |
459 |
|
} |
288 |
460 |
|
|
289 |
|
- |
if (TRACE) { |
290 |
|
- |
StringBuilder buffer = new StringBuilder(256); |
291 |
|
- |
for (String text : command) { |
292 |
|
- |
buffer.append(text); |
293 |
|
- |
buffer.append(' '); |
|
461 |
+ |
if ( TRACE ) |
|
462 |
+ |
{ |
|
463 |
+ |
StringBuilder buffer = new StringBuilder( 256 ); |
|
464 |
+ |
for ( String text : command ) |
|
465 |
+ |
{ |
|
466 |
+ |
buffer.append( text ); |
|
467 |
+ |
buffer.append( ' ' ); |
294 |
468 |
|
} |
295 |
|
- |
trace("scar", "Executing command: " + buffer); |
|
469 |
+ |
trace( "scar", "Executing command: " + buffer ); |
296 |
470 |
|
} |
297 |
471 |
|
|
298 |
|
- |
Process process = new ProcessBuilder(command).start(); |
|
472 |
+ |
Process process = new ProcessBuilder( command ).start(); |
299 |
473 |
|
// try { |
300 |
474 |
|
// process.waitFor(); |
301 |
475 |
|
// } catch (InterruptedException ignored) { |
302 |
476 |
|
// } |
303 |
|
- |
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); |
304 |
|
- |
while (true) { |
|
477 |
+ |
BufferedReader reader = new BufferedReader( new InputStreamReader( process.getInputStream() ) ); |
|
478 |
+ |
while ( true ) |
|
479 |
+ |
{ |
305 |
480 |
|
String line = reader.readLine(); |
306 |
|
- |
if (line == null) break; |
307 |
|
- |
System.out.println(line); |
|
481 |
+ |
if ( line == null ) |
|
482 |
+ |
{ |
|
483 |
+ |
break; |
|
484 |
+ |
} |
|
485 |
+ |
System.out.println( line ); |
308 |
486 |
|
} |
309 |
487 |
|
reader.close(); |
310 |
|
- |
reader = new BufferedReader(new InputStreamReader(process.getErrorStream())); |
311 |
|
- |
while (true) { |
|
488 |
+ |
reader = new BufferedReader( new InputStreamReader( process.getErrorStream() ) ); |
|
489 |
+ |
while ( true ) |
|
490 |
+ |
{ |
312 |
491 |
|
String line = reader.readLine(); |
313 |
|
- |
if (line == null) break; |
314 |
|
- |
System.out.println(line); |
|
492 |
+ |
if ( line == null ) |
|
493 |
+ |
{ |
|
494 |
+ |
break; |
|
495 |
+ |
} |
|
496 |
+ |
System.out.println( line ); |
315 |
497 |
|
} |
316 |
|
- |
if (process.exitValue() != 0) { |
317 |
|
- |
StringBuilder buffer = new StringBuilder(256); |
318 |
|
- |
for (String text : command) { |
319 |
|
- |
buffer.append(text); |
320 |
|
- |
buffer.append(' '); |
|
498 |
+ |
if ( process.exitValue() != 0 ) |
|
499 |
+ |
{ |
|
500 |
+ |
StringBuilder buffer = new StringBuilder( 256 ); |
|
501 |
+ |
for ( String text : command ) |
|
502 |
+ |
{ |
|
503 |
+ |
buffer.append( text ); |
|
504 |
+ |
buffer.append( ' ' ); |
321 |
505 |
|
} |
322 |
|
- |
throw new RuntimeException("Error executing command: " + buffer); |
|
506 |
+ |
throw new RuntimeException( "Error executing command: " + buffer ); |
323 |
507 |
|
} |
324 |
508 |
|
} |
325 |
509 |
|
|
326 |
510 |
|
/** |
327 |
511 |
|
* Creates a new keystore for signing JARs. If the keystore file already exists, no action will be taken. |
|
512 |
+ |
* |
328 |
513 |
|
* @return The path to the keystore file. |
329 |
514 |
|
*/ |
330 |
|
- |
static public String keystore (String keystoreFile, String alias, String password, String company, String title) |
331 |
|
- |
throws IOException { |
332 |
|
- |
if (keystoreFile == null) throw new IllegalArgumentException("keystoreFile cannot be null."); |
333 |
|
- |
if (fileExists(keystoreFile)) return keystoreFile; |
334 |
|
- |
if (alias == null) throw new IllegalArgumentException("alias cannot be null."); |
335 |
|
- |
if (password == null) throw new IllegalArgumentException("password cannot be null."); |
336 |
|
- |
if (password.length() < 6) throw new IllegalArgumentException("password must be 6 or more characters."); |
337 |
|
- |
if (company == null) throw new IllegalArgumentException("company cannot be null."); |
338 |
|
- |
if (title == null) throw new IllegalArgumentException("title cannot be null."); |
|
515 |
+ |
static public String keystore( String keystoreFile, String alias, String password, String company, String title ) |
|
516 |
+ |
throws IOException |
|
517 |
+ |
{ |
|
518 |
+ |
if ( keystoreFile == null ) |
|
519 |
+ |
{ |
|
520 |
+ |
throw new IllegalArgumentException( "keystoreFile cannot be null." ); |
|
521 |
+ |
} |
|
522 |
+ |
if ( fileExists( keystoreFile ) ) |
|
523 |
+ |
{ |
|
524 |
+ |
return keystoreFile; |
|
525 |
+ |
} |
|
526 |
+ |
if ( alias == null ) |
|
527 |
+ |
{ |
|
528 |
+ |
throw new IllegalArgumentException( "alias cannot be null." ); |
|
529 |
+ |
} |
|
530 |
+ |
if ( password == null ) |
|
531 |
+ |
{ |
|
532 |
+ |
throw new IllegalArgumentException( "password cannot be null." ); |
|
533 |
+ |
} |
|
534 |
+ |
if ( password.length() < 6 ) |
|
535 |
+ |
{ |
|
536 |
+ |
throw new IllegalArgumentException( "password must be 6 or more characters." ); |
|
537 |
+ |
} |
|
538 |
+ |
if ( company == null ) |
|
539 |
+ |
{ |
|
540 |
+ |
throw new IllegalArgumentException( "company cannot be null." ); |
|
541 |
+ |
} |
|
542 |
+ |
if ( title == null ) |
|
543 |
+ |
{ |
|
544 |
+ |
throw new IllegalArgumentException( "title cannot be null." ); |
|
545 |
+ |
} |
339 |
546 |
|
|
340 |
|
- |
if (DEBUG) |
341 |
|
- |
debug("scar", "Creating keystore (" + alias + ":" + password + ", " + company + ", " + title + "): " + keystoreFile); |
|
547 |
+ |
if ( DEBUG ) |
|
548 |
+ |
{ |
|
549 |
+ |
debug( "scar", "Creating keystore (" + alias + ":" + password + ", " + company + ", " + title + "): " + keystoreFile ); |
|
550 |
+ |
} |
342 |
551 |
|
|
343 |
|
- |
File file = new File(keystoreFile); |
|
552 |
+ |
File file = new File( keystoreFile ); |
344 |
553 |
|
file.delete(); |
345 |
|
- |
Process process = Runtime.getRuntime().exec( |
346 |
|
- |
new String[] {resolvePath("keytool"), "-genkey", "-keystore", keystoreFile, "-alias", alias}); |
347 |
|
- |
OutputStreamWriter writer = new OutputStreamWriter(process.getOutputStream()); |
348 |
|
- |
writer.write(password + "\n"); // Enter keystore password: |
349 |
|
- |
writer.write(password + "\n"); // Re-enter new password: |
350 |
|
- |
writer.write(company + "\n"); // What is your first and last name? |
351 |
|
- |
writer.write(title + "\n"); // What is the name of your organizational unit? |
352 |
|
- |
writer.write(title + "\n"); // What is the name of your organization? |
353 |
|
- |
writer.write("\n"); // What is the name of your City or Locality? [Unknown] |
354 |
|
- |
writer.write("\n"); // What is the name of your State or Province? [Unknown] |
355 |
|
- |
writer.write("\n"); // What is the two-letter country code for this unit? [Unknown] |
356 |
|
- |
writer.write("yes\n"); // Correct? |
357 |
|
- |
writer.write("\n"); // Return if same alias key password as keystore. |
|
554 |
+ |
Process process = Runtime.getRuntime().exec( new String[]{resolvePath( "keytool" ), "-genkey", "-keystore", keystoreFile, "-alias", alias} ); |
|
555 |
+ |
OutputStreamWriter writer = new OutputStreamWriter( process.getOutputStream() ); |
|
556 |
+ |
writer.write( password + "\n" ); // Enter keystore password: |
|
557 |
+ |
writer.write( password + "\n" ); // Re-enter new password: |
|
558 |
+ |
writer.write( company + "\n" ); // What is your first and last name? |
|
559 |
+ |
writer.write( title + "\n" ); // What is the name of your organizational unit? |
|
560 |
+ |
writer.write( title + "\n" ); // What is the name of your organization? |
|
561 |
+ |
writer.write( "\n" ); // What is the name of your City or Locality? [Unknown] |
|
562 |
+ |
writer.write( "\n" ); // What is the name of your State or Province? [Unknown] |
|
563 |
+ |
writer.write( "\n" ); // What is the two-letter country code for this unit? [Unknown] |
|
564 |
+ |
writer.write( "yes\n" ); // Correct? |
|
565 |
+ |
writer.write( "\n" ); // Return if same alias key password as keystore. |
358 |
566 |
|
writer.flush(); |
359 |
567 |
|
process.getOutputStream().close(); |
360 |
568 |
|
process.getInputStream().close(); |
361 |
569 |
|
process.getErrorStream().close(); |
362 |
|
- |
try { |
|
570 |
+ |
try |
|
571 |
+ |
{ |
363 |
572 |
|
process.waitFor(); |
364 |
|
- |
} catch (InterruptedException ignored) { |
365 |
573 |
|
} |
366 |
|
- |
if (!file.exists()) throw new RuntimeException("Error creating keystore."); |
|
574 |
+ |
catch ( InterruptedException ignored ) |
|
575 |
+ |
{ |
|
576 |
+ |
} |
|
577 |
+ |
if ( !file.exists() ) |
|
578 |
+ |
{ |
|
579 |
+ |
throw new RuntimeException( "Error creating keystore." ); |
|
580 |
+ |
} |
367 |
581 |
|
return keystoreFile; |
368 |
582 |
|
} |
369 |
583 |
|
|
|
584 |
+ |
public static Class compileDynamicCodeToClass( int pOverheadStartLines, final String pCode, final URL... pClasspathURLs ) |
|
585 |
+ |
throws ClassNotFoundException |
|
586 |
+ |
{ |
|
587 |
+ |
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); |
|
588 |
+ |
if ( compiler == null ) |
|
589 |
+ |
{ |
|
590 |
+ |
throw new RuntimeException( "No compiler available. Ensure you are running from a 1.6+ JDK, and not a JRE." ); |
|
591 |
+ |
} |
|
592 |
+ |
|
|
593 |
+ |
final ByteArrayOutputStream output = new ByteArrayOutputStream( 32 * 1024 ); |
|
594 |
+ |
final SimpleJavaFileObject javaObject = new SimpleJavaFileObject( URI.create( "Generated.java" ), JavaFileObject.Kind.SOURCE ) |
|
595 |
+ |
{ |
|
596 |
+ |
@Override |
|
597 |
+ |
public OutputStream openOutputStream() |
|
598 |
+ |
{ |
|
599 |
+ |
return output; |
|
600 |
+ |
} |
|
601 |
+ |
|
|
602 |
+ |
@Override |
|
603 |
+ |
public CharSequence getCharContent( boolean ignoreEncodingErrors ) |
|
604 |
+ |
{ |
|
605 |
+ |
return pCode; |
|
606 |
+ |
} |
|
607 |
+ |
}; |
|
608 |
+ |
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>(); |
|
609 |
+ |
//noinspection unchecked |
|
610 |
+ |
compiler.getTask( null, new ForwardingJavaFileManager( compiler.getStandardFileManager( null, null, null ) ) |
|
611 |
+ |
{ |
|
612 |
+ |
@Override |
|
613 |
+ |
public JavaFileObject getJavaFileForOutput( Location location, String className, JavaFileObject.Kind kind, FileObject sibling ) |
|
614 |
+ |
{ |
|
615 |
+ |
return javaObject; |
|
616 |
+ |
} |
|
617 |
+ |
}, diagnostics, null, null, Arrays.asList( javaObject ) ).call(); |
|
618 |
+ |
|
|
619 |
+ |
if ( !diagnostics.getDiagnostics().isEmpty() ) |
|
620 |
+ |
{ |
|
621 |
+ |
StringBuilder buffer = new StringBuilder( 1024 ); |
|
622 |
+ |
for ( Diagnostic diagnostic : diagnostics.getDiagnostics() ) |
|
623 |
+ |
{ |
|
624 |
+ |
if ( buffer.length() > 0 ) |
|
625 |
+ |
{ |
|
626 |
+ |
buffer.append( "\n" ); |
|
627 |
+ |
} |
|
628 |
+ |
buffer.append( "Line " ); |
|
629 |
+ |
buffer.append( diagnostic.getLineNumber() - pOverheadStartLines ); |
|
630 |
+ |
buffer.append( ": " ); |
|
631 |
+ |
buffer.append( diagnostic.getMessage( null ).replaceAll( "^Generated.java:\\d+:\\d* ", "" ) ); |
|
632 |
+ |
} |
|
633 |
+ |
throw new RuntimeException( "Compilation errors:\n" + buffer ); |
|
634 |
+ |
} |
|
635 |
+ |
|
|
636 |
+ |
// Load class. |
|
637 |
+ |
return new URLClassLoader( pClasspathURLs, Scar.class.getClassLoader() ) |
|
638 |
+ |
{ |
|
639 |
+ |
@Override |
|
640 |
+ |
protected synchronized Class<?> loadClass( String name, boolean resolve ) |
|
641 |
+ |
throws ClassNotFoundException |
|
642 |
+ |
{ |
|
643 |
+ |
// Look in this classloader before the parent. |
|
644 |
+ |
Class c = findLoadedClass( name ); |
|
645 |
+ |
if ( c == null ) |
|
646 |
+ |
{ |
|
647 |
+ |
try |
|
648 |
+ |
{ |
|
649 |
+ |
c = findClass( name ); |
|
650 |
+ |
} |
|
651 |
+ |
catch ( ClassNotFoundException e ) |
|
652 |
+ |
{ |
|
653 |
+ |
return super.loadClass( name, resolve ); |
|
654 |
+ |
} |
|
655 |
+ |
} |
|
656 |
+ |
if ( resolve ) |
|
657 |
+ |
{ |
|
658 |
+ |
resolveClass( c ); |
|
659 |
+ |
} |
|
660 |
+ |
return c; |
|
661 |
+ |
} |
|
662 |
+ |
|
|
663 |
+ |
@Override |
|
664 |
+ |
protected Class<?> findClass( String name ) |
|
665 |
+ |
throws ClassNotFoundException |
|
666 |
+ |
{ |
|
667 |
+ |
if ( name.equals( "Generated" ) ) |
|
668 |
+ |
{ |
|
669 |
+ |
byte[] bytes = output.toByteArray(); |
|
670 |
+ |
return defineClass( name, bytes, 0, bytes.length ); |
|
671 |
+ |
} |
|
672 |
+ |
return super.findClass( name ); |
|
673 |
+ |
} |
|
674 |
+ |
}.loadClass( "Generated" ); |
|
675 |
+ |
} |
370 |
676 |
|
} |