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