blob: d2d1bf1726eed3595344803a64117857cb7e0200 [file] [log] [blame]
package org.apache.maven.shared.test.plugin;
/*
* 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.IOException;
import java.io.Reader;
import java.net.MalformedURLException;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.installer.ArtifactInstallationException;
import org.apache.maven.artifact.installer.ArtifactInstaller;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
import org.apache.maven.execution.DefaultMavenExecutionRequest;
import org.apache.maven.execution.DefaultMavenExecutionResult;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Model;
import org.apache.maven.model.Parent;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.plugin.LegacySupport;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.artifact.ProjectArtifactMetadata;
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
import org.apache.maven.settings.MavenSettingsBuilder;
import org.apache.maven.settings.Settings;
import org.codehaus.plexus.PlexusConstants;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.context.Context;
import org.codehaus.plexus.context.ContextException;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
/**
* Tools to access and manage Maven repositories for test builds, including construction of a local
* repository directory structure.
*
* <p>
* <b>WARNING:</b> Currently, the <code>createLocalRepositoryFromPlugin</code> method will not
* resolve parent POMs that exist <b>only</b> in your normal local repository, and are not reachable
* using the relativePath element. This may result in failed test builds, as one or more of the
* plugin's ancestor POMs cannot be resolved.
* </p>
*
* @author jdcasey
* @version $Id$
*/
@Deprecated
@Component( role = RepositoryTool.class )
public class RepositoryTool
implements Contextualizable
{
/** Plexus role */
public static final String ROLE = RepositoryTool.class.getName();
@Requirement
private ArtifactRepositoryFactory repositoryFactory;
@Requirement
private MavenSettingsBuilder settingsBuilder;
@Requirement
private ArtifactFactory artifactFactory;
@Requirement
private ArtifactInstaller artifactInstaller;
@Requirement
private LegacySupport legacySupport;
// contextualized.
private PlexusContainer container;
/**
* Lookup and return the location of the normal Maven local repository.
*
* @return the location of the normal Maven local repository.
* @throws TestToolsException if any
*/
public File findLocalRepositoryDirectory()
throws TestToolsException
{
String localRepo = System.getProperty( "maven.local.repo" );
if ( StringUtils.isNotEmpty( localRepo ) )
{
return new File( localRepo );
}
Settings settings;
try
{
DefaultMavenExecutionRequest request = new DefaultMavenExecutionRequest();
request.setUserSettingsFile( new File( System.getProperty( "user.home" ), ".m2/settings.xml" ) );
request.setGlobalSettingsFile( new File( System.getProperty( "maven.home" ), "conf/settings.xml" ) );
settings = settingsBuilder.buildSettings( request );
}
catch ( IOException e )
{
throw new TestToolsException( "Error building Maven settings.", e );
}
catch ( XmlPullParserException e )
{
throw new TestToolsException( "Error building Maven settings.", e );
}
if ( settings == null || settings.getLocalRepository() == null
|| settings.getLocalRepository().trim().length() < 1 )
{
return new File( System.getProperty( "user.home" ), ".m2/repository" );
}
return new File( settings.getLocalRepository() );
}
/**
* Construct an ArtifactRepository instance that refers to the normal Maven local repository.
*
* @return an ArtifactRepository instance
* @throws TestToolsException if any
*/
public ArtifactRepository createLocalArtifactRepositoryInstance()
throws TestToolsException
{
File localRepoDir = findLocalRepositoryDirectory();
return createLocalArtifactRepositoryInstance( localRepoDir );
}
/**
* Construct an ArtifactRepository instance that refers to the test-time Maven local repository.
*
* @param localRepositoryDirectory The location of the local repository to be used for test builds.
* @return an ArtifactRepository instance
* @throws TestToolsException if any
*/
public ArtifactRepository createLocalArtifactRepositoryInstance( File localRepositoryDirectory )
throws TestToolsException
{
ArtifactRepositoryLayout defaultLayout;
try
{
defaultLayout = (ArtifactRepositoryLayout) container.lookup( ArtifactRepositoryLayout.ROLE, "default" );
}
catch ( ComponentLookupException e )
{
throw new TestToolsException( "Error retrieving default repository layout.", e );
}
try
{
return repositoryFactory.createArtifactRepository( "local", localRepositoryDirectory.toURL()
.toExternalForm(), defaultLayout, null, null );
}
catch ( MalformedURLException e )
{
throw new TestToolsException( "Error converting local repo directory to a URL.", e );
}
}
/**
* Install a test version of a plugin - along with its POM, and as many ancestor POMs as can be
* reached using the &lt;relativePath/&gt; element - to a clean local repository directory for
* use in test builds.
*
* <p>
* <b>WARNING:</b> Currently, this method will not resolve parent POMs that exist <b>only</b> in
* your normal local repository, and are not reachable using the relativePath element. This may
* result in failed test builds, as one or more of the plugin's ancestor POMs cannot be resolved.
* </p>
*
* @param project
* @param realPomFile
* @param targetLocalRepoBasedir
* @throws TestToolsException if any
*/
public void createLocalRepositoryFromComponentProject( MavenProject project, File realPomFile,
File targetLocalRepoBasedir )
throws TestToolsException
{
Artifact artifact = project.getArtifact();
if ( "pom".equals( project.getPackaging() ) )
{
artifact.setFile( project.getFile() );
}
ArtifactRepository localRepository = createLocalArtifactRepositoryInstance( targetLocalRepoBasedir );
String localPath = localRepository.pathOf( artifact );
File destination = new File( localRepository.getBasedir(), localPath );
if ( !destination.getParentFile().exists() )
{
destination.getParentFile().mkdirs();
}
legacySupport.setSession( new MavenSession( container, MavenRepositorySystemUtils.newSession(),
new DefaultMavenExecutionRequest(),
new DefaultMavenExecutionResult() ) );
try
{
artifactInstaller.install( artifact.getFile(), artifact, localRepository );
}
catch ( ArtifactInstallationException e )
{
throw new TestToolsException( "Error installing plugin artifact to target local repository: "
+ targetLocalRepoBasedir, e );
}
finally
{
legacySupport.setSession( null );
}
installLocallyReachableAncestorPoms( realPomFile, localRepository );
}
/**
* Traverse &lt;relativePath/&gt; links for successive POMs in the plugin's ancestry, installing
* each one into the test-time local repository.
*
* @param realPomFile The real plugin POM; a starting point, but the POM is already installed,
* so we won't actually install this file, only use it to locate parents.
* @param localRepo The test-time local repository instance
* @throws TestToolsException if any
*/
private void installLocallyReachableAncestorPoms( File realPomFile, ArtifactRepository localRepo )
throws TestToolsException
{
MavenXpp3Reader pomReader = new MavenXpp3Reader();
File pom = realPomFile;
boolean firstPass = true;
while ( pom != null )
{
if ( !pom.exists() )
{
pom = null;
break;
}
String pomGroupId = null;
String pomArtifactId = null;
String pomVersion = null;
Reader reader = null;
File currentPom = pom;
try
{
reader = ReaderFactory.newXmlReader( pom );
Model model = pomReader.read( reader );
pomGroupId = model.getGroupId();
pomArtifactId = model.getArtifactId();
pomVersion = model.getVersion();
Parent parent = model.getParent();
if ( parent != null )
{
pom = new File( pom.getParentFile(), parent.getRelativePath() );
if ( pomGroupId == null )
{
pomGroupId = parent.getGroupId();
}
if ( pomVersion == null )
{
pomVersion = parent.getVersion();
}
}
else
{
pom = null;
}
}
catch ( IOException e )
{
throw new TestToolsException( "Error reading ancestor POM: " + currentPom, e );
}
catch ( XmlPullParserException e )
{
throw new TestToolsException( "Error reading ancestor POM: " + currentPom, e );
}
finally
{
IOUtil.close( reader );
}
if ( !firstPass )
{
Artifact pomArtifact = artifactFactory.createProjectArtifact( pomGroupId, pomArtifactId, pomVersion );
pomArtifact.addMetadata( new ProjectArtifactMetadata( pomArtifact, currentPom ) );
try
{
artifactInstaller.install( currentPom, pomArtifact, localRepo );
}
catch ( ArtifactInstallationException e )
{
throw new TestToolsException( "Error installing ancestor POM: " + currentPom
+ " to target local repository: " + localRepo.getBasedir(), e );
}
}
else
{
firstPass = false;
}
}
}
/**
* Retrieve the PlexusContainer instance used to instantiate this component. The container is
* used to retrieve the default ArtifactRepositoryLayout component, for use in constructing
* instances of ArtifactRepository that can be used to access local repositories.
*
* @see org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable#contextualize(org.codehaus.plexus.context.Context)
*/
public void contextualize( Context context )
throws ContextException
{
this.container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
}
}