package org.apache.maven.plugins.install; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.io.Writer; import java.util.Enumeration; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.regex.Pattern; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.handler.DefaultArtifactHandler; import org.apache.maven.model.Model; import org.apache.maven.model.Parent; import org.apache.maven.model.building.ModelBuildingException; import org.apache.maven.model.building.ModelSource; import org.apache.maven.model.building.StringModelSource; import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import org.apache.maven.model.io.xpp3.MavenXpp3Writer; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.DefaultProjectBuildingRequest; import org.apache.maven.project.MavenProject; import org.apache.maven.project.MavenProjectHelper; import org.apache.maven.project.ProjectBuilder; import org.apache.maven.project.ProjectBuildingException; import org.apache.maven.project.ProjectBuildingRequest; import org.apache.maven.project.artifact.ProjectArtifactMetadata; import org.apache.maven.shared.project.install.ProjectInstaller; import org.apache.maven.shared.project.install.ProjectInstallerRequest; import org.apache.maven.shared.utils.Os; import org.apache.maven.shared.utils.ReaderFactory; import org.apache.maven.shared.utils.WriterFactory; import org.apache.maven.shared.utils.io.IOUtil; import org.codehaus.plexus.util.FileUtils; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; /** * Installs a file in the local repository. * * @author <a href="mailto:brett@apache.org">Brett Porter</a> * @version $Id$ */ @Mojo( name = "install-file", requiresProject = false, aggregator = true, threadSafe = true ) public class InstallFileMojo extends AbstractInstallMojo { /** * GroupId of the artifact to be installed. Retrieved from POM file if one is specified or extracted from * {@code pom.xml} in jar if available. */ @Parameter( property = "groupId" ) private String groupId; /** * ArtifactId of the artifact to be installed. Retrieved from POM file if one is specified or extracted from * {@code pom.xml} in jar if available. */ @Parameter( property = "artifactId" ) private String artifactId; /** * Version of the artifact to be installed. Retrieved from POM file if one is specified or extracted from * {@code pom.xml} in jar if available. */ @Parameter( property = "version" ) private String version; /** * Packaging type of the artifact to be installed. Retrieved from POM file if one is specified or extracted from * {@code pom.xml} in jar if available. */ @Parameter( property = "packaging" ) private String packaging; /** * Classifier type of the artifact to be installed. For example, "sources" or "javadoc". Defaults to none which * means this is the project's main artifact. * * @since 2.2 */ @Parameter( property = "classifier" ) private String classifier; /** * The file to be installed in the local repository. */ @Parameter( property = "file", required = true ) private File file; /** * The bundled API docs for the artifact. * * @since 2.3 */ @Parameter( property = "javadoc" ) private File javadoc; /** * The bundled sources for the artifact. * * @since 2.3 */ @Parameter( property = "sources" ) private File sources; /** * Location of an existing POM file to be installed alongside the main artifact, given by the {@link #file} * parameter. * * @since 2.1 */ @Parameter( property = "pomFile" ) private File pomFile; /** * Generate a minimal POM for the artifact if none is supplied via the parameter {@link #pomFile}. Defaults to * <code>true</code> if there is no existing POM in the local repository yet. * * @since 2.1 */ @Parameter( property = "generatePom" ) private Boolean generatePom; /** * The path for a specific local repository directory. If not specified the local repository path configured in the * Maven settings will be used. * * @since 2.2 */ @Parameter( property = "localRepositoryPath" ) private File localRepositoryPath; /** * Used for attaching the artifacts to install to the project. */ @Component private MavenProjectHelper projectHelper; /** * Used for creating the project to which the artifacts to install will be attached. */ @Component private ProjectBuilder projectBuilder; /** * Used to install the project created. */ @Component private ProjectInstaller installer; /** * @see org.apache.maven.plugin.Mojo#execute() */ public void execute() throws MojoExecutionException, MojoFailureException { if ( !file.exists() ) { String message = "The specified file '" + file.getPath() + "' not exists"; getLog().error( message ); throw new MojoFailureException( message ); } ProjectBuildingRequest buildingRequest = session.getProjectBuildingRequest(); // ---------------------------------------------------------------------- // Override the default localRepository variable // ---------------------------------------------------------------------- if ( localRepositoryPath != null ) { buildingRequest = repositoryManager.setLocalRepositoryBasedir( buildingRequest, localRepositoryPath ); getLog().debug( "localRepoPath: " + repositoryManager.getLocalRepositoryBasedir( buildingRequest ) ); } File temporaryPom = null; if ( pomFile != null ) { processModel( readModel( pomFile ) ); } else { temporaryPom = readingPomFromJarFile(); pomFile = temporaryPom; } MavenProject project = createMavenProject(); // We need to set a new ArtifactHandler otherwise // the extension will be set to the packaging type // which is sometimes wrong. DefaultArtifactHandler ah = new DefaultArtifactHandler( packaging ); ah.setExtension( FileUtils.getExtension( file.getName() ) ); project.getArtifact().setArtifactHandler( ah ); Artifact artifact = project.getArtifact(); if ( file.equals( getLocalRepoFile( buildingRequest, artifact ) ) ) { throw new MojoFailureException( "Cannot install artifact. " + "Artifact is already in the local repository.\n\nFile in question is: " + file + "\n" ); } if ( classifier == null ) { artifact.setFile( file ); if ( "pom".equals( packaging ) ) { project.setFile( file ); } } else { projectHelper.attachArtifact( project, packaging, classifier, file ); } if ( !"pom".equals( packaging ) ) { if ( pomFile != null ) { if ( classifier == null ) { artifact.addMetadata( new ProjectArtifactMetadata( artifact, pomFile ) ); } else { project.setFile( pomFile ); } } else { temporaryPom = generatePomFile(); ProjectArtifactMetadata pomMetadata = new ProjectArtifactMetadata( artifact, temporaryPom ); if ( Boolean.TRUE.equals( generatePom ) || ( generatePom == null && !getLocalRepoFile( buildingRequest, pomMetadata ).exists() ) ) { getLog().debug( "Installing generated POM" ); if ( classifier == null ) { artifact.addMetadata( pomMetadata ); } else { project.setFile( temporaryPom ); } } else if ( generatePom == null ) { getLog().debug( "Skipping installation of generated POM, already present in local repository" ); } } } if ( sources != null ) { projectHelper.attachArtifact( project, "jar", "sources", sources ); } if ( javadoc != null ) { projectHelper.attachArtifact( project, "jar", "javadoc", javadoc ); } try { // CHECKSTYLE_OFF: LineLength ProjectInstallerRequest projectInstallerRequest = new ProjectInstallerRequest().setProject( project ).setCreateChecksum( createChecksum ).setUpdateReleaseInfo( updateReleaseInfo ); // CHECKSTYLE_ON: LineLength installer.install( buildingRequest, projectInstallerRequest ); } catch ( Exception e ) { throw new MojoExecutionException( e.getMessage(), e ); } finally { if ( temporaryPom != null ) { // noinspection ResultOfMethodCallIgnored temporaryPom.delete(); } } } /** * Creates a Maven project in-memory from the user-supplied groupId, artifactId and version. When a classifier is * supplied, the packaging must be POM because the project with only have attachments. This project serves as basis * to attach the artifacts to install to. * * @return The created Maven project, never <code>null</code>. * @throws MojoExecutionException When the model of the project could not be built. * @throws MojoFailureException When building the project failed. */ private MavenProject createMavenProject() throws MojoExecutionException, MojoFailureException { if ( groupId == null || artifactId == null || version == null || packaging == null ) { throw new MojoExecutionException( "The artifact information is incomplete: 'groupId', 'artifactId', " + "'version' and 'packaging' are required." ); } ModelSource modelSource = new StringModelSource( "<project><modelVersion>4.0.0</modelVersion><groupId>" + groupId + "</groupId><artifactId>" + artifactId + "</artifactId><version>" + version + "</version><packaging>" + ( classifier == null ? packaging : "pom" ) + "</packaging></project>" ); ProjectBuildingRequest pbr = new DefaultProjectBuildingRequest( session.getProjectBuildingRequest() ); pbr.setProcessPlugins( false ); try { return projectBuilder.build( modelSource, pbr ).getProject(); } catch ( ProjectBuildingException e ) { if ( e.getCause() instanceof ModelBuildingException ) { throw new MojoExecutionException( "The artifact information is not valid:" + Os.LINE_SEP + e.getCause().getMessage() ); } throw new MojoFailureException( "Unable to create the project.", e ); } } private File readingPomFromJarFile() throws MojoExecutionException { File pomFile = null; JarFile jarFile = null; try { Pattern pomEntry = Pattern.compile( "META-INF/maven/.*/pom\\.xml" ); jarFile = new JarFile( file ); Enumeration<JarEntry> jarEntries = jarFile.entries(); while ( jarEntries.hasMoreElements() ) { JarEntry entry = jarEntries.nextElement(); if ( pomEntry.matcher( entry.getName() ).matches() ) { getLog().debug( "Using " + entry.getName() + " as pomFile" ); InputStream pomInputStream = null; OutputStream pomOutputStream = null; try { pomInputStream = jarFile.getInputStream( entry ); String base = file.getName(); if ( base.indexOf( '.' ) > 0 ) { base = base.substring( 0, base.lastIndexOf( '.' ) ); } pomFile = File.createTempFile( base, ".pom" ); pomOutputStream = new FileOutputStream( pomFile ); IOUtil.copy( pomInputStream, pomOutputStream ); pomOutputStream.close(); pomOutputStream = null; pomInputStream.close(); pomInputStream = null; processModel( readModel( pomFile ) ); break; } finally { IOUtil.close( pomInputStream ); IOUtil.close( pomOutputStream ); } } } if ( pomFile == null ) { getLog().info( "pom.xml not found in " + file.getName() ); } } catch ( IOException e ) { // ignore, artifact not packaged by Maven } finally { if ( jarFile != null ) { try { jarFile.close(); } catch ( IOException e ) { // we did our best } } } return pomFile; } /** * Parses a POM. * * @param pomFile The path of the POM file to parse, must not be <code>null</code>. * @return The model from the POM file, never <code>null</code>. * @throws MojoExecutionException If the POM could not be parsed. */ private Model readModel( File pomFile ) throws MojoExecutionException { Reader reader = null; try { reader = ReaderFactory.newXmlReader( pomFile ); final Model model = new MavenXpp3Reader().read( reader ); reader.close(); reader = null; return model; } catch ( FileNotFoundException e ) { throw new MojoExecutionException( "File not found " + pomFile, e ); } catch ( IOException e ) { throw new MojoExecutionException( "Error reading POM " + pomFile, e ); } catch ( XmlPullParserException e ) { throw new MojoExecutionException( "Error parsing POM " + pomFile, e ); } finally { IOUtil.close( reader ); } } /** * Populates missing mojo parameters from the specified POM. * * @param model The POM to extract missing artifact coordinates from, must not be <code>null</code>. */ private void processModel( Model model ) { Parent parent = model.getParent(); if ( this.groupId == null ) { this.groupId = model.getGroupId(); if ( this.groupId == null && parent != null ) { this.groupId = parent.getGroupId(); } } if ( this.artifactId == null ) { this.artifactId = model.getArtifactId(); } if ( this.version == null ) { this.version = model.getVersion(); if ( this.version == null && parent != null ) { this.version = parent.getVersion(); } } if ( this.packaging == null ) { this.packaging = model.getPackaging(); } } /** * Generates a minimal model from the user-supplied artifact information. * * @return The generated model, never <code>null</code>. */ private Model generateModel() { Model model = new Model(); model.setModelVersion( "4.0.0" ); model.setGroupId( groupId ); model.setArtifactId( artifactId ); model.setVersion( version ); model.setPackaging( packaging ); model.setDescription( "POM was created from install:install-file" ); return model; } /** * Generates a (temporary) POM file from the plugin configuration. It's the responsibility of the caller to delete * the generated file when no longer needed. * * @return The path to the generated POM file, never <code>null</code>. * @throws MojoExecutionException If the POM file could not be generated. */ private File generatePomFile() throws MojoExecutionException { Model model = generateModel(); Writer writer = null; try { File pomFile = File.createTempFile( "mvninstall", ".pom" ); writer = WriterFactory.newXmlWriter( pomFile ); new MavenXpp3Writer().write( writer, model ); writer.close(); writer = null; return pomFile; } catch ( IOException e ) { throw new MojoExecutionException( "Error writing temporary POM file: " + e.getMessage(), e ); } finally { IOUtil.close( writer ); } } }