/*
* Copyright 2012 James Moger
*
* Licensed 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.moxie.ant;
import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Copy;
import org.apache.tools.ant.taskdefs.Javac;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.Path.PathElement;
import org.moxie.Build;
import org.moxie.MoxieException;
import org.moxie.Scope;
import org.moxie.SourceDirectory;
import org.moxie.Toolkit;
import org.moxie.Toolkit.Key;
import org.moxie.console.Console;
import org.moxie.maxml.MaxmlMap;
import org.moxie.utils.DeepCopier;
import org.moxie.utils.FileUtils;
import org.moxie.utils.StringUtils;
public class MxJavac extends Javac {
Scope scope;
String tag;
boolean clean;
boolean compileLinkedProjects;
String includes;
String excludes;
Set<Build> builds;
private boolean configured;
private Boolean showtitle;
public MxJavac() {
super();
setTaskName("mx:javac");
}
private MxJavac(Set<Build> builds) {
this.builds = builds;
setTaskName("mx:javac");
}
public boolean getClean() {
return clean;
}
public void setClean(boolean clean) {
this.clean = clean;
}
public boolean getCompilelinkedprojects() {
return compileLinkedProjects;
}
public void setCompilelinkedprojects(boolean compileLinkedProjects) {
this.compileLinkedProjects = compileLinkedProjects;
}
public String getScope() {
return scope.name();
}
public void setScope(String scope) {
this.scope = Scope.fromString(scope);
}
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public String getIncludes() {
return includes;
}
@Override
public void setIncludes(String includes) {
this.includes = includes;
}
public String getExcludes() {
return excludes;
}
@Override
public void setExcludes(String excludes) {
this.excludes = excludes;
}
public void setShowtitle(boolean value) {
this.showtitle = value;
}
public boolean isShowTitle() {
return showtitle == null || showtitle;
}
@Override
public void setProject(Project project) {
super.setProject(project);
Build build = (Build) getProject().getReference(Key.build.referenceId());
if (build != null) {
configure(build);
}
}
/**
* Configure the javac task from the mxjavac attributes
* @param build
*/
private void configure(Build build) {
configured = true;
MaxmlMap attributes = build.getConfig().getTaskAttributes(getTaskName());
if (attributes == null) {
build.getConsole().error(getTaskName() + " attributes are null!");
return;
}
// clone the original attributes because we remove the compiler args
attributes = DeepCopier.copy(attributes);
Object args = attributes.remove(Key.compilerArgs.name());
AttributeReflector.setAttributes(getProject(), this, attributes);
if (args != null) {
// set the compiler args, if any
List<Object> list = new ArrayList<Object>();
if (args instanceof List) {
list = (List<Object>) args;
} else if (args instanceof String) {
for (String value : StringUtils.breakCSV(args.toString())) {
if (!StringUtils.isEmpty(value)) {
list.add(value);
}
}
}
for (Object o : list) {
createCompilerArg().setValue(o.toString());
}
}
// create compiler arg for apt generated source
for (SourceDirectory sd : build.getConfig().getSourceDirectories()) {
if (sd.apt) {
createCompilerArg().setLine("-s " + sd.getSources().getAbsolutePath());
}
}
}
@Override
public void execute() {
Build build = (Build) getProject().getReference(Key.build.referenceId());
Console console = build.getConsole();
if (!configured) {
// called from moxie.compile
configure(build);
}
if (scope == null) {
scope = Scope.defaultScope;
}
if (builds == null) {
// top-level mx:javac instantiates the build stack
builds = new HashSet<Build>();
}
if (compileLinkedProjects) {
for (Build linkedProject: build.getSolver().getLinkedModules()) {
if (builds.contains(linkedProject)) {
// already built, skip
console.debug(1, "skipping {0}, already compiled", linkedProject.getPom().getManagementId());
continue;
}
// add the build to the stack so we do not rebuild
builds.add(linkedProject);
try {
// compile the linked project
Project project = new Project();
project.setBaseDir(linkedProject.getConfig().getProjectDirectory());
project.addReference(Key.build.referenceId(), linkedProject);
MxJavac subCompile = new MxJavac(builds);
subCompile.setProject(project);
subCompile.setShowtitle(false);
subCompile.perform();
} catch (Exception e) {
console.error(e);
throw new MoxieException(e);
}
}
}
if (isShowTitle()) {
console.title(getClass(), build.getPom().getCoordinates() + ", " + scope.name());
}
console.debug("mxjavac configuration");
// display specified mxjavac attributes
MaxmlMap attributes = build.getConfig().getTaskAttributes(getTaskName());
AttributeReflector.logAttributes(this, attributes, console);
// project folder
console.debug(1, "projectdir = {0}", build.getConfig().getProjectDirectory());
// create sourcepath
Path sources = createSrc();
for (File file : build.getConfig().getSourceDirectories(scope, tag)) {
PathElement element = sources.createPathElement();
element.setLocation(file);
}
console.debug(1, "sources = {0}", sources);
// set output folder
setDestdir(build.getConfig().getOutputDirectory(scope));
console.debug(1, "destdir = {0}", getDestdir());
// create classpath
Path classpath = createClasspath();
if (Scope.test.equals(scope)) {
// add the compile output folder
PathElement element = classpath.createPathElement();
element.setLocation(build.getConfig().getOutputDirectory(Scope.compile));
}
for (File file : build.getSolver().getClasspath(scope)) {
PathElement element = classpath.createPathElement();
element.setLocation(file);
}
for (Build subbuild : build.getSolver().getLinkedModules()) {
PathElement element = classpath.createPathElement();
element.setLocation(subbuild.getConfig().getOutputDirectory(Scope.compile));
}
console.debug(1, "classpath = {0}", classpath);
for (SourceDirectory sd : build.getConfig().getSourceDirectories()) {
// clean apt source directories before compiling
if (sd.apt) {
console.log("Cleaning apt source directory {0}", sd.name);
FileUtils.delete(sd.getSources());
sd.getSources().mkdirs();
}
}
if (clean) {
// clean the output folder before compiling
console.log("Cleaning output directory {0}", getDestdir().getAbsolutePath());
FileUtils.delete(getDestdir());
}
getDestdir().mkdirs();
// set the update property name so we know if nothing compiled
String prop = build.getPom().getCoordinates().replace(':', '.') + ".compiled";
setUpdatedProperty(prop);
super.execute();
if (getProject().getProperty(prop) == null) {
console.log(1, "compiled classes are up-to-date");
}
Copy copy = new Copy();
copy.setTaskName(getTaskName());
copy.setProject(getProject());
copy.setTodir(getDestdir());
copy.setVerbose(getVerbose());
if (getVerbose()) {
console.log("copying resources => {0}", getDestdir());
}
if (excludes == null) {
// default exclusions
excludes = Toolkit.DEFAULT_CODE_EXCLUDES;
}
for (String path : getSrcdir().list()) {
File file = new File(path);
if (file.isDirectory()) {
FileSet set = prepareResourceSet(file);
copy.addFileset(set);
if (getVerbose()) {
console.log("adding resource path {0}", path);
}
}
}
copy.execute();
}
protected FileSet prepareResourceSet(File dir) {
FileSet set = new FileSet();
set.setDir(dir);
if (includes != null) {
set.setIncludes(includes);
}
if (excludes != null) {
set.setExcludes(excludes);
}
return set;
}
}