package xapi.javac.dev.model;
import xapi.file.X_File;
import xapi.fu.Rethrowable;
import xapi.log.X_Log;
import xapi.util.X_Debug;
import xapi.util.X_Namespace;
import xapi.util.X_String;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
/**
* @author James X. Nelson (james@wetheinter.net)
* Created on 4/3/16.
*/
public class CompilerSettings implements Rethrowable {
private boolean verbose;
private String outputDirectory;
private boolean test;
private String root;
private String sourceDirectory;
private String generateDirectory;
private String processorPath;
private List<String> plugins;
private Set<String> classpath;
private boolean generateDebugging;
private boolean useRuntimeClasspath;
private PreferMode preferMode;
private ImplicitMode implicitMode;
private ProcessorMode processorMode;
private boolean clearGenerateDirectory;
private boolean addedRuntimePath;
public CompilerSettings() {
generateDebugging = true;
}
public String[] toArguments(String... files) {
List<String> args = new ArrayList<>();
if (isVerbose()) {
args.add("-verbose");
}
String output = getOutputDirectory();
args.add("-d");
args.add(output);
String sources = getSourceDirectory();
args.add("-sourcepath");
int ind = sources.indexOf("src/main/java");
if (ind != -1) {
sources += File.pathSeparator + sources.replace("src/main/java", "src/main/resources");
sources += File.pathSeparator + sources.replace("src/main/java", "target/generated-sources/annotations");
} else {
ind = sources.indexOf("src/test/java");
if (ind != -1) {
sources += File.pathSeparator + sources.replace("src/test/java", "src/test/resources");
sources += File.pathSeparator + sources.replace("src/test/java", "target/generated-test-sources/test");
}
}
args.add(sources);
String genDir = getGenerateDirectory();
args.add("-s");
args.add(genDir);
if (isClearGenerateDirectory()) {
resetGenerateDirectory();
}
final ProcessorMode proc = getProcessorMode();
final boolean addProcessor;
switch (proc) {
case CompileOnly:
args.add("-proc:none");
addProcessor = false;
break;
case Both:
addProcessor = true;
break;
case ProcessOnly:
args.add("-proc:only");
addProcessor = true;
break;
default:
throw new AssertionError("Can't get here");
}
if (addProcessor) {
String processorPath = getProcessorPath();
args.add("-processorpath");
args.add(processorPath);
}
final Set<String> path = getClasspath();
if (path != null && !path.isEmpty()) {
args.add("-cp");
args.add(X_String.join(File.pathSeparator, path));
}
getPlugins().forEach(plugin -> {
if (!plugin.startsWith("-Xplugin:")) {
plugin = "-Xplugin:" + plugin;
}
args.add(plugin);
});
if (isGenerateDebugging()) {
args.add("-g");
}
PreferMode prefer = getPreferMode();
args.add("-Xprefer:" + prefer.name().toLowerCase());
ImplicitMode implicit = getImplicitMode();
args.add("-implicit:" + implicit.name().toLowerCase());
try {
for (String file : files) {
File asFile = new File(file);
if (asFile.exists()) {
args.add(asFile.getCanonicalPath());
} else {
asFile = new File(getSourceDirectory(), file);
if (asFile.exists()) {
args.add(asFile.getCanonicalPath());
} else {
asFile = new File(getGenerateDirectory(), file);
if (asFile.exists()) {
args.add(asFile.getCanonicalPath());
} else {
asFile = new File(getOutputDirectory(), file);
if (asFile.exists()) {
args.add(asFile.getCanonicalPath());
} else {
throw new IllegalArgumentException("Cannot find file " + file + " in any classpath directories");
}
}
}
}
}
} catch (IOException e) {
throw rethrow(e);
}
X_Log.info(getClass(), "Javac args:\n",
"javac " + X_String.join(" ", args));
return args.toArray(new String[args.size()]);
}
public CompilerSettings resetGenerateDirectory() {
final String genDir = getGenerateDirectory();
File genFile = new File(genDir);
if (!genFile.exists()) {
if (!genFile.mkdirs()) {
X_Log.error(getClass(), "Cannot create generate directory ", genFile, "expect subsequent failures");
}
}
X_File.deepDelete(genDir);
boolean result = genFile.mkdirs();
assert result : "Unable to create generate directory " + genFile;
return this;
}
public PreferMode getPreferMode() {
if (preferMode == null) {
preferMode = PreferMode.NEWER;
}
return preferMode;
}
public CompilerSettings setPreferMode(PreferMode preferMode) {
this.preferMode = preferMode;
return this;
}
public ImplicitMode getImplicitMode() {
if (implicitMode == null) {
implicitMode = ImplicitMode.NONE;
}
return implicitMode;
}
public CompilerSettings setImplicitMode(ImplicitMode implicitMode) {
this.implicitMode = implicitMode;
return this;
}
public boolean isClearGenerateDirectory() {
return clearGenerateDirectory;
}
public CompilerSettings setClearGenerateDirectory(boolean clearGenerateDirectory) {
this.clearGenerateDirectory = clearGenerateDirectory;
return this;
}
public enum PreferMode {
NEWER, SOURCE
}
public enum ImplicitMode {
CLASS, NONE
}
public enum ProcessorMode {
CompileOnly, ProcessOnly, Both
}
public String getRoot() {
if (root == null) {
try {
root = new File(".").getCanonicalPath();
} catch (IOException e) {
throw rethrow(e);
}
}
return root;
}
public CompilerSettings setRoot(String root) {
this.root = root;
return this;
}
@Override
public RuntimeException rethrow(Throwable e) {
X_Debug.debug(e);
return Rethrowable.super.rethrow(e);
}
public boolean isVerbose() {
return verbose;
}
public CompilerSettings setVerbose(boolean verbose) {
this.verbose = verbose;
return this;
}
public String getOutputDirectory() {
if (outputDirectory == null) {
final File classesDir = new File(getRoot(), "target/" + (test ? "test-" : "") + "classes");
try {
if (!classesDir.exists()) {
classesDir.mkdirs();
}
outputDirectory = classesDir.getCanonicalPath();
} catch (IOException e) {
throw rethrow(e);
}
}
return outputDirectory;
}
public CompilerSettings setOutputDirectory(String outputDirectory) {
this.outputDirectory = outputDirectory;
return this;
}
public boolean isTest() {
return test;
}
public CompilerSettings setTest(boolean test) {
this.test = test;
if (test && generateDirectory == null) {
try {
final File f = new File(getRoot(), "target/generated-test-sources/test");
if (!f.exists()) {
f.mkdirs();
}
return setGenerateDirectory(f.getCanonicalPath());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return this;
}
public String getSourceDirectory() {
if (sourceDirectory == null) {
final File resourcesDir = new File(getRoot(), "src/" + (test ? "test" : "main") + "/resources");
try {
sourceDirectory = resourcesDir.getCanonicalPath();
if (!resourcesDir.exists()) {
resourcesDir.mkdirs();
}
} catch (IOException e) {
throw rethrow(e);
}
}
String genDir = getGenerateDirectory();
if (!sourceDirectory.contains(genDir)) {
return X_String.join(File.pathSeparator, sourceDirectory, genDir);
}
return sourceDirectory;
}
public CompilerSettings setSourceDirectory(String sourceDirectory) {
this.sourceDirectory = sourceDirectory;
return this;
}
public String getGenerateDirectory() {
if (generateDirectory == null) {
try {
File f = new File(getRoot(), "target/generated-" + (test ? "test-" : "") + "sources/gwt");
generateDirectory = f.getCanonicalPath();
if (!f.exists()) {
f.mkdirs();
}
} catch (IOException e) {
throw rethrow(e);
}
}
return generateDirectory;
}
public CompilerSettings setGenerateDirectory(String generateDirectory) {
this.generateDirectory = generateDirectory;
return this;
}
public String getProcessorPath() {
if (processorPath == null) {
try {
final File f = new File(root, "target/xapi-dev-javac-" + X_Namespace.XAPI_VERSION + ".jar");
processorPath = f.getCanonicalPath();
} catch (IOException e) {
throw rethrow(e);
}
}
return processorPath;
}
public CompilerSettings setProcessorPath(String processorPath) {
this.processorPath = processorPath;
return this;
}
public List<String> getPlugins() {
if (plugins == null) {
plugins = new ArrayList<>();
plugins.add("MagicMethodPlugin");
plugins.add("GwtCreatePlugin");
plugins.add("XapiCompilerPlugin");
}
return plugins;
}
public void setPlugins(List<String> plugins) {
this.plugins = plugins;
}
public Set<String> getClasspath() {
if (classpath == null) {
classpath = new LinkedHashSet<>();
}
if (isUseRuntimeClasspath() && !addedRuntimePath) {
addedRuntimePath = true;
ClassLoader cl = Thread.currentThread().getContextClassLoader();
while (cl != null) {
if (cl instanceof URLClassLoader) {
for (URL url : ((URLClassLoader) cl).getURLs()) {
classpath.add(url.toExternalForm().replace("file:", ""));
}
}
cl = cl.getParent();
}
}
return classpath;
}
public CompilerSettings setClasspath(Set<String> classpath) {
this.classpath = classpath;
return this;
}
public CompilerSettings addToClasspath(String loc) {
this.classpath.add(loc);
return this;
}
public boolean isGenerateDebugging() {
return generateDebugging;
}
public CompilerSettings setGenerateDebugging(boolean generateDebugging) {
this.generateDebugging = generateDebugging;
return this;
}
public ProcessorMode getProcessorMode() {
if (processorMode == null) {
processorMode = ProcessorMode.Both;
}
return processorMode;
}
public CompilerSettings setProcessorMode(ProcessorMode processorMode) {
this.processorMode = processorMode;
return this;
}
public boolean isUseRuntimeClasspath() {
return useRuntimeClasspath;
}
public CompilerSettings setUseRuntimeClasspath(boolean useRuntimeClasspath) {
this.useRuntimeClasspath = useRuntimeClasspath;
return this;
}
}