blob: bb7f3ea063542946d0e6feb696f1b29823a7cd70 [file] [log] [blame]
/*
* 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.
*/
package npanday.executable.impl;
import com.google.common.base.Objects;
import npanday.ArtifactType;
import npanday.ArtifactTypeHelper;
import npanday.PlatformUnsupportedException;
import npanday.RepositoryNotFoundException;
import npanday.artifact.ArtifactContext;
import npanday.artifact.ArtifactException;
import npanday.executable.CommandExecutor;
import npanday.executable.ExecutionException;
import npanday.executable.compiler.CompilerCapability;
import npanday.executable.compiler.CompilerConfig;
import npanday.executable.compiler.CompilerContext;
import npanday.executable.compiler.CompilerExecutable;
import npanday.executable.compiler.InvalidArtifactException;
import npanday.executable.compiler.KeyInfo;
import npanday.registry.Repository;
import npanday.registry.RepositoryRegistry;
import npanday.vendor.Vendor;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.model.Dependency;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.logging.LogEnabled;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.util.DirectoryScanner;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.StringUtils;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
* Provides an implementation of the Compiler Context.
*
* @author Shane Isbell
* @plexus.component role="npanday.executable.compiler.CompilerContext"
*/
public final class CompilerContextImpl
extends ExecutableContextImpl
implements CompilerContext, LogEnabled
{
/**
* The maven project
*/
private MavenProject project;
private CompilerConfig config;
private CompilerCapability compilerCapability;
private List<Artifact> libraries;
private List<Artifact> directLibraries;
private List<Artifact> modules;
/**
* @plexus.requirement
*/
private ArtifactContext artifactContext;
/**
* @plexus.requirement
*/
private RepositoryRegistry repositoryRegistry;
/**
* A logger for writing log messages
*/
private Logger logger;
private List<File> linkedResources;
/**
* @deprecated
*/
private List<File> embeddedResources;
private List<String> embeddedResourceArgs;
private File win32icon;
private List<File> win32resources;
public List<File> getLinkedResources()
{
return linkedResources;
}
public List<File> getEmbeddedResources()
{
return embeddedResources;
}
public List<String> getEmbeddedResourceArgs()
{
return embeddedResourceArgs;
}
public File getWin32Icon()
{
return win32icon;
}
public List<File> getWin32Resources()
{
return win32resources;
}
public File getAssemblyPath()
{
return Objects.firstNonNull( config.getAssemblyPath(), compilerCapability.getAssemblyPath() );
}
public String getTargetFramework()
{
// TODO: Target framework could be overridden through the config here...
return compilerCapability.getTargetFramework();
}
public String getTargetProfile()
{
return compilerCapability.getProfile();
}
public ArtifactType getTargetArtifactType()
{
return config.getArtifactType();
}
public String getFrameworkVersion()
{
return compilerCapability.getVendorInfo().getFrameworkVersion();
}
public boolean isTestCompile()
{
return config.isTestCompile();
}
public void enableLogging( Logger logger )
{
this.logger = logger;
}
public List<String> getCoreAssemblyNames()
{
return compilerCapability.getCoreAssemblies();
}
public List<Artifact> getModuleDependencies()
{
return modules;
}
public List<Artifact> getDirectModuleDependencies()
{
List<Artifact> artifacts;
try
{
artifacts = artifactContext.getNetModulesFor( project.getArtifact() );
}
catch ( ArtifactException e )
{
logger.error( "NPANDAY-061-000: Improper Initialization of the Net Modules", e );
return new ArrayList<Artifact>();
//TODO: How to handle this: usually implies improper init of ArtifactContext
}
if ( config.isTestCompile() && ArtifactTypeHelper.isDotnetModule( config.getArtifactType() ) )
{
artifacts.add( project.getArtifact() );
}
if ( config.isTestCompile() && ArtifactTypeHelper.isDotnetModule( project.getArtifact().getType() )
&& project.getArtifact().getFile() != null && project.getArtifact().getFile().exists() )
{
artifacts.add( project.getArtifact() );
}
return artifacts;
}
public KeyInfo getKeyInfo()
{
if ( ( compilerCapability.getVendorInfo().getVendor().equals( Vendor.MICROSOFT )
&& compilerCapability.getVendorInfo().getFrameworkVersion().equals( "1.1.4322" ) )
|| config.getKeyInfo() == null )
{
return KeyInfo.Factory.createDefaultKeyInfo();
}
else
{
return config.getKeyInfo();
}
}
public List<Artifact> getLibraryDependencies()
{
addProjectArtifactForTestCompile( libraries );
return libraries;
}
private void addProjectArtifactForTestCompile( List<Artifact> libraries )
{
if ( config.isTestCompile() && ( ArtifactTypeHelper.isDotnetLibrary( config.getArtifactType() )
|| ArtifactTypeHelper.isDotnetMavenPlugin( config.getArtifactType() ) )
&& project.getArtifact().getFile() != null && project.getArtifact().getFile().exists()
&& !libraries.contains( project.getArtifact() ) && !ArtifactTypeHelper.isDotnetModule(
project.getArtifact().getType() ) )
{
libraries.add( project.getArtifact() );
}
}
public List<Artifact> getDirectLibraryDependencies()
{
for ( Iterator i = project.getDependencyArtifacts().iterator(); i.hasNext(); )
{
Artifact artifact = (Artifact) i.next();
if ( !hasArtifact( artifact ) )
{
directLibraries.add( artifact );
}
boolean found = false;
for ( Iterator j = project.getDependencies().iterator(); j.hasNext() && !found; )
{
Dependency dependency = (Dependency) j.next();
if ( dependency.getGroupId().equals( artifact.getGroupId() )
&& dependency.getArtifactId().equals( artifact.getArtifactId() ) && dependency.getVersion().equals(
artifact.getBaseVersion() ) )
{
found = true;
}
}
if ( !found )
{
directLibraries.remove( artifact );
}
}
addProjectArtifactForTestCompile( directLibraries );
return directLibraries;
}
private boolean hasArtifact( Artifact artifact )
{
for ( Artifact art : directLibraries )
{
if ( art.getArtifactId().equals( artifact.getArtifactId() ) )
{
return true;
}
}
return false;
}
public Logger getLogger()
{
return logger;
}
public CompilerConfig getNetCompilerConfig()
{
return config;
}
public CompilerCapability getCompilerCapability()
{
return compilerCapability;
}
public String getSourceDirectoryName()
{
return ( config.isTestCompile() )
? project.getBuild().getDirectory() + File.separator + "build-test-sources"
: project.getBuild().getDirectory() + File.separator + "build-sources";
}
public File getTargetDirectory()
{
return new File( project.getBuild().getDirectory() );
}
/**
* This method will return a File where File.isExist() returns false, if NetCompile.compile has not been
* invoked.
*
* @return
* @throws InvalidArtifactException
*/
public File getArtifact()
throws InvalidArtifactException
{
ArtifactType artifactType = config.getArtifactType();
if ( artifactType == null || artifactType.equals( ArtifactType.NULL ) )
{
throw new InvalidArtifactException( "NPANDAY-061-001: Artifact Type cannot be null" );
}
//TODO: The test-plugin has a dependency on this fileName/dir. If we change it here, it will break the plugin. Fix this encapsulation issue.
String fileName = ( config.isTestCompile() )
? project.getBuild().getDirectory() + File.separator + project.getArtifactId() + "-test.dll"
: project.getBuild().getDirectory() + File.separator + project.getArtifactId() + "."
+ artifactType.getExtension();
return new File( fileName );
}
public CompilerExecutable getCompilerExecutable()
throws ExecutionException
{
return (CompilerExecutable)getNetExecutable();
}
public Repository find( String repositoryName )
throws RepositoryNotFoundException
{
Repository repository = repositoryRegistry.find( repositoryName );
if ( repository == null )
{
throw new RepositoryNotFoundException(
"NPANDAY-061-002: Could not find repository: Name = " + repositoryName );
}
return repository;
}
public void init( CompilerCapability capability, CompilerConfig config, MavenProject project )
throws PlatformUnsupportedException
{
this.project = project;
this.config = config;
libraries = new ArrayList<Artifact>();
directLibraries = new ArrayList<Artifact>();
modules = new ArrayList<Artifact>();
artifactContext.init( project, project.getRemoteArtifactRepositories(), config.getLocalRepository() );
Set<Artifact> artifacts = project.getDependencyArtifacts();//Can add WFC deps prior
if ( artifacts != null )
{
for ( Artifact artifact : artifacts )
{
String type = artifact.getType();
logger.debug( "NPANDAY-061-006: Artifact Type:" + type );
logger.debug( "NPANDAY-061-007: Artifact Type:" + ArtifactTypeHelper.isDotnetGenericGac( type ) );
ArtifactType artifactType = ArtifactType.getArtifactTypeForPackagingName( type );
if ( ArtifactTypeHelper.isDotnetModule( type ) )
{
modules.add( artifact );
}
else if ( ( artifactType != ArtifactType.NULL && (
StringUtils.equals( artifactType.getTargetCompileType(), "library" )
|| artifactType.getExtension().equals( "dll" ) || artifactType.getExtension().equals(
"exe" ) ) ) || type.equals( "jar" ) )
{
libraries.add( artifact );
}
File gacRoot = capability.getVendorInfo().getGlobalAssemblyCacheDirectoryFor( type );
if ( gacRoot != null )
{
setArtifactGacFile( gacRoot.getAbsolutePath(), artifact );
libraries.add( artifact );
}
else if ( type.equals( ArtifactType.COM_REFERENCE.getPackagingType() ) )
{
moveInteropDllToBuildDirectory( artifact );
libraries.add( artifact );
}
else if ( ( artifactType != null && ( "library".equals( artifactType.getTargetCompileType() )
|| "dll".equals( artifactType.getExtension() ) || "exe".equals( artifactType.getExtension() ) ) )
|| "jar".equals( type ) )
{
libraries.add( artifact );
}
}
}
// TODO: matching the capability for the compiler requirement should be done on the outside
compilerCapability = capability;
super.init( compilerCapability, config );
String basedir = project.getBuild().getDirectory() + File.separator + "assembly-resources" + File.separator;
linkedResources = new File( basedir, "linkresource" ).exists() ? Arrays.asList(
new File( basedir, "linkresource" ).listFiles() ) : new ArrayList<File>();
getEmbeddedResources( new File( basedir, "resource" ) );
win32resources = new File( basedir, "win32res" ).exists()
? Arrays.asList( new File( basedir, "win32res" ).listFiles() )
: new ArrayList<File>();
File win32IconDir = new File( basedir, "win32icon" );
if ( win32IconDir.exists() )
{
File[] icons = win32IconDir.listFiles();
if ( icons.length > 1 )
{
throw new PlatformUnsupportedException(
"NPANDAY-061-007: There is more than one win32icon in resource directory: Number = "
+ icons.length );
}
if ( icons.length == 1 )
{
win32icon = icons[0];
}
}
}
public List<String> getIncludeSources()
{
// TODO: directory scanner should run already here!
return config.getIncludeSources();
}
public File getOutputDirectory()
{
return config.getOutputDirectory();
}
private void getEmbeddedResources( File basedir )
{
List<File> embeddedResources = new ArrayList<File>();
List<String> embeddedResourceArgs = new ArrayList<String>();
if ( basedir.exists() )
{
DirectoryScanner scanner = new DirectoryScanner();
scanner.setBasedir( basedir );
scanner.scan();
for ( String file : scanner.getIncludedFiles() )
{
File f = new File( basedir, file );
embeddedResources.add( f );
if ( f.getName().endsWith( ".resources" ) )
{
embeddedResourceArgs.add( f.getAbsolutePath() );
}
else
{
String resourceName = project.getArtifactId() + "." + file.replace( File.separatorChar, '.' );
embeddedResourceArgs.add( f.getAbsolutePath() + "," + resourceName );
}
}
}
this.embeddedResources = embeddedResources;
this.embeddedResourceArgs = embeddedResourceArgs;
}
private void moveInteropDllToBuildDirectory( Artifact artifact )
throws PlatformUnsupportedException
{
try
{
File file = artifact.getFile();
String oldPath = file.getAbsolutePath();
String target = project.getBuild().getDirectory();
String newPath = target + File.separator + "Interop." + artifact.getArtifactId() + ".dll";
if ( oldPath.contains( target ) ) //already copied to target
{
return;
}
logger.info( "NPANDAY-000-000:[COM Reference] copying file [" + oldPath + "] to [" + target + "]" );
FileUtils.copyFileToDirectory( file, new File( target ) );
logger.info( "NPANDAY-000-000:[COM Reference] deleting directory [" + file.getParentFile() + "]" );
FileUtils.deleteDirectory( file.getParentFile() );
logger.info( "NPANDAY-000-000:[COM Reference] updating artifact path to [" + newPath + "]" );
artifact.setFile( new File( newPath ) );
}
catch ( Exception e )
{
throw new PlatformUnsupportedException( e );
}
}
/*
* Installs the artifact to the gac so that it can be used in aspnet
*/
private void installArtifactGacFile( Artifact artifact )
{
try
{
CommandExecutor commandExecutor = CommandExecutor.Factory.createDefaultCommmandExecutor();
String executable = "gacutil";
List<String> commands = new ArrayList<String>();
//searching for the .dll to be installed.
String sourceDir = config.getIncludeSources().get( 0 );
String[] sourceDirTokens = sourceDir.split( "\\\\" );
String sDir = "";
//constructing the directory for the.dll
for ( int i = 0; i < sourceDirTokens.length - 3; i++ )
{
if ( sDir.equalsIgnoreCase( "" ) )
{
sDir = sourceDirTokens[i];
}
else
{
sDir = sDir + "\\" + sourceDirTokens[i];
}
}
String dll = artifact.getArtifactId() + ".dll";
String dllSysPath = "";
List<File> potentialDlls = FileUtils.getFiles( new File( sDir ), "**", null );
for ( File cFile : potentialDlls )
{
String pSysPath = cFile.getAbsolutePath();
String[] pathTokens = pSysPath.split( "\\\\" );
if ( pathTokens[pathTokens.length - 1].equalsIgnoreCase( dll ) )
{
dllSysPath = cFile.getAbsolutePath();
//break;
}
}
commands.add( "/i " + dllSysPath );
commandExecutor.executeCommand( executable, commands );
}
catch ( Exception e )
{
System.out.println(
"NPANDAY-000-000: Could not install artifact to GAC artifact:" + artifact.getArtifactId() );
}
}
private void setArtifactGacFile( String gacRoot, Artifact artifact )
throws PlatformUnsupportedException
{
// TODO: Refactor to PathUtil.getGlobalAssemblyCacheFileFor
String type = artifact.getType();
logger.debug( "NPANDAY-061-001: Gac Root:" + gacRoot );
logger.debug( "NPANDAY-061-003: Artifact Type:" + type );
File gacFile;
if ( "gac_msil4".equalsIgnoreCase( type ) || "gac_32_4".equalsIgnoreCase( type ) || "gac_64_4".equalsIgnoreCase(
type ) )
{
gacFile = new File( gacRoot, artifact.getArtifactId() + File.separator + "v"
+ compilerCapability.getVendorInfo().getFrameworkVersion() + "_" + artifact.getVersion() + "__"
+ artifact.getClassifier() + File.separator + artifact.getArtifactId() + ".dll" );
}
else
{
gacFile = new File( gacRoot, artifact.getArtifactId() + File.separator + artifact.getVersion() + "__"
+ artifact.getClassifier() + File.separator + artifact.getArtifactId() + ".dll" );
}
logger.debug( "NPANDAY-061-001: gacFile to:" + gacFile.getAbsolutePath() );
// first check if the artifact is not yet installed
if ( !gacFile.exists() )
{
installArtifactGacFile( artifact );
}
// after installing the gac check if it is installed in the system.
if ( !gacFile.exists() )
{
// TODO: this will only work on Windows
//check for gac_msil
gacRoot = System.getenv( "SystemRoot" ) + "\\assembly\\GAC_MSIL\\";
gacFile = new File( gacRoot, artifact.getArtifactId() + File.separator + artifact.getVersion() + "__"
+ artifact.getClassifier() + File.separator + artifact.getArtifactId() + ".dll" );
if ( !gacFile.exists() )
{
throw new PlatformUnsupportedException(
"NPANDAY-000-000: Could not find GAC dependency: File = " + gacFile.getAbsolutePath() );
}
}
artifact.setFile( gacFile );
}
}