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