|
@@ -1,1536 +1,1536 @@ |
1 |
|
- |
package com.esotericsoftware.scar; |
2 |
|
- |
|
3 |
|
- |
import org.litesoft.logger.*; |
4 |
|
- |
import org.litesoft.logger.nonpublic.*; |
5 |
|
- |
|
6 |
|
- |
import SevenZip.*; |
7 |
|
- |
import com.esotericsoftware.filesystem.*; |
8 |
|
- |
import com.esotericsoftware.scar.support.*; |
9 |
|
- |
import com.esotericsoftware.utils.*; |
10 |
|
- |
import com.esotericsoftware.yamlbeans.*; |
11 |
|
- |
import com.esotericsoftware.yamlbeans.parser.*; |
12 |
|
- |
import com.esotericsoftware.yamlbeans.tokenizer.*; |
13 |
|
- |
|
14 |
|
- |
import java.io.*; |
15 |
|
- |
import java.lang.reflect.*; |
16 |
|
- |
import java.net.*; |
17 |
|
- |
import java.util.*; |
18 |
|
- |
import java.util.Map.*; |
19 |
|
- |
import java.util.jar.*; |
20 |
|
- |
import java.util.zip.*; |
21 |
|
- |
|
22 |
|
- |
// BOZO - Add javadocs method. |
23 |
|
- |
|
24 |
|
- |
/** |
25 |
|
- |
* Provides utility methods for common Java build tasks. |
26 |
|
- |
*/ |
27 |
|
- |
@SuppressWarnings({"ResultOfMethodCallIgnored"}) |
28 |
|
- |
public class Scar extends Utils implements ProjectFactory |
29 |
|
- |
{ |
30 |
|
- |
public static final String VERSION = "2.92 - 1.7"; |
31 |
|
- |
|
32 |
|
- |
public static final String DEFAULT_PROJECT_FILE_NAME = "Build"; |
33 |
|
- |
|
34 |
|
- |
public static final String JAVA_EXTENSION = ".java"; |
35 |
|
- |
public static final String YAML_EXTENSION = ".yaml"; |
36 |
|
- |
|
37 |
|
- |
protected static final Logger LOGGER = LoggerFactory.getLogger( Scar.class ); |
38 |
|
- |
|
39 |
|
- |
protected final ProjectCache mProjectCache = new ProjectCache(); |
40 |
|
- |
|
41 |
|
- |
private Project mLaunchProject; |
42 |
|
- |
|
43 |
|
- |
/** |
44 |
|
- |
* The command line arguments Scar was started with. Empty if Scar was started with no arguments or Scar was not started from |
45 |
|
- |
* the command line. |
46 |
|
- |
*/ |
47 |
|
- |
public final Arguments mArgs; |
48 |
|
- |
|
49 |
|
- |
public Scar( Arguments pArgs ) |
50 |
|
- |
{ |
51 |
|
- |
mArgs = (pArgs != null) ? pArgs : new Arguments(); |
52 |
|
- |
} |
53 |
|
- |
|
54 |
|
- |
@SuppressWarnings({"UnusedDeclaration"}) |
55 |
|
- |
public Project getLaunchProject() |
56 |
|
- |
{ |
57 |
|
- |
return mLaunchProject; |
58 |
|
- |
} |
59 |
|
- |
|
60 |
|
- |
/** |
61 |
|
- |
* Loads the specified project with default values and loads any other projects needed for the "include" property. |
62 |
|
- |
* |
63 |
|
- |
* @param pCanonicalCurrentDirectory |
64 |
|
- |
* @param pPath Path to a YAML project file, or a directory containing a "project.yaml" file. |
65 |
|
- |
*/ |
66 |
|
- |
@Override |
67 |
|
- |
public Project project( File pCanonicalCurrentDirectory, String pPath ) |
68 |
|
- |
{ |
69 |
|
- |
Util.assertNotNull( "CurrentDirectory", pCanonicalCurrentDirectory ); |
70 |
|
- |
pPath = Util.assertNotEmpty( "Path", pPath ); |
71 |
|
- |
File zFile = new File( pPath ); |
72 |
|
- |
if ( !zFile.isAbsolute() ) |
73 |
|
- |
{ |
74 |
|
- |
zFile = new File( pCanonicalCurrentDirectory, pPath ); |
75 |
|
- |
} |
76 |
|
- |
try |
77 |
|
- |
{ |
78 |
|
- |
zFile = zFile.getCanonicalFile(); |
79 |
|
- |
} |
80 |
|
- |
catch ( IOException e ) |
81 |
|
- |
{ |
82 |
|
- |
throw new WrappedIOException( e ); |
83 |
|
- |
} |
84 |
|
- |
|
85 |
|
- |
String zPath = zFile.getPath(); |
86 |
|
- |
Project zProject = mProjectCache.getByPath( zPath ); |
87 |
|
- |
if ( zProject != null ) |
88 |
|
- |
{ |
89 |
|
- |
return zProject; |
90 |
|
- |
} |
91 |
|
- |
try |
92 |
|
- |
{ |
93 |
|
- |
if ( zFile.isFile() ) // Assume Project Build File |
94 |
|
- |
{ |
95 |
|
- |
return mProjectCache.initialize( this, zPath, createProject( zFile, zFile.getParentFile() ) ); |
96 |
|
- |
} |
97 |
|
- |
if ( zFile.isDirectory() ) // Assume Project Dir |
98 |
|
- |
{ |
99 |
|
- |
return mProjectCache.initialize( this, zPath, createProject( findBuildFile( zFile ), zFile, zFile.getName() ) ); |
100 |
|
- |
} |
101 |
|
- |
} |
102 |
|
- |
catch ( WrappedIOException e ) |
103 |
|
- |
{ |
104 |
|
- |
throw new WrappedIOException( pPath, e ); |
105 |
|
- |
} |
106 |
|
- |
throw new IllegalArgumentException( "Project is Neither a Project File, nor a Project Directory: " + zFile ); |
107 |
|
- |
} |
108 |
|
- |
|
109 |
|
- |
protected File findBuildFile( File pProjectDir ) |
110 |
|
- |
{ |
111 |
|
- |
File[] zFiles = pProjectDir.listFiles( BuildFileFilter.INSTANCE ); |
112 |
|
- |
if ( (zFiles == null) || (zFiles.length == 0) ) |
113 |
|
- |
{ |
114 |
|
- |
return null; |
115 |
|
- |
} |
116 |
|
- |
if ( zFiles.length == 1 ) |
117 |
|
- |
{ |
118 |
|
- |
return zFiles[0]; |
119 |
|
- |
} |
120 |
|
- |
File zFile = findBuildFile( zFiles, JAVA_EXTENSION ); |
121 |
|
- |
return (zFile != null) ? zFile : findBuildFile( zFiles, YAML_EXTENSION ); |
122 |
|
- |
} |
123 |
|
- |
|
124 |
|
- |
private File findBuildFile( File[] pFiles, String pExtension ) |
125 |
|
- |
{ |
126 |
|
- |
File rv = null; |
127 |
|
- |
for ( File zFile : pFiles ) |
128 |
|
- |
{ |
129 |
|
- |
if ( zFile.getName().endsWith( pExtension ) ) |
130 |
|
- |
{ |
131 |
|
- |
if ( rv != null ) |
132 |
|
- |
{ |
133 |
|
- |
throw new IllegalStateException( "Found Both:\n " + rv + "\n " + zFile ); |
134 |
|
- |
} |
135 |
|
- |
rv = zFile; |
136 |
|
- |
} |
137 |
|
- |
} |
138 |
|
- |
return rv; |
139 |
|
- |
} |
140 |
|
- |
|
141 |
|
- |
protected Project createProject( File pPossibleBuildFile, File pCanonicalProjectDir ) |
142 |
|
- |
{ |
143 |
|
- |
String zBuildFileName = pPossibleBuildFile.getName(); |
144 |
|
- |
int zDotAt = zBuildFileName.lastIndexOf( '.' ); |
145 |
|
- |
if ( (zDotAt != -1) && (pCanonicalProjectDir != null) ) |
146 |
|
- |
{ |
147 |
|
- |
String zName = zBuildFileName.substring( 0, zDotAt ).trim(); |
148 |
|
- |
if ( DEFAULT_PROJECT_FILE_NAME.equalsIgnoreCase( zName ) ) |
149 |
|
- |
{ |
150 |
|
- |
zName = pCanonicalProjectDir.getName(); |
151 |
|
- |
} |
152 |
|
- |
return createProject( pPossibleBuildFile, pCanonicalProjectDir, zName ); |
153 |
|
- |
} |
154 |
|
- |
throw new IllegalArgumentException( "Unacceptable Project Path or Name, Project File " + pPossibleBuildFile ); |
155 |
|
- |
} |
156 |
|
- |
|
157 |
|
- |
protected Project createProject( File pBuildFile, File pCanonicalProjectDir, String pProjectName ) |
158 |
|
- |
{ |
159 |
|
- |
if ( pBuildFile == null ) |
160 |
|
- |
{ |
161 |
|
- |
throw new IllegalArgumentException( "No 'Build.java' or 'Build.yaml' file found in Project Directory: " + pCanonicalProjectDir ); |
162 |
|
- |
} |
163 |
|
- |
String zBuildFileName = pBuildFile.getName(); |
164 |
|
- |
if ( zBuildFileName.endsWith( JAVA_EXTENSION ) ) |
165 |
|
- |
{ |
166 |
|
- |
return createJavaProject( pBuildFile, pCanonicalProjectDir, pProjectName ); |
167 |
|
- |
} |
168 |
|
- |
if ( zBuildFileName.endsWith( YAML_EXTENSION ) ) |
169 |
|
- |
{ |
170 |
|
- |
return createYamlProject( pBuildFile, pCanonicalProjectDir, pProjectName ); |
171 |
|
- |
} |
172 |
|
- |
throw new IllegalArgumentException( pBuildFile + " was NOT either a '.java' or a '.yaml' file!" ); |
173 |
|
- |
} |
174 |
|
- |
|
175 |
|
- |
protected Project createYamlProject( File pYamlBuildFile, File pCanonicalProjectDir, String pProjectName ) |
176 |
|
- |
{ |
177 |
|
- |
List<String> zLines = readLines( pYamlBuildFile ); |
178 |
|
- |
int at = findLine( zLines, "---" ); |
179 |
|
- |
String zYAML, zCode = null; |
180 |
|
- |
if ( at == -1 ) |
181 |
|
- |
{ |
182 |
|
- |
zYAML = mergeLines( zLines, 0 ); |
183 |
|
- |
} |
184 |
|
- |
else |
185 |
|
- |
{ |
186 |
|
- |
zYAML = mergeLines( zLines, 0, at ); |
187 |
|
- |
zCode = Util.noEmpty( mergeLines( zLines, at + 1 ) ); |
188 |
|
- |
} |
189 |
|
- |
Map<Object, Object> zData = (zYAML.length() == 0) ? new HashMap<Object, Object>() : parseYAML( pCanonicalProjectDir, zYAML ); |
190 |
|
- |
Class<? extends Project> zClass = createYamlProjectClass(); |
191 |
|
- |
if ( zCode != null ) |
192 |
|
- |
{ |
193 |
|
- |
zClass = createYamlCodeProjectClass( zClass, zCode, at + 1 ); |
194 |
|
- |
} |
195 |
|
- |
return instantiate( pYamlBuildFile, zClass, pCanonicalProjectDir, pProjectName, zData ); |
196 |
|
- |
} |
197 |
|
- |
|
198 |
|
- |
protected Project createJavaProject( File pJavaBuildFile, File pCanonicalProjectDir, String pProjectName ) |
199 |
|
- |
{ |
200 |
|
- |
String zFile = mergeLines( readLines( pJavaBuildFile ), 0 ); |
201 |
|
- |
Class<? extends Project> zClass = createJavaProjectClass(); |
202 |
|
- |
zClass = createJavaCodeProjectClass( zClass, zFile ); |
203 |
|
- |
return instantiate( pJavaBuildFile, zClass, pCanonicalProjectDir, pProjectName, null ); |
204 |
|
- |
} |
205 |
|
- |
|
206 |
|
- |
protected Project instantiate( File zProjectFile, Class<? extends Project> pClass, File pCanonicalProjectDir, String pProjectName, Map<Object, Object> pData ) |
207 |
|
- |
{ |
208 |
|
- |
return instantiate( pClass, new ProjectParameters( zProjectFile, pProjectName, pCanonicalProjectDir, pData ) ); |
209 |
|
- |
} |
210 |
|
- |
|
211 |
|
- |
protected Project instantiate( Class<? extends Project> pClass, ProjectParameters pParameters ) |
212 |
|
- |
{ |
213 |
|
- |
Throwable zCause; |
214 |
|
- |
try |
215 |
|
- |
{ |
216 |
|
- |
Constructor zConstructor = pClass.getConstructor( ProjectParameters.class ); |
217 |
|
- |
return (Project) zConstructor.newInstance( pParameters ); |
218 |
|
- |
} |
219 |
|
- |
catch ( NoSuchMethodException e ) |
220 |
|
- |
{ |
221 |
|
- |
zCause = e; |
222 |
|
- |
} |
223 |
|
- |
catch ( InvocationTargetException e ) |
224 |
|
- |
{ |
225 |
|
- |
zCause = e; |
226 |
|
- |
} |
227 |
|
- |
catch ( ClassCastException e ) |
228 |
|
- |
{ |
229 |
|
- |
zCause = e; |
230 |
|
- |
} |
231 |
|
- |
catch ( InstantiationException e ) |
232 |
|
- |
{ |
233 |
|
- |
zCause = e; |
234 |
|
- |
} |
235 |
|
- |
catch ( IllegalAccessException e ) |
236 |
|
- |
{ |
237 |
|
- |
zCause = e; |
238 |
|
- |
} |
239 |
|
- |
catch ( RuntimeException e ) |
240 |
|
- |
{ |
241 |
|
- |
zCause = e; |
242 |
|
- |
} |
243 |
|
- |
throw new RuntimeException( "Unable to Instantiate Project Class for Project: " + pParameters.getName() + " in dir " + pParameters.getCanonicalProjectDir(), zCause ); |
244 |
|
- |
} |
245 |
|
- |
|
246 |
|
- |
protected Class<? extends Project> createYamlProjectClass() |
247 |
|
- |
{ |
248 |
|
- |
return Project.class; |
249 |
|
- |
} |
250 |
|
- |
|
251 |
|
- |
protected Class<? extends Project> createJavaProjectClass() |
252 |
|
- |
{ |
253 |
|
- |
return Project.class; |
254 |
|
- |
} |
255 |
|
- |
|
256 |
|
- |
protected Map<Object, Object> parseYAML( File pProjectDir, String pYAML ) |
257 |
|
- |
{ |
258 |
|
- |
final String zProjectDir = pProjectDir.getPath().replace( '\\', '/' ); |
259 |
|
- |
|
260 |
|
- |
YamlReader yamlReader = new YamlReader( new StringReader( pYAML ) ) |
261 |
|
- |
{ |
262 |
|
- |
@Override |
263 |
|
- |
protected Object readValue( Class type, Class elementType, Class defaultType ) |
264 |
|
- |
throws YamlException, Parser.ParserException, Tokenizer.TokenizerException |
265 |
|
- |
{ |
266 |
|
- |
Object value = super.readValue( type, elementType, defaultType ); |
267 |
|
- |
if ( value instanceof String ) |
268 |
|
- |
{ |
269 |
|
- |
value = ((String) value).replaceAll( "\\$dir\\$", zProjectDir ); |
270 |
|
- |
} |
271 |
|
- |
return value; |
272 |
|
- |
} |
273 |
|
- |
}; |
274 |
|
- |
try |
275 |
|
- |
{ |
276 |
|
- |
//noinspection unchecked |
277 |
|
- |
return yamlReader.read( HashMap.class ); |
278 |
|
- |
} |
279 |
|
- |
catch ( IOException e ) |
280 |
|
- |
{ |
281 |
|
- |
throw new WrappedIOException( e ); |
282 |
|
- |
} |
283 |
|
- |
finally |
284 |
|
- |
{ |
285 |
|
- |
try |
286 |
|
- |
{ |
287 |
|
- |
yamlReader.close(); |
288 |
|
- |
} |
289 |
|
- |
catch ( IOException e ) |
290 |
|
- |
{ |
291 |
|
- |
throw new WrappedIOException( e ); |
292 |
|
- |
} |
293 |
|
- |
} |
294 |
|
- |
} |
295 |
|
- |
|
296 |
|
- |
protected String mergeLines( List<String> pLines, int pFrom ) |
297 |
|
- |
{ |
298 |
|
- |
return mergeLines( pLines, pFrom, pLines.size() ); |
299 |
|
- |
} |
300 |
|
- |
|
301 |
|
- |
protected String mergeLines( List<String> pLines, int pFrom, int pToExclusive ) |
302 |
|
- |
{ |
303 |
|
- |
StringBuilder sb = new StringBuilder(); |
304 |
|
- |
while ( (pFrom < pToExclusive) && (pFrom < pLines.size()) ) |
305 |
|
- |
{ |
306 |
|
- |
sb.append( pLines.get( pFrom++ ) ).append( '\n' ); |
307 |
|
- |
} |
308 |
|
- |
return sb.toString(); |
309 |
|
- |
} |
310 |
|
- |
|
311 |
|
- |
private int findLine( List<String> pLines, String zLine ) |
312 |
|
- |
{ |
313 |
|
- |
for ( int i = 0; i < pLines.size(); i++ ) |
314 |
|
- |
{ |
315 |
|
- |
if ( zLine.equals( pLines.get( i ) ) ) |
316 |
|
- |
{ |
317 |
|
- |
return i; |
318 |
|
- |
} |
319 |
|
- |
} |
320 |
|
- |
return -1; |
321 |
|
- |
} |
322 |
|
- |
|
323 |
|
- |
protected List<String> readLines( File zFile ) |
324 |
|
- |
{ |
325 |
|
- |
BufferedReader fileReader; |
326 |
|
- |
try |
327 |
|
- |
{ |
328 |
|
- |
fileReader = new BufferedReader( new FileReader( zFile ) ); |
329 |
|
- |
} |
330 |
|
- |
catch ( FileNotFoundException e ) |
331 |
|
- |
{ |
332 |
|
- |
throw new WrappedIOException( e ); |
333 |
|
- |
} |
334 |
|
- |
try |
335 |
|
- |
{ |
336 |
|
- |
List<String> lines = new ArrayList<String>(); |
337 |
|
- |
for ( String line; null != (line = fileReader.readLine()); ) |
338 |
|
- |
{ |
339 |
|
- |
lines.add( line.trim() ); |
340 |
|
- |
} |
341 |
|
- |
Closeable c = fileReader; |
342 |
|
- |
fileReader = null; |
343 |
|
- |
c.close(); |
344 |
|
- |
return lines; |
345 |
|
- |
} |
346 |
|
- |
catch ( IOException e ) |
347 |
|
- |
{ |
348 |
|
- |
if ( fileReader != null ) |
349 |
|
- |
{ |
350 |
|
- |
try |
351 |
|
- |
{ |
352 |
|
- |
fileReader.close(); |
353 |
|
- |
} |
354 |
|
- |
catch ( IOException e1 ) |
355 |
|
- |
{ |
356 |
|
- |
// Whatever! |
357 |
|
- |
} |
358 |
|
- |
} |
359 |
|
- |
throw new WrappedIOException( e ); |
360 |
|
- |
} |
361 |
|
- |
} |
362 |
|
- |
|
363 |
|
- |
protected void initLoggerFactory() |
364 |
|
- |
{ |
365 |
|
- |
LoggerFactory.init( createLoggerLevel() ); |
366 |
|
- |
} |
367 |
|
- |
|
368 |
|
- |
protected LoggerLevel createLoggerLevel() |
369 |
|
- |
{ |
370 |
|
- |
int zLevel = LoggerLevel.ERROR; |
371 |
|
- |
String[] zLevels = LoggerLevel.LEVELS; |
372 |
|
- |
for ( int i = 0; i < zLevels.length; i++ ) |
373 |
|
- |
{ |
374 |
|
- |
if ( null != mArgs.get( zLevels[i] ) ) |
375 |
|
- |
{ |
376 |
|
- |
zLevel = i; |
377 |
|
- |
break; |
378 |
|
- |
} |
379 |
|
- |
} |
380 |
|
- |
final int zLoggerLevel = zLevel; |
381 |
|
- |
return new LoggerLevel() |
382 |
|
- |
{ |
383 |
|
- |
@Override |
384 |
|
- |
public int getEnabledLevel( String pClassName ) |
385 |
|
- |
{ |
386 |
|
- |
return zLoggerLevel; |
387 |
|
- |
} |
388 |
|
- |
}; |
389 |
|
- |
} |
390 |
|
- |
|
391 |
|
- |
protected Class<Project> createYamlCodeProjectClass( Class<? extends Project> pClass, String pCode, int pOverheadStartLines ) |
392 |
|
- |
{ |
393 |
|
- |
throw new UnsupportedOperationException(); // todo: See - executeDocument(); |
394 |
|
- |
} |
395 |
|
- |
|
396 |
|
- |
protected Class<Project> createJavaCodeProjectClass( Class<? extends Project> pClass, String pCode ) |
397 |
|
- |
{ |
398 |
|
- |
throw new UnsupportedOperationException(); // todo: See - executeDocument()!; |
399 |
|
- |
} |
400 |
|
- |
|
401 |
|
- |
/** |
402 |
|
- |
* Cleans All projects - Normally called reflectively |
403 |
|
- |
*/ |
404 |
|
- |
@SuppressWarnings({"UnusedDeclaration"}) |
405 |
|
- |
public void cleanAll() |
406 |
|
- |
{ |
407 |
|
- |
progress( "CleanAll" ); |
408 |
|
- |
Set<Project> zProjects = mProjectCache.getAllProjects(); |
409 |
|
- |
for ( Project zProject : zProjects ) |
410 |
|
- |
{ |
411 |
|
- |
zProject.clean(); |
412 |
|
- |
} |
413 |
|
- |
} |
414 |
|
- |
|
415 |
|
- |
/** |
416 |
|
- |
* Builds the Launch Project - Normally called reflectively |
417 |
|
- |
*/ |
418 |
|
- |
@SuppressWarnings({"UnusedDeclaration"}) |
419 |
|
- |
public void build() |
420 |
|
- |
{ |
421 |
|
- |
mLaunchProject.build(); |
422 |
|
- |
} |
423 |
|
- |
|
424 |
|
- |
/** |
425 |
|
- |
* Versions the current (GWT) Launch Project - Normally called reflectively |
426 |
|
- |
*/ |
427 |
|
- |
@SuppressWarnings({"UnusedDeclaration"}) |
428 |
|
- |
public void versionGWT() |
429 |
|
- |
{ |
430 |
|
- |
mLaunchProject.versionGWT(); |
431 |
|
- |
} |
432 |
|
- |
|
433 |
|
- |
/// todo: ================================================================================================================== |
434 |
|
- |
/// todo: ================================================================================================================== |
435 |
|
- |
/// todo: ================================================================================================================== |
436 |
|
- |
/// todo: ================================================================================================================== |
437 |
|
- |
/// todo: ================================================================================================================== |
438 |
|
- |
/// todo: ================================================================================================================== |
439 |
|
- |
/// todo: ================================================================================================================== |
440 |
|
- |
/// todo: ================================================================================================================== |
441 |
|
- |
/// todo: ================================================================================================================== |
442 |
|
- |
/// todo: ================================================================================================================== |
443 |
|
- |
/// todo: ================================================================================================================== |
444 |
|
- |
/// todo: vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv Here be Dragons vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv |
445 |
|
- |
|
446 |
|
- |
/** |
447 |
|
- |
* Loads the specified project with the specified defaults and loads any other projects needed for the "include" property. |
448 |
|
- |
* |
449 |
|
- |
* @param path Path to a YAML project file, or a directory containing a "project.yaml" file. |
450 |
|
- |
*/ |
451 |
|
- |
// public Project project( String path, Project defaults ) |
452 |
|
- |
// { |
453 |
|
- |
// Util.assertNotNull( "path", path ); |
454 |
|
- |
// Util.assertNotNull( "defaults", defaults ); |
455 |
|
- |
// |
456 |
|
- |
// Project actualProject = new Project( path, this ); |
457 |
|
- |
// |
458 |
|
- |
// Project project = new Project(); |
459 |
|
- |
// project.replace( defaults ); |
460 |
|
- |
// |
461 |
|
- |
// File parent = actualProject.getDirectory().getParentFile(); |
462 |
|
- |
// while ( parent != null ) |
463 |
|
- |
// { |
464 |
|
- |
// File includeFile = new File( parent, "include.yaml" ); |
465 |
|
- |
// if ( includeFile.exists() ) |
466 |
|
- |
// { |
467 |
|
- |
// try |
468 |
|
- |
// { |
469 |
|
- |
// project.replace( project( includeFile.getAbsolutePath(), defaults ) ); |
470 |
|
- |
// } |
471 |
|
- |
// catch ( RuntimeException ex ) |
472 |
|
- |
// { |
473 |
|
- |
// throw new RuntimeException( "Error loading included project: " + includeFile.getAbsolutePath(), ex ); |
474 |
|
- |
// } |
475 |
|
- |
// } |
476 |
|
- |
// parent = parent.getParentFile(); |
477 |
|
- |
// } |
478 |
|
- |
// |
479 |
|
- |
// for ( String include : actualProject.getInclude() ) |
480 |
|
- |
// { |
481 |
|
- |
// try |
482 |
|
- |
// { |
483 |
|
- |
// project.replace( project( actualProject.path( include ), defaults ) ); |
484 |
|
- |
// } |
485 |
|
- |
// catch ( RuntimeException ex ) |
486 |
|
- |
// { |
487 |
|
- |
// throw new RuntimeException( "Error loading included project: " + actualProject.path( include ), ex ); |
488 |
|
- |
// } |
489 |
|
- |
// } |
490 |
|
- |
// project.replace( actualProject ); |
491 |
|
- |
// return project; |
492 |
|
- |
// } |
493 |
|
- |
|
494 |
|
- |
/** |
495 |
|
- |
* Removes any code signatures on the specified JAR. Removes any signature files in the META-INF directory and removes any |
496 |
|
- |
* signature entries from the JAR's manifest. |
497 |
|
- |
* |
498 |
|
- |
* @return The path to the JAR file. |
499 |
|
- |
*/ |
500 |
|
- |
public String unsign( String jarFile ) |
501 |
|
- |
{ |
502 |
|
- |
Util.assertNotNull( "jarFile", jarFile ); |
503 |
|
- |
|
504 |
|
- |
progress( "Removing signature from JAR: " + jarFile ); |
505 |
|
- |
|
506 |
|
- |
File tempFile; |
507 |
|
- |
try |
508 |
|
- |
{ |
509 |
|
- |
tempFile = File.createTempFile( "scar", "removejarsig" ); |
510 |
|
- |
} |
511 |
|
- |
catch ( IOException e ) |
512 |
|
- |
{ |
513 |
|
- |
throw new WrappedIOException( e ); |
514 |
|
- |
} |
515 |
|
- |
JarOutputStream jarOutput = null; |
516 |
|
- |
JarInputStream jarInput = null; |
517 |
|
- |
try |
518 |
|
- |
{ |
519 |
|
- |
jarOutput = new JarOutputStream( new FileOutputStream( tempFile ) ); |
520 |
|
- |
jarInput = new JarInputStream( new FileInputStream( jarFile ) ); |
521 |
|
- |
Manifest manifest = jarInput.getManifest(); |
522 |
|
- |
if ( manifest != null ) |
523 |
|
- |
{ |
524 |
|
- |
// Remove manifest file entries. |
525 |
|
- |
manifest.getEntries().clear(); |
526 |
|
- |
jarOutput.putNextEntry( new JarEntry( "META-INF/MANIFEST.MF" ) ); |
527 |
|
- |
manifest.write( jarOutput ); |
528 |
|
- |
} |
529 |
|
- |
byte[] buffer = new byte[4096]; |
530 |
|
- |
while ( true ) |
531 |
|
- |
{ |
532 |
|
- |
JarEntry entry = jarInput.getNextJarEntry(); |
533 |
|
- |
if ( entry == null ) |
534 |
|
- |
{ |
535 |
|
- |
break; |
536 |
|
- |
} |
537 |
|
- |
String name = entry.getName(); |
538 |
|
- |
// Skip signature files. |
539 |
|
- |
if ( name.startsWith( "META-INF/" ) && (name.endsWith( ".SF" ) || name.endsWith( ".DSA" ) || name.endsWith( ".RSA" )) ) |
540 |
|
- |
{ |
541 |
|
- |
continue; |
542 |
|
- |
} |
543 |
|
- |
jarOutput.putNextEntry( new JarEntry( name ) ); |
544 |
|
- |
while ( true ) |
545 |
|
- |
{ |
546 |
|
- |
int length = jarInput.read( buffer ); |
547 |
|
- |
if ( length == -1 ) |
548 |
|
- |
{ |
549 |
|
- |
break; |
550 |
|
- |
} |
551 |
|
- |
jarOutput.write( buffer, 0, length ); |
552 |
|
- |
} |
553 |
|
- |
} |
554 |
|
- |
jarInput.close(); |
555 |
|
- |
jarOutput.close(); |
556 |
|
- |
copyFile( tempFile.getAbsolutePath(), jarFile ); |
557 |
|
- |
} |
558 |
|
- |
catch ( IOException ex ) |
559 |
|
- |
{ |
560 |
|
- |
throw new WrappedIOException( "Error unsigning JAR file: " + jarFile, ex ); |
561 |
|
- |
} |
562 |
|
- |
finally |
563 |
|
- |
{ |
564 |
|
- |
dispose( jarInput ); |
565 |
|
- |
dispose( jarOutput ); |
566 |
|
- |
tempFile.delete(); |
567 |
|
- |
} |
568 |
|
- |
return jarFile; |
569 |
|
- |
} |
570 |
|
- |
|
571 |
|
- |
/** |
572 |
|
- |
* Signs the specified JAR. |
573 |
|
- |
* |
574 |
|
- |
* @return The path to the JAR. |
575 |
|
- |
*/ |
576 |
|
- |
public String sign( String jarFile, String keystoreFile, String alias, String password ) |
577 |
|
- |
{ |
578 |
|
- |
Util.assertNotNull( "jarFile", jarFile ); |
579 |
|
- |
Util.assertNotNull( "keystoreFile", keystoreFile ); |
580 |
|
- |
Util.assertNotNull( "alias", alias ); |
581 |
|
- |
Util.assertNotNull( "password", password ); |
582 |
|
- |
if ( password.length() < 6 ) |
583 |
|
- |
{ |
584 |
|
- |
throw new IllegalArgumentException( "password must be 6 or more characters." ); |
585 |
|
- |
} |
586 |
|
- |
progress( "Signing JAR (" + keystoreFile + ", " + alias + ":" + password + "): " + jarFile ); |
587 |
|
- |
|
588 |
|
- |
shell( "jarsigner", "-keystore", keystoreFile, "-storepass", password, "-keypass", password, jarFile, alias ); |
589 |
|
- |
return jarFile; |
590 |
|
- |
} |
591 |
|
- |
|
592 |
|
- |
/** |
593 |
|
- |
* Encodes the specified file with pack200. The resulting filename is the filename plus ".pack". The file is deleted after |
594 |
|
- |
* encoding. |
595 |
|
- |
* |
596 |
|
- |
* @return The path to the encoded file. |
597 |
|
- |
*/ |
598 |
|
- |
public String pack200( String jarFile ) |
599 |
|
- |
{ |
600 |
|
- |
String packedFile = pack200( jarFile, jarFile + ".pack" ); |
601 |
|
- |
delete( jarFile ); |
602 |
|
- |
return packedFile; |
603 |
|
- |
} |
604 |
|
- |
|
605 |
|
- |
/** |
606 |
|
- |
* Encodes the specified file with pack200. |
607 |
|
- |
* |
608 |
|
- |
* @return The path to the encoded file. |
609 |
|
- |
*/ |
610 |
|
- |
public String pack200( String jarFile, String packedFile ) |
611 |
|
- |
{ |
612 |
|
- |
Util.assertNotNull( "jarFile", jarFile ); |
613 |
|
- |
Util.assertNotNull( "packedFile", packedFile ); |
614 |
|
- |
|
615 |
|
- |
progress( "Packing JAR: " + jarFile + " -> " + packedFile ); |
616 |
|
- |
|
617 |
|
- |
shell( "pack200", "--no-gzip", "--segment-limit=-1", "--no-keep-file-order", "--effort=7", "--modification-time=latest", packedFile, jarFile ); |
618 |
|
- |
return packedFile; |
619 |
|
- |
} |
620 |
|
- |
|
621 |
|
- |
/** |
622 |
|
- |
* Decodes the specified file with pack200. The filename must end in ".pack" and the resulting filename has this stripped. The |
623 |
|
- |
* encoded file is deleted after decoding. |
624 |
|
- |
* |
625 |
|
- |
* @return The path to the decoded file. |
626 |
|
- |
*/ |
627 |
|
- |
public String unpack200( String packedFile ) |
628 |
|
- |
{ |
629 |
|
- |
Util.assertNotNull( "packedFile", packedFile ); |
630 |
|
- |
if ( !packedFile.endsWith( ".pack" ) ) |
631 |
|
- |
{ |
632 |
|
- |
throw new IllegalArgumentException( "packedFile must end with .pack: " + packedFile ); |
633 |
|
- |
} |
634 |
|
- |
|
635 |
|
- |
String jarFile = unpack200( packedFile, substring( packedFile, 0, -5 ) ); |
636 |
|
- |
delete( packedFile ); |
637 |
|
- |
return jarFile; |
638 |
|
- |
} |
639 |
|
- |
|
640 |
|
- |
/** |
641 |
|
- |
* Decodes the specified file with pack200. |
642 |
|
- |
* |
643 |
|
- |
* @return The path to the decoded file. |
644 |
|
- |
*/ |
645 |
|
- |
public String unpack200( String packedFile, String jarFile ) |
646 |
|
- |
{ |
647 |
|
- |
Util.assertNotNull( "packedFile", packedFile ); |
648 |
|
- |
Util.assertNotNull( "jarFile", jarFile ); |
649 |
|
- |
|
650 |
|
- |
progress( "Unpacking JAR: " + packedFile + " -> " + jarFile ); |
651 |
|
- |
|
652 |
|
- |
shell( "unpack200", packedFile, jarFile ); |
653 |
|
- |
return jarFile; |
654 |
|
- |
} |
655 |
|
- |
|
656 |
|
- |
/** |
657 |
|
- |
* Encodes the specified file with GZIP. The resulting filename is the filename plus ".gz". The file is deleted after encoding. |
658 |
|
- |
* |
659 |
|
- |
* @return The path to the encoded file. |
660 |
|
- |
*/ |
661 |
|
- |
public String gzip( String file ) |
662 |
|
- |
{ |
663 |
|
- |
String gzipFile = gzip( file, file + ".gz" ); |
664 |
|
- |
delete( file ); |
665 |
|
- |
return gzipFile; |
666 |
|
- |
} |
667 |
|
- |
|
668 |
|
- |
/** |
669 |
|
- |
* Encodes the specified file with GZIP. |
670 |
|
- |
* |
671 |
|
- |
* @return The path to the encoded file. |
672 |
|
- |
*/ |
673 |
|
- |
public String gzip( String file, String gzipFile ) |
674 |
|
- |
{ |
675 |
|
- |
Util.assertNotNull( "file", file ); |
676 |
|
- |
Util.assertNotNull( "gzipFile", gzipFile ); |
677 |
|
- |
|
678 |
|
- |
progress( "GZIP encoding: " + file + " -> " + gzipFile ); |
679 |
|
- |
|
680 |
|
- |
InputStream input; |
681 |
|
- |
try |
682 |
|
- |
{ |
683 |
|
- |
input = new FileInputStream( file ); |
684 |
|
- |
} |
685 |
|
- |
catch ( FileNotFoundException e ) |
686 |
|
- |
{ |
687 |
|
- |
throw new WrappedIOException( e ); |
688 |
|
- |
} |
689 |
|
- |
try |
690 |
|
- |
{ |
691 |
|
- |
copyStreamAndCloseEm( input, new GZIPOutputStream( new FileOutputStream( gzipFile ) ) ); |
692 |
|
- |
} |
693 |
|
- |
catch ( IOException e ) |
694 |
|
- |
{ |
695 |
|
- |
throw new WrappedIOException( e ); |
696 |
|
- |
} |
697 |
|
- |
finally |
698 |
|
- |
{ |
699 |
|
- |
dispose( input ); |
700 |
|
- |
} |
701 |
|
- |
return gzipFile; |
702 |
|
- |
} |
703 |
|
- |
|
704 |
|
- |
/** |
705 |
|
- |
* Decodes the specified GZIP file. The filename must end in ".gz" and the resulting filename has this stripped. The encoded |
706 |
|
- |
* file is deleted after decoding. |
707 |
|
- |
* |
708 |
|
- |
* @return The path to the decoded file. |
709 |
|
- |
*/ |
710 |
|
- |
public String ungzip( String gzipFile ) |
711 |
|
- |
{ |
712 |
|
- |
Util.assertNotNull( "gzipFile", gzipFile ); |
713 |
|
- |
if ( !gzipFile.endsWith( ".gz" ) ) |
714 |
|
- |
{ |
715 |
|
- |
throw new IllegalArgumentException( "gzipFile must end with .gz: " + gzipFile ); |
716 |
|
- |
} |
717 |
|
- |
|
718 |
|
- |
String file = ungzip( gzipFile, substring( gzipFile, 0, -3 ) ); |
719 |
|
- |
delete( gzipFile ); |
720 |
|
- |
return file; |
721 |
|
- |
} |
722 |
|
- |
|
723 |
|
- |
/** |
724 |
|
- |
* Decodes the specified GZIP file. |
725 |
|
- |
* |
726 |
|
- |
* @return The path to the decoded file. |
727 |
|
- |
*/ |
728 |
|
- |
public String ungzip( String gzipFile, String file ) |
729 |
|
- |
{ |
730 |
|
- |
Util.assertNotNull( "gzipFile", gzipFile ); |
731 |
|
- |
Util.assertNotNull( "file", file ); |
732 |
|
- |
progress( "GZIP decoding: " + gzipFile + " -> " + file ); |
733 |
|
- |
|
734 |
|
- |
InputStream input; |
735 |
|
- |
try |
736 |
|
- |
{ |
737 |
|
- |
input = new GZIPInputStream( new FileInputStream( gzipFile ) ); |
738 |
|
- |
} |
739 |
|
- |
catch ( IOException e ) |
740 |
|
- |
{ |
741 |
|
- |
throw new WrappedIOException( e ); |
742 |
|
- |
} |
743 |
|
- |
try |
744 |
|
- |
{ |
745 |
|
- |
copyStreamAndCloseEm( input, new FileOutputStream( file ) ); |
746 |
|
- |
} |
747 |
|
- |
catch ( FileNotFoundException e ) |
748 |
|
- |
{ |
749 |
|
- |
throw new WrappedIOException( e ); |
750 |
|
- |
} |
751 |
|
- |
finally |
752 |
|
- |
{ |
753 |
|
- |
dispose( input ); |
754 |
|
- |
} |
755 |
|
- |
return file; |
756 |
|
- |
} |
757 |
|
- |
|
758 |
|
- |
/** |
759 |
|
- |
* Encodes the specified files with ZIP. |
760 |
|
- |
* |
761 |
|
- |
* @return The path to the encoded file. |
762 |
|
- |
*/ |
763 |
|
- |
public String zip( Paths paths, String zipFile ) |
764 |
|
- |
{ |
765 |
|
- |
Util.assertNotNull( "paths", paths ); |
766 |
|
- |
Util.assertNotNull( "zipFile", zipFile ); |
767 |
|
- |
progress( "Creating ZIP (" + paths.count() + " entries): " + zipFile ); |
768 |
|
- |
|
769 |
|
- |
paths.zip( zipFile ); |
770 |
|
- |
return zipFile; |
771 |
|
- |
} |
772 |
|
- |
|
773 |
|
- |
/** |
774 |
|
- |
* Encodes the specified file with LZMA. The resulting filename is the filename plus ".lzma". The file is deleted after |
775 |
|
- |
* encoding. |
776 |
|
- |
* |
777 |
|
- |
* @return The path to the encoded file. |
778 |
|
- |
*/ |
779 |
|
- |
public String lzma( String file ) |
780 |
|
- |
{ |
781 |
|
- |
String lzmaFile = lzma( file, file + ".lzma" ); |
782 |
|
- |
delete( file ); |
783 |
|
- |
return lzmaFile; |
784 |
|
- |
} |
785 |
|
- |
|
786 |
|
- |
/** |
787 |
|
- |
* Encodes the specified file with LZMA. |
788 |
|
- |
* |
789 |
|
- |
* @return The path to the encoded file. |
790 |
|
- |
*/ |
791 |
|
- |
public String lzma( String file, String lzmaFile ) |
792 |
|
- |
{ |
793 |
|
- |
Util.assertNotNull( "file", file ); |
794 |
|
- |
Util.assertNotNull( "lzmaFile", lzmaFile ); |
795 |
|
- |
progress( "LZMA encoding: " + file + " -> " + lzmaFile ); |
796 |
|
- |
|
797 |
|
- |
try |
798 |
|
- |
{ |
799 |
|
- |
LzmaAlone.main( new String[]{"e", file, lzmaFile} ); |
800 |
|
- |
} |
801 |
|
- |
catch ( Exception ex ) |
802 |
|
- |
{ |
803 |
|
- |
throw new WrappedIOException( "Error lzma compressing file: " + file, ex ); |
804 |
|
- |
} |
805 |
|
- |
return lzmaFile; |
806 |
|
- |
} |
807 |
|
- |
|
808 |
|
- |
/** |
809 |
|
- |
* Decodes the specified LZMA file. The filename must end in ".lzma" and the resulting filename has this stripped. The encoded |
810 |
|
- |
* file is deleted after decoding. |
811 |
|
- |
* |
812 |
|
- |
* @return The path to the decoded file. |
813 |
|
- |
*/ |
814 |
|
- |
public String unlzma( String lzmaFile ) |
815 |
|
- |
{ |
816 |
|
- |
Util.assertNotNull( "lzmaFile", lzmaFile ); |
817 |
|
- |
if ( !lzmaFile.endsWith( ".lzma" ) ) |
818 |
|
- |
{ |
819 |
|
- |
throw new IllegalArgumentException( "lzmaFile must end with .lzma: " + lzmaFile ); |
820 |
|
- |
} |
821 |
|
- |
|
822 |
|
- |
String file = unlzma( lzmaFile, substring( lzmaFile, 0, -5 ) ); |
823 |
|
- |
delete( lzmaFile ); |
824 |
|
- |
return file; |
825 |
|
- |
} |
826 |
|
- |
|
827 |
|
- |
/** |
828 |
|
- |
* Decodes the specified LZMA file. |
829 |
|
- |
* |
830 |
|
- |
* @return The path to the decoded file. |
831 |
|
- |
*/ |
832 |
|
- |
public String unlzma( String lzmaFile, String file ) |
833 |
|
- |
{ |
834 |
|
- |
Util.assertNotNull( "lzmaFile", lzmaFile ); |
835 |
|
- |
Util.assertNotNull( "file", file ); |
836 |
|
- |
progress( "LZMA decoding: " + lzmaFile + " -> " + file ); |
837 |
|
- |
|
838 |
|
- |
try |
839 |
|
- |
{ |
840 |
|
- |
LzmaAlone.main( new String[]{"d", lzmaFile, file} ); |
841 |
|
- |
} |
842 |
|
- |
catch ( Exception ex ) |
843 |
|
- |
{ |
844 |
|
- |
throw new WrappedIOException( "Error lzma decompressing file: " + file, ex ); |
845 |
|
- |
} |
846 |
|
- |
return file; |
847 |
|
- |
} |
848 |
|
- |
|
849 |
|
- |
/** |
850 |
|
- |
* Copies all the JAR and JNLP files from the "dist" directory to a "jws" directory under the "target" directory. It then uses |
851 |
|
- |
* the specified keystore to sign each JAR. If the "pack" parameter is true, it also compresses each JAR using pack200 and |
852 |
|
- |
* GZIP. |
853 |
|
- |
*/ |
854 |
|
- |
public void jws( Project project, boolean pack, String keystoreFile, String alias, String password ) |
855 |
|
- |
{ |
856 |
|
- |
Util.assertNotNull( "Project", project ); |
857 |
|
- |
Util.assertNotNull( "keystoreFile", keystoreFile ); |
858 |
|
- |
Util.assertNotNull( "alias", alias ); |
859 |
|
- |
Util.assertNotNull( "password", password ); |
860 |
|
- |
if ( password.length() < 6 ) |
861 |
|
- |
{ |
862 |
|
- |
throw new IllegalArgumentException( "password must be 6 or more characters." ); |
863 |
|
- |
} |
864 |
|
- |
|
865 |
|
- |
progress( "JWS: " + project ); |
866 |
|
- |
|
867 |
|
- |
String jwsDir = mkdir( project.path( "$target$/jws/" ) ); |
868 |
|
- |
String distDir = project.path( "$target$/dist/" ); |
869 |
|
- |
new Paths( distDir, "*.jar", "*.jnlp" ).copyTo( jwsDir ); |
870 |
|
- |
for ( String file : new Paths( jwsDir, "*.jar" ).getFullPaths() ) |
871 |
|
- |
{ |
872 |
|
- |
sign( unpack200( pack200( unsign( file ) ) ), keystoreFile, alias, password ); |
873 |
|
- |
} |
874 |
|
- |
if ( pack ) |
875 |
|
- |
{ |
876 |
|
- |
String unpackedDir = mkdir( jwsDir + "unpacked/" ); |
877 |
|
- |
String packedDir = mkdir( jwsDir + "packed/" ); |
878 |
|
- |
for ( String file : new Paths( jwsDir, "*.jar", "!*native*" ).getFullPaths() ) |
879 |
|
- |
{ |
880 |
|
- |
String fileName = fileName( file ); |
881 |
|
- |
String unpackedFile = unpackedDir + fileName; |
882 |
|
- |
moveFile( file, unpackedFile ); |
883 |
|
- |
String packedFile = packedDir + fileName; |
884 |
|
- |
gzip( pack200( copyFile( unpackedFile, packedFile ) ) ); |
885 |
|
- |
} |
886 |
|
- |
} |
887 |
|
- |
} |
888 |
|
- |
|
889 |
|
- |
/** |
890 |
|
- |
* Generates ".htaccess" and "type map" VAR files in the "jws" directory. These files allow Apache to serve both pack200/GZIP |
891 |
|
- |
* JARs and regular JARs, based on capability of the client requesting the JAR. |
892 |
|
- |
*/ |
893 |
|
- |
public void jwsHtaccess( Project project ) |
894 |
|
- |
{ |
895 |
|
- |
Util.assertNotNull( "Project", project ); |
896 |
|
- |
|
897 |
|
- |
progress( "JWS htaccess: " + project ); |
898 |
|
- |
|
899 |
|
- |
String jwsDir = mkdir( project.path( "$target$/jws/" ) ); |
900 |
|
- |
for ( String packedFile : new Paths( jwsDir + "packed", "*.jar.pack.gz" ).getFullPaths() ) |
901 |
|
- |
{ |
902 |
|
- |
String packedFileName = fileName( packedFile ); |
903 |
|
- |
String jarFileName = substring( packedFileName, 0, -8 ); |
904 |
|
- |
FileWriter writer; |
905 |
|
- |
try |
906 |
|
- |
{ |
907 |
|
- |
writer = new FileWriter( jwsDir + jarFileName + ".var" ); |
908 |
|
- |
} |
909 |
|
- |
catch ( IOException e ) |
910 |
|
- |
{ |
911 |
|
- |
throw new WrappedIOException( e ); |
912 |
|
- |
} |
913 |
|
- |
try |
914 |
|
- |
{ |
915 |
|
- |
writer.write( "URI: packed/" + packedFileName + "\n" ); |
916 |
|
- |
writer.write( "Content-Type: x-java-archive\n" ); |
917 |
|
- |
writer.write( "Content-Encoding: pack200-gzip\n" ); |
918 |
|
- |
writer.write( "URI: unpacked/" + jarFileName + "\n" ); |
919 |
|
- |
writer.write( "Content-Type: x-java-archive\n" ); |
920 |
|
- |
} |
921 |
|
- |
catch ( IOException e ) |
922 |
|
- |
{ |
923 |
|
- |
throw new WrappedIOException( e ); |
924 |
|
- |
} |
925 |
|
- |
finally |
926 |
|
- |
{ |
927 |
|
- |
dispose( writer ); |
928 |
|
- |
} |
929 |
|
- |
} |
930 |
|
- |
FileWriter writer; |
931 |
|
- |
try |
932 |
|
- |
{ |
933 |
|
- |
writer = new FileWriter( jwsDir + ".htaccess" ); |
934 |
|
- |
} |
935 |
|
- |
catch ( IOException e ) |
936 |
|
- |
{ |
937 |
|
- |
throw new WrappedIOException( e ); |
938 |
|
- |
} |
939 |
|
- |
try |
940 |
|
- |
{ |
941 |
|
- |
writer.write( "AddType application/x-java-jnlp-file .jnlp" ); // JNLP mime type. |
942 |
|
- |
writer.write( "AddType application/x-java-archive .jar\n" ); // JAR mime type. |
943 |
|
- |
writer.write( "AddHandler application/x-type-map .var\n" ); // Enable type maps. |
944 |
|
- |
writer.write( "Options +MultiViews\n" ); |
945 |
|
- |
writer.write( "MultiViewsMatch Any\n" ); // Apache 2.0 only. |
946 |
|
- |
writer.write( "<Files *.pack.gz>\n" ); |
947 |
|
- |
writer.write( "AddEncoding pack200-gzip .jar\n" ); // Enable Content-Encoding header for .jar.pack.gz files. |
948 |
|
- |
writer.write( "RemoveEncoding .gz\n" ); // Prevent mod_gzip from messing with the Content-Encoding response. |
949 |
|
- |
writer.write( "</Files>\n" ); |
950 |
|
- |
} |
951 |
|
- |
catch ( IOException e ) |
952 |
|
- |
{ |
953 |
|
- |
throw new WrappedIOException( e ); |
954 |
|
- |
} |
955 |
|
- |
finally |
956 |
|
- |
{ |
957 |
|
- |
dispose( writer ); |
958 |
|
- |
} |
959 |
|
- |
} |
960 |
|
- |
|
961 |
|
- |
/** |
962 |
|
- |
* Generates a JNLP file in the "jws" directory. JARs in the "jws" directory are included in the JNLP. JARs containing "native" |
963 |
|
- |
* and "win", "mac", "linux", or "solaris" are properly included in the native section of the JNLP. The "main" property is used |
964 |
|
- |
* for the main class in the JNLP. |
965 |
|
- |
* |
966 |
|
- |
* @param splashImage Can be null. |
967 |
|
- |
*/ |
968 |
|
- |
public void jnlp( Project project, String url, String company, String title, String splashImage ) |
969 |
|
- |
{ |
970 |
|
- |
Util.assertNotNull( "Project", project ); |
971 |
|
- |
Util.assertNotNull( "company", company ); |
972 |
|
- |
Util.assertNotNull( "title", title ); |
973 |
|
- |
Util.assertNotNull( "url", url ); |
974 |
|
- |
if ( !url.startsWith( "http" ) ) |
975 |
|
- |
{ |
976 |
|
- |
throw new RuntimeException( "Invalid url: " + url ); |
977 |
|
- |
} |
978 |
|
- |
|
979 |
|
- |
if ( LOGGER.debug.isEnabled() ) |
980 |
|
- |
{ |
981 |
|
- |
progress( "JNLP: " + project + " (" + url + ", " + company + ", " + title + ", " + splashImage + ")" ); |
982 |
|
- |
} |
983 |
|
- |
else |
984 |
|
- |
{ |
985 |
|
- |
progress( "JNLP: " + project ); |
986 |
|
- |
} |
987 |
|
- |
|
988 |
|
- |
if ( !project.hasMain() ) |
989 |
|
- |
{ |
990 |
|
- |
throw new RuntimeException( "Unable to generate JNLP: project has no main class" ); |
991 |
|
- |
} |
992 |
|
- |
|
993 |
|
- |
int firstSlash = url.indexOf( "/", 7 ); |
994 |
|
- |
int lastSlash = url.lastIndexOf( "/" ); |
995 |
|
- |
if ( firstSlash == -1 || lastSlash == -1 ) |
996 |
|
- |
{ |
997 |
|
- |
throw new RuntimeException( "Invalid url: " + url ); |
998 |
|
- |
} |
999 |
|
- |
String domain = url.substring( 0, firstSlash + 1 ); |
1000 |
|
- |
String path = url.substring( firstSlash + 1, lastSlash + 1 ); |
1001 |
|
- |
String jnlpFile = url.substring( lastSlash + 1 ); |
1002 |
|
- |
|
1003 |
|
- |
String jwsDir = mkdir( project.path( "$target$/jws/" ) ); |
1004 |
|
- |
FileWriter writer; |
1005 |
|
- |
try |
1006 |
|
- |
{ |
1007 |
|
- |
writer = new FileWriter( jwsDir + jnlpFile ); |
1008 |
|
- |
} |
1009 |
|
- |
catch ( IOException e ) |
1010 |
|
- |
{ |
1011 |
|
- |
throw new WrappedIOException( e ); |
1012 |
|
- |
} |
1013 |
|
- |
try |
1014 |
|
- |
{ |
1015 |
|
- |
writer.write( "<?xml version='1.0' encoding='utf-8'?>\n" ); |
1016 |
|
- |
writer.write( "<jnlp spec='1.0+' codebase='" + domain + "' href='" + path + jnlpFile + "'>\n" ); |
1017 |
|
- |
writer.write( "<information>\n" ); |
1018 |
|
- |
writer.write( "\t<title>" + title + "</title>\n" ); |
1019 |
|
- |
writer.write( "\t<vendor>" + company + "</vendor>\n" ); |
1020 |
|
- |
writer.write( "\t<homepage href='" + domain + "'/>\n" ); |
1021 |
|
- |
writer.write( "\t<description>" + title + "</description>\n" ); |
1022 |
|
- |
writer.write( "\t<description kind='short'>" + title + "</description>\n" ); |
1023 |
|
- |
if ( splashImage != null ) |
1024 |
|
- |
{ |
1025 |
|
- |
writer.write( "\t<icon kind='splash' href='" + path + splashImage + "'/>\n" ); |
1026 |
|
- |
} |
1027 |
|
- |
writer.write( "</information>\n" ); |
1028 |
|
- |
writer.write( "<security>\n" ); |
1029 |
|
- |
writer.write( "\t<all-permissions/>\n" ); |
1030 |
|
- |
writer.write( "</security>\n" ); |
1031 |
|
- |
writer.write( "<resources>\n" ); |
1032 |
|
- |
writer.write( "\t<j2se href='http://java.sun.com/products/autodl/j2se' version='1.5+' max-heap-size='128m'/>\n" ); |
1033 |
|
- |
|
1034 |
|
- |
// JAR with main class first. |
1035 |
|
- |
String projectJarName; |
1036 |
|
- |
if ( project.hasVersion() ) |
1037 |
|
- |
{ |
1038 |
|
- |
projectJarName = project.format( "$name$-$version$.jar" ); |
1039 |
|
- |
} |
1040 |
|
- |
else |
1041 |
|
- |
{ |
1042 |
|
- |
projectJarName = project.format( "$name$.jar" ); |
1043 |
|
- |
} |
1044 |
|
- |
writer.write( "\t<jar href='" + path + projectJarName + "'/>\n" ); |
1045 |
|
- |
|
1046 |
|
- |
// Rest of JARs, except natives. |
1047 |
|
- |
for ( String file : new Paths( jwsDir, "**/*.jar", "!*native*", "!**/" + projectJarName ).getFullPaths() ) |
1048 |
|
- |
{ |
1049 |
|
- |
writer.write( "\t<jar href='" + path + fileName( file ) + "'/>\n" ); |
1050 |
|
- |
} |
1051 |
|
- |
|
1052 |
|
- |
writer.write( "</resources>\n" ); |
1053 |
|
- |
Paths nativePaths = new Paths( jwsDir, "*native*win*", "*win*native*" ); |
1054 |
|
- |
if ( nativePaths.count() == 1 ) |
1055 |
|
- |
{ |
1056 |
|
- |
writer.write( "<resources os='Windows'>\n" ); |
1057 |
|
- |
writer.write( "\t<j2se href='http://java.sun.com/products/autodl/j2se' version='1.5+' max-heap-size='128m'/>\n" ); |
1058 |
|
- |
writer.write( "\t<nativelib href='" + path + nativePaths.getNames().get( 0 ) + "'/>\n" ); |
1059 |
|
- |
writer.write( "</resources>\n" ); |
1060 |
|
- |
} |
1061 |
|
- |
nativePaths = new Paths( jwsDir, "*native*mac*", "*mac*native*" ); |
1062 |
|
- |
if ( nativePaths.count() == 1 ) |
1063 |
|
- |
{ |
1064 |
|
- |
writer.write( "<resources os='Mac'>\n" ); |
1065 |
|
- |
writer.write( "\t<j2se href='http://java.sun.com/products/autodl/j2se' version='1.5+' max-heap-size='128m'/>\n" ); |
1066 |
|
- |
writer.write( "\t<nativelib href='" + path + nativePaths.getNames().get( 0 ) + "'/>\n" ); |
1067 |
|
- |
writer.write( "</resources>\n" ); |
1068 |
|
- |
} |
1069 |
|
- |
nativePaths = new Paths( jwsDir, "*native*linux*", "*linux*native*" ); |
1070 |
|
- |
if ( nativePaths.count() == 1 ) |
1071 |
|
- |
{ |
1072 |
|
- |
writer.write( "<resources os='Linux'>\n" ); |
1073 |
|
- |
writer.write( "\t<j2se href='http://java.sun.com/products/autodl/j2se' version='1.5+' max-heap-size='128m'/>\n" ); |
1074 |
|
- |
writer.write( "\t<nativelib href='" + path + nativePaths.getNames().get( 0 ) + "'/>\n" ); |
1075 |
|
- |
writer.write( "</resources>\n" ); |
1076 |
|
- |
} |
1077 |
|
- |
nativePaths = new Paths( jwsDir, "*native*solaris*", "*solaris*native*" ); |
1078 |
|
- |
if ( nativePaths.count() == 1 ) |
1079 |
|
- |
{ |
1080 |
|
- |
writer.write( "<resources os='SunOS'>\n" ); |
1081 |
|
- |
writer.write( "\t<j2se href='http://java.sun.com/products/autodl/j2se' version='1.5+' max-heap-size='128m'/>\n" ); |
1082 |
|
- |
writer.write( "\t<nativelib href='" + path + nativePaths.getNames().get( 0 ) + "'/>\n" ); |
1083 |
|
- |
writer.write( "</resources>\n" ); |
1084 |
|
- |
} |
1085 |
|
- |
writer.write( "<application-desc main-class='" + project.getMain() + "'/>\n" ); |
1086 |
|
- |
writer.write( "</jnlp>" ); |
1087 |
|
- |
} |
1088 |
|
- |
catch ( IOException e ) |
1089 |
|
- |
{ |
1090 |
|
- |
throw new WrappedIOException( e ); |
1091 |
|
- |
} |
1092 |
|
- |
finally |
1093 |
|
- |
{ |
1094 |
|
- |
dispose( writer ); |
1095 |
|
- |
} |
1096 |
|
- |
} |
1097 |
|
- |
|
1098 |
|
- |
public String lwjglApplet( Project project, String keystoreFile, String alias, String password ) |
1099 |
|
- |
{ |
1100 |
|
- |
Util.assertNotNull( "Project", project ); |
1101 |
|
- |
Util.assertNotNull( "keystoreFile", keystoreFile ); |
1102 |
|
- |
Util.assertNotNull( "alias", alias ); |
1103 |
|
- |
Util.assertNotNull( "password", password ); |
1104 |
|
- |
if ( password.length() < 6 ) |
1105 |
|
- |
{ |
1106 |
|
- |
throw new IllegalArgumentException( "password must be 6 or more characters." ); |
1107 |
|
- |
} |
1108 |
|
- |
|
1109 |
|
- |
progress( "LWJGL applet: " + project ); |
1110 |
|
- |
|
1111 |
|
- |
String appletDir = mkdir( project.path( "$target$/applet-lwjgl/" ) ); |
1112 |
|
- |
String distDir = project.path( "$target$/dist/" ); |
1113 |
|
- |
new Paths( distDir, "**/*.jar", "*.html", "*.htm" ).flatten().copyTo( appletDir ); |
1114 |
|
- |
for ( String jarFile : new Paths( appletDir, "*.jar" ).getFullPaths() ) |
1115 |
|
- |
{ |
1116 |
|
- |
sign( unpack200( pack200( unsign( jarFile ) ) ), keystoreFile, alias, password ); |
1117 |
|
- |
String fileName = fileName( jarFile ); |
1118 |
|
- |
if ( fileName.equals( "lwjgl_util_applet.jar" ) || fileName.equals( "lzma.jar" ) ) |
1119 |
|
- |
{ |
1120 |
|
- |
continue; |
1121 |
|
- |
} |
1122 |
|
- |
if ( fileName.contains( "native" ) ) |
1123 |
|
- |
{ |
1124 |
|
- |
lzma( jarFile ); |
1125 |
|
- |
} |
1126 |
|
- |
else |
1127 |
|
- |
{ |
1128 |
|
- |
lzma( pack200( jarFile ) ); |
1129 |
|
- |
} |
1130 |
|
- |
} |
1131 |
|
- |
|
1132 |
|
- |
if ( !new Paths( appletDir, "*.html", "*.htm" ).isEmpty() ) |
1133 |
|
- |
{ |
1134 |
|
- |
return appletDir; |
1135 |
|
- |
} |
1136 |
|
- |
if ( !project.hasMain() ) |
1137 |
|
- |
{ |
1138 |
|
- |
LOGGER.debug.log( "Unable to generate applet.html: project has no main class" ); |
1139 |
|
- |
return appletDir; |
1140 |
|
- |
} |
1141 |
|
- |
progress( "Generating: applet.html" ); |
1142 |
|
- |
FileWriter writer; |
1143 |
|
- |
try |
1144 |
|
- |
{ |
1145 |
|
- |
writer = new FileWriter( appletDir + "applet.html" ); |
1146 |
|
- |
} |
1147 |
|
- |
catch ( IOException e ) |
1148 |
|
- |
{ |
1149 |
|
- |
throw new WrappedIOException( e ); |
1150 |
|
- |
} |
1151 |
|
- |
try |
1152 |
|
- |
{ |
1153 |
|
- |
writer.write( "<html>\n" ); |
1154 |
|
- |
writer.write( "<head><title>Applet</title></head>\n" ); |
1155 |
|
- |
writer.write( "<body>\n" ); |
1156 |
|
- |
writer.write( "<applet code='org.lwjgl.util.applet.AppletLoader' archive='lwjgl_util_applet.jar, lzma.jar' codebase='.' width='640' height='480'>\n" ); |
1157 |
|
- |
if ( project.hasVersion() ) |
1158 |
|
- |
{ |
1159 |
|
- |
writer.write( "<param name='al_version' value='" + project.getVersion() + "'>\n" ); |
1160 |
|
- |
} |
1161 |
|
- |
writer.write( "<param name='al_title' value='" + project + "'>\n" ); |
1162 |
|
- |
writer.write( "<param name='al_main' value='" + project.getMain() + "'>\n" ); |
1163 |
|
- |
writer.write( "<param name='al_jars' value='" ); |
1164 |
|
- |
int i = 0; |
1165 |
|
- |
for ( String name : new Paths( appletDir, "*.jar.pack.lzma" ).getNames() ) |
1166 |
|
- |
{ |
1167 |
|
- |
if ( i++ > 0 ) |
1168 |
|
- |
{ |
1169 |
|
- |
writer.write( ", " ); |
1170 |
|
- |
} |
1171 |
|
- |
writer.write( name ); |
1172 |
|
- |
} |
1173 |
|
- |
writer.write( "'>\n" ); |
1174 |
|
- |
Paths nativePaths = new Paths( appletDir, "*native*win*.jar.lzma", "*win*native*.jar.lzma" ); |
1175 |
|
- |
if ( nativePaths.count() == 1 ) |
1176 |
|
- |
{ |
1177 |
|
- |
writer.write( "<param name='al_windows' value='" + nativePaths.getNames().get( 0 ) + "'>\n" ); |
1178 |
|
- |
} |
1179 |
|
- |
nativePaths = new Paths( appletDir, "*native*mac*.jar.lzma", "*mac*native*.jar.lzma" ); |
1180 |
|
- |
if ( nativePaths.count() == 1 ) |
1181 |
|
- |
{ |
1182 |
|
- |
writer.write( "<param name='al_mac' value='" + nativePaths.getNames().get( 0 ) + "'>\n" ); |
1183 |
|
- |
} |
1184 |
|
- |
nativePaths = new Paths( appletDir, "*native*linux*.jar.lzma", "*linux*native*.jar.lzma" ); |
1185 |
|
- |
if ( nativePaths.count() == 1 ) |
1186 |
|
- |
{ |
1187 |
|
- |
writer.write( "<param name='al_linux' value='" + nativePaths.getNames().get( 0 ) + "'>\n" ); |
1188 |
|
- |
} |
1189 |
|
- |
nativePaths = new Paths( appletDir, "*native*solaris*.jar.lzma", "*solaris*native*.jar.lzma" ); |
1190 |
|
- |
if ( nativePaths.count() == 1 ) |
1191 |
|
- |
{ |
1192 |
|
- |
writer.write( "<param name='al_solaris' value='" + nativePaths.getNames().get( 0 ) + "'>\n" ); |
1193 |
|
- |
} |
1194 |
|
- |
writer.write( "<param name='al_logo' value='appletlogo.png'>\n" ); |
1195 |
|
- |
writer.write( "<param name='al_progressbar' value='appletprogress.gif'>\n" ); |
1196 |
|
- |
writer.write( "<param name='separate_jvm' value='true'>\n" ); |
1197 |
|
- |
writer.write( "<param name='java_arguments' value='-Dsun.java2d.noddraw=true -Dsun.awt.noerasebackground=true -Dsun.java2d.d3d=false -Dsun.java2d.opengl=false -Dsun.java2d.pmoffscreen=false'>\n" ); |
1198 |
|
- |
writer.write( "</applet>\n" ); |
1199 |
|
- |
writer.write( "</body></html>\n" ); |
1200 |
|
- |
} |
1201 |
|
- |
catch ( IOException e ) |
1202 |
|
- |
{ |
1203 |
|
- |
throw new WrappedIOException( e ); |
1204 |
|
- |
} |
1205 |
|
- |
finally |
1206 |
|
- |
{ |
1207 |
|
- |
dispose( writer ); |
1208 |
|
- |
} |
1209 |
|
- |
return appletDir; |
1210 |
|
- |
} |
1211 |
|
- |
|
1212 |
|
- |
/** |
1213 |
|
- |
* Compiles and executes the specified Java code. The code is compiled as if it were a Java method body. |
1214 |
|
- |
* <p/> |
1215 |
|
- |
* Imports statements can be used at the start of the code. These imports are automatically used:<br> |
1216 |
|
- |
* import com.esotericsoftware.scar.Scar;<br> |
1217 |
|
- |
* import com.esotericsoftware.filesystem.Paths;<br> |
1218 |
|
- |
* import com.esotericsoftware.minlog.Log;<br> |
1219 |
|
- |
* import static com.esotericsoftware.scar.Scar.*;<br> |
1220 |
|
- |
* import static com.esotericsoftware.minlog.Log.*;<br> |
1221 |
|
- |
* <p/> |
1222 |
|
- |
* Entries can be added to the classpath by using "classpath [url];" statements at the start of the code. These classpath |
1223 |
|
- |
* entries are checked before the classloader that loaded the Scar class is checked. Examples:<br> |
1224 |
|
- |
* classpath someTools.jar;<br> |
1225 |
|
- |
* classpath some/directory/of/class/files;<br> |
1226 |
|
- |
* classpath http://example.com/someTools.jar;<br> |
1227 |
|
- |
* |
1228 |
|
- |
* @param parameters These parameters will be available in the scope where the code is executed. |
1229 |
|
- |
*/ |
1230 |
|
- |
public void executeCode( Project project, String code, HashMap<String, Object> parameters ) |
1231 |
|
- |
{ |
1232 |
|
- |
try |
1233 |
|
- |
{ |
1234 |
|
- |
// Wrap code in a class. |
1235 |
|
- |
StringBuilder classBuffer = new StringBuilder( 2048 ); |
1236 |
|
- |
classBuffer.append( "import com.esotericsoftware.scar.*;\n" ); |
1237 |
|
- |
classBuffer.append( "import com.esotericsoftware.minlog.Log;\n" ); |
1238 |
|
- |
classBuffer.append( "import com.esotericsoftware.filesystem.Paths;\n" ); |
1239 |
|
- |
classBuffer.append( "import static com.esotericsoftware.scar.Scar.*;\n" ); |
1240 |
|
- |
classBuffer.append( "import static com.esotericsoftware.minlog.Log.*;\n" ); |
1241 |
|
- |
classBuffer.append( "public class Generated {\n" ); |
1242 |
|
- |
int pOverheadStartLines = 6; |
1243 |
|
- |
classBuffer.append( "public void execute (" ); |
1244 |
|
- |
int i = 0; |
1245 |
|
- |
for ( Entry<String, Object> entry : parameters.entrySet() ) |
1246 |
|
- |
{ |
1247 |
|
- |
if ( i++ > 0 ) |
1248 |
|
- |
{ |
1249 |
|
- |
classBuffer.append( ',' ); |
1250 |
|
- |
} |
1251 |
|
- |
classBuffer.append( '\n' ); |
1252 |
|
- |
pOverheadStartLines++; |
1253 |
|
- |
classBuffer.append( entry.getValue().getClass().getName() ); |
1254 |
|
- |
classBuffer.append( ' ' ); |
1255 |
|
- |
classBuffer.append( entry.getKey() ); |
1256 |
|
- |
} |
1257 |
|
- |
classBuffer.append( "\n) throws Exception {\n" ); |
1258 |
|
- |
pOverheadStartLines += 2; |
1259 |
|
- |
|
1260 |
|
- |
// Append code, collecting imports statements and classpath URLs. |
1261 |
|
- |
StringBuilder importBuffer = new StringBuilder( 512 ); |
1262 |
|
- |
ArrayList<URL> classpathURLs = new ArrayList<URL>(); |
1263 |
|
- |
BufferedReader reader = new BufferedReader( new StringReader( code ) ); |
1264 |
|
- |
boolean header = true; |
1265 |
|
- |
while ( true ) |
1266 |
|
- |
{ |
1267 |
|
- |
String line = reader.readLine(); |
1268 |
|
- |
if ( line == null ) |
1269 |
|
- |
{ |
1270 |
|
- |
break; |
1271 |
|
- |
} |
1272 |
|
- |
String trimmed = line.trim(); |
1273 |
|
- |
if ( header && trimmed.startsWith( "import " ) && trimmed.endsWith( ";" ) ) |
1274 |
|
- |
{ |
1275 |
|
- |
importBuffer.append( line ); |
1276 |
|
- |
importBuffer.append( '\n' ); |
1277 |
|
- |
} |
1278 |
|
- |
else if ( header && trimmed.startsWith( "classpath " ) && trimmed.endsWith( ";" ) ) |
1279 |
|
- |
{ |
1280 |
|
- |
String path = substring( line.trim(), 10, -1 ); |
1281 |
|
- |
try |
1282 |
|
- |
{ |
1283 |
|
- |
classpathURLs.add( new URL( path ) ); |
1284 |
|
- |
} |
1285 |
|
- |
catch ( MalformedURLException ex ) |
1286 |
|
- |
{ |
1287 |
|
- |
classpathURLs.add( new File( project.path( path ) ).toURI().toURL() ); |
1288 |
|
- |
} |
1289 |
|
- |
} |
1290 |
|
- |
else |
1291 |
|
- |
{ |
1292 |
|
- |
if ( trimmed.length() > 0 ) |
1293 |
|
- |
{ |
1294 |
|
- |
header = false; |
1295 |
|
- |
} |
1296 |
|
- |
classBuffer.append( line ); |
1297 |
|
- |
classBuffer.append( '\n' ); |
1298 |
|
- |
} |
1299 |
|
- |
} |
1300 |
|
- |
classBuffer.append( "}}" ); |
1301 |
|
- |
|
1302 |
|
- |
final String classCode = importBuffer.append( classBuffer ).toString(); |
1303 |
|
- |
if ( LOGGER.trace.isEnabled() ) |
1304 |
|
- |
{ |
1305 |
|
- |
progress( "Executing code:\n" + classCode ); |
1306 |
|
- |
} |
1307 |
|
- |
// Compile class. |
1308 |
|
- |
Class generatedClass = compileDynamicCodeToClass( pOverheadStartLines, classCode, classpathURLs.toArray( new URL[classpathURLs.size()] ) ); |
1309 |
|
- |
|
1310 |
|
- |
// Execute. |
1311 |
|
- |
Class[] parameterTypes = new Class[parameters.size()]; |
1312 |
|
- |
Object[] parameterValues = new Object[parameters.size()]; |
1313 |
|
- |
i = 0; |
1314 |
|
- |
for ( Object object : parameters.values() ) |
1315 |
|
- |
{ |
1316 |
|
- |
parameterValues[i] = object; |
1317 |
|
- |
parameterTypes[i++] = object.getClass(); |
1318 |
|
- |
} |
1319 |
|
- |
generatedClass.getMethod( "execute", parameterTypes ).invoke( generatedClass.newInstance(), parameterValues ); |
1320 |
|
- |
} |
1321 |
|
- |
catch ( Throwable ex ) |
1322 |
|
- |
{ |
1323 |
|
- |
throw new RuntimeException( "Error executing code:\n" + code.trim(), ex ); |
1324 |
|
- |
} |
1325 |
|
- |
} |
1326 |
|
- |
|
1327 |
|
- |
// /** |
1328 |
|
- |
// * Executes Java code in the specified project's document, if any. |
1329 |
|
- |
// * |
1330 |
|
- |
// * @return true if code was executed. |
1331 |
|
- |
// */ |
1332 |
|
- |
// public boolean executeDocument( Project project ) |
1333 |
|
- |
// { |
1334 |
|
- |
// String code = null; // todo: was -- project.getDocument(); |
1335 |
|
- |
// if ( code == null || code.trim().isEmpty() ) |
1336 |
|
- |
// { |
1337 |
|
- |
// return false; |
1338 |
|
- |
// } |
1339 |
|
- |
// HashMap<String, Object> parameters = new HashMap<String, Object>(); |
1340 |
|
- |
// parameters.put( "project", project ); |
1341 |
|
- |
// executeCode( project, code, parameters ); |
1342 |
|
- |
// return true; |
1343 |
|
- |
// } |
1344 |
|
- |
|
1345 |
|
- |
// /** |
1346 |
|
- |
// * List of project names that have been built. {@link #buildDependencies(Project)} will skip any projects with a matching name. |
1347 |
|
- |
// */ |
1348 |
|
- |
// static public final List<String> builtProjects = new ArrayList<String>(); |
1349 |
|
- |
// |
1350 |
|
- |
static |
1351 |
|
- |
{ |
1352 |
|
- |
Paths.addDefaultGlobExcludes( "**/.svn/**" ); |
1353 |
|
- |
} |
1354 |
|
- |
|
1355 |
|
- |
/// todo: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Here be Dragons ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
1356 |
|
- |
/// todo: ================================================================================================================== |
1357 |
|
- |
/// todo: ================================================================================================================== |
1358 |
|
- |
/// todo: ================================================================================================================== |
1359 |
|
- |
/// todo: ================================================================================================================== |
1360 |
|
- |
/// todo: ================================================================================================================== |
1361 |
|
- |
/// todo: ================================================================================================================== |
1362 |
|
- |
/// todo: ================================================================================================================== |
1363 |
|
- |
/// todo: ================================================================================================================== |
1364 |
|
- |
/// todo: ================================================================================================================== |
1365 |
|
- |
/// todo: ================================================================================================================== |
1366 |
|
- |
/// todo: ================================================================================================================== |
1367 |
|
- |
|
1368 |
|
- |
private static class BuildFileFilter implements FileFilter |
1369 |
|
- |
{ |
1370 |
|
- |
private static final String DEFAULT_JAVA_PROJECT_FILE_NAME = DEFAULT_PROJECT_FILE_NAME + JAVA_EXTENSION; |
1371 |
|
- |
private static final String DEFAULT_YAML_PROJECT_FILE_NAME = DEFAULT_PROJECT_FILE_NAME + YAML_EXTENSION; |
1372 |
|
- |
|
1373 |
|
- |
@Override |
1374 |
|
- |
public boolean accept( File pFile ) |
1375 |
|
- |
{ |
1376 |
|
- |
if ( pFile.isFile() ) |
1377 |
|
- |
{ |
1378 |
|
- |
String zName = pFile.getName(); |
1379 |
|
- |
if ( DEFAULT_JAVA_PROJECT_FILE_NAME.equalsIgnoreCase( zName ) || DEFAULT_YAML_PROJECT_FILE_NAME.equalsIgnoreCase( zName ) ) |
1380 |
|
- |
{ |
1381 |
|
- |
return pFile.canRead(); |
1382 |
|
- |
} |
1383 |
|
- |
} |
1384 |
|
- |
return false; |
1385 |
|
- |
} |
1386 |
|
- |
|
1387 |
|
- |
public static final FileFilter INSTANCE = new BuildFileFilter(); |
1388 |
|
- |
} |
1389 |
|
- |
|
1390 |
|
- |
private static class ProjectCache |
1391 |
|
- |
{ |
1392 |
|
- |
private Map<String, Project> mProjectByName = new HashMap<String, Project>(); |
1393 |
|
- |
private Map<String, Project> mProjectByPath = new HashMap<String, Project>(); |
1394 |
|
- |
|
1395 |
|
- |
public synchronized Project getByPath( String pPath ) |
1396 |
|
- |
{ |
1397 |
|
- |
return mProjectByPath.get( pPath ); |
1398 |
|
- |
} |
1399 |
|
- |
|
1400 |
|
- |
private Project initialize( ProjectFactory pFactory, String pPath, Project pProject ) |
1401 |
|
- |
{ |
1402 |
|
- |
synchronized ( this ) |
1403 |
|
- |
{ |
1404 |
|
- |
String zName = pProject.getName(); |
1405 |
|
- |
Project zProject = mProjectByName.get( zName ); |
1406 |
|
- |
if ( zProject != null ) |
1407 |
|
- |
{ |
1408 |
|
- |
mProjectByPath.put( pPath, zProject ); |
1409 |
|
- |
return zProject; |
1410 |
|
- |
} |
1411 |
|
- |
mProjectByPath.put( pPath, pProject ); |
1412 |
|
- |
mProjectByName.put( zName, pProject ); |
1413 |
|
- |
} |
1414 |
|
- |
pProject.initialize( pFactory ); |
1415 |
|
- |
return pProject; |
1416 |
|
- |
} |
1417 |
|
- |
|
1418 |
|
- |
public Set<Project> getAllProjects() |
1419 |
|
- |
{ |
1420 |
|
- |
return new HashSet<Project>( mProjectByName.values() ); |
1421 |
|
- |
} |
1422 |
|
- |
} |
1423 |
|
- |
|
1424 |
|
- |
protected Runnable createRunnableFor( String pMethodName ) |
1425 |
|
- |
{ |
1426 |
|
- |
Runnable zRunnable = createRunnableFor( this, pMethodName ); |
1427 |
|
- |
return (zRunnable != null) ? zRunnable : createRunnableFor( mLaunchProject, pMethodName ); |
1428 |
|
- |
} |
1429 |
|
- |
|
1430 |
|
- |
protected Runnable createRunnableFor( final Object pObject, String pMethodName ) |
1431 |
|
- |
{ |
1432 |
|
- |
final Method zMethod = getMatchingMethod( pObject, pMethodName ); |
1433 |
|
- |
return (zMethod == null) ? null : new Runnable() |
1434 |
|
- |
{ |
1435 |
|
- |
@Override public void run() |
1436 |
|
- |
{ |
1437 |
|
- |
try |
1438 |
|
- |
{ |
1439 |
|
- |
zMethod.invoke( pObject ); |
1440 |
|
- |
} |
1441 |
|
- |
catch ( Exception e ) |
1442 |
|
- |
{ |
1443 |
|
- |
throw new RuntimeException( e ); |
1444 |
|
- |
} |
1445 |
|
- |
} |
1446 |
|
- |
}; |
1447 |
|
- |
} |
1448 |
|
- |
|
1449 |
|
- |
protected Method getMatchingMethod( Object pObject, String pMethodName ) |
1450 |
|
- |
{ |
1451 |
|
- |
List<Method> zFound = new ArrayList<Method>(); |
1452 |
|
- |
Method[] zMethods = pObject.getClass().getMethods(); |
1453 |
|
- |
for ( Method zMethod : zMethods ) |
1454 |
|
- |
{ |
1455 |
|
- |
if ( zMethod.getReturnType().equals( Void.TYPE ) && (zMethod.getParameterTypes().length == 0) ) |
1456 |
|
- |
{ |
1457 |
|
- |
if ( pMethodName.equals( zMethod.getName() ) ) |
1458 |
|
- |
{ |
1459 |
|
- |
return zMethod; |
1460 |
|
- |
} |
1461 |
|
- |
if ( pMethodName.equalsIgnoreCase( zMethod.getName() ) ) |
1462 |
|
- |
{ |
1463 |
|
- |
zFound.add( zMethod ); |
1464 |
|
- |
} |
1465 |
|
- |
} |
1466 |
|
- |
} |
1467 |
|
- |
if ( zFound.size() == 0 ) |
1468 |
|
- |
{ |
1469 |
|
- |
return null; |
1470 |
|
- |
} |
1471 |
|
- |
if ( zFound.size() == 1 ) |
1472 |
|
- |
{ |
1473 |
|
- |
return zFound.get( 0 ); |
1474 |
|
- |
} |
1475 |
|
- |
throw new IllegalArgumentException( "Multiple Methods " + zFound + " found on '" + pObject.getClass().getSimpleName() + "' than match: " + pMethodName ); |
1476 |
|
- |
} |
1477 |
|
- |
|
1478 |
|
- |
protected void createLaunchProject() |
1479 |
|
- |
{ |
1480 |
|
- |
mLaunchProject = project( CANONICAL_USER_DIR, mArgs.get( "file", "." ) ); |
1481 |
|
- |
} |
1482 |
|
- |
|
1483 |
|
- |
protected int run() |
1484 |
|
- |
{ |
1485 |
|
- |
System.out.println( getClass().getSimpleName() + " vs " + VERSION ); |
1486 |
|
- |
if ( mArgs.count() == 0 ) |
1487 |
|
- |
{ |
1488 |
|
- |
mLaunchProject.build(); |
1489 |
|
- |
return 0; |
1490 |
|
- |
} |
1491 |
|
- |
List<Runnable> zToExecute = getArgsBasedRunnables(); |
1492 |
|
- |
for ( Runnable zRunnable : zToExecute ) |
1493 |
|
- |
{ |
1494 |
|
- |
zRunnable.run(); |
1495 |
|
- |
} |
1496 |
|
- |
return 0; |
1497 |
|
- |
} |
1498 |
|
- |
|
1499 |
|
- |
private ArrayList<Runnable> getArgsBasedRunnables() |
1500 |
|
- |
{ |
1501 |
|
- |
ArrayList<Runnable> zRunnables = new ArrayList<Runnable>(); |
1502 |
|
- |
List<String> zUnrecognizedNames = new ArrayList<String>(); |
1503 |
|
- |
for ( Arguments.NameValuePair zPair; null != (zPair = mArgs.getNext()); ) |
1504 |
|
- |
{ |
1505 |
|
- |
Runnable zRunnable = createRunnableFor( zPair.getName() ); |
1506 |
|
- |
if ( zRunnable != null ) |
1507 |
|
- |
{ |
1508 |
|
- |
zRunnables.add( zRunnable ); |
1509 |
|
- |
} |
1510 |
|
- |
else |
1511 |
|
- |
{ |
1512 |
|
- |
zUnrecognizedNames.add( zPair.getName() ); |
1513 |
|
- |
} |
1514 |
|
- |
} |
1515 |
|
- |
if ( !zUnrecognizedNames.isEmpty() ) |
1516 |
|
- |
{ |
1517 |
|
- |
System.err.println( "\nUnrecognized Command Line Args:" ); |
1518 |
|
- |
for ( String zName : zUnrecognizedNames ) |
1519 |
|
- |
{ |
1520 |
|
- |
System.err.println( " " + zName ); |
1521 |
|
- |
} |
1522 |
|
- |
System.exit( 1 ); |
1523 |
|
- |
} |
1524 |
|
- |
return zRunnables; |
1525 |
|
- |
} |
1526 |
|
- |
|
1527 |
|
- |
public static void main( String[] args ) |
1528 |
|
- |
throws Exception |
1529 |
|
- |
{ |
1530 |
|
- |
Arguments arguments = new Arguments( args ); |
1531 |
|
- |
Scar scar = new Scar( arguments ); |
1532 |
|
- |
scar.initLoggerFactory(); |
1533 |
|
- |
scar.createLaunchProject(); |
1534 |
|
- |
System.exit( scar.run() ); |
1535 |
|
- |
} |
1536 |
|
- |
} |
|
1 |
+ |
package com.esotericsoftware.scar; |
|
2 |
+ |
|
|
3 |
+ |
import org.litesoft.logger.*; |
|
4 |
+ |
import org.litesoft.logger.nonpublic.*; |
|
5 |
+ |
|
|
6 |
+ |
import SevenZip.*; |
|
7 |
+ |
import com.esotericsoftware.filesystem.*; |
|
8 |
+ |
import com.esotericsoftware.scar.support.*; |
|
9 |
+ |
import com.esotericsoftware.utils.*; |
|
10 |
+ |
import com.esotericsoftware.yamlbeans.*; |
|
11 |
+ |
import com.esotericsoftware.yamlbeans.parser.*; |
|
12 |
+ |
import com.esotericsoftware.yamlbeans.tokenizer.*; |
|
13 |
+ |
|
|
14 |
+ |
import java.io.*; |
|
15 |
+ |
import java.lang.reflect.*; |
|
16 |
+ |
import java.net.*; |
|
17 |
+ |
import java.util.*; |
|
18 |
+ |
import java.util.Map.*; |
|
19 |
+ |
import java.util.jar.*; |
|
20 |
+ |
import java.util.zip.*; |
|
21 |
+ |
|
|
22 |
+ |
// BOZO - Add javadocs method. |
|
23 |
+ |
|
|
24 |
+ |
/** |
|
25 |
+ |
* Provides utility methods for common Java build tasks. |
|
26 |
+ |
*/ |
|
27 |
+ |
@SuppressWarnings({"ResultOfMethodCallIgnored"}) |
|
28 |
+ |
public class Scar extends Utils implements ProjectFactory |
|
29 |
+ |
{ |
|
30 |
+ |
public static final String VERSION = "2.92 - 1.7"; |
|
31 |
+ |
|
|
32 |
+ |
public static final String DEFAULT_PROJECT_FILE_NAME = "Build"; |
|
33 |
+ |
|
|
34 |
+ |
public static final String JAVA_EXTENSION = ".java"; |
|
35 |
+ |
public static final String YAML_EXTENSION = ".yaml"; |
|
36 |
+ |
|
|
37 |
+ |
protected static final Logger LOGGER = LoggerFactory.getLogger( Scar.class ); |
|
38 |
+ |
|
|
39 |
+ |
protected final ProjectCache mProjectCache = new ProjectCache(); |
|
40 |
+ |
|
|
41 |
+ |
private Project mLaunchProject; |
|
42 |
+ |
|
|
43 |
+ |
/** |
|
44 |
+ |
* The command line arguments Scar was started with. Empty if Scar was started with no arguments or Scar was not started from |
|
45 |
+ |
* the command line. |
|
46 |
+ |
*/ |
|
47 |
+ |
public final Arguments mArgs; |
|
48 |
+ |
|
|
49 |
+ |
public Scar( Arguments pArgs ) |
|
50 |
+ |
{ |
|
51 |
+ |
mArgs = (pArgs != null) ? pArgs : new Arguments(); |
|
52 |
+ |
} |
|
53 |
+ |
|
|
54 |
+ |
@SuppressWarnings({"UnusedDeclaration"}) |
|
55 |
+ |
public Project getLaunchProject() |
|
56 |
+ |
{ |
|
57 |
+ |
return mLaunchProject; |
|
58 |
+ |
} |
|
59 |
+ |
|
|
60 |
+ |
/** |
|
61 |
+ |
* Loads the specified project with default values and loads any other projects needed for the "include" property. |
|
62 |
+ |
* |
|
63 |
+ |
* @param pCanonicalCurrentDirectory |
|
64 |
+ |
* @param pPath Path to a YAML project file, or a directory containing a "project.yaml" file. |
|
65 |
+ |
*/ |
|
66 |
+ |
@Override |
|
67 |
+ |
public Project project( File pCanonicalCurrentDirectory, String pPath ) |
|
68 |
+ |
{ |
|
69 |
+ |
Util.assertNotNull( "CurrentDirectory", pCanonicalCurrentDirectory ); |
|
70 |
+ |
pPath = Util.assertNotEmpty( "Path", pPath ); |
|
71 |
+ |
File zFile = new File( pPath ); |
|
72 |
+ |
if ( !zFile.isAbsolute() ) |
|
73 |
+ |
{ |
|
74 |
+ |
zFile = new File( pCanonicalCurrentDirectory, pPath ); |
|
75 |
+ |
} |
|
76 |
+ |
try |
|
77 |
+ |
{ |
|
78 |
+ |
zFile = zFile.getCanonicalFile(); |
|
79 |
+ |
} |
|
80 |
+ |
catch ( IOException e ) |
|
81 |
+ |
{ |
|
82 |
+ |
throw new WrappedIOException( e ); |
|
83 |
+ |
} |
|
84 |
+ |
|
|
85 |
+ |
String zPath = zFile.getPath(); |
|
86 |
+ |
Project zProject = mProjectCache.getByPath( zPath ); |
|
87 |
+ |
if ( zProject != null ) |
|
88 |
+ |
{ |
|
89 |
+ |
return zProject; |
|
90 |
+ |
} |
|
91 |
+ |
try |
|
92 |
+ |
{ |
|
93 |
+ |
if ( zFile.isFile() ) // Assume Project Build File |
|
94 |
+ |
{ |
|
95 |
+ |
return mProjectCache.initialize( this, zPath, createProject( zFile, zFile.getParentFile() ) ); |
|
96 |
+ |
} |
|
97 |
+ |
if ( zFile.isDirectory() ) // Assume Project Dir |
|
98 |
+ |
{ |
|
99 |
+ |
return mProjectCache.initialize( this, zPath, createProject( findBuildFile( zFile ), zFile, zFile.getName() ) ); |
|
100 |
+ |
} |
|
101 |
+ |
} |
|
102 |
+ |
catch ( WrappedIOException e ) |
|
103 |
+ |
{ |
|
104 |
+ |
throw new WrappedIOException( pPath, e ); |
|
105 |
+ |
} |
|
106 |
+ |
throw new IllegalArgumentException( "Project is Neither a Project File, nor a Project Directory: " + zFile ); |
|
107 |
+ |
} |
|
108 |
+ |
|
|
109 |
+ |
protected File findBuildFile( File pProjectDir ) |
|
110 |
+ |
{ |
|
111 |
+ |
File[] zFiles = pProjectDir.listFiles( BuildFileFilter.INSTANCE ); |
|
112 |
+ |
if ( (zFiles == null) || (zFiles.length == 0) ) |
|
113 |
+ |
{ |
|
114 |
+ |
return null; |
|
115 |
+ |
} |
|
116 |
+ |
if ( zFiles.length == 1 ) |
|
117 |
+ |
{ |
|
118 |
+ |
return zFiles[0]; |
|
119 |
+ |
} |
|
120 |
+ |
File zFile = findBuildFile( zFiles, JAVA_EXTENSION ); |
|
121 |
+ |
return (zFile != null) ? zFile : findBuildFile( zFiles, YAML_EXTENSION ); |
|
122 |
+ |
} |
|
123 |
+ |
|
|
124 |
+ |
private File findBuildFile( File[] pFiles, String pExtension ) |
|
125 |
+ |
{ |
|
126 |
+ |
File rv = null; |
|
127 |
+ |
for ( File zFile : pFiles ) |
|
128 |
+ |
{ |
|
129 |
+ |
if ( zFile.getName().endsWith( pExtension ) ) |
|
130 |
+ |
{ |
|
131 |
+ |
if ( rv != null ) |
|
132 |
+ |
{ |
|
133 |
+ |
throw new IllegalStateException( "Found Both:\n " + rv + "\n " + zFile ); |
|
134 |
+ |
} |
|
135 |
+ |
rv = zFile; |
|
136 |
+ |
} |
|
137 |
+ |
} |
|
138 |
+ |
return rv; |
|
139 |
+ |
} |
|
140 |
+ |
|
|
141 |
+ |
protected Project createProject( File pPossibleBuildFile, File pCanonicalProjectDir ) |
|
142 |
+ |
{ |
|
143 |
+ |
String zBuildFileName = pPossibleBuildFile.getName(); |
|
144 |
+ |
int zDotAt = zBuildFileName.lastIndexOf( '.' ); |
|
145 |
+ |
if ( (zDotAt != -1) && (pCanonicalProjectDir != null) ) |
|
146 |
+ |
{ |
|
147 |
+ |
String zName = zBuildFileName.substring( 0, zDotAt ).trim(); |
|
148 |
+ |
if ( DEFAULT_PROJECT_FILE_NAME.equalsIgnoreCase( zName ) ) |
|
149 |
+ |
{ |
|
150 |
+ |
zName = pCanonicalProjectDir.getName(); |
|
151 |
+ |
} |
|
152 |
+ |
return createProject( pPossibleBuildFile, pCanonicalProjectDir, zName ); |
|
153 |
+ |
} |
|
154 |
+ |
throw new IllegalArgumentException( "Unacceptable Project Path or Name, Project File " + pPossibleBuildFile ); |
|
155 |
+ |
} |
|
156 |
+ |
|
|
157 |
+ |
protected Project createProject( File pBuildFile, File pCanonicalProjectDir, String pProjectName ) |
|
158 |
+ |
{ |
|
159 |
+ |
if ( pBuildFile == null ) |
|
160 |
+ |
{ |
|
161 |
+ |
throw new IllegalArgumentException( "No 'Build.java' or 'Build.yaml' file found in Project Directory: " + pCanonicalProjectDir ); |
|
162 |
+ |
} |
|
163 |
+ |
String zBuildFileName = pBuildFile.getName(); |
|
164 |
+ |
if ( zBuildFileName.endsWith( JAVA_EXTENSION ) ) |
|
165 |
+ |
{ |
|
166 |
+ |
return createJavaProject( pBuildFile, pCanonicalProjectDir, pProjectName ); |
|
167 |
+ |
} |
|
168 |
+ |
if ( zBuildFileName.endsWith( YAML_EXTENSION ) ) |
|
169 |
+ |
{ |
|
170 |
+ |
return createYamlProject( pBuildFile, pCanonicalProjectDir, pProjectName ); |
|
171 |
+ |
} |
|
172 |
+ |
throw new IllegalArgumentException( pBuildFile + " was NOT either a '.java' or a '.yaml' file!" ); |
|
173 |
+ |
} |
|
174 |
+ |
|
|
175 |
+ |
protected Project createYamlProject( File pYamlBuildFile, File pCanonicalProjectDir, String pProjectName ) |
|
176 |
+ |
{ |
|
177 |
+ |
List<String> zLines = readLines( pYamlBuildFile ); |
|
178 |
+ |
int at = findLine( zLines, "---" ); |
|
179 |
+ |
String zYAML, zCode = null; |
|
180 |
+ |
if ( at == -1 ) |
|
181 |
+ |
{ |
|
182 |
+ |
zYAML = mergeLines( zLines, 0 ); |
|
183 |
+ |
} |
|
184 |
+ |
else |
|
185 |
+ |
{ |
|
186 |
+ |
zYAML = mergeLines( zLines, 0, at ); |
|
187 |
+ |
zCode = Util.noEmpty( mergeLines( zLines, at + 1 ) ); |
|
188 |
+ |
} |
|
189 |
+ |
Map<Object, Object> zData = (zYAML.length() == 0) ? new HashMap<Object, Object>() : parseYAML( pCanonicalProjectDir, zYAML ); |
|
190 |
+ |
Class<? extends Project> zClass = createYamlProjectClass(); |
|
191 |
+ |
if ( zCode != null ) |
|
192 |
+ |
{ |
|
193 |
+ |
zClass = createYamlCodeProjectClass( zClass, zCode, at + 1 ); |
|
194 |
+ |
} |
|
195 |
+ |
return instantiate( pYamlBuildFile, zClass, pCanonicalProjectDir, pProjectName, zData ); |
|
196 |
+ |
} |
|
197 |
+ |
|
|
198 |
+ |
protected Project createJavaProject( File pJavaBuildFile, File pCanonicalProjectDir, String pProjectName ) |
|
199 |
+ |
{ |
|
200 |
+ |
String zFile = mergeLines( readLines( pJavaBuildFile ), 0 ); |
|
201 |
+ |
Class<? extends Project> zClass = createJavaProjectClass(); |
|
202 |
+ |
zClass = createJavaCodeProjectClass( zClass, zFile ); |
|
203 |
+ |
return instantiate( pJavaBuildFile, zClass, pCanonicalProjectDir, pProjectName, null ); |
|
204 |
+ |
} |
|
205 |
+ |
|
|
206 |
+ |
protected Project instantiate( File zProjectFile, Class<? extends Project> pClass, File pCanonicalProjectDir, String pProjectName, Map<Object, Object> pData ) |
|
207 |
+ |
{ |
|
208 |
+ |
return instantiate( pClass, new ProjectParameters( zProjectFile, pProjectName, pCanonicalProjectDir, pData ) ); |
|
209 |
+ |
} |
|
210 |
+ |
|
|
211 |
+ |
protected Project instantiate( Class<? extends Project> pClass, ProjectParameters pParameters ) |
|
212 |
+ |
{ |
|
213 |
+ |
Throwable zCause; |
|
214 |
+ |
try |
|
215 |
+ |
{ |
|
216 |
+ |
Constructor zConstructor = pClass.getConstructor( ProjectParameters.class ); |
|
217 |
+ |
return (Project) zConstructor.newInstance( pParameters ); |
|
218 |
+ |
} |
|
219 |
+ |
catch ( NoSuchMethodException e ) |
|
220 |
+ |
{ |
|
221 |
+ |
zCause = e; |
|
222 |
+ |
} |
|
223 |
+ |
catch ( InvocationTargetException e ) |
|
224 |
+ |
{ |
|
225 |
+ |
zCause = e; |
|
226 |
+ |
} |
|
227 |
+ |
catch ( ClassCastException e ) |
|
228 |
+ |
{ |
|
229 |
+ |
zCause = e; |
|
230 |
+ |
} |
|
231 |
+ |
catch ( InstantiationException e ) |
|
232 |
+ |
{ |
|
233 |
+ |
zCause = e; |
|
234 |
+ |
} |
|
235 |
+ |
catch ( IllegalAccessException e ) |
|
236 |
+ |
{ |
|
237 |
+ |
zCause = e; |
|
238 |
+ |
} |
|
239 |
+ |
catch ( RuntimeException e ) |
|
240 |
+ |
{ |
|
241 |
+ |
zCause = e; |
|
242 |
+ |
} |
|
243 |
+ |
throw new RuntimeException( "Unable to Instantiate Project Class for Project: " + pParameters.getName() + " in dir " + pParameters.getCanonicalProjectDir(), zCause ); |
|
244 |
+ |
} |
|
245 |
+ |
|
|
246 |
+ |
protected Class<? extends Project> createYamlProjectClass() |
|
247 |
+ |
{ |
|
248 |
+ |
return Project.class; |
|
249 |
+ |
} |
|
250 |
+ |
|
|
251 |
+ |
protected Class<? extends Project> createJavaProjectClass() |
|
252 |
+ |
{ |
|
253 |
+ |
return Project.class; |
|
254 |
+ |
} |
|
255 |
+ |
|
|
256 |
+ |
protected Map<Object, Object> parseYAML( File pProjectDir, String pYAML ) |
|
257 |
+ |
{ |
|
258 |
+ |
final String zProjectDir = pProjectDir.getPath().replace( '\\', '/' ); |
|
259 |
+ |
|
|
260 |
+ |
YamlReader yamlReader = new YamlReader( new StringReader( pYAML ) ) |
|
261 |
+ |
{ |
|
262 |
+ |
@Override |
|
263 |
+ |
protected Object readValue( Class type, Class elementType, Class defaultType ) |
|
264 |
+ |
throws YamlException, Parser.ParserException, Tokenizer.TokenizerException |
|
265 |
+ |
{ |
|
266 |
+ |
Object value = super.readValue( type, elementType, defaultType ); |
|
267 |
+ |
if ( value instanceof String ) |
|
268 |
+ |
{ |
|
269 |
+ |
value = ((String) value).replaceAll( "\\$dir\\$", zProjectDir ); |
|
270 |
+ |
} |
|
271 |
+ |
return value; |
|
272 |
+ |
} |
|
273 |
+ |
}; |
|
274 |
+ |
try |
|
275 |
+ |
{ |
|
276 |
+ |
//noinspection unchecked |
|
277 |
+ |
return yamlReader.read( HashMap.class ); |
|
278 |
+ |
} |
|
279 |
+ |
catch ( IOException e ) |
|
280 |
+ |
{ |
|
281 |
+ |
throw new WrappedIOException( e ); |
|
282 |
+ |
} |
|
283 |
+ |
finally |
|
284 |
+ |
{ |
|
285 |
+ |
try |
|
286 |
+ |
{ |
|
287 |
+ |
yamlReader.close(); |
|
288 |
+ |
} |
|
289 |
+ |
catch ( IOException e ) |
|
290 |
+ |
{ |
|
291 |
+ |
throw new WrappedIOException( e ); |
|
292 |
+ |
} |
|
293 |
+ |
} |
|
294 |
+ |
} |
|
295 |
+ |
|
|
296 |
+ |
protected String mergeLines( List<String> pLines, int pFrom ) |
|
297 |
+ |
{ |
|
298 |
+ |
return mergeLines( pLines, pFrom, pLines.size() ); |
|
299 |
+ |
} |
|
300 |
+ |
|
|
301 |
+ |
protected String mergeLines( List<String> pLines, int pFrom, int pToExclusive ) |
|
302 |
+ |
{ |
|
303 |
+ |
StringBuilder sb = new StringBuilder(); |
|
304 |
+ |
while ( (pFrom < pToExclusive) && (pFrom < pLines.size()) ) |
|
305 |
+ |
{ |
|
306 |
+ |
sb.append( pLines.get( pFrom++ ) ).append( '\n' ); |
|
307 |
+ |
} |
|
308 |
+ |
return sb.toString(); |
|
309 |
+ |
} |
|
310 |
+ |
|
|
311 |
+ |
private int findLine( List<String> pLines, String zLine ) |
|
312 |
+ |
{ |
|
313 |
+ |
for ( int i = 0; i < pLines.size(); i++ ) |
|
314 |
+ |
{ |
|
315 |
+ |
if ( zLine.equals( pLines.get( i ) ) ) |
|
316 |
+ |
{ |
|
317 |
+ |
return i; |
|
318 |
+ |
} |
|
319 |
+ |
} |
|
320 |
+ |
return -1; |
|
321 |
+ |
} |
|
322 |
+ |
|
|
323 |
+ |
protected List<String> readLines( File zFile ) |
|
324 |
+ |
{ |
|
325 |
+ |
BufferedReader fileReader; |
|
326 |
+ |
try |
|
327 |
+ |
{ |
|
328 |
+ |
fileReader = new BufferedReader( new FileReader( zFile ) ); |
|
329 |
+ |
} |
|
330 |
+ |
catch ( FileNotFoundException e ) |
|
331 |
+ |
{ |
|
332 |
+ |
throw new WrappedIOException( e ); |
|
333 |
+ |
} |
|
334 |
+ |
try |
|
335 |
+ |
{ |
|
336 |
+ |
List<String> lines = new ArrayList<String>(); |
|
337 |
+ |
for ( String line; null != (line = fileReader.readLine()); ) |
|
338 |
+ |
{ |
|
339 |
+ |
lines.add( line.trim() ); |
|
340 |
+ |
} |
|
341 |
+ |
Closeable c = fileReader; |
|
342 |
+ |
fileReader = null; |
|
343 |
+ |
c.close(); |
|
344 |
+ |
return lines; |
|
345 |
+ |
} |
|
346 |
+ |
catch ( IOException e ) |
|
347 |
+ |
{ |
|
348 |
+ |
if ( fileReader != null ) |
|
349 |
+ |
{ |
|
350 |
+ |
try |
|
351 |
+ |
{ |
|
352 |
+ |
fileReader.close(); |
|
353 |
+ |
} |
|
354 |
+ |
catch ( IOException e1 ) |
|
355 |
+ |
{ |
|
356 |
+ |
// Whatever! |
|
357 |
+ |
} |
|
358 |
+ |
} |
|
359 |
+ |
throw new WrappedIOException( e ); |
|
360 |
+ |
} |
|
361 |
+ |
} |
|
362 |
+ |
|
|
363 |
+ |
protected void initLoggerFactory() |
|
364 |
+ |
{ |
|
365 |
+ |
LoggerFactory.init( createLoggerLevel() ); |
|
366 |
+ |
} |
|
367 |
+ |
|
|
368 |
+ |
protected LoggerLevel createLoggerLevel() |
|
369 |
+ |
{ |
|
370 |
+ |
int zLevel = LoggerLevel.ERROR; |
|
371 |
+ |
String[] zLevels = LoggerLevel.LEVELS; |
|
372 |
+ |
for ( int i = 0; i < zLevels.length; i++ ) |
|
373 |
+ |
{ |
|
374 |
+ |
if ( null != mArgs.get( zLevels[i] ) ) |
|
375 |
+ |
{ |
|
376 |
+ |
zLevel = i; |
|
377 |
+ |
break; |
|
378 |
+ |
} |
|
379 |
+ |
} |
|
380 |
+ |
final int zLoggerLevel = zLevel; |
|
381 |
+ |
return new LoggerLevel() |
|
382 |
+ |
{ |
|
383 |
+ |
@Override |
|
384 |
+ |
public int getEnabledLevel( String pClassName ) |
|
385 |
+ |
{ |
|
386 |
+ |
return zLoggerLevel; |
|
387 |
+ |
} |
|
388 |
+ |
}; |
|
389 |
+ |
} |
|
390 |
+ |
|
|
391 |
+ |
protected Class<Project> createYamlCodeProjectClass( Class<? extends Project> pClass, String pCode, int pOverheadStartLines ) |
|
392 |
+ |
{ |
|
393 |
+ |
throw new UnsupportedOperationException(); // todo: See - executeDocument(); |
|
394 |
+ |
} |
|
395 |
+ |
|
|
396 |
+ |
protected Class<Project> createJavaCodeProjectClass( Class<? extends Project> pClass, String pCode ) |
|
397 |
+ |
{ |
|
398 |
+ |
throw new UnsupportedOperationException(); // todo: See - executeDocument()!; |
|
399 |
+ |
} |
|
400 |
+ |
|
|
401 |
+ |
/** |
|
402 |
+ |
* Cleans All projects - Normally called reflectively |
|
403 |
+ |
*/ |
|
404 |
+ |
@SuppressWarnings({"UnusedDeclaration"}) |
|
405 |
+ |
public void cleanAll() |
|
406 |
+ |
{ |
|
407 |
+ |
progress( "CleanAll" ); |
|
408 |
+ |
Set<Project> zProjects = mProjectCache.getAllProjects(); |
|
409 |
+ |
for ( Project zProject : zProjects ) |
|
410 |
+ |
{ |
|
411 |
+ |
zProject.clean(); |
|
412 |
+ |
} |
|
413 |
+ |
} |
|
414 |
+ |
|
|
415 |
+ |
/** |
|
416 |
+ |
* Builds the Launch Project - Normally called reflectively |
|
417 |
+ |
*/ |
|
418 |
+ |
@SuppressWarnings({"UnusedDeclaration"}) |
|
419 |
+ |
public void build() |
|
420 |
+ |
{ |
|
421 |
+ |
mLaunchProject.build(); |
|
422 |
+ |
} |
|
423 |
+ |
|
|
424 |
+ |
/** |
|
425 |
+ |
* Versions the current (GWT) Launch Project - Normally called reflectively |
|
426 |
+ |
*/ |
|
427 |
+ |
@SuppressWarnings({"UnusedDeclaration"}) |
|
428 |
+ |
public void versionGWT() |
|
429 |
+ |
{ |
|
430 |
+ |
mLaunchProject.versionGWT(); |
|
431 |
+ |
} |
|
432 |
+ |
|
|
433 |
+ |
/// todo: ================================================================================================================== |
|
434 |
+ |
/// todo: ================================================================================================================== |
|
435 |
+ |
/// todo: ================================================================================================================== |
|
436 |
+ |
/// todo: ================================================================================================================== |
|
437 |
+ |
/// todo: ================================================================================================================== |
|
438 |
+ |
/// todo: ================================================================================================================== |
|
439 |
+ |
/// todo: ================================================================================================================== |
|
440 |
+ |
/// todo: ================================================================================================================== |
|
441 |
+ |
/// todo: ================================================================================================================== |
|
442 |
+ |
/// todo: ================================================================================================================== |
|
443 |
+ |
/// todo: ================================================================================================================== |
|
444 |
+ |
/// todo: vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv Here be Dragons vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv |
|
445 |
+ |
|
|
446 |
+ |
/** |
|
447 |
+ |
* Loads the specified project with the specified defaults and loads any other projects needed for the "include" property. |
|
448 |
+ |
* |
|
449 |
+ |
* @param path Path to a YAML project file, or a directory containing a "project.yaml" file. |
|
450 |
+ |
*/ |
|
451 |
+ |
// public Project project( String path, Project defaults ) |
|
452 |
+ |
// { |
|
453 |
+ |
// Util.assertNotNull( "path", path ); |
|
454 |
+ |
// Util.assertNotNull( "defaults", defaults ); |
|
455 |
+ |
// |
|
456 |
+ |
// Project actualProject = new Project( path, this ); |
|
457 |
+ |
// |
|
458 |
+ |
// Project project = new Project(); |
|
459 |
+ |
// project.replace( defaults ); |
|
460 |
+ |
// |
|
461 |
+ |
// File parent = actualProject.getDirectory().getParentFile(); |
|
462 |
+ |
// while ( parent != null ) |
|
463 |
+ |
// { |
|
464 |
+ |
// File includeFile = new File( parent, "include.yaml" ); |
|
465 |
+ |
// if ( includeFile.exists() ) |
|
466 |
+ |
// { |
|
467 |
+ |
// try |
|
468 |
+ |
// { |
|
469 |
+ |
// project.replace( project( includeFile.getAbsolutePath(), defaults ) ); |
|
470 |
+ |
// } |
|
471 |
+ |
// catch ( RuntimeException ex ) |
|
472 |
+ |
// { |
|
473 |
+ |
// throw new RuntimeException( "Error loading included project: " + includeFile.getAbsolutePath(), ex ); |
|
474 |
+ |
// } |
|
475 |
+ |
// } |
|
476 |
+ |
// parent = parent.getParentFile(); |
|
477 |
+ |
// } |
|
478 |
+ |
// |
|
479 |
+ |
// for ( String include : actualProject.getInclude() ) |
|
480 |
+ |
// { |
|
481 |
+ |
// try |
|
482 |
+ |
// { |
|
483 |
+ |
// project.replace( project( actualProject.path( include ), defaults ) ); |
|
484 |
+ |
// } |
|
485 |
+ |
// catch ( RuntimeException ex ) |
|
486 |
+ |
// { |
|
487 |
+ |
// throw new RuntimeException( "Error loading included project: " + actualProject.path( include ), ex ); |
|
488 |
+ |
// } |
|
489 |
+ |
// } |
|
490 |
+ |
// project.replace( actualProject ); |
|
491 |
+ |
// return project; |
|
492 |
+ |
// } |
|
493 |
+ |
|
|
494 |
+ |
/** |
|
495 |
+ |
* Removes any code signatures on the specified JAR. Removes any signature files in the META-INF directory and removes any |
|
496 |
+ |
* signature entries from the JAR's manifest. |
|
497 |
+ |
* |
|
498 |
+ |
* @return The path to the JAR file. |
|
499 |
+ |
*/ |
|
500 |
+ |
public String unsign( String jarFile ) |
|
501 |
+ |
{ |
|
502 |
+ |
Util.assertNotNull( "jarFile", jarFile ); |
|
503 |
+ |
|
|
504 |
+ |
progress( "Removing signature from JAR: " + jarFile ); |
|
505 |
+ |
|
|
506 |
+ |
File tempFile; |
|
507 |
+ |
try |
|
508 |
+ |
{ |
|
509 |
+ |
tempFile = File.createTempFile( "scar", "removejarsig" ); |
|
510 |
+ |
} |
|
511 |
+ |
catch ( IOException e ) |
|
512 |
+ |
{ |
|
513 |
+ |
throw new WrappedIOException( e ); |
|
514 |
+ |
} |
|
515 |
+ |
JarOutputStream jarOutput = null; |
|
516 |
+ |
JarInputStream jarInput = null; |
|
517 |
+ |
try |
|
518 |
+ |
{ |
|
519 |
+ |
jarOutput = new JarOutputStream( new FileOutputStream( tempFile ) ); |
|
520 |
+ |
jarInput = new JarInputStream( new FileInputStream( jarFile ) ); |
|
521 |
+ |
Manifest manifest = jarInput.getManifest(); |
|
522 |
+ |
if ( manifest != null ) |
|
523 |
+ |
{ |
|
524 |
+ |
// Remove manifest file entries. |
|
525 |
+ |
manifest.getEntries().clear(); |
|
526 |
+ |
jarOutput.putNextEntry( new JarEntry( "META-INF/MANIFEST.MF" ) ); |
|
527 |
+ |
manifest.write( jarOutput ); |
|
528 |
+ |
} |
|
529 |
+ |
byte[] buffer = new byte[4096]; |
|
530 |
+ |
while ( true ) |
|
531 |
+ |
{ |
|
532 |
+ |
JarEntry entry = jarInput.getNextJarEntry(); |
|
533 |
+ |
if ( entry == null ) |
|
534 |
+ |
{ |
|
535 |
+ |
break; |
|
536 |
+ |
} |
|
537 |
+ |
String name = entry.getName(); |
|
538 |
+ |
// Skip signature files. |
|
539 |
+ |
if ( name.startsWith( "META-INF/" ) && (name.endsWith( ".SF" ) || name.endsWith( ".DSA" ) || name.endsWith( ".RSA" )) ) |
|
540 |
+ |
{ |
|
541 |
+ |
continue; |
|
542 |
+ |
} |
|
543 |
+ |
jarOutput.putNextEntry( new JarEntry( name ) ); |
|
544 |
+ |
while ( true ) |
|
545 |
+ |
{ |
|
546 |
+ |
int length = jarInput.read( buffer ); |
|
547 |
+ |
if ( length == -1 ) |
|
548 |
+ |
{ |
|
549 |
+ |
break; |
|
550 |
+ |
} |
|
551 |
+ |
jarOutput.write( buffer, 0, length ); |
|
552 |
+ |
} |
|
553 |
+ |
} |
|
554 |
+ |
jarInput.close(); |
|
555 |
+ |
jarOutput.close(); |
|
556 |
+ |
copyFile( tempFile.getAbsolutePath(), jarFile ); |
|
557 |
+ |
} |
|
558 |
+ |
catch ( IOException ex ) |
|
559 |
+ |
{ |
|
560 |
+ |
throw new WrappedIOException( "Error unsigning JAR file: " + jarFile, ex ); |
|
561 |
+ |
} |
|
562 |
+ |
finally |
|
563 |
+ |
{ |
|
564 |
+ |
dispose( jarInput ); |
|
565 |
+ |
dispose( jarOutput ); |
|
566 |
+ |
tempFile.delete(); |
|
567 |
+ |
} |
|
568 |
+ |
return jarFile; |
|
569 |
+ |
} |
|
570 |
+ |
|
|
571 |
+ |
/** |
|
572 |
+ |
* Signs the specified JAR. |
|
573 |
+ |
* |
|
574 |
+ |
* @return The path to the JAR. |
|
575 |
+ |
*/ |
|
576 |
+ |
public String sign( String jarFile, String keystoreFile, String alias, String password ) |
|
577 |
+ |
{ |
|
578 |
+ |
Util.assertNotNull( "jarFile", jarFile ); |
|
579 |
+ |
Util.assertNotNull( "keystoreFile", keystoreFile ); |
|
580 |
+ |
Util.assertNotNull( "alias", alias ); |
|
581 |
+ |
Util.assertNotNull( "password", password ); |
|
582 |
+ |
if ( password.length() < 6 ) |
|
583 |
+ |
{ |
|
584 |
+ |
throw new IllegalArgumentException( "password must be 6 or more characters." ); |
|
585 |
+ |
} |
|
586 |
+ |
progress( "Signing JAR (" + keystoreFile + ", " + alias + ":" + password + "): " + jarFile ); |
|
587 |
+ |
|
|
588 |
+ |
shell( "jarsigner", "-keystore", keystoreFile, "-storepass", password, "-keypass", password, jarFile, alias ); |
|
589 |
+ |
return jarFile; |
|
590 |
+ |
} |
|
591 |
+ |
|
|
592 |
+ |
/** |
|
593 |
+ |
* Encodes the specified file with pack200. The resulting filename is the filename plus ".pack". The file is deleted after |
|
594 |
+ |
* encoding. |
|
595 |
+ |
* |
|
596 |
+ |
* @return The path to the encoded file. |
|
597 |
+ |
*/ |
|
598 |
+ |
public String pack200( String jarFile ) |
|
599 |
+ |
{ |
|
600 |
+ |
String packedFile = pack200( jarFile, jarFile + ".pack" ); |
|
601 |
+ |
delete( jarFile ); |
|
602 |
+ |
return packedFile; |
|
603 |
+ |
} |
|
604 |
+ |
|
|
605 |
+ |
/** |
|
606 |
+ |
* Encodes the specified file with pack200. |
|
607 |
+ |
* |
|
608 |
+ |
* @return The path to the encoded file. |
|
609 |
+ |
*/ |
|
610 |
+ |
public String pack200( String jarFile, String packedFile ) |
|
611 |
+ |
{ |
|
612 |
+ |
Util.assertNotNull( "jarFile", jarFile ); |
|
613 |
+ |
Util.assertNotNull( "packedFile", packedFile ); |
|
614 |
+ |
|
|
615 |
+ |
progress( "Packing JAR: " + jarFile + " -> " + packedFile ); |
|
616 |
+ |
|
|
617 |
+ |
shell( "pack200", "--no-gzip", "--segment-limit=-1", "--no-keep-file-order", "--effort=7", "--modification-time=latest", packedFile, jarFile ); |
|
618 |
+ |
return packedFile; |
|
619 |
+ |
} |
|
620 |
+ |
|
|
621 |
+ |
/** |
|
622 |
+ |
* Decodes the specified file with pack200. The filename must end in ".pack" and the resulting filename has this stripped. The |
|
623 |
+ |
* encoded file is deleted after decoding. |
|
624 |
+ |
* |
|
625 |
+ |
* @return The path to the decoded file. |
|
626 |
+ |
*/ |
|
627 |
+ |
public String unpack200( String packedFile ) |
|
628 |
+ |
{ |
|
629 |
+ |
Util.assertNotNull( "packedFile", packedFile ); |
|
630 |
+ |
if ( !packedFile.endsWith( ".pack" ) ) |
|
631 |
+ |
{ |
|
632 |
+ |
throw new IllegalArgumentException( "packedFile must end with .pack: " + packedFile ); |
|
633 |
+ |
} |
|
634 |
+ |
|
|
635 |
+ |
String jarFile = unpack200( packedFile, substring( packedFile, 0, -5 ) ); |
|
636 |
+ |
delete( packedFile ); |
|
637 |
+ |
return jarFile; |
|
638 |
+ |
} |
|
639 |
+ |
|
|
640 |
+ |
/** |
|
641 |
+ |
* Decodes the specified file with pack200. |
|
642 |
+ |
* |
|
643 |
+ |
* @return The path to the decoded file. |
|
644 |
+ |
*/ |
|
645 |
+ |
public String unpack200( String packedFile, String jarFile ) |
|
646 |
+ |
{ |
|
647 |
+ |
Util.assertNotNull( "packedFile", packedFile ); |
|
648 |
+ |
Util.assertNotNull( "jarFile", jarFile ); |
|
649 |
+ |
|
|
650 |
+ |
progress( "Unpacking JAR: " + packedFile + " -> " + jarFile ); |
|
651 |
+ |
|
|
652 |
+ |
shell( "unpack200", packedFile, jarFile ); |
|
653 |
+ |
return jarFile; |
|
654 |
+ |
} |
|
655 |
+ |
|
|
656 |
+ |
/** |
|
657 |
+ |
* Encodes the specified file with GZIP. The resulting filename is the filename plus ".gz". The file is deleted after encoding. |
|
658 |
+ |
* |
|
659 |
+ |
* @return The path to the encoded file. |
|
660 |
+ |
*/ |
|
661 |
+ |
public String gzip( String file ) |
|
662 |
+ |
{ |
|
663 |
+ |
String gzipFile = gzip( file, file + ".gz" ); |
|
664 |
+ |
delete( file ); |
|
665 |
+ |
return gzipFile; |
|
666 |
+ |
} |
|
667 |
+ |
|
|
668 |
+ |
/** |
|
669 |
+ |
* Encodes the specified file with GZIP. |
|
670 |
+ |
* |
|
671 |
+ |
* @return The path to the encoded file. |
|
672 |
+ |
*/ |
|
673 |
+ |
public String gzip( String file, String gzipFile ) |
|
674 |
+ |
{ |
|
675 |
+ |
Util.assertNotNull( "file", file ); |
|
676 |
+ |
Util.assertNotNull( "gzipFile", gzipFile ); |
|
677 |
+ |
|
|
678 |
+ |
progress( "GZIP encoding: " + file + " -> " + gzipFile ); |
|
679 |
+ |
|
|
680 |
+ |
InputStream input; |
|
681 |
+ |
try |
|
682 |
+ |
{ |
|
683 |
+ |
input = new FileInputStream( file ); |
|
684 |
+ |
} |
|
685 |
+ |
catch ( FileNotFoundException e ) |
|
686 |
+ |
{ |
|
687 |
+ |
throw new WrappedIOException( e ); |
|
688 |
+ |
} |
|
689 |
+ |
try |
|
690 |
+ |
{ |
|
691 |
+ |
copyStreamAndCloseEm( input, new GZIPOutputStream( new FileOutputStream( gzipFile ) ) ); |
|
692 |
+ |
} |
|
693 |
+ |
catch ( IOException e ) |
|
694 |
+ |
{ |
|
695 |
+ |
throw new WrappedIOException( e ); |
|
696 |
+ |
} |
|
697 |
+ |
finally |
|
698 |
+ |
{ |
|
699 |
+ |
dispose( input ); |
|
700 |
+ |
} |
|
701 |
+ |
return gzipFile; |
|
702 |
+ |
} |
|
703 |
+ |
|
|
704 |
+ |
/** |
|
705 |
+ |
* Decodes the specified GZIP file. The filename must end in ".gz" and the resulting filename has this stripped. The encoded |
|
706 |
+ |
* file is deleted after decoding. |
|
707 |
+ |
* |
|
708 |
+ |
* @return The path to the decoded file. |
|
709 |
+ |
*/ |
|
710 |
+ |
public String ungzip( String gzipFile ) |
|
711 |
+ |
{ |
|
712 |
+ |
Util.assertNotNull( "gzipFile", gzipFile ); |
|
713 |
+ |
if ( !gzipFile.endsWith( ".gz" ) ) |
|
714 |
+ |
{ |
|
715 |
+ |
throw new IllegalArgumentException( "gzipFile must end with .gz: " + gzipFile ); |
|
716 |
+ |
} |
|
717 |
+ |
|
|
718 |
+ |
String file = ungzip( gzipFile, substring( gzipFile, 0, -3 ) ); |
|
719 |
+ |
delete( gzipFile ); |
|
720 |
+ |
return file; |
|
721 |
+ |
} |
|
722 |
+ |
|
|
723 |
+ |
/** |
|
724 |
+ |
* Decodes the specified GZIP file. |
|
725 |
+ |
* |
|
726 |
+ |
* @return The path to the decoded file. |
|
727 |
+ |
*/ |
|
728 |
+ |
public String ungzip( String gzipFile, String file ) |
|
729 |
+ |
{ |
|
730 |
+ |
Util.assertNotNull( "gzipFile", gzipFile ); |
|
731 |
+ |
Util.assertNotNull( "file", file ); |
|
732 |
+ |
progress( "GZIP decoding: " + gzipFile + " -> " + file ); |
|
733 |
+ |
|
|
734 |
+ |
InputStream input; |
|
735 |
+ |
try |
|
736 |
+ |
{ |
|
737 |
+ |
input = new GZIPInputStream( new FileInputStream( gzipFile ) ); |
|
738 |
+ |
} |
|
739 |
+ |
catch ( IOException e ) |
|
740 |
+ |
{ |
|
741 |
+ |
throw new WrappedIOException( e ); |
|
742 |
+ |
} |
|
743 |
+ |
try |
|
744 |
+ |
{ |
|
745 |
+ |
copyStreamAndCloseEm( input, new FileOutputStream( file ) ); |
|
746 |
+ |
} |
|
747 |
+ |
catch ( FileNotFoundException e ) |
|
748 |
+ |
{ |
|
749 |
+ |
throw new WrappedIOException( e ); |
|
750 |
+ |
} |
|
751 |
+ |
finally |
|
752 |
+ |
{ |
|
753 |
+ |
dispose( input ); |
|
754 |
+ |
} |
|
755 |
+ |
return file; |
|
756 |
+ |
} |
|
757 |
+ |
|
|
758 |
+ |
/** |
|
759 |
+ |
* Encodes the specified files with ZIP. |
|
760 |
+ |
* |
|
761 |
+ |
* @return The path to the encoded file. |
|
762 |
+ |
*/ |
|
763 |
+ |
public String zip( Paths paths, String zipFile ) |
|
764 |
+ |
{ |
|
765 |
+ |
Util.assertNotNull( "paths", paths ); |
|
766 |
+ |
Util.assertNotNull( "zipFile", zipFile ); |
|
767 |
+ |
progress( "Creating ZIP (" + paths.count() + " entries): " + zipFile ); |
|
768 |
+ |
|
|
769 |
+ |
paths.zip( zipFile ); |
|
770 |
+ |
return zipFile; |
|
771 |
+ |
} |
|
772 |
+ |
|
|
773 |
+ |
/** |
|
774 |
+ |
* Encodes the specified file with LZMA. The resulting filename is the filename plus ".lzma". The file is deleted after |
|
775 |
+ |
* encoding. |
|
776 |
+ |
* |
|
777 |
+ |
* @return The path to the encoded file. |
|
778 |
+ |
*/ |
|
779 |
+ |
public String lzma( String file ) |
|
780 |
+ |
{ |
|
781 |
+ |
String lzmaFile = lzma( file, file + ".lzma" ); |
|
782 |
+ |
delete( file ); |
|
783 |
+ |
return lzmaFile; |
|
784 |
+ |
} |
|
785 |
+ |
|
|
786 |
+ |
/** |
|
787 |
+ |
* Encodes the specified file with LZMA. |
|
788 |
+ |
* |
|
789 |
+ |
* @return The path to the encoded file. |
|
790 |
+ |
*/ |
|
791 |
+ |
public String lzma( String file, String lzmaFile ) |
|
792 |
+ |
{ |
|
793 |
+ |
Util.assertNotNull( "file", file ); |
|
794 |
+ |
Util.assertNotNull( "lzmaFile", lzmaFile ); |
|
795 |
+ |
progress( "LZMA encoding: " + file + " -> " + lzmaFile ); |
|
796 |
+ |
|
|
797 |
+ |
try |
|
798 |
+ |
{ |
|
799 |
+ |
LzmaAlone.main( new String[]{"e", file, lzmaFile} ); |
|
800 |
+ |
} |
|
801 |
+ |
catch ( Exception ex ) |
|
802 |
+ |
{ |
|
803 |
+ |
throw new WrappedIOException( "Error lzma compressing file: " + file, ex ); |
|
804 |
+ |
} |
|
805 |
+ |
return lzmaFile; |
|
806 |
+ |
} |
|
807 |
+ |
|
|
808 |
+ |
/** |
|
809 |
+ |
* Decodes the specified LZMA file. The filename must end in ".lzma" and the resulting filename has this stripped. The encoded |
|
810 |
+ |
* file is deleted after decoding. |
|
811 |
+ |
* |
|
812 |
+ |
* @return The path to the decoded file. |
|
813 |
+ |
*/ |
|
814 |
+ |
public String unlzma( String lzmaFile ) |
|
815 |
+ |
{ |
|
816 |
+ |
Util.assertNotNull( "lzmaFile", lzmaFile ); |
|
817 |
+ |
if ( !lzmaFile.endsWith( ".lzma" ) ) |
|
818 |
+ |
{ |
|
819 |
+ |
throw new IllegalArgumentException( "lzmaFile must end with .lzma: " + lzmaFile ); |
|
820 |
+ |
} |
|
821 |
+ |
|
|
822 |
+ |
String file = unlzma( lzmaFile, substring( lzmaFile, 0, -5 ) ); |
|
823 |
+ |
delete( lzmaFile ); |
|
824 |
+ |
return file; |
|
825 |
+ |
} |
|
826 |
+ |
|
|
827 |
+ |
/** |
|
828 |
+ |
* Decodes the specified LZMA file. |
|
829 |
+ |
* |
|
830 |
+ |
* @return The path to the decoded file. |
|
831 |
+ |
*/ |
|
832 |
+ |
public String unlzma( String lzmaFile, String file ) |
|
833 |
+ |
{ |
|
834 |
+ |
Util.assertNotNull( "lzmaFile", lzmaFile ); |
|
835 |
+ |
Util.assertNotNull( "file", file ); |
|
836 |
+ |
progress( "LZMA decoding: " + lzmaFile + " -> " + file ); |
|
837 |
+ |
|
|
838 |
+ |
try |
|
839 |
+ |
{ |
|
840 |
+ |
LzmaAlone.main( new String[]{"d", lzmaFile, file} ); |
|
841 |
+ |
} |
|
842 |
+ |
catch ( Exception ex ) |
|
843 |
+ |
{ |
|
844 |
+ |
throw new WrappedIOException( "Error lzma decompressing file: " + file, ex ); |
|
845 |
+ |
} |
|
846 |
+ |
return file; |
|
847 |
+ |
} |
|
848 |
+ |
|
|
849 |
+ |
/** |
|
850 |
+ |
* Copies all the JAR and JNLP files from the "dist" directory to a "jws" directory under the "target" directory. It then uses |
|
851 |
+ |
* the specified keystore to sign each JAR. If the "pack" parameter is true, it also compresses each JAR using pack200 and |
|
852 |
+ |
* GZIP. |
|
853 |
+ |
*/ |
|
854 |
+ |
public void jws( Project project, boolean pack, String keystoreFile, String alias, String password ) |
|
855 |
+ |
{ |
|
856 |
+ |
Util.assertNotNull( "Project", project ); |
|
857 |
+ |
Util.assertNotNull( "keystoreFile", keystoreFile ); |
|
858 |
+ |
Util.assertNotNull( "alias", alias ); |
|
859 |
+ |
Util.assertNotNull( "password", password ); |
|
860 |
+ |
if ( password.length() < 6 ) |
|
861 |
+ |
{ |
|
862 |
+ |
throw new IllegalArgumentException( "password must be 6 or more characters." ); |
|
863 |
+ |
} |
|
864 |
+ |
|
|
865 |
+ |
progress( "JWS: " + project ); |
|
866 |
+ |
|
|
867 |
+ |
String jwsDir = mkdir( project.path( "$target$/jws/" ) ); |
|
868 |
+ |
String distDir = project.path( "$target$/dist/" ); |
|
869 |
+ |
new Paths( distDir, "*.jar", "*.jnlp" ).copyTo( jwsDir ); |
|
870 |
+ |
for ( String file : new Paths( jwsDir, "*.jar" ).getFullPaths() ) |
|
871 |
+ |
{ |
|
872 |
+ |
sign( unpack200( pack200( unsign( file ) ) ), keystoreFile, alias, password ); |
|
873 |
+ |
} |
|
874 |
+ |
if ( pack ) |
|
875 |
+ |
{ |
|
876 |
+ |
String unpackedDir = mkdir( jwsDir + "unpacked/" ); |
|
877 |
+ |
String packedDir = mkdir( jwsDir + "packed/" ); |
|
878 |
+ |
for ( String file : new Paths( jwsDir, "*.jar", "!*native*" ).getFullPaths() ) |
|
879 |
+ |
{ |
|
880 |
+ |
String fileName = fileName( file ); |
|
881 |
+ |
String unpackedFile = unpackedDir + fileName; |
|
882 |
+ |
moveFile( file, unpackedFile ); |
|
883 |
+ |
String packedFile = packedDir + fileName; |
|
884 |
+ |
gzip( pack200( copyFile( unpackedFile, packedFile ) ) ); |
|
885 |
+ |
} |
|
886 |
+ |
} |
|
887 |
+ |
} |
|
888 |
+ |
|
|
889 |
+ |
/** |
|
890 |
+ |
* Generates ".htaccess" and "type map" VAR files in the "jws" directory. These files allow Apache to serve both pack200/GZIP |
|
891 |
+ |
* JARs and regular JARs, based on capability of the client requesting the JAR. |
|
892 |
+ |
*/ |
|
893 |
+ |
public void jwsHtaccess( Project project ) |
|
894 |
+ |
{ |
|
895 |
+ |
Util.assertNotNull( "Project", project ); |
|
896 |
+ |
|
|
897 |
+ |
progress( "JWS htaccess: " + project ); |
|
898 |
+ |
|
|
899 |
+ |
String jwsDir = mkdir( project.path( "$target$/jws/" ) ); |
|
900 |
+ |
for ( String packedFile : new Paths( jwsDir + "packed", "*.jar.pack.gz" ).getFullPaths() ) |
|
901 |
+ |
{ |
|
902 |
+ |
String packedFileName = fileName( packedFile ); |
|
903 |
+ |
String jarFileName = substring( packedFileName, 0, -8 ); |
|
904 |
+ |
FileWriter writer; |
|
905 |
+ |
try |
|
906 |
+ |
{ |
|
907 |
+ |
writer = new FileWriter( jwsDir + jarFileName + ".var" ); |
|
908 |
+ |
} |
|
909 |
+ |
catch ( IOException e ) |
|
910 |
+ |
{ |
|
911 |
+ |
throw new WrappedIOException( e ); |
|
912 |
+ |
} |
|
913 |
+ |
try |
|
914 |
+ |
{ |
|
915 |
+ |
writer.write( "URI: packed/" + packedFileName + "\n" ); |
|
916 |
+ |
writer.write( "Content-Type: x-java-archive\n" ); |
|
917 |
+ |
writer.write( "Content-Encoding: pack200-gzip\n" ); |
|
918 |
+ |
writer.write( "URI: unpacked/" + jarFileName + "\n" ); |
|
919 |
+ |
writer.write( "Content-Type: x-java-archive\n" ); |
|
920 |
+ |
} |
|
921 |
+ |
catch ( IOException e ) |
|
922 |
+ |
{ |
|
923 |
+ |
throw new WrappedIOException( e ); |
|
924 |
+ |
} |
|
925 |
+ |
finally |
|
926 |
+ |
{ |
|
927 |
+ |
dispose( writer ); |
|
928 |
+ |
} |
|
929 |
+ |
} |
|
930 |
+ |
FileWriter writer; |
|
931 |
+ |
try |
|
932 |
+ |
{ |
|
933 |
+ |
writer = new FileWriter( jwsDir + ".htaccess" ); |
|
934 |
+ |
} |
|
935 |
+ |
catch ( IOException e ) |
|
936 |
+ |
{ |
|
937 |
+ |
throw new WrappedIOException( e ); |
|
938 |
+ |
} |
|
939 |
+ |
try |
|
940 |
+ |
{ |
|
941 |
+ |
writer.write( "AddType application/x-java-jnlp-file .jnlp" ); // JNLP mime type. |
|
942 |
+ |
writer.write( "AddType application/x-java-archive .jar\n" ); // JAR mime type. |
|
943 |
+ |
writer.write( "AddHandler application/x-type-map .var\n" ); // Enable type maps. |
|
944 |
+ |
writer.write( "Options +MultiViews\n" ); |
|
945 |
+ |
writer.write( "MultiViewsMatch Any\n" ); // Apache 2.0 only. |
|
946 |
+ |
writer.write( "<Files *.pack.gz>\n" ); |
|
947 |
+ |
writer.write( "AddEncoding pack200-gzip .jar\n" ); // Enable Content-Encoding header for .jar.pack.gz files. |
|
948 |
+ |
writer.write( "RemoveEncoding .gz\n" ); // Prevent mod_gzip from messing with the Content-Encoding response. |
|
949 |
+ |
writer.write( "</Files>\n" ); |
|
950 |
+ |
} |
|
951 |
+ |
catch ( IOException e ) |
|
952 |
+ |
{ |
|
953 |
+ |
throw new WrappedIOException( e ); |
|
954 |
+ |
} |
|
955 |
+ |
finally |
|
956 |
+ |
{ |
|
957 |
+ |
dispose( writer ); |
|
958 |
+ |
} |
|
959 |
+ |
} |
|
960 |
+ |
|
|
961 |
+ |
/** |
|
962 |
+ |
* Generates a JNLP file in the "jws" directory. JARs in the "jws" directory are included in the JNLP. JARs containing "native" |
|
963 |
+ |
* and "win", "mac", "linux", or "solaris" are properly included in the native section of the JNLP. The "main" property is used |
|
964 |
+ |
* for the main class in the JNLP. |
|
965 |
+ |
* |
|
966 |
+ |
* @param splashImage Can be null. |
|
967 |
+ |
*/ |
|
968 |
+ |
public void jnlp( Project project, String url, String company, String title, String splashImage ) |
|
969 |
+ |
{ |
|
970 |
+ |
Util.assertNotNull( "Project", project ); |
|
971 |
+ |
Util.assertNotNull( "company", company ); |
|
972 |
+ |
Util.assertNotNull( "title", title ); |
|
973 |
+ |
Util.assertNotNull( "url", url ); |
|
974 |
+ |
if ( !url.startsWith( "http" ) ) |
|
975 |
+ |
{ |
|
976 |
+ |
throw new RuntimeException( "Invalid url: " + url ); |
|
977 |
+ |
} |
|
978 |
+ |
|
|
979 |
+ |
if ( LOGGER.debug.isEnabled() ) |
|
980 |
+ |
{ |
|
981 |
+ |
progress( "JNLP: " + project + " (" + url + ", " + company + ", " + title + ", " + splashImage + ")" ); |
|
982 |
+ |
} |
|
983 |
+ |
else |
|
984 |
+ |
{ |
|
985 |
+ |
progress( "JNLP: " + project ); |
|
986 |
+ |
} |
|
987 |
+ |
|
|
988 |
+ |
if ( !project.hasMain() ) |
|
989 |
+ |
{ |
|
990 |
+ |
throw new RuntimeException( "Unable to generate JNLP: project has no main class" ); |
|
991 |
+ |
} |
|
992 |
+ |
|
|
993 |
+ |
int firstSlash = url.indexOf( "/", 7 ); |
|
994 |
+ |
int lastSlash = url.lastIndexOf( "/" ); |
|
995 |
+ |
if ( firstSlash == -1 || lastSlash == -1 ) |
|
996 |
+ |
{ |
|
997 |
+ |
throw new RuntimeException( "Invalid url: " + url ); |
|
998 |
+ |
} |
|
999 |
+ |
String domain = url.substring( 0, firstSlash + 1 ); |
|
1000 |
+ |
String path = url.substring( firstSlash + 1, lastSlash + 1 ); |
|
1001 |
+ |
String jnlpFile = url.substring( lastSlash + 1 ); |
|
1002 |
+ |
|
|
1003 |
+ |
String jwsDir = mkdir( project.path( "$target$/jws/" ) ); |
|
1004 |
+ |
FileWriter writer; |
|
1005 |
+ |
try |
|
1006 |
+ |
{ |
|
1007 |
+ |
writer = new FileWriter( jwsDir + jnlpFile ); |
|
1008 |
+ |
} |
|
1009 |
+ |
catch ( IOException e ) |
|
1010 |
+ |
{ |
|
1011 |
+ |
throw new WrappedIOException( e ); |
|
1012 |
+ |
} |
|
1013 |
+ |
try |
|
1014 |
+ |
{ |
|
1015 |
+ |
writer.write( "<?xml version='1.0' encoding='utf-8'?>\n" ); |
|
1016 |
+ |
writer.write( "<jnlp spec='1.0+' codebase='" + domain + "' href='" + path + jnlpFile + "'>\n" ); |
|
1017 |
+ |
writer.write( "<information>\n" ); |
|
1018 |
+ |
writer.write( "\t<title>" + title + "</title>\n" ); |
|
1019 |
+ |
writer.write( "\t<vendor>" + company + "</vendor>\n" ); |
|
1020 |
+ |
writer.write( "\t<homepage href='" + domain + "'/>\n" ); |
|
1021 |
+ |
writer.write( "\t<description>" + title + "</description>\n" ); |
|
1022 |
+ |
writer.write( "\t<description kind='short'>" + title + "</description>\n" ); |
|
1023 |
+ |
if ( splashImage != null ) |
|
1024 |
+ |
{ |
|
1025 |
+ |
writer.write( "\t<icon kind='splash' href='" + path + splashImage + "'/>\n" ); |
|
1026 |
+ |
} |
|
1027 |
+ |
writer.write( "</information>\n" ); |
|
1028 |
+ |
writer.write( "<security>\n" ); |
|
1029 |
+ |
writer.write( "\t<all-permissions/>\n" ); |
|
1030 |
+ |
writer.write( "</security>\n" ); |
|
1031 |
+ |
writer.write( "<resources>\n" ); |
|
1032 |
+ |
writer.write( "\t<j2se href='http://java.sun.com/products/autodl/j2se' version='1.5+' max-heap-size='128m'/>\n" ); |
|
1033 |
+ |
|
|
1034 |
+ |
// JAR with main class first. |
|
1035 |
+ |
String projectJarName; |
|
1036 |
+ |
if ( project.hasVersion() ) |
|
1037 |
+ |
{ |
|
1038 |
+ |
projectJarName = project.format( "$name$-$version$.jar" ); |
|
1039 |
+ |
} |
|
1040 |
+ |
else |
|
1041 |
+ |
{ |
|
1042 |
+ |
projectJarName = project.format( "$name$.jar" ); |
|
1043 |
+ |
} |
|
1044 |
+ |
writer.write( "\t<jar href='" + path + projectJarName + "'/>\n" ); |
|
1045 |
+ |
|
|
1046 |
+ |
// Rest of JARs, except natives. |
|
1047 |
+ |
for ( String file : new Paths( jwsDir, "**/*.jar", "!*native*", "!**/" + projectJarName ).getFullPaths() ) |
|
1048 |
+ |
{ |
|
1049 |
+ |
writer.write( "\t<jar href='" + path + fileName( file ) + "'/>\n" ); |
|
1050 |
+ |
} |
|
1051 |
+ |
|
|
1052 |
+ |
writer.write( "</resources>\n" ); |
|
1053 |
+ |
Paths nativePaths = new Paths( jwsDir, "*native*win*", "*win*native*" ); |
|
1054 |
+ |
if ( nativePaths.count() == 1 ) |
|
1055 |
+ |
{ |
|
1056 |
+ |
writer.write( "<resources os='Windows'>\n" ); |
|
1057 |
+ |
writer.write( "\t<j2se href='http://java.sun.com/products/autodl/j2se' version='1.5+' max-heap-size='128m'/>\n" ); |
|
1058 |
+ |
writer.write( "\t<nativelib href='" + path + nativePaths.getNames().get( 0 ) + "'/>\n" ); |
|
1059 |
+ |
writer.write( "</resources>\n" ); |
|
1060 |
+ |
} |
|
1061 |
+ |
nativePaths = new Paths( jwsDir, "*native*mac*", "*mac*native*" ); |
|
1062 |
+ |
if ( nativePaths.count() == 1 ) |
|
1063 |
+ |
{ |
|
1064 |
+ |
writer.write( "<resources os='Mac'>\n" ); |
|
1065 |
+ |
writer.write( "\t<j2se href='http://java.sun.com/products/autodl/j2se' version='1.5+' max-heap-size='128m'/>\n" ); |
|
1066 |
+ |
writer.write( "\t<nativelib href='" + path + nativePaths.getNames().get( 0 ) + "'/>\n" ); |
|
1067 |
+ |
writer.write( "</resources>\n" ); |
|
1068 |
+ |
} |
|
1069 |
+ |
nativePaths = new Paths( jwsDir, "*native*linux*", "*linux*native*" ); |
|
1070 |
+ |
if ( nativePaths.count() == 1 ) |
|
1071 |
+ |
{ |
|
1072 |
+ |
writer.write( "<resources os='Linux'>\n" ); |
|
1073 |
+ |
writer.write( "\t<j2se href='http://java.sun.com/products/autodl/j2se' version='1.5+' max-heap-size='128m'/>\n" ); |
|
1074 |
+ |
writer.write( "\t<nativelib href='" + path + nativePaths.getNames().get( 0 ) + "'/>\n" ); |
|
1075 |
+ |
writer.write( "</resources>\n" ); |
|
1076 |
+ |
} |
|
1077 |
+ |
nativePaths = new Paths( jwsDir, "*native*solaris*", "*solaris*native*" ); |
|
1078 |
+ |
if ( nativePaths.count() == 1 ) |
|
1079 |
+ |
{ |
|
1080 |
+ |
writer.write( "<resources os='SunOS'>\n" ); |
|
1081 |
+ |
writer.write( "\t<j2se href='http://java.sun.com/products/autodl/j2se' version='1.5+' max-heap-size='128m'/>\n" ); |
|
1082 |
+ |
writer.write( "\t<nativelib href='" + path + nativePaths.getNames().get( 0 ) + "'/>\n" ); |
|
1083 |
+ |
writer.write( "</resources>\n" ); |
|
1084 |
+ |
} |
|
1085 |
+ |
writer.write( "<application-desc main-class='" + project.getMain() + "'/>\n" ); |
|
1086 |
+ |
writer.write( "</jnlp>" ); |
|
1087 |
+ |
} |
|
1088 |
+ |
catch ( IOException e ) |
|
1089 |
+ |
{ |
|
1090 |
+ |
throw new WrappedIOException( e ); |
|
1091 |
+ |
} |
|
1092 |
+ |
finally |
|
1093 |
+ |
{ |
|
1094 |
+ |
dispose( writer ); |
|
1095 |
+ |
} |
|
1096 |
+ |
} |
|
1097 |
+ |
|
|
1098 |
+ |
public String lwjglApplet( Project project, String keystoreFile, String alias, String password ) |
|
1099 |
+ |
{ |
|
1100 |
+ |
Util.assertNotNull( "Project", project ); |
|
1101 |
+ |
Util.assertNotNull( "keystoreFile", keystoreFile ); |
|
1102 |
+ |
Util.assertNotNull( "alias", alias ); |
|
1103 |
+ |
Util.assertNotNull( "password", password ); |
|
1104 |
+ |
if ( password.length() < 6 ) |
|
1105 |
+ |
{ |
|
1106 |
+ |
throw new IllegalArgumentException( "password must be 6 or more characters." ); |
|
1107 |
+ |
} |
|
1108 |
+ |
|
|
1109 |
+ |
progress( "LWJGL applet: " + project ); |
|
1110 |
+ |
|
|
1111 |
+ |
String appletDir = mkdir( project.path( "$target$/applet-lwjgl/" ) ); |
|
1112 |
+ |
String distDir = project.path( "$target$/dist/" ); |
|
1113 |
+ |
new Paths( distDir, "**/*.jar", "*.html", "*.htm" ).flatten().copyTo( appletDir ); |
|
1114 |
+ |
for ( String jarFile : new Paths( appletDir, "*.jar" ).getFullPaths() ) |
|
1115 |
+ |
{ |
|
1116 |
+ |
sign( unpack200( pack200( unsign( jarFile ) ) ), keystoreFile, alias, password ); |
|
1117 |
+ |
String fileName = fileName( jarFile ); |
|
1118 |
+ |
if ( fileName.equals( "lwjgl_util_applet.jar" ) || fileName.equals( "lzma.jar" ) ) |
|
1119 |
+ |
{ |
|
1120 |
+ |
continue; |
|
1121 |
+ |
} |
|
1122 |
+ |
if ( fileName.contains( "native" ) ) |
|
1123 |
+ |
{ |
|
1124 |
+ |
lzma( jarFile ); |
|
1125 |
+ |
} |
|
1126 |
+ |
else |
|
1127 |
+ |
{ |
|
1128 |
+ |
lzma( pack200( jarFile ) ); |
|
1129 |
+ |
} |
|
1130 |
+ |
} |
|
1131 |
+ |
|
|
1132 |
+ |
if ( !new Paths( appletDir, "*.html", "*.htm" ).isEmpty() ) |
|
1133 |
+ |
{ |
|
1134 |
+ |
return appletDir; |
|
1135 |
+ |
} |
|
1136 |
+ |
if ( !project.hasMain() ) |
|
1137 |
+ |
{ |
|
1138 |
+ |
LOGGER.debug.log( "Unable to generate applet.html: project has no main class" ); |
|
1139 |
+ |
return appletDir; |
|
1140 |
+ |
} |
|
1141 |
+ |
progress( "Generating: applet.html" ); |
|
1142 |
+ |
FileWriter writer; |
|
1143 |
+ |
try |
|
1144 |
+ |
{ |
|
1145 |
+ |
writer = new FileWriter( appletDir + "applet.html" ); |
|
1146 |
+ |
} |
|
1147 |
+ |
catch ( IOException e ) |
|
1148 |
+ |
{ |
|
1149 |
+ |
throw new WrappedIOException( e ); |
|
1150 |
+ |
} |
|
1151 |
+ |
try |
|
1152 |
+ |
{ |
|
1153 |
+ |
writer.write( "<html>\n" ); |
|
1154 |
+ |
writer.write( "<head><title>Applet</title></head>\n" ); |
|
1155 |
+ |
writer.write( "<body>\n" ); |
|
1156 |
+ |
writer.write( "<applet code='org.lwjgl.util.applet.AppletLoader' archive='lwjgl_util_applet.jar, lzma.jar' codebase='.' width='640' height='480'>\n" ); |
|
1157 |
+ |
if ( project.hasVersion() ) |
|
1158 |
+ |
{ |
|
1159 |
+ |
writer.write( "<param name='al_version' value='" + project.getVersion() + "'>\n" ); |
|
1160 |
+ |
} |
|
1161 |
+ |
writer.write( "<param name='al_title' value='" + project + "'>\n" ); |
|
1162 |
+ |
writer.write( "<param name='al_main' value='" + project.getMain() + "'>\n" ); |
|
1163 |
+ |
writer.write( "<param name='al_jars' value='" ); |
|
1164 |
+ |
int i = 0; |
|
1165 |
+ |
for ( String name : new Paths( appletDir, "*.jar.pack.lzma" ).getNames() ) |
|
1166 |
+ |
{ |
|
1167 |
+ |
if ( i++ > 0 ) |
|
1168 |
+ |
{ |
|
1169 |
+ |
writer.write( ", " ); |
|
1170 |
+ |
} |
|
1171 |
+ |
writer.write( name ); |
|
1172 |
+ |
} |
|
1173 |
+ |
writer.write( "'>\n" ); |
|
1174 |
+ |
Paths nativePaths = new Paths( appletDir, "*native*win*.jar.lzma", "*win*native*.jar.lzma" ); |
|
1175 |
+ |
if ( nativePaths.count() == 1 ) |
|
1176 |
+ |
{ |
|
1177 |
+ |
writer.write( "<param name='al_windows' value='" + nativePaths.getNames().get( 0 ) + "'>\n" ); |
|
1178 |
+ |
} |
|
1179 |
+ |
nativePaths = new Paths( appletDir, "*native*mac*.jar.lzma", "*mac*native*.jar.lzma" ); |
|
1180 |
+ |
if ( nativePaths.count() == 1 ) |
|
1181 |
+ |
{ |
|
1182 |
+ |
writer.write( "<param name='al_mac' value='" + nativePaths.getNames().get( 0 ) + "'>\n" ); |
|
1183 |
+ |
} |
|
1184 |
+ |
nativePaths = new Paths( appletDir, "*native*linux*.jar.lzma", "*linux*native*.jar.lzma" ); |
|
1185 |
+ |
if ( nativePaths.count() == 1 ) |
|
1186 |
+ |
{ |
|
1187 |
+ |
writer.write( "<param name='al_linux' value='" + nativePaths.getNames().get( 0 ) + "'>\n" ); |
|
1188 |
+ |
} |
|
1189 |
+ |
nativePaths = new Paths( appletDir, "*native*solaris*.jar.lzma", "*solaris*native*.jar.lzma" ); |
|
1190 |
+ |
if ( nativePaths.count() == 1 ) |
|
1191 |
+ |
{ |
|
1192 |
+ |
writer.write( "<param name='al_solaris' value='" + nativePaths.getNames().get( 0 ) + "'>\n" ); |
|
1193 |
+ |
} |
|
1194 |
+ |
writer.write( "<param name='al_logo' value='appletlogo.png'>\n" ); |
|
1195 |
+ |
writer.write( "<param name='al_progressbar' value='appletprogress.gif'>\n" ); |
|
1196 |
+ |
writer.write( "<param name='separate_jvm' value='true'>\n" ); |
|
1197 |
+ |
writer.write( "<param name='java_arguments' value='-Dsun.java2d.noddraw=true -Dsun.awt.noerasebackground=true -Dsun.java2d.d3d=false -Dsun.java2d.opengl=false -Dsun.java2d.pmoffscreen=false'>\n" ); |
|
1198 |
+ |
writer.write( "</applet>\n" ); |
|
1199 |
+ |
writer.write( "</body></html>\n" ); |
|
1200 |
+ |
} |
|
1201 |
+ |
catch ( IOException e ) |
|
1202 |
+ |
{ |
|
1203 |
+ |
throw new WrappedIOException( e ); |
|
1204 |
+ |
} |
|
1205 |
+ |
finally |
|
1206 |
+ |
{ |
|
1207 |
+ |
dispose( writer ); |
|
1208 |
+ |
} |
|
1209 |
+ |
return appletDir; |
|
1210 |
+ |
} |
|
1211 |
+ |
|
|
1212 |
+ |
/** |
|
1213 |
+ |
* Compiles and executes the specified Java code. The code is compiled as if it were a Java method body. |
|
1214 |
+ |
* <p/> |
|
1215 |
+ |
* Imports statements can be used at the start of the code. These imports are automatically used:<br> |
|
1216 |
+ |
* import com.esotericsoftware.scar.Scar;<br> |
|
1217 |
+ |
* import com.esotericsoftware.filesystem.Paths;<br> |
|
1218 |
+ |
* import com.esotericsoftware.minlog.Log;<br> |
|
1219 |
+ |
* import static com.esotericsoftware.scar.Scar.*;<br> |
|
1220 |
+ |
* import static com.esotericsoftware.minlog.Log.*;<br> |
|
1221 |
+ |
* <p/> |
|
1222 |
+ |
* Entries can be added to the classpath by using "classpath [url];" statements at the start of the code. These classpath |
|
1223 |
+ |
* entries are checked before the classloader that loaded the Scar class is checked. Examples:<br> |
|
1224 |
+ |
* classpath someTools.jar;<br> |
|
1225 |
+ |
* classpath some/directory/of/class/files;<br> |
|
1226 |
+ |
* classpath http://example.com/someTools.jar;<br> |
|
1227 |
+ |
* |
|
1228 |
+ |
* @param parameters These parameters will be available in the scope where the code is executed. |
|
1229 |
+ |
*/ |
|
1230 |
+ |
public void executeCode( Project project, String code, HashMap<String, Object> parameters ) |
|
1231 |
+ |
{ |
|
1232 |
+ |
try |
|
1233 |
+ |
{ |
|
1234 |
+ |
// Wrap code in a class. |
|
1235 |
+ |
StringBuilder classBuffer = new StringBuilder( 2048 ); |
|
1236 |
+ |
classBuffer.append( "import com.esotericsoftware.scar.*;\n" ); |
|
1237 |
+ |
classBuffer.append( "import com.esotericsoftware.minlog.Log;\n" ); |
|
1238 |
+ |
classBuffer.append( "import com.esotericsoftware.filesystem.Paths;\n" ); |
|
1239 |
+ |
classBuffer.append( "import static com.esotericsoftware.scar.Scar.*;\n" ); |
|
1240 |
+ |
classBuffer.append( "import static com.esotericsoftware.minlog.Log.*;\n" ); |
|
1241 |
+ |
classBuffer.append( "public class Generated {\n" ); |
|
1242 |
+ |
int pOverheadStartLines = 6; |
|
1243 |
+ |
classBuffer.append( "public void execute (" ); |
|
1244 |
+ |
int i = 0; |
|
1245 |
+ |
for ( Entry<String, Object> entry : parameters.entrySet() ) |
|
1246 |
+ |
{ |
|
1247 |
+ |
if ( i++ > 0 ) |
|
1248 |
+ |
{ |
|
1249 |
+ |
classBuffer.append( ',' ); |
|
1250 |
+ |
} |
|
1251 |
+ |
classBuffer.append( '\n' ); |
|
1252 |
+ |
pOverheadStartLines++; |
|
1253 |
+ |
classBuffer.append( entry.getValue().getClass().getName() ); |
|
1254 |
+ |
classBuffer.append( ' ' ); |
|
1255 |
+ |
classBuffer.append( entry.getKey() ); |
|
1256 |
+ |
} |
|
1257 |
+ |
classBuffer.append( "\n) throws Exception {\n" ); |
|
1258 |
+ |
pOverheadStartLines += 2; |
|
1259 |
+ |
|
|
1260 |
+ |
// Append code, collecting imports statements and classpath URLs. |
|
1261 |
+ |
StringBuilder importBuffer = new StringBuilder( 512 ); |
|
1262 |
+ |
ArrayList<URL> classpathURLs = new ArrayList<URL>(); |
|
1263 |
+ |
BufferedReader reader = new BufferedReader( new StringReader( code ) ); |
|
1264 |
+ |
boolean header = true; |
|
1265 |
+ |
while ( true ) |
|
1266 |
+ |
{ |
|
1267 |
+ |
String line = reader.readLine(); |
|
1268 |
+ |
if ( line == null ) |
|
1269 |
+ |
{ |
|
1270 |
+ |
break; |
|
1271 |
+ |
} |
|
1272 |
+ |
String trimmed = line.trim(); |
|
1273 |
+ |
if ( header && trimmed.startsWith( "import " ) && trimmed.endsWith( ";" ) ) |
|
1274 |
+ |
{ |
|
1275 |
+ |
importBuffer.append( line ); |
|
1276 |
+ |
importBuffer.append( '\n' ); |
|
1277 |
+ |
} |
|
1278 |
+ |
else if ( header && trimmed.startsWith( "classpath " ) && trimmed.endsWith( ";" ) ) |
|
1279 |
+ |
{ |
|
1280 |
+ |
String path = substring( line.trim(), 10, -1 ); |
|
1281 |
+ |
try |
|
1282 |
+ |
{ |
|
1283 |
+ |
classpathURLs.add( new URL( path ) ); |
|
1284 |
+ |
} |
|
1285 |
+ |
catch ( MalformedURLException ex ) |
|
1286 |
+ |
{ |
|
1287 |
+ |
classpathURLs.add( new File( project.path( path ) ).toURI().toURL() ); |
|
1288 |
+ |
} |
|
1289 |
+ |
} |
|
1290 |
+ |
else |
|
1291 |
+ |
{ |
|
1292 |
+ |
if ( trimmed.length() > 0 ) |
|
1293 |
+ |
{ |
|
1294 |
+ |
header = false; |
|
1295 |
+ |
} |
|
1296 |
+ |
classBuffer.append( line ); |
|
1297 |
+ |
classBuffer.append( '\n' ); |
|
1298 |
+ |
} |
|
1299 |
+ |
} |
|
1300 |
+ |
classBuffer.append( "}}" ); |
|
1301 |
+ |
|
|
1302 |
+ |
final String classCode = importBuffer.append( classBuffer ).toString(); |
|
1303 |
+ |
if ( LOGGER.trace.isEnabled() ) |
|
1304 |
+ |
{ |
|
1305 |
+ |
progress( "Executing code:\n" + classCode ); |
|
1306 |
+ |
} |
|
1307 |
+ |
// Compile class. |
|
1308 |
+ |
Class generatedClass = compileDynamicCodeToClass( pOverheadStartLines, classCode, classpathURLs.toArray( new URL[classpathURLs.size()] ) ); |
|
1309 |
+ |
|
|
1310 |
+ |
// Execute. |
|
1311 |
+ |
Class[] parameterTypes = new Class[parameters.size()]; |
|
1312 |
+ |
Object[] parameterValues = new Object[parameters.size()]; |
|
1313 |
+ |
i = 0; |
|
1314 |
+ |
for ( Object object : parameters.values() ) |
|
1315 |
+ |
{ |
|
1316 |
+ |
parameterValues[i] = object; |
|
1317 |
+ |
parameterTypes[i++] = object.getClass(); |
|
1318 |
+ |
} |
|
1319 |
+ |
generatedClass.getMethod( "execute", parameterTypes ).invoke( generatedClass.newInstance(), parameterValues ); |
|
1320 |
+ |
} |
|
1321 |
+ |
catch ( Throwable ex ) |
|
1322 |
+ |
{ |
|
1323 |
+ |
throw new RuntimeException( "Error executing code:\n" + code.trim(), ex ); |
|
1324 |
+ |
} |
|
1325 |
+ |
} |
|
1326 |
+ |
|
|
1327 |
+ |
// /** |
|
1328 |
+ |
// * Executes Java code in the specified project's document, if any. |
|
1329 |
+ |
// * |
|
1330 |
+ |
// * @return true if code was executed. |
|
1331 |
+ |
// */ |
|
1332 |
+ |
// public boolean executeDocument( Project project ) |
|
1333 |
+ |
// { |
|
1334 |
+ |
// String code = null; // todo: was -- project.getDocument(); |
|
1335 |
+ |
// if ( code == null || code.trim().isEmpty() ) |
|
1336 |
+ |
// { |
|
1337 |
+ |
// return false; |
|
1338 |
+ |
// } |
|
1339 |
+ |
// HashMap<String, Object> parameters = new HashMap<String, Object>(); |
|
1340 |
+ |
// parameters.put( "project", project ); |
|
1341 |
+ |
// executeCode( project, code, parameters ); |
|
1342 |
+ |
// return true; |
|
1343 |
+ |
// } |
|
1344 |
+ |
|
|
1345 |
+ |
// /** |
|
1346 |
+ |
// * List of project names that have been built. {@link #buildDependencies(Project)} will skip any projects with a matching name. |
|
1347 |
+ |
// */ |
|
1348 |
+ |
// static public final List<String> builtProjects = new ArrayList<String>(); |
|
1349 |
+ |
// |
|
1350 |
+ |
static |
|
1351 |
+ |
{ |
|
1352 |
+ |
Paths.addDefaultGlobExcludes( "**/.svn/**" ); |
|
1353 |
+ |
} |
|
1354 |
+ |
|
|
1355 |
+ |
/// todo: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Here be Dragons ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
|
1356 |
+ |
/// todo: ================================================================================================================== |
|
1357 |
+ |
/// todo: ================================================================================================================== |
|
1358 |
+ |
/// todo: ================================================================================================================== |
|
1359 |
+ |
/// todo: ================================================================================================================== |
|
1360 |
+ |
/// todo: ================================================================================================================== |
|
1361 |
+ |
/// todo: ================================================================================================================== |
|
1362 |
+ |
/// todo: ================================================================================================================== |
|
1363 |
+ |
/// todo: ================================================================================================================== |
|
1364 |
+ |
/// todo: ================================================================================================================== |
|
1365 |
+ |
/// todo: ================================================================================================================== |
|
1366 |
+ |
/// todo: ================================================================================================================== |
|
1367 |
+ |
|
|
1368 |
+ |
private static class BuildFileFilter implements FileFilter |
|
1369 |
+ |
{ |
|
1370 |
+ |
private static final String DEFAULT_JAVA_PROJECT_FILE_NAME = DEFAULT_PROJECT_FILE_NAME + JAVA_EXTENSION; |
|
1371 |
+ |
private static final String DEFAULT_YAML_PROJECT_FILE_NAME = DEFAULT_PROJECT_FILE_NAME + YAML_EXTENSION; |
|
1372 |
+ |
|
|
1373 |
+ |
@Override |
|
1374 |
+ |
public boolean accept( File pFile ) |
|
1375 |
+ |
{ |
|
1376 |
+ |
if ( pFile.isFile() ) |
|
1377 |
+ |
{ |
|
1378 |
+ |
String zName = pFile.getName(); |
|
1379 |
+ |
if ( DEFAULT_JAVA_PROJECT_FILE_NAME.equalsIgnoreCase( zName ) || DEFAULT_YAML_PROJECT_FILE_NAME.equalsIgnoreCase( zName ) ) |
|
1380 |
+ |
{ |
|
1381 |
+ |
return pFile.canRead(); |
|
1382 |
+ |
} |
|
1383 |
+ |
} |
|
1384 |
+ |
return false; |
|
1385 |
+ |
} |
|
1386 |
+ |
|
|
1387 |
+ |
public static final FileFilter INSTANCE = new BuildFileFilter(); |
|
1388 |
+ |
} |
|
1389 |
+ |
|
|
1390 |
+ |
private static class ProjectCache |
|
1391 |
+ |
{ |
|
1392 |
+ |
private Map<String, Project> mProjectByName = new HashMap<String, Project>(); |
|
1393 |
+ |
private Map<String, Project> mProjectByPath = new HashMap<String, Project>(); |
|
1394 |
+ |
|
|
1395 |
+ |
public synchronized Project getByPath( String pPath ) |
|
1396 |
+ |
{ |
|
1397 |
+ |
return mProjectByPath.get( pPath ); |
|
1398 |
+ |
} |
|
1399 |
+ |
|
|
1400 |
+ |
private Project initialize( ProjectFactory pFactory, String pPath, Project pProject ) |
|
1401 |
+ |
{ |
|
1402 |
+ |
synchronized ( this ) |
|
1403 |
+ |
{ |
|
1404 |
+ |
String zName = pProject.getName(); |
|
1405 |
+ |
Project zProject = mProjectByName.get( zName ); |
|
1406 |
+ |
if ( zProject != null ) |
|
1407 |
+ |
{ |
|
1408 |
+ |
mProjectByPath.put( pPath, zProject ); |
|
1409 |
+ |
return zProject; |
|
1410 |
+ |
} |
|
1411 |
+ |
mProjectByPath.put( pPath, pProject ); |
|
1412 |
+ |
mProjectByName.put( zName, pProject ); |
|
1413 |
+ |
} |
|
1414 |
+ |
pProject.initialize( pFactory ); |
|
1415 |
+ |
return pProject; |
|
1416 |
+ |
} |
|
1417 |
+ |
|
|
1418 |
+ |
public Set<Project> getAllProjects() |
|
1419 |
+ |
{ |
|
1420 |
+ |
return new HashSet<Project>( mProjectByName.values() ); |
|
1421 |
+ |
} |
|
1422 |
+ |
} |
|
1423 |
+ |
|
|
1424 |
+ |
protected Runnable createRunnableFor( String pMethodName ) |
|
1425 |
+ |
{ |
|
1426 |
+ |
Runnable zRunnable = createRunnableFor( this, pMethodName ); |
|
1427 |
+ |
return (zRunnable != null) ? zRunnable : createRunnableFor( mLaunchProject, pMethodName ); |
|
1428 |
+ |
} |
|
1429 |
+ |
|
|
1430 |
+ |
protected Runnable createRunnableFor( final Object pObject, String pMethodName ) |
|
1431 |
+ |
{ |
|
1432 |
+ |
final Method zMethod = getMatchingMethod( pObject, pMethodName ); |
|
1433 |
+ |
return (zMethod == null) ? null : new Runnable() |
|
1434 |
+ |
{ |
|
1435 |
+ |
@Override public void run() |
|
1436 |
+ |
{ |
|
1437 |
+ |
try |
|
1438 |
+ |
{ |
|
1439 |
+ |
zMethod.invoke( pObject ); |
|
1440 |
+ |
} |
|
1441 |
+ |
catch ( Exception e ) |
|
1442 |
+ |
{ |
|
1443 |
+ |
throw new RuntimeException( e ); |
|
1444 |
+ |
} |
|
1445 |
+ |
} |
|
1446 |
+ |
}; |
|
1447 |
+ |
} |
|
1448 |
+ |
|
|
1449 |
+ |
protected Method getMatchingMethod( Object pObject, String pMethodName ) |
|
1450 |
+ |
{ |
|
1451 |
+ |
List<Method> zFound = new ArrayList<Method>(); |
|
1452 |
+ |
Method[] zMethods = pObject.getClass().getMethods(); |
|
1453 |
+ |
for ( Method zMethod : zMethods ) |
|
1454 |
+ |
{ |
|
1455 |
+ |
if ( zMethod.getReturnType().equals( Void.TYPE ) && (zMethod.getParameterTypes().length == 0) ) |
|
1456 |
+ |
{ |
|
1457 |
+ |
if ( pMethodName.equals( zMethod.getName() ) ) |
|
1458 |
+ |
{ |
|
1459 |
+ |
return zMethod; |
|
1460 |
+ |
} |
|
1461 |
+ |
if ( pMethodName.equalsIgnoreCase( zMethod.getName() ) ) |
|
1462 |
+ |
{ |
|
1463 |
+ |
zFound.add( zMethod ); |
|
1464 |
+ |
} |
|
1465 |
+ |
} |
|
1466 |
+ |
} |
|
1467 |
+ |
if ( zFound.size() == 0 ) |
|
1468 |
+ |
{ |
|
1469 |
+ |
return null; |
|
1470 |
+ |
} |
|
1471 |
+ |
if ( zFound.size() == 1 ) |
|
1472 |
+ |
{ |
|
1473 |
+ |
return zFound.get( 0 ); |
|
1474 |
+ |
} |
|
1475 |
+ |
throw new IllegalArgumentException( "Multiple Methods " + zFound + " found on '" + pObject.getClass().getSimpleName() + "' than match: " + pMethodName ); |
|
1476 |
+ |
} |
|
1477 |
+ |
|
|
1478 |
+ |
protected void createLaunchProject() |
|
1479 |
+ |
{ |
|
1480 |
+ |
mLaunchProject = project( CANONICAL_USER_DIR, mArgs.get( "file", "." ) ); |
|
1481 |
+ |
} |
|
1482 |
+ |
|
|
1483 |
+ |
protected int run() |
|
1484 |
+ |
{ |
|
1485 |
+ |
System.out.println( getClass().getSimpleName() + " vs " + VERSION ); |
|
1486 |
+ |
if ( mArgs.count() == 0 ) |
|
1487 |
+ |
{ |
|
1488 |
+ |
mLaunchProject.build(); |
|
1489 |
+ |
return 0; |
|
1490 |
+ |
} |
|
1491 |
+ |
List<Runnable> zToExecute = getArgsBasedRunnables(); |
|
1492 |
+ |
for ( Runnable zRunnable : zToExecute ) |
|
1493 |
+ |
{ |
|
1494 |
+ |
zRunnable.run(); |
|
1495 |
+ |
} |
|
1496 |
+ |
return 0; |
|
1497 |
+ |
} |
|
1498 |
+ |
|
|
1499 |
+ |
private ArrayList<Runnable> getArgsBasedRunnables() |
|
1500 |
+ |
{ |
|
1501 |
+ |
ArrayList<Runnable> zRunnables = new ArrayList<Runnable>(); |
|
1502 |
+ |
List<String> zUnrecognizedNames = new ArrayList<String>(); |
|
1503 |
+ |
for ( Arguments.NameValuePair zPair; null != (zPair = mArgs.getNext()); ) |
|
1504 |
+ |
{ |
|
1505 |
+ |
Runnable zRunnable = createRunnableFor( zPair.getName() ); |
|
1506 |
+ |
if ( zRunnable != null ) |
|
1507 |
+ |
{ |
|
1508 |
+ |
zRunnables.add( zRunnable ); |
|
1509 |
+ |
} |
|
1510 |
+ |
else |
|
1511 |
+ |
{ |
|
1512 |
+ |
zUnrecognizedNames.add( zPair.getName() ); |
|
1513 |
+ |
} |
|
1514 |
+ |
} |
|
1515 |
+ |
if ( !zUnrecognizedNames.isEmpty() ) |
|
1516 |
+ |
{ |
|
1517 |
+ |
System.err.println( "\nUnrecognized Command Line Args:" ); |
|
1518 |
+ |
for ( String zName : zUnrecognizedNames ) |
|
1519 |
+ |
{ |
|
1520 |
+ |
System.err.println( " " + zName ); |
|
1521 |
+ |
} |
|
1522 |
+ |
System.exit( 1 ); |
|
1523 |
+ |
} |
|
1524 |
+ |
return zRunnables; |
|
1525 |
+ |
} |
|
1526 |
+ |
|
|
1527 |
+ |
public static void main( String[] args ) |
|
1528 |
+ |
throws Exception |
|
1529 |
+ |
{ |
|
1530 |
+ |
Arguments arguments = new Arguments( args ); |
|
1531 |
+ |
Scar scar = new Scar( arguments ); |
|
1532 |
+ |
scar.initLoggerFactory(); |
|
1533 |
+ |
scar.createLaunchProject(); |
|
1534 |
+ |
System.exit( scar.run() ); |
|
1535 |
+ |
} |
|
1536 |
+ |
} |