blob: cc7ce047eeaf444a6e920cf803ccc522750c5638 [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 npanday.ArtifactTypeHelper;
import npanday.executable.CommandExecutor;
import npanday.executable.ExecutionException;
import npanday.executable.CapabilityMatcher;
import npanday.executable.CommandFilter;
import npanday.PlatformUnsupportedException;
import npanday.executable.compiler.*;
import npanday.artifact.ArtifactContext;
import npanday.artifact.ArtifactException;
import npanday.ArtifactType;
import org.apache.maven.project.MavenProject;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.model.Dependency;
import npanday.registry.Repository;
import npanday.registry.RepositoryRegistry;
import npanday.RepositoryNotFoundException;
import npanday.vendor.Vendor;
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.util.*;
import java.io.File;
/**
* Provides an implementation of the Compiler Context.
*
* @author Shane Isbell
*/
public final class CompilerContextImpl
implements CompilerContext, LogEnabled
{
/**
* The maven project
*/
private MavenProject project;
private CompilerConfig config;
private List<Artifact> libraries;
private List<Artifact> directLibraries;
private List<Artifact> modules;
private CompilerExecutable netCompiler;
private CompilerCapability compilerCapability;
private CompilerRequirement compilerRequirement;
private CommandFilter commandFilter;
private ArtifactContext artifactContext;
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 void enableLogging( Logger logger )
{
this.logger = logger;
}
public CompilerRequirement getCompilerRequirement()
{
return compilerRequirement;
}
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 ( ( compilerRequirement.getVendor().equals( Vendor.MICROSOFT ) &&
compilerRequirement.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 netCompiler;
}
public CommandFilter getCommandFilter()
{
return commandFilter;
}
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;
}
private String getGacRootForMono()
throws PlatformUnsupportedException
{
String path = System.getenv( "PATH" );
if ( path != null )
{
String[] tokens = path.split( System.getProperty( "path.separator" ) );
for ( String token : tokens )
{
File gacRoot = new File( new File( token ).getParentFile(), "lib/mono/gac/" );
if ( gacRoot.exists() )
{
return gacRoot.getAbsolutePath();
}
}
}
//check settings file
String monoRoot = System.getenv( "MONO_ROOT" );
if ( monoRoot != null && !new File( monoRoot ).exists() )
{
logger.warn( "MONO_ROOT has been incorrectly set. Trying /usr : MONO_ROOT = " + monoRoot );
}
else if ( monoRoot != null )
{
return ( !monoRoot.endsWith( File.separator ) ) ? monoRoot + File.separator : monoRoot;
}
if ( new File( "/usr/lib/mono/gac/" ).exists() )
{
// Linux default location
return new File( "/usr/lib/mono/gac/" ).getAbsolutePath();
}
else if ( new File( "/Library/Frameworks/Mono.framework/Home/lib/mono/gac/" ).exists() )
{
// Mac OS X default location
return new File( "/Library/Frameworks/Mono.framework/Home/lib/mono/gac/" ).getAbsolutePath();
}
else
{
throw new PlatformUnsupportedException(
"NPANDAY-061-008: Could not locate Global Assembly Cache for Mono. Try setting the MONO_ROOT environmental variable." );
}
}
public void init( CompilerRequirement compilerRequirement, CompilerConfig config, MavenProject project,
CapabilityMatcher capabilityMatcher )
throws PlatformUnsupportedException
{
this.project = project;
this.config = config;
this.compilerRequirement = compilerRequirement;
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 );
//Resolving here since the GAC path is vendor and framework aware
if ( ArtifactTypeHelper.isDotnetGenericGac( type ) )
{
// TODO: Duplicate code with VendorInfoRepositoryImpl.getGlobalAssemblyCacheDirectoryFor
String gacRoot = null;
if ( compilerRequirement.getVendor().equals( Vendor.MICROSOFT ) &&
compilerRequirement.getFrameworkVersion().equals( "1.1.4322" ) )
{
gacRoot = System.getenv( "SystemRoot" ) + "\\assembly\\GAC\\";
}
else if ( compilerRequirement.getVendor().equals( Vendor.MICROSOFT ) )
{
// Layout changed since 2.0
// http://discuss.joelonsoftware.com/default.asp?dotnet.12.383883.5
gacRoot = System.getenv( "SystemRoot" ) + "\\assembly\\GAC_MSIL\\";
}
else if ( compilerRequirement.getVendor().equals( Vendor.MONO ) )
{
gacRoot = getGacRootForMono();
}
if ( gacRoot != null )
{
setArtifactGacFile( gacRoot, artifact );
libraries.add( artifact );
}
}
else if (type.equals(ArtifactType.GAC_MSIL4.getPackagingType())) {
String gacRoot = System.getenv( "SystemRoot" ) + "\\Microsoft.NET\\assembly\\GAC_MSIL\\";
setArtifactGacFile( gacRoot, artifact );
libraries.add( artifact );
}
else if ( type.equals( ArtifactType.GAC.getPackagingType() ) )
{
String gacRoot = ( compilerRequirement.getVendor().equals( Vendor.MONO ) ) ? getGacRootForMono()
: System.getenv( "SystemRoot" ) + "\\assembly\\GAC\\";
setArtifactGacFile( gacRoot, artifact );
libraries.add( artifact );
}
else if ( type.equals( ArtifactType.GAC_32.getPackagingType() ) )
{
String gacRoot = ( compilerRequirement.getVendor().equals( Vendor.MONO ) ) ? getGacRootForMono()
: System.getenv( "SystemRoot" ) + "\\assembly\\GAC_32\\";
setArtifactGacFile( gacRoot, artifact );
libraries.add( artifact );
}
else if ( type.equals( ArtifactType.GAC_64.getPackagingType() ) )
{
String gacRoot = ( compilerRequirement.getVendor().equals( Vendor.MONO ) ) ? getGacRootForMono()
: System.getenv( "SystemRoot" ) + "\\assembly\\GAC_64\\";
setArtifactGacFile( gacRoot, artifact );
libraries.add( artifact );
}
else if ( type.equals( ArtifactType.GAC_MSIL.getPackagingType() ) )
{
String gacRoot = ( compilerRequirement.getVendor().equals( Vendor.MONO ) ) ? getGacRootForMono()
: System.getenv( "SystemRoot" ) + "\\assembly\\GAC_MSIL\\";
setArtifactGacFile( gacRoot, 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 );
}
}
}
compilerCapability = capabilityMatcher.matchCompilerCapabilityFor( compilerRequirement );
String className = compilerCapability.getPluginClassName();
try
{
Class cc = Class.forName( className );
netCompiler = (CompilerExecutable) cc.newInstance();
netCompiler.init( this );//TODO: Add ArtifactInfo?
}
catch ( ClassNotFoundException e )
{
throw new PlatformUnsupportedException(
"NPANDAY-061-004: Unable to create NetCompiler: Class Name = " + className, e );
}
catch ( InstantiationException e )
{
throw new PlatformUnsupportedException(
"NPANDAY-061-005: Unable to create NetCompiler: Class Name = " + className, e );
}
catch ( IllegalAccessException e )
{
throw new PlatformUnsupportedException(
"NPANDAY-061-006: Unable to create NetCompiler: Class Name = " + className, e );
}
commandFilter =
CommandFilter.Factory.createDefaultCommandFilter( compilerCapability.getCommandCapability(), logger );
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];
}
}
}
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)) {
gacFile = new File( gacRoot, artifact.getArtifactId() + File.separator + "v" + compilerRequirement.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 );
}
}