1 package org.codehaus.mojo.natives.plugin;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 import java.io.File;
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Set;
30
31 import org.apache.maven.artifact.Artifact;
32 import org.apache.maven.artifact.DefaultArtifact;
33 import org.apache.maven.artifact.factory.ArtifactFactory;
34 import org.apache.maven.plugin.MojoExecutionException;
35 import org.apache.maven.plugins.annotations.Component;
36 import org.apache.maven.plugins.annotations.LifecyclePhase;
37 import org.apache.maven.plugins.annotations.Mojo;
38 import org.apache.maven.plugins.annotations.Parameter;
39 import org.apache.maven.plugins.annotations.ResolutionScope;
40 import org.codehaus.mojo.natives.NativeBuildException;
41 import org.codehaus.mojo.natives.linker.Linker;
42 import org.codehaus.mojo.natives.linker.LinkerConfiguration;
43 import org.codehaus.mojo.natives.manager.LinkerManager;
44 import org.codehaus.mojo.natives.manager.NoSuchNativeProviderException;
45 import org.codehaus.plexus.util.FileUtils;
46 import org.codehaus.plexus.util.StringUtils;
47
48
49
50
51 @Mojo(name = "link", defaultPhase = LifecyclePhase.PACKAGE, requiresDependencyResolution = ResolutionScope.COMPILE)
52 public class NativeLinkMojo
53 extends AbstractNativeMojo
54 {
55
56
57
58
59
60 @Parameter(defaultValue = "generic", required = true)
61 private String compilerProvider;
62
63
64
65
66
67 @Parameter
68 private String linkerProvider;
69
70
71
72
73
74 @Parameter
75 private String linkerExecutable;
76
77
78
79
80
81 @Parameter
82 private List linkerStartOptions;
83
84
85
86
87
88 @Parameter
89 private List linkerMiddleOptions;
90
91
92
93
94
95 @Parameter
96 private List linkerEndOptions;
97
98
99
100
101
102 @Parameter
103 private List linkingOrderLibs;
104
105
106
107
108
109
110 @Parameter(defaultValue = "")
111 private String linkerSecondaryOutputExtensions;
112
113
114
115
116
117 @Parameter(defaultValue = "${project.build.directory}", required = true)
118 protected File linkerOutputDirectory;
119
120
121
122
123
124 @Parameter(defaultValue = "${project.build.finalName}", required = true)
125 private String linkerFinalName;
126
127
128
129
130
131
132 @Parameter(defaultValue = "${project.artifact.artifactHandler.extension}", required = true)
133 private String linkerFinalNameExt;
134
135
136
137
138
139 @Component
140 private LinkerManager manager;
141
142
143
144
145
146 @Component
147 private ArtifactFactory artifactFactory;
148
149
150
151
152
153 @Parameter(defaultValue = "${project.build.directory}/lib", required = true)
154 private File externalLibDirectory;
155
156
157
158
159
160 @Parameter
161 private String classifier;
162
163
164
165
166
167
168 @Parameter(defaultValue = "true")
169 private boolean attach;
170
171
172
173
174
175 @Parameter(defaultValue = "false")
176 private boolean usingLinkerResponseFile;
177
178
179
180
181
182 @Parameter(defaultValue = "false")
183 private boolean checkStaleLinkage;
184
185 public void execute()
186 throws MojoExecutionException
187 {
188
189 if ( StringUtils.isEmpty( this.classifier ) )
190 {
191 this.classifier = null;
192 }
193
194 Linker linker = this.getLinker();
195
196 this.config = this.createLinkerConfiguration();
197
198 try
199 {
200 List allCompilerOuputFiles = this.getAllCompilersOutputFileList();
201
202 File outputFile = linker.link( config, allCompilerOuputFiles );
203
204
205 this.getPluginContext().put( AbstractNativeMojo.LINKER_OUTPUT_PATH, outputFile );
206
207 }
208 catch ( IOException ioe )
209 {
210 throw new MojoExecutionException( ioe.getMessage(), ioe );
211 }
212 catch ( NativeBuildException nbe )
213 {
214 throw new MojoExecutionException( nbe.getMessage(), nbe );
215 }
216
217 if ( this.attach )
218 {
219 this.attachPrimaryArtifact();
220
221 this.attachSecondaryArtifacts();
222 }
223 }
224
225 private LinkerConfiguration createLinkerConfiguration()
226 throws MojoExecutionException
227 {
228 LinkerConfiguration config = new LinkerConfiguration();
229 config.setWorkingDirectory( this.workingDirectory );
230 config.setExecutable( this.linkerExecutable );
231 config.setStartOptions( removeEmptyOptions( this.linkerStartOptions ) );
232 config.setMiddleOptions( removeEmptyOptions( this.linkerMiddleOptions ) );
233 config.setEndOptions( removeEmptyOptions( this.linkerEndOptions ) );
234 config.setOutputDirectory( this.linkerOutputDirectory );
235 config.setOutputFileName( this.linkerFinalName );
236 config.setOutputFileExtension( this.linkerFinalNameExt );
237 config.setExternalLibDirectory( this.externalLibDirectory );
238 config.setExternalLibFileNames( this.getLibFileNames() );
239 config.setEnvFactory( this.getEnvFactory() );
240 config.setUsingLinkerResponseFile( usingLinkerResponseFile );
241 config.setCheckStaleLinkage( this.checkStaleLinkage );
242
243 return config;
244 }
245
246 private Linker getLinker()
247 throws MojoExecutionException
248 {
249 Linker linker;
250
251 try
252 {
253 if ( this.linkerProvider == null )
254 {
255 this.linkerProvider = this.compilerProvider;
256 }
257
258 linker = this.manager.getLinker( this.linkerProvider );
259 }
260 catch ( NoSuchNativeProviderException pe )
261 {
262 throw new MojoExecutionException( pe.getMessage() );
263 }
264
265 return linker;
266 }
267
268
269
270
271 private void attachPrimaryArtifact()
272 {
273 Artifact artifact = this.project.getArtifact();
274
275 if ( null == this.classifier )
276 {
277 artifact.setFile( new File( this.linkerOutputDirectory + "/" + this.project.getBuild().getFinalName() + "."
278 + this.project.getArtifact().getArtifactHandler().getExtension() ) );
279 }
280 else
281 {
282
283
284 DefaultArtifact clone =
285 new DefaultArtifact( artifact.getGroupId(), artifact.getArtifactId(),
286 artifact.getVersionRange().cloneOf(), artifact.getScope(), artifact.getType(),
287 classifier, artifact.getArtifactHandler(), artifact.isOptional() );
288
289 clone.setRelease( artifact.isRelease() );
290 clone.setResolvedVersion( artifact.getVersion() );
291 clone.setResolved( artifact.isResolved() );
292 clone.setFile( artifact.getFile() );
293
294 if ( artifact.getAvailableVersions() != null )
295 {
296 clone.setAvailableVersions( new ArrayList( artifact.getAvailableVersions() ) );
297 }
298
299 clone.setBaseVersion( artifact.getBaseVersion() );
300 clone.setDependencyFilter( artifact.getDependencyFilter() );
301
302 if ( artifact.getDependencyTrail() != null )
303 {
304 clone.setDependencyTrail( new ArrayList( artifact.getDependencyTrail() ) );
305 }
306
307 clone.setDownloadUrl( artifact.getDownloadUrl() );
308 clone.setRepository( artifact.getRepository() );
309
310 clone.setFile( new File( this.linkerOutputDirectory + "/" + this.project.getBuild().getFinalName() + "."
311 + this.project.getArtifact().getArtifactHandler().getExtension() ) );
312
313 project.setArtifact( clone );
314 }
315 }
316
317 private void attachSecondaryArtifacts()
318 {
319 final String[] tokens;
320 if(this.linkerSecondaryOutputExtensions != null) {
321 tokens = StringUtils.split( this.linkerSecondaryOutputExtensions, "," );
322 } else {
323 tokens = new String[0];
324 }
325
326 for ( int i = 0; i < tokens.length; ++i )
327 {
328
329 Artifact artifact =
330 artifactFactory.createArtifact( project.getGroupId(), project.getArtifactId(), project.getVersion(),
331 this.classifier, tokens[i].trim() );
332 artifact.setFile( new File( this.linkerOutputDirectory + "/" + this.project.getBuild().getFinalName() + "."
333 + tokens[i].trim() ) );
334
335 project.addAttachedArtifact( artifact );
336 }
337
338 }
339
340 private List getLibFileNames()
341 throws MojoExecutionException
342 {
343 List libList = new ArrayList();
344
345 Set artifacts = this.project.getArtifacts();
346
347 for ( Iterator iter = artifacts.iterator(); iter.hasNext(); )
348 {
349 Artifact artifact = (Artifact) iter.next();
350
351 if ( INCZIP_TYPE.equals( artifact.getType() ) )
352 {
353 continue;
354 }
355
356 String libFileName = FileUtils.filename( this.getDependencyFile( artifact, true ).getPath() );
357
358 libList.add( libFileName );
359 }
360
361 libList = this.reorderLibDependencies( libList );
362
363 return libList;
364 }
365
366
367
368
369
370
371 private List getDependenciesFileOrderList()
372 throws MojoExecutionException
373 {
374 List list = new ArrayList();
375
376 if ( this.linkingOrderLibs != null )
377 {
378 for ( Iterator i = linkingOrderLibs.iterator(); i.hasNext(); )
379 {
380 String element = i.next().toString();
381
382 Artifact artifact = lookupDependencyUsingGroupArtifactIdPair( element );
383
384 if ( artifact != null )
385 {
386 String libFileName = FileUtils.filename( this.getDependencyFile( artifact, false ).getPath() );
387
388 list.add( libFileName );
389 }
390 else
391 {
392 throw new MojoExecutionException( element + " not found on project dependencies." );
393 }
394 }
395 }
396
397 return list;
398 }
399
400
401
402
403
404
405
406
407
408
409 private Artifact lookupDependencyUsingGroupArtifactIdPair( String groupArtifactIdPair )
410 throws MojoExecutionException
411 {
412 String[] tokens = StringUtils.split( groupArtifactIdPair, ":" );
413
414 if ( tokens.length != 2 )
415 {
416 throw new MojoExecutionException( "Invalid groupId and artifactId pair: " + groupArtifactIdPair );
417 }
418
419 Set allDependencyArtifacts = project.getDependencyArtifacts();
420
421 for ( Iterator iter = allDependencyArtifacts.iterator(); iter.hasNext(); )
422 {
423 Artifact artifact = (Artifact) iter.next();
424 if ( INCZIP_TYPE.equals( artifact.getType() ) )
425 {
426 continue;
427 }
428
429 if ( tokens[0].equals( artifact.getGroupId() ) && tokens[1].equals( artifact.getArtifactId() ) )
430 {
431 return artifact;
432 }
433 }
434
435 return null;
436
437 }
438
439 private List reorderLibDependencies( List libs )
440 throws MojoExecutionException
441 {
442 List requestedOrderList = getDependenciesFileOrderList();
443
444 if ( requestedOrderList.size() != 0 )
445 {
446
447 for ( Iterator i = requestedOrderList.iterator(); i.hasNext(); )
448 {
449 libs.remove( i.next() );
450 }
451
452 for ( Iterator i = libs.iterator(); i.hasNext(); )
453 {
454 requestedOrderList.add( i.next() );
455 }
456
457 return requestedOrderList;
458 }
459 else
460 {
461 return libs;
462 }
463 }
464
465 private File getDependencyFile( Artifact artifact, boolean doCopy )
466 throws MojoExecutionException
467 {
468
469 File newLocation =
470 new File( this.externalLibDirectory, artifact.getArtifactId() + "."
471 + artifact.getArtifactHandler().getExtension() );
472
473 try
474 {
475 if ( doCopy && !artifact.getFile().isDirectory()
476 && ( !newLocation.exists() || newLocation.lastModified() <= artifact.getFile().lastModified() ) )
477 {
478 FileUtils.copyFile( artifact.getFile(), newLocation );
479 }
480 }
481 catch ( IOException ioe )
482 {
483 throw new MojoExecutionException( "Unable to copy dependency to staging area. Could not copy "
484 + artifact.getFile() + " to " + newLocation, ioe );
485 }
486
487 return newLocation;
488 }
489
490
491
492
493
494
495 private LinkerConfiguration config;
496
497 protected LinkerConfiguration getLgetLinkerConfiguration()
498 {
499 return this.config;
500 }
501
502 }