View Javadoc

1   package org.apache.maven.plugins.repository;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.artifact.Artifact;
23  import org.apache.maven.artifact.factory.ArtifactFactory;
24  import org.apache.maven.artifact.repository.ArtifactRepository;
25  import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
26  import org.apache.maven.artifact.resolver.ArtifactResolutionException;
27  import org.apache.maven.artifact.resolver.ArtifactResolver;
28  import org.apache.maven.model.License;
29  import org.apache.maven.model.Model;
30  import org.apache.maven.model.Scm;
31  import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
32  import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
33  import org.apache.maven.plugin.AbstractMojo;
34  import org.apache.maven.plugin.MojoExecutionException;
35  import org.apache.maven.settings.Settings;
36  import org.codehaus.plexus.archiver.ArchiverException;
37  import org.codehaus.plexus.archiver.jar.JarArchiver;
38  import org.codehaus.plexus.components.interactivity.InputHandler;
39  import org.codehaus.plexus.util.ReaderFactory;
40  import org.codehaus.plexus.util.WriterFactory;
41  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
42  
43  import java.io.File;
44  import java.io.FileNotFoundException;
45  import java.io.IOException;
46  import java.util.Collections;
47  import java.util.List;
48  
49  /**
50   * Packs artifacts already available in a local repository in a bundle for an
51   * upload requests. It requires that the artifact has a POM in the local
52   * repository. It will check for mandatory elements, asking interactively for
53   * missing values. Can be used to generate bundles for third parties artifacts
54   * that have been manually added to the local repository.
55   *
56   * @goal bundle-pack
57   * @requiresProject false
58   * @since 2.1
59   */
60  public class BundlePackMojo
61      extends AbstractMojo
62  {
63      public static final String POM = "pom.xml";
64  
65      /**
66       * Jar archiver.
67       * 
68       * @component role="org.codehaus.plexus.archiver.Archiver" roleHint="jar"
69       */
70      protected JarArchiver jarArchiver;
71  
72      /**
73       * Artifact resolver.
74       * 
75       * @component
76       */
77      protected ArtifactResolver artifactResolver;
78  
79      /**
80       * Artifact factory.
81       * 
82       * @component
83       */
84      protected ArtifactFactory artifactFactory;
85  
86      /**
87       * Local maven repository.
88       * 
89       * @parameter default-value="${localRepository}"
90       * @required
91       * @readonly
92       */
93      protected ArtifactRepository localRepository;
94  
95      /**
96       * @component
97       */
98      protected InputHandler inputHandler;
99  
100     /**
101      * Directory where the upload-bundle will be created.
102      *
103      * @parameter default-value="${basedir}"
104      * @readonly
105      */
106     protected String basedir;
107 
108     /**
109      * GroupId for the artifact to create an upload bundle for.
110      *
111      * @parameter expression="${groupId}"
112      */
113     protected String groupId;
114 
115     /**
116      * ArtifactId for the artifact to create an upload bundle for.
117      *
118      * @parameter expression="${artifactId}"
119      */
120     protected String artifactId;
121 
122     /**
123      * Version for the artifact to create an upload bundle for.
124      * 
125      * @parameter expression="${version}"
126      */
127     protected String version;
128     
129     /**
130      * Viewable URL for SCM connections, in cases where this isn't provided by the POM.
131      * @parameter expression="${scmUrl}"
132      */
133     protected String scmUrl;
134     
135     /**
136      * Read-only URL for SCM tool connections, in cases where this isn't provided by the POM.
137      * <br/>
138      * <b>NOTE:</b> This should be a standard maven-scm URL. See the 
139      * <a href="http://maven.apache.org/scm/scm-url-format.html">format guidelines</a> for more 
140      * information.
141      * 
142      * @parameter expression="${scmConnection}"
143      */
144     protected String scmConnection;
145     
146     /**
147      * @parameter default-value="${settings}"
148      * @readonly
149      */
150     protected Settings settings;
151 
152     /**
153      * Disable validations to make sure bundle supports project materialization.
154      * <br/>
155      * <b>WARNING: This means your project will be MUCH harder to use.</b>
156      * @parameter expression="${bundle.disableMaterialization}" default-value="false"
157      */
158     private boolean disableMaterialization;
159 
160     @SuppressWarnings( "unchecked" )
161     public void execute()
162         throws MojoExecutionException
163     {
164         readArtifactDataFromUser();
165 
166         Artifact artifact = artifactFactory.createProjectArtifact( groupId, artifactId, version );
167 
168         try
169         {
170             artifactResolver.resolve( artifact, Collections.EMPTY_LIST, localRepository );
171         }
172         catch ( ArtifactResolutionException e )
173         {
174             throw new MojoExecutionException( "Unable to resolve artifact " + artifact.getId(), e );
175         }
176         catch ( ArtifactNotFoundException e )
177         {
178             throw new MojoExecutionException( "Artifact " + artifact.getId() + " not found in local repository", e );
179         }
180 
181         File pom = artifact.getFile();
182 
183         File dir = pom.getParentFile();
184 
185         Model model = readPom( pom );
186 
187         boolean rewrite = false;
188         try
189         {
190 
191             if ( model.getPackaging() == null )
192             {
193                 model.setPackaging( "jar" );
194                 rewrite = true;
195             }
196             if ( model.getName() == null )
197             {
198                 getLog().info( "Project name is missing, please type the project name [" + artifactId + "]:" );
199                 model.setName( inputHandler.readLine() );
200                 if ( model.getName() == null )
201                 {
202                     model.setName( artifactId );
203                 }
204                 rewrite = true;
205             }
206             if ( model.getDescription() == null )
207             {
208                 getLog().info( "Project description is missing, please type the project description:" );
209                 model.setDescription( inputHandler.readLine() );
210                 rewrite = true;
211             }
212             if ( model.getUrl() == null )
213             {
214                 getLog().info( "Project URL is missing, please type the project URL:" );
215                 model.setUrl( inputHandler.readLine() );
216                 rewrite = true;
217             }
218 
219             List<License> licenses = model.getLicenses();
220             if ( licenses.isEmpty() )
221             {
222                 License license = new License();
223 
224                 getLog().info( "License name is missing, please type the license name:" );
225                 license.setName( inputHandler.readLine() );
226                 getLog().info( "License URL is missing, please type the license URL:" );
227                 license.setUrl( inputHandler.readLine() );
228                 licenses.add( license );
229                 rewrite = true;
230             }
231             
232             if ( disableMaterialization )
233             {
234                 getLog().warn( "Validations to confirm support for project materialization have been DISABLED." +
235                         "\n\nYour project may not provide the POM elements necessary to allow users to retrieve sources on-demand," +
236                         "\nor to easily checkout your project in an IDE. THIS CAN SERIOUSLY INCONVENIENCE YOUR USERS." +
237                         "\n\nContinue? [y/N]" );
238                 
239                 try
240                 {
241                     if ( 'y' != inputHandler.readLine().toLowerCase().charAt( 0 ) )
242                     {
243                         disableMaterialization = false;
244                     }
245                 }
246                 catch ( IOException e )
247                 {
248                     getLog().debug( "Error reading confirmation: " + e.getMessage(), e );
249                 }
250                 
251             }
252             
253             if ( !disableMaterialization )
254             {
255                 Scm scm = model.getScm();
256                 if ( scm == null )
257                 {
258                     scm = new Scm();
259                     model.setScm( scm );
260                 }
261                 
262                 if ( scm.getUrl() == null )
263                 {
264                     if ( scmUrl != null )
265                     {
266                         scm.setUrl( scmUrl );
267                     }
268                     else
269                     {
270                         getLog().info( "SCM view URL is missing, please type the URL for the viewable SCM interface:" );
271                         scm.setUrl( inputHandler.readLine() );
272                         rewrite = true;
273                     }
274                 }
275                 
276                 if ( scm.getConnection() == null )
277                 {
278                     if ( scmConnection != null )
279                     {
280                         scm.setConnection( scmConnection );
281                     }
282                     else
283                     {
284                         getLog().info( "SCM read-only connection URL is missing, please type the read-only SCM URL:" );
285                         scm.setConnection( inputHandler.readLine() );
286                         rewrite = true;
287                     }
288                 }
289             }
290         }
291         catch ( IOException e )
292         {
293             throw new MojoExecutionException( e.getMessage(), e );
294         }
295 
296         try
297         {
298             if ( rewrite )
299             {
300                 new MavenXpp3Writer().write( WriterFactory.newXmlWriter( pom ), model );
301             }
302 
303             String finalName = null;
304 
305             if ( model.getBuild() != null )
306             {
307                 finalName = model.getBuild().getFinalName();
308             }
309             if ( finalName == null )
310             {
311                 finalName = model.getArtifactId() + "-" + model.getVersion();
312             }
313             
314             boolean batchMode = settings == null ? false : !settings.isInteractiveMode();
315             List<File> files = BundleUtils.selectProjectFiles( dir, inputHandler, finalName, pom, getLog(), batchMode );
316 
317             File bundle = new File( basedir, finalName + "-bundle.jar" );
318 
319             jarArchiver.addFile( pom, POM );
320 
321             boolean artifactChecks = !"pom".equals( model.getPackaging() );
322             boolean sourcesFound = false;
323             boolean javadocsFound = false;
324             
325             for ( File f : files )
326             {
327                 if ( artifactChecks && f.getName().endsWith( finalName + "-sources.jar" ) )
328                 {
329                     sourcesFound = true;
330                 }
331                 else if ( artifactChecks && f.getName().equals( finalName + "-javadoc.jar" ) )
332                 {
333                     javadocsFound = true;
334                 }
335                 
336                 jarArchiver.addFile( f, f.getName() );
337             }
338             
339             if ( artifactChecks && !sourcesFound )
340             {
341                 getLog().warn( "Sources not included in upload bundle." );
342             }
343 
344             if ( artifactChecks && !javadocsFound )
345             {
346                 getLog().warn( "Javadoc not included in upload bundle." );
347             }
348 
349             jarArchiver.setDestFile( bundle );
350 
351             jarArchiver.createArchive();
352 
353         }
354         catch ( IOException e )
355         {
356             throw new MojoExecutionException( e.getMessage(), e );
357         }
358         catch ( ArchiverException e )
359         {
360             throw new MojoExecutionException( e.getMessage(), e );
361         }
362 
363     }
364 
365     /**
366      * Read groupId, artifactId and version from the user on the command line,
367      * if they were not provided as parameters.
368      *
369      * @throws MojoExecutionException If the values can't be read
370      */
371     private void readArtifactDataFromUser()
372         throws MojoExecutionException
373     {
374         try
375         {
376             if ( groupId == null )
377             {
378                 getLog().info( "groupId? " );
379 
380                 groupId = inputHandler.readLine();
381 
382             }
383 
384             if ( artifactId == null )
385             {
386                 getLog().info( "artifactId? " );
387                 artifactId = inputHandler.readLine();
388             }
389 
390             if ( version == null )
391             {
392                 getLog().info( "version? " );
393                 version = inputHandler.readLine();
394             }
395         }
396         catch ( IOException e )
397         {
398             throw new MojoExecutionException( e.getMessage(), e );
399         }
400     }
401 
402     /**
403      * Read the POM file.
404      *
405      * @param pom The file to read
406      * @return A Maven Model
407      * @throws MojoExecutionException if something goes wrong when reading the file
408      */
409     private Model readPom( File pom )
410         throws MojoExecutionException
411     {
412         Model model;
413         try
414         {
415             model = new MavenXpp3Reader().read( ReaderFactory.newXmlReader( pom ) );
416         }
417         catch ( XmlPullParserException e )
418         {
419             throw new MojoExecutionException( "Unable to parse POM at " + pom.getAbsolutePath() + ": " + e.getMessage(),
420                                               e );
421         }
422         catch ( FileNotFoundException e )
423         {
424             throw new MojoExecutionException( "Unable to read POM at " + pom.getAbsolutePath() + ": " + e.getMessage(),
425                                               e );
426         }
427         catch ( IOException e )
428         {
429             throw new MojoExecutionException( "Unable to read POM at " + pom.getAbsolutePath() + ": " + e.getMessage(),
430                                               e );
431         }
432         return model;
433     }
434 
435 }