blob: 8dc26568a62ad6a900e2a124006fdd8e6d490b62 [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 org.apache.royale.maven;
import org.apache.royale.maven.utils.DependencyHelper;
import org.apache.flex.tools.FlexTool;
import org.apache.flex.tools.FlexToolGroup;
import org.apache.flex.tools.FlexToolRegistry;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectDependenciesResolver;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import org.eclipse.aether.RepositorySystemSession;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
/**
*/
public abstract class BaseMojo
extends AbstractMojo
{
@Parameter(defaultValue = "${project}", readonly = true)
protected MavenProject project;
@Parameter(defaultValue="${project.build.directory}")
protected File outputDirectory;
@Parameter
private Namespace[] namespaces;
@Parameter
private String[] includeClasses;
@Parameter
private IncludeFile[] includeFiles;
@Parameter
private Define[] defines;
@Parameter
private String[] keepAs3Metadata;
/**
* When compiling framework libraries, it might be desirable to link the
* dependencies externally, by setting this option to 'true' all dependencies
* are added to the external-library-path, no matter what scope they have.
*/
@Parameter(defaultValue = "false")
private boolean forceSwcExternalLibraryPath;
@Parameter(defaultValue = "11.1")
private String targetPlayer;
@Parameter(defaultValue = "false")
private boolean includeSources;
@Parameter
protected boolean debug = false;
@Parameter
protected boolean failOnCompilerWarnings = false;
@Parameter
protected boolean allowSubclassOverrides = false;
@Parameter
private Boolean includeLookupOnly = null;
@Parameter(readonly = true, defaultValue = "${repositorySystemSession}")
private RepositorySystemSession repositorySystemSession;
@Parameter
private String additionalCompilerOptions = null;
@Component
private ProjectDependenciesResolver projectDependenciesResolver;
protected boolean skip() {
return false;
}
protected abstract String getConfigFileName() throws MojoExecutionException;
protected abstract File getOutput() throws MojoExecutionException;
protected String getLanguageManifestFileName()
{
return "mxml-language-manifest.xml";
}
protected String getLanguageNamespaceURI()
{
return "http://ns.adobe.com/mxml/2009";
}
protected VelocityContext getVelocityContext() throws MojoExecutionException {
VelocityContext context = new VelocityContext();
List<Artifact> allLibraries = DependencyHelper.getAllLibraries(
project, repositorySystemSession, projectDependenciesResolver);
List<Artifact> filteredLibraries = getFilteredLibraries(allLibraries);
List<Artifact> libraries = getLibraries(filteredLibraries);
List<Artifact> jsLibraries = getJSLibraries(filteredLibraries);
List<Artifact> swfLibraries = getSWFLibraries(filteredLibraries);
List<Artifact> externalLibraries = getExternalLibraries(filteredLibraries);
List<Artifact> jsExternalLibraries = getJSExternalLibraries(filteredLibraries);
List<Artifact> swfExternalLibraries = getSWFExternalLibraries(filteredLibraries);
List<Artifact> themeLibraries = getThemeLibraries(filteredLibraries);
List<String> sourcePaths = getSourcePaths();
context.put("libraries", libraries);
context.put("externalLibraries", externalLibraries);
context.put("jsLibraries", jsLibraries);
context.put("jsExternalLibraries", jsExternalLibraries);
context.put("swfLibraries", swfLibraries);
context.put("swfExternalLibraries", swfExternalLibraries);
context.put("themeLibraries", themeLibraries);
context.put("sourcePaths", sourcePaths);
context.put("languageNamespace", getLanguageNamespace());
context.put("namespaces", getNamespaces());
context.put("jsNamespaces", getNamespacesJS());
context.put("namespaceUris", getNamespaceUris());
context.put("includeClasses", includeClasses);
context.put("includeFiles", includeFiles);
context.put("defines", getDefines());
context.put("keepAs3Metadata", keepAs3Metadata);
context.put("targetPlayer", targetPlayer);
context.put("includeSources", includeSources);
context.put("debug", debug);
context.put("allowSubclassOverrides", allowSubclassOverrides);
if(includeLookupOnly != null) {
context.put("includeLookupOnly", includeLookupOnly);
}
context.put("output", getOutput());
context.put("manifestComponents", getLanguageManifestComponents());
return context;
}
protected abstract String getToolGroupName();
protected abstract String getFlexTool();
protected List<Namespace> getNamespaces() {
List<Namespace> namespaces = new LinkedList<Namespace>();
if(this.namespaces != null) {
for (Namespace namespace : this.namespaces) {
namespaces.add(namespace);
}
}
return namespaces;
}
protected Namespace getLanguageNamespace() {
File manifestFile = new File(outputDirectory, getLanguageManifestFileName());
Namespace namespace = new Namespace();
namespace.setUri(getLanguageNamespaceURI());
namespace.setManifest(manifestFile.getAbsolutePath());
return namespace;
}
protected List<Namespace> getNamespacesJS() {
List<Namespace> namespaces = new LinkedList<Namespace>();
if(this.namespaces != null) {
for (Namespace namespace : this.namespaces) {
namespaces.add(namespace);
}
}
return namespaces;
}
protected Set<String> getNamespaceUris() {
Set<String> namespaceUris = new HashSet<String>();
for(Namespace namespace : getNamespaces()) {
namespaceUris.add(namespace.getUri());
}
return namespaceUris;
}
protected List<ManifestComponent> getLanguageManifestComponents()
{
List<ManifestComponent> manifestComponents = new ArrayList<ManifestComponent>();
manifestComponents.add(new ManifestComponent("Array", "Array", true));
manifestComponents.add(new ManifestComponent("Boolean", "Boolean", true));
manifestComponents.add(new ManifestComponent("Class", "Class", true));
manifestComponents.add(new ManifestComponent("Date", "Date", true));
manifestComponents.add(new ManifestComponent("DesignLayer", "mx.core.DesignLayer", false));
manifestComponents.add(new ManifestComponent("Function", "Function", true));
manifestComponents.add(new ManifestComponent("int", "int", true));
manifestComponents.add(new ManifestComponent("Number", "Number", true));
manifestComponents.add(new ManifestComponent("Object", "Object", true));
manifestComponents.add(new ManifestComponent("RegExp", "RegExp", true));
manifestComponents.add(new ManifestComponent("String", "String", true));
manifestComponents.add(new ManifestComponent("uint", "uint", true));
manifestComponents.add(new ManifestComponent("Vector", "__AS3__.vec.Vector", true));
manifestComponents.add(new ManifestComponent("XML", "XML", true));
manifestComponents.add(new ManifestComponent("XMLList", "XMLList", true));
return manifestComponents;
}
@SuppressWarnings("unchecked")
protected List<String> getSourcePaths() {
List<String> sourcePaths = new LinkedList<String>();
for(String sourcePath : (List<String>) project.getCompileSourceRoots()) {
if(new File(sourcePath).exists()) {
sourcePaths.add(sourcePath);
}
}
return sourcePaths;
}
protected String getSourcePath(String resourceOnPath) {
for(String path : getSourcePaths()) {
File tmpFile = new File(path, resourceOnPath);
if(tmpFile.exists()) {
return tmpFile.getPath();
}
}
return null;
}
/*@SuppressWarnings("unchecked")
protected List<IncludeFile> getIncludedFiles() {
List<IncludeFile> includedFiles = new LinkedList<IncludeFile>();
// Add all manually added files.
if(includeFiles != null) {
includedFiles.addAll(Arrays.asList(includeFiles));
}
// Add all files in the resources directory.
if(project.getResources() != null) {
for(Resource resource : (List<Resource>) project.getResources()) {
File resourceDirectory = new File(resource.getDirectory());
if(resourceDirectory.exists()) {
Collection<File> files = FileUtils.listFiles(resourceDirectory,
new RegexFileFilter("^(.*?)"), DirectoryFileFilter.DIRECTORY);
for(File file : files) {
IncludeFile includeFile = new IncludeFile();
String relativePath = file.getPath().substring(resourceDirectory.getPath().length());
includeFile.setName(relativePath);
includeFile.setPath(file.getPath());
includedFiles.add(includeFile);
}
}
}
}
return includedFiles;
}*/
protected List<String> getCompilerArgs(File configFile) throws MojoExecutionException {
List<String> args = new LinkedList<String>();
args.add("-load-config=" + configFile.getPath());
if(additionalCompilerOptions != null) {
//remove whitespace after any '=' or '+='
additionalCompilerOptions = additionalCompilerOptions.replaceAll("=\\s+", "=");
//remove whitespace before or after any ',' (this assumes that ',' is never part of a value assignment itself and is only used to separate list values in config settings)
additionalCompilerOptions = additionalCompilerOptions.replaceAll("\\s*,\\s*", ",");
//any explicit line separators can be resolved to a single separator (';') multiple sequential separators will be ignored if there are explicit ';' separators included below
additionalCompilerOptions = additionalCompilerOptions.replaceAll("(\\r\\n?|\\n)+", ";");
if (additionalCompilerOptions.contains(";"))
{
String[] options = additionalCompilerOptions.split(";");
for (String option : options)
{
if (option.trim().length() > 0)
args.add(option.trim());
}
}
else {
if (additionalCompilerOptions.trim().length() > 0)
args.add(additionalCompilerOptions.trim());
}
}
return args;
}
public void execute()
throws MojoExecutionException
{
// Skip this step if not all preconditions are met.
if(skip()) {
return;
}
VelocityEngine velocityEngine = new VelocityEngine();
velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
velocityEngine.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
velocityEngine.init();
VelocityContext context = getVelocityContext();
// Prepare the config file.
File configFile = new File(outputDirectory, getConfigFileName());
Template configTemplate = velocityEngine.getTemplate("config/" + getConfigFileName());
if(!configFile.getParentFile().exists()) {
if(!configFile.getParentFile().mkdirs()) {
throw new MojoExecutionException("Could not create output directory: " + configFile.getParent());
}
}
FileWriter configWriter = null;
try {
configWriter = new FileWriter(configFile);
configTemplate.merge(context, configWriter);
} catch (IOException e) {
throw new MojoExecutionException("Error creating config file at " + configFile.getPath());
} finally {
if(configWriter != null) {
try {
configWriter.close();
} catch (IOException e) {
throw new MojoExecutionException("Error creating config file at " + configFile.getPath());
}
}
}
// Prepare the MXML language manifest file.
File manifestFile = new File(outputDirectory, getLanguageManifestFileName());
Template manifestTemplate = velocityEngine.getTemplate("config/" + getLanguageManifestFileName());
if(!manifestFile.getParentFile().exists()) {
if(!manifestFile.getParentFile().mkdirs()) {
throw new MojoExecutionException("Could not create output directory: " + manifestFile.getParent());
}
}
FileWriter manifestWriter = null;
try {
manifestWriter = new FileWriter(manifestFile);
manifestTemplate.merge(context, manifestWriter);
} catch (IOException e) {
throw new MojoExecutionException("Error creating manifest file at " + manifestFile.getPath());
} finally {
if(manifestWriter != null) {
try {
manifestWriter.close();
} catch (IOException e) {
throw new MojoExecutionException("Error creating manifest file at " + manifestFile.getPath());
}
}
}
// Get the tool group.
FlexToolRegistry toolRegistry = new FlexToolRegistry();
FlexToolGroup toolGroup = toolRegistry.getToolGroup(getToolGroupName());
if(toolGroup == null) {
throw new MojoExecutionException("Could not find tool group: " + getToolGroupName());
}
// Get an instance of the compiler and run the build.
FlexTool tool = toolGroup.getFlexTool(getFlexTool());
String[] args = getCompilerArgs(configFile).toArray(new String[0]);
getLog().info("Executing " + getFlexTool() + " in tool group " + getToolGroupName() + " with args: " + Arrays.toString(args));
int exitCode = tool.execute(args);
handleExitCode(exitCode);
}
protected void handleExitCode(int exitCode) throws MojoExecutionException {
if(exitCode == 1000) {
throw new MojoExecutionException("The --watch compiler option is not supported by royale-maven-plugin");
}
if(exitCode != 0) {
throw new MojoExecutionException("There were errors during the build. Got return code " + exitCode);
}
}
protected List<Artifact> getFilteredLibraries(List<Artifact> artifacts) {
List<Artifact> filteredLibraries = new LinkedList<Artifact>();
if(artifacts != null) {
for(Artifact artifact : artifacts) {
// Strip out non SWCs for now
if("swc".equals(artifact.getType())) {
filteredLibraries.add(artifact);
}
}
}
return filteredLibraries;
}
protected List<Artifact> getLibraries(List<Artifact> artifacts) {
if(!isForceSwcExternalLibraryPath()) {
return internalGetLibraries(artifacts);
}
return Collections.emptyList();
}
protected List<Artifact> getJSLibraries(List<Artifact> artifacts) {
if(!isForceSwcExternalLibraryPath()) {
return internalGetLibrariesJS(artifacts);
}
return Collections.emptyList();
}
protected List<Artifact> getSWFLibraries(List<Artifact> artifacts) {
if(!isForceSwcExternalLibraryPath()) {
return internalGetLibrariesSWF(artifacts);
}
return Collections.emptyList();
}
protected List<Artifact> getThemeLibraries(List<Artifact> artifacts) {
List<Artifact> themeLibraries = new LinkedList<Artifact>();
for(Artifact artifact : artifacts) {
if("theme".equalsIgnoreCase(artifact.getScope())) {
themeLibraries.add(artifact);
}
}
return themeLibraries;
}
protected List<Artifact> getExternalLibraries(List<Artifact> artifacts) {
List<Artifact> externalLibraries = new LinkedList<Artifact>();
for(Artifact artifact : artifacts) {
if(("provided".equalsIgnoreCase(artifact.getScope()) || "runtime".equalsIgnoreCase(artifact.getScope()))
&& includeLibrary(artifact)) {
if(!"pom".equals(artifact.getType())) {
externalLibraries.add(artifact);
}
}
}
if(isForceSwcExternalLibraryPath()) {
externalLibraries.addAll(internalGetLibraries(artifacts));
}
return externalLibraries;
}
protected List<Artifact> getJSExternalLibraries(List<Artifact> artifacts) {
List<Artifact> externalLibraries = new LinkedList<Artifact>();
for(Artifact artifact : artifacts) {
if(("provided".equalsIgnoreCase(artifact.getScope()) || "runtime".equalsIgnoreCase(artifact.getScope()))
&& includeLibraryJS(artifact)) {
if(!"pom".equals(artifact.getType())) {
externalLibraries.add(artifact);
}
}
}
if(isForceSwcExternalLibraryPath()) {
externalLibraries.addAll(internalGetLibrariesJS(artifacts));
}
return externalLibraries;
}
protected List<Artifact> getSWFExternalLibraries(List<Artifact> artifacts) {
List<Artifact> externalLibraries = new LinkedList<Artifact>();
for(Artifact artifact : artifacts) {
if(("provided".equalsIgnoreCase(artifact.getScope()) || "runtime".equalsIgnoreCase(artifact.getScope()))
&& includeLibrarySWF(artifact)) {
if(!"pom".equals(artifact.getType())) {
externalLibraries.add(artifact);
}
}
}
if(isForceSwcExternalLibraryPath()) {
externalLibraries.addAll(internalGetLibrariesSWF(artifacts));
}
return externalLibraries;
}
protected boolean isForceSwcExternalLibraryPath() {
return forceSwcExternalLibraryPath;
}
private List<Artifact> internalGetLibraries(List<Artifact> artifacts) {
List<Artifact> libraries = new LinkedList<Artifact>();
for (Artifact artifact : artifacts) {
if (!("provided".equalsIgnoreCase(artifact.getScope()) || "runtime".equalsIgnoreCase(artifact.getScope()) || "theme".equalsIgnoreCase(artifact.getScope()))
&& includeLibrary(artifact)) {
if(!"pom".equals(artifact.getType())) {
libraries.add(artifact);
}
}
}
return libraries;
}
private List<Artifact> internalGetLibrariesJS(List<Artifact> artifacts) {
List<Artifact> libraries = new LinkedList<Artifact>();
for (Artifact artifact : artifacts) {
if (!("provided".equalsIgnoreCase(artifact.getScope()) || "runtime".equalsIgnoreCase(artifact.getScope()))
&& includeLibraryJS(artifact)) {
if(!"pom".equals(artifact.getType())) {
libraries.add(artifact);
}
}
}
return libraries;
}
private List<Artifact> internalGetLibrariesSWF(List<Artifact> artifacts) {
List<Artifact> libraries = new LinkedList<Artifact>();
for (Artifact artifact : artifacts) {
if (!("provided".equalsIgnoreCase(artifact.getScope()) || "runtime".equalsIgnoreCase(artifact.getScope()))
&& includeLibrarySWF(artifact)) {
if(!"pom".equals(artifact.getType())) {
libraries.add(artifact);
}
}
}
return libraries;
}
protected List<Define> getDefines() throws MojoExecutionException {
List<Define> defines = new LinkedList<Define>();
if(this.defines != null) {
for(Define define : this.defines) {
defines.add(define);
}
}
return defines;
}
protected boolean includeLibrary(Artifact library) {
return true;
}
protected boolean includeLibraryJS(Artifact library) {
return true;
}
protected boolean includeLibrarySWF(Artifact library) {
return true;
}
}