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