All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.redhat.ceylon.maven.CeylonCompileMojo Maven / Gradle / Ivy

There is a newer version: 1.3.3
Show newest version
package com.redhat.ceylon.maven;

import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

import org.apache.maven.model.Dependency;
import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.eclipse.aether.util.artifact.JavaScopes;

import com.redhat.ceylon.common.Backend;
import com.redhat.ceylon.common.FileUtil;
import com.redhat.ceylon.common.ModuleUtil;
import com.redhat.ceylon.common.Versions;
import com.redhat.ceylon.common.config.CeylonConfig;
import com.redhat.ceylon.compiler.java.runtime.tools.CompilationListener;
import com.redhat.ceylon.compiler.java.runtime.tools.Compiler;
import com.redhat.ceylon.compiler.java.runtime.tools.CompilerOptions;
import com.redhat.ceylon.compiler.java.runtime.tools.JavaCompilerOptions;
import com.redhat.ceylon.compiler.java.runtime.tools.impl.JavaCompilerImpl;

/**
 * @author Julien Viet
 */
@Mojo(name = "compile", defaultPhase = LifecyclePhase.COMPILE)
public class CeylonCompileMojo extends AbstractCeylonCompileMojo {

  @Parameter
  private boolean disablePomChecks;

  @Parameter
  private boolean flatClasspath;

  @Parameter
  private boolean autoExportMavenDependencies;

  @Parameter
  private boolean fullyExportMavenDependencies;

  @Parameter
  private String jdkProvider;

  @Parameter
  private List aptModules;
  
  @Parameter
  private String javacOptions;

  @Parameter
  private File explodeTo;

  @Parameter
  private boolean explode;

  @Override
  protected void compile(List sourcePath, List resourcePath, List files, List modules) 
		  throws MojoExecutionException, MojoFailureException {
	exportDependencies();
    Compiler compiler = new JavaCompilerImpl() {
        @Override
        protected List translateOptions(CompilerOptions options) {
            List translatedOptions = super.translateOptions(options);
            if (javacOptions != null) {
                Collections.addAll(translatedOptions, javacOptions.split("\\s+"));
            }
            // Temporary until 1.3.2 is released
            Collections.addAll(translatedOptions, "-source", getDefaultTarget().toString());
            return translatedOptions;
        }
    };
    CeylonConfig cfg = CeylonConfig.createFromLocalDir(cwd);
    JavaCompilerOptions options = JavaCompilerOptions.fromConfig(cfg);
    options.setModules(modules);
    options.setJavacTarget(getDefaultTarget());
    options.setSourcePath(sourcePath);
    options.setResourcePath(resourcePath);
    if (cwd != null) {
        options.setWorkingDirectory(cwd.getAbsolutePath());
    }
    options.setOutputRepository(out);
    options.setFlatClasspath(flatClasspath);
    options.setAutoExportMavenDependencies(autoExportMavenDependencies);
    options.setFullyExportMavenDependencies(fullyExportMavenDependencies);
    options.setJdkProvider(jdkProvider);
    if (aptModules != null) {
        options.setAptModules(aptModules);
    }
    if (verbose != null) {
      options.setVerbose(true);
      if (!"true".equals(verbose)) {
        options.setVerboseCategory(verbose);
      }
    }
    if (userRepos != null) {
      for (String userRepo : userRepos) {
        options.addUserRepository(userRepo);
      }
    } else {
      options.addUserRepository(buildDir + "/modules");
    }
    addExportedUserRepository(options);
    if(ceylonHome != null)
    	options.setSystemRepository(ceylonHome + "/repo");
    if(timeout != null)
    	options.setTimeout(timeout);
    options.setFiles(files);
    final MojoExecutionException[] x = new MojoExecutionException[1];
    boolean ok = compiler.compile(options, new CompilationListener() {

      public void error(File file, long line, long column, String message) {
        String msg;
        if (file != null) {
          msg = "Compilation error at (" + line + "," + column + ") in " +
              file.getAbsolutePath() + ":" + message;
        } else {
          msg = "Compilation error:" + message;
        }
        getLog().error(msg);
      }

      public void warning(File file, long line, long column, String message) {
        String msg;
        if (file != null) {
          msg = "Compilation warning at (" + line + "," + column + ") in " +
              file.getAbsolutePath() + ":" + message;
        } else {
          msg = "Compilation warning:" + message;
        }
        getLog().warn(msg);
      }

      public void moduleCompiled(String module, String version) {
        getLog().info("Compiled module " + module + "/" + version);
        if(explode){
        	explodeModule(module, version, new File(getClassesOutput()));
        }else if (explodeTo != null) {
            explodeModule(module, version, explodeTo);
        }
        try {
        	if(!disablePomChecks && !isTest())
        		checkDependencies(module, version);
		} catch (MojoExecutionException e) {
			x[0] = e;
		}
      }
    });

    if(x[0] != null)
    	throw x[0];
    if (!ok) {
      throw new MojoExecutionException("Compilation failed");
    }
  }
  
  protected String getClassesOutput() {
	return project.getBuild().getOutputDirectory();
  }

  private static Long getDefaultTarget() {
      String dottedVersion = System.getProperty("java.version");
      return Long.parseLong(dottedVersion.split("\\.|_|-")[1]);
  }
  
    protected void explodeModule(String module, String version, File explodeTo) {
        File fOut = new File(out);
        if (fOut.isDirectory()) {
            File path = new File(ModuleUtil.moduleToPath(fOut, module), version);
            File car = new File(path, module + "-" + version + ".car");
            unzip(car, FileUtil.applyCwd(cwd, explodeTo));
        }
    }
    
    private void checkDependencies(String module, String version) throws MojoExecutionException{
      File fOut = new File(out);
      if (fOut.isDirectory()) {
          File path = new File(ModuleUtil.moduleToPath(fOut, module), version);
          File car = new File(path, module + "-" + version + ".car");
      	  MavenXpp3Reader reader = new MavenXpp3Reader();
      	  try(ZipFile zipFile = new ZipFile(car)){
      		  String groupId = project.getGroupId();
      		  String artifactId = project.getArtifactId();
      		  ZipEntry entry = zipFile.getEntry("META-INF/maven/"+groupId+"/"+artifactId+"/pom.xml");
      		  if(entry == null){
      	        throw new MojoExecutionException("Maven descriptor missing in Ceylon module "+car
      	        		+": perhaps you did not set group/artifact to "+groupId+":"+artifactId+"?");
      		  }
      		  try(InputStream is = zipFile.getInputStream(entry)){
      			  Model model = reader.read(is);
      			  compareDependencies(model);
      		  } catch (XmlPullParserException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
      	  } catch (ZipException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
      }
    }

	private void compareDependencies(Model model) throws MojoExecutionException {
    	Set projectDependencies = new HashSet<>(project.getDependencies());
    	Set augmentedModelDependencies = new HashSet<>(model.getDependencies());
    	Dependency languageDep = new Dependency();
    	languageDep.setGroupId("org.ceylon-lang");
    	languageDep.setArtifactId("ceylon.language");
    	languageDep.setVersion(Versions.CEYLON_VERSION_NUMBER);
    	augmentedModelDependencies.add(languageDep);
    	Set modelDependencies = new HashSet<>(augmentedModelDependencies);
    	OUTER:
    	for (Dependency pomDependency : project.getDependencies()) {
    		// skip test deps
    		if(pomDependency.getScope().equals(JavaScopes.TEST)){
    			projectDependencies.remove(pomDependency);
    			continue;
    		}
    		String pomGroupId = pomDependency.getGroupId();
    		String pomArtifactId = pomDependency.getArtifactId();
    		String pomVersion = pomDependency.getVersion();
			for (Dependency modelDependency : augmentedModelDependencies) {
	    		String modelGroupId = modelDependency.getGroupId();
	    		String modelArtifactId = modelDependency.getArtifactId();
	    		// FIXME: workaround for ceylon bug
	    		int colon = modelArtifactId.indexOf(':');
	    		if(colon != -1){
	    			modelGroupId += "."+modelArtifactId.substring(0, colon);
	    			modelArtifactId = modelArtifactId.substring(colon+1);
	    		}
	    		String modelVersion = modelDependency.getVersion();
	    		if(pomGroupId.equals(modelGroupId)
	    				&& pomArtifactId.equals(modelArtifactId)
	    				&& pomVersion.equals(modelVersion)){
	    			// we found a match, let's remove both and move to the next
	    			projectDependencies.remove(pomDependency);
	    			modelDependencies.remove(modelDependency);
	    			continue OUTER;
	    		}
			}
		}
    	if(projectDependencies.isEmpty()
    			&& modelDependencies.isEmpty())
    		return; // OK
    	
    	StringBuilder sb = new StringBuilder();
    	// At this point, the sets are left with the differences where each are errors
    	if(!projectDependencies.isEmpty()){
    		sb.append("pom.xml dependencies missing from module.ceylon descriptor: ");
    		boolean once = true;
    		for (Dependency projectDependency : projectDependencies) {
    			if(once)
    				once = false;
    			else
    				sb.append(", ");
    			sb.append(projectDependency.getGroupId()+":"+projectDependency.getArtifactId()+"/"+projectDependency.getVersion());
    		}
    		sb.append(".");
        	if(!modelDependencies.isEmpty())
        		sb.append(" ");
    	}
    	if(!modelDependencies.isEmpty()){
    		sb.append("module.ceylon dependencies missing from pom.xml descriptor: ");
    		boolean once = true;
    		for (Dependency modelDependency : modelDependencies) {
    			if(once)
    				once = false;
    			else
    				sb.append(", ");
    			sb.append(modelDependency.getGroupId()+":"+modelDependency.getArtifactId()+"/"+modelDependency.getVersion());
    		}
    	}
        throw new MojoExecutionException("Descriptors mismatch: "+sb.toString());
	}

	private void unzip(File zip, File targetDir) {
      try {
          final ZipFile zipFile = new ZipFile(zip);
          try {
              final Enumeration entries = zipFile.entries();
              while (entries.hasMoreElements()) {
                  final ZipEntry ze = entries.nextElement();
                  final File file = new File(targetDir, ze.getName());
                  if (ze.isDirectory()) {
                      if (!file.exists() && file.mkdirs() == false)
                          throw new IllegalArgumentException("Cannot create dir: " + file);
                  } else {
                      final FileOutputStream fos = new FileOutputStream(file);
                      copyStream(zipFile.getInputStream(ze), fos);
                  }
              }
          } finally {
              zipFile.close();
          }
      } catch (IOException e) {
          throw new IllegalArgumentException(e);
      }
  }

  private static void copyStream(final InputStream in, final OutputStream out) throws IOException {
      final byte[] bytes = new byte[8192];
      int cnt;
      try {
          while ((cnt = in.read(bytes)) != -1) {
              out.write(bytes, 0, cnt);
          }
      } finally {
          safeClose(in);
          safeClose(out);
      }
  }

  private static void safeClose(Closeable c) {
      try {
          c.close();
      } catch (Exception ignored) {
      }
  }

  @Override
  protected Backend getBackend() {
	return Backend.Java;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy