blob: 73bc8eea75b64495893df72e05d04d1a174bec3a [file] [log] [blame]
package org.apache.maven.plugin.testing;
/*
* 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.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DefaultArtifact;
import org.apache.maven.artifact.handler.ArtifactHandler;
import org.apache.maven.artifact.versioning.VersionRange;
import org.apache.maven.plugin.testing.stubs.DefaultArtifactHandlerStub;
import org.codehaus.plexus.archiver.Archiver;
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.archiver.manager.ArchiverManager;
import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
import org.codehaus.plexus.archiver.war.WarArchiver;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.ReflectionUtils;
import org.codehaus.plexus.util.StringUtils;
/**
* This class creates artifacts to be used for testing purposes. It can optionally create actual files on the local disk
* for things like copying. It can create these files as archives with named files inside to be used for testing things
* like unpack. Also provided are some utility methods to quickly get a set of artifacts distinguished by various things
* like group,artifact,type,scope, etc It was originally developed for the dependency plugin, but can be useful in other
* plugins that need to simulate artifacts for unit tests.
*
* @author <a href="mailto:brianf@apache.org">Brian Fox</a>
*/
public class ArtifactStubFactory
{
private File workingDir;
private boolean createFiles;
private File srcFile;
private boolean createUnpackableFile;
private ArchiverManager archiverManager;
/**
* Default constructor. This should be used only if real files aren't needed...just the artifact objects
*/
public ArtifactStubFactory()
{
this.workingDir = null;
this.createFiles = false;
}
/**
* This constructor is to be used if files are needed and to set a working dir
*
* @param workingDir
* @param createFiles
*/
public ArtifactStubFactory( File workingDir, boolean createFiles )
{
this.workingDir = new File( workingDir, "localTestRepo" );
this.createFiles = createFiles;
}
/**
* If set, the file will be created as a zip/jar/war with a file inside that can be checked to exist after
* unpacking.
*
* @param archiverManager
*/
public void setUnpackableFile( ArchiverManager archiverManager )
{
this.createUnpackableFile = true;
this.archiverManager = archiverManager;
}
/**
* @param groupId
* @param artifactId
* @param version
* @return a <code>DefaultArtifact</code> instance for the given parameters
* @throws IOException if any
* @see #createArtifact(String, String, String, String, String, String)
*/
public Artifact createArtifact( String groupId, String artifactId, String version )
throws IOException
{
return createArtifact( groupId, artifactId, version, Artifact.SCOPE_COMPILE, "jar", "" );
}
/**
* @param groupId
* @param artifactId
* @param version
* @param scope
* @return a <code>DefaultArtifact</code> instance for the given parameters
* @throws IOException if any
* @see #createArtifact(String, String, String, String, String, String)
*/
public Artifact createArtifact( String groupId, String artifactId, String version, String scope )
throws IOException
{
return createArtifact( groupId, artifactId, version, scope, "jar", "" );
}
/**
* @param groupId
* @param artifactId
* @param version
* @param scope
* @param type
* @param classifier
* @return a <code>DefaultArtifact</code> instance for the given parameters
* @throws IOException if any
* @see #createArtifact(String, String, VersionRange, String, String, String, boolean)
*/
public Artifact createArtifact( String groupId, String artifactId, String version, String scope, String type,
String classifier )
throws IOException
{
VersionRange vr = VersionRange.createFromVersion( version );
return createArtifact( groupId, artifactId, vr, scope, type, classifier, false );
}
/**
* @param groupId not null
* @param artifactId not null
* @param versionRange not null
* @param scope not null
* @param type not null
* @param classifier
* @param optional not null
* @return a <code>DefaultArtifact</code> instance
* @throws IOException if any
*/
public Artifact createArtifact( String groupId, String artifactId, VersionRange versionRange, String scope,
String type, String classifier, boolean optional )
throws IOException
{
ArtifactHandler ah = new DefaultArtifactHandlerStub( type, classifier );
Artifact artifact =
new DefaultArtifact( groupId, artifactId, versionRange, scope, type, classifier, ah, optional );
// i have no idea why this needs to be done manually when isSnapshot is able to figure it out.
artifact.setRelease( !artifact.isSnapshot() );
if ( createFiles )
{
setArtifactFile( artifact, this.workingDir, this.srcFile, this.createUnpackableFile );
}
return artifact;
}
/**
* Creates a new empty file and attaches it to the artifact.
*
* @param artifact to attach the file to.
* @param workingDir where to locate the new file
* @throws IOException
*/
public void setArtifactFile( Artifact artifact, File workingDir )
throws IOException
{
setArtifactFile( artifact, workingDir, null, false );
}
/**
* Copyies the srcFile to the workingDir and then attaches it to the artifact. If srcFile is null, a new empty file
* will be created.
*
* @param artifact to attach
* @param workingDir where to copy the srcFile.
* @param srcFile file to be attached.
* @throws IOException
*/
public void setArtifactFile( Artifact artifact, File workingDir, File srcFile )
throws IOException
{
setArtifactFile( artifact, workingDir, srcFile, false );
}
/**
* Creates an unpackable file (zip,jar etc) containing an empty file.
*
* @param artifact to attach
* @param workingDir where to create the file.
* @throws IOException
*/
public void setUnpackableArtifactFile( Artifact artifact, File workingDir )
throws IOException
{
setArtifactFile( artifact, workingDir, null, true );
}
/**
* Creates an unpackable file (zip,jar etc) containing the srcFile. If srcFile is null, a new empty file will be
* created.
*
* @param artifact to attach
* @param workingDir where to create the file.
* @param srcFile
* @throws IOException if any
*/
public void setUnpackableArtifactFile( Artifact artifact, File workingDir, File srcFile )
throws IOException
{
setArtifactFile( artifact, workingDir, srcFile, true );
}
/**
* Creates a file that can be copied or unpacked based on the passed in artifact
*
* @param artifact
* @param workingDir
* @param srcFile
* @param createUnpackableFile
* @throws IOException if any
*/
private void setArtifactFile( Artifact artifact, File workingDir, File srcFile, boolean createUnpackableFile )
throws IOException
{
if ( workingDir == null )
{
throw new IllegalArgumentException(
"The workingDir must be set." );
}
String fileName = getFormattedFileName( artifact, false );
File theFile = new File( workingDir, fileName );
theFile.getParentFile().mkdirs();
if ( srcFile == null )
{
theFile.createNewFile();
}
else if ( createUnpackableFile )
{
try
{
createUnpackableFile( artifact, theFile );
}
catch ( NoSuchArchiverException e )
{
throw new IOException( "NoSuchArchiverException: " + e.getMessage() );
}
catch ( ArchiverException e )
{
throw new IOException( "ArchiverException: " + e.getMessage() );
}
}
else
{
FileUtils.copyFile( srcFile, theFile );
}
artifact.setFile( theFile );
}
/**
* @param artifact
* @return
*/
public static String getUnpackableFileName( Artifact artifact )
{
return "" + artifact.getGroupId() + "-" + artifact.getArtifactId() + "-" + artifact.getVersion() + "-"
+ artifact.getClassifier() + "-" + artifact.getType() + ".txt";
}
/**
* @param artifact
* @param destFile
* @throws NoSuchArchiverException
* @throws ArchiverException if any
* @throws IOException if any
*/
public void createUnpackableFile( Artifact artifact, File destFile )
throws NoSuchArchiverException, ArchiverException, IOException
{
Archiver archiver = archiverManager.getArchiver( destFile );
archiver.setDestFile( destFile );
archiver.addFile( srcFile, getUnpackableFileName( artifact ) );
try
{
setVariableValueToObject( archiver, "logger", new SilentLog() );
}
catch ( IllegalAccessException e )
{
System.out.println( "Unable to override logger with silent log." );
e.printStackTrace();
}
if ( archiver instanceof WarArchiver )
{
WarArchiver war = (WarArchiver) archiver;
// the use of this is counter-intuitive:
// http://jira.codehaus.org/browse/PLX-286
war.setIgnoreWebxml( false );
}
archiver.createArchive();
}
/**
* @return a <code>DefaultArtifact</code> instance for <code>testGroupId:release:jar:1.0</code>
* @throws IOException if any
*/
public Artifact getReleaseArtifact()
throws IOException
{
return createArtifact( "testGroupId", "release", "1.0" );
}
/**
* @return a default <code>DefaultArtifact</code> instance for <code>testGroupId:snapshot:jar:2.0-SNAPSHOT</code>
* @throws IOException if any
*/
public Artifact getSnapshotArtifact()
throws IOException
{
return createArtifact( "testGroupId", "snapshot", "2.0-SNAPSHOT" );
}
/**
* @return a default set of release and snapshot <code>DefaultArtifact</code>, i.e.:
* <code>testGroupId:snapshot:jar:2.0-SNAPSHOT, testGroupId:release:jar:1.0</code>
* @throws IOException if any
* @see #getReleaseArtifact()
* @see #getSnapshotArtifact()
*/
public Set<Artifact> getReleaseAndSnapshotArtifacts()
throws IOException
{
Set<Artifact> set = new HashSet<>();
set.add( getReleaseArtifact() );
set.add( getSnapshotArtifact() );
return set;
}
/**
* @return a default set of <code>DefaultArtifact</code>, i.e.:
* <code>g:provided:jar:1.0, g:compile:jar:1.0, g:system:jar:1.0, g:test:jar:1.0, g:runtime:jar:1.0</code>
* @throws IOException if any
*/
public Set<Artifact> getScopedArtifacts()
throws IOException
{
Set<Artifact> set = new HashSet<>();
set.add( createArtifact( "g", "compile", "1.0", Artifact.SCOPE_COMPILE ) );
set.add( createArtifact( "g", "provided", "1.0", Artifact.SCOPE_PROVIDED ) );
set.add( createArtifact( "g", "test", "1.0", Artifact.SCOPE_TEST ) );
set.add( createArtifact( "g", "runtime", "1.0", Artifact.SCOPE_RUNTIME ) );
set.add( createArtifact( "g", "system", "1.0", Artifact.SCOPE_SYSTEM ) );
return set;
}
/**
* @return a set of <code>DefaultArtifact</code>, i.e.:
* <code>g:d:zip:1.0, g:a:war:1.0, g:b:jar:1.0, g:c:sources:1.0, g:e:rar:1.0</code>
* @throws IOException if any
*/
public Set<Artifact> getTypedArtifacts()
throws IOException
{
Set<Artifact> set = new HashSet<>();
set.add( createArtifact( "g", "a", "1.0", Artifact.SCOPE_COMPILE, "war", null ) );
set.add( createArtifact( "g", "b", "1.0", Artifact.SCOPE_COMPILE, "jar", null ) );
set.add( createArtifact( "g", "c", "1.0", Artifact.SCOPE_COMPILE, "sources", null ) );
set.add( createArtifact( "g", "d", "1.0", Artifact.SCOPE_COMPILE, "zip", null ) );
set.add( createArtifact( "g", "e", "1.0", Artifact.SCOPE_COMPILE, "rar", null ) );
return set;
}
/**
* @return a set of <code>DefaultArtifact</code>, i.e.:
* <code>g:c:jar:three:1.0, g:b:jar:two:1.0, g:d:jar:four:1.0, g:a:jar:one:1.0</code>
* @throws IOException if any
*/
public Set<Artifact> getClassifiedArtifacts()
throws IOException
{
Set<Artifact> set = new HashSet<>();
set.add( createArtifact( "g", "a", "1.0", Artifact.SCOPE_COMPILE, "jar", "one" ) );
set.add( createArtifact( "g", "b", "1.0", Artifact.SCOPE_COMPILE, "jar", "two" ) );
set.add( createArtifact( "g", "c", "1.0", Artifact.SCOPE_COMPILE, "jar", "three" ) );
set.add( createArtifact( "g", "d", "1.0", Artifact.SCOPE_COMPILE, "jar", "four" ) );
return set;
}
/**
* @return a set of <code>DefaultArtifact</code>, i.e.:
* <code>g:d:zip:1.0, g:a:war:1.0, g:b:jar:1.0, g:e:rar:1.0</code>
* @throws IOException if any
*/
public Set<Artifact> getTypedArchiveArtifacts()
throws IOException
{
Set<Artifact> set = new HashSet<>();
set.add( createArtifact( "g", "a", "1.0", Artifact.SCOPE_COMPILE, "war", null ) );
set.add( createArtifact( "g", "b", "1.0", Artifact.SCOPE_COMPILE, "jar", null ) );
set.add( createArtifact( "g", "d", "1.0", Artifact.SCOPE_COMPILE, "zip", null ) );
set.add( createArtifact( "g", "e", "1.0", Artifact.SCOPE_COMPILE, "rar", null ) );
return set;
}
/**
* @return a set of <code>DefaultArtifact</code>, i.e.:
* <code>g:one:jar:a:1.0, g:two:jar:a:1.0, g:four:jar:a:1.0, g:three:jar:a:1.0</code>
* @throws IOException if any
*/
public Set<Artifact> getArtifactArtifacts()
throws IOException
{
Set<Artifact> set = new HashSet<>();
set.add( createArtifact( "g", "one", "1.0", Artifact.SCOPE_COMPILE, "jar", "a" ) );
set.add( createArtifact( "g", "two", "1.0", Artifact.SCOPE_COMPILE, "jar", "a" ) );
set.add( createArtifact( "g", "three", "1.0", Artifact.SCOPE_COMPILE, "jar", "a" ) );
set.add( createArtifact( "g", "four", "1.0", Artifact.SCOPE_COMPILE, "jar", "a" ) );
return set;
}
/**
* @return a set of <code>DefaultArtifact</code>, i.e.:
* <code>one:group-one:jar:a:1.0, three:group-three:jar:a:1.0, four:group-four:jar:a:1.0,
* two:group-two:jar:a:1.0</code>
* @throws IOException if any
*/
public Set<Artifact> getGroupIdArtifacts()
throws IOException
{
Set<Artifact> set = new HashSet<>();
set.add( createArtifact( "one", "group-one", "1.0", Artifact.SCOPE_COMPILE, "jar", "a" ) );
set.add( createArtifact( "two", "group-two", "1.0", Artifact.SCOPE_COMPILE, "jar", "a" ) );
set.add( createArtifact( "three", "group-three", "1.0", Artifact.SCOPE_COMPILE, "jar", "a" ) );
set.add( createArtifact( "four", "group-four", "1.0", Artifact.SCOPE_COMPILE, "jar", "a" ) );
return set;
}
/**
* @return a set of <code>DefaultArtifact</code>
* @throws IOException if any
* @see #getTypedArtifacts()
* @see #getScopedArtifacts()
* @see #getReleaseAndSnapshotArtifacts()
*/
public Set<Artifact> getMixedArtifacts()
throws IOException
{
Set<Artifact> set = new HashSet<>();
set.addAll( getTypedArtifacts() );
set.addAll( getScopedArtifacts() );
set.addAll( getReleaseAndSnapshotArtifacts() );
return set;
}
/**
* @return Returns the createFiles.
*/
public boolean isCreateFiles()
{
return this.createFiles;
}
/**
* @param createFiles The createFiles to set.
*/
public void setCreateFiles( boolean createFiles )
{
this.createFiles = createFiles;
}
/**
* @return Returns the workingDir.
*/
public File getWorkingDir()
{
return this.workingDir;
}
/**
* @param workingDir The workingDir to set.
*/
public void setWorkingDir( File workingDir )
{
this.workingDir = workingDir;
}
/**
* @return Returns the srcFile.
*/
public File getSrcFile()
{
return this.srcFile;
}
/**
* @param srcFile The srcFile to set.
*/
public void setSrcFile( File srcFile )
{
this.srcFile = srcFile;
}
/**
* Convenience method to set values to variables in objects that don't have setters
*
* @param object
* @param variable
* @param value
* @throws IllegalAccessException
*/
public static void setVariableValueToObject( Object object, String variable, Object value )
throws IllegalAccessException
{
Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses( variable, object.getClass() );
field.setAccessible( true );
field.set( object, value );
}
/**
* Builds the file name. If removeVersion is set, then the file name must be reconstructed from the artifactId,
* Classifier (if used) and Type. Otherwise, this method returns the artifact file name.
*
* @param artifact File to be formatted.
* @param removeVersion Specifies if the version should be removed from the file name.
* @return Formatted file name in the format artifactId-[version]-[classifier].[type]
*/
public static String getFormattedFileName( Artifact artifact, boolean removeVersion )
{
String destFileName = null;
// if there is a file and we aren't stripping the version, just get the
// name directly
if ( artifact.getFile() != null && !removeVersion )
{
destFileName = artifact.getFile().getName();
}
else
// if offline
{
String versionString = null;
if ( !removeVersion )
{
versionString = "-" + artifact.getVersion();
}
else
{
versionString = "";
}
String classifierString = "";
if ( StringUtils.isNotEmpty( artifact.getClassifier() ) )
{
classifierString = "-" + artifact.getClassifier();
}
destFileName = artifact.getArtifactId() + versionString + classifierString + "."
+ artifact.getArtifactHandler().getExtension();
}
return destFileName;
}
}