View Javadoc

1   package org.apache.maven.plugin.install;
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.installer.ArtifactInstallationException;
24  import org.apache.maven.artifact.metadata.ArtifactMetadata;
25  import org.apache.maven.artifact.repository.DefaultArtifactRepository;
26  import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
27  import org.apache.maven.model.Model;
28  import org.apache.maven.model.Parent;
29  import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
30  import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
31  import org.apache.maven.plugin.MojoExecutionException;
32  import org.apache.maven.plugin.MojoFailureException;
33  import org.apache.maven.project.artifact.ProjectArtifactMetadata;
34  import org.apache.maven.project.validation.ModelValidationResult;
35  import org.apache.maven.project.validation.ModelValidator;
36  import org.codehaus.plexus.util.IOUtil;
37  import org.codehaus.plexus.util.ReaderFactory;
38  import org.codehaus.plexus.util.WriterFactory;
39  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
40  
41  import java.io.File;
42  import java.io.FileNotFoundException;
43  import java.io.IOException;
44  import java.io.Reader;
45  import java.io.Writer;
46  import java.net.MalformedURLException;
47  import java.util.Map;
48  
49  /**
50   * Installs a file in the local repository.
51   *
52   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
53   * @version $Id: InstallFileMojo.java 942550 2010-05-09 15:19:07Z krosenvold $
54   * @goal install-file
55   * @requiresProject false
56   * @aggregator
57   * @threadSafe
58   */
59  public class InstallFileMojo
60      extends AbstractInstallMojo
61  {
62  
63      /**
64       * GroupId of the artifact to be installed. Retrieved from POM file if one is specified.
65       *
66       * @parameter expression="${groupId}"
67       */
68      protected String groupId;
69  
70      /**
71       * ArtifactId of the artifact to be installed. Retrieved from POM file if one is specified.
72       *
73       * @parameter expression="${artifactId}"
74       */
75      protected String artifactId;
76  
77      /**
78       * Version of the artifact to be installed. Retrieved from POM file if one is specified.
79       *
80       * @parameter expression="${version}"
81       */
82      protected String version;
83  
84      /**
85       * Packaging type of the artifact to be installed. Retrieved from POM file if one is specified.
86       *
87       * @parameter expression="${packaging}"
88       */
89      protected String packaging;
90  
91      /**
92       * Classifier type of the artifact to be installed. For example, "sources" or "javadoc". Defaults to none which
93       * means this is the project's main artifact.
94       *
95       * @parameter expression="${classifier}"
96       * @since 2.2
97       */
98      protected String classifier;
99  
100     /**
101      * The file to be installed in the local repository.
102      *
103      * @parameter expression="${file}"
104      * @required
105      */
106     private File file;
107 
108     /**
109      * The bundled API docs for the artifact.
110      *
111      * @parameter expression="${javadoc}"
112      * @since 2.3
113      */
114     private File javadoc;
115 
116     /**
117      * The bundled sources for the artifact.
118      *
119      * @parameter expression="${sources}"
120      * @since 2.3
121      */
122     private File sources;
123 
124     /**
125      * Location of an existing POM file to be installed alongside the main artifact, given by the {@link #file}
126      * parameter.
127      *
128      * @parameter expression="${pomFile}"
129      * @since 2.1
130      */
131     private File pomFile;
132 
133     /**
134      * Generate a minimal POM for the artifact if none is supplied via the parameter {@link #pomFile}. Defaults to
135      * <code>true</code> if there is no existing POM in the local repository yet.
136      *
137      * @parameter expression="${generatePom}"
138      * @since 2.1
139      */
140     private Boolean generatePom;
141 
142     /**
143      * The type of remote repository layout to install to. Try <code>legacy</code> for a Maven 1.x-style repository
144      * layout.
145      *
146      * @parameter expression="${repositoryLayout}" default-value="default"
147      * @required
148      * @since 2.2
149      */
150     private String repositoryLayout;
151 
152     /**
153      * Map that contains the repository layouts.
154      *
155      * @component role="org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout"
156      */
157     private Map repositoryLayouts;
158 
159     /**
160      * The path for a specific local repository directory. If not specified the local repository path configured in the
161      * Maven settings will be used.
162      *
163      * @parameter expression="${localRepositoryPath}"
164      * @since 2.2
165      */
166     private File localRepositoryPath;
167 
168     /**
169      * The component used to validate the user-supplied artifact coordinates.
170      *
171      * @component
172      */
173     private ModelValidator modelValidator;
174 
175     /**
176      * @see org.apache.maven.plugin.Mojo#execute()
177      */
178     public void execute()
179         throws MojoExecutionException, MojoFailureException
180     {
181         // ----------------------------------------------------------------------
182         // Override the default localRepository variable
183         // ----------------------------------------------------------------------
184         if ( localRepositoryPath != null )
185         {
186             try
187             {
188                 ArtifactRepositoryLayout layout = (ArtifactRepositoryLayout) repositoryLayouts.get( repositoryLayout );
189                 getLog().debug( "Layout: " + layout.getClass() );
190 
191                 localRepository =
192                     new DefaultArtifactRepository( localRepository.getId(), localRepositoryPath.toURL().toString(),
193                                                    layout );
194             }
195             catch ( MalformedURLException e )
196             {
197                 throw new MojoExecutionException( "MalformedURLException: " + e.getMessage(), e );
198             }
199         }
200 
201         if ( pomFile != null )
202         {
203             processModel( readModel( pomFile ) );
204         }
205 
206         validateArtifactInformation();
207 
208         Artifact artifact =
209             artifactFactory.createArtifactWithClassifier( groupId, artifactId, version, packaging, classifier );
210 
211         if ( file.equals( getLocalRepoFile( artifact ) ) )
212         {
213             throw new MojoFailureException( "Cannot install artifact. "
214                 + "Artifact is already in the local repository.\n\nFile in question is: " + file + "\n" );
215         }
216 
217         File generatedPomFile = null;
218 
219         if ( !"pom".equals( packaging ) )
220         {
221             if ( pomFile != null )
222             {
223                 ArtifactMetadata pomMetadata = new ProjectArtifactMetadata( artifact, pomFile );
224                 artifact.addMetadata( pomMetadata );
225             }
226             else
227             {
228                 generatedPomFile = generatePomFile();
229                 ArtifactMetadata pomMetadata = new ProjectArtifactMetadata( artifact, generatedPomFile );
230                 if ( Boolean.TRUE.equals( generatePom )
231                     || ( generatePom == null && !getLocalRepoFile( pomMetadata ).exists() ) )
232                 {
233                     getLog().debug( "Installing generated POM" );
234                     artifact.addMetadata( pomMetadata );
235                 }
236                 else if ( generatePom == null )
237                 {
238                     getLog().debug( "Skipping installation of generated POM, already present in local repository" );
239                 }
240             }
241         }
242 
243         if ( updateReleaseInfo )
244         {
245             artifact.setRelease( true );
246         }
247 
248         // TODO: maybe not strictly correct, while we should enforce that packaging has a type handler of the same id,
249         // we don't
250         try
251         {
252             installer.install( file, artifact, localRepository );
253             installChecksums( artifact );
254         }
255         catch ( ArtifactInstallationException e )
256         {
257             throw new MojoExecutionException( "Error installing artifact '" + artifact.getDependencyConflictId()
258                 + "': " + e.getMessage(), e );
259         }
260         finally
261         {
262             if ( generatedPomFile != null )
263             {
264                 generatedPomFile.delete();
265             }
266         }
267 
268         if ( sources != null )
269         {
270             artifact = artifactFactory.createArtifactWithClassifier( groupId, artifactId, version, "jar", "sources" );
271             try
272             {
273                 installer.install( sources, artifact, localRepository );
274                 installChecksums( artifact );
275             }
276             catch ( ArtifactInstallationException e )
277             {
278                 throw new MojoExecutionException( "Error installing sources " + sources + ": " + e.getMessage(), e );
279             }
280         }
281 
282         if ( javadoc != null )
283         {
284             artifact = artifactFactory.createArtifactWithClassifier( groupId, artifactId, version, "jar", "javadoc" );
285             try
286             {
287                 installer.install( javadoc, artifact, localRepository );
288                 installChecksums( artifact );
289             }
290             catch ( ArtifactInstallationException e )
291             {
292                 throw new MojoExecutionException( "Error installing API docs " + javadoc + ": " + e.getMessage(), e );
293             }
294         }
295     }
296 
297     /**
298      * Parses a POM.
299      *
300      * @param pomFile The path of the POM file to parse, must not be <code>null</code>.
301      * @return The model from the POM file, never <code>null</code>.
302      * @throws MojoExecutionException If the POM could not be parsed.
303      */
304     private Model readModel( File pomFile )
305         throws MojoExecutionException
306     {
307         Reader reader = null;
308         try
309         {
310             reader = ReaderFactory.newXmlReader( pomFile );
311             return new MavenXpp3Reader().read( reader );
312         }
313         catch ( FileNotFoundException e )
314         {
315             throw new MojoExecutionException( "File not found " + pomFile, e );
316         }
317         catch ( IOException e )
318         {
319             throw new MojoExecutionException( "Error reading POM " + pomFile, e );
320         }
321         catch ( XmlPullParserException e )
322         {
323             throw new MojoExecutionException( "Error parsing POM " + pomFile, e );
324         }
325         finally
326         {
327             IOUtil.close( reader );
328         }
329     }
330 
331     /**
332      * Populates missing mojo parameters from the specified POM.
333      *
334      * @param model The POM to extract missing artifact coordinates from, must not be <code>null</code>.
335      */
336     private void processModel( Model model )
337     {
338         Parent parent = model.getParent();
339 
340         if ( this.groupId == null )
341         {
342             this.groupId = model.getGroupId();
343             if ( this.groupId == null && parent != null )
344             {
345                 this.groupId = parent.getGroupId();
346             }
347         }
348         if ( this.artifactId == null )
349         {
350             this.artifactId = model.getArtifactId();
351         }
352         if ( this.version == null )
353         {
354             this.version = model.getVersion();
355             if ( this.version == null && parent != null )
356             {
357                 this.version = parent.getVersion();
358             }
359         }
360         if ( this.packaging == null )
361         {
362             this.packaging = model.getPackaging();
363         }
364     }
365 
366     /**
367      * Validates the user-supplied artifact information.
368      *
369      * @throws MojoExecutionException If any artifact coordinate is invalid.
370      */
371     private void validateArtifactInformation()
372         throws MojoExecutionException
373     {
374         Model model = generateModel();
375 
376         ModelValidationResult result = modelValidator.validate( model );
377 
378         if ( result.getMessageCount() > 0 )
379         {
380             throw new MojoExecutionException( "The artifact information is incomplete or not valid:\n"
381                 + result.render( "  " ) );
382         }
383     }
384 
385     /**
386      * Generates a minimal model from the user-supplied artifact information.
387      *
388      * @return The generated model, never <code>null</code>.
389      */
390     private Model generateModel()
391     {
392         Model model = new Model();
393 
394         model.setModelVersion( "4.0.0" );
395 
396         model.setGroupId( groupId );
397         model.setArtifactId( artifactId );
398         model.setVersion( version );
399         model.setPackaging( packaging );
400 
401         model.setDescription( "POM was created from install:install-file" );
402 
403         return model;
404     }
405 
406     /**
407      * Generates a (temporary) POM file from the plugin configuration. It's the responsibility of the caller to delete
408      * the generated file when no longer needed.
409      *
410      * @return The path to the generated POM file, never <code>null</code>.
411      * @throws MojoExecutionException If the POM file could not be generated.
412      */
413     private File generatePomFile()
414         throws MojoExecutionException
415     {
416         Model model = generateModel();
417 
418         Writer writer = null;
419         try
420         {
421             File pomFile = File.createTempFile( "mvninstall", ".pom" );
422 
423             writer = WriterFactory.newXmlWriter( pomFile );
424             new MavenXpp3Writer().write( writer, model );
425 
426             return pomFile;
427         }
428         catch ( IOException e )
429         {
430             throw new MojoExecutionException( "Error writing temporary POM file: " + e.getMessage(), e );
431         }
432         finally
433         {
434             IOUtil.close( writer );
435         }
436     }
437 
438     /**
439      * @return the localRepositoryPath
440      */
441     public File getLocalRepositoryPath()
442     {
443         return this.localRepositoryPath;
444     }
445 
446     /**
447      * @param theLocalRepositoryPath the localRepositoryPath to set
448      */
449     public void setLocalRepositoryPath( File theLocalRepositoryPath )
450     {
451         this.localRepositoryPath = theLocalRepositoryPath;
452     }
453 
454 }