1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugin.eclipse;
20
21 import java.io.File;
22 import java.io.FileOutputStream;
23 import java.io.IOException;
24 import java.io.OutputStreamWriter;
25 import java.io.Writer;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.regex.Matcher;
32 import java.util.regex.Pattern;
33
34 import aQute.lib.osgi.Analyzer;
35
36 import org.apache.maven.artifact.Artifact;
37 import org.apache.maven.artifact.deployer.ArtifactDeployer;
38 import org.apache.maven.artifact.deployer.ArtifactDeploymentException;
39 import org.apache.maven.artifact.factory.ArtifactFactory;
40 import org.apache.maven.artifact.installer.ArtifactInstallationException;
41 import org.apache.maven.artifact.installer.ArtifactInstaller;
42 import org.apache.maven.artifact.metadata.ArtifactMetadata;
43 import org.apache.maven.artifact.repository.ArtifactRepository;
44 import org.apache.maven.artifact.repository.DefaultArtifactRepository;
45 import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
46 import org.apache.maven.model.Dependency;
47 import org.apache.maven.model.License;
48 import org.apache.maven.model.Model;
49 import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
50 import org.apache.maven.plugin.AbstractMojo;
51 import org.apache.maven.plugin.MojoExecutionException;
52 import org.apache.maven.plugin.MojoFailureException;
53 import org.apache.maven.plugin.eclipse.osgiplugin.EclipseOsgiPlugin;
54 import org.apache.maven.plugin.eclipse.osgiplugin.ExplodedPlugin;
55 import org.apache.maven.plugin.eclipse.osgiplugin.PackagedPlugin;
56 import org.apache.maven.project.artifact.ProjectArtifactMetadata;
57 import org.codehaus.plexus.PlexusConstants;
58 import org.codehaus.plexus.PlexusContainer;
59 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
60 import org.codehaus.plexus.components.interactivity.InputHandler;
61 import org.codehaus.plexus.context.Context;
62 import org.codehaus.plexus.context.ContextException;
63 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
64 import org.codehaus.plexus.util.IOUtil;
65 import org.codehaus.plexus.util.StringUtils;
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80 public class EclipseToMavenMojo
81 extends AbstractMojo
82 implements Contextualizable
83 {
84
85
86
87
88 private static final Pattern DEPLOYTO_PATTERN = Pattern.compile( "(.+)::(.+)::(.+)" );
89
90
91
92
93 private static final Pattern VERSION_PATTERN = Pattern.compile( "(([0-9]+\\.)+[0-9]+)" );
94
95
96
97
98 private PlexusContainer container;
99
100
101
102
103
104
105
106
107 private ArtifactRepository localRepository;
108
109
110
111
112
113
114 private ArtifactFactory artifactFactory;
115
116
117
118
119
120
121 protected ArtifactInstaller installer;
122
123
124
125
126
127
128 private ArtifactDeployer deployer;
129
130
131
132
133
134
135 private File eclipseDir;
136
137
138
139
140
141
142 protected InputHandler inputHandler;
143
144
145
146
147
148
149
150
151
152
153 private boolean stripQualifier;
154
155
156
157
158
159
160
161 private String deployTo;
162
163
164
165
166 public void execute()
167 throws MojoExecutionException, MojoFailureException
168 {
169 if ( eclipseDir == null )
170 {
171 getLog().info( "Eclipse directory? " );
172
173 String eclipseDirString;
174 try
175 {
176 eclipseDirString = inputHandler.readLine();
177 }
178 catch ( IOException e )
179 {
180 throw new MojoFailureException( "Unable to read from standard input" );
181 }
182 eclipseDir = new File( eclipseDirString );
183 }
184
185 if ( !eclipseDir.isDirectory() )
186 {
187 throw new MojoFailureException( "Directory " + eclipseDir.getAbsolutePath() + " doesn't exists" );
188 }
189
190 File pluginDir = new File( eclipseDir, "plugins" );
191
192 if ( !pluginDir.isDirectory() )
193 {
194 throw new MojoFailureException( "Plugin directory " + pluginDir.getAbsolutePath() + " doesn't exists" );
195 }
196
197 File[] files = pluginDir.listFiles();
198
199 ArtifactRepository remoteRepo = resolveRemoteRepo();
200
201 if ( remoteRepo != null )
202 {
203 getLog().info( "Will deploy artifacts to remote repository " + deployTo );
204 }
205
206 Map plugins = new HashMap();
207 Map models = new HashMap();
208
209 for ( int j = 0; j < files.length; j++ )
210 {
211 File file = files[j];
212
213 getLog().info( "Processing file " + file.getAbsolutePath() );
214
215 processFile( file, plugins, models );
216 }
217
218 int i = 1;
219 for ( Iterator it = plugins.keySet().iterator(); it.hasNext(); )
220 {
221 getLog().info( "Processing " + ( i++ ) + " of " + plugins.keySet().size() );
222 String key = (String) it.next();
223 EclipseOsgiPlugin plugin = (EclipseOsgiPlugin) plugins.get( key );
224 Model model = (Model) models.get( key );
225 writeArtifact( plugin, model, remoteRepo );
226 }
227 }
228
229 protected void processFile( File file, Map plugins, Map models )
230 throws MojoExecutionException, MojoFailureException
231 {
232 EclipseOsgiPlugin plugin = getEclipsePlugin( file );
233
234 if ( plugin == null )
235 {
236 getLog().warn( "Skipping file " + file.getAbsolutePath() );
237 return;
238 }
239
240 Model model = createModel( plugin );
241
242 if ( model == null )
243 {
244 return;
245 }
246
247 processPlugin( plugin, model, plugins, models );
248 }
249
250 protected void processPlugin( EclipseOsgiPlugin plugin, Model model, Map plugins, Map models )
251 throws MojoExecutionException, MojoFailureException
252 {
253 plugins.put( getKey( model ), plugin );
254 models.put( getKey( model ), model );
255 }
256
257 protected String getKey( Model model )
258 {
259 return model.getGroupId() + "." + model.getArtifactId();
260 }
261
262 private String getKey( Dependency dependency )
263 {
264 return dependency.getGroupId() + "." + dependency.getArtifactId();
265 }
266
267
268
269
270
271
272
273
274
275 protected void resolveVersionRanges( Model model, Map models )
276 throws MojoFailureException
277 {
278 for ( Iterator it = model.getDependencies().iterator(); it.hasNext(); )
279 {
280 Dependency dep = (Dependency) it.next();
281 if ( dep.getVersion().indexOf( "[" ) > -1 || dep.getVersion().indexOf( "(" ) > -1 )
282 {
283 String key = getKey( model );
284 Model dependencyModel = (Model) models.get( getKey( dep ) );
285 if ( dependencyModel != null )
286 {
287 dep.setVersion( dependencyModel.getVersion() );
288 }
289 else
290 {
291 throw new MojoFailureException( "Unable to resolve version range for dependency " + dep +
292 " in project " + key );
293 }
294 }
295 }
296 }
297
298
299
300
301
302
303
304 private EclipseOsgiPlugin getEclipsePlugin( File file )
305 throws MojoExecutionException
306 {
307 if ( file.isDirectory() )
308 {
309 return new ExplodedPlugin( file );
310 }
311 else if ( file.getName().endsWith( ".jar" ) )
312 {
313 try
314 {
315 return new PackagedPlugin( file );
316 }
317 catch ( IOException e )
318 {
319 throw new MojoExecutionException( "Unable to access jar " + file.getAbsolutePath(), e );
320 }
321 }
322
323 return null;
324 }
325
326
327
328
329
330
331
332 private Model createModel( EclipseOsgiPlugin plugin )
333 throws MojoExecutionException
334 {
335
336 String name, bundleName, version, groupId, artifactId, requireBundle;
337
338 try
339 {
340 if ( !plugin.hasManifest() )
341 {
342 getLog().warn( "Plugin " + plugin + " does not have a manifest; skipping.." );
343 return null;
344 }
345
346 Analyzer analyzer = new Analyzer();
347
348 Map bundleSymbolicNameHeader =
349 analyzer.parseHeader( plugin.getManifestAttribute( Analyzer.BUNDLE_SYMBOLICNAME ) );
350 bundleName = (String) bundleSymbolicNameHeader.keySet().iterator().next();
351 version = plugin.getManifestAttribute( Analyzer.BUNDLE_VERSION );
352
353 if ( bundleName == null || version == null )
354 {
355 getLog().error( "Unable to read bundle name/version from manifest, skipping..." );
356 return null;
357 }
358
359 version = osgiVersionToMavenVersion( version );
360
361 name = plugin.getManifestAttribute( Analyzer.BUNDLE_NAME );
362
363 requireBundle = plugin.getManifestAttribute( Analyzer.REQUIRE_BUNDLE );
364
365 }
366 catch ( IOException e )
367 {
368 throw new MojoExecutionException( "Error processing plugin " + plugin, e );
369 }
370
371 Dependency[] deps = parseDependencies( requireBundle );
372
373 groupId = createGroupId( bundleName );
374 artifactId = createArtifactId( bundleName );
375
376 Model model = new Model();
377 model.setModelVersion( "4.0.0" );
378 model.setGroupId( groupId );
379 model.setArtifactId( artifactId );
380 model.setName( name );
381 model.setVersion( version );
382
383 model.setProperties( plugin.getPomProperties() );
384
385 if ( groupId.startsWith( "org.eclipse" ) )
386 {
387
388
389
390
391
392
393
394
395
396
397 License license = new License();
398 license.setName( "Eclipse Public License - v 1.0" );
399 license.setUrl( "http://www.eclipse.org/org/documents/epl-v10.html" );
400 model.addLicense( license );
401 }
402
403 if ( deps.length > 0 )
404 {
405 for ( int k = 0; k < deps.length; k++ )
406 {
407 model.getDependencies().add( deps[k] );
408 }
409
410 }
411
412 return model;
413 }
414
415
416
417
418
419
420
421
422 private void writeArtifact( EclipseOsgiPlugin plugin, Model model, ArtifactRepository remoteRepo )
423 throws MojoExecutionException
424 {
425 Writer fw = null;
426 ArtifactMetadata metadata = null;
427 File pomFile = null;
428 Artifact pomArtifact =
429 artifactFactory.createArtifact( model.getGroupId(), model.getArtifactId(), model.getVersion(), null, "pom" );
430 Artifact artifact =
431 artifactFactory.createArtifact( model.getGroupId(), model.getArtifactId(), model.getVersion(), null,
432 Constants.PROJECT_PACKAGING_JAR );
433 try
434 {
435 pomFile = File.createTempFile( "pom-", ".xml" );
436
437
438 fw = new OutputStreamWriter( new FileOutputStream( pomFile ), "UTF-8" );
439 model.setModelEncoding( "UTF-8" );
440 pomFile.deleteOnExit();
441 new MavenXpp3Writer().write( fw, model );
442 metadata = new ProjectArtifactMetadata( pomArtifact, pomFile );
443 pomArtifact.addMetadata( metadata );
444 }
445 catch ( IOException e )
446 {
447 throw new MojoExecutionException( "Error writing temporary pom file: " + e.getMessage(), e );
448 }
449 finally
450 {
451 IOUtil.close( fw );
452 }
453
454 try
455 {
456 File jarFile = plugin.getJarFile();
457
458 if ( remoteRepo != null )
459 {
460 deployer.deploy( pomFile, pomArtifact, remoteRepo, localRepository );
461 deployer.deploy( jarFile, artifact, remoteRepo, localRepository );
462 }
463 else
464 {
465 installer.install( pomFile, pomArtifact, localRepository );
466 installer.install( jarFile, artifact, localRepository );
467 }
468 }
469 catch ( ArtifactDeploymentException e )
470 {
471 throw new MojoExecutionException( "Unable to deploy artifact to repository.", e );
472 }
473 catch ( ArtifactInstallationException e )
474 {
475 throw new MojoExecutionException( "Unable to install artifact to repository.", e );
476 }
477 catch ( IOException e )
478 {
479 throw new MojoExecutionException( "Error getting the jar file for plugin " + plugin, e );
480 }
481 finally
482 {
483 pomFile.delete();
484 }
485
486 }
487
488 protected String osgiVersionToMavenVersion( String version )
489 {
490 return osgiVersionToMavenVersion( version, null, stripQualifier );
491 }
492
493
494
495
496
497
498
499
500
501
502 protected String osgiVersionToMavenVersion( String version, String forcedQualifier, boolean stripQualifier )
503 {
504 if ( stripQualifier && StringUtils.countMatches( version, "." ) > 2 )
505 {
506 version = StringUtils.substring( version, 0, version.lastIndexOf( "." ) );
507 }
508 else if ( StringUtils.countMatches( version, "." ) > 2 )
509 {
510 int lastDot = version.lastIndexOf( "." );
511 if ( StringUtils.isNotEmpty( forcedQualifier ) )
512 {
513 version = StringUtils.substring( version, 0, lastDot ) + "-" + forcedQualifier;
514 }
515 else
516 {
517 version =
518 StringUtils.substring( version, 0, lastDot ) + "-" +
519 StringUtils.substring( version, lastDot + 1, version.length() );
520 }
521 }
522 return version;
523 }
524
525
526
527
528
529
530
531
532 private ArtifactRepository resolveRemoteRepo()
533 throws MojoFailureException, MojoExecutionException
534 {
535 if ( deployTo != null )
536 {
537 Matcher matcher = DEPLOYTO_PATTERN.matcher( deployTo );
538
539 if ( !matcher.matches() )
540 {
541 throw new MojoFailureException( deployTo, "Invalid syntax for repository.",
542 "Invalid syntax for remote repository. Use \"id::layout::url\"." );
543 }
544 else
545 {
546 String id = matcher.group( 1 ).trim();
547 String layout = matcher.group( 2 ).trim();
548 String url = matcher.group( 3 ).trim();
549
550 ArtifactRepositoryLayout repoLayout;
551 try
552 {
553 repoLayout = (ArtifactRepositoryLayout) container.lookup( ArtifactRepositoryLayout.ROLE, layout );
554 }
555 catch ( ComponentLookupException e )
556 {
557 throw new MojoExecutionException( "Cannot find repository layout: " + layout, e );
558 }
559
560 return new DefaultArtifactRepository( id, url, repoLayout );
561 }
562 }
563 return null;
564 }
565
566
567
568
569 public void contextualize( Context context )
570 throws ContextException
571 {
572 this.container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
573 }
574
575
576
577
578
579
580
581 protected String createGroupId( String bundleName )
582 {
583 int i = bundleName.lastIndexOf( "." );
584 if ( i > 0 )
585 {
586 return bundleName.substring( 0, i );
587 }
588 else
589 return bundleName;
590 }
591
592
593
594
595
596
597
598 protected String createArtifactId( String bundleName )
599 {
600 int i = bundleName.lastIndexOf( "." );
601 if ( i > 0 )
602 {
603 return bundleName.substring( i + 1 );
604 }
605 else
606 return bundleName;
607 }
608
609
610
611
612
613
614
615 protected Dependency[] parseDependencies( String requireBundle )
616 {
617 if ( requireBundle == null )
618 {
619 return new Dependency[0];
620 }
621
622 List dependencies = new ArrayList();
623
624 Analyzer analyzer = new Analyzer();
625
626 Map requireBundleHeader = analyzer.parseHeader( requireBundle );
627
628
629 for ( Iterator iter = requireBundleHeader.entrySet().iterator(); iter.hasNext(); )
630 {
631 Map.Entry entry = (Map.Entry) iter.next();
632 String bundleName = (String) entry.getKey();
633 Map attributes = (Map) entry.getValue();
634
635 String version = (String) attributes.get( Analyzer.BUNDLE_VERSION.toLowerCase() );
636 boolean optional = "optional".equals( attributes.get( "resolution:" ) );
637
638 if ( version == null )
639 {
640 getLog().info( "Missing version for bundle " + bundleName + ", assuming any version > 0" );
641 version = "[0,)";
642 }
643
644 version = fixBuildNumberSeparator( version );
645
646 Dependency dep = new Dependency();
647 dep.setGroupId( createGroupId( bundleName ) );
648 dep.setArtifactId( createArtifactId( bundleName ) );
649 dep.setVersion( version );
650 dep.setOptional( optional );
651
652 dependencies.add( dep );
653
654 }
655
656 return (Dependency[]) dependencies.toArray( new Dependency[dependencies.size()] );
657
658 }
659
660
661
662
663
664
665
666 protected String fixBuildNumberSeparator( String versionRange )
667 {
668
669 if ( versionRange == null )
670 {
671 return null;
672 }
673
674 StringBuffer newVersionRange = new StringBuffer();
675
676 Matcher matcher = VERSION_PATTERN.matcher( versionRange );
677
678 while ( matcher.find() )
679 {
680 String group = matcher.group();
681
682 if ( StringUtils.countMatches( group, "." ) > 2 )
683 {
684
685 int lastDot = group.lastIndexOf( "." );
686 group =
687 StringUtils.substring( group, 0, lastDot ) + "-" +
688 StringUtils.substring( group, lastDot + 1, group.length() );
689 }
690 matcher.appendReplacement( newVersionRange, group );
691 }
692
693 matcher.appendTail( newVersionRange );
694
695 return newVersionRange.toString();
696 }
697
698 }