blob: d32a7390dce75e47c303c41cd10b37f29a5d0d6d [file] [log] [blame]
package org.apache.maven.artifact.ant;
/*
* 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 org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.manager.WagonManager;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
import org.apache.maven.artifact.repository.DefaultArtifactRepository;
import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
import org.apache.maven.profiles.DefaultProfileManager;
import org.apache.maven.profiles.ProfileManager;
import org.apache.maven.profiles.activation.ProfileActivationException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectBuilder;
import org.apache.maven.project.ProjectBuildingException;
import org.apache.maven.settings.Mirror;
import org.apache.maven.settings.RuntimeInfo;
import org.apache.maven.settings.Server;
import org.apache.maven.settings.Settings;
import org.apache.maven.settings.SettingsUtils;
import org.apache.maven.settings.TrackableBase;
import org.apache.maven.settings.io.xpp3.SettingsXpp3Reader;
import org.apache.maven.usability.diagnostics.ErrorDiagnostics;
import org.apache.maven.wagon.Wagon;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.taskdefs.Execute;
import org.codehaus.classworlds.ClassWorld;
import org.codehaus.classworlds.DuplicateRealmException;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.PlexusContainerException;
import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.embed.Embedder;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.interpolation.EnvarBasedValueSource;
import org.codehaus.plexus.util.interpolation.RegexBasedInterpolator;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Base class for artifact tasks.
*
* @author <a href="mailto:brett@apache.org">Brett Porter</a>
* @version $Id$
*/
public abstract class AbstractArtifactTask
extends Task
{
private File userSettingsFile;
private File globalSettingsFile;
private Settings settings;
private ProfileManager profileManager;
private PlexusContainer container;
private Pom pom;
private String pomRefId;
private LocalRepository localRepository;
protected ArtifactRepository createLocalArtifactRepository()
{
if ( localRepository == null )
{
localRepository = getDefaultLocalRepository();
}
ArtifactRepositoryLayout repositoryLayout =
(ArtifactRepositoryLayout) lookup( ArtifactRepositoryLayout.ROLE, localRepository.getLayout() );
return new DefaultArtifactRepository( "local", "file://" + localRepository.getPath(), repositoryLayout );
}
/**
* Create a core-Maven ArtifactRepositoryFactory from a Maven Ant Tasks's RemoteRepository definition,
* eventually configured with authentication and proxy information.
* @param repository the remote repository as defined in Ant
* @return the corresponding ArtifactRepositoryFactory
*/
protected ArtifactRepositoryFactory getArtifactRepositoryFactory( RemoteRepository repository )
{
WagonManager manager = (WagonManager) lookup( WagonManager.ROLE );
Authentication authentication = repository.getAuthentication();
if ( authentication != null )
{
manager.addAuthenticationInfo( repository.getId(), authentication.getUserName(),
authentication.getPassword(), authentication.getPrivateKey(),
authentication.getPassphrase() );
}
Proxy proxy = repository.getProxy();
if ( proxy != null )
{
manager.addProxy( proxy.getType(), proxy.getHost(), proxy.getPort(), proxy.getUserName(),
proxy.getPassword(), proxy.getNonProxyHosts() );
}
return (ArtifactRepositoryFactory) lookup( ArtifactRepositoryFactory.ROLE );
}
protected void releaseArtifactRepositoryFactory( ArtifactRepositoryFactory repositoryFactory )
{
try
{
getContainer().release( repositoryFactory );
}
catch ( ComponentLifecycleException e )
{
// TODO: Warn the user, or not?
}
}
/**
* Create a core-Maven ArtifactRepository from a Maven Ant Tasks's RemoteRepository definition.
* @param repository the remote repository as defined in Ant
* @return the corresponding ArtifactRepository
*/
protected ArtifactRepository createRemoteArtifactRepository( RemoteRepository repository )
{
ArtifactRepositoryLayout repositoryLayout =
(ArtifactRepositoryLayout) lookup( ArtifactRepositoryLayout.ROLE, repository.getLayout() );
ArtifactRepositoryFactory repositoryFactory = null;
ArtifactRepository artifactRepository;
try
{
repositoryFactory = getArtifactRepositoryFactory( repository );
ArtifactRepositoryPolicy snapshots = buildArtifactRepositoryPolicy( repository.getSnapshots() );
ArtifactRepositoryPolicy releases = buildArtifactRepositoryPolicy( repository.getReleases() );
artifactRepository = repositoryFactory.createArtifactRepository( repository.getId(), repository.getUrl(),
repositoryLayout, snapshots, releases );
}
finally
{
releaseArtifactRepositoryFactory( repositoryFactory );
}
return artifactRepository;
}
private static ArtifactRepositoryPolicy buildArtifactRepositoryPolicy( RepositoryPolicy policy )
{
boolean enabled = true;
String updatePolicy = null;
String checksumPolicy = null;
if ( policy != null )
{
enabled = policy.isEnabled();
if ( policy.getUpdatePolicy() != null )
{
updatePolicy = policy.getUpdatePolicy();
}
if ( policy.getChecksumPolicy() != null )
{
checksumPolicy = policy.getChecksumPolicy();
}
}
return new ArtifactRepositoryPolicy( enabled, updatePolicy, checksumPolicy );
}
protected LocalRepository getDefaultLocalRepository()
{
Settings settings = getSettings();
LocalRepository localRepository = new LocalRepository();
localRepository.setId( "local" );
localRepository.setPath( new File( settings.getLocalRepository() ) );
return localRepository;
}
protected synchronized Settings getSettings()
{
if ( settings == null )
{
initSettings();
}
return settings;
}
private File newFile( String parent, String subdir, String filename )
{
return new File( new File( parent, subdir ), filename );
}
private void initSettings()
{
if ( userSettingsFile == null )
{
File settingsFile = newFile( System.getProperty( "user.home" ), ".ant", "settings.xml" );
if ( settingsFile.exists() )
{
userSettingsFile = settingsFile;
} else {
settingsFile = newFile( System.getProperty( "user.home" ), ".m2", "settings.xml" );
if ( settingsFile.exists() )
{
userSettingsFile = settingsFile;
}
}
}
if ( globalSettingsFile == null )
{
File settingsFile = newFile( System.getProperty( "ant.home" ), "etc", "settings.xml" );
if ( settingsFile.exists() )
{
globalSettingsFile = settingsFile;
} else {
// look in ${M2_HOME}/conf
List env = Execute.getProcEnvironment();
for ( Iterator iter = env.iterator(); iter.hasNext(); )
{
String var = (String) iter.next();
if ( var.startsWith( "M2_HOME=" ) )
{
String m2_home = var.substring( "M2_HOME=".length() );
globalSettingsFile = newFile( m2_home, "conf", "settings.xml" );
break;
}
}
}
}
Settings userSettings = loadSettings( userSettingsFile );
Settings globalSettings = loadSettings( globalSettingsFile );
SettingsUtils.merge( userSettings, globalSettings, TrackableBase.GLOBAL_LEVEL );
settings = userSettings;
if ( StringUtils.isEmpty( settings.getLocalRepository() ) )
{
String location = newFile( System.getProperty( "user.home" ), ".m2", "repository" ).getAbsolutePath();
settings.setLocalRepository( location );
}
profileManager = new DefaultProfileManager( getContainer(), getSettings(), System.getProperties() );
WagonManager wagonManager = (WagonManager) lookup( WagonManager.ROLE );
wagonManager.setDownloadMonitor( new AntDownloadMonitor() );
if ( settings.isOffline() )
{
log( "You are working in offline mode.", Project.MSG_INFO );
wagonManager.setOnline( false );
}
else
{
wagonManager.setOnline( true );
}
}
private Settings loadSettings( File settingsFile )
{
Settings settings = null;
try
{
if ( settingsFile != null )
{
log( "Loading Maven settings file: " + settingsFile.getPath(), Project.MSG_VERBOSE );
settings = readSettings( settingsFile );
}
}
catch ( IOException e )
{
log( "Error reading settings file '" + settingsFile + "' - ignoring. Error was: " + e.getMessage(),
Project.MSG_WARN );
}
catch ( XmlPullParserException e )
{
log( "Error parsing settings file '" + settingsFile + "' - ignoring. Error was: " + e.getMessage(),
Project.MSG_WARN );
}
if ( settings == null )
{
settings = new Settings();
RuntimeInfo rtInfo = new RuntimeInfo(settings);
settings.setRuntimeInfo(rtInfo);
}
return settings;
}
public void setSettingsFile( File settingsFile )
{
if ( !settingsFile.exists() )
throw new BuildException( "settingsFile does not exist: " + settingsFile.getAbsolutePath() );
userSettingsFile = settingsFile;
settings = null;
}
/**
* @see org.apache.maven.settings.DefaultMavenSettingsBuilder#readSettings
*/
private Settings readSettings( File settingsFile )
throws IOException, XmlPullParserException
{
Settings settings = null;
Reader reader = null;
try
{
reader = ReaderFactory.newXmlReader( settingsFile );
StringWriter sWriter = new StringWriter();
IOUtil.copy( reader, sWriter );
String rawInput = sWriter.toString();
try
{
RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
interpolator.addValueSource( new EnvarBasedValueSource() );
rawInput = interpolator.interpolate( rawInput, "settings" );
}
catch ( Exception e )
{
log( "Failed to initialize environment variable resolver. Skipping environment substitution in settings." );
}
StringReader sReader = new StringReader( rawInput );
SettingsXpp3Reader modelReader = new SettingsXpp3Reader();
settings = modelReader.read( sReader );
RuntimeInfo rtInfo = new RuntimeInfo( settings );
rtInfo.setFile( settingsFile );
settings.setRuntimeInfo( rtInfo );
}
finally
{
IOUtil.close( reader );
}
return settings;
}
protected RemoteRepository createAntRemoteRepository( org.apache.maven.model.Repository pomRepository )
{
RemoteRepository r = createAntRemoteRepositoryBase( pomRepository );
if ( pomRepository.getSnapshots() != null )
{
r.addSnapshots( convertRepositoryPolicy( pomRepository.getSnapshots() ) );
}
if ( pomRepository.getReleases() != null )
{
r.addReleases( convertRepositoryPolicy( pomRepository.getReleases() ) );
}
return r;
}
protected RemoteRepository createAntRemoteRepositoryBase( org.apache.maven.model.RepositoryBase pomRepository )
{
RemoteRepository r = new RemoteRepository();
r.setId( pomRepository.getId() );
r.setUrl( pomRepository.getUrl() );
r.setLayout( pomRepository.getLayout() );
updateRepositoryWithSettings( r );
return r;
}
protected void updateRepositoryWithSettings( RemoteRepository repository )
{
// TODO: actually, we need to not funnel this through the ant repository - we should pump settings into wagon
// manager at the start like m2 does, and then match up by repository id
// As is, this could potentially cause a problem with 2 remote repositories with different authentication info
if ( repository.getAuthentication() == null )
{
Server server = getSettings().getServer( repository.getId() );
if ( server != null )
{
repository.addAuthentication( new Authentication( server ) );
}
}
if ( repository.getProxy() == null )
{
org.apache.maven.settings.Proxy proxy = getSettings().getActiveProxy();
if ( proxy != null )
{
repository.addProxy( new Proxy( proxy ) );
}
}
Mirror mirror = getSettings().getMirrorOf( repository.getId() );
if ( mirror == null )
{
mirror = getSettings().getMirrorOf( "*" );
}
if ( mirror != null )
{
repository.setUrl( mirror.getUrl() );
}
}
protected Object lookup( String role )
{
try
{
return getContainer().lookup( role );
}
catch ( ComponentLookupException e )
{
throw new BuildException( "Unable to find component: " + role, e );
}
}
protected Object lookup( String role,
String roleHint )
{
try
{
return getContainer().lookup( role, roleHint );
}
catch ( ComponentLookupException e )
{
throw new BuildException( "Unable to find component: " + role + "[" + roleHint + "]", e );
}
}
protected synchronized PlexusContainer getContainer()
{
if ( container == null )
{
container = (PlexusContainer) getProject().getReference( PlexusContainer.class.getName() );
if ( container == null )
{
try
{
ClassWorld classWorld = new ClassWorld();
classWorld.newRealm( "plexus.core", getClass().getClassLoader() );
Embedder embedder = new Embedder();
embedder.start( classWorld );
container = embedder.getContainer();
}
catch ( PlexusContainerException e )
{
throw new BuildException( "Unable to start embedder", e );
}
catch ( DuplicateRealmException e )
{
throw new BuildException( "Unable to create embedder ClassRealm", e );
}
getProject().addReference( PlexusContainer.class.getName(), container );
}
}
return container;
}
public Pom buildPom( ArtifactRepository localArtifactRepository )
{
if ( pomRefId != null && pom != null )
{
throw new BuildException( "You cannot specify both a POM element and a pomrefid element" );
}
Pom pom = this.pom;
if ( pomRefId != null )
{
pom = (Pom) getProject().getReference( pomRefId );
if ( pom == null )
{
throw new BuildException( "Reference '" + pomRefId + "' was not found." );
}
}
if ( pom != null )
{
MavenProjectBuilder projectBuilder = (MavenProjectBuilder) lookup( MavenProjectBuilder.ROLE );
pom.initialise( projectBuilder, localArtifactRepository );
}
return pom;
}
protected Pom createDummyPom( ArtifactRepository localArtifactRepository )
{
MavenProjectBuilder projectBuilder = (MavenProjectBuilder) lookup( MavenProjectBuilder.ROLE );
MavenProject mavenProject;
try
{
mavenProject = projectBuilder.buildStandaloneSuperProject( localArtifactRepository, getProfileManager() );
}
catch (ProjectBuildingException e)
{
throw new BuildException( "Unable to create dummy Pom", e );
}
Pom pom = new Pom();
pom.setMavenProject( mavenProject );
return pom;
}
protected Artifact createDummyArtifact()
{
ArtifactFactory factory = (ArtifactFactory) lookup( ArtifactFactory.ROLE );
// TODO: maybe not strictly correct, while we should enforce that packaging has a type handler of the same id, we don't
return factory.createBuildArtifact( "unspecified", "unspecified", "0.0", "jar" );
}
public String[] getSupportedProtocols()
{
try
{
Map wagonMap = getContainer().lookupMap( Wagon.ROLE );
List protocols = new ArrayList();
for ( Iterator iter = wagonMap.entrySet().iterator(); iter.hasNext(); )
{
Map.Entry entry = (Map.Entry) iter.next();
protocols.add( entry.getKey() );
}
return (String[]) protocols.toArray( new String[protocols.size()] );
}
catch ( ComponentLookupException e )
{
throw new BuildException( "Unable to lookup Wagon providers", e );
}
}
public String getSupportedProtocolsAsString()
{
return StringUtils.join( getSupportedProtocols(), ", " );
}
public void diagnoseError( Throwable error )
{
try
{
ErrorDiagnostics diagnostics = (ErrorDiagnostics) container.lookup( ErrorDiagnostics.ROLE );
StringBuffer message = new StringBuffer();
message.append( "An error has occurred while processing the Maven artifact tasks.\n" );
message.append( " Diagnosis:\n\n" );
message.append( diagnostics.diagnose( error ) );
message.append( "\n\n" );
log( message.toString(), Project.MSG_INFO );
}
catch ( ComponentLookupException e )
{
log( "Failed to retrieve error diagnoser.", Project.MSG_DEBUG );
}
}
public void addPom( Pom pom )
{
this.pom = pom;
}
public String getPomRefId()
{
return pomRefId;
}
public void setPomRefId( String pomRefId )
{
this.pomRefId = pomRefId;
}
public LocalRepository getLocalRepository()
{
return localRepository;
}
protected ProfileManager getProfileManager()
{
return profileManager;
}
public void addLocalRepository( LocalRepository localRepository )
{
this.localRepository = localRepository;
}
public void setProfiles( String profiles )
{
if ( profiles != null )
{
// TODO: not sure this is the best way to do this...
log( "Profiles not yet supported, ignoring profiles '" + profiles + "'", Project.MSG_WARN );
// System.setProperty( ProfileActivationUtils.ACTIVE_PROFILE_IDS, profiles );
}
}
private static RepositoryPolicy convertRepositoryPolicy( org.apache.maven.model.RepositoryPolicy pomRepoPolicy )
{
RepositoryPolicy policy = new RepositoryPolicy();
policy.setEnabled( pomRepoPolicy.isEnabled() );
policy.setUpdatePolicy( pomRepoPolicy.getUpdatePolicy() );
return policy;
}
/** @noinspection RefusedBequest */
public void execute()
{
try
{
initSettings();
doExecute();
}
catch ( BuildException e )
{
diagnoseError( e );
throw e;
}
}
protected abstract void doExecute();
}